@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,647 @@
|
|
|
1
|
+
import { t as BashRunService } from "./bashRunService-CJ02XaAq.mjs";
|
|
2
|
+
import { g as noninteractiveEnvironment, s as getLogMaxBytes, u as getResultMaxBytes } from "./runnerConfig-BQBlVAXn.mjs";
|
|
3
|
+
import { t as LogReader } from "./logReader-UfbDbwQl.mjs";
|
|
4
|
+
import { t as SystemClock } from "./clock-Cv2pddgo.mjs";
|
|
5
|
+
import { t as RmuxBackend } from "./rmuxBackend-DfyQwJrc.mjs";
|
|
6
|
+
import { NO_TERMINAL_INPUT_ENV, cleanupSupervisorFiles, readExitMetadata, runtimeEntry, shellJoin, supervisorPaths, writeCommandSpec } from "./services/runnerSupervisor/index.mjs";
|
|
7
|
+
import { t as RtkProcessor } from "./rtkProcessor-B9KPdyzr.mjs";
|
|
8
|
+
import { t as Launcher } from "./launcher-BDm6-DiQ.mjs";
|
|
9
|
+
import { t as NodeLifeline } from "./lifeline-BZaQA0rm.mjs";
|
|
10
|
+
import { t as LogFile } from "./logFile-KKPbkC-a.mjs";
|
|
11
|
+
import { t as NodeProcessControl } from "./processControl-DApTpV16.mjs";
|
|
12
|
+
import { t as PtyHost } from "./ptyHost-DlQtTB8F.mjs";
|
|
13
|
+
import { t as NodePtySpawner } from "./ptySpawner-DEi1KOnd.mjs";
|
|
14
|
+
import { t as RunnerNamer } from "./runnerNamer-B8FH7n2v.mjs";
|
|
15
|
+
import { t as RunnerPaths } from "./runnerPaths-B_dAAeco.mjs";
|
|
16
|
+
import { n as createDefaultProcessRegistry, t as RunnerRegistry } from "./runnerRegistry-CeOHEjBv.mjs";
|
|
17
|
+
import { t as NodeSpawner } from "./spawner-LoVsn55-.mjs";
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import fs from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { execFile } from "node:child_process";
|
|
22
|
+
import { sharedExecutionBudget } from "@agimon-ai/po-core/packageApi";
|
|
23
|
+
//#region src/constants/tmuxBackend.ts
|
|
24
|
+
const LOG_DRAIN_TIMEOUT_MS = 2e3;
|
|
25
|
+
const PANE_STATE_FORMAT = "#{pane_dead}:#{pane_dead_status}:#{session_name}";
|
|
26
|
+
const SESSION_PREFIX = "doom-tmux-";
|
|
27
|
+
const OWNED_TARGET_PATTERN = /^doom-tmux-[A-Za-z0-9_-]+$/;
|
|
28
|
+
const SOCKET_PREFIX = "doom-tmux-";
|
|
29
|
+
const NON_INTERACTIVE_ENV = {
|
|
30
|
+
NO_COLOR: "1",
|
|
31
|
+
CI: "1"
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/services/ptyBackendChain/index.ts
|
|
35
|
+
/**
|
|
36
|
+
* Presents the available PTY backends as one, preferring RMUX.
|
|
37
|
+
*
|
|
38
|
+
* A launch takes the first backend that accepts it, so a host without a
|
|
39
|
+
* compatible RMUX binary still gets panes rather than falling through to the
|
|
40
|
+
* plain subprocess launcher. Every later call routes on the target's prefix
|
|
41
|
+
* instead of asking each backend in turn: a backend cannot tell "this session
|
|
42
|
+
* is gone" from "this session was never mine", and guessing would let one
|
|
43
|
+
* report success for the other's run.
|
|
44
|
+
*/
|
|
45
|
+
var PtyBackendChain = class {
|
|
46
|
+
rmux;
|
|
47
|
+
tmux;
|
|
48
|
+
constructor(rmux, tmux) {
|
|
49
|
+
this.rmux = rmux;
|
|
50
|
+
this.tmux = tmux;
|
|
51
|
+
}
|
|
52
|
+
async launch(request) {
|
|
53
|
+
return await this.rmux.launch(request) ?? await this.tmux.launch(request);
|
|
54
|
+
}
|
|
55
|
+
watch(id, target, sessionId) {
|
|
56
|
+
return this.owner(target).watch(id, target, sessionId);
|
|
57
|
+
}
|
|
58
|
+
stop(target, expectedPid) {
|
|
59
|
+
return this.owner(target).stop(target, expectedPid);
|
|
60
|
+
}
|
|
61
|
+
input(target, text) {
|
|
62
|
+
return this.owner(target).input(target, text);
|
|
63
|
+
}
|
|
64
|
+
capture(target) {
|
|
65
|
+
return this.owner(target).capture(target);
|
|
66
|
+
}
|
|
67
|
+
/** Both backends persist terminal evidence at the same path, so either answers. */
|
|
68
|
+
readOutcome(id, sessionId) {
|
|
69
|
+
return this.rmux.readOutcome(id, sessionId) ?? this.tmux.readOutcome(id, sessionId);
|
|
70
|
+
}
|
|
71
|
+
get(name) {
|
|
72
|
+
return this.rmux.get(name) ?? this.tmux.get(name);
|
|
73
|
+
}
|
|
74
|
+
owner(target) {
|
|
75
|
+
return target.startsWith("doom-tmux-") ? this.tmux : this.rmux;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/services/tmuxBackend/TmuxClient.ts
|
|
80
|
+
const TMUX_BINARY = "tmux";
|
|
81
|
+
const SOCKET_OPTION = "-L";
|
|
82
|
+
/** Long enough for a loaded server, short enough that a hung tmux is not fatal. */
|
|
83
|
+
const COMMAND_TIMEOUT_MS = 1e4;
|
|
84
|
+
const MAX_OUTPUT_BYTES = 4194304;
|
|
85
|
+
var TmuxClient = class {
|
|
86
|
+
socket;
|
|
87
|
+
binary;
|
|
88
|
+
constructor(socket, binary = TMUX_BINARY) {
|
|
89
|
+
this.socket = socket;
|
|
90
|
+
this.binary = binary;
|
|
91
|
+
}
|
|
92
|
+
run(args) {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
execFile(this.binary, [
|
|
95
|
+
SOCKET_OPTION,
|
|
96
|
+
this.socket,
|
|
97
|
+
...args
|
|
98
|
+
], {
|
|
99
|
+
timeout: COMMAND_TIMEOUT_MS,
|
|
100
|
+
maxBuffer: MAX_OUTPUT_BYTES,
|
|
101
|
+
encoding: "utf8"
|
|
102
|
+
}, (error, stdout, stderr) => {
|
|
103
|
+
const code = error?.code;
|
|
104
|
+
if (error && typeof code !== "number") {
|
|
105
|
+
reject(error);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
resolve({
|
|
109
|
+
returnCode: typeof code === "number" ? code : 0,
|
|
110
|
+
stdout,
|
|
111
|
+
stderr
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async format(target, format) {
|
|
117
|
+
const result = await this.run([
|
|
118
|
+
"display-message",
|
|
119
|
+
"-p",
|
|
120
|
+
"-t",
|
|
121
|
+
target,
|
|
122
|
+
"-F",
|
|
123
|
+
format
|
|
124
|
+
]).catch(() => void 0);
|
|
125
|
+
if (!result || result.returnCode !== 0) return void 0;
|
|
126
|
+
return result.stdout.replace(/\n$/, "");
|
|
127
|
+
}
|
|
128
|
+
async sessionMissing(target) {
|
|
129
|
+
const result = await this.run([
|
|
130
|
+
"has-session",
|
|
131
|
+
"-t",
|
|
132
|
+
target
|
|
133
|
+
]).catch(() => void 0);
|
|
134
|
+
return !result || result.returnCode !== 0;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
//#endregion
|
|
138
|
+
//#region src/services/tmuxBackend/index.ts
|
|
139
|
+
/** Pane liveness, its exit status, and whether the session still exists, in one read. */
|
|
140
|
+
/** Distinct from the RMUX prefix so a target names the backend that owns it. */
|
|
141
|
+
/**
|
|
142
|
+
* Supervises runs in tmux panes, for hosts with no compatible RMUX binary.
|
|
143
|
+
*
|
|
144
|
+
* The pane runs the same runnerHost supervisor as the RMUX backend, so exit
|
|
145
|
+
* metadata, log rotation, and lifeline handling are shared rather than
|
|
146
|
+
* reimplemented: only the multiplexer differs. Kept beside the RMUX backend
|
|
147
|
+
* rather than folded into it because that path has no unit coverage to
|
|
148
|
+
* refactor against.
|
|
149
|
+
*/
|
|
150
|
+
var TmuxBackend = class {
|
|
151
|
+
paths;
|
|
152
|
+
createClient;
|
|
153
|
+
env;
|
|
154
|
+
settings;
|
|
155
|
+
clientPromise;
|
|
156
|
+
runs = /* @__PURE__ */ new Map();
|
|
157
|
+
completions = /* @__PURE__ */ new Map();
|
|
158
|
+
constructor(paths, createClient = (socket) => new TmuxClient(socket), env = process.env, settings) {
|
|
159
|
+
this.paths = paths;
|
|
160
|
+
this.createClient = createClient;
|
|
161
|
+
this.env = env;
|
|
162
|
+
this.settings = settings;
|
|
163
|
+
}
|
|
164
|
+
async launch(request) {
|
|
165
|
+
const tmux = await this.client();
|
|
166
|
+
if (!tmux) return void 0;
|
|
167
|
+
this.paths.ensureDirectories();
|
|
168
|
+
const target = `${SESSION_PREFIX}${request.id}`;
|
|
169
|
+
const logPath = this.paths.logPathFor(request.id);
|
|
170
|
+
const aux = this.auxPaths(request.id, request.sessionId);
|
|
171
|
+
let created = false;
|
|
172
|
+
let released = false;
|
|
173
|
+
try {
|
|
174
|
+
this.prepareFiles(request, logPath, aux);
|
|
175
|
+
const supervisor = shellJoin([
|
|
176
|
+
process.execPath,
|
|
177
|
+
runtimeEntry("runnerHost"),
|
|
178
|
+
aux.spec,
|
|
179
|
+
aux.gate,
|
|
180
|
+
aux.exit
|
|
181
|
+
]);
|
|
182
|
+
await this.checked(tmux, [
|
|
183
|
+
"new-session",
|
|
184
|
+
"-d",
|
|
185
|
+
"-s",
|
|
186
|
+
target,
|
|
187
|
+
"-c",
|
|
188
|
+
request.cwd,
|
|
189
|
+
supervisor
|
|
190
|
+
]);
|
|
191
|
+
created = true;
|
|
192
|
+
await this.checked(tmux, [
|
|
193
|
+
"set-option",
|
|
194
|
+
"-t",
|
|
195
|
+
target,
|
|
196
|
+
"remain-on-exit",
|
|
197
|
+
"on"
|
|
198
|
+
]);
|
|
199
|
+
await this.checked(tmux, [
|
|
200
|
+
"pipe-pane",
|
|
201
|
+
"-t",
|
|
202
|
+
target,
|
|
203
|
+
this.logPipeCommand(logPath, aux.logDone, request)
|
|
204
|
+
]);
|
|
205
|
+
const pid = await panePid(tmux, target);
|
|
206
|
+
fs.writeFileSync(aux.gate, "", { mode: 384 });
|
|
207
|
+
released = true;
|
|
208
|
+
let buffering = true;
|
|
209
|
+
const completion = this.monitor(tmux, target, aux);
|
|
210
|
+
this.trackCompletion(target, completion);
|
|
211
|
+
const handle = {
|
|
212
|
+
id: request.id,
|
|
213
|
+
name: request.name,
|
|
214
|
+
pid,
|
|
215
|
+
logPath,
|
|
216
|
+
backend: "tmux",
|
|
217
|
+
backendTarget: target,
|
|
218
|
+
output: () => buffering ? readTail(logPath, getResultMaxBytes(this.env, this.settings) * 2) : "",
|
|
219
|
+
completion: () => completion,
|
|
220
|
+
detach: () => {
|
|
221
|
+
buffering = false;
|
|
222
|
+
},
|
|
223
|
+
stop: () => this.stop(target, pid)
|
|
224
|
+
};
|
|
225
|
+
if (request.interactive) this.runs.set(request.name, this.interactiveRun(handle, tmux, target, completion));
|
|
226
|
+
completion.finally(() => this.runs.delete(request.name)).catch((error) => process.emitWarning(`tmux completion failed for ${target}: ${errorMessage(error)}`));
|
|
227
|
+
return handle;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (released) throw error;
|
|
230
|
+
if (created) await killSession(tmux, target);
|
|
231
|
+
cleanupSupervisorFiles(aux);
|
|
232
|
+
process.emitWarning(request.interactive ? `tmux launch unavailable for interactive runner: ${errorMessage(error)}` : `tmux launch unavailable, using supervised subprocess: ${errorMessage(error)}`);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async stop(target, expectedPid) {
|
|
237
|
+
if (!OWNED_TARGET_PATTERN.test(target) || !Number.isInteger(expectedPid) || expectedPid <= 0) return false;
|
|
238
|
+
const tmux = await this.client();
|
|
239
|
+
if (!tmux) return false;
|
|
240
|
+
try {
|
|
241
|
+
if (await tmux.sessionMissing(target)) return true;
|
|
242
|
+
const pid = await panePid(tmux, target);
|
|
243
|
+
if (pid !== expectedPid) return false;
|
|
244
|
+
const signalled = signalPane(pid, target);
|
|
245
|
+
if (signalled === "gone") return true;
|
|
246
|
+
if (signalled === "failed") return false;
|
|
247
|
+
if (await waitForPaneStop(tmux, target, 3e3)) return true;
|
|
248
|
+
if (await tmux.sessionMissing(target)) return true;
|
|
249
|
+
if (await panePid(tmux, target).catch(() => void 0) !== expectedPid) return false;
|
|
250
|
+
return killSession(tmux, target);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
process.emitWarning(`Could not stop tmux target ${target}: ${errorMessage(error)}`);
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async watch(id, target, sessionId) {
|
|
257
|
+
const tmux = await this.client();
|
|
258
|
+
if (!tmux) return void 0;
|
|
259
|
+
if (await tmux.sessionMissing(target)) return void 0;
|
|
260
|
+
const completion = this.monitor(tmux, target, this.auxPaths(id, sessionId));
|
|
261
|
+
this.trackCompletion(target, completion);
|
|
262
|
+
return completion;
|
|
263
|
+
}
|
|
264
|
+
async input(target, text) {
|
|
265
|
+
const tmux = await this.client();
|
|
266
|
+
if (!tmux) return false;
|
|
267
|
+
return (await tmux.run([
|
|
268
|
+
"send-keys",
|
|
269
|
+
"-t",
|
|
270
|
+
target,
|
|
271
|
+
"-l",
|
|
272
|
+
text
|
|
273
|
+
]).catch((error) => {
|
|
274
|
+
process.emitWarning(`Could not send input to tmux target ${target}: ${errorMessage(error)}`);
|
|
275
|
+
}))?.returnCode === 0;
|
|
276
|
+
}
|
|
277
|
+
async capture(target) {
|
|
278
|
+
const tmux = await this.client();
|
|
279
|
+
if (!tmux) return void 0;
|
|
280
|
+
const result = await tmux.run([
|
|
281
|
+
"capture-pane",
|
|
282
|
+
"-p",
|
|
283
|
+
"-t",
|
|
284
|
+
target
|
|
285
|
+
]).catch((error) => {
|
|
286
|
+
process.emitWarning(`Could not capture tmux target ${target}: ${errorMessage(error)}`);
|
|
287
|
+
});
|
|
288
|
+
return result?.returnCode === 0 ? result.stdout : void 0;
|
|
289
|
+
}
|
|
290
|
+
get(name) {
|
|
291
|
+
return this.runs.get(name);
|
|
292
|
+
}
|
|
293
|
+
readOutcome(id, sessionId) {
|
|
294
|
+
return readExitMetadata(this.auxPaths(id, sessionId).exit);
|
|
295
|
+
}
|
|
296
|
+
trackCompletion(target, completion) {
|
|
297
|
+
this.completions.set(target, completion);
|
|
298
|
+
completion.finally(() => this.completions.delete(target)).catch((error) => process.emitWarning(`tmux monitor failed for ${target}: ${errorMessage(error)}`));
|
|
299
|
+
}
|
|
300
|
+
client() {
|
|
301
|
+
this.clientPromise ??= this.resolveClient();
|
|
302
|
+
return this.clientPromise;
|
|
303
|
+
}
|
|
304
|
+
async resolveClient() {
|
|
305
|
+
const client = this.createClient(socketName(this.paths.repositoryPath()));
|
|
306
|
+
try {
|
|
307
|
+
const version = await client.run(["-V"]);
|
|
308
|
+
if (version.returnCode !== 0) throw new Error(version.stderr.trim() || "tmux reported no version");
|
|
309
|
+
return client;
|
|
310
|
+
} catch (error) {
|
|
311
|
+
process.emitWarning(`tmux is unavailable: ${errorMessage(error)}`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async checked(tmux, args) {
|
|
316
|
+
const result = await tmux.run(args);
|
|
317
|
+
if (result.returnCode !== 0) throw new Error(`tmux ${args[0] ?? ""} failed: ${result.stderr.trim() || `exit ${result.returnCode}`}`);
|
|
318
|
+
}
|
|
319
|
+
prepareFiles(request, logPath, aux) {
|
|
320
|
+
cleanupSupervisorFiles(aux);
|
|
321
|
+
fs.writeFileSync(logPath, "", { mode: 384 });
|
|
322
|
+
const env = environment(request.sessionId, request.interactive, this.env);
|
|
323
|
+
const spec = {
|
|
324
|
+
command: request.command,
|
|
325
|
+
cwd: request.cwd,
|
|
326
|
+
env
|
|
327
|
+
};
|
|
328
|
+
writeCommandSpec(aux.spec, spec);
|
|
329
|
+
}
|
|
330
|
+
auxPaths(id, sessionId) {
|
|
331
|
+
return supervisorPaths(this.paths.stateDirectory(sessionId), id);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* The sink the pane pipes into.
|
|
335
|
+
*
|
|
336
|
+
* An interactive run also asks for a raw copy: the scrubbed log it writes
|
|
337
|
+
* beside it has had cursor movement taken out, which is what a terminal
|
|
338
|
+
* needs most. Only interactive runs pay for it, because only they can be
|
|
339
|
+
* attached to.
|
|
340
|
+
*/
|
|
341
|
+
logPipeCommand(logPath, donePath, request) {
|
|
342
|
+
const id = path.basename(logPath, ".log");
|
|
343
|
+
return shellJoin([
|
|
344
|
+
process.execPath,
|
|
345
|
+
runtimeEntry("logSink"),
|
|
346
|
+
logPath,
|
|
347
|
+
this.paths.rotatedLogPathFor(id),
|
|
348
|
+
String(getLogMaxBytes(this.env)),
|
|
349
|
+
donePath,
|
|
350
|
+
...request.interactive ? [this.paths.rawLogPathFor(id)] : []
|
|
351
|
+
]);
|
|
352
|
+
}
|
|
353
|
+
async monitor(tmux, target, aux) {
|
|
354
|
+
try {
|
|
355
|
+
const paneCode = await waitForRunEnd(tmux, target, aux.exit);
|
|
356
|
+
await waitForLogDrain(tmux, target, aux.logDone);
|
|
357
|
+
return readExitMetadata(aux.exit) ?? {
|
|
358
|
+
code: paneCode,
|
|
359
|
+
signal: null
|
|
360
|
+
};
|
|
361
|
+
} finally {
|
|
362
|
+
if (!await tmux.sessionMissing(target).catch(() => false)) await killSession(tmux, target);
|
|
363
|
+
cleanupSupervisorFiles(aux);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
interactiveRun(handle, tmux, target, completion) {
|
|
367
|
+
let screen = "";
|
|
368
|
+
let active = true;
|
|
369
|
+
const handlers = /* @__PURE__ */ new Set();
|
|
370
|
+
const refresh = async () => {
|
|
371
|
+
while (active) {
|
|
372
|
+
const captured = await tmux.run([
|
|
373
|
+
"capture-pane",
|
|
374
|
+
"-p",
|
|
375
|
+
"-t",
|
|
376
|
+
target
|
|
377
|
+
]).catch((error) => {
|
|
378
|
+
process.emitWarning(`Could not capture tmux screen for ${handle.name}: ${errorMessage(error)}`);
|
|
379
|
+
});
|
|
380
|
+
const next = captured?.returnCode === 0 ? captured.stdout : screen;
|
|
381
|
+
if (next !== screen) {
|
|
382
|
+
screen = next;
|
|
383
|
+
for (const handler of handlers) handler(next);
|
|
384
|
+
}
|
|
385
|
+
await delay(100);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
refresh();
|
|
389
|
+
completion.finally(() => {
|
|
390
|
+
active = false;
|
|
391
|
+
}).catch((error) => process.emitWarning(`tmux interactive completion failed for ${handle.name}: ${errorMessage(error)}`));
|
|
392
|
+
return {
|
|
393
|
+
...handle,
|
|
394
|
+
write: (text) => {
|
|
395
|
+
tmux.run([
|
|
396
|
+
"send-keys",
|
|
397
|
+
"-t",
|
|
398
|
+
target,
|
|
399
|
+
"-l",
|
|
400
|
+
text
|
|
401
|
+
]).catch((error) => process.emitWarning(errorMessage(error)));
|
|
402
|
+
},
|
|
403
|
+
screen: () => screen,
|
|
404
|
+
onData: (handler) => {
|
|
405
|
+
handlers.add(handler);
|
|
406
|
+
return () => handlers.delete(handler);
|
|
407
|
+
},
|
|
408
|
+
resize: (cols, rows) => {
|
|
409
|
+
tmux.run([
|
|
410
|
+
"resize-window",
|
|
411
|
+
"-t",
|
|
412
|
+
target,
|
|
413
|
+
"-x",
|
|
414
|
+
String(cols),
|
|
415
|
+
"-y",
|
|
416
|
+
String(rows)
|
|
417
|
+
]).catch((error) => process.emitWarning(errorMessage(error)));
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
function socketName(repositoryPath) {
|
|
423
|
+
const hash = createHash("sha256").update(repositoryPath).digest("hex").slice(0, 12);
|
|
424
|
+
return `${SOCKET_PREFIX}${hash}`;
|
|
425
|
+
}
|
|
426
|
+
function environment(sessionId, interactive, env) {
|
|
427
|
+
const values = {
|
|
428
|
+
...env,
|
|
429
|
+
...interactive ? {} : {
|
|
430
|
+
...NON_INTERACTIVE_ENV,
|
|
431
|
+
...noninteractiveEnvironment(env)
|
|
432
|
+
},
|
|
433
|
+
...NO_TERMINAL_INPUT_ENV,
|
|
434
|
+
PI_SESSION_ID: sessionId
|
|
435
|
+
};
|
|
436
|
+
if (!interactive) delete values["FORCE_COLOR"];
|
|
437
|
+
return Object.fromEntries(Object.entries(values).filter((entry) => entry[1] !== void 0));
|
|
438
|
+
}
|
|
439
|
+
async function killSession(tmux, target) {
|
|
440
|
+
return (await tmux.run([
|
|
441
|
+
"kill-session",
|
|
442
|
+
"-t",
|
|
443
|
+
target
|
|
444
|
+
]).catch((error) => {
|
|
445
|
+
process.emitWarning(`Could not close tmux target ${target}: ${errorMessage(error)}`);
|
|
446
|
+
}))?.returnCode === 0;
|
|
447
|
+
}
|
|
448
|
+
async function panePid(tmux, target) {
|
|
449
|
+
const message = await tmux.format(target, "#{pane_pid}");
|
|
450
|
+
const pid = Number(message);
|
|
451
|
+
if (!Number.isInteger(pid) || pid <= 0) throw new Error(`tmux did not report a pane pid for ${target}`);
|
|
452
|
+
return pid;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Waits for the run to end, preferring the supervisor's own record of it.
|
|
456
|
+
*
|
|
457
|
+
* The sidecar is written before the pane can end and outlives the server the
|
|
458
|
+
* pane's exit takes down, so asking tmux is the fallback for a supervisor that
|
|
459
|
+
* died without recording anything.
|
|
460
|
+
*/
|
|
461
|
+
async function waitForRunEnd(tmux, target, exitPath) {
|
|
462
|
+
for (;;) {
|
|
463
|
+
if (fs.existsSync(exitPath)) return null;
|
|
464
|
+
const state = await readPaneExit(tmux, target);
|
|
465
|
+
if (state.exited) return state.code;
|
|
466
|
+
await delay(100);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
async function waitForLogDrain(tmux, target, donePath) {
|
|
470
|
+
const deadline = Date.now() + LOG_DRAIN_TIMEOUT_MS;
|
|
471
|
+
while (Date.now() < deadline) {
|
|
472
|
+
if (fs.existsSync(donePath)) return;
|
|
473
|
+
if (await tmux.sessionMissing(target)) return;
|
|
474
|
+
await delay(25);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
async function waitForPaneStop(tmux, target, timeoutMs) {
|
|
478
|
+
const deadline = Date.now() + timeoutMs;
|
|
479
|
+
while (Date.now() < deadline) {
|
|
480
|
+
if ((await readPaneExit(tmux, target)).exited) return true;
|
|
481
|
+
await delay(100);
|
|
482
|
+
}
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
/** One formatted read answers both questions this poll asks. */
|
|
486
|
+
async function readPaneExit(tmux, target) {
|
|
487
|
+
const message = await tmux.format(target, PANE_STATE_FORMAT);
|
|
488
|
+
if (message === void 0) return {
|
|
489
|
+
exited: true,
|
|
490
|
+
code: null
|
|
491
|
+
};
|
|
492
|
+
const [dead, status, ...rest] = message.trim().split(":");
|
|
493
|
+
if (rest.join(":") === "") return {
|
|
494
|
+
exited: true,
|
|
495
|
+
code: null
|
|
496
|
+
};
|
|
497
|
+
if (dead === "1" || dead === "true") {
|
|
498
|
+
const code = Number(status);
|
|
499
|
+
return {
|
|
500
|
+
exited: true,
|
|
501
|
+
code: Number.isInteger(code) ? code : null
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
exited: false,
|
|
506
|
+
code: null
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
function signalPane(pid, target) {
|
|
510
|
+
try {
|
|
511
|
+
process.kill(pid, "SIGTERM");
|
|
512
|
+
return "signalled";
|
|
513
|
+
} catch (error) {
|
|
514
|
+
if (error.code === "ESRCH") return "gone";
|
|
515
|
+
process.emitWarning(`Could not signal tmux target ${target}: ${errorMessage(error)}`);
|
|
516
|
+
return "failed";
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
function readTail(target, maxBytes) {
|
|
520
|
+
let handle;
|
|
521
|
+
try {
|
|
522
|
+
const size = fs.statSync(target).size;
|
|
523
|
+
const bytes = Math.min(size, maxBytes);
|
|
524
|
+
const buffer = Buffer.alloc(bytes);
|
|
525
|
+
handle = fs.openSync(target, "r");
|
|
526
|
+
fs.readSync(handle, buffer, 0, bytes, size - bytes);
|
|
527
|
+
return buffer.toString("utf8");
|
|
528
|
+
} catch (error) {
|
|
529
|
+
if (error.code !== "ENOENT") process.emitWarning(`Could not read tmux log ${target}: ${errorMessage(error)}`);
|
|
530
|
+
return "";
|
|
531
|
+
} finally {
|
|
532
|
+
if (handle !== void 0) fs.closeSync(handle);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function delay(ms) {
|
|
536
|
+
return new Promise((resolve) => {
|
|
537
|
+
setTimeout(resolve, ms).unref?.();
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function errorMessage(error) {
|
|
541
|
+
return error instanceof Error ? error.message : String(error);
|
|
542
|
+
}
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region src/services/runnerDependencies/index.ts
|
|
545
|
+
/** Build once on first access, then hand back the same instance. */
|
|
546
|
+
function memoize(build) {
|
|
547
|
+
let value;
|
|
548
|
+
let built = false;
|
|
549
|
+
return () => {
|
|
550
|
+
if (!built) {
|
|
551
|
+
value = build();
|
|
552
|
+
built = true;
|
|
553
|
+
}
|
|
554
|
+
return value;
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Builds the extension's service graph.
|
|
559
|
+
*
|
|
560
|
+
* A factory rather than a module-level singleton: the extension owns one graph
|
|
561
|
+
* per session, and tests get a fresh one they can substitute ports on through
|
|
562
|
+
* `overrides` without leaking state between cases.
|
|
563
|
+
*
|
|
564
|
+
* Every slot resolves lazily and memoizes, which keeps the previous container's
|
|
565
|
+
* behaviour: nothing is constructed until it is asked for, so opening the SQLite
|
|
566
|
+
* process registry stays deferred until something actually needs a runner.
|
|
567
|
+
*/
|
|
568
|
+
function createRunnerDependencies(overrides) {
|
|
569
|
+
const settings = overrides.settings === void 0 ? void 0 : Object.freeze({
|
|
570
|
+
...overrides.settings,
|
|
571
|
+
...overrides.settings?.errorPatterns ? { errorPatterns: Object.freeze([...overrides.settings.errorPatterns]) } : {}
|
|
572
|
+
});
|
|
573
|
+
const environment = { ...overrides.environment };
|
|
574
|
+
const cwd = overrides.cwd ?? process.cwd();
|
|
575
|
+
const clock = memoize(() => overrides.clock ?? new SystemClock());
|
|
576
|
+
const spawner = memoize(() => overrides.spawner ?? new NodeSpawner());
|
|
577
|
+
const processControl = memoize(() => overrides.processControl ?? new NodeProcessControl());
|
|
578
|
+
const ptySpawner = memoize(() => overrides.ptySpawner ?? new NodePtySpawner());
|
|
579
|
+
const paths = memoize(() => overrides.paths ?? new RunnerPaths(cwd, environment));
|
|
580
|
+
const lifeline = memoize(() => overrides.lifeline ?? new NodeLifeline(paths()));
|
|
581
|
+
const processRegistry = memoize(() => overrides.processRegistry ?? createDefaultProcessRegistry(environment));
|
|
582
|
+
const runnerRegistry = memoize(() => overrides.runnerRegistry ?? new RunnerRegistry(paths(), processControl(), processRegistry(), environment));
|
|
583
|
+
const namer = memoize(() => overrides.namer ?? new RunnerNamer(runnerRegistry()));
|
|
584
|
+
const logFile = memoize(() => overrides.logFile ?? new LogFile(paths()));
|
|
585
|
+
const logReader = memoize(() => overrides.logReader ?? new LogReader());
|
|
586
|
+
const launcher = memoize(() => overrides.launcher ?? new Launcher(spawner(), processControl(), logFile(), clock(), paths(), lifeline(), environment, settings));
|
|
587
|
+
const rmuxBackend = memoize(() => overrides.rmuxBackend ?? new PtyBackendChain(new RmuxBackend(paths(), environment, settings), new TmuxBackend(paths(), void 0, environment, settings)));
|
|
588
|
+
const rtkProcessor = memoize(() => overrides.rtkProcessor ?? new RtkProcessor(void 0, void 0, environment, settings));
|
|
589
|
+
const ptyHost = memoize(() => overrides.ptyHost ?? new PtyHost(ptySpawner(), logFile(), processControl(), clock(), environment, settings));
|
|
590
|
+
const bashRunService = memoize(() => overrides.bashRunService ?? new BashRunService(launcher(), rmuxBackend(), namer(), runnerRegistry(), clock(), rtkProcessor(), cwd, environment, overrides.executionBudget ?? sharedExecutionBudget(environment)));
|
|
591
|
+
return {
|
|
592
|
+
settings,
|
|
593
|
+
environment,
|
|
594
|
+
get clock() {
|
|
595
|
+
return clock();
|
|
596
|
+
},
|
|
597
|
+
get spawner() {
|
|
598
|
+
return spawner();
|
|
599
|
+
},
|
|
600
|
+
get processControl() {
|
|
601
|
+
return processControl();
|
|
602
|
+
},
|
|
603
|
+
get ptySpawner() {
|
|
604
|
+
return ptySpawner();
|
|
605
|
+
},
|
|
606
|
+
get paths() {
|
|
607
|
+
return paths();
|
|
608
|
+
},
|
|
609
|
+
get lifeline() {
|
|
610
|
+
return lifeline();
|
|
611
|
+
},
|
|
612
|
+
get processRegistry() {
|
|
613
|
+
return processRegistry();
|
|
614
|
+
},
|
|
615
|
+
get runnerRegistry() {
|
|
616
|
+
return runnerRegistry();
|
|
617
|
+
},
|
|
618
|
+
get namer() {
|
|
619
|
+
return namer();
|
|
620
|
+
},
|
|
621
|
+
get logFile() {
|
|
622
|
+
return logFile();
|
|
623
|
+
},
|
|
624
|
+
get logReader() {
|
|
625
|
+
return logReader();
|
|
626
|
+
},
|
|
627
|
+
get launcher() {
|
|
628
|
+
return launcher();
|
|
629
|
+
},
|
|
630
|
+
get rmuxBackend() {
|
|
631
|
+
return rmuxBackend();
|
|
632
|
+
},
|
|
633
|
+
get rtkProcessor() {
|
|
634
|
+
return rtkProcessor();
|
|
635
|
+
},
|
|
636
|
+
get ptyHost() {
|
|
637
|
+
return ptyHost();
|
|
638
|
+
},
|
|
639
|
+
get bashRunService() {
|
|
640
|
+
return bashRunService();
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
//#endregion
|
|
645
|
+
export { TmuxBackend as n, PtyBackendChain as r, createRunnerDependencies as t };
|
|
646
|
+
|
|
647
|
+
//# sourceMappingURL=runnerDependencies-DruByBGS.mjs.map
|