@wrongstack/tools 0.318.0 → 0.319.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 (101) hide show
  1. package/dist/_edit-match.d.ts +1 -3
  2. package/dist/_util.d.ts +20 -0
  3. package/dist/audit.js +4 -4
  4. package/dist/bash.js +2 -2
  5. package/dist/builtin.d.ts +10 -0
  6. package/dist/builtin.js +46 -44
  7. package/dist/{chunk-TKA4VEX2.js → chunk-2OXHS3KZ.js} +17 -5
  8. package/dist/{chunk-X5K3U6GI.js → chunk-3M7LLN7W.js} +71 -7
  9. package/dist/{chunk-4AEZIFOW.js → chunk-5EUJF3WC.js} +36 -8
  10. package/dist/{chunk-CVALEVGA.js → chunk-64VIJPFV.js} +34 -13
  11. package/dist/{chunk-ZE6KLBUO.js → chunk-6AAOT4PW.js} +58 -10
  12. package/dist/{chunk-A6BRWIXN.js → chunk-6IEBD27U.js} +20 -5
  13. package/dist/{chunk-HTYEO67J.js → chunk-AKHYMB4V.js} +36 -12
  14. package/dist/{chunk-4E42D7UF.js → chunk-ATSKPZUK.js} +2 -2
  15. package/dist/{chunk-H6AWAZ2Y.js → chunk-B4HTSV6Z.js} +57 -6
  16. package/dist/{chunk-5ZYEGP2P.js → chunk-BK732J7I.js} +72 -27
  17. package/dist/{chunk-WI3VDXHD.js → chunk-BSJSNVGA.js} +108 -19
  18. package/dist/{chunk-UKGMDCXT.js → chunk-C2DQKVLO.js} +61 -28
  19. package/dist/{chunk-CIFAIIHI.js → chunk-CFLJFDYV.js} +100 -58
  20. package/dist/{chunk-JJQB6R7Y.js → chunk-CMOUCKGC.js} +6 -6
  21. package/dist/{chunk-MX25MTDJ.js → chunk-DC4KMPJO.js} +2 -2
  22. package/dist/{chunk-VZLX2JZG.js → chunk-DP6CXMJZ.js} +3 -3
  23. package/dist/{chunk-3QQSBUXR.js → chunk-EADULOZV.js} +36 -12
  24. package/dist/{chunk-6RNIFLG4.js → chunk-ELRRTWNP.js} +38 -6
  25. package/dist/{chunk-CPSAF2AU.js → chunk-FQNXYA6W.js} +45 -6
  26. package/dist/{chunk-ZZT45EHF.js → chunk-GMZYW52L.js} +3 -3
  27. package/dist/{chunk-ZLTFLC25.js → chunk-IIF5HIVF.js} +2 -2
  28. package/dist/{chunk-EMRGN4KM.js → chunk-IU4DV2PA.js} +18 -8
  29. package/dist/{chunk-AGUSOFNI.js → chunk-IWS56OY7.js} +30 -7
  30. package/dist/{chunk-MRZOVQ5D.js → chunk-IYKXK356.js} +98 -11
  31. package/dist/{chunk-6GZPSWP3.js → chunk-JDPQOR7C.js} +14 -7
  32. package/dist/{chunk-BLCSYKNN.js → chunk-KY4PXYSO.js} +10 -15
  33. package/dist/{chunk-WJYXMB2R.js → chunk-LOBRWKCR.js} +63 -14
  34. package/dist/{chunk-J5SKD6LN.js → chunk-MNP3GE7H.js} +38 -27
  35. package/dist/{chunk-S2GBLQ5S.js → chunk-O44IMQCN.js} +31 -7
  36. package/dist/{chunk-P7ZQ2FAJ.js → chunk-OG2BEUBY.js} +69 -34
  37. package/dist/{chunk-K23JNFE3.js → chunk-OTINMOKK.js} +233 -45
  38. package/dist/{chunk-PQTONQ4P.js → chunk-QPNYDH5B.js} +19 -5
  39. package/dist/{chunk-UE3UBMCP.js → chunk-RLMX75EM.js} +19 -8
  40. package/dist/{chunk-3U4H6ZRF.js → chunk-RNWUCZ2U.js} +53 -25
  41. package/dist/{chunk-YF3D5INN.js → chunk-RTZWBNTY.js} +121 -91
  42. package/dist/{chunk-SOG7XIRF.js → chunk-TTZOK6IY.js} +2 -2
  43. package/dist/{chunk-6GVXZCQV.js → chunk-UDVKRX5R.js} +2 -2
  44. package/dist/{chunk-CPVLVQYT.js → chunk-UQQS3VNT.js} +43 -9
  45. package/dist/{chunk-VB3MJGCV.js → chunk-VD2LV5WO.js} +82 -13
  46. package/dist/{chunk-5WNDJHT6.js → chunk-VPALDFYM.js} +2 -2
  47. package/dist/{chunk-FJEQZHZN.js → chunk-W2CECGTG.js} +24 -14
  48. package/dist/{chunk-CISOLTOP.js → chunk-X5FOFGXX.js} +72 -33
  49. package/dist/{chunk-CWALNI6K.js → chunk-X6KXNHUO.js} +1 -1
  50. package/dist/{chunk-EEOFQDT6.js → chunk-XRNN44QY.js} +46 -2
  51. package/dist/{chunk-EOOFNYIT.js → chunk-YOKD4GWJ.js} +67 -27
  52. package/dist/{chunk-D33S4RQG.js → chunk-ZUFHAHTE.js} +18 -6
  53. package/dist/codebase-index/generic-parser.d.ts +8 -1
  54. package/dist/codebase-index/index.js +9 -9
  55. package/dist/codebase-index/parser-worker-script.js +3 -3
  56. package/dist/codebase-index/project-server.js +5 -5
  57. package/dist/codebase-index/worker.js +4 -4
  58. package/dist/codebase-index/writer-refs.d.ts +1 -1
  59. package/dist/design.d.ts +1 -1
  60. package/dist/design.js +1 -1
  61. package/dist/diff.js +3 -2
  62. package/dist/document.js +2 -2
  63. package/dist/e2e.js +2 -2
  64. package/dist/edit.js +8 -8
  65. package/dist/exec.js +2 -2
  66. package/dist/fetch.js +2 -2
  67. package/dist/format.js +4 -4
  68. package/dist/{generic-parser-VUXDIAOZ.js → generic-parser-WFMIRHBX.js} +2 -2
  69. package/dist/git.js +2 -2
  70. package/dist/glob.js +2 -2
  71. package/dist/grep.d.ts +2 -0
  72. package/dist/grep.js +4 -2
  73. package/dist/index.js +46 -46
  74. package/dist/install.js +4 -4
  75. package/dist/json.js +2 -2
  76. package/dist/kanban-tool-types.d.ts +2 -0
  77. package/dist/kanban.js +2 -2
  78. package/dist/languages/index.js +2 -2
  79. package/dist/{legacy-bridge-SFNXIRAP.js → legacy-bridge-3T7SR4SK.js} +4 -4
  80. package/dist/lint.js +4 -4
  81. package/dist/logs.js +2 -2
  82. package/dist/outdated.js +4 -2
  83. package/dist/pack.js +45 -45
  84. package/dist/{parser-dispatch-X62UWXJS.js → parser-dispatch-QGC4HSP5.js} +4 -4
  85. package/dist/patch.js +8 -8
  86. package/dist/plan.js +4 -4
  87. package/dist/{py-parser-TDXSQZBC.js → py-parser-RFWG2HYI.js} +3 -3
  88. package/dist/read.js +8 -8
  89. package/dist/replace.js +9 -8
  90. package/dist/scaffold.js +2 -2
  91. package/dist/search.js +1 -1
  92. package/dist/session-kanban.js +1 -1
  93. package/dist/task.js +4 -4
  94. package/dist/test.js +4 -4
  95. package/dist/todo.js +3 -3
  96. package/dist/tool-tier.js +46 -46
  97. package/dist/{tree-sitter-parser-AIERW3YI.js → tree-sitter-parser-GILYQLS4.js} +2 -2
  98. package/dist/tree.js +2 -2
  99. package/dist/typecheck.js +4 -4
  100. package/dist/write.js +8 -8
  101. package/package.json +5 -5
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolvePythonBinary
3
- } from "./chunk-ZLTFLC25.js";
3
+ } from "./chunk-IIF5HIVF.js";
4
4
  import {
5
5
  parseParserBatchOutput,
6
6
  withSpawnGate
@@ -832,7 +832,7 @@ async function dispatch(file, content, lang) {
832
832
  return parseSymbols({ file, content, lang: "go" });
833
833
  }
834
834
  case "py": {
835
- const { parseSymbols } = await import("./py-parser-TDXSQZBC.js");
835
+ const { parseSymbols } = await import("./py-parser-RFWG2HYI.js");
836
836
  return parseSymbols({ file, content, lang: "py" });
837
837
  }
838
838
  case "rs": {
@@ -863,16 +863,16 @@ async function dispatch(file, content, lang) {
863
863
  case "shell":
864
864
  case "elixir": {
865
865
  try {
866
- const { parseSymbols: parseSymbols2 } = await import("./tree-sitter-parser-AIERW3YI.js");
866
+ const { parseSymbols: parseSymbols2 } = await import("./tree-sitter-parser-GILYQLS4.js");
867
867
  const parsed = await parseSymbols2({ file, content, lang });
868
868
  if (parsed.symbols.length > 0) return parsed;
869
869
  } catch {
870
870
  }
871
- const { parseSymbols } = await import("./generic-parser-VUXDIAOZ.js");
871
+ const { parseSymbols } = await import("./generic-parser-WFMIRHBX.js");
872
872
  return parseSymbols({ file, content, lang });
873
873
  }
874
874
  default: {
875
- const { parseSymbols } = await import("./generic-parser-VUXDIAOZ.js");
875
+ const { parseSymbols } = await import("./generic-parser-WFMIRHBX.js");
876
876
  return parseSymbols({ file, content, lang });
877
877
  }
878
878
  }
@@ -889,4 +889,4 @@ export {
889
889
  parseFileContent,
890
890
  parseFilesContent
891
891
  };
892
- //# sourceMappingURL=chunk-JJQB6R7Y.js.map
892
+ //# sourceMappingURL=chunk-CMOUCKGC.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  builtinTools
3
- } from "./chunk-K23JNFE3.js";
3
+ } from "./chunk-OTINMOKK.js";
4
4
 
