@wrongstack/tools 0.320.1 → 1.0.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.
Files changed (192) hide show
  1. package/dist/_danger-detect.d.ts +8 -0
  2. package/dist/_syntax-check.d.ts +1 -2
  3. package/dist/audit.d.ts +4 -5
  4. package/dist/audit.js +6 -6
  5. package/dist/auto-proceed-loop-guard.d.ts +1 -1
  6. package/dist/auto-proceed-loop-guard.js +9 -160
  7. package/dist/bash-kill-guard.d.ts +2 -3
  8. package/dist/bash.d.ts +2 -3
  9. package/dist/bash.js +4 -4
  10. package/dist/batch-tool-use.d.ts +2 -3
  11. package/dist/batch-tool-use.js +1 -1
  12. package/dist/browser/index.d.ts +1 -1
  13. package/dist/browser/index.js +1 -1
  14. package/dist/browser/tools.d.ts +56 -45
  15. package/dist/builtin.js +50 -50
  16. package/dist/{chunk-T77XOX7E.js → chunk-24T5XIJU.js} +1 -1
  17. package/dist/{chunk-DTQ75VBC.js → chunk-2CTZW6JQ.js} +2 -2
  18. package/dist/{chunk-KWXIKGE3.js → chunk-3D5DJWOE.js} +3 -3
  19. package/dist/{chunk-XSSFBS5I.js → chunk-4ERMPDHV.js} +11 -6
  20. package/dist/{chunk-QSNVDHOZ.js → chunk-4WPBS45A.js} +4 -5
  21. package/dist/{chunk-4CQWNZ62.js → chunk-5ITQPCLC.js} +2 -2
  22. package/dist/{chunk-B4HTSV6Z.js → chunk-5KS24LTS.js} +11 -11
  23. package/dist/{chunk-QPNYDH5B.js → chunk-62OAECEQ.js} +29 -7
  24. package/dist/{chunk-DFQDJT22.js → chunk-6GOZTS6F.js} +3 -3
  25. package/dist/{chunk-5UFVCIUB.js → chunk-6H4ERJP7.js} +140 -24
  26. package/dist/{chunk-34VLZ35Z.js → chunk-7HL23T3T.js} +63 -10
  27. package/dist/{chunk-HFXSNKCV.js → chunk-7JJFC6CT.js} +1 -1
  28. package/dist/{chunk-23EX5WDO.js → chunk-7LQCT3LT.js} +3 -3
  29. package/dist/{chunk-NDIT3SBZ.js → chunk-7N5U2RAU.js} +2 -2
  30. package/dist/{chunk-QBV725YG.js → chunk-7ODZTPCU.js} +2 -2
  31. package/dist/{chunk-6AAOT4PW.js → chunk-AQ5YBURX.js} +16 -4
  32. package/dist/{chunk-ZMW6WJFT.js → chunk-ASEXQRA7.js} +3 -3
  33. package/dist/{chunk-FRN7TIAA.js → chunk-B3MGJBFI.js} +1 -1
  34. package/dist/{chunk-JLYA4X7K.js → chunk-CGXTR34H.js} +21 -6
  35. package/dist/{chunk-IU4DV2PA.js → chunk-CHEK3ASV.js} +6 -3
  36. package/dist/{chunk-GOIZNNOA.js → chunk-DJYLI7EW.js} +1 -1
  37. package/dist/{chunk-Z6IHMJMC.js → chunk-DK4J2WMH.js} +11 -11
  38. package/dist/{chunk-OYP27E3I.js → chunk-DRRY6SCM.js} +47 -20
  39. package/dist/{chunk-JVRLTEO7.js → chunk-E7JE3UEX.js} +2 -2
  40. package/dist/{chunk-BK732J7I.js → chunk-FBUP524S.js} +4 -4
  41. package/dist/{chunk-NYRLWDT5.js → chunk-FVM3O4JQ.js} +1 -1
  42. package/dist/chunk-FYDBUVQD.js +244 -0
  43. package/dist/{chunk-PV6HIZQD.js → chunk-GDDXX27P.js} +50 -50
  44. package/dist/{chunk-3GIKYHLA.js → chunk-GKSG5CPH.js} +6 -6
  45. package/dist/{chunk-ESLPBT5A.js → chunk-HDYUBRMF.js} +4 -3
  46. package/dist/{chunk-4BABEJC2.js → chunk-IAYMTTR2.js} +236 -79
  47. package/dist/{chunk-ELRRTWNP.js → chunk-IXIS7RSG.js} +2 -2
  48. package/dist/{chunk-HR67OWEP.js → chunk-IYH4OHBP.js} +5 -5
  49. package/dist/{chunk-W232EFEM.js → chunk-JDOO4P6Z.js} +7 -4
  50. package/dist/{chunk-2OXHS3KZ.js → chunk-KLJZ4WV4.js} +4 -3
  51. package/dist/{chunk-3M7LLN7W.js → chunk-LQSOU63Z.js} +12 -11
  52. package/dist/{chunk-OTPTQBYE.js → chunk-MGPR7VG3.js} +279 -265
  53. package/dist/{chunk-C2DQKVLO.js → chunk-MJSJWXBF.js} +1 -1
  54. package/dist/{chunk-NSPNFOJ7.js → chunk-MK2JK35J.js} +25 -10
  55. package/dist/{chunk-JSNSMG5R.js → chunk-MSOAX3GC.js} +1 -1
  56. package/dist/{chunk-J43O3BOX.js → chunk-N3K2SFEI.js} +532 -492
  57. package/dist/{chunk-J74TMK4M.js → chunk-NJX2RXKJ.js} +50 -7
  58. package/dist/chunk-NL2S2CXD.js +171 -0
  59. package/dist/{chunk-WAQASTXB.js → chunk-O6BY43ZB.js} +29 -8
  60. package/dist/{chunk-QGF2C7TF.js → chunk-PVCB7RUZ.js} +2 -2
  61. package/dist/{chunk-YTKSNTT4.js → chunk-QA6IASYX.js} +8 -8
  62. package/dist/{chunk-VPALDFYM.js → chunk-RV7BVTDG.js} +1 -1
  63. package/dist/chunk-S57CDR2H.js +288 -0
  64. package/dist/{chunk-W2CECGTG.js → chunk-SMARDKAC.js} +1 -1
  65. package/dist/{chunk-QWKSKFKZ.js → chunk-SOR7OCYP.js} +1 -1
  66. package/dist/{chunk-I7FBZOEP.js → chunk-T3SMFF5Q.js} +11 -5
  67. package/dist/{chunk-4BHUSMNL.js → chunk-UI3ZJIG3.js} +1 -1
  68. package/dist/{chunk-WXJY3BKV.js → chunk-VBF2YXUW.js} +2 -2
  69. package/dist/{chunk-FQNXYA6W.js → chunk-VU3QBYL4.js} +36 -5
  70. package/dist/{chunk-VD2LV5WO.js → chunk-VZGPASGD.js} +37 -12
  71. package/dist/{chunk-UZFY3CKD.js → chunk-WEEVSWQB.js} +17 -6
  72. package/dist/chunk-XXRMF2BC.js +186 -0
  73. package/dist/{chunk-LRDIRJJL.js → chunk-YEISRT4S.js} +5 -11
  74. package/dist/{chunk-Q5JPPCZC.js → chunk-YJTXRH5Y.js} +3 -2
  75. package/dist/{chunk-Z5Q3TXRY.js → chunk-ZTCJCYLN.js} +3 -3
  76. package/dist/circuit-breaker.d.ts +1 -0
  77. package/dist/circuit-breaker.js +1 -1
  78. package/dist/clarify.d.ts +1 -0
  79. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +2 -3
  80. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +5 -4
  81. package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +4 -3
  82. package/dist/codebase-index/codebase-index-tool.d.ts +2 -3
  83. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +2 -3
  84. package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +4 -3
  85. package/dist/codebase-index/codebase-repo-map-tool.d.ts +2 -3
  86. package/dist/codebase-index/codebase-search-tool.d.ts +2 -3
  87. package/dist/codebase-index/codebase-skeleton-tool.d.ts +2 -3
  88. package/dist/codebase-index/codebase-stats-tool.d.ts +9 -3
  89. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +4 -3
  90. package/dist/codebase-index/index.d.ts +11 -11
  91. package/dist/codebase-index/index.js +8 -8
  92. package/dist/codebase-index/project-server-framing.d.ts +29 -0
  93. package/dist/codebase-index/project-server-lifecycle.d.ts +20 -0
  94. package/dist/codebase-index/project-server-operations.d.ts +37 -0
  95. package/dist/codebase-index/project-server-types.d.ts +30 -0
  96. package/dist/codebase-index/project-server-watcher.d.ts +25 -0
  97. package/dist/codebase-index/project-server.js +448 -391
  98. package/dist/codebase-index/worker.js +2 -2
  99. package/dist/codebase-index/writer-init.d.ts +13 -0
  100. package/dist/codebase-index/writer-maintenance.d.ts +14 -0
  101. package/dist/codebase-index/writer.d.ts +0 -15
  102. package/dist/design.d.ts +2 -2
  103. package/dist/design.js +1 -1
  104. package/dist/diff.d.ts +4 -4
  105. package/dist/diff.js +1 -1
  106. package/dist/document.d.ts +3 -4
  107. package/dist/document.js +1 -1
  108. package/dist/e2e.d.ts +1 -1
  109. package/dist/e2e.js +1 -1
  110. package/dist/edit.d.ts +3 -3
  111. package/dist/edit.js +6 -6
  112. package/dist/exec.d.ts +2 -3
  113. package/dist/exec.js +4 -4
  114. package/dist/fetch.d.ts +4 -3
  115. package/dist/fetch.js +1 -1
  116. package/dist/format.d.ts +17 -45
  117. package/dist/format.js +12 -8
  118. package/dist/git.d.ts +3 -3
  119. package/dist/git.js +1 -1
  120. package/dist/glob.d.ts +2 -3
  121. package/dist/glob.js +2 -2
  122. package/dist/grep.d.ts +7 -5
  123. package/dist/grep.js +3 -3
  124. package/dist/index.d.ts +54 -45
  125. package/dist/index.js +118 -59
  126. package/dist/install.d.ts +7 -55
  127. package/dist/install.js +6 -6
  128. package/dist/json.d.ts +3 -4
  129. package/dist/json.js +2 -2
  130. package/dist/kanban-tool-types.d.ts +1 -2
  131. package/dist/kanban.d.ts +3 -19
  132. package/dist/kanban.js +1 -1
  133. package/dist/languages/execute-tool.d.ts +2 -3
  134. package/dist/languages/index.d.ts +2 -2
  135. package/dist/languages/index.js +4 -4
  136. package/dist/languages/tool.d.ts +3 -4
  137. package/dist/{legacy-bridge-FOV5ODDI.js → legacy-bridge-YXANP5QB.js} +6 -6
  138. package/dist/lint.d.ts +5 -4
  139. package/dist/lint.js +6 -6
  140. package/dist/logs.d.ts +3 -4
  141. package/dist/logs.js +2 -2
  142. package/dist/memory.d.ts +7 -8
  143. package/dist/memory.js +1 -1
  144. package/dist/mode.d.ts +3 -4
  145. package/dist/mode.js +1 -1
  146. package/dist/next-steps-tool.d.ts +2 -3
  147. package/dist/next-steps.d.ts +4 -0
  148. package/dist/next-steps.js +9 -175
  149. package/dist/outdated.d.ts +5 -29
  150. package/dist/outdated.js +3 -3
  151. package/dist/pack.js +51 -51
  152. package/dist/patch.d.ts +2 -3
  153. package/dist/patch.js +5 -5
  154. package/dist/plan.d.ts +4 -4
  155. package/dist/plan.js +3 -3
  156. package/dist/process-registry.js +2 -2
  157. package/dist/ps-slash.js +4 -4
  158. package/dist/pwsh.d.ts +1 -0
  159. package/dist/read.d.ts +5 -5
  160. package/dist/read.js +5 -5
  161. package/dist/replace.d.ts +2 -3
  162. package/dist/replace.js +6 -6
  163. package/dist/scaffold.d.ts +7 -3
  164. package/dist/scaffold.js +3 -1
  165. package/dist/search.d.ts +17 -3
  166. package/dist/search.js +5 -1
  167. package/dist/set-working-dir.d.ts +2 -3
  168. package/dist/skill.d.ts +4 -5
  169. package/dist/skill.js +1 -1
  170. package/dist/task.d.ts +6 -6
  171. package/dist/task.js +3 -3
  172. package/dist/test.d.ts +5 -4
  173. package/dist/test.js +6 -6
  174. package/dist/todo.d.ts +8 -8
  175. package/dist/todo.js +2 -2
  176. package/dist/tool-diff.js +11 -230
  177. package/dist/tool-help.d.ts +2 -3
  178. package/dist/tool-help.js +1 -1
  179. package/dist/tool-search.d.ts +2 -3
  180. package/dist/tool-search.js +1 -1
  181. package/dist/tool-summary.js +5 -281
  182. package/dist/tool-tier.js +52 -52
  183. package/dist/tool-use.d.ts +2 -3
  184. package/dist/tool-use.js +1 -1
  185. package/dist/tree.d.ts +5 -3
  186. package/dist/tree.js +5 -1
  187. package/dist/typecheck.d.ts +3 -3
  188. package/dist/typecheck.js +6 -6
  189. package/dist/write.d.ts +2 -3
  190. package/dist/write.js +6 -6
  191. package/package.json +5 -5
  192. package/dist/spawn-background.d.ts +0 -80
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  tryLegacyCodeOperation
3
- } from "./chunk-I7FBZOEP.js";
3
+ } from "./chunk-T3SMFF5Q.js";
4
4
  import {
5
5
  spawnStream
6
- } from "./chunk-OYP27E3I.js";
6
+ } from "./chunk-DRRY6SCM.js";
7
7
  import {
8
8
  normalizeCommandOutput,
9
9
  safeResolveReal
@@ -181,4 +181,4 @@ async function detectLinter(cwd) {
181
181
  export {
182
182
  lintTool
183
183
  };
184
- //# sourceMappingURL=chunk-KWXIKGE3.js.map
184
+ //# sourceMappingURL=chunk-3D5DJWOE.js.map
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  capSubject,
3
3
  compileUserRegex
4
- } from "./chunk-Q5JPPCZC.js";
4
+ } from "./chunk-YJTXRH5Y.js";
5
5
  import {
6
6
  mapWithConcurrency
7
7
  } from "./chunk-ZBMANLYH.js";
