@molecule/api-ai-tools 1.6.5 → 1.6.6

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.
@@ -0,0 +1,267 @@
1
+ /**
2
+ * A command that a budget stopped before it finished, and the state its result carries so no
3
+ * reader can mistake it for a run that ended.
4
+ *
5
+ * X1 xr-molecule-flash-m93 (2026-10-16, +12:37) sent the supplied RealWorld suite as
6
+ * `timeout 280 hurl --test --continue-on-error --jobs 1 … hurl/*.hurl 2>&1 | tail -60` and got
7
+ * back `exitCode: 0`, four finished files' lines and nothing else. Two lies in one result: the
8
+ * `timeout 280` killed the run at 280 s, and the `| tail` made the pipeline's status the status —
9
+ * so the executor read a suite that stopped at its fifth file as a suite that ran and nearly
10
+ * passed, fixed one message, and immediately sent the same 280-second command again (the run's
11
+ * third, ~14 minutes of a 60-minute cap across three of them).
12
+ *
13
+ * So the tool never reports a stopped run as `exitCode: 0`. Such a result carries
14
+ * `status: 'cut_at_budget'` and an exit code that is `null` whenever the number the pipeline
15
+ * reported belongs to the filter rather than to the run, and every reader of a run's verdict reads
16
+ * the state through {@link commandRunState} — a cut run is NOT RUN, never a pass.
17
+ *
18
+ * Two things stop a run, and both are read from the command and the result, never inferred:
19
+ *
20
+ * 1. **Its own bound** — a `timeout <N>` the command carries ({@link commandTimeoutSeconds}). The
21
+ * run used it, so the run was killed at it; with no closing tally in the output, the run did
22
+ * not finish. This is m93's shape.
23
+ * 2. **This tool's budget** — the backend runs the command under `timeout` (see
24
+ * `backends/sandbox.ts`), which reports 124 whatever the pipeline did, and returns everything
25
+ * printed until then. The budget is the tool's own, so its number belongs to the tool.
26
+ *
27
+ * @module
28
+ */
29
+ import { commandTimeoutSeconds } from './command-position.js';
30
+ import { isSuiteRunCommand } from './utilities.js';
31
+ /**
32
+ * The state a result carries when a budget stopped its command: a run that did not finish is not a
33
+ * run that passed, and no reader may treat it as one.
34
+ */
35
+ export const CUT_AT_BUDGET = 'cut_at_budget';
36
+ /**
37
+ * The state a command's result records — THE reader every verdict about a run goes through.
38
+ *
39
+ * A result that carries no state is a run that ended: the state is written where the run is
40
+ * stopped ({@link commandCutRun}), so a result without it was never stopped by a budget this
41
+ * platform set or can see. Results produced before this state existed read the same way, which is
42
+ * what keeps a past turn's tally readable.
43
+ *
44
+ * @param result - The exec_command / wait_for_task result.
45
+ * @returns The state the result records.
46
+ */
47
+ export function commandRunState(result) {
48
+ if (result === null || typeof result !== 'object')
49
+ return 'ran';
50
+ return result.status === CUT_AT_BUDGET ? CUT_AT_BUDGET : 'ran';
51
+ }
52
+ /**
53
+ * The gap between a bound and the elapsed time a run killed at it reports. Zero, and deliberately
54
+ * not a tolerance: a command killed at its bound reports AT LEAST the bound (the shell's own
55
+ * bookkeeping runs after the kill, and this tool's round trip is on top), so any slack would only
56
+ * make a SHORT bound fire on a run that finished inside it (`timeout 5 curl …` answering in 3 s).
57
+ * A run that finished near its bound carried its runner's closing summary — {@link suiteTally}.
58
+ *
59
+ * @param boundSeconds - The bound the run was allowed.
60
+ * @returns The elapsed ms a run stopped at that bound reports at least.
61
+ */
62
+ function atBoundMs(boundSeconds) {
63
+ return boundSeconds * 1000;
64
+ }
65
+ /**
66
+ * A runner's closing summary, printed only by a run that walked its whole suite: Hurl's
67
+ * `Executed files:` block and the `N passed` / `N failed` / `N flaky` line Playwright and Vitest
68
+ * print when they finish.
69
+ *
70
+ * This is what separates "stopped at the bound" from "used the bound and finished": a suite that
71
+ * printed its summary ran to its end, and is read as the run it was.
72
+ */
73
+ const SUITE_TALLY = /\bExecuted files:\s*\d+|\b\d+\s+(?:passed|failed|flaky|skipped)\b/;
74
+ /**
75
+ * Whether text carries a runner's closing summary ({@link SUITE_TALLY}).
76
+ *
77
+ * @param text - The run's stdout and stderr.
78
+ * @returns True when the runner's own end-of-run summary is there.
79
+ */
80
+ export function suiteTally(text) {
81
+ return SUITE_TALLY.test(text);
82
+ }
83
+ /** The last thing a run printed: its last non-blank line, as one line and short enough to quote. */
84
+ function lastPrinted(text) {
85
+ const lines = text.split('\n');
86
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
87
+ const line = (lines[i] ?? '').trim();
88
+ if (line)
89
+ return line.length > 180 ? `${line.slice(0, 177)}…` : line;
90
+ }
91
+ return null;
92
+ }
93
+ /** Hurl's per-file line: `Success hurl/articles.hurl (17 request(s) in 318 ms)`. */
94
+ const HURL_FILE_LINE = /^(?:Success|Failure)\s+(\S+)/gm;
95
+ /** Playwright's progress line — `[5/13] specs/auth.spec.ts:10:5 › signs up`. */
96
+ const PROGRESS_LINE = /^\s*\[(\d+)\/(\d+)\]/gm;
97
+ /**
98
+ * What the runner's own output says the run got through.
99
+ *
100
+ * Hurl prints a line per finished file and no total unless it finished; Playwright's line reporter
101
+ * prints `[n/K]` with both numbers. Neither is inferred from the command — a run that printed
102
+ * nothing says nothing, which is what `null` means here.
103
+ *
104
+ * @param text - The run's stdout and stderr.
105
+ * @param suite - Whether the command runs a suite.
106
+ * @returns How many finished, how many the run was walking, and the noun.
107
+ */
108
+ function runProgress(text, suite) {
109
+ const files = new Set();
110
+ for (const m of text.matchAll(HURL_FILE_LINE))
111
+ files.add(m[1] ?? '');
112
+ if (files.size > 0)
113
+ return { ran: files.size, total: null, noun: 'files' };
114
+ let ran = null;
115
+ let total = null;
116
+ for (const m of text.matchAll(PROGRESS_LINE)) {
117
+ ran = Number(m[1]);
118
+ total = Number(m[2]);
119
+ }
120
+ if (ran !== null)
121
+ return { ran, total, noun: 'tests' };
122
+ return { ran: null, total: null, noun: suite ? 'tests' : 'files' };
123
+ }
124
+ /**
125
+ * The run a command's result records as stopped by a budget, or null when the result is a run that
126
+ * ended (or says nothing about a run).
127
+ *
128
+ * Evidence, in order — never a guess:
129
+ *
130
+ * - `timeout`'s own 124 (the code the backend's wrapper returns whenever the TOOL's budget fired,
131
+ * whatever the pipeline ended with) — and, when the clock says the command's own smaller bound
132
+ * ran out first and less than the budget, that bound instead.
133
+ * - the command carried its own `timeout <N>`, N is inside this tool's budget (a larger one never
134
+ * fires — the tool's does), the run used N, and no runner printed a closing summary: the run was
135
+ * killed at its own bound. Its exit code, when the pipeline handed one back, is the filter's.
136
+ * - the run used this tool's whole budget behind a filter that withheld its output, and printed no
137
+ * closing summary: the budget stopped it, and no code in the result is the run's.
138
+ *
139
+ * @param command - The command the executor sent.
140
+ * @param result - Its result.
141
+ * @param elapsedMs - How long the command ran, in ms.
142
+ * @param budgetSeconds - This tool's foreground budget, in seconds (0 when it has none).
143
+ * @returns The stopped run, or null.
144
+ */
145
+ export function commandCutRun(command, result, elapsedMs, budgetSeconds = 0) {
146
+ if (typeof command !== 'string' || !command.trim())
147
+ return null;
148
+ if (result === null || typeof result !== 'object')
149
+ return null;
150
+ if (!Number.isFinite(elapsedMs))
151
+ return null;
152
+ const r = result;
153
+ const exitCode = typeof r.exitCode === 'number' ? r.exitCode : null;
154
+ const text = `${String(r.stdout ?? '')}\n${String(r.stderr ?? '')}`;
155
+ // A suite that printed its summary ran to its end, whatever it was wrapped in.
156
+ if (suiteTally(text))
157
+ return null;
158
+ const suite = isSuiteRunCommand(command);
159
+ const withheld = /\|\s*(?:tail|head|grep|egrep|fgrep|sort|uniq|wc|jq)\b/.test(command);
160
+ const progress = runProgress(text, suite);
161
+ const doing = lastPrinted(text);
162
+ const declared = commandTimeoutSeconds(command);
163
+ // A command whose own bound is inside this tool's budget is stopped by ITS bound: a larger one
164
+ // never gets the chance — the backend's `timeout` fires first (see the module doc). With no
165
+ // tool budget at all (a reader re-reading a background run) the command's own bound is the only
166
+ // one there is.
167
+ const ownBoundStops = budgetSeconds === 0 || (declared !== null && declared < budgetSeconds);
168
+ // `timeout`'s own 124 — the code the backend's wrapper returns when the TOOL's budget fires,
169
+ // whatever the pipeline ended with (`backends/sandbox.ts`). Which of the two bounds fired is the
170
+ // clock's to say: a run killed at the tool's budget reports at least the budget, and one killed
171
+ // at its own bound reports at least that bound and less than the budget.
172
+ if (budgetSeconds > 0 && exitCode === 124) {
173
+ const ownFired = declared !== null &&
174
+ ownBoundStops &&
175
+ elapsedMs >= atBoundMs(declared) &&
176
+ elapsedMs < atBoundMs(budgetSeconds);
177
+ return {
178
+ seconds: ownFired ? declared : budgetSeconds,
179
+ stoppedBy: ownFired ? 'command-timeout' : 'tool-budget',
180
+ exitCode,
181
+ ...progress,
182
+ doing,
183
+ };
184
+ }
185
+ if (declared !== null && ownBoundStops && elapsedMs >= atBoundMs(declared)) {
186
+ return {
187
+ seconds: declared,
188
+ stoppedBy: 'command-timeout',
189
+ // A code the filter produced is not the run's: `… | tail` handed back 0 forever (m93).
190
+ exitCode: withheld || exitCode === 0 ? null : exitCode,
191
+ ...progress,
192
+ doing,
193
+ };
194
+ }
195
+ // The tool's budget with its code masked: the run used the whole budget and the pipeline left
196
+ // nothing readable of it — no code of its own, and no runner's closing summary.
197
+ if (budgetSeconds > 0 && withheld && elapsedMs >= atBoundMs(budgetSeconds)) {
198
+ return {
199
+ seconds: budgetSeconds,
200
+ stoppedBy: 'tool-budget',
201
+ exitCode: exitCode === 0 ? null : exitCode,
202
+ ...progress,
203
+ doing,
204
+ };
205
+ }
206
+ return null;
207
+ }
208
+ /**
209
+ * The facts a result records about the run a budget stopped it in — what a reader needs to say
210
+ * how far the run got WITHOUT re-reading its log or re-deriving the counts.
211
+ *
212
+ * The numbers are read from the runner's own output where it printed them (Hurl's per-file lines,
213
+ * Playwright's `[n/K]`), so a caller that can also see the suite itself — the file count of the
214
+ * `*.hurl` directory the run walked — fills in the `total` this could not know, and both then say
215
+ * the same sentence ({@link cutRunSentence}).
216
+ *
217
+ * @param result - The exec_command / wait_for_task result.
218
+ * @returns The facts the result carries, or null when it records no stopped run.
219
+ */
220
+ export function cutRunFacts(result) {
221
+ if (result === null || typeof result !== 'object')
222
+ return null;
223
+ if (commandRunState(result) !== CUT_AT_BUDGET)
224
+ return null;
225
+ const cut = result.cutRun;
226
+ if (cut === null || typeof cut !== 'object')
227
+ return null;
228
+ const c = cut;
229
+ if (typeof c.seconds !== 'number' || typeof c.stoppedBy !== 'string')
230
+ return null;
231
+ return {
232
+ seconds: c.seconds,
233
+ stoppedBy: c.stoppedBy,
234
+ exitCode: typeof c.exitCode === 'number' ? c.exitCode : null,
235
+ ran: typeof c.ran === 'number' ? c.ran : null,
236
+ total: typeof c.total === 'number' ? c.total : null,
237
+ noun: c.noun === 'tests' ? 'tests' : 'files',
238
+ doing: typeof c.doing === 'string' && c.doing ? c.doing : null,
239
+ };
240
+ }
241
+ /**
242
+ * The first line of a stopped run's result: how long it was allowed, what stopped it, how far it
243
+ * got, and the last thing it printed.
244
+ *
245
+ * Written to be quotable by the model in one sentence and to leave no room for "nearly passing":
246
+ * the counts come from the runner's own output ({@link runProgress}), and a `total` the caller
247
+ * read elsewhere (the suite's own file count) fills in the "M of K" it can then state.
248
+ *
249
+ * @param run - The stopped run.
250
+ * @returns The sentence.
251
+ */
252
+ export function cutRunSentence(run) {
253
+ const by = run.stoppedBy === 'tool-budget' ? "this tool's limit" : `its own \`timeout ${run.seconds}\``;
254
+ const lead = `This run was stopped after ${run.seconds}s (${by})`;
255
+ const count = run.ran !== null && run.total !== null
256
+ ? `: ${run.ran} of ${run.total} ${run.noun} ran, the rest did not run`
257
+ : run.ran !== null
258
+ ? `: ${run.ran} ${run.noun} ran and the rest did not run`
259
+ : ' before it finished';
260
+ const doing = run.doing ? `; the last thing it was doing: ${run.doing}` : '';
261
+ // Why the result carries no code: without this the model reads the missing field as an
262
+ // omission, and the number it used to read there was the pipeline's own 0.
263
+ const code = run.exitCode === null
264
+ ? ' It has no exit code of its own to report — the one this pipeline produced belongs to the filter, not to the run.'
265
+ : '';
266
+ return `${lead}${count}${doing}.${code}`;
267
+ }
package/dist/index.d.ts CHANGED
@@ -133,6 +133,7 @@ export * from './backends/local.js';
133
133
  export * from './backends/sandbox.js';
