@agimon-ai/doompi-runner 0.0.1-alpha.31 → 0.0.1-alpha.33
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/README.md +19 -5
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +2 -2
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +1 -1
- package/dist/src/adapters/RunnerSettings/RunnerSettingsLoader.cjs +1 -1
- package/dist/src/adapters/RunnerSettings/RunnerSettingsLoader.cjs.map +1 -1
- package/dist/src/adapters/RunnerSettings/RunnerSettingsLoader.mjs +1 -1
- package/dist/src/adapters/RunnerSettings/RunnerSettingsLoader.mjs.map +1 -1
- package/dist/src/adapters/pi/extension.cjs +1 -1
- package/dist/src/adapters/pi/extension.cjs.map +1 -1
- package/dist/src/adapters/pi/extension.mjs +1 -1
- package/dist/src/adapters/pi/extension.mjs.map +1 -1
- package/dist/src/commands/bash/bashTool.cjs +2 -2
- package/dist/src/commands/bash/bashTool.cjs.map +1 -1
- package/dist/src/commands/bash/bashTool.d.cts.map +1 -1
- package/dist/src/commands/bash/bashTool.d.mts.map +1 -1
- package/dist/src/commands/bash/bashTool.mjs +5 -5
- package/dist/src/commands/bash/bashTool.mjs.map +1 -1
- package/dist/src/commands/bash/responseEnvelope.cjs +10 -10
- package/dist/src/commands/bash/responseEnvelope.cjs.map +1 -1
- package/dist/src/commands/bash/responseEnvelope.d.cts +4 -3
- package/dist/src/commands/bash/responseEnvelope.d.cts.map +1 -1
- package/dist/src/commands/bash/responseEnvelope.d.mts +4 -3
- package/dist/src/commands/bash/responseEnvelope.d.mts.map +1 -1
- package/dist/src/commands/bash/responseEnvelope.mjs +10 -10
- package/dist/src/commands/bash/responseEnvelope.mjs.map +1 -1
- package/dist/src/services/TokenEstimate/tokenEstimate.cjs +2 -0
- package/dist/src/services/TokenEstimate/tokenEstimate.cjs.map +1 -0
- package/dist/src/services/TokenEstimate/tokenEstimate.mjs +2 -0
- package/dist/src/services/TokenEstimate/tokenEstimate.mjs.map +1 -0
- package/dist/src/tui/runnerSpace.cjs.map +1 -1
- package/dist/src/tui/runnerSpace.mjs.map +1 -1
- package/dist/src/types/config.cjs +1 -1
- package/dist/src/types/config.cjs.map +1 -1
- package/dist/src/types/config.d.cts +14 -1
- package/dist/src/types/config.d.cts.map +1 -1
- package/dist/src/types/config.d.mts +14 -1
- package/dist/src/types/config.d.mts.map +1 -1
- package/dist/src/types/config.mjs +1 -1
- package/dist/src/types/config.mjs.map +1 -1
- package/dist/src/types/runnerSettings.d.cts +4 -0
- package/dist/src/types/runnerSettings.d.cts.map +1 -1
- package/dist/src/types/runnerSettings.d.mts +4 -0
- package/dist/src/types/runnerSettings.d.mts.map +1 -1
- package/package.json +12 -12
- package/skills/doom-runner/SKILL.md +1 -1
- package/src/prompts/doompi-use-runner/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -59,7 +59,7 @@ also returns bounded raw output with a warning and does not change the command e
|
|
|
59
59
|
|
|
60
60
|
## Inspect and control runs
|
|
61
61
|
|
|
62
|
-
Use `/runners` or `SPC r
|
|
62
|
+
Use `/runners` or `SPC r l` in the TUI. The `doom-runner` CLI supports:
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
65
|
doom-runner list
|
|
@@ -108,9 +108,21 @@ exit status 0
|
|
|
108
108
|
Full log: /path/to/run.log (17.0 KB, 604 lines); inspect with doom-runner logs run-a
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
for
|
|
111
|
+
Three ceilings apply and whichever binds first wins: bytes, lines, and tokens. Tokens are there
|
|
112
|
+
because bytes do not track context cost. Measured against `gpt-tokenizer`, real text runs from about
|
|
113
|
+
1.4 characters per token for base64 to 4.7 for English prose, so 8 KiB of one costs several times
|
|
114
|
+
what 8 KiB of the other does. The defaults are 2,048 tokens on failure and 512 on success.
|
|
115
|
+
|
|
116
|
+
Token counts are estimated rather than tokenized: truncation runs on every command and is
|
|
117
|
+
synchronous, so loading a vocabulary would charge every session for a table most never need. The
|
|
118
|
+
estimator models how BPE behaves, with punctuation forcing boundaries, natural words cheap, and
|
|
119
|
+
letter-digit runs expensive. Its worst error against `gpt-tokenizer` is a factor of about 1.46
|
|
120
|
+
either way, which is why the byte ceiling stays behind it as the hard bound.
|
|
121
|
+
|
|
122
|
+
`DOOM_RUNNER_RESULT_MAX_BYTES`, `DOOM_RUNNER_RESULT_MAX_TOKENS`, and their
|
|
123
|
+
`DOOM_RUNNER_SUCCESS_*` counterparts move these for one invocation. A pragma overrides all of
|
|
124
|
+
them, which is how one noisy successful command can still ask for the wider result. Raising only
|
|
125
|
+
`maxResultBytes` will not help when the token ceiling is the one binding.
|
|
114
126
|
|
|
115
127
|
Error lines found in the dropped span are rescued into that marker's block, up to ten entries.
|
|
116
128
|
Matching looks for a severity word in the first 60 characters, so `[widget] build: error TS2322`
|
|
@@ -135,7 +147,7 @@ One command that needs a wider result can say so on its first line. The pragma i
|
|
|
135
147
|
so it stays harmless to the command itself:
|
|
136
148
|
|
|
137
149
|
```bash
|
|
138
|
-
# @doom: {"maxResultBytes": 32768, "maxResultLines": 300}
|
|
150
|
+
# @doom: {"maxResultBytes": 32768, "maxResultTokens": 8192, "maxResultLines": 300}
|
|
139
151
|
pnpm build
|
|
140
152
|
```
|
|
141
153
|
|
|
@@ -148,6 +160,8 @@ trusted, and an unrecognized or out-of-range key is reported rather than silentl
|
|
|
148
160
|
"maxResultBytes": 16384,
|
|
149
161
|
"maxResultLines": 200,
|
|
150
162
|
"successMaxResultBytes": 2048,
|
|
163
|
+
"maxResultTokens": 2048,
|
|
164
|
+
"successMaxResultTokens": 512,
|
|
151
165
|
"headRatio": 0.2,
|
|
152
166
|
"errorPatterns": ["^FEHLER", "^\\s*FAILED\\b"],
|
|
153
167
|
"errorMaxEntries": 10,
|
package/dist/config.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src/types/config.cjs");exports.BG_THRESHOLD_MS_ENV=e.BG_THRESHOLD_MS_ENV,exports.DEFAULT_BG_THRESHOLD_MS=e.DEFAULT_BG_THRESHOLD_MS,exports.DEFAULT_ERROR_BUDGET_RATIO=e.DEFAULT_ERROR_BUDGET_RATIO,exports.DEFAULT_ERROR_MAX_ENTRIES=e.DEFAULT_ERROR_MAX_ENTRIES,exports.DEFAULT_ERROR_MAX_VARIANTS_JOINED=e.DEFAULT_ERROR_MAX_VARIANTS_JOINED,exports.DEFAULT_HEAD_RATIO=e.DEFAULT_HEAD_RATIO,exports.DEFAULT_LOG_MAX_BYTES=e.DEFAULT_LOG_MAX_BYTES,exports.DEFAULT_LOG_TTL_MS=e.DEFAULT_LOG_TTL_MS,exports.DEFAULT_RESULT_MAX_BYTES=e.DEFAULT_RESULT_MAX_BYTES,exports.DEFAULT_RESULT_MAX_LINES=e.DEFAULT_RESULT_MAX_LINES,exports.DEFAULT_SUCCESS_RESULT_MAX_BYTES=e.DEFAULT_SUCCESS_RESULT_MAX_BYTES,exports.LOG_DIR_ENV=e.LOG_DIR_ENV,exports.LOG_MAX_BYTES_ENV=e.LOG_MAX_BYTES_ENV,exports.LOG_TTL_MS_ENV=e.LOG_TTL_MS_ENV,exports.RESULT_MAX_BYTES_ENV=e.RESULT_MAX_BYTES_ENV,exports.SUCCESS_RESULT_MAX_BYTES_ENV=e.SUCCESS_RESULT_MAX_BYTES_ENV,exports.getBackgroundThresholdMs=e.getBackgroundThresholdMs,exports.getErrorBudgetRatio=e.getErrorBudgetRatio,exports.getErrorMaxEntries=e.getErrorMaxEntries,exports.getErrorMaxVariantsJoined=e.getErrorMaxVariantsJoined,exports.getErrorPatterns=e.getErrorPatterns,exports.getHeadRatio=e.getHeadRatio,exports.getLogMaxBytes=e.getLogMaxBytes,exports.getLogTtlMs=e.getLogTtlMs,exports.getResultMaxBytes=e.getResultMaxBytes,exports.getResultMaxLines=e.getResultMaxLines,exports.getRunnerSettings=e.getRunnerSettings,exports.getSuccessResultMaxBytes=e.getSuccessResultMaxBytes,exports.setRunnerSettings=e.setRunnerSettings;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src/types/config.cjs");exports.BG_THRESHOLD_MS_ENV=e.BG_THRESHOLD_MS_ENV,exports.DEFAULT_BG_THRESHOLD_MS=e.DEFAULT_BG_THRESHOLD_MS,exports.DEFAULT_ERROR_BUDGET_RATIO=e.DEFAULT_ERROR_BUDGET_RATIO,exports.DEFAULT_ERROR_MAX_ENTRIES=e.DEFAULT_ERROR_MAX_ENTRIES,exports.DEFAULT_ERROR_MAX_VARIANTS_JOINED=e.DEFAULT_ERROR_MAX_VARIANTS_JOINED,exports.DEFAULT_HEAD_RATIO=e.DEFAULT_HEAD_RATIO,exports.DEFAULT_LOG_MAX_BYTES=e.DEFAULT_LOG_MAX_BYTES,exports.DEFAULT_LOG_TTL_MS=e.DEFAULT_LOG_TTL_MS,exports.DEFAULT_RESULT_MAX_BYTES=e.DEFAULT_RESULT_MAX_BYTES,exports.DEFAULT_RESULT_MAX_LINES=e.DEFAULT_RESULT_MAX_LINES,exports.DEFAULT_RESULT_MAX_TOKENS=e.DEFAULT_RESULT_MAX_TOKENS,exports.DEFAULT_SUCCESS_RESULT_MAX_BYTES=e.DEFAULT_SUCCESS_RESULT_MAX_BYTES,exports.DEFAULT_SUCCESS_RESULT_MAX_TOKENS=e.DEFAULT_SUCCESS_RESULT_MAX_TOKENS,exports.LOG_DIR_ENV=e.LOG_DIR_ENV,exports.LOG_MAX_BYTES_ENV=e.LOG_MAX_BYTES_ENV,exports.LOG_TTL_MS_ENV=e.LOG_TTL_MS_ENV,exports.RESULT_MAX_BYTES_ENV=e.RESULT_MAX_BYTES_ENV,exports.RESULT_MAX_TOKENS_ENV=e.RESULT_MAX_TOKENS_ENV,exports.SUCCESS_RESULT_MAX_BYTES_ENV=e.SUCCESS_RESULT_MAX_BYTES_ENV,exports.SUCCESS_RESULT_MAX_TOKENS_ENV=e.SUCCESS_RESULT_MAX_TOKENS_ENV,exports.getBackgroundThresholdMs=e.getBackgroundThresholdMs,exports.getErrorBudgetRatio=e.getErrorBudgetRatio,exports.getErrorMaxEntries=e.getErrorMaxEntries,exports.getErrorMaxVariantsJoined=e.getErrorMaxVariantsJoined,exports.getErrorPatterns=e.getErrorPatterns,exports.getHeadRatio=e.getHeadRatio,exports.getLogMaxBytes=e.getLogMaxBytes,exports.getLogTtlMs=e.getLogTtlMs,exports.getResultMaxBytes=e.getResultMaxBytes,exports.getResultMaxLines=e.getResultMaxLines,exports.getResultMaxTokens=e.getResultMaxTokens,exports.getRunnerSettings=e.getRunnerSettings,exports.getSuccessResultMaxBytes=e.getSuccessResultMaxBytes,exports.getSuccessResultMaxTokens=e.getSuccessResultMaxTokens,exports.setRunnerSettings=e.setRunnerSettings;
|
package/dist/config.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_SUCCESS_RESULT_MAX_BYTES, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getRunnerSettings, getSuccessResultMaxBytes, setRunnerSettings } from "./src/types/config.cjs";
|
|
2
|
-
export { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_SUCCESS_RESULT_MAX_BYTES, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getRunnerSettings, getSuccessResultMaxBytes, setRunnerSettings };
|
|
1
|
+
import { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_RESULT_MAX_TOKENS, DEFAULT_SUCCESS_RESULT_MAX_BYTES, DEFAULT_SUCCESS_RESULT_MAX_TOKENS, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, RESULT_MAX_TOKENS_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_TOKENS_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getResultMaxTokens, getRunnerSettings, getSuccessResultMaxBytes, getSuccessResultMaxTokens, setRunnerSettings } from "./src/types/config.cjs";
|
|
2
|
+
export { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_RESULT_MAX_TOKENS, DEFAULT_SUCCESS_RESULT_MAX_BYTES, DEFAULT_SUCCESS_RESULT_MAX_TOKENS, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, RESULT_MAX_TOKENS_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_TOKENS_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getResultMaxTokens, getRunnerSettings, getSuccessResultMaxBytes, getSuccessResultMaxTokens, setRunnerSettings };
|
package/dist/config.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_SUCCESS_RESULT_MAX_BYTES, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getRunnerSettings, getSuccessResultMaxBytes, setRunnerSettings } from "./src/types/config.mjs";
|
|
2
|
-
export { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_SUCCESS_RESULT_MAX_BYTES, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getRunnerSettings, getSuccessResultMaxBytes, setRunnerSettings };
|
|
1
|
+
import { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_RESULT_MAX_TOKENS, DEFAULT_SUCCESS_RESULT_MAX_BYTES, DEFAULT_SUCCESS_RESULT_MAX_TOKENS, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, RESULT_MAX_TOKENS_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_TOKENS_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getResultMaxTokens, getRunnerSettings, getSuccessResultMaxBytes, getSuccessResultMaxTokens, setRunnerSettings } from "./src/types/config.mjs";
|
|
2
|
+
export { BG_THRESHOLD_MS_ENV, DEFAULT_BG_THRESHOLD_MS, DEFAULT_ERROR_BUDGET_RATIO, DEFAULT_ERROR_MAX_ENTRIES, DEFAULT_ERROR_MAX_VARIANTS_JOINED, DEFAULT_HEAD_RATIO, DEFAULT_LOG_MAX_BYTES, DEFAULT_LOG_TTL_MS, DEFAULT_RESULT_MAX_BYTES, DEFAULT_RESULT_MAX_LINES, DEFAULT_RESULT_MAX_TOKENS, DEFAULT_SUCCESS_RESULT_MAX_BYTES, DEFAULT_SUCCESS_RESULT_MAX_TOKENS, LOG_DIR_ENV, LOG_MAX_BYTES_ENV, LOG_TTL_MS_ENV, RESULT_MAX_BYTES_ENV, RESULT_MAX_TOKENS_ENV, SUCCESS_RESULT_MAX_BYTES_ENV, SUCCESS_RESULT_MAX_TOKENS_ENV, getBackgroundThresholdMs, getErrorBudgetRatio, getErrorMaxEntries, getErrorMaxVariantsJoined, getErrorPatterns, getHeadRatio, getLogMaxBytes, getLogTtlMs, getResultMaxBytes, getResultMaxLines, getResultMaxTokens, getRunnerSettings, getSuccessResultMaxBytes, getSuccessResultMaxTokens, setRunnerSettings };
|
package/dist/config.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BG_THRESHOLD_MS_ENV as e,DEFAULT_BG_THRESHOLD_MS as t,DEFAULT_ERROR_BUDGET_RATIO as n,DEFAULT_ERROR_MAX_ENTRIES as r,DEFAULT_ERROR_MAX_VARIANTS_JOINED as i,DEFAULT_HEAD_RATIO as a,DEFAULT_LOG_MAX_BYTES as o,DEFAULT_LOG_TTL_MS as s,DEFAULT_RESULT_MAX_BYTES as c,DEFAULT_RESULT_MAX_LINES as l,
|
|
1
|
+
import{BG_THRESHOLD_MS_ENV as e,DEFAULT_BG_THRESHOLD_MS as t,DEFAULT_ERROR_BUDGET_RATIO as n,DEFAULT_ERROR_MAX_ENTRIES as r,DEFAULT_ERROR_MAX_VARIANTS_JOINED as i,DEFAULT_HEAD_RATIO as a,DEFAULT_LOG_MAX_BYTES as o,DEFAULT_LOG_TTL_MS as s,DEFAULT_RESULT_MAX_BYTES as c,DEFAULT_RESULT_MAX_LINES as l,DEFAULT_RESULT_MAX_TOKENS as u,DEFAULT_SUCCESS_RESULT_MAX_BYTES as d,DEFAULT_SUCCESS_RESULT_MAX_TOKENS as f,LOG_DIR_ENV as p,LOG_MAX_BYTES_ENV as m,LOG_TTL_MS_ENV as h,RESULT_MAX_BYTES_ENV as g,RESULT_MAX_TOKENS_ENV as _,SUCCESS_RESULT_MAX_BYTES_ENV as v,SUCCESS_RESULT_MAX_TOKENS_ENV as y,getBackgroundThresholdMs as b,getErrorBudgetRatio as x,getErrorMaxEntries as S,getErrorMaxVariantsJoined as C,getErrorPatterns as w,getHeadRatio as T,getLogMaxBytes as E,getLogTtlMs as D,getResultMaxBytes as O,getResultMaxLines as k,getResultMaxTokens as A,getRunnerSettings as j,getSuccessResultMaxBytes as M,getSuccessResultMaxTokens as N,setRunnerSettings as P}from"./src/types/config.mjs";export{e as BG_THRESHOLD_MS_ENV,t as DEFAULT_BG_THRESHOLD_MS,n as DEFAULT_ERROR_BUDGET_RATIO,r as DEFAULT_ERROR_MAX_ENTRIES,i as DEFAULT_ERROR_MAX_VARIANTS_JOINED,a as DEFAULT_HEAD_RATIO,o as DEFAULT_LOG_MAX_BYTES,s as DEFAULT_LOG_TTL_MS,c as DEFAULT_RESULT_MAX_BYTES,l as DEFAULT_RESULT_MAX_LINES,u as DEFAULT_RESULT_MAX_TOKENS,d as DEFAULT_SUCCESS_RESULT_MAX_BYTES,f as DEFAULT_SUCCESS_RESULT_MAX_TOKENS,p as LOG_DIR_ENV,m as LOG_MAX_BYTES_ENV,h as LOG_TTL_MS_ENV,g as RESULT_MAX_BYTES_ENV,_ as RESULT_MAX_TOKENS_ENV,v as SUCCESS_RESULT_MAX_BYTES_ENV,y as SUCCESS_RESULT_MAX_TOKENS_ENV,b as getBackgroundThresholdMs,x as getErrorBudgetRatio,S as getErrorMaxEntries,C as getErrorMaxVariantsJoined,w as getErrorPatterns,T as getHeadRatio,E as getLogMaxBytes,D as getLogTtlMs,O as getResultMaxBytes,k as getResultMaxLines,A as getResultMaxTokens,j as getRunnerSettings,M as getSuccessResultMaxBytes,N as getSuccessResultMaxTokens,P as setRunnerSettings};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("@earendil-works/pi-coding-agent");const i=`doompi-runner.json`,a={settings:{},issues:[]},o=[`headRatio`,`errorBudgetRatio`],s=[`maxResultBytes`,`maxResultLines`,`successMaxResultBytes`,`errorMaxEntries`,`errorMaxVariantsJoined`],c=new Set([...o,...s,`errorPatterns`]),l=262144,u={maxResultBytes:l,successMaxResultBytes:l,maxResultLines:5e3,errorMaxEntries:100,errorMaxVariantsJoined:100};var
|
|
1
|
+
const e=require("../../../_virtual/_rolldown/runtime.cjs");let t=require("node:fs");t=e.__toESM(t,1);let n=require("node:path");n=e.__toESM(n,1);let r=require("@earendil-works/pi-coding-agent");const i=`doompi-runner.json`,a={settings:{},issues:[]},o=[`headRatio`,`errorBudgetRatio`],s=[`maxResultBytes`,`maxResultLines`,`successMaxResultBytes`,`maxResultTokens`,`successMaxResultTokens`,`errorMaxEntries`,`errorMaxVariantsJoined`],c=new Set([...o,...s,`errorPatterns`]),l=262144,u=1e5,d={maxResultBytes:l,successMaxResultBytes:l,maxResultTokens:u,successMaxResultTokens:u,maxResultLines:5e3,errorMaxEntries:100,errorMaxVariantsJoined:100};var f=class{load(e,o){if(!o)return a;let s;try{s=t.default.readFileSync(n.default.join(e,r.CONFIG_DIR_NAME,i),`utf8`)}catch(e){return e.code===`ENOENT`?a:{settings:{},issues:[`${i} could not be read`]}}let c;try{c=JSON.parse(s)}catch{return{settings:{},issues:[`${i} is not valid JSON`]}}return p(c)}};function p(e){if(typeof e!=`object`||!e||Array.isArray(e))return{settings:{},issues:[`${i} must contain a JSON object`]};let t=e,n={},r=[];for(let e of Object.keys(t))c.has(e)||r.push(`unknown key ${e}`);for(let e of s){let i=t[e];if(i!==void 0){if(typeof i!=`number`||!Number.isInteger(i)||i<=0){r.push(`${e} must be a positive integer`);continue}n[e]=Math.min(i,d[e]??i)}}for(let e of o){let i=t[e];if(i!==void 0){if(typeof i!=`number`||!Number.isFinite(i)||i<=0||i>=1){r.push(`${e} must be a number above 0 and below 1`);continue}n[e]=i}}let a=t.errorPatterns;if(a!==void 0){if(!Array.isArray(a)||a.some(e=>typeof e!=`string`))r.push(`errorPatterns must be an array of strings`);else{let e=[];for(let t of a.slice(0,32)){if(t.length>512){r.push(`errorPatterns entry is too long`);continue}try{new RegExp(t,`iu`),e.push(t)}catch{r.push(`errorPatterns entry is not a valid regular expression: ${t}`)}}e.length>0&&(n.errorPatterns=e)}}return{settings:n,issues:r}}exports.RUNNER_SETTINGS_FILE=i,exports.RunnerSettingsLoader=f;
|
|
2
2
|
//# sourceMappingURL=RunnerSettingsLoader.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunnerSettingsLoader.cjs","names":["fs","path","CONFIG_DIR_NAME"],"sources":["../../../../src/adapters/RunnerSettings/RunnerSettingsLoader.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_DIR_NAME } from '@earendil-works/pi-coding-agent';\nimport type { IRunnerSettingsLoader, RunnerSettings, RunnerSettingsLoad } from '../../types/runnerSettings';\n\n/** Pi's convention is one JSON file per extension under the config directory. */\nexport const RUNNER_SETTINGS_FILE = 'doompi-runner.json';\n\nconst EMPTY: RunnerSettingsLoad = { settings: {}, issues: [] };\nconst RATIO_KEYS = ['headRatio', 'errorBudgetRatio'] as const;\nconst COUNT_KEYS = [\n 'maxResultBytes',\n 'maxResultLines',\n 'successMaxResultBytes',\n 'errorMaxEntries',\n 'errorMaxVariantsJoined',\n] as const;\nconst KNOWN_KEYS = new Set<string>([...RATIO_KEYS, ...COUNT_KEYS, 'errorPatterns']);\n/** Ceilings so a project file cannot flood the model's context. */\nconst MAX_RESULT_BYTES_CEILING = 262_144;\nconst MAX_RESULT_LINES_CEILING = 5_000;\nconst MAX_ERROR_ENTRIES_CEILING = 100;\nconst MAX_PATTERNS = 32;\nconst MAX_PATTERN_LENGTH = 512;\nconst CEILINGS: Readonly<Record<string, number>> = {\n maxResultBytes: MAX_RESULT_BYTES_CEILING,\n successMaxResultBytes: MAX_RESULT_BYTES_CEILING,\n maxResultLines: MAX_RESULT_LINES_CEILING,\n errorMaxEntries: MAX_ERROR_ENTRIES_CEILING,\n errorMaxVariantsJoined: MAX_ERROR_ENTRIES_CEILING,\n};\n\nexport class RunnerSettingsLoader implements IRunnerSettingsLoader {\n load(cwd: string, trusted: boolean): RunnerSettingsLoad {\n // Project-local configuration is untrusted input until the project is.\n if (!trusted) return EMPTY;\n\n let raw: string;\n try {\n raw = fs.readFileSync(path.join(cwd, CONFIG_DIR_NAME, RUNNER_SETTINGS_FILE), 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return EMPTY;\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} could not be read`] };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} is not valid JSON`] };\n }\n return validate(parsed);\n }\n}\n\nfunction validate(parsed: unknown): RunnerSettingsLoad {\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} must contain a JSON object`] };\n }\n\n const source = parsed as Record<string, unknown>;\n const settings: Record<string, unknown> = {};\n const issues: string[] = [];\n // A rejected key is reported rather than dropped: a silent typo reads as a\n // setting that simply does not work.\n for (const key of Object.keys(source)) if (!KNOWN_KEYS.has(key)) issues.push(`unknown key ${key}`);\n\n for (const key of COUNT_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {\n issues.push(`${key} must be a positive integer`);\n continue;\n }\n settings[key] = Math.min(value, CEILINGS[key] ?? value);\n }\n\n for (const key of RATIO_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0 || value >= 1) {\n issues.push(`${key} must be a number above 0 and below 1`);\n continue;\n }\n settings[key] = value;\n }\n\n const patterns = source.errorPatterns;\n if (patterns !== undefined) {\n if (!Array.isArray(patterns) || patterns.some((entry) => typeof entry !== 'string')) {\n issues.push('errorPatterns must be an array of strings');\n } else {\n const accepted: string[] = [];\n for (const pattern of patterns.slice(0, MAX_PATTERNS) as string[]) {\n if (pattern.length > MAX_PATTERN_LENGTH) {\n issues.push('errorPatterns entry is too long');\n continue;\n }\n try {\n new RegExp(pattern, 'iu');\n accepted.push(pattern);\n } catch {\n issues.push(`errorPatterns entry is not a valid regular expression: ${pattern}`);\n }\n }\n if (accepted.length > 0) settings.errorPatterns = accepted;\n }\n }\n\n return { settings: settings as RunnerSettings, issues };\n}\n"],"mappings":"kMAMA,MAAa,EAAuB,qBAE9B,EAA4B,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,CAAE,EACvD,EAAa,CAAC,YAAa,kBAAkB,EAC7C,EAAa,CACjB,iBACA,iBACA,wBACA,kBACA,wBACF,EACM,EAAa,IAAI,IAAY,CAAC,GAAG,EAAY,GAAG,EAAY,eAAe,CAAC,EAE5E,EAA2B,
|
|
1
|
+
{"version":3,"file":"RunnerSettingsLoader.cjs","names":["fs","path","CONFIG_DIR_NAME"],"sources":["../../../../src/adapters/RunnerSettings/RunnerSettingsLoader.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_DIR_NAME } from '@earendil-works/pi-coding-agent';\nimport type { IRunnerSettingsLoader, RunnerSettings, RunnerSettingsLoad } from '../../types/runnerSettings';\n\n/** Pi's convention is one JSON file per extension under the config directory. */\nexport const RUNNER_SETTINGS_FILE = 'doompi-runner.json';\n\nconst EMPTY: RunnerSettingsLoad = { settings: {}, issues: [] };\nconst RATIO_KEYS = ['headRatio', 'errorBudgetRatio'] as const;\nconst COUNT_KEYS = [\n 'maxResultBytes',\n 'maxResultLines',\n 'successMaxResultBytes',\n 'maxResultTokens',\n 'successMaxResultTokens',\n 'errorMaxEntries',\n 'errorMaxVariantsJoined',\n] as const;\nconst KNOWN_KEYS = new Set<string>([...RATIO_KEYS, ...COUNT_KEYS, 'errorPatterns']);\n/** Ceilings so a project file cannot flood the model's context. */\nconst MAX_RESULT_BYTES_CEILING = 262_144;\nconst MAX_RESULT_LINES_CEILING = 5_000;\nconst MAX_RESULT_TOKENS_CEILING = 100_000;\nconst MAX_ERROR_ENTRIES_CEILING = 100;\nconst MAX_PATTERNS = 32;\nconst MAX_PATTERN_LENGTH = 512;\nconst CEILINGS: Readonly<Record<string, number>> = {\n maxResultBytes: MAX_RESULT_BYTES_CEILING,\n successMaxResultBytes: MAX_RESULT_BYTES_CEILING,\n maxResultTokens: MAX_RESULT_TOKENS_CEILING,\n successMaxResultTokens: MAX_RESULT_TOKENS_CEILING,\n maxResultLines: MAX_RESULT_LINES_CEILING,\n errorMaxEntries: MAX_ERROR_ENTRIES_CEILING,\n errorMaxVariantsJoined: MAX_ERROR_ENTRIES_CEILING,\n};\n\nexport class RunnerSettingsLoader implements IRunnerSettingsLoader {\n load(cwd: string, trusted: boolean): RunnerSettingsLoad {\n // Project-local configuration is untrusted input until the project is.\n if (!trusted) return EMPTY;\n\n let raw: string;\n try {\n raw = fs.readFileSync(path.join(cwd, CONFIG_DIR_NAME, RUNNER_SETTINGS_FILE), 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return EMPTY;\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} could not be read`] };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} is not valid JSON`] };\n }\n return validate(parsed);\n }\n}\n\nfunction validate(parsed: unknown): RunnerSettingsLoad {\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} must contain a JSON object`] };\n }\n\n const source = parsed as Record<string, unknown>;\n const settings: Record<string, unknown> = {};\n const issues: string[] = [];\n // A rejected key is reported rather than dropped: a silent typo reads as a\n // setting that simply does not work.\n for (const key of Object.keys(source)) if (!KNOWN_KEYS.has(key)) issues.push(`unknown key ${key}`);\n\n for (const key of COUNT_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {\n issues.push(`${key} must be a positive integer`);\n continue;\n }\n settings[key] = Math.min(value, CEILINGS[key] ?? value);\n }\n\n for (const key of RATIO_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0 || value >= 1) {\n issues.push(`${key} must be a number above 0 and below 1`);\n continue;\n }\n settings[key] = value;\n }\n\n const patterns = source.errorPatterns;\n if (patterns !== undefined) {\n if (!Array.isArray(patterns) || patterns.some((entry) => typeof entry !== 'string')) {\n issues.push('errorPatterns must be an array of strings');\n } else {\n const accepted: string[] = [];\n for (const pattern of patterns.slice(0, MAX_PATTERNS) as string[]) {\n if (pattern.length > MAX_PATTERN_LENGTH) {\n issues.push('errorPatterns entry is too long');\n continue;\n }\n try {\n new RegExp(pattern, 'iu');\n accepted.push(pattern);\n } catch {\n issues.push(`errorPatterns entry is not a valid regular expression: ${pattern}`);\n }\n }\n if (accepted.length > 0) settings.errorPatterns = accepted;\n }\n }\n\n return { settings: settings as RunnerSettings, issues };\n}\n"],"mappings":"kMAMA,MAAa,EAAuB,qBAE9B,EAA4B,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,CAAE,EACvD,EAAa,CAAC,YAAa,kBAAkB,EAC7C,EAAa,CACjB,iBACA,iBACA,wBACA,kBACA,yBACA,kBACA,wBACF,EACM,EAAa,IAAI,IAAY,CAAC,GAAG,EAAY,GAAG,EAAY,eAAe,CAAC,EAE5E,EAA2B,OAE3B,EAA4B,IAI5B,EAA6C,CACjD,eAAgB,EAChB,sBAAuB,EACvB,gBAAiB,EACjB,uBAAwB,EACxB,eAAgB,IAChB,gBAAiB,IACjB,uBAAwB,GAC1B,EAEA,IAAa,EAAb,KAAmE,CACjE,KAAK,EAAa,EAAsC,CAEtD,GAAI,CAAC,EAAS,OAAO,EAErB,IAAI,EACJ,GAAI,CACF,EAAMA,EAAAA,QAAG,aAAaC,EAAAA,QAAK,KAAK,EAAKC,EAAAA,gBAAiB,CAAoB,EAAG,MAAM,CACrF,OAAS,EAAO,CAEd,OADK,EAAgC,OAAS,SAAiB,EACxD,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,GAAG,EAAqB,mBAAmB,CAAE,CAC/E,CAEA,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAG,CACzB,MAAQ,CACN,MAAO,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,GAAG,EAAqB,mBAAmB,CAAE,CAC/E,CACA,OAAO,EAAS,CAAM,CACxB,CACF,EAEA,SAAS,EAAS,EAAqC,CACrD,GAAI,OAAO,GAAW,WAAY,GAAmB,MAAM,QAAQ,CAAM,EACvE,MAAO,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,GAAG,EAAqB,4BAA4B,CAAE,EAGxF,IAAM,EAAS,EACT,EAAoC,CAAC,EACrC,EAAmB,CAAC,EAG1B,IAAK,IAAM,KAAO,OAAO,KAAK,CAAM,EAAQ,EAAW,IAAI,CAAG,GAAG,EAAO,KAAK,eAAe,GAAK,EAEjG,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAO,GACjB,OAAU,IAAA,GACd,IAAI,OAAO,GAAU,UAAY,CAAC,OAAO,UAAU,CAAK,GAAK,GAAS,EAAG,CACvE,EAAO,KAAK,GAAG,EAAI,4BAA4B,EAC/C,QACF,CACA,EAAS,GAAO,KAAK,IAAI,EAAO,EAAS,IAAQ,CAAK,CADtD,CAEF,CAEA,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAO,GACjB,OAAU,IAAA,GACd,IAAI,OAAO,GAAU,UAAY,CAAC,OAAO,SAAS,CAAK,GAAK,GAAS,GAAK,GAAS,EAAG,CACpF,EAAO,KAAK,GAAG,EAAI,sCAAsC,EACzD,QACF,CACA,EAAS,GAAO,CADhB,CAEF,CAEA,IAAM,EAAW,EAAO,cACxB,GAAI,IAAa,IAAA,GAAW,CAC1B,GAAI,CAAC,MAAM,QAAQ,CAAQ,GAAK,EAAS,KAAM,GAAU,OAAO,GAAU,QAAQ,EAChF,EAAO,KAAK,2CAA2C,MAClD,CACL,IAAM,EAAqB,CAAC,EAC5B,IAAK,IAAM,KAAW,EAAS,MAAM,EAAG,EAAY,EAAe,CACjE,GAAI,EAAQ,OAAS,IAAoB,CACvC,EAAO,KAAK,iCAAiC,EAC7C,QACF,CACA,GAAI,CACF,IAAI,OAAO,EAAS,IAAI,EACxB,EAAS,KAAK,CAAO,CACvB,MAAQ,CACN,EAAO,KAAK,0DAA0D,GAAS,CACjF,CACF,CACI,EAAS,OAAS,IAAG,EAAS,cAAgB,EACpD,CACF,CAEA,MAAO,CAAY,WAA4B,QAAO,CACxD"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"node:fs";import t from"node:path";import{CONFIG_DIR_NAME as n}from"@earendil-works/pi-coding-agent";const r=`doompi-runner.json`,i={settings:{},issues:[]},a=[`headRatio`,`errorBudgetRatio`],o=[`maxResultBytes`,`maxResultLines`,`successMaxResultBytes`,`errorMaxEntries`,`errorMaxVariantsJoined`],s=new Set([...a,...o,`errorPatterns`]),c=262144,l={maxResultBytes:c,successMaxResultBytes:c,maxResultLines:5e3,errorMaxEntries:100,errorMaxVariantsJoined:100};var
|
|
1
|
+
import e from"node:fs";import t from"node:path";import{CONFIG_DIR_NAME as n}from"@earendil-works/pi-coding-agent";const r=`doompi-runner.json`,i={settings:{},issues:[]},a=[`headRatio`,`errorBudgetRatio`],o=[`maxResultBytes`,`maxResultLines`,`successMaxResultBytes`,`maxResultTokens`,`successMaxResultTokens`,`errorMaxEntries`,`errorMaxVariantsJoined`],s=new Set([...a,...o,`errorPatterns`]),c=262144,l=1e5,u={maxResultBytes:c,successMaxResultBytes:c,maxResultTokens:l,successMaxResultTokens:l,maxResultLines:5e3,errorMaxEntries:100,errorMaxVariantsJoined:100};var d=class{load(a,o){if(!o)return i;let s;try{s=e.readFileSync(t.join(a,n,r),`utf8`)}catch(e){return e.code===`ENOENT`?i:{settings:{},issues:[`${r} could not be read`]}}let c;try{c=JSON.parse(s)}catch{return{settings:{},issues:[`${r} is not valid JSON`]}}return f(c)}};function f(e){if(typeof e!=`object`||!e||Array.isArray(e))return{settings:{},issues:[`${r} must contain a JSON object`]};let t=e,n={},i=[];for(let e of Object.keys(t))s.has(e)||i.push(`unknown key ${e}`);for(let e of o){let r=t[e];if(r!==void 0){if(typeof r!=`number`||!Number.isInteger(r)||r<=0){i.push(`${e} must be a positive integer`);continue}n[e]=Math.min(r,u[e]??r)}}for(let e of a){let r=t[e];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<=0||r>=1){i.push(`${e} must be a number above 0 and below 1`);continue}n[e]=r}}let c=t.errorPatterns;if(c!==void 0){if(!Array.isArray(c)||c.some(e=>typeof e!=`string`))i.push(`errorPatterns must be an array of strings`);else{let e=[];for(let t of c.slice(0,32)){if(t.length>512){i.push(`errorPatterns entry is too long`);continue}try{new RegExp(t,`iu`),e.push(t)}catch{i.push(`errorPatterns entry is not a valid regular expression: ${t}`)}}e.length>0&&(n.errorPatterns=e)}}return{settings:n,issues:i}}export{r as RUNNER_SETTINGS_FILE,d as RunnerSettingsLoader};
|
|
2
2
|
//# sourceMappingURL=RunnerSettingsLoader.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RunnerSettingsLoader.mjs","names":[],"sources":["../../../../src/adapters/RunnerSettings/RunnerSettingsLoader.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_DIR_NAME } from '@earendil-works/pi-coding-agent';\nimport type { IRunnerSettingsLoader, RunnerSettings, RunnerSettingsLoad } from '../../types/runnerSettings';\n\n/** Pi's convention is one JSON file per extension under the config directory. */\nexport const RUNNER_SETTINGS_FILE = 'doompi-runner.json';\n\nconst EMPTY: RunnerSettingsLoad = { settings: {}, issues: [] };\nconst RATIO_KEYS = ['headRatio', 'errorBudgetRatio'] as const;\nconst COUNT_KEYS = [\n 'maxResultBytes',\n 'maxResultLines',\n 'successMaxResultBytes',\n 'errorMaxEntries',\n 'errorMaxVariantsJoined',\n] as const;\nconst KNOWN_KEYS = new Set<string>([...RATIO_KEYS, ...COUNT_KEYS, 'errorPatterns']);\n/** Ceilings so a project file cannot flood the model's context. */\nconst MAX_RESULT_BYTES_CEILING = 262_144;\nconst MAX_RESULT_LINES_CEILING = 5_000;\nconst MAX_ERROR_ENTRIES_CEILING = 100;\nconst MAX_PATTERNS = 32;\nconst MAX_PATTERN_LENGTH = 512;\nconst CEILINGS: Readonly<Record<string, number>> = {\n maxResultBytes: MAX_RESULT_BYTES_CEILING,\n successMaxResultBytes: MAX_RESULT_BYTES_CEILING,\n maxResultLines: MAX_RESULT_LINES_CEILING,\n errorMaxEntries: MAX_ERROR_ENTRIES_CEILING,\n errorMaxVariantsJoined: MAX_ERROR_ENTRIES_CEILING,\n};\n\nexport class RunnerSettingsLoader implements IRunnerSettingsLoader {\n load(cwd: string, trusted: boolean): RunnerSettingsLoad {\n // Project-local configuration is untrusted input until the project is.\n if (!trusted) return EMPTY;\n\n let raw: string;\n try {\n raw = fs.readFileSync(path.join(cwd, CONFIG_DIR_NAME, RUNNER_SETTINGS_FILE), 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return EMPTY;\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} could not be read`] };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} is not valid JSON`] };\n }\n return validate(parsed);\n }\n}\n\nfunction validate(parsed: unknown): RunnerSettingsLoad {\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} must contain a JSON object`] };\n }\n\n const source = parsed as Record<string, unknown>;\n const settings: Record<string, unknown> = {};\n const issues: string[] = [];\n // A rejected key is reported rather than dropped: a silent typo reads as a\n // setting that simply does not work.\n for (const key of Object.keys(source)) if (!KNOWN_KEYS.has(key)) issues.push(`unknown key ${key}`);\n\n for (const key of COUNT_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {\n issues.push(`${key} must be a positive integer`);\n continue;\n }\n settings[key] = Math.min(value, CEILINGS[key] ?? value);\n }\n\n for (const key of RATIO_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0 || value >= 1) {\n issues.push(`${key} must be a number above 0 and below 1`);\n continue;\n }\n settings[key] = value;\n }\n\n const patterns = source.errorPatterns;\n if (patterns !== undefined) {\n if (!Array.isArray(patterns) || patterns.some((entry) => typeof entry !== 'string')) {\n issues.push('errorPatterns must be an array of strings');\n } else {\n const accepted: string[] = [];\n for (const pattern of patterns.slice(0, MAX_PATTERNS) as string[]) {\n if (pattern.length > MAX_PATTERN_LENGTH) {\n issues.push('errorPatterns entry is too long');\n continue;\n }\n try {\n new RegExp(pattern, 'iu');\n accepted.push(pattern);\n } catch {\n issues.push(`errorPatterns entry is not a valid regular expression: ${pattern}`);\n }\n }\n if (accepted.length > 0) settings.errorPatterns = accepted;\n }\n }\n\n return { settings: settings as RunnerSettings, issues };\n}\n"],"mappings":"kHAMA,MAAa,EAAuB,qBAE9B,EAA4B,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,CAAE,EACvD,EAAa,CAAC,YAAa,kBAAkB,EAC7C,EAAa,CACjB,iBACA,iBACA,wBACA,kBACA,wBACF,EACM,EAAa,IAAI,IAAY,CAAC,GAAG,EAAY,GAAG,EAAY,eAAe,CAAC,EAE5E,EAA2B,
|
|
1
|
+
{"version":3,"file":"RunnerSettingsLoader.mjs","names":[],"sources":["../../../../src/adapters/RunnerSettings/RunnerSettingsLoader.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_DIR_NAME } from '@earendil-works/pi-coding-agent';\nimport type { IRunnerSettingsLoader, RunnerSettings, RunnerSettingsLoad } from '../../types/runnerSettings';\n\n/** Pi's convention is one JSON file per extension under the config directory. */\nexport const RUNNER_SETTINGS_FILE = 'doompi-runner.json';\n\nconst EMPTY: RunnerSettingsLoad = { settings: {}, issues: [] };\nconst RATIO_KEYS = ['headRatio', 'errorBudgetRatio'] as const;\nconst COUNT_KEYS = [\n 'maxResultBytes',\n 'maxResultLines',\n 'successMaxResultBytes',\n 'maxResultTokens',\n 'successMaxResultTokens',\n 'errorMaxEntries',\n 'errorMaxVariantsJoined',\n] as const;\nconst KNOWN_KEYS = new Set<string>([...RATIO_KEYS, ...COUNT_KEYS, 'errorPatterns']);\n/** Ceilings so a project file cannot flood the model's context. */\nconst MAX_RESULT_BYTES_CEILING = 262_144;\nconst MAX_RESULT_LINES_CEILING = 5_000;\nconst MAX_RESULT_TOKENS_CEILING = 100_000;\nconst MAX_ERROR_ENTRIES_CEILING = 100;\nconst MAX_PATTERNS = 32;\nconst MAX_PATTERN_LENGTH = 512;\nconst CEILINGS: Readonly<Record<string, number>> = {\n maxResultBytes: MAX_RESULT_BYTES_CEILING,\n successMaxResultBytes: MAX_RESULT_BYTES_CEILING,\n maxResultTokens: MAX_RESULT_TOKENS_CEILING,\n successMaxResultTokens: MAX_RESULT_TOKENS_CEILING,\n maxResultLines: MAX_RESULT_LINES_CEILING,\n errorMaxEntries: MAX_ERROR_ENTRIES_CEILING,\n errorMaxVariantsJoined: MAX_ERROR_ENTRIES_CEILING,\n};\n\nexport class RunnerSettingsLoader implements IRunnerSettingsLoader {\n load(cwd: string, trusted: boolean): RunnerSettingsLoad {\n // Project-local configuration is untrusted input until the project is.\n if (!trusted) return EMPTY;\n\n let raw: string;\n try {\n raw = fs.readFileSync(path.join(cwd, CONFIG_DIR_NAME, RUNNER_SETTINGS_FILE), 'utf8');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return EMPTY;\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} could not be read`] };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} is not valid JSON`] };\n }\n return validate(parsed);\n }\n}\n\nfunction validate(parsed: unknown): RunnerSettingsLoad {\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n return { settings: {}, issues: [`${RUNNER_SETTINGS_FILE} must contain a JSON object`] };\n }\n\n const source = parsed as Record<string, unknown>;\n const settings: Record<string, unknown> = {};\n const issues: string[] = [];\n // A rejected key is reported rather than dropped: a silent typo reads as a\n // setting that simply does not work.\n for (const key of Object.keys(source)) if (!KNOWN_KEYS.has(key)) issues.push(`unknown key ${key}`);\n\n for (const key of COUNT_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {\n issues.push(`${key} must be a positive integer`);\n continue;\n }\n settings[key] = Math.min(value, CEILINGS[key] ?? value);\n }\n\n for (const key of RATIO_KEYS) {\n const value = source[key];\n if (value === undefined) continue;\n if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0 || value >= 1) {\n issues.push(`${key} must be a number above 0 and below 1`);\n continue;\n }\n settings[key] = value;\n }\n\n const patterns = source.errorPatterns;\n if (patterns !== undefined) {\n if (!Array.isArray(patterns) || patterns.some((entry) => typeof entry !== 'string')) {\n issues.push('errorPatterns must be an array of strings');\n } else {\n const accepted: string[] = [];\n for (const pattern of patterns.slice(0, MAX_PATTERNS) as string[]) {\n if (pattern.length > MAX_PATTERN_LENGTH) {\n issues.push('errorPatterns entry is too long');\n continue;\n }\n try {\n new RegExp(pattern, 'iu');\n accepted.push(pattern);\n } catch {\n issues.push(`errorPatterns entry is not a valid regular expression: ${pattern}`);\n }\n }\n if (accepted.length > 0) settings.errorPatterns = accepted;\n }\n }\n\n return { settings: settings as RunnerSettings, issues };\n}\n"],"mappings":"kHAMA,MAAa,EAAuB,qBAE9B,EAA4B,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,CAAE,EACvD,EAAa,CAAC,YAAa,kBAAkB,EAC7C,EAAa,CACjB,iBACA,iBACA,wBACA,kBACA,yBACA,kBACA,wBACF,EACM,EAAa,IAAI,IAAY,CAAC,GAAG,EAAY,GAAG,EAAY,eAAe,CAAC,EAE5E,EAA2B,OAE3B,EAA4B,IAI5B,EAA6C,CACjD,eAAgB,EAChB,sBAAuB,EACvB,gBAAiB,EACjB,uBAAwB,EACxB,eAAgB,IAChB,gBAAiB,IACjB,uBAAwB,GAC1B,EAEA,IAAa,EAAb,KAAmE,CACjE,KAAK,EAAa,EAAsC,CAEtD,GAAI,CAAC,EAAS,OAAO,EAErB,IAAI,EACJ,GAAI,CACF,EAAM,EAAG,aAAa,EAAK,KAAK,EAAK,EAAiB,CAAoB,EAAG,MAAM,CACrF,OAAS,EAAO,CAEd,OADK,EAAgC,OAAS,SAAiB,EACxD,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,GAAG,EAAqB,mBAAmB,CAAE,CAC/E,CAEA,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAG,CACzB,MAAQ,CACN,MAAO,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,GAAG,EAAqB,mBAAmB,CAAE,CAC/E,CACA,OAAO,EAAS,CAAM,CACxB,CACF,EAEA,SAAS,EAAS,EAAqC,CACrD,GAAI,OAAO,GAAW,WAAY,GAAmB,MAAM,QAAQ,CAAM,EACvE,MAAO,CAAE,SAAU,CAAC,EAAG,OAAQ,CAAC,GAAG,EAAqB,4BAA4B,CAAE,EAGxF,IAAM,EAAS,EACT,EAAoC,CAAC,EACrC,EAAmB,CAAC,EAG1B,IAAK,IAAM,KAAO,OAAO,KAAK,CAAM,EAAQ,EAAW,IAAI,CAAG,GAAG,EAAO,KAAK,eAAe,GAAK,EAEjG,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAO,GACjB,OAAU,IAAA,GACd,IAAI,OAAO,GAAU,UAAY,CAAC,OAAO,UAAU,CAAK,GAAK,GAAS,EAAG,CACvE,EAAO,KAAK,GAAG,EAAI,4BAA4B,EAC/C,QACF,CACA,EAAS,GAAO,KAAK,IAAI,EAAO,EAAS,IAAQ,CAAK,CADtD,CAEF,CAEA,IAAK,IAAM,KAAO,EAAY,CAC5B,IAAM,EAAQ,EAAO,GACjB,OAAU,IAAA,GACd,IAAI,OAAO,GAAU,UAAY,CAAC,OAAO,SAAS,CAAK,GAAK,GAAS,GAAK,GAAS,EAAG,CACpF,EAAO,KAAK,GAAG,EAAI,sCAAsC,EACzD,QACF,CACA,EAAS,GAAO,CADhB,CAEF,CAEA,IAAM,EAAW,EAAO,cACxB,GAAI,IAAa,IAAA,GAAW,CAC1B,GAAI,CAAC,MAAM,QAAQ,CAAQ,GAAK,EAAS,KAAM,GAAU,OAAO,GAAU,QAAQ,EAChF,EAAO,KAAK,2CAA2C,MAClD,CACL,IAAM,EAAqB,CAAC,EAC5B,IAAK,IAAM,KAAW,EAAS,MAAM,EAAG,EAAY,EAAe,CACjE,GAAI,EAAQ,OAAS,IAAoB,CACvC,EAAO,KAAK,iCAAiC,EAC7C,QACF,CACA,GAAI,CACF,IAAI,OAAO,EAAS,IAAI,EACxB,EAAS,KAAK,CAAO,CACvB,MAAQ,CACN,EAAO,KAAK,0DAA0D,GAAS,CACjF,CACF,CACI,EAAS,OAAS,IAAG,EAAS,cAAgB,EACpD,CACF,CAEA,MAAO,CAAY,WAA4B,QAAO,CACxD"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
const e=require("../../services/runs/compaction.cjs"),t=require("../../types/config.cjs"),n=require("../../container/index.cjs"),r=require("../../services/runs/reconcile.cjs"),i=require("../../commands/bash/bashTool.cjs"),a=require("../../tui/format.cjs"),o=require("../../tui/runnerSpace.cjs"),s=require("../RunnerSettings/RunnerSettingsLoader.cjs");let c=require("@agimon-ai/doompi-extension-contracts/child-process"),l=require("@agimon-ai/doompi-extension-contracts/cordis-host"),u=require("@agimon-ai/doompi-extension-contracts/help"),d=require("@agimon-ai/doompi-extension-contracts/readiness"),f=require("@agimon-ai/doompi-extension-contracts/ui-hub"),p=require("@agimon-ai/doompi-telemetry");const m=`@agimon-ai/doompi-runner`,ee=`runners`,h=`completed`,te=`stopped`,g=`doom-runner-runners`;function ne(e){try{let n=e.isProjectTrusted?.()??!1,{settings:r,issues:i}=new s.RunnerSettingsLoader().load(e.cwd,n);t.setRunnerSettings(r);for(let e of i)process.emitWarning(`${s.RUNNER_SETTINGS_FILE}: ${e}`)}catch(e){process.emitWarning(`Could not read ${s.RUNNER_SETTINGS_FILE}: ${String(e)}`),t.setRunnerSettings({})}}function _(s,l){let u=n.createRunnerContainer(),_=u.runnerRegistry,v=async()=>{try{_.close()}catch(e){process.emitWarning(`Could not close a partially installed doom-runner registry: ${String(e)}`)}};s.effect(()=>()=>v(),`${m}/runtime`);let y=u.launcher,b=u.rmuxBackend,re=u.logReader,x=u.ptyHost,ie=u.bashRunService,S=u.paths,C=u.processControl,w=u.lifeline,T=!0,E=0,D,O,k=[],A,j,M,N=!1,P=!1,F,I,L,R,z,B=Promise.resolve(),V,H=!1,U=!1,W,G=new Set,K=new Set,q=new Set,J=e=>(q.add(e),e.then(()=>q.delete(e),()=>q.delete(e)),e),Y=async()=>{if(await B,!T||!N||!D)throw Error(`doom-runner requires an active Pi session`)},ae={run:async e=>(await Y(),J(ie.run(e)))},X=(e,t=D)=>T&&!P&&e===E&&t===D,Z=e=>(M??=(0,p.createDoomTelemetry)({serviceName:`doom-runner`,packageName:`@agimon-ai/doompi-runner`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),M),oe=async e=>{let t=D,n=E;if(!t||!X(n,t))return;let i=await _.list();if(!X(n,t))return;let o=i;if(e){let e=await r.reconcileActiveRunners({registry:_,launcher:y,rmuxBackend:b,processControl:C,currentHostPid:process.pid,startup:!1,active:i});for(let t of e.errors)process.emitWarning(t);if(e.reclaimed.length>0){let t=new Set(e.reclaimed);o=i.filter(e=>!t.has(e.id))}}if(!X(n,t))return;k=o.filter(e=>e.sessionId===t);let s=(O?o.filter(e=>(e.rootSessionId??e.sessionId)===O):[]).length;W!==s&&(W=s,j?.update(a.formatRunnerFooterContribution(s)),A?.hasUI&&A.ui.setStatus(g,a.formatRunnerStatus(s)));let c=[...K],u=await Promise.all(c.map(e=>_.get(e,t)));if(X(n,t))for(let[e,n]of u.entries()){let r=c[e];if(!r)continue;if(!n||n.sessionId!==t){K.delete(r);continue}if(n.state!==h||(K.delete(n.id),G.has(n.id)))continue;G.add(n.id);let i=n.exit?.reason??h,a=n.exit?.code===null||n.exit?.code===void 0?``:`, exit code ${n.exit.code}`,o=[`Background runner ${n.name} exited: ${i}${a}.`,`Runner ID: ${n.id}`,`Log: ${n.logPath}`,`Inspect: doom-runner logs ${n.id}`].join(`
|
|
2
|
-
`);l.sendMessage({customType:`doom-runner-finished`,content:o,display:!0},{triggerTurn:!0,deliverAs:`steer`}),A&&J(Z(A).recordEvent(`doom_runner.process_finished`,{outcome:`completed`,"runner.exit_code":n.exit?.code??0,"runner.backend":n.backend,...Number.isFinite(Date.parse(n.startedAt))?{duration_ms:Math.max(0,Date.now()-Date.parse(n.startedAt))}:{}}))}},Q=(e=!0)=>{if(!D||!N||P)return Promise.resolve();if(F)return H=!0,U||=e,F;let t=(async()=>{let t=e;do H=!1,U=!1,await oe(t),t=U;while(H&&!P)})().finally(()=>{F===t&&(F=void 0)});return F=t,t},se=e=>{P||(A&&J(Z(A).recordError(`doom_runner.refresh_failed`,e)),process.emitWarning(`Could not refresh doom-runner: ${String(e)}`))},ce=e=>{Q(e).catch(se)},le=()=>{L||I||P||(L=setImmediate(()=>{if(L=void 0,P)return;let e=(async()=>{let e=S.sweepHistoryAsync?await S.sweepHistoryAsync(t.getLogTtlMs()):S.sweepHistory(t.getLogTtlMs());for(let t of e.errors)process.emitWarning(t)})().catch(e=>process.emitWarning(`Could not sweep doom-runner history: ${String(e)}`)).finally(()=>{I===e&&(I=void 0)});I=e}),L.unref?.())},$=async(e,t)=>{try{await t()}catch(t){process.emitWarning(`Doom-runner cleanup could not ${e}: ${String(t)}`)}};v=async()=>{if(P)return;T=!1,P=!0,E+=1,N=!1,R&&clearInterval(R),R=void 0,L&&clearImmediate(L),L=void 0;let e=z;z=void 0,e&&await $(`unsubscribe from the runner registry`,e);let t=V;V=void 0,t&&await $(`cancel standalone readiness work`,()=>t.dispose()),await Promise.allSettled(q);let n=F;n&&await $(`settle the runner refresh`,()=>n);let i=I;i&&await $(`settle runner history cleanup`,()=>i),await $(`dispose runner PTYs`,()=>x.disposeAll());let a=[];if(D)try{a=await _.listBySession(D)}catch(e){process.emitWarning(`Could not list runners during doom-runner shutdown: ${String(e)}`)}await Promise.all(a.map(async e=>{try{let t=await r.stopRunnerProcess(e,y,b);if(!t&&C.isAlive(e.pid)){process.emitWarning(`Could not stop runner ${e.id} during session shutdown`);return}await _.complete(e.id,{reason:te,code:null,signal:t?`SIGTERM`:null,stopReason:`session ended`},e.sessionId)}catch(t){process.emitWarning(`Could not clean up runner ${e.id}: ${String(t)}`)}}));let o=A,s=M;M=void 0,A=void 0,D=void 0,O=void 0,k=[],G.clear(),K.clear(),await Promise.all([$(`dispose the runner lifeline`,()=>w.dispose()),...o?.hasUI?[$(`clear the runner status`,()=>o.ui.setStatus(g,void 0))]:[]]),await $(`close the runner registry`,()=>_.close()),s&&(await $(`record the runner session finish`,()=>s.recordEvent(`doom_runner.session_finished`,{outcome:`stopped`})),await $(`stop runner telemetry`,()=>s.shutdown()))},s.inject([f.DOOM_UI_HUB_SERVICE],e=>{let t=(0,f.requireDoomUiHub)(e).registerFooter({source:m,id:`runner-count`,order:10});return j=t,()=>{t.dispose(),j===t&&(j=void 0)}}),z=_.subscribe(()=>ce(!1)),R=setInterval(()=>ce(!0),500),R.unref?.(),i.registerBashTool(l,{bashRunService:ae,getSessionId:async()=>{if(await Y(),!D)throw Error(`doom-runner requires an active Pi session`);return D},onRunnerStarted:e=>{!T||!N||(K.add(e),ce(!1))}}),e.registerRunnerCompactionRecovery(l,{getSessionId:async()=>{try{return await Y(),D}catch{return}},listBySession:async e=>{try{await Y()}catch{return[]}return T?_.listBySession(e):[]}}),l.registerCommand(ee,{description:`Open Runner Space: background processes started by bash`,handler:async(e,t)=>{if(!T)return;let n=E,r=D;if(r){if(!t.hasUI){t.ui.notify(`/runners requires interactive mode`,`error`);return}await Y(),await Q(),!(!r||!X(n,r))&&await o.openRunnerSpace(t,{getRunners:()=>X(n,r)?k:[],getPtyRun:e=>X(n,r)?b.get(e)??x.get(e):void 0,readLog:e=>X(n,r)?re.read(e,{lines:1e3}).text:``,stopRunner:async(e,t)=>{if(!X(n,r))return;let i=k.find(t=>t.id===e);i&&(i.backend===`rmux`&&i.backendTarget?await b.stop(i.backendTarget,i.pid):await y.stop(i.pid),X(n,r)&&(await _.complete(i.id,{reason:te,code:null,signal:null,stopReason:t},i.sessionId),X(n,r)&&await Q()))}})}}}),s.inject([f.DOOM_UI_HUB_SERVICE],e=>{let t=(0,f.requireDoomUiHub)(e).registerLeader({source:m,bindings:[{id:`runners.open`,path:[{key:`r`,label:`runners`,order:67},{key:`
|
|
2
|
+
`);l.sendMessage({customType:`doom-runner-finished`,content:o,display:!0},{triggerTurn:!0,deliverAs:`steer`}),A&&J(Z(A).recordEvent(`doom_runner.process_finished`,{outcome:`completed`,"runner.exit_code":n.exit?.code??0,"runner.backend":n.backend,...Number.isFinite(Date.parse(n.startedAt))?{duration_ms:Math.max(0,Date.now()-Date.parse(n.startedAt))}:{}}))}},Q=(e=!0)=>{if(!D||!N||P)return Promise.resolve();if(F)return H=!0,U||=e,F;let t=(async()=>{let t=e;do H=!1,U=!1,await oe(t),t=U;while(H&&!P)})().finally(()=>{F===t&&(F=void 0)});return F=t,t},se=e=>{P||(A&&J(Z(A).recordError(`doom_runner.refresh_failed`,e)),process.emitWarning(`Could not refresh doom-runner: ${String(e)}`))},ce=e=>{Q(e).catch(se)},le=()=>{L||I||P||(L=setImmediate(()=>{if(L=void 0,P)return;let e=(async()=>{let e=S.sweepHistoryAsync?await S.sweepHistoryAsync(t.getLogTtlMs()):S.sweepHistory(t.getLogTtlMs());for(let t of e.errors)process.emitWarning(t)})().catch(e=>process.emitWarning(`Could not sweep doom-runner history: ${String(e)}`)).finally(()=>{I===e&&(I=void 0)});I=e}),L.unref?.())},$=async(e,t)=>{try{await t()}catch(t){process.emitWarning(`Doom-runner cleanup could not ${e}: ${String(t)}`)}};v=async()=>{if(P)return;T=!1,P=!0,E+=1,N=!1,R&&clearInterval(R),R=void 0,L&&clearImmediate(L),L=void 0;let e=z;z=void 0,e&&await $(`unsubscribe from the runner registry`,e);let t=V;V=void 0,t&&await $(`cancel standalone readiness work`,()=>t.dispose()),await Promise.allSettled(q);let n=F;n&&await $(`settle the runner refresh`,()=>n);let i=I;i&&await $(`settle runner history cleanup`,()=>i),await $(`dispose runner PTYs`,()=>x.disposeAll());let a=[];if(D)try{a=await _.listBySession(D)}catch(e){process.emitWarning(`Could not list runners during doom-runner shutdown: ${String(e)}`)}await Promise.all(a.map(async e=>{try{let t=await r.stopRunnerProcess(e,y,b);if(!t&&C.isAlive(e.pid)){process.emitWarning(`Could not stop runner ${e.id} during session shutdown`);return}await _.complete(e.id,{reason:te,code:null,signal:t?`SIGTERM`:null,stopReason:`session ended`},e.sessionId)}catch(t){process.emitWarning(`Could not clean up runner ${e.id}: ${String(t)}`)}}));let o=A,s=M;M=void 0,A=void 0,D=void 0,O=void 0,k=[],G.clear(),K.clear(),await Promise.all([$(`dispose the runner lifeline`,()=>w.dispose()),...o?.hasUI?[$(`clear the runner status`,()=>o.ui.setStatus(g,void 0))]:[]]),await $(`close the runner registry`,()=>_.close()),s&&(await $(`record the runner session finish`,()=>s.recordEvent(`doom_runner.session_finished`,{outcome:`stopped`})),await $(`stop runner telemetry`,()=>s.shutdown()))},s.inject([f.DOOM_UI_HUB_SERVICE],e=>{let t=(0,f.requireDoomUiHub)(e).registerFooter({source:m,id:`runner-count`,order:10});return j=t,()=>{t.dispose(),j===t&&(j=void 0)}}),z=_.subscribe(()=>ce(!1)),R=setInterval(()=>ce(!0),500),R.unref?.(),i.registerBashTool(l,{bashRunService:ae,getSessionId:async()=>{if(await Y(),!D)throw Error(`doom-runner requires an active Pi session`);return D},onRunnerStarted:e=>{!T||!N||(K.add(e),ce(!1))}}),e.registerRunnerCompactionRecovery(l,{getSessionId:async()=>{try{return await Y(),D}catch{return}},listBySession:async e=>{try{await Y()}catch{return[]}return T?_.listBySession(e):[]}}),l.registerCommand(ee,{description:`Open Runner Space: background processes started by bash`,handler:async(e,t)=>{if(!T)return;let n=E,r=D;if(r){if(!t.hasUI){t.ui.notify(`/runners requires interactive mode`,`error`);return}await Y(),await Q(),!(!r||!X(n,r))&&await o.openRunnerSpace(t,{getRunners:()=>X(n,r)?k:[],getPtyRun:e=>X(n,r)?b.get(e)??x.get(e):void 0,readLog:e=>X(n,r)?re.read(e,{lines:1e3}).text:``,stopRunner:async(e,t)=>{if(!X(n,r))return;let i=k.find(t=>t.id===e);i&&(i.backend===`rmux`&&i.backendTarget?await b.stop(i.backendTarget,i.pid):await y.stop(i.pid),X(n,r)&&(await _.complete(i.id,{reason:te,code:null,signal:null,stopReason:t},i.sessionId),X(n,r)&&await Q()))}})}}}),s.inject([f.DOOM_UI_HUB_SERVICE],e=>{let t=(0,f.requireDoomUiHub)(e).registerLeader({source:m,bindings:[{id:`runners.open`,path:[{key:`r`,label:`runners`,detail:`background processes`,order:67},{key:`l`,label:`list`,detail:`runners in this session`}],command:{name:ee}}]});return()=>t.dispose()}),l.on(`session_start`,(e,t)=>{if(!T)return;let n=t;ne(n);let i=n.sessionManager.getSessionId(),a=D,o=A,l=++E;D=i,O=(0,c.resolveRootSessionId)(i),A=n,N=!1,W=void 0,G.clear(),K.clear();let u=async e=>{let t=()=>!e.aborted&&X(l,i);if(!t())return[];if(a&&a!==i){await $(`dispose the previous session PTYs`,()=>x.disposeAll()),await $(`dispose the previous session lifeline`,()=>w.dispose()),o?.hasUI&&await $(`clear the previous session status`,()=>o.ui.setStatus(g,void 0));let e=M;if(M=void 0,e&&await $(`stop the previous session telemetry`,()=>e.shutdown()),!t())return[]}let s=Z(n);if(await s.recordEvent(`doom_runner.session_started`,{outcome:`started`}),!t()||(S.setSessionId(i),await w.arm(i),!t()))return[];let c=await _.listAll(i);if(!t())return[];for(let e of c)e.state===h?G.add(e.id):e.promoted&&K.add(e.id);let u=await r.cleanupLegacyRunnerStore({registry:_,launcher:y,rmuxBackend:b,processControl:C,currentHostPid:process.pid,paths:S});if(!t())return[];let d=await r.reconcileActiveRunners({registry:_,launcher:y,rmuxBackend:b,processControl:C,currentHostPid:process.pid,startup:!0});if(!t()||(N=!0,await Q(!1),!t()))return[];le();let f=[...u.errors,...d.errors],p=u.reclaimed.length+d.reclaimed.length;return p>0&&n.hasUI&&n.ui.notify(`Reclaimed ${p} stale runner record(s)`,`warning`),await s.recordEvent(`doom_runner.reconciled`,{"runner.reclaimed_count":p,"runner.error_count":f.length,outcome:f.length===0?`completed`:`degraded`}),f},f=B.catch(()=>void 0),p=(async()=>{await f,X(l,i)&&await((0,d.readDoomReadinessCoordinator)(s)??(V??=(0,d.createDoomReadinessCoordinator)({notify:e=>{process.emitWarning(`${e.packageId} initialization ${e.state}: ${e.error?.message??e.diagnostics.join(`; `)}`)}}))).start(m,`${i}:${l}`,async e=>({value:void 0,diagnostics:await u(e)})).wait()})();B=p,J(p).catch(()=>void 0)})}async function v(e){let t=await(0,l.connectDoomCordisHost)(e,m),n=t.root.plugin(y,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function y(e,t){e.inject([u.DOOM_HELP_SERVICE],e=>{let t=(0,u.requireDoomHelpService)(e).register({source:m,moduleUrl:require("url").pathToFileURL(__filename).href,skills:[{name:`doompi-use-runner`,description:`Use Doom Pi Runner to supervise shell commands, inspect durable logs, provide interactive input, and stop background runs.`}]});return()=>t.dispose()}),_(e,t.pi)}exports.default=v,exports.runnerExtension=v,exports.installRunnerRuntime=_;
|
|
3
3
|
//# sourceMappingURL=extension.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.cjs","names":["RunnerSettingsLoader","RUNNER_SETTINGS_FILE","createRunnerContainer","createDoomTelemetry","reconcileActiveRunners","formatRunnerFooterContribution","formatRunnerStatus","getLogTtlMs","stopRunnerProcess","DOOM_UI_HUB_SERVICE","requireDoomUiHub","openRunnerSpace","resolveRootSessionId","cleanupLegacyRunnerStore","readDoomReadinessCoordinator","createDoomReadinessCoordinator","connectDoomCordisHost","DOOM_HELP_SERVICE","requireDoomHelpService"],"sources":["../../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { resolveRootSessionId } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport type { DoomFooterContributionHandle } from '@agimon-ai/doompi-extension-contracts/footer';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { registerBashTool } from '../../commands/bash/bashTool.ts';\nimport { createRunnerContainer } from '../../container/index.ts';\nimport type { IBashRunService } from '../../types/bashRunService';\nimport type { RunnerRecord } from '../../types/runnerRegistry';\nimport { registerRunnerCompactionRecovery } from '../../services/runs/compaction.ts';\nimport { cleanupLegacyRunnerStore, reconcileActiveRunners, stopRunnerProcess } from '../../services/runs/reconcile.ts';\nimport { formatRunnerFooterContribution, formatRunnerStatus } from '../../tui/format.ts';\nimport { openRunnerSpace } from '../../tui/runnerSpace.ts';\nimport { getLogTtlMs } from '../../types/config.ts';\n\nconst LEADER_SOURCE = '@agimon-ai/doompi-runner';\n/** After doom-task's `t` (65) and before the core help group (70). */\nconst LEADER_GROUP_ORDER = 67;\nconst COMMAND_NAME = 'runners';\nconst ERR_REQUIRES_INTERACTIVE = '/runners requires interactive mode';\n\nimport { RUNNER_SETTINGS_FILE, RunnerSettingsLoader } from '../RunnerSettings/RunnerSettingsLoader';\nimport { setRunnerSettings } from '../../types/config.ts';\n\nconst SESSION_START_EVENT = 'session_start';\nconst RUNNER_FINISHED_MESSAGE = 'doom-runner-finished';\nconst COMPLETED_STATE = 'completed';\nconst RMUX_BACKEND = 'rmux';\nconst STOPPED_REASON = 'stopped';\nconst RUNNER_STATUS_KEY = 'doom-runner-runners';\nconst RUNNER_FOOTER_ORDER = 10;\nconst RUNNER_STATUS_POLL_MS = 500;\n\n/**\n * Project-local extension config, read the way Pi documents it: one JSON file\n * per extension under the config directory, and only for a trusted project.\n */\nfunction loadRunnerSettings(context: ExtensionContext): void {\n try {\n const trusted = context.isProjectTrusted?.() ?? false;\n const { settings, issues } = new RunnerSettingsLoader().load(context.cwd, trusted);\n setRunnerSettings(settings);\n // A rejected key is surfaced rather than dropped: silence reads as a\n // setting that simply does not work.\n for (const issue of issues) process.emitWarning(`${RUNNER_SETTINGS_FILE}: ${issue}`);\n } catch (error) {\n process.emitWarning(`Could not read ${RUNNER_SETTINGS_FILE}: ${String(error)}`);\n setRunnerSettings({});\n }\n}\n\n/**\n * doom-runner: replaces pi's `bash` tool with a supervised one and provides a\n * CLI for anything it leaves running.\n */\nexport function installRunnerRuntime(cordis: Context, pi: ExtensionAPI): void {\n const container = createRunnerContainer();\n const registry = container.runnerRegistry;\n let disposeRuntime = async (): Promise<void> => {\n try {\n registry.close();\n } catch (error) {\n process.emitWarning(`Could not close a partially installed doom-runner registry: ${String(error)}`);\n }\n };\n cordis.effect(() => () => disposeRuntime(), `${LEADER_SOURCE}/runtime`);\n\n const launcher = container.launcher;\n const rmuxBackend = container.rmuxBackend;\n const logReader = container.logReader;\n const ptyHost = container.ptyHost;\n const bashRunService = container.bashRunService;\n const paths = container.paths;\n const processControl = container.processControl;\n const lifeline = container.lifeline;\n\n let active = true;\n let sessionGeneration = 0;\n let sessionId: string | undefined;\n let rootSessionId: string | undefined;\n let runners: RunnerRecord[] = [];\n let sessionContext: ExtensionContext | undefined;\n let footerContribution: DoomFooterContributionHandle | undefined;\n let telemetry: DoomTelemetry | undefined;\n let sessionReady = false;\n let disposed = false;\n let refreshInFlight: Promise<void> | undefined;\n let historySweepInFlight: Promise<void> | undefined;\n let historySweepTimer: ReturnType<typeof setImmediate> | undefined;\n let statusPoll: ReturnType<typeof setInterval> | undefined;\n let unsubscribeRegistry: (() => void) | undefined;\n let sessionInitialization: Promise<void> = Promise.resolve();\n let fallbackReadiness: DoomReadinessCoordinator | undefined;\n let refreshQueued = false;\n let queuedReconciliation = false;\n let lastRunnerCount: number | undefined;\n const notifiedRunnerIds = new Set<string>();\n const pendingPromotedRunnerIds = new Set<string>();\n const pendingOperations = new Set<Promise<unknown>>();\n const trackOperation = <T>(operation: Promise<T>): Promise<T> => {\n pendingOperations.add(operation);\n void operation.then(\n () => pendingOperations.delete(operation),\n () => pendingOperations.delete(operation),\n );\n return operation;\n };\n const waitForSessionReadiness = async (): Promise<void> => {\n await sessionInitialization;\n if (!active || !sessionReady || !sessionId) {\n throw new Error('doom-runner requires an active Pi session');\n }\n };\n const trackedBashRunService: IBashRunService = {\n run: async (request) => {\n await waitForSessionReadiness();\n return trackOperation(bashRunService.run(request));\n },\n };\n const isCurrent = (generation: number, expectedSessionId = sessionId): boolean =>\n active && !disposed && generation === sessionGeneration && expectedSessionId === sessionId;\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-runner',\n packageName: '@agimon-ai/doompi-runner',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n /** Performs one bounded pass over active state and explicitly monitored runners. */\n const refreshNow = async (shouldReconcile: boolean): Promise<void> => {\n const activeSessionId = sessionId;\n const generation = sessionGeneration;\n if (!activeSessionId || !isCurrent(generation, activeSessionId)) return;\n\n const activeRecords = await registry.list();\n if (!isCurrent(generation, activeSessionId)) return;\n let visibleActive = activeRecords;\n if (shouldReconcile) {\n const reconciled = await reconcileActiveRunners({\n registry,\n launcher,\n rmuxBackend,\n processControl,\n currentHostPid: process.pid,\n startup: false,\n active: activeRecords,\n });\n for (const error of reconciled.errors) process.emitWarning(error);\n if (reconciled.reclaimed.length > 0) {\n const reclaimedIds = new Set(reconciled.reclaimed);\n visibleActive = activeRecords.filter((record) => !reclaimedIds.has(record.id));\n }\n }\n if (!isCurrent(generation, activeSessionId)) return;\n\n runners = visibleActive.filter((record) => record.sessionId === activeSessionId);\n const rootRunners = rootSessionId\n ? visibleActive.filter((record) => (record.rootSessionId ?? record.sessionId) === rootSessionId)\n : [];\n const runnerCount = rootRunners.length;\n if (lastRunnerCount !== runnerCount) {\n lastRunnerCount = runnerCount;\n footerContribution?.update(formatRunnerFooterContribution(runnerCount));\n if (sessionContext?.hasUI) sessionContext.ui.setStatus(RUNNER_STATUS_KEY, formatRunnerStatus(runnerCount));\n }\n\n const pendingIds = [...pendingPromotedRunnerIds];\n const monitored = await Promise.all(pendingIds.map((id) => registry.get(id, activeSessionId)));\n if (!isCurrent(generation, activeSessionId)) return;\n for (const [index, record] of monitored.entries()) {\n const id = pendingIds[index];\n if (!id) continue;\n if (!record || record.sessionId !== activeSessionId) {\n pendingPromotedRunnerIds.delete(id);\n continue;\n }\n if (record.state !== COMPLETED_STATE) continue;\n pendingPromotedRunnerIds.delete(record.id);\n if (notifiedRunnerIds.has(record.id)) continue;\n notifiedRunnerIds.add(record.id);\n const outcome = record.exit?.reason ?? COMPLETED_STATE;\n const code =\n record.exit?.code === null || record.exit?.code === undefined ? '' : `, exit code ${record.exit.code}`;\n const content = [\n `Background runner ${record.name} exited: ${outcome}${code}.`,\n `Runner ID: ${record.id}`,\n `Log: ${record.logPath}`,\n `Inspect: doom-runner logs ${record.id}`,\n ].join('\\n');\n pi.sendMessage(\n { customType: RUNNER_FINISHED_MESSAGE, content, display: true },\n { triggerTurn: true, deliverAs: 'steer' },\n );\n if (sessionContext) {\n void trackOperation(\n getTelemetry(sessionContext).recordEvent('doom_runner.process_finished', {\n outcome: 'completed',\n 'runner.exit_code': record.exit?.code ?? 0,\n 'runner.backend': record.backend,\n ...(Number.isFinite(Date.parse(record.startedAt))\n ? { duration_ms: Math.max(0, Date.now() - Date.parse(record.startedAt)) }\n : {}),\n }),\n );\n }\n }\n };\n\n /** Coalesces timer and event triggers without losing a requested reconciliation pass. */\n const refresh = (shouldReconcile = true): Promise<void> => {\n if (!sessionId || !sessionReady || disposed) return Promise.resolve();\n if (refreshInFlight) {\n refreshQueued = true;\n queuedReconciliation ||= shouldReconcile;\n return refreshInFlight;\n }\n\n const execution = (async () => {\n let reconcileNext = shouldReconcile;\n do {\n refreshQueued = false;\n queuedReconciliation = false;\n await refreshNow(reconcileNext);\n reconcileNext = queuedReconciliation;\n } while (refreshQueued && !disposed);\n })().finally(() => {\n if (refreshInFlight === execution) refreshInFlight = undefined;\n });\n refreshInFlight = execution;\n return execution;\n };\n\n const reportRefreshError = (error: unknown): void => {\n if (disposed) return;\n if (sessionContext) {\n void trackOperation(getTelemetry(sessionContext).recordError('doom_runner.refresh_failed', error));\n }\n process.emitWarning(`Could not refresh doom-runner: ${String(error)}`);\n };\n const scheduleRefresh = (shouldReconcile: boolean): void => {\n void refresh(shouldReconcile).catch(reportRefreshError);\n };\n const scheduleHistorySweep = (): void => {\n if (historySweepTimer || historySweepInFlight || disposed) return;\n historySweepTimer = setImmediate(() => {\n historySweepTimer = undefined;\n if (disposed) return;\n const execution = (async () => {\n const sweep = paths.sweepHistoryAsync\n ? await paths.sweepHistoryAsync(getLogTtlMs())\n : paths.sweepHistory(getLogTtlMs());\n for (const error of sweep.errors) process.emitWarning(error);\n })()\n .catch((error) => process.emitWarning(`Could not sweep doom-runner history: ${String(error)}`))\n .finally(() => {\n if (historySweepInFlight === execution) historySweepInFlight = undefined;\n });\n historySweepInFlight = execution;\n });\n historySweepTimer.unref?.();\n };\n\n const runCleanup = async (label: string, cleanup: () => void | Promise<void>): Promise<void> => {\n try {\n await cleanup();\n } catch (error) {\n process.emitWarning(`Doom-runner cleanup could not ${label}: ${String(error)}`);\n }\n };\n\n const shutdownRuntime = async (): Promise<void> => {\n if (disposed) return;\n active = false;\n disposed = true;\n sessionGeneration += 1;\n sessionReady = false;\n if (statusPoll) clearInterval(statusPoll);\n statusPoll = undefined;\n if (historySweepTimer) clearImmediate(historySweepTimer);\n historySweepTimer = undefined;\n const unsubscribe = unsubscribeRegistry;\n unsubscribeRegistry = undefined;\n if (unsubscribe) await runCleanup('unsubscribe from the runner registry', unsubscribe);\n\n const ownedReadiness = fallbackReadiness;\n fallbackReadiness = undefined;\n if (ownedReadiness) await runCleanup('cancel standalone readiness work', () => ownedReadiness.dispose());\n await Promise.allSettled(pendingOperations);\n const activeRefresh = refreshInFlight;\n if (activeRefresh) await runCleanup('settle the runner refresh', () => activeRefresh);\n const activeHistorySweep = historySweepInFlight;\n if (activeHistorySweep) await runCleanup('settle runner history cleanup', () => activeHistorySweep);\n\n await runCleanup('dispose runner PTYs', () => ptyHost.disposeAll());\n\n let owned: RunnerRecord[] = [];\n if (sessionId) {\n try {\n owned = await registry.listBySession(sessionId);\n } catch (error) {\n process.emitWarning(`Could not list runners during doom-runner shutdown: ${String(error)}`);\n }\n }\n await Promise.all(\n owned.map(async (record) => {\n try {\n const stopped = await stopRunnerProcess(record, launcher, rmuxBackend);\n if (!stopped && processControl.isAlive(record.pid)) {\n process.emitWarning(`Could not stop runner ${record.id} during session shutdown`);\n return;\n }\n await registry.complete(\n record.id,\n {\n reason: STOPPED_REASON,\n code: null,\n signal: stopped ? 'SIGTERM' : null,\n stopReason: 'session ended',\n },\n record.sessionId,\n );\n } catch (error) {\n process.emitWarning(`Could not clean up runner ${record.id}: ${String(error)}`);\n }\n }),\n );\n\n const context = sessionContext;\n const ownedTelemetry = telemetry;\n telemetry = undefined;\n sessionContext = undefined;\n sessionId = undefined;\n rootSessionId = undefined;\n runners = [];\n notifiedRunnerIds.clear();\n pendingPromotedRunnerIds.clear();\n\n await Promise.all([\n runCleanup('dispose the runner lifeline', () => lifeline.dispose()),\n ...(context?.hasUI\n ? [runCleanup('clear the runner status', () => context.ui.setStatus(RUNNER_STATUS_KEY, undefined))]\n : []),\n ]);\n await runCleanup('close the runner registry', () => registry.close());\n if (ownedTelemetry) {\n await runCleanup('record the runner session finish', () =>\n ownedTelemetry.recordEvent('doom_runner.session_finished', { outcome: 'stopped' }),\n );\n await runCleanup('stop runner telemetry', () => ownedTelemetry.shutdown());\n }\n };\n\n disposeRuntime = shutdownRuntime;\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerFooter({\n source: LEADER_SOURCE,\n id: 'runner-count',\n order: RUNNER_FOOTER_ORDER,\n });\n footerContribution = contribution;\n return () => {\n contribution.dispose();\n if (footerContribution === contribution) footerContribution = undefined;\n };\n });\n unsubscribeRegistry = registry.subscribe(() => scheduleRefresh(false));\n statusPoll = setInterval(() => scheduleRefresh(true), RUNNER_STATUS_POLL_MS);\n statusPoll.unref?.();\n\n registerBashTool(pi, {\n bashRunService: trackedBashRunService,\n getSessionId: async () => {\n await waitForSessionReadiness();\n if (!sessionId) throw new Error('doom-runner requires an active Pi session');\n return sessionId;\n },\n onRunnerStarted: (id) => {\n if (!active || !sessionReady) return;\n pendingPromotedRunnerIds.add(id);\n scheduleRefresh(false);\n },\n });\n\n registerRunnerCompactionRecovery(pi, {\n getSessionId: async () => {\n try {\n await waitForSessionReadiness();\n return sessionId;\n } catch {\n return undefined;\n }\n },\n listBySession: async (activeSessionId) => {\n try {\n await waitForSessionReadiness();\n } catch {\n return [];\n }\n return active ? registry.listBySession(activeSessionId) : [];\n },\n });\n\n pi.registerCommand(COMMAND_NAME, {\n description: 'Open Runner Space: background processes started by bash',\n handler: async (_args, ctx) => {\n if (!active) return;\n const generation = sessionGeneration;\n const activeSessionId = sessionId;\n if (!activeSessionId) return;\n if (!ctx.hasUI) {\n ctx.ui.notify(ERR_REQUIRES_INTERACTIVE, 'error');\n return;\n }\n await waitForSessionReadiness();\n await refresh();\n if (!activeSessionId || !isCurrent(generation, activeSessionId)) return;\n await openRunnerSpace(ctx, {\n getRunners: () => (isCurrent(generation, activeSessionId) ? runners : []),\n getPtyRun: (name) =>\n isCurrent(generation, activeSessionId) ? (rmuxBackend.get(name) ?? ptyHost.get(name)) : undefined,\n readLog: (logPath) =>\n isCurrent(generation, activeSessionId) ? logReader.read(logPath, { lines: 1_000 }).text : '',\n stopRunner: async (id, reason) => {\n if (!isCurrent(generation, activeSessionId)) return;\n const record = runners.find((candidate) => candidate.id === id);\n if (!record) return;\n if (record.backend === RMUX_BACKEND && record.backendTarget) {\n await rmuxBackend.stop(record.backendTarget, record.pid);\n } else await launcher.stop(record.pid);\n if (!isCurrent(generation, activeSessionId)) return;\n await registry.complete(\n record.id,\n { reason: STOPPED_REASON, code: null, signal: null, stopReason: reason },\n record.sessionId,\n );\n if (isCurrent(generation, activeSessionId)) await refresh();\n },\n });\n },\n });\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerLeader({\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'runners.open',\n path: [\n { key: 'r', label: 'runners', order: LEADER_GROUP_ORDER },\n { key: 'r', label: 'open', detail: 'background processes' },\n ],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n if (!active) return;\n const context = ctx as ExtensionContext;\n loadRunnerSettings(context);\n const activeSessionId = context.sessionManager.getSessionId();\n const previousSessionId = sessionId;\n const previousContext = sessionContext;\n const generation = ++sessionGeneration;\n sessionId = activeSessionId;\n rootSessionId = resolveRootSessionId(activeSessionId);\n sessionContext = context;\n sessionReady = false;\n lastRunnerCount = undefined;\n notifiedRunnerIds.clear();\n pendingPromotedRunnerIds.clear();\n\n const initializeSession = async (signal: AbortSignal): Promise<readonly string[]> => {\n const stillCurrent = (): boolean => !signal.aborted && isCurrent(generation, activeSessionId);\n if (!stillCurrent()) return [];\n if (previousSessionId && previousSessionId !== activeSessionId) {\n await runCleanup('dispose the previous session PTYs', () => ptyHost.disposeAll());\n await runCleanup('dispose the previous session lifeline', () => lifeline.dispose());\n if (previousContext?.hasUI) {\n await runCleanup('clear the previous session status', () =>\n previousContext.ui.setStatus(RUNNER_STATUS_KEY, undefined),\n );\n }\n const previousTelemetry = telemetry;\n telemetry = undefined;\n if (previousTelemetry) {\n await runCleanup('stop the previous session telemetry', () => previousTelemetry.shutdown());\n }\n if (!stillCurrent()) return [];\n }\n\n const activeTelemetry = getTelemetry(context);\n await activeTelemetry.recordEvent('doom_runner.session_started', { outcome: 'started' });\n if (!stillCurrent()) return [];\n paths.setSessionId(activeSessionId);\n // Awaited before anything can launch, so every runner this session starts\n // finds a lifeline it can connect to rather than a socket that is not\n // listening yet, which would read as an owner that is already gone.\n await lifeline.arm(activeSessionId);\n if (!stillCurrent()) return [];\n\n const retained = await registry.listAll(activeSessionId);\n if (!stillCurrent()) return [];\n for (const record of retained) {\n if (record.state === COMPLETED_STATE) notifiedRunnerIds.add(record.id);\n else if (record.promoted) pendingPromotedRunnerIds.add(record.id);\n }\n const legacy = await cleanupLegacyRunnerStore({\n registry,\n launcher,\n rmuxBackend,\n processControl,\n currentHostPid: process.pid,\n paths,\n });\n if (!stillCurrent()) return [];\n const reconciled = await reconcileActiveRunners({\n registry,\n launcher,\n rmuxBackend,\n processControl,\n currentHostPid: process.pid,\n startup: true,\n });\n if (!stillCurrent()) return [];\n sessionReady = true;\n await refresh(false);\n if (!stillCurrent()) return [];\n scheduleHistorySweep();\n const errors = [...legacy.errors, ...reconciled.errors];\n const reclaimedCount = legacy.reclaimed.length + reconciled.reclaimed.length;\n if (reclaimedCount > 0 && context.hasUI) {\n context.ui.notify(`Reclaimed ${reclaimedCount} stale runner record(s)`, 'warning');\n }\n await activeTelemetry.recordEvent('doom_runner.reconciled', {\n 'runner.reclaimed_count': reclaimedCount,\n 'runner.error_count': errors.length,\n outcome: errors.length === 0 ? 'completed' : 'degraded',\n });\n return errors;\n };\n\n const previousInitialization = sessionInitialization.catch(() => undefined);\n const startReadiness = async (): Promise<void> => {\n await previousInitialization;\n if (!isCurrent(generation, activeSessionId)) return;\n const coordinator =\n readDoomReadinessCoordinator(cordis) ??\n (fallbackReadiness ??= createDoomReadinessCoordinator({\n notify: (notification) => {\n process.emitWarning(\n `${notification.packageId} initialization ${notification.state}: ${notification.error?.message ?? notification.diagnostics.join('; ')}`,\n );\n },\n }));\n const handle = coordinator.start(LEADER_SOURCE, `${activeSessionId}:${generation}`, async (signal) => ({\n value: undefined,\n diagnostics: await initializeSession(signal),\n }));\n await handle.wait();\n };\n const operation = startReadiness();\n sessionInitialization = operation;\n // The coordinator reports a failed generation once; this branch only marks\n // the detached waiter handled so Pi is not held open by the notification path.\n void trackOperation(operation).catch(() => undefined);\n });\n}\n\n/** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */\nexport async function runnerExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, LEADER_SOURCE);\n const fiber = connection.root.plugin(runnerPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface RunnerPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction runnerPlugin(cordis: Context, config: RunnerPluginConfig): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: LEADER_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-use-runner',\n description:\n 'Use Doom Pi Runner to supervise shell commands, inspect durable logs, provide interactive input, and stop background runs.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n installRunnerRuntime(cordis, config.pi);\n}\n\nexport default runnerExtension;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension.cjs","names":["RunnerSettingsLoader","RUNNER_SETTINGS_FILE","createRunnerContainer","createDoomTelemetry","reconcileActiveRunners","formatRunnerFooterContribution","formatRunnerStatus","getLogTtlMs","stopRunnerProcess","DOOM_UI_HUB_SERVICE","requireDoomUiHub","openRunnerSpace","resolveRootSessionId","cleanupLegacyRunnerStore","readDoomReadinessCoordinator","createDoomReadinessCoordinator","connectDoomCordisHost","DOOM_HELP_SERVICE","requireDoomHelpService"],"sources":["../../../../src/adapters/pi/extension.ts"],"sourcesContent":["import { resolveRootSessionId } from '@agimon-ai/doompi-extension-contracts/child-process';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport {\n createDoomReadinessCoordinator,\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport type { DoomFooterContributionHandle } from '@agimon-ai/doompi-extension-contracts/footer';\nimport { DOOM_UI_HUB_SERVICE, requireDoomUiHub } from '@agimon-ai/doompi-extension-contracts/ui-hub';\nimport { createDoomTelemetry, type DoomTelemetry } from '@agimon-ai/doompi-telemetry';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport { registerBashTool } from '../../commands/bash/bashTool.ts';\nimport { createRunnerContainer } from '../../container/index.ts';\nimport type { IBashRunService } from '../../types/bashRunService';\nimport type { RunnerRecord } from '../../types/runnerRegistry';\nimport { registerRunnerCompactionRecovery } from '../../services/runs/compaction.ts';\nimport { cleanupLegacyRunnerStore, reconcileActiveRunners, stopRunnerProcess } from '../../services/runs/reconcile.ts';\nimport { formatRunnerFooterContribution, formatRunnerStatus } from '../../tui/format.ts';\nimport { openRunnerSpace } from '../../tui/runnerSpace.ts';\nimport { getLogTtlMs } from '../../types/config.ts';\n\nconst LEADER_SOURCE = '@agimon-ai/doompi-runner';\n/** After doom-task's `t` (65) and before the core help group (70). */\nconst LEADER_GROUP_ORDER = 67;\nconst COMMAND_NAME = 'runners';\nconst ERR_REQUIRES_INTERACTIVE = '/runners requires interactive mode';\n\nimport { RUNNER_SETTINGS_FILE, RunnerSettingsLoader } from '../RunnerSettings/RunnerSettingsLoader';\nimport { setRunnerSettings } from '../../types/config.ts';\n\nconst SESSION_START_EVENT = 'session_start';\nconst RUNNER_FINISHED_MESSAGE = 'doom-runner-finished';\nconst COMPLETED_STATE = 'completed';\nconst RMUX_BACKEND = 'rmux';\nconst STOPPED_REASON = 'stopped';\nconst RUNNER_STATUS_KEY = 'doom-runner-runners';\nconst RUNNER_FOOTER_ORDER = 10;\nconst RUNNER_STATUS_POLL_MS = 500;\n\n/**\n * Project-local extension config, read the way Pi documents it: one JSON file\n * per extension under the config directory, and only for a trusted project.\n */\nfunction loadRunnerSettings(context: ExtensionContext): void {\n try {\n const trusted = context.isProjectTrusted?.() ?? false;\n const { settings, issues } = new RunnerSettingsLoader().load(context.cwd, trusted);\n setRunnerSettings(settings);\n // A rejected key is surfaced rather than dropped: silence reads as a\n // setting that simply does not work.\n for (const issue of issues) process.emitWarning(`${RUNNER_SETTINGS_FILE}: ${issue}`);\n } catch (error) {\n process.emitWarning(`Could not read ${RUNNER_SETTINGS_FILE}: ${String(error)}`);\n setRunnerSettings({});\n }\n}\n\n/**\n * doom-runner: replaces pi's `bash` tool with a supervised one and provides a\n * CLI for anything it leaves running.\n */\nexport function installRunnerRuntime(cordis: Context, pi: ExtensionAPI): void {\n const container = createRunnerContainer();\n const registry = container.runnerRegistry;\n let disposeRuntime = async (): Promise<void> => {\n try {\n registry.close();\n } catch (error) {\n process.emitWarning(`Could not close a partially installed doom-runner registry: ${String(error)}`);\n }\n };\n cordis.effect(() => () => disposeRuntime(), `${LEADER_SOURCE}/runtime`);\n\n const launcher = container.launcher;\n const rmuxBackend = container.rmuxBackend;\n const logReader = container.logReader;\n const ptyHost = container.ptyHost;\n const bashRunService = container.bashRunService;\n const paths = container.paths;\n const processControl = container.processControl;\n const lifeline = container.lifeline;\n\n let active = true;\n let sessionGeneration = 0;\n let sessionId: string | undefined;\n let rootSessionId: string | undefined;\n let runners: RunnerRecord[] = [];\n let sessionContext: ExtensionContext | undefined;\n let footerContribution: DoomFooterContributionHandle | undefined;\n let telemetry: DoomTelemetry | undefined;\n let sessionReady = false;\n let disposed = false;\n let refreshInFlight: Promise<void> | undefined;\n let historySweepInFlight: Promise<void> | undefined;\n let historySweepTimer: ReturnType<typeof setImmediate> | undefined;\n let statusPoll: ReturnType<typeof setInterval> | undefined;\n let unsubscribeRegistry: (() => void) | undefined;\n let sessionInitialization: Promise<void> = Promise.resolve();\n let fallbackReadiness: DoomReadinessCoordinator | undefined;\n let refreshQueued = false;\n let queuedReconciliation = false;\n let lastRunnerCount: number | undefined;\n const notifiedRunnerIds = new Set<string>();\n const pendingPromotedRunnerIds = new Set<string>();\n const pendingOperations = new Set<Promise<unknown>>();\n const trackOperation = <T>(operation: Promise<T>): Promise<T> => {\n pendingOperations.add(operation);\n void operation.then(\n () => pendingOperations.delete(operation),\n () => pendingOperations.delete(operation),\n );\n return operation;\n };\n const waitForSessionReadiness = async (): Promise<void> => {\n await sessionInitialization;\n if (!active || !sessionReady || !sessionId) {\n throw new Error('doom-runner requires an active Pi session');\n }\n };\n const trackedBashRunService: IBashRunService = {\n run: async (request) => {\n await waitForSessionReadiness();\n return trackOperation(bashRunService.run(request));\n },\n };\n const isCurrent = (generation: number, expectedSessionId = sessionId): boolean =>\n active && !disposed && generation === sessionGeneration && expectedSessionId === sessionId;\n const getTelemetry = (ctx: ExtensionContext): DoomTelemetry => {\n telemetry ??= createDoomTelemetry({\n serviceName: 'doom-runner',\n packageName: '@agimon-ai/doompi-runner',\n cwd: ctx.cwd,\n env: process.env,\n enableLogs: true,\n enableTraces: true,\n });\n return telemetry;\n };\n /** Performs one bounded pass over active state and explicitly monitored runners. */\n const refreshNow = async (shouldReconcile: boolean): Promise<void> => {\n const activeSessionId = sessionId;\n const generation = sessionGeneration;\n if (!activeSessionId || !isCurrent(generation, activeSessionId)) return;\n\n const activeRecords = await registry.list();\n if (!isCurrent(generation, activeSessionId)) return;\n let visibleActive = activeRecords;\n if (shouldReconcile) {\n const reconciled = await reconcileActiveRunners({\n registry,\n launcher,\n rmuxBackend,\n processControl,\n currentHostPid: process.pid,\n startup: false,\n active: activeRecords,\n });\n for (const error of reconciled.errors) process.emitWarning(error);\n if (reconciled.reclaimed.length > 0) {\n const reclaimedIds = new Set(reconciled.reclaimed);\n visibleActive = activeRecords.filter((record) => !reclaimedIds.has(record.id));\n }\n }\n if (!isCurrent(generation, activeSessionId)) return;\n\n runners = visibleActive.filter((record) => record.sessionId === activeSessionId);\n const rootRunners = rootSessionId\n ? visibleActive.filter((record) => (record.rootSessionId ?? record.sessionId) === rootSessionId)\n : [];\n const runnerCount = rootRunners.length;\n if (lastRunnerCount !== runnerCount) {\n lastRunnerCount = runnerCount;\n footerContribution?.update(formatRunnerFooterContribution(runnerCount));\n if (sessionContext?.hasUI) sessionContext.ui.setStatus(RUNNER_STATUS_KEY, formatRunnerStatus(runnerCount));\n }\n\n const pendingIds = [...pendingPromotedRunnerIds];\n const monitored = await Promise.all(pendingIds.map((id) => registry.get(id, activeSessionId)));\n if (!isCurrent(generation, activeSessionId)) return;\n for (const [index, record] of monitored.entries()) {\n const id = pendingIds[index];\n if (!id) continue;\n if (!record || record.sessionId !== activeSessionId) {\n pendingPromotedRunnerIds.delete(id);\n continue;\n }\n if (record.state !== COMPLETED_STATE) continue;\n pendingPromotedRunnerIds.delete(record.id);\n if (notifiedRunnerIds.has(record.id)) continue;\n notifiedRunnerIds.add(record.id);\n const outcome = record.exit?.reason ?? COMPLETED_STATE;\n const code =\n record.exit?.code === null || record.exit?.code === undefined ? '' : `, exit code ${record.exit.code}`;\n const content = [\n `Background runner ${record.name} exited: ${outcome}${code}.`,\n `Runner ID: ${record.id}`,\n `Log: ${record.logPath}`,\n `Inspect: doom-runner logs ${record.id}`,\n ].join('\\n');\n pi.sendMessage(\n { customType: RUNNER_FINISHED_MESSAGE, content, display: true },\n { triggerTurn: true, deliverAs: 'steer' },\n );\n if (sessionContext) {\n void trackOperation(\n getTelemetry(sessionContext).recordEvent('doom_runner.process_finished', {\n outcome: 'completed',\n 'runner.exit_code': record.exit?.code ?? 0,\n 'runner.backend': record.backend,\n ...(Number.isFinite(Date.parse(record.startedAt))\n ? { duration_ms: Math.max(0, Date.now() - Date.parse(record.startedAt)) }\n : {}),\n }),\n );\n }\n }\n };\n\n /** Coalesces timer and event triggers without losing a requested reconciliation pass. */\n const refresh = (shouldReconcile = true): Promise<void> => {\n if (!sessionId || !sessionReady || disposed) return Promise.resolve();\n if (refreshInFlight) {\n refreshQueued = true;\n queuedReconciliation ||= shouldReconcile;\n return refreshInFlight;\n }\n\n const execution = (async () => {\n let reconcileNext = shouldReconcile;\n do {\n refreshQueued = false;\n queuedReconciliation = false;\n await refreshNow(reconcileNext);\n reconcileNext = queuedReconciliation;\n } while (refreshQueued && !disposed);\n })().finally(() => {\n if (refreshInFlight === execution) refreshInFlight = undefined;\n });\n refreshInFlight = execution;\n return execution;\n };\n\n const reportRefreshError = (error: unknown): void => {\n if (disposed) return;\n if (sessionContext) {\n void trackOperation(getTelemetry(sessionContext).recordError('doom_runner.refresh_failed', error));\n }\n process.emitWarning(`Could not refresh doom-runner: ${String(error)}`);\n };\n const scheduleRefresh = (shouldReconcile: boolean): void => {\n void refresh(shouldReconcile).catch(reportRefreshError);\n };\n const scheduleHistorySweep = (): void => {\n if (historySweepTimer || historySweepInFlight || disposed) return;\n historySweepTimer = setImmediate(() => {\n historySweepTimer = undefined;\n if (disposed) return;\n const execution = (async () => {\n const sweep = paths.sweepHistoryAsync\n ? await paths.sweepHistoryAsync(getLogTtlMs())\n : paths.sweepHistory(getLogTtlMs());\n for (const error of sweep.errors) process.emitWarning(error);\n })()\n .catch((error) => process.emitWarning(`Could not sweep doom-runner history: ${String(error)}`))\n .finally(() => {\n if (historySweepInFlight === execution) historySweepInFlight = undefined;\n });\n historySweepInFlight = execution;\n });\n historySweepTimer.unref?.();\n };\n\n const runCleanup = async (label: string, cleanup: () => void | Promise<void>): Promise<void> => {\n try {\n await cleanup();\n } catch (error) {\n process.emitWarning(`Doom-runner cleanup could not ${label}: ${String(error)}`);\n }\n };\n\n const shutdownRuntime = async (): Promise<void> => {\n if (disposed) return;\n active = false;\n disposed = true;\n sessionGeneration += 1;\n sessionReady = false;\n if (statusPoll) clearInterval(statusPoll);\n statusPoll = undefined;\n if (historySweepTimer) clearImmediate(historySweepTimer);\n historySweepTimer = undefined;\n const unsubscribe = unsubscribeRegistry;\n unsubscribeRegistry = undefined;\n if (unsubscribe) await runCleanup('unsubscribe from the runner registry', unsubscribe);\n\n const ownedReadiness = fallbackReadiness;\n fallbackReadiness = undefined;\n if (ownedReadiness) await runCleanup('cancel standalone readiness work', () => ownedReadiness.dispose());\n await Promise.allSettled(pendingOperations);\n const activeRefresh = refreshInFlight;\n if (activeRefresh) await runCleanup('settle the runner refresh', () => activeRefresh);\n const activeHistorySweep = historySweepInFlight;\n if (activeHistorySweep) await runCleanup('settle runner history cleanup', () => activeHistorySweep);\n\n await runCleanup('dispose runner PTYs', () => ptyHost.disposeAll());\n\n let owned: RunnerRecord[] = [];\n if (sessionId) {\n try {\n owned = await registry.listBySession(sessionId);\n } catch (error) {\n process.emitWarning(`Could not list runners during doom-runner shutdown: ${String(error)}`);\n }\n }\n await Promise.all(\n owned.map(async (record) => {\n try {\n const stopped = await stopRunnerProcess(record, launcher, rmuxBackend);\n if (!stopped && processControl.isAlive(record.pid)) {\n process.emitWarning(`Could not stop runner ${record.id} during session shutdown`);\n return;\n }\n await registry.complete(\n record.id,\n {\n reason: STOPPED_REASON,\n code: null,\n signal: stopped ? 'SIGTERM' : null,\n stopReason: 'session ended',\n },\n record.sessionId,\n );\n } catch (error) {\n process.emitWarning(`Could not clean up runner ${record.id}: ${String(error)}`);\n }\n }),\n );\n\n const context = sessionContext;\n const ownedTelemetry = telemetry;\n telemetry = undefined;\n sessionContext = undefined;\n sessionId = undefined;\n rootSessionId = undefined;\n runners = [];\n notifiedRunnerIds.clear();\n pendingPromotedRunnerIds.clear();\n\n await Promise.all([\n runCleanup('dispose the runner lifeline', () => lifeline.dispose()),\n ...(context?.hasUI\n ? [runCleanup('clear the runner status', () => context.ui.setStatus(RUNNER_STATUS_KEY, undefined))]\n : []),\n ]);\n await runCleanup('close the runner registry', () => registry.close());\n if (ownedTelemetry) {\n await runCleanup('record the runner session finish', () =>\n ownedTelemetry.recordEvent('doom_runner.session_finished', { outcome: 'stopped' }),\n );\n await runCleanup('stop runner telemetry', () => ownedTelemetry.shutdown());\n }\n };\n\n disposeRuntime = shutdownRuntime;\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerFooter({\n source: LEADER_SOURCE,\n id: 'runner-count',\n order: RUNNER_FOOTER_ORDER,\n });\n footerContribution = contribution;\n return () => {\n contribution.dispose();\n if (footerContribution === contribution) footerContribution = undefined;\n };\n });\n unsubscribeRegistry = registry.subscribe(() => scheduleRefresh(false));\n statusPoll = setInterval(() => scheduleRefresh(true), RUNNER_STATUS_POLL_MS);\n statusPoll.unref?.();\n\n registerBashTool(pi, {\n bashRunService: trackedBashRunService,\n getSessionId: async () => {\n await waitForSessionReadiness();\n if (!sessionId) throw new Error('doom-runner requires an active Pi session');\n return sessionId;\n },\n onRunnerStarted: (id) => {\n if (!active || !sessionReady) return;\n pendingPromotedRunnerIds.add(id);\n scheduleRefresh(false);\n },\n });\n\n registerRunnerCompactionRecovery(pi, {\n getSessionId: async () => {\n try {\n await waitForSessionReadiness();\n return sessionId;\n } catch {\n return undefined;\n }\n },\n listBySession: async (activeSessionId) => {\n try {\n await waitForSessionReadiness();\n } catch {\n return [];\n }\n return active ? registry.listBySession(activeSessionId) : [];\n },\n });\n\n pi.registerCommand(COMMAND_NAME, {\n description: 'Open Runner Space: background processes started by bash',\n handler: async (_args, ctx) => {\n if (!active) return;\n const generation = sessionGeneration;\n const activeSessionId = sessionId;\n if (!activeSessionId) return;\n if (!ctx.hasUI) {\n ctx.ui.notify(ERR_REQUIRES_INTERACTIVE, 'error');\n return;\n }\n await waitForSessionReadiness();\n await refresh();\n if (!activeSessionId || !isCurrent(generation, activeSessionId)) return;\n await openRunnerSpace(ctx, {\n getRunners: () => (isCurrent(generation, activeSessionId) ? runners : []),\n getPtyRun: (name) =>\n isCurrent(generation, activeSessionId) ? (rmuxBackend.get(name) ?? ptyHost.get(name)) : undefined,\n readLog: (logPath) =>\n isCurrent(generation, activeSessionId) ? logReader.read(logPath, { lines: 1_000 }).text : '',\n stopRunner: async (id, reason) => {\n if (!isCurrent(generation, activeSessionId)) return;\n const record = runners.find((candidate) => candidate.id === id);\n if (!record) return;\n if (record.backend === RMUX_BACKEND && record.backendTarget) {\n await rmuxBackend.stop(record.backendTarget, record.pid);\n } else await launcher.stop(record.pid);\n if (!isCurrent(generation, activeSessionId)) return;\n await registry.complete(\n record.id,\n { reason: STOPPED_REASON, code: null, signal: null, stopReason: reason },\n record.sessionId,\n );\n if (isCurrent(generation, activeSessionId)) await refresh();\n },\n });\n },\n });\n\n cordis.inject([DOOM_UI_HUB_SERVICE], (uiContext) => {\n const contribution = requireDoomUiHub(uiContext).registerLeader({\n source: LEADER_SOURCE,\n bindings: [\n {\n id: 'runners.open',\n path: [\n { key: 'r', label: 'runners', detail: 'background processes', order: LEADER_GROUP_ORDER },\n { key: 'l', label: 'list', detail: 'runners in this session' },\n ],\n command: { name: COMMAND_NAME },\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n pi.on(SESSION_START_EVENT, (_event, ctx) => {\n if (!active) return;\n const context = ctx as ExtensionContext;\n loadRunnerSettings(context);\n const activeSessionId = context.sessionManager.getSessionId();\n const previousSessionId = sessionId;\n const previousContext = sessionContext;\n const generation = ++sessionGeneration;\n sessionId = activeSessionId;\n rootSessionId = resolveRootSessionId(activeSessionId);\n sessionContext = context;\n sessionReady = false;\n lastRunnerCount = undefined;\n notifiedRunnerIds.clear();\n pendingPromotedRunnerIds.clear();\n\n const initializeSession = async (signal: AbortSignal): Promise<readonly string[]> => {\n const stillCurrent = (): boolean => !signal.aborted && isCurrent(generation, activeSessionId);\n if (!stillCurrent()) return [];\n if (previousSessionId && previousSessionId !== activeSessionId) {\n await runCleanup('dispose the previous session PTYs', () => ptyHost.disposeAll());\n await runCleanup('dispose the previous session lifeline', () => lifeline.dispose());\n if (previousContext?.hasUI) {\n await runCleanup('clear the previous session status', () =>\n previousContext.ui.setStatus(RUNNER_STATUS_KEY, undefined),\n );\n }\n const previousTelemetry = telemetry;\n telemetry = undefined;\n if (previousTelemetry) {\n await runCleanup('stop the previous session telemetry', () => previousTelemetry.shutdown());\n }\n if (!stillCurrent()) return [];\n }\n\n const activeTelemetry = getTelemetry(context);\n await activeTelemetry.recordEvent('doom_runner.session_started', { outcome: 'started' });\n if (!stillCurrent()) return [];\n paths.setSessionId(activeSessionId);\n // Awaited before anything can launch, so every runner this session starts\n // finds a lifeline it can connect to rather than a socket that is not\n // listening yet, which would read as an owner that is already gone.\n await lifeline.arm(activeSessionId);\n if (!stillCurrent()) return [];\n\n const retained = await registry.listAll(activeSessionId);\n if (!stillCurrent()) return [];\n for (const record of retained) {\n if (record.state === COMPLETED_STATE) notifiedRunnerIds.add(record.id);\n else if (record.promoted) pendingPromotedRunnerIds.add(record.id);\n }\n const legacy = await cleanupLegacyRunnerStore({\n registry,\n launcher,\n rmuxBackend,\n processControl,\n currentHostPid: process.pid,\n paths,\n });\n if (!stillCurrent()) return [];\n const reconciled = await reconcileActiveRunners({\n registry,\n launcher,\n rmuxBackend,\n processControl,\n currentHostPid: process.pid,\n startup: true,\n });\n if (!stillCurrent()) return [];\n sessionReady = true;\n await refresh(false);\n if (!stillCurrent()) return [];\n scheduleHistorySweep();\n const errors = [...legacy.errors, ...reconciled.errors];\n const reclaimedCount = legacy.reclaimed.length + reconciled.reclaimed.length;\n if (reclaimedCount > 0 && context.hasUI) {\n context.ui.notify(`Reclaimed ${reclaimedCount} stale runner record(s)`, 'warning');\n }\n await activeTelemetry.recordEvent('doom_runner.reconciled', {\n 'runner.reclaimed_count': reclaimedCount,\n 'runner.error_count': errors.length,\n outcome: errors.length === 0 ? 'completed' : 'degraded',\n });\n return errors;\n };\n\n const previousInitialization = sessionInitialization.catch(() => undefined);\n const startReadiness = async (): Promise<void> => {\n await previousInitialization;\n if (!isCurrent(generation, activeSessionId)) return;\n const coordinator =\n readDoomReadinessCoordinator(cordis) ??\n (fallbackReadiness ??= createDoomReadinessCoordinator({\n notify: (notification) => {\n process.emitWarning(\n `${notification.packageId} initialization ${notification.state}: ${notification.error?.message ?? notification.diagnostics.join('; ')}`,\n );\n },\n }));\n const handle = coordinator.start(LEADER_SOURCE, `${activeSessionId}:${generation}`, async (signal) => ({\n value: undefined,\n diagnostics: await initializeSession(signal),\n }));\n await handle.wait();\n };\n const operation = startReadiness();\n sessionInitialization = operation;\n // The coordinator reports a failed generation once; this branch only marks\n // the detached waiter handled so Pi is not held open by the notification path.\n void trackOperation(operation).catch(() => undefined);\n });\n}\n\n/** The package's sole Pi factory; Pi reloads it and Cordis owns all package resources. */\nexport async function runnerExtension(pi: ExtensionAPI): Promise<void> {\n const connection = await connectDoomCordisHost(pi, LEADER_SOURCE);\n const fiber = connection.root.plugin(runnerPlugin, { pi });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\ninterface RunnerPluginConfig {\n readonly pi: ExtensionAPI;\n}\n\nfunction runnerPlugin(cordis: Context, config: RunnerPluginConfig): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: LEADER_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-use-runner',\n description:\n 'Use Doom Pi Runner to supervise shell commands, inspect durable logs, provide interactive input, and stop background runs.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n installRunnerRuntime(cordis, config.pi);\n}\n\nexport default runnerExtension;\n"],"mappings":"2rBAuBA,MAAM,EAAgB,2BAGhB,GAAe,UAQf,EAAkB,YAElB,GAAiB,UACjB,EAAoB,sBAQ1B,SAAS,GAAmB,EAAiC,CAC3D,GAAI,CACF,IAAM,EAAU,EAAQ,mBAAmB,GAAK,GAC1C,CAAE,WAAU,UAAW,IAAIA,EAAAA,qBAAqB,CAAC,CAAC,KAAK,EAAQ,IAAK,CAAO,EACjF,EAAA,kBAAkB,CAAQ,EAG1B,IAAK,IAAM,KAAS,EAAQ,QAAQ,YAAY,GAAGC,EAAAA,qBAAqB,IAAI,GAAO,CACrF,OAAS,EAAO,CACd,QAAQ,YAAY,kBAAkBA,EAAAA,qBAAqB,IAAI,OAAO,CAAK,GAAG,EAC9E,EAAA,kBAAkB,CAAC,CAAC,CACtB,CACF,CAMA,SAAgB,EAAqB,EAAiB,EAAwB,CAC5E,IAAM,EAAYC,EAAAA,sBAAsB,EAClC,EAAW,EAAU,eACvB,EAAiB,SAA2B,CAC9C,GAAI,CACF,EAAS,MAAM,CACjB,OAAS,EAAO,CACd,QAAQ,YAAY,+DAA+D,OAAO,CAAK,GAAG,CACpG,CACF,EACA,EAAO,eAAmB,EAAe,EAAG,GAAG,EAAc,SAAS,EAEtE,IAAM,EAAW,EAAU,SACrB,EAAc,EAAU,YACxB,GAAY,EAAU,UACtB,EAAU,EAAU,QACpB,GAAiB,EAAU,eAC3B,EAAQ,EAAU,MAClB,EAAiB,EAAU,eAC3B,EAAW,EAAU,SAEvB,EAAS,GACT,EAAoB,EACpB,EACA,EACA,EAA0B,CAAC,EAC3B,EACA,EACA,EACA,EAAe,GACf,EAAW,GACX,EACA,EACA,EACA,EACA,EACA,EAAuC,QAAQ,QAAQ,EACvD,EACA,EAAgB,GAChB,EAAuB,GACvB,EACE,EAAoB,IAAI,IACxB,EAA2B,IAAI,IAC/B,EAAoB,IAAI,IACxB,EAAqB,IACzB,EAAkB,IAAI,CAAS,EAC/B,EAAe,SACP,EAAkB,OAAO,CAAS,MAClC,EAAkB,OAAO,CAAS,CAC1C,EACO,GAEH,EAA0B,SAA2B,CAEzD,GADA,MAAM,EACF,CAAC,GAAU,CAAC,GAAgB,CAAC,EAC/B,MAAU,MAAM,2CAA2C,CAE/D,EACM,GAAyC,CAC7C,IAAK,KAAO,KACV,MAAM,EAAwB,EACvB,EAAe,GAAe,IAAI,CAAO,CAAC,EAErD,EACM,GAAa,EAAoB,EAAoB,IACzD,GAAU,CAAC,GAAY,IAAe,GAAqB,IAAsB,EAC7E,EAAgB,IACpB,KAAA,EAAcC,EAAAA,oBAAAA,CAAoB,CAChC,YAAa,cACb,YAAa,2BACb,IAAK,EAAI,IACT,IAAK,QAAQ,IACb,WAAY,GACZ,aAAc,EAChB,CAAC,EACM,GAGH,GAAa,KAAO,IAA4C,CACpE,IAAM,EAAkB,EAClB,EAAa,EACnB,GAAI,CAAC,GAAmB,CAAC,EAAU,EAAY,CAAe,EAAG,OAEjE,IAAM,EAAgB,MAAM,EAAS,KAAK,EAC1C,GAAI,CAAC,EAAU,EAAY,CAAe,EAAG,OAC7C,IAAI,EAAgB,EACpB,GAAI,EAAiB,CACnB,IAAM,EAAa,MAAMC,EAAAA,uBAAuB,CAC9C,WACA,WACA,cACA,iBACA,eAAgB,QAAQ,IACxB,QAAS,GACT,OAAQ,CACV,CAAC,EACD,IAAK,IAAM,KAAS,EAAW,OAAQ,QAAQ,YAAY,CAAK,EAChE,GAAI,EAAW,UAAU,OAAS,EAAG,CACnC,IAAM,EAAe,IAAI,IAAI,EAAW,SAAS,EACjD,EAAgB,EAAc,OAAQ,GAAW,CAAC,EAAa,IAAI,EAAO,EAAE,CAAC,CAC/E,CACF,CACA,GAAI,CAAC,EAAU,EAAY,CAAe,EAAG,OAE7C,EAAU,EAAc,OAAQ,GAAW,EAAO,YAAc,CAAe,EAI/E,IAAM,GAHc,EAChB,EAAc,OAAQ,IAAY,EAAO,eAAiB,EAAO,aAAe,CAAa,EAC7F,CAAC,EAAA,CAC2B,OAC5B,IAAoB,IACtB,EAAkB,EAClB,GAAoB,OAAOC,EAAAA,+BAA+B,CAAW,CAAC,EAClE,GAAgB,OAAO,EAAe,GAAG,UAAU,EAAmBC,EAAAA,mBAAmB,CAAW,CAAC,GAG3G,IAAM,EAAa,CAAC,GAAG,CAAwB,EACzC,EAAY,MAAM,QAAQ,IAAI,EAAW,IAAK,GAAO,EAAS,IAAI,EAAI,CAAe,CAAC,CAAC,EACxF,KAAU,EAAY,CAAe,EAC1C,IAAK,GAAM,CAAC,EAAO,KAAW,EAAU,QAAQ,EAAG,CACjD,IAAM,EAAK,EAAW,GACtB,GAAI,CAAC,EAAI,SACT,GAAI,CAAC,GAAU,EAAO,YAAc,EAAiB,CACnD,EAAyB,OAAO,CAAE,EAClC,QACF,CAGA,GAFI,EAAO,QAAU,IACrB,EAAyB,OAAO,EAAO,EAAE,EACrC,EAAkB,IAAI,EAAO,EAAE,GAAG,SACtC,EAAkB,IAAI,EAAO,EAAE,EAC/B,IAAM,EAAU,EAAO,MAAM,QAAU,EACjC,EACJ,EAAO,MAAM,OAAS,MAAQ,EAAO,MAAM,OAAS,IAAA,GAAY,GAAK,eAAe,EAAO,KAAK,OAC5F,EAAU,CACd,qBAAqB,EAAO,KAAK,WAAW,IAAU,EAAK,GAC3D,cAAc,EAAO,KACrB,QAAQ,EAAO,UACf,6BAA6B,EAAO,IACtC,CAAC,CAAC,KAAK;CAAI,EACX,EAAG,YACD,CAAE,WAAY,uBAAyB,UAAS,QAAS,EAAK,EAC9D,CAAE,YAAa,GAAM,UAAW,OAAQ,CAC1C,EACI,GACF,EACE,EAAa,CAAc,CAAC,CAAC,YAAY,+BAAgC,CACvE,QAAS,YACT,mBAAoB,EAAO,MAAM,MAAQ,EACzC,iBAAkB,EAAO,QACzB,GAAI,OAAO,SAAS,KAAK,MAAM,EAAO,SAAS,CAAC,EAC5C,CAAE,YAAa,KAAK,IAAI,EAAG,KAAK,IAAI,EAAI,KAAK,MAAM,EAAO,SAAS,CAAC,CAAE,EACtE,CAAC,CACP,CAAC,CACH,CAEJ,CACF,EAGM,GAAW,EAAkB,KAAwB,CACzD,GAAI,CAAC,GAAa,CAAC,GAAgB,EAAU,OAAO,QAAQ,QAAQ,EACpE,GAAI,EAGF,MAFA,GAAgB,GAChB,IAAyB,EAClB,EAGT,IAAM,GAAa,SAAY,CAC7B,IAAI,EAAgB,EACpB,EACE,GAAgB,GAChB,EAAuB,GACvB,MAAM,GAAW,CAAa,EAC9B,EAAgB,QACT,GAAiB,CAAC,EAC7B,EAAA,CAAG,CAAC,CAAC,YAAc,CACb,IAAoB,IAAW,EAAkB,IAAA,GACvD,CAAC,EAED,MADA,GAAkB,EACX,CACT,EAEM,GAAsB,GAAyB,CAC/C,IACA,GACF,EAAoB,EAAa,CAAc,CAAC,CAAC,YAAY,6BAA8B,CAAK,CAAC,EAEnG,QAAQ,YAAY,kCAAkC,OAAO,CAAK,GAAG,EACvE,EACM,GAAmB,GAAmC,CAC1D,EAAa,CAAe,CAAC,CAAC,MAAM,EAAkB,CACxD,EACM,OAAmC,CACnC,GAAqB,GAAwB,IACjD,EAAoB,iBAAmB,CAErC,GADA,EAAoB,IAAA,GAChB,EAAU,OACd,IAAM,GAAa,SAAY,CAC7B,IAAM,EAAQ,EAAM,kBAChB,MAAM,EAAM,kBAAkBC,EAAAA,YAAY,CAAC,EAC3C,EAAM,aAAaA,EAAAA,YAAY,CAAC,EACpC,IAAK,IAAM,KAAS,EAAM,OAAQ,QAAQ,YAAY,CAAK,CAC7D,EAAA,CAAG,CAAC,CACD,MAAO,GAAU,QAAQ,YAAY,wCAAwC,OAAO,CAAK,GAAG,CAAC,CAAC,CAC9F,YAAc,CACT,IAAyB,IAAW,EAAuB,IAAA,GACjE,CAAC,EACH,EAAuB,CACzB,CAAC,EACD,EAAkB,QAAQ,EAC5B,EAEM,EAAa,MAAO,EAAe,IAAuD,CAC9F,GAAI,CACF,MAAM,EAAQ,CAChB,OAAS,EAAO,CACd,QAAQ,YAAY,iCAAiC,EAAM,IAAI,OAAO,CAAK,GAAG,CAChF,CACF,EAoFA,EAAiB,SAlFkC,CACjD,GAAI,EAAU,OACd,EAAS,GACT,EAAW,GACX,GAAqB,EACrB,EAAe,GACX,GAAY,cAAc,CAAU,EACxC,EAAa,IAAA,GACT,GAAmB,eAAe,CAAiB,EACvD,EAAoB,IAAA,GACpB,IAAM,EAAc,EACpB,EAAsB,IAAA,GAClB,GAAa,MAAM,EAAW,uCAAwC,CAAW,EAErF,IAAM,EAAiB,EACvB,EAAoB,IAAA,GAChB,GAAgB,MAAM,EAAW,uCAA0C,EAAe,QAAQ,CAAC,EACvG,MAAM,QAAQ,WAAW,CAAiB,EAC1C,IAAM,EAAgB,EAClB,GAAe,MAAM,EAAW,gCAAmC,CAAa,EACpF,IAAM,EAAqB,EACvB,GAAoB,MAAM,EAAW,oCAAuC,CAAkB,EAElG,MAAM,EAAW,0BAA6B,EAAQ,WAAW,CAAC,EAElE,IAAI,EAAwB,CAAC,EAC7B,GAAI,EACF,GAAI,CACF,EAAQ,MAAM,EAAS,cAAc,CAAS,CAChD,OAAS,EAAO,CACd,QAAQ,YAAY,uDAAuD,OAAO,CAAK,GAAG,CAC5F,CAEF,MAAM,QAAQ,IACZ,EAAM,IAAI,KAAO,IAAW,CAC1B,GAAI,CACF,IAAM,EAAU,MAAMC,EAAAA,kBAAkB,EAAQ,EAAU,CAAW,EACrE,GAAI,CAAC,GAAW,EAAe,QAAQ,EAAO,GAAG,EAAG,CAClD,QAAQ,YAAY,yBAAyB,EAAO,GAAG,yBAAyB,EAChF,MACF,CACA,MAAM,EAAS,SACb,EAAO,GACP,CACE,OAAQ,GACR,KAAM,KACN,OAAQ,EAAU,UAAY,KAC9B,WAAY,eACd,EACA,EAAO,SACT,CACF,OAAS,EAAO,CACd,QAAQ,YAAY,6BAA6B,EAAO,GAAG,IAAI,OAAO,CAAK,GAAG,CAChF,CACF,CAAC,CACH,EAEA,IAAM,EAAU,EACV,EAAiB,EACvB,EAAY,IAAA,GACZ,EAAiB,IAAA,GACjB,EAAY,IAAA,GACZ,EAAgB,IAAA,GAChB,EAAU,CAAC,EACX,EAAkB,MAAM,EACxB,EAAyB,MAAM,EAE/B,MAAM,QAAQ,IAAI,CAChB,EAAW,kCAAqC,EAAS,QAAQ,CAAC,EAClE,GAAI,GAAS,MACT,CAAC,EAAW,8BAAiC,EAAQ,GAAG,UAAU,EAAmB,IAAA,EAAS,CAAC,CAAC,EAChG,CAAC,CACP,CAAC,EACD,MAAM,EAAW,gCAAmC,EAAS,MAAM,CAAC,EAChE,IACF,MAAM,EAAW,uCACf,EAAe,YAAY,+BAAgC,CAAE,QAAS,SAAU,CAAC,CACnF,EACA,MAAM,EAAW,4BAA+B,EAAe,SAAS,CAAC,EAE7E,EAIA,EAAO,OAAO,CAACC,EAAAA,mBAAmB,EAAI,GAAc,CAClD,IAAM,GAAA,EAAeC,EAAAA,iBAAAA,CAAiB,CAAS,CAAC,CAAC,eAAe,CAC9D,OAAQ,EACR,GAAI,eACJ,MAAO,EACT,CAAC,EAED,MADA,GAAqB,MACR,CACX,EAAa,QAAQ,EACjB,IAAuB,IAAc,EAAqB,IAAA,GAChE,CACF,CAAC,EACD,EAAsB,EAAS,cAAgB,GAAgB,EAAK,CAAC,EACrE,EAAa,gBAAkB,GAAgB,EAAI,EAAG,GAAqB,EAC3E,EAAW,QAAQ,EAEnB,EAAA,iBAAiB,EAAI,CACnB,eAAgB,GAChB,aAAc,SAAY,CAExB,GADA,MAAM,EAAwB,EAC1B,CAAC,EAAW,MAAU,MAAM,2CAA2C,EAC3E,OAAO,CACT,EACA,gBAAkB,GAAO,CACnB,CAAC,GAAU,CAAC,IAChB,EAAyB,IAAI,CAAE,EAC/B,GAAgB,EAAK,EACvB,CACF,CAAC,EAED,EAAA,iCAAiC,EAAI,CACnC,aAAc,SAAY,CACxB,GAAI,CAEF,OADA,MAAM,EAAwB,EACvB,CACT,MAAQ,CACN,MACF,CACF,EACA,cAAe,KAAO,IAAoB,CACxC,GAAI,CACF,MAAM,EAAwB,CAChC,MAAQ,CACN,MAAO,CAAC,CACV,CACA,OAAO,EAAS,EAAS,cAAc,CAAe,EAAI,CAAC,CAC7D,CACF,CAAC,EAED,EAAG,gBAAgB,GAAc,CAC/B,YAAa,0DACb,QAAS,MAAO,EAAO,IAAQ,CAC7B,GAAI,CAAC,EAAQ,OACb,IAAM,EAAa,EACb,EAAkB,EACnB,KACL,IAAI,CAAC,EAAI,MAAO,CACd,EAAI,GAAG,OAAO,qCAA0B,OAAO,EAC/C,MACF,CACA,MAAM,EAAwB,EAC9B,MAAM,EAAQ,EACV,GAAC,GAAmB,CAAC,EAAU,EAAY,CAAe,IAC9D,MAAMC,EAAAA,gBAAgB,EAAK,CACzB,eAAmB,EAAU,EAAY,CAAe,EAAI,EAAU,CAAC,EACvE,UAAY,GACV,EAAU,EAAY,CAAe,EAAK,EAAY,IAAI,CAAI,GAAK,EAAQ,IAAI,CAAI,EAAK,IAAA,GAC1F,QAAU,GACR,EAAU,EAAY,CAAe,EAAI,GAAU,KAAK,EAAS,CAAE,MAAO,GAAM,CAAC,CAAC,CAAC,KAAO,GAC5F,WAAY,MAAO,EAAI,IAAW,CAChC,GAAI,CAAC,EAAU,EAAY,CAAe,EAAG,OAC7C,IAAM,EAAS,EAAQ,KAAM,GAAc,EAAU,KAAO,CAAE,EACzD,IACD,EAAO,UAAY,QAAgB,EAAO,cAC5C,MAAM,EAAY,KAAK,EAAO,cAAe,EAAO,GAAG,EAClD,MAAM,EAAS,KAAK,EAAO,GAAG,EAChC,EAAU,EAAY,CAAe,IAC1C,MAAM,EAAS,SACb,EAAO,GACP,CAAE,OAAQ,GAAgB,KAAM,KAAM,OAAQ,KAAM,WAAY,CAAO,EACvE,EAAO,SACT,EACI,EAAU,EAAY,CAAe,GAAG,MAAM,EAAQ,GAC5D,CACF,CAAC,CAzBD,CA0BF,CACF,CAAC,EAED,EAAO,OAAO,CAACF,EAAAA,mBAAmB,EAAI,GAAc,CAClD,IAAM,GAAA,EAAeC,EAAAA,iBAAAA,CAAiB,CAAS,CAAC,CAAC,eAAe,CAC9D,OAAQ,EACR,SAAU,CACR,CACE,GAAI,eACJ,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,UAAW,OAAQ,uBAAwB,MAAO,EAAmB,EACxF,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAQ,yBAA0B,CAC/D,EACA,QAAS,CAAE,KAAM,EAAa,CAChC,CACF,CACF,CAAC,EACD,UAAa,EAAa,QAAQ,CACpC,CAAC,EAED,EAAG,GAAG,iBAAsB,EAAQ,IAAQ,CAC1C,GAAI,CAAC,EAAQ,OACb,IAAM,EAAU,EAChB,GAAmB,CAAO,EAC1B,IAAM,EAAkB,EAAQ,eAAe,aAAa,EACtD,EAAoB,EACpB,EAAkB,EAClB,EAAa,EAAE,EACrB,EAAY,EACZ,GAAA,EAAgBE,EAAAA,qBAAAA,CAAqB,CAAe,EACpD,EAAiB,EACjB,EAAe,GACf,EAAkB,IAAA,GAClB,EAAkB,MAAM,EACxB,EAAyB,MAAM,EAE/B,IAAM,EAAoB,KAAO,IAAoD,CACnF,IAAM,MAA8B,CAAC,EAAO,SAAW,EAAU,EAAY,CAAe,EAC5F,GAAI,CAAC,EAAa,EAAG,MAAO,CAAC,EAC7B,GAAI,GAAqB,IAAsB,EAAiB,CAC9D,MAAM,EAAW,wCAA2C,EAAQ,WAAW,CAAC,EAChF,MAAM,EAAW,4CAA+C,EAAS,QAAQ,CAAC,EAC9E,GAAiB,OACnB,MAAM,EAAW,wCACf,EAAgB,GAAG,UAAU,EAAmB,IAAA,EAAS,CAC3D,EAEF,IAAM,EAAoB,EAK1B,GAJA,EAAY,IAAA,GACR,GACF,MAAM,EAAW,0CAA6C,EAAkB,SAAS,CAAC,EAExF,CAAC,EAAa,EAAG,MAAO,CAAC,CAC/B,CAEA,IAAM,EAAkB,EAAa,CAAO,EAQ5C,GAPA,MAAM,EAAgB,YAAY,8BAA+B,CAAE,QAAS,SAAU,CAAC,EACnF,CAAC,EAAa,IAClB,EAAM,aAAa,CAAe,EAIlC,MAAM,EAAS,IAAI,CAAe,EAC9B,CAAC,EAAa,GAAG,MAAO,CAAC,EAE7B,IAAM,EAAW,MAAM,EAAS,QAAQ,CAAe,EACvD,GAAI,CAAC,EAAa,EAAG,MAAO,CAAC,EAC7B,IAAK,IAAM,KAAU,EACf,EAAO,QAAU,EAAiB,EAAkB,IAAI,EAAO,EAAE,EAC5D,EAAO,UAAU,EAAyB,IAAI,EAAO,EAAE,EAElE,IAAM,EAAS,MAAMC,EAAAA,yBAAyB,CAC5C,WACA,WACA,cACA,iBACA,eAAgB,QAAQ,IACxB,OACF,CAAC,EACD,GAAI,CAAC,EAAa,EAAG,MAAO,CAAC,EAC7B,IAAM,EAAa,MAAMT,EAAAA,uBAAuB,CAC9C,WACA,WACA,cACA,iBACA,eAAgB,QAAQ,IACxB,QAAS,EACX,CAAC,EAID,GAHI,CAAC,EAAa,IAClB,EAAe,GACf,MAAM,EAAQ,EAAK,EACf,CAAC,EAAa,GAAG,MAAO,CAAC,EAC7B,GAAqB,EACrB,IAAM,EAAS,CAAC,GAAG,EAAO,OAAQ,GAAG,EAAW,MAAM,EAChD,EAAiB,EAAO,UAAU,OAAS,EAAW,UAAU,OAStE,OARI,EAAiB,GAAK,EAAQ,OAChC,EAAQ,GAAG,OAAO,aAAa,EAAe,yBAA0B,SAAS,EAEnF,MAAM,EAAgB,YAAY,yBAA0B,CAC1D,yBAA0B,EAC1B,qBAAsB,EAAO,OAC7B,QAAS,EAAO,SAAW,EAAI,YAAc,UAC/C,CAAC,EACM,CACT,EAEM,EAAyB,EAAsB,UAAY,IAAA,EAAS,EAmBpE,GAAY,SAlBgC,CAChD,MAAM,EACD,EAAU,EAAY,CAAe,GAc1C,OAAA,EAZEU,EAAAA,6BAAAA,CAA6B,CAAM,IAClC,KAAA,EAAsBC,EAAAA,+BAAAA,CAA+B,CACpD,OAAS,GAAiB,CACxB,QAAQ,YACN,GAAG,EAAa,UAAU,kBAAkB,EAAa,MAAM,IAAI,EAAa,OAAO,SAAW,EAAa,YAAY,KAAK,IAAI,GACtI,CACF,CACF,CAAC,GAAA,CACwB,MAAM,EAAe,GAAG,EAAgB,GAAG,IAAc,KAAO,KAAY,CACrG,MAAO,IAAA,GACP,YAAa,MAAM,EAAkB,CAAM,CAC7C,EACW,CAAC,CAAC,KAAK,CACpB,EACkB,CAAe,EACjC,EAAwB,EAGxB,EAAoB,CAAS,CAAC,CAAC,UAAY,IAAA,EAAS,CACtD,CAAC,CACH,CAGA,eAAsB,EAAgB,EAAiC,CACrE,IAAM,EAAa,MAAA,EAAMC,EAAAA,sBAAAA,CAAsB,EAAI,CAAa,EAC1D,EAAQ,EAAW,KAAK,OAAO,EAAc,CAAE,IAAG,CAAC,EACzD,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF,CAMA,SAAS,EAAa,EAAiB,EAAkC,CACvE,EAAO,OAAO,CAACC,EAAAA,iBAAiB,EAAI,GAAgB,CAClD,IAAM,GAAA,EAAeC,EAAAA,uBAAAA,CAAuB,CAAW,CAAC,CAAC,SAAS,CAChE,OAAQ,EACR,UAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,KACA,OAAQ,CACN,CACE,KAAM,oBACN,YACE,4HACJ,CACF,CACF,CAAC,EACD,UAAa,EAAa,QAAQ,CACpC,CAAC,EACD,EAAqB,EAAQ,EAAO,EAAE,CACxC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import{registerRunnerCompactionRecovery as e}from"../../services/runs/compaction.mjs";import{getLogTtlMs as t,setRunnerSettings as n}from"../../types/config.mjs";import{createRunnerContainer as r}from"../../container/index.mjs";import{cleanupLegacyRunnerStore as i,reconcileActiveRunners as a,stopRunnerProcess as o}from"../../services/runs/reconcile.mjs";import{registerBashTool as s}from"../../commands/bash/bashTool.mjs";import{formatRunnerFooterContribution as c,formatRunnerStatus as l}from"../../tui/format.mjs";import{openRunnerSpace as u}from"../../tui/runnerSpace.mjs";import{RUNNER_SETTINGS_FILE as d,RunnerSettingsLoader as f}from"../RunnerSettings/RunnerSettingsLoader.mjs";import{resolveRootSessionId as p}from"@agimon-ai/doompi-extension-contracts/child-process";import{connectDoomCordisHost as m}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_HELP_SERVICE as h,requireDoomHelpService as g}from"@agimon-ai/doompi-extension-contracts/help";import{createDoomReadinessCoordinator as ee,readDoomReadinessCoordinator as te}from"@agimon-ai/doompi-extension-contracts/readiness";import{DOOM_UI_HUB_SERVICE as ne,requireDoomUiHub as re}from"@agimon-ai/doompi-extension-contracts/ui-hub";import{createDoomTelemetry as ie}from"@agimon-ai/doompi-telemetry";const _=`@agimon-ai/doompi-runner`,ae=`runners`,v=`completed`,oe=`stopped`,y=`doom-runner-runners`;function se(e){try{let t=e.isProjectTrusted?.()??!1,{settings:r,issues:i}=new f().load(e.cwd,t);n(r);for(let e of i)process.emitWarning(`${d}: ${e}`)}catch(e){process.emitWarning(`Could not read ${d}: ${String(e)}`),n({})}}function b(n,d){let f=r(),m=f.runnerRegistry,h=async()=>{try{m.close()}catch(e){process.emitWarning(`Could not close a partially installed doom-runner registry: ${String(e)}`)}};n.effect(()=>()=>h(),`${_}/runtime`);let g=f.launcher,b=f.rmuxBackend,x=f.logReader,S=f.ptyHost,ce=f.bashRunService,C=f.paths,w=f.processControl,T=f.lifeline,E=!0,D=0,O,k,A=[],j,M,N,P=!1,F=!1,I,L,R,z,B,V=Promise.resolve(),H,U=!1,W=!1,G,K=new Set,q=new Set,J=new Set,Y=e=>(J.add(e),e.then(()=>J.delete(e),()=>J.delete(e)),e),X=async()=>{if(await V,!E||!P||!O)throw Error(`doom-runner requires an active Pi session`)},le={run:async e=>(await X(),Y(ce.run(e)))},Z=(e,t=O)=>E&&!F&&e===D&&t===O,ue=e=>(N??=ie({serviceName:`doom-runner`,packageName:`@agimon-ai/doompi-runner`,cwd:e.cwd,env:process.env,enableLogs:!0,enableTraces:!0}),N),de=async e=>{let t=O,n=D;if(!t||!Z(n,t))return;let r=await m.list();if(!Z(n,t))return;let i=r;if(e){let e=await a({registry:m,launcher:g,rmuxBackend:b,processControl:w,currentHostPid:process.pid,startup:!1,active:r});for(let t of e.errors)process.emitWarning(t);if(e.reclaimed.length>0){let t=new Set(e.reclaimed);i=r.filter(e=>!t.has(e.id))}}if(!Z(n,t))return;A=i.filter(e=>e.sessionId===t);let o=(k?i.filter(e=>(e.rootSessionId??e.sessionId)===k):[]).length;G!==o&&(G=o,M?.update(c(o)),j?.hasUI&&j.ui.setStatus(y,l(o)));let s=[...q],u=await Promise.all(s.map(e=>m.get(e,t)));if(Z(n,t))for(let[e,n]of u.entries()){let r=s[e];if(!r)continue;if(!n||n.sessionId!==t){q.delete(r);continue}if(n.state!==v||(q.delete(n.id),K.has(n.id)))continue;K.add(n.id);let i=n.exit?.reason??v,a=n.exit?.code===null||n.exit?.code===void 0?``:`, exit code ${n.exit.code}`,o=[`Background runner ${n.name} exited: ${i}${a}.`,`Runner ID: ${n.id}`,`Log: ${n.logPath}`,`Inspect: doom-runner logs ${n.id}`].join(`
|
|
2
|
-
`);d.sendMessage({customType:`doom-runner-finished`,content:o,display:!0},{triggerTurn:!0,deliverAs:`steer`}),j&&Y(ue(j).recordEvent(`doom_runner.process_finished`,{outcome:`completed`,"runner.exit_code":n.exit?.code??0,"runner.backend":n.backend,...Number.isFinite(Date.parse(n.startedAt))?{duration_ms:Math.max(0,Date.now()-Date.parse(n.startedAt))}:{}}))}},Q=(e=!0)=>{if(!O||!P||F)return Promise.resolve();if(I)return U=!0,W||=e,I;let t=(async()=>{let t=e;do U=!1,W=!1,await de(t),t=W;while(U&&!F)})().finally(()=>{I===t&&(I=void 0)});return I=t,t},fe=e=>{F||(j&&Y(ue(j).recordError(`doom_runner.refresh_failed`,e)),process.emitWarning(`Could not refresh doom-runner: ${String(e)}`))},pe=e=>{Q(e).catch(fe)},me=()=>{R||L||F||(R=setImmediate(()=>{if(R=void 0,F)return;let e=(async()=>{let e=C.sweepHistoryAsync?await C.sweepHistoryAsync(t()):C.sweepHistory(t());for(let t of e.errors)process.emitWarning(t)})().catch(e=>process.emitWarning(`Could not sweep doom-runner history: ${String(e)}`)).finally(()=>{L===e&&(L=void 0)});L=e}),R.unref?.())},$=async(e,t)=>{try{await t()}catch(t){process.emitWarning(`Doom-runner cleanup could not ${e}: ${String(t)}`)}};h=async()=>{if(F)return;E=!1,F=!0,D+=1,P=!1,z&&clearInterval(z),z=void 0,R&&clearImmediate(R),R=void 0;let e=B;B=void 0,e&&await $(`unsubscribe from the runner registry`,e);let t=H;H=void 0,t&&await $(`cancel standalone readiness work`,()=>t.dispose()),await Promise.allSettled(J);let n=I;n&&await $(`settle the runner refresh`,()=>n);let r=L;r&&await $(`settle runner history cleanup`,()=>r),await $(`dispose runner PTYs`,()=>S.disposeAll());let i=[];if(O)try{i=await m.listBySession(O)}catch(e){process.emitWarning(`Could not list runners during doom-runner shutdown: ${String(e)}`)}await Promise.all(i.map(async e=>{try{let t=await o(e,g,b);if(!t&&w.isAlive(e.pid)){process.emitWarning(`Could not stop runner ${e.id} during session shutdown`);return}await m.complete(e.id,{reason:oe,code:null,signal:t?`SIGTERM`:null,stopReason:`session ended`},e.sessionId)}catch(t){process.emitWarning(`Could not clean up runner ${e.id}: ${String(t)}`)}}));let a=j,s=N;N=void 0,j=void 0,O=void 0,k=void 0,A=[],K.clear(),q.clear(),await Promise.all([$(`dispose the runner lifeline`,()=>T.dispose()),...a?.hasUI?[$(`clear the runner status`,()=>a.ui.setStatus(y,void 0))]:[]]),await $(`close the runner registry`,()=>m.close()),s&&(await $(`record the runner session finish`,()=>s.recordEvent(`doom_runner.session_finished`,{outcome:`stopped`})),await $(`stop runner telemetry`,()=>s.shutdown()))},n.inject([ne],e=>{let t=re(e).registerFooter({source:_,id:`runner-count`,order:10});return M=t,()=>{t.dispose(),M===t&&(M=void 0)}}),B=m.subscribe(()=>pe(!1)),z=setInterval(()=>pe(!0),500),z.unref?.(),s(d,{bashRunService:le,getSessionId:async()=>{if(await X(),!O)throw Error(`doom-runner requires an active Pi session`);return O},onRunnerStarted:e=>{!E||!P||(q.add(e),pe(!1))}}),e(d,{getSessionId:async()=>{try{return await X(),O}catch{return}},listBySession:async e=>{try{await X()}catch{return[]}return E?m.listBySession(e):[]}}),d.registerCommand(ae,{description:`Open Runner Space: background processes started by bash`,handler:async(e,t)=>{if(!E)return;let n=D,r=O;if(r){if(!t.hasUI){t.ui.notify(`/runners requires interactive mode`,`error`);return}await X(),await Q(),!(!r||!Z(n,r))&&await u(t,{getRunners:()=>Z(n,r)?A:[],getPtyRun:e=>Z(n,r)?b.get(e)??S.get(e):void 0,readLog:e=>Z(n,r)?x.read(e,{lines:1e3}).text:``,stopRunner:async(e,t)=>{if(!Z(n,r))return;let i=A.find(t=>t.id===e);i&&(i.backend===`rmux`&&i.backendTarget?await b.stop(i.backendTarget,i.pid):await g.stop(i.pid),Z(n,r)&&(await m.complete(i.id,{reason:oe,code:null,signal:null,stopReason:t},i.sessionId),Z(n,r)&&await Q()))}})}}}),n.inject([ne],e=>{let t=re(e).registerLeader({source:_,bindings:[{id:`runners.open`,path:[{key:`r`,label:`runners`,order:67},{key:`
|
|
2
|
+
`);d.sendMessage({customType:`doom-runner-finished`,content:o,display:!0},{triggerTurn:!0,deliverAs:`steer`}),j&&Y(ue(j).recordEvent(`doom_runner.process_finished`,{outcome:`completed`,"runner.exit_code":n.exit?.code??0,"runner.backend":n.backend,...Number.isFinite(Date.parse(n.startedAt))?{duration_ms:Math.max(0,Date.now()-Date.parse(n.startedAt))}:{}}))}},Q=(e=!0)=>{if(!O||!P||F)return Promise.resolve();if(I)return U=!0,W||=e,I;let t=(async()=>{let t=e;do U=!1,W=!1,await de(t),t=W;while(U&&!F)})().finally(()=>{I===t&&(I=void 0)});return I=t,t},fe=e=>{F||(j&&Y(ue(j).recordError(`doom_runner.refresh_failed`,e)),process.emitWarning(`Could not refresh doom-runner: ${String(e)}`))},pe=e=>{Q(e).catch(fe)},me=()=>{R||L||F||(R=setImmediate(()=>{if(R=void 0,F)return;let e=(async()=>{let e=C.sweepHistoryAsync?await C.sweepHistoryAsync(t()):C.sweepHistory(t());for(let t of e.errors)process.emitWarning(t)})().catch(e=>process.emitWarning(`Could not sweep doom-runner history: ${String(e)}`)).finally(()=>{L===e&&(L=void 0)});L=e}),R.unref?.())},$=async(e,t)=>{try{await t()}catch(t){process.emitWarning(`Doom-runner cleanup could not ${e}: ${String(t)}`)}};h=async()=>{if(F)return;E=!1,F=!0,D+=1,P=!1,z&&clearInterval(z),z=void 0,R&&clearImmediate(R),R=void 0;let e=B;B=void 0,e&&await $(`unsubscribe from the runner registry`,e);let t=H;H=void 0,t&&await $(`cancel standalone readiness work`,()=>t.dispose()),await Promise.allSettled(J);let n=I;n&&await $(`settle the runner refresh`,()=>n);let r=L;r&&await $(`settle runner history cleanup`,()=>r),await $(`dispose runner PTYs`,()=>S.disposeAll());let i=[];if(O)try{i=await m.listBySession(O)}catch(e){process.emitWarning(`Could not list runners during doom-runner shutdown: ${String(e)}`)}await Promise.all(i.map(async e=>{try{let t=await o(e,g,b);if(!t&&w.isAlive(e.pid)){process.emitWarning(`Could not stop runner ${e.id} during session shutdown`);return}await m.complete(e.id,{reason:oe,code:null,signal:t?`SIGTERM`:null,stopReason:`session ended`},e.sessionId)}catch(t){process.emitWarning(`Could not clean up runner ${e.id}: ${String(t)}`)}}));let a=j,s=N;N=void 0,j=void 0,O=void 0,k=void 0,A=[],K.clear(),q.clear(),await Promise.all([$(`dispose the runner lifeline`,()=>T.dispose()),...a?.hasUI?[$(`clear the runner status`,()=>a.ui.setStatus(y,void 0))]:[]]),await $(`close the runner registry`,()=>m.close()),s&&(await $(`record the runner session finish`,()=>s.recordEvent(`doom_runner.session_finished`,{outcome:`stopped`})),await $(`stop runner telemetry`,()=>s.shutdown()))},n.inject([ne],e=>{let t=re(e).registerFooter({source:_,id:`runner-count`,order:10});return M=t,()=>{t.dispose(),M===t&&(M=void 0)}}),B=m.subscribe(()=>pe(!1)),z=setInterval(()=>pe(!0),500),z.unref?.(),s(d,{bashRunService:le,getSessionId:async()=>{if(await X(),!O)throw Error(`doom-runner requires an active Pi session`);return O},onRunnerStarted:e=>{!E||!P||(q.add(e),pe(!1))}}),e(d,{getSessionId:async()=>{try{return await X(),O}catch{return}},listBySession:async e=>{try{await X()}catch{return[]}return E?m.listBySession(e):[]}}),d.registerCommand(ae,{description:`Open Runner Space: background processes started by bash`,handler:async(e,t)=>{if(!E)return;let n=D,r=O;if(r){if(!t.hasUI){t.ui.notify(`/runners requires interactive mode`,`error`);return}await X(),await Q(),!(!r||!Z(n,r))&&await u(t,{getRunners:()=>Z(n,r)?A:[],getPtyRun:e=>Z(n,r)?b.get(e)??S.get(e):void 0,readLog:e=>Z(n,r)?x.read(e,{lines:1e3}).text:``,stopRunner:async(e,t)=>{if(!Z(n,r))return;let i=A.find(t=>t.id===e);i&&(i.backend===`rmux`&&i.backendTarget?await b.stop(i.backendTarget,i.pid):await g.stop(i.pid),Z(n,r)&&(await m.complete(i.id,{reason:oe,code:null,signal:null,stopReason:t},i.sessionId),Z(n,r)&&await Q()))}})}}}),n.inject([ne],e=>{let t=re(e).registerLeader({source:_,bindings:[{id:`runners.open`,path:[{key:`r`,label:`runners`,detail:`background processes`,order:67},{key:`l`,label:`list`,detail:`runners in this session`}],command:{name:ae}}]});return()=>t.dispose()}),d.on(`session_start`,(e,t)=>{if(!E)return;let r=t;se(r);let o=r.sessionManager.getSessionId(),s=O,c=j,l=++D;O=o,k=p(o),j=r,P=!1,G=void 0,K.clear(),q.clear();let u=async e=>{let t=()=>!e.aborted&&Z(l,o);if(!t())return[];if(s&&s!==o){await $(`dispose the previous session PTYs`,()=>S.disposeAll()),await $(`dispose the previous session lifeline`,()=>T.dispose()),c?.hasUI&&await $(`clear the previous session status`,()=>c.ui.setStatus(y,void 0));let e=N;if(N=void 0,e&&await $(`stop the previous session telemetry`,()=>e.shutdown()),!t())return[]}let n=ue(r);if(await n.recordEvent(`doom_runner.session_started`,{outcome:`started`}),!t()||(C.setSessionId(o),await T.arm(o),!t()))return[];let u=await m.listAll(o);if(!t())return[];for(let e of u)e.state===v?K.add(e.id):e.promoted&&q.add(e.id);let d=await i({registry:m,launcher:g,rmuxBackend:b,processControl:w,currentHostPid:process.pid,paths:C});if(!t())return[];let f=await a({registry:m,launcher:g,rmuxBackend:b,processControl:w,currentHostPid:process.pid,startup:!0});if(!t()||(P=!0,await Q(!1),!t()))return[];me();let p=[...d.errors,...f.errors],h=d.reclaimed.length+f.reclaimed.length;return h>0&&r.hasUI&&r.ui.notify(`Reclaimed ${h} stale runner record(s)`,`warning`),await n.recordEvent(`doom_runner.reconciled`,{"runner.reclaimed_count":h,"runner.error_count":p.length,outcome:p.length===0?`completed`:`degraded`}),p},d=V.catch(()=>void 0),f=(async()=>{await d,Z(l,o)&&await(te(n)??(H??=ee({notify:e=>{process.emitWarning(`${e.packageId} initialization ${e.state}: ${e.error?.message??e.diagnostics.join(`; `)}`)}}))).start(_,`${o}:${l}`,async e=>({value:void 0,diagnostics:await u(e)})).wait()})();V=f,Y(f).catch(()=>void 0)})}async function x(e){let t=await m(e,_),n=t.root.plugin(S,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function S(e,t){e.inject([h],e=>{let t=g(e).register({source:_,moduleUrl:import.meta.url,skills:[{name:`doompi-use-runner`,description:`Use Doom Pi Runner to supervise shell commands, inspect durable logs, provide interactive input, and stop background runs.`}]});return()=>t.dispose()}),b(e,t.pi)}export{x as default,x as runnerExtension,b as installRunnerRuntime};
|
|
3
3
|
//# sourceMappingURL=extension.mjs.map
|