8
8
  import {
9
9
  loadGitignoreMatcher
10
- } from "./chunk-DTQ75VBC.js";
10
+ } from "./chunk-2CTZW6JQ.js";
11
11
  import {
12
12
  isBinaryBuffer,
13
13
  safeResolveReal
@@ -374,6 +374,7 @@ async function runNative(input, base, mode, limit, signal) {
374
374
  const maxBytes = NATIVE_MAX_FILE_BYTES;
375
375
  let total = 0;
376
376
  let stopped = false;
377
+ let countTruncated = false;
377
378
  const scanFile = async (full, name, rel) => {
378
379
  if (stopped || signal.aborted) return;
379
380
  if (globRe) {
@@ -449,8 +450,12 @@ async function runNative(input, base, mode, limit, signal) {
449
450
  }
450
451
  }
451
452
  if (fileHits > 0) {
452
- if (mode === "count" && matches.length < limit) {
453
- matches.push(`${full}:${fileHits}`);
453
+ if (mode === "count") {
454
+ if (matches.length < limit) {
455
+ matches.push(`${full}:${fileHits}`);
456
+ } else {
457
+ countTruncated = true;
458
+ }
454
459
  }
455
460
  if (mode === "files_with_matches" && matches.length >= limit) stopped = true;
456
461
  }
@@ -507,7 +512,7 @@ async function runNative(input, base, mode, limit, signal) {
507
512
  return {
508
513
  matches,
509
514
  count: total,
510
- truncated: stopped,
515
+ truncated: stopped || countTruncated,
511
516
  used: "native"
512
517
  };
513
518
  }
@@ -517,4 +522,4 @@ export {
517
522
  __resetRgDetectionForTests,
518
523
  __setRgAvailableForTests
519
524
  };
520
- //# sourceMappingURL=chunk-XSSFBS5I.js.map
525
+ //# sourceMappingURL=chunk-4ERMPDHV.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  tryLegacyCodeOperation
3
- } from "./chunk-I7FBZOEP.js";
3
+ } from "./chunk-T3SMFF5Q.js";
4
4
  import {
5
5
  spawnStream
6
- } from "./chunk-OYP27E3I.js";
6
+ } from "./chunk-DRRY6SCM.js";
7
7
  import {
8
8
  detectPackageManager,
9
9
  normalizeCommandOutput,
@@ -118,8 +118,7 @@ var typecheckTool = {
118
118
  signal,
119
119
  maxBytes: 2e5
120
120
  });
121
- const combined = `${result.stdout}
122
- ${result.stderr}`;
121
+ const combined = [result.stdout, result.stderr, result.error].filter(Boolean).join("\n");
123
122
  let errors = [...combined.matchAll(/^.*\berror TS\d+:/gmi)].length;
124
123
  const warnings = [...combined.matchAll(/^.*\bwarning TS\d+:/gmi)].length;
125
124
  if (errors === 0 && result.exitCode !== 0) {
@@ -163,4 +162,4 @@ async function findTsConfig(cwd) {
163
162
  export {
164
163
  typecheckTool
165
164
  };
166
- //# sourceMappingURL=chunk-QSNVDHOZ.js.map
165
+ //# sourceMappingURL=chunk-4WPBS45A.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getPersistentProcessRegistry
3
- } from "./chunk-QGF2C7TF.js";
3
+ } from "./chunk-PVCB7RUZ.js";
4
4
 
5
5
  // src/ps-slash.ts
6
6
  import * as os from "node:os";
@@ -334,4 +334,4 @@ export {
334
334
  formatInstanceSummary,
335
335
  createGlobalPsSlashCommand
336
336
  };
337
- //# sourceMappingURL=chunk-4CQWNZ62.js.map
337
+ //# sourceMappingURL=chunk-5ITQPCLC.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  todoTool
3
- } from "./chunk-BK732J7I.js";
3
+ } from "./chunk-FBUP524S.js";
4
4
  import {
5
5
  projectSessionPlanToKanban
6
6
  } from "./chunk-X6KXNHUO.js";
