@agimon-ai/doompi-runner 0.0.1-alpha.31 → 0.0.1-alpha.32
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 +18 -4
- 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/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/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/README.md
CHANGED
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
const e=require("../../types/config.cjs"),t=require("../../services/AnsiScrub/ansiScrub.cjs"),n=require("./responseEnvelope.cjs"),r=require("../../schemas/bashTool.cjs"),i=require("../../tui/bashRender.cjs"),a=1e3,o={requested:`Started in the background`,threshold:`Still running after the background threshold`,interactive:`Started interactively`},s=`Execute shell commands with bounded foreground output and supervised background runners`;function c(t=e.getBackgroundThresholdMs()){return[`A command still running after ${Math.round(t/a)} seconds remains active as a background runner with an id and streaming log path.`,`Pass background: true only for commands you know will remain active, such as dev servers, watchers, and tails.`,`Pass interactive: true only when the command will prompt for input. Use Runner Space for terminal input; avoid interactive mode otherwise because its logs are noisier.`,`On failure, use the returned output first. Inspect the saved log only when the result says output was truncated or no useful output was returned. Never retry an unchanged command merely to recover output.`,`Stop background runners when they are no longer needed. Every runner is stopped automatically when the session ends.`]}function l(e,t){e.registerTool({name:r.BASH_TOOL_NAME,label:r.BASH_TOOL_LABEL,description:`Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path. Do not rerun a command merely to recover output; inspect the saved log only when the result identifies missing context.`,promptSnippet:s,promptGuidelines:c(),parameters:r.BashParamsSchema,renderShell:`self`,async execute(e,r,i,o,s){let{command:c,timeout:l,background:u,interactive:d,name:p}=r,m;o&&o(n.textResult(`Starting ${d===!0?`interactive runner`:u===!0?`background runner`:`command`}...`)),u!==!0&&d!==!0&&o&&(m=e=>o(n.textResult(e)));let h;try{h=await t.bashRunService.run({command:c,timeoutMs:l===void 0?void 0:l*a,background:u,interactive:d,name:p,...m?{onOutput:m}:{},sessionId:await t.getSessionId()})}catch(e){let t=e instanceof Error?e.message:String(e);throw Error([`Could not execute command: ${t}`,`Next: verify the command, runtime, and working directory. Retry only after correcting the cause.`].join(`
|
|
2
2
|
`),{cause:e})}return h.kind===`promoted`&&t.onRunnerStarted(h.id),f(h,n.parseResultPragma(r.command))},renderCall(e,t,n){return i.renderBashCall(e,t)},renderResult(e,t,n,r){return i.renderBashResult(e,{...t,isError:r.isError},n)}})}function u(e){return e.timedOut===!0||e.signal!==null||e.exitCode!==null&&e.exitCode!==0}function d(e){if(e.timedOut===!0)return`Timed out: exceeded the requested timeout.`;if(e.signal!==null)return`Signal: ${e.signal}`;if(e.exitCode===null)return`Exit status unavailable.`;if(e.exitCode!==0)return`Exit: ${e.exitCode}`}function f(r,i={}){if(r.kind===`failed`)throw Error([`Could not start runner "${r.name}": ${r.error}`,`Next: correct the reported launch or supervision problem. Retry only after changing the command or environment.`].join(`
|
|
3
3
|
`));if(r.kind===`promoted`){let e=[`${o[r.reason]}: runner "${r.name}" (${r.id}).`,`Streaming log: ${r.logPath}`,`Inspect: doom-runner logs ${r.id}`].join(`
|
|
4
|
-
`);return n.textResult(e,{id:r.id,runner:r.name,pid:r.pid,logPath:r.logPath,promoted:!0,reason:r.reason})}let a=!u(r),s=i.maxLines??e.getResultMaxLines(),c=i.maxBytes??(a?e.getSuccessResultMaxBytes():e.getResultMaxBytes()),l=n.summarizeLog(r.logPath,s,c),
|
|
5
|
-
`),c),
|
|
4
|
+
`);return n.textResult(e,{id:r.id,runner:r.name,pid:r.pid,logPath:r.logPath,promoted:!0,reason:r.reason})}let a=!u(r),s=i.maxLines??e.getResultMaxLines(),c=i.maxBytes??(a?e.getSuccessResultMaxBytes():e.getResultMaxBytes()),l=i.maxTokens??(a?e.getSuccessResultMaxTokens():e.getResultMaxTokens()),f=n.summarizeLog(r.logPath,s,c,l),p=!r.rtkOutput&&f.tail.length===0&&r.output.length>0,m,h,g,_,v;if(r.rtkOutput){let e=Buffer.byteLength(r.rtkOutput.output,`utf8`)<r.rtkOutput.bytes?n.composeExcerpt(r.rtkOutput.head,r.rtkOutput.output,r.rtkOutput.lines,s,c,[],l):n.boundExcerpt(r.rtkOutput.output,s,c,l);m=e.text,h=e.lines,g=r.rtkOutput.lines,_=r.rtkOutput.bytes,v=g>h||_>Buffer.byteLength(m,`utf8`)}else m=p?r.output:f.tail,h=p?n.countLines(m):f.tailLines,g=Math.max(f.lines,h),_=p?Buffer.byteLength(m,`utf8`):f.bytes,v=!p&&(g>h||_>Buffer.byteLength(m,`utf8`));let y=t.stripAnsi(m).replace(/\r?\n$/,``),b=u(r),x=d(r),S=[];if(y.length===0)S.push(x===void 0?`Completed with no output.`:`No output.`);else if(v){let e=r.rtkOutput?`RTK ${r.rtkOutput.filter} excerpt`:`Log excerpt`;S.push(`${e} (${h.toLocaleString(`en-US`)} of ${g.toLocaleString(`en-US`)} lines):\n${y}`)}else S.push(y);if(x!==void 0&&S.push(x),r.rtkWarning&&S.push(r.rtkWarning),v){let e=r.rtkOutput?`Complete raw log`:`Full log`;S.push(`${e}: ${r.logPath} (${n.formatSize(f.bytes)}, ${f.lines.toLocaleString(`en-US`)} lines); inspect with doom-runner logs ${r.id}`)}else b&&y.length===0&&S.push(`Log: ${r.logPath}`,`Next: run one read-only diagnostic; retry only after correcting the cause.`);let C=n.boundResultText(S.join(`
|
|
5
|
+
`),c),w={id:r.id,runner:r.name,exitCode:r.exitCode,logPath:r.logPath,backend:r.backend,fileSize:f.bytes,lines:p?h:f.lines,tail:m,tailLines:h,...r.rtkOutput?{rtkFilter:r.rtkOutput.filter,rtkOutputBytes:r.rtkOutput.bytes,rtkOutputLines:r.rtkOutput.lines}:{},...r.rtkWarning?{rtkWarning:r.rtkWarning}:{},...r.timedOut?{timedOut:!0}:{}};if(b)throw Error(C);return n.textResult(C,w)}exports.BASH_PROMPT_SNIPPET=s,exports.bashPromptGuidelines=c,exports.formatRunResult=f,exports.registerBashTool=l;
|
|
6
6
|
//# sourceMappingURL=bashTool.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashTool.cjs","names":["getBackgroundThresholdMs","BASH_TOOL_NAME","BASH_TOOL_LABEL","BashParamsSchema","textResult","parseResultPragma","renderBashCall","renderBashResult","getResultMaxLines","getSuccessResultMaxBytes","getResultMaxBytes","summarizeLog","composeExcerpt","boundExcerpt","countLines","stripAnsi","formatSize","boundResultText"],"sources":["../../../../src/commands/bash/bashTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME, type BashParams, BashParamsSchema } from '../../schemas/bashTool.ts';\nimport { stripAnsi } from '../../services/AnsiScrub/ansiScrub';\nimport type { BashRunResult, CompletedRun, IBashRunService } from '../../types/bashRunService';\nimport { renderBashCall, renderBashResult } from '../../tui/bashRender.ts';\nimport {\n getBackgroundThresholdMs,\n getResultMaxBytes,\n getResultMaxLines,\n getSuccessResultMaxBytes,\n} from '../../types/config.ts';\nimport {\n boundExcerpt,\n boundResultText,\n composeExcerpt,\n parseResultPragma,\n type ResultBudget,\n countLines,\n formatSize,\n summarizeLog,\n type ToolResult,\n textResult,\n} from './responseEnvelope.ts';\n\nconst MS_PER_SECOND = 1000;\n\nconst PROMOTION_REASONS: Record<'requested' | 'threshold' | 'interactive', string> = {\n requested: 'Started in the background',\n threshold: 'Still running after the background threshold',\n interactive: 'Started interactively',\n};\n\nexport const BASH_PROMPT_SNIPPET =\n 'Execute shell commands with bounded foreground output and supervised background runners';\n\n/** Written at registration time so the stated threshold matches the configured one. */\nexport function bashPromptGuidelines(thresholdMs = getBackgroundThresholdMs()): string[] {\n return [\n `A command still running after ${Math.round(thresholdMs / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true only for commands you know will remain active, such as dev servers, watchers, and tails.',\n 'Pass interactive: true only when the command will prompt for input. Use Runner Space for terminal input; avoid interactive mode otherwise because its logs are noisier.',\n 'On failure, use the returned output first. Inspect the saved log only when the result says output was truncated or no useful output was returned. Never retry an unchanged command merely to recover output.',\n 'Stop background runners when they are no longer needed. Every runner is stopped automatically when the session ends.',\n ];\n}\n\nexport interface BashToolDependencies {\n bashRunService: IBashRunService;\n getSessionId(): string | Promise<string>;\n /** Called after a runner is promoted, so UI state can refresh. */\n onRunnerStarted(id: string): void;\n}\n\n/**\n * Registers a tool named `bash`, replacing pi's built-in.\n *\n * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on\n * `bash`, and they keep working only while the replacement keeps the name.\n */\nexport function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void {\n pi.registerTool({\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path. Do not rerun a command merely to recover output; inspect the saved log only when the result identifies missing context.',\n promptSnippet: BASH_PROMPT_SNIPPET,\n promptGuidelines: bashPromptGuidelines(),\n parameters: BashParamsSchema,\n // Bash output already carries its own status glyphs and ANSI colours. Owning\n // the shell keeps Pi from filling every successful command with the global\n // toolSuccessBg, which overwhelms long logs and diffs.\n renderShell: 'self',\n\n async execute(_toolCallId, params, _signal, onUpdate, _ctx): Promise<ToolResult> {\n const { command, timeout, background, interactive, name } = params as BashParams;\n let onOutput: ((output: string) => void) | undefined;\n if (onUpdate) {\n const mode =\n interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command';\n onUpdate(textResult(`Starting ${mode}...`));\n }\n if (background !== true && interactive !== true && onUpdate) {\n onOutput = (output) => onUpdate(textResult(output));\n }\n let result: BashRunResult;\n try {\n result = await dependencies.bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n sessionId: await dependencies.getSessionId(),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `Could not execute command: ${message}`,\n 'Next: verify the command, runtime, and working directory. Retry only after correcting the cause.',\n ].join('\\n'),\n { cause: error },\n );\n }\n\n if (result.kind === 'promoted') dependencies.onRunnerStarted(result.id);\n return formatRunResult(result, parseResultPragma(params.command));\n },\n\n // Without these, pi falls back to echoing the raw command and the tail end of\n // the result text, which is the metadata footer rather than the log output.\n renderCall(args, theme, _context) {\n return renderBashCall(args as BashParams, theme);\n },\n\n renderResult(result, options, theme, context) {\n return renderBashResult(result, { ...options, isError: context.isError }, theme);\n },\n });\n}\n\nfunction completionFailed(result: CompletedRun): boolean {\n return result.timedOut === true || result.signal !== null || (result.exitCode !== null && result.exitCode !== 0);\n}\n\nfunction completionStatus(result: CompletedRun): string | undefined {\n if (result.timedOut === true) return 'Timed out: exceeded the requested timeout.';\n if (result.signal !== null) return `Signal: ${result.signal}`;\n if (result.exitCode === null) return 'Exit status unavailable.';\n if (result.exitCode !== 0) return `Exit: ${result.exitCode}`;\n return undefined;\n}\n\nexport function formatRunResult(result: BashRunResult, budget: ResultBudget = {}): ToolResult {\n if (result.kind === 'failed') {\n throw new Error(\n [\n `Could not start runner \"${result.name}\": ${result.error}`,\n 'Next: correct the reported launch or supervision problem. Retry only after changing the command or environment.',\n ].join('\\n'),\n );\n }\n\n if (result.kind === 'promoted') {\n const reason = PROMOTION_REASONS[result.reason];\n const body = [\n `${reason}: runner \"${result.name}\" (${result.id}).`,\n `Streaming log: ${result.logPath}`,\n `Inspect: doom-runner logs ${result.id}`,\n ].join('\\n');\n\n return textResult(body, {\n id: result.id,\n runner: result.name,\n pid: result.pid,\n logPath: result.logPath,\n promoted: true,\n reason: result.reason,\n });\n }\n\n // Same shape either way; a success just buys less of it. Exiting 0 has already\n // reported the outcome, so its output is worth a fraction of a failure's.\n const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\n // An explicit pragma still wins: asking for a wider result is the point of it.\n const maxBytes = budget.maxBytes ?? (succeeded ? getSuccessResultMaxBytes() : getResultMaxBytes());\n const log = summarizeLog(result.logPath, maxLines, maxBytes);\n const useCapturedOutput = !result.rtkOutput && log.tail.length === 0 && result.output.length > 0;\n let tail: string;\n let tailLines: number;\n let outputLines: number;\n let outputBytes: number;\n let truncated: boolean;\n if (result.rtkOutput) {\n const clipped = Buffer.byteLength(result.rtkOutput.output, 'utf8') < result.rtkOutput.bytes;\n const bounded = clipped\n ? composeExcerpt(result.rtkOutput.head, result.rtkOutput.output, result.rtkOutput.lines, maxLines, maxBytes)\n : boundExcerpt(result.rtkOutput.output, maxLines, maxBytes);\n tail = bounded.text;\n tailLines = bounded.lines;\n outputLines = result.rtkOutput.lines;\n outputBytes = result.rtkOutput.bytes;\n truncated = outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8');\n } else {\n tail = useCapturedOutput ? result.output : log.tail;\n tailLines = useCapturedOutput ? countLines(tail) : log.tailLines;\n outputLines = Math.max(log.lines, tailLines);\n outputBytes = useCapturedOutput ? Buffer.byteLength(tail, 'utf8') : log.bytes;\n truncated = !useCapturedOutput && (outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8'));\n }\n const plainTail = stripAnsi(tail).replace(/\\r?\\n$/, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\n\n if (plainTail.length === 0) {\n textLines.push(status === undefined ? 'Completed with no output.' : 'No output.');\n } else if (truncated) {\n const label = result.rtkOutput ? `RTK ${result.rtkOutput.filter} excerpt` : 'Log excerpt';\n textLines.push(\n `${label} (${tailLines.toLocaleString('en-US')} of ${outputLines.toLocaleString('en-US')} lines):\\n${plainTail}`,\n );\n } else {\n textLines.push(plainTail);\n }\n if (status !== undefined) textLines.push(status);\n if (result.rtkWarning) textLines.push(result.rtkWarning);\n\n if (truncated) {\n const label = result.rtkOutput ? 'Complete raw log' : 'Full log';\n textLines.push(\n `${label}: ${result.logPath} (${formatSize(log.bytes)}, ${log.lines.toLocaleString('en-US')} lines); inspect with doom-runner logs ${result.id}`,\n );\n } else if (failed && plainTail.length === 0) {\n textLines.push(\n `Log: ${result.logPath}`,\n 'Next: run one read-only diagnostic; retry only after correcting the cause.',\n );\n }\n\n const text = boundResultText(textLines.join('\\n'), maxBytes);\n const details = {\n id: result.id,\n runner: result.name,\n exitCode: result.exitCode,\n logPath: result.logPath,\n backend: result.backend,\n fileSize: log.bytes,\n lines: useCapturedOutput ? tailLines : log.lines,\n tail,\n tailLines,\n ...(result.rtkOutput\n ? {\n rtkFilter: result.rtkOutput.filter,\n rtkOutputBytes: result.rtkOutput.bytes,\n rtkOutputLines: result.rtkOutput.lines,\n }\n : {}),\n ...(result.rtkWarning ? { rtkWarning: result.rtkWarning } : {}),\n ...(result.timedOut ? { timedOut: true } : {}),\n };\n\n if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bashTool.cjs","names":["getBackgroundThresholdMs","BASH_TOOL_NAME","BASH_TOOL_LABEL","BashParamsSchema","textResult","parseResultPragma","renderBashCall","renderBashResult","getResultMaxLines","getSuccessResultMaxBytes","getResultMaxBytes","getSuccessResultMaxTokens","getResultMaxTokens","summarizeLog","composeExcerpt","boundExcerpt","countLines","stripAnsi","formatSize","boundResultText"],"sources":["../../../../src/commands/bash/bashTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME, type BashParams, BashParamsSchema } from '../../schemas/bashTool.ts';\nimport { stripAnsi } from '../../services/AnsiScrub/ansiScrub';\nimport type { BashRunResult, CompletedRun, IBashRunService } from '../../types/bashRunService';\nimport { renderBashCall, renderBashResult } from '../../tui/bashRender.ts';\nimport {\n getBackgroundThresholdMs,\n getResultMaxBytes,\n getResultMaxLines,\n getResultMaxTokens,\n getSuccessResultMaxBytes,\n getSuccessResultMaxTokens,\n} from '../../types/config.ts';\nimport {\n boundExcerpt,\n boundResultText,\n composeExcerpt,\n parseResultPragma,\n type ResultBudget,\n countLines,\n formatSize,\n summarizeLog,\n type ToolResult,\n textResult,\n} from './responseEnvelope.ts';\n\nconst MS_PER_SECOND = 1000;\n\nconst PROMOTION_REASONS: Record<'requested' | 'threshold' | 'interactive', string> = {\n requested: 'Started in the background',\n threshold: 'Still running after the background threshold',\n interactive: 'Started interactively',\n};\n\nexport const BASH_PROMPT_SNIPPET =\n 'Execute shell commands with bounded foreground output and supervised background runners';\n\n/** Written at registration time so the stated threshold matches the configured one. */\nexport function bashPromptGuidelines(thresholdMs = getBackgroundThresholdMs()): string[] {\n return [\n `A command still running after ${Math.round(thresholdMs / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true only for commands you know will remain active, such as dev servers, watchers, and tails.',\n 'Pass interactive: true only when the command will prompt for input. Use Runner Space for terminal input; avoid interactive mode otherwise because its logs are noisier.',\n 'On failure, use the returned output first. Inspect the saved log only when the result says output was truncated or no useful output was returned. Never retry an unchanged command merely to recover output.',\n 'Stop background runners when they are no longer needed. Every runner is stopped automatically when the session ends.',\n ];\n}\n\nexport interface BashToolDependencies {\n bashRunService: IBashRunService;\n getSessionId(): string | Promise<string>;\n /** Called after a runner is promoted, so UI state can refresh. */\n onRunnerStarted(id: string): void;\n}\n\n/**\n * Registers a tool named `bash`, replacing pi's built-in.\n *\n * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on\n * `bash`, and they keep working only while the replacement keeps the name.\n */\nexport function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void {\n pi.registerTool({\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path. Do not rerun a command merely to recover output; inspect the saved log only when the result identifies missing context.',\n promptSnippet: BASH_PROMPT_SNIPPET,\n promptGuidelines: bashPromptGuidelines(),\n parameters: BashParamsSchema,\n // Bash output already carries its own status glyphs and ANSI colours. Owning\n // the shell keeps Pi from filling every successful command with the global\n // toolSuccessBg, which overwhelms long logs and diffs.\n renderShell: 'self',\n\n async execute(_toolCallId, params, _signal, onUpdate, _ctx): Promise<ToolResult> {\n const { command, timeout, background, interactive, name } = params as BashParams;\n let onOutput: ((output: string) => void) | undefined;\n if (onUpdate) {\n const mode =\n interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command';\n onUpdate(textResult(`Starting ${mode}...`));\n }\n if (background !== true && interactive !== true && onUpdate) {\n onOutput = (output) => onUpdate(textResult(output));\n }\n let result: BashRunResult;\n try {\n result = await dependencies.bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n sessionId: await dependencies.getSessionId(),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `Could not execute command: ${message}`,\n 'Next: verify the command, runtime, and working directory. Retry only after correcting the cause.',\n ].join('\\n'),\n { cause: error },\n );\n }\n\n if (result.kind === 'promoted') dependencies.onRunnerStarted(result.id);\n return formatRunResult(result, parseResultPragma(params.command));\n },\n\n // Without these, pi falls back to echoing the raw command and the tail end of\n // the result text, which is the metadata footer rather than the log output.\n renderCall(args, theme, _context) {\n return renderBashCall(args as BashParams, theme);\n },\n\n renderResult(result, options, theme, context) {\n return renderBashResult(result, { ...options, isError: context.isError }, theme);\n },\n });\n}\n\nfunction completionFailed(result: CompletedRun): boolean {\n return result.timedOut === true || result.signal !== null || (result.exitCode !== null && result.exitCode !== 0);\n}\n\nfunction completionStatus(result: CompletedRun): string | undefined {\n if (result.timedOut === true) return 'Timed out: exceeded the requested timeout.';\n if (result.signal !== null) return `Signal: ${result.signal}`;\n if (result.exitCode === null) return 'Exit status unavailable.';\n if (result.exitCode !== 0) return `Exit: ${result.exitCode}`;\n return undefined;\n}\n\nexport function formatRunResult(result: BashRunResult, budget: ResultBudget = {}): ToolResult {\n if (result.kind === 'failed') {\n throw new Error(\n [\n `Could not start runner \"${result.name}\": ${result.error}`,\n 'Next: correct the reported launch or supervision problem. Retry only after changing the command or environment.',\n ].join('\\n'),\n );\n }\n\n if (result.kind === 'promoted') {\n const reason = PROMOTION_REASONS[result.reason];\n const body = [\n `${reason}: runner \"${result.name}\" (${result.id}).`,\n `Streaming log: ${result.logPath}`,\n `Inspect: doom-runner logs ${result.id}`,\n ].join('\\n');\n\n return textResult(body, {\n id: result.id,\n runner: result.name,\n pid: result.pid,\n logPath: result.logPath,\n promoted: true,\n reason: result.reason,\n });\n }\n\n // Same shape either way; a success just buys less of it. Exiting 0 has already\n // reported the outcome, so its output is worth a fraction of a failure's.\n const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\n // An explicit pragma still wins: asking for a wider result is the point of it.\n const maxBytes = budget.maxBytes ?? (succeeded ? getSuccessResultMaxBytes() : getResultMaxBytes());\n const maxTokens = budget.maxTokens ?? (succeeded ? getSuccessResultMaxTokens() : getResultMaxTokens());\n const log = summarizeLog(result.logPath, maxLines, maxBytes, maxTokens);\n const useCapturedOutput = !result.rtkOutput && log.tail.length === 0 && result.output.length > 0;\n let tail: string;\n let tailLines: number;\n let outputLines: number;\n let outputBytes: number;\n let truncated: boolean;\n if (result.rtkOutput) {\n const clipped = Buffer.byteLength(result.rtkOutput.output, 'utf8') < result.rtkOutput.bytes;\n const bounded = clipped\n ? composeExcerpt(\n result.rtkOutput.head,\n result.rtkOutput.output,\n result.rtkOutput.lines,\n maxLines,\n maxBytes,\n [],\n maxTokens,\n )\n : boundExcerpt(result.rtkOutput.output, maxLines, maxBytes, maxTokens);\n tail = bounded.text;\n tailLines = bounded.lines;\n outputLines = result.rtkOutput.lines;\n outputBytes = result.rtkOutput.bytes;\n truncated = outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8');\n } else {\n tail = useCapturedOutput ? result.output : log.tail;\n tailLines = useCapturedOutput ? countLines(tail) : log.tailLines;\n outputLines = Math.max(log.lines, tailLines);\n outputBytes = useCapturedOutput ? Buffer.byteLength(tail, 'utf8') : log.bytes;\n truncated = !useCapturedOutput && (outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8'));\n }\n const plainTail = stripAnsi(tail).replace(/\\r?\\n$/, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\n\n if (plainTail.length === 0) {\n textLines.push(status === undefined ? 'Completed with no output.' : 'No output.');\n } else if (truncated) {\n const label = result.rtkOutput ? `RTK ${result.rtkOutput.filter} excerpt` : 'Log excerpt';\n textLines.push(\n `${label} (${tailLines.toLocaleString('en-US')} of ${outputLines.toLocaleString('en-US')} lines):\\n${plainTail}`,\n );\n } else {\n textLines.push(plainTail);\n }\n if (status !== undefined) textLines.push(status);\n if (result.rtkWarning) textLines.push(result.rtkWarning);\n\n if (truncated) {\n const label = result.rtkOutput ? 'Complete raw log' : 'Full log';\n textLines.push(\n `${label}: ${result.logPath} (${formatSize(log.bytes)}, ${log.lines.toLocaleString('en-US')} lines); inspect with doom-runner logs ${result.id}`,\n );\n } else if (failed && plainTail.length === 0) {\n textLines.push(\n `Log: ${result.logPath}`,\n 'Next: run one read-only diagnostic; retry only after correcting the cause.',\n );\n }\n\n const text = boundResultText(textLines.join('\\n'), maxBytes);\n const details = {\n id: result.id,\n runner: result.name,\n exitCode: result.exitCode,\n logPath: result.logPath,\n backend: result.backend,\n fileSize: log.bytes,\n lines: useCapturedOutput ? tailLines : log.lines,\n tail,\n tailLines,\n ...(result.rtkOutput\n ? {\n rtkFilter: result.rtkOutput.filter,\n rtkOutputBytes: result.rtkOutput.bytes,\n rtkOutputLines: result.rtkOutput.lines,\n }\n : {}),\n ...(result.rtkWarning ? { rtkWarning: result.rtkWarning } : {}),\n ...(result.timedOut ? { timedOut: true } : {}),\n };\n\n if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashTool.d.cts","names":[],"sources":["../../../../src/commands/bash/bashTool.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"bashTool.d.cts","names":[],"sources":["../../../../src/commands/bash/bashTool.ts"],"mappings":";;;;cAkCa;;iBAIG,qBAAqB;UAUpB;EACf,gBAAgB;EAChB,yBAAyB;;EAEzB,gBAAgB;;;;;;;;iBASF,iBAAiB,IAAI,cAAc,cAAc;iBA2EjD,gBAAgB,QAAQ,eAAe,SAAQ,eAAoB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashTool.d.mts","names":[],"sources":["../../../../src/commands/bash/bashTool.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"bashTool.d.mts","names":[],"sources":["../../../../src/commands/bash/bashTool.ts"],"mappings":";;;;cAkCa;;iBAIG,qBAAqB;UAUpB;EACf,gBAAgB;EAChB,yBAAyB;;EAEzB,gBAAgB;;;;;;;;iBASF,iBAAiB,IAAI,cAAc,cAAc;iBA2EjD,gBAAgB,QAAQ,eAAe,SAAQ,eAAoB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{getBackgroundThresholdMs as e,getResultMaxBytes as t,getResultMaxLines as n,getSuccessResultMaxBytes as
|
|
2
|
-
`),{cause:e})}return
|
|
3
|
-
`));if(e.kind===`promoted`){let t=[`${
|
|
4
|
-
`);return
|
|
5
|
-
`),
|
|
1
|
+
import{getBackgroundThresholdMs as e,getResultMaxBytes as t,getResultMaxLines as n,getResultMaxTokens as r,getSuccessResultMaxBytes as i,getSuccessResultMaxTokens as a}from"../../types/config.mjs";import{stripAnsi as o}from"../../services/AnsiScrub/ansiScrub.mjs";import{boundExcerpt as s,boundResultText as c,composeExcerpt as l,countLines as u,formatSize as d,parseResultPragma as f,summarizeLog as p,textResult as m}from"./responseEnvelope.mjs";import{BASH_TOOL_LABEL as h,BASH_TOOL_NAME as g,BashParamsSchema as _}from"../../schemas/bashTool.mjs";import{renderBashCall as v,renderBashResult as y}from"../../tui/bashRender.mjs";const b=1e3,x={requested:`Started in the background`,threshold:`Still running after the background threshold`,interactive:`Started interactively`},S=`Execute shell commands with bounded foreground output and supervised background runners`;function C(t=e()){return[`A command still running after ${Math.round(t/b)} seconds remains active as a background runner with an id and streaming log path.`,`Pass background: true only for commands you know will remain active, such as dev servers, watchers, and tails.`,`Pass interactive: true only when the command will prompt for input. Use Runner Space for terminal input; avoid interactive mode otherwise because its logs are noisier.`,`On failure, use the returned output first. Inspect the saved log only when the result says output was truncated or no useful output was returned. Never retry an unchanged command merely to recover output.`,`Stop background runners when they are no longer needed. Every runner is stopped automatically when the session ends.`]}function w(e,t){e.registerTool({name:g,label:h,description:`Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path. Do not rerun a command merely to recover output; inspect the saved log only when the result identifies missing context.`,promptSnippet:S,promptGuidelines:C(),parameters:_,renderShell:`self`,async execute(e,n,r,i,a){let{command:o,timeout:s,background:c,interactive:l,name:u}=n,d;i&&i(m(`Starting ${l===!0?`interactive runner`:c===!0?`background runner`:`command`}...`)),c!==!0&&l!==!0&&i&&(d=e=>i(m(e)));let p;try{p=await t.bashRunService.run({command:o,timeoutMs:s===void 0?void 0:s*b,background:c,interactive:l,name:u,...d?{onOutput:d}:{},sessionId:await t.getSessionId()})}catch(e){let t=e instanceof Error?e.message:String(e);throw Error([`Could not execute command: ${t}`,`Next: verify the command, runtime, and working directory. Retry only after correcting the cause.`].join(`
|
|
2
|
+
`),{cause:e})}return p.kind===`promoted`&&t.onRunnerStarted(p.id),D(p,f(n.command))},renderCall(e,t,n){return v(e,t)},renderResult(e,t,n,r){return y(e,{...t,isError:r.isError},n)}})}function T(e){return e.timedOut===!0||e.signal!==null||e.exitCode!==null&&e.exitCode!==0}function E(e){if(e.timedOut===!0)return`Timed out: exceeded the requested timeout.`;if(e.signal!==null)return`Signal: ${e.signal}`;if(e.exitCode===null)return`Exit status unavailable.`;if(e.exitCode!==0)return`Exit: ${e.exitCode}`}function D(e,f={}){if(e.kind===`failed`)throw Error([`Could not start runner "${e.name}": ${e.error}`,`Next: correct the reported launch or supervision problem. Retry only after changing the command or environment.`].join(`
|
|
3
|
+
`));if(e.kind===`promoted`){let t=[`${x[e.reason]}: runner "${e.name}" (${e.id}).`,`Streaming log: ${e.logPath}`,`Inspect: doom-runner logs ${e.id}`].join(`
|
|
4
|
+
`);return m(t,{id:e.id,runner:e.name,pid:e.pid,logPath:e.logPath,promoted:!0,reason:e.reason})}let h=!T(e),g=f.maxLines??n(),_=f.maxBytes??(h?i():t()),v=f.maxTokens??(h?a():r()),y=p(e.logPath,g,_,v),b=!e.rtkOutput&&y.tail.length===0&&e.output.length>0,S,C,w,D,O;if(e.rtkOutput){let t=Buffer.byteLength(e.rtkOutput.output,`utf8`)<e.rtkOutput.bytes?l(e.rtkOutput.head,e.rtkOutput.output,e.rtkOutput.lines,g,_,[],v):s(e.rtkOutput.output,g,_,v);S=t.text,C=t.lines,w=e.rtkOutput.lines,D=e.rtkOutput.bytes,O=w>C||D>Buffer.byteLength(S,`utf8`)}else S=b?e.output:y.tail,C=b?u(S):y.tailLines,w=Math.max(y.lines,C),D=b?Buffer.byteLength(S,`utf8`):y.bytes,O=!b&&(w>C||D>Buffer.byteLength(S,`utf8`));let k=o(S).replace(/\r?\n$/,``),A=T(e),j=E(e),M=[];if(k.length===0)M.push(j===void 0?`Completed with no output.`:`No output.`);else if(O){let t=e.rtkOutput?`RTK ${e.rtkOutput.filter} excerpt`:`Log excerpt`;M.push(`${t} (${C.toLocaleString(`en-US`)} of ${w.toLocaleString(`en-US`)} lines):\n${k}`)}else M.push(k);if(j!==void 0&&M.push(j),e.rtkWarning&&M.push(e.rtkWarning),O){let t=e.rtkOutput?`Complete raw log`:`Full log`;M.push(`${t}: ${e.logPath} (${d(y.bytes)}, ${y.lines.toLocaleString(`en-US`)} lines); inspect with doom-runner logs ${e.id}`)}else A&&k.length===0&&M.push(`Log: ${e.logPath}`,`Next: run one read-only diagnostic; retry only after correcting the cause.`);let N=c(M.join(`
|
|
5
|
+
`),_),P={id:e.id,runner:e.name,exitCode:e.exitCode,logPath:e.logPath,backend:e.backend,fileSize:y.bytes,lines:b?C:y.lines,tail:S,tailLines:C,...e.rtkOutput?{rtkFilter:e.rtkOutput.filter,rtkOutputBytes:e.rtkOutput.bytes,rtkOutputLines:e.rtkOutput.lines}:{},...e.rtkWarning?{rtkWarning:e.rtkWarning}:{},...e.timedOut?{timedOut:!0}:{}};if(A)throw Error(N);return m(N,P)}export{S as BASH_PROMPT_SNIPPET,C as bashPromptGuidelines,D as formatRunResult,w as registerBashTool};
|
|
6
6
|
//# sourceMappingURL=bashTool.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashTool.mjs","names":[],"sources":["../../../../src/commands/bash/bashTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME, type BashParams, BashParamsSchema } from '../../schemas/bashTool.ts';\nimport { stripAnsi } from '../../services/AnsiScrub/ansiScrub';\nimport type { BashRunResult, CompletedRun, IBashRunService } from '../../types/bashRunService';\nimport { renderBashCall, renderBashResult } from '../../tui/bashRender.ts';\nimport {\n getBackgroundThresholdMs,\n getResultMaxBytes,\n getResultMaxLines,\n getSuccessResultMaxBytes,\n} from '../../types/config.ts';\nimport {\n boundExcerpt,\n boundResultText,\n composeExcerpt,\n parseResultPragma,\n type ResultBudget,\n countLines,\n formatSize,\n summarizeLog,\n type ToolResult,\n textResult,\n} from './responseEnvelope.ts';\n\nconst MS_PER_SECOND = 1000;\n\nconst PROMOTION_REASONS: Record<'requested' | 'threshold' | 'interactive', string> = {\n requested: 'Started in the background',\n threshold: 'Still running after the background threshold',\n interactive: 'Started interactively',\n};\n\nexport const BASH_PROMPT_SNIPPET =\n 'Execute shell commands with bounded foreground output and supervised background runners';\n\n/** Written at registration time so the stated threshold matches the configured one. */\nexport function bashPromptGuidelines(thresholdMs = getBackgroundThresholdMs()): string[] {\n return [\n `A command still running after ${Math.round(thresholdMs / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true only for commands you know will remain active, such as dev servers, watchers, and tails.',\n 'Pass interactive: true only when the command will prompt for input. Use Runner Space for terminal input; avoid interactive mode otherwise because its logs are noisier.',\n 'On failure, use the returned output first. Inspect the saved log only when the result says output was truncated or no useful output was returned. Never retry an unchanged command merely to recover output.',\n 'Stop background runners when they are no longer needed. Every runner is stopped automatically when the session ends.',\n ];\n}\n\nexport interface BashToolDependencies {\n bashRunService: IBashRunService;\n getSessionId(): string | Promise<string>;\n /** Called after a runner is promoted, so UI state can refresh. */\n onRunnerStarted(id: string): void;\n}\n\n/**\n * Registers a tool named `bash`, replacing pi's built-in.\n *\n * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on\n * `bash`, and they keep working only while the replacement keeps the name.\n */\nexport function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void {\n pi.registerTool({\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path. Do not rerun a command merely to recover output; inspect the saved log only when the result identifies missing context.',\n promptSnippet: BASH_PROMPT_SNIPPET,\n promptGuidelines: bashPromptGuidelines(),\n parameters: BashParamsSchema,\n // Bash output already carries its own status glyphs and ANSI colours. Owning\n // the shell keeps Pi from filling every successful command with the global\n // toolSuccessBg, which overwhelms long logs and diffs.\n renderShell: 'self',\n\n async execute(_toolCallId, params, _signal, onUpdate, _ctx): Promise<ToolResult> {\n const { command, timeout, background, interactive, name } = params as BashParams;\n let onOutput: ((output: string) => void) | undefined;\n if (onUpdate) {\n const mode =\n interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command';\n onUpdate(textResult(`Starting ${mode}...`));\n }\n if (background !== true && interactive !== true && onUpdate) {\n onOutput = (output) => onUpdate(textResult(output));\n }\n let result: BashRunResult;\n try {\n result = await dependencies.bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n sessionId: await dependencies.getSessionId(),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `Could not execute command: ${message}`,\n 'Next: verify the command, runtime, and working directory. Retry only after correcting the cause.',\n ].join('\\n'),\n { cause: error },\n );\n }\n\n if (result.kind === 'promoted') dependencies.onRunnerStarted(result.id);\n return formatRunResult(result, parseResultPragma(params.command));\n },\n\n // Without these, pi falls back to echoing the raw command and the tail end of\n // the result text, which is the metadata footer rather than the log output.\n renderCall(args, theme, _context) {\n return renderBashCall(args as BashParams, theme);\n },\n\n renderResult(result, options, theme, context) {\n return renderBashResult(result, { ...options, isError: context.isError }, theme);\n },\n });\n}\n\nfunction completionFailed(result: CompletedRun): boolean {\n return result.timedOut === true || result.signal !== null || (result.exitCode !== null && result.exitCode !== 0);\n}\n\nfunction completionStatus(result: CompletedRun): string | undefined {\n if (result.timedOut === true) return 'Timed out: exceeded the requested timeout.';\n if (result.signal !== null) return `Signal: ${result.signal}`;\n if (result.exitCode === null) return 'Exit status unavailable.';\n if (result.exitCode !== 0) return `Exit: ${result.exitCode}`;\n return undefined;\n}\n\nexport function formatRunResult(result: BashRunResult, budget: ResultBudget = {}): ToolResult {\n if (result.kind === 'failed') {\n throw new Error(\n [\n `Could not start runner \"${result.name}\": ${result.error}`,\n 'Next: correct the reported launch or supervision problem. Retry only after changing the command or environment.',\n ].join('\\n'),\n );\n }\n\n if (result.kind === 'promoted') {\n const reason = PROMOTION_REASONS[result.reason];\n const body = [\n `${reason}: runner \"${result.name}\" (${result.id}).`,\n `Streaming log: ${result.logPath}`,\n `Inspect: doom-runner logs ${result.id}`,\n ].join('\\n');\n\n return textResult(body, {\n id: result.id,\n runner: result.name,\n pid: result.pid,\n logPath: result.logPath,\n promoted: true,\n reason: result.reason,\n });\n }\n\n // Same shape either way; a success just buys less of it. Exiting 0 has already\n // reported the outcome, so its output is worth a fraction of a failure's.\n const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\n // An explicit pragma still wins: asking for a wider result is the point of it.\n const maxBytes = budget.maxBytes ?? (succeeded ? getSuccessResultMaxBytes() : getResultMaxBytes());\n const log = summarizeLog(result.logPath, maxLines, maxBytes);\n const useCapturedOutput = !result.rtkOutput && log.tail.length === 0 && result.output.length > 0;\n let tail: string;\n let tailLines: number;\n let outputLines: number;\n let outputBytes: number;\n let truncated: boolean;\n if (result.rtkOutput) {\n const clipped = Buffer.byteLength(result.rtkOutput.output, 'utf8') < result.rtkOutput.bytes;\n const bounded = clipped\n ? composeExcerpt(result.rtkOutput.head, result.rtkOutput.output, result.rtkOutput.lines, maxLines, maxBytes)\n : boundExcerpt(result.rtkOutput.output, maxLines, maxBytes);\n tail = bounded.text;\n tailLines = bounded.lines;\n outputLines = result.rtkOutput.lines;\n outputBytes = result.rtkOutput.bytes;\n truncated = outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8');\n } else {\n tail = useCapturedOutput ? result.output : log.tail;\n tailLines = useCapturedOutput ? countLines(tail) : log.tailLines;\n outputLines = Math.max(log.lines, tailLines);\n outputBytes = useCapturedOutput ? Buffer.byteLength(tail, 'utf8') : log.bytes;\n truncated = !useCapturedOutput && (outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8'));\n }\n const plainTail = stripAnsi(tail).replace(/\\r?\\n$/, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\n\n if (plainTail.length === 0) {\n textLines.push(status === undefined ? 'Completed with no output.' : 'No output.');\n } else if (truncated) {\n const label = result.rtkOutput ? `RTK ${result.rtkOutput.filter} excerpt` : 'Log excerpt';\n textLines.push(\n `${label} (${tailLines.toLocaleString('en-US')} of ${outputLines.toLocaleString('en-US')} lines):\\n${plainTail}`,\n );\n } else {\n textLines.push(plainTail);\n }\n if (status !== undefined) textLines.push(status);\n if (result.rtkWarning) textLines.push(result.rtkWarning);\n\n if (truncated) {\n const label = result.rtkOutput ? 'Complete raw log' : 'Full log';\n textLines.push(\n `${label}: ${result.logPath} (${formatSize(log.bytes)}, ${log.lines.toLocaleString('en-US')} lines); inspect with doom-runner logs ${result.id}`,\n );\n } else if (failed && plainTail.length === 0) {\n textLines.push(\n `Log: ${result.logPath}`,\n 'Next: run one read-only diagnostic; retry only after correcting the cause.',\n );\n }\n\n const text = boundResultText(textLines.join('\\n'), maxBytes);\n const details = {\n id: result.id,\n runner: result.name,\n exitCode: result.exitCode,\n logPath: result.logPath,\n backend: result.backend,\n fileSize: log.bytes,\n lines: useCapturedOutput ? tailLines : log.lines,\n tail,\n tailLines,\n ...(result.rtkOutput\n ? {\n rtkFilter: result.rtkOutput.filter,\n rtkOutputBytes: result.rtkOutput.bytes,\n rtkOutputLines: result.rtkOutput.lines,\n }\n : {}),\n ...(result.rtkWarning ? { rtkWarning: result.rtkWarning } : {}),\n ...(result.timedOut ? { timedOut: true } : {}),\n };\n\n if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bashTool.mjs","names":[],"sources":["../../../../src/commands/bash/bashTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport { BASH_TOOL_LABEL, BASH_TOOL_NAME, type BashParams, BashParamsSchema } from '../../schemas/bashTool.ts';\nimport { stripAnsi } from '../../services/AnsiScrub/ansiScrub';\nimport type { BashRunResult, CompletedRun, IBashRunService } from '../../types/bashRunService';\nimport { renderBashCall, renderBashResult } from '../../tui/bashRender.ts';\nimport {\n getBackgroundThresholdMs,\n getResultMaxBytes,\n getResultMaxLines,\n getResultMaxTokens,\n getSuccessResultMaxBytes,\n getSuccessResultMaxTokens,\n} from '../../types/config.ts';\nimport {\n boundExcerpt,\n boundResultText,\n composeExcerpt,\n parseResultPragma,\n type ResultBudget,\n countLines,\n formatSize,\n summarizeLog,\n type ToolResult,\n textResult,\n} from './responseEnvelope.ts';\n\nconst MS_PER_SECOND = 1000;\n\nconst PROMOTION_REASONS: Record<'requested' | 'threshold' | 'interactive', string> = {\n requested: 'Started in the background',\n threshold: 'Still running after the background threshold',\n interactive: 'Started interactively',\n};\n\nexport const BASH_PROMPT_SNIPPET =\n 'Execute shell commands with bounded foreground output and supervised background runners';\n\n/** Written at registration time so the stated threshold matches the configured one. */\nexport function bashPromptGuidelines(thresholdMs = getBackgroundThresholdMs()): string[] {\n return [\n `A command still running after ${Math.round(thresholdMs / MS_PER_SECOND)} seconds remains active as a background runner with an id and streaming log path.`,\n 'Pass background: true only for commands you know will remain active, such as dev servers, watchers, and tails.',\n 'Pass interactive: true only when the command will prompt for input. Use Runner Space for terminal input; avoid interactive mode otherwise because its logs are noisier.',\n 'On failure, use the returned output first. Inspect the saved log only when the result says output was truncated or no useful output was returned. Never retry an unchanged command merely to recover output.',\n 'Stop background runners when they are no longer needed. Every runner is stopped automatically when the session ends.',\n ];\n}\n\nexport interface BashToolDependencies {\n bashRunService: IBashRunService;\n getSessionId(): string | Promise<string>;\n /** Called after a runner is promoted, so UI state can refresh. */\n onRunnerStarted(id: string): void;\n}\n\n/**\n * Registers a tool named `bash`, replacing pi's built-in.\n *\n * The name is deliberate: hooks, guardrails and doom-pi's dispatcher all key on\n * `bash`, and they keep working only while the replacement keeps the name.\n */\nexport function registerBashTool(pi: ExtensionAPI, dependencies: BashToolDependencies): void {\n pi.registerTool({\n name: BASH_TOOL_NAME,\n label: BASH_TOOL_LABEL,\n description:\n 'Execute one Bash command in the current working directory. Foreground commands return bounded output; commands that outlive the threshold return a supervised runner id and streaming log path. Do not rerun a command merely to recover output; inspect the saved log only when the result identifies missing context.',\n promptSnippet: BASH_PROMPT_SNIPPET,\n promptGuidelines: bashPromptGuidelines(),\n parameters: BashParamsSchema,\n // Bash output already carries its own status glyphs and ANSI colours. Owning\n // the shell keeps Pi from filling every successful command with the global\n // toolSuccessBg, which overwhelms long logs and diffs.\n renderShell: 'self',\n\n async execute(_toolCallId, params, _signal, onUpdate, _ctx): Promise<ToolResult> {\n const { command, timeout, background, interactive, name } = params as BashParams;\n let onOutput: ((output: string) => void) | undefined;\n if (onUpdate) {\n const mode =\n interactive === true ? 'interactive runner' : background === true ? 'background runner' : 'command';\n onUpdate(textResult(`Starting ${mode}...`));\n }\n if (background !== true && interactive !== true && onUpdate) {\n onOutput = (output) => onUpdate(textResult(output));\n }\n let result: BashRunResult;\n try {\n result = await dependencies.bashRunService.run({\n command,\n timeoutMs: timeout === undefined ? undefined : timeout * MS_PER_SECOND,\n background,\n interactive,\n name,\n ...(onOutput ? { onOutput } : {}),\n sessionId: await dependencies.getSessionId(),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(\n [\n `Could not execute command: ${message}`,\n 'Next: verify the command, runtime, and working directory. Retry only after correcting the cause.',\n ].join('\\n'),\n { cause: error },\n );\n }\n\n if (result.kind === 'promoted') dependencies.onRunnerStarted(result.id);\n return formatRunResult(result, parseResultPragma(params.command));\n },\n\n // Without these, pi falls back to echoing the raw command and the tail end of\n // the result text, which is the metadata footer rather than the log output.\n renderCall(args, theme, _context) {\n return renderBashCall(args as BashParams, theme);\n },\n\n renderResult(result, options, theme, context) {\n return renderBashResult(result, { ...options, isError: context.isError }, theme);\n },\n });\n}\n\nfunction completionFailed(result: CompletedRun): boolean {\n return result.timedOut === true || result.signal !== null || (result.exitCode !== null && result.exitCode !== 0);\n}\n\nfunction completionStatus(result: CompletedRun): string | undefined {\n if (result.timedOut === true) return 'Timed out: exceeded the requested timeout.';\n if (result.signal !== null) return `Signal: ${result.signal}`;\n if (result.exitCode === null) return 'Exit status unavailable.';\n if (result.exitCode !== 0) return `Exit: ${result.exitCode}`;\n return undefined;\n}\n\nexport function formatRunResult(result: BashRunResult, budget: ResultBudget = {}): ToolResult {\n if (result.kind === 'failed') {\n throw new Error(\n [\n `Could not start runner \"${result.name}\": ${result.error}`,\n 'Next: correct the reported launch or supervision problem. Retry only after changing the command or environment.',\n ].join('\\n'),\n );\n }\n\n if (result.kind === 'promoted') {\n const reason = PROMOTION_REASONS[result.reason];\n const body = [\n `${reason}: runner \"${result.name}\" (${result.id}).`,\n `Streaming log: ${result.logPath}`,\n `Inspect: doom-runner logs ${result.id}`,\n ].join('\\n');\n\n return textResult(body, {\n id: result.id,\n runner: result.name,\n pid: result.pid,\n logPath: result.logPath,\n promoted: true,\n reason: result.reason,\n });\n }\n\n // Same shape either way; a success just buys less of it. Exiting 0 has already\n // reported the outcome, so its output is worth a fraction of a failure's.\n const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\n // An explicit pragma still wins: asking for a wider result is the point of it.\n const maxBytes = budget.maxBytes ?? (succeeded ? getSuccessResultMaxBytes() : getResultMaxBytes());\n const maxTokens = budget.maxTokens ?? (succeeded ? getSuccessResultMaxTokens() : getResultMaxTokens());\n const log = summarizeLog(result.logPath, maxLines, maxBytes, maxTokens);\n const useCapturedOutput = !result.rtkOutput && log.tail.length === 0 && result.output.length > 0;\n let tail: string;\n let tailLines: number;\n let outputLines: number;\n let outputBytes: number;\n let truncated: boolean;\n if (result.rtkOutput) {\n const clipped = Buffer.byteLength(result.rtkOutput.output, 'utf8') < result.rtkOutput.bytes;\n const bounded = clipped\n ? composeExcerpt(\n result.rtkOutput.head,\n result.rtkOutput.output,\n result.rtkOutput.lines,\n maxLines,\n maxBytes,\n [],\n maxTokens,\n )\n : boundExcerpt(result.rtkOutput.output, maxLines, maxBytes, maxTokens);\n tail = bounded.text;\n tailLines = bounded.lines;\n outputLines = result.rtkOutput.lines;\n outputBytes = result.rtkOutput.bytes;\n truncated = outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8');\n } else {\n tail = useCapturedOutput ? result.output : log.tail;\n tailLines = useCapturedOutput ? countLines(tail) : log.tailLines;\n outputLines = Math.max(log.lines, tailLines);\n outputBytes = useCapturedOutput ? Buffer.byteLength(tail, 'utf8') : log.bytes;\n truncated = !useCapturedOutput && (outputLines > tailLines || outputBytes > Buffer.byteLength(tail, 'utf8'));\n }\n const plainTail = stripAnsi(tail).replace(/\\r?\\n$/, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\n\n if (plainTail.length === 0) {\n textLines.push(status === undefined ? 'Completed with no output.' : 'No output.');\n } else if (truncated) {\n const label = result.rtkOutput ? `RTK ${result.rtkOutput.filter} excerpt` : 'Log excerpt';\n textLines.push(\n `${label} (${tailLines.toLocaleString('en-US')} of ${outputLines.toLocaleString('en-US')} lines):\\n${plainTail}`,\n );\n } else {\n textLines.push(plainTail);\n }\n if (status !== undefined) textLines.push(status);\n if (result.rtkWarning) textLines.push(result.rtkWarning);\n\n if (truncated) {\n const label = result.rtkOutput ? 'Complete raw log' : 'Full log';\n textLines.push(\n `${label}: ${result.logPath} (${formatSize(log.bytes)}, ${log.lines.toLocaleString('en-US')} lines); inspect with doom-runner logs ${result.id}`,\n );\n } else if (failed && plainTail.length === 0) {\n textLines.push(\n `Log: ${result.logPath}`,\n 'Next: run one read-only diagnostic; retry only after correcting the cause.',\n );\n }\n\n const text = boundResultText(textLines.join('\\n'), maxBytes);\n const details = {\n id: result.id,\n runner: result.name,\n exitCode: result.exitCode,\n logPath: result.logPath,\n backend: result.backend,\n fileSize: log.bytes,\n lines: useCapturedOutput ? tailLines : log.lines,\n tail,\n tailLines,\n ...(result.rtkOutput\n ? {\n rtkFilter: result.rtkOutput.filter,\n rtkOutputBytes: result.rtkOutput.bytes,\n rtkOutputLines: result.rtkOutput.lines,\n }\n : {}),\n ...(result.rtkWarning ? { rtkWarning: result.rtkWarning } : {}),\n ...(result.timedOut ? { timedOut: true } : {}),\n };\n\n if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const e=require("../../../_virtual/_rolldown/runtime.cjs"),t=require("../../types/config.cjs");let
|
|
1
|
+
const e=require("../../../_virtual/_rolldown/runtime.cjs"),t=require("../../types/config.cjs"),n=require("../../services/TokenEstimate/tokenEstimate.cjs");let r=require("node:fs");r=e.__toESM(r,1);let i=require("node:string_decoder");const a=1024,o=a*a,s=65536,c=/(?<![\w\-/=.])(?:errors?|fatal|panic|exception|traceback|assertion|assert|fail(?:ed|ure|ures)?)\b/iu,l=/\b(?:no|not|without|zero|0)\s+$/iu;function u(e,t={}){return{content:[{type:`text`,text:e}],details:t}}function d(e){return u(`Error: ${e}`,{error:e})}function f(e){return e<a?`${e} B`:e<o?`${(e/a).toFixed(1)} KB`:`${(e/o).toFixed(1)} MB`}function p(e){return e.toLocaleString(`en-US`)}function m(e){return e.length===0?0:e.endsWith(`
|
|
2
2
|
`)?e.split(`
|
|
3
3
|
`).length-1:e.split(`
|
|
4
|
-
`).length}var
|
|
5
|
-
`);for(;
|
|
6
|
-
`)}
|
|
7
|
-
`,1)[0]??``);if(!t?.[1])return{};let n;try{n=JSON.parse(t[1])}catch{return{}}if(typeof n!=`object`||!n||Array.isArray(n))return{};let r=n,i=
|
|
8
|
-
`);let l=r.map(e=>e.slice(o.length,e.length-c.length)),u=e.variants.length-r.length;return`${o}[${u>0?`${l.join(`|`)}|+${
|
|
4
|
+
`).length}var h=class{maxEntries;byKey=new Map;constructor(e=t.getErrorMaxEntries()){this.maxEntries=e}push(e){if(!b(e))return;let t=e.trim(),n=C(e),r=this.byKey.get(n);if(r){r.count+=1,!r.variants.includes(t)&&r.variants.length<12&&r.variants.push(t);return}this.byKey.size>=this.maxEntries||this.byKey.set(n,{variants:[t],count:1})}entries(){return[...this.byKey.values()]}};function g(e,n=t.getResultMaxLines(),a=t.getResultMaxBytes(),o=t.getResultMaxTokens()){let c;try{let t=r.default.statSync(e).size;c=r.default.openSync(e,`r`);let l=Buffer.alloc(s),u=Math.max(1,a+1),d=Buffer.alloc(0),f=Buffer.alloc(0),p=0,m,g=new i.StringDecoder(`utf8`),_=new h,v=``;for(;;){let e=r.default.readSync(c,l,0,l.byteLength,null);if(e===0)break;let t=l.subarray(0,e);for(let e of t)e===10&&(p+=1);m=t.at(-1),d.byteLength<u&&(d=Buffer.concat([d,t.subarray(0,u-d.byteLength)])),f=G(f,t,u),v+=g.write(t);let n=v.indexOf(`
|
|
5
|
+
`);for(;n>=0;)_.push(v.slice(0,n)),v=v.slice(n+1),n=v.indexOf(`
|
|
6
|
+
`)}v+=g.end(),v.length>0&&_.push(v);let y=p+ +(t>0&&m!==10),b=t<=f.byteLength?L(W(f,f.byteLength),n,a,o):R(d.toString(`utf8`),W(f,f.byteLength),y,n,a,_.entries(),o);return{tail:b.text,bytes:t,lines:y,tailLines:b.lines}}catch{return{tail:``,bytes:0,lines:0,tailLines:0}}finally{c!==void 0&&r.default.closeSync(c)}}const _=/^\s*(?:#|\/\/)\s*@doom:\s*(\{.*\})\s*$/u;function v(e){return typeof e==`number`&&Number.isInteger(e)&&e>0?e:void 0}function y(e){let t=_.exec(e.split(`
|
|
7
|
+
`,1)[0]??``);if(!t?.[1])return{};let n;try{n=JSON.parse(t[1])}catch{return{}}if(typeof n!=`object`||!n||Array.isArray(n))return{};let r=n,i=v(r.maxResultBytes),a=v(r.maxResultLines),o=v(r.maxResultTokens);return{...i===void 0?{}:{maxBytes:Math.min(i,262144)},...a===void 0?{}:{maxLines:Math.min(a,5e3)},...o===void 0?{}:{maxTokens:Math.min(o,1e5)}}}function b(e){let n=e.slice(0,60),r=c.exec(n);return r&&!l.test(n.slice(0,r.index))?!0:t.getErrorPatterns().some(t=>S(t,e))}const x=new Map;function S(e,t){if(!x.has(e))try{x.set(e,new RegExp(e,`iu`))}catch{x.set(e,void 0)}return x.get(e)?.test(t)??!1}function C(e){return e.replace(/0x[0-9a-f]+/giu,`0x#`).replace(/\/[^\s:,)]+/gu,`/#`).replace(/\d+/gu,`#`).trim().toLowerCase()}function w(e,n=t.getErrorMaxEntries()){let r=new h(n);for(let t of e)r.push(t);return r.entries()}function T(e){let t=e.reduce((e,t)=>Math.min(e,t.length),1/0),n=0;for(;n<t&&e.every(t=>t[n]===e[0][n]);)n+=1;let r=0;for(;r<t-n&&e.every(t=>t[t.length-1-r]===e[0][e[0].length-1-r]);)r+=1;return{prefix:n,suffix:r}}function E(e,t){let n=e.lastIndexOf(` `,Math.max(0,t-1));return n>=0?n+1:0}function D(e,t){let n=e.length-t,r=e.indexOf(` `,n);return r>=0?e.length-r:0}function O(e){let[n]=e.variants;if(n===void 0)return``;if(e.variants.length===1)return e.count>1?`${n} (\u00d7${p(e.count)})`:n;let r=e.variants.slice(0,t.getErrorMaxVariantsJoined()),{prefix:i,suffix:a}=T(r),o=n.slice(0,E(n,i)),s=D(n,a),c=s>0?n.slice(n.length-s):``;if(o.length+c.length<8)return r.join(`
|
|
8
|
+
`);let l=r.map(e=>e.slice(o.length,e.length-c.length)),u=e.variants.length-r.length;return`${o}[${u>0?`${l.join(`|`)}|+${p(u)}`:l.join(`|`)}]${c}`}function k(e,t){let n=[],r=0;for(let i of e){let e=O(i);if(e.length===0)continue;let a=Buffer.byteLength(e,`utf8`)+1;if(r+a>t)break;n.push(e),r+=a}return n}function A(e,t=0){let n=e===1?`line`:`lines`,r=t>0?`, ${p(t)} shown below`:``;return`\u2026 [${p(e)} ${n} elided${r}] \u2026`}function j(e){let t=e.endsWith(`
|
|
9
9
|
`),n=e.split(`
|
|
10
|
-
`);return t&&n.pop(),{lines:n,trailingNewline:t}}function
|
|
11
|
-
`),count:
|
|
12
|
-
`),i=r>=0?n.slice(r+1):n;return{text:i,count:+(i.length>0)}}function
|
|
13
|
-
`),l=r&&c.length>0?`${c}\n`:c,u=Buffer.from(l,`utf8`);return{text:u.byteLength>i?
|
|
10
|
+
`);return t&&n.pop(),{lines:n,trailingNewline:t}}function M(e,t,r,i,a=1/0){if(r<=0||t<=0)return{text:``,count:0};let o=i?[...e].reverse():[...e],s=[],c=0,l=0;for(let e of o){if(s.length>=t)break;let i=Buffer.byteLength(e,`utf8`)+ +(s.length>0),o=n.estimateTokens(e)+ +(s.length>0);if(c+i>r||l+o>a)break;s.push(e),c+=i,l+=o}if(s.length===0)return{text:``,count:0};let u=i?s.reverse():s;return{text:u.join(`
|
|
11
|
+
`),count:u.length}}function N(e,t){let n=W(Buffer.from(e,`utf8`),t),r=n.indexOf(`
|
|
12
|
+
`),i=r>=0?n.slice(r+1):n;return{text:i,count:+(i.length>0)}}function P(e){return Buffer.byteLength(A(e),`utf8`)+2}function F(e,t,n,r,i,a=[]){let o=n>0?[A(n,a.length)]:[],s=n>0&&a.length>0?[`…`]:[],c=[e.text,...o,...a,...s,t.text].filter(e=>e.length>0).join(`
|
|
13
|
+
`),l=r&&c.length>0?`${c}\n`:c,u=Buffer.from(l,`utf8`);return{text:u.byteLength>i?W(u,i):l,lines:e.count+t.count,truncated:!0,elidedLines:Math.max(0,n)}}function I(e,r,i,a){let o=Math.max(1,Math.floor(e)),s=Math.max(0,r-P(i)),c=Math.max(1,Math.floor(a)-n.estimateTokens(A(i)));return{limitLines:o,headLines:Math.max(1,Math.floor(o*t.getHeadRatio())),headBytes:Math.max(0,Math.floor(s*t.getHeadRatio())),headTokens:Math.max(1,Math.floor(c*t.getHeadRatio())),usable:s,tokens:c}}function L(e,r=t.getResultMaxLines(),i=t.getResultMaxBytes(),a=t.getResultMaxTokens()){if(e.length===0)return{text:``,lines:0,truncated:!1,elidedLines:0};let{lines:o,trailingNewline:s}=j(e),c=Buffer.byteLength(e,`utf8`),l=Number.isFinite(i)?Math.max(0,Math.floor(i)):c,u=Math.max(1,Math.floor(r));if(o.length<=u&&c<=l&&n.estimateTokens(e)<=a)return{text:e,lines:o.length,truncated:!1,elidedLines:0};let d=I(r,l,o.length,a),f=M(o,d.headLines,d.headBytes,!1,d.headTokens),p=o.slice(f.count),m=p.some(b)?Math.floor(d.usable*t.getErrorBudgetRatio()):0,h=d.usable-Buffer.byteLength(f.text,`utf8`)-m,g=d.tokens-n.estimateTokens(f.text),_=M(p,Math.max(1,d.limitLines-f.count),h,!0,g);if(f.count===0&&_.count===0){let t=N(e,l);return{text:t.text,lines:t.count,truncated:!0,elidedLines:o.length-t.count}}let v=o.slice(f.count,o.length-_.count),y=m>0?k(w(v),m):[];return F(f,_,o.length-f.count-_.count,s,l,y)}function R(e,r,i,a=t.getResultMaxLines(),o=t.getResultMaxBytes(),s=[],c=t.getResultMaxTokens()){let l=Number.isFinite(o)?Math.max(0,Math.floor(o)):2**53-1,u=I(a,l,i,c),d=j(e).lines,{lines:f,trailingNewline:p}=j(r),m=M(d.slice(0,Math.max(0,d.length-1)),u.headLines,u.headBytes,!1,u.headTokens),h=s.length>0?Math.floor(u.usable*t.getErrorBudgetRatio()):0,g=u.usable-Buffer.byteLength(m.text,`utf8`)-h,_=u.tokens-n.estimateTokens(m.text),v=M(f.slice(1),Math.max(1,u.limitLines-m.count),g,!0,_);if(m.count===0&&v.count===0){let e=N(r,l);return{text:e.text,lines:e.count,truncated:!0,elidedLines:Math.max(0,i-e.count)}}let y=h>0?k(s,h):[];return F(m,v,Math.max(0,i-m.count-v.count),p,l,y)}function z(e,n=t.getResultMaxLines(),r=t.getResultMaxBytes()){let i=L(e,n,r);return{tail:i.text,tailLines:i.lines}}function B(e,n=t.getResultMaxBytes()){return L(e,t.getResultMaxLines(),n).text}function V(e,n,r=t.getResultMaxBytes(),i=t.getResultMaxLines()){let a=L(e,i,r);return a.truncated?{text:`${a.text}\n${H(a,n,e)}`,truncated:!0,outputLines:a.lines}:{text:e,truncated:!1,outputLines:a.lines}}function H(e,t,n){let r=U(t),i=r?.lines??m(n),a=r?.bytes??Buffer.byteLength(n,`utf8`);return[`[output truncated: showing ${p(e.lines)} of ${p(i)} lines,`,`${p(e.elidedLines)} elided from the middle.`,`Full output is at ${t} (${f(a)}, ${p(i)} lines).`,`Inspect it with doom-runner logs, or read the file with an offset near line ${p(i)}.]`].join(` `)}function U(e){let t;try{let n=r.default.statSync(e).size;t=r.default.openSync(e,`r`);let i=Buffer.alloc(s),a=0,o;for(;;){let e=r.default.readSync(t,i,0,i.byteLength,null);if(e===0)break;let n=i.subarray(0,e);for(let e of n)e===10&&(a+=1);o=n.at(-1)}return{bytes:n,lines:a+ +(n>0&&o!==10)}}catch{return}finally{t!==void 0&&r.default.closeSync(t)}}function W(e,t){let n=Math.max(0,e.byteLength-t);for(;n<e.byteLength&&(e[n]&192)==128;)n+=1;return e.subarray(n).toString(`utf8`)}function G(e,t,n){if(t.byteLength>=n)return Buffer.from(t.subarray(t.byteLength-n));let r=Buffer.concat([e,t]);return r.byteLength>n?Buffer.from(r.subarray(r.byteLength-n)):r}function K(e,t=Date.now()){let n=e.interactive?` interactive`:``;return`${e.name} pid ${e.pid} up ${q(e.startedAt,t)}${n} ${e.command}`}function q(e,t){let n=Date.parse(e);if(Number.isNaN(n))return`unknown`;let r=Math.max(0,Math.floor((t-n)/1e3));if(r<60)return`${r}s`;let i=Math.floor(r/60);if(i<60)return`${i}m`;let a=Math.floor(i/60);return a<24?`${a}h`:`${Math.floor(a/24)}d`}exports.boundExcerpt=L,exports.boundResultText=B,exports.collectErrorLines=w,exports.composeExcerpt=R,exports.countLines=m,exports.errorResult=d,exports.formatRunnerLine=K,exports.formatSize=f,exports.formatUptime=q,exports.parseResultPragma=y,exports.summarizeLog=g,exports.summarizeText=z,exports.textResult=u,exports.truncateForResult=V;
|
|
14
14
|
//# sourceMappingURL=responseEnvelope.cjs.map
|