feat: expand live chat and work server tools
This commit is contained in:
168
etc/servers/work-server/src/services/managed-schedule-service.ts
Normal file
168
etc/servers/work-server/src/services/managed-schedule-service.ts
Normal file
@@ -0,0 +1,168 @@
|
||||
import path from 'node:path';
|
||||
import { access, mkdir, rm } from 'node:fs/promises';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { getEnv } from '../config/env.js';
|
||||
import { sendManagedStockAlertWebPush } from './stock-alert-service.js';
|
||||
|
||||
export type ManagedScheduleServiceResult = {
|
||||
ok: boolean;
|
||||
skipped: boolean;
|
||||
title: string;
|
||||
body: string;
|
||||
itemCount: number;
|
||||
lines: string[];
|
||||
ios: {
|
||||
ok: boolean;
|
||||
skipped: boolean;
|
||||
reason?: string;
|
||||
sentCount: number;
|
||||
failedCount: number;
|
||||
};
|
||||
web: {
|
||||
ok: boolean;
|
||||
skipped: boolean;
|
||||
reason?: string;
|
||||
sentCount: number;
|
||||
failedCount: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type ManagedScheduleServiceMetadata = {
|
||||
scheduleId: number;
|
||||
serviceKey: string;
|
||||
packageName: string;
|
||||
relativeDirectory: string;
|
||||
manifestPath: string;
|
||||
readmePath: string;
|
||||
sourcePath: string;
|
||||
runtimePath: string;
|
||||
};
|
||||
|
||||
function sanitizeManagedServiceToken(value: string) {
|
||||
return value
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
.slice(0, 60);
|
||||
}
|
||||
|
||||
function appendScheduleSuffixOnce(value: string, suffix: string) {
|
||||
const normalizedValue = value.trim();
|
||||
const normalizedSuffix = suffix.trim().toLowerCase();
|
||||
|
||||
if (!normalizedValue || !normalizedSuffix) {
|
||||
return normalizedValue;
|
||||
}
|
||||
|
||||
return normalizedValue.toLowerCase().endsWith(`-${normalizedSuffix}`)
|
||||
? normalizedValue
|
||||
: `${normalizedValue}-${suffix.trim()}`;
|
||||
}
|
||||
|
||||
function getScheduleRepoRoot() {
|
||||
const env = getEnv();
|
||||
return env.SERVER_COMMAND_MAIN_PROJECT_ROOT || env.PLAN_MAIN_PROJECT_REPO_PATH || process.cwd();
|
||||
}
|
||||
|
||||
export function buildManagedScheduleServiceMetadata(scheduleId: number, workId: string): ManagedScheduleServiceMetadata {
|
||||
const workToken = sanitizeManagedServiceToken(appendScheduleSuffixOnce(workId, 'service')) || 'task-service';
|
||||
const serviceKey = `schedule-${scheduleId}-${workToken}`;
|
||||
const relativeDirectory = `.auto_codex/schedule/${scheduleId}`;
|
||||
const packageName = workToken || `schedule-${scheduleId}-service`;
|
||||
|
||||
return {
|
||||
scheduleId,
|
||||
serviceKey,
|
||||
packageName,
|
||||
relativeDirectory,
|
||||
manifestPath: `${relativeDirectory}/service-manifest.json`,
|
||||
readmePath: `${relativeDirectory}/README.md`,
|
||||
sourcePath: `${relativeDirectory}/service.ts`,
|
||||
runtimePath: `${relativeDirectory}/service.mjs`,
|
||||
};
|
||||
}
|
||||
|
||||
export async function prepareManagedScheduleServiceDirectory(scheduleId: number) {
|
||||
const repoRoot = getScheduleRepoRoot();
|
||||
const absoluteDirectory = path.join(repoRoot, '.auto_codex', 'schedule', String(scheduleId));
|
||||
|
||||
await mkdir(absoluteDirectory, { recursive: true });
|
||||
await rm(path.join(absoluteDirectory, 'managed-service'), { recursive: true, force: true });
|
||||
}
|
||||
|
||||
export async function removeManagedScheduleServiceArtifacts(scheduleId: number) {
|
||||
const repoRoot = getScheduleRepoRoot();
|
||||
const scheduleDirectory = path.join(repoRoot, '.auto_codex', 'schedule', String(scheduleId));
|
||||
|
||||
await rm(path.join(scheduleDirectory, 'managed-service'), { recursive: true, force: true });
|
||||
await rm(path.join(scheduleDirectory, 'README.md'), { force: true });
|
||||
await rm(path.join(scheduleDirectory, 'service-manifest.json'), { force: true });
|
||||
await rm(path.join(scheduleDirectory, 'service.ts'), { force: true });
|
||||
await rm(path.join(scheduleDirectory, 'service.mjs'), { force: true });
|
||||
}
|
||||
|
||||
export async function hasManagedScheduleServicePackage(relativeDirectory: string | null | undefined) {
|
||||
const trimmedDirectory = String(relativeDirectory ?? '').trim();
|
||||
|
||||
if (!trimmedDirectory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const repoRoot = getScheduleRepoRoot();
|
||||
const runtimePath = path.join(repoRoot, trimmedDirectory, 'service.mjs');
|
||||
const manifestPath = path.join(repoRoot, trimmedDirectory, 'service-manifest.json');
|
||||
|
||||
try {
|
||||
await Promise.all([access(runtimePath), access(manifestPath)]);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function runManagedScheduleService(relativeDirectory: string) {
|
||||
const repoRoot = getScheduleRepoRoot();
|
||||
const runtimePath = path.join(repoRoot, relativeDirectory, 'service.mjs');
|
||||
const importedModule = await import(`${pathToFileURL(runtimePath).href}?t=${Date.now()}`);
|
||||
const run =
|
||||
typeof importedModule.run === 'function'
|
||||
? importedModule.run
|
||||
: typeof importedModule.default?.run === 'function'
|
||||
? importedModule.default.run
|
||||
: null;
|
||||
|
||||
if (!run) {
|
||||
throw new Error(`스케줄 서비스 실행 함수를 찾을 수 없습니다: ${relativeDirectory}/service.mjs`);
|
||||
}
|
||||
|
||||
return run({
|
||||
scheduleRoot: path.join(repoRoot, trimmedRelativeDirectory(relativeDirectory)),
|
||||
scheduleDirectory: trimmedRelativeDirectory(relativeDirectory),
|
||||
repoRoot,
|
||||
now: new Date().toISOString(),
|
||||
runCurrentPriceStockAlertService(definition: { scheduleId: number; serviceKey: string; title: string }) {
|
||||
return sendManagedStockAlertWebPush({
|
||||
scheduleId: definition.scheduleId,
|
||||
serviceKey: definition.serviceKey,
|
||||
title: definition.title,
|
||||
mode: 'price',
|
||||
});
|
||||
},
|
||||
runChangeRateThresholdStockAlertService(
|
||||
definition: { scheduleId: number; serviceKey: string; title: string; thresholdPercent: number },
|
||||
) {
|
||||
return sendManagedStockAlertWebPush({
|
||||
scheduleId: definition.scheduleId,
|
||||
serviceKey: definition.serviceKey,
|
||||
title: definition.title,
|
||||
mode: 'change-threshold',
|
||||
thresholdPercent: definition.thresholdPercent,
|
||||
});
|
||||
},
|
||||
}) as Promise<ManagedScheduleServiceResult>;
|
||||
}
|
||||
|
||||
function trimmedRelativeDirectory(relativeDirectory: string) {
|
||||
return String(relativeDirectory ?? '').trim().replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
|
||||
}
|
||||
Reference in New Issue
Block a user