feat: add exec host routing + node daemon

This commit is contained in:
Peter Steinberger
2026-01-18 07:44:28 +00:00
parent 49bd2d96fa
commit ae0b4c4990
38 changed files with 2370 additions and 117 deletions

View File

@@ -16,9 +16,18 @@ const formatLine = (label: string, value: string) => {
return `${colorize(rich, theme.muted, `${label}:`)} ${colorize(rich, theme.command, value)}`;
};
function resolveTaskName(env: Record<string, string | undefined>): string {
const override = env.CLAWDBOT_WINDOWS_TASK_NAME?.trim();
if (override) return override;
return resolveGatewayWindowsTaskName(env.CLAWDBOT_PROFILE);
}
export function resolveTaskScriptPath(env: Record<string, string | undefined>): string {
const override = env.CLAWDBOT_TASK_SCRIPT?.trim();
if (override) return override;
const scriptName = env.CLAWDBOT_TASK_SCRIPT_NAME?.trim() || "gateway.cmd";
const stateDir = resolveGatewayStateDir(env);
return path.join(stateDir, "gateway.cmd");
return path.join(stateDir, scriptName);
}
function quoteCmdArg(value: string): string {
@@ -201,29 +210,33 @@ export async function installScheduledTask({
programArguments,
workingDirectory,
environment,
description,
}: {
env: Record<string, string | undefined>;
stdout: NodeJS.WritableStream;
programArguments: string[];
workingDirectory?: string;
environment?: Record<string, string | undefined>;
description?: string;
}): Promise<{ scriptPath: string }> {
await assertSchtasksAvailable();
const scriptPath = resolveTaskScriptPath(env);
await fs.mkdir(path.dirname(scriptPath), { recursive: true });
const description = formatGatewayServiceDescription({
profile: env.CLAWDBOT_PROFILE,
version: environment?.CLAWDBOT_SERVICE_VERSION ?? env.CLAWDBOT_SERVICE_VERSION,
});
const taskDescription =
description ??
formatGatewayServiceDescription({
profile: env.CLAWDBOT_PROFILE,
version: environment?.CLAWDBOT_SERVICE_VERSION ?? env.CLAWDBOT_SERVICE_VERSION,
});
const script = buildTaskScript({
description,
description: taskDescription,
programArguments,
workingDirectory,
environment,
});
await fs.writeFile(scriptPath, script, "utf8");
const taskName = resolveGatewayWindowsTaskName(env.CLAWDBOT_PROFILE);
const taskName = resolveTaskName(env);
const quotedScript = quoteCmdArg(scriptPath);
const baseArgs = [
"/Create",
@@ -268,7 +281,7 @@ export async function uninstallScheduledTask({
stdout: NodeJS.WritableStream;
}): Promise<void> {
await assertSchtasksAvailable();
const taskName = resolveGatewayWindowsTaskName(env.CLAWDBOT_PROFILE);
const taskName = resolveTaskName(env);
await execSchtasks(["/Delete", "/F", "/TN", taskName]);
const scriptPath = resolveTaskScriptPath(env);
@@ -293,7 +306,7 @@ export async function stopScheduledTask({
env?: Record<string, string | undefined>;
}): Promise<void> {
await assertSchtasksAvailable();
const taskName = resolveGatewayWindowsTaskName(env?.CLAWDBOT_PROFILE);
const taskName = resolveTaskName(env ?? (process.env as Record<string, string | undefined>));
const res = await execSchtasks(["/End", "/TN", taskName]);
if (res.code !== 0 && !isTaskNotRunning(res)) {
throw new Error(`schtasks end failed: ${res.stderr || res.stdout}`.trim());
@@ -309,7 +322,7 @@ export async function restartScheduledTask({
env?: Record<string, string | undefined>;
}): Promise<void> {
await assertSchtasksAvailable();
const taskName = resolveGatewayWindowsTaskName(env?.CLAWDBOT_PROFILE);
const taskName = resolveTaskName(env ?? (process.env as Record<string, string | undefined>));
await execSchtasks(["/End", "/TN", taskName]);
const res = await execSchtasks(["/Run", "/TN", taskName]);
if (res.code !== 0) {
@@ -322,7 +335,7 @@ export async function isScheduledTaskInstalled(args: {
env?: Record<string, string | undefined>;
}): Promise<boolean> {
await assertSchtasksAvailable();
const taskName = resolveGatewayWindowsTaskName(args.env?.CLAWDBOT_PROFILE);
const taskName = resolveTaskName(args.env ?? (process.env as Record<string, string | undefined>));
const res = await execSchtasks(["/Query", "/TN", taskName]);
return res.code === 0;
}
@@ -338,7 +351,7 @@ export async function readScheduledTaskRuntime(
detail: String(err),
};
}
const taskName = resolveGatewayWindowsTaskName(env.CLAWDBOT_PROFILE);
const taskName = resolveTaskName(env);
const res = await execSchtasks(["/Query", "/TN", taskName, "/V", "/FO", "LIST"]);
if (res.code !== 0) {
const detail = (res.stderr || res.stdout).trim();