@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,39 @@
|
|
|
1
|
+
import { t as ExitResult } from "./spawner-CdrN_HNk.mjs";
|
|
2
|
+
//#region src/types/launcher.d.ts
|
|
3
|
+
interface LaunchRequest {
|
|
4
|
+
id: string;
|
|
5
|
+
/** Runner name, already allocated and free of collisions. */
|
|
6
|
+
name: string;
|
|
7
|
+
command: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
sessionId: string;
|
|
10
|
+
}
|
|
11
|
+
interface RunHandle {
|
|
12
|
+
readonly id: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly pid: number | undefined;
|
|
15
|
+
readonly logPath: string;
|
|
16
|
+
readonly backend: 'rmux' | 'tmux' | 'native';
|
|
17
|
+
readonly backendTarget?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Output captured so far, tail-capped. The log file always holds everything.
|
|
20
|
+
*/
|
|
21
|
+
output(): string;
|
|
22
|
+
/** Resolves when the process exits, or rejects if it never started. */
|
|
23
|
+
completion(): Promise<ExitResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Stops buffering output in memory and lets the process outlive this handle.
|
|
26
|
+
* Called when a run is promoted to a background runner.
|
|
27
|
+
*/
|
|
28
|
+
detach(): void;
|
|
29
|
+
/** Signals the process group and waits for it to go away. */
|
|
30
|
+
stop(): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
interface ILauncher {
|
|
33
|
+
launch(request: LaunchRequest): RunHandle;
|
|
34
|
+
/** SIGTERM the group led by `pid`, then SIGKILL if it outlasts the grace period. */
|
|
35
|
+
stop(pid: number): Promise<boolean>;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
export { LaunchRequest as n, RunHandle as r, ILauncher as t };
|
|
39
|
+
//# sourceMappingURL=launcher-BG5t9nvG.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launcher-BG5t9nvG.d.mts","names":[],"sources":["../src/types/launcher.ts"],"mappings":";;UAEiB;EACf;;EAEA;EACA;EACA;EACA;;UAGe;WACN;WACA;WACA;WACA;WACA;WACA;;;;EAIT;;EAEA,cAAc,QAAQ;;;;;EAKtB;;EAEA,QAAQ;;UAGO;EACf,OAAO,SAAS,gBAAgB;;EAEhC,KAAK,cAAc"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
+
const require_runnerConfig = require("./runnerConfig-D2tGq5ZM.cjs");
|
|
3
|
+
const require_session = require("./session-SfIPtdZO.cjs");
|
|
4
|
+
const require_services_runnerSupervisor_index = require("./services/runnerSupervisor/index.cjs");
|
|
5
|
+
const require_services_lifeline_client = require("./services/lifeline/client.cjs");
|
|
6
|
+
let node_fs = require("node:fs");
|
|
7
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
8
|
+
//#region src/constants/launcher.ts
|
|
9
|
+
const NON_INTERACTIVE_ENV = {
|
|
10
|
+
FORCE_COLOR: "1",
|
|
11
|
+
CI: "1"
|
|
12
|
+
};
|
|
13
|
+
const TERM_GRACE_MS = 2e3;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/services/launcher/index.ts
|
|
16
|
+
/**
|
|
17
|
+
* Prompts belong on a screen, not in a log file, so `CI` stays set.
|
|
18
|
+
*
|
|
19
|
+
* Colour is kept: the log is replayed into the transcript, and the scrub keeps
|
|
20
|
+
* SGR while still removing the cursor moves that made raw output unreadable.
|
|
21
|
+
*/
|
|
22
|
+
/** In-memory output is a multiple of the result ceiling; the log holds the rest. */
|
|
23
|
+
var Launcher = class {
|
|
24
|
+
spawner;
|
|
25
|
+
processControl;
|
|
26
|
+
logFile;
|
|
27
|
+
clock;
|
|
28
|
+
paths;
|
|
29
|
+
lifeline;
|
|
30
|
+
environment;
|
|
31
|
+
settings;
|
|
32
|
+
constructor(spawner, processControl, logFile, clock, paths, lifeline, environment = process.env, settings) {
|
|
33
|
+
this.spawner = spawner;
|
|
34
|
+
this.processControl = processControl;
|
|
35
|
+
this.logFile = logFile;
|
|
36
|
+
this.clock = clock;
|
|
37
|
+
this.paths = paths;
|
|
38
|
+
this.lifeline = lifeline;
|
|
39
|
+
this.environment = environment;
|
|
40
|
+
this.settings = settings;
|
|
41
|
+
}
|
|
42
|
+
launch(request) {
|
|
43
|
+
const writer = this.logFile.open(request.id);
|
|
44
|
+
const memoryLimit = require_runnerConfig.getResultMaxBytes(this.environment, this.settings) * 2;
|
|
45
|
+
let buffer = "";
|
|
46
|
+
let buffering = true;
|
|
47
|
+
let settled = false;
|
|
48
|
+
let resolveCompletion = () => void 0;
|
|
49
|
+
let rejectCompletion = () => void 0;
|
|
50
|
+
const completion = new Promise((resolve, reject) => {
|
|
51
|
+
resolveCompletion = resolve;
|
|
52
|
+
rejectCompletion = reject;
|
|
53
|
+
});
|
|
54
|
+
this.paths.ensureDirectories(request.sessionId);
|
|
55
|
+
const supervisor = require_services_runnerSupervisor_index.supervisorPaths(this.paths.stateDirectory(request.sessionId), request.id);
|
|
56
|
+
const { [require_services_lifeline_client.LIFELINE_ENV]: _inheritedLifeline, ...environment } = this.environment;
|
|
57
|
+
const env = {
|
|
58
|
+
...environment,
|
|
59
|
+
...NON_INTERACTIVE_ENV,
|
|
60
|
+
...require_runnerConfig.noninteractiveEnvironment(environment),
|
|
61
|
+
...require_services_runnerSupervisor_index.NO_TERMINAL_INPUT_ENV,
|
|
62
|
+
[require_session.PI_SESSION_ID_ENV]: request.sessionId,
|
|
63
|
+
[require_services_lifeline_client.LIFELINE_ENV]: this.lifeline?.path()
|
|
64
|
+
};
|
|
65
|
+
require_services_runnerSupervisor_index.cleanupSupervisorFiles(supervisor);
|
|
66
|
+
require_services_runnerSupervisor_index.writeCommandSpec(supervisor.spec, {
|
|
67
|
+
command: request.command,
|
|
68
|
+
cwd: request.cwd,
|
|
69
|
+
env: defined(env)
|
|
70
|
+
});
|
|
71
|
+
node_fs.default.writeFileSync(supervisor.gate, "", { mode: 384 });
|
|
72
|
+
const child = this.spawner.spawn({
|
|
73
|
+
command: require_services_runnerSupervisor_index.supervisorCommand(supervisor),
|
|
74
|
+
cwd: request.cwd,
|
|
75
|
+
env,
|
|
76
|
+
detached: true
|
|
77
|
+
});
|
|
78
|
+
const failLaunch = (error) => {
|
|
79
|
+
if (settled) return;
|
|
80
|
+
settled = true;
|
|
81
|
+
writer.close();
|
|
82
|
+
require_services_runnerSupervisor_index.cleanupSupervisorFiles(supervisor);
|
|
83
|
+
try {
|
|
84
|
+
child.kill("SIGTERM");
|
|
85
|
+
} catch (killError) {
|
|
86
|
+
process.emitWarning(`Could not stop runner after log failure: ${String(killError)}`);
|
|
87
|
+
}
|
|
88
|
+
rejectCompletion(error instanceof Error ? error : new Error(String(error)));
|
|
89
|
+
};
|
|
90
|
+
child.onOutput((chunk) => {
|
|
91
|
+
if (settled) return;
|
|
92
|
+
try {
|
|
93
|
+
writer.append(chunk);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
failLaunch(error);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!buffering) return;
|
|
99
|
+
buffer += chunk;
|
|
100
|
+
if (buffer.length > memoryLimit) buffer = buffer.slice(-memoryLimit);
|
|
101
|
+
});
|
|
102
|
+
child.onError(failLaunch);
|
|
103
|
+
child.onExit((result) => {
|
|
104
|
+
if (settled) return;
|
|
105
|
+
settled = true;
|
|
106
|
+
writer.close();
|
|
107
|
+
const outcome = require_services_runnerSupervisor_index.readExitMetadata(supervisor.exit) ?? result;
|
|
108
|
+
require_services_runnerSupervisor_index.cleanupSupervisorFiles(supervisor);
|
|
109
|
+
resolveCompletion(outcome);
|
|
110
|
+
});
|
|
111
|
+
child.unref();
|
|
112
|
+
const stop = async () => child.pid === void 0 ? false : this.stop(child.pid);
|
|
113
|
+
return {
|
|
114
|
+
id: request.id,
|
|
115
|
+
name: request.name,
|
|
116
|
+
pid: child.pid,
|
|
117
|
+
logPath: writer.path,
|
|
118
|
+
backend: "native",
|
|
119
|
+
output: () => buffer,
|
|
120
|
+
completion: () => completion,
|
|
121
|
+
detach: () => {
|
|
122
|
+
buffering = false;
|
|
123
|
+
buffer = "";
|
|
124
|
+
},
|
|
125
|
+
stop
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async stop(pid) {
|
|
129
|
+
if (!this.processControl.isAlive(pid)) return false;
|
|
130
|
+
this.processControl.signalGroup(pid, "SIGTERM");
|
|
131
|
+
const deadline = this.clock.now() + TERM_GRACE_MS;
|
|
132
|
+
while (this.clock.now() < deadline) {
|
|
133
|
+
if (!this.processControl.isAlive(pid)) return true;
|
|
134
|
+
await this.sleep(100);
|
|
135
|
+
}
|
|
136
|
+
this.processControl.signalGroup(pid, "SIGKILL");
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
sleep(ms) {
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
this.clock.after(ms, resolve);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
/** The spec is JSON, which has no way to carry an unset variable. */
|
|
146
|
+
function defined(env) {
|
|
147
|
+
return Object.fromEntries(Object.entries(env).filter((entry) => entry[1] !== void 0));
|
|
148
|
+
}
|
|
149
|
+
//#endregion
|
|
150
|
+
Object.defineProperty(exports, "Launcher", {
|
|
151
|
+
enumerable: true,
|
|
152
|
+
get: function() {
|
|
153
|
+
return Launcher;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=launcher-SlyE8R3b.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launcher-SlyE8R3b.cjs","names":["getResultMaxBytes","supervisorPaths","LIFELINE_ENV","noninteractiveEnvironment","NO_TERMINAL_INPUT_ENV","PI_SESSION_ID_ENV","supervisorCommand","readExitMetadata"],"sources":["../src/constants/launcher.ts","../src/services/launcher/index.ts"],"sourcesContent":["export const NON_INTERACTIVE_ENV = { FORCE_COLOR: '1', CI: '1' };\nexport const TERM_GRACE_MS = 2_000;\nexport const LIVENESS_POLL_MS = 100;\nexport const MEMORY_BUFFER_FACTOR = 2;\nexport const GATE_MODE = 0o600;\n","import fs from 'node:fs';\n\nimport {\n GATE_MODE,\n LIVENESS_POLL_MS,\n MEMORY_BUFFER_FACTOR,\n NON_INTERACTIVE_ENV,\n TERM_GRACE_MS,\n} from '../../constants/launcher';\nimport { PI_SESSION_ID_ENV } from '../../constants/session';\nimport type { IClock } from '../../types/clock';\nimport type { ILauncher, LaunchRequest, RunHandle } from '../../types/launcher';\nimport type { ILifeline } from '../../types/lifeline';\nimport type { ILogFile } from '../../types/logFile';\nimport type { IProcessControl } from '../../types/processControl';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport type { ExitResult, ISpawner } from '../../types/spawner';\nimport { LIFELINE_ENV } from '../lifeline/client';\nimport { getResultMaxBytes, noninteractiveEnvironment } from '../runnerConfig';\nimport type { IRunnerPaths } from '../runnerPaths/type';\nimport {\n cleanupSupervisorFiles,\n NO_TERMINAL_INPUT_ENV,\n readExitMetadata,\n supervisorCommand,\n supervisorPaths,\n writeCommandSpec,\n} from '../runnerSupervisor';\n\n/**\n * Prompts belong on a screen, not in a log file, so `CI` stays set.\n *\n * Colour is kept: the log is replayed into the transcript, and the scrub keeps\n * SGR while still removing the cursor moves that made raw output unreadable.\n */\n/** In-memory output is a multiple of the result ceiling; the log holds the rest. */\n\nexport class Launcher implements ILauncher {\n constructor(\n private readonly spawner: ISpawner,\n private readonly processControl: IProcessControl,\n private readonly logFile: ILogFile,\n private readonly clock: IClock,\n private readonly paths: IRunnerPaths,\n private readonly lifeline?: ILifeline,\n private readonly environment: Readonly<Record<string, string | undefined>> = process.env,\n private readonly settings?: RunnerSettings,\n ) {}\n\n launch(request: LaunchRequest): RunHandle {\n const writer = this.logFile.open(request.id);\n const memoryLimit = getResultMaxBytes(this.environment, this.settings) * MEMORY_BUFFER_FACTOR;\n\n let buffer = '';\n let buffering = true;\n let settled = false;\n let resolveCompletion: (result: ExitResult) => void = () => undefined;\n let rejectCompletion: (error: Error) => void = () => undefined;\n const completion = new Promise<ExitResult>((resolve, reject) => {\n resolveCompletion = resolve;\n rejectCompletion = reject;\n });\n\n this.paths.ensureDirectories(request.sessionId);\n const supervisor = supervisorPaths(this.paths.stateDirectory(request.sessionId), request.id);\n const { [LIFELINE_ENV]: _inheritedLifeline, ...environment } = this.environment;\n const env = {\n ...environment,\n ...NON_INTERACTIVE_ENV,\n ...noninteractiveEnvironment(environment),\n ...NO_TERMINAL_INPUT_ENV,\n [PI_SESSION_ID_ENV]: request.sessionId,\n [LIFELINE_ENV]: this.lifeline?.path(),\n };\n cleanupSupervisorFiles(supervisor);\n writeCommandSpec(supervisor.spec, { command: request.command, cwd: request.cwd, env: defined(env) });\n // Nothing has to be attached before this runner starts, so its gate opens at once.\n fs.writeFileSync(supervisor.gate, '', { mode: GATE_MODE });\n\n const child = this.spawner.spawn({\n // runnerHost supervises the command: it forwards signals and, if the owning\n // pi dies without running its shutdown handler, kills the group itself.\n command: supervisorCommand(supervisor),\n cwd: request.cwd,\n env,\n // Its own process group, so stopping a runner takes the whole tree with it.\n detached: true,\n });\n\n const failLaunch = (error: unknown): void => {\n if (settled) return;\n settled = true;\n writer.close();\n cleanupSupervisorFiles(supervisor);\n try {\n child.kill('SIGTERM');\n } catch (killError) {\n process.emitWarning(`Could not stop runner after log failure: ${String(killError)}`);\n }\n rejectCompletion(error instanceof Error ? error : new Error(String(error)));\n };\n child.onOutput((chunk) => {\n if (settled) return;\n try {\n writer.append(chunk);\n } catch (error) {\n failLaunch(error);\n return;\n }\n if (!buffering) return;\n buffer += chunk;\n if (buffer.length > memoryLimit) buffer = buffer.slice(-memoryLimit);\n });\n\n child.onError(failLaunch);\n\n child.onExit((result) => {\n if (settled) return;\n settled = true;\n writer.close();\n // The supervisor collapses a signalled command into an exit code, so its\n // own sidecar is the only place the original signal survives.\n const outcome = readExitMetadata(supervisor.exit) ?? result;\n cleanupSupervisorFiles(supervisor);\n resolveCompletion(outcome);\n });\n\n // The launcher must never hold the pi process open on a runner's behalf.\n child.unref();\n\n const stop = async (): Promise<boolean> => (child.pid === undefined ? false : this.stop(child.pid));\n\n return {\n id: request.id,\n name: request.name,\n pid: child.pid,\n logPath: writer.path,\n backend: 'native',\n output: () => buffer,\n completion: () => completion,\n detach: () => {\n buffering = false;\n buffer = '';\n },\n stop,\n };\n }\n\n async stop(pid: number): Promise<boolean> {\n if (!this.processControl.isAlive(pid)) return false;\n\n this.processControl.signalGroup(pid, 'SIGTERM');\n const deadline = this.clock.now() + TERM_GRACE_MS;\n while (this.clock.now() < deadline) {\n if (!this.processControl.isAlive(pid)) return true;\n await this.sleep(LIVENESS_POLL_MS);\n }\n\n this.processControl.signalGroup(pid, 'SIGKILL');\n return true;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n this.clock.after(ms, resolve);\n });\n }\n}\n\n/** The spec is JSON, which has no way to carry an unset variable. */\nfunction defined(env: Readonly<Record<string, string | undefined>>): Record<string, string> {\n return Object.fromEntries(Object.entries(env).filter((entry): entry is [string, string] => entry[1] !== undefined));\n}\n"],"mappings":";;;;;;;;AAAA,MAAa,sBAAsB;CAAE,aAAa;CAAK,IAAI;AAAI;AAC/D,MAAa,gBAAgB;;;;;;;;;;ACoC7B,IAAa,WAAb,MAA2C;CAEtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CARnB,YACE,SACA,gBACA,SACA,OACA,OACA,UACA,cAA6E,QAAQ,KACrF,UACA;EARiB,KAAA,UAAA;EACA,KAAA,iBAAA;EACA,KAAA,UAAA;EACA,KAAA,QAAA;EACA,KAAA,QAAA;EACA,KAAA,WAAA;EACA,KAAA,cAAA;EACA,KAAA,WAAA;CAChB;CAEH,OAAO,SAAmC;EACxC,MAAM,SAAS,KAAK,QAAQ,KAAK,QAAQ,EAAE;EAC3C,MAAM,cAAcA,qBAAAA,kBAAkB,KAAK,aAAa,KAAK,QAAQ,IAAA;EAErE,IAAI,SAAS;EACb,IAAI,YAAY;EAChB,IAAI,UAAU;EACd,IAAI,0BAAwD,KAAA;EAC5D,IAAI,yBAAiD,KAAA;EACrD,MAAM,aAAa,IAAI,SAAqB,SAAS,WAAW;GAC9D,oBAAoB;GACpB,mBAAmB;EACrB,CAAC;EAED,KAAK,MAAM,kBAAkB,QAAQ,SAAS;EAC9C,MAAM,aAAaC,wCAAAA,gBAAgB,KAAK,MAAM,eAAe,QAAQ,SAAS,GAAG,QAAQ,EAAE;EAC3F,MAAM,GAAGC,iCAAAA,eAAe,oBAAoB,GAAG,gBAAgB,KAAK;EACpE,MAAM,MAAM;GACV,GAAG;GACH,GAAG;GACH,GAAGC,qBAAAA,0BAA0B,WAAW;GACxC,GAAGC,wCAAAA;IACFC,gBAAAA,oBAAoB,QAAQ;IAC5BH,iCAAAA,eAAe,KAAK,UAAU,KAAK;EACtC;EACA,wCAAA,uBAAuB,UAAU;EACjC,wCAAA,iBAAiB,WAAW,MAAM;GAAE,SAAS,QAAQ;GAAS,KAAK,QAAQ;GAAK,KAAK,QAAQ,GAAG;EAAE,CAAC;EAEnG,QAAA,QAAG,cAAc,WAAW,MAAM,IAAI,EAAE,MAAA,IAAgB,CAAC;EAEzD,MAAM,QAAQ,KAAK,QAAQ,MAAM;GAG/B,SAASI,wCAAAA,kBAAkB,UAAU;GACrC,KAAK,QAAQ;GACb;GAEA,UAAU;EACZ,CAAC;EAED,MAAM,cAAc,UAAyB;GAC3C,IAAI,SAAS;GACb,UAAU;GACV,OAAO,MAAM;GACb,wCAAA,uBAAuB,UAAU;GACjC,IAAI;IACF,MAAM,KAAK,SAAS;GACtB,SAAS,WAAW;IAClB,QAAQ,YAAY,4CAA4C,OAAO,SAAS,GAAG;GACrF;GACA,iBAAiB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;EAC5E;EACA,MAAM,UAAU,UAAU;GACxB,IAAI,SAAS;GACb,IAAI;IACF,OAAO,OAAO,KAAK;GACrB,SAAS,OAAO;IACd,WAAW,KAAK;IAChB;GACF;GACA,IAAI,CAAC,WAAW;GAChB,UAAU;GACV,IAAI,OAAO,SAAS,aAAa,SAAS,OAAO,MAAM,CAAC,WAAW;EACrE,CAAC;EAED,MAAM,QAAQ,UAAU;EAExB,MAAM,QAAQ,WAAW;GACvB,IAAI,SAAS;GACb,UAAU;GACV,OAAO,MAAM;GAGb,MAAM,UAAUC,wCAAAA,iBAAiB,WAAW,IAAI,KAAK;GACrD,wCAAA,uBAAuB,UAAU;GACjC,kBAAkB,OAAO;EAC3B,CAAC;EAGD,MAAM,MAAM;EAEZ,MAAM,OAAO,YAA+B,MAAM,QAAQ,KAAA,IAAY,QAAQ,KAAK,KAAK,MAAM,GAAG;EAEjG,OAAO;GACL,IAAI,QAAQ;GACZ,MAAM,QAAQ;GACd,KAAK,MAAM;GACX,SAAS,OAAO;GAChB,SAAS;GACT,cAAc;GACd,kBAAkB;GAClB,cAAc;IACZ,YAAY;IACZ,SAAS;GACX;GACA;EACF;CACF;CAEA,MAAM,KAAK,KAA+B;EACxC,IAAI,CAAC,KAAK,eAAe,QAAQ,GAAG,GAAG,OAAO;EAE9C,KAAK,eAAe,YAAY,KAAK,SAAS;EAC9C,MAAM,WAAW,KAAK,MAAM,IAAI,IAAI;EACpC,OAAO,KAAK,MAAM,IAAI,IAAI,UAAU;GAClC,IAAI,CAAC,KAAK,eAAe,QAAQ,GAAG,GAAG,OAAO;GAC9C,MAAM,KAAK,MAAA,GAAsB;EACnC;EAEA,KAAK,eAAe,YAAY,KAAK,SAAS;EAC9C,OAAO;CACT;CAEA,MAAc,IAA2B;EACvC,OAAO,IAAI,SAAS,YAAY;GAC9B,KAAK,MAAM,MAAM,IAAI,OAAO;EAC9B,CAAC;CACH;AACF;;AAGA,SAAS,QAAQ,KAA2E;CAC1F,OAAO,OAAO,YAAY,OAAO,QAAQ,GAAG,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CAAC;AACpH"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { t as IClock } from "./clock-euJkweLq.mjs";
|
|
2
|
+
import { n as ISpawner } from "./spawner-CdrN_HNk.mjs";
|
|
3
|
+
import { n as LaunchRequest, r as RunHandle, t as ILauncher } from "./launcher-BG5t9nvG.mjs";
|
|
4
|
+
import { t as ILifeline } from "./lifeline-eJdZV0nN.mjs";
|
|
5
|
+
import { t as ILogFile } from "./logFile-C7oQ_v-g.mjs";
|
|
6
|
+
import { t as IProcessControl } from "./processControl-BAOa3oo_.mjs";
|
|
7
|
+
import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
|
|
8
|
+
import { t as IRunnerPaths } from "./type-BXM03qSw.mjs";
|
|
9
|
+
//#region src/services/launcher/index.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* Prompts belong on a screen, not in a log file, so `CI` stays set.
|
|
12
|
+
*
|
|
13
|
+
* Colour is kept: the log is replayed into the transcript, and the scrub keeps
|
|
14
|
+
* SGR while still removing the cursor moves that made raw output unreadable.
|
|
15
|
+
*/
|
|
16
|
+
/** In-memory output is a multiple of the result ceiling; the log holds the rest. */
|
|
17
|
+
export declare class Launcher implements ILauncher {
|
|
18
|
+
private readonly spawner;
|
|
19
|
+
private readonly processControl;
|
|
20
|
+
private readonly logFile;
|
|
21
|
+
private readonly clock;
|
|
22
|
+
private readonly paths;
|
|
23
|
+
private readonly lifeline?;
|
|
24
|
+
private readonly environment;
|
|
25
|
+
private readonly settings?;
|
|
26
|
+
constructor(spawner: ISpawner, processControl: IProcessControl, logFile: ILogFile, clock: IClock, paths: IRunnerPaths, lifeline?: ILifeline | undefined, environment?: Readonly<Record<string, string | undefined>>, settings?: RunnerSettings | undefined);
|
|
27
|
+
launch(request: LaunchRequest): RunHandle;
|
|
28
|
+
stop(pid: number): Promise<boolean>;
|
|
29
|
+
private sleep;
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export type { ILauncher, LaunchRequest, RunHandle };
|
|
33
|
+
//# sourceMappingURL=launcher.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launcher.d.mts","names":[],"sources":["../src/services/launcher/index.ts"],"mappings":";;;;;;;;;;;;;;;;qBAqCa,oBAAoB;mBAEZ;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EARnB,YACmB,SAAS,UACT,gBAAgB,iBAChB,SAAS,UACT,OAAO,QACP,OAAO,cACP,WAAW,uBACX,cAAa,SAAS,qCACtB,WAAW;EAG9B,OAAO,SAAS,gBAAgB;EAmG1B,KAAK,cAAc;UAcjB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import net from "node:net";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
//#region src/constants/lifeline.ts
|
|
7
|
+
const SOCKET_NAME = "lifeline.sock";
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/services/lifeline/index.ts
|
|
10
|
+
/** Unix socket paths are capped at 104 bytes, so a long agent directory falls back to the temp dir. */
|
|
11
|
+
var NodeLifeline = class {
|
|
12
|
+
paths;
|
|
13
|
+
server;
|
|
14
|
+
target;
|
|
15
|
+
/** Closing a server stops it accepting; only the connections carry the death signal. */
|
|
16
|
+
connections = /* @__PURE__ */ new Set();
|
|
17
|
+
constructor(paths) {
|
|
18
|
+
this.paths = paths;
|
|
19
|
+
}
|
|
20
|
+
async arm(sessionId) {
|
|
21
|
+
if (this.target) return this.target;
|
|
22
|
+
try {
|
|
23
|
+
this.paths.ensureDirectories(sessionId);
|
|
24
|
+
const target = this.socketPath(sessionId);
|
|
25
|
+
fs.rmSync(target, { force: true });
|
|
26
|
+
const server = net.createServer((connection) => {
|
|
27
|
+
connection.unref();
|
|
28
|
+
connection.resume();
|
|
29
|
+
this.connections.add(connection);
|
|
30
|
+
connection.on("close", () => this.connections.delete(connection));
|
|
31
|
+
});
|
|
32
|
+
await listen(server, target);
|
|
33
|
+
fs.chmodSync(target, 384);
|
|
34
|
+
server.unref();
|
|
35
|
+
this.server = server;
|
|
36
|
+
this.target = target;
|
|
37
|
+
return target;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
process.emitWarning(`Could not arm the doom-runner lifeline: ${String(error)}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
path() {
|
|
44
|
+
return this.target;
|
|
45
|
+
}
|
|
46
|
+
dispose() {
|
|
47
|
+
for (const connection of this.connections) connection.destroy();
|
|
48
|
+
this.connections.clear();
|
|
49
|
+
if (this.server) {
|
|
50
|
+
try {
|
|
51
|
+
this.server.close();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
process.emitWarning(`Could not close the doom-runner lifeline: ${String(error)}`);
|
|
54
|
+
}
|
|
55
|
+
this.server = void 0;
|
|
56
|
+
}
|
|
57
|
+
if (this.target) {
|
|
58
|
+
try {
|
|
59
|
+
fs.rmSync(this.target, { force: true });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
process.emitWarning(`Could not remove the doom-runner lifeline: ${String(error)}`);
|
|
62
|
+
}
|
|
63
|
+
this.target = void 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Keeps the socket beside the session it belongs to unless that path is too long to bind. */
|
|
67
|
+
socketPath(sessionId) {
|
|
68
|
+
const preferred = path.join(this.paths.stateDirectory(sessionId), SOCKET_NAME);
|
|
69
|
+
if (Buffer.byteLength(preferred) <= 100) return preferred;
|
|
70
|
+
const hash = createHash("sha256").update(preferred).digest("hex").slice(0, 12);
|
|
71
|
+
return path.join(os.tmpdir(), `doom-runner-${hash}.sock`);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
/** Binding must complete before the first runner launches, so arming waits for it. */
|
|
75
|
+
function listen(server, target) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
server.once("error", reject);
|
|
78
|
+
server.listen(target, () => {
|
|
79
|
+
server.removeListener("error", reject);
|
|
80
|
+
server.on("error", (error) => process.emitWarning(`doom-runner lifeline failed: ${error.message}`));
|
|
81
|
+
resolve();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { NodeLifeline as t };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=lifeline-BZaQA0rm.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifeline-BZaQA0rm.mjs","names":[],"sources":["../src/constants/lifeline.ts","../src/services/lifeline/index.ts"],"sourcesContent":["export const SOCKET_NAME = 'lifeline.sock';\nexport const SOCKET_PATH_LIMIT = 100;\nexport const SOCKET_HASH_LENGTH = 12;\nexport const SOCKET_MODE = 0o600;\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport net from 'node:net';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { SOCKET_HASH_LENGTH, SOCKET_MODE, SOCKET_NAME, SOCKET_PATH_LIMIT } from '../../constants/lifeline';\nimport type { ILifeline } from '../../types/lifeline';\nimport type { IRunnerPaths } from '../runnerPaths/type';\n\n/** Unix socket paths are capped at 104 bytes, so a long agent directory falls back to the temp dir. */\n\nexport class NodeLifeline implements ILifeline {\n private server: net.Server | undefined;\n private target: string | undefined;\n /** Closing a server stops it accepting; only the connections carry the death signal. */\n private readonly connections = new Set<net.Socket>();\n\n constructor(private readonly paths: IRunnerPaths) {}\n\n async arm(sessionId: string): Promise<string | undefined> {\n if (this.target) return this.target;\n try {\n this.paths.ensureDirectories(sessionId);\n const target = this.socketPath(sessionId);\n // A socket left behind by a SIGKILLed predecessor refuses connections, never accepts them.\n fs.rmSync(target, { force: true });\n const server = net.createServer((connection) => {\n // Runners need only the close edge, so their liveness and their data are equally irrelevant.\n connection.unref();\n connection.resume();\n this.connections.add(connection);\n connection.on('close', () => this.connections.delete(connection));\n });\n await listen(server, target);\n fs.chmodSync(target, SOCKET_MODE);\n // The lifeline must never be the reason pi stays alive.\n server.unref();\n this.server = server;\n this.target = target;\n return target;\n } catch (error) {\n // Runners stay unwatched rather than unlaunchable, so a session without a\n // lifeline degrades to running them unsupervised instead of failing.\n process.emitWarning(`Could not arm the doom-runner lifeline: ${String(error)}`);\n return undefined;\n }\n }\n\n path(): string | undefined {\n return this.target;\n }\n\n dispose(): void {\n // Dropping the connections is what a runner sees, and it is the whole point\n // of disposing: closing the server alone would leave every runner waiting.\n for (const connection of this.connections) connection.destroy();\n this.connections.clear();\n if (this.server) {\n try {\n this.server.close();\n } catch (error) {\n process.emitWarning(`Could not close the doom-runner lifeline: ${String(error)}`);\n }\n this.server = undefined;\n }\n if (this.target) {\n try {\n fs.rmSync(this.target, { force: true });\n } catch (error) {\n process.emitWarning(`Could not remove the doom-runner lifeline: ${String(error)}`);\n }\n this.target = undefined;\n }\n }\n\n /** Keeps the socket beside the session it belongs to unless that path is too long to bind. */\n private socketPath(sessionId: string): string {\n const preferred = path.join(this.paths.stateDirectory(sessionId), SOCKET_NAME);\n if (Buffer.byteLength(preferred) <= SOCKET_PATH_LIMIT) return preferred;\n const hash = createHash('sha256').update(preferred).digest('hex').slice(0, SOCKET_HASH_LENGTH);\n return path.join(os.tmpdir(), `doom-runner-${hash}.sock`);\n }\n}\n\n/** Binding must complete before the first runner launches, so arming waits for it. */\nfunction listen(server: net.Server, target: string): Promise<void> {\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(target, () => {\n server.removeListener('error', reject);\n // Later errors would otherwise reach the process as unhandled.\n server.on('error', (error: Error) => process.emitWarning(`doom-runner lifeline failed: ${error.message}`));\n resolve();\n });\n });\n}\n"],"mappings":";;;;;;AAAA,MAAa,cAAc;;;;ACY3B,IAAa,eAAb,MAA+C;CAMhB;CAL7B;CACA;;CAEA,8BAA+B,IAAI,IAAgB;CAEnD,YAAY,OAAsC;EAArB,KAAA,QAAA;CAAsB;CAEnD,MAAM,IAAI,WAAgD;EACxD,IAAI,KAAK,QAAQ,OAAO,KAAK;EAC7B,IAAI;GACF,KAAK,MAAM,kBAAkB,SAAS;GACtC,MAAM,SAAS,KAAK,WAAW,SAAS;GAExC,GAAG,OAAO,QAAQ,EAAE,OAAO,KAAK,CAAC;GACjC,MAAM,SAAS,IAAI,cAAc,eAAe;IAE9C,WAAW,MAAM;IACjB,WAAW,OAAO;IAClB,KAAK,YAAY,IAAI,UAAU;IAC/B,WAAW,GAAG,eAAe,KAAK,YAAY,OAAO,UAAU,CAAC;GAClE,CAAC;GACD,MAAM,OAAO,QAAQ,MAAM;GAC3B,GAAG,UAAU,QAAA,GAAmB;GAEhC,OAAO,MAAM;GACb,KAAK,SAAS;GACd,KAAK,SAAS;GACd,OAAO;EACT,SAAS,OAAO;GAGd,QAAQ,YAAY,2CAA2C,OAAO,KAAK,GAAG;GAC9E;EACF;CACF;CAEA,OAA2B;EACzB,OAAO,KAAK;CACd;CAEA,UAAgB;EAGd,KAAK,MAAM,cAAc,KAAK,aAAa,WAAW,QAAQ;EAC9D,KAAK,YAAY,MAAM;EACvB,IAAI,KAAK,QAAQ;GACf,IAAI;IACF,KAAK,OAAO,MAAM;GACpB,SAAS,OAAO;IACd,QAAQ,YAAY,6CAA6C,OAAO,KAAK,GAAG;GAClF;GACA,KAAK,SAAS,KAAA;EAChB;EACA,IAAI,KAAK,QAAQ;GACf,IAAI;IACF,GAAG,OAAO,KAAK,QAAQ,EAAE,OAAO,KAAK,CAAC;GACxC,SAAS,OAAO;IACd,QAAQ,YAAY,8CAA8C,OAAO,KAAK,GAAG;GACnF;GACA,KAAK,SAAS,KAAA;EAChB;CACF;;CAGA,WAAmB,WAA2B;EAC5C,MAAM,YAAY,KAAK,KAAK,KAAK,MAAM,eAAe,SAAS,GAAG,WAAW;EAC7E,IAAI,OAAO,WAAW,SAAS,KAAA,KAAwB,OAAO;EAC9D,MAAM,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAA,EAAqB;EAC7F,OAAO,KAAK,KAAK,GAAG,OAAO,GAAG,eAAe,KAAK,MAAM;CAC1D;AACF;;AAGA,SAAS,OAAO,QAAoB,QAA+B;CACjE,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,OAAO,KAAK,SAAS,MAAM;EAC3B,OAAO,OAAO,cAAc;GAC1B,OAAO,eAAe,SAAS,MAAM;GAErC,OAAO,GAAG,UAAU,UAAiB,QAAQ,YAAY,gCAAgC,MAAM,SAAS,CAAC;GACzG,QAAQ;EACV,CAAC;CACH,CAAC;AACH"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
+
let node_crypto = require("node:crypto");
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
5
|
+
let node_path = require("node:path");
|
|
6
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
7
|
+
let node_net = require("node:net");
|
|
8
|
+
node_net = require_rolldown_runtime.__toESM(node_net, 1);
|
|
9
|
+
let node_os = require("node:os");
|
|
10
|
+
node_os = require_rolldown_runtime.__toESM(node_os, 1);
|
|
11
|
+
//#region src/constants/lifeline.ts
|
|
12
|
+
const SOCKET_NAME = "lifeline.sock";
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/services/lifeline/index.ts
|
|
15
|
+
/** Unix socket paths are capped at 104 bytes, so a long agent directory falls back to the temp dir. */
|
|
16
|
+
var NodeLifeline = class {
|
|
17
|
+
paths;
|
|
18
|
+
server;
|
|
19
|
+
target;
|
|
20
|
+
/** Closing a server stops it accepting; only the connections carry the death signal. */
|
|
21
|
+
connections = /* @__PURE__ */ new Set();
|
|
22
|
+
constructor(paths) {
|
|
23
|
+
this.paths = paths;
|
|
24
|
+
}
|
|
25
|
+
async arm(sessionId) {
|
|
26
|
+
if (this.target) return this.target;
|
|
27
|
+
try {
|
|
28
|
+
this.paths.ensureDirectories(sessionId);
|
|
29
|
+
const target = this.socketPath(sessionId);
|
|
30
|
+
node_fs.default.rmSync(target, { force: true });
|
|
31
|
+
const server = node_net.default.createServer((connection) => {
|
|
32
|
+
connection.unref();
|
|
33
|
+
connection.resume();
|
|
34
|
+
this.connections.add(connection);
|
|
35
|
+
connection.on("close", () => this.connections.delete(connection));
|
|
36
|
+
});
|
|
37
|
+
await listen(server, target);
|
|
38
|
+
node_fs.default.chmodSync(target, 384);
|
|
39
|
+
server.unref();
|
|
40
|
+
this.server = server;
|
|
41
|
+
this.target = target;
|
|
42
|
+
return target;
|
|
43
|
+
} catch (error) {
|
|
44
|
+
process.emitWarning(`Could not arm the doom-runner lifeline: ${String(error)}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
path() {
|
|
49
|
+
return this.target;
|
|
50
|
+
}
|
|
51
|
+
dispose() {
|
|
52
|
+
for (const connection of this.connections) connection.destroy();
|
|
53
|
+
this.connections.clear();
|
|
54
|
+
if (this.server) {
|
|
55
|
+
try {
|
|
56
|
+
this.server.close();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
process.emitWarning(`Could not close the doom-runner lifeline: ${String(error)}`);
|
|
59
|
+
}
|
|
60
|
+
this.server = void 0;
|
|
61
|
+
}
|
|
62
|
+
if (this.target) {
|
|
63
|
+
try {
|
|
64
|
+
node_fs.default.rmSync(this.target, { force: true });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
process.emitWarning(`Could not remove the doom-runner lifeline: ${String(error)}`);
|
|
67
|
+
}
|
|
68
|
+
this.target = void 0;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Keeps the socket beside the session it belongs to unless that path is too long to bind. */
|
|
72
|
+
socketPath(sessionId) {
|
|
73
|
+
const preferred = node_path.default.join(this.paths.stateDirectory(sessionId), SOCKET_NAME);
|
|
74
|
+
if (Buffer.byteLength(preferred) <= 100) return preferred;
|
|
75
|
+
const hash = (0, node_crypto.createHash)("sha256").update(preferred).digest("hex").slice(0, 12);
|
|
76
|
+
return node_path.default.join(node_os.default.tmpdir(), `doom-runner-${hash}.sock`);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/** Binding must complete before the first runner launches, so arming waits for it. */
|
|
80
|
+
function listen(server, target) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
server.once("error", reject);
|
|
83
|
+
server.listen(target, () => {
|
|
84
|
+
server.removeListener("error", reject);
|
|
85
|
+
server.on("error", (error) => process.emitWarning(`doom-runner lifeline failed: ${error.message}`));
|
|
86
|
+
resolve();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
Object.defineProperty(exports, "NodeLifeline", {
|
|
92
|
+
enumerable: true,
|
|
93
|
+
get: function() {
|
|
94
|
+
return NodeLifeline;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=lifeline-BuV_erib.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifeline-BuV_erib.cjs","names":["net","path","createHash","os"],"sources":["../src/constants/lifeline.ts","../src/services/lifeline/index.ts"],"sourcesContent":["export const SOCKET_NAME = 'lifeline.sock';\nexport const SOCKET_PATH_LIMIT = 100;\nexport const SOCKET_HASH_LENGTH = 12;\nexport const SOCKET_MODE = 0o600;\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport net from 'node:net';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport { SOCKET_HASH_LENGTH, SOCKET_MODE, SOCKET_NAME, SOCKET_PATH_LIMIT } from '../../constants/lifeline';\nimport type { ILifeline } from '../../types/lifeline';\nimport type { IRunnerPaths } from '../runnerPaths/type';\n\n/** Unix socket paths are capped at 104 bytes, so a long agent directory falls back to the temp dir. */\n\nexport class NodeLifeline implements ILifeline {\n private server: net.Server | undefined;\n private target: string | undefined;\n /** Closing a server stops it accepting; only the connections carry the death signal. */\n private readonly connections = new Set<net.Socket>();\n\n constructor(private readonly paths: IRunnerPaths) {}\n\n async arm(sessionId: string): Promise<string | undefined> {\n if (this.target) return this.target;\n try {\n this.paths.ensureDirectories(sessionId);\n const target = this.socketPath(sessionId);\n // A socket left behind by a SIGKILLed predecessor refuses connections, never accepts them.\n fs.rmSync(target, { force: true });\n const server = net.createServer((connection) => {\n // Runners need only the close edge, so their liveness and their data are equally irrelevant.\n connection.unref();\n connection.resume();\n this.connections.add(connection);\n connection.on('close', () => this.connections.delete(connection));\n });\n await listen(server, target);\n fs.chmodSync(target, SOCKET_MODE);\n // The lifeline must never be the reason pi stays alive.\n server.unref();\n this.server = server;\n this.target = target;\n return target;\n } catch (error) {\n // Runners stay unwatched rather than unlaunchable, so a session without a\n // lifeline degrades to running them unsupervised instead of failing.\n process.emitWarning(`Could not arm the doom-runner lifeline: ${String(error)}`);\n return undefined;\n }\n }\n\n path(): string | undefined {\n return this.target;\n }\n\n dispose(): void {\n // Dropping the connections is what a runner sees, and it is the whole point\n // of disposing: closing the server alone would leave every runner waiting.\n for (const connection of this.connections) connection.destroy();\n this.connections.clear();\n if (this.server) {\n try {\n this.server.close();\n } catch (error) {\n process.emitWarning(`Could not close the doom-runner lifeline: ${String(error)}`);\n }\n this.server = undefined;\n }\n if (this.target) {\n try {\n fs.rmSync(this.target, { force: true });\n } catch (error) {\n process.emitWarning(`Could not remove the doom-runner lifeline: ${String(error)}`);\n }\n this.target = undefined;\n }\n }\n\n /** Keeps the socket beside the session it belongs to unless that path is too long to bind. */\n private socketPath(sessionId: string): string {\n const preferred = path.join(this.paths.stateDirectory(sessionId), SOCKET_NAME);\n if (Buffer.byteLength(preferred) <= SOCKET_PATH_LIMIT) return preferred;\n const hash = createHash('sha256').update(preferred).digest('hex').slice(0, SOCKET_HASH_LENGTH);\n return path.join(os.tmpdir(), `doom-runner-${hash}.sock`);\n }\n}\n\n/** Binding must complete before the first runner launches, so arming waits for it. */\nfunction listen(server: net.Server, target: string): Promise<void> {\n return new Promise((resolve, reject) => {\n server.once('error', reject);\n server.listen(target, () => {\n server.removeListener('error', reject);\n // Later errors would otherwise reach the process as unhandled.\n server.on('error', (error: Error) => process.emitWarning(`doom-runner lifeline failed: ${error.message}`));\n resolve();\n });\n });\n}\n"],"mappings":";;;;;;;;;;;AAAA,MAAa,cAAc;;;;ACY3B,IAAa,eAAb,MAA+C;CAMhB;CAL7B;CACA;;CAEA,8BAA+B,IAAI,IAAgB;CAEnD,YAAY,OAAsC;EAArB,KAAA,QAAA;CAAsB;CAEnD,MAAM,IAAI,WAAgD;EACxD,IAAI,KAAK,QAAQ,OAAO,KAAK;EAC7B,IAAI;GACF,KAAK,MAAM,kBAAkB,SAAS;GACtC,MAAM,SAAS,KAAK,WAAW,SAAS;GAExC,QAAA,QAAG,OAAO,QAAQ,EAAE,OAAO,KAAK,CAAC;GACjC,MAAM,SAASA,SAAAA,QAAI,cAAc,eAAe;IAE9C,WAAW,MAAM;IACjB,WAAW,OAAO;IAClB,KAAK,YAAY,IAAI,UAAU;IAC/B,WAAW,GAAG,eAAe,KAAK,YAAY,OAAO,UAAU,CAAC;GAClE,CAAC;GACD,MAAM,OAAO,QAAQ,MAAM;GAC3B,QAAA,QAAG,UAAU,QAAA,GAAmB;GAEhC,OAAO,MAAM;GACb,KAAK,SAAS;GACd,KAAK,SAAS;GACd,OAAO;EACT,SAAS,OAAO;GAGd,QAAQ,YAAY,2CAA2C,OAAO,KAAK,GAAG;GAC9E;EACF;CACF;CAEA,OAA2B;EACzB,OAAO,KAAK;CACd;CAEA,UAAgB;EAGd,KAAK,MAAM,cAAc,KAAK,aAAa,WAAW,QAAQ;EAC9D,KAAK,YAAY,MAAM;EACvB,IAAI,KAAK,QAAQ;GACf,IAAI;IACF,KAAK,OAAO,MAAM;GACpB,SAAS,OAAO;IACd,QAAQ,YAAY,6CAA6C,OAAO,KAAK,GAAG;GAClF;GACA,KAAK,SAAS,KAAA;EAChB;EACA,IAAI,KAAK,QAAQ;GACf,IAAI;IACF,QAAA,QAAG,OAAO,KAAK,QAAQ,EAAE,OAAO,KAAK,CAAC;GACxC,SAAS,OAAO;IACd,QAAQ,YAAY,8CAA8C,OAAO,KAAK,GAAG;GACnF;GACA,KAAK,SAAS,KAAA;EAChB;CACF;;CAGA,WAAmB,WAA2B;EAC5C,MAAM,YAAYC,UAAAA,QAAK,KAAK,KAAK,MAAM,eAAe,SAAS,GAAG,WAAW;EAC7E,IAAI,OAAO,WAAW,SAAS,KAAA,KAAwB,OAAO;EAC9D,MAAM,QAAA,GAAOC,YAAAA,WAAAA,CAAW,QAAQ,CAAC,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAA,EAAqB;EAC7F,OAAOD,UAAAA,QAAK,KAAKE,QAAAA,QAAG,OAAO,GAAG,eAAe,KAAK,MAAM;CAC1D;AACF;;AAGA,SAAS,OAAO,QAAoB,QAA+B;CACjE,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,OAAO,KAAK,SAAS,MAAM;EAC3B,OAAO,OAAO,cAAc;GAC1B,OAAO,eAAe,SAAS,MAAM;GAErC,OAAO,GAAG,UAAU,UAAiB,QAAQ,YAAY,gCAAgC,MAAM,SAAS,CAAC;GACzG,QAAQ;EACV,CAAC;CACH,CAAC;AACH"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/types/lifeline.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A Unix socket the owning pi process listens on for the life of a session.
|
|
4
|
+
*
|
|
5
|
+
* Runner supervisors connect to it and watch for the close edge, which arrives
|
|
6
|
+
* on every owner exit path including SIGKILL. That is the one death signal a
|
|
7
|
+
* graceful shutdown handler cannot provide.
|
|
8
|
+
*/
|
|
9
|
+
interface ILifeline {
|
|
10
|
+
/** Binds the socket and starts listening. Idempotent; resolves with the path. */
|
|
11
|
+
arm(sessionId: string): Promise<string | undefined>;
|
|
12
|
+
/** Path of the armed lifeline, if arming succeeded. */
|
|
13
|
+
path(): string | undefined;
|
|
14
|
+
/** Stops listening and removes the socket. */
|
|
15
|
+
dispose(): void;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { ILifeline as t };
|
|
19
|
+
//# sourceMappingURL=lifeline-eJdZV0nN.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifeline-eJdZV0nN.d.mts","names":[],"sources":["../src/types/lifeline.ts"],"mappings":";;;;;;;;UAOiB;;EAEf,IAAI,oBAAoB;;EAExB;;EAEA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_services_lifeline_client = require("./services/lifeline/client.cjs");
|
|
3
|
+
const require_lifeline = require("./lifeline-BuV_erib.cjs");
|
|
4
|
+
exports.LIFELINE_ENV = require_services_lifeline_client.LIFELINE_ENV;
|
|
5
|
+
exports.NodeLifeline = require_lifeline.NodeLifeline;
|
|
6
|
+
exports.watchOwner = require_services_lifeline_client.watchOwner;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t as ILifeline } from "./lifeline-eJdZV0nN.mjs";
|
|
2
|
+
import { t as IRunnerPaths } from "./type-BXM03qSw.mjs";
|
|
3
|
+
import { LIFELINE_ENV, watchOwner } from "./services/lifeline/client.mjs";
|
|
4
|
+
//#region src/services/lifeline/index.d.ts
|
|
5
|
+
/** Unix socket paths are capped at 104 bytes, so a long agent directory falls back to the temp dir. */
|
|
6
|
+
export declare class NodeLifeline implements ILifeline {
|
|
7
|
+
private readonly paths;
|
|
8
|
+
private server;
|
|
9
|
+
private target;
|
|
10
|
+
/** Closing a server stops it accepting; only the connections carry the death signal. */
|
|
11
|
+
private readonly connections;
|
|
12
|
+
constructor(paths: IRunnerPaths);
|
|
13
|
+
arm(sessionId: string): Promise<string | undefined>;
|
|
14
|
+
path(): string | undefined;
|
|
15
|
+
dispose(): void;
|
|
16
|
+
/** Keeps the socket beside the session it belongs to unless that path is too long to bind. */
|
|
17
|
+
private socketPath;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { type ILifeline, LIFELINE_ENV, watchOwner };
|
|
21
|
+
//# sourceMappingURL=lifeline.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifeline.d.mts","names":[],"sources":["../src/services/lifeline/index.ts"],"mappings":";;;;;qBAYa,wBAAwB;mBAMN;UALrB;UACA;;mBAES;EAEjB,YAA6B,OAAO;EAE9B,IAAI,oBAAoB;EA6B9B;EAIA;;UAwBQ"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/types/logFile.d.ts
|
|
2
|
+
/** An open append handle for one runner's log. */
|
|
3
|
+
interface LogWriter {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
append(text: string): void;
|
|
6
|
+
/** Bytes currently in the file at `path`; rotation restarts the count. */
|
|
7
|
+
size(): number;
|
|
8
|
+
close(): void;
|
|
9
|
+
}
|
|
10
|
+
/** Opens runner log files, truncating any output left by a previous runner of the same name. */
|
|
11
|
+
interface ILogFile {
|
|
12
|
+
open(id: string): LogWriter;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { LogWriter as n, ILogFile as t };
|
|
16
|
+
//# sourceMappingURL=logFile-C7oQ_v-g.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logFile-C7oQ_v-g.d.mts","names":[],"sources":["../src/types/logFile.ts"],"mappings":";;UACiB;WACN;EACT,OAAO;;EAEP;EACA;;;UAIe;EACf,KAAK,aAAa"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
+
const require_runnerConfig = require("./runnerConfig-D2tGq5ZM.cjs");
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
|
|
5
|
+
//#region src/services/logFile/index.ts
|
|
6
|
+
var LogFile = class {
|
|
7
|
+
paths;
|
|
8
|
+
constructor(paths) {
|
|
9
|
+
this.paths = paths;
|
|
10
|
+
}
|
|
11
|
+
open(id) {
|
|
12
|
+
this.paths.ensureDirectories();
|
|
13
|
+
const logPath = this.paths.logPathFor(id);
|
|
14
|
+
const rotatedPath = this.paths.rotatedLogPathFor(id);
|
|
15
|
+
const maxBytes = require_runnerConfig.getLogMaxBytes();
|
|
16
|
+
let handle = node_fs.default.openSync(logPath, "w");
|
|
17
|
+
let written = 0;
|
|
18
|
+
let closed = false;
|
|
19
|
+
/**
|
|
20
|
+
* A run that keeps producing output for hours would otherwise grow one file
|
|
21
|
+
* without limit. Rotating keeps the newest window at the advertised path
|
|
22
|
+
* and the window before it alongside, so on-disk cost is bounded at roughly
|
|
23
|
+
* twice the ceiling, the path a result advertises stays valid, and the line
|
|
24
|
+
* counts a reader reports still describe the file it actually read.
|
|
25
|
+
*/
|
|
26
|
+
const rotate = () => {
|
|
27
|
+
node_fs.default.closeSync(handle);
|
|
28
|
+
try {
|
|
29
|
+
node_fs.default.renameSync(logPath, rotatedPath);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
process.emitWarning(`Could not rotate runner log ${logPath}: ${String(error)}`);
|
|
32
|
+
}
|
|
33
|
+
handle = node_fs.default.openSync(logPath, "w");
|
|
34
|
+
written = 0;
|
|
35
|
+
};
|
|
36
|
+
return {
|
|
37
|
+
path: logPath,
|
|
38
|
+
append(text) {
|
|
39
|
+
const chunk = Buffer.from(text, "utf8");
|
|
40
|
+
if (written > 0 && written + chunk.byteLength > maxBytes) rotate();
|
|
41
|
+
node_fs.default.writeSync(handle, chunk);
|
|
42
|
+
written += chunk.byteLength;
|
|
43
|
+
},
|
|
44
|
+
size() {
|
|
45
|
+
return written;
|
|
46
|
+
},
|
|
47
|
+
close() {
|
|
48
|
+
if (closed) return;
|
|
49
|
+
closed = true;
|
|
50
|
+
try {
|
|
51
|
+
node_fs.default.closeSync(handle);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
process.emitWarning(`Could not close runner log ${logPath}: ${String(error)}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
//#endregion
|
|
60
|
+
Object.defineProperty(exports, "LogFile", {
|
|
61
|
+
enumerable: true,
|
|
62
|
+
get: function() {
|
|
63
|
+
return LogFile;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=logFile-CNvepZh0.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logFile-CNvepZh0.cjs","names":["getLogMaxBytes","fs"],"sources":["../src/services/logFile/index.ts"],"sourcesContent":["import fs from 'node:fs';\n\nimport type { ILogFile, LogWriter } from '../../types/logFile';\nimport { getLogMaxBytes } from '../runnerConfig';\nimport type { IRunnerPaths } from '../runnerPaths/type';\n\nexport class LogFile implements ILogFile {\n constructor(private readonly paths: IRunnerPaths) {}\n\n open(id: string): LogWriter {\n this.paths.ensureDirectories();\n const logPath = this.paths.logPathFor(id);\n const rotatedPath = this.paths.rotatedLogPathFor(id);\n const maxBytes = getLogMaxBytes();\n\n // A reused name starts clean: the previous runner's output is already\n // available to whoever wanted it, and mixing two runs in one file makes\n // both unreadable.\n let handle = fs.openSync(logPath, 'w');\n let written = 0;\n let closed = false;\n\n /**\n * A run that keeps producing output for hours would otherwise grow one file\n * without limit. Rotating keeps the newest window at the advertised path\n * and the window before it alongside, so on-disk cost is bounded at roughly\n * twice the ceiling, the path a result advertises stays valid, and the line\n * counts a reader reports still describe the file it actually read.\n */\n const rotate = (): void => {\n fs.closeSync(handle);\n try {\n fs.renameSync(logPath, rotatedPath);\n } catch (error) {\n // Holding the ceiling matters more than keeping the previous window,\n // so the new file is opened either way and the loss is reported.\n process.emitWarning(`Could not rotate runner log ${logPath}: ${String(error)}`);\n }\n handle = fs.openSync(logPath, 'w');\n written = 0;\n };\n\n return {\n path: logPath,\n append(text: string): void {\n const chunk = Buffer.from(text, 'utf8');\n // An empty file always takes the chunk, so a single write larger than\n // the ceiling is stored rather than rotated away into nothing.\n if (written > 0 && written + chunk.byteLength > maxBytes) rotate();\n fs.writeSync(handle, chunk);\n written += chunk.byteLength;\n },\n size(): number {\n return written;\n },\n close(): void {\n // Closing twice is normal: a launch that fails closes the log before\n // the exit handler does. Only a first close that fails is news.\n if (closed) return;\n closed = true;\n try {\n fs.closeSync(handle);\n } catch (error) {\n process.emitWarning(`Could not close runner log ${logPath}: ${String(error)}`);\n }\n },\n };\n }\n}\n"],"mappings":";;;;;AAMA,IAAa,UAAb,MAAyC;CACV;CAA7B,YAAY,OAAsC;EAArB,KAAA,QAAA;CAAsB;CAEnD,KAAK,IAAuB;EAC1B,KAAK,MAAM,kBAAkB;EAC7B,MAAM,UAAU,KAAK,MAAM,WAAW,EAAE;EACxC,MAAM,cAAc,KAAK,MAAM,kBAAkB,EAAE;EACnD,MAAM,WAAWA,qBAAAA,eAAe;EAKhC,IAAI,SAASC,QAAAA,QAAG,SAAS,SAAS,GAAG;EACrC,IAAI,UAAU;EACd,IAAI,SAAS;;;;;;;;EASb,MAAM,eAAqB;GACzB,QAAA,QAAG,UAAU,MAAM;GACnB,IAAI;IACF,QAAA,QAAG,WAAW,SAAS,WAAW;GACpC,SAAS,OAAO;IAGd,QAAQ,YAAY,+BAA+B,QAAQ,IAAI,OAAO,KAAK,GAAG;GAChF;GACA,SAASA,QAAAA,QAAG,SAAS,SAAS,GAAG;GACjC,UAAU;EACZ;EAEA,OAAO;GACL,MAAM;GACN,OAAO,MAAoB;IACzB,MAAM,QAAQ,OAAO,KAAK,MAAM,MAAM;IAGtC,IAAI,UAAU,KAAK,UAAU,MAAM,aAAa,UAAU,OAAO;IACjE,QAAA,QAAG,UAAU,QAAQ,KAAK;IAC1B,WAAW,MAAM;GACnB;GACA,OAAe;IACb,OAAO;GACT;GACA,QAAc;IAGZ,IAAI,QAAQ;IACZ,SAAS;IACT,IAAI;KACF,QAAA,QAAG,UAAU,MAAM;IACrB,SAAS,OAAO;KACd,QAAQ,YAAY,8BAA8B,QAAQ,IAAI,OAAO,KAAK,GAAG;IAC/E;GACF;EACF;CACF;AACF"}
|