5
5
  // src/pack.ts
6
6
  var builtinToolsPack = {
@@ -12,4 +12,4 @@ var builtinToolsPack = {
12
12
  export {
13
13
  builtinToolsPack
14
14
  };
15
- //# sourceMappingURL=chunk-MX25MTDJ.js.map
15
+ //# sourceMappingURL=chunk-DC4KMPJO.js.map
@@ -9,7 +9,7 @@ import {
9
9
  projectIndexServerBuildId,
10
10
  projectIndexServerEndpoint,
11
11
  projectIndexServerMetadataPath
12
- } from "./chunk-6GVXZCQV.js";
12
+ } from "./chunk-UDVKRX5R.js";
13
13
  import {
14
14
  CircuitOpenError,
15
15
  IndexTimeoutError,
@@ -24,7 +24,7 @@ import {
24
24
  searchService,
25
25
  statsService,
26
26
  symbolGraphService
27
- } from "./chunk-BLCSYKNN.js";
27
+ } from "./chunk-KY4PXYSO.js";
28
28
  import {
29
29
  isIndexablePath
30
30
  } from "./chunk-YOHO4DVT.js";
@@ -1269,4 +1269,4 @@ export {
1269
1269
  checkCodebaseIndexServerHealth,
1270
1270
  ensureCodebaseIndexServer
1271
1271
  };
1272
- //# sourceMappingURL=chunk-VZLX2JZG.js.map
1272
+ //# sourceMappingURL=chunk-DP6CXMJZ.js.map
@@ -1,15 +1,16 @@
1
1
  import {
2
2
  tryLegacyCodeOperation
3
- } from "./chunk-4E42D7UF.js";
3
+ } from "./chunk-ATSKPZUK.js";
4
4
  import {
5
5
  spawnStream
6
6
  } from "./chunk-ZHH3BEWU.js";
