@wrongstack/tools 1.0.8 → 1.0.9

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 (135) hide show
  1. package/dist/_win32-resolve.d.ts +5 -0
  2. package/dist/audit.js +5 -5
  3. package/dist/bash.js +2 -2
  4. package/dist/browser/index.js +1 -1
  5. package/dist/builtin.js +41 -41
  6. package/dist/{chunk-N3OTTQNC.js → chunk-2OCAAFAT.js} +44 -25
  7. package/dist/{chunk-5MP76C72.js → chunk-2UVAIS5O.js} +24 -29
  8. package/dist/{chunk-SIIOHBNY.js → chunk-3RRK33YM.js} +2 -2
  9. package/dist/{chunk-M2W36JT7.js → chunk-4CE3RKEP.js} +6 -3
  10. package/dist/{chunk-QJARSK2G.js → chunk-4SUGLJLO.js} +11 -3
  11. package/dist/{chunk-AH7J5HWL.js → chunk-5RBUYFRV.js} +15 -7
  12. package/dist/{chunk-WKLUOXR4.js → chunk-7GOE2ZTZ.js} +2 -2
  13. package/dist/{chunk-O6AGFJBO.js → chunk-7V33PHT6.js} +49 -77
  14. package/dist/{chunk-CAF4L6KN.js → chunk-C3WP6ZOT.js} +36 -48
  15. package/dist/{chunk-KMXPP32M.js → chunk-C6ZOXNXV.js} +13 -3
  16. package/dist/{chunk-EGT5QLCB.js → chunk-D6RQZMZS.js} +123 -255
  17. package/dist/{chunk-S6CGSFLX.js → chunk-DBG7UQGK.js} +10 -3
  18. package/dist/{chunk-FI6SOIVE.js → chunk-DLZCOEVG.js} +21 -3
  19. package/dist/{chunk-NL45OWEO.js → chunk-DOAHONOS.js} +7 -12
  20. package/dist/{chunk-3LQJXJDM.js → chunk-E7A4SLKR.js} +2 -2
  21. package/dist/{chunk-JB5JLY7V.js → chunk-ENE22I5W.js} +387 -394
  22. package/dist/{chunk-SEONDNLN.js → chunk-G7CYW5EP.js} +2 -2
  23. package/dist/{chunk-MF6ZUBI7.js → chunk-HV7RWDCL.js} +3 -3
  24. package/dist/{chunk-TU6UVATU.js → chunk-HYHE4VNA.js} +3 -3
  25. package/dist/{chunk-HIRVCXLP.js → chunk-IE4KDAOB.js} +3 -3
  26. package/dist/{chunk-YA2ZYCJY.js → chunk-JPK2HHBK.js} +1 -1
  27. package/dist/{chunk-7E55DAFW.js → chunk-KHUCKLOR.js} +12 -7
  28. package/dist/{chunk-R3HIZVFS.js → chunk-KPDCKSN5.js} +23 -3
  29. package/dist/{chunk-B3MGJBFI.js → chunk-KS2OEZWV.js} +23 -47
  30. package/dist/{chunk-UI3ZJIG3.js → chunk-LKLIQUCW.js} +14 -8
  31. package/dist/{chunk-62OAECEQ.js → chunk-LLSFOUZF.js} +8 -8
  32. package/dist/{chunk-YZQSUL5G.js → chunk-M4ZHHCCW.js} +14 -6
  33. package/dist/{chunk-IXIS7RSG.js → chunk-MRXWOOOR.js} +29 -47
  34. package/dist/{chunk-C4DSQBTT.js → chunk-NEYUPZL6.js} +3 -3
  35. package/dist/{chunk-6XYFYLN7.js → chunk-O2MHULBO.js} +13 -8
  36. package/dist/{chunk-B62LKMWQ.js → chunk-OKZJJDOG.js} +86 -188
  37. package/dist/{chunk-HOFVYIPI.js → chunk-ON6ET5ER.js} +16 -1
  38. package/dist/{chunk-KF7GMVNU.js → chunk-OUERRFEM.js} +32 -11
  39. package/dist/{chunk-GNLHBDFO.js → chunk-OXO773CW.js} +127 -196
  40. package/dist/{chunk-GF4JHLCO.js → chunk-PWZUHZP7.js} +2 -2
  41. package/dist/{chunk-5KRKL3WD.js → chunk-QA37PFYL.js} +28 -67
  42. package/dist/{chunk-OGQMPX3J.js → chunk-QAWI3RSK.js} +37 -81
  43. package/dist/{chunk-ZMCV3XOV.js → chunk-SPNXDTCJ.js} +29 -63
  44. package/dist/{chunk-H2VB7GCR.js → chunk-ULI2J6TX.js} +27 -14
  45. package/dist/{chunk-EMA2XENR.js → chunk-UVYRQKPZ.js} +4 -3
  46. package/dist/{chunk-2NTHMZV3.js → chunk-VMJY6FYJ.js} +693 -276
  47. package/dist/{chunk-YUK3WLHJ.js → chunk-WEUEU53R.js} +2 -2
  48. package/dist/{chunk-ZOUG3KKS.js → chunk-XPVYZ2S6.js} +2 -2
  49. package/dist/{chunk-5U5ULQX2.js → chunk-XZLVJD56.js} +5 -1
  50. package/dist/{chunk-HCPSVK7J.js → chunk-YKSOSI2N.js} +47 -31
  51. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +5 -6
  52. package/dist/codebase-index/codebase-context-tool.d.ts +4 -6
  53. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +1 -2
  54. package/dist/codebase-index/codebase-incoming-calls-tool.d.ts +0 -2
  55. package/dist/codebase-index/codebase-index-tool.d.ts +0 -2
  56. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +1 -2
  57. package/dist/codebase-index/codebase-outgoing-calls-tool.d.ts +0 -2
  58. package/dist/codebase-index/codebase-repo-map-tool.d.ts +1 -2
  59. package/dist/codebase-index/codebase-search-tool.d.ts +1 -1
  60. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +1 -2
  61. package/dist/codebase-index/index.js +8 -8
  62. package/dist/codebase-index/parser-worker-script.js +3 -3
  63. package/dist/codebase-index/project-server.js +5 -5
  64. package/dist/codebase-index/worker.js +4 -4
  65. package/dist/design.js +1 -1
  66. package/dist/diff.js +1 -1
  67. package/dist/edit.js +7 -7
  68. package/dist/exec.d.ts +7 -7
  69. package/dist/exec.js +2 -2
  70. package/dist/format.js +5 -5
  71. package/dist/git.js +1 -1
  72. package/dist/glob.js +1 -1
  73. package/dist/{go-parser-VDPRQEGM.js → go-parser-Z4H6SR3R.js} +6 -3
  74. package/dist/grep.js +1 -1
  75. package/dist/index.js +45 -45
  76. package/dist/install.js +5 -5
  77. package/dist/json.d.ts +0 -1
  78. package/dist/json.js +1 -1
  79. package/dist/kanban-presence.d.ts +6 -0
  80. package/dist/kanban-serializer.d.ts +9 -1
  81. package/dist/kanban-split-task-handler.d.ts +1 -1
  82. package/dist/kanban-tool-results.d.ts +57 -2
  83. package/dist/kanban-tool-types.d.ts +16 -5
  84. package/dist/kanban.d.ts +14 -0
  85. package/dist/kanban.js +9 -1
  86. package/dist/languages/index.js +3 -3
  87. package/dist/{legacy-bridge-4T4OTSQP.js → legacy-bridge-BPT2S2F4.js} +5 -5
  88. package/dist/lint.js +5 -5
  89. package/dist/logs.js +1 -1
  90. package/dist/mode.d.ts +3 -2
  91. package/dist/mode.js +1 -1
  92. package/dist/outdated.js +2 -2
  93. package/dist/pack.js +42 -42
  94. package/dist/{parser-dispatch-4E2SDQUO.js → parser-dispatch-WG4DNBHH.js} +4 -4
  95. package/dist/patch.js +7 -7
  96. package/dist/plan.d.ts +2 -1
  97. package/dist/plan.js +3 -3
  98. package/dist/{py-parser-MAW6DHFE.js → py-parser-4PFZYAJ7.js} +3 -3
  99. package/dist/read.js +7 -7
  100. package/dist/replace.js +7 -7
  101. package/dist/search.d.ts +0 -6
  102. package/dist/search.js +1 -1
  103. package/dist/security-ast-scan-tool.d.ts +1 -2
  104. package/dist/session-shell.js +2 -2
  105. package/dist/task.d.ts +2 -1
  106. package/dist/task.js +3 -3
  107. package/dist/test.d.ts +8 -1
  108. package/dist/test.js +5 -5
  109. package/dist/todo.js +2 -2
  110. package/dist/tool-search.d.ts +2 -0
  111. package/dist/tool-search.js +1 -1
  112. package/dist/tool-tier.js +43 -43
  113. package/dist/tool-use.d.ts +2 -2
  114. package/dist/tool-use.js +1 -1
  115. package/dist/tree.js +1 -1
  116. package/dist/typecheck.js +5 -5
  117. package/dist/wasm/bash/tree-sitter-bash.wasm +0 -0
  118. package/dist/wasm/c/tree-sitter-c.wasm +0 -0
  119. package/dist/wasm/c_sharp/tree-sitter-c_sharp.wasm +0 -0
  120. package/dist/wasm/checksums.json +16 -0
  121. package/dist/wasm/cpp/tree-sitter-cpp.wasm +0 -0
  122. package/dist/wasm/elixir/tree-sitter-elixir.wasm +0 -0
  123. package/dist/wasm/go/tree-sitter-go.wasm +0 -0
  124. package/dist/wasm/java/tree-sitter-java.wasm +0 -0
  125. package/dist/wasm/kotlin/tree-sitter-kotlin.wasm +0 -0
  126. package/dist/wasm/php/tree-sitter-php.wasm +0 -0
  127. package/dist/wasm/python/tree-sitter-python.wasm +0 -0
  128. package/dist/wasm/ruby/tree-sitter-ruby.wasm +0 -0
  129. package/dist/wasm/rust/tree-sitter-rust.wasm +0 -0
  130. package/dist/wasm/swift/tree-sitter-swift.wasm +0 -0
  131. package/dist/wasm/tree-sitter-runtime.wasm +0 -0
  132. package/dist/win32.d.ts +1 -1
  133. package/dist/win32.js +3 -1
  134. package/dist/write.js +7 -7
  135. package/package.json +10 -10
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  spawnStream
3
- } from "./chunk-EMA2XENR.js";
3
+ } from "./chunk-UVYRQKPZ.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-SEONDNLN.js.map
3518
+ //# sourceMappingURL=chunk-G7CYW5EP.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  builtinToolsPack
3
- } from "./chunk-YUK3WLHJ.js";
3
+ } from "./chunk-WEUEU53R.js";
4
4
  import {
5
5
  TIER1_TOOLS,
6
6
  TIER2_TOOLS
7
- } from "./chunk-GNLHBDFO.js";
7
+ } from "./chunk-OXO773CW.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-MF6ZUBI7.js.map
57
+ //# sourceMappingURL=chunk-HV7RWDCL.js.map
@@ -13,7 +13,7 @@ import {
13
13
  projectIndexServerMetadataPath,
14
14
  projectIndexServerStderrPath,
15
15
  readProjectIndexServerStderrTail
16
- } from "./chunk-ZOUG3KKS.js";
16
+ } from "./chunk-XPVYZ2S6.js";
17
17
  import {
18
18
  CircuitOpenError,
19
19
  IndexTimeoutError,
@@ -28,7 +28,7 @@ import {
28
28
  searchService,
29
29
  statsService,
30
30
  symbolGraphService
31
- } from "./chunk-C4DSQBTT.js";
31
+ } from "./chunk-NEYUPZL6.js";
32
32
  import {
33
33
  recordIpcPending
34
34
  } from "./chunk-ZKC5UNGD.js";
