@agimon-ai/doompi-runner 0.0.1-alpha.97 → 0.0.1-alpha.98

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.
Files changed (129) hide show
  1. package/README.md +23 -0
  2. package/dist/bashRender.cjs +1 -1
  3. package/dist/bashRender.mjs +1 -1
  4. package/dist/{bashResult-SkF8WzLS.cjs → bashResult-CkTthslG.cjs} +2 -2
  5. package/dist/{bashResult-SkF8WzLS.cjs.map → bashResult-CkTthslG.cjs.map} +1 -1
  6. package/dist/{bashResult-BKLi1Zpx.mjs → bashResult-DhbolCo5.mjs} +2 -2
  7. package/dist/{bashResult-BKLi1Zpx.mjs.map → bashResult-DhbolCo5.mjs.map} +1 -1
  8. package/dist/{bashRunService-CxnXkCyV.cjs → bashRunService-CpPOtFmX.cjs} +34 -9
  9. package/dist/bashRunService-CpPOtFmX.cjs.map +1 -0
  10. package/dist/{bashRunService-C1m8Mgkx.mjs → bashRunService-DGHoojwa.mjs} +34 -9
  11. package/dist/bashRunService-DGHoojwa.mjs.map +1 -0
  12. package/dist/bashRunService.cjs +1 -1
  13. package/dist/bashRunService.d.mts +3 -1
  14. package/dist/bashRunService.d.mts.map +1 -1
  15. package/dist/bashRunService.mjs +1 -1
  16. package/dist/{bashTool-DzucJQKE.cjs → bashTool-BTaD5ah_.cjs} +3 -3
  17. package/dist/{bashTool-DzucJQKE.cjs.map → bashTool-BTaD5ah_.cjs.map} +1 -1
  18. package/dist/{bashTool-BX4UF_cF.mjs → bashTool-CmsWe5tz.mjs} +3 -3
  19. package/dist/{bashTool-BX4UF_cF.mjs.map → bashTool-CmsWe5tz.mjs.map} +1 -1
  20. package/dist/bashTool.cjs +3 -3
  21. package/dist/bashTool.mjs +3 -3
  22. package/dist/bin/cli.cjs +2 -2
  23. package/dist/bin/cli.mjs +2 -2
  24. package/dist/{cliApp-dVY9mnBz.mjs → cliApp-CRGF7dQZ.mjs} +2 -2
  25. package/dist/{cliApp-dVY9mnBz.mjs.map → cliApp-CRGF7dQZ.mjs.map} +1 -1
  26. package/dist/{cliApp-CP2WKUG_.cjs → cliApp-j67GnsVr.cjs} +2 -2
  27. package/dist/{cliApp-CP2WKUG_.cjs.map → cliApp-j67GnsVr.cjs.map} +1 -1
  28. package/dist/cliApp.cjs +1 -1
  29. package/dist/cliApp.mjs +1 -1
  30. package/dist/config.cjs +2 -1
  31. package/dist/config.d.mts +2 -2
  32. package/dist/config.mjs +2 -2
  33. package/dist/extensions/mcp.cjs.map +1 -1
  34. package/dist/extensions/mcp.mjs.map +1 -1
  35. package/dist/extensions/pi.cjs +7 -7
  36. package/dist/extensions/pi.mjs +7 -7
  37. package/dist/extensions/server.cjs +12 -8
  38. package/dist/extensions/server.cjs.map +1 -1
  39. package/dist/extensions/server.mjs +12 -8
  40. package/dist/extensions/server.mjs.map +1 -1
  41. package/dist/{format-BaAcUdvA.cjs → format-DZnvaa9t.cjs} +2 -2
  42. package/dist/{format-BaAcUdvA.cjs.map → format-DZnvaa9t.cjs.map} +1 -1
  43. package/dist/{format-BCl0BTQw.mjs → format-ccmgjlvo.mjs} +2 -2
  44. package/dist/{format-BCl0BTQw.mjs.map → format-ccmgjlvo.mjs.map} +1 -1
  45. package/dist/{headless-D2UKFWVg.cjs → headless-95n3qVdk.cjs} +3 -3
  46. package/dist/{headless-D2UKFWVg.cjs.map → headless-95n3qVdk.cjs.map} +1 -1
  47. package/dist/{headless-CsjrWGKk.mjs → headless-Bh35ieNx.mjs} +3 -3
  48. package/dist/{headless-CsjrWGKk.mjs.map → headless-Bh35ieNx.mjs.map} +1 -1
  49. package/dist/{index-BjSmZc3m.d.mts → index-CsakAtTY.d.mts} +3 -1
  50. package/dist/index-CsakAtTY.d.mts.map +1 -0
  51. package/dist/index.cjs +5 -5
  52. package/dist/index.d.mts +2 -2
  53. package/dist/index.mjs +5 -5
  54. package/dist/{launcher-DT3B7nFi.mjs → launcher-C3K7KS41.mjs} +3 -2
  55. package/dist/launcher-C3K7KS41.mjs.map +1 -0
  56. package/dist/{launcher-s03kVk1v.cjs → launcher-J7FraZCx.cjs} +3 -2
  57. package/dist/launcher-J7FraZCx.cjs.map +1 -0
  58. package/dist/launcher.cjs +1 -1
  59. package/dist/launcher.d.mts.map +1 -1
  60. package/dist/launcher.mjs +1 -1
  61. package/dist/{logFile-BbIrIcWY.mjs → logFile-B1KnO9xy.mjs} +2 -2
  62. package/dist/{logFile-BbIrIcWY.mjs.map → logFile-B1KnO9xy.mjs.map} +1 -1
  63. package/dist/{logFile-BACXeSRG.cjs → logFile-Di1WEAtZ.cjs} +2 -2
  64. package/dist/{logFile-BACXeSRG.cjs.map → logFile-Di1WEAtZ.cjs.map} +1 -1
  65. package/dist/logFile.cjs +1 -1
  66. package/dist/logFile.mjs +1 -1
  67. package/dist/{logReader-7R1V06IS.cjs → logReader-B3mAZwOb.cjs} +3 -3
  68. package/dist/{logReader-7R1V06IS.cjs.map → logReader-B3mAZwOb.cjs.map} +1 -1
  69. package/dist/{logReader-DfUVwLLJ.mjs → logReader-K3DIaUAE.mjs} +3 -3
  70. package/dist/{logReader-DfUVwLLJ.mjs.map → logReader-K3DIaUAE.mjs.map} +1 -1
  71. package/dist/logReader.cjs +1 -1
  72. package/dist/logReader.mjs +1 -1
  73. package/dist/{ptyHost-BMrUFpMX.mjs → ptyHost-Bh7RChQN.mjs} +2 -2
  74. package/dist/{ptyHost-BMrUFpMX.mjs.map → ptyHost-Bh7RChQN.mjs.map} +1 -1
  75. package/dist/{ptyHost-BsChzCm7.cjs → ptyHost-t81Ghu2w.cjs} +2 -2
  76. package/dist/{ptyHost-BsChzCm7.cjs.map → ptyHost-t81Ghu2w.cjs.map} +1 -1
  77. package/dist/ptyHost.cjs +1 -1
  78. package/dist/ptyHost.mjs +1 -1
  79. package/dist/responseEnvelope.cjs +2 -2
  80. package/dist/responseEnvelope.mjs +2 -2
  81. package/dist/{rmuxBackend-B7w7KaF3.mjs → rmuxBackend-BBLAlHFV.mjs} +6 -3
  82. package/dist/rmuxBackend-BBLAlHFV.mjs.map +1 -0
  83. package/dist/{rmuxBackend-D3ZQCkTw.cjs → rmuxBackend-frWNHhjq.cjs} +6 -3
  84. package/dist/rmuxBackend-frWNHhjq.cjs.map +1 -0
  85. package/dist/rmuxBackend.cjs +1 -1
  86. package/dist/rmuxBackend.mjs +1 -1
  87. package/dist/{rtkProcessor-DJedzL3y.cjs → rtkProcessor-BGdkgf05.cjs} +2 -2
  88. package/dist/{rtkProcessor-DJedzL3y.cjs.map → rtkProcessor-BGdkgf05.cjs.map} +1 -1
  89. package/dist/{rtkProcessor-C1cmQhJO.mjs → rtkProcessor-Co0wLjZs.mjs} +2 -2
  90. package/dist/{rtkProcessor-C1cmQhJO.mjs.map → rtkProcessor-Co0wLjZs.mjs.map} +1 -1
  91. package/dist/rtkProcessor.cjs +1 -1
  92. package/dist/rtkProcessor.mjs +1 -1
  93. package/dist/{runnerConfig-D1OoyRo0.mjs → runnerConfig-BamWjxBH.mjs} +11 -2
  94. package/dist/{runnerConfig-DsHrA6i2.cjs.map → runnerConfig-BamWjxBH.mjs.map} +1 -1
  95. package/dist/{runnerConfig-DsHrA6i2.cjs → runnerConfig-CzcAcYXI.cjs} +16 -1
  96. package/dist/{runnerConfig-D1OoyRo0.mjs.map → runnerConfig-CzcAcYXI.cjs.map} +1 -1
  97. package/dist/{runnerConfig-BQnCguNO.d.mts → runnerConfig-o0WHN8Z_.d.mts} +4 -2
  98. package/dist/{runnerConfig-BQnCguNO.d.mts.map → runnerConfig-o0WHN8Z_.d.mts.map} +1 -1
  99. package/dist/{runnerDependencies-CZncce9q.mjs → runnerDependencies-BiOlQVdJ.mjs} +15 -12
  100. package/dist/runnerDependencies-BiOlQVdJ.mjs.map +1 -0
  101. package/dist/{runnerDependencies-BsM9qefi.cjs → runnerDependencies-DAgl_x1Y.cjs} +15 -12
  102. package/dist/runnerDependencies-DAgl_x1Y.cjs.map +1 -0
  103. package/dist/runnerDependencies.cjs +1 -1
  104. package/dist/runnerDependencies.d.mts +1 -1
  105. package/dist/runnerDependencies.mjs +1 -1
  106. package/dist/runnerFormat.cjs +1 -1
  107. package/dist/runnerFormat.mjs +1 -1
  108. package/dist/{runnerPaths-BSkjI5EO.cjs → runnerPaths-DDtlQ9of.cjs} +2 -2
  109. package/dist/{runnerPaths-BSkjI5EO.cjs.map → runnerPaths-DDtlQ9of.cjs.map} +1 -1
  110. package/dist/{runnerPaths-xeHQjhYj.mjs → runnerPaths-DdzDY3xs.mjs} +2 -2
  111. package/dist/{runnerPaths-xeHQjhYj.mjs.map → runnerPaths-DdzDY3xs.mjs.map} +1 -1
  112. package/dist/runnerPaths.cjs +1 -1
  113. package/dist/runnerPaths.mjs +1 -1
  114. package/dist/{runnerSpace-DwQOUo3E.cjs → runnerSpace-B8J5Yf7_.cjs} +2 -2
  115. package/dist/{runnerSpace-DwQOUo3E.cjs.map → runnerSpace-B8J5Yf7_.cjs.map} +1 -1
  116. package/dist/{runnerSpace-BzcAlchW.mjs → runnerSpace-DeXscB19.mjs} +2 -2
  117. package/dist/{runnerSpace-BzcAlchW.mjs.map → runnerSpace-DeXscB19.mjs.map} +1 -1
  118. package/dist/runnerSpace.cjs +1 -1
  119. package/dist/runnerSpace.mjs +1 -1
  120. package/package.json +16 -16
  121. package/dist/bashRunService-C1m8Mgkx.mjs.map +0 -1
  122. package/dist/bashRunService-CxnXkCyV.cjs.map +0 -1
  123. package/dist/index-BjSmZc3m.d.mts.map +0 -1
  124. package/dist/launcher-DT3B7nFi.mjs.map +0 -1
  125. package/dist/launcher-s03kVk1v.cjs.map +0 -1
  126. package/dist/rmuxBackend-B7w7KaF3.mjs.map +0 -1
  127. package/dist/rmuxBackend-D3ZQCkTw.cjs.map +0 -1
  128. package/dist/runnerDependencies-BsM9qefi.cjs.map +0 -1
  129. package/dist/runnerDependencies-CZncce9q.mjs.map +0 -1
package/README.md CHANGED
@@ -190,6 +190,29 @@ Commands inherit the DoomPi process environment and the operating system user's
190
190
  may contain prompts, source, command output, credentials, or other secrets; restrict access and
191
191
  retention accordingly.
192
192
 
193
+ ### Host-wide resource budget
194
+
195
+ The headless DoomPi server shares one heavy-job queue across its sessions. Known
196
+ noninteractive build, test, lint, and typecheck commands acquire a slot before
197
+ launching. The default is two concurrent jobs; set `DOOM_RUNNER_MAX_HEAVY_JOBS`
198
+ to a positive integer in the server's environment to change it. The waiting queue
199
+ is bounded to 128 jobs. Cancellation removes queued work without launching it.
200
+
201
+ A background promotion keeps its slot until the process exits. Closing one
202
+ session does not release another session's slot. Interactive commands and ordinary
203
+ inspection commands bypass this queue. This is admission for recognized command
204
+ forms, not an operating-system CPU quota or a parser for arbitrary shell scripts.
205
+
206
+ For noninteractive native, RMUX, and tmux launches, unset child environment values
207
+ default to `NX_NATIVE_COMMAND_RUNNER=false`, `NX_TUI=false`, `NX_PARALLEL=2`, and
208
+ `VITEST_MAX_WORKERS=2`. Explicit environment values still win; interactive launches
209
+ keep their original settings. Standalone Pi gets the child defaults but does not
210
+ receive a headless host's cross-session queue.
211
+
212
+ The server records changed queue counts as `doompi_server.execution_budget`
213
+ events with the host PID, running jobs, queued jobs, and limit. These are not
214
+ per-session memory measurements.
215
+
193
216
  ## Native artifacts
194
217
 
195
218
  Runner selects the matching optional dependencies automatically:
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
3
3
  const require_bashRender = require("./bashRender-61ZjIac8.cjs");
4
- const require_bashResult = require("./bashResult-SkF8WzLS.cjs");
4
+ const require_bashResult = require("./bashResult-CkTthslG.cjs");
5
5
  let node_os = require("node:os");
6
6
  node_os = require_rolldown_runtime.__toESM(node_os, 1);
7
7
  let _agimon_ai_doompi_ui_toolChrome = require("@agimon-ai/doompi-ui/toolChrome");
@@ -1,5 +1,5 @@
1
1
  import { n as SGR_PATTERN, t as GAP } from "./bashRender-CLi1orVw.mjs";
