@wrongstack/tools 0.319.1 → 1.0.0

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 (203) 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 +8 -8
  5. package/dist/auto-proceed-loop-guard.js +9 -160
  6. package/dist/bash-kill-guard.d.ts +2 -3
  7. package/dist/bash.d.ts +2 -3
  8. package/dist/bash.js +6 -6
  9. package/dist/batch-tool-use.d.ts +2 -3
  10. package/dist/batch-tool-use.js +1 -1
  11. package/dist/browser/index.d.ts +1 -1
  12. package/dist/browser/index.js +1 -1
  13. package/dist/browser/tools.d.ts +56 -45
  14. package/dist/builtin.js +55 -55
  15. package/dist/{chunk-RJZQWEMS.js → chunk-24T5XIJU.js} +3 -2
  16. package/dist/{chunk-DTQ75VBC.js → chunk-2CTZW6JQ.js} +2 -2
  17. package/dist/chunk-37QKUQ2Z.js +171 -0
  18. package/dist/{chunk-LOBRWKCR.js → chunk-3D5DJWOE.js} +3 -3
  19. package/dist/{chunk-YOKD4GWJ.js → chunk-4ERMPDHV.js} +14 -8
  20. package/dist/{chunk-5EUJF3WC.js → chunk-4WPBS45A.js} +4 -5
  21. package/dist/{chunk-42BHI7TN.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-IYKXK356.js → chunk-6GOZTS6F.js} +4 -4
  25. package/dist/{chunk-OG2BEUBY.js → chunk-7HL23T3T.js} +73 -16
  26. package/dist/{chunk-HFXSNKCV.js → chunk-7JJFC6CT.js} +1 -1
  27. package/dist/{chunk-TTZOK6IY.js → chunk-7N5U2RAU.js} +2 -2
  28. package/dist/{chunk-QBV725YG.js → chunk-7ODZTPCU.js} +2 -2
  29. package/dist/{chunk-OTINMOKK.js → chunk-AB2CAUOP.js} +66 -55
  30. package/dist/{chunk-6AAOT4PW.js → chunk-AQ5YBURX.js} +16 -4
  31. package/dist/{chunk-JDPQOR7C.js → chunk-ASEXQRA7.js} +19 -19
  32. package/dist/{chunk-FRN7TIAA.js → chunk-B3MGJBFI.js} +1 -1
  33. package/dist/{chunk-IWS56OY7.js → chunk-CGXTR34H.js} +63 -4
  34. package/dist/{chunk-IU4DV2PA.js → chunk-CHEK3ASV.js} +6 -3
  35. package/dist/{chunk-GOIZNNOA.js → chunk-DJYLI7EW.js} +1 -1
  36. package/dist/{chunk-CFLJFDYV.js → chunk-DK4J2WMH.js} +14 -11
  37. package/dist/{chunk-ZHH3BEWU.js → chunk-DRRY6SCM.js} +49 -22
  38. package/dist/{chunk-BK732J7I.js → chunk-FBUP524S.js} +4 -4
  39. package/dist/{chunk-WHIIIREL.js → chunk-FVM3O4JQ.js} +7 -3
  40. package/dist/chunk-FYDBUVQD.js +244 -0
  41. package/dist/{chunk-UDVKRX5R.js → chunk-GDDXX27P.js} +50 -50
  42. package/dist/{chunk-O44IMQCN.js → chunk-GKSG5CPH.js} +6 -6
  43. package/dist/{chunk-3PVYQFRQ.js → chunk-HDYUBRMF.js} +5 -3
  44. package/dist/{chunk-ELRRTWNP.js → chunk-IXIS7RSG.js} +2 -2
  45. package/dist/{chunk-X5FOFGXX.js → chunk-IYH4OHBP.js} +6 -6
  46. package/dist/{chunk-MNP3GE7H.js → chunk-JDOO4P6Z.js} +21 -16
  47. package/dist/{chunk-BSJSNVGA.js → chunk-KDEXUQY7.js} +24 -11
  48. package/dist/{chunk-V43EQ6VR.js → chunk-KE7A76VC.js} +3 -2
  49. package/dist/{chunk-2OXHS3KZ.js → chunk-KLJZ4WV4.js} +4 -3
  50. package/dist/{chunk-3M7LLN7W.js → chunk-LQSOU63Z.js} +12 -11
  51. package/dist/{chunk-DC4KMPJO.js → chunk-M6UV67BH.js} +2 -2
  52. package/dist/{chunk-C2DQKVLO.js → chunk-MJSJWXBF.js} +1 -1
  53. package/dist/{chunk-RNWUCZ2U.js → chunk-MK2JK35J.js} +29 -12
  54. package/dist/{chunk-FQZOHLG3.js → chunk-MSOAX3GC.js} +3 -2
  55. package/dist/{chunk-KY4PXYSO.js → chunk-N3K2SFEI.js} +534 -494
  56. package/dist/{chunk-EADULOZV.js → chunk-NJX2RXKJ.js} +50 -7
  57. package/dist/{chunk-AKHYMB4V.js → chunk-NN2SNP2R.js} +6 -6
  58. package/dist/{chunk-CMOUCKGC.js → chunk-NU2IZ72J.js} +6 -6
  59. package/dist/{chunk-RLMX75EM.js → chunk-O6BY43ZB.js} +29 -8
  60. package/dist/{chunk-NKNOBUBU.js → chunk-PVCB7RUZ.js} +2 -2
  61. package/dist/{chunk-UQQS3VNT.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-2VSZC6QM.js → chunk-SCMRM6NL.js} +6 -4
  65. package/dist/{chunk-W2CECGTG.js → chunk-SMARDKAC.js} +1 -1
  66. package/dist/{chunk-45JPRMC2.js → chunk-SOR7OCYP.js} +7 -3
  67. package/dist/{chunk-ATSKPZUK.js → chunk-T3SMFF5Q.js} +11 -5
  68. package/dist/{chunk-4BHUSMNL.js → chunk-UI3ZJIG3.js} +1 -1
  69. package/dist/{chunk-WXJY3BKV.js → chunk-VBF2YXUW.js} +2 -2
  70. package/dist/{chunk-FQNXYA6W.js → chunk-VU3QBYL4.js} +36 -5
  71. package/dist/{chunk-IIF5HIVF.js → chunk-VVZPQPTY.js} +2 -2
  72. package/dist/{chunk-VD2LV5WO.js → chunk-VZGPASGD.js} +37 -12
  73. package/dist/{chunk-64VIJPFV.js → chunk-WEEVSWQB.js} +17 -6
  74. package/dist/chunk-XXRMF2BC.js +186 -0
  75. package/dist/{chunk-RTZWBNTY.js → chunk-YEISRT4S.js} +7 -12
  76. package/dist/{chunk-Q5JPPCZC.js → chunk-YJTXRH5Y.js} +3 -2
  77. package/dist/{chunk-GMZYW52L.js → chunk-YULVUTK5.js} +6 -3
  78. package/dist/{chunk-NWZ6XGBJ.js → chunk-ZBMANLYH.js} +5 -3
  79. package/dist/{chunk-DP6CXMJZ.js → chunk-ZTCJCYLN.js} +3 -3
  80. package/dist/circuit-breaker.d.ts +1 -0
  81. package/dist/circuit-breaker.js +1 -1
  82. package/dist/clarify.d.ts +1 -0
  83. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +2 -3
  84. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +5 -4
  85. package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +4 -3
  86. package/dist/codebase-index/codebase-index-tool.d.ts +2 -3
  87. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +2 -3
  88. package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +4 -3
  89. package/dist/codebase-index/codebase-repo-map-tool.d.ts +2 -3
  90. package/dist/codebase-index/codebase-search-tool.d.ts +2 -3
  91. package/dist/codebase-index/codebase-skeleton-tool.d.ts +2 -3
  92. package/dist/codebase-index/codebase-stats-tool.d.ts +9 -3
  93. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +4 -3
  94. package/dist/codebase-index/index.d.ts +11 -11
  95. package/dist/codebase-index/index.js +12 -12
  96. package/dist/codebase-index/parser-worker-script.js +3 -3
  97. package/dist/codebase-index/project-server-framing.d.ts +29 -0
  98. package/dist/codebase-index/project-server-lifecycle.d.ts +20 -0
  99. package/dist/codebase-index/project-server-operations.d.ts +37 -0
  100. package/dist/codebase-index/project-server-types.d.ts +30 -0
  101. package/dist/codebase-index/project-server-watcher.d.ts +25 -0
  102. package/dist/codebase-index/project-server.js +451 -394
  103. package/dist/codebase-index/worker.js +5 -5
  104. package/dist/codebase-index/writer-init.d.ts +13 -0
  105. package/dist/codebase-index/writer-maintenance.d.ts +14 -0
  106. package/dist/codebase-index/writer.d.ts +0 -15
  107. package/dist/design.d.ts +2 -2
  108. package/dist/design.js +1 -1
  109. package/dist/diff.d.ts +4 -4
  110. package/dist/diff.js +2 -2
  111. package/dist/document.d.ts +3 -4
  112. package/dist/document.js +1 -1
  113. package/dist/e2e.d.ts +1 -1
  114. package/dist/e2e.js +1 -1
  115. package/dist/edit.d.ts +3 -3
  116. package/dist/edit.js +9 -9
  117. package/dist/exec.d.ts +2 -3
  118. package/dist/exec.js +6 -6
  119. package/dist/fetch.d.ts +4 -3
  120. package/dist/fetch.js +1 -1
  121. package/dist/format.d.ts +17 -45
  122. package/dist/format.js +14 -10
  123. package/dist/git.d.ts +3 -3
  124. package/dist/git.js +1 -1
  125. package/dist/glob.d.ts +2 -3
  126. package/dist/glob.js +3 -3
  127. package/dist/{go-parser-IKHW67WE.js → go-parser-D7ELWQ7F.js} +2 -2
  128. package/dist/grep.d.ts +7 -5
  129. package/dist/grep.js +4 -4
  130. package/dist/index.d.ts +54 -45
  131. package/dist/index.js +122 -63
  132. package/dist/install.d.ts +7 -55
  133. package/dist/install.js +8 -8
  134. package/dist/{json-parser-2EOVP5MR.js → json-parser-34DHYCPW.js} +1 -18
  135. package/dist/json.d.ts +3 -4
  136. package/dist/json.js +2 -2
  137. package/dist/kanban-tool-types.d.ts +1 -2
  138. package/dist/kanban.d.ts +3 -19
  139. package/dist/kanban.js +1 -1
  140. package/dist/languages/execute-tool.d.ts +2 -3
  141. package/dist/languages/index.d.ts +2 -2
  142. package/dist/languages/index.js +6 -6
  143. package/dist/languages/tool.d.ts +3 -4
  144. package/dist/legacy-bridge-YXANP5QB.js +18 -0
  145. package/dist/lint.d.ts +5 -4
  146. package/dist/lint.js +8 -8
  147. package/dist/logs.d.ts +3 -4
  148. package/dist/logs.js +2 -2
  149. package/dist/memory.d.ts +7 -8
  150. package/dist/memory.js +1 -1
  151. package/dist/mode.d.ts +3 -4
  152. package/dist/mode.js +1 -1
  153. package/dist/next-steps-tool.d.ts +2 -3
  154. package/dist/next-steps.d.ts +11 -0
  155. package/dist/next-steps.js +10 -132
  156. package/dist/outdated.d.ts +5 -29
  157. package/dist/outdated.js +4 -4
  158. package/dist/pack.js +56 -56
  159. package/dist/{parser-dispatch-QGC4HSP5.js → parser-dispatch-BDVCJXTV.js} +4 -4
  160. package/dist/patch.d.ts +2 -3
  161. package/dist/patch.js +8 -8
  162. package/dist/plan.d.ts +4 -4
  163. package/dist/plan.js +3 -3
  164. package/dist/process-registry.js +2 -2
  165. package/dist/ps-slash.js +4 -4
  166. package/dist/pwsh.d.ts +1 -0
  167. package/dist/{py-parser-RFWG2HYI.js → py-parser-QC6MR4GB.js} +3 -3
  168. package/dist/read.d.ts +5 -5
  169. package/dist/read.js +8 -8
  170. package/dist/replace.d.ts +2 -3
  171. package/dist/replace.js +10 -10
  172. package/dist/scaffold.d.ts +7 -3
  173. package/dist/scaffold.js +3 -1
  174. package/dist/search.d.ts +17 -3
  175. package/dist/search.js +5 -1
  176. package/dist/set-working-dir.d.ts +2 -3
  177. package/dist/skill.d.ts +4 -5
  178. package/dist/skill.js +1 -1
  179. package/dist/task.d.ts +6 -6
  180. package/dist/task.js +3 -3
  181. package/dist/test.d.ts +5 -4
  182. package/dist/test.js +8 -8
  183. package/dist/todo.d.ts +8 -8
  184. package/dist/todo.js +2 -2
  185. package/dist/tool-diff.js +11 -230
  186. package/dist/tool-help.d.ts +2 -3
  187. package/dist/tool-help.js +1 -1
  188. package/dist/tool-search.d.ts +2 -3
  189. package/dist/tool-search.js +1 -1
  190. package/dist/tool-summary.js +5 -281
  191. package/dist/tool-tier.js +57 -57
  192. package/dist/tool-use.d.ts +2 -3
  193. package/dist/tool-use.js +1 -1
  194. package/dist/tree.d.ts +5 -3
  195. package/dist/tree.js +5 -1
  196. package/dist/typecheck.d.ts +3 -3
  197. package/dist/typecheck.js +8 -8
  198. package/dist/win32.js +1 -1
  199. package/dist/write.d.ts +2 -3
  200. package/dist/write.js +9 -9
  201. package/package.json +5 -5
  202. package/dist/legacy-bridge-3T7SR4SK.js +0 -18
  203. package/dist/spawn-background.d.ts +0 -80