@@ -1352,4 +1352,4 @@ export {
1352
1352
  checkCodebaseIndexServerHealth,
1353
1353
  ensureCodebaseIndexServer
1354
1354
  };
1355
- //# sourceMappingURL=chunk-TU6UVATU.js.map
1355
+ //# sourceMappingURL=chunk-HYHE4VNA.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getIndexState,
3
3
  searchCodebaseIndex
4
- } from "./chunk-TU6UVATU.js";
4
+ } from "./chunk-HYHE4VNA.js";
5
5
  import {
6
6
  codebaseIndexDirOverride
7
- } from "./chunk-C4DSQBTT.js";
7
+ } from "./chunk-NEYUPZL6.js";
8
8
  import {
9
9
  isBinaryBuffer,
10
10
  safeResolveReal,
@@ -340,4 +340,4 @@ ${interesting.join("\n")}` : "symbols/imports: (none detected)"
340
340
  export {
341
341
  readTool
342
342
  };
343
- //# sourceMappingURL=chunk-HIRVCXLP.js.map
343
+ //# sourceMappingURL=chunk-IE4KDAOB.js.map
@@ -82,4 +82,4 @@ var toolSearchTool = {
82
82
  export {
83
83
  toolSearchTool
84
84
  };
85
- //# sourceMappingURL=chunk-YA2ZYCJY.js.map
85
+ //# sourceMappingURL=chunk-JPK2HHBK.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolvePythonBinary
3
- } from "./chunk-M2W36JT7.js";
3
+ } from "./chunk-4CE3RKEP.js";
4
4
  import {
5
5
  parseParserBatchOutput,
6
6
  recordParserSubprocess,
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-ZKC5UNGD.js";
9
9
  import {
10
10
  resolveWin32Command
11
- } from "./chunk-5U5ULQX2.js";
11
+ } from "./chunk-XZLVJD56.js";
12
12
 
13
13
  // src/codebase-index/import-extractor.ts
14
14
  var IMPORT_MAX_FILE_CHARS = 512 * 1024;
@@ -140,6 +140,7 @@ import * as fsSync from "node:fs";
140
140
  import * as fs from "node:fs/promises";
141
141
  import * as os from "node:os";
142
142
  import * as path from "node:path";
143
+ import { StringDecoder } from "node:string_decoder";
143
144
  var MAX_BATCH_FILES = 100;
144
145
  var MAX_BATCH_BYTES = 8 * 1024 * 1024;
145
146
  function chunkBatchFiles(files) {
@@ -665,15 +666,19 @@ function runToolchainChild(binary, args, stdinPayload, timeoutMs) {
665
666
  }, timeoutMs);
666
667
  timer.unref?.();
667
668
  proc.on("error", () => finish(null));
669
+ const stdoutDecoder = new StringDecoder("utf8");
668
670
  proc.stdout?.on("data", (chunk) => {
669
- stdout += chunk.toString();
671
+ stdout += stdoutDecoder.write(chunk);
670
672
  });
671
673
  proc.stderr?.resume();
672
674
  proc.stdin?.on("error", () => {
673
675
  });
674
676
  proc.stdin?.write(stdinPayload);
675
677
  proc.stdin?.end();
676
- proc.on("close", (code) => finish({ code, stdout }));
678
+ proc.on("close", (code) => {
679
+ stdout += stdoutDecoder.end();
680
+ finish({ code, stdout });
681
+ });
677
682
  });
678
683
  }
679
684
  async function runGoBatch(files, goBinary) {
@@ -830,11 +835,11 @@ async function dispatch(file, content, lang) {
830
835
  return parseSymbols({ file, content, lang });
831
836
  }
832
837
  case "go": {
833
- const { parseSymbols } = await import("./go-parser-VDPRQEGM.js");
838
+ const { parseSymbols } = await import("./go-parser-Z4H6SR3R.js");
834
839
  return parseSymbols({ file, content, lang: "go" });
835
840
  }
836
841
  case "py": {
837
- const { parseSymbols } = await import("./py-parser-MAW6DHFE.js");
842
+ const { parseSymbols } = await import("./py-parser-4PFZYAJ7.js");
838
843
  return parseSymbols({ file, content, lang: "py" });
839
844
  }
840
845
  case "rs": {
@@ -891,4 +896,4 @@ export {
891
896
  parseFileContent,
892
897
  parseFilesContent
893
898
  };
894
- //# sourceMappingURL=chunk-7E55DAFW.js.map
899
+ //# sourceMappingURL=chunk-KHUCKLOR.js.map
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  tryLegacyCodeOperation
3
- } from "./chunk-3LQJXJDM.js";
3
+ } from "./chunk-E7A4SLKR.js";
4
4
  import {
5
5
  spawnStream
6
- } from "./chunk-EMA2XENR.js";
6
+ } from "./chunk-UVYRQKPZ.js";
7
7
  import {
8
+ ensureInsideRoot,
8
9
  normalizeCommandOutput,
9
10
  safeResolveReal
10
11
  } from "./chunk-2IAEJRLT.js";
11
12
 
12
13
  // src/lint.ts
14
+ import * as path from "node:path";
13
15
  import { ToolValidationError } from "@wrongstack/core/types";
14
16
  var lintTool = {
15
17
  name: "lint",
@@ -67,6 +69,11 @@ var lintTool = {
67
69
  });
68
70
  if (bridge?.run) {
69
71
  const run = bridge.run;
72
+ if (run.status === "unavailable" || run.status === "cancelled" || run.status === "timed_out") {
73
+ throw new Error(
74
+ `lint: ${bridge.language} lint did not run (${run.status})${run.error ? `: ${run.error}` : ""}`
75
+ );
76
+ }
70
77
  yield {
71
78
  type: "final",
72
79
  output: {
@@ -108,6 +115,16 @@ var lintTool = {
108
115
  });
109
116
  }
110
117
  }
118
+ for (const f of files) {
119
+ try {
120
+ ensureInsideRoot(path.resolve(cwd, f), ctx);
121
+ } catch (err) {
122
+ throw new ToolValidationError({
123
+ message: `lint: file "${f}" ${err.message}`,
124
+ field: "files"
125
+ });
126
+ }
127
+ }
111
128
  const args = [];
112
129
  if (detected === "eslint") {
113
130
  if (input.fix) args.push("--fix");
@@ -119,6 +136,9 @@ var lintTool = {
119
136
  }
120
137
  const cmd = detected === "biome" ? "biome" : detected;
121
138
  const result = yield* spawnStream({ cmd, args, cwd, signal, maxBytes: 1e5 });
139
+ if (result.error) {
140
+ throw new Error(`lint: could not run ${cmd}: ${result.error}`);
141
+ }
122
142
  const combined = `${result.stdout}
123
143
  ${result.stderr}`;
124
144
  let errors = 0;
@@ -189,4 +209,4 @@ async function detectLinter(cwd) {
189
209
  export {
190
210
  lintTool
191
211
  };
192
- //# sourceMappingURL=chunk-R3HIZVFS.js.map
212
+ //# sourceMappingURL=chunk-KPDCKSN5.js.map
@@ -1,6 +1,7 @@
1
1
  // src/tool-use.ts
2
2
  import {
3
- GOVERNED_TOOL_EXECUTOR_META_KEY
3
+ GOVERNED_TOOL_EXECUTOR_META_KEY,
4
+ ToolValidationError
4
5
  } from "@wrongstack/core/types";
5
6
  var toolUseTool = {
6
7
  name: "tool_use",
@@ -33,67 +34,42 @@ var toolUseTool = {
33
34
  async execute(input, ctx) {
34
35
  const start = Date.now();
35
36
  if (!input?.tool) {
36
- return {
37
- tool: "unknown",
38
- success: false,
39
- error: "tool_use: tool name is required",
40
- executionMs: 0
41
- };
37
+ throw new ToolValidationError({ message: "tool_use: tool name is required", field: "tool" });
42
38
  }
43
39
  const tool = (ctx.catalogTools ?? ctx.tools).find((t) => t.name === input.tool);
44
40
  if (!tool) {
45
- return {
46
- tool: input.tool,
47
- success: false,
48
- error: `tool_use: tool "${input.tool}" not found`,
49
- executionMs: Date.now() - start
50
- };
41
+ throw new ToolValidationError({
42
+ message: `tool_use: tool "${input.tool}" not found`,
43
+ field: "tool"
44
+ });
51
45
  }
52
46
  if (tool.name === toolUseTool.name) {
53
- return {
54
- tool: input.tool,
55
- success: false,
56
- error: "tool_use: recursive meta-tool execution is not allowed",
57
- executionMs: Date.now() - start
58
- };
47
+ throw new ToolValidationError({
48
+ message: "tool_use: recursive meta-tool execution is not allowed",
49
+ field: "tool"
50
+ });
59
51
  }
60
52
  if (tool.permission === "deny") {
61
- return {
62
- tool: input.tool,
63
- success: false,
64
- error: `tool_use: tool "${input.tool}" is denied by policy`,
65
- executionMs: Date.now() - start
66
- };
53
+ throw new Error(`tool_use: tool "${input.tool}" is denied by policy`);
67
54
  }
68
55
  const governedExecute = ctx.meta?.[GOVERNED_TOOL_EXECUTOR_META_KEY];
69
56
  if (typeof governedExecute !== "function") {
70
- return {
71
- tool: input.tool,
72
- success: false,
73
- error: "tool_use: governed nested execution is unavailable; call the tool directly",
74
- executionMs: Date.now() - start
75
- };
57
+ throw new Error("tool_use: governed nested execution is unavailable; call the tool directly");
76
58
  }
77
- try {
78
- const result = await governedExecute(input.tool, input.input ?? {});
79
- return {
80
- tool: input.tool,
81
- success: result.success,
82
- ...result.success ? { result: result.result } : { error: result.error ?? "nested tool failed" },
83
- executionMs: Date.now() - start
84
- };
85
- } catch (e) {
86
- return {
87
- tool: input.tool,
88
- success: false,
89
- error: e instanceof Error ? e.message : String(e),
90
- executionMs: Date.now() - start
91
- };
59
+ const result = await governedExecute(input.tool, input.input ?? {});
60
+ if (!result.success) {
61
+ throw new Error(`tool_use: "${input.tool}" failed: ${result.error ?? "nested tool failed"}`);
92
62
  }
63
+ return {
64
+ tool: input.tool,
65
+ success: true,
66
+ result: result.result,
67
+ executionMs: Date.now() - start
68
+ };
93
69
  }
94
70
  };
95
71
 
96
72
  export {
97
73
  toolUseTool
98
74
  };
99
- //# sourceMappingURL=chunk-B3MGJBFI.js.map
75
+ //# sourceMappingURL=chunk-KS2OEZWV.js.map
@@ -1,4 +1,5 @@
1
1
  // src/mode.ts
2
+ import { ToolValidationError } from "@wrongstack/core/types";
2
3
  function modeFamily(mode) {
3
4
  if (mode.tags?.includes("lite")) return "lite";
4
5
  if (mode.tags?.includes("deep")) return "deep";
@@ -63,11 +64,17 @@ function createModeTool(modeStore) {
63
64
  }
64
65
  case "set": {
65
66
  if (!input.mode) {
66
- return { action: "set", success: false, message: "mode is required for action=set" };
67
+ throw new ToolValidationError({
68
+ message: "mode: mode is required for action=set",
69
+ field: "mode"
70
+ });
67
71
  }
68
72
  const mode = await modeStore.getMode(input.mode);
69
73
  if (!mode) {
70
- return { action: "set", success: false, message: `Mode "${input.mode}" not found` };
74
+ throw new ToolValidationError({
75
+ message: `mode: Mode "${input.mode}" not found \u2014 use action=list to see available modes`,
76
+ field: "mode"
77
+ });
71
78
  }
72
79
  await modeStore.setActiveMode(input.mode);
73
80
  return {
@@ -88,11 +95,10 @@ ${mode.description}`
88
95
  };
