@agimon-ai/po-runner 0.0.0-alpha.21 → 0.0.0-alpha.22
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/dist/{bashRunService-Ci0cGdYO.d.mts → bashRunService-BL4JIUi2.d.mts} +6 -1
- package/dist/bashRunService-BL4JIUi2.d.mts.map +1 -0
- package/dist/{bashRunService-DjOH5kye.cjs → bashRunService-CJhMNrPz.cjs} +8 -4
- package/dist/bashRunService-CJhMNrPz.cjs.map +1 -0
- package/dist/{bashRunService-Cl3pYccr.mjs → bashRunService-DbYsj1zc.mjs} +8 -4
- package/dist/bashRunService-DbYsj1zc.mjs.map +1 -0
- package/dist/bashRunService.cjs +1 -1
- package/dist/bashRunService.d.mts +1 -1
- package/dist/bashRunService.d.mts.map +1 -1
- package/dist/bashRunService.mjs +1 -1
- package/dist/bashTool.cjs +1 -1
- package/dist/bashTool.d.mts +2 -2
- package/dist/bashTool.mjs +1 -1
- package/dist/bin/cli.cjs +1 -1
- package/dist/bin/cli.mjs +1 -1
- package/dist/extensions/native.mjs +212 -203
- package/dist/extensions/native.mjs.map +1 -1
- package/dist/extensions/server.cjs +2 -2
- package/dist/extensions/server.mjs +2 -2
- package/dist/extensions/web.mjs +334 -500
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/{headless-Dko_yBiy.cjs → headless-C4Bvl2B-.cjs} +8 -4
- package/dist/headless-C4Bvl2B-.cjs.map +1 -0
- package/dist/{headless-DOlCixyf.mjs → headless-DidUBSSf.mjs} +8 -4
- package/dist/headless-DidUBSSf.mjs.map +1 -0
- package/dist/{index--xF7DvsE.d.mts → index-CXbcmf-G.d.mts} +2 -2
- package/dist/{index--xF7DvsE.d.mts.map → index-CXbcmf-G.d.mts.map} +1 -1
- package/dist/{index-BzeXJk6V.d.mts → index-DJkjYgir.d.mts} +3 -3
- package/dist/{index-BzeXJk6V.d.mts.map → index-DJkjYgir.d.mts.map} +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/responseEnvelope.d.mts +1 -1
- package/dist/{runnerDependencies-7h_cxOva.mjs → runnerDependencies-CamKwphq.mjs} +2 -2
- package/dist/{runnerDependencies-7h_cxOva.mjs.map → runnerDependencies-CamKwphq.mjs.map} +1 -1
- package/dist/{runnerDependencies-DSun3xO-.cjs → runnerDependencies-vkpJfxZZ.cjs} +2 -2
- package/dist/{runnerDependencies-DSun3xO-.cjs.map → runnerDependencies-vkpJfxZZ.cjs.map} +1 -1
- package/dist/runnerDependencies.cjs +1 -1
- package/dist/runnerDependencies.d.mts +1 -1
- package/dist/runnerDependencies.mjs +1 -1
- package/dist/{type-Do0YxwVQ.d.mts → type-BQ2shEB5.d.mts} +2 -2
- package/dist/{type-Do0YxwVQ.d.mts.map → type-BQ2shEB5.d.mts.map} +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +17 -17
- package/dist/bashRunService-Ci0cGdYO.d.mts.map +0 -1
- package/dist/bashRunService-Cl3pYccr.mjs.map +0 -1
- package/dist/bashRunService-DjOH5kye.cjs.map +0 -1
- package/dist/headless-DOlCixyf.mjs.map +0 -1
- package/dist/headless-Dko_yBiy.cjs.map +0 -1
|
@@ -46,7 +46,10 @@ function parseStart(tail) {
|
|
|
46
46
|
const key = token.slice(0, split);
|
|
47
47
|
if (key === "name" && value !== "") request.name = value;
|
|
48
48
|
if (key === "cwd" && value !== "") request.cwd = value;
|
|
49
|
-
if (key === "interactive")
|
|
49
|
+
if (key === "interactive") {
|
|
50
|
+
request.interactive = value === "true";
|
|
51
|
+
if (value === "prefer") request.preferInteractive = true;
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
54
|
return request;
|
|
52
55
|
}
|
|
@@ -125,11 +128,12 @@ function createHeadlessRunnersCommand(dependencies) {
|
|
|
125
128
|
sessionId: context.sessionId,
|
|
126
129
|
cwd: request.cwd === void 0 ? context.cwd : request.cwd,
|
|
127
130
|
...request.name ? { name: request.name } : {},
|
|
128
|
-
...request.interactive ? { interactive: true } : {}
|
|
131
|
+
...request.interactive ? { interactive: true } : {},
|
|
132
|
+
...request.preferInteractive ? { preferInteractive: true } : {}
|
|
129
133
|
});
|
|
130
134
|
await context.client.notify({
|
|
131
135
|
body: require_bashResult.formatRunResult(result, {}, void 0, dependencies.settings, dependencies.environment).content[0]?.text ?? "Runner started.",
|
|
132
|
-
level: "info"
|
|
136
|
+
level: result.kind === "failed" ? "error" : "info"
|
|
133
137
|
});
|
|
134
138
|
return;
|
|
135
139
|
}
|
|
@@ -177,4 +181,4 @@ Object.defineProperty(exports, "createHeadlessRunnersCommand", {
|
|
|
177
181
|
}
|
|
178
182
|
});
|
|
179
183
|
|
|
180
|
-
//# sourceMappingURL=headless-
|
|
184
|
+
//# sourceMappingURL=headless-C4Bvl2B-.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-C4Bvl2B-.cjs","names":["BASH_TOOL_NAME","BASH_TOOL_LABEL","getBackgroundThresholdMs","BashParamsSchema","textResult","formatRunResult","parseResultPragma","stopRunnerProcess"],"sources":["../src/constants/headless.ts","../src/constants/runners.ts","../src/constants/runnersCommand.ts","../src/services/runnersCommand/index.ts","../src/services/headless/index.ts"],"sourcesContent":["export const MS_PER_SECOND = 1000;\n","export const COMMAND_NAME = 'runners';\nexport const COMMAND_DESCRIPTION =\n 'Open Runner Space: background processes started by bash. `/runners stop <id> [reason]` stops one, `/runners start [name=x] [cwd=y] [interactive=true] -- <command>` starts one.';\nexport const SERVER_COMMAND_DESCRIPTION = 'Start and stop supervised background runners without a terminal UI.';\n","export const RUNNERS_STOP_VERB = 'stop';\nexport const RUNNERS_START_VERB = 'start';\nexport const RUNNERS_COMMAND_SEPARATOR = '--';\nexport const NAME_KEY = 'name';\nexport const CWD_KEY = 'cwd';\nexport const INTERACTIVE_KEY = 'interactive';\n/** `interactive=prefer`: a terminal when rmux or tmux is available, plain output otherwise. */\nexport const INTERACTIVE_PREFER = 'prefer';\n","import {\n CWD_KEY,\n INTERACTIVE_KEY,\n INTERACTIVE_PREFER,\n NAME_KEY,\n RUNNERS_COMMAND_SEPARATOR,\n RUNNERS_START_VERB,\n RUNNERS_STOP_VERB,\n} from '../../constants/runnersCommand';\n/** The `/runners` verb that stops one runner without opening Runner Space. */\n/** The `/runners` verb that starts one, for a client that cannot call the bash tool. */\n/**\n * Ends the options and begins the command.\n *\n * A command is arbitrary shell: it may hold `=`, and it may hold flags of its\n * own (`pnpm test -- --watch`). Only the first of these is the separator, so\n * everything the reader typed survives intact after it.\n */\n\nexport interface RunnersStartRequest {\n kind: 'start';\n /** The shell command to run; empty when the reader gave none. */\n command: string;\n cwd?: string;\n name?: string;\n interactive: boolean;\n /** `interactive=prefer`: a terminal when one is available, plain output otherwise. */\n preferInteractive?: boolean;\n}\n\nexport type RunnersCommandRequest =\n /** No arguments: open Runner Space. */\n | { kind: 'space' }\n /** `stop <id> [reason]`: stop one runner headlessly; id is empty when it was left out. */\n | { kind: 'stop'; id: string; reason?: string }\n /** `start [key=value ...] -- <command>`: start one headlessly. */\n | RunnersStartRequest;\n\n/** Splits on whitespace but keeps a double-quoted run together, so a path with spaces survives. */\nfunction tokenize(text: string): string[] {\n return text.match(/(?:\"[^\"]*\"|\\S)+/gu) ?? [];\n}\n\nfunction unquote(value: string): string {\n return value.length >= 2 && value.startsWith('\"') && value.endsWith('\"') ? value.slice(1, -1) : value;\n}\n\n/**\n * Parses `start`'s tail: `key=value` pairs up to the separator, then the\n * command verbatim.\n *\n * Without a separator the whole tail is the command, so typing\n * `/runners start pnpm build` does what it looks like. Options are read only\n * when a separator says where they end, which is what keeps a command such as\n * `FOO=bar pnpm test` from being mistaken for one.\n */\nfunction parseStart(tail: string): RunnersStartRequest {\n const tokens = tokenize(tail);\n const separator = tokens.indexOf(RUNNERS_COMMAND_SEPARATOR);\n if (separator === -1) return { kind: 'start', command: tail.trim(), interactive: false };\n\n const request: RunnersStartRequest = {\n kind: 'start',\n // Sliced from the raw text rather than rejoined from tokens: rejoining\n // would collapse the spacing the reader wrote.\n command: tail.slice(tail.indexOf(RUNNERS_COMMAND_SEPARATOR) + RUNNERS_COMMAND_SEPARATOR.length).trim(),\n interactive: false,\n };\n for (const token of tokens.slice(0, separator)) {\n const split = token.indexOf('=');\n if (split <= 0) continue;\n const value = unquote(token.slice(split + 1));\n const key = token.slice(0, split);\n if (key === NAME_KEY && value !== '') request.name = value;\n if (key === CWD_KEY && value !== '') request.cwd = value;\n if (key === INTERACTIVE_KEY) {\n request.interactive = value === 'true';\n if (value === INTERACTIVE_PREFER) request.preferInteractive = true;\n }\n }\n return request;\n}\n\n/**\n * Parses `/runners` arguments. Anything other than a known verb opens Runner\n * Space, which is what the bare command has always done.\n */\nexport function parseRunnersCommand(args: string): RunnersCommandRequest {\n const trimmed = args.trim();\n const [verb = '', id = '', ...rest] = trimmed.split(/\\s+/u).filter(Boolean);\n if (verb === RUNNERS_START_VERB) return parseStart(trimmed.slice(verb.length).trim());\n if (verb !== RUNNERS_STOP_VERB) return { kind: 'space' };\n const reason = rest.join(' ').trim();\n return { kind: 'stop', id, ...(reason ? { reason } : {}) };\n}\n","import type {\n PoHeadlessCommand,\n PoHeadlessExecutionContext,\n PoHeadlessTool,\n PoHeadlessToolResult,\n} from '@agimon-ai/po-core/headless';\n\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME } from '../../constants/bashTool';\nimport { MS_PER_SECOND } from '../../constants/headless';\nimport { COMMAND_NAME, SERVER_COMMAND_DESCRIPTION } from '../../constants/runners';\nimport { type BashParams, BashParamsSchema } from '../../schemas/bashTool';\nimport { formatRunResult, parseResultPragma, textResult } from '../../services/bashResult';\nimport { stopRunnerProcess } from '../../services/reconcile';\nimport { getBackgroundThresholdMs } from '../../services/runnerConfig';\nimport type { RunnerDependencies } from '../../services/runnerDependencies/type';\nimport { parseRunnersCommand } from '../../services/runnersCommand';\nimport { type LogSummarizer } from '../../types/bashResult';\nimport type { IBashRunService } from '../../types/bashRunService';\nimport type { RunnerSettings } from '../../types/runnerSettings';\n\nexport function createHeadlessBashTool(\n bashRunService: IBashRunService,\n summarizeLog?: LogSummarizer,\n settings?: RunnerSettings,\n environment: NodeJS.ProcessEnv = process.env,\n): PoHeadlessTool<typeof BashParamsSchema> {\n return {\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path.',\n promptSnippet: 'Execute shell commands with bounded foreground output and supervised background runners',\n promptGuidelines: [\n `A command still running after ${Math.round(getBackgroundThresholdMs() / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true for commands that should remain active, such as dev servers, watchers, and tails.',\n 'Stop background runners when they are no longer needed.',\n ],\n parameters: BashParamsSchema,\n executionMode: 'serial',\n execute: async (\n _toolCallId: string,\n params: BashParams,\n signal: AbortSignal | undefined,\n onUpdate: ((result: PoHeadlessToolResult) => void) | undefined,\n context: PoHeadlessExecutionContext,\n ) => {\n const { command, timeout, background, interactive, name } = params;\n if (signal?.aborted) throw new Error('Operation aborted');\n if (onUpdate)\n onUpdate(\n textResult(\n `Starting ${interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command'}...`,\n ),\n );\n let onOutput: ((output: string) => void) | undefined;\n if (background !== true && interactive !== true && onUpdate) onOutput = (output) => onUpdate(textResult(output));\n const result = await bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n ...(signal ? { signal } : {}),\n cwd: context.cwd,\n sessionId: context.sessionId,\n });\n if (signal?.aborted) throw new Error('Operation aborted');\n return formatRunResult(result, parseResultPragma(command), summarizeLog, settings, environment);\n },\n };\n}\n\nexport function createHeadlessRunnersCommand(dependencies: RunnerDependencies): PoHeadlessCommand {\n return {\n name: COMMAND_NAME,\n description: SERVER_COMMAND_DESCRIPTION,\n async execute(args: string, context: PoHeadlessExecutionContext) {\n const request = parseRunnersCommand(args);\n if (request.kind === 'space') {\n const active = await dependencies.runnerRegistry.listBySession(context.sessionId);\n await context.client.notify({\n body: `${active.length} active runner${active.length === 1 ? '' : 's'}.`,\n level: 'info',\n });\n return;\n }\n if (request.kind === 'start') {\n if (!request.command) throw new Error('Usage: /runners start [name=x] [cwd=y] [interactive=true] -- <command>');\n const result = await dependencies.bashRunService.run({\n command: request.command,\n background: true,\n sessionId: context.sessionId,\n cwd: request.cwd === undefined ? context.cwd : request.cwd,\n ...(request.name ? { name: request.name } : {}),\n ...(request.interactive ? { interactive: true } : {}),\n ...(request.preferInteractive ? { preferInteractive: true } : {}),\n });\n await context.client.notify({\n body:\n formatRunResult(result, {}, undefined, dependencies.settings, dependencies.environment).content[0]?.text ??\n 'Runner started.',\n level: result.kind === 'failed' ? 'error' : 'info',\n });\n return;\n }\n if (!request.id) throw new Error('Usage: /runners stop <runner-id> [reason]');\n const record = await dependencies.runnerRegistry.get(request.id, context.sessionId);\n if (!record) {\n await context.client.notify({ body: `No active runner ${request.id} in this session.`, level: 'warning' });\n return;\n }\n const stopped = await stopRunnerProcess(record, dependencies.launcher, dependencies.rmuxBackend, {\n registry: dependencies.runnerRegistry,\n intent: {\n reason: 'stopped',\n terminationReason: 'user_stop',\n ...(request.reason ? { stopReason: request.reason } : {}),\n },\n });\n if (stopped) {\n await dependencies.runnerRegistry.complete(\n request.id,\n {\n reason: 'stopped',\n code: null,\n signal: null,\n ...(request.reason ? { stopReason: request.reason } : {}),\n },\n context.sessionId,\n );\n }\n await context.client.notify({\n body: stopped ? `Stopped runner ${request.id}.` : `Could not stop runner ${request.id}.`,\n level: stopped ? 'info' : 'error',\n });\n },\n };\n}\n"],"mappings":";;;;;AAAA,MAAa,gBAAgB;;;ACA7B,MAAa,eAAe;AAG5B,MAAa,6BAA6B;;;;AEoC1C,SAAS,SAAS,MAAwB;CACxC,OAAO,KAAK,MAAM,mBAAmB,KAAK,CAAC;AAC7C;AAEA,SAAS,QAAQ,OAAuB;CACtC,OAAO,MAAM,UAAU,KAAK,MAAM,WAAW,IAAG,KAAK,MAAM,SAAS,IAAG,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI;AAClG;;;;;;;;;;AAWA,SAAS,WAAW,MAAmC;CACrD,MAAM,SAAS,SAAS,IAAI;CAC5B,MAAM,YAAY,OAAO,QAAA,IAAiC;CAC1D,IAAI,cAAc,IAAI,OAAO;EAAE,MAAM;EAAS,SAAS,KAAK,KAAK;EAAG,aAAa;CAAM;CAEvF,MAAM,UAA+B;EACnC,MAAM;EAGN,SAAS,KAAK,MAAM,KAAK,QAAA,IAAiC,IAAA,CAAoC,CAAC,CAAC,KAAK;EACrG,aAAa;CACf;CACA,KAAK,MAAM,SAAS,OAAO,MAAM,GAAG,SAAS,GAAG;EAC9C,MAAM,QAAQ,MAAM,QAAQ,GAAG;EAC/B,IAAI,SAAS,GAAG;EAChB,MAAM,QAAQ,QAAQ,MAAM,MAAM,QAAQ,CAAC,CAAC;EAC5C,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK;EAChC,IAAI,QAAA,UAAoB,UAAU,IAAI,QAAQ,OAAO;EACrD,IAAI,QAAA,SAAmB,UAAU,IAAI,QAAQ,MAAM;EACnD,IAAI,QAAA,eAAyB;GAC3B,QAAQ,cAAc,UAAU;GAChC,IAAI,UAAA,UAA8B,QAAQ,oBAAoB;EAChE;CACF;CACA,OAAO;AACT;;;;;AAMA,SAAgB,oBAAoB,MAAqC;CACvE,MAAM,UAAU,KAAK,KAAK;CAC1B,MAAM,CAAC,OAAO,IAAI,KAAK,IAAI,GAAG,QAAQ,QAAQ,MAAM,MAAM,CAAC,CAAC,OAAO,OAAO;CAC1E,IAAI,SAAA,SAA6B,OAAO,WAAW,QAAQ,MAAM,KAAK,MAAM,CAAC,CAAC,KAAK,CAAC;CACpF,IAAI,SAAA,QAA4B,OAAO,EAAE,MAAM,QAAQ;CACvD,MAAM,SAAS,KAAK,KAAK,GAAG,CAAC,CAAC,KAAK;CACnC,OAAO;EAAE,MAAM;EAAQ;EAAI,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAAG;AAC3D;;;AC1EA,SAAgB,uBACd,gBACA,cACA,UACA,cAAiC,QAAQ,KACA;CACzC,OAAO;EACL,MAAMA,iBAAAA;EACN,OAAOC,iBAAAA;EACP,aACE;EACF,eAAe;EACf,kBAAkB;GAChB,iCAAiC,KAAK,MAAMC,qBAAAA,yBAAyB,IAAI,aAAa,EAAE;GACxF;GACA;EACF;EACA,YAAYC,iBAAAA;EACZ,eAAe;EACf,SAAS,OACP,aACA,QACA,QACA,UACA,YACG;GACH,MAAM,EAAE,SAAS,SAAS,YAAY,aAAa,SAAS;GAC5D,IAAI,QAAQ,SAAS,MAAM,IAAI,MAAM,mBAAmB;GACxD,IAAI,UACF,SACEC,mBAAAA,WACE,YAAY,gBAAgB,OAAO,uBAAuB,eAAe,OAAO,sBAAsB,UAAU,IAClH,CACF;GACF,IAAI;GACJ,IAAI,eAAe,QAAQ,gBAAgB,QAAQ,UAAU,YAAY,WAAW,SAASA,mBAAAA,WAAW,MAAM,CAAC;GAC/G,MAAM,SAAS,MAAM,eAAe,IAAI;IACtC;IACA,WAAW,YAAY,KAAA,IAAY,KAAA,IAAY,UAAU;IACzD;IACA;IACA;IACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;IAC/B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAC3B,KAAK,QAAQ;IACb,WAAW,QAAQ;GACrB,CAAC;GACD,IAAI,QAAQ,SAAS,MAAM,IAAI,MAAM,mBAAmB;GACxD,OAAOC,mBAAAA,gBAAgB,QAAQC,mBAAAA,kBAAkB,OAAO,GAAG,cAAc,UAAU,WAAW;EAChG;CACF;AACF;AAEA,SAAgB,6BAA6B,cAAqD;CAChG,OAAO;EACL,MAAM;EACN,aAAa;EACb,MAAM,QAAQ,MAAc,SAAqC;GAC/D,MAAM,UAAU,oBAAoB,IAAI;GACxC,IAAI,QAAQ,SAAS,SAAS;IAC5B,MAAM,SAAS,MAAM,aAAa,eAAe,cAAc,QAAQ,SAAS;IAChF,MAAM,QAAQ,OAAO,OAAO;KAC1B,MAAM,GAAG,OAAO,OAAO,gBAAgB,OAAO,WAAW,IAAI,KAAK,IAAI;KACtE,OAAO;IACT,CAAC;IACD;GACF;GACA,IAAI,QAAQ,SAAS,SAAS;IAC5B,IAAI,CAAC,QAAQ,SAAS,MAAM,IAAI,MAAM,wEAAwE;IAC9G,MAAM,SAAS,MAAM,aAAa,eAAe,IAAI;KACnD,SAAS,QAAQ;KACjB,YAAY;KACZ,WAAW,QAAQ;KACnB,KAAK,QAAQ,QAAQ,KAAA,IAAY,QAAQ,MAAM,QAAQ;KACvD,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;KAC7C,GAAI,QAAQ,cAAc,EAAE,aAAa,KAAK,IAAI,CAAC;KACnD,GAAI,QAAQ,oBAAoB,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjE,CAAC;IACD,MAAM,QAAQ,OAAO,OAAO;KAC1B,MACED,mBAAAA,gBAAgB,QAAQ,CAAC,GAAG,KAAA,GAAW,aAAa,UAAU,aAAa,WAAW,CAAC,CAAC,QAAQ,EAAE,EAAE,QACpG;KACF,OAAO,OAAO,SAAS,WAAW,UAAU;IAC9C,CAAC;IACD;GACF;GACA,IAAI,CAAC,QAAQ,IAAI,MAAM,IAAI,MAAM,2CAA2C;GAC5E,MAAM,SAAS,MAAM,aAAa,eAAe,IAAI,QAAQ,IAAI,QAAQ,SAAS;GAClF,IAAI,CAAC,QAAQ;IACX,MAAM,QAAQ,OAAO,OAAO;KAAE,MAAM,oBAAoB,QAAQ,GAAG;KAAoB,OAAO;IAAU,CAAC;IACzG;GACF;GACA,MAAM,UAAU,MAAME,kBAAAA,kBAAkB,QAAQ,aAAa,UAAU,aAAa,aAAa;IAC/F,UAAU,aAAa;IACvB,QAAQ;KACN,QAAQ;KACR,mBAAmB;KACnB,GAAI,QAAQ,SAAS,EAAE,YAAY,QAAQ,OAAO,IAAI,CAAC;IACzD;GACF,CAAC;GACD,IAAI,SACF,MAAM,aAAa,eAAe,SAChC,QAAQ,IACR;IACE,QAAQ;IACR,MAAM;IACN,QAAQ;IACR,GAAI,QAAQ,SAAS,EAAE,YAAY,QAAQ,OAAO,IAAI,CAAC;GACzD,GACA,QAAQ,SACV;GAEF,MAAM,QAAQ,OAAO,OAAO;IAC1B,MAAM,UAAU,kBAAkB,QAAQ,GAAG,KAAK,yBAAyB,QAAQ,GAAG;IACtF,OAAO,UAAU,SAAS;GAC5B,CAAC;EACH;CACF;AACF"}
|
|
@@ -46,7 +46,10 @@ function parseStart(tail) {
|
|
|
46
46
|
const key = token.slice(0, split);
|
|
47
47
|
if (key === "name" && value !== "") request.name = value;
|
|
48
48
|
if (key === "cwd" && value !== "") request.cwd = value;
|
|
49
|
-
if (key === "interactive")
|
|
49
|
+
if (key === "interactive") {
|
|
50
|
+
request.interactive = value === "true";
|
|
51
|
+
if (value === "prefer") request.preferInteractive = true;
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
54
|
return request;
|
|
52
55
|
}
|
|
@@ -125,11 +128,12 @@ function createHeadlessRunnersCommand(dependencies) {
|
|
|
125
128
|
sessionId: context.sessionId,
|
|
126
129
|
cwd: request.cwd === void 0 ? context.cwd : request.cwd,
|
|
127
130
|
...request.name ? { name: request.name } : {},
|
|
128
|
-
...request.interactive ? { interactive: true } : {}
|
|
131
|
+
...request.interactive ? { interactive: true } : {},
|
|
132
|
+
...request.preferInteractive ? { preferInteractive: true } : {}
|
|
129
133
|
});
|
|
130
134
|
await context.client.notify({
|
|
131
135
|
body: formatRunResult(result, {}, void 0, dependencies.settings, dependencies.environment).content[0]?.text ?? "Runner started.",
|
|
132
|
-
level: "info"
|
|
136
|
+
level: result.kind === "failed" ? "error" : "info"
|
|
133
137
|
});
|
|
134
138
|
return;
|
|
135
139
|
}
|
|
@@ -166,4 +170,4 @@ function createHeadlessRunnersCommand(dependencies) {
|
|
|
166
170
|
//#endregion
|
|
167
171
|
export { createHeadlessRunnersCommand as n, createHeadlessBashTool as t };
|
|
168
172
|
|
|
169
|
-
//# sourceMappingURL=headless-
|
|
173
|
+
//# sourceMappingURL=headless-DidUBSSf.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headless-DidUBSSf.mjs","names":[],"sources":["../src/constants/headless.ts","../src/constants/runners.ts","../src/constants/runnersCommand.ts","../src/services/runnersCommand/index.ts","../src/services/headless/index.ts"],"sourcesContent":["export const MS_PER_SECOND = 1000;\n","export const COMMAND_NAME = 'runners';\nexport const COMMAND_DESCRIPTION =\n 'Open Runner Space: background processes started by bash. `/runners stop <id> [reason]` stops one, `/runners start [name=x] [cwd=y] [interactive=true] -- <command>` starts one.';\nexport const SERVER_COMMAND_DESCRIPTION = 'Start and stop supervised background runners without a terminal UI.';\n","export const RUNNERS_STOP_VERB = 'stop';\nexport const RUNNERS_START_VERB = 'start';\nexport const RUNNERS_COMMAND_SEPARATOR = '--';\nexport const NAME_KEY = 'name';\nexport const CWD_KEY = 'cwd';\nexport const INTERACTIVE_KEY = 'interactive';\n/** `interactive=prefer`: a terminal when rmux or tmux is available, plain output otherwise. */\nexport const INTERACTIVE_PREFER = 'prefer';\n","import {\n CWD_KEY,\n INTERACTIVE_KEY,\n INTERACTIVE_PREFER,\n NAME_KEY,\n RUNNERS_COMMAND_SEPARATOR,\n RUNNERS_START_VERB,\n RUNNERS_STOP_VERB,\n} from '../../constants/runnersCommand';\n/** The `/runners` verb that stops one runner without opening Runner Space. */\n/** The `/runners` verb that starts one, for a client that cannot call the bash tool. */\n/**\n * Ends the options and begins the command.\n *\n * A command is arbitrary shell: it may hold `=`, and it may hold flags of its\n * own (`pnpm test -- --watch`). Only the first of these is the separator, so\n * everything the reader typed survives intact after it.\n */\n\nexport interface RunnersStartRequest {\n kind: 'start';\n /** The shell command to run; empty when the reader gave none. */\n command: string;\n cwd?: string;\n name?: string;\n interactive: boolean;\n /** `interactive=prefer`: a terminal when one is available, plain output otherwise. */\n preferInteractive?: boolean;\n}\n\nexport type RunnersCommandRequest =\n /** No arguments: open Runner Space. */\n | { kind: 'space' }\n /** `stop <id> [reason]`: stop one runner headlessly; id is empty when it was left out. */\n | { kind: 'stop'; id: string; reason?: string }\n /** `start [key=value ...] -- <command>`: start one headlessly. */\n | RunnersStartRequest;\n\n/** Splits on whitespace but keeps a double-quoted run together, so a path with spaces survives. */\nfunction tokenize(text: string): string[] {\n return text.match(/(?:\"[^\"]*\"|\\S)+/gu) ?? [];\n}\n\nfunction unquote(value: string): string {\n return value.length >= 2 && value.startsWith('\"') && value.endsWith('\"') ? value.slice(1, -1) : value;\n}\n\n/**\n * Parses `start`'s tail: `key=value` pairs up to the separator, then the\n * command verbatim.\n *\n * Without a separator the whole tail is the command, so typing\n * `/runners start pnpm build` does what it looks like. Options are read only\n * when a separator says where they end, which is what keeps a command such as\n * `FOO=bar pnpm test` from being mistaken for one.\n */\nfunction parseStart(tail: string): RunnersStartRequest {\n const tokens = tokenize(tail);\n const separator = tokens.indexOf(RUNNERS_COMMAND_SEPARATOR);\n if (separator === -1) return { kind: 'start', command: tail.trim(), interactive: false };\n\n const request: RunnersStartRequest = {\n kind: 'start',\n // Sliced from the raw text rather than rejoined from tokens: rejoining\n // would collapse the spacing the reader wrote.\n command: tail.slice(tail.indexOf(RUNNERS_COMMAND_SEPARATOR) + RUNNERS_COMMAND_SEPARATOR.length).trim(),\n interactive: false,\n };\n for (const token of tokens.slice(0, separator)) {\n const split = token.indexOf('=');\n if (split <= 0) continue;\n const value = unquote(token.slice(split + 1));\n const key = token.slice(0, split);\n if (key === NAME_KEY && value !== '') request.name = value;\n if (key === CWD_KEY && value !== '') request.cwd = value;\n if (key === INTERACTIVE_KEY) {\n request.interactive = value === 'true';\n if (value === INTERACTIVE_PREFER) request.preferInteractive = true;\n }\n }\n return request;\n}\n\n/**\n * Parses `/runners` arguments. Anything other than a known verb opens Runner\n * Space, which is what the bare command has always done.\n */\nexport function parseRunnersCommand(args: string): RunnersCommandRequest {\n const trimmed = args.trim();\n const [verb = '', id = '', ...rest] = trimmed.split(/\\s+/u).filter(Boolean);\n if (verb === RUNNERS_START_VERB) return parseStart(trimmed.slice(verb.length).trim());\n if (verb !== RUNNERS_STOP_VERB) return { kind: 'space' };\n const reason = rest.join(' ').trim();\n return { kind: 'stop', id, ...(reason ? { reason } : {}) };\n}\n","import type {\n PoHeadlessCommand,\n PoHeadlessExecutionContext,\n PoHeadlessTool,\n PoHeadlessToolResult,\n} from '@agimon-ai/po-core/headless';\n\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME } from '../../constants/bashTool';\nimport { MS_PER_SECOND } from '../../constants/headless';\nimport { COMMAND_NAME, SERVER_COMMAND_DESCRIPTION } from '../../constants/runners';\nimport { type BashParams, BashParamsSchema } from '../../schemas/bashTool';\nimport { formatRunResult, parseResultPragma, textResult } from '../../services/bashResult';\nimport { stopRunnerProcess } from '../../services/reconcile';\nimport { getBackgroundThresholdMs } from '../../services/runnerConfig';\nimport type { RunnerDependencies } from '../../services/runnerDependencies/type';\nimport { parseRunnersCommand } from '../../services/runnersCommand';\nimport { type LogSummarizer } from '../../types/bashResult';\nimport type { IBashRunService } from '../../types/bashRunService';\nimport type { RunnerSettings } from '../../types/runnerSettings';\n\nexport function createHeadlessBashTool(\n bashRunService: IBashRunService,\n summarizeLog?: LogSummarizer,\n settings?: RunnerSettings,\n environment: NodeJS.ProcessEnv = process.env,\n): PoHeadlessTool<typeof BashParamsSchema> {\n return {\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path.',\n promptSnippet: 'Execute shell commands with bounded foreground output and supervised background runners',\n promptGuidelines: [\n `A command still running after ${Math.round(getBackgroundThresholdMs() / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true for commands that should remain active, such as dev servers, watchers, and tails.',\n 'Stop background runners when they are no longer needed.',\n ],\n parameters: BashParamsSchema,\n executionMode: 'serial',\n execute: async (\n _toolCallId: string,\n params: BashParams,\n signal: AbortSignal | undefined,\n onUpdate: ((result: PoHeadlessToolResult) => void) | undefined,\n context: PoHeadlessExecutionContext,\n ) => {\n const { command, timeout, background, interactive, name } = params;\n if (signal?.aborted) throw new Error('Operation aborted');\n if (onUpdate)\n onUpdate(\n textResult(\n `Starting ${interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command'}...`,\n ),\n );\n let onOutput: ((output: string) => void) | undefined;\n if (background !== true && interactive !== true && onUpdate) onOutput = (output) => onUpdate(textResult(output));\n const result = await bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n ...(signal ? { signal } : {}),\n cwd: context.cwd,\n sessionId: context.sessionId,\n });\n if (signal?.aborted) throw new Error('Operation aborted');\n return formatRunResult(result, parseResultPragma(command), summarizeLog, settings, environment);\n },\n };\n}\n\nexport function createHeadlessRunnersCommand(dependencies: RunnerDependencies): PoHeadlessCommand {\n return {\n name: COMMAND_NAME,\n description: SERVER_COMMAND_DESCRIPTION,\n async execute(args: string, context: PoHeadlessExecutionContext) {\n const request = parseRunnersCommand(args);\n if (request.kind === 'space') {\n const active = await dependencies.runnerRegistry.listBySession(context.sessionId);\n await context.client.notify({\n body: `${active.length} active runner${active.length === 1 ? '' : 's'}.`,\n level: 'info',\n });\n return;\n }\n if (request.kind === 'start') {\n if (!request.command) throw new Error('Usage: /runners start [name=x] [cwd=y] [interactive=true] -- <command>');\n const result = await dependencies.bashRunService.run({\n command: request.command,\n background: true,\n sessionId: context.sessionId,\n cwd: request.cwd === undefined ? context.cwd : request.cwd,\n ...(request.name ? { name: request.name } : {}),\n ...(request.interactive ? { interactive: true } : {}),\n ...(request.preferInteractive ? { preferInteractive: true } : {}),\n });\n await context.client.notify({\n body:\n formatRunResult(result, {}, undefined, dependencies.settings, dependencies.environment).content[0]?.text ??\n 'Runner started.',\n level: result.kind === 'failed' ? 'error' : 'info',\n });\n return;\n }\n if (!request.id) throw new Error('Usage: /runners stop <runner-id> [reason]');\n const record = await dependencies.runnerRegistry.get(request.id, context.sessionId);\n if (!record) {\n await context.client.notify({ body: `No active runner ${request.id} in this session.`, level: 'warning' });\n return;\n }\n const stopped = await stopRunnerProcess(record, dependencies.launcher, dependencies.rmuxBackend, {\n registry: dependencies.runnerRegistry,\n intent: {\n reason: 'stopped',\n terminationReason: 'user_stop',\n ...(request.reason ? { stopReason: request.reason } : {}),\n },\n });\n if (stopped) {\n await dependencies.runnerRegistry.complete(\n request.id,\n {\n reason: 'stopped',\n code: null,\n signal: null,\n ...(request.reason ? { stopReason: request.reason } : {}),\n },\n context.sessionId,\n );\n }\n await context.client.notify({\n body: stopped ? `Stopped runner ${request.id}.` : `Could not stop runner ${request.id}.`,\n level: stopped ? 'info' : 'error',\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as RunnerDependencies } from "./type-
|
|
1
|
+
import { t as RunnerDependencies } from "./type-BQ2shEB5.mjs";
|
|
2
2
|
import { PoHostExecutionBudget } from "@agimon-ai/po-core/packageApi";
|
|
3
3
|
//#region src/services/runnerDependencies/index.d.ts
|
|
4
4
|
/**
|
|
@@ -19,4 +19,4 @@ declare function createRunnerDependencies(overrides: Partial<RunnerDependencies>
|
|
|
19
19
|
}): RunnerDependencies;
|
|
20
20
|
//#endregion
|
|
21
21
|
export { createRunnerDependencies as t };
|
|
22
|
-
//# sourceMappingURL=index
|
|
22
|
+
//# sourceMappingURL=index-CXbcmf-G.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index
|
|
1
|
+
{"version":3,"file":"index-CXbcmf-G.d.mts","names":[],"sources":["../src/services/runnerDependencies/index.ts"],"mappings":";;;;;;;;;;;;;;iBA4CgB,yBACd,WAAW,QAAQ;EACjB,aAAa,SAAS;EACtB;EACA,kBAAkB;IAEnB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { a as IBashRunService } from "./bashRunService-
|
|
1
|
+
import { a as IBashRunService } from "./bashRunService-BL4JIUi2.mjs";
|
|
2
2
|
import { n as BashParamsSchema } from "./bashTool-B1EwZLo_.mjs";
|
|
3
3
|
import { r as LogSummarizer } from "./bashResult-DcrRaBLv.mjs";
|
|
4
4
|
import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
|
|
5
|
-
import { t as RunnerDependencies } from "./type-
|
|
5
|
+
import { t as RunnerDependencies } from "./type-BQ2shEB5.mjs";
|
|
6
6
|
import { PoHeadlessCommand, PoHeadlessTool } from "@agimon-ai/po-core/headless";
|
|
7
7
|
//#region src/services/headless/index.d.ts
|
|
8
8
|
declare function createHeadlessBashTool(bashRunService: IBashRunService, summarizeLog?: LogSummarizer, settings?: RunnerSettings, environment?: NodeJS.ProcessEnv): PoHeadlessTool<typeof BashParamsSchema>;
|
|
9
9
|
declare function createHeadlessRunnersCommand(dependencies: RunnerDependencies): PoHeadlessCommand;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { createHeadlessRunnersCommand as n, createHeadlessBashTool as t };
|
|
12
|
-
//# sourceMappingURL=index-
|
|
12
|
+
//# sourceMappingURL=index-DJkjYgir.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index-
|
|
1
|
+
{"version":3,"file":"index-DJkjYgir.d.mts","names":[],"sources":["../src/services/headless/index.ts"],"mappings":";;;;;;;iBAoBgB,uBACd,gBAAgB,iBAChB,eAAe,eACf,WAAW,gBACX,cAAa,OAAO,aACnB,sBAAsB;iBAgDT,6BAA6B,cAAc,qBAAqB"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_runnerConfig = require("./runnerConfig-BoLMinlx.cjs");
|
|
3
|
-
const require_headless = require("./headless-
|
|
3
|
+
const require_headless = require("./headless-C4Bvl2B-.cjs");
|
|
4
4
|
const require_rmuxBackend = require("./rmuxBackend-Dh0CYVAL.cjs");
|
|
5
5
|
const require_rtkProcessor = require("./rtkProcessor-DSGbM-Cm.cjs");
|
|
6
|
-
const require_runnerDependencies = require("./runnerDependencies-
|
|
6
|
+
const require_runnerDependencies = require("./runnerDependencies-vkpJfxZZ.cjs");
|
|
7
7
|
exports.DEFAULT_BG_THRESHOLD_MS = require_runnerConfig.DEFAULT_BG_THRESHOLD_MS;
|
|
8
8
|
exports.DEFAULT_LOG_MAX_BYTES = require_runnerConfig.DEFAULT_LOG_MAX_BYTES;
|
|
9
9
|
exports.DEFAULT_LOG_TTL_MS = require_runnerConfig.DEFAULT_LOG_TTL_MS;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as RmuxLaunchRequest, t as IRmuxBackend } from "./rmuxBackend-CaEWooWn.mjs";
|
|
2
|
-
import { n as createHeadlessRunnersCommand, t as createHeadlessBashTool } from "./index-
|
|
2
|
+
import { n as createHeadlessRunnersCommand, t as createHeadlessBashTool } from "./index-DJkjYgir.mjs";
|
|
3
3
|
import { A as getLogTtlMs, C as getBackgroundThresholdMs, M as getResultMaxBytes, c as DEFAULT_LOG_TTL_MS, k as getLogMaxBytes, n as DEFAULT_BG_THRESHOLD_MS, s as DEFAULT_LOG_MAX_BYTES, u as DEFAULT_RESULT_MAX_BYTES } from "./runnerConfig-DuWL6TJx.mjs";
|
|
4
4
|
import { t as RmuxBackend } from "./index-C-IC35d9.mjs";
|
|
5
5
|
import { r as rtkPackageForTarget } from "./index-BCCF1sGD.mjs";
|
|
6
|
-
import { t as createRunnerDependencies } from "./index
|
|
6
|
+
import { t as createRunnerDependencies } from "./index-CXbcmf-G.mjs";
|
|
7
7
|
export { DEFAULT_BG_THRESHOLD_MS, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, type IRmuxBackend, RmuxBackend, type RmuxLaunchRequest, createHeadlessBashTool, createHeadlessRunnersCommand, createRunnerDependencies, getBackgroundThresholdMs, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, rtkPackageForTarget };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { D as DEFAULT_RESULT_MAX_BYTES, T as DEFAULT_LOG_TTL_MS, c as getLogTtlMs, s as getLogMaxBytes, t as getBackgroundThresholdMs, u as getResultMaxBytes, w as DEFAULT_LOG_MAX_BYTES, y as DEFAULT_BG_THRESHOLD_MS } from "./runnerConfig-XXMq4VQA.mjs";
|
|
2
|
-
import { n as createHeadlessRunnersCommand, t as createHeadlessBashTool } from "./headless-
|
|
2
|
+
import { n as createHeadlessRunnersCommand, t as createHeadlessBashTool } from "./headless-DidUBSSf.mjs";
|
|
3
3
|
import { t as RmuxBackend } from "./rmuxBackend-rjrVTG6K.mjs";
|
|
4
4
|
import { r as rtkPackageForTarget } from "./rtkProcessor-Iw9gP5Xp.mjs";
|
|
5
|
-
import { t as createRunnerDependencies } from "./runnerDependencies-
|
|
5
|
+
import { t as createRunnerDependencies } from "./runnerDependencies-CamKwphq.mjs";
|
|
6
6
|
export { DEFAULT_BG_THRESHOLD_MS, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, RmuxBackend, createHeadlessBashTool, createHeadlessRunnersCommand, createRunnerDependencies, getBackgroundThresholdMs, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, rtkPackageForTarget };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as BashRunResult } from "./bashRunService-
|
|
1
|
+
import { n as BashRunResult } from "./bashRunService-BL4JIUi2.mjs";
|
|
2
2
|
import { i as RunnerRecord } from "./runnerRegistry-V-Ocaf4N.mjs";
|
|
3
3
|
import { a as ResultBudget, c as TruncatedOutput, i as LogSummary, n as Excerpt, o as SalvagedError, r as LogSummarizer, s as ToolResult, t as ErrorLineScanner } from "./bashResult-DcrRaBLv.mjs";
|
|
4
4
|
import { t as RunnerSettings } from "./runnerSettings-DiV1lvzx.mjs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as BashRunService } from "./bashRunService-
|
|
1
|
+
import { t as BashRunService } from "./bashRunService-DbYsj1zc.mjs";
|
|
2
2
|
import { g as noninteractiveEnvironment, s as getLogMaxBytes, u as getResultMaxBytes } from "./runnerConfig-XXMq4VQA.mjs";
|
|
3
3
|
import { t as LogReader } from "./logReader-mq9uVurh.mjs";
|
|
4
4
|
import { t as SystemClock } from "./clock-Cv2pddgo.mjs";
|
|
@@ -644,4 +644,4 @@ function createRunnerDependencies(overrides) {
|
|
|
644
644
|
//#endregion
|
|
645
645
|
export { TmuxBackend as n, PtyBackendChain as r, createRunnerDependencies as t };
|
|
646
646
|
|
|
647
|
-
//# sourceMappingURL=runnerDependencies-
|
|
647
|
+
//# sourceMappingURL=runnerDependencies-CamKwphq.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runnerDependencies-7h_cxOva.mjs","names":[],"sources":["../src/constants/tmuxBackend.ts","../src/services/ptyBackendChain/index.ts","../src/services/tmuxBackend/TmuxClient.ts","../src/services/tmuxBackend/index.ts","../src/services/runnerDependencies/index.ts"],"sourcesContent":["export const POLL_MS = 100;\nexport const LOG_DRAIN_TIMEOUT_MS = 2_000;\nexport const LOG_DRAIN_POLL_MS = 25;\nexport const PANE_STATE_FORMAT = '#{pane_dead}:#{pane_dead_status}:#{session_name}';\nexport const STOP_GRACE_MS = 3_000;\nexport const SESSION_PREFIX = 'po-tmux-';\nexport const OWNED_TARGET_PATTERN = /^po-tmux-[A-Za-z0-9_-]+$/;\nexport const TMUX_TARGET_PREFIX = SESSION_PREFIX;\nexport const SOCKET_HASH_LENGTH = 12;\nexport const SOCKET_PREFIX = 'po-tmux-';\nexport const NON_INTERACTIVE_ENV = { NO_COLOR: '1', CI: '1' };\n","import { TMUX_TARGET_PREFIX } from '../../constants/tmuxBackend';\nimport type { RunHandle } from '../../types/launcher';\nimport type { PtyRun } from '../../types/ptyHost';\nimport type { IRmuxBackend, RmuxLaunchRequest } from '../../types/rmuxBackend';\nimport type { ExitResult } from '../../types/spawner';\n\n/**\n * Presents the available PTY backends as one, preferring RMUX.\n *\n * A launch takes the first backend that accepts it, so a host without a\n * compatible RMUX binary still gets panes rather than falling through to the\n * plain subprocess launcher. Every later call routes on the target's prefix\n * instead of asking each backend in turn: a backend cannot tell \"this session\n * is gone\" from \"this session was never mine\", and guessing would let one\n * report success for the other's run.\n */\nexport class PtyBackendChain implements IRmuxBackend {\n constructor(\n private readonly rmux: IRmuxBackend,\n private readonly tmux: IRmuxBackend,\n ) {}\n\n async launch(request: RmuxLaunchRequest): Promise<RunHandle | undefined> {\n return (await this.rmux.launch(request)) ?? (await this.tmux.launch(request));\n }\n\n watch(id: string, target: string, sessionId?: string): Promise<ExitResult | undefined> {\n return this.owner(target).watch(id, target, sessionId);\n }\n\n stop(target: string, expectedPid: number): Promise<boolean> {\n return this.owner(target).stop(target, expectedPid);\n }\n\n input(target: string, text: string): Promise<boolean> {\n return this.owner(target).input(target, text);\n }\n\n capture(target: string): Promise<string | undefined> {\n return this.owner(target).capture(target);\n }\n\n /** Both backends persist terminal evidence at the same path, so either answers. */\n readOutcome(id: string, sessionId: string): ExitResult | undefined {\n return this.rmux.readOutcome(id, sessionId) ?? this.tmux.readOutcome(id, sessionId);\n }\n\n get(name: string): PtyRun | undefined {\n return this.rmux.get(name) ?? this.tmux.get(name);\n }\n\n private owner(target: string): IRmuxBackend {\n return target.startsWith(TMUX_TARGET_PREFIX) ? this.tmux : this.rmux;\n }\n}\n","import { execFile } from 'node:child_process';\n\nimport type { ITmuxClient, TmuxResult } from '../../types/tmuxClient';\n\nconst TMUX_BINARY = 'tmux';\nconst SOCKET_OPTION = '-L';\n/** Long enough for a loaded server, short enough that a hung tmux is not fatal. */\nconst COMMAND_TIMEOUT_MS = 10_000;\nconst MAX_OUTPUT_BYTES = 4 * 1024 * 1024;\n\nexport class TmuxClient implements ITmuxClient {\n constructor(\n private readonly socket: string,\n private readonly binary = TMUX_BINARY,\n ) {}\n\n run(args: readonly string[]): Promise<TmuxResult> {\n return new Promise((resolve, reject) => {\n execFile(\n this.binary,\n [SOCKET_OPTION, this.socket, ...args],\n { timeout: COMMAND_TIMEOUT_MS, maxBuffer: MAX_OUTPUT_BYTES, encoding: 'utf8' },\n (error, stdout, stderr) => {\n // A non-zero tmux exit is an answer, not a fault: `has-session`\n // reports absence that way. Only a missing or hung binary rejects.\n const code = (error as (Error & { code?: number | string }) | null)?.code;\n if (error && typeof code !== 'number') {\n reject(error);\n return;\n }\n resolve({ returnCode: typeof code === 'number' ? code : 0, stdout, stderr });\n },\n );\n });\n }\n\n async format(target: string, format: string): Promise<string | undefined> {\n const result = await this.run(['display-message', '-p', '-t', target, '-F', format]).catch(() => undefined);\n if (!result || result.returnCode !== 0) return undefined;\n return result.stdout.replace(/\\n$/, '');\n }\n\n async sessionMissing(target: string): Promise<boolean> {\n const result = await this.run(['has-session', '-t', target]).catch(() => undefined);\n return !result || result.returnCode !== 0;\n }\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {\n LOG_DRAIN_POLL_MS,\n LOG_DRAIN_TIMEOUT_MS,\n NON_INTERACTIVE_ENV,\n OWNED_TARGET_PATTERN,\n PANE_STATE_FORMAT,\n POLL_MS,\n SESSION_PREFIX,\n SOCKET_HASH_LENGTH,\n SOCKET_PREFIX,\n STOP_GRACE_MS,\n} from '../../constants/tmuxBackend';\nimport type { RunHandle } from '../../types/launcher';\nimport type { PtyRun } from '../../types/ptyHost';\nimport type { IRmuxBackend, RmuxLaunchRequest } from '../../types/rmuxBackend';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport type { ExitResult } from '../../types/spawner';\nimport type { ITmuxClient } from '../../types/tmuxClient';\nimport { getLogMaxBytes, getResultMaxBytes, noninteractiveEnvironment } from '../runnerConfig';\nimport type { IRunnerPaths } from '../runnerPaths/type';\nimport {\n type CommandSpec,\n type SupervisorPaths,\n cleanupSupervisorFiles,\n NO_TERMINAL_INPUT_ENV,\n readExitMetadata,\n runtimeEntry,\n shellJoin,\n supervisorPaths,\n writeCommandSpec,\n} from '../runnerSupervisor';\nimport { TmuxClient } from './TmuxClient';\n\n/** Pane liveness, its exit status, and whether the session still exists, in one read. */\n/** Distinct from the RMUX prefix so a target names the backend that owns it. */\n\n/**\n * Supervises runs in tmux panes, for hosts with no compatible RMUX binary.\n *\n * The pane runs the same runnerHost supervisor as the RMUX backend, so exit\n * metadata, log rotation, and lifeline handling are shared rather than\n * reimplemented: only the multiplexer differs. Kept beside the RMUX backend\n * rather than folded into it because that path has no unit coverage to\n * refactor against.\n */\nexport class TmuxBackend implements IRmuxBackend {\n private clientPromise: Promise<ITmuxClient | undefined> | undefined;\n private readonly runs = new Map<string, PtyRun>();\n private readonly completions = new Map<string, Promise<ExitResult>>();\n\n constructor(\n private readonly paths: IRunnerPaths,\n private readonly createClient: (socket: string) => ITmuxClient = (socket) => new TmuxClient(socket),\n private readonly env: Readonly<Record<string, string | undefined>> = process.env,\n private readonly settings?: RunnerSettings,\n ) {}\n\n async launch(request: RmuxLaunchRequest): Promise<RunHandle | undefined> {\n const tmux = await this.client();\n if (!tmux) return undefined;\n\n this.paths.ensureDirectories();\n const target = `${SESSION_PREFIX}${request.id}`;\n const logPath = this.paths.logPathFor(request.id);\n const aux = this.auxPaths(request.id, request.sessionId);\n let created = false;\n let released = false;\n\n try {\n this.prepareFiles(request, logPath, aux);\n // One quoted command rather than an argv: tmux takes shell-command as a\n // single word, and quoting here is what keeps a path with spaces intact.\n const supervisor = shellJoin([process.execPath, runtimeEntry('runnerHost'), aux.spec, aux.gate, aux.exit]);\n await this.checked(tmux, ['new-session', '-d', '-s', target, '-c', request.cwd, supervisor]);\n created = true;\n // Set before the gate opens, so it is in force by the time the command\n // can exit. A pane that vanishes on exit takes the log sink down with it\n // before Node has finished starting, losing the output of fast commands,\n // and leaves #{pane_dead} with nothing to report.\n await this.checked(tmux, ['set-option', '-t', target, 'remain-on-exit', 'on']);\n await this.checked(tmux, ['pipe-pane', '-t', target, this.logPipeCommand(logPath, aux.logDone, request)]);\n\n const pid = await panePid(tmux, target);\n fs.writeFileSync(aux.gate, '', { mode: 0o600 });\n released = true;\n\n let buffering = true;\n const completion = this.monitor(tmux, target, aux);\n this.trackCompletion(target, completion);\n const handle: RunHandle = {\n id: request.id,\n name: request.name,\n pid,\n logPath,\n backend: 'tmux',\n backendTarget: target,\n output: () => (buffering ? readTail(logPath, getResultMaxBytes(this.env, this.settings) * 2) : ''),\n completion: () => completion,\n detach: () => {\n buffering = false;\n },\n stop: () => this.stop(target, pid),\n };\n\n if (request.interactive) this.runs.set(request.name, this.interactiveRun(handle, tmux, target, completion));\n void completion\n .finally(() => this.runs.delete(request.name))\n .catch((error: unknown) => process.emitWarning(`tmux completion failed for ${target}: ${errorMessage(error)}`));\n return handle;\n } catch (error) {\n if (released) throw error;\n if (created) await killSession(tmux, target);\n cleanupSupervisorFiles(aux);\n process.emitWarning(\n request.interactive\n ? `tmux launch unavailable for interactive runner: ${errorMessage(error)}`\n : `tmux launch unavailable, using supervised subprocess: ${errorMessage(error)}`,\n );\n return undefined;\n }\n }\n\n async stop(target: string, expectedPid: number): Promise<boolean> {\n if (!OWNED_TARGET_PATTERN.test(target) || !Number.isInteger(expectedPid) || expectedPid <= 0) return false;\n\n const tmux = await this.client();\n if (!tmux) return false;\n try {\n if (await tmux.sessionMissing(target)) return true;\n\n const pid = await panePid(tmux, target);\n if (pid !== expectedPid) return false;\n const signalled = signalPane(pid, target);\n if (signalled === 'gone') return true;\n if (signalled === 'failed') return false;\n\n if (await waitForPaneStop(tmux, target, STOP_GRACE_MS)) return true;\n if (await tmux.sessionMissing(target)) return true;\n\n // Revalidate after the grace period so a replacement pane is never closed.\n const currentPid = await panePid(tmux, target).catch(() => undefined);\n if (currentPid !== expectedPid) return false;\n\n return killSession(tmux, target);\n } catch (error) {\n process.emitWarning(`Could not stop tmux target ${target}: ${errorMessage(error)}`);\n return false;\n }\n }\n\n async watch(id: string, target: string, sessionId?: string): Promise<ExitResult | undefined> {\n const tmux = await this.client();\n if (!tmux) return undefined;\n if (await tmux.sessionMissing(target)) return undefined;\n const completion = this.monitor(tmux, target, this.auxPaths(id, sessionId));\n this.trackCompletion(target, completion);\n return completion;\n }\n\n async input(target: string, text: string): Promise<boolean> {\n const tmux = await this.client();\n if (!tmux) return false;\n const result = await tmux.run(['send-keys', '-t', target, '-l', text]).catch((error: unknown) => {\n process.emitWarning(`Could not send input to tmux target ${target}: ${errorMessage(error)}`);\n return undefined;\n });\n return result?.returnCode === 0;\n }\n\n async capture(target: string): Promise<string | undefined> {\n const tmux = await this.client();\n if (!tmux) return undefined;\n const result = await tmux.run(['capture-pane', '-p', '-t', target]).catch((error: unknown) => {\n process.emitWarning(`Could not capture tmux target ${target}: ${errorMessage(error)}`);\n return undefined;\n });\n return result?.returnCode === 0 ? result.stdout : undefined;\n }\n\n get(name: string): PtyRun | undefined {\n return this.runs.get(name);\n }\n\n readOutcome(id: string, sessionId: string): ExitResult | undefined {\n return readExitMetadata(this.auxPaths(id, sessionId).exit);\n }\n\n private trackCompletion(target: string, completion: Promise<ExitResult>): void {\n this.completions.set(target, completion);\n void completion\n .finally(() => this.completions.delete(target))\n .catch((error: unknown) => process.emitWarning(`tmux monitor failed for ${target}: ${errorMessage(error)}`));\n }\n\n private client(): Promise<ITmuxClient | undefined> {\n this.clientPromise ??= this.resolveClient();\n return this.clientPromise;\n }\n\n private async resolveClient(): Promise<ITmuxClient | undefined> {\n const client = this.createClient(socketName(this.paths.repositoryPath()));\n try {\n const version = await client.run(['-V']);\n if (version.returnCode !== 0) throw new Error(version.stderr.trim() || 'tmux reported no version');\n return client;\n } catch (error) {\n process.emitWarning(`tmux is unavailable: ${errorMessage(error)}`);\n return undefined;\n }\n }\n\n private async checked(tmux: ITmuxClient, args: readonly string[]): Promise<void> {\n const result = await tmux.run(args);\n if (result.returnCode !== 0) {\n throw new Error(`tmux ${args[0] ?? ''} failed: ${result.stderr.trim() || `exit ${result.returnCode}`}`);\n }\n }\n\n private prepareFiles(request: RmuxLaunchRequest, logPath: string, aux: SupervisorPaths): void {\n cleanupSupervisorFiles(aux);\n fs.writeFileSync(logPath, '', { mode: 0o600 });\n const env = environment(request.sessionId, request.interactive, this.env);\n const spec: CommandSpec = { command: request.command, cwd: request.cwd, env };\n writeCommandSpec(aux.spec, spec);\n }\n\n private auxPaths(id: string, sessionId?: string): SupervisorPaths {\n return supervisorPaths(this.paths.stateDirectory(sessionId), id);\n }\n\n /**\n * The sink the pane pipes into.\n *\n * An interactive run also asks for a raw copy: the scrubbed log it writes\n * beside it has had cursor movement taken out, which is what a terminal\n * needs most. Only interactive runs pay for it, because only they can be\n * attached to.\n */\n private logPipeCommand(logPath: string, donePath: string, request: RmuxLaunchRequest): string {\n const id = path.basename(logPath, '.log');\n return shellJoin([\n process.execPath,\n runtimeEntry('logSink'),\n logPath,\n this.paths.rotatedLogPathFor(id),\n String(getLogMaxBytes(this.env)),\n donePath,\n ...(request.interactive ? [this.paths.rawLogPathFor(id)] : []),\n ]);\n }\n\n private async monitor(tmux: ITmuxClient, target: string, aux: SupervisorPaths): Promise<ExitResult> {\n try {\n const paneCode = await waitForRunEnd(tmux, target, aux.exit);\n await waitForLogDrain(tmux, target, aux.logDone);\n return readExitMetadata(aux.exit) ?? { code: paneCode, signal: null };\n } finally {\n if (!(await tmux.sessionMissing(target).catch(() => false))) await killSession(tmux, target);\n cleanupSupervisorFiles(aux);\n }\n }\n\n private interactiveRun(\n handle: RunHandle,\n tmux: ITmuxClient,\n target: string,\n completion: Promise<ExitResult>,\n ): PtyRun {\n let screen = '';\n let active = true;\n const handlers = new Set<(data: string) => void>();\n const refresh = async (): Promise<void> => {\n while (active) {\n const captured = await tmux.run(['capture-pane', '-p', '-t', target]).catch((error: unknown) => {\n process.emitWarning(`Could not capture tmux screen for ${handle.name}: ${errorMessage(error)}`);\n return undefined;\n });\n const next = captured?.returnCode === 0 ? captured.stdout : screen;\n if (next !== screen) {\n screen = next;\n for (const handler of handlers) handler(next);\n }\n await delay(POLL_MS);\n }\n };\n void refresh();\n void completion\n .finally(() => {\n active = false;\n })\n .catch((error: unknown) =>\n process.emitWarning(`tmux interactive completion failed for ${handle.name}: ${errorMessage(error)}`),\n );\n return {\n ...handle,\n write: (text) => {\n void tmux\n .run(['send-keys', '-t', target, '-l', text])\n .catch((error: unknown) => process.emitWarning(errorMessage(error)));\n },\n screen: () => screen,\n onData: (handler) => {\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n resize: (cols, rows) => {\n void tmux\n .run(['resize-window', '-t', target, '-x', String(cols), '-y', String(rows)])\n .catch((error: unknown) => process.emitWarning(errorMessage(error)));\n },\n };\n }\n}\n\nfunction socketName(repositoryPath: string): string {\n const hash = createHash('sha256').update(repositoryPath).digest('hex').slice(0, SOCKET_HASH_LENGTH);\n return `${SOCKET_PREFIX}${hash}`;\n}\n\nfunction environment(\n sessionId: string,\n interactive: boolean,\n env: Readonly<Record<string, string | undefined>>,\n): Record<string, string> {\n const values: NodeJS.ProcessEnv = {\n ...env,\n ...(interactive ? {} : { ...NON_INTERACTIVE_ENV, ...noninteractiveEnvironment(env) }),\n ...NO_TERMINAL_INPUT_ENV,\n PI_SESSION_ID: sessionId,\n };\n if (!interactive) delete values['FORCE_COLOR'];\n return Object.fromEntries(\n Object.entries(values).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n}\n\nasync function killSession(tmux: ITmuxClient, target: string): Promise<boolean> {\n const result = await tmux.run(['kill-session', '-t', target]).catch((error: unknown) => {\n process.emitWarning(`Could not close tmux target ${target}: ${errorMessage(error)}`);\n return undefined;\n });\n return result?.returnCode === 0;\n}\n\nasync function panePid(tmux: ITmuxClient, target: string): Promise<number> {\n const message = await tmux.format(target, '#{pane_pid}');\n const pid = Number(message);\n if (!Number.isInteger(pid) || pid <= 0) throw new Error(`tmux did not report a pane pid for ${target}`);\n return pid;\n}\n\n/**\n * Waits for the run to end, preferring the supervisor's own record of it.\n *\n * The sidecar is written before the pane can end and outlives the server the\n * pane's exit takes down, so asking tmux is the fallback for a supervisor that\n * died without recording anything.\n */\nasync function waitForRunEnd(tmux: ITmuxClient, target: string, exitPath: string): Promise<number | null> {\n for (;;) {\n if (fs.existsSync(exitPath)) return null;\n const state = await readPaneExit(tmux, target);\n if (state.exited) return state.code;\n await delay(POLL_MS);\n }\n}\n\nasync function waitForLogDrain(tmux: ITmuxClient, target: string, donePath: string): Promise<void> {\n const deadline = Date.now() + LOG_DRAIN_TIMEOUT_MS;\n while (Date.now() < deadline) {\n if (fs.existsSync(donePath)) return;\n if (await tmux.sessionMissing(target)) return;\n await delay(LOG_DRAIN_POLL_MS);\n }\n}\n\nasync function waitForPaneStop(tmux: ITmuxClient, target: string, timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if ((await readPaneExit(tmux, target)).exited) return true;\n await delay(POLL_MS);\n }\n return false;\n}\n\n/** One formatted read answers both questions this poll asks. */\nasync function readPaneExit(tmux: ITmuxClient, target: string): Promise<{ exited: boolean; code: number | null }> {\n const message = await tmux.format(target, PANE_STATE_FORMAT);\n // An unreachable server is the ordinary end of the last run: the pane exiting\n // ends its session, and the last session ending stops the server.\n if (message === undefined) return { exited: true, code: null };\n const [dead, status, ...rest] = message.trim().split(':');\n if (rest.join(':') === '') return { exited: true, code: null };\n if (dead === '1' || dead === 'true') {\n const code = Number(status);\n return { exited: true, code: Number.isInteger(code) ? code : null };\n }\n return { exited: false, code: null };\n}\n\nfunction signalPane(pid: number, target: string): 'signalled' | 'gone' | 'failed' {\n try {\n process.kill(pid, 'SIGTERM');\n return 'signalled';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ESRCH') return 'gone';\n process.emitWarning(`Could not signal tmux target ${target}: ${errorMessage(error)}`);\n return 'failed';\n }\n}\n\nfunction readTail(target: string, maxBytes: number): string {\n let handle: number | undefined;\n try {\n const size = fs.statSync(target).size;\n const bytes = Math.min(size, maxBytes);\n const buffer = Buffer.alloc(bytes);\n handle = fs.openSync(target, 'r');\n fs.readSync(handle, buffer, 0, bytes, size - bytes);\n return buffer.toString('utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n process.emitWarning(`Could not read tmux log ${target}: ${errorMessage(error)}`);\n }\n return '';\n } finally {\n if (handle !== undefined) fs.closeSync(handle);\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import { sharedExecutionBudget, type PoHostExecutionBudget } from '@agimon-ai/po-core/packageApi';\n\nimport { BashRunService } from '../bashRunService';\nimport { SystemClock } from '../clock';\nimport { Launcher } from '../launcher';\nimport { NodeLifeline } from '../lifeline';\nimport { LogFile } from '../logFile';\nimport { LogReader } from '../logReader';\nimport { NodeProcessControl } from '../processControl';\nimport { PtyBackendChain } from '../ptyBackendChain';\nimport { PtyHost } from '../ptyHost';\nimport { NodePtySpawner } from '../ptySpawner';\nimport { RmuxBackend } from '../rmuxBackend';\nimport { RtkProcessor } from '../rtkProcessor';\nimport { RunnerNamer } from '../runnerNamer';\nimport { RunnerPaths } from '../runnerPaths';\nimport { RunnerRegistry, createDefaultProcessRegistry } from '../runnerRegistry';\nimport { NodeSpawner } from '../spawner';\nimport { TmuxBackend } from '../tmuxBackend';\nimport type { RunnerDependencies } from './type';\n/** Build once on first access, then hand back the same instance. */\nfunction memoize<T>(build: () => T): () => T {\n let value: T | undefined;\n let built = false;\n return () => {\n if (!built) {\n value = build();\n built = true;\n }\n return value as T;\n };\n}\n\n/**\n * Builds the extension's service graph.\n *\n * A factory rather than a module-level singleton: the extension owns one graph\n * per session, and tests get a fresh one they can substitute ports on through\n * `overrides` without leaking state between cases.\n *\n * Every slot resolves lazily and memoizes, which keeps the previous container's\n * behaviour: nothing is constructed until it is asked for, so opening the SQLite\n * process registry stays deferred until something actually needs a runner.\n */\nexport function createRunnerDependencies(\n overrides: Partial<RunnerDependencies> & {\n environment: Readonly<Record<string, string | undefined>>;\n cwd?: string;\n executionBudget?: PoHostExecutionBudget;\n },\n): RunnerDependencies {\n const settings =\n overrides.settings === undefined\n ? undefined\n : Object.freeze({\n ...overrides.settings,\n ...(overrides.settings?.errorPatterns\n ? { errorPatterns: Object.freeze([...overrides.settings.errorPatterns]) }\n : {}),\n });\n const environment = { ...overrides.environment };\n const cwd = overrides.cwd ?? process.cwd();\n const clock = memoize(() => overrides.clock ?? new SystemClock());\n const spawner = memoize(() => overrides.spawner ?? new NodeSpawner());\n const processControl = memoize(() => overrides.processControl ?? new NodeProcessControl());\n const ptySpawner = memoize(() => overrides.ptySpawner ?? new NodePtySpawner());\n const paths = memoize(() => overrides.paths ?? new RunnerPaths(cwd, environment));\n const lifeline = memoize(() => overrides.lifeline ?? new NodeLifeline(paths()));\n const processRegistry = memoize(() => overrides.processRegistry ?? createDefaultProcessRegistry(environment));\n const runnerRegistry = memoize(\n () => overrides.runnerRegistry ?? new RunnerRegistry(paths(), processControl(), processRegistry(), environment),\n );\n const namer = memoize(() => overrides.namer ?? new RunnerNamer(runnerRegistry()));\n const logFile = memoize(() => overrides.logFile ?? new LogFile(paths()));\n const logReader = memoize(() => overrides.logReader ?? new LogReader());\n const launcher = memoize(\n () =>\n overrides.launcher ??\n new Launcher(spawner(), processControl(), logFile(), clock(), paths(), lifeline(), environment, settings),\n );\n const rmuxBackend = memoize(\n () =>\n overrides.rmuxBackend ??\n new PtyBackendChain(\n new RmuxBackend(paths(), environment, settings),\n new TmuxBackend(paths(), undefined, environment, settings),\n ),\n );\n const rtkProcessor = memoize(\n () => overrides.rtkProcessor ?? new RtkProcessor(undefined, undefined, environment, settings),\n );\n const ptyHost = memoize(\n () => overrides.ptyHost ?? new PtyHost(ptySpawner(), logFile(), processControl(), clock(), environment, settings),\n );\n const bashRunService = memoize(\n () =>\n overrides.bashRunService ??\n new BashRunService(\n launcher(),\n rmuxBackend(),\n namer(),\n runnerRegistry(),\n clock(),\n rtkProcessor(),\n cwd,\n environment,\n overrides.executionBudget ?? sharedExecutionBudget(environment),\n ),\n );\n\n return {\n settings,\n environment,\n get clock() {\n return clock();\n },\n get spawner() {\n return spawner();\n },\n get processControl() {\n return processControl();\n },\n get ptySpawner() {\n return ptySpawner();\n },\n get paths() {\n return paths();\n },\n get lifeline() {\n return lifeline();\n },\n get processRegistry() {\n return processRegistry();\n },\n get runnerRegistry() {\n return runnerRegistry();\n },\n get namer() {\n return namer();\n },\n get logFile() {\n return logFile();\n },\n get logReader() {\n return logReader();\n },\n get launcher() {\n return launcher();\n },\n get rmuxBackend() {\n return rmuxBackend();\n },\n get rtkProcessor() {\n return rtkProcessor();\n },\n get ptyHost() {\n return ptyHost();\n },\n get bashRunService() {\n return bashRunService();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AACA,MAAa,uBAAuB;AAEpC,MAAa,oBAAoB;AAEjC,MAAa,iBAAiB;AAC9B,MAAa,uBAAuB;AAGpC,MAAa,gBAAgB;AAC7B,MAAa,sBAAsB;CAAE,UAAU;CAAK,IAAI;AAAI;;;;;;;;;;;;;ACM5D,IAAa,kBAAb,MAAqD;CAEhC;CACA;CAFnB,YACE,MACA,MACA;EAFiB,KAAA,OAAA;EACA,KAAA,OAAA;CAChB;CAEH,MAAM,OAAO,SAA4D;EACvE,OAAQ,MAAM,KAAK,KAAK,OAAO,OAAO,KAAO,MAAM,KAAK,KAAK,OAAO,OAAO;CAC7E;CAEA,MAAM,IAAY,QAAgB,WAAqD;EACrF,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,MAAM,IAAI,QAAQ,SAAS;CACvD;CAEA,KAAK,QAAgB,aAAuC;EAC1D,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,KAAK,QAAQ,WAAW;CACpD;CAEA,MAAM,QAAgB,MAAgC;EACpD,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,MAAM,QAAQ,IAAI;CAC9C;CAEA,QAAQ,QAA6C;EACnD,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,QAAQ,MAAM;CAC1C;;CAGA,YAAY,IAAY,WAA2C;EACjE,OAAO,KAAK,KAAK,YAAY,IAAI,SAAS,KAAK,KAAK,KAAK,YAAY,IAAI,SAAS;CACpF;CAEA,IAAI,MAAkC;EACpC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,IAAI;CAClD;CAEA,MAAc,QAA8B;EAC1C,OAAO,OAAO,WAAA,UAA6B,IAAI,KAAK,OAAO,KAAK;CAClE;AACF;;;AClDA,MAAM,cAAc;AACpB,MAAM,gBAAgB;;AAEtB,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;AAEzB,IAAa,aAAb,MAA+C;CAE1B;CACA;CAFnB,YACE,QACA,SAA0B,aAC1B;EAFiB,KAAA,SAAA;EACA,KAAA,SAAA;CAChB;CAEH,IAAI,MAA8C;EAChD,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,SACE,KAAK,QACL;IAAC;IAAe,KAAK;IAAQ,GAAG;GAAI,GACpC;IAAE,SAAS;IAAoB,WAAW;IAAkB,UAAU;GAAO,IAC5E,OAAO,QAAQ,WAAW;IAGzB,MAAM,OAAQ,OAAuD;IACrE,IAAI,SAAS,OAAO,SAAS,UAAU;KACrC,OAAO,KAAK;KACZ;IACF;IACA,QAAQ;KAAE,YAAY,OAAO,SAAS,WAAW,OAAO;KAAG;KAAQ;IAAO,CAAC;GAC7E,CACF;EACF,CAAC;CACH;CAEA,MAAM,OAAO,QAAgB,QAA6C;EACxE,MAAM,SAAS,MAAM,KAAK,IAAI;GAAC;GAAmB;GAAM;GAAM;GAAQ;GAAM;EAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAC1G,IAAI,CAAC,UAAU,OAAO,eAAe,GAAG,OAAO,KAAA;EAC/C,OAAO,OAAO,OAAO,QAAQ,OAAO,EAAE;CACxC;CAEA,MAAM,eAAe,QAAkC;EACrD,MAAM,SAAS,MAAM,KAAK,IAAI;GAAC;GAAe;GAAM;EAAM,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EAClF,OAAO,CAAC,UAAU,OAAO,eAAe;CAC1C;AACF;;;;;;;;;;;;;;ACGA,IAAa,cAAb,MAAiD;CAM5B;CACA;CACA;CACA;CARnB;CACA,uBAAwB,IAAI,IAAoB;CAChD,8BAA+B,IAAI,IAAiC;CAEpE,YACE,OACA,gBAAkE,WAAW,IAAI,WAAW,MAAM,GAClG,MAAqE,QAAQ,KAC7E,UACA;EAJiB,KAAA,QAAA;EACA,KAAA,eAAA;EACA,KAAA,MAAA;EACA,KAAA,WAAA;CAChB;CAEH,MAAM,OAAO,SAA4D;EACvE,MAAM,OAAO,MAAM,KAAK,OAAO;EAC/B,IAAI,CAAC,MAAM,OAAO,KAAA;EAElB,KAAK,MAAM,kBAAkB;EAC7B,MAAM,SAAS,GAAG,iBAAiB,QAAQ;EAC3C,MAAM,UAAU,KAAK,MAAM,WAAW,QAAQ,EAAE;EAChD,MAAM,MAAM,KAAK,SAAS,QAAQ,IAAI,QAAQ,SAAS;EACvD,IAAI,UAAU;EACd,IAAI,WAAW;EAEf,IAAI;GACF,KAAK,aAAa,SAAS,SAAS,GAAG;GAGvC,MAAM,aAAa,UAAU;IAAC,QAAQ;IAAU,aAAa,YAAY;IAAG,IAAI;IAAM,IAAI;IAAM,IAAI;GAAI,CAAC;GACzG,MAAM,KAAK,QAAQ,MAAM;IAAC;IAAe;IAAM;IAAM;IAAQ;IAAM,QAAQ;IAAK;GAAU,CAAC;GAC3F,UAAU;GAKV,MAAM,KAAK,QAAQ,MAAM;IAAC;IAAc;IAAM;IAAQ;IAAkB;GAAI,CAAC;GAC7E,MAAM,KAAK,QAAQ,MAAM;IAAC;IAAa;IAAM;IAAQ,KAAK,eAAe,SAAS,IAAI,SAAS,OAAO;GAAC,CAAC;GAExG,MAAM,MAAM,MAAM,QAAQ,MAAM,MAAM;GACtC,GAAG,cAAc,IAAI,MAAM,IAAI,EAAE,MAAM,IAAM,CAAC;GAC9C,WAAW;GAEX,IAAI,YAAY;GAChB,MAAM,aAAa,KAAK,QAAQ,MAAM,QAAQ,GAAG;GACjD,KAAK,gBAAgB,QAAQ,UAAU;GACvC,MAAM,SAAoB;IACxB,IAAI,QAAQ;IACZ,MAAM,QAAQ;IACd;IACA;IACA,SAAS;IACT,eAAe;IACf,cAAe,YAAY,SAAS,SAAS,kBAAkB,KAAK,KAAK,KAAK,QAAQ,IAAI,CAAC,IAAI;IAC/F,kBAAkB;IAClB,cAAc;KACZ,YAAY;IACd;IACA,YAAY,KAAK,KAAK,QAAQ,GAAG;GACnC;GAEA,IAAI,QAAQ,aAAa,KAAK,KAAK,IAAI,QAAQ,MAAM,KAAK,eAAe,QAAQ,MAAM,QAAQ,UAAU,CAAC;GAC1G,WACG,cAAc,KAAK,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC,CAC7C,OAAO,UAAmB,QAAQ,YAAY,8BAA8B,OAAO,IAAI,aAAa,KAAK,GAAG,CAAC;GAChH,OAAO;EACT,SAAS,OAAO;GACd,IAAI,UAAU,MAAM;GACpB,IAAI,SAAS,MAAM,YAAY,MAAM,MAAM;GAC3C,uBAAuB,GAAG;GAC1B,QAAQ,YACN,QAAQ,cACJ,mDAAmD,aAAa,KAAK,MACrE,yDAAyD,aAAa,KAAK,GACjF;GACA;EACF;CACF;CAEA,MAAM,KAAK,QAAgB,aAAuC;EAChE,IAAI,CAAC,qBAAqB,KAAK,MAAM,KAAK,CAAC,OAAO,UAAU,WAAW,KAAK,eAAe,GAAG,OAAO;EAErG,MAAM,OAAO,MAAM,KAAK,OAAO;EAC/B,IAAI,CAAC,MAAM,OAAO;EAClB,IAAI;GACF,IAAI,MAAM,KAAK,eAAe,MAAM,GAAG,OAAO;GAE9C,MAAM,MAAM,MAAM,QAAQ,MAAM,MAAM;GACtC,IAAI,QAAQ,aAAa,OAAO;GAChC,MAAM,YAAY,WAAW,KAAK,MAAM;GACxC,IAAI,cAAc,QAAQ,OAAO;GACjC,IAAI,cAAc,UAAU,OAAO;GAEnC,IAAI,MAAM,gBAAgB,MAAM,QAAA,GAAqB,GAAG,OAAO;GAC/D,IAAI,MAAM,KAAK,eAAe,MAAM,GAAG,OAAO;GAI9C,IAAI,MADqB,QAAQ,MAAM,MAAM,CAAC,CAAC,YAAY,KAAA,CAAS,MACjD,aAAa,OAAO;GAEvC,OAAO,YAAY,MAAM,MAAM;EACjC,SAAS,OAAO;GACd,QAAQ,YAAY,8BAA8B,OAAO,IAAI,aAAa,KAAK,GAAG;GAClF,OAAO;EACT;CACF;CAEA,MAAM,MAAM,IAAY,QAAgB,WAAqD;EAC3F,MAAM,OAAO,MAAM,KAAK,OAAO;EAC/B,IAAI,CAAC,MAAM,OAAO,KAAA;EAClB,IAAI,MAAM,KAAK,eAAe,MAAM,GAAG,OAAO,KAAA;EAC9C,MAAM,aAAa,KAAK,QAAQ,MAAM,QAAQ,KAAK,SAAS,IAAI,SAAS,CAAC;EAC1E,KAAK,gBAAgB,QAAQ,UAAU;EACvC,OAAO;CACT;CAEA,MAAM,MAAM,QAAgB,MAAgC;EAC1D,MAAM,OAAO,MAAM,KAAK,OAAO;EAC/B,IAAI,CAAC,MAAM,OAAO;EAKlB,QAAO,MAJc,KAAK,IAAI;GAAC;GAAa;GAAM;GAAQ;GAAM;EAAI,CAAC,CAAC,CAAC,OAAO,UAAmB;GAC/F,QAAQ,YAAY,uCAAuC,OAAO,IAAI,aAAa,KAAK,GAAG;EAE7F,CAAC,EAAA,EACc,eAAe;CAChC;CAEA,MAAM,QAAQ,QAA6C;EACzD,MAAM,OAAO,MAAM,KAAK,OAAO;EAC/B,IAAI,CAAC,MAAM,OAAO,KAAA;EAClB,MAAM,SAAS,MAAM,KAAK,IAAI;GAAC;GAAgB;GAAM;GAAM;EAAM,CAAC,CAAC,CAAC,OAAO,UAAmB;GAC5F,QAAQ,YAAY,iCAAiC,OAAO,IAAI,aAAa,KAAK,GAAG;EAEvF,CAAC;EACD,OAAO,QAAQ,eAAe,IAAI,OAAO,SAAS,KAAA;CACpD;CAEA,IAAI,MAAkC;EACpC,OAAO,KAAK,KAAK,IAAI,IAAI;CAC3B;CAEA,YAAY,IAAY,WAA2C;EACjE,OAAO,iBAAiB,KAAK,SAAS,IAAI,SAAS,CAAC,CAAC,IAAI;CAC3D;CAEA,gBAAwB,QAAgB,YAAuC;EAC7E,KAAK,YAAY,IAAI,QAAQ,UAAU;EACvC,WACG,cAAc,KAAK,YAAY,OAAO,MAAM,CAAC,CAAC,CAC9C,OAAO,UAAmB,QAAQ,YAAY,2BAA2B,OAAO,IAAI,aAAa,KAAK,GAAG,CAAC;CAC/G;CAEA,SAAmD;EACjD,KAAK,kBAAkB,KAAK,cAAc;EAC1C,OAAO,KAAK;CACd;CAEA,MAAc,gBAAkD;EAC9D,MAAM,SAAS,KAAK,aAAa,WAAW,KAAK,MAAM,eAAe,CAAC,CAAC;EACxE,IAAI;GACF,MAAM,UAAU,MAAM,OAAO,IAAI,CAAC,IAAI,CAAC;GACvC,IAAI,QAAQ,eAAe,GAAG,MAAM,IAAI,MAAM,QAAQ,OAAO,KAAK,KAAK,0BAA0B;GACjG,OAAO;EACT,SAAS,OAAO;GACd,QAAQ,YAAY,wBAAwB,aAAa,KAAK,GAAG;GACjE;EACF;CACF;CAEA,MAAc,QAAQ,MAAmB,MAAwC;EAC/E,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;EAClC,IAAI,OAAO,eAAe,GACxB,MAAM,IAAI,MAAM,QAAQ,KAAK,MAAM,GAAG,WAAW,OAAO,OAAO,KAAK,KAAK,QAAQ,OAAO,cAAc;CAE1G;CAEA,aAAqB,SAA4B,SAAiB,KAA4B;EAC5F,uBAAuB,GAAG;EAC1B,GAAG,cAAc,SAAS,IAAI,EAAE,MAAM,IAAM,CAAC;EAC7C,MAAM,MAAM,YAAY,QAAQ,WAAW,QAAQ,aAAa,KAAK,GAAG;EACxE,MAAM,OAAoB;GAAE,SAAS,QAAQ;GAAS,KAAK,QAAQ;GAAK;EAAI;EAC5E,iBAAiB,IAAI,MAAM,IAAI;CACjC;CAEA,SAAiB,IAAY,WAAqC;EAChE,OAAO,gBAAgB,KAAK,MAAM,eAAe,SAAS,GAAG,EAAE;CACjE;;;;;;;;;CAUA,eAAuB,SAAiB,UAAkB,SAAoC;EAC5F,MAAM,KAAK,KAAK,SAAS,SAAS,MAAM;EACxC,OAAO,UAAU;GACf,QAAQ;GACR,aAAa,SAAS;GACtB;GACA,KAAK,MAAM,kBAAkB,EAAE;GAC/B,OAAO,eAAe,KAAK,GAAG,CAAC;GAC/B;GACA,GAAI,QAAQ,cAAc,CAAC,KAAK,MAAM,cAAc,EAAE,CAAC,IAAI,CAAC;EAC9D,CAAC;CACH;CAEA,MAAc,QAAQ,MAAmB,QAAgB,KAA2C;EAClG,IAAI;GACF,MAAM,WAAW,MAAM,cAAc,MAAM,QAAQ,IAAI,IAAI;GAC3D,MAAM,gBAAgB,MAAM,QAAQ,IAAI,OAAO;GAC/C,OAAO,iBAAiB,IAAI,IAAI,KAAK;IAAE,MAAM;IAAU,QAAQ;GAAK;EACtE,UAAU;GACR,IAAI,CAAE,MAAM,KAAK,eAAe,MAAM,CAAC,CAAC,YAAY,KAAK,GAAI,MAAM,YAAY,MAAM,MAAM;GAC3F,uBAAuB,GAAG;EAC5B;CACF;CAEA,eACE,QACA,MACA,QACA,YACQ;EACR,IAAI,SAAS;EACb,IAAI,SAAS;EACb,MAAM,2BAAW,IAAI,IAA4B;EACjD,MAAM,UAAU,YAA2B;GACzC,OAAO,QAAQ;IACb,MAAM,WAAW,MAAM,KAAK,IAAI;KAAC;KAAgB;KAAM;KAAM;IAAM,CAAC,CAAC,CAAC,OAAO,UAAmB;KAC9F,QAAQ,YAAY,qCAAqC,OAAO,KAAK,IAAI,aAAa,KAAK,GAAG;IAEhG,CAAC;IACD,MAAM,OAAO,UAAU,eAAe,IAAI,SAAS,SAAS;IAC5D,IAAI,SAAS,QAAQ;KACnB,SAAS;KACT,KAAK,MAAM,WAAW,UAAU,QAAQ,IAAI;IAC9C;IACA,MAAM,MAAA,GAAa;GACrB;EACF;EACA,QAAa;EACb,WACG,cAAc;GACb,SAAS;EACX,CAAC,CAAC,CACD,OAAO,UACN,QAAQ,YAAY,0CAA0C,OAAO,KAAK,IAAI,aAAa,KAAK,GAAG,CACrG;EACF,OAAO;GACL,GAAG;GACH,QAAQ,SAAS;IACf,KACG,IAAI;KAAC;KAAa;KAAM;KAAQ;KAAM;IAAI,CAAC,CAAC,CAC5C,OAAO,UAAmB,QAAQ,YAAY,aAAa,KAAK,CAAC,CAAC;GACvE;GACA,cAAc;GACd,SAAS,YAAY;IACnB,SAAS,IAAI,OAAO;IACpB,aAAa,SAAS,OAAO,OAAO;GACtC;GACA,SAAS,MAAM,SAAS;IACtB,KACG,IAAI;KAAC;KAAiB;KAAM;KAAQ;KAAM,OAAO,IAAI;KAAG;KAAM,OAAO,IAAI;IAAC,CAAC,CAAC,CAC5E,OAAO,UAAmB,QAAQ,YAAY,aAAa,KAAK,CAAC,CAAC;GACvE;EACF;CACF;AACF;AAEA,SAAS,WAAW,gBAAgC;CAClD,MAAM,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,cAAc,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAA,EAAqB;CAClG,OAAO,GAAG,gBAAgB;AAC5B;AAEA,SAAS,YACP,WACA,aACA,KACwB;CACxB,MAAM,SAA4B;EAChC,GAAG;EACH,GAAI,cAAc,CAAC,IAAI;GAAE,GAAG;GAAqB,GAAG,0BAA0B,GAAG;EAAE;EACnF,GAAG;EACH,eAAe;CACjB;CACA,IAAI,CAAC,aAAa,OAAO,OAAO;CAChC,OAAO,OAAO,YACZ,OAAO,QAAQ,MAAM,CAAC,CAAC,QAAQ,UAAqC,MAAM,OAAO,KAAA,CAAS,CAC5F;AACF;AAEA,eAAe,YAAY,MAAmB,QAAkC;CAK9E,QAAO,MAJc,KAAK,IAAI;EAAC;EAAgB;EAAM;CAAM,CAAC,CAAC,CAAC,OAAO,UAAmB;EACtF,QAAQ,YAAY,+BAA+B,OAAO,IAAI,aAAa,KAAK,GAAG;CAErF,CAAC,EAAA,EACc,eAAe;AAChC;AAEA,eAAe,QAAQ,MAAmB,QAAiC;CACzE,MAAM,UAAU,MAAM,KAAK,OAAO,QAAQ,aAAa;CACvD,MAAM,MAAM,OAAO,OAAO;CAC1B,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,OAAO,GAAG,MAAM,IAAI,MAAM,sCAAsC,QAAQ;CACtG,OAAO;AACT;;;;;;;;AASA,eAAe,cAAc,MAAmB,QAAgB,UAA0C;CACxG,SAAS;EACP,IAAI,GAAG,WAAW,QAAQ,GAAG,OAAO;EACpC,MAAM,QAAQ,MAAM,aAAa,MAAM,MAAM;EAC7C,IAAI,MAAM,QAAQ,OAAO,MAAM;EAC/B,MAAM,MAAA,GAAa;CACrB;AACF;AAEA,eAAe,gBAAgB,MAAmB,QAAgB,UAAiC;CACjG,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,OAAO,KAAK,IAAI,IAAI,UAAU;EAC5B,IAAI,GAAG,WAAW,QAAQ,GAAG;EAC7B,IAAI,MAAM,KAAK,eAAe,MAAM,GAAG;EACvC,MAAM,MAAA,EAAuB;CAC/B;AACF;AAEA,eAAe,gBAAgB,MAAmB,QAAgB,WAAqC;CACrG,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,OAAO,KAAK,IAAI,IAAI,UAAU;EAC5B,KAAK,MAAM,aAAa,MAAM,MAAM,EAAA,CAAG,QAAQ,OAAO;EACtD,MAAM,MAAA,GAAa;CACrB;CACA,OAAO;AACT;;AAGA,eAAe,aAAa,MAAmB,QAAmE;CAChH,MAAM,UAAU,MAAM,KAAK,OAAO,QAAQ,iBAAiB;CAG3D,IAAI,YAAY,KAAA,GAAW,OAAO;EAAE,QAAQ;EAAM,MAAM;CAAK;CAC7D,MAAM,CAAC,MAAM,QAAQ,GAAG,QAAQ,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG;CACxD,IAAI,KAAK,KAAK,GAAG,MAAM,IAAI,OAAO;EAAE,QAAQ;EAAM,MAAM;CAAK;CAC7D,IAAI,SAAS,OAAO,SAAS,QAAQ;EACnC,MAAM,OAAO,OAAO,MAAM;EAC1B,OAAO;GAAE,QAAQ;GAAM,MAAM,OAAO,UAAU,IAAI,IAAI,OAAO;EAAK;CACpE;CACA,OAAO;EAAE,QAAQ;EAAO,MAAM;CAAK;AACrC;AAEA,SAAS,WAAW,KAAa,QAAiD;CAChF,IAAI;EACF,QAAQ,KAAK,KAAK,SAAS;EAC3B,OAAO;CACT,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,SAAS,OAAO;EAC9D,QAAQ,YAAY,gCAAgC,OAAO,IAAI,aAAa,KAAK,GAAG;EACpF,OAAO;CACT;AACF;AAEA,SAAS,SAAS,QAAgB,UAA0B;CAC1D,IAAI;CACJ,IAAI;EACF,MAAM,OAAO,GAAG,SAAS,MAAM,CAAC,CAAC;EACjC,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ;EACrC,MAAM,SAAS,OAAO,MAAM,KAAK;EACjC,SAAS,GAAG,SAAS,QAAQ,GAAG;EAChC,GAAG,SAAS,QAAQ,QAAQ,GAAG,OAAO,OAAO,KAAK;EAClD,OAAO,OAAO,SAAS,MAAM;CAC/B,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAC5C,QAAQ,YAAY,2BAA2B,OAAO,IAAI,aAAa,KAAK,GAAG;EAEjF,OAAO;CACT,UAAU;EACR,IAAI,WAAW,KAAA,GAAW,GAAG,UAAU,MAAM;CAC/C;AACF;AAEA,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAS,YAAY;EAE9B,WADyB,SAAS,EAC9B,CAAC,CAAC,QAAQ;CAChB,CAAC;AACH;AAEA,SAAS,aAAa,OAAwB;CAC5C,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;;;;ACtaA,SAAS,QAAW,OAAyB;CAC3C,IAAI;CACJ,IAAI,QAAQ;CACZ,aAAa;EACX,IAAI,CAAC,OAAO;GACV,QAAQ,MAAM;GACd,QAAQ;EACV;EACA,OAAO;CACT;AACF;;;;;;;;;;;;AAaA,SAAgB,yBACd,WAKoB;CACpB,MAAM,WACJ,UAAU,aAAa,KAAA,IACnB,KAAA,IACA,OAAO,OAAO;EACZ,GAAG,UAAU;EACb,GAAI,UAAU,UAAU,gBACpB,EAAE,eAAe,OAAO,OAAO,CAAC,GAAG,UAAU,SAAS,aAAa,CAAC,EAAE,IACtE,CAAC;CACP,CAAC;CACP,MAAM,cAAc,EAAE,GAAG,UAAU,YAAY;CAC/C,MAAM,MAAM,UAAU,OAAO,QAAQ,IAAI;CACzC,MAAM,QAAQ,cAAc,UAAU,SAAS,IAAI,YAAY,CAAC;CAChE,MAAM,UAAU,cAAc,UAAU,WAAW,IAAI,YAAY,CAAC;CACpE,MAAM,iBAAiB,cAAc,UAAU,kBAAkB,IAAI,mBAAmB,CAAC;CACzF,MAAM,aAAa,cAAc,UAAU,cAAc,IAAI,eAAe,CAAC;CAC7E,MAAM,QAAQ,cAAc,UAAU,SAAS,IAAI,YAAY,KAAK,WAAW,CAAC;CAChF,MAAM,WAAW,cAAc,UAAU,YAAY,IAAI,aAAa,MAAM,CAAC,CAAC;CAC9E,MAAM,kBAAkB,cAAc,UAAU,mBAAmB,6BAA6B,WAAW,CAAC;CAC5G,MAAM,iBAAiB,cACf,UAAU,kBAAkB,IAAI,eAAe,MAAM,GAAG,eAAe,GAAG,gBAAgB,GAAG,WAAW,CAChH;CACA,MAAM,QAAQ,cAAc,UAAU,SAAS,IAAI,YAAY,eAAe,CAAC,CAAC;CAChF,MAAM,UAAU,cAAc,UAAU,WAAW,IAAI,QAAQ,MAAM,CAAC,CAAC;CACvE,MAAM,YAAY,cAAc,UAAU,aAAa,IAAI,UAAU,CAAC;CACtE,MAAM,WAAW,cAEb,UAAU,YACV,IAAI,SAAS,QAAQ,GAAG,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,QAAQ,CAC5G;CACA,MAAM,cAAc,cAEhB,UAAU,eACV,IAAI,gBACF,IAAI,YAAY,MAAM,GAAG,aAAa,QAAQ,GAC9C,IAAI,YAAY,MAAM,GAAG,KAAA,GAAW,aAAa,QAAQ,CAC3D,CACJ;CACA,MAAM,eAAe,cACb,UAAU,gBAAgB,IAAI,aAAa,KAAA,GAAW,KAAA,GAAW,aAAa,QAAQ,CAC9F;CACA,MAAM,UAAU,cACR,UAAU,WAAW,IAAI,QAAQ,WAAW,GAAG,QAAQ,GAAG,eAAe,GAAG,MAAM,GAAG,aAAa,QAAQ,CAClH;CACA,MAAM,iBAAiB,cAEnB,UAAU,kBACV,IAAI,eACF,SAAS,GACT,YAAY,GACZ,MAAM,GACN,eAAe,GACf,MAAM,GACN,aAAa,GACb,KACA,aACA,UAAU,mBAAmB,sBAAsB,WAAW,CAChE,CACJ;CAEA,OAAO;EACL;EACA;EACA,IAAI,QAAQ;GACV,OAAO,MAAM;EACf;EACA,IAAI,UAAU;GACZ,OAAO,QAAQ;EACjB;EACA,IAAI,iBAAiB;GACnB,OAAO,eAAe;EACxB;EACA,IAAI,aAAa;GACf,OAAO,WAAW;EACpB;EACA,IAAI,QAAQ;GACV,OAAO,MAAM;EACf;EACA,IAAI,WAAW;GACb,OAAO,SAAS;EAClB;EACA,IAAI,kBAAkB;GACpB,OAAO,gBAAgB;EACzB;EACA,IAAI,iBAAiB;GACnB,OAAO,eAAe;EACxB;EACA,IAAI,QAAQ;GACV,OAAO,MAAM;EACf;EACA,IAAI,UAAU;GACZ,OAAO,QAAQ;EACjB;EACA,IAAI,YAAY;GACd,OAAO,UAAU;EACnB;EACA,IAAI,WAAW;GACb,OAAO,SAAS;EAClB;EACA,IAAI,cAAc;GAChB,OAAO,YAAY;EACrB;EACA,IAAI,eAAe;GACjB,OAAO,aAAa;EACtB;EACA,IAAI,UAAU;GACZ,OAAO,QAAQ;EACjB;EACA,IAAI,iBAAiB;GACnB,OAAO,eAAe;EACxB;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"runnerDependencies-CamKwphq.mjs","names":[],"sources":["../src/constants/tmuxBackend.ts","../src/services/ptyBackendChain/index.ts","../src/services/tmuxBackend/TmuxClient.ts","../src/services/tmuxBackend/index.ts","../src/services/runnerDependencies/index.ts"],"sourcesContent":["export const POLL_MS = 100;\nexport const LOG_DRAIN_TIMEOUT_MS = 2_000;\nexport const LOG_DRAIN_POLL_MS = 25;\nexport const PANE_STATE_FORMAT = '#{pane_dead}:#{pane_dead_status}:#{session_name}';\nexport const STOP_GRACE_MS = 3_000;\nexport const SESSION_PREFIX = 'po-tmux-';\nexport const OWNED_TARGET_PATTERN = /^po-tmux-[A-Za-z0-9_-]+$/;\nexport const TMUX_TARGET_PREFIX = SESSION_PREFIX;\nexport const SOCKET_HASH_LENGTH = 12;\nexport const SOCKET_PREFIX = 'po-tmux-';\nexport const NON_INTERACTIVE_ENV = { NO_COLOR: '1', CI: '1' };\n","import { TMUX_TARGET_PREFIX } from '../../constants/tmuxBackend';\nimport type { RunHandle } from '../../types/launcher';\nimport type { PtyRun } from '../../types/ptyHost';\nimport type { IRmuxBackend, RmuxLaunchRequest } from '../../types/rmuxBackend';\nimport type { ExitResult } from '../../types/spawner';\n\n/**\n * Presents the available PTY backends as one, preferring RMUX.\n *\n * A launch takes the first backend that accepts it, so a host without a\n * compatible RMUX binary still gets panes rather than falling through to the\n * plain subprocess launcher. Every later call routes on the target's prefix\n * instead of asking each backend in turn: a backend cannot tell \"this session\n * is gone\" from \"this session was never mine\", and guessing would let one\n * report success for the other's run.\n */\nexport class PtyBackendChain implements IRmuxBackend {\n constructor(\n private readonly rmux: IRmuxBackend,\n private readonly tmux: IRmuxBackend,\n ) {}\n\n async launch(request: RmuxLaunchRequest): Promise<RunHandle | undefined> {\n return (await this.rmux.launch(request)) ?? (await this.tmux.launch(request));\n }\n\n watch(id: string, target: string, sessionId?: string): Promise<ExitResult | undefined> {\n return this.owner(target).watch(id, target, sessionId);\n }\n\n stop(target: string, expectedPid: number): Promise<boolean> {\n return this.owner(target).stop(target, expectedPid);\n }\n\n input(target: string, text: string): Promise<boolean> {\n return this.owner(target).input(target, text);\n }\n\n capture(target: string): Promise<string | undefined> {\n return this.owner(target).capture(target);\n }\n\n /** Both backends persist terminal evidence at the same path, so either answers. */\n readOutcome(id: string, sessionId: string): ExitResult | undefined {\n return this.rmux.readOutcome(id, sessionId) ?? this.tmux.readOutcome(id, sessionId);\n }\n\n get(name: string): PtyRun | undefined {\n return this.rmux.get(name) ?? this.tmux.get(name);\n }\n\n private owner(target: string): IRmuxBackend {\n return target.startsWith(TMUX_TARGET_PREFIX) ? this.tmux : this.rmux;\n }\n}\n","import { execFile } from 'node:child_process';\n\nimport type { ITmuxClient, TmuxResult } from '../../types/tmuxClient';\n\nconst TMUX_BINARY = 'tmux';\nconst SOCKET_OPTION = '-L';\n/** Long enough for a loaded server, short enough that a hung tmux is not fatal. */\nconst COMMAND_TIMEOUT_MS = 10_000;\nconst MAX_OUTPUT_BYTES = 4 * 1024 * 1024;\n\nexport class TmuxClient implements ITmuxClient {\n constructor(\n private readonly socket: string,\n private readonly binary = TMUX_BINARY,\n ) {}\n\n run(args: readonly string[]): Promise<TmuxResult> {\n return new Promise((resolve, reject) => {\n execFile(\n this.binary,\n [SOCKET_OPTION, this.socket, ...args],\n { timeout: COMMAND_TIMEOUT_MS, maxBuffer: MAX_OUTPUT_BYTES, encoding: 'utf8' },\n (error, stdout, stderr) => {\n // A non-zero tmux exit is an answer, not a fault: `has-session`\n // reports absence that way. Only a missing or hung binary rejects.\n const code = (error as (Error & { code?: number | string }) | null)?.code;\n if (error && typeof code !== 'number') {\n reject(error);\n return;\n }\n resolve({ returnCode: typeof code === 'number' ? code : 0, stdout, stderr });\n },\n );\n });\n }\n\n async format(target: string, format: string): Promise<string | undefined> {\n const result = await this.run(['display-message', '-p', '-t', target, '-F', format]).catch(() => undefined);\n if (!result || result.returnCode !== 0) return undefined;\n return result.stdout.replace(/\\n$/, '');\n }\n\n async sessionMissing(target: string): Promise<boolean> {\n const result = await this.run(['has-session', '-t', target]).catch(() => undefined);\n return !result || result.returnCode !== 0;\n }\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {\n LOG_DRAIN_POLL_MS,\n LOG_DRAIN_TIMEOUT_MS,\n NON_INTERACTIVE_ENV,\n OWNED_TARGET_PATTERN,\n PANE_STATE_FORMAT,\n POLL_MS,\n SESSION_PREFIX,\n SOCKET_HASH_LENGTH,\n SOCKET_PREFIX,\n STOP_GRACE_MS,\n} from '../../constants/tmuxBackend';\nimport type { RunHandle } from '../../types/launcher';\nimport type { PtyRun } from '../../types/ptyHost';\nimport type { IRmuxBackend, RmuxLaunchRequest } from '../../types/rmuxBackend';\nimport type { RunnerSettings } from '../../types/runnerSettings';\nimport type { ExitResult } from '../../types/spawner';\nimport type { ITmuxClient } from '../../types/tmuxClient';\nimport { getLogMaxBytes, getResultMaxBytes, noninteractiveEnvironment } from '../runnerConfig';\nimport type { IRunnerPaths } from '../runnerPaths/type';\nimport {\n type CommandSpec,\n type SupervisorPaths,\n cleanupSupervisorFiles,\n NO_TERMINAL_INPUT_ENV,\n readExitMetadata,\n runtimeEntry,\n shellJoin,\n supervisorPaths,\n writeCommandSpec,\n} from '../runnerSupervisor';\nimport { TmuxClient } from './TmuxClient';\n\n/** Pane liveness, its exit status, and whether the session still exists, in one read. */\n/** Distinct from the RMUX prefix so a target names the backend that owns it. */\n\n/**\n * Supervises runs in tmux panes, for hosts with no compatible RMUX binary.\n *\n * The pane runs the same runnerHost supervisor as the RMUX backend, so exit\n * metadata, log rotation, and lifeline handling are shared rather than\n * reimplemented: only the multiplexer differs. Kept beside the RMUX backend\n * rather than folded into it because that path has no unit coverage to\n * refactor against.\n */\nexport class TmuxBackend implements IRmuxBackend {\n private clientPromise: Promise<ITmuxClient | undefined> | undefined;\n private readonly runs = new Map<string, PtyRun>();\n private readonly completions = new Map<string, Promise<ExitResult>>();\n\n constructor(\n private readonly paths: IRunnerPaths,\n private readonly createClient: (socket: string) => ITmuxClient = (socket) => new TmuxClient(socket),\n private readonly env: Readonly<Record<string, string | undefined>> = process.env,\n private readonly settings?: RunnerSettings,\n ) {}\n\n async launch(request: RmuxLaunchRequest): Promise<RunHandle | undefined> {\n const tmux = await this.client();\n if (!tmux) return undefined;\n\n this.paths.ensureDirectories();\n const target = `${SESSION_PREFIX}${request.id}`;\n const logPath = this.paths.logPathFor(request.id);\n const aux = this.auxPaths(request.id, request.sessionId);\n let created = false;\n let released = false;\n\n try {\n this.prepareFiles(request, logPath, aux);\n // One quoted command rather than an argv: tmux takes shell-command as a\n // single word, and quoting here is what keeps a path with spaces intact.\n const supervisor = shellJoin([process.execPath, runtimeEntry('runnerHost'), aux.spec, aux.gate, aux.exit]);\n await this.checked(tmux, ['new-session', '-d', '-s', target, '-c', request.cwd, supervisor]);\n created = true;\n // Set before the gate opens, so it is in force by the time the command\n // can exit. A pane that vanishes on exit takes the log sink down with it\n // before Node has finished starting, losing the output of fast commands,\n // and leaves #{pane_dead} with nothing to report.\n await this.checked(tmux, ['set-option', '-t', target, 'remain-on-exit', 'on']);\n await this.checked(tmux, ['pipe-pane', '-t', target, this.logPipeCommand(logPath, aux.logDone, request)]);\n\n const pid = await panePid(tmux, target);\n fs.writeFileSync(aux.gate, '', { mode: 0o600 });\n released = true;\n\n let buffering = true;\n const completion = this.monitor(tmux, target, aux);\n this.trackCompletion(target, completion);\n const handle: RunHandle = {\n id: request.id,\n name: request.name,\n pid,\n logPath,\n backend: 'tmux',\n backendTarget: target,\n output: () => (buffering ? readTail(logPath, getResultMaxBytes(this.env, this.settings) * 2) : ''),\n completion: () => completion,\n detach: () => {\n buffering = false;\n },\n stop: () => this.stop(target, pid),\n };\n\n if (request.interactive) this.runs.set(request.name, this.interactiveRun(handle, tmux, target, completion));\n void completion\n .finally(() => this.runs.delete(request.name))\n .catch((error: unknown) => process.emitWarning(`tmux completion failed for ${target}: ${errorMessage(error)}`));\n return handle;\n } catch (error) {\n if (released) throw error;\n if (created) await killSession(tmux, target);\n cleanupSupervisorFiles(aux);\n process.emitWarning(\n request.interactive\n ? `tmux launch unavailable for interactive runner: ${errorMessage(error)}`\n : `tmux launch unavailable, using supervised subprocess: ${errorMessage(error)}`,\n );\n return undefined;\n }\n }\n\n async stop(target: string, expectedPid: number): Promise<boolean> {\n if (!OWNED_TARGET_PATTERN.test(target) || !Number.isInteger(expectedPid) || expectedPid <= 0) return false;\n\n const tmux = await this.client();\n if (!tmux) return false;\n try {\n if (await tmux.sessionMissing(target)) return true;\n\n const pid = await panePid(tmux, target);\n if (pid !== expectedPid) return false;\n const signalled = signalPane(pid, target);\n if (signalled === 'gone') return true;\n if (signalled === 'failed') return false;\n\n if (await waitForPaneStop(tmux, target, STOP_GRACE_MS)) return true;\n if (await tmux.sessionMissing(target)) return true;\n\n // Revalidate after the grace period so a replacement pane is never closed.\n const currentPid = await panePid(tmux, target).catch(() => undefined);\n if (currentPid !== expectedPid) return false;\n\n return killSession(tmux, target);\n } catch (error) {\n process.emitWarning(`Could not stop tmux target ${target}: ${errorMessage(error)}`);\n return false;\n }\n }\n\n async watch(id: string, target: string, sessionId?: string): Promise<ExitResult | undefined> {\n const tmux = await this.client();\n if (!tmux) return undefined;\n if (await tmux.sessionMissing(target)) return undefined;\n const completion = this.monitor(tmux, target, this.auxPaths(id, sessionId));\n this.trackCompletion(target, completion);\n return completion;\n }\n\n async input(target: string, text: string): Promise<boolean> {\n const tmux = await this.client();\n if (!tmux) return false;\n const result = await tmux.run(['send-keys', '-t', target, '-l', text]).catch((error: unknown) => {\n process.emitWarning(`Could not send input to tmux target ${target}: ${errorMessage(error)}`);\n return undefined;\n });\n return result?.returnCode === 0;\n }\n\n async capture(target: string): Promise<string | undefined> {\n const tmux = await this.client();\n if (!tmux) return undefined;\n const result = await tmux.run(['capture-pane', '-p', '-t', target]).catch((error: unknown) => {\n process.emitWarning(`Could not capture tmux target ${target}: ${errorMessage(error)}`);\n return undefined;\n });\n return result?.returnCode === 0 ? result.stdout : undefined;\n }\n\n get(name: string): PtyRun | undefined {\n return this.runs.get(name);\n }\n\n readOutcome(id: string, sessionId: string): ExitResult | undefined {\n return readExitMetadata(this.auxPaths(id, sessionId).exit);\n }\n\n private trackCompletion(target: string, completion: Promise<ExitResult>): void {\n this.completions.set(target, completion);\n void completion\n .finally(() => this.completions.delete(target))\n .catch((error: unknown) => process.emitWarning(`tmux monitor failed for ${target}: ${errorMessage(error)}`));\n }\n\n private client(): Promise<ITmuxClient | undefined> {\n this.clientPromise ??= this.resolveClient();\n return this.clientPromise;\n }\n\n private async resolveClient(): Promise<ITmuxClient | undefined> {\n const client = this.createClient(socketName(this.paths.repositoryPath()));\n try {\n const version = await client.run(['-V']);\n if (version.returnCode !== 0) throw new Error(version.stderr.trim() || 'tmux reported no version');\n return client;\n } catch (error) {\n process.emitWarning(`tmux is unavailable: ${errorMessage(error)}`);\n return undefined;\n }\n }\n\n private async checked(tmux: ITmuxClient, args: readonly string[]): Promise<void> {\n const result = await tmux.run(args);\n if (result.returnCode !== 0) {\n throw new Error(`tmux ${args[0] ?? ''} failed: ${result.stderr.trim() || `exit ${result.returnCode}`}`);\n }\n }\n\n private prepareFiles(request: RmuxLaunchRequest, logPath: string, aux: SupervisorPaths): void {\n cleanupSupervisorFiles(aux);\n fs.writeFileSync(logPath, '', { mode: 0o600 });\n const env = environment(request.sessionId, request.interactive, this.env);\n const spec: CommandSpec = { command: request.command, cwd: request.cwd, env };\n writeCommandSpec(aux.spec, spec);\n }\n\n private auxPaths(id: string, sessionId?: string): SupervisorPaths {\n return supervisorPaths(this.paths.stateDirectory(sessionId), id);\n }\n\n /**\n * The sink the pane pipes into.\n *\n * An interactive run also asks for a raw copy: the scrubbed log it writes\n * beside it has had cursor movement taken out, which is what a terminal\n * needs most. Only interactive runs pay for it, because only they can be\n * attached to.\n */\n private logPipeCommand(logPath: string, donePath: string, request: RmuxLaunchRequest): string {\n const id = path.basename(logPath, '.log');\n return shellJoin([\n process.execPath,\n runtimeEntry('logSink'),\n logPath,\n this.paths.rotatedLogPathFor(id),\n String(getLogMaxBytes(this.env)),\n donePath,\n ...(request.interactive ? [this.paths.rawLogPathFor(id)] : []),\n ]);\n }\n\n private async monitor(tmux: ITmuxClient, target: string, aux: SupervisorPaths): Promise<ExitResult> {\n try {\n const paneCode = await waitForRunEnd(tmux, target, aux.exit);\n await waitForLogDrain(tmux, target, aux.logDone);\n return readExitMetadata(aux.exit) ?? { code: paneCode, signal: null };\n } finally {\n if (!(await tmux.sessionMissing(target).catch(() => false))) await killSession(tmux, target);\n cleanupSupervisorFiles(aux);\n }\n }\n\n private interactiveRun(\n handle: RunHandle,\n tmux: ITmuxClient,\n target: string,\n completion: Promise<ExitResult>,\n ): PtyRun {\n let screen = '';\n let active = true;\n const handlers = new Set<(data: string) => void>();\n const refresh = async (): Promise<void> => {\n while (active) {\n const captured = await tmux.run(['capture-pane', '-p', '-t', target]).catch((error: unknown) => {\n process.emitWarning(`Could not capture tmux screen for ${handle.name}: ${errorMessage(error)}`);\n return undefined;\n });\n const next = captured?.returnCode === 0 ? captured.stdout : screen;\n if (next !== screen) {\n screen = next;\n for (const handler of handlers) handler(next);\n }\n await delay(POLL_MS);\n }\n };\n void refresh();\n void completion\n .finally(() => {\n active = false;\n })\n .catch((error: unknown) =>\n process.emitWarning(`tmux interactive completion failed for ${handle.name}: ${errorMessage(error)}`),\n );\n return {\n ...handle,\n write: (text) => {\n void tmux\n .run(['send-keys', '-t', target, '-l', text])\n .catch((error: unknown) => process.emitWarning(errorMessage(error)));\n },\n screen: () => screen,\n onData: (handler) => {\n handlers.add(handler);\n return () => handlers.delete(handler);\n },\n resize: (cols, rows) => {\n void tmux\n .run(['resize-window', '-t', target, '-x', String(cols), '-y', String(rows)])\n .catch((error: unknown) => process.emitWarning(errorMessage(error)));\n },\n };\n }\n}\n\nfunction socketName(repositoryPath: string): string {\n const hash = createHash('sha256').update(repositoryPath).digest('hex').slice(0, SOCKET_HASH_LENGTH);\n return `${SOCKET_PREFIX}${hash}`;\n}\n\nfunction environment(\n sessionId: string,\n interactive: boolean,\n env: Readonly<Record<string, string | undefined>>,\n): Record<string, string> {\n const values: NodeJS.ProcessEnv = {\n ...env,\n ...(interactive ? {} : { ...NON_INTERACTIVE_ENV, ...noninteractiveEnvironment(env) }),\n ...NO_TERMINAL_INPUT_ENV,\n PI_SESSION_ID: sessionId,\n };\n if (!interactive) delete values['FORCE_COLOR'];\n return Object.fromEntries(\n Object.entries(values).filter((entry): entry is [string, string] => entry[1] !== undefined),\n );\n}\n\nasync function killSession(tmux: ITmuxClient, target: string): Promise<boolean> {\n const result = await tmux.run(['kill-session', '-t', target]).catch((error: unknown) => {\n process.emitWarning(`Could not close tmux target ${target}: ${errorMessage(error)}`);\n return undefined;\n });\n return result?.returnCode === 0;\n}\n\nasync function panePid(tmux: ITmuxClient, target: string): Promise<number> {\n const message = await tmux.format(target, '#{pane_pid}');\n const pid = Number(message);\n if (!Number.isInteger(pid) || pid <= 0) throw new Error(`tmux did not report a pane pid for ${target}`);\n return pid;\n}\n\n/**\n * Waits for the run to end, preferring the supervisor's own record of it.\n *\n * The sidecar is written before the pane can end and outlives the server the\n * pane's exit takes down, so asking tmux is the fallback for a supervisor that\n * died without recording anything.\n */\nasync function waitForRunEnd(tmux: ITmuxClient, target: string, exitPath: string): Promise<number | null> {\n for (;;) {\n if (fs.existsSync(exitPath)) return null;\n const state = await readPaneExit(tmux, target);\n if (state.exited) return state.code;\n await delay(POLL_MS);\n }\n}\n\nasync function waitForLogDrain(tmux: ITmuxClient, target: string, donePath: string): Promise<void> {\n const deadline = Date.now() + LOG_DRAIN_TIMEOUT_MS;\n while (Date.now() < deadline) {\n if (fs.existsSync(donePath)) return;\n if (await tmux.sessionMissing(target)) return;\n await delay(LOG_DRAIN_POLL_MS);\n }\n}\n\nasync function waitForPaneStop(tmux: ITmuxClient, target: string, timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if ((await readPaneExit(tmux, target)).exited) return true;\n await delay(POLL_MS);\n }\n return false;\n}\n\n/** One formatted read answers both questions this poll asks. */\nasync function readPaneExit(tmux: ITmuxClient, target: string): Promise<{ exited: boolean; code: number | null }> {\n const message = await tmux.format(target, PANE_STATE_FORMAT);\n // An unreachable server is the ordinary end of the last run: the pane exiting\n // ends its session, and the last session ending stops the server.\n if (message === undefined) return { exited: true, code: null };\n const [dead, status, ...rest] = message.trim().split(':');\n if (rest.join(':') === '') return { exited: true, code: null };\n if (dead === '1' || dead === 'true') {\n const code = Number(status);\n return { exited: true, code: Number.isInteger(code) ? code : null };\n }\n return { exited: false, code: null };\n}\n\nfunction signalPane(pid: number, target: string): 'signalled' | 'gone' | 'failed' {\n try {\n process.kill(pid, 'SIGTERM');\n return 'signalled';\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ESRCH') return 'gone';\n process.emitWarning(`Could not signal tmux target ${target}: ${errorMessage(error)}`);\n return 'failed';\n }\n}\n\nfunction readTail(target: string, maxBytes: number): string {\n let handle: number | undefined;\n try {\n const size = fs.statSync(target).size;\n const bytes = Math.min(size, maxBytes);\n const buffer = Buffer.alloc(bytes);\n handle = fs.openSync(target, 'r');\n fs.readSync(handle, buffer, 0, bytes, size - bytes);\n return buffer.toString('utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n process.emitWarning(`Could not read tmux log ${target}: ${errorMessage(error)}`);\n }\n return '';\n } finally {\n if (handle !== undefined) fs.closeSync(handle);\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n const timer = setTimeout(resolve, ms);\n timer.unref?.();\n });\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import { sharedExecutionBudget, type PoHostExecutionBudget } from '@agimon-ai/po-core/packageApi';\n\nimport { BashRunService } from '../bashRunService';\nimport { SystemClock } from '../clock';\nimport { Launcher } from '../launcher';\nimport { NodeLifeline } from '../lifeline';\nimport { LogFile } from '../logFile';\nimport { LogReader } from '../logReader';\nimport { NodeProcessControl } from '../processControl';\nimport { PtyBackendChain } from '../ptyBackendChain';\nimport { PtyHost } from '../ptyHost';\nimport { NodePtySpawner } from '../ptySpawner';\nimport { RmuxBackend } from '../rmuxBackend';\nimport { RtkProcessor } from '../rtkProcessor';\nimport { RunnerNamer } from '../runnerNamer';\nimport { RunnerPaths } from '../runnerPaths';\nimport { RunnerRegistry, createDefaultProcessRegistry } from '../runnerRegistry';\nimport { NodeSpawner } from '../spawner';\nimport { TmuxBackend } from '../tmuxBackend';\nimport type { RunnerDependencies } from './type';\n/** Build once on first access, then hand back the same instance. */\nfunction memoize<T>(build: () => T): () => T {\n let value: T | undefined;\n let built = false;\n return () => {\n if (!built) {\n value = build();\n built = true;\n }\n return value as T;\n };\n}\n\n/**\n * Builds the extension's service graph.\n *\n * A factory rather than a module-level singleton: the extension owns one graph\n * per session, and tests get a fresh one they can substitute ports on through\n * `overrides` without leaking state between cases.\n *\n * Every slot resolves lazily and memoizes, which keeps the previous container's\n * behaviour: nothing is constructed until it is asked for, so opening the SQLite\n * process registry stays deferred until something actually needs a runner.\n */\nexport function createRunnerDependencies(\n overrides: Partial<RunnerDependencies> & {\n environment: Readonly<Record<string, string | undefined>>;\n cwd?: string;\n executionBudget?: PoHostExecutionBudget;\n },\n): RunnerDependencies {\n const settings =\n overrides.settings === undefined\n ? undefined\n : Object.freeze({\n ...overrides.settings,\n ...(overrides.settings?.errorPatterns\n ? { errorPatterns: Object.freeze([...overrides.settings.errorPatterns]) }\n : {}),\n });\n const environment = { ...overrides.environment };\n const cwd = overrides.cwd ?? process.cwd();\n const clock = memoize(() => overrides.clock ?? new SystemClock());\n const spawner = memoize(() => overrides.spawner ?? new NodeSpawner());\n const processControl = memoize(() => overrides.processControl ?? new NodeProcessControl());\n const ptySpawner = memoize(() => overrides.ptySpawner ?? new NodePtySpawner());\n const paths = memoize(() => overrides.paths ?? new RunnerPaths(cwd, environment));\n const lifeline = memoize(() => overrides.lifeline ?? new NodeLifeline(paths()));\n const processRegistry = memoize(() => overrides.processRegistry ?? createDefaultProcessRegistry(environment));\n const runnerRegistry = memoize(\n () => overrides.runnerRegistry ?? new RunnerRegistry(paths(), processControl(), processRegistry(), environment),\n );\n const namer = memoize(() => overrides.namer ?? new RunnerNamer(runnerRegistry()));\n const logFile = memoize(() => overrides.logFile ?? new LogFile(paths()));\n const logReader = memoize(() => overrides.logReader ?? new LogReader());\n const launcher = memoize(\n () =>\n overrides.launcher ??\n new Launcher(spawner(), processControl(), logFile(), clock(), paths(), lifeline(), environment, settings),\n );\n const rmuxBackend = memoize(\n () =>\n overrides.rmuxBackend ??\n new PtyBackendChain(\n new RmuxBackend(paths(), environment, settings),\n new TmuxBackend(paths(), undefined, environment, settings),\n ),\n );\n const rtkProcessor = memoize(\n () => overrides.rtkProcessor ?? new RtkProcessor(undefined, undefined, environment, settings),\n );\n const ptyHost = memoize(\n () => overrides.ptyHost ?? new PtyHost(ptySpawner(), logFile(), processControl(), clock(), environment, settings),\n );\n const bashRunService = memoize(\n () =>\n overrides.bashRunService ??\n new BashRunService(\n launcher(),\n rmuxBackend(),\n namer(),\n runnerRegistry(),\n clock(),\n rtkProcessor(),\n cwd,\n environment,\n overrides.executionBudget ?? sharedExecutionBudget(environment),\n ),\n );\n\n return {\n settings,\n environment,\n get clock() {\n return clock();\n },\n get spawner() {\n return spawner();\n },\n get processControl() {\n return processControl();\n },\n get ptySpawner() {\n return ptySpawner();\n },\n get paths() {\n return paths();\n },\n get lifeline() {\n return lifeline();\n },\n get processRegistry() {\n return processRegistry();\n },\n get runnerRegistry() {\n return runnerRegistry();\n },\n get namer() {\n return namer();\n },\n get logFile() {\n return logFile();\n },\n get logReader() {\n return logReader();\n },\n get launcher() {\n return launcher();\n },\n get rmuxBackend() {\n return rmuxBackend();\n },\n get rtkProcessor() {\n return rtkProcessor();\n },\n get ptyHost() {\n return ptyHost();\n },\n get bashRunService() {\n return bashRunService();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_bashRunService = require("./bashRunService-
|
|
2
|
+
const require_bashRunService = require("./bashRunService-CJhMNrPz.cjs");
|
|
3
3
|
const require_runnerConfig = require("./runnerConfig-BoLMinlx.cjs");
|
|
4
4
|
const require_logReader = require("./logReader-DHCK2BEr.cjs");
|
|
5
5
|
const require_clock = require("./clock-jqnLWziT.cjs");
|
|
@@ -664,4 +664,4 @@ Object.defineProperty(exports, "createRunnerDependencies", {
|
|
|
664
664
|
}
|
|
665
665
|
});
|
|
666
666
|
|
|
667
|
-
//# sourceMappingURL=runnerDependencies-
|
|
667
|
+
//# sourceMappingURL=runnerDependencies-vkpJfxZZ.cjs.map
|