@@ -0,0 +1,171 @@
1
+ // src/auto-proceed-loop-guard.ts
2
+ function normalizeForRepetition(prompt) {
3
+ return prompt.replace(/\s+/g, " ").trim().toLowerCase();
4
+ }
5
+ var GROUNDED_NO_PROGRESS_STEER = [
6
+ "NOTE: The todo board has not changed since the previous automatic continuation \u2014 this exact instruction is being repeated.",
7
+ "Before anything else, bring the board up to date so the loop stays grounded:",
8
+ "- mark work that is actually finished as completed,",
9
+ "- split the current item into smaller concrete sub-items if it needs more than one turn,",
10
+ "- remove or reword items that no longer apply.",
11
+ "Then continue the work. If you are blocked, state exactly what is blocking you instead of repeating the same turn."
12
+ ].join("\n");
13
+ function createContinuationAttemptTracker() {
14
+ const attempts = /* @__PURE__ */ new Map();
15
+ const skipped = /* @__PURE__ */ new Set();
16
+ return {
17
+ recordAttempt(todoId) {
18
+ const count = (attempts.get(todoId) ?? 0) + 1;
19
+ attempts.set(todoId, count);
20
+ return count;
21
+ },
22
+ getAttempts(todoId) {
23
+ return attempts.get(todoId) ?? 0;
24
+ },
25
+ markSkipped(todoId) {
26
+ skipped.add(todoId);
27
+ },
28
+ isSkipped(todoId) {
29
+ return skipped.has(todoId);
30
+ },
31
+ reset() {
32
+ attempts.clear();
33
+ skipped.clear();
34
+ },
35
+ snapshot() {
36
+ const result = {};
37
+ const allIds = /* @__PURE__ */ new Set([...attempts.keys(), ...skipped]);
38
+ for (const id of allIds) {
39
+ result[id] = { attempts: attempts.get(id) ?? 0, skipped: skipped.has(id) };
40
+ }
41
+ return result;
42
+ }
43
+ };
44
+ }
45
+ var ADVANCE_PREAMBLES = [
46
+ "Pivoting to the next open item \u2014 previous todo still pending after {attempts} attempt(s).",
47
+ "Shifting focus to a different task while the previous item ({label}) remains open after {attempts} attempt(s).",
48
+ "No board progress on the current item after {attempts} attempt(s). Continuing with the next todo.",
49
+ "The previous item is still unresolved after {attempts} try(ies). Moving on down the list.",
50
+ "Advancing to the next piece of work after {attempts} unproductive attempt(s) on the prior one.",
51
+ "Taking a different angle \u2014 the stalled item ({label}) stays open after {attempts} attempt(s). Pressing ahead.",
52
+ "The todo board shows no movement on the current task after {attempts} attempt(s). Switching gears.",
53
+ "No change on the board from the last {attempts} continuation(s). Proceeding to the next open item."
54
+ ];
55
+ function generateAdvancementPrompt(stalledTodo, nextTodo, attemptCount, todos) {
56
+ const idx = Math.max(0, Math.min(attemptCount - 1, ADVANCE_PREAMBLES.length - 1));
57
+ const preamble = ADVANCE_PREAMBLES[idx].replace(
58
+ /\{attempts\}/g,
59
+ () => String(attemptCount)
60
+ ).replace(/\{label\}/g, () => stalledTodo.content.slice(0, 72));
61
+ if (!nextTodo) {
62
+ return [
63
+ preamble,
64
+ "",
65
+ "No more open items remain on the todo list. What has been accomplished and what should I do next?"
66
+ ].join("\n");
67
+ }
68
+ const itemLabel = nextTodo.status === "in_progress" && nextTodo.activeForm ? nextTodo.activeForm : nextTodo.content;
69
+ const done = todos.filter((t) => t.status === "completed").length;
70
+ const total = todos.length;
71
+ const lines = [preamble, "", `Proceed with: ${itemLabel}`];
72
+ if (total > 0) {
73
+ lines.push("", `Todo board (${done}/${total} done):`);
74
+ lines.push(
75
+ ...todos.slice(0, 20).map((t) => {
76
+ const mark = t.status === "completed" ? "[x]" : t.status === "in_progress" ? "[~]" : "[ ]";
77
+ const flat = t.content.replace(/\n|\r/g, " ");
78
+ return ` ${mark} ${flat}`;
79
+ })
80
+ );
81
+ }
82
+ lines.push(
83
+ "",
84
+ "If this item is already done, mark it complete and move to the next open todo. Keep the board honest as you work."
85
+ );
86
+ return lines.join("\n");
87
+ }
88
+ function matchTodoIdFromPrompt(todos, prompt) {
89
+ if (todos.length === 0 || !prompt) return null;
90
+ const lowerPrompt = prompt.toLowerCase();
91
+ const inProgress = todos.find((t) => t.status === "in_progress");
92
+ if (inProgress) {
93
+ const label = (inProgress.activeForm ?? inProgress.content).toLowerCase();
94
+ if (label.length > 5 && lowerPrompt.includes(label)) {
95
+ return { id: inProgress.id, content: inProgress.activeForm ?? inProgress.content };
96
+ }
97
+ }
98
+ for (const t of todos) {
99
+ if (t.status === "completed") continue;
100
+ if (inProgress && t.id === inProgress.id) continue;
101
+ const label = (t.activeForm ?? t.content).toLowerCase();
102
+ if (label.length > 5 && lowerPrompt.includes(label)) {
103
+ return { id: t.id, content: t.activeForm ?? t.content };
104
+ }
105
+ }
106
+ const firstOpen = todos.find((t) => t.status !== "completed");
107
+ return firstOpen ? { id: firstOpen.id, content: firstOpen.activeForm ?? firstOpen.content } : null;
108
+ }
109
+ var MAX_ADVANCEMENT_ATTEMPTS = 9;
110
+ function createAutoProceedLoopGuard(options = {}) {
111
+ const safeIntegerOption = (value, fallback) => {
112
+ if (value === void 0) return fallback;
113
+ if (!Number.isFinite(value)) return fallback;
114
+ return Math.floor(value);
115
+ };
116
+ const repeatThreshold = Math.max(2, safeIntegerOption(options.repeatThreshold, 2));
117
+ const windowSize = Math.max(repeatThreshold, safeIntegerOption(options.windowSize, 3));
118
+ let buffer = [];
119
+ let steeredFor = null;
120
+ function record(prompt) {
121
+ const normalized = normalizeForRepetition(prompt);
122
+ buffer.push(normalized);
123
+ if (buffer.length > windowSize) {
124
+ buffer = buffer.slice(buffer.length - windowSize);
125
+ }
126
+ let runLength = 0;
127
+ for (let i = buffer.length - 1; i >= 0; i--) {
128
+ if (buffer[i] === normalized) runLength++;
129
+ else break;
130
+ }
131
+ return {
132
+ normalized,
133
+ runLength,
134
+ shouldHalt: runLength >= repeatThreshold
135
+ };
136
+ }
137
+ function recordGrounded(prompt) {
138
+ const signal = record(prompt);
139
+ if (!signal.shouldHalt) {
140
+ steeredFor = null;
141
+ return { ...signal, shouldHalt: false, action: "feed" };
142
+ }
143
+ if (steeredFor === signal.normalized) {
144
+ return { ...signal, action: "halt" };
145
+ }
146
+ steeredFor = signal.normalized;
147
+ return { ...signal, shouldHalt: false, action: "steer" };
148
+ }
149
+ function reset() {
150
+ buffer = [];
151
+ steeredFor = null;
152
+ }
153
+ function history() {
154
+ return buffer.slice();
155
+ }
156
+ function size() {
157
+ return buffer.length;
158
+ }
159
+ return { record, recordGrounded, reset, history, size };
160
+ }
161
+
162
+ export {
163
+ normalizeForRepetition,
164
+ GROUNDED_NO_PROGRESS_STEER,
165
+ createContinuationAttemptTracker,
166
+ generateAdvancementPrompt,
167
+ matchTodoIdFromPrompt,
168
+ MAX_ADVANCEMENT_ATTEMPTS,
169
+ createAutoProceedLoopGuard
170
+ };
171
+ //# sourceMappingURL=chunk-37QKUQ2Z.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  tryLegacyCodeOperation
3
- } from "./chunk-ATSKPZUK.js";
3
+ } from "./chunk-T3SMFF5Q.js";
4
4
  import {
5
5
  spawnStream
6
- } from "./chunk-ZHH3BEWU.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-LOBRWKCR.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
- } from "./chunk-NWZ6XGBJ.js";
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
@@ -99,7 +99,8 @@ var grepTool = {
99
99
  }