134
134
  export * from './browser-guard.js';
135
135
  export * from './command-position.js';
136
+ export * from './cut-run.js';
136
137
  export * from './input-normalizer.js';
137
138
  export * from './no-test-run.js';
138
139
  export * from './schemas.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkIG;AAEH,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkIG;AAEH,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,cAAc,CAAA;AAC5B,cAAc,uBAAuB,CAAA;AACrC,cAAc,kBAAkB,CAAA;AAChC,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -133,6 +133,7 @@ export * from './backends/local.js';
133
133
  export * from './backends/sandbox.js';
134
134
  export * from './browser-guard.js';
135
135
  export * from './command-position.js';
136
+ export * from './cut-run.js';
136
137
  export * from './input-normalizer.js';
137
138
  export * from './no-test-run.js';
138
139
  export * from './schemas.js';
package/dist/tools.d.ts CHANGED
@@ -26,6 +26,26 @@ import type { AITool } from '@molecule/api-ai';
26
26
  */
27
27
  export declare function taskStopCommand(backend: ExecutionBackend, taskId: string): Promise<string>;
28
28
  import type { ExecutionBackend, ToolBuildConfig } from './types.js';
29
+ /**
30
+ * The closing advice on an over-budget message for a command that is not a test
31
+ * suite: the work it was chaining is what to split.
32
+ */
33
+ export declare const SPLIT_WORK_ADVICE: string;
34
+ /**
35
+ * The closing advice on an over-budget message for a command that IS a suite run
36
+ * (Playwright, Vitest, a `hurl` run — {@link isSuiteRunCommand}): its files are not
37
+ * a bigger unit to break up.
38
+ *
39
+ * X1 flash-m36 asked for this half and the message kept saying "run a smaller unit"
40
+ * for two months. It is the wrong direction for a suite, and measurably: a run
41
+ * stopped here reports NO tally, so nothing in the result says which test or request
42
+ * hung — the run has to be sent again in the background (off this budget, its output
43
+ * written to a log that can be read mid-run) or, when a consumer knows the runner's
44
+ * per-request limit, with each request bounded. xr-molecule-flash-m93 (+06:22,
45
+ * 2026-10-16) lost 4.8 minutes to a Hurl run whose ONE unanswered request had hurl's
46
+ * 300 s default per request holding the file, ten seconds past this tool's budget.
47
+ */
48
+ export declare const SUITE_OVER_BUDGET_ADVICE: string;
29
49
  /**
30
50
  * The steer attached to a SUCCESSFUL read of a package's built output. The ENOENT
31
51
  * redirect below fires only when the read FAILS, so a model that knows the hoisted
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAiF9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AAwHD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAoEnE;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBxE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAgjExF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAkF9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AAwHD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAgEnE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAEA,CAAA;AAE9B;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,QAI6C,CAAA;AAmBlF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBxE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAipExF"}
package/dist/tools.js CHANGED
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @module
8
8
  */