2
- import { u as formatSize } from "./bashResult-BKLi1Zpx.mjs";
2
+ import { u as formatSize } from "./bashResult-DhbolCo5.mjs";
3
3
  import os from "node:os";
4
4
  import { DoomToolCall, renderToolBadge } from "@agimon-ai/doompi-ui/toolChrome";
5
5
  import { highlightCode } from "@earendil-works/pi-coding-agent";
@@ -1,5 +1,5 @@
1
1
  const require_ansiScrub = require("./ansiScrub-D5gpHDch.cjs");
2
- const require_runnerConfig = require("./runnerConfig-DsHrA6i2.cjs");
2
+ const require_runnerConfig = require("./runnerConfig-CzcAcYXI.cjs");
3
3
  //#region src/constants/bashResult.ts
4
4
  const BYTES_PER_KB = 1024;
5
5
  const BYTES_PER_MB = 1048576;
@@ -636,4 +636,4 @@ Object.defineProperty(exports, "textResult", {
636
636
  }
637
637
  });
638
638
 
639
- //# sourceMappingURL=bashResult-SkF8WzLS.cjs.map
639
+ //# sourceMappingURL=bashResult-CkTthslG.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bashResult-SkF8WzLS.cjs","names":["getErrorMaxEntries","getErrorPatterns","getErrorMaxVariantsJoined","getHeadRatio","getResultMaxLines","getResultMaxBytes","getResultMaxTokens","getErrorBudgetRatio","getSuccessResultMaxBytes","getSuccessResultMaxTokens","stripAnsi"],"sources":["../src/constants/bashResult.ts","../src/constants/tokenEstimate.ts","../src/services/tokenEstimate/index.ts","../src/services/bashResult/index.ts"],"sourcesContent":["export const BYTES_PER_KB = 1024;\nexport const BYTES_PER_MB = 1_048_576;\nexport const MAX_VARIANTS_TRACKED = 12;\nexport const MIN_SHARED_AFFIX = 8;\nexport const ERROR_WINDOW_CHARS = 60;\nexport const PRAGMA_PATTERN = /^\\s*(?:#|\\/\\/)\\s*@doom:\\s*(\\{.*\\})\\s*$/u;\nexport const PRAGMA_BYTES_CEILING = 262_144;\nexport const PRAGMA_LINES_CEILING = 5_000;\nexport const PRAGMA_TOKENS_CEILING = 100_000;\n","export const WORD_CHARS_PER_TOKEN = 5;\nexport const MIXED_CHARS_PER_TOKEN = 2.1;\nexport const PUNCTUATION_CHARS_PER_TOKEN = 2;\nexport const DENSE_SCRIPT_START = 0x2fff;\nexport const ASTRAL_TOKEN_COST = 2;\nexport const ALPHANUMERIC_RUN = /([^\\p{L}\\p{N}]+)/u;\nexport const HAS_ALPHANUMERIC = /[\\p{L}\\p{N}]/u;\nexport const HAS_DIGIT = /\\d/u;\nexport const HAS_LETTER = /[A-Za-z]/u;\n","import {\n ALPHANUMERIC_RUN,\n ASTRAL_TOKEN_COST,\n DENSE_SCRIPT_START,\n HAS_ALPHANUMERIC,\n HAS_DIGIT,\n HAS_LETTER,\n MIXED_CHARS_PER_TOKEN,\n PUNCTUATION_CHARS_PER_TOKEN,\n WORD_CHARS_PER_TOKEN,\n} from '../../constants/tokenEstimate';\n/**\n * Estimates BPE tokens without carrying a vocabulary.\n *\n * Bytes are a poor proxy for what a result costs: measured against\n * `gpt-tokenizer`, real text ranges from 1.4 characters per token for base64 to\n * 4.7 for English prose, a spread of more than three. Truncation runs on every\n * command and is synchronous, so loading a real tokenizer here would charge\n * every session for a table most of them never need.\n *\n * The shape below follows how BPE actually behaves: punctuation forces token\n * boundaries, natural words are cheap, and runs mixing letters with digits are\n * expensive. Calibrated against `gpt-tokenizer` over build logs, source, JSON,\n * stack traces, CJK, base64, hex, and UUIDs, the worst error is a factor of\n * 1.46 either way. It stays an estimate, so the byte ceiling remains the hard\n * bound behind it.\n */\n\n/** Characters per token for a natural word. */\n/** Characters per token for a run mixing letters and digits, which tokenizes poorly. */\n/** Characters per token for a run of punctuation or whitespace. */\n/** Dense scripts such as CJK cost about one token per character. */\n\nexport function estimateTokens(text: string): number {\n let tokens = 0;\n for (const run of text.split(ALPHANUMERIC_RUN)) {\n if (run.length === 0) continue;\n if (!HAS_ALPHANUMERIC.test(run)) {\n tokens += run.length / PUNCTUATION_CHARS_PER_TOKEN;\n continue;\n }\n\n let ascii = 0;\n let dense = 0;\n let astral = 0;\n for (const character of run) {\n const code = character.codePointAt(0) ?? 0;\n if (code > 0xffff) astral += 1;\n else if (code > DENSE_SCRIPT_START) dense += 1;\n else ascii += 1;\n }\n tokens += astral * ASTRAL_TOKEN_COST + dense;\n if (ascii > 0) {\n const mixed = HAS_DIGIT.test(run) && HAS_LETTER.test(run);\n tokens += Math.max(1, ascii / (mixed ? MIXED_CHARS_PER_TOKEN : WORD_CHARS_PER_TOKEN));\n }\n }\n return Math.ceil(tokens);\n}\n","import {\n BYTES_PER_KB,\n BYTES_PER_MB,\n ERROR_WINDOW_CHARS,\n MAX_VARIANTS_TRACKED,\n MIN_SHARED_AFFIX,\n PRAGMA_BYTES_CEILING,\n PRAGMA_LINES_CEILING,\n PRAGMA_PATTERN,\n PRAGMA_TOKENS_CEILING,\n} from '../../constants/bashResult';\nimport type {\n ErrorLineScanner,\n Excerpt,\n LogSummarizer,\n LogSummary,\n ResultBudget,\n SalvagedError,\n ToolResult,\n} from '../../types/bashResult';\nimport type { BashRunResult, CompletedRun } from '../../types/bashRunService';\nimport type { RunnerRecord } from '../../types/runnerRegistry';\nimport { stripAnsi } from '../ansiScrub';\nimport {\n getErrorBudgetRatio,\n getErrorMaxEntries,\n getErrorMaxVariantsJoined,\n getErrorPatterns,\n getHeadRatio,\n getResultMaxBytes,\n getResultMaxLines,\n getResultMaxTokens,\n getSuccessResultMaxBytes,\n getSuccessResultMaxTokens,\n} from '../runnerConfig';\nimport { estimateTokens } from '../tokenEstimate';\n\n/** Variants retained per group while scanning; the rest only add to the count. */\n/** Below this much shared text, joining reads worse than separate lines. */\n/**\n * Severity anywhere in the opening of the line, not only at its start. Real\n * tooling buries it behind a tag or a timestamp: `[widget] build: error TS2322`.\n */\nconst SEVERITY_TOKEN =\n /(?<![\\w\\-/=.])(?:errors?|fatal|panic|exception|traceback|assertion|assert|fail(?:ed|ure|ures)?)\\b/iu;\n/** `0 errors` and `no failures` are the success case wearing the same words. */\nconst NEGATED_SEVERITY = /\\b(?:no|not|without|zero|0)\\s+$/iu;\n\nexport function textResult(text: string, details: Record<string, unknown> = {}): ToolResult {\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function errorResult(message: string): ToolResult {\n return textResult(`Error: ${message}`, { error: message });\n}\n\n/** Human-readable byte count, matching how pi reports output sizes. */\nexport function formatSize(bytes: number): string {\n if (bytes < BYTES_PER_KB) return `${bytes} B`;\n if (bytes < BYTES_PER_MB) return `${(bytes / BYTES_PER_KB).toFixed(1)} KB`;\n return `${(bytes / BYTES_PER_MB).toFixed(1)} MB`;\n}\n\nfunction formatCount(value: number): string {\n return value.toLocaleString('en-US');\n}\n\nexport function countLines(text: string): number {\n if (text.length === 0) return 0;\n return text.endsWith('\\n') ? text.split('\\n').length - 1 : text.split('\\n').length;\n}\n\n/** Accumulates grouped error lines while a log streams past, without holding it. */\nclass ErrorScan {\n private readonly byKey = new Map<string, { variants: string[]; count: number }>();\n\n constructor(private readonly maxEntries = getErrorMaxEntries()) {}\n\n push(line: string): void {\n if (!isErrorLine(line)) return;\n const trimmed = line.trim();\n const key = normalizeErrorLine(line);\n const existing = this.byKey.get(key);\n if (existing) {\n existing.count += 1;\n // Only a line we have not seen verbatim earns a slot; identical repeats\n // are carried by the count alone.\n if (!existing.variants.includes(trimmed) && existing.variants.length < MAX_VARIANTS_TRACKED) {\n existing.variants.push(trimmed);\n }\n return;\n }\n if (this.byKey.size >= this.maxEntries) return;\n this.byKey.set(key, { variants: [trimmed], count: 1 });\n }\n\n entries(): SalvagedError[] {\n return [...this.byKey.values()];\n }\n}\n\nexport function createErrorScanner(maxEntries = getErrorMaxEntries()): ErrorLineScanner {\n return new ErrorScan(maxEntries);\n}\n\n/** Codex-style first-line pragma, for the one command that needs a wider result. */\n\nfunction positiveInteger(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;\n}\n\n/**\n * Reads `# @doom: {\"maxResultBytes\": 32768}` from the command's first line.\n *\n * The pragma is a shell comment, so it stays harmless if this parse is ever\n * skipped, and it survives verbatim into the log where a wider result can be\n * explained after the fact.\n */\nexport function parseResultPragma(command: string): ResultBudget {\n const match = PRAGMA_PATTERN.exec(command.split('\\n', 1)[0] ?? '');\n if (!match?.[1]) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(match[1]);\n } catch {\n return {};\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n\n const source = parsed as Record<string, unknown>;\n const maxBytes = positiveInteger(source.maxResultBytes);\n const maxLines = positiveInteger(source.maxResultLines);\n const maxTokens = positiveInteger(source.maxResultTokens);\n return {\n ...(maxBytes === undefined ? {} : { maxBytes: Math.min(maxBytes, PRAGMA_BYTES_CEILING) }),\n ...(maxLines === undefined ? {} : { maxLines: Math.min(maxLines, PRAGMA_LINES_CEILING) }),\n ...(maxTokens === undefined ? {} : { maxTokens: Math.min(maxTokens, PRAGMA_TOKENS_CEILING) }),\n };\n}\n\nfunction isErrorLine(line: string): boolean {\n const opening = line.slice(0, ERROR_WINDOW_CHARS);\n const match = SEVERITY_TOKEN.exec(opening);\n if (match && !NEGATED_SEVERITY.test(opening.slice(0, match.index))) return true;\n // Project patterns extend the built-in matcher; tooling this does not\n // recognise is exactly why they exist, so they are not negation-checked.\n return getErrorPatterns().some((pattern) => matchesCustomPattern(pattern, line));\n}\n\nconst customPatterns = new Map<string, RegExp | undefined>();\n\nfunction matchesCustomPattern(pattern: string, line: string): boolean {\n if (!customPatterns.has(pattern)) {\n try {\n customPatterns.set(pattern, new RegExp(pattern, 'iu'));\n } catch {\n customPatterns.set(pattern, undefined);\n }\n }\n return customPatterns.get(pattern)?.test(line) ?? false;\n}\n\n/** Masks the parts that differ between repeats of the same underlying failure. */\nfunction normalizeErrorLine(line: string): string {\n return line\n .replace(/0x[0-9a-f]+/giu, '0x#')\n .replace(/\\/[^\\s:,)]+/gu, '/#')\n .replace(/\\d+/gu, '#')\n .trim()\n .toLowerCase();\n}\n\n/**\n * Collapses repeats so one failure repeated two hundred times costs one slot.\n * Counting continues past the entry cap so the tallies stay honest.\n */\nexport function collectErrorLines(lines: Iterable<string>, maxEntries = getErrorMaxEntries()): SalvagedError[] {\n const scan = new ErrorScan(maxEntries);\n for (const line of lines) scan.push(line);\n return scan.entries();\n}\n\nfunction commonAffixLengths(values: readonly string[]): { prefix: number; suffix: number } {\n const shortest = values.reduce((min, value) => Math.min(min, value.length), Infinity);\n let prefix = 0;\n while (prefix < shortest && values.every((value) => value[prefix] === values[0]![prefix])) prefix += 1;\n let suffix = 0;\n while (\n suffix < shortest - prefix &&\n values.every((value) => value[value.length - 1 - suffix] === values[0]![values[0]!.length - 1 - suffix])\n ) {\n suffix += 1;\n }\n return { prefix, suffix };\n}\n\n/** Back off to a whitespace boundary so the brackets hold whole tokens. */\nfunction retreatToBoundary(value: string, length: number): number {\n const boundary = value.lastIndexOf(' ', Math.max(0, length - 1));\n return boundary >= 0 ? boundary + 1 : 0;\n}\n\nfunction advanceToBoundary(value: string, length: number): number {\n const cut = value.length - length;\n const boundary = value.indexOf(' ', cut);\n return boundary >= 0 ? value.length - boundary : 0;\n}\n\n/**\n * One line per distinct failure would be ideal, but repeats of one failure\n * across many files are the common case. Sharing the fixed text and joining\n * only the parts that differ keeps every file name without paying for the\n * message N times.\n */\nfunction renderGroup(group: SalvagedError): string {\n const [first] = group.variants;\n if (first === undefined) return '';\n if (group.variants.length === 1) {\n return group.count > 1 ? `${first} (\\u00d7${formatCount(group.count)})` : first;\n }\n\n const shown = group.variants.slice(0, getErrorMaxVariantsJoined());\n const { prefix, suffix } = commonAffixLengths(shown);\n const head = first.slice(0, retreatToBoundary(first, prefix));\n const tailLength = advanceToBoundary(first, suffix);\n const tail = tailLength > 0 ? first.slice(first.length - tailLength) : '';\n if (head.length + tail.length < MIN_SHARED_AFFIX) return shown.join('\\n');\n\n const middles = shown.map((value) => value.slice(head.length, value.length - tail.length));\n const overflow = group.variants.length - shown.length;\n const joined = overflow > 0 ? `${middles.join('|')}|+${formatCount(overflow)}` : middles.join('|');\n return `${head}[${joined}]${tail}`;\n}\n\nfunction renderSalvaged(errors: readonly SalvagedError[], maxBytes: number): string[] {\n const rendered: string[] = [];\n let used = 0;\n for (const group of errors) {\n const text = renderGroup(group);\n if (text.length === 0) continue;\n const cost = Buffer.byteLength(text, 'utf8') + 1;\n if (used + cost > maxBytes) break;\n rendered.push(text);\n used += cost;\n }\n return rendered;\n}\n\ninterface Side {\n readonly text: string;\n readonly count: number;\n}\n\nfunction elisionMarker(elidedLines: number, salvagedCount = 0): string {\n const unit = elidedLines === 1 ? 'line' : 'lines';\n const errors = salvagedCount > 0 ? `, ${formatCount(salvagedCount)} shown below` : '';\n return `\\u2026 [${formatCount(elidedLines)} ${unit} elided${errors}] \\u2026`;\n}\n\nfunction splitTextLines(text: string): { lines: string[]; trailingNewline: boolean } {\n const trailingNewline = text.endsWith('\\n');\n const lines = text.split('\\n');\n if (trailingNewline) lines.pop();\n return { lines, trailingNewline };\n}\n\n/** Whole lines only: a fragment of a line reads as data that was never there. */\nfunction takeSide(\n lines: readonly string[],\n maxCount: number,\n maxBytes: number,\n fromEnd: boolean,\n maxTokens = Number.POSITIVE_INFINITY,\n): Side {\n if (maxBytes <= 0 || maxCount <= 0) return { text: '', count: 0 };\n const ordered = fromEnd ? [...lines].reverse() : [...lines];\n const taken: string[] = [];\n let used = 0;\n let tokens = 0;\n for (const line of ordered) {\n if (taken.length >= maxCount) break;\n const cost = Buffer.byteLength(line, 'utf8') + (taken.length > 0 ? 1 : 0);\n // Dense output costs far more context than its byte count implies, so the\n // token ceiling stops the side even while bytes remain. The separator is\n // charged too: summing per-line estimates otherwise drifts past the ceiling\n // once the newlines between them are counted.\n const lineTokens = estimateTokens(line) + (taken.length > 0 ? 1 : 0);\n if (used + cost > maxBytes || tokens + lineTokens > maxTokens) break;\n taken.push(line);\n used += cost;\n tokens += lineTokens;\n }\n if (taken.length === 0) return { text: '', count: 0 };\n const restored = fromEnd ? taken.reverse() : taken;\n return { text: restored.join('\\n'), count: restored.length };\n}\n\n/**\n * Used only when no whole line fits either side, which means the source has no\n * usable line boundary. A clamped fragment beats returning nothing at all.\n */\nfunction clampedFragment(text: string, limitBytes: number): Side {\n const clamped = utf8Tail(Buffer.from(text, 'utf8'), limitBytes);\n const newline = clamped.indexOf('\\n');\n const whole = newline >= 0 ? clamped.slice(newline + 1) : clamped;\n return { text: whole, count: whole.length > 0 ? 1 : 0 };\n}\n\n/** Charged against the budget so the composed excerpt still honours the ceiling. */\nfunction markerReservation(totalLines: number): number {\n return Buffer.byteLength(elisionMarker(totalLines), 'utf8') + 2;\n}\n\nfunction assembleSides(\n head: Side,\n tail: Side,\n elidedLines: number,\n trailingNewline: boolean,\n limitBytes: number,\n salvaged: readonly string[] = [],\n): Excerpt {\n const opening = elidedLines > 0 ? [elisionMarker(elidedLines, salvaged.length)] : [];\n const closing = elidedLines > 0 && salvaged.length > 0 ? ['\\u2026'] : [];\n const parts = [head.text, ...opening, ...salvaged, ...closing, tail.text].filter((part) => part.length > 0);\n const body = parts.join('\\n');\n const withNewline = trailingNewline && body.length > 0 ? `${body}\\n` : body;\n const encoded = Buffer.from(withNewline, 'utf8');\n // Last resort: the ceiling is a hard promise to the caller.\n const text = encoded.byteLength > limitBytes ? utf8Tail(encoded, limitBytes) : withNewline;\n return { text, lines: head.count + tail.count, truncated: true, elidedLines: Math.max(0, elidedLines) };\n}\n\nfunction budgetFor(maxLines: number, maxBytes: number, totalLines: number, maxTokens: number) {\n const limitLines = Math.max(1, Math.floor(maxLines));\n const usable = Math.max(0, maxBytes - markerReservation(totalLines));\n // The marker is charged against both ceilings; counting it in bytes alone let\n // the composed excerpt drift past the token ceiling.\n const tokens = Math.max(1, Math.floor(maxTokens) - estimateTokens(elisionMarker(totalLines)));\n return {\n limitLines,\n headLines: Math.max(1, Math.floor(limitLines * getHeadRatio())),\n headBytes: Math.max(0, Math.floor(usable * getHeadRatio())),\n headTokens: Math.max(1, Math.floor(tokens * getHeadRatio())),\n usable,\n tokens,\n };\n}\n\n/**\n * Bounds text to the budget, keeping a leading excerpt as well as the tail.\n *\n * Failures announce themselves at both ends: a command that could not start\n * says so on line one, and a command that died says so on the last. Keeping\n * only the tail loses the first kind entirely.\n */\nexport function boundExcerpt(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n if (text.length === 0) return { text: '', lines: 0, truncated: false, elidedLines: 0 };\n const { lines, trailingNewline } = splitTextLines(text);\n const totalBytes = Buffer.byteLength(text, 'utf8');\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : totalBytes;\n const limitLines = Math.max(1, Math.floor(maxLines));\n if (lines.length <= limitLines && totalBytes <= limitBytes && estimateTokens(text) <= maxTokens) {\n return { text, lines: lines.length, truncated: false, elidedLines: 0 };\n }\n\n const budget = budgetFor(maxLines, limitBytes, lines.length, maxTokens);\n const head = takeSide(lines, budget.headLines, budget.headBytes, false, budget.headTokens);\n const rest = lines.slice(head.count);\n // Reserved only when the region beyond the head actually holds errors, so a\n // clean run still spends the whole remaining budget on its tail.\n const errorBytes = rest.some(isErrorLine) ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(rest, Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(text, limitBytes);\n return { text: fragment.text, lines: fragment.count, truncated: true, elidedLines: lines.length - fragment.count };\n }\n const middle = lines.slice(head.count, lines.length - tail.count);\n const salvaged = errorBytes > 0 ? renderSalvaged(collectErrorLines(middle), errorBytes) : [];\n return assembleSides(head, tail, lines.length - head.count - tail.count, trailingNewline, limitBytes, salvaged);\n}\n\n/**\n * Same budget as `boundExcerpt`, for callers that streamed the two ends\n * separately and never held the middle. `totalLines` counts the whole source,\n * so the marker states what was dropped rather than what was captured.\n */\nexport function composeExcerpt(\n headSource: string,\n tailSource: string,\n totalLines: number,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n errors: readonly SalvagedError[] = [],\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : Number.MAX_SAFE_INTEGER;\n const budget = budgetFor(maxLines, limitBytes, totalLines, maxTokens);\n const headLines = splitTextLines(headSource).lines;\n const { lines: tailLines, trailingNewline } = splitTextLines(tailSource);\n // The line at each cut is a fragment of a line neither capture saw whole.\n const head = takeSide(\n headLines.slice(0, Math.max(0, headLines.length - 1)),\n budget.headLines,\n budget.headBytes,\n false,\n budget.headTokens,\n );\n const errorBytes = errors.length > 0 ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(tailLines.slice(1), Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(tailSource, limitBytes);\n return {\n text: fragment.text,\n lines: fragment.count,\n truncated: true,\n elidedLines: Math.max(0, totalLines - fragment.count),\n };\n }\n const salvaged = errorBytes > 0 ? renderSalvaged(errors, errorBytes) : [];\n return assembleSides(\n head,\n tail,\n Math.max(0, totalLines - head.count - tail.count),\n trailingNewline,\n limitBytes,\n salvaged,\n );\n}\n\n/** Applies Doom's line and byte ceilings to text already held in memory. */\nexport function summarizeText(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n): Pick<LogSummary, 'tail' | 'tailLines'> {\n const excerpt = boundExcerpt(text, maxLines, maxBytes);\n return { tail: excerpt.text, tailLines: excerpt.lines };\n}\n\n/** Bounds the complete model-facing result after status and recovery text are attached. */\nexport function boundResultText(text: string, maxBytes = getResultMaxBytes()): string {\n return boundExcerpt(text, getResultMaxLines(), maxBytes).text;\n}\n\n/**\n * Keeps both ends of an oversized result and points at the file holding the rest.\n *\n * The notice states the file's real size and line count so the model does not\n * guess at offsets when it goes on to read the file, which is the failure this\n * whole policy exists to prevent.\n */\n\nfunction utf8Tail(encoded: Buffer<ArrayBufferLike>, maxBytes: number): string {\n let start = Math.max(0, encoded.byteLength - maxBytes);\n while (start < encoded.byteLength && (encoded[start]! & 0xc0) === 0x80) start += 1;\n return encoded.subarray(start).toString('utf8');\n}\n\n/** `name pid 1234 up 3m sleep 60` — one runner per line. */\nexport function formatRunnerLine(record: RunnerRecord, now = Date.now()): string {\n const mode = record.interactive ? ' interactive' : '';\n return `${record.name} pid ${record.pid} up ${formatUptime(record.startedAt, now)}${mode} ${record.command}`;\n}\n\nexport function formatUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\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\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\nconst emptyLogSummary: LogSummarizer = () => ({ tail: '', bytes: 0, lines: 0, tailLines: 0 });\n\nexport function formatRunResult(\n result: BashRunResult,\n budget: ResultBudget = {},\n summarizeLog: LogSummarizer = emptyLogSummary,\n): 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 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 const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\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$/u, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\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 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 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 if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bashResult-CkTthslG.cjs","names":["getErrorMaxEntries","getErrorPatterns","getErrorMaxVariantsJoined","getHeadRatio","getResultMaxLines","getResultMaxBytes","getResultMaxTokens","getErrorBudgetRatio","getSuccessResultMaxBytes","getSuccessResultMaxTokens","stripAnsi"],"sources":["../src/constants/bashResult.ts","../src/constants/tokenEstimate.ts","../src/services/tokenEstimate/index.ts","../src/services/bashResult/index.ts"],"sourcesContent":["export const BYTES_PER_KB = 1024;\nexport const BYTES_PER_MB = 1_048_576;\nexport const MAX_VARIANTS_TRACKED = 12;\nexport const MIN_SHARED_AFFIX = 8;\nexport const ERROR_WINDOW_CHARS = 60;\nexport const PRAGMA_PATTERN = /^\\s*(?:#|\\/\\/)\\s*@doom:\\s*(\\{.*\\})\\s*$/u;\nexport const PRAGMA_BYTES_CEILING = 262_144;\nexport const PRAGMA_LINES_CEILING = 5_000;\nexport const PRAGMA_TOKENS_CEILING = 100_000;\n","export const WORD_CHARS_PER_TOKEN = 5;\nexport const MIXED_CHARS_PER_TOKEN = 2.1;\nexport const PUNCTUATION_CHARS_PER_TOKEN = 2;\nexport const DENSE_SCRIPT_START = 0x2fff;\nexport const ASTRAL_TOKEN_COST = 2;\nexport const ALPHANUMERIC_RUN = /([^\\p{L}\\p{N}]+)/u;\nexport const HAS_ALPHANUMERIC = /[\\p{L}\\p{N}]/u;\nexport const HAS_DIGIT = /\\d/u;\nexport const HAS_LETTER = /[A-Za-z]/u;\n","import {\n ALPHANUMERIC_RUN,\n ASTRAL_TOKEN_COST,\n DENSE_SCRIPT_START,\n HAS_ALPHANUMERIC,\n HAS_DIGIT,\n HAS_LETTER,\n MIXED_CHARS_PER_TOKEN,\n PUNCTUATION_CHARS_PER_TOKEN,\n WORD_CHARS_PER_TOKEN,\n} from '../../constants/tokenEstimate';\n/**\n * Estimates BPE tokens without carrying a vocabulary.\n *\n * Bytes are a poor proxy for what a result costs: measured against\n * `gpt-tokenizer`, real text ranges from 1.4 characters per token for base64 to\n * 4.7 for English prose, a spread of more than three. Truncation runs on every\n * command and is synchronous, so loading a real tokenizer here would charge\n * every session for a table most of them never need.\n *\n * The shape below follows how BPE actually behaves: punctuation forces token\n * boundaries, natural words are cheap, and runs mixing letters with digits are\n * expensive. Calibrated against `gpt-tokenizer` over build logs, source, JSON,\n * stack traces, CJK, base64, hex, and UUIDs, the worst error is a factor of\n * 1.46 either way. It stays an estimate, so the byte ceiling remains the hard\n * bound behind it.\n */\n\n/** Characters per token for a natural word. */\n/** Characters per token for a run mixing letters and digits, which tokenizes poorly. */\n/** Characters per token for a run of punctuation or whitespace. */\n/** Dense scripts such as CJK cost about one token per character. */\n\nexport function estimateTokens(text: string): number {\n let tokens = 0;\n for (const run of text.split(ALPHANUMERIC_RUN)) {\n if (run.length === 0) continue;\n if (!HAS_ALPHANUMERIC.test(run)) {\n tokens += run.length / PUNCTUATION_CHARS_PER_TOKEN;\n continue;\n }\n\n let ascii = 0;\n let dense = 0;\n let astral = 0;\n for (const character of run) {\n const code = character.codePointAt(0) ?? 0;\n if (code > 0xffff) astral += 1;\n else if (code > DENSE_SCRIPT_START) dense += 1;\n else ascii += 1;\n }\n tokens += astral * ASTRAL_TOKEN_COST + dense;\n if (ascii > 0) {\n const mixed = HAS_DIGIT.test(run) && HAS_LETTER.test(run);\n tokens += Math.max(1, ascii / (mixed ? MIXED_CHARS_PER_TOKEN : WORD_CHARS_PER_TOKEN));\n }\n }\n return Math.ceil(tokens);\n}\n","import {\n BYTES_PER_KB,\n BYTES_PER_MB,\n ERROR_WINDOW_CHARS,\n MAX_VARIANTS_TRACKED,\n MIN_SHARED_AFFIX,\n PRAGMA_BYTES_CEILING,\n PRAGMA_LINES_CEILING,\n PRAGMA_PATTERN,\n PRAGMA_TOKENS_CEILING,\n} from '../../constants/bashResult';\nimport type {\n ErrorLineScanner,\n Excerpt,\n LogSummarizer,\n LogSummary,\n ResultBudget,\n SalvagedError,\n ToolResult,\n} from '../../types/bashResult';\nimport type { BashRunResult, CompletedRun } from '../../types/bashRunService';\nimport type { RunnerRecord } from '../../types/runnerRegistry';\nimport { stripAnsi } from '../ansiScrub';\nimport {\n getErrorBudgetRatio,\n getErrorMaxEntries,\n getErrorMaxVariantsJoined,\n getErrorPatterns,\n getHeadRatio,\n getResultMaxBytes,\n getResultMaxLines,\n getResultMaxTokens,\n getSuccessResultMaxBytes,\n getSuccessResultMaxTokens,\n} from '../runnerConfig';\nimport { estimateTokens } from '../tokenEstimate';\n\n/** Variants retained per group while scanning; the rest only add to the count. */\n/** Below this much shared text, joining reads worse than separate lines. */\n/**\n * Severity anywhere in the opening of the line, not only at its start. Real\n * tooling buries it behind a tag or a timestamp: `[widget] build: error TS2322`.\n */\nconst SEVERITY_TOKEN =\n /(?<![\\w\\-/=.])(?:errors?|fatal|panic|exception|traceback|assertion|assert|fail(?:ed|ure|ures)?)\\b/iu;\n/** `0 errors` and `no failures` are the success case wearing the same words. */\nconst NEGATED_SEVERITY = /\\b(?:no|not|without|zero|0)\\s+$/iu;\n\nexport function textResult(text: string, details: Record<string, unknown> = {}): ToolResult {\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function errorResult(message: string): ToolResult {\n return textResult(`Error: ${message}`, { error: message });\n}\n\n/** Human-readable byte count, matching how pi reports output sizes. */\nexport function formatSize(bytes: number): string {\n if (bytes < BYTES_PER_KB) return `${bytes} B`;\n if (bytes < BYTES_PER_MB) return `${(bytes / BYTES_PER_KB).toFixed(1)} KB`;\n return `${(bytes / BYTES_PER_MB).toFixed(1)} MB`;\n}\n\nfunction formatCount(value: number): string {\n return value.toLocaleString('en-US');\n}\n\nexport function countLines(text: string): number {\n if (text.length === 0) return 0;\n return text.endsWith('\\n') ? text.split('\\n').length - 1 : text.split('\\n').length;\n}\n\n/** Accumulates grouped error lines while a log streams past, without holding it. */\nclass ErrorScan {\n private readonly byKey = new Map<string, { variants: string[]; count: number }>();\n\n constructor(private readonly maxEntries = getErrorMaxEntries()) {}\n\n push(line: string): void {\n if (!isErrorLine(line)) return;\n const trimmed = line.trim();\n const key = normalizeErrorLine(line);\n const existing = this.byKey.get(key);\n if (existing) {\n existing.count += 1;\n // Only a line we have not seen verbatim earns a slot; identical repeats\n // are carried by the count alone.\n if (!existing.variants.includes(trimmed) && existing.variants.length < MAX_VARIANTS_TRACKED) {\n existing.variants.push(trimmed);\n }\n return;\n }\n if (this.byKey.size >= this.maxEntries) return;\n this.byKey.set(key, { variants: [trimmed], count: 1 });\n }\n\n entries(): SalvagedError[] {\n return [...this.byKey.values()];\n }\n}\n\nexport function createErrorScanner(maxEntries = getErrorMaxEntries()): ErrorLineScanner {\n return new ErrorScan(maxEntries);\n}\n\n/** Codex-style first-line pragma, for the one command that needs a wider result. */\n\nfunction positiveInteger(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;\n}\n\n/**\n * Reads `# @doom: {\"maxResultBytes\": 32768}` from the command's first line.\n *\n * The pragma is a shell comment, so it stays harmless if this parse is ever\n * skipped, and it survives verbatim into the log where a wider result can be\n * explained after the fact.\n */\nexport function parseResultPragma(command: string): ResultBudget {\n const match = PRAGMA_PATTERN.exec(command.split('\\n', 1)[0] ?? '');\n if (!match?.[1]) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(match[1]);\n } catch {\n return {};\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n\n const source = parsed as Record<string, unknown>;\n const maxBytes = positiveInteger(source.maxResultBytes);\n const maxLines = positiveInteger(source.maxResultLines);\n const maxTokens = positiveInteger(source.maxResultTokens);\n return {\n ...(maxBytes === undefined ? {} : { maxBytes: Math.min(maxBytes, PRAGMA_BYTES_CEILING) }),\n ...(maxLines === undefined ? {} : { maxLines: Math.min(maxLines, PRAGMA_LINES_CEILING) }),\n ...(maxTokens === undefined ? {} : { maxTokens: Math.min(maxTokens, PRAGMA_TOKENS_CEILING) }),\n };\n}\n\nfunction isErrorLine(line: string): boolean {\n const opening = line.slice(0, ERROR_WINDOW_CHARS);\n const match = SEVERITY_TOKEN.exec(opening);\n if (match && !NEGATED_SEVERITY.test(opening.slice(0, match.index))) return true;\n // Project patterns extend the built-in matcher; tooling this does not\n // recognise is exactly why they exist, so they are not negation-checked.\n return getErrorPatterns().some((pattern) => matchesCustomPattern(pattern, line));\n}\n\nconst customPatterns = new Map<string, RegExp | undefined>();\n\nfunction matchesCustomPattern(pattern: string, line: string): boolean {\n if (!customPatterns.has(pattern)) {\n try {\n customPatterns.set(pattern, new RegExp(pattern, 'iu'));\n } catch {\n customPatterns.set(pattern, undefined);\n }\n }\n return customPatterns.get(pattern)?.test(line) ?? false;\n}\n\n/** Masks the parts that differ between repeats of the same underlying failure. */\nfunction normalizeErrorLine(line: string): string {\n return line\n .replace(/0x[0-9a-f]+/giu, '0x#')\n .replace(/\\/[^\\s:,)]+/gu, '/#')\n .replace(/\\d+/gu, '#')\n .trim()\n .toLowerCase();\n}\n\n/**\n * Collapses repeats so one failure repeated two hundred times costs one slot.\n * Counting continues past the entry cap so the tallies stay honest.\n */\nexport function collectErrorLines(lines: Iterable<string>, maxEntries = getErrorMaxEntries()): SalvagedError[] {\n const scan = new ErrorScan(maxEntries);\n for (const line of lines) scan.push(line);\n return scan.entries();\n}\n\nfunction commonAffixLengths(values: readonly string[]): { prefix: number; suffix: number } {\n const shortest = values.reduce((min, value) => Math.min(min, value.length), Infinity);\n let prefix = 0;\n while (prefix < shortest && values.every((value) => value[prefix] === values[0]![prefix])) prefix += 1;\n let suffix = 0;\n while (\n suffix < shortest - prefix &&\n values.every((value) => value[value.length - 1 - suffix] === values[0]![values[0]!.length - 1 - suffix])\n ) {\n suffix += 1;\n }\n return { prefix, suffix };\n}\n\n/** Back off to a whitespace boundary so the brackets hold whole tokens. */\nfunction retreatToBoundary(value: string, length: number): number {\n const boundary = value.lastIndexOf(' ', Math.max(0, length - 1));\n return boundary >= 0 ? boundary + 1 : 0;\n}\n\nfunction advanceToBoundary(value: string, length: number): number {\n const cut = value.length - length;\n const boundary = value.indexOf(' ', cut);\n return boundary >= 0 ? value.length - boundary : 0;\n}\n\n/**\n * One line per distinct failure would be ideal, but repeats of one failure\n * across many files are the common case. Sharing the fixed text and joining\n * only the parts that differ keeps every file name without paying for the\n * message N times.\n */\nfunction renderGroup(group: SalvagedError): string {\n const [first] = group.variants;\n if (first === undefined) return '';\n if (group.variants.length === 1) {\n return group.count > 1 ? `${first} (\\u00d7${formatCount(group.count)})` : first;\n }\n\n const shown = group.variants.slice(0, getErrorMaxVariantsJoined());\n const { prefix, suffix } = commonAffixLengths(shown);\n const head = first.slice(0, retreatToBoundary(first, prefix));\n const tailLength = advanceToBoundary(first, suffix);\n const tail = tailLength > 0 ? first.slice(first.length - tailLength) : '';\n if (head.length + tail.length < MIN_SHARED_AFFIX) return shown.join('\\n');\n\n const middles = shown.map((value) => value.slice(head.length, value.length - tail.length));\n const overflow = group.variants.length - shown.length;\n const joined = overflow > 0 ? `${middles.join('|')}|+${formatCount(overflow)}` : middles.join('|');\n return `${head}[${joined}]${tail}`;\n}\n\nfunction renderSalvaged(errors: readonly SalvagedError[], maxBytes: number): string[] {\n const rendered: string[] = [];\n let used = 0;\n for (const group of errors) {\n const text = renderGroup(group);\n if (text.length === 0) continue;\n const cost = Buffer.byteLength(text, 'utf8') + 1;\n if (used + cost > maxBytes) break;\n rendered.push(text);\n used += cost;\n }\n return rendered;\n}\n\ninterface Side {\n readonly text: string;\n readonly count: number;\n}\n\nfunction elisionMarker(elidedLines: number, salvagedCount = 0): string {\n const unit = elidedLines === 1 ? 'line' : 'lines';\n const errors = salvagedCount > 0 ? `, ${formatCount(salvagedCount)} shown below` : '';\n return `\\u2026 [${formatCount(elidedLines)} ${unit} elided${errors}] \\u2026`;\n}\n\nfunction splitTextLines(text: string): { lines: string[]; trailingNewline: boolean } {\n const trailingNewline = text.endsWith('\\n');\n const lines = text.split('\\n');\n if (trailingNewline) lines.pop();\n return { lines, trailingNewline };\n}\n\n/** Whole lines only: a fragment of a line reads as data that was never there. */\nfunction takeSide(\n lines: readonly string[],\n maxCount: number,\n maxBytes: number,\n fromEnd: boolean,\n maxTokens = Number.POSITIVE_INFINITY,\n): Side {\n if (maxBytes <= 0 || maxCount <= 0) return { text: '', count: 0 };\n const ordered = fromEnd ? [...lines].reverse() : [...lines];\n const taken: string[] = [];\n let used = 0;\n let tokens = 0;\n for (const line of ordered) {\n if (taken.length >= maxCount) break;\n const cost = Buffer.byteLength(line, 'utf8') + (taken.length > 0 ? 1 : 0);\n // Dense output costs far more context than its byte count implies, so the\n // token ceiling stops the side even while bytes remain. The separator is\n // charged too: summing per-line estimates otherwise drifts past the ceiling\n // once the newlines between them are counted.\n const lineTokens = estimateTokens(line) + (taken.length > 0 ? 1 : 0);\n if (used + cost > maxBytes || tokens + lineTokens > maxTokens) break;\n taken.push(line);\n used += cost;\n tokens += lineTokens;\n }\n if (taken.length === 0) return { text: '', count: 0 };\n const restored = fromEnd ? taken.reverse() : taken;\n return { text: restored.join('\\n'), count: restored.length };\n}\n\n/**\n * Used only when no whole line fits either side, which means the source has no\n * usable line boundary. A clamped fragment beats returning nothing at all.\n */\nfunction clampedFragment(text: string, limitBytes: number): Side {\n const clamped = utf8Tail(Buffer.from(text, 'utf8'), limitBytes);\n const newline = clamped.indexOf('\\n');\n const whole = newline >= 0 ? clamped.slice(newline + 1) : clamped;\n return { text: whole, count: whole.length > 0 ? 1 : 0 };\n}\n\n/** Charged against the budget so the composed excerpt still honours the ceiling. */\nfunction markerReservation(totalLines: number): number {\n return Buffer.byteLength(elisionMarker(totalLines), 'utf8') + 2;\n}\n\nfunction assembleSides(\n head: Side,\n tail: Side,\n elidedLines: number,\n trailingNewline: boolean,\n limitBytes: number,\n salvaged: readonly string[] = [],\n): Excerpt {\n const opening = elidedLines > 0 ? [elisionMarker(elidedLines, salvaged.length)] : [];\n const closing = elidedLines > 0 && salvaged.length > 0 ? ['\\u2026'] : [];\n const parts = [head.text, ...opening, ...salvaged, ...closing, tail.text].filter((part) => part.length > 0);\n const body = parts.join('\\n');\n const withNewline = trailingNewline && body.length > 0 ? `${body}\\n` : body;\n const encoded = Buffer.from(withNewline, 'utf8');\n // Last resort: the ceiling is a hard promise to the caller.\n const text = encoded.byteLength > limitBytes ? utf8Tail(encoded, limitBytes) : withNewline;\n return { text, lines: head.count + tail.count, truncated: true, elidedLines: Math.max(0, elidedLines) };\n}\n\nfunction budgetFor(maxLines: number, maxBytes: number, totalLines: number, maxTokens: number) {\n const limitLines = Math.max(1, Math.floor(maxLines));\n const usable = Math.max(0, maxBytes - markerReservation(totalLines));\n // The marker is charged against both ceilings; counting it in bytes alone let\n // the composed excerpt drift past the token ceiling.\n const tokens = Math.max(1, Math.floor(maxTokens) - estimateTokens(elisionMarker(totalLines)));\n return {\n limitLines,\n headLines: Math.max(1, Math.floor(limitLines * getHeadRatio())),\n headBytes: Math.max(0, Math.floor(usable * getHeadRatio())),\n headTokens: Math.max(1, Math.floor(tokens * getHeadRatio())),\n usable,\n tokens,\n };\n}\n\n/**\n * Bounds text to the budget, keeping a leading excerpt as well as the tail.\n *\n * Failures announce themselves at both ends: a command that could not start\n * says so on line one, and a command that died says so on the last. Keeping\n * only the tail loses the first kind entirely.\n */\nexport function boundExcerpt(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n if (text.length === 0) return { text: '', lines: 0, truncated: false, elidedLines: 0 };\n const { lines, trailingNewline } = splitTextLines(text);\n const totalBytes = Buffer.byteLength(text, 'utf8');\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : totalBytes;\n const limitLines = Math.max(1, Math.floor(maxLines));\n if (lines.length <= limitLines && totalBytes <= limitBytes && estimateTokens(text) <= maxTokens) {\n return { text, lines: lines.length, truncated: false, elidedLines: 0 };\n }\n\n const budget = budgetFor(maxLines, limitBytes, lines.length, maxTokens);\n const head = takeSide(lines, budget.headLines, budget.headBytes, false, budget.headTokens);\n const rest = lines.slice(head.count);\n // Reserved only when the region beyond the head actually holds errors, so a\n // clean run still spends the whole remaining budget on its tail.\n const errorBytes = rest.some(isErrorLine) ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(rest, Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(text, limitBytes);\n return { text: fragment.text, lines: fragment.count, truncated: true, elidedLines: lines.length - fragment.count };\n }\n const middle = lines.slice(head.count, lines.length - tail.count);\n const salvaged = errorBytes > 0 ? renderSalvaged(collectErrorLines(middle), errorBytes) : [];\n return assembleSides(head, tail, lines.length - head.count - tail.count, trailingNewline, limitBytes, salvaged);\n}\n\n/**\n * Same budget as `boundExcerpt`, for callers that streamed the two ends\n * separately and never held the middle. `totalLines` counts the whole source,\n * so the marker states what was dropped rather than what was captured.\n */\nexport function composeExcerpt(\n headSource: string,\n tailSource: string,\n totalLines: number,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n errors: readonly SalvagedError[] = [],\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : Number.MAX_SAFE_INTEGER;\n const budget = budgetFor(maxLines, limitBytes, totalLines, maxTokens);\n const headLines = splitTextLines(headSource).lines;\n const { lines: tailLines, trailingNewline } = splitTextLines(tailSource);\n // The line at each cut is a fragment of a line neither capture saw whole.\n const head = takeSide(\n headLines.slice(0, Math.max(0, headLines.length - 1)),\n budget.headLines,\n budget.headBytes,\n false,\n budget.headTokens,\n );\n const errorBytes = errors.length > 0 ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(tailLines.slice(1), Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(tailSource, limitBytes);\n return {\n text: fragment.text,\n lines: fragment.count,\n truncated: true,\n elidedLines: Math.max(0, totalLines - fragment.count),\n };\n }\n const salvaged = errorBytes > 0 ? renderSalvaged(errors, errorBytes) : [];\n return assembleSides(\n head,\n tail,\n Math.max(0, totalLines - head.count - tail.count),\n trailingNewline,\n limitBytes,\n salvaged,\n );\n}\n\n/** Applies Doom's line and byte ceilings to text already held in memory. */\nexport function summarizeText(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n): Pick<LogSummary, 'tail' | 'tailLines'> {\n const excerpt = boundExcerpt(text, maxLines, maxBytes);\n return { tail: excerpt.text, tailLines: excerpt.lines };\n}\n\n/** Bounds the complete model-facing result after status and recovery text are attached. */\nexport function boundResultText(text: string, maxBytes = getResultMaxBytes()): string {\n return boundExcerpt(text, getResultMaxLines(), maxBytes).text;\n}\n\n/**\n * Keeps both ends of an oversized result and points at the file holding the rest.\n *\n * The notice states the file's real size and line count so the model does not\n * guess at offsets when it goes on to read the file, which is the failure this\n * whole policy exists to prevent.\n */\n\nfunction utf8Tail(encoded: Buffer<ArrayBufferLike>, maxBytes: number): string {\n let start = Math.max(0, encoded.byteLength - maxBytes);\n while (start < encoded.byteLength && (encoded[start]! & 0xc0) === 0x80) start += 1;\n return encoded.subarray(start).toString('utf8');\n}\n\n/** `name pid 1234 up 3m sleep 60` — one runner per line. */\nexport function formatRunnerLine(record: RunnerRecord, now = Date.now()): string {\n const mode = record.interactive ? ' interactive' : '';\n return `${record.name} pid ${record.pid} up ${formatUptime(record.startedAt, now)}${mode} ${record.command}`;\n}\n\nexport function formatUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\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\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\nconst emptyLogSummary: LogSummarizer = () => ({ tail: '', bytes: 0, lines: 0, tailLines: 0 });\n\nexport function formatRunResult(\n result: BashRunResult,\n budget: ResultBudget = {},\n summarizeLog: LogSummarizer = emptyLogSummary,\n): 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 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 const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\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$/u, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\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 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 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 if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { i as stripAnsi } from "./ansiScrub-CsqTSaVT.mjs";
2
- import { a as getErrorPatterns, d as getResultMaxLines, f as getResultMaxTokens, h as getSuccessResultMaxTokens, i as getErrorMaxVariantsJoined, m as getSuccessResultMaxBytes, n as getErrorBudgetRatio, o as getHeadRatio, r as getErrorMaxEntries, u as getResultMaxBytes } from "./runnerConfig-D1OoyRo0.mjs";
2
+ import { a as getErrorPatterns, d as getResultMaxLines, f as getResultMaxTokens, h as getSuccessResultMaxTokens, i as getErrorMaxVariantsJoined, m as getSuccessResultMaxBytes, n as getErrorBudgetRatio, o as getHeadRatio, r as getErrorMaxEntries, u as getResultMaxBytes } from "./runnerConfig-BamWjxBH.mjs";
3
3
  //#region src/constants/bashResult.ts