100
100
  const base = input.path ? await safeResolveReal(input.path, ctx) : ctx.cwd;
101
101
  const mode = input.output_mode ?? "content";
102
- const limit = Math.max(1, Math.min(input.limit ?? 200, 2e3));
102
+ const rawLimit = typeof input.limit === "number" && Number.isFinite(input.limit) ? input.limit : 200;
103
+ const limit = Math.max(1, Math.min(Math.floor(rawLimit), 2e3));
103
104
  const validation = compileUserRegex(input.pattern, input.case_insensitive ? "i" : "");
104
105
  if (!validation.ok) {
105
106
  throw new ToolValidationError({
@@ -373,6 +374,7 @@ async function runNative(input, base, mode, limit, signal) {
373
374
  const maxBytes = NATIVE_MAX_FILE_BYTES;
374
375
  let total = 0;
375
376
  let stopped = false;
377
+ let countTruncated = false;
376
378
  const scanFile = async (full, name, rel) => {
377
379
  if (stopped || signal.aborted) return;
378
380
  if (globRe) {
@@ -448,8 +450,12 @@ async function runNative(input, base, mode, limit, signal) {
448
450
  }
449
451
  }
450
452
  if (fileHits > 0) {
451
- if (mode === "count" && matches.length < limit) {
452
- matches.push(`${full}:${fileHits}`);
453
+ if (mode === "count") {
454
+ if (matches.length < limit) {
455
+ matches.push(`${full}:${fileHits}`);
456
+ } else {
457
+ countTruncated = true;
458
+ }
453
459
  }
454
460
  if (mode === "files_with_matches" && matches.length >= limit) stopped = true;
455
461
  }
@@ -506,7 +512,7 @@ async function runNative(input, base, mode, limit, signal) {
506
512
  return {
507
513
  matches,
508
514
  count: total,
509
- truncated: stopped,
515
+ truncated: stopped || countTruncated,
510
516
  used: "native"
511
517
  };
512
518
  }
@@ -516,4 +522,4 @@ export {
516
522
  __resetRgDetectionForTests,
517
523
  __setRgAvailableForTests
518
524
  };
519
- //# sourceMappingURL=chunk-YOKD4GWJ.js.map
525
+ //# sourceMappingURL=chunk-4ERMPDHV.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  tryLegacyCodeOperation
3
- } from "./chunk-ATSKPZUK.js";
3
+ } from "./chunk-T3SMFF5Q.js";
4
4
  import {
5
5
  spawnStream
6
- } from "./chunk-ZHH3BEWU.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-5EUJF3WC.js.map
165
+ //# sourceMappingURL=chunk-4WPBS45A.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getPersistentProcessRegistry
3
- } from "./chunk-NKNOBUBU.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-42BHI7TN.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,11 +1,11 @@
1
1
  import {
2
2
  getProcessRegistry,
3
3
  redactCommand
4
- } from "./chunk-3PVYQFRQ.js";
4
+ } from "./chunk-HDYUBRMF.js";
5
5
  import {
6
6
  buildWin32CmdShimInvocation,
7
7
  resolveWin32Command
8
- } from "./chunk-V43EQ6VR.js";
8
+ } from "./chunk-KE7A76VC.js";
9
9
  import {
10
10
  COMMAND_OUTPUT_MAX_BYTES,
11
11
  detectPackageManager,
@@ -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-3T7SR4SK.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-IYKXK356.js.map
285
+ //# sourceMappingURL=chunk-6GOZTS6F.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  mapWithConcurrency
3
- } from "./chunk-NWZ6XGBJ.js";
3
+ } from "./chunk-ZBMANLYH.js";
4
4
  import {
5
5
  safeResolveReal
6
6
  } from "./chunk-ZUFHAHTE.js";
