@molecule/api-ai-tools 1.10.0 → 1.10.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAyU1C,CAAA"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,UAAU,CAAA;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CA2U1C,CAAA"}
package/dist/schemas.js CHANGED
@@ -132,7 +132,8 @@ export const TOOL_SCHEMAS = {
132
132
  },
133
133
  include: {
134
134
  type: 'string',
135
- description: "File glob pattern to filter files (e.g. '*.ts', '*.tsx'). Optional.",
135
+ description: "File glob pattern to filter files (e.g. '*.ts', '*.tsx'). Several extensions go in one " +
136
+ "brace group of comma-separated alternatives: '*.{ts,tsx,yml,json,md}' (up to 16). Optional.",
136
137
  },
137
138
  contextLines: {
138
139
  type: 'number',
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AA4K9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AA6ZD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAqFnE;;;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;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAoBpF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GACxE,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AA2GD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAguFxF"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AA4K9C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAahG;AA6ZD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAqFnE;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAEA,CAAA;AAE9B;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,QAI6C,CAAA;AA2ElF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUhE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAA;AAoBpF;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GACxE,qBAAqB,CAkBvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,qBAAqB,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AA2GD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,EAAE,CAyuFxF"}
package/dist/tools.js CHANGED
@@ -596,6 +596,62 @@ export const SUITE_OVER_BUDGET_ADVICE = 'A test suite is not a bigger unit to sp
596
596
  * sentence, which names an option the executor cannot set.
597
597
  */
598
598
  const SEARCH_TIMEOUT_MS = 10_000;
599
+ /**
600
+ * The most alternatives one brace group in a `search_files` include may expand
601
+ * to. The point is to accept the ordinary multi-extension form a model writes
602
+ * from habit (`*.{ts,tsx,yml,json,md}`), not to grow a glob engine: a group is
603
+ * bounded so a pattern cannot turn one grep call into hundreds.
604
+ */
605
+ const MAX_INCLUDE_BRACE_ALTERNATIVES = 16;
606
+ /**
607
+ * Expand ONE level of brace alternatives in a `search_files` include pattern,
608
+ * validating every expanded pattern.
609
+ *
610
+ * `grep --include` has no brace expansion of its own (the shell that would do it
611
+ * is never involved — the pattern is `shellQuote`d first), so the group has to
612
+ * be expanded here and each alternative passed as its own `--include`. The
613
+ * m189 run wrote the everyday `*.{ts,tsx,yml,json,md}` and the search was
614
+ * refused outright, costing a round trip and pushing the agent to a narrower
615
+ * search.
616
+ *
617
+ * Bounded on purpose: one level of braces, alternatives split on `,`, at most
618
+ * {@link MAX_INCLUDE_BRACE_ALTERNATIVES}, none empty, and each EXPANDED
619
+ * pattern must still pass {@link isValidGlob} — so a shell metacharacter in any
620
+ * alternative (`*.{ts,$(rm)}`) is refused exactly as a bare one is.
621
+ *
622
+ * @param pattern - The user-supplied `include` value.
623
+ * @returns Every pattern to pass to grep, or null when the value is not
624
+ * accepted (the caller reports the include-glob error).
625
+ */
626
+ function expandIncludeGlob(pattern) {
627
+ const open = pattern.indexOf('{');
628
+ if (open === -1)
629
+ return isValidGlob(pattern) ? [pattern] : null;
630
+ const close = pattern.indexOf('}', open + 1);
631
+ if (close === -1)
632
+ return null;
633
+ // One level only: a second `{` before the close or a second `}` after it is a
634
+ // nested/malformed group, not an alternative.
635
+ const nextOpen = pattern.indexOf('{', open + 1);
636
+ if (nextOpen !== -1 && nextOpen < close)
637
+ return null;
638
+ if (pattern.indexOf('}', close + 1) !== -1)
639
+ return null;
640
+ const alternatives = pattern.slice(open + 1, close).split(',');
641
+ if (alternatives.length > MAX_INCLUDE_BRACE_ALTERNATIVES)
642
+ return null;
643
+ if (alternatives.some((alt) => alt.length === 0))
644
+ return null;
645
+ const expanded = alternatives.map((alt) => `${pattern.slice(0, open)}${alt}${pattern.slice(close + 1)}`);
646
+ return expanded.every((p) => isValidGlob(p)) ? expanded : null;
647
+ }
648
+ /**
649
+ * The include-glob error. It keeps the original character-rule sentence and
650
+ * names the accepted multi-extension form, so a refusal teaches the syntax
651
+ * rather than only reporting that the value was wrong.
652
+ */
653
+ const INCLUDE_GLOB_ERROR = 'Invalid include glob pattern. Allowed: alphanumeric and @ * ? . _ - / [ ] ( ), ' +
654
+ 'or one brace group of up to 16 comma-separated alternatives such as *.{ts,tsx}.';
599
655
  /**
600
656
  * The share of its budget a command must use before the "you asked for more than
601
657
  * this tool's ceiling" note is worth attaching. Below it the clamp changed nothing
@@ -1654,7 +1710,14 @@ export function buildTools(backend, config) {
1654
1710
  await backend.writeFile(path, content);
1655
1711
  if (onAfterWrite)
1656
1712
  await onAfterWrite(path).catch(() => { });
1657
- const finalContent = await backend.readFile(path).catch(() => content);
1713
+ // The text on disk is the text just written unless an after-write hook (a formatter)
1714
+ // may have rewritten it. Without one, the re-read is a whole sandbox round trip per
1715
+ // write that can only return what is already in hand — measured in the write path's
1716
+ // own timings (x0 fast-file-writes: four sandbox calls per write, one of them this
1717
+ // re-read, and the excerpt it feeds is identical either way).
1718
+ const finalContent = onAfterWrite
1719
+ ? await backend.readFile(path).catch(() => content)
1720
+ : content;
1658
1721
  const diff = computeDiff(oldContent, finalContent);
1659
1722
  if (onFileChange)
1660
1723
  onFileChange({ type: oldContent === null ? 'created' : 'modified', path });
@@ -2179,15 +2242,18 @@ export function buildTools(backend, config) {
2179
2242
  const contextLines = Number.isFinite(rawContext)
2180
2243
  ? Math.min(Math.max(Math.trunc(rawContext), 0), MAX_SEARCH_CONTEXT_LINES)
2181
2244
  : 0;
2182
- if (include && !isValidGlob(include))
2183
- return {
2184
- error: 'Invalid include glob pattern. Allowed: alphanumeric and @ * ? . _ - / [ ] ( ).',
2185
- };
2245
+ // `--include` has no brace expansion inside the quoted grep argument, so
2246
+ // a brace group is expanded here and grep gets one --include per pattern.
2247
+ const includes = include ? expandIncludeGlob(include) : [];
2248
+ if (includes === null)
2249
+ return { error: INCLUDE_GLOB_ERROR };
2186
2250
  const symlinkErr = await checkSymlink(path);
2187
2251
  if (symlinkErr)
2188
2252
  return { error: symlinkErr };
2189
2253
  try {
2190
- const globArg = include ? `--include=${shellQuote(include)}` : '';
2254
+ const globArg = includes.length
2255
+ ? includes.map((p) => `--include=${shellQuote(p)}`).join(' ')
2256
+ : '';
2191
2257
  // With context, grep emits `file-line-content` for context lines and
2192
2258
  // `file:line:content` for matches, plus `--` group separators. Both
2193
2259
  // shapes are parsed below; without context the output is unchanged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-ai-tools",
3
- "version": "1.10.0",
3
+ "version": "1.10.1",
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",