@@ -308,17 +308,17 @@ var planTool = {
308
308
  );
309
309
  return p;
310
310
  }
311
- let itemIdx = -1;
312
- const asNum = Number.parseInt(input.target, 10);
313
- if (!Number.isNaN(asNum) && asNum >= 1 && asNum <= p.items.length) {
314
- itemIdx = asNum - 1;
315
- } else {
316
- itemIdx = p.items.findIndex((it) => it.id === input.target);
317
- if (itemIdx === -1) {
318
- const lower = input.target.toLowerCase();
319
- itemIdx = p.items.findIndex((it) => it.title.toLowerCase().includes(lower));
311
+ let itemIdx = p.items.findIndex((it) => it.id === input.target);
312
+ if (itemIdx === -1 && /^[1-9]\d*$/.test(input.target)) {
313
+ const asNum = Number.parseInt(input.target, 10) - 1;
314
+ if (asNum >= 0 && asNum < p.items.length) {
315
+ itemIdx = asNum;
320
316
  }
321
317
  }
318
+ if (itemIdx === -1) {
319
+ const lower = input.target.toLowerCase();
320
+ itemIdx = p.items.findIndex((it) => it.title.toLowerCase().includes(lower));
321
+ }
322
322
  if (itemIdx === -1 || !p.items[itemIdx]) {
323
323
  early = mkResult(p, false, `No plan item matched "${input.target}".`);
324
324
  return p;
@@ -414,4 +414,4 @@ function mkResult(plan, ok, message, todos) {
414
414
  export {
415
415
  planTool
416
416
  };
417
- //# sourceMappingURL=chunk-B4HTSV6Z.js.map
417
+ //# sourceMappingURL=chunk-5KS24LTS.js.map
@@ -63,8 +63,21 @@ var searchTool = {
63
63
  });
64
64
  }
65
65
  const signal = opts?.signal ?? ctx?.signal ?? new AbortController().signal;
66
+ if (input.num_results !== void 0 && (typeof input.num_results !== "number" || !Number.isFinite(input.num_results) || input.num_results <= 0)) {
67
+ throw new ToolValidationError({
68
+ message: "search: num_results must be a positive integer",
69
+ field: "num_results"
70
+ });
71
+ }
66
72
  const rawNum = typeof input.num_results === "number" && !Number.isNaN(input.num_results) ? input.num_results : DEFAULT_NUM;
67
73
  const num = Math.max(1, Math.min(Math.floor(rawNum), MAX_RESULTS));
74
+ const VALID_SOURCES = /* @__PURE__ */ new Set(["duckduckgo", "google", "bing"]);
75
+ if (input.source !== void 0 && !VALID_SOURCES.has(input.source)) {
76
+ throw new ToolValidationError({
77
+ message: `search: unknown source "${input.source}"`,
78
+ field: "source"
79
+ });
80
+ }
68
81
  const source = input.source ?? "duckduckgo";
69
82
  const skipCache = input.skip_cache ?? false;
70
83
  const normalizedQuery = input.query.trim().toLowerCase().replace(/\s+/g, " ");
@@ -77,21 +90,22 @@ var searchTool = {
77
90
  url: r.url,
78
91
  snippet: r.snippet
79
92
  }));