@@ -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,32 +63,54 @@ 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);
70
92
  }
71
93
  };
72
94
  async function gitDiff(input, ctx, signal) {
73
- if (input.a !== void 0 && (!input.a || !input.a.trim())) {
95
+ if (input.a !== void 0 && (typeof input.a !== "string" || !input.a.trim())) {
74
96
  throw new ToolValidationError({
75
97
  message: "diff: ref 'a' cannot be empty or whitespace-only",
76
98
  field: "a"
77
99
  });
78
100
  }
79
- if (input.b !== void 0 && (!input.b || !input.b.trim())) {
101
+ if (input.b !== void 0 && (typeof input.b !== "string" || !input.b.trim())) {
80
102
  throw new ToolValidationError({
81
103
  message: "diff: ref 'b' cannot be empty or whitespace-only",
82
104
  field: "b"
83
105
  });
84
106
  }
85
- if (input.a?.trim().startsWith("-")) {
107
+ if (typeof input.a === "string" && input.a.trim().startsWith("-")) {
86
108
  throw new ToolValidationError({
87
109
  message: `diff: unsafe ref "${input.a}" \u2014 refs may not begin with '-' (flag injection)`,
88
110
  field: "a"
89
111
  });
90
112
  }
91
- if (input.b?.trim().startsWith("-")) {
113
+ if (typeof input.b === "string" && input.b.trim().startsWith("-")) {
92
114
  throw new ToolValidationError({
93
115
  message: `diff: unsafe ref "${input.b}" \u2014 refs may not begin with '-' (flag injection)`,
94
116
  field: "b"
@@ -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,9 +148,18 @@ 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
- const files = Array.isArray(input.files) ? input.files : input.files.split(",");
123
- args.push("--", ...files.map((f) => f.trim().replace(/\\/g, "/")));
153
+ const rawFiles = Array.isArray(input.files) ? input.files : typeof input.files === "string" ? input.files.split(",") : [];
154
+ const files = [
155
+ ...new Set(
156
+ rawFiles.filter((f) => typeof f === "string").map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean)
157
+ )
158
+ ];
159
+ if (files.length > 0) {
160
+ effectiveFiles = files;
161
+ args.push("--", ...files);
162
+ }
124
163
  }
125
164
  const result = await runGit(args, gitDir, signal);
126
165
  let diff = result.stdout;
@@ -137,7 +176,7 @@ async function gitDiff(input, ctx, signal) {
137
176
  const combinedNote = [sideBySideNote, exitNote].filter(Boolean).join("\n") || void 0;
138
177
  return {
139
178
  diff,
140
- files: [],
179
+ files: effectiveFiles,
141
180
  truncated,
142
181
  mode: effectiveMode,
143
182
  note: combinedNote
@@ -148,7 +187,7 @@ function findGitDir(cwd) {
148
187
  for (let i = 0; i < 20; i++) {
149
188
  try {
150
189
  const stat2 = statSync(path.join(dir, ".git"));
151
- if (stat2.isDirectory()) return dir;
190
+ if (stat2.isDirectory() || stat2.isFile()) return dir;
152
191
  } catch {
153
192
  }
154
193
  const parent = path.dirname(dir);
@@ -184,7 +223,12 @@ function runGit(args, cwd, signal) {
184
223
  async function fileDiff(input, ctx, signal) {
185
224
  signal.throwIfAborted();
186
225
  void input.context;
187
- const files = input.files ? (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim()).filter(Boolean) : [];
226
+ const rawFiles = Array.isArray(input.files) ? input.files : typeof input.files === "string" ? input.files.split(",") : [];
227
+ const files = [
228
+ ...new Set(
229
+ rawFiles.filter((f) => typeof f === "string").map((f) => f.trim()).filter(Boolean)
230
+ )
231
+ ];
188
232
  if (files.length === 0) {
189
233
  return {
190
234
  diff: "No files specified",
@@ -193,11 +237,24 @@ async function fileDiff(input, ctx, signal) {
193
237
  mode: "dump"
194
238
  };
195
239
  }
196
- 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
+ }
197
249
  const fileEntries = await mapWithConcurrency(files, 16, async (file) => {
198
250
  signal.throwIfAborted();
199
251
  const fileToResolve = path.isAbsolute(file) ? file : path.resolve(basePath, file);
200
- const absPath = await safeResolveReal(fileToResolve, ctx);
252
+ let absPath;
253
+ try {
254
+ absPath = await safeResolveReal(fileToResolve, ctx);
255
+ } catch {
256
+ return null;
257
+ }
201
258
  const stat2 = await fs.stat(absPath).catch(() => null);
202
259
  if (!stat2?.isFile()) return null;
203
260
  if (stat2.size > MAX_FILE_DUMP_BYTES) {
@@ -245,4 +302,4 @@ ${parts.join("\n")}`;
245
302
  export {
246
303
  diffTool
247
304
  };
248
- //# sourceMappingURL=chunk-OG2BEUBY.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,6 +1,6 @@
1
1
  import {
2
2
  spawnStream
3
- } from "./chunk-ZHH3BEWU.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-TTZOK6IY.js.map
3518
+ //# sourceMappingURL=chunk-7N5U2RAU.js.map
@@ -117,7 +117,7 @@ function formatAllToolsMarkdown(tools) {
117
117
  lines.push("| Tool | Description |");
118
118
  lines.push("|------|-------------|");
119
119
  for (const t of tools) {
120
- lines.push(`| \`${t.name}\` | ${t.description} |`);
120
+ lines.push(`| \`${t.name}\` | ${t.description.replaceAll("|", "\\|")} |`);
121
121
  }
122
122
  return lines.join("\n");
123
123
  }
@@ -125,4 +125,4 @@ function formatAllToolsMarkdown(tools) {
125
125
  export {
126
126
  toolHelpTool
127
127
  };
128
- //# sourceMappingURL=chunk-QBV725YG.js.map
128
+ //# sourceMappingURL=chunk-7ODZTPCU.js.map