9
+ import { commandCutRun, CUT_AT_BUDGET, cutRunSentence } from './cut-run.js';
9
10
  import { addChangeSpan, changedSpan, countLines, renderEditExcerpt, renderSmallFile, } from './edit-excerpt.js';
10
11
  import { guardToolExecute, missingParamError, ToolInputError } from './input-normalizer.js';
11
12
  import { TOOL_SCHEMAS } from './schemas.js';
@@ -208,12 +209,43 @@ function runningNote(clauses) {
208
209
  const joined = clauses.join('; ');
209
210
  return `${joined[0].toUpperCase()}${joined.slice(1)}.`;
210
211
  }
211
- import { checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, emptyCallError, failureCausesNote, findPatternArgs, fusedLine, htmlOutline, isEnvFilePath, isOutsideRoot, isPlaywrightRunCommand, isValidGlob, linesWithinSerialized, MAX_BATCH_READ_FILES, MAX_FIND_RESULTS, MAX_HTML_INLINE_CHARS, MAX_OUTPUT_SIZE, MAX_READ_CALL_CHARS, MAX_READ_RETURN_CHARS, MAX_READ_SIZE, MAX_SEARCH_CONTEXT_LINES, MAX_SEARCH_RESULTS, MAX_WRITE_SIZE, outputIsWithheldUntilExit, outputRedirectTarget, parseCheckCommand, parseCheckProblem, pathArgError, printsOnlySource, READ_RESULT_ENVELOPE_CHARS, redactSecrets, redactSecretsInCode, repeatingFailure, repeatingFailureNote, resolvePath, RUNNING_FAILURE_LINES, runningCauseCommand, runningOutputSliceCommand, serializedChars, shellQuote, sliceLines, SMALL_FILE_WHOLE_CHARS, streamingBackgroundCommand, stripControlChars, suiteRunPriorityLaunch, truncateMiddle, universalCause, whitespaceTolerantReplace, } from './utilities.js';
212
+ import { checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, emptyCallError, failureCausesNote, findPathArgs, findPatternArgs, fusedLine, htmlOutline, isCommandTimeout, isEnvFilePath, isOutsideRoot, isPlaywrightRunCommand, isSuiteRunCommand, isValidGlob, linesWithinSerialized, literalDirPrefix, MAX_BATCH_READ_FILES, MAX_FIND_RESULTS, MAX_HTML_INLINE_CHARS, MAX_OUTPUT_SIZE, MAX_READ_CALL_CHARS, MAX_READ_RETURN_CHARS, MAX_READ_SIZE, MAX_SEARCH_CONTEXT_LINES, MAX_SEARCH_RESULTS, MAX_WRITE_SIZE, outputIsWithheldUntilExit, outputRedirectTarget, parseCheckCommand, parseCheckProblem, pathArgError, printsOnlySource, READ_RESULT_ENVELOPE_CHARS, redactSecrets, redactSecretsInCode, repeatingFailure, repeatingFailureNote, resolvePath, RUNNING_FAILURE_LINES, runningCauseCommand, runningOutputSliceCommand, searchTimeoutError, serializedChars, shellQuote, sliceLines, SMALL_FILE_WHOLE_CHARS, streamingBackgroundCommand, stripControlChars, suiteRunPriorityLaunch, truncateMiddle, universalCause, whitespaceTolerantReplace, } from './utilities.js';
212
213
  /**
213
214
  * How long exec_command waits for a command it backgrounded only because the
214
215
  * command asked for more than the tool's ceiling, before handing back a task id.
215
216
  */