4
4
  const BYTES_PER_KB = 1024;
5
5
  const BYTES_PER_MB = 1048576;
@@ -541,4 +541,4 @@ function formatRunResult(result, budget = {}, summarizeLog = emptyLogSummary) {
541
541
  //#endregion
542
542
  export { countLines as a, formatRunResult as c, formatUptime as d, parseResultPragma as f, BYTES_PER_MB as g, BYTES_PER_KB as h, composeExcerpt as i, formatRunnerLine as l, textResult as m, boundResultText as n, createErrorScanner as o, summarizeText as p, collectErrorLines as r, errorResult as s, boundExcerpt as t, formatSize as u };
543
543
 
544
- //# sourceMappingURL=bashResult-BKLi1Zpx.mjs.map
544
+ //# sourceMappingURL=bashResult-DhbolCo5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bashResult-BKLi1Zpx.mjs","names":[],"sources":["../src/constants/bashResult.ts","../src/constants/tokenEstimate.ts","../src/services/tokenEstimate/index.ts","../src/services/bashResult/index.ts"],"sourcesContent":["export const BYTES_PER_KB = 1024;\nexport const BYTES_PER_MB = 1_048_576;\nexport const MAX_VARIANTS_TRACKED = 12;\nexport const MIN_SHARED_AFFIX = 8;\nexport const ERROR_WINDOW_CHARS = 60;\nexport const PRAGMA_PATTERN = /^\\s*(?:#|\\/\\/)\\s*@doom:\\s*(\\{.*\\})\\s*$/u;\nexport const PRAGMA_BYTES_CEILING = 262_144;\nexport const PRAGMA_LINES_CEILING = 5_000;\nexport const PRAGMA_TOKENS_CEILING = 100_000;\n","export const WORD_CHARS_PER_TOKEN = 5;\nexport const MIXED_CHARS_PER_TOKEN = 2.1;\nexport const PUNCTUATION_CHARS_PER_TOKEN = 2;\nexport const DENSE_SCRIPT_START = 0x2fff;\nexport const ASTRAL_TOKEN_COST = 2;\nexport const ALPHANUMERIC_RUN = /([^\\p{L}\\p{N}]+)/u;\nexport const HAS_ALPHANUMERIC = /[\\p{L}\\p{N}]/u;\nexport const HAS_DIGIT = /\\d/u;\nexport const HAS_LETTER = /[A-Za-z]/u;\n","import {\n ALPHANUMERIC_RUN,\n ASTRAL_TOKEN_COST,\n DENSE_SCRIPT_START,\n HAS_ALPHANUMERIC,\n HAS_DIGIT,\n HAS_LETTER,\n MIXED_CHARS_PER_TOKEN,\n PUNCTUATION_CHARS_PER_TOKEN,\n WORD_CHARS_PER_TOKEN,\n} from '../../constants/tokenEstimate';\n/**\n * Estimates BPE tokens without carrying a vocabulary.\n *\n * Bytes are a poor proxy for what a result costs: measured against\n * `gpt-tokenizer`, real text ranges from 1.4 characters per token for base64 to\n * 4.7 for English prose, a spread of more than three. Truncation runs on every\n * command and is synchronous, so loading a real tokenizer here would charge\n * every session for a table most of them never need.\n *\n * The shape below follows how BPE actually behaves: punctuation forces token\n * boundaries, natural words are cheap, and runs mixing letters with digits are\n * expensive. Calibrated against `gpt-tokenizer` over build logs, source, JSON,\n * stack traces, CJK, base64, hex, and UUIDs, the worst error is a factor of\n * 1.46 either way. It stays an estimate, so the byte ceiling remains the hard\n * bound behind it.\n */\n\n/** Characters per token for a natural word. */\n/** Characters per token for a run mixing letters and digits, which tokenizes poorly. */\n/** Characters per token for a run of punctuation or whitespace. */\n/** Dense scripts such as CJK cost about one token per character. */\n\nexport function estimateTokens(text: string): number {\n let tokens = 0;\n for (const run of text.split(ALPHANUMERIC_RUN)) {\n if (run.length === 0) continue;\n if (!HAS_ALPHANUMERIC.test(run)) {\n tokens += run.length / PUNCTUATION_CHARS_PER_TOKEN;\n continue;\n }\n\n let ascii = 0;\n let dense = 0;\n let astral = 0;\n for (const character of run) {\n const code = character.codePointAt(0) ?? 0;\n if (code > 0xffff) astral += 1;\n else if (code > DENSE_SCRIPT_START) dense += 1;\n else ascii += 1;\n }\n tokens += astral * ASTRAL_TOKEN_COST + dense;\n if (ascii > 0) {\n const mixed = HAS_DIGIT.test(run) && HAS_LETTER.test(run);\n tokens += Math.max(1, ascii / (mixed ? MIXED_CHARS_PER_TOKEN : WORD_CHARS_PER_TOKEN));\n }\n }\n return Math.ceil(tokens);\n}\n","import {\n BYTES_PER_KB,\n BYTES_PER_MB,\n ERROR_WINDOW_CHARS,\n MAX_VARIANTS_TRACKED,\n MIN_SHARED_AFFIX,\n PRAGMA_BYTES_CEILING,\n PRAGMA_LINES_CEILING,\n PRAGMA_PATTERN,\n PRAGMA_TOKENS_CEILING,\n} from '../../constants/bashResult';\nimport type {\n ErrorLineScanner,\n Excerpt,\n LogSummarizer,\n LogSummary,\n ResultBudget,\n SalvagedError,\n ToolResult,\n} from '../../types/bashResult';\nimport type { BashRunResult, CompletedRun } from '../../types/bashRunService';\nimport type { RunnerRecord } from '../../types/runnerRegistry';\nimport { stripAnsi } from '../ansiScrub';\nimport {\n getErrorBudgetRatio,\n getErrorMaxEntries,\n getErrorMaxVariantsJoined,\n getErrorPatterns,\n getHeadRatio,\n getResultMaxBytes,\n getResultMaxLines,\n getResultMaxTokens,\n getSuccessResultMaxBytes,\n getSuccessResultMaxTokens,\n} from '../runnerConfig';\nimport { estimateTokens } from '../tokenEstimate';\n\n/** Variants retained per group while scanning; the rest only add to the count. */\n/** Below this much shared text, joining reads worse than separate lines. */\n/**\n * Severity anywhere in the opening of the line, not only at its start. Real\n * tooling buries it behind a tag or a timestamp: `[widget] build: error TS2322`.\n */\nconst SEVERITY_TOKEN =\n /(?<![\\w\\-/=.])(?:errors?|fatal|panic|exception|traceback|assertion|assert|fail(?:ed|ure|ures)?)\\b/iu;\n/** `0 errors` and `no failures` are the success case wearing the same words. */\nconst NEGATED_SEVERITY = /\\b(?:no|not|without|zero|0)\\s+$/iu;\n\nexport function textResult(text: string, details: Record<string, unknown> = {}): ToolResult {\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function errorResult(message: string): ToolResult {\n return textResult(`Error: ${message}`, { error: message });\n}\n\n/** Human-readable byte count, matching how pi reports output sizes. */\nexport function formatSize(bytes: number): string {\n if (bytes < BYTES_PER_KB) return `${bytes} B`;\n if (bytes < BYTES_PER_MB) return `${(bytes / BYTES_PER_KB).toFixed(1)} KB`;\n return `${(bytes / BYTES_PER_MB).toFixed(1)} MB`;\n}\n\nfunction formatCount(value: number): string {\n return value.toLocaleString('en-US');\n}\n\nexport function countLines(text: string): number {\n if (text.length === 0) return 0;\n return text.endsWith('\\n') ? text.split('\\n').length - 1 : text.split('\\n').length;\n}\n\n/** Accumulates grouped error lines while a log streams past, without holding it. */\nclass ErrorScan {\n private readonly byKey = new Map<string, { variants: string[]; count: number }>();\n\n constructor(private readonly maxEntries = getErrorMaxEntries()) {}\n\n push(line: string): void {\n if (!isErrorLine(line)) return;\n const trimmed = line.trim();\n const key = normalizeErrorLine(line);\n const existing = this.byKey.get(key);\n if (existing) {\n existing.count += 1;\n // Only a line we have not seen verbatim earns a slot; identical repeats\n // are carried by the count alone.\n if (!existing.variants.includes(trimmed) && existing.variants.length < MAX_VARIANTS_TRACKED) {\n existing.variants.push(trimmed);\n }\n return;\n }\n if (this.byKey.size >= this.maxEntries) return;\n this.byKey.set(key, { variants: [trimmed], count: 1 });\n }\n\n entries(): SalvagedError[] {\n return [...this.byKey.values()];\n }\n}\n\nexport function createErrorScanner(maxEntries = getErrorMaxEntries()): ErrorLineScanner {\n return new ErrorScan(maxEntries);\n}\n\n/** Codex-style first-line pragma, for the one command that needs a wider result. */\n\nfunction positiveInteger(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;\n}\n\n/**\n * Reads `# @doom: {\"maxResultBytes\": 32768}` from the command's first line.\n *\n * The pragma is a shell comment, so it stays harmless if this parse is ever\n * skipped, and it survives verbatim into the log where a wider result can be\n * explained after the fact.\n */\nexport function parseResultPragma(command: string): ResultBudget {\n const match = PRAGMA_PATTERN.exec(command.split('\\n', 1)[0] ?? '');\n if (!match?.[1]) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(match[1]);\n } catch {\n return {};\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n\n const source = parsed as Record<string, unknown>;\n const maxBytes = positiveInteger(source.maxResultBytes);\n const maxLines = positiveInteger(source.maxResultLines);\n const maxTokens = positiveInteger(source.maxResultTokens);\n return {\n ...(maxBytes === undefined ? {} : { maxBytes: Math.min(maxBytes, PRAGMA_BYTES_CEILING) }),\n ...(maxLines === undefined ? {} : { maxLines: Math.min(maxLines, PRAGMA_LINES_CEILING) }),\n ...(maxTokens === undefined ? {} : { maxTokens: Math.min(maxTokens, PRAGMA_TOKENS_CEILING) }),\n };\n}\n\nfunction isErrorLine(line: string): boolean {\n const opening = line.slice(0, ERROR_WINDOW_CHARS);\n const match = SEVERITY_TOKEN.exec(opening);\n if (match && !NEGATED_SEVERITY.test(opening.slice(0, match.index))) return true;\n // Project patterns extend the built-in matcher; tooling this does not\n // recognise is exactly why they exist, so they are not negation-checked.\n return getErrorPatterns().some((pattern) => matchesCustomPattern(pattern, line));\n}\n\nconst customPatterns = new Map<string, RegExp | undefined>();\n\nfunction matchesCustomPattern(pattern: string, line: string): boolean {\n if (!customPatterns.has(pattern)) {\n try {\n customPatterns.set(pattern, new RegExp(pattern, 'iu'));\n } catch {\n customPatterns.set(pattern, undefined);\n }\n }\n return customPatterns.get(pattern)?.test(line) ?? false;\n}\n\n/** Masks the parts that differ between repeats of the same underlying failure. */\nfunction normalizeErrorLine(line: string): string {\n return line\n .replace(/0x[0-9a-f]+/giu, '0x#')\n .replace(/\\/[^\\s:,)]+/gu, '/#')\n .replace(/\\d+/gu, '#')\n .trim()\n .toLowerCase();\n}\n\n/**\n * Collapses repeats so one failure repeated two hundred times costs one slot.\n * Counting continues past the entry cap so the tallies stay honest.\n */\nexport function collectErrorLines(lines: Iterable<string>, maxEntries = getErrorMaxEntries()): SalvagedError[] {\n const scan = new ErrorScan(maxEntries);\n for (const line of lines) scan.push(line);\n return scan.entries();\n}\n\nfunction commonAffixLengths(values: readonly string[]): { prefix: number; suffix: number } {\n const shortest = values.reduce((min, value) => Math.min(min, value.length), Infinity);\n let prefix = 0;\n while (prefix < shortest && values.every((value) => value[prefix] === values[0]![prefix])) prefix += 1;\n let suffix = 0;\n while (\n suffix < shortest - prefix &&\n values.every((value) => value[value.length - 1 - suffix] === values[0]![values[0]!.length - 1 - suffix])\n ) {\n suffix += 1;\n }\n return { prefix, suffix };\n}\n\n/** Back off to a whitespace boundary so the brackets hold whole tokens. */\nfunction retreatToBoundary(value: string, length: number): number {\n const boundary = value.lastIndexOf(' ', Math.max(0, length - 1));\n return boundary >= 0 ? boundary + 1 : 0;\n}\n\nfunction advanceToBoundary(value: string, length: number): number {\n const cut = value.length - length;\n const boundary = value.indexOf(' ', cut);\n return boundary >= 0 ? value.length - boundary : 0;\n}\n\n/**\n * One line per distinct failure would be ideal, but repeats of one failure\n * across many files are the common case. Sharing the fixed text and joining\n * only the parts that differ keeps every file name without paying for the\n * message N times.\n */\nfunction renderGroup(group: SalvagedError): string {\n const [first] = group.variants;\n if (first === undefined) return '';\n if (group.variants.length === 1) {\n return group.count > 1 ? `${first} (\\u00d7${formatCount(group.count)})` : first;\n }\n\n const shown = group.variants.slice(0, getErrorMaxVariantsJoined());\n const { prefix, suffix } = commonAffixLengths(shown);\n const head = first.slice(0, retreatToBoundary(first, prefix));\n const tailLength = advanceToBoundary(first, suffix);\n const tail = tailLength > 0 ? first.slice(first.length - tailLength) : '';\n if (head.length + tail.length < MIN_SHARED_AFFIX) return shown.join('\\n');\n\n const middles = shown.map((value) => value.slice(head.length, value.length - tail.length));\n const overflow = group.variants.length - shown.length;\n const joined = overflow > 0 ? `${middles.join('|')}|+${formatCount(overflow)}` : middles.join('|');\n return `${head}[${joined}]${tail}`;\n}\n\nfunction renderSalvaged(errors: readonly SalvagedError[], maxBytes: number): string[] {\n const rendered: string[] = [];\n let used = 0;\n for (const group of errors) {\n const text = renderGroup(group);\n if (text.length === 0) continue;\n const cost = Buffer.byteLength(text, 'utf8') + 1;\n if (used + cost > maxBytes) break;\n rendered.push(text);\n used += cost;\n }\n return rendered;\n}\n\ninterface Side {\n readonly text: string;\n readonly count: number;\n}\n\nfunction elisionMarker(elidedLines: number, salvagedCount = 0): string {\n const unit = elidedLines === 1 ? 'line' : 'lines';\n const errors = salvagedCount > 0 ? `, ${formatCount(salvagedCount)} shown below` : '';\n return `\\u2026 [${formatCount(elidedLines)} ${unit} elided${errors}] \\u2026`;\n}\n\nfunction splitTextLines(text: string): { lines: string[]; trailingNewline: boolean } {\n const trailingNewline = text.endsWith('\\n');\n const lines = text.split('\\n');\n if (trailingNewline) lines.pop();\n return { lines, trailingNewline };\n}\n\n/** Whole lines only: a fragment of a line reads as data that was never there. */\nfunction takeSide(\n lines: readonly string[],\n maxCount: number,\n maxBytes: number,\n fromEnd: boolean,\n maxTokens = Number.POSITIVE_INFINITY,\n): Side {\n if (maxBytes <= 0 || maxCount <= 0) return { text: '', count: 0 };\n const ordered = fromEnd ? [...lines].reverse() : [...lines];\n const taken: string[] = [];\n let used = 0;\n let tokens = 0;\n for (const line of ordered) {\n if (taken.length >= maxCount) break;\n const cost = Buffer.byteLength(line, 'utf8') + (taken.length > 0 ? 1 : 0);\n // Dense output costs far more context than its byte count implies, so the\n // token ceiling stops the side even while bytes remain. The separator is\n // charged too: summing per-line estimates otherwise drifts past the ceiling\n // once the newlines between them are counted.\n const lineTokens = estimateTokens(line) + (taken.length > 0 ? 1 : 0);\n if (used + cost > maxBytes || tokens + lineTokens > maxTokens) break;\n taken.push(line);\n used += cost;\n tokens += lineTokens;\n }\n if (taken.length === 0) return { text: '', count: 0 };\n const restored = fromEnd ? taken.reverse() : taken;\n return { text: restored.join('\\n'), count: restored.length };\n}\n\n/**\n * Used only when no whole line fits either side, which means the source has no\n * usable line boundary. A clamped fragment beats returning nothing at all.\n */\nfunction clampedFragment(text: string, limitBytes: number): Side {\n const clamped = utf8Tail(Buffer.from(text, 'utf8'), limitBytes);\n const newline = clamped.indexOf('\\n');\n const whole = newline >= 0 ? clamped.slice(newline + 1) : clamped;\n return { text: whole, count: whole.length > 0 ? 1 : 0 };\n}\n\n/** Charged against the budget so the composed excerpt still honours the ceiling. */\nfunction markerReservation(totalLines: number): number {\n return Buffer.byteLength(elisionMarker(totalLines), 'utf8') + 2;\n}\n\nfunction assembleSides(\n head: Side,\n tail: Side,\n elidedLines: number,\n trailingNewline: boolean,\n limitBytes: number,\n salvaged: readonly string[] = [],\n): Excerpt {\n const opening = elidedLines > 0 ? [elisionMarker(elidedLines, salvaged.length)] : [];\n const closing = elidedLines > 0 && salvaged.length > 0 ? ['\\u2026'] : [];\n const parts = [head.text, ...opening, ...salvaged, ...closing, tail.text].filter((part) => part.length > 0);\n const body = parts.join('\\n');\n const withNewline = trailingNewline && body.length > 0 ? `${body}\\n` : body;\n const encoded = Buffer.from(withNewline, 'utf8');\n // Last resort: the ceiling is a hard promise to the caller.\n const text = encoded.byteLength > limitBytes ? utf8Tail(encoded, limitBytes) : withNewline;\n return { text, lines: head.count + tail.count, truncated: true, elidedLines: Math.max(0, elidedLines) };\n}\n\nfunction budgetFor(maxLines: number, maxBytes: number, totalLines: number, maxTokens: number) {\n const limitLines = Math.max(1, Math.floor(maxLines));\n const usable = Math.max(0, maxBytes - markerReservation(totalLines));\n // The marker is charged against both ceilings; counting it in bytes alone let\n // the composed excerpt drift past the token ceiling.\n const tokens = Math.max(1, Math.floor(maxTokens) - estimateTokens(elisionMarker(totalLines)));\n return {\n limitLines,\n headLines: Math.max(1, Math.floor(limitLines * getHeadRatio())),\n headBytes: Math.max(0, Math.floor(usable * getHeadRatio())),\n headTokens: Math.max(1, Math.floor(tokens * getHeadRatio())),\n usable,\n tokens,\n };\n}\n\n/**\n * Bounds text to the budget, keeping a leading excerpt as well as the tail.\n *\n * Failures announce themselves at both ends: a command that could not start\n * says so on line one, and a command that died says so on the last. Keeping\n * only the tail loses the first kind entirely.\n */\nexport function boundExcerpt(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n if (text.length === 0) return { text: '', lines: 0, truncated: false, elidedLines: 0 };\n const { lines, trailingNewline } = splitTextLines(text);\n const totalBytes = Buffer.byteLength(text, 'utf8');\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : totalBytes;\n const limitLines = Math.max(1, Math.floor(maxLines));\n if (lines.length <= limitLines && totalBytes <= limitBytes && estimateTokens(text) <= maxTokens) {\n return { text, lines: lines.length, truncated: false, elidedLines: 0 };\n }\n\n const budget = budgetFor(maxLines, limitBytes, lines.length, maxTokens);\n const head = takeSide(lines, budget.headLines, budget.headBytes, false, budget.headTokens);\n const rest = lines.slice(head.count);\n // Reserved only when the region beyond the head actually holds errors, so a\n // clean run still spends the whole remaining budget on its tail.\n const errorBytes = rest.some(isErrorLine) ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(rest, Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(text, limitBytes);\n return { text: fragment.text, lines: fragment.count, truncated: true, elidedLines: lines.length - fragment.count };\n }\n const middle = lines.slice(head.count, lines.length - tail.count);\n const salvaged = errorBytes > 0 ? renderSalvaged(collectErrorLines(middle), errorBytes) : [];\n return assembleSides(head, tail, lines.length - head.count - tail.count, trailingNewline, limitBytes, salvaged);\n}\n\n/**\n * Same budget as `boundExcerpt`, for callers that streamed the two ends\n * separately and never held the middle. `totalLines` counts the whole source,\n * so the marker states what was dropped rather than what was captured.\n */\nexport function composeExcerpt(\n headSource: string,\n tailSource: string,\n totalLines: number,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n errors: readonly SalvagedError[] = [],\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : Number.MAX_SAFE_INTEGER;\n const budget = budgetFor(maxLines, limitBytes, totalLines, maxTokens);\n const headLines = splitTextLines(headSource).lines;\n const { lines: tailLines, trailingNewline } = splitTextLines(tailSource);\n // The line at each cut is a fragment of a line neither capture saw whole.\n const head = takeSide(\n headLines.slice(0, Math.max(0, headLines.length - 1)),\n budget.headLines,\n budget.headBytes,\n false,\n budget.headTokens,\n );\n const errorBytes = errors.length > 0 ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(tailLines.slice(1), Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(tailSource, limitBytes);\n return {\n text: fragment.text,\n lines: fragment.count,\n truncated: true,\n elidedLines: Math.max(0, totalLines - fragment.count),\n };\n }\n const salvaged = errorBytes > 0 ? renderSalvaged(errors, errorBytes) : [];\n return assembleSides(\n head,\n tail,\n Math.max(0, totalLines - head.count - tail.count),\n trailingNewline,\n limitBytes,\n salvaged,\n );\n}\n\n/** Applies Doom's line and byte ceilings to text already held in memory. */\nexport function summarizeText(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n): Pick<LogSummary, 'tail' | 'tailLines'> {\n const excerpt = boundExcerpt(text, maxLines, maxBytes);\n return { tail: excerpt.text, tailLines: excerpt.lines };\n}\n\n/** Bounds the complete model-facing result after status and recovery text are attached. */\nexport function boundResultText(text: string, maxBytes = getResultMaxBytes()): string {\n return boundExcerpt(text, getResultMaxLines(), maxBytes).text;\n}\n\n/**\n * Keeps both ends of an oversized result and points at the file holding the rest.\n *\n * The notice states the file's real size and line count so the model does not\n * guess at offsets when it goes on to read the file, which is the failure this\n * whole policy exists to prevent.\n */\n\nfunction utf8Tail(encoded: Buffer<ArrayBufferLike>, maxBytes: number): string {\n let start = Math.max(0, encoded.byteLength - maxBytes);\n while (start < encoded.byteLength && (encoded[start]! & 0xc0) === 0x80) start += 1;\n return encoded.subarray(start).toString('utf8');\n}\n\n/** `name pid 1234 up 3m sleep 60` — one runner per line. */\nexport function formatRunnerLine(record: RunnerRecord, now = Date.now()): string {\n const mode = record.interactive ? ' interactive' : '';\n return `${record.name} pid ${record.pid} up ${formatUptime(record.startedAt, now)}${mode} ${record.command}`;\n}\n\nexport function formatUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\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\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\nconst emptyLogSummary: LogSummarizer = () => ({ tail: '', bytes: 0, lines: 0, tailLines: 0 });\n\nexport function formatRunResult(\n result: BashRunResult,\n budget: ResultBudget = {},\n summarizeLog: LogSummarizer = emptyLogSummary,\n): 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 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 const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\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$/u, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\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 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 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 if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bashResult-DhbolCo5.mjs","names":[],"sources":["../src/constants/bashResult.ts","../src/constants/tokenEstimate.ts","../src/services/tokenEstimate/index.ts","../src/services/bashResult/index.ts"],"sourcesContent":["export const BYTES_PER_KB = 1024;\nexport const BYTES_PER_MB = 1_048_576;\nexport const MAX_VARIANTS_TRACKED = 12;\nexport const MIN_SHARED_AFFIX = 8;\nexport const ERROR_WINDOW_CHARS = 60;\nexport const PRAGMA_PATTERN = /^\\s*(?:#|\\/\\/)\\s*@doom:\\s*(\\{.*\\})\\s*$/u;\nexport const PRAGMA_BYTES_CEILING = 262_144;\nexport const PRAGMA_LINES_CEILING = 5_000;\nexport const PRAGMA_TOKENS_CEILING = 100_000;\n","export const WORD_CHARS_PER_TOKEN = 5;\nexport const MIXED_CHARS_PER_TOKEN = 2.1;\nexport const PUNCTUATION_CHARS_PER_TOKEN = 2;\nexport const DENSE_SCRIPT_START = 0x2fff;\nexport const ASTRAL_TOKEN_COST = 2;\nexport const ALPHANUMERIC_RUN = /([^\\p{L}\\p{N}]+)/u;\nexport const HAS_ALPHANUMERIC = /[\\p{L}\\p{N}]/u;\nexport const HAS_DIGIT = /\\d/u;\nexport const HAS_LETTER = /[A-Za-z]/u;\n","import {\n ALPHANUMERIC_RUN,\n ASTRAL_TOKEN_COST,\n DENSE_SCRIPT_START,\n HAS_ALPHANUMERIC,\n HAS_DIGIT,\n HAS_LETTER,\n MIXED_CHARS_PER_TOKEN,\n PUNCTUATION_CHARS_PER_TOKEN,\n WORD_CHARS_PER_TOKEN,\n} from '../../constants/tokenEstimate';\n/**\n * Estimates BPE tokens without carrying a vocabulary.\n *\n * Bytes are a poor proxy for what a result costs: measured against\n * `gpt-tokenizer`, real text ranges from 1.4 characters per token for base64 to\n * 4.7 for English prose, a spread of more than three. Truncation runs on every\n * command and is synchronous, so loading a real tokenizer here would charge\n * every session for a table most of them never need.\n *\n * The shape below follows how BPE actually behaves: punctuation forces token\n * boundaries, natural words are cheap, and runs mixing letters with digits are\n * expensive. Calibrated against `gpt-tokenizer` over build logs, source, JSON,\n * stack traces, CJK, base64, hex, and UUIDs, the worst error is a factor of\n * 1.46 either way. It stays an estimate, so the byte ceiling remains the hard\n * bound behind it.\n */\n\n/** Characters per token for a natural word. */\n/** Characters per token for a run mixing letters and digits, which tokenizes poorly. */\n/** Characters per token for a run of punctuation or whitespace. */\n/** Dense scripts such as CJK cost about one token per character. */\n\nexport function estimateTokens(text: string): number {\n let tokens = 0;\n for (const run of text.split(ALPHANUMERIC_RUN)) {\n if (run.length === 0) continue;\n if (!HAS_ALPHANUMERIC.test(run)) {\n tokens += run.length / PUNCTUATION_CHARS_PER_TOKEN;\n continue;\n }\n\n let ascii = 0;\n let dense = 0;\n let astral = 0;\n for (const character of run) {\n const code = character.codePointAt(0) ?? 0;\n if (code > 0xffff) astral += 1;\n else if (code > DENSE_SCRIPT_START) dense += 1;\n else ascii += 1;\n }\n tokens += astral * ASTRAL_TOKEN_COST + dense;\n if (ascii > 0) {\n const mixed = HAS_DIGIT.test(run) && HAS_LETTER.test(run);\n tokens += Math.max(1, ascii / (mixed ? MIXED_CHARS_PER_TOKEN : WORD_CHARS_PER_TOKEN));\n }\n }\n return Math.ceil(tokens);\n}\n","import {\n BYTES_PER_KB,\n BYTES_PER_MB,\n ERROR_WINDOW_CHARS,\n MAX_VARIANTS_TRACKED,\n MIN_SHARED_AFFIX,\n PRAGMA_BYTES_CEILING,\n PRAGMA_LINES_CEILING,\n PRAGMA_PATTERN,\n PRAGMA_TOKENS_CEILING,\n} from '../../constants/bashResult';\nimport type {\n ErrorLineScanner,\n Excerpt,\n LogSummarizer,\n LogSummary,\n ResultBudget,\n SalvagedError,\n ToolResult,\n} from '../../types/bashResult';\nimport type { BashRunResult, CompletedRun } from '../../types/bashRunService';\nimport type { RunnerRecord } from '../../types/runnerRegistry';\nimport { stripAnsi } from '../ansiScrub';\nimport {\n getErrorBudgetRatio,\n getErrorMaxEntries,\n getErrorMaxVariantsJoined,\n getErrorPatterns,\n getHeadRatio,\n getResultMaxBytes,\n getResultMaxLines,\n getResultMaxTokens,\n getSuccessResultMaxBytes,\n getSuccessResultMaxTokens,\n} from '../runnerConfig';\nimport { estimateTokens } from '../tokenEstimate';\n\n/** Variants retained per group while scanning; the rest only add to the count. */\n/** Below this much shared text, joining reads worse than separate lines. */\n/**\n * Severity anywhere in the opening of the line, not only at its start. Real\n * tooling buries it behind a tag or a timestamp: `[widget] build: error TS2322`.\n */\nconst SEVERITY_TOKEN =\n /(?<![\\w\\-/=.])(?:errors?|fatal|panic|exception|traceback|assertion|assert|fail(?:ed|ure|ures)?)\\b/iu;\n/** `0 errors` and `no failures` are the success case wearing the same words. */\nconst NEGATED_SEVERITY = /\\b(?:no|not|without|zero|0)\\s+$/iu;\n\nexport function textResult(text: string, details: Record<string, unknown> = {}): ToolResult {\n return { content: [{ type: 'text', text }], details };\n}\n\nexport function errorResult(message: string): ToolResult {\n return textResult(`Error: ${message}`, { error: message });\n}\n\n/** Human-readable byte count, matching how pi reports output sizes. */\nexport function formatSize(bytes: number): string {\n if (bytes < BYTES_PER_KB) return `${bytes} B`;\n if (bytes < BYTES_PER_MB) return `${(bytes / BYTES_PER_KB).toFixed(1)} KB`;\n return `${(bytes / BYTES_PER_MB).toFixed(1)} MB`;\n}\n\nfunction formatCount(value: number): string {\n return value.toLocaleString('en-US');\n}\n\nexport function countLines(text: string): number {\n if (text.length === 0) return 0;\n return text.endsWith('\\n') ? text.split('\\n').length - 1 : text.split('\\n').length;\n}\n\n/** Accumulates grouped error lines while a log streams past, without holding it. */\nclass ErrorScan {\n private readonly byKey = new Map<string, { variants: string[]; count: number }>();\n\n constructor(private readonly maxEntries = getErrorMaxEntries()) {}\n\n push(line: string): void {\n if (!isErrorLine(line)) return;\n const trimmed = line.trim();\n const key = normalizeErrorLine(line);\n const existing = this.byKey.get(key);\n if (existing) {\n existing.count += 1;\n // Only a line we have not seen verbatim earns a slot; identical repeats\n // are carried by the count alone.\n if (!existing.variants.includes(trimmed) && existing.variants.length < MAX_VARIANTS_TRACKED) {\n existing.variants.push(trimmed);\n }\n return;\n }\n if (this.byKey.size >= this.maxEntries) return;\n this.byKey.set(key, { variants: [trimmed], count: 1 });\n }\n\n entries(): SalvagedError[] {\n return [...this.byKey.values()];\n }\n}\n\nexport function createErrorScanner(maxEntries = getErrorMaxEntries()): ErrorLineScanner {\n return new ErrorScan(maxEntries);\n}\n\n/** Codex-style first-line pragma, for the one command that needs a wider result. */\n\nfunction positiveInteger(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isInteger(value) && value > 0 ? value : undefined;\n}\n\n/**\n * Reads `# @doom: {\"maxResultBytes\": 32768}` from the command's first line.\n *\n * The pragma is a shell comment, so it stays harmless if this parse is ever\n * skipped, and it survives verbatim into the log where a wider result can be\n * explained after the fact.\n */\nexport function parseResultPragma(command: string): ResultBudget {\n const match = PRAGMA_PATTERN.exec(command.split('\\n', 1)[0] ?? '');\n if (!match?.[1]) return {};\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(match[1]);\n } catch {\n return {};\n }\n if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) return {};\n\n const source = parsed as Record<string, unknown>;\n const maxBytes = positiveInteger(source.maxResultBytes);\n const maxLines = positiveInteger(source.maxResultLines);\n const maxTokens = positiveInteger(source.maxResultTokens);\n return {\n ...(maxBytes === undefined ? {} : { maxBytes: Math.min(maxBytes, PRAGMA_BYTES_CEILING) }),\n ...(maxLines === undefined ? {} : { maxLines: Math.min(maxLines, PRAGMA_LINES_CEILING) }),\n ...(maxTokens === undefined ? {} : { maxTokens: Math.min(maxTokens, PRAGMA_TOKENS_CEILING) }),\n };\n}\n\nfunction isErrorLine(line: string): boolean {\n const opening = line.slice(0, ERROR_WINDOW_CHARS);\n const match = SEVERITY_TOKEN.exec(opening);\n if (match && !NEGATED_SEVERITY.test(opening.slice(0, match.index))) return true;\n // Project patterns extend the built-in matcher; tooling this does not\n // recognise is exactly why they exist, so they are not negation-checked.\n return getErrorPatterns().some((pattern) => matchesCustomPattern(pattern, line));\n}\n\nconst customPatterns = new Map<string, RegExp | undefined>();\n\nfunction matchesCustomPattern(pattern: string, line: string): boolean {\n if (!customPatterns.has(pattern)) {\n try {\n customPatterns.set(pattern, new RegExp(pattern, 'iu'));\n } catch {\n customPatterns.set(pattern, undefined);\n }\n }\n return customPatterns.get(pattern)?.test(line) ?? false;\n}\n\n/** Masks the parts that differ between repeats of the same underlying failure. */\nfunction normalizeErrorLine(line: string): string {\n return line\n .replace(/0x[0-9a-f]+/giu, '0x#')\n .replace(/\\/[^\\s:,)]+/gu, '/#')\n .replace(/\\d+/gu, '#')\n .trim()\n .toLowerCase();\n}\n\n/**\n * Collapses repeats so one failure repeated two hundred times costs one slot.\n * Counting continues past the entry cap so the tallies stay honest.\n */\nexport function collectErrorLines(lines: Iterable<string>, maxEntries = getErrorMaxEntries()): SalvagedError[] {\n const scan = new ErrorScan(maxEntries);\n for (const line of lines) scan.push(line);\n return scan.entries();\n}\n\nfunction commonAffixLengths(values: readonly string[]): { prefix: number; suffix: number } {\n const shortest = values.reduce((min, value) => Math.min(min, value.length), Infinity);\n let prefix = 0;\n while (prefix < shortest && values.every((value) => value[prefix] === values[0]![prefix])) prefix += 1;\n let suffix = 0;\n while (\n suffix < shortest - prefix &&\n values.every((value) => value[value.length - 1 - suffix] === values[0]![values[0]!.length - 1 - suffix])\n ) {\n suffix += 1;\n }\n return { prefix, suffix };\n}\n\n/** Back off to a whitespace boundary so the brackets hold whole tokens. */\nfunction retreatToBoundary(value: string, length: number): number {\n const boundary = value.lastIndexOf(' ', Math.max(0, length - 1));\n return boundary >= 0 ? boundary + 1 : 0;\n}\n\nfunction advanceToBoundary(value: string, length: number): number {\n const cut = value.length - length;\n const boundary = value.indexOf(' ', cut);\n return boundary >= 0 ? value.length - boundary : 0;\n}\n\n/**\n * One line per distinct failure would be ideal, but repeats of one failure\n * across many files are the common case. Sharing the fixed text and joining\n * only the parts that differ keeps every file name without paying for the\n * message N times.\n */\nfunction renderGroup(group: SalvagedError): string {\n const [first] = group.variants;\n if (first === undefined) return '';\n if (group.variants.length === 1) {\n return group.count > 1 ? `${first} (\\u00d7${formatCount(group.count)})` : first;\n }\n\n const shown = group.variants.slice(0, getErrorMaxVariantsJoined());\n const { prefix, suffix } = commonAffixLengths(shown);\n const head = first.slice(0, retreatToBoundary(first, prefix));\n const tailLength = advanceToBoundary(first, suffix);\n const tail = tailLength > 0 ? first.slice(first.length - tailLength) : '';\n if (head.length + tail.length < MIN_SHARED_AFFIX) return shown.join('\\n');\n\n const middles = shown.map((value) => value.slice(head.length, value.length - tail.length));\n const overflow = group.variants.length - shown.length;\n const joined = overflow > 0 ? `${middles.join('|')}|+${formatCount(overflow)}` : middles.join('|');\n return `${head}[${joined}]${tail}`;\n}\n\nfunction renderSalvaged(errors: readonly SalvagedError[], maxBytes: number): string[] {\n const rendered: string[] = [];\n let used = 0;\n for (const group of errors) {\n const text = renderGroup(group);\n if (text.length === 0) continue;\n const cost = Buffer.byteLength(text, 'utf8') + 1;\n if (used + cost > maxBytes) break;\n rendered.push(text);\n used += cost;\n }\n return rendered;\n}\n\ninterface Side {\n readonly text: string;\n readonly count: number;\n}\n\nfunction elisionMarker(elidedLines: number, salvagedCount = 0): string {\n const unit = elidedLines === 1 ? 'line' : 'lines';\n const errors = salvagedCount > 0 ? `, ${formatCount(salvagedCount)} shown below` : '';\n return `\\u2026 [${formatCount(elidedLines)} ${unit} elided${errors}] \\u2026`;\n}\n\nfunction splitTextLines(text: string): { lines: string[]; trailingNewline: boolean } {\n const trailingNewline = text.endsWith('\\n');\n const lines = text.split('\\n');\n if (trailingNewline) lines.pop();\n return { lines, trailingNewline };\n}\n\n/** Whole lines only: a fragment of a line reads as data that was never there. */\nfunction takeSide(\n lines: readonly string[],\n maxCount: number,\n maxBytes: number,\n fromEnd: boolean,\n maxTokens = Number.POSITIVE_INFINITY,\n): Side {\n if (maxBytes <= 0 || maxCount <= 0) return { text: '', count: 0 };\n const ordered = fromEnd ? [...lines].reverse() : [...lines];\n const taken: string[] = [];\n let used = 0;\n let tokens = 0;\n for (const line of ordered) {\n if (taken.length >= maxCount) break;\n const cost = Buffer.byteLength(line, 'utf8') + (taken.length > 0 ? 1 : 0);\n // Dense output costs far more context than its byte count implies, so the\n // token ceiling stops the side even while bytes remain. The separator is\n // charged too: summing per-line estimates otherwise drifts past the ceiling\n // once the newlines between them are counted.\n const lineTokens = estimateTokens(line) + (taken.length > 0 ? 1 : 0);\n if (used + cost > maxBytes || tokens + lineTokens > maxTokens) break;\n taken.push(line);\n used += cost;\n tokens += lineTokens;\n }\n if (taken.length === 0) return { text: '', count: 0 };\n const restored = fromEnd ? taken.reverse() : taken;\n return { text: restored.join('\\n'), count: restored.length };\n}\n\n/**\n * Used only when no whole line fits either side, which means the source has no\n * usable line boundary. A clamped fragment beats returning nothing at all.\n */\nfunction clampedFragment(text: string, limitBytes: number): Side {\n const clamped = utf8Tail(Buffer.from(text, 'utf8'), limitBytes);\n const newline = clamped.indexOf('\\n');\n const whole = newline >= 0 ? clamped.slice(newline + 1) : clamped;\n return { text: whole, count: whole.length > 0 ? 1 : 0 };\n}\n\n/** Charged against the budget so the composed excerpt still honours the ceiling. */\nfunction markerReservation(totalLines: number): number {\n return Buffer.byteLength(elisionMarker(totalLines), 'utf8') + 2;\n}\n\nfunction assembleSides(\n head: Side,\n tail: Side,\n elidedLines: number,\n trailingNewline: boolean,\n limitBytes: number,\n salvaged: readonly string[] = [],\n): Excerpt {\n const opening = elidedLines > 0 ? [elisionMarker(elidedLines, salvaged.length)] : [];\n const closing = elidedLines > 0 && salvaged.length > 0 ? ['\\u2026'] : [];\n const parts = [head.text, ...opening, ...salvaged, ...closing, tail.text].filter((part) => part.length > 0);\n const body = parts.join('\\n');\n const withNewline = trailingNewline && body.length > 0 ? `${body}\\n` : body;\n const encoded = Buffer.from(withNewline, 'utf8');\n // Last resort: the ceiling is a hard promise to the caller.\n const text = encoded.byteLength > limitBytes ? utf8Tail(encoded, limitBytes) : withNewline;\n return { text, lines: head.count + tail.count, truncated: true, elidedLines: Math.max(0, elidedLines) };\n}\n\nfunction budgetFor(maxLines: number, maxBytes: number, totalLines: number, maxTokens: number) {\n const limitLines = Math.max(1, Math.floor(maxLines));\n const usable = Math.max(0, maxBytes - markerReservation(totalLines));\n // The marker is charged against both ceilings; counting it in bytes alone let\n // the composed excerpt drift past the token ceiling.\n const tokens = Math.max(1, Math.floor(maxTokens) - estimateTokens(elisionMarker(totalLines)));\n return {\n limitLines,\n headLines: Math.max(1, Math.floor(limitLines * getHeadRatio())),\n headBytes: Math.max(0, Math.floor(usable * getHeadRatio())),\n headTokens: Math.max(1, Math.floor(tokens * getHeadRatio())),\n usable,\n tokens,\n };\n}\n\n/**\n * Bounds text to the budget, keeping a leading excerpt as well as the tail.\n *\n * Failures announce themselves at both ends: a command that could not start\n * says so on line one, and a command that died says so on the last. Keeping\n * only the tail loses the first kind entirely.\n */\nexport function boundExcerpt(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n if (text.length === 0) return { text: '', lines: 0, truncated: false, elidedLines: 0 };\n const { lines, trailingNewline } = splitTextLines(text);\n const totalBytes = Buffer.byteLength(text, 'utf8');\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : totalBytes;\n const limitLines = Math.max(1, Math.floor(maxLines));\n if (lines.length <= limitLines && totalBytes <= limitBytes && estimateTokens(text) <= maxTokens) {\n return { text, lines: lines.length, truncated: false, elidedLines: 0 };\n }\n\n const budget = budgetFor(maxLines, limitBytes, lines.length, maxTokens);\n const head = takeSide(lines, budget.headLines, budget.headBytes, false, budget.headTokens);\n const rest = lines.slice(head.count);\n // Reserved only when the region beyond the head actually holds errors, so a\n // clean run still spends the whole remaining budget on its tail.\n const errorBytes = rest.some(isErrorLine) ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(rest, Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(text, limitBytes);\n return { text: fragment.text, lines: fragment.count, truncated: true, elidedLines: lines.length - fragment.count };\n }\n const middle = lines.slice(head.count, lines.length - tail.count);\n const salvaged = errorBytes > 0 ? renderSalvaged(collectErrorLines(middle), errorBytes) : [];\n return assembleSides(head, tail, lines.length - head.count - tail.count, trailingNewline, limitBytes, salvaged);\n}\n\n/**\n * Same budget as `boundExcerpt`, for callers that streamed the two ends\n * separately and never held the middle. `totalLines` counts the whole source,\n * so the marker states what was dropped rather than what was captured.\n */\nexport function composeExcerpt(\n headSource: string,\n tailSource: string,\n totalLines: number,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n errors: readonly SalvagedError[] = [],\n maxTokens = getResultMaxTokens(),\n): Excerpt {\n const limitBytes = Number.isFinite(maxBytes) ? Math.max(0, Math.floor(maxBytes)) : Number.MAX_SAFE_INTEGER;\n const budget = budgetFor(maxLines, limitBytes, totalLines, maxTokens);\n const headLines = splitTextLines(headSource).lines;\n const { lines: tailLines, trailingNewline } = splitTextLines(tailSource);\n // The line at each cut is a fragment of a line neither capture saw whole.\n const head = takeSide(\n headLines.slice(0, Math.max(0, headLines.length - 1)),\n budget.headLines,\n budget.headBytes,\n false,\n budget.headTokens,\n );\n const errorBytes = errors.length > 0 ? Math.floor(budget.usable * getErrorBudgetRatio()) : 0;\n const tailBytes = budget.usable - Buffer.byteLength(head.text, 'utf8') - errorBytes;\n const tailTokens = budget.tokens - estimateTokens(head.text);\n const tail = takeSide(tailLines.slice(1), Math.max(1, budget.limitLines - head.count), tailBytes, true, tailTokens);\n if (head.count === 0 && tail.count === 0) {\n const fragment = clampedFragment(tailSource, limitBytes);\n return {\n text: fragment.text,\n lines: fragment.count,\n truncated: true,\n elidedLines: Math.max(0, totalLines - fragment.count),\n };\n }\n const salvaged = errorBytes > 0 ? renderSalvaged(errors, errorBytes) : [];\n return assembleSides(\n head,\n tail,\n Math.max(0, totalLines - head.count - tail.count),\n trailingNewline,\n limitBytes,\n salvaged,\n );\n}\n\n/** Applies Doom's line and byte ceilings to text already held in memory. */\nexport function summarizeText(\n text: string,\n maxLines = getResultMaxLines(),\n maxBytes = getResultMaxBytes(),\n): Pick<LogSummary, 'tail' | 'tailLines'> {\n const excerpt = boundExcerpt(text, maxLines, maxBytes);\n return { tail: excerpt.text, tailLines: excerpt.lines };\n}\n\n/** Bounds the complete model-facing result after status and recovery text are attached. */\nexport function boundResultText(text: string, maxBytes = getResultMaxBytes()): string {\n return boundExcerpt(text, getResultMaxLines(), maxBytes).text;\n}\n\n/**\n * Keeps both ends of an oversized result and points at the file holding the rest.\n *\n * The notice states the file's real size and line count so the model does not\n * guess at offsets when it goes on to read the file, which is the failure this\n * whole policy exists to prevent.\n */\n\nfunction utf8Tail(encoded: Buffer<ArrayBufferLike>, maxBytes: number): string {\n let start = Math.max(0, encoded.byteLength - maxBytes);\n while (start < encoded.byteLength && (encoded[start]! & 0xc0) === 0x80) start += 1;\n return encoded.subarray(start).toString('utf8');\n}\n\n/** `name pid 1234 up 3m sleep 60` — one runner per line. */\nexport function formatRunnerLine(record: RunnerRecord, now = Date.now()): string {\n const mode = record.interactive ? ' interactive' : '';\n return `${record.name} pid ${record.pid} up ${formatUptime(record.startedAt, now)}${mode} ${record.command}`;\n}\n\nexport function formatUptime(startedAt: string, now: number): string {\n const started = Date.parse(startedAt);\n if (Number.isNaN(started)) return 'unknown';\n const seconds = Math.max(0, Math.floor((now - started) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n return hours < 24 ? `${hours}h` : `${Math.floor(hours / 24)}d`;\n}\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\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\nconst emptyLogSummary: LogSummarizer = () => ({ tail: '', bytes: 0, lines: 0, tailLines: 0 });\n\nexport function formatRunResult(\n result: BashRunResult,\n budget: ResultBudget = {},\n summarizeLog: LogSummarizer = emptyLogSummary,\n): 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 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 const succeeded = !completionFailed(result);\n const maxLines = budget.maxLines ?? getResultMaxLines();\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$/u, '');\n const failed = completionFailed(result);\n const status = completionStatus(result);\n const textLines: string[] = [];\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 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 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 if (failed) throw new Error(text);\n return textResult(text, details);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- const require_runnerConfig = require("./runnerConfig-DsHrA6i2.cjs");
1
+ const require_runnerConfig = require("./runnerConfig-CzcAcYXI.cjs");
2
2
  const require_rtkProcessor = require("./rtkProcessor-CsrCPyTQ.cjs");
3
3
  let node_crypto = require("node:crypto");
4
4
  //#region src/constants/bashRunService.ts
@@ -6,6 +6,21 @@ const COMPLETED = "completed";
6
6
  const FAILED = "failed";
7
7
  const LAUNCHER_ERROR = "launcher_error";
8
8
  //#endregion
9
+ //#region src/services/bashRunService/resources.ts
10
+ /** Classify known expensive commands without rewriting the user's shell command. */
11
+ function isHeavyCommand(command) {
12
+ return command.split(/\s*(?:&&|\|\||[;|\n])\s*/).some((segment) => {
13
+ let invocation = segment.trim().replace(/^(?:[A-Za-z_][A-Za-z_0-9]*=(?:"[^"]*"|'[^']*'|\S+)\s+)*/, "");
14
+ invocation = invocation.replace(/^(?:env|command|exec|time)\s+/, "");
15
+ const packageManager = /^(?:pnpm|npm|npx|yarn|bun)\s+(?:(?:--filter|--dir|-C)\s+\S+\s+|(?:-w|--workspace-root)\s+)*(?:(?:exec|run)\s+)?/.exec(invocation);
16
+ if (packageManager) invocation = invocation.slice(packageManager[0].length);
17
+ if (/(?:^|\s)--(?:help|version)(?:\s|$)/.test(invocation)) return false;
18
+ if (packageManager && /^(?:build|test|lint|typecheck|check)(?::[\w-]+)?(?:\s|$)/.test(invocation)) return true;
19
+ if (/^(?:\S*\/)?(?:vitest|jest|tsc|tsdown|webpack|rollup|esbuild)(?:\s|$)/.test(invocation)) return true;
20
+ return /^nx\s+(?!(?:show|graph|daemon|reset)\b)/.test(invocation) && /(?:^|[\s:,])(?:build|test(?:-[\w-]+)?|lint|typecheck)(?:[\s:,=]|$)/.test(invocation);
21
+ });
22
+ }
23
+ //#endregion
9
24
  //#region src/services/bashRunService/index.ts
10
25
  /** The command outlived the background threshold and should be promoted. */
11
26
  const TIMED_OUT = Symbol("threshold-reached");
@@ -25,7 +40,8 @@ var BashRunService = class {
25
40
  rtkProcessor;
26
41
  cwd;
27
42
  env;
28
- constructor(launcher, rmuxBackend, namer, registry, clock, rtkProcessor, cwd = process.cwd(), env = process.env) {
43
+ executionBudget;
44
+ constructor(launcher, rmuxBackend, namer, registry, clock, rtkProcessor, cwd = process.cwd(), env = process.env, executionBudget) {
29
45
  this.launcher = launcher;
30
46
  this.rmuxBackend = rmuxBackend;
31
47
  this.namer = namer;
@@ -34,6 +50,7 @@ var BashRunService = class {
34
50
  this.rtkProcessor = rtkProcessor;
35
51
  this.cwd = cwd;
36
52
  this.env = env;
53
+ this.executionBudget = executionBudget;
37
54
  }
38
55
  async run(request) {
39
56
  const id = runnerId();
@@ -47,7 +64,10 @@ var BashRunService = class {
47
64
  error: "Operation aborted"
48
65
  };
49
66
  let handle;
67
+ let releaseSlot;
50
68
  try {
69
+ if (!interactive && this.executionBudget && isHeavyCommand(request.command)) releaseSlot = await this.executionBudget.acquire(request.signal);
70
+ request.signal?.throwIfAborted();
51
71
  const rmuxHandle = await this.rmuxBackend.launch({
52
72
  id,
53
73
  name,
@@ -70,6 +90,7 @@ var BashRunService = class {
70
90
  sessionId: request.sessionId
71
91
  });
72
92
  } catch (error) {
93
+ releaseSlot?.();
73
94
  return {
74
95
  kind: FAILED,
75
96
  id,
@@ -77,12 +98,16 @@ var BashRunService = class {
77
98
  error: error instanceof Error ? error.message : String(error)
78
99
  };
79
100
  }
80
- if (handle.pid === void 0) return {
81
- kind: FAILED,
82
- id,
83
- name,
84
- error: "The command did not start, so it cannot be supervised"
85
- };
101
+ if (handle.pid === void 0) {
102
+ releaseSlot?.();
103
+ return {
104
+ kind: FAILED,
105
+ id,
106
+ name,
107
+ error: "The command did not start, so it cannot be supervised"
108
+ };
109
+ }
110
+ if (releaseSlot) handle.completion().then(releaseSlot, releaseSlot);
86
111
  if (request.signal?.aborted) {
87
112
  await handle.stop();
88
113
  return {
@@ -340,4 +365,4 @@ Object.defineProperty(exports, "BashRunService", {
340
365
  }
341
366
  });
342
367
 
343
- //# sourceMappingURL=bashRunService-CxnXkCyV.cjs.map
368
+ //# sourceMappingURL=bashRunService-CpPOtFmX.cjs.map