@agimon-ai/po-runner 0.0.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/ansiScrub-CsqTSaVT.mjs +71 -0
- package/dist/ansiScrub-CsqTSaVT.mjs.map +1 -0
- package/dist/ansiScrub-D5gpHDch.cjs +100 -0
- package/dist/ansiScrub-D5gpHDch.cjs.map +1 -0
- package/dist/ansiScrub.cjs +7 -0
- package/dist/ansiScrub.d.mts +26 -0
- package/dist/ansiScrub.d.mts.map +1 -0
- package/dist/ansiScrub.mjs +2 -0
- package/dist/apiContracts.cjs +162 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +157 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/bashResult-DNgtahGR.cjs +629 -0
- package/dist/bashResult-DNgtahGR.cjs.map +1 -0
- package/dist/bashResult-DcrRaBLv.d.mts +49 -0
- package/dist/bashResult-DcrRaBLv.d.mts.map +1 -0
- package/dist/bashResult-bIVSzoj-.mjs +546 -0
- package/dist/bashResult-bIVSzoj-.mjs.map +1 -0
- package/dist/bashRunService-CJ02XaAq.mjs +440 -0
- package/dist/bashRunService-CJ02XaAq.mjs.map +1 -0
- package/dist/bashRunService-Ci0cGdYO.d.mts +71 -0
- package/dist/bashRunService-Ci0cGdYO.d.mts.map +1 -0
- package/dist/bashRunService-DyqxOSlx.cjs +445 -0
- package/dist/bashRunService-DyqxOSlx.cjs.map +1 -0
- package/dist/bashRunService.cjs +3 -0
- package/dist/bashRunService.d.mts +36 -0
- package/dist/bashRunService.d.mts.map +1 -0
- package/dist/bashRunService.mjs +2 -0
- package/dist/bashSchema.cjs +5 -0
- package/dist/bashSchema.d.mts +7 -0
- package/dist/bashSchema.d.mts.map +1 -0
- package/dist/bashSchema.mjs +2 -0
- package/dist/bashTool-B1EwZLo_.d.mts +20 -0
- package/dist/bashTool-B1EwZLo_.d.mts.map +1 -0
- package/dist/bashTool-C-k7fmyh.mjs +24 -0
- package/dist/bashTool-C-k7fmyh.mjs.map +1 -0
- package/dist/bashTool-CdgtqVFD.cjs +41 -0
- package/dist/bashTool-CdgtqVFD.cjs.map +1 -0
- package/dist/bashTool.cjs +13 -0
- package/dist/bashTool.cjs.map +1 -0
- package/dist/bashTool.d.mts +8 -0
- package/dist/bashTool.d.mts.map +1 -0
- package/dist/bashTool.mjs +11 -0
- package/dist/bashTool.mjs.map +1 -0
- package/dist/bin/cli.cjs +78 -0
- package/dist/bin/cli.cjs.map +1 -0
- package/dist/bin/cli.d.mts +4 -0
- package/dist/bin/cli.d.mts.map +1 -0
- package/dist/bin/cli.mjs +77 -0
- package/dist/bin/cli.mjs.map +1 -0
- package/dist/bin/logSink.cjs +102 -0
- package/dist/bin/logSink.cjs.map +1 -0
- package/dist/bin/logSink.d.mts +4 -0
- package/dist/bin/logSink.d.mts.map +1 -0
- package/dist/bin/logSink.mjs +99 -0
- package/dist/bin/logSink.mjs.map +1 -0
- package/dist/bin/runnerHost.cjs +131 -0
- package/dist/bin/runnerHost.cjs.map +1 -0
- package/dist/bin/runnerHost.d.mts +4 -0
- package/dist/bin/runnerHost.d.mts.map +1 -0
- package/dist/bin/runnerHost.mjs +127 -0
- package/dist/bin/runnerHost.mjs.map +1 -0
- package/dist/cliApp-Dj9nwaOv.cjs +244 -0
- package/dist/cliApp-Dj9nwaOv.cjs.map +1 -0
- package/dist/cliApp-v8Z3rMCi.mjs +237 -0
- package/dist/cliApp-v8Z3rMCi.mjs.map +1 -0
- package/dist/cliApp.cjs +3 -0
- package/dist/cliApp.d.mts +18 -0
- package/dist/cliApp.d.mts.map +1 -0
- package/dist/cliApp.mjs +2 -0
- package/dist/clock-Cv2pddgo.mjs +16 -0
- package/dist/clock-Cv2pddgo.mjs.map +1 -0
- package/dist/clock-euJkweLq.d.mts +11 -0
- package/dist/clock-euJkweLq.d.mts.map +1 -0
- package/dist/clock-jqnLWziT.cjs +21 -0
- package/dist/clock-jqnLWziT.cjs.map +1 -0
- package/dist/clock.cjs +3 -0
- package/dist/clock.d.mts +10 -0
- package/dist/clock.d.mts.map +1 -0
- package/dist/clock.mjs +2 -0
- package/dist/compaction-4QSUsBxq.cjs +40 -0
- package/dist/compaction-4QSUsBxq.cjs.map +1 -0
- package/dist/compaction-DCw80VZj.mjs +29 -0
- package/dist/compaction-DCw80VZj.mjs.map +1 -0
- package/dist/compaction.cjs +4 -0
- package/dist/compaction.d.mts +10 -0
- package/dist/compaction.d.mts.map +1 -0
- package/dist/compaction.mjs +2 -0
- package/dist/config.cjs +41 -0
- package/dist/config.d.mts +2 -0
- package/dist/config.mjs +2 -0
- package/dist/extensions/mcp-ui.mjs +23 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +142 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +114 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/server.cjs +1156 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +1146 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +1785 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/headless-BGYfIlNk.mjs +169 -0
- package/dist/headless-BGYfIlNk.mjs.map +1 -0
- package/dist/headless-CHUsBGhg.cjs +180 -0
- package/dist/headless-CHUsBGhg.cjs.map +1 -0
- package/dist/index-BZL7keVW.d.mts +31 -0
- package/dist/index-BZL7keVW.d.mts.map +1 -0
- package/dist/index-BwB_jTI9.d.mts +12 -0
- package/dist/index-BwB_jTI9.d.mts.map +1 -0
- package/dist/index-D9-IXax4.d.mts +43 -0
- package/dist/index-D9-IXax4.d.mts.map +1 -0
- package/dist/index-DBz0DxnL.d.mts +39 -0
- package/dist/index-DBz0DxnL.d.mts.map +1 -0
- package/dist/index-DM7yJpMs.d.mts +25 -0
- package/dist/index-DM7yJpMs.d.mts.map +1 -0
- package/dist/index-Dhi8asLH.d.mts +22 -0
- package/dist/index-Dhi8asLH.d.mts.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +6 -0
- package/dist/launcher-BDm6-DiQ.mjs +150 -0
- package/dist/launcher-BDm6-DiQ.mjs.map +1 -0
- package/dist/launcher-BG5t9nvG.d.mts +39 -0
- package/dist/launcher-BG5t9nvG.d.mts.map +1 -0
- package/dist/launcher-SlyE8R3b.cjs +157 -0
- package/dist/launcher-SlyE8R3b.cjs.map +1 -0
- package/dist/launcher.cjs +3 -0
- package/dist/launcher.d.mts +33 -0
- package/dist/launcher.d.mts.map +1 -0
- package/dist/launcher.mjs +2 -0
- package/dist/lifeline-BZaQA0rm.mjs +88 -0
- package/dist/lifeline-BZaQA0rm.mjs.map +1 -0
- package/dist/lifeline-BuV_erib.cjs +98 -0
- package/dist/lifeline-BuV_erib.cjs.map +1 -0
- package/dist/lifeline-eJdZV0nN.d.mts +19 -0
- package/dist/lifeline-eJdZV0nN.d.mts.map +1 -0
- package/dist/lifeline.cjs +6 -0
- package/dist/lifeline.d.mts +21 -0
- package/dist/lifeline.d.mts.map +1 -0
- package/dist/lifeline.mjs +3 -0
- package/dist/logFile-C7oQ_v-g.d.mts +16 -0
- package/dist/logFile-C7oQ_v-g.d.mts.map +1 -0
- package/dist/logFile-CNvepZh0.cjs +67 -0
- package/dist/logFile-CNvepZh0.cjs.map +1 -0
- package/dist/logFile-KKPbkC-a.mjs +60 -0
- package/dist/logFile-KKPbkC-a.mjs.map +1 -0
- package/dist/logFile.cjs +3 -0
- package/dist/logFile.d.mts +11 -0
- package/dist/logFile.d.mts.map +1 -0
- package/dist/logFile.mjs +2 -0
- package/dist/logReader-B6J7L7Ua.cjs +282 -0
- package/dist/logReader-B6J7L7Ua.cjs.map +1 -0
- package/dist/logReader-MdW9ffvV.d.mts +43 -0
- package/dist/logReader-MdW9ffvV.d.mts.map +1 -0
- package/dist/logReader-UfbDbwQl.mjs +257 -0
- package/dist/logReader-UfbDbwQl.mjs.map +1 -0
- package/dist/logReader.cjs +4 -0
- package/dist/logReader.d.mts +3 -0
- package/dist/logReader.mjs +2 -0
- package/dist/processControl-BAOa3oo_.d.mts +14 -0
- package/dist/processControl-BAOa3oo_.d.mts.map +1 -0
- package/dist/processControl-DApTpV16.mjs +26 -0
- package/dist/processControl-DApTpV16.mjs.map +1 -0
- package/dist/processControl-DNJ1WZ9N.cjs +31 -0
- package/dist/processControl-DNJ1WZ9N.cjs.map +1 -0
- package/dist/processControl.cjs +3 -0
- package/dist/processControl.d.mts +10 -0
- package/dist/processControl.d.mts.map +1 -0
- package/dist/processControl.mjs +2 -0
- package/dist/ptyHost-DWWtRrGn.d.mts +38 -0
- package/dist/ptyHost-DWWtRrGn.d.mts.map +1 -0
- package/dist/ptyHost-DlQtTB8F.mjs +150 -0
- package/dist/ptyHost-DlQtTB8F.mjs.map +1 -0
- package/dist/ptyHost-MI2Z6WTG.cjs +157 -0
- package/dist/ptyHost-MI2Z6WTG.cjs.map +1 -0
- package/dist/ptyHost.cjs +3 -0
- package/dist/ptyHost.d.mts +26 -0
- package/dist/ptyHost.d.mts.map +1 -0
- package/dist/ptyHost.mjs +2 -0
- package/dist/ptySpawner-B6GsueZd.d.mts +28 -0
- package/dist/ptySpawner-B6GsueZd.d.mts.map +1 -0
- package/dist/ptySpawner-DEi1KOnd.mjs +17 -0
- package/dist/ptySpawner-DEi1KOnd.mjs.map +1 -0
- package/dist/ptySpawner-ijw0g5_T.cjs +22 -0
- package/dist/ptySpawner-ijw0g5_T.cjs.map +1 -0
- package/dist/ptySpawner.cjs +3 -0
- package/dist/ptySpawner.d.mts +14 -0
- package/dist/ptySpawner.d.mts.map +1 -0
- package/dist/ptySpawner.mjs +2 -0
- package/dist/reconcile-BugwYFbV.cjs +133 -0
- package/dist/reconcile-BugwYFbV.cjs.map +1 -0
- package/dist/reconcile-DMeNSxwn.mjs +114 -0
- package/dist/reconcile-DMeNSxwn.mjs.map +1 -0
- package/dist/reconcile.cjs +5 -0
- package/dist/reconcile.d.mts +36 -0
- package/dist/reconcile.d.mts.map +1 -0
- package/dist/reconcile.mjs +2 -0
- package/dist/responseEnvelope.cjs +19 -0
- package/dist/responseEnvelope.d.mts +50 -0
- package/dist/responseEnvelope.d.mts.map +1 -0
- package/dist/responseEnvelope.mjs +3 -0
- package/dist/rmuxBackend-CaEWooWn.d.mts +36 -0
- package/dist/rmuxBackend-CaEWooWn.d.mts.map +1 -0
- package/dist/rmuxBackend-DfyQwJrc.mjs +509 -0
- package/dist/rmuxBackend-DfyQwJrc.mjs.map +1 -0
- package/dist/rmuxBackend-DlxgqRZ1.cjs +523 -0
- package/dist/rmuxBackend-DlxgqRZ1.cjs.map +1 -0
- package/dist/rmuxBackend.cjs +4 -0
- package/dist/rmuxBackend.d.mts +3 -0
- package/dist/rmuxBackend.mjs +2 -0
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/rtkProcessor-B4_urXQr.mjs +10 -0
- package/dist/rtkProcessor-B4_urXQr.mjs.map +1 -0
- package/dist/rtkProcessor-B9KPdyzr.mjs +309 -0
- package/dist/rtkProcessor-B9KPdyzr.mjs.map +1 -0
- package/dist/rtkProcessor-Bc4L4o_8.cjs +335 -0
- package/dist/rtkProcessor-Bc4L4o_8.cjs.map +1 -0
- package/dist/rtkProcessor-CVZvNhkJ.d.mts +35 -0
- package/dist/rtkProcessor-CVZvNhkJ.d.mts.map +1 -0
- package/dist/rtkProcessor-CsrCPyTQ.cjs +33 -0
- package/dist/rtkProcessor-CsrCPyTQ.cjs.map +1 -0
- package/dist/rtkProcessor.cjs +11 -0
- package/dist/rtkProcessor.d.mts +7 -0
- package/dist/rtkProcessor.d.mts.map +1 -0
- package/dist/rtkProcessor.mjs +3 -0
- package/dist/runnerConfig-BQBlVAXn.mjs +134 -0
- package/dist/runnerConfig-BQBlVAXn.mjs.map +1 -0
- package/dist/runnerConfig-BjtulXBI.d.mts +57 -0
- package/dist/runnerConfig-BjtulXBI.d.mts.map +1 -0
- package/dist/runnerConfig-D2tGq5ZM.cjs +367 -0
- package/dist/runnerConfig-D2tGq5ZM.cjs.map +1 -0
- package/dist/runnerDependencies-DruByBGS.mjs +647 -0
- package/dist/runnerDependencies-DruByBGS.mjs.map +1 -0
- package/dist/runnerDependencies-KMZigIxB.cjs +667 -0
- package/dist/runnerDependencies-KMZigIxB.cjs.map +1 -0
- package/dist/runnerDependencies.cjs +3 -0
- package/dist/runnerDependencies.d.mts +2 -0
- package/dist/runnerDependencies.mjs +2 -0
- package/dist/runnerNamer-B8FH7n2v.mjs +44 -0
- package/dist/runnerNamer-B8FH7n2v.mjs.map +1 -0
- package/dist/runnerNamer-we1XVYfM.cjs +49 -0
- package/dist/runnerNamer-we1XVYfM.cjs.map +1 -0
- package/dist/runnerNamer.cjs +3 -0
- package/dist/runnerNamer.d.mts +11 -0
- package/dist/runnerNamer.d.mts.map +1 -0
- package/dist/runnerNamer.mjs +2 -0
- package/dist/runnerPaths-BTEuzxw0.cjs +471 -0
- package/dist/runnerPaths-BTEuzxw0.cjs.map +1 -0
- package/dist/runnerPaths-B_dAAeco.mjs +451 -0
- package/dist/runnerPaths-B_dAAeco.mjs.map +1 -0
- package/dist/runnerPaths.cjs +3 -0
- package/dist/runnerPaths.d.mts +50 -0
- package/dist/runnerPaths.d.mts.map +1 -0
- package/dist/runnerPaths.mjs +2 -0
- package/dist/runnerRegistry-BmkZTJHi.cjs +371 -0
- package/dist/runnerRegistry-BmkZTJHi.cjs.map +1 -0
- package/dist/runnerRegistry-CeOHEjBv.mjs +339 -0
- package/dist/runnerRegistry-CeOHEjBv.mjs.map +1 -0
- package/dist/runnerRegistry-CtJiD02R.d.mts +88 -0
- package/dist/runnerRegistry-CtJiD02R.d.mts.map +1 -0
- package/dist/runnerRegistry.cjs +4 -0
- package/dist/runnerRegistry.d.mts +3 -0
- package/dist/runnerRegistry.mjs +2 -0
- package/dist/runnerSettings-DiV1lvzx.d.mts +34 -0
- package/dist/runnerSettings-DiV1lvzx.d.mts.map +1 -0
- package/dist/services/lifeline/client.cjs +52 -0
- package/dist/services/lifeline/client.cjs.map +1 -0
- package/dist/services/lifeline/client.d.mts +22 -0
- package/dist/services/lifeline/client.d.mts.map +1 -0
- package/dist/services/lifeline/client.mjs +48 -0
- package/dist/services/lifeline/client.mjs.map +1 -0
- package/dist/services/runnerSupervisor/index.cjs +207 -0
- package/dist/services/runnerSupervisor/index.cjs.map +1 -0
- package/dist/services/runnerSupervisor/index.d.mts +71 -0
- package/dist/services/runnerSupervisor/index.d.mts.map +1 -0
- package/dist/services/runnerSupervisor/index.mjs +195 -0
- package/dist/services/runnerSupervisor/index.mjs.map +1 -0
- package/dist/session-BC43uEyG.cjs +29 -0
- package/dist/session-BC43uEyG.cjs.map +1 -0
- package/dist/session-Chsb_Nh2.mjs +18 -0
- package/dist/session-Chsb_Nh2.mjs.map +1 -0
- package/dist/session-DE2Acesp.mjs +6 -0
- package/dist/session-DE2Acesp.mjs.map +1 -0
- package/dist/session-SfIPtdZO.cjs +11 -0
- package/dist/session-SfIPtdZO.cjs.map +1 -0
- package/dist/session.cjs +6 -0
- package/dist/session.d.mts +11 -0
- package/dist/session.d.mts.map +1 -0
- package/dist/session.mjs +3 -0
- package/dist/spawner-BxFsINXP.cjs +68 -0
- package/dist/spawner-BxFsINXP.cjs.map +1 -0
- package/dist/spawner-CdrN_HNk.d.mts +35 -0
- package/dist/spawner-CdrN_HNk.d.mts.map +1 -0
- package/dist/spawner-LoVsn55-.mjs +63 -0
- package/dist/spawner-LoVsn55-.mjs.map +1 -0
- package/dist/spawner.cjs +3 -0
- package/dist/spawner.d.mts +9 -0
- package/dist/spawner.d.mts.map +1 -0
- package/dist/spawner.mjs +2 -0
- package/dist/type-BXM03qSw.d.mts +44 -0
- package/dist/type-BXM03qSw.d.mts.map +1 -0
- package/dist/type-C31e1gla.d.mts +43 -0
- package/dist/type-C31e1gla.d.mts.map +1 -0
- package/dist/type-vWQNTahw.d.mts +12 -0
- package/dist/type-vWQNTahw.d.mts.map +1 -0
- package/dist/types.cjs +0 -0
- package/dist/types.d.mts +3 -0
- package/dist/types.mjs +1 -0
- package/llms.txt +9 -0
- package/package.json +303 -0
- package/skills/doom-runner/SKILL.md +78 -0
- package/src/prompts/po-use-runner/SKILL.md +47 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
+
let node_fs = require("node:fs");
|
|
3
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
6
|
+
let node_child_process = require("node:child_process");
|
|
7
|
+
let node_util = require("node:util");
|
|
8
|
+
let _agimon_ai_foundation_process_registry = require("@agimon-ai/foundation-process-registry");
|
|
9
|
+
let _agimon_ai_po_core_childProcess = require("@agimon-ai/po-core/childProcess");
|
|
10
|
+
//#region src/constants/runnerRegistry.ts
|
|
11
|
+
const SERVICE_TYPE = "tool";
|
|
12
|
+
const SERVICE_PREFIX = "doom-runner:";
|
|
13
|
+
const RUNNER_TAG = "doom-runner";
|
|
14
|
+
const REGISTRY_PATH_ENV = "PROCESS_REGISTRY_PATH";
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/services/runnerRecord/index.ts
|
|
17
|
+
/** The disk record's shape guard, shared by the registry and every reader of its files. */
|
|
18
|
+
function isRunnerRecord(value) {
|
|
19
|
+
if (typeof value !== "object" || value === null) return false;
|
|
20
|
+
const record = value;
|
|
21
|
+
return typeof record.id === "string" && typeof record.name === "string" && typeof record.pid === "number" && typeof record.command === "string" && typeof record.cwd === "string" && typeof record.logPath === "string" && typeof record.sessionId === "string" && typeof record.startedAt === "string" && (record.state === "running" || record.state === "completed") && typeof record.promoted === "boolean" && (record.backend === "rmux" || record.backend === "tmux" || record.backend === "native");
|
|
22
|
+
}
|
|
23
|
+
/** What the agent reads when a runner it sent to the background exits. Shared by the Pi and server hosts. */
|
|
24
|
+
function formatRunnerFinished(record) {
|
|
25
|
+
const outcome = record.exit?.reason ?? record.state;
|
|
26
|
+
const code = record.exit?.code === null || record.exit?.code === void 0 ? "" : `, exit code ${record.exit.code}`;
|
|
27
|
+
return [
|
|
28
|
+
`Background runner ${record.name} exited: ${outcome}${code}.`,
|
|
29
|
+
`Runner ID: ${record.id}`,
|
|
30
|
+
`Log: ${record.logPath}`,
|
|
31
|
+
`Inspect: doom-runner logs ${record.id}`
|
|
32
|
+
].join("\n");
|
|
33
|
+
}
|
|
34
|
+
/** Compact footer text. An absent value removes the group entirely. */
|
|
35
|
+
function formatRunnerStatus(count) {
|
|
36
|
+
return count > 0 ? `Runners ${count} ●` : void 0;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
//#region src/services/runnerRegistry/index.ts
|
|
40
|
+
/** Opens the SQLite-backed registry the rest of the monorepo already shares. */
|
|
41
|
+
function createDefaultProcessRegistry(env = process.env) {
|
|
42
|
+
return (0, _agimon_ai_foundation_process_registry.createProcessRegistryService)(env[REGISTRY_PATH_ENV]);
|
|
43
|
+
}
|
|
44
|
+
function sessionTag(sessionId) {
|
|
45
|
+
return `session:${sessionId}`;
|
|
46
|
+
}
|
|
47
|
+
function readString(record, key) {
|
|
48
|
+
const value = record.metadata?.[key];
|
|
49
|
+
return typeof value === "string" ? value : "";
|
|
50
|
+
}
|
|
51
|
+
function readNumber(record, key) {
|
|
52
|
+
const value = record.metadata?.[key];
|
|
53
|
+
return typeof value === "number" ? value : 0;
|
|
54
|
+
}
|
|
55
|
+
const runCommand = (0, node_util.promisify)(node_child_process.execFile);
|
|
56
|
+
/**
|
|
57
|
+
* The process start time the registry stores to prove a pid is still the
|
|
58
|
+
* process it registered.
|
|
59
|
+
*
|
|
60
|
+
* The registry resolves it itself when the caller omits it, and it does so with
|
|
61
|
+
* `execFileSync`, which stops this process for the length of a `ps` on every
|
|
62
|
+
* runner that starts. Reading it here costs the same subprocess and blocks
|
|
63
|
+
* nothing: the command is already running by the time a runner is registered.
|
|
64
|
+
*
|
|
65
|
+
* The value has to match what the registry would have read, so the command and
|
|
66
|
+
* the trimming are deliberately identical to its own.
|
|
67
|
+
*/
|
|
68
|
+
async function processStartedAt(pid) {
|
|
69
|
+
if (process.platform === "win32") return void 0;
|
|
70
|
+
try {
|
|
71
|
+
const { stdout } = await runCommand("ps", [
|
|
72
|
+
"-o",
|
|
73
|
+
"lstart=",
|
|
74
|
+
"-p",
|
|
75
|
+
String(pid)
|
|
76
|
+
], { encoding: "utf8" });
|
|
77
|
+
return stdout.trim() || void 0;
|
|
78
|
+
} catch {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const listenersBySession = /* @__PURE__ */ new Map();
|
|
83
|
+
var RunnerRegistry = class {
|
|
84
|
+
paths;
|
|
85
|
+
processControl;
|
|
86
|
+
registry;
|
|
87
|
+
environment;
|
|
88
|
+
subscriptions = /* @__PURE__ */ new Set();
|
|
89
|
+
constructor(paths, processControl, registry, environment) {
|
|
90
|
+
this.paths = paths;
|
|
91
|
+
this.processControl = processControl;
|
|
92
|
+
this.registry = registry;
|
|
93
|
+
this.environment = environment;
|
|
94
|
+
}
|
|
95
|
+
async register(input) {
|
|
96
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
97
|
+
const rootSessionId = (0, _agimon_ai_po_core_childProcess.resolveRootSessionId)(input.sessionId, this.environment);
|
|
98
|
+
const identity = await processStartedAt(input.pid);
|
|
99
|
+
const response = await this.registry.registerProcess({
|
|
100
|
+
repositoryPath: this.repositoryPath(),
|
|
101
|
+
serviceName: `${SERVICE_PREFIX}${input.id}`,
|
|
102
|
+
serviceType: SERVICE_TYPE,
|
|
103
|
+
pid: input.pid,
|
|
104
|
+
command: input.command,
|
|
105
|
+
...identity === void 0 ? {} : { processStartedAt: identity },
|
|
106
|
+
tags: (0, _agimon_ai_foundation_process_registry.resolveProcessTags)([
|
|
107
|
+
RUNNER_TAG,
|
|
108
|
+
`runner:${input.id}`,
|
|
109
|
+
sessionTag(input.sessionId)
|
|
110
|
+
]),
|
|
111
|
+
metadata: {
|
|
112
|
+
id: input.id,
|
|
113
|
+
name: input.name,
|
|
114
|
+
command: input.command,
|
|
115
|
+
cwd: input.cwd,
|
|
116
|
+
logPath: input.logPath,
|
|
117
|
+
interactive: input.interactive,
|
|
118
|
+
sessionId: input.sessionId,
|
|
119
|
+
rootSessionId,
|
|
120
|
+
backend: input.backend,
|
|
121
|
+
...input.backendTarget ? { backendTarget: input.backendTarget } : {},
|
|
122
|
+
startedAt,
|
|
123
|
+
hostPid: process.pid
|
|
124
|
+
},
|
|
125
|
+
force: true
|
|
126
|
+
});
|
|
127
|
+
if (!response.success) throw new Error(response.error ?? `Failed to register runner ${input.name}`);
|
|
128
|
+
const record = {
|
|
129
|
+
id: input.id,
|
|
130
|
+
name: input.name,
|
|
131
|
+
pid: input.pid,
|
|
132
|
+
command: input.command,
|
|
133
|
+
cwd: input.cwd,
|
|
134
|
+
logPath: input.logPath,
|
|
135
|
+
interactive: input.interactive,
|
|
136
|
+
sessionId: input.sessionId,
|
|
137
|
+
rootSessionId,
|
|
138
|
+
startedAt,
|
|
139
|
+
state: "running",
|
|
140
|
+
promoted: false,
|
|
141
|
+
backend: input.backend,
|
|
142
|
+
...input.backendTarget ? { backendTarget: input.backendTarget } : {},
|
|
143
|
+
hostPid: process.pid
|
|
144
|
+
};
|
|
145
|
+
this.writeRecord(record);
|
|
146
|
+
this.notify(record.sessionId);
|
|
147
|
+
return record;
|
|
148
|
+
}
|
|
149
|
+
async list() {
|
|
150
|
+
return (await this.registry.listProcesses({
|
|
151
|
+
repositoryPath: this.repositoryPath(),
|
|
152
|
+
serviceType: SERVICE_TYPE,
|
|
153
|
+
tags: (0, _agimon_ai_foundation_process_registry.resolveProcessTags)([RUNNER_TAG])
|
|
154
|
+
})).map(toRunnerRecord);
|
|
155
|
+
}
|
|
156
|
+
async listAcrossRepositories() {
|
|
157
|
+
return (await this.registry.listProcesses({
|
|
158
|
+
serviceType: SERVICE_TYPE,
|
|
159
|
+
tags: (0, _agimon_ai_foundation_process_registry.resolveProcessTags)([RUNNER_TAG])
|
|
160
|
+
})).map(toRunnerRecord);
|
|
161
|
+
}
|
|
162
|
+
async listBySession(sessionId) {
|
|
163
|
+
return (await this.list()).filter((record) => record.sessionId === sessionId);
|
|
164
|
+
}
|
|
165
|
+
async listByRootSession(rootSessionId) {
|
|
166
|
+
return (await this.list()).filter((record) => (record.rootSessionId ?? record.sessionId) === rootSessionId);
|
|
167
|
+
}
|
|
168
|
+
async listAll(sessionId) {
|
|
169
|
+
this.paths.ensureDirectories(sessionId);
|
|
170
|
+
const records = [];
|
|
171
|
+
const directory = this.paths.stateDirectory(sessionId);
|
|
172
|
+
for (const entry of node_fs.default.readdirSync(directory)) {
|
|
173
|
+
if (!isPrimaryMetadataEntry(entry)) continue;
|
|
174
|
+
try {
|
|
175
|
+
const parsed = JSON.parse(node_fs.default.readFileSync(`${directory}/${entry}`, "utf8"));
|
|
176
|
+
if (isRunnerRecord(parsed)) records.push(parsed);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
process.emitWarning(`Could not read runner metadata ${entry}: ${String(error)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return records.sort((left, right) => right.startedAt.localeCompare(left.startedAt));
|
|
182
|
+
}
|
|
183
|
+
async get(id, sessionId) {
|
|
184
|
+
const target = this.paths.statePathFor(id, sessionId);
|
|
185
|
+
try {
|
|
186
|
+
const parsed = JSON.parse(node_fs.default.readFileSync(target, "utf8"));
|
|
187
|
+
if (!isRunnerRecord(parsed) || parsed.id !== id) {
|
|
188
|
+
process.emitWarning(`Could not read runner metadata ${node_path.default.basename(target)}: invalid runner record`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
return parsed;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (error.code === "ENOENT") return void 0;
|
|
194
|
+
process.emitWarning(`Could not read runner metadata ${node_path.default.basename(target)}: ${String(error)}`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async markPromoted(id) {
|
|
199
|
+
const record = await this.get(id);
|
|
200
|
+
if (!record) return void 0;
|
|
201
|
+
const promoted = {
|
|
202
|
+
...record,
|
|
203
|
+
promoted: true
|
|
204
|
+
};
|
|
205
|
+
this.writeRecord(promoted);
|
|
206
|
+
this.notify(promoted.sessionId);
|
|
207
|
+
return promoted;
|
|
208
|
+
}
|
|
209
|
+
async requestTermination(id, intent, sessionId) {
|
|
210
|
+
const record = await this.get(id, sessionId);
|
|
211
|
+
if (!record) return void 0;
|
|
212
|
+
if (record.state === "completed") return record;
|
|
213
|
+
if (intent !== void 0 && record.terminationIntent !== void 0) return record;
|
|
214
|
+
const { terminationIntent: _previous, ...rest } = record;
|
|
215
|
+
const updated = {
|
|
216
|
+
...rest,
|
|
217
|
+
...intent ? { terminationIntent: intent } : {}
|
|
218
|
+
};
|
|
219
|
+
this.writeRecord(updated);
|
|
220
|
+
return updated;
|
|
221
|
+
}
|
|
222
|
+
async complete(id, outcome, sessionId) {
|
|
223
|
+
const persisted = await this.get(id, sessionId);
|
|
224
|
+
if (persisted?.state === "completed") {
|
|
225
|
+
await this.release(id, persisted.sessionId);
|
|
226
|
+
return persisted;
|
|
227
|
+
}
|
|
228
|
+
const active = await this.list();
|
|
229
|
+
const record = persisted ?? active.find((candidate) => candidate.id === id && (sessionId === void 0 || candidate.sessionId === sessionId));
|
|
230
|
+
if (!record) {
|
|
231
|
+
if (!(sessionId !== void 0 && active.some((candidate) => candidate.id === id && candidate.sessionId !== sessionId))) await this.release(id, sessionId);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const completed = {
|
|
235
|
+
...record,
|
|
236
|
+
state: "completed",
|
|
237
|
+
exit: {
|
|
238
|
+
...outcome,
|
|
239
|
+
...outcome.signal !== null && outcome.terminationReason === void 0 && record.terminationIntent === void 0 ? { terminationReason: "external_signal" } : {},
|
|
240
|
+
...record.terminationIntent,
|
|
241
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
this.writeRecord(completed);
|
|
245
|
+
await this.release(id, completed.sessionId);
|
|
246
|
+
return completed;
|
|
247
|
+
}
|
|
248
|
+
async release(id, sessionId) {
|
|
249
|
+
const ownedSessionId = sessionId ?? (await this.list()).find((record) => record.id === id)?.sessionId ?? (await this.get(id))?.sessionId;
|
|
250
|
+
const response = await this.registry.releaseProcess({
|
|
251
|
+
repositoryPath: this.repositoryPath(),
|
|
252
|
+
serviceName: `${SERVICE_PREFIX}${id}`,
|
|
253
|
+
serviceType: SERVICE_TYPE,
|
|
254
|
+
kill: false,
|
|
255
|
+
releasePort: false,
|
|
256
|
+
force: true
|
|
257
|
+
});
|
|
258
|
+
if (!response.success && !response.error?.includes("No matching process entry")) throw new Error(response.error ?? `Failed to release runner ${id}`);
|
|
259
|
+
if (ownedSessionId !== void 0) this.notify(ownedSessionId);
|
|
260
|
+
}
|
|
261
|
+
async pruneDead() {
|
|
262
|
+
const dead = (await this.list()).filter((record) => !this.processControl.isAlive(record.pid));
|
|
263
|
+
for (const record of dead) await this.complete(record.id, {
|
|
264
|
+
reason: "backend_lost",
|
|
265
|
+
code: null,
|
|
266
|
+
signal: null
|
|
267
|
+
}, record.sessionId);
|
|
268
|
+
return dead.map((record) => record.id);
|
|
269
|
+
}
|
|
270
|
+
subscribe(listener, sessionId) {
|
|
271
|
+
const subscribed = () => listener();
|
|
272
|
+
const registration = {
|
|
273
|
+
key: this.subscriptionKey(sessionId),
|
|
274
|
+
listener: subscribed
|
|
275
|
+
};
|
|
276
|
+
const listeners = listenersBySession.get(registration.key) ?? /* @__PURE__ */ new Set();
|
|
277
|
+
listeners.add(subscribed);
|
|
278
|
+
listenersBySession.set(registration.key, listeners);
|
|
279
|
+
this.subscriptions.add(registration);
|
|
280
|
+
return () => this.removeSubscription(registration);
|
|
281
|
+
}
|
|
282
|
+
close() {
|
|
283
|
+
for (const registration of this.subscriptions) this.removeSubscription(registration);
|
|
284
|
+
this.registry.close();
|
|
285
|
+
}
|
|
286
|
+
notify(sessionId) {
|
|
287
|
+
for (const listener of listenersBySession.get(this.subscriptionKey(sessionId)) ?? []) try {
|
|
288
|
+
listener();
|
|
289
|
+
} catch (error) {
|
|
290
|
+
process.emitWarning(`Runner registry listener failed: ${String(error)}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
removeSubscription(registration) {
|
|
294
|
+
const listeners = listenersBySession.get(registration.key);
|
|
295
|
+
listeners?.delete(registration.listener);
|
|
296
|
+
if (listeners?.size === 0) listenersBySession.delete(registration.key);
|
|
297
|
+
this.subscriptions.delete(registration);
|
|
298
|
+
}
|
|
299
|
+
subscriptionKey(sessionId) {
|
|
300
|
+
return JSON.stringify([node_path.default.resolve(this.paths.stateDirectory(sessionId)), sessionId]);
|
|
301
|
+
}
|
|
302
|
+
repositoryPath() {
|
|
303
|
+
return (0, _agimon_ai_foundation_process_registry.normalizeRepositoryPath)(this.paths.repositoryPath());
|
|
304
|
+
}
|
|
305
|
+
writeRecord(record) {
|
|
306
|
+
this.paths.ensureDirectories(record.sessionId);
|
|
307
|
+
const target = this.paths.statePathFor(record.id, record.sessionId);
|
|
308
|
+
const temporary = `${target}.${process.pid}.tmp`;
|
|
309
|
+
node_fs.default.writeFileSync(temporary, `${JSON.stringify(record, null, 2)}\n`, "utf8");
|
|
310
|
+
node_fs.default.renameSync(temporary, target);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
/** Every field is read back from metadata this class wrote on registration. */
|
|
314
|
+
function toRunnerRecord(record) {
|
|
315
|
+
return {
|
|
316
|
+
id: readString(record, "id"),
|
|
317
|
+
name: readString(record, "name"),
|
|
318
|
+
pid: record.pid,
|
|
319
|
+
command: readString(record, "command"),
|
|
320
|
+
cwd: readString(record, "cwd"),
|
|
321
|
+
logPath: readString(record, "logPath"),
|
|
322
|
+
interactive: record.metadata?.interactive === true,
|
|
323
|
+
sessionId: readString(record, "sessionId"),
|
|
324
|
+
...readString(record, "rootSessionId") ? { rootSessionId: readString(record, "rootSessionId") } : {},
|
|
325
|
+
startedAt: readString(record, "startedAt"),
|
|
326
|
+
state: "running",
|
|
327
|
+
promoted: false,
|
|
328
|
+
backend: readBackend(record.metadata?.backend),
|
|
329
|
+
...readString(record, "backendTarget") ? { backendTarget: readString(record, "backendTarget") } : {},
|
|
330
|
+
hostPid: readNumber(record, "hostPid")
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function readBackend(value) {
|
|
334
|
+
return value === "rmux" || value === "tmux" ? value : "native";
|
|
335
|
+
}
|
|
336
|
+
function isPrimaryMetadataEntry(entry) {
|
|
337
|
+
return entry.endsWith(".json") && !entry.endsWith(".command.json") && !entry.endsWith(".exit.json");
|
|
338
|
+
}
|
|
339
|
+
//#endregion
|
|
340
|
+
Object.defineProperty(exports, "RunnerRegistry", {
|
|
341
|
+
enumerable: true,
|
|
342
|
+
get: function() {
|
|
343
|
+
return RunnerRegistry;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
Object.defineProperty(exports, "createDefaultProcessRegistry", {
|
|
347
|
+
enumerable: true,
|
|
348
|
+
get: function() {
|
|
349
|
+
return createDefaultProcessRegistry;
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
Object.defineProperty(exports, "formatRunnerFinished", {
|
|
353
|
+
enumerable: true,
|
|
354
|
+
get: function() {
|
|
355
|
+
return formatRunnerFinished;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
Object.defineProperty(exports, "formatRunnerStatus", {
|
|
359
|
+
enumerable: true,
|
|
360
|
+
get: function() {
|
|
361
|
+
return formatRunnerStatus;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
Object.defineProperty(exports, "isRunnerRecord", {
|
|
365
|
+
enumerable: true,
|
|
366
|
+
get: function() {
|
|
367
|
+
return isRunnerRecord;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
//# sourceMappingURL=runnerRegistry-BmkZTJHi.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runnerRegistry-BmkZTJHi.cjs","names":["createProcessRegistryService","promisify","execFile","resolveRootSessionId","resolveProcessTags","fs","path","normalizeRepositoryPath"],"sources":["../src/constants/runnerRegistry.ts","../src/services/runnerRecord/index.ts","../src/services/runnerRegistry/index.ts"],"sourcesContent":["export const SERVICE_TYPE = 'tool';\nexport const SERVICE_PREFIX = 'doom-runner:';\nexport const RUNNER_TAG = 'doom-runner';\nexport const REGISTRY_PATH_ENV = 'PROCESS_REGISTRY_PATH';\nexport const JSON_EXTENSION = '.json';\nexport const COMMAND_SIDECAR_SUFFIX = '.command.json';\nexport const EXIT_SIDECAR_SUFFIX = '.exit.json';\nexport const NOT_FOUND_ERROR_CODE = 'ENOENT';\n","import type { RunnerRecord } from '../../types/runnerRegistry';\n\n/** The disk record's shape guard, shared by the registry and every reader of its files. */\nexport function isRunnerRecord(value: unknown): value is RunnerRecord {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Partial<RunnerRecord>;\n return (\n typeof record.id === 'string' &&\n typeof record.name === 'string' &&\n typeof record.pid === 'number' &&\n typeof record.command === 'string' &&\n typeof record.cwd === 'string' &&\n typeof record.logPath === 'string' &&\n typeof record.sessionId === 'string' &&\n typeof record.startedAt === 'string' &&\n (record.state === 'running' || record.state === 'completed') &&\n typeof record.promoted === 'boolean' &&\n (record.backend === 'rmux' || record.backend === 'tmux' || record.backend === 'native')\n );\n}\n\n/** What the agent reads when a runner it sent to the background exits. Shared by the Pi and server hosts. */\nexport function formatRunnerFinished(record: RunnerRecord): string {\n const outcome = record.exit?.reason ?? record.state;\n const code = record.exit?.code === null || record.exit?.code === undefined ? '' : `, exit code ${record.exit.code}`;\n return [\n `Background runner ${record.name} exited: ${outcome}${code}.`,\n `Runner ID: ${record.id}`,\n `Log: ${record.logPath}`,\n `Inspect: doom-runner logs ${record.id}`,\n ].join('\\n');\n}\n\n/** Compact footer text. An absent value removes the group entirely. */\nexport function formatRunnerStatus(count: number): string | undefined {\n return count > 0 ? `Runners ${count} ●` : undefined;\n}\n\nexport function formatRunnerFooterContribution(count: number): { fullText: string; compactText: string } | undefined {\n return count > 0 ? { fullText: `Runner ${count}`, compactText: `R${count}` } : undefined;\n}\n","import { execFile } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { promisify } from 'node:util';\n\nimport {\n createProcessRegistryService,\n normalizeRepositoryPath,\n type ProcessRegistryRecord,\n type ProcessRegistryService,\n resolveProcessTags,\n} from '@agimon-ai/foundation-process-registry';\nimport { resolveRootSessionId } from '@agimon-ai/po-core/childProcess';\n\nimport {\n COMMAND_SIDECAR_SUFFIX,\n EXIT_SIDECAR_SUFFIX,\n JSON_EXTENSION,\n NOT_FOUND_ERROR_CODE,\n REGISTRY_PATH_ENV,\n RUNNER_TAG,\n SERVICE_PREFIX,\n SERVICE_TYPE,\n} from '../../constants/runnerRegistry';\nimport type { IProcessControl } from '../../types/processControl';\nimport type {\n CompleteRunnerInput,\n IRunnerRegistry,\n RegisterRunnerInput,\n RunnerRecord,\n RunnerTerminationIntent,\n} from '../../types/runnerRegistry';\nimport type { IRunnerPaths } from '../runnerPaths/type';\nimport { isRunnerRecord } from '../runnerRecord';\n\n/** The slice of the shared registry service this wrapper depends on. */\nexport type ProcessRegistryPort = Pick<\n ProcessRegistryService,\n 'registerProcess' | 'releaseProcess' | 'listProcesses' | 'close'\n>;\n\n/** Opens the SQLite-backed registry the rest of the monorepo already shares. */\nexport function createDefaultProcessRegistry(\n env: Readonly<Record<string, string | undefined>> = process.env,\n): ProcessRegistryPort {\n return createProcessRegistryService(env[REGISTRY_PATH_ENV]);\n}\n\nfunction sessionTag(sessionId: string): string {\n return `session:${sessionId}`;\n}\n\nfunction readString(record: ProcessRegistryRecord, key: string): string {\n const value = record.metadata?.[key];\n return typeof value === 'string' ? value : '';\n}\n\nfunction readNumber(record: ProcessRegistryRecord, key: string): number {\n const value = record.metadata?.[key];\n return typeof value === 'number' ? value : 0;\n}\n\nconst runCommand = promisify(execFile);\n\n/**\n * The process start time the registry stores to prove a pid is still the\n * process it registered.\n *\n * The registry resolves it itself when the caller omits it, and it does so with\n * `execFileSync`, which stops this process for the length of a `ps` on every\n * runner that starts. Reading it here costs the same subprocess and blocks\n * nothing: the command is already running by the time a runner is registered.\n *\n * The value has to match what the registry would have read, so the command and\n * the trimming are deliberately identical to its own.\n */\nasync function processStartedAt(pid: number): Promise<string | undefined> {\n if (process.platform === 'win32') return undefined;\n try {\n const { stdout } = await runCommand('ps', ['-o', 'lstart=', '-p', String(pid)], { encoding: 'utf8' });\n return stdout.trim() || undefined;\n } catch {\n return undefined;\n }\n}\n\ntype ListenerRegistration = Readonly<{ key: string; listener: () => void }>;\n\n// Facet replacement can leave an in-flight tool and its publisher on different registry instances.\nconst listenersBySession = new Map<string, Set<() => void>>();\n\nexport class RunnerRegistry implements IRunnerRegistry {\n private readonly subscriptions = new Set<ListenerRegistration>();\n\n constructor(\n private readonly paths: IRunnerPaths,\n private readonly processControl: IProcessControl,\n private readonly registry: ProcessRegistryPort,\n private readonly environment: Readonly<Record<string, string | undefined>>,\n ) {}\n\n async register(input: RegisterRunnerInput): Promise<RunnerRecord> {\n const startedAt = new Date().toISOString();\n const rootSessionId = resolveRootSessionId(input.sessionId, this.environment);\n const identity = await processStartedAt(input.pid);\n const response = await this.registry.registerProcess({\n repositoryPath: this.repositoryPath(),\n serviceName: `${SERVICE_PREFIX}${input.id}`,\n serviceType: SERVICE_TYPE,\n pid: input.pid,\n command: input.command,\n ...(identity === undefined ? {} : { processStartedAt: identity }),\n tags: resolveProcessTags([RUNNER_TAG, `runner:${input.id}`, sessionTag(input.sessionId)]),\n metadata: {\n id: input.id,\n name: input.name,\n command: input.command,\n cwd: input.cwd,\n logPath: input.logPath,\n interactive: input.interactive,\n sessionId: input.sessionId,\n rootSessionId,\n backend: input.backend,\n ...(input.backendTarget ? { backendTarget: input.backendTarget } : {}),\n startedAt,\n hostPid: process.pid,\n },\n // The caller has already resolved name collisions against live records,\n // so anything still holding this name is stale.\n force: true,\n });\n if (!response.success) throw new Error(response.error ?? `Failed to register runner ${input.name}`);\n const record: RunnerRecord = {\n id: input.id,\n name: input.name,\n pid: input.pid,\n command: input.command,\n cwd: input.cwd,\n logPath: input.logPath,\n interactive: input.interactive,\n sessionId: input.sessionId,\n rootSessionId,\n startedAt,\n state: 'running',\n promoted: false,\n backend: input.backend,\n ...(input.backendTarget ? { backendTarget: input.backendTarget } : {}),\n hostPid: process.pid,\n };\n this.writeRecord(record);\n this.notify(record.sessionId);\n return record;\n }\n\n async list(): Promise<RunnerRecord[]> {\n const records = await this.registry.listProcesses({\n repositoryPath: this.repositoryPath(),\n serviceType: SERVICE_TYPE,\n tags: resolveProcessTags([RUNNER_TAG]),\n });\n return records.map(toRunnerRecord);\n }\n\n async listAcrossRepositories(): Promise<RunnerRecord[]> {\n const records = await this.registry.listProcesses({\n serviceType: SERVICE_TYPE,\n tags: resolveProcessTags([RUNNER_TAG]),\n });\n return records.map(toRunnerRecord);\n }\n\n async listBySession(sessionId: string): Promise<RunnerRecord[]> {\n const records = await this.list();\n return records.filter((record) => record.sessionId === sessionId);\n }\n\n async listByRootSession(rootSessionId: string): Promise<RunnerRecord[]> {\n const records = await this.list();\n return records.filter((record) => (record.rootSessionId ?? record.sessionId) === rootSessionId);\n }\n\n async listAll(sessionId?: string): Promise<RunnerRecord[]> {\n this.paths.ensureDirectories(sessionId);\n const records: RunnerRecord[] = [];\n const directory = this.paths.stateDirectory(sessionId);\n for (const entry of fs.readdirSync(directory)) {\n if (!isPrimaryMetadataEntry(entry)) continue;\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(`${directory}/${entry}`, 'utf8'));\n if (isRunnerRecord(parsed)) records.push(parsed);\n } catch (error) {\n process.emitWarning(`Could not read runner metadata ${entry}: ${String(error)}`);\n }\n }\n return records.sort((left, right) => right.startedAt.localeCompare(left.startedAt));\n }\n\n async get(id: string, sessionId?: string): Promise<RunnerRecord | undefined> {\n const target = this.paths.statePathFor(id, sessionId);\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(target, 'utf8'));\n if (!isRunnerRecord(parsed) || parsed.id !== id) {\n process.emitWarning(`Could not read runner metadata ${path.basename(target)}: invalid runner record`);\n return undefined;\n }\n return parsed;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === NOT_FOUND_ERROR_CODE) return undefined;\n process.emitWarning(`Could not read runner metadata ${path.basename(target)}: ${String(error)}`);\n return undefined;\n }\n }\n\n async markPromoted(id: string): Promise<RunnerRecord | undefined> {\n const record = await this.get(id);\n if (!record) return undefined;\n const promoted = { ...record, promoted: true };\n this.writeRecord(promoted);\n this.notify(promoted.sessionId);\n return promoted;\n }\n\n async requestTermination(\n id: string,\n intent: RunnerTerminationIntent | undefined,\n sessionId?: string,\n ): Promise<RunnerRecord | undefined> {\n const record = await this.get(id, sessionId);\n if (!record) return undefined;\n if (record.state === 'completed') return record;\n if (intent !== undefined && record.terminationIntent !== undefined) return record;\n const { terminationIntent: _previous, ...rest } = record;\n const updated: RunnerRecord = { ...rest, ...(intent ? { terminationIntent: intent } : {}) };\n this.writeRecord(updated);\n return updated;\n }\n\n async complete(id: string, outcome: CompleteRunnerInput, sessionId?: string): Promise<RunnerRecord | undefined> {\n const persisted = await this.get(id, sessionId);\n if (persisted?.state === 'completed') {\n await this.release(id, persisted.sessionId);\n return persisted;\n }\n const active = await this.list();\n const record =\n persisted ??\n active.find((candidate) => candidate.id === id && (sessionId === undefined || candidate.sessionId === sessionId));\n if (!record) {\n const belongsToAnotherSession =\n sessionId !== undefined && active.some((candidate) => candidate.id === id && candidate.sessionId !== sessionId);\n if (!belongsToAnotherSession) await this.release(id, sessionId);\n return undefined;\n }\n const completed: RunnerRecord = {\n ...record,\n state: 'completed',\n exit: {\n ...outcome,\n ...(outcome.signal !== null && outcome.terminationReason === undefined && record.terminationIntent === undefined\n ? { terminationReason: 'external_signal' as const }\n : {}),\n ...record.terminationIntent,\n finishedAt: new Date().toISOString(),\n },\n };\n this.writeRecord(completed);\n await this.release(id, completed.sessionId);\n return completed;\n }\n\n async release(id: string, sessionId?: string): Promise<void> {\n const activeSessionId = sessionId ?? (await this.list()).find((record) => record.id === id)?.sessionId;\n const ownedSessionId = activeSessionId ?? (await this.get(id))?.sessionId;\n const response = await this.registry.releaseProcess({\n repositoryPath: this.repositoryPath(),\n serviceName: `${SERVICE_PREFIX}${id}`,\n serviceType: SERVICE_TYPE,\n kill: false,\n releasePort: false,\n force: true,\n });\n if (!response.success && !response.error?.includes('No matching process entry')) {\n throw new Error(response.error ?? `Failed to release runner ${id}`);\n }\n if (ownedSessionId !== undefined) this.notify(ownedSessionId);\n }\n\n async pruneDead(): Promise<string[]> {\n const dead = (await this.list()).filter((record) => !this.processControl.isAlive(record.pid));\n for (const record of dead) {\n await this.complete(record.id, { reason: 'backend_lost', code: null, signal: null }, record.sessionId);\n }\n return dead.map((record) => record.id);\n }\n\n subscribe(listener: () => void, sessionId: string): () => void {\n const subscribed = (): void => listener();\n const registration = { key: this.subscriptionKey(sessionId), listener: subscribed };\n const listeners = listenersBySession.get(registration.key) ?? new Set<() => void>();\n listeners.add(subscribed);\n listenersBySession.set(registration.key, listeners);\n this.subscriptions.add(registration);\n return () => this.removeSubscription(registration);\n }\n\n close(): void {\n for (const registration of this.subscriptions) this.removeSubscription(registration);\n this.registry.close();\n }\n\n private notify(sessionId: string): void {\n for (const listener of listenersBySession.get(this.subscriptionKey(sessionId)) ?? []) {\n try {\n listener();\n } catch (error) {\n process.emitWarning(`Runner registry listener failed: ${String(error)}`);\n }\n }\n }\n\n private removeSubscription(registration: ListenerRegistration): void {\n const listeners = listenersBySession.get(registration.key);\n listeners?.delete(registration.listener);\n if (listeners?.size === 0) listenersBySession.delete(registration.key);\n this.subscriptions.delete(registration);\n }\n\n private subscriptionKey(sessionId: string): string {\n return JSON.stringify([path.resolve(this.paths.stateDirectory(sessionId)), sessionId]);\n }\n\n private repositoryPath(): string {\n return normalizeRepositoryPath(this.paths.repositoryPath());\n }\n\n private writeRecord(record: RunnerRecord): void {\n this.paths.ensureDirectories(record.sessionId);\n const target = this.paths.statePathFor(record.id, record.sessionId);\n const temporary = `${target}.${process.pid}.tmp`;\n fs.writeFileSync(temporary, `${JSON.stringify(record, null, 2)}\\n`, 'utf8');\n fs.renameSync(temporary, target);\n }\n}\n\n/** Every field is read back from metadata this class wrote on registration. */\nfunction toRunnerRecord(record: ProcessRegistryRecord): RunnerRecord {\n return {\n id: readString(record, 'id'),\n name: readString(record, 'name'),\n pid: record.pid,\n command: readString(record, 'command'),\n cwd: readString(record, 'cwd'),\n logPath: readString(record, 'logPath'),\n interactive: record.metadata?.interactive === true,\n sessionId: readString(record, 'sessionId'),\n ...(readString(record, 'rootSessionId') ? { rootSessionId: readString(record, 'rootSessionId') } : {}),\n startedAt: readString(record, 'startedAt'),\n state: 'running',\n promoted: false,\n backend: readBackend(record.metadata?.backend),\n ...(readString(record, 'backendTarget') ? { backendTarget: readString(record, 'backendTarget') } : {}),\n hostPid: readNumber(record, 'hostPid'),\n };\n}\n\nfunction readBackend(value: unknown): RunnerRecord['backend'] {\n return value === 'rmux' || value === 'tmux' ? value : 'native';\n}\n\nfunction isPrimaryMetadataEntry(entry: string): boolean {\n return (\n entry.endsWith(JSON_EXTENSION) && !entry.endsWith(COMMAND_SIDECAR_SUFFIX) && !entry.endsWith(EXIT_SIDECAR_SUFFIX)\n );\n}\n"],"mappings":"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"}
|