216
217
  const OVER_CEILING_GRACE_MS = 45_000;
218
+ /**
219
+ * The closing advice on an over-budget message for a command that is not a test
220
+ * suite: the work it was chaining is what to split.
221
+ */
222
+ export const SPLIT_WORK_ADVICE = 'Run a smaller unit per command (one test file, one build step) instead of chaining ' +
223
+ 'a build and a whole suite.';
224
+ /**
225
+ * The closing advice on an over-budget message for a command that IS a suite run
226
+ * (Playwright, Vitest, a `hurl` run — {@link isSuiteRunCommand}): its files are not
227
+ * a bigger unit to break up.
228
+ *
229
+ * X1 flash-m36 asked for this half and the message kept saying "run a smaller unit"
230
+ * for two months. It is the wrong direction for a suite, and measurably: a run
231
+ * stopped here reports NO tally, so nothing in the result says which test or request
232
+ * hung — the run has to be sent again in the background (off this budget, its output
233
+ * written to a log that can be read mid-run) or, when a consumer knows the runner's
234
+ * per-request limit, with each request bounded. xr-molecule-flash-m93 (+06:22,
235
+ * 2026-10-16) lost 4.8 minutes to a Hurl run whose ONE unanswered request had hurl's
236
+ * 300 s default per request holding the file, ten seconds past this tool's budget.
237
+ */
238
+ export const SUITE_OVER_BUDGET_ADVICE = 'A test suite is not a bigger unit to split: stopped here it reports no tally at all, so nothing ' +
239
+ 'in this result says which test or request never finished — run it in the background ' +
240
+ '(`run_in_background`, then `wait_for_task`), which takes it off this budget and writes its output ' +
241
+ "to a log, and read that log (or the app's own log) for what it was waiting on.";
242
+ /**
243
+ * How long a tree walk (`find_files`, `search_files`) may run before the backend's
244
+ * own deadline stops it. Both tools answer that deadline in their own words
245
+ * (see searchTimeoutError) rather than forwarding the sandbox SDK's `timeoutMs`
246
+ * sentence, which names an option the executor cannot set.
247
+ */
248
+ const SEARCH_TIMEOUT_MS = 10_000;
217
249
  /**
218
250
  * The share of its budget a command must use before the "you asked for more than
219
251
  * this tool's ceiling" note is worth attaching. Below it the clamp changed nothing
@@ -1484,7 +1516,7 @@ export function buildTools(backend, config) {
1484
1516
  // -H: a search scoped to one file printed `line:content` with no file, and every match
1485
1517
  // came back `{file: "", line: 0}` (X1 flash-m62).
1486
1518
  const grepArgs = `-rnH ${globArg} ${contextArg} ${grepExcludeArgs(path)} --max-count=${MAX_SEARCH_RESULTS} -- ${shellQuote(pattern)} ${shellQuote(path)}`;
1487
- const result = await backend.run(`{ grep -E ${grepArgs}; s=$?; if [ "$s" -eq 2 ]; then grep -F ${grepArgs}; fi; } 2>/dev/null || true`, { timeout: 10000 });
1519
+ const result = await backend.run(`{ grep -E ${grepArgs}; s=$?; if [ "$s" -eq 2 ]; then grep -F ${grepArgs}; fi; } 2>/dev/null || true`, { timeout: SEARCH_TIMEOUT_MS });
1488
1520
  // grep emits `<file>:<line>:<content>`, so redaction runs PER MATCH on the
1489
1521
  // content alone: the file prefix would otherwise hide an env assignment from
1490
1522
  // the line-anchored env pattern, and knowing each match's own path is what
@@ -1521,6 +1553,11 @@ export function buildTools(backend, config) {
1521
1553
  return { pattern, path, matches };
1522
1554
  }
1523
1555
  catch (e) {
1556
+ if (isCommandTimeout(e))
1557
+ return {
1558
+ error: searchTimeoutError('search_files', path, pattern, SEARCH_TIMEOUT_MS / 1000, `Give \`path\` the subdirectory you mean and narrow with \`include\` ` +
1559
+ `(e.g. "*.ts"), or use find_files with the directory in the pattern.`),
1560
+ };
1524
1561
  return { error: `Search failed: ${e.message}` };
1525
1562
  }
1526
1563
  },
@@ -1542,21 +1579,54 @@ export function buildTools(backend, config) {
1542
1579
  const symlinkErr = await checkSymlink(path);
1543
1580
  if (symlinkErr)
1544
1581
  return { error: symlinkErr };
1582
+ // The directory the PATTERN itself names (`node_modules` +
1583
+ // `@molecule/api-resource-user/dist/*.d.ts`) becomes the search root. Matched
1584
+ // against the whole path with an implicit "any parent" anchor, the pattern
1585
+ // made `find` visit every entry below `path` — the whole dependency tree,
1586
+ // which hit the 10 s deadline with no result at all while the one directory
1587
+ // the model meant answered a `list_files` instantly (xr-molecule-flash-m94).
1588
+ // A bare first segment (`helpers/*`) is left alone on purpose: it means "any
1589
+ // `helpers/` below the root" (xr-molecule-flash-m77, see literalDirPrefix).
1590
+ const prefixDir = literalDirPrefix(pattern);
1591
+ let findRoot = path;
1592
+ let findArgs = findPatternArgs(pattern);
1593
+ let missingPrefix;
1545
1594
  try {
1595
+ if (prefixDir) {
1596
+ const candidate = `${path.replace(/\/+$/, '')}/${prefixDir}`;
1597
+ const probe = await backend.run(`test -d ${shellQuote(candidate)}`, {
1598
+ timeout: SEARCH_TIMEOUT_MS,
1599
+ });
1600
+ if (probe.exitCode === 0) {
1601
+ findRoot = candidate;
1602
+ // The remainder keeps the `-path` form: `*` crosses `/`, so a `.d.ts`
1603
+ // in `dist/utilities/` is still found (see findPathArgs).
1604
+ findArgs = findPathArgs(pattern.replace(/^(?:\.?\/)+/, '').slice(prefixDir.length + 1));
1605
+ }
1606
+ else {
1607
+ missingPrefix = `"${candidate}" does not exist; searched all of ${path}.`;
1608
+ }
1609
+ }
1546
1610
  // `findPatternArgs`, not `-name`: a pattern with a `/` in it
1547
1611
  // (`helpers/*`, `e2e/*.spec.ts`) matched nothing at all, because `-name`
1548
1612
  // compares it against the basename (xr-molecule-flash-m77).
1549
- const result = await backend.run(`find ${shellQuote(path)} ${findPruneArgs(path)} ${findPatternArgs(pattern)} -print 2>/dev/null | head -${MAX_FIND_RESULTS}`, { timeout: 10000 });
1613
+ const result = await backend.run(`find ${shellQuote(findRoot)} ${findPruneArgs(findRoot)} ${findArgs} -print 2>/dev/null | head -${MAX_FIND_RESULTS}`, { timeout: SEARCH_TIMEOUT_MS });
1550
1614
  const files = result.stdout.trim().split('\n').filter(Boolean);
1551
1615
  // A slash changes what the pattern means — the whole path, not the file
1552
1616
  // name — and an empty result does not say so, so the model reads it as
1553
1617
  // "no such file" and goes looking elsewhere. Name the rule on the miss.
1554
- const note = files.length === 0 && pattern.includes('/')
1618
+ const missNote = files.length === 0 && pattern.includes('/')
1555
1619
  ? `"${pattern}" contains a "/", so it was matched against each file's PATH below ${path} (a leading "*/" is implicit), not against the file name — no path matched it. list_files shows the real entries.`
