@molecule/api-ai-tools 1.5.5 → 1.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-10-15T20:27:42.092Z
6
+ Generated: 2026-10-15T21:29:34.478Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-ai-tools
@@ -282,6 +282,13 @@ interface ToolBuildConfig {
282
282
  */
283
283
  commandBudgetMs?: number
284
284
 
285
+ /**
286
+ * How long (ms) exec_command waits for a command it backgrounded only because the
287
+ * command asked for more than {@link commandBudgetMs}, before handing back a task
288
+ * id; one that finishes inside it returns like a foreground run. Default 45000.
289
+ */
290
+ overCeilingGraceMs?: number
291
+
285
292
  /**
286
293
  * Directory names `search_files` and `find_files` skip (VS Code
287
294
  * `search.exclude` semantics). Defaults to `DEFAULT_SEARCH_EXCLUDED_DIRS`
@@ -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;AA2B9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAiCnE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CA06CxF"}
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;AA2B9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAuCnE;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAs+CxF"}
package/dist/tools.js CHANGED
@@ -24,6 +24,11 @@ const waitedByTask = new Map();
24
24
  */
25
25
  const logBytesByTask = new Map();
26
26
  import { checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIRS, directoryReadHint, isEnvFilePath, isOutsideRoot, isValidGlob, MAX_BATCH_READ_BYTES, MAX_BATCH_READ_FILES, MAX_FIND_RESULTS, MAX_OUTPUT_SIZE, MAX_READ_RETURN_CHARS, MAX_READ_SIZE, MAX_SEARCH_CONTEXT_LINES, MAX_SEARCH_RESULTS, MAX_WRITE_SIZE, outputIsWithheldUntilExit, parseCheckCommand, parseCheckProblem, pathArgError, redactSecrets, redactSecretsInCode, resolvePath, shellQuote, sliceLines, streamingBackgroundCommand, stripControlChars, truncateMiddle, whitespaceTolerantReplace, } from './utilities.js';
27
+ /**
28
+ * How long exec_command waits for a command it backgrounded only because the
29
+ * command asked for more than the tool's ceiling, before handing back a task id.
30
+ */
31
+ const OVER_CEILING_GRACE_MS = 45_000;
27
32
  /**
28
33
  * Build a complete set of AI agent tools bound to an execution backend.
29
34
  *
@@ -32,7 +37,7 @@ import { checkBlockedCommand, declaredBudgetSeconds, DEFAULT_SEARCH_EXCLUDED_DIR
32
37
  * @returns Array of AITool objects ready to pass to an AI provider
33
38
  */
34
39
  export function buildTools(backend, config) {
35
- const { include, exclude, pathGuards = true, symlinkGuards = false, redactSecrets: doRedact = true, blockDangerousCommands = false, blockCommand, execTimeoutMs = 120_000, commandBudgetMs, searchExcludedDirs, onAfterWrite, onFileDiff, onFileChange, } = config ?? {};
40
+ const { include, exclude, pathGuards = true, symlinkGuards = false, redactSecrets: doRedact = true, blockDangerousCommands = false, blockCommand, execTimeoutMs = 120_000, commandBudgetMs, overCeilingGraceMs = OVER_CEILING_GRACE_MS, searchExcludedDirs, onAfterWrite, onFileDiff, onFileChange, } = config ?? {};
36
41
  const root = backend.projectRoot;
37
42
  // A host-filesystem backend with escape guards off is the combination the
38
43
  // audit flagged: `pathGuards` off lets `..` paths out of the workspace,
@@ -98,9 +103,15 @@ export function buildTools(backend, config) {
98
103
  .run(command, { cwd: path.slice(0, path.lastIndexOf('/')) || '/', timeout: 15_000 })
99
104
  .catch(() => null);
100
105
  const problem = result ? parseCheckProblem(result) : null;
106
+ // JSX in a `.ts` file parses as a type assertion and fails on the first
107
+ // attribute — `Expected ">" but found "className"` — which does not say the
108
+ // file just needs to be `.tsx` (X1 flash-m28: three writes and 2.5 minutes).
109
+ const jsxInTs = problem !== null && /\.ts$/.test(path) && /Expected ">" but found|JSX/i.test(problem)
110
+ ? '\nThis looks like JSX in a `.ts` file: JSX only parses in a `.tsx` file — rename it (and its imports keep the `.js` extension).'
111
+ : '';
101
112
  return problem
102
113
  ? {
103
- syntaxError: `The file no longer parses after this change — fix it before anything else, every build and test fails until it does:\n${problem}`,
114
+ syntaxError: `The file no longer parses after this change — fix it before anything else, every build and test fails until it does:\n${problem}${jsxInTs}`,
104
115
  }
105
116
  : {};
106
117
  }
@@ -796,10 +807,23 @@ export function buildTools(backend, config) {
796
807
  }
797
808
  }
798
809
  const excerpt = renderEditExcerpt(finalContent, spans);
810
+ // A replacement whose old text ended in a newline and whose new text does not
811
+ // joins the line after it onto its last line. Applied as written, but said:
812
+ // flash-m28 saw two lines merged only one round trip later.
813
+ const joined = replacements.filter((r) => typeof r.old_string === 'string' &&
814
+ typeof r.new_string === 'string' &&
815
+ r.old_string.endsWith('\n') &&
816
+ r.new_string !== '' &&
817
+ !r.new_string.endsWith('\n')).length;
799
818
  return {
800
819
  path,
801
820
  ok: true,
802
821
  replacementsApplied: replacements.length - alreadyApplied,
822
+ ...(joined > 0
823
+ ? {
824
+ newlineNote: `${joined === 1 ? 'A replacement' : `${joined} replacements`} removed the line break after the replaced text (old_string ended with a newline, new_string does not), so the next line now continues on the same line. Check the excerpt; add the newline back if that was not intended.`,
825
+ }
826
+ : {}),
803
827
  ...(alreadyApplied > 0 ? { alreadyApplied, note: alreadyNote } : {}),
804
828
  totalLines: countLines(finalContent),
805
829
  ...(excerpt ? { excerpt: sanitizeFileContent(excerpt, path) } : {}),
@@ -1027,6 +1051,44 @@ export function buildTools(backend, config) {
1027
1051
  await backend.writeFile(script, `${streaming.command}\n`);
1028
1052
  await backend.run(`nohup sh -c ${shellQuote(`sh ${script} > ${log} 2>&1; echo $? > ${exitFile}`)} ` +
1029
1053
  `> /dev/null 2>&1 & echo $! > /tmp/${id}.pid`, { cwd, timeout: 15_000 });
1054
+ // A command backgrounded only for the budget it ASKED for often ends in
1055
+ // seconds (a Hurl suite: 37 ms). Handing it back as a task cost a
1056
+ // wait_for_task round trip each time (X1 flash-m20, twice in ten
1057
+ // minutes), so wait a short grace first and return a finished command
1058
+ // exactly as a foreground run returns.
1059
+ if (overCeiling && input.run_in_background !== true) {
1060
+ const graceUntil = Date.now() + overCeilingGraceMs;
1061
+ while (Date.now() < graceUntil) {
1062
+ let code = null;
1063
+ try {
1064
+ const raw = await backend.readFile(exitFile);
1065
+ const parsed = Number.parseInt(raw.trim(), 10);
1066
+ code = Number.isFinite(parsed) ? parsed : 0;
1067
+ }
1068
+ catch (_error) {
1069
+ // No exit file yet: still running.
1070
+ code = null;
1071
+ }
1072
+ if (code !== null) {
1073
+ let output = '';
1074
+ try {
1075
+ output = await backend.readFile(log);
1076
+ }
1077
+ catch (_error) {
1078
+ // Finished without writing anything: an empty output is still a result.
1079
+ output = '';
1080
+ }
1081
+ return {
1082
+ stdout: sanitizeOutput(truncateMiddle(output, MAX_OUTPUT_SIZE)),
1083
+ stderr: '',
1084
+ exitCode: code,
1085
+ ...(output.length > MAX_OUTPUT_SIZE ? { truncated: true, fullOutput: log } : {}),
1086
+ ...(streaming.changes.length ? { note: streaming.changes.join(' ') } : {}),
1087
+ };
1088
+ }
1089
+ await new Promise((r) => setTimeout(r, 1_500));
1090
+ }
1091
+ }
1030
1092
  return {
1031
1093
  taskId: id,
1032
1094
  log,
package/dist/types.d.ts CHANGED
@@ -99,6 +99,12 @@ export interface ToolBuildConfig {
99
99
  * little under that outer timeout. Unset = no budget.
100
100
  */
101
101
  commandBudgetMs?: number;
102
+ /**
103
+ * How long (ms) exec_command waits for a command it backgrounded only because the
104
+ * command asked for more than {@link commandBudgetMs}, before handing back a task
105
+ * id; one that finishes inside it returns like a foreground run. Default 45000.
106
+ */
107
+ overCeilingGraceMs?: number;
102
108
  /**
103
109
  * Directory names `search_files` and `find_files` skip (VS Code
104
110
  * `search.exclude` semantics). Defaults to `DEFAULT_SEARCH_EXCLUDED_DIRS`
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yFAAyF;IACzF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAE5B;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IAEzB,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAEvC,qEAAqE;IACrE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvD,qBAAqB;IACrB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvC,mCAAmC;IACnC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;KAAE,CAAC,CAAC,CAAA;IAEnF;;;OAGG;IACH,GAAG,CACD,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB;;;;;WAKG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,GACA,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACjE;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAElB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAElB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAA;IAEpB,2FAA2F;IAC3F,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB,iFAAiF;IACjF,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB,2FAA2F;IAC3F,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAEhC;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAE1E;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IAExB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAE3B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE7B,uGAAuG;IACvG,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9C,yEAAyE;IACzE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAA;IAE3C,wFAAwF;IACxF,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;CAChD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,CAAA;IACxC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAA;IAEjB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAA;IAEnB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,EAAE,CAAA;IAEf,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IAEjB,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAA;IAE/B,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "description": "Shared AI agent tools with backend abstraction for sandbox and local execution",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",