7
7
  import {
8
8
  normalizeCommandOutput,
9
9
  safeResolveReal
10
- } from "./chunk-D33S4RQG.js";
10
+ } from "./chunk-ZUFHAHTE.js";
11
11
 
12
12
  // src/format.ts
13
+ import { ToolValidationError } from "@wrongstack/core/types";
13
14
  var formatTool = {
14
15
  name: "format",
15
16
  category: "Code Quality",
@@ -55,6 +56,14 @@ var formatTool = {
55
56
  async *executeStream(input, ctx, opts) {
56
57
  const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
57
58
  const signal = opts?.signal ?? ctx.signal ?? new AbortController().signal;
59
+ signal.throwIfAborted();
60
+ const VALID_FIXERS = /* @__PURE__ */ new Set(["biome", "prettier", "auto"]);
61
+ if (input.fixer !== void 0 && !VALID_FIXERS.has(input.fixer)) {
62
+ throw new ToolValidationError({
63
+ message: `format: unsupported fixer "${input.fixer}". Allowed fixers: biome, prettier, auto`,
64
+ field: "fixer"
65
+ });
66
+ }
58
67
  const fixer = input.fixer ?? "auto";
59
68
  if (fixer === "auto" && !input.files) {
60
69
  const op = input.check ? "format-check" : "format-write";
@@ -98,7 +107,7 @@ var formatTool = {
98
107
  text: `Running ${detected}\u2026`,
99
108
  data: { fixer: detected, check: !!input.check }
100
109
  };
101
- const fileList = input.files ? (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim()) : [];
110
+ const fileList = input.files ? (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean) : [];
102
111
  let args;
103
112
  if (detected === "prettier") {
104
113
  args = [input.check ? "--check" : "--write"];
@@ -116,33 +125,45 @@ var formatTool = {
116
125
  });
117
126
  const combinedOut = `${result.stdout}
118
127
  ${result.stderr}`;
119
- const counts = parseFormatterCounts(detected, combinedOut);
128
+ const counts = parseFormatterCounts(detected, combinedOut, !!input.check);
129
+ const rawOutput = result.stdout && result.stderr ? `${result.stdout}
130
+ ${result.stderr}` : result.stdout || result.stderr || result.error || "";
120
131
  yield {
121
132
  type: "final",
122
133
  output: {
123
134
  fixer: detected,
124
135
  files_checked: counts.checked,
125
136
  files_changed: counts.changed,
126
- output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ""),
137
+ output: normalizeCommandOutput(rawOutput),
127
138
  truncated: result.truncated
128
139
  }
129
140
  };
130
141
  }
131
142
  };
132
- function parseFormatterCounts(fixer, output) {
143
+ function parseFormatterCounts(fixer, output, isCheck = false) {
133
144
  if (fixer !== "biome") return { checked: void 0, changed: void 0 };
134
145
  const checkedMatch = /\b(?:Checked|Formatted)\s+(\d+)\s+files?\b/i.exec(output);
135
- const changedMatch = /\bFixed\s+(\d+)\s+files?\b/i.exec(output);
146
+ const fixedMatch = /\bFixed\s+(\d+)\s+files?\b/i.exec(output);
147
+ const formattedCountMatch = /\bFormatted\s+(\d+)\s+files?\b/i.exec(output);
148
+ let changed;
149
+ if (isCheck) {
150
+ changed = 0;
151
+ } else if (fixedMatch?.[1] !== void 0) {
152
+ changed = Number(fixedMatch[1]);
153
+ } else if (formattedCountMatch?.[1] !== void 0) {
154
+ changed = Number(formattedCountMatch[1]);
155
+ }
136
156
  return {
137
157
  checked: checkedMatch?.[1] !== void 0 ? Number(checkedMatch[1]) : void 0,
138
- changed: changedMatch?.[1] !== void 0 ? Number(changedMatch[1]) : void 0
158
+ changed
139
159
  };
140
160
  }
141
161
  async function detectFixer(cwd) {
142
162
  const fs = await import("node:fs/promises");
163
+ const { join } = await import("node:path");
143
164
  const exists = async (file) => {
144
165
  try {
145
- await fs.stat(`${cwd}/${file}`);
166
+ await fs.stat(join(cwd, file));
146
167
  return true;
147
168
  } catch {
148
169
  return false;
@@ -152,20 +173,23 @@ async function detectFixer(cwd) {
152
173
  const PRETTIER_CONFIGS = [
153
174
  ".prettierrc",
154
175
  ".prettierrc.json",
176
+ ".prettierrc.json5",
155
177
  ".prettierrc.yml",
156
178
  ".prettierrc.yaml",
179
+ ".prettierrc.toml",
157
180
  ".prettierrc.js",
158
181
  ".prettierrc.cjs",
159
182
  ".prettierrc.mjs",
160
183
  "prettier.config.js",
161
184
  "prettier.config.cjs",
162
- "prettier.config.mjs"
185
+ "prettier.config.mjs",
186
+ "prettier.config.ts"
163
187
  ];
164
188
  for (const cfg of PRETTIER_CONFIGS) {
165
189
  if (await exists(cfg)) return "prettier";
166
190
  }
167
191
  try {
168
- const raw = await fs.readFile(`${cwd}/package.json`, "utf8");
192
+ const raw = await fs.readFile(join(cwd, "package.json"), "utf8");
169
193
  const pkg = JSON.parse(raw);
170
194
  if (pkg["prettier"] !== void 0) return "prettier";
171
195
  } catch {
@@ -176,4 +200,4 @@ async function detectFixer(cwd) {
176
200
  export {
177
201
  formatTool
178
202
  };
179
- //# sourceMappingURL=chunk-3QQSBUXR.js.map
203
+ //# sourceMappingURL=chunk-EADULOZV.js.map
@@ -14,6 +14,8 @@ import {
14
14
  setActiveKit,
15
15
  setDesignOverrides
16
16
  } from "@wrongstack/core/design";
17
+ import { ToolValidationError } from "@wrongstack/core/types";
18
+ import { atomicWrite } from "@wrongstack/core/utils";
17
19
  async function resolveReal(p) {
18
20
  const resolved = path.resolve(p);
19
21
  let probe = resolved;
@@ -102,10 +104,33 @@ var designTool = {
102
104
  },
103
105
  required: []
104
106
  },
105
- async execute(input, ctx) {
107
+ async execute(input, ctx, _opts) {
108
+ const signal = _opts?.signal ?? ctx?.signal;
109
+ signal?.throwIfAborted();
110
+ const VALID_ACTIONS = /* @__PURE__ */ new Set([
111
+ "list",
112
+ "use",
113
+ "foundations",
114
+ "set",
115
+ "tune",
116
+ "materialize",
117
+ "verify"
118
+ ]);
119
+ if (input.action !== void 0 && !VALID_ACTIONS.has(input.action)) {
120
+ throw new ToolValidationError({
121
+ message: `design: unknown action "${input.action}". Allowed actions: ${[...VALID_ACTIONS].join(", ")}`,
122
+ field: "action"
123
+ });
124
+ }
125
+ if (input.stack !== void 0 && !isDesignStack(input.stack)) {
126
+ throw new ToolValidationError({
127
+ message: `design: invalid stack "${input.stack}". Allowed stacks: web, react-native, flutter, swiftui, compose`,
128
+ field: "stack"
129
+ });
130
+ }
106
131
  const loader = getDesignKitLoader(ctx.projectRoot);
107
132
  const action = input.action ?? "list";
108
- const stack = input.stack && isDesignStack(input.stack) ? input.stack : void 0;
133
+ const stack = input.stack;
109
134
  if (action === "foundations") {
110
135
  const text = await loader.foundationsText(stack);
111
136
  return { action, stack, output: text || "No foundations document is installed." };
@@ -231,7 +256,10 @@ Run \`design {action:"materialize"}\` to write the tuned tokens to your theme fi
231
256
  const abs = path.join(absParent, path.basename(absResolved));
232
257
  const rel = path.relative(root, abs);
233
258
  if (rel.startsWith("..") || path.isAbsolute(rel)) {
234
- throw new Error(`design: materialize path "${result.path}" would escape the project root`);
259
+ throw new ToolValidationError({
260
+ message: `design: materialize path "${result.path}" would escape the project root`,
261
+ field: "out"
262
+ });
235
263
  }
236
264
  let exists = false;
237
265
  try {
@@ -253,7 +281,7 @@ ${result.content}
253
281
  };
254
282
  }
255
283
  await fs.mkdir(path.dirname(abs), { recursive: true });
256
- await fs.writeFile(abs, result.content);
284
+ await atomicWrite(abs, result.content);
257
285
  return {
258
286
  action,
259
287
  kit: active.kit,
@@ -263,6 +291,7 @@ ${result.content}
263
291
  };
264
292
  }
265
293
  if (action === "verify") {
294
+ signal?.throwIfAborted();
266
295
  const active = await loadActiveKit(ctx.projectRoot);
267
296
  if (!active) {
268
297
  return {
@@ -270,12 +299,15 @@ ${result.content}
270
299
  output: 'No active kit to verify against. Pick one: `design {action:"use", kit:"<id>"}`.'
271
300
  };
272
301
  }
302
+ signal?.throwIfAborted();
273
303
  const rawTokens = await loader.readTokens(active.kit);
274
304
  if (!rawTokens) {
275
305
  return { action, kit: active.kit, output: `Kit "${active.kit}" has no tokens.json.` };
276
306
  }
307
+ signal?.throwIfAborted();
277
308
  const tokens = applyTokenOverrides(rawTokens, active.overrides);
278
- const report = await runDesignVerify(ctx.projectRoot, tokens, input.files);
309
+ const normalizedFiles = input.files ? (Array.isArray(input.files) ? input.files : String(input.files).split(",")).map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean) : void 0;
310
+ const report = await runDesignVerify(ctx.projectRoot, tokens, normalizedFiles);
279
311
  const pct = Math.round(report.score * 100);
280
312
  const top = report.violations.slice(0, 25).map((v) => ` ${v.file}:${v.line} \u2014 ${v.reason}: ${v.snippet}`).join("\n");
281
313
  const summary = `Adherence: ${pct}% on-palette across ${report.filesScanned} file(s). ${report.violations.length} violation(s).` + (report.violations.length ? `
@@ -302,4 +334,4 @@ Replace off-palette colors with kit tokens (or the materialized CSS vars / token
302
334
  export {
303
335
  designTool
304
336
  };
305
- //# sourceMappingURL=chunk-6RNIFLG4.js.map
337
+ //# sourceMappingURL=chunk-ELRRTWNP.js.map
@@ -3,11 +3,13 @@ import {
3
3
  } from "./chunk-Q5JPPCZC.js";
4
4
  import {
5
5
  safeResolveReal
6
- } from "./chunk-D33S4RQG.js";
6
+ } from "./chunk-ZUFHAHTE.js";
7
7
 
8
8
  // src/logs.ts
9
9
  import { spawn } from "node:child_process";
10
+ import { StringDecoder } from "node:string_decoder";
10
11
  import { buildChildEnv } from "@wrongstack/core/utils";
12
+ import { ToolValidationError } from "@wrongstack/core/types";
11
13
  var logsTool = {
12
14
  name: "logs",
13
15
  category: "Logs",
@@ -51,12 +53,32 @@ var logsTool = {
51
53
  async execute(input, ctx, opts) {
52
54
  const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
53
55
  const signal = opts?.signal ?? ctx.signal ?? new AbortController().signal;
54
- const lines = input.lines ?? 100;
56
+ if (signal.aborted) {
57
+ return {
58
+ source: "none",
59
+ entries: [],
60
+ total: 0,
61
+ truncated: false,
62
+ stream_mode: false
63
+ };
64
+ }
65
+ const VALID_SINCE = /* @__PURE__ */ new Set(["1h", "6h", "24h", "all"]);
66
+ if (input.since !== void 0 && !VALID_SINCE.has(input.since)) {
67
+ throw new ToolValidationError({
68
+ message: `logs: invalid since option "${input.since}". Allowed: 1h, 6h, 24h, all`,
69
+ field: "since"
70
+ });
71
+ }
72
+ const rawLines = typeof input.lines === "number" && !Number.isNaN(input.lines) ? input.lines : 100;
73
+ const lines = Math.max(0, Math.floor(rawLines));
55
74
  let filterRe = null;
56
75
  if (input.filter) {
57
76
  const compiled = compileUserRegex(input.filter, "i");
58
77
  if (!compiled.ok) {
59
- throw new Error(`logs: ${compiled.reason}`);
78
+ throw new ToolValidationError({
79
+ message: `logs: ${compiled.reason}`,
80
+ field: "filter"
81
+ });
60
82
  }
61
83
  filterRe = compiled.regex;
62
84
  }
@@ -92,10 +114,21 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
92
114
  };
93
115
  }
94
116
  args.push("--timestamps", service);
117
+ if (signal.aborted) {
118
+ return Promise.resolve({
119
+ source: `docker:${service}`,
120
+ entries: [],
121
+ total: 0,
122
+ truncated: false,
123
+ stream_mode: false
124
+ });
125
+ }
95
126
  return new Promise((resolve) => {
96
127
  let stdout = "";
97
128
  let stderr = "";
98
129
  const MAX = 2e5;
130
+ const stdoutDecoder = new StringDecoder("utf8");
131
+ const stderrDecoder = new StringDecoder("utf8");
99
132
  let settled = false;
100
133
  const empty = () => ({
101
134
  source: `docker:${service}`,
@@ -122,10 +155,16 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
122
155
  finish(empty());
123
156
  }, DOCKER_LOGS_TIMEOUT_MS);
124
157
  child.stdout?.on("data", (c) => {
125
- if (stdout.length < MAX) stdout += c.toString();
158
+ if (stdout.length < MAX) {
159
+ const text = stdoutDecoder.write(c);
160
+ stdout += text.slice(0, MAX - stdout.length);
161
+ }
126
162
  });
127
163
  child.stderr?.on("data", (c) => {
128
- if (stderr.length < MAX) stderr += c.toString();
164
+ if (stderr.length < MAX) {
165
+ const text = stderrDecoder.write(c);
166
+ stderr += text.slice(0, MAX - stderr.length);
167
+ }
129
168
  });
130
169
  child.stdout?.on("error", (e) => {
131
170
  console.log(
@@ -229,4 +268,4 @@ function parseLine(line) {
229
268
  export {
230
269
  logsTool
231
270
  };
232
- //# sourceMappingURL=chunk-CPSAF2AU.js.map
271
+ //# sourceMappingURL=chunk-FQNXYA6W.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  builtinToolsPack
3
- } from "./chunk-MX25MTDJ.js";
3
+ } from "./chunk-DC4KMPJO.js";
4
4
  import {
5
5
  TIER1_TOOLS,
6
6
  TIER2_TOOLS
7
- } from "./chunk-K23JNFE3.js";
7
+ } from "./chunk-OTINMOKK.js";
8
8
 
9
9
  // src/tool-tier.ts
10
10
  function toolNameSet(tools) {
@@ -51,4 +51,4 @@ export {
51
51
  selectBuiltinToolsForTier,
52
52
  registerBuiltinToolTier
53
53
  };
54
- //# sourceMappingURL=chunk-ZZT45EHF.js.map
54
+ //# sourceMappingURL=chunk-GMZYW52L.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseGeneric
3
- } from "./chunk-A6BRWIXN.js";
3
+ } from "./chunk-6IEBD27U.js";
4
4
  import {
5
5
  parseParserOutput,
6
6
  withSpawnGate
@@ -382,4 +382,4 @@ export {
382
382
  parseSymbols,
383
383
  resolvePythonBinary
384
384
  };
385
- //# sourceMappingURL=chunk-ZLTFLC25.js.map
385
+ //# sourceMappingURL=chunk-IIF5HIVF.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureInsideRoot,
3
3
  safeResolveReal
4
- } from "./chunk-D33S4RQG.js";
4
+ } from "./chunk-ZUFHAHTE.js";
5
5
 
6
6
  // src/document.ts
7
7
  import * as fs from "node:fs/promises";
@@ -40,7 +40,9 @@ var documentTool = {
40
40
  cwd: { type: "string", description: "Working directory (default: cwd)" }
41
41
  }
42
42
  },
43
- async execute(input, ctx) {
43
+ async execute(input, ctx, _opts) {
44
+ const signal = _opts?.signal ?? ctx?.signal;
45
+ signal?.throwIfAborted();
44
46
  const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
45
47
  const style = input.style ?? "jsdoc";
46
48
  const results = [];
@@ -52,6 +54,7 @@ var documentTool = {
52
54
  ctx
53
55
  ) : input.path ? [await safeResolveReal(input.path, ctx)] : [];
54
56
  for (const absPath of fileList) {
57
+ if (signal?.aborted) break;
55
58
  try {
56
59
  const content = await fs.readFile(absPath, "utf8");
57
60
  filesProcessed++;
@@ -67,7 +70,7 @@ var documentTool = {
67
70
  } catch (e) {
68
71
  results.push({
69
72
  path: absPath,
70
- name: absPath.split("/").pop() ?? absPath,
73
+ name: path.basename(absPath),
71
74
  signature: "",
72
75
  docstring: "",
73
76
  status: "error",
@@ -83,6 +86,13 @@ var documentTool = {
83
86
  };
84
87
  }
85
88
  };
89
+ function getLineNumber(content, index) {
90
+ let line = 1;
91
+ for (let i = 0; i < index; i++) {
92
+ if (content.charCodeAt(i) === 10) line++;
93
+ }
94
+ return line;
95
+ }
86
96
  async function resolveFiles(filesInput, cwd, ctx) {
87
97
  const files = filesInput.split(",");
88
98
  const resolved = [];
@@ -117,7 +127,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
117
127
  name: m[1],
118
128
  sig: m[2] ?? "",
119
129
  type: "function",
120
- line: content.slice(0, m.index).split("\n").length
130
+ line: getLineNumber(content, m.index)
121
131
  });
122
132
  }
123
133
  for (const m of content.matchAll(arrowRegex)) {
@@ -126,7 +136,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
126
136
  name: m[1],
127
137
  sig: m[2] ?? "",
128
138
  type: "arrow",
129
- line: content.slice(0, m.index).split("\n").length
139
+ line: getLineNumber(content, m.index)
130
140
  });
131
141
  }
132
142
  }
@@ -137,7 +147,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
137
147
  name: m[1],
138
148
  sig: "",
139
149
  type: "class",
140
- line: content.slice(0, m.index).split("\n").length
150
+ line: getLineNumber(content, m.index)
141
151
  });
142
152
  }
143
153
  }
@@ -148,7 +158,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
148
158
  name: m[1],
149
159
  sig: m[0] ?? "",
150
160
  type: "type",
151
- line: content.slice(0, m.index).split("\n").length
161
+ line: getLineNumber(content, m.index)
152
162
  });
153
163
  }
154
164
  }
@@ -167,4 +177,4 @@ function processFile(content, absPath, _style, _overwrite, target) {
167
177
  export {
168
178
  documentTool
169
179
  };
170
- //# sourceMappingURL=chunk-EMRGN4KM.js.map
180
+ //# sourceMappingURL=chunk-IU4DV2PA.js.map
@@ -1,17 +1,18 @@
1
1
  import {
2
2
  enqueueReindex
3
- } from "./chunk-VZLX2JZG.js";
3
+ } from "./chunk-DP6CXMJZ.js";
4
4
  import {
5
5
  resolveRealInsideRoot,
6
6
  safeResolveReal,
7
7
  sha256hex
8
- } from "./chunk-D33S4RQG.js";
8
+ } from "./chunk-ZUFHAHTE.js";
9
9
 
10
10
  // src/patch.ts
11
11
  import { spawn } from "node:child_process";
12
12
  import * as fs from "node:fs/promises";
13
13
  import * as os from "node:os";
14
14
  import * as path from "node:path";
15
+ import { ToolValidationError } from "@wrongstack/core/types";
15
16
  import { buildChildEnv, toErrorMessage } from "@wrongstack/core/utils";
16
17
  var patchTool = {
17
18
  name: "patch",
@@ -42,9 +43,15 @@ var patchTool = {
42
43
  required: ["patch"]
43
44
  },
44
45
  async execute(input, ctx, opts) {
45
- if (!input?.patch) throw new Error("patch: patch content is required");
46
+ if (!input?.patch || typeof input.patch !== "string" || !input.patch.trim()) {
47
+ throw new ToolValidationError({
48
+ message: "patch: patch content is required and cannot be empty",
49
+ field: "patch"
50
+ });
51
+ }
46
52
  const signal = opts?.signal ?? ctx.signal ?? new AbortController().signal;
47
- const strip = Math.max(1, input.strip ?? 1);
53
+ signal.throwIfAborted();
54
+ const strip = typeof input.strip === "number" && Number.isFinite(input.strip) && input.strip >= 0 ? Math.floor(input.strip) : 1;
48
55
  const dryRun = input.dry_run ?? false;
49
56
  const refuse = (message) => ({
50
57
  applied: 0,
@@ -196,7 +203,11 @@ function extractDiffTargets(patch) {
196
203
  const out = [];
197
204
  const clean = (raw) => {
198
205
  if (!raw) return "";
199
- return (raw.length > 4096 ? raw.slice(0, 4096) : raw).trim();
206
+ let s = (raw.length > 4096 ? raw.slice(0, 4096) : raw).trim();
207
+ if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
208
+ s = s.slice(1, -1).trim();
209
+ }
210
+ return s;
200
211
  };
201
212
  let lastOld;
202
213
  let inHunk = false;
@@ -269,6 +280,14 @@ function runPatch(args, cwd, signal, fallback) {
269
280
  });
270
281
  }
271
282
  function runPatchProcess(command, args, cwd, signal) {
283
+ if (signal.aborted) {
284
+ return Promise.resolve({
285
+ exitCode: 124,
286
+ stdout: "",
287
+ stderr: "Aborted",
288
+ unavailable: false
289
+ });
290
+ }
272
291
  return new Promise((resolve2) => {
273
292
  let stdout = "";
274
293
  let stderr = "";
@@ -280,6 +299,7 @@ function runPatchProcess(command, args, cwd, signal) {
280
299
  stdio: ["pipe", "pipe", "pipe"],
281
300
  windowsHide: true
282
301
  });
302
+ child.stdin?.end();
283
303
  child.stdout?.on("data", (c) => {
284
304
  stdout += c.toString();
285
305
  });
@@ -305,7 +325,10 @@ function extractPatchedFiles(output) {
305
325
  const files = [];
306
326
  const re = /(?:patching|checking) file (.+)/gi;
307
327
  for (const m of output.matchAll(re)) {
308
- if (m[1]) files.push(m[1]);
328
+ if (m[1]) {
329
+ const sanitized = m[1].replace(/^['"`]|['"`\r\n]+$/g, "").trim();
330
+ if (sanitized) files.push(sanitized);
331
+ }
309
332
  }
310
333
  return files;
311
334
  }
@@ -313,4 +336,4 @@ function extractPatchedFiles(output) {
313
336
  export {
314
337
  patchTool
315
338
  };
316
- //# sourceMappingURL=chunk-AGUSOFNI.js.map
339
+ //# sourceMappingURL=chunk-IWS56OY7.js.map