89
96
  }
90
97
  default:
91
- return {
92
- action: input.action,
93
- success: false,
94
- message: `Unknown action "${input.action}"`
95
- };
98
+ throw new ToolValidationError({
99
+ message: `mode: Unknown action "${input?.action}". Allowed: get, list, set, clear`,
100
+ field: "action"
101
+ });
96
102
  }
97
103
  }
98
104
  };
@@ -101,4 +107,4 @@ ${mode.description}`
101
107
  export {
102
108
  createModeTool
103
109
  };
104
- //# sourceMappingURL=chunk-UI3ZJIG3.js.map
110
+ //# sourceMappingURL=chunk-LKLIQUCW.js.map
@@ -150,14 +150,15 @@ var searchTool = {
150
150
  engineError = fallback.error;
151
151
  effectiveSource = "duckduckgo";
152
152
  }
153
- const finalResults = ranked.slice(0, num);
154
- if (!engineError) {
155
- cache.set(cacheKey, { results: ranked, source: effectiveSource, timestamp: Date.now() });
156
- pruneCacheEntries();
153
+ if (engineError) {
154
+ throw new Error(`search: ${engineError}`);
157
155
  }
156
+ const finalResults = ranked.slice(0, num);
157
+ cache.set(cacheKey, { results: ranked, source: effectiveSource, timestamp: Date.now() });
158
+ pruneCacheEntries();
158
159
  yield {
159
160
  type: "partial_output",
160
- text: engineError ? `search failed: ${engineError}` : `${finalResults.length} results from ${effectiveSource}`,
161
+ text: `${finalResults.length} results from ${effectiveSource}`,
161
162
  data: { count: finalResults.length, cached: false, source: effectiveSource }
162
163
  };
163
164
  yield {
@@ -171,8 +172,7 @@ var searchTool = {
171
172
  })),
172
173
  source: effectiveSource,
173
174
  truncated: ranked.length > num,
174
- cached: false,
175
- ...engineError ? { error: engineError } : {}
175
+ cached: false
176
176
  }
177
177
  };
178
178
  }
@@ -469,4 +469,4 @@ export {
469
469
  __setSearchCacheForTest,
470
470
  __getSearchCacheSizeForTest
471
471
  };
472
- //# sourceMappingURL=chunk-62OAECEQ.js.map
472
+ //# sourceMappingURL=chunk-LLSFOUZF.js.map
@@ -5,7 +5,12 @@ import {
5
5
  // src/tree.ts
6
6
  import * as fs from "node:fs/promises";
7
7
  import * as path from "node:path";
8
- import { compileGlob, DEFAULT_WALK_IGNORE_DIRS, expectDefined } from "@wrongstack/core/utils";
8
+ import {
9
+ compileGlob,
10
+ DEFAULT_WALK_IGNORE_DIRS,
11
+ expectDefined,
12
+ toErrorMessage
13
+ } from "@wrongstack/core/utils";
9
14
  var DEFAULT_IGNORE = /* @__PURE__ */ new Set([
10
15
  ...DEFAULT_WALK_IGNORE_DIRS,
11
16
  ".wrongstack",
@@ -88,9 +93,7 @@ var treeTool = {
88
93
  const rawExclude = Array.isArray(input.exclude) ? input.exclude : typeof input.exclude === "string" ? [input.exclude] : [];
89
94
  const exclude = /* @__PURE__ */ new Set([
90
95
  ...DEFAULT_IGNORE,
91
- ...rawExclude.filter((s) => typeof s === "string").map(
92
- (s) => s.trim().replace(/\\/g, "/").replace(/\/+$/, "").replace(/^\.\//, "")
93
- ).filter(Boolean)
96
+ ...rawExclude.filter((s) => typeof s === "string").map((s) => s.trim().replace(/\\/g, "/").replace(/\/+$/, "").replace(/^\.\//, "")).filter(Boolean)
94
97
  ]);
95
98
  const globRe = input.glob ? compileGlob(input.glob) : void 0;
96
99
  const maxEntries = typeof input.max_entries === "number" && Number.isFinite(input.max_entries) && input.max_entries > 0 ? Math.floor(input.max_entries) : DEFAULT_MAX_ENTRIES;
@@ -184,7 +187,12 @@ function matchesTreeGlob(globRe, fileName, absPath, basePath) {
184
187
  async function walkDir(dir, depth, opts) {
185
188
  opts.signal.throwIfAborted();
186
189
  if (opts.retention.truncated) return;
187
- const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
190
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch((err) => {
191
+ if (depth === 0) {
192
+ throw new Error(`tree: cannot list "${dir}": ${toErrorMessage(err)}`, { cause: err });
193
+ }
194
+ return [];
195
+ });
188
196
  const filtered = entries.filter((e) => {
189
197
  if (!opts.showHidden && e.name.startsWith(".")) return false;
190
198
  if (opts.exclude.has(e.name)) return false;
@@ -248,4 +256,4 @@ export {
248
256
  MAX_TREE_OUTPUT_BYTES,
249
257
  treeTool
250
258
  };
251
- //# sourceMappingURL=chunk-YZQSUL5G.js.map
259
+ //# sourceMappingURL=chunk-M4ZHHCCW.js.map
@@ -16,6 +16,7 @@ import {
16
16
  } from "@wrongstack/core/design";
17
17
  import { ToolValidationError } from "@wrongstack/core/types";
18
18
  import { atomicWrite } from "@wrongstack/core/utils";
19
+ var NO_ACTIVE_KIT = 'design: no active kit. Pick one first: `design {action:"use", kit:"<id>"}`.';
19
20
  async function resolveReal(p) {
20
21
  const resolved = path.resolve(p);
21
22
  let probe = resolved;
@@ -139,16 +140,22 @@ var designTool = {
139
140
  const kitId = input.kit?.trim();
140
141
  if (!kitId) {
141
142
  const menu2 = await loader.menuText();
142
- return { action, output: `No kit id provided.
143
+ throw new ToolValidationError({
144
+ message: `design: "use" requires a kit id.
143
145
 
144
- ${menu2}` };
146
+ ${menu2}`,
147
+ field: "kit"
148
+ });
145
149
  }
146
150
  const manifest = await loader.find(kitId);
147
151
  if (!manifest) {
148
152
  const menu2 = await loader.menuText();
149
- return { action, kit: kitId, output: `Kit "${kitId}" not found.
153
+ throw new ToolValidationError({
154
+ message: `design: kit "${kitId}" not found.
150
155
 
151
- ${menu2}` };
156
+ ${menu2}`,
157
+ field: "kit"
158
+ });
152
159
  }
153
160
  const resolvedStack = stack ?? manifest.stacks[0] ?? "web";
154
161
  const body = await loader.readBody(manifest.id, resolvedStack);
@@ -192,15 +199,13 @@ ${body}`
192
199
  if (action === "set") {
193
200
  const patch = normalizeOverrides(input.set);
194
201
  if (Object.keys(patch).length === 0) {
195
- return { action, output: 'No overrides given. Pass set:{ "primary": "oklch(\u2026)" }.' };
202
+ throw new ToolValidationError({
203
+ message: 'design: no overrides given. Pass set:{ "primary": "oklch(\u2026)" }.',
204
+ field: "set"
205
+ });
196
206
  }
197
207
  const merged = await recordOverrides(ctx.projectRoot, patch, (/* @__PURE__ */ new Date()).toISOString());
198
- if (!merged) {
199
- return {
200
- action,
201
- output: 'No active kit. Pick one first: `design {action:"use", kit:"<id>"}`.'
202
- };
203
- }
208
+ if (!merged) throw new Error(NO_ACTIVE_KIT);
204
209
  setDesignOverrides(ctx, merged);
205
210
  return {
206
211
  action,
@@ -211,18 +216,13 @@ These win over kit tokens. Run \`design {action:"materialize"}\` to write them t
211
216
  if (action === "tune") {
212
217
  const patch = resolveSemanticTune(input.tune ?? {});
213
218
  if (Object.keys(patch).length === 0) {
214
- return {
215
- action,
216
- output: 'No recognized knobs. Pass tune:{ radius:"lg", density:"compact", font:"\u2026", motion:"snappy" }.'
217
- };
219
+ throw new ToolValidationError({
220
+ message: 'design: no recognized knobs. Pass tune:{ radius:"lg", density:"compact", font:"\u2026", motion:"snappy" }.',
221
+ field: "tune"
222
+ });
218
223
  }
219
224
  const merged = await recordOverrides(ctx.projectRoot, patch, (/* @__PURE__ */ new Date()).toISOString());
220
- if (!merged) {
221
- return {
222
- action,
223
- output: 'No active kit. Pick one first: `design {action:"use", kit:"<id>"}`.'
224
- };
225
- }
225
+ if (!merged) throw new Error(NO_ACTIVE_KIT);
226
226
  setDesignOverrides(ctx, merged);
227
227
  return {
228
228
  action,
@@ -232,17 +232,10 @@ Run \`design {action:"materialize"}\` to write the tuned tokens to your theme fi
232
232
  }
233
233
  if (action === "materialize") {
234
234
  const active = await loadActiveKit(ctx.projectRoot);
235
- if (!active) {
236
- return {
237
- action,
238
- output: 'No active kit. Pick one first: `design {action:"use", kit:"<id>"}`.'
239
- };
240
- }
235
+ if (!active) throw new Error(NO_ACTIVE_KIT);
241
236
  const resolvedStack = stack ?? (active.stack && isDesignStack(active.stack) ? active.stack : "web");
242
237
  const rawTokens = await loader.readTokens(active.kit);
243
- if (!rawTokens) {
244
- return { action, kit: active.kit, output: `Kit "${active.kit}" has no tokens.json.` };
245
- }
238
+ if (!rawTokens) throw new Error(`design: kit "${active.kit}" has no tokens.json.`);
246
239
  const tokens = applyTokenOverrides(rawTokens, active.overrides);
247
240
  const result = materializeTokens({
248
241
  tokens,
@@ -268,17 +261,13 @@ Run \`design {action:"materialize"}\` to write the tuned tokens to your theme fi
268
261
  } catch {
269
262
  }
270
263
  if (exists && !input.force) {
271
- return {
272
- action,
273
- kit: active.kit,
274
- stack: resolvedStack,
275
- path: result.path,
276
- output: `${result.path} already exists. Re-run with force:true to overwrite, or write this ${result.format} yourself:
264
+ throw new Error(
265
+ `design: ${result.path} already exists \u2014 nothing was written. Re-run with force:true to overwrite, or write this ${result.format} yourself:
277
266
 
278
267
  \`\`\`
279
268
  ${result.content}
280
269
  \`\`\``
281
- };
270
+ );
282
271
  }
283
272
  await fs.mkdir(path.dirname(abs), { recursive: true });
284
273
  await atomicWrite(abs, result.content);
@@ -293,17 +282,10 @@ ${result.content}
293
282
  if (action === "verify") {
294
283
  signal?.throwIfAborted();
295
284
  const active = await loadActiveKit(ctx.projectRoot);
296
- if (!active) {
297
- return {
298
- action,
299
- output: 'No active kit to verify against. Pick one: `design {action:"use", kit:"<id>"}`.'
300
- };
301
- }
285
+ if (!active) throw new Error(NO_ACTIVE_KIT);
302
286
  signal?.throwIfAborted();
303
287
  const rawTokens = await loader.readTokens(active.kit);
304
- if (!rawTokens) {
305
- return { action, kit: active.kit, output: `Kit "${active.kit}" has no tokens.json.` };
306
- }
288
+ if (!rawTokens) throw new Error(`design: kit "${active.kit}" has no tokens.json.`);
307
289
  signal?.throwIfAborted();
308
290
  const tokens = applyTokenOverrides(rawTokens, active.overrides);
309
291
  const normalizedFiles = input.files ? (Array.isArray(input.files) ? input.files : String(input.files).split(",")).filter((f) => typeof f === "string").map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean) : void 0;
@@ -334,4 +316,4 @@ Replace off-palette colors with kit tokens (or the materialized CSS vars / token
334
316
  export {
335
317
  designTool
336
318
  };
337
- //# sourceMappingURL=chunk-IXIS7RSG.js.map
319
+ //# sourceMappingURL=chunk-MRXWOOOR.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseFilesContent
3
- } from "./chunk-7E55DAFW.js";
3
+ } from "./chunk-KHUCKLOR.js";
4
4
  import {
5
5
  recordFilesystemRead
6
6
  } from "./chunk-ZKC5UNGD.js";
@@ -4993,7 +4993,7 @@ var ParserWorkerPool = class {
4993
4993
  */
4994
4994
  async reparseInline(batch, orphaned, workerId) {
4995
4995
  try {
4996
- const { parseFileContent } = await import("./parser-dispatch-4E2SDQUO.js");
4996
+ const { parseFileContent } = await import("./parser-dispatch-WG4DNBHH.js");
4997
4997
  for (const item of orphaned) {
4998
4998
  if (batch.settled) return;
4999
4999
  try {
@@ -5856,4 +5856,4 @@ export {
5856
5856
  incomingCallsService,
5857
5857
  outgoingCallsService
5858
5858
  };
5859
- //# sourceMappingURL=chunk-C4DSQBTT.js.map
5859
+ //# sourceMappingURL=chunk-NEYUPZL6.js.map
@@ -133,6 +133,10 @@ async function assertBrowserUrlAllowed(rawUrl, opts) {
133
133
  const url = parseBrowserUrl(rawUrl, opts.navigation ?? true);
134
134
  if (!opts.navigation && SAFE_SUBRESOURCE_PROTOCOLS.has(url.protocol)) return url;
135
135
  if (!opts.allowPrivateHosts && !isAllowedPrivateOrigin(url, opts.allowedPrivateOrigins)) {
136
+ const normalizedHost = unbracket(url.hostname).replace(/\.+$/, "").toLowerCase();
137
+ if (normalizedHost === "localhost" || normalizedHost.endsWith(".localhost")) {
138
+ throw new Error("browser: blocked localhost target");
139
+ }
136
140
  await assertNotPrivateHost(url.hostname);
137
141
  }
138
142
  return url;
@@ -148,7 +152,8 @@ async function resolvePinnedBrowserTarget(rawUrl, opts = {}) {
148
152
  }
149
153
  return { url, address: hostname, family: literalFamily };
150
154
  }
151
- if ((hostname === "localhost" || hostname.endsWith(".localhost")) && !allowPrivate) {
155
+ const normalizedHost = hostname.replace(/\.+$/, "").toLowerCase();
156
+ if ((normalizedHost === "localhost" || normalizedHost.endsWith(".localhost")) && !allowPrivate) {
152
157
  throw new Error("browser: blocked localhost target");
153
158
  }
154
159
  const lookup2 = opts.lookup ?? ((host) => dns.lookup(host, { all: true }));
@@ -225,12 +230,12 @@ function safeBrowserUrl(rawUrl) {
225
230
  }
226
231
  }
227
232
  function redactBrowserText(text) {
228
- return text.replace(/\bauthorization\b\s*[:=]\s*[^\r\n]+/gi, "Authorization=[REDACTED]").replace(
229
- /\bauthorization\b\s*[:=]\s*(?:Basic|Bearer)\s+[^\s,;]+/gi,
230
- "Authorization=[REDACTED]"
231
- ).replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [REDACTED]").replace(
232
- /\b(authorization|set[-_ ]?cookie|cookie|api[-_ ]?key|private[-_ ]?key|client[-_ ]?secret|access[-_ ]?token|refresh[-_ ]?token|session[-_ ]?token|auth[-_ ]?token|token|password|secret)\b\s*[:=]\s*[^\s,;]+/gi,
233
- "$1=[REDACTED]"
233
+ return text.replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [REDACTED]").replace(
234
+ /(["']?)\b(authorization|set[-_ ]?cookie|cookie|api[-_ ]?key|private[-_ ]?key|client[-_ ]?secret|access[-_ ]?token|refresh[-_ ]?token|session[-_ ]?token|auth[-_ ]?token|token|password|secret)\b\1(\s*[:=]\s*)((?:"[^"\r\n]*"|'[^'\r\n]*'|(?:Basic|Bearer)\s+[^\s,;]+|[^\s,;]+))/gi,
235
+ (_match, q1, key, sep, val) => {
236
+ const quote = val.startsWith('"') ? '"' : val.startsWith("'") ? "'" : "";
237
+ return `${q1}${key}${q1}${sep}${quote}[REDACTED]${quote}`;
238
+ }
234
239
  );
235
240
  }
236
241
 
@@ -1420,4 +1425,4 @@ export {
1420
1425
  isBrowserSuiteEnabled,
1421
1426
  shutdownBrowserTools
1422
1427
  };
1423
- //# sourceMappingURL=chunk-6XYFYLN7.js.map
1428
+ //# sourceMappingURL=chunk-O2MHULBO.js.map