startJob
uses node:fs
Start a background job in dir (a session's jobs directory, jobsDirFor): runJob, detached (a process group of
its own, with nothing tying it to this process), running run.cmd in run.cwd with run.env, or asking it
run.call. Its record, output and end are files there, so it runs on when the server that started it stops (tcm
replaced), and the next one follows it. Ids go on from the directory's last, whatever's been cleared away since;
finished jobs' files a day old are cleared away first (sweepJobs).
import { lastJobId, runJob, sweepJobs } from "#codebase/tcmts/cli/mcp"; import type { Job } from "#codebase/tcmts/cli/mcp"; import { spawn } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; export function startJob( dir: string, job: { argv: string[]; tool?: string }, run: { cmd: string[]; cwd: string; env: NodeJS.ProcessEnv; call?: { name: string; arguments: Record<string, unknown> }; }, ): number { fs.mkdirSync(dir, { recursive: true }); sweepJobs(dir); const id = lastJobId(dir) + 1; fs.writeFileSync(path.join(dir, "last"), String(id)); const file = (ext: string) => path.join(dir, `${id}.${ext}`); fs.writeFileSync(file("log"), ""); const spec = { cmd: run.cmd, cwd: run.cwd, log: file("log"), exit: file("exit"), ...(run.call ? { call: run.call } : {}), }; const child = spawn( process.execPath, [ "-e", `(${runJob.toString()})(JSON.parse(process.argv[1]), { spawn: require("node:child_process").spawn, fs: require("node:fs") })`, JSON.stringify(spec), ], { cwd: run.cwd, env: run.env, detached: true, stdio: "ignore" }, ); child.unref(); const record: Job = { ...job, started: Date.now(), pid: child.pid ?? 0, server: process.pid }; fs.writeFileSync(file("json"), JSON.stringify(record)); return id; }