93
+ const finalResults2 = results.slice(0, num);
80
94
  yield {
81
95
  type: "log",
82
- text: `Cache hit for "${input.query}" (${source})`,
83
- data: { source, query: input.query, cached: true }
96
+ text: `Cache hit for "${input.query}" (${entry.source})`,
97
+ data: { source: entry.source, query: input.query, cached: true }
84
98
  };
85
99
  yield {
86
100
  type: "partial_output",
87
- text: `${results.length} cached results from ${entry.source}`,
88
- data: { count: results.length, cached: true, source: entry.source }
101
+ text: `${finalResults2.length} cached results from ${entry.source}`,
102
+ data: { count: finalResults2.length, cached: true, source: entry.source }
89
103
  };
90
104
  yield {
91
105
  type: "final",
92
106
  output: {
93
107
  query: input.query,
94
- results: results.slice(0, num),
108
+ results: finalResults2,
95
109
  source: entry.source,
96
110
  truncated: results.length > num,
97
111
  cached: true
@@ -181,6 +195,12 @@ function pruneCacheEntries() {
181
195
  function __clearSearchCache() {
182
196
  cache.clear();
183
197
  }
198
+ function __setSearchCacheForTest(key, entry) {
199
+ cache.set(key, entry);
200
+ }
201
+ function __getSearchCacheSizeForTest() {
202
+ return cache.size;
203
+ }
184
204
  function rankSearchResults(results, query) {
185
205
  const seenUrls = /* @__PURE__ */ new Set();
186
206
  const deduped = [];
@@ -445,6 +465,8 @@ function decodeHtmlEntities(text) {
445
465
 
446
466
  export {
447
467
  searchTool,
448
- __clearSearchCache
468
+ __clearSearchCache,
469
+ __setSearchCacheForTest,
470
+ __getSearchCacheSizeForTest
449
471
  };
450
- //# sourceMappingURL=chunk-QPNYDH5B.js.map
472
+ //# sourceMappingURL=chunk-62OAECEQ.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getProcessRegistry,
3
3
  redactCommand
4
- } from "./chunk-ESLPBT5A.js";
4
+ } from "./chunk-HDYUBRMF.js";
5
5
  import {
6
6
  buildWin32CmdShimInvocation,
7
7
  resolveWin32Command
@@ -66,7 +66,7 @@ var outdatedTool = {
66
66
  const manager = await detectPackageManager(cwd, ctx.projectRoot);
67
67
  if (manager === "npm") {
68
68
  try {
69
- const { detectNonJsEcosystem } = await import("./legacy-bridge-FOV5ODDI.js");
69
+ const { detectNonJsEcosystem } = await import("./legacy-bridge-YXANP5QB.js");
70
70
  const nonJs = await detectNonJsEcosystem(cwd, ctx.projectRoot);
71
71
  if (nonJs) {
72
72
  const { planLanguageOperation, executePackagePlan } = await import("./languages/index.js");
@@ -282,4 +282,4 @@ Note: exit code 1 from \`outdated\` means outdated packages were found (expected
282
282
  export {
283
283
  outdatedTool
284
284
  };
285
- //# sourceMappingURL=chunk-DFQDJT22.js.map
285
+ //# sourceMappingURL=chunk-6GOZTS6F.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-BTSFTGIL.js";
4
4
  import {
5
5
  getPersistentProcessRegistry
6
- } from "./chunk-QGF2C7TF.js";
6
+ } from "./chunk-PVCB7RUZ.js";
7
7
  import {
8
8
  createOutputSpool,
9
9
  spoolNote
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  getProcessRegistry,
13
13
  redactCommand
14
- } from "./chunk-ESLPBT5A.js";
14
+ } from "./chunk-HDYUBRMF.js";
15
15
  import {
16
16
  resolvePowerShell
17
17
  } from "./chunk-KE7A76VC.js";
@@ -627,17 +627,51 @@ var bashTool = {
627
627
  const detached = !isWin2;
628
628
  const startedAt = Date.now();
629
629
  if (input.background) {
630
- const child2 = spawn(shell, args, {
631
- cwd: spawnCwd,
632
- env,
633
- stdio: ["ignore", "ignore", "ignore"],
634
- detached: !isWin2,
635
- windowsHide: true
636
- });
630
+ let child2;
631
+ try {
632
+ child2 = spawn(shell, args, {
633
+ cwd: spawnCwd,
634
+ env,
635
+ stdio: ["ignore", "ignore", "ignore"],
636
+ detached: !isWin2,
637
+ windowsHide: true
638
+ });
639
+ } catch (err) {
640
+ registry.afterCall(Date.now() - startedAt, true, bypassBreaker);
641
+ emitProcessStarted({
642
+ parentPid: process.pid,
643
+ command: redactCommand(`${shell} ${args.join(" ")}`),
644
+ args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
645
+ cwd: spawnCwd,
646
+ background: true,
647
+ startedAt: new Date(startedAt).toISOString()
648
+ });
649
+ emitProcessCompleted({
650
+ exitCode: 1,
651
+ durationMs: Date.now() - startedAt,
652
+ stdoutBytes: 0,
653
+ stderrBytes: 0,
654
+ timedOut: false,
655
+ endedAt: (/* @__PURE__ */ new Date()).toISOString()
656
+ });
657
+ yield {
658
+ type: "final",
659
+ output: {
660
+ output: "",
661
+ exit_code: 1,
662
+ timed_out: false,
663
+ pid: null,
664
+ error: `spawn failed: ${err instanceof Error ? err.message : String(err)}`
665
+ }
666
+ };
667
+ return;
668
+ }
637
669
  const pid2 = child2.pid;
638
670
  const stdoutBytes2 = 0;
639
671
  const stderrBytes2 = 0;
640
672
  let telemetryCompleted2 = false;
673
+ let bgErrorOccurred = false;
674
+ let bgSettled = false;
641
675
  emitProcessStarted({
642
676
  ...pid2 !== void 0 ? { pid: pid2 } : {},
643
677
  parentPid: process.pid,
@@ -675,15 +709,33 @@ var bashTool = {
675
709
  child2.on("close", () => registry.unregister(pid2));
676
710
  }
677
711
  child2.on("error", () => {
678
- if (typeof pid2 === "number") registry.unregister(pid2);
712
+ if (bgSettled) return;
713
+ bgErrorOccurred = true;
679
714
  registry.afterCall(Date.now() - startedAt, true, bypassBreaker);
680
715
  completeBackground(1);
681
716
  });
682
717
  child2.on("close", (code, signal) => {
683
- registry.afterCall(Date.now() - startedAt, false, bypassBreaker);
718
+ bgSettled = true;
719
+ if (bgErrorOccurred) return;
720
+ const failed = code !== 0 && code !== null || !!signal;
721
+ registry.afterCall(Date.now() - startedAt, failed, bypassBreaker);
684
722
  completeBackground(code ?? (signal ? 1 : 0), signal ?? void 0);
685
723
  });
686
- if (typeof pid2 === "number") child2.unref();
724
+ if (typeof pid2 !== "number") {
725
+ completeBackground(1);
726
+ yield {
727
+ type: "final",
728
+ output: {
729
+ output: "",
730
+ exit_code: 1,
731
+ timed_out: false,
732
+ pid: null,
733
+ error: "Failed to launch background process: invalid PID"
734
+ }
735
+ };
736
+ return;
737
+ }
738
+ child2.unref();
687
739
  yield {
688
740
  type: "final",
689
741
  output: {
@@ -705,14 +757,46 @@ var bashTool = {
705
757
  });
706
758
  return;
707
759
  }
708
- const child = spawn(shell, args, {
709
- cwd: spawnCwd,
710
- env,
711
- stdio: ["ignore", "pipe", "pipe"],
712
- detached,
713
- windowsHide: true,
714
- ...isWin2 ? {} : { signal: callerSignal }
715
- });
760
+ let child;
761
+ try {
762
+ child = spawn(shell, args, {
763
+ cwd: spawnCwd,
764
+ env,
765
+ stdio: ["ignore", "pipe", "pipe"],
766
+ detached,
767
+ windowsHide: true,
768
+ ...isWin2 ? {} : { signal: callerSignal }
769
+ });
770
+ } catch (err) {
771
+ registry.afterCall(Date.now() - startedAt, true, bypassBreaker);
772
+ emitProcessStarted({
773
+ parentPid: process.pid,
774
+ command: redactCommand(`${shell} ${args.join(" ")}`),
775
+ args: redactCommand(args.join(" ")).split(" ").filter(Boolean),
776
+ cwd: spawnCwd,
777
+ background: false,
778
+ startedAt: new Date(startedAt).toISOString()
779
+ });
780
+ emitProcessCompleted({
781
+ exitCode: 1,
782
+ durationMs: Date.now() - startedAt,
783
+ stdoutBytes: 0,
784
+ stderrBytes: 0,
785
+ timedOut: false,
786
+ endedAt: (/* @__PURE__ */ new Date()).toISOString()
787
+ });
788
+ yield {
789
+ type: "final",
790
+ output: {
791
+ output: "",
792
+ exit_code: 1,
793
+ timed_out: false,
794
+ pid: null,
795
+ error: `spawn failed: ${err instanceof Error ? err.message : String(err)}`
796
+ }
797
+ };
798
+ return;
799
+ }
716
800
  const pid = child.pid;
717
801
  let stdoutBytes = 0;
718
802
  let stderrBytes = 0;
@@ -862,15 +946,21 @@ var bashTool = {
862
946
  const onStderrData = (chunk) => onData(chunk, "stderr");
863
947
  child.stdout?.on("data", onStdoutData);
864
948
  child.stderr?.on("data", onStderrData);
949
+ let fgErrorOccurred = false;
950
+ let sawClose = false;
865
951
  child.on("error", (err) => {
952
+ if (sawClose) return;
953
+ fgErrorOccurred = true;
866
954
  for (const t of timers) clearTimeout(t);
867
955
  registry.afterCall(Date.now() - startedAt, true);
868
956
  completeForeground(1);
869
957
  push({ kind: "error", err });
870
958
  });
871
959
  child.on("close", (code, signal) => {
960
+ sawClose = true;
872
961
  for (const t of timers) clearTimeout(t);
873
962
  if (typeof pid === "number") registry.unregister(pid);
963
+ if (fgErrorOccurred) return;
874
964
  registry.afterCall(Date.now() - startedAt, code !== 0 && code !== null);
875
965
  completeForeground(timedOut ? 124 : code ?? (signal ? 1 : 0), signal ?? void 0);
876
966
  const tail = stdoutDecoder.end() + stderrDecoder.end();
@@ -885,7 +975,33 @@ var bashTool = {
885
975
  while (true) {
886
976
  const c = await next();
887
977
  resumeIfDrained();
888
- if (c.kind === "error") throw c.err;
978
+ if (c.kind === "error") {
979
+ const isAbort = c.err?.code === "ABORT_ERR" || callerSignal.aborted;
980
+ const remainder = flush();
981
+ if (remainder !== null) {
982
+ yield { type: "partial_output", text: remainder };
983
+ }
984
+ const spooled = spool.finalize();
985
+ yield {
986
+ type: "final",
987
+ output: {
988
+ output: normalizeCommandOutput(buf) + (spooled ? spoolNote(spooled) : "") + pipeToShellNote,
989
+ exit_code: isAbort ? 124 : 1,
990
+ timed_out: isAbort,
991
+ pid: pid ?? null,
992
+ error: isAbort ? "Command aborted by user or signal" : c.err.message
993
+ }
994
+ };
995
+ ctx.recordSideEffect?.({
996
+ toolUseId: `bash-${Date.now()}`,
997
+ toolName: "bash",
998
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
999
+ input: { command: redactCommand(input.command) },
1000
+ outcome: isAbort ? "aborted" : `error (${c.err.message})`,
1001
+ risk: "shell"
1002
+ });
1003
+ return;
1004
+ }
889
1005
  if (c.kind === "end") {
890
1006
  const remainder = flush();
891
1007
  if (remainder !== null) {
@@ -903,7 +1019,7 @@ ${hint}` : "") + pipeToShellNote,
903
1019
  exit_code: timedOut || isAborted ? 124 : c.code,
904
1020
  timed_out: timedOut || isAborted,
905
1021
  pid: pid ?? null,
906
- error: isAborted ? "Command aborted by user or signal" : void 0
1022
+ error: timedOut ? "Command timed out" : isAborted ? "Command aborted by user or signal" : void 0
907
1023
  }
908
1024
  };
909
1025
  ctx.recordSideEffect?.({
@@ -930,7 +1046,7 @@ ${hint}` : "") + pipeToShellNote,
930
1046
  child.stderr?.off("data", onStderrData);
931
1047
  child.stdout?.destroy();
932
1048
  child.stderr?.destroy();
933
- if (child.exitCode === null && !child.killed) {
1049
+ if (!sawClose && child.exitCode === null && !child.killed) {
934
1050
  if (typeof pid === "number") registry.kill(pid, { force: true });
935
1051
  else killWithTimeout(child, 2e3);
936
1052
  }
@@ -977,4 +1093,4 @@ export {
977
1093
  checkAndBlockKillCommand,
978
1094
  bashTool
979
1095
  };
980
- //# sourceMappingURL=chunk-5UFVCIUB.js.map
1096
+ //# sourceMappingURL=chunk-6H4ERJP7.js.map
@@ -18,7 +18,7 @@ var diffTool = {
18
18
  name: "diff",
19
19
  category: "Filesystem",
20
20
  description: "Show file content with line numbers, staged/working-tree diffs via git, or commit/branch diffs. A safer and more structured alternative to raw `git diff` via shell.",
21
- usageHint: 'USE FOR CODE REVIEW AND CHANGE INSPECTION:\n\n- `files` + no `a`/`b` \u2192 show file content with line numbers (NOT a unified diff; no +/- prefixes). Result `mode` is "dump".\n- `a` and/or `b` \u2192 git-style commit/branch diff (unified format, real +/- prefixes).\n- `staged: true` \u2192 only show staged changes.\n- `mode` only affects the git-diff path: "stat" runs `git diff --stat`; "side-by-side" is not supported and falls back to unified (result `mode` reports what was produced).\n- `context` sets the unified-diff context line count on the git path (`-U<n>`); the dump path has no context notion.\n\nNOTE: For a true file-vs-file unified diff, supply `a` and `b` so the tool delegates to `git diff`. The `files`-only path is a line-numbered dump, not a diff.\n\nThis tool has important safety guards against flag injection (see previous security findings).',
21
+ usageHint: 'USE FOR CODE REVIEW AND CHANGE INSPECTION:\n\n- `files` + no `a`/`b` \u2192 show file content with line numbers (NOT a unified diff; no +/- prefixes). Result `mode` is "dump".\n- `a` and/or `b` \u2192 git-style commit/branch diff (unified format, real +/- prefixes).\n- `staged: true` \u2192 only show staged changes.\n- `mode` only affects the git-diff path: "stat" runs `git diff --stat`; "side-by-side" is unimplemented and falls back to unified (result `mode` reports what was produced).\n- `context` sets the unified-diff context line count on the git path (`-U<n>`); the dump path has no context notion.\n\nNOTE: For a true file-vs-file unified diff, supply `a` and `b` so the tool delegates to `git diff`. The `files`-only path is a line-numbered dump, not a diff.\n\nThis tool has important safety guards against flag injection (see previous security findings).',
22
22
  permission: "auto",
23
23
  mutating: false,
24
24
  maxOutputBytes: 262144,
@@ -63,7 +63,29 @@ var diffTool = {
63
63
  async execute(input, ctx, opts) {
64
64
  const signal = opts?.signal ?? ctx.signal ?? new AbortController().signal;
65
65
  signal.throwIfAborted();
66
- if (input.a !== void 0 || input.b !== void 0) {
66
+ if (input.path !== void 0) {
67
+ if (typeof input.path !== "string" || !input.path.trim()) {
68
+ throw new ToolValidationError({
69
+ message: "diff: 'path' must be a non-empty string when provided",
70
+ field: "path"
71
+ });
72
+ }
73
+ try {
74
+ await safeResolveReal(input.path, ctx);
75
+ } catch (err) {
76
+ throw new ToolValidationError({
77
+ message: `diff: ${err.message}`,
78
+ field: "path"
79
+ });
80
+ }
81
+ }
82
+ if (input.context !== void 0 && (typeof input.context !== "number" || !Number.isInteger(input.context) || input.context < 0 || input.context > 100)) {
83
+ throw new ToolValidationError({
84
+ message: "diff: context must be an integer between 0 and 100",
85
+ field: "context"
86
+ });
87
+ }
88
+ if (input.staged || input.a !== void 0 || input.b !== void 0) {
67
89
  return await gitDiff(input, ctx, signal);
68
90
  }
69
91
  return await fileDiff(input, ctx, signal);
@@ -98,7 +120,15 @@ async function gitDiff(input, ctx, signal) {
98
120
  const statMode = requestedMode === "stat";
99
121
  const effectiveMode = statMode ? "stat" : "unified";
100
122
  const sideBySideNote = requestedMode === "side-by-side" ? "side-by-side output is not supported; a unified diff was produced instead." : void 0;
101
- const basePath = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
123
+ let basePath;
124
+ try {
125
+ basePath = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
126
+ } catch (err) {
127
+ throw new ToolValidationError({
128
+ message: `diff: ${err.message}`,
129
+ field: "path"
130
+ });
131
+ }
102
132
  const gitDir = findGitDir(basePath);
103
133
  if (!gitDir) {
104
134
  return {
@@ -118,10 +148,16 @@ async function gitDiff(input, ctx, signal) {
118
148
  if (input.staged) args.push("--staged");
119
149
  if (input.a) args.push(input.a.trim());
120
150
  if (input.b) args.push(input.b.trim());
151
+ let effectiveFiles = [];
121
152
  if (input.files) {
122
153
  const rawFiles = Array.isArray(input.files) ? input.files : typeof input.files === "string" ? input.files.split(",") : [];
123
- const files = rawFiles.filter((f) => typeof f === "string").map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean);
154
+ const files = [
155
+ ...new Set(
156
+ rawFiles.filter((f) => typeof f === "string").map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean)
157
+ )
158
+ ];
124
159
  if (files.length > 0) {
160
+ effectiveFiles = files;
125
161
  args.push("--", ...files);
126
162
  }
127
163
  }
@@ -140,7 +176,7 @@ async function gitDiff(input, ctx, signal) {
140
176
  const combinedNote = [sideBySideNote, exitNote].filter(Boolean).join("\n") || void 0;
141
177
  return {
142
178
  diff,
143
- files: [],
179
+ files: effectiveFiles,
144
180
  truncated,
145
181
  mode: effectiveMode,
146
182
  note: combinedNote
@@ -151,7 +187,7 @@ function findGitDir(cwd) {
151
187
  for (let i = 0; i < 20; i++) {
152
188
  try {
153
189
  const stat2 = statSync(path.join(dir, ".git"));
154
- if (stat2.isDirectory()) return dir;
190
+ if (stat2.isDirectory() || stat2.isFile()) return dir;
155
191
  } catch {
156
192
  }
157
193
  const parent = path.dirname(dir);
@@ -188,7 +224,11 @@ async function fileDiff(input, ctx, signal) {
188
224
  signal.throwIfAborted();
189
225
  void input.context;
190
226
  const rawFiles = Array.isArray(input.files) ? input.files : typeof input.files === "string" ? input.files.split(",") : [];
191
- const files = rawFiles.filter((f) => typeof f === "string").map((f) => f.trim()).filter(Boolean);
227
+ const files = [
228
+ ...new Set(
229
+ rawFiles.filter((f) => typeof f === "string").map((f) => f.trim()).filter(Boolean)
230
+ )
231
+ ];
192
232
  if (files.length === 0) {
193
233
  return {
194
234
  diff: "No files specified",
@@ -197,11 +237,24 @@ async function fileDiff(input, ctx, signal) {
197
237
  mode: "dump"
198
238
  };
199
239
  }
200
- const basePath = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
240
+ let basePath;
241
+ try {
242
+ basePath = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
243
+ } catch (err) {
244
+ throw new ToolValidationError({
245
+ message: `diff: ${err.message}`,
246
+ field: "path"
247
+ });
248
+ }
201
249
  const fileEntries = await mapWithConcurrency(files, 16, async (file) => {
202
250
  signal.throwIfAborted();
203
251
  const fileToResolve = path.isAbsolute(file) ? file : path.resolve(basePath, file);
204
- const absPath = await safeResolveReal(fileToResolve, ctx);
252
+ let absPath;
253
+ try {
254
+ absPath = await safeResolveReal(fileToResolve, ctx);
255
+ } catch {
256
+ return null;
257
+ }
205
258
  const stat2 = await fs.stat(absPath).catch(() => null);
206
259
  if (!stat2?.isFile()) return null;
207
260
  if (stat2.size > MAX_FILE_DUMP_BYTES) {
@@ -249,4 +302,4 @@ ${parts.join("\n")}`;
249
302
  export {
250
303
  diffTool
251
304
  };
252
- //# sourceMappingURL=chunk-34VLZ35Z.js.map
305
+ //# sourceMappingURL=chunk-7HL23T3T.js.map
@@ -193,4 +193,4 @@ var CircuitBreaker = class {
193
193
  export {
194
194
  CircuitBreaker
195
195
  };
196
- //# sourceMappingURL=chunk-HFXSNKCV.js.map
196
+ //# sourceMappingURL=chunk-7JJFC6CT.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  builtinToolsPack
3
- } from "./chunk-JVRLTEO7.js";
3
+ } from "./chunk-E7JE3UEX.js";
4
4
  import {
5
5
  TIER1_TOOLS,
6
6
  TIER2_TOOLS
7
- } from "./chunk-4BABEJC2.js";
7
+ } from "./chunk-IAYMTTR2.js";
8
8
 
9
9
  // src/tool-tier.ts
10
10
  function toolNameSet(tools) {
@@ -54,4 +54,4 @@ export {
54
54
  selectBuiltinToolsForTier,
55
55
  registerBuiltinToolTier
56
56
  };
57
- //# sourceMappingURL=chunk-23EX5WDO.js.map
57
+ //# sourceMappingURL=chunk-7LQCT3LT.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  spawnStream
3
- } from "./chunk-OYP27E3I.js";
3
+ } from "./chunk-DRRY6SCM.js";
4
4
  import {
5
5
  normalizeCommandOutput,
6
6
  safeResolveReal
@@ -3515,4 +3515,4 @@ export {
3515
3515
  languagePackageTool,
3516
3516
  languageInfoTool
3517
3517
  };
3518
- //# sourceMappingURL=chunk-NDIT3SBZ.js.map
3518
+ //# sourceMappingURL=chunk-7N5U2RAU.js.map