1556
1620
  : undefined;
1557
- return { pattern, path, files, ...(note ? { note } : {}) };
1621
+ const notes = [missingPrefix, missNote].filter((n) => Boolean(n));
1622
+ return { pattern, path, files, ...(notes.length ? { note: notes.join(' ') } : {}) };
1558
1623
  }
1559
1624
  catch (e) {
1625
+ if (isCommandTimeout(e))
1626
+ return {
1627
+ error: searchTimeoutError('find_files', findRoot === path ? path : `${findRoot} (under ${path})`, pattern, SEARCH_TIMEOUT_MS / 1000, `Give \`path\` the directory you mean (a package's own folder rather than all of ` +
1628
+ `${path}) or use list_files on it, and keep the pattern narrow.`),
1629
+ };
1560
1630
  return { error: `Find failed: ${e.message}` };
1561
1631
  }
1562
1632
  },
@@ -1825,18 +1895,31 @@ export function buildTools(backend, config) {
1825
1895
  : sanitizeOutput;
1826
1896
  const stdout = grade(truncateMiddle(result.stdout, MAX_OUTPUT_SIZE));
1827
1897
  const stderr = sanitizeOutput(truncateMiddle(result.stderr, MAX_OUTPUT_SIZE));
1828
- if (budgetSeconds && result.exitCode === 124) {
1898
+ // A run a budget stopped is NOT a run that ended: it reports `status: 'cut_at_budget'`,
1899
+ // never a 0 the pipeline produced, and names how far it got. Read from the command, the
1900
+ // output and the clock in one place (cut-run.ts) so every reader of a run's verdict reads
1901
+ // the same state (X1 xr-molecule-flash-m93: `timeout 280 hurl … | tail -60` came back
1902
+ // `exitCode: 0` after 284 s and four of thirteen files, and the executor re-sent it).
1903
+ const cut = commandCutRun(command, { exitCode: result.exitCode, stdout, stderr }, elapsedMs, budgetSeconds);
1904
+ if (cut) {
1905
+ const cutLead = cutRunSentence(cut);
1829
1906
  return {
1830
1907
  stdout,
1831
1908
  stderr,
1832
- exitCode: result.exitCode,
1833
- error: `The command was stopped after ${budgetSeconds}s, this tool's limit; the output above is ` +
1834
- 'everything it printed until then' +
1835
- (/\|\s*(tail|head)\b/.test(command)
1836
- ? ' — and a pipe through tail/head holds everything back until the command ends, so it printed nothing: run it without the pipe (use a line reporter and let the output stream)'
1909
+ status: CUT_AT_BUDGET,
1910
+ exitCode: cut.exitCode,
1911
+ // The facts, so a reader that can also see the suite itself (its own `.hurl` file
1912
+ // count) says the same sentence with the total the output alone cannot give.
1913
+ cutRun: cut,
1914
+ error: `${cutLead} ` +
1915
+ // The tool's own budget stopping a run that printed nothing: keep the sentence that
1916
+ // says why the output is empty, since nothing else in the result can say it.
1917
+ (cut.stoppedBy === 'tool-budget'
1918
+ ? `The output above is everything it printed until then${/\|\s*(tail|head)\b/.test(command)
1919
+ ? ' — and a pipe through tail/head holds everything back until the command ends, so it printed nothing: run it without the pipe (use a line reporter and let the output stream)'
1920
+ : ''}. `
1837
1921
  : '') +
1838
- '. Run a smaller unit per command (one test file, one build step) instead of chaining ' +
1839
- 'a build and a whole suite.',
1922
+ (isSuiteRunCommand(command) ? SUITE_OVER_BUDGET_ADVICE : SPLIT_WORK_ADVICE),
1840
1923
  };
1841
1924
  }
1842
1925
  return {
@@ -2175,6 +2258,28 @@ export function buildTools(backend, config) {
2175
2258
  // the second and third were found by runs stopped before they walked the rest. Null for
2176
2259
  // anything that is not a run with failures in it.
2177
2260
  const causes = failureCausesNote(output);
2261
+ // A backgrounded run is under no tool budget, and the exit file hands back the PIPELINE's
2262
+ // code — so a suite killed at a `timeout 280` the command carried behind a `| tail` reports
2263
+ // 0 here too. The run's start is in its own id ({@link taskStartedAt}), so the bound it used
2264
+ // is readable without new state: say stopped, and never hand the pipeline's 0 back as the
2265
+ // run's (X1 xr-molecule-flash-m93 re-sent that run three times).
2266
+ const run = runByTask.get(taskId);
2267
+ const startedAtMs = taskStartedAt(taskId);
2268
+ const cut = run && startedAtMs !== null
2269
+ ? commandCutRun(run.command, { exitCode, stdout: output, stderr: '' }, Date.now() - startedAtMs, 0)
2270
+ : null;
2271
+ if (cut) {
2272
+ return {
2273
+ taskId,
2274
+ status: CUT_AT_BUDGET,
2275
+ exitCode: cut.exitCode,
2276
+ waitedMs,
2277
+ cutRun: cut,
2278
+ note: [cutRunSentence(cut), causes].filter((n) => Boolean(n)).join(' '),
2279
+ stdout: sanitizeOutput(truncateMiddle(output, MAX_OUTPUT_SIZE)),
2280
+ ...(output.length > MAX_OUTPUT_SIZE ? { truncated: true, fullOutput: log } : {}),
2281
+ };
2282
+ }
2178
2283
  // Same shaping as a foreground exec result, so the executor reads both
2179
2284
  // the same way.
2180
2285
  return {
@@ -274,6 +274,81 @@ export declare function isValidGlob(pattern: string): boolean;
274
274
  * `-path '…'` alternatives, ORed inside parens when there is more than one.
275
275
  */
276
276
  export declare function findPatternArgs(pattern: string): string;
277
+ /**
278
+ * The `-path` alternatives of {@link findPatternArgs}, for a pattern whose
279
+ * directory the caller has already rooted the search at.
280
+ *
281
+ * `find_files` narrows the search root itself when the pattern spells its own
282
+ * directory out (see {@link literalDirPrefix}) — `node_modules` plus
283
+ * `@molecule/api-resource-user/dist/*.d.ts` searched that one directory. The
284
+ * remainder (`*.d.ts`) must then keep the `-path` form rather than collapsing to
285
+ * `-name`: `*` crosses `/` in an fnmatch glob, so the `-path` form still finds a
286
+ * declaration file in a `dist/utilities/` subdirectory, which `-name '*.d.ts'`
287
+ * would drop (a silent partial answer, which is worse than the timeout it
288
+ * replaced).
289
+ *
290
+ * @param pattern - The pattern's remainder, with a `/` in it or not.
291
+ * @returns One or more `-path '…'` alternatives, ORed inside parens when there
292
+ * is more than one.
293
+ */
294
+ export declare function findPathArgs(pattern: string): string;
295
+ /**
296
+ * The directory a GLOB pattern spells out, when it spells one out: everything
297
+ * before the pattern's first glob character, trimmed back to the last `/`.
298
+ *
299
+ * A pattern is matched against the whole path with a leading "any parent"
300
+ * anchor ({@link findPatternArgs}), so `find` visits every entry below the
301
+ * search root. Handed `/workspace/node_modules` and
302
+ * `@molecule/api-resource-user/dist/*.d.ts` — a directory named outright —
303
+ * `find` walked the sandbox's entire dependency tree and hit the tool's 10 s
304
+ * deadline without printing a result (xr-molecule-flash-m94: the one directory
305
+ * the model meant answered a `list_files` in 0 s). The literal prefix is that
306
+ * directory, and rooting the search at it is what keeps the call instant.
307
+ *
308
+ * A BARE first segment (`helpers/*`, `bonds/*`, `e2e/*.spec.ts`) is NOT one:
309
+ * `helpers/*` means "a `helpers/` directory anywhere below the root", which the
310
+ * tool documents and a live run relied on (xr-molecule-flash-m77 — a path
311
+ * pattern is not anchored to one depth). Rooting those at
312
+ * `<root>/helpers` would answer with a SUBSET, silently: the nested
313
+ * `api/src/helpers/` matches would disappear, and a missing file reads as
314
+ * "no such file". So a prefix is returned only when it names a path of two or
315
+ * more segments (`@molecule/api-resource-user/dist`), which is the shape that
316
+ * is a directory rather than a directory name.
317
+ *
318
+ * @param pattern - A pattern already accepted by {@link isValidGlob}.
319
+ * @returns The literal directory prefix, without a trailing slash, or null when
320
+ * the pattern has no glob character, no `/`, or only a bare name before one.
321
+ */
322
+ export declare function literalDirPrefix(pattern: string): string | null;
323
+ /**
324
+ * Whether a backend error is the sandbox's own command deadline.
325
+ *
326
+ * The E2B SDK answers a timed-out `exec` with its generic text —
327
+ * `[deadline_exceeded] the operation timed out: … It can be modified by passing
328
+ * 'timeoutMs' when making the request. Use '0' to disable the timeout.` — which
329
+ * names an option the executor cannot set and says nothing about the search
330
+ * that died. Handing that sentence to the model is what xr-molecule-flash-m94
331
+ * read after `find_files` spent 10 s walking `node_modules`; the tool answers
332
+ * the deadline in its own words instead (see {@link searchTimeoutError}).
333
+ *
334
+ * @param error - The error the backend threw.
335
+ * @returns True when the error reads as a timeout or a deadline.
336
+ */
337
+ export declare function isCommandTimeout(error: unknown): boolean;
338
+ /**
339
+ * The answer a search tool gives when the backend's deadline fires: what was
340
+ * searched, for what, how long the tool allowed, and the two ways to get an
341
+ * answer — a narrower `path`, or a listing. Never the vendor's `timeoutMs`
342
+ * sentence (see {@link isCommandTimeout}).
343
+ *
344
+ * @param tool - The tool that timed out (`find_files`, `search_files`).
345
+ * @param searched - The directory the search actually covered.
346
+ * @param pattern - The pattern it was searching for.
347
+ * @param seconds - The tool's own limit, in seconds.
348
+ * @param hint - What to do differently — the narrower target or the listing tool.
349
+ * @returns The message's text.
350
+ */
351
+ export declare function searchTimeoutError(tool: string, searched: string, pattern: string, seconds: number, hint: string): string;
277
352
  /**
278
353
  * Validate a file tool's `path` argument is a non-empty string. A weak model
279
354
  * sometimes omits it or passes a non-string, which would otherwise crash
@@ -1 +1 @@
1
- {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}