@wrongstack/tools 0.284.0 → 0.285.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 (311) hide show
  1. package/dist/_concurrency.d.ts +16 -0
  2. package/dist/_concurrency.d.ts.map +1 -0
  3. package/dist/_danger-detect.d.ts +54 -0
  4. package/dist/_danger-detect.d.ts.map +1 -0
  5. package/dist/_edit-match.d.ts +86 -0
  6. package/dist/_edit-match.d.ts.map +1 -0
  7. package/dist/_env.d.ts +6 -0
  8. package/dist/_env.d.ts.map +1 -0
  9. package/dist/_fetch-guard.d.ts +31 -0
  10. package/dist/_fetch-guard.d.ts.map +1 -0
  11. package/dist/_output-spool.d.ts +38 -0
  12. package/dist/_output-spool.d.ts.map +1 -0
  13. package/dist/_redact-command.d.ts +6 -0
  14. package/dist/_redact-command.d.ts.map +1 -0
  15. package/dist/_regex.d.ts +39 -0
  16. package/dist/_regex.d.ts.map +1 -0
  17. package/dist/_session-shell.d.ts +73 -0
  18. package/dist/_session-shell.d.ts.map +1 -0
  19. package/dist/_shell-pick.d.ts +158 -0
  20. package/dist/_shell-pick.d.ts.map +1 -0
  21. package/dist/_spawn-stream.d.ts +32 -0
  22. package/dist/_spawn-stream.d.ts.map +1 -0
  23. package/dist/_syntax-check.d.ts +16 -0
  24. package/dist/_syntax-check.d.ts.map +1 -0
  25. package/dist/_util.d.ts +68 -0
  26. package/dist/_util.d.ts.map +1 -0
  27. package/dist/_win32-resolve.d.ts +42 -0
  28. package/dist/_win32-resolve.d.ts.map +1 -0
  29. package/dist/audit.d.ts +4 -5
  30. package/dist/audit.d.ts.map +1 -0
  31. package/dist/audit.js +2743 -28
  32. package/dist/audit.js.map +7 -1
  33. package/dist/bash-kill-guard.d.ts +62 -0
  34. package/dist/bash-kill-guard.d.ts.map +1 -0
  35. package/dist/bash.d.ts +4 -5
  36. package/dist/bash.d.ts.map +1 -0
  37. package/dist/bash.js +59 -30
  38. package/dist/bash.js.map +7 -1
  39. package/dist/batch-tool-use.d.ts +4 -5
  40. package/dist/batch-tool-use.d.ts.map +1 -0
  41. package/dist/batch-tool-use.js +3 -3
  42. package/dist/batch-tool-use.js.map +7 -1
  43. package/dist/builtin.d.ts +7 -9
  44. package/dist/builtin.d.ts.map +1 -0
  45. package/dist/builtin.js +5282 -1019
  46. package/dist/builtin.js.map +7 -1
  47. package/dist/circuit-breaker.d.ts +4 -5
  48. package/dist/circuit-breaker.d.ts.map +1 -0
  49. package/dist/circuit-breaker.js +3 -3
  50. package/dist/circuit-breaker.js.map +7 -1
  51. package/dist/codebase-index/background-indexer.d.ts +116 -0
  52. package/dist/codebase-index/background-indexer.d.ts.map +1 -0
  53. package/dist/codebase-index/bm25.d.ts +40 -0
  54. package/dist/codebase-index/bm25.d.ts.map +1 -0
  55. package/dist/codebase-index/circuit-breaker.d.ts +94 -0
  56. package/dist/codebase-index/circuit-breaker.d.ts.map +1 -0
  57. package/dist/codebase-index/codebase-index-tool.d.ts +17 -0
  58. package/dist/codebase-index/codebase-index-tool.d.ts.map +1 -0
  59. package/dist/codebase-index/codebase-search-tool.d.ts +43 -0
  60. package/dist/codebase-index/codebase-search-tool.d.ts.map +1 -0
  61. package/dist/codebase-index/codebase-stats-tool.d.ts +23 -0
  62. package/dist/codebase-index/codebase-stats-tool.d.ts.map +1 -0
  63. package/dist/codebase-index/gitignore.d.ts +22 -0
  64. package/dist/codebase-index/gitignore.d.ts.map +1 -0
  65. package/dist/codebase-index/go-parser.d.ts +16 -0
  66. package/dist/codebase-index/go-parser.d.ts.map +1 -0
  67. package/dist/codebase-index/index-service.d.ts +25 -0
  68. package/dist/codebase-index/index-service.d.ts.map +1 -0
  69. package/dist/codebase-index/index.d.ts +23 -271
  70. package/dist/codebase-index/index.d.ts.map +1 -0
  71. package/dist/codebase-index/index.js +136 -68
  72. package/dist/codebase-index/index.js.map +7 -1
  73. package/dist/codebase-index/indexer.d.ts +28 -0
  74. package/dist/codebase-index/indexer.d.ts.map +1 -0
  75. package/dist/codebase-index/json-parser.d.ts +8 -0
  76. package/dist/codebase-index/json-parser.d.ts.map +1 -0
  77. package/dist/codebase-index/lsp-kind.d.ts +53 -0
  78. package/dist/codebase-index/lsp-kind.d.ts.map +1 -0
  79. package/dist/codebase-index/py-parser.d.ts +16 -0
  80. package/dist/codebase-index/py-parser.d.ts.map +1 -0
  81. package/dist/codebase-index/refs-extractor.d.ts +25 -0
  82. package/dist/codebase-index/refs-extractor.d.ts.map +1 -0
  83. package/dist/codebase-index/rs-parser.d.ts +8 -0
  84. package/dist/codebase-index/rs-parser.d.ts.map +1 -0
  85. package/dist/codebase-index/schema.d.ts +82 -0
  86. package/dist/codebase-index/schema.d.ts.map +1 -0
  87. package/dist/codebase-index/ts-parser.d.ts +30 -0
  88. package/dist/codebase-index/ts-parser.d.ts.map +1 -0
  89. package/dist/codebase-index/worker-protocol.d.ts +77 -0
  90. package/dist/codebase-index/worker-protocol.d.ts.map +1 -0
  91. package/dist/codebase-index/worker.d.ts +16 -2
  92. package/dist/codebase-index/worker.d.ts.map +1 -0
  93. package/dist/codebase-index/worker.js +103 -65
  94. package/dist/codebase-index/worker.js.map +7 -1
  95. package/dist/codebase-index/writer.d.ts +189 -0
  96. package/dist/codebase-index/writer.d.ts.map +1 -0
  97. package/dist/codebase-index/yaml-parser.d.ts +8 -0
  98. package/dist/codebase-index/yaml-parser.d.ts.map +1 -0
  99. package/dist/design.d.ts +38 -0
  100. package/dist/design.d.ts.map +1 -0
  101. package/dist/design.js +270 -0
  102. package/dist/design.js.map +7 -0
  103. package/dist/diff.d.ts +4 -5
  104. package/dist/diff.d.ts.map +1 -0
  105. package/dist/diff.js +14 -12
  106. package/dist/diff.js.map +7 -1
  107. package/dist/document.d.ts +4 -5
  108. package/dist/document.d.ts.map +1 -0
  109. package/dist/document.js +8 -7
  110. package/dist/document.js.map +7 -1
  111. package/dist/edit.d.ts +5 -36
  112. package/dist/edit.d.ts.map +1 -0
  113. package/dist/edit.js +28 -16
  114. package/dist/edit.js.map +7 -1
  115. package/dist/exec.d.ts +67 -2
  116. package/dist/exec.d.ts.map +1 -0
  117. package/dist/exec.js +50 -25
  118. package/dist/exec.js.map +7 -1
  119. package/dist/fetch.d.ts +4 -32
  120. package/dist/fetch.d.ts.map +1 -0
  121. package/dist/fetch.js +89 -77
  122. package/dist/fetch.js.map +7 -1
  123. package/dist/format.d.ts +4 -5
  124. package/dist/format.d.ts.map +1 -0
  125. package/dist/format.js +2415 -28
  126. package/dist/format.js.map +7 -1
  127. package/dist/git.d.ts +4 -5
  128. package/dist/git.d.ts.map +1 -0
  129. package/dist/git.js +10 -9
  130. package/dist/git.js.map +7 -1
  131. package/dist/glob.d.ts +4 -5
  132. package/dist/glob.d.ts.map +1 -0
  133. package/dist/glob.js +15 -12
  134. package/dist/glob.js.map +7 -1
  135. package/dist/grep.d.ts +4 -5
  136. package/dist/grep.d.ts.map +1 -0
  137. package/dist/grep.js +13 -10
  138. package/dist/grep.js.map +7 -1
  139. package/dist/index.d.ts +19 -724
  140. package/dist/index.d.ts.map +1 -0
  141. package/dist/index.js +6088 -1690
  142. package/dist/index.js.map +7 -1
  143. package/dist/install.d.ts +4 -5
  144. package/dist/install.d.ts.map +1 -0
  145. package/dist/install.js +2680 -31
  146. package/dist/install.js.map +7 -1
  147. package/dist/json.d.ts +4 -5
  148. package/dist/json.d.ts.map +1 -0
  149. package/dist/json.js +13 -11
  150. package/dist/json.js.map +7 -1
  151. package/dist/kanban.d.ts +107 -0
  152. package/dist/kanban.d.ts.map +1 -0
  153. package/dist/kanban.js +845 -0
  154. package/dist/kanban.js.map +7 -0
  155. package/dist/languages/detect.d.ts +3 -0
  156. package/dist/languages/detect.d.ts.map +1 -0
  157. package/dist/languages/diagnostics.d.ts +15 -0
  158. package/dist/languages/diagnostics.d.ts.map +1 -0
  159. package/dist/languages/execute-tool.d.ts +34 -0
  160. package/dist/languages/execute-tool.d.ts.map +1 -0
  161. package/dist/languages/execute.d.ts +18 -0
  162. package/dist/languages/execute.d.ts.map +1 -0
  163. package/dist/languages/index.d.ts +12 -0
  164. package/dist/languages/index.d.ts.map +1 -0
  165. package/dist/languages/index.js +4457 -0
  166. package/dist/languages/index.js.map +7 -0
  167. package/dist/languages/legacy-bridge.d.ts +29 -0
  168. package/dist/languages/legacy-bridge.d.ts.map +1 -0
  169. package/dist/languages/package-tool.d.ts +29 -0
  170. package/dist/languages/package-tool.d.ts.map +1 -0
  171. package/dist/languages/plan.d.ts +4 -0
  172. package/dist/languages/plan.d.ts.map +1 -0
  173. package/dist/languages/profile-helpers.d.ts +14 -0
  174. package/dist/languages/profile-helpers.d.ts.map +1 -0
  175. package/dist/languages/profiles/additional.d.ts +3 -0
  176. package/dist/languages/profiles/additional.d.ts.map +1 -0
  177. package/dist/languages/profiles/primary.d.ts +3 -0
  178. package/dist/languages/profiles/primary.d.ts.map +1 -0
  179. package/dist/languages/registry.d.ts +11 -0
  180. package/dist/languages/registry.d.ts.map +1 -0
  181. package/dist/languages/tool.d.ts +32 -0
  182. package/dist/languages/tool.d.ts.map +1 -0
  183. package/dist/languages/types.d.ts +207 -0
  184. package/dist/languages/types.d.ts.map +1 -0
  185. package/dist/lint.d.ts +4 -5
  186. package/dist/lint.d.ts.map +1 -0
  187. package/dist/lint.js +2415 -27
  188. package/dist/lint.js.map +7 -1
  189. package/dist/logs.d.ts +4 -5
  190. package/dist/logs.d.ts.map +1 -0
  191. package/dist/logs.js +16 -10
  192. package/dist/logs.js.map +7 -1
  193. package/dist/memory.d.ts +7 -8
  194. package/dist/memory.d.ts.map +1 -0
  195. package/dist/memory.js +7 -5
  196. package/dist/memory.js.map +7 -1
  197. package/dist/mode.d.ts +4 -5
  198. package/dist/mode.d.ts.map +1 -0
  199. package/dist/mode.js +3 -3
  200. package/dist/mode.js.map +7 -1
  201. package/dist/next-steps.d.ts +5 -6
  202. package/dist/next-steps.d.ts.map +1 -0
  203. package/dist/next-steps.js +5 -4
  204. package/dist/next-steps.js.map +7 -1
  205. package/dist/outdated.d.ts +4 -5
  206. package/dist/outdated.d.ts.map +1 -0
  207. package/dist/outdated.js +4777 -68
  208. package/dist/outdated.js.map +7 -1
  209. package/dist/pack.d.ts +3 -6
  210. package/dist/pack.d.ts.map +1 -0
  211. package/dist/pack.js +5275 -1019
  212. package/dist/pack.js.map +7 -1
  213. package/dist/patch.d.ts +4 -5
  214. package/dist/patch.d.ts.map +1 -0
  215. package/dist/patch.js +18 -16
  216. package/dist/patch.js.map +7 -1
  217. package/dist/plan.d.ts +55 -0
  218. package/dist/plan.d.ts.map +1 -0
  219. package/dist/plan.js +280 -0
  220. package/dist/plan.js.map +7 -0
  221. package/dist/process-guardian.d.ts +100 -0
  222. package/dist/process-guardian.d.ts.map +1 -0
  223. package/dist/process-registry-persistent.d.ts +121 -0
  224. package/dist/process-registry-persistent.d.ts.map +1 -0
  225. package/dist/process-registry.d.ts +13 -17
  226. package/dist/process-registry.d.ts.map +1 -0
  227. package/dist/process-registry.js +15 -9
  228. package/dist/process-registry.js.map +7 -1
  229. package/dist/ps-slash.d.ts +106 -0
  230. package/dist/ps-slash.d.ts.map +1 -0
  231. package/dist/ps-slash.js +1291 -0
  232. package/dist/ps-slash.js.map +7 -0
  233. package/dist/read.d.ts +4 -5
  234. package/dist/read.d.ts.map +1 -0
  235. package/dist/read.js +13 -11
  236. package/dist/read.js.map +7 -1
  237. package/dist/replace.d.ts +4 -5
  238. package/dist/replace.d.ts.map +1 -0
  239. package/dist/replace.js +26 -13
  240. package/dist/replace.js.map +7 -1
  241. package/dist/scaffold.d.ts +4 -5
  242. package/dist/scaffold.d.ts.map +1 -0
  243. package/dist/scaffold.js +16 -14
  244. package/dist/scaffold.js.map +7 -1
  245. package/dist/search.d.ts +5 -6
  246. package/dist/search.d.ts.map +1 -0
  247. package/dist/search.js +24 -25
  248. package/dist/search.js.map +7 -1
  249. package/dist/set-working-dir.d.ts +18 -0
  250. package/dist/set-working-dir.d.ts.map +1 -0
  251. package/dist/shim/node-sqlite.d.ts +3 -0
  252. package/dist/shim/node-sqlite.d.ts.map +1 -0
  253. package/dist/skill.d.ts +45 -0
  254. package/dist/skill.d.ts.map +1 -0
  255. package/dist/skill.js +175 -0
  256. package/dist/skill.js.map +7 -0
  257. package/dist/spawn-background.d.ts +80 -0
  258. package/dist/spawn-background.d.ts.map +1 -0
  259. package/dist/task.d.ts +35 -0
  260. package/dist/task.d.ts.map +1 -0
  261. package/dist/task.js +380 -0
  262. package/dist/task.js.map +7 -0
  263. package/dist/test.d.ts +4 -5
  264. package/dist/test.d.ts.map +1 -0
  265. package/dist/test.js +2419 -27
  266. package/dist/test.js.map +7 -1
  267. package/dist/todo.d.ts +4 -5
  268. package/dist/todo.d.ts.map +1 -0
  269. package/dist/todo.js +5 -5
  270. package/dist/todo.js.map +7 -1
  271. package/dist/tool-diff.d.ts +16 -17
  272. package/dist/tool-diff.d.ts.map +1 -0
  273. package/dist/tool-diff.js +11 -3
  274. package/dist/tool-diff.js.map +7 -1
  275. package/dist/tool-help.d.ts +4 -5
  276. package/dist/tool-help.d.ts.map +1 -0
  277. package/dist/tool-help.js +3 -3
  278. package/dist/tool-help.js.map +7 -1
  279. package/dist/tool-icon-map.d.ts +45 -0
  280. package/dist/tool-icon-map.d.ts.map +1 -0
  281. package/dist/tool-icons.d.ts +5 -6
  282. package/dist/tool-icons.d.ts.map +1 -0
  283. package/dist/tool-icons.js +16 -4
  284. package/dist/tool-icons.js.map +7 -1
  285. package/dist/tool-search.d.ts +4 -5
  286. package/dist/tool-search.d.ts.map +1 -0
  287. package/dist/tool-search.js +3 -3
  288. package/dist/tool-search.js.map +7 -1
  289. package/dist/tool-summary.d.ts +4 -5
  290. package/dist/tool-summary.d.ts.map +1 -0
  291. package/dist/tool-summary.js +5 -3
  292. package/dist/tool-summary.js.map +7 -1
  293. package/dist/tool-use.d.ts +4 -5
  294. package/dist/tool-use.d.ts.map +1 -0
  295. package/dist/tool-use.js +3 -3
  296. package/dist/tool-use.js.map +7 -1
  297. package/dist/tree.d.ts +4 -5
  298. package/dist/tree.d.ts.map +1 -0
  299. package/dist/tree.js +11 -9
  300. package/dist/tree.js.map +7 -1
  301. package/dist/typecheck.d.ts +4 -5
  302. package/dist/typecheck.d.ts.map +1 -0
  303. package/dist/typecheck.js +2416 -28
  304. package/dist/typecheck.js.map +7 -1
  305. package/dist/write.d.ts +4 -5
  306. package/dist/write.d.ts.map +1 -0
  307. package/dist/write.js +21 -16
  308. package/dist/write.js.map +7 -1
  309. package/package.json +34 -6
  310. package/dist/background-indexer-BeDBxfSh.d.ts +0 -371
  311. package/dist/exec-2OKoT6tk.d.ts +0 -121
@@ -77,7 +77,7 @@ var toolSearchTool = {
77
77
  };
78
78
  }
79
79
  };
80
-
81
- export { toolSearchTool };
80
+ export {
81
+ toolSearchTool
82
+ };
82
83
  //# sourceMappingURL=tool-search.js.map
83
- //# sourceMappingURL=tool-search.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../src/tool-search.ts"],"names":[],"mappings":"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","file":"tool-search.js","sourcesContent":["import type { Tool } from '@wrongstack/core';\n\ninterface ToolSearchInput {\n query?: string | undefined;\n tags?: string[] | undefined;\n permission?: 'auto' | 'confirm' | 'deny' | undefined;\n mutating?: boolean | undefined;\n limit?: number | undefined;\n}\n\ninterface ToolSearchOutput {\n tools: {\n name: string;\n description: string;\n permission: string;\n mutating: boolean;\n }[];\n total: number;\n truncated: boolean;\n /** Total count of tools in the registry (for \"no results\" hints). */\n _available?: number;\n}\n\nexport const toolSearchTool: Tool<ToolSearchInput, ToolSearchOutput> = {\n name: 'tool_search',\n category: 'Meta',\n description:\n 'Search the catalog of available tools by name or description. Use this to discover which tool to use for a task. ' +\n 'For the full schema and usage details of a specific tool, use `tool_help` instead.',\n usageHint:\n 'SELF-DISCOVERY TOOL:\\n\\n' +\n '- Use when you need to find the right tool for a job.\\n' +\n '- `query` searches names and descriptions.\\n' +\n '- You can filter by `tags` (category), `permission`, or `mutating`.\\n' +\n '- Once you find the right tool name, use `tool_help` with that name for full schema details.\\n' +\n 'Call this before guessing tool names. It helps you discover the best tool for the current situation.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 1_000,\n capabilities: ['tool.meta'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query for tool name or description',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Filter by tags (e.g. \"filesystem\", \"network\", \"dev\")',\n },\n permission: {\n type: 'string',\n enum: ['auto', 'confirm', 'deny'],\n description: 'Filter by required permission level',\n },\n mutating: {\n type: 'boolean',\n description: 'Filter by mutating flag (true=filters that modify, false=read-only)',\n },\n limit: {\n type: 'integer',\n description: 'Maximum results to return (default: 20)',\n minimum: 1,\n maximum: 100,\n },\n },\n },\n async execute(input, ctx) {\n const limit = Math.min(input.limit ?? 20, 100);\n const tools = ctx.tools;\n const query = input.query?.toLowerCase() ?? '';\n\n const filtered = tools.filter((t: Tool) => {\n if (\n query &&\n !t.name.toLowerCase().includes(query) &&\n !t.description.toLowerCase().includes(query)\n ) {\n return false;\n }\n if (input.tags && input.tags.length > 0) {\n const toolCat = (t.category ?? '').toLowerCase();\n if (!input.tags.some((tag: string) => toolCat.includes(tag.toLowerCase()))) {\n return false;\n }\n }\n if (input.permission && t.permission !== input.permission) {\n return false;\n }\n if (typeof input.mutating === 'boolean' && t.mutating !== input.mutating) {\n return false;\n }\n return true;\n });\n\n const results = filtered.slice(0, limit).map((t: Tool) => ({\n name: t.name,\n description: t.description,\n permission: t.permission,\n mutating: t.mutating,\n }));\n\n // When no tools match, give the model actionable guidance so it\n // doesn't spiral through random queries. Point it at tool-help\n // which lists every available tool with descriptions.\n const totalAvailable = tools.length;\n const hint =\n results.length === 0 && query\n ? `No tools matched \"${input.query}\". Use tool-help (without arguments) to see all ${totalAvailable} available tools.`\n : undefined;\n\n return {\n tools: results,\n total: filtered.length,\n truncated: filtered.length > limit,\n ...(hint ? { hint } : {}),\n _available: totalAvailable,\n };\n },\n};"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tool-search.ts"],
4
+ "sourcesContent": ["import type { Tool } from '@wrongstack/core';\n\ninterface ToolSearchInput {\n query?: string | undefined;\n tags?: string[] | undefined;\n permission?: 'auto' | 'confirm' | 'deny' | undefined;\n mutating?: boolean | undefined;\n limit?: number | undefined;\n}\n\ninterface ToolSearchOutput {\n tools: {\n name: string;\n description: string;\n permission: string;\n mutating: boolean;\n }[];\n total: number;\n truncated: boolean;\n /** Total count of tools in the registry (for \"no results\" hints). */\n _available?: number;\n}\n\nexport const toolSearchTool: Tool<ToolSearchInput, ToolSearchOutput> = {\n name: 'tool_search',\n category: 'Meta',\n description:\n 'Search the catalog of available tools by name or description. Use this to discover which tool to use for a task. ' +\n 'For the full schema and usage details of a specific tool, use `tool_help` instead.',\n usageHint:\n 'SELF-DISCOVERY TOOL:\\n\\n' +\n '- Use when you need to find the right tool for a job.\\n' +\n '- `query` searches names and descriptions.\\n' +\n '- You can filter by `tags` (category), `permission`, or `mutating`.\\n' +\n '- Once you find the right tool name, use `tool_help` with that name for full schema details.\\n' +\n 'Call this before guessing tool names. It helps you discover the best tool for the current situation.',\n permission: 'auto',\n mutating: false,\n timeoutMs: 1_000,\n capabilities: ['tool.meta'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query for tool name or description',\n },\n tags: {\n type: 'array',\n items: { type: 'string' },\n description: 'Filter by tags (e.g. \"filesystem\", \"network\", \"dev\")',\n },\n permission: {\n type: 'string',\n enum: ['auto', 'confirm', 'deny'],\n description: 'Filter by required permission level',\n },\n mutating: {\n type: 'boolean',\n description: 'Filter by mutating flag (true=filters that modify, false=read-only)',\n },\n limit: {\n type: 'integer',\n description: 'Maximum results to return (default: 20)',\n minimum: 1,\n maximum: 100,\n },\n },\n },\n async execute(input, ctx) {\n const limit = Math.min(input.limit ?? 20, 100);\n const tools = ctx.tools;\n const query = input.query?.toLowerCase() ?? '';\n\n const filtered = tools.filter((t: Tool) => {\n if (\n query &&\n !t.name.toLowerCase().includes(query) &&\n !t.description.toLowerCase().includes(query)\n ) {\n return false;\n }\n if (input.tags && input.tags.length > 0) {\n const toolCat = (t.category ?? '').toLowerCase();\n if (!input.tags.some((tag: string) => toolCat.includes(tag.toLowerCase()))) {\n return false;\n }\n }\n if (input.permission && t.permission !== input.permission) {\n return false;\n }\n if (typeof input.mutating === 'boolean' && t.mutating !== input.mutating) {\n return false;\n }\n return true;\n });\n\n const results = filtered.slice(0, limit).map((t: Tool) => ({\n name: t.name,\n description: t.description,\n permission: t.permission,\n mutating: t.mutating,\n }));\n\n // When no tools match, give the model actionable guidance so it\n // doesn't spiral through random queries. Point it at tool-help\n // which lists every available tool with descriptions.\n const totalAvailable = tools.length;\n const hint =\n results.length === 0 && query\n ? `No tools matched \"${input.query}\". Use tool-help (without arguments) to see all ${totalAvailable} available tools.`\n : undefined;\n\n return {\n tools: results,\n total: filtered.length,\n truncated: filtered.length > limit,\n ...(hint ? { hint } : {}),\n _available: totalAvailable,\n };\n },\n};"],
5
+ "mappings": ";AAuBO,IAAM,iBAA0D;AAAA,EACrE,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aACE;AAAA,EAEF,WACE;AAAA,EAMF,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc,CAAC,WAAW;AAAA,EAC1B,MAAM;AAAA,EACN,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,OAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,OAAO,EAAE,MAAM,SAAS;AAAA,QACxB,aAAa;AAAA,MACf;AAAA,MACA,YAAY;AAAA,QACV,MAAM;AAAA,QACN,MAAM,CAAC,QAAQ,WAAW,MAAM;AAAA,QAChC,aAAa;AAAA,MACf;AAAA,MACA,UAAU;AAAA,QACR,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,OAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,QACT,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,IAAI,GAAG;AAC7C,UAAM,QAAQ,IAAI;AAClB,UAAM,QAAQ,MAAM,OAAO,YAAY,KAAK;AAE5C,UAAM,WAAW,MAAM,OAAO,CAAC,MAAY;AACzC,UACE,SACA,CAAC,EAAE,KAAK,YAAY,EAAE,SAAS,KAAK,KACpC,CAAC,EAAE,YAAY,YAAY,EAAE,SAAS,KAAK,GAC3C;AACA,eAAO;AAAA,MACT;AACA,UAAI,MAAM,QAAQ,MAAM,KAAK,SAAS,GAAG;AACvC,cAAM,WAAW,EAAE,YAAY,IAAI,YAAY;AAC/C,YAAI,CAAC,MAAM,KAAK,KAAK,CAAC,QAAgB,QAAQ,SAAS,IAAI,YAAY,CAAC,CAAC,GAAG;AAC1E,iBAAO;AAAA,QACT;AAAA,MACF;AACA,UAAI,MAAM,cAAc,EAAE,eAAe,MAAM,YAAY;AACzD,eAAO;AAAA,MACT;AACA,UAAI,OAAO,MAAM,aAAa,aAAa,EAAE,aAAa,MAAM,UAAU;AACxE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT,CAAC;AAED,UAAM,UAAU,SAAS,MAAM,GAAG,KAAK,EAAE,IAAI,CAAC,OAAa;AAAA,MACzD,MAAM,EAAE;AAAA,MACR,aAAa,EAAE;AAAA,MACf,YAAY,EAAE;AAAA,MACd,UAAU,EAAE;AAAA,IACd,EAAE;AAKF,UAAM,iBAAiB,MAAM;AAC7B,UAAM,OACJ,QAAQ,WAAW,KAAK,QACpB,qBAAqB,MAAM,KAAK,mDAAmD,cAAc,sBACjG;AAEN,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,SAAS;AAAA,MAChB,WAAW,SAAS,SAAS;AAAA,MAC7B,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,MACvB,YAAY;AAAA,IACd;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -1,12 +1,12 @@
1
1
  /** Head-field lookup order for the generic fallback. */
2
- declare const FALLBACK_HEAD_FIELDS: readonly ["path", "file_path", "pattern", "command", "cmd", "url", "query", "description", "content"];
2
+ export declare const FALLBACK_HEAD_FIELDS: readonly ['path', 'file_path', 'pattern', 'command', 'cmd', 'url', 'query', 'description', 'content'];
3
3
  /**
4
4
  * One-line, tool-aware summary of a tool call's input.
5
5
  *
6
6
  * @param toolName canonical or aliased tool name (case-insensitive).
7
7
  * @param input the tool input — a parsed object OR a JSON string.
8
8
  */
9
- declare function summarizeToolInput(toolName: string | undefined, input: unknown): string;
9
+ export declare function summarizeToolInput(toolName: string | undefined, input: unknown): string;
10
10
  /**
11
11
  * Authored-once browser-JS transcription of `summarizeToolInput`, for surfaces
12
12
  * that cannot `import` at runtime (the HQ dashboard is a served template-literal
@@ -19,6 +19,5 @@ declare function summarizeToolInput(toolName: string | undefined, input: unknown
19
19
  *
20
20
  * A parity test asserts this produces identical output to the TS function above.
21
21
  */
22
- declare const SUMMARIZE_TOOL_INPUT_BROWSER_SRC: string;
23
-
24
- export { FALLBACK_HEAD_FIELDS, SUMMARIZE_TOOL_INPUT_BROWSER_SRC, summarizeToolInput };
22
+ export declare const SUMMARIZE_TOOL_INPUT_BROWSER_SRC: string;
23
+ //# sourceMappingURL=tool-summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-summary.d.ts","sourceRoot":"","sources":["../src/tool-summary.ts"],"names":[],"mappings":"AA0BA,wDAAwD;AACxD,eAAO,MAAM,oBAAoB,YAC/B,MAAM,EACN,WAAW,EACX,SAAS,EACT,SAAS,EACT,KAAK,EACL,KAAK,EACL,OAAO,EACP,aAAa,EACb,SAAS,CACD,CAAC;AAyCX;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CA4GvF;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gCAAgC,EAAE,MA2EnC,CAAC"}
@@ -202,7 +202,9 @@ var SUMMARIZE_TOOL_INPUT_BROWSER_SRC = [
202
202
  " return __clip(jsonStr,120);",
203
203
  "}"
204
204
  ].join("\n");
205
-
206
- export { FALLBACK_HEAD_FIELDS, SUMMARIZE_TOOL_INPUT_BROWSER_SRC, summarizeToolInput };
205
+ export {
206
+ FALLBACK_HEAD_FIELDS,
207
+ SUMMARIZE_TOOL_INPUT_BROWSER_SRC,
208
+ summarizeToolInput
209
+ };
207
210
  //# sourceMappingURL=tool-summary.js.map
208
- //# sourceMappingURL=tool-summary.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../src/tool-summary.ts"],"names":[],"mappings":"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","file":"tool-summary.js","sourcesContent":["// Tool-aware one-line input summary — the single source of truth shared by the\n// WebUI chat bubbles and the HQ dashboard chat-history sidebar.\n//\n// The whole point: 8 parallel `read` calls should NOT look identical, and a\n// TodoWrite with 8 todos shouldn't dump 800 chars of JSON when \"8 todos · 3\n// done\" tells the whole story.\n//\n// PURE DATA + PURE FUNCTION — no node imports — so it is safe to import from the\n// browser (WebUI). The HQ dashboard is a served template-literal string that\n// cannot `import` at runtime, so it embeds `SUMMARIZE_TOOL_INPUT_BROWSER_SRC`\n// (an authored-once browser-JS transcription of the same logic) instead of a\n// second hand-rolled copy. A test (`tool-summary.parity`) runs both against one\n// fixture table to guarantee they never drift.\n//\n// Cases that earn a custom branch:\n// - TodoWrite -> \"8 todos · 3 done · 2 in-progress\"\n// - batch/parallel -> \"N sub-tools · read, grep +2\"\n// - edit / str_replace -> \"edit foo.ts (3 → 5 lines)\"\n// - write / create -> \"write foo.ts · 12 lines\"\n// - bash / shell / exec -> \"$ <command snippet>\"\n// - fetch / http / web -> \"GET https://…\"\n// - grep / search -> \"grep <pattern> in <scope>\"\n// - glob / find -> \"glob <pattern>\"\n// - read -> \"read path (N…M)\"\n// - fallback -> first non-empty head field, else compact JSON.\n\n/** Head-field lookup order for the generic fallback. */\nexport const FALLBACK_HEAD_FIELDS = [\n 'path',\n 'file_path',\n 'pattern',\n 'command',\n 'cmd',\n 'url',\n 'query',\n 'description',\n 'content',\n] as const;\n\nfunction clip(s: string, n: number): string {\n return s.length > n ? `${s.slice(0, n - 1)}…` : s;\n}\n\nfunction pickPath(obj: Record<string, unknown>): string {\n const p = obj.file_path ?? obj.path ?? obj.filepath;\n return typeof p === 'string' ? p : '';\n}\n\nfunction safeJson(v: unknown): string {\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n\n/**\n * Normalize the two shapes callers hold: WebUI passes a parsed object; HQ holds\n * a JSON *string*. A string that parses to an object is treated as that object;\n * a string that does not parse is returned clipped as-is.\n */\nfunction coerceInput(input: unknown): { obj: Record<string, unknown> | null; raw: unknown } {\n if (typeof input === 'string') {\n const s = input.trim();\n if (s.startsWith('{') || s.startsWith('[')) {\n try {\n const parsed = JSON.parse(s);\n if (parsed && typeof parsed === 'object') return { obj: parsed as Record<string, unknown>, raw: parsed };\n } catch {\n // fall through — non-JSON string\n }\n }\n return { obj: null, raw: input };\n }\n if (input && typeof input === 'object') return { obj: input as Record<string, unknown>, raw: input };\n return { obj: null, raw: input };\n}\n\n/**\n * One-line, tool-aware summary of a tool call's input.\n *\n * @param toolName canonical or aliased tool name (case-insensitive).\n * @param input the tool input — a parsed object OR a JSON string.\n */\nexport function summarizeToolInput(toolName: string | undefined, input: unknown): string {\n if (input === null || input === undefined || input === '') return '';\n const { obj, raw } = coerceInput(input);\n if (!obj) return clip(String(raw), 120);\n\n const name = (toolName ?? '').toLowerCase();\n\n // ---- TodoWrite ----------------------------------------------------\n if (/^todo(_?write)?$|^todos$/.test(name) || Array.isArray(obj.todos)) {\n const todos = (obj.todos ?? []) as Array<{ status?: string | undefined }>;\n if (Array.isArray(todos)) {\n const done = todos.filter((t) => t?.status === 'completed').length;\n const wip = todos.filter((t) => t?.status === 'in_progress').length;\n const parts = [`${todos.length} todo${todos.length === 1 ? '' : 's'}`];\n if (done > 0) parts.push(`${done} done`);\n if (wip > 0) parts.push(`${wip} in-progress`);\n return parts.join(' · ');\n }\n }\n\n // ---- batch_tool_use / parallel_tool_use ---------------------------\n if (/batch|parallel/.test(name) || Array.isArray(obj.tool_uses) || Array.isArray(obj.calls)) {\n const list = (obj.tool_uses ?? obj.calls ?? obj.batch) as unknown[];\n if (Array.isArray(list)) {\n const subNames = new Set<string>();\n for (const item of list) {\n if (item && typeof item === 'object' && 'name' in item) {\n subNames.add(String((item as { name: unknown }).name));\n } else if (item && typeof item === 'object' && 'tool' in item) {\n subNames.add(String((item as { tool: unknown }).tool));\n }\n }\n const preview = [...subNames].slice(0, 3).join(', ');\n const more = subNames.size > 3 ? ` +${subNames.size - 3}` : '';\n return `${list.length} sub-tool${list.length === 1 ? '' : 's'}${preview ? ` · ${preview}${more}` : ''}`;\n }\n }\n\n // ---- edit / str_replace / patch -----------------------------------\n if (/^(edit|str_replace|edit_file|patch)$/.test(name)) {\n const fp = pickPath(obj);\n const oldS = typeof obj.old_string === 'string' ? obj.old_string : '';\n const newS = typeof obj.new_string === 'string' ? obj.new_string : '';\n const oldLines = oldS ? oldS.split('\\n').length : 0;\n const newLines = newS ? newS.split('\\n').length : 0;\n return `edit ${fp || '(file)'}${oldLines || newLines ? ` (${oldLines} → ${newLines} lines)` : ''}`;\n }\n\n // ---- write / create -----------------------------------------------\n if (/^(write|write_file|create_file|new_file)$/.test(name)) {\n const fp = pickPath(obj);\n const c = typeof obj.content === 'string' ? obj.content : '';\n const lines = c ? c.split('\\n').length : 0;\n return `write ${fp || '(file)'}${lines ? ` · ${lines} lines` : ''}`;\n }\n\n // ---- bash / shell / exec / run ------------------------------------\n if (/^(bash|shell|sh|exec|run|run_command|run_shell|command)$/.test(name)) {\n const cmd = (obj.command ?? obj.cmd ?? obj.script) as string | undefined;\n if (typeof cmd === 'string') return `$ ${clip(cmd, 110)}`;\n }\n\n // ---- fetch / http / web -------------------------------------------\n if (/^(fetch|http|web|web_fetch|web_search|webfetch|curl|request)$/.test(name)) {\n const url = obj.url as string | undefined;\n if (typeof url === 'string') {\n const method = (obj.method as string | undefined) ?? 'GET';\n return `${method.toUpperCase()} ${clip(url, 100)}`;\n }\n }\n\n // ---- grep / search ------------------------------------------------\n if (/^(grep|search|ripgrep|rg)$/.test(name)) {\n const pattern = obj.pattern as string | undefined;\n const scope = (obj.path ?? obj.glob ?? obj.type) as string | undefined;\n if (typeof pattern === 'string') {\n return scope ? `grep ${clip(pattern, 60)} in ${scope}` : `grep ${clip(pattern, 100)}`;\n }\n }\n\n // ---- glob / find --------------------------------------------------\n if (/^(glob|find)$/.test(name)) {\n const p = (obj.pattern ?? obj.glob) as string | undefined;\n if (typeof p === 'string') return `glob ${clip(p, 80)}`;\n }\n\n // ---- read with offset/limit --------------------------------------\n if (/^(read|read_file|cat|view)$/.test(name)) {\n const fp = pickPath(obj);\n const offset = obj.offset as number | undefined;\n const limit = obj.limit as number | undefined;\n if (fp && (typeof offset === 'number' || typeof limit === 'number')) {\n const start = offset ?? 0;\n const end = typeof limit === 'number' ? start + limit : '';\n return `read ${fp} (${start}…${end})`;\n }\n if (fp) return `read ${fp}`;\n }\n\n // ---- Fallback: first non-empty headline string field --------------\n for (const k of FALLBACK_HEAD_FIELDS) {\n const v = obj[k];\n if (typeof v === 'string' && v.length > 0) {\n return `${k}: ${clip(v, 100)}`;\n }\n }\n // Last resort: compact JSON.\n return clip(safeJson(raw), 120);\n}\n\n/**\n * Authored-once browser-JS transcription of `summarizeToolInput`, for surfaces\n * that cannot `import` at runtime (the HQ dashboard is a served template-literal\n * string). This is DELIBERATELY written with string concatenation and single\n * backslashes only: the HQ template literal escapes `\\` and `` ` ``/`${` before\n * embedding, so this text must contain NO backticks and NO `${` sequences.\n *\n * Defines one global function: `toolInputSummary(name, rawInput)` where\n * rawInput is a JSON string (HQ's on-wire shape) or null.\n *\n * A parity test asserts this produces identical output to the TS function above.\n */\nexport const SUMMARIZE_TOOL_INPUT_BROWSER_SRC: string = [\n 'function __clip(s,n){ s=String(s==null?\"\":s); return s.length>n ? s.slice(0,n-1)+\"\\\\u2026\" : s; }',\n 'function toolInputSummary(name, rawInput){',\n ' if(rawInput==null || rawInput===\"\") return \"\";',\n ' var obj=null, raw=rawInput;',\n ' if(typeof rawInput===\"string\"){',\n ' var s=rawInput.trim();',\n ' if(s.charAt(0)===\"{\" || s.charAt(0)===\"[\"){ try{ var pj=JSON.parse(s); if(pj && typeof pj===\"object\"){ obj=pj; raw=pj; } }catch(_e){} }',\n ' } else if(rawInput && typeof rawInput===\"object\"){ obj=rawInput; raw=rawInput; }',\n ' if(!obj) return __clip(String(raw),120);',\n ' var n=String(name==null?\"\":name).toLowerCase();',\n ' if(/^todo(_?write)?$|^todos$/.test(n) || Array.isArray(obj.todos)){',\n ' var todos=obj.todos||[];',\n ' if(Array.isArray(todos)){',\n ' var done=0, wip=0, ti;',\n ' for(ti=0; ti<todos.length; ti++){ var st=todos[ti]&&todos[ti].status; if(st===\"completed\") done++; else if(st===\"in_progress\") wip++; }',\n ' var tp=[todos.length+\" todo\"+(todos.length===1?\"\":\"s\")];',\n ' if(done>0) tp.push(done+\" done\"); if(wip>0) tp.push(wip+\" in-progress\");',\n ' return tp.join(\" \\\\u00b7 \");',\n ' }',\n ' }',\n ' if(/batch|parallel/.test(n) || Array.isArray(obj.tool_uses) || Array.isArray(obj.calls)){',\n ' var list=obj.tool_uses||obj.calls||obj.batch;',\n ' if(Array.isArray(list)){',\n ' var names={}, ord=[], li, it, nm;',\n ' for(li=0; li<list.length; li++){ it=list[li]; if(it && typeof it===\"object\"){ nm=(\"name\" in it)?it.name:((\"tool\" in it)?it.tool:null); if(nm!=null){ nm=String(nm); if(!names[nm]){ names[nm]=1; ord.push(nm); } } } }',\n ' var preview=ord.slice(0,3).join(\", \");',\n ' var more=ord.length>3 ? \" +\"+(ord.length-3) : \"\";',\n ' return list.length+\" sub-tool\"+(list.length===1?\"\":\"s\")+(preview?(\" \\\\u00b7 \"+preview+more):\"\");',\n ' }',\n ' }',\n ' var fp;',\n ' if(/^(edit|str_replace|edit_file|patch)$/.test(n)){',\n ' fp=(obj.file_path!=null?obj.file_path:(obj.path!=null?obj.path:obj.filepath));',\n ' var oldS=typeof obj.old_string===\"string\"?obj.old_string:\"\";',\n ' var newS=typeof obj.new_string===\"string\"?obj.new_string:\"\";',\n ' var ol=oldS?oldS.split(\"\\\\n\").length:0, nl=newS?newS.split(\"\\\\n\").length:0;',\n ' var efp=typeof fp===\"string\"?fp:\"\";',\n ' return \"edit \"+(efp||\"(file)\")+((ol||nl)?(\" (\"+ol+\" \\\\u2192 \"+nl+\" lines)\"):\"\");',\n ' }',\n ' if(/^(write|write_file|create_file|new_file)$/.test(n)){',\n ' fp=(obj.file_path!=null?obj.file_path:(obj.path!=null?obj.path:obj.filepath));',\n ' var wc=typeof obj.content===\"string\"?obj.content:\"\";',\n ' var wl=wc?wc.split(\"\\\\n\").length:0;',\n ' var wfp=typeof fp===\"string\"?fp:\"\";',\n ' return \"write \"+(wfp||\"(file)\")+(wl?(\" \\\\u00b7 \"+wl+\" lines\"):\"\");',\n ' }',\n ' if(/^(bash|shell|sh|exec|run|run_command|run_shell|command)$/.test(n)){',\n ' var cmd=(obj.command!=null?obj.command:(obj.cmd!=null?obj.cmd:obj.script));',\n ' if(typeof cmd===\"string\") return \"$ \"+__clip(cmd,110);',\n ' }',\n ' if(/^(fetch|http|web|web_fetch|web_search|webfetch|curl|request)$/.test(n)){',\n ' if(typeof obj.url===\"string\"){ var mth=(typeof obj.method===\"string\"?obj.method:\"GET\"); return mth.toUpperCase()+\" \"+__clip(obj.url,100); }',\n ' }',\n ' if(/^(grep|search|ripgrep|rg)$/.test(n)){',\n ' var pat=obj.pattern, scope=(obj.path!=null?obj.path:(obj.glob!=null?obj.glob:obj.type));',\n ' if(typeof pat===\"string\"){ return scope ? (\"grep \"+__clip(pat,60)+\" in \"+scope) : (\"grep \"+__clip(pat,100)); }',\n ' }',\n ' if(/^(glob|find)$/.test(n)){',\n ' var gp=(obj.pattern!=null?obj.pattern:obj.glob);',\n ' if(typeof gp===\"string\") return \"glob \"+__clip(gp,80);',\n ' }',\n ' if(/^(read|read_file|cat|view)$/.test(n)){',\n ' fp=(obj.file_path!=null?obj.file_path:(obj.path!=null?obj.path:obj.filepath));',\n ' if(typeof fp===\"string\" && fp){',\n ' var off=obj.offset, lim=obj.limit;',\n ' if(typeof off===\"number\" || typeof lim===\"number\"){ var start=(typeof off===\"number\"?off:0); var end=(typeof lim===\"number\"?(start+lim):\"\"); return \"read \"+fp+\" (\"+start+\"\\\\u2026\"+end+\")\"; }',\n ' return \"read \"+fp;',\n ' }',\n ' }',\n ' var HEAD=[\"path\",\"file_path\",\"pattern\",\"command\",\"cmd\",\"url\",\"query\",\"description\",\"content\"], hi;',\n ' for(hi=0; hi<HEAD.length; hi++){ var hv=obj[HEAD[hi]]; if(typeof hv===\"string\" && hv.length>0){ return HEAD[hi]+\": \"+__clip(hv,100); } }',\n ' var jsonStr; try{ jsonStr=JSON.stringify(raw); }catch(_e2){ jsonStr=String(raw); }',\n ' return __clip(jsonStr,120);',\n '}',\n].join('\\n');\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tool-summary.ts"],
4
+ "sourcesContent": ["// Tool-aware one-line input summary \u2014 the single source of truth shared by the\n// WebUI chat bubbles and the HQ dashboard chat-history sidebar.\n//\n// The whole point: 8 parallel `read` calls should NOT look identical, and a\n// TodoWrite with 8 todos shouldn't dump 800 chars of JSON when \"8 todos \u00B7 3\n// done\" tells the whole story.\n//\n// PURE DATA + PURE FUNCTION \u2014 no node imports \u2014 so it is safe to import from the\n// browser (WebUI). The HQ dashboard is a served template-literal string that\n// cannot `import` at runtime, so it embeds `SUMMARIZE_TOOL_INPUT_BROWSER_SRC`\n// (an authored-once browser-JS transcription of the same logic) instead of a\n// second hand-rolled copy. A test (`tool-summary.parity`) runs both against one\n// fixture table to guarantee they never drift.\n//\n// Cases that earn a custom branch:\n// - TodoWrite -> \"8 todos \u00B7 3 done \u00B7 2 in-progress\"\n// - batch/parallel -> \"N sub-tools \u00B7 read, grep +2\"\n// - edit / str_replace -> \"edit foo.ts (3 \u2192 5 lines)\"\n// - write / create -> \"write foo.ts \u00B7 12 lines\"\n// - bash / shell / exec -> \"$ <command snippet>\"\n// - fetch / http / web -> \"GET https://\u2026\"\n// - grep / search -> \"grep <pattern> in <scope>\"\n// - glob / find -> \"glob <pattern>\"\n// - read -> \"read path (N\u2026M)\"\n// - fallback -> first non-empty head field, else compact JSON.\n\n/** Head-field lookup order for the generic fallback. */\nexport const FALLBACK_HEAD_FIELDS = [\n 'path',\n 'file_path',\n 'pattern',\n 'command',\n 'cmd',\n 'url',\n 'query',\n 'description',\n 'content',\n] as const;\n\nfunction clip(s: string, n: number): string {\n return s.length > n ? `${s.slice(0, n - 1)}\u2026` : s;\n}\n\nfunction pickPath(obj: Record<string, unknown>): string {\n const p = obj.file_path ?? obj.path ?? obj.filepath;\n return typeof p === 'string' ? p : '';\n}\n\nfunction safeJson(v: unknown): string {\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n\n/**\n * Normalize the two shapes callers hold: WebUI passes a parsed object; HQ holds\n * a JSON *string*. A string that parses to an object is treated as that object;\n * a string that does not parse is returned clipped as-is.\n */\nfunction coerceInput(input: unknown): { obj: Record<string, unknown> | null; raw: unknown } {\n if (typeof input === 'string') {\n const s = input.trim();\n if (s.startsWith('{') || s.startsWith('[')) {\n try {\n const parsed = JSON.parse(s);\n if (parsed && typeof parsed === 'object') return { obj: parsed as Record<string, unknown>, raw: parsed };\n } catch {\n // fall through \u2014 non-JSON string\n }\n }\n return { obj: null, raw: input };\n }\n if (input && typeof input === 'object') return { obj: input as Record<string, unknown>, raw: input };\n return { obj: null, raw: input };\n}\n\n/**\n * One-line, tool-aware summary of a tool call's input.\n *\n * @param toolName canonical or aliased tool name (case-insensitive).\n * @param input the tool input \u2014 a parsed object OR a JSON string.\n */\nexport function summarizeToolInput(toolName: string | undefined, input: unknown): string {\n if (input === null || input === undefined || input === '') return '';\n const { obj, raw } = coerceInput(input);\n if (!obj) return clip(String(raw), 120);\n\n const name = (toolName ?? '').toLowerCase();\n\n // ---- TodoWrite ----------------------------------------------------\n if (/^todo(_?write)?$|^todos$/.test(name) || Array.isArray(obj.todos)) {\n const todos = (obj.todos ?? []) as Array<{ status?: string | undefined }>;\n if (Array.isArray(todos)) {\n const done = todos.filter((t) => t?.status === 'completed').length;\n const wip = todos.filter((t) => t?.status === 'in_progress').length;\n const parts = [`${todos.length} todo${todos.length === 1 ? '' : 's'}`];\n if (done > 0) parts.push(`${done} done`);\n if (wip > 0) parts.push(`${wip} in-progress`);\n return parts.join(' \u00B7 ');\n }\n }\n\n // ---- batch_tool_use / parallel_tool_use ---------------------------\n if (/batch|parallel/.test(name) || Array.isArray(obj.tool_uses) || Array.isArray(obj.calls)) {\n const list = (obj.tool_uses ?? obj.calls ?? obj.batch) as unknown[];\n if (Array.isArray(list)) {\n const subNames = new Set<string>();\n for (const item of list) {\n if (item && typeof item === 'object' && 'name' in item) {\n subNames.add(String((item as { name: unknown }).name));\n } else if (item && typeof item === 'object' && 'tool' in item) {\n subNames.add(String((item as { tool: unknown }).tool));\n }\n }\n const preview = [...subNames].slice(0, 3).join(', ');\n const more = subNames.size > 3 ? ` +${subNames.size - 3}` : '';\n return `${list.length} sub-tool${list.length === 1 ? '' : 's'}${preview ? ` \u00B7 ${preview}${more}` : ''}`;\n }\n }\n\n // ---- edit / str_replace / patch -----------------------------------\n if (/^(edit|str_replace|edit_file|patch)$/.test(name)) {\n const fp = pickPath(obj);\n const oldS = typeof obj.old_string === 'string' ? obj.old_string : '';\n const newS = typeof obj.new_string === 'string' ? obj.new_string : '';\n const oldLines = oldS ? oldS.split('\\n').length : 0;\n const newLines = newS ? newS.split('\\n').length : 0;\n return `edit ${fp || '(file)'}${oldLines || newLines ? ` (${oldLines} \u2192 ${newLines} lines)` : ''}`;\n }\n\n // ---- write / create -----------------------------------------------\n if (/^(write|write_file|create_file|new_file)$/.test(name)) {\n const fp = pickPath(obj);\n const c = typeof obj.content === 'string' ? obj.content : '';\n const lines = c ? c.split('\\n').length : 0;\n return `write ${fp || '(file)'}${lines ? ` \u00B7 ${lines} lines` : ''}`;\n }\n\n // ---- bash / shell / exec / run ------------------------------------\n if (/^(bash|shell|sh|exec|run|run_command|run_shell|command)$/.test(name)) {\n const cmd = (obj.command ?? obj.cmd ?? obj.script) as string | undefined;\n if (typeof cmd === 'string') return `$ ${clip(cmd, 110)}`;\n }\n\n // ---- fetch / http / web -------------------------------------------\n if (/^(fetch|http|web|web_fetch|web_search|webfetch|curl|request)$/.test(name)) {\n const url = obj.url as string | undefined;\n if (typeof url === 'string') {\n const method = (obj.method as string | undefined) ?? 'GET';\n return `${method.toUpperCase()} ${clip(url, 100)}`;\n }\n }\n\n // ---- grep / search ------------------------------------------------\n if (/^(grep|search|ripgrep|rg)$/.test(name)) {\n const pattern = obj.pattern as string | undefined;\n const scope = (obj.path ?? obj.glob ?? obj.type) as string | undefined;\n if (typeof pattern === 'string') {\n return scope ? `grep ${clip(pattern, 60)} in ${scope}` : `grep ${clip(pattern, 100)}`;\n }\n }\n\n // ---- glob / find --------------------------------------------------\n if (/^(glob|find)$/.test(name)) {\n const p = (obj.pattern ?? obj.glob) as string | undefined;\n if (typeof p === 'string') return `glob ${clip(p, 80)}`;\n }\n\n // ---- read with offset/limit --------------------------------------\n if (/^(read|read_file|cat|view)$/.test(name)) {\n const fp = pickPath(obj);\n const offset = obj.offset as number | undefined;\n const limit = obj.limit as number | undefined;\n if (fp && (typeof offset === 'number' || typeof limit === 'number')) {\n const start = offset ?? 0;\n const end = typeof limit === 'number' ? start + limit : '';\n return `read ${fp} (${start}\u2026${end})`;\n }\n if (fp) return `read ${fp}`;\n }\n\n // ---- Fallback: first non-empty headline string field --------------\n for (const k of FALLBACK_HEAD_FIELDS) {\n const v = obj[k];\n if (typeof v === 'string' && v.length > 0) {\n return `${k}: ${clip(v, 100)}`;\n }\n }\n // Last resort: compact JSON.\n return clip(safeJson(raw), 120);\n}\n\n/**\n * Authored-once browser-JS transcription of `summarizeToolInput`, for surfaces\n * that cannot `import` at runtime (the HQ dashboard is a served template-literal\n * string). This is DELIBERATELY written with string concatenation and single\n * backslashes only: the HQ template literal escapes `\\` and `` ` ``/`${` before\n * embedding, so this text must contain NO backticks and NO `${` sequences.\n *\n * Defines one global function: `toolInputSummary(name, rawInput)` where\n * rawInput is a JSON string (HQ's on-wire shape) or null.\n *\n * A parity test asserts this produces identical output to the TS function above.\n */\nexport const SUMMARIZE_TOOL_INPUT_BROWSER_SRC: string = [\n 'function __clip(s,n){ s=String(s==null?\"\":s); return s.length>n ? s.slice(0,n-1)+\"\\\\u2026\" : s; }',\n 'function toolInputSummary(name, rawInput){',\n ' if(rawInput==null || rawInput===\"\") return \"\";',\n ' var obj=null, raw=rawInput;',\n ' if(typeof rawInput===\"string\"){',\n ' var s=rawInput.trim();',\n ' if(s.charAt(0)===\"{\" || s.charAt(0)===\"[\"){ try{ var pj=JSON.parse(s); if(pj && typeof pj===\"object\"){ obj=pj; raw=pj; } }catch(_e){} }',\n ' } else if(rawInput && typeof rawInput===\"object\"){ obj=rawInput; raw=rawInput; }',\n ' if(!obj) return __clip(String(raw),120);',\n ' var n=String(name==null?\"\":name).toLowerCase();',\n ' if(/^todo(_?write)?$|^todos$/.test(n) || Array.isArray(obj.todos)){',\n ' var todos=obj.todos||[];',\n ' if(Array.isArray(todos)){',\n ' var done=0, wip=0, ti;',\n ' for(ti=0; ti<todos.length; ti++){ var st=todos[ti]&&todos[ti].status; if(st===\"completed\") done++; else if(st===\"in_progress\") wip++; }',\n ' var tp=[todos.length+\" todo\"+(todos.length===1?\"\":\"s\")];',\n ' if(done>0) tp.push(done+\" done\"); if(wip>0) tp.push(wip+\" in-progress\");',\n ' return tp.join(\" \\\\u00b7 \");',\n ' }',\n ' }',\n ' if(/batch|parallel/.test(n) || Array.isArray(obj.tool_uses) || Array.isArray(obj.calls)){',\n ' var list=obj.tool_uses||obj.calls||obj.batch;',\n ' if(Array.isArray(list)){',\n ' var names={}, ord=[], li, it, nm;',\n ' for(li=0; li<list.length; li++){ it=list[li]; if(it && typeof it===\"object\"){ nm=(\"name\" in it)?it.name:((\"tool\" in it)?it.tool:null); if(nm!=null){ nm=String(nm); if(!names[nm]){ names[nm]=1; ord.push(nm); } } } }',\n ' var preview=ord.slice(0,3).join(\", \");',\n ' var more=ord.length>3 ? \" +\"+(ord.length-3) : \"\";',\n ' return list.length+\" sub-tool\"+(list.length===1?\"\":\"s\")+(preview?(\" \\\\u00b7 \"+preview+more):\"\");',\n ' }',\n ' }',\n ' var fp;',\n ' if(/^(edit|str_replace|edit_file|patch)$/.test(n)){',\n ' fp=(obj.file_path!=null?obj.file_path:(obj.path!=null?obj.path:obj.filepath));',\n ' var oldS=typeof obj.old_string===\"string\"?obj.old_string:\"\";',\n ' var newS=typeof obj.new_string===\"string\"?obj.new_string:\"\";',\n ' var ol=oldS?oldS.split(\"\\\\n\").length:0, nl=newS?newS.split(\"\\\\n\").length:0;',\n ' var efp=typeof fp===\"string\"?fp:\"\";',\n ' return \"edit \"+(efp||\"(file)\")+((ol||nl)?(\" (\"+ol+\" \\\\u2192 \"+nl+\" lines)\"):\"\");',\n ' }',\n ' if(/^(write|write_file|create_file|new_file)$/.test(n)){',\n ' fp=(obj.file_path!=null?obj.file_path:(obj.path!=null?obj.path:obj.filepath));',\n ' var wc=typeof obj.content===\"string\"?obj.content:\"\";',\n ' var wl=wc?wc.split(\"\\\\n\").length:0;',\n ' var wfp=typeof fp===\"string\"?fp:\"\";',\n ' return \"write \"+(wfp||\"(file)\")+(wl?(\" \\\\u00b7 \"+wl+\" lines\"):\"\");',\n ' }',\n ' if(/^(bash|shell|sh|exec|run|run_command|run_shell|command)$/.test(n)){',\n ' var cmd=(obj.command!=null?obj.command:(obj.cmd!=null?obj.cmd:obj.script));',\n ' if(typeof cmd===\"string\") return \"$ \"+__clip(cmd,110);',\n ' }',\n ' if(/^(fetch|http|web|web_fetch|web_search|webfetch|curl|request)$/.test(n)){',\n ' if(typeof obj.url===\"string\"){ var mth=(typeof obj.method===\"string\"?obj.method:\"GET\"); return mth.toUpperCase()+\" \"+__clip(obj.url,100); }',\n ' }',\n ' if(/^(grep|search|ripgrep|rg)$/.test(n)){',\n ' var pat=obj.pattern, scope=(obj.path!=null?obj.path:(obj.glob!=null?obj.glob:obj.type));',\n ' if(typeof pat===\"string\"){ return scope ? (\"grep \"+__clip(pat,60)+\" in \"+scope) : (\"grep \"+__clip(pat,100)); }',\n ' }',\n ' if(/^(glob|find)$/.test(n)){',\n ' var gp=(obj.pattern!=null?obj.pattern:obj.glob);',\n ' if(typeof gp===\"string\") return \"glob \"+__clip(gp,80);',\n ' }',\n ' if(/^(read|read_file|cat|view)$/.test(n)){',\n ' fp=(obj.file_path!=null?obj.file_path:(obj.path!=null?obj.path:obj.filepath));',\n ' if(typeof fp===\"string\" && fp){',\n ' var off=obj.offset, lim=obj.limit;',\n ' if(typeof off===\"number\" || typeof lim===\"number\"){ var start=(typeof off===\"number\"?off:0); var end=(typeof lim===\"number\"?(start+lim):\"\"); return \"read \"+fp+\" (\"+start+\"\\\\u2026\"+end+\")\"; }',\n ' return \"read \"+fp;',\n ' }',\n ' }',\n ' var HEAD=[\"path\",\"file_path\",\"pattern\",\"command\",\"cmd\",\"url\",\"query\",\"description\",\"content\"], hi;',\n ' for(hi=0; hi<HEAD.length; hi++){ var hv=obj[HEAD[hi]]; if(typeof hv===\"string\" && hv.length>0){ return HEAD[hi]+\": \"+__clip(hv,100); } }',\n ' var jsonStr; try{ jsonStr=JSON.stringify(raw); }catch(_e2){ jsonStr=String(raw); }',\n ' return __clip(jsonStr,120);',\n '}',\n].join('\\n');\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,5 +1,4 @@
1
- import { Tool } from '@wrongstack/core';
2
-
1
+ import type { Tool } from '@wrongstack/core';
3
2
  interface ToolUseInput {
4
3
  tool: string;
5
4
  input: Record<string, unknown>;
@@ -11,6 +10,6 @@ interface ToolUseOutput {
11
10
  error?: string | undefined;
12
11
  executionMs: number;
13
12
  }
14
- declare const toolUseTool: Tool<ToolUseInput, ToolUseOutput>;
15
-
16
- export { toolUseTool };
13
+ export declare const toolUseTool: Tool<ToolUseInput, ToolUseOutput>;
14
+ export {};
15
+ //# sourceMappingURL=tool-use.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-use.d.ts","sourceRoot":"","sources":["../src/tool-use.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE7C,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,WAAW,EAAE,IAAI,CAAC,YAAY,EAAE,aAAa,CA2FzD,CAAC"}
package/dist/tool-use.js CHANGED
@@ -68,7 +68,7 @@ var toolUseTool = {
68
68
  }
69
69
  }
70
70
  };
71
-
72
- export { toolUseTool };
71
+ export {
72
+ toolUseTool
73
+ };
73
74
  //# sourceMappingURL=tool-use.js.map
74
- //# sourceMappingURL=tool-use.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../src/tool-use.ts"],"names":[],"mappings":";AAeO,IAAM,WAAA,GAAiD;AAAA,EAC5D,IAAA,EAAM,UAAA;AAAA,EACN,QAAA,EAAU,MAAA;AAAA,EACV,WAAA,EACE,gNAAA;AAAA,EAEF,SAAA,EACE,+WAAA;AAAA,EAKF,UAAA,EAAY,SAAA;AAAA,EACZ,QAAA,EAAU,IAAA;AAAA,EACV,SAAA,EAAW,GAAA;AAAA,EACX,YAAA,EAAc,CAAC,iBAAiB,CAAA;AAAA,EAChC,IAAA,EAAM,MAAA;AAAA,EACN,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,QAAA;AAAA,IACN,UAAA,EAAY;AAAA,MACV,IAAA,EAAM;AAAA,QACJ,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EAAa;AAAA,OACf;AAAA,MACA,KAAA,EAAO;AAAA,QACL,IAAA,EAAM,QAAA;AAAA,QACN,WAAA,EAAa;AAAA;AACf,KACF;AAAA,IACA,QAAA,EAAU,CAAC,MAAM;AAAA,GACnB;AAAA,EACA,MAAM,OAAA,CAAQ,KAAA,EAAO,GAAA,EAAK,IAAA,EAAM;AAC9B,IAAA,MAAM,KAAA,GAAQ,KAAK,GAAA,EAAI;AAEvB,IAAA,IAAI,CAAC,OAAO,IAAA,EAAM;AAChB,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,SAAA;AAAA,QACN,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,iCAAA;AAAA,QACP,WAAA,EAAa;AAAA,OACf;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,IAAI,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAY,CAAA,CAAE,IAAA,KAAS,KAAA,CAAM,IAAI,CAAA;AAC9D,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,OAAO;AAAA,QACL,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,CAAA,gBAAA,EAAmB,KAAA,CAAM,IAAI,CAAA,WAAA,CAAA;AAAA,QACpC,WAAA,EAAa,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,OAC5B;AAAA,IACF;AAKA,IAAA,IAAI,IAAA,CAAK,eAAe,MAAA,EAAQ;AAC9B,MAAA,OAAO;AAAA,QACL,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO,CAAA,gBAAA,EAAmB,KAAA,CAAM,IAAI,CAAA,qBAAA,CAAA;AAAA,QACpC,WAAA,EAAa,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,OAC5B;AAAA,IACF;AAWA,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,QAAQ,KAAA,CAAM,KAAA,EAAO,KAAK,IAAI,CAAA;AACxD,MAAA,OAAO;AAAA,QACL,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,OAAA,EAAS,IAAA;AAAA,QACT,MAAA;AAAA,QACA,WAAA,EAAa,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,OAC5B;AAAA,IACF,SAAS,CAAA,EAAG;AACV,MAAA,OAAO;AAAA,QACL,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,OAAA,EAAS,KAAA;AAAA,QACT,OAAO,CAAA,YAAa,KAAA,GAAQ,CAAA,CAAE,OAAA,GAAU,OAAO,CAAC,CAAA;AAAA,QAChD,WAAA,EAAa,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,OAC5B;AAAA,IACF;AAAA,EACF;AACF","file":"tool-use.js","sourcesContent":["import type { Tool } from '@wrongstack/core';\n\ninterface ToolUseInput {\n tool: string;\n input: Record<string, unknown>;\n}\n\ninterface ToolUseOutput {\n tool: string;\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n executionMs: number;\n}\n\nexport const toolUseTool: Tool<ToolUseInput, ToolUseOutput> = {\n name: 'tool_use',\n category: 'Meta',\n description:\n 'Directly execute any registered tool by its exact name, bypassing normal discovery. ' +\n 'This is a powerful meta-tool intended for cases where the agent has a clear plan and knows precisely which tool to invoke.',\n usageHint:\n 'ADVANCED META TOOL — USE WITH CARE:\\n\\n' +\n '- Only use when you are certain of the exact tool name and its expected input shape.\\n' +\n '- Prefer using the normal tool calling mechanism when possible.\\n' +\n '- Very useful in batch-tool-use or when orchestrating complex workflows programmatically.\\n' +\n '- The call still goes through full permission checks and capability validation.',\n permission: 'confirm',\n mutating: true,\n timeoutMs: 60_000,\n capabilities: ['tool.mutate.any'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n tool: {\n type: 'string',\n description: 'The exact registered name of the tool to invoke (e.g. \"bash\", \"read\", \"codebase-search\").',\n },\n input: {\n type: 'object',\n description: 'The input object matching the target tool\\'s inputSchema.',\n },\n },\n required: ['tool'],\n },\n async execute(input, ctx, opts) {\n const start = Date.now();\n\n if (!input?.tool) {\n return {\n tool: 'unknown',\n success: false,\n error: 'tool_use: tool name is required',\n executionMs: 0,\n };\n }\n\n const tool = ctx.tools.find((t: Tool) => t.name === input.tool);\n if (!tool) {\n return {\n tool: input.tool,\n success: false,\n error: `tool_use: tool \"${input.tool}\" not found`,\n executionMs: Date.now() - start,\n };\n }\n\n // `deny` is a hard policy gate — bypassing it through a meta-tool\n // would defeat the whole point of the permission system. Keep this\n // check even though the outer `tool_use` already requires `confirm`.\n if (tool.permission === 'deny') {\n return {\n tool: input.tool,\n success: false,\n error: `tool_use: tool \"${input.tool}\" is denied by policy`,\n executionMs: Date.now() - start,\n };\n }\n\n // Note: inner `permission === 'confirm'` is intentionally NOT short-\n // circuited here. The outer `tool_use` itself has `permission: 'confirm'`,\n // so the user already saw the full args (including which inner tool will\n // run, and with what input) before approving the meta-call. Duplicating\n // the check inside execute() turned every confirm-tool dispatch through\n // `tool_use` into a hard failure — the model would see \"requires\n // confirmation\" with no way to proceed, even after the user said yes.\n // `batch_tool_use` already follows this same model.\n\n try {\n const result = await tool.execute(input.input, ctx, opts);\n return {\n tool: input.tool,\n success: true,\n result,\n executionMs: Date.now() - start,\n };\n } catch (e) {\n return {\n tool: input.tool,\n success: false,\n error: e instanceof Error ? e.message : String(e),\n executionMs: Date.now() - start,\n };\n }\n },\n};\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tool-use.ts"],
4
+ "sourcesContent": ["import type { Tool } from '@wrongstack/core';\n\ninterface ToolUseInput {\n tool: string;\n input: Record<string, unknown>;\n}\n\ninterface ToolUseOutput {\n tool: string;\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n executionMs: number;\n}\n\nexport const toolUseTool: Tool<ToolUseInput, ToolUseOutput> = {\n name: 'tool_use',\n category: 'Meta',\n description:\n 'Directly execute any registered tool by its exact name, bypassing normal discovery. ' +\n 'This is a powerful meta-tool intended for cases where the agent has a clear plan and knows precisely which tool to invoke.',\n usageHint:\n 'ADVANCED META TOOL \u2014 USE WITH CARE:\\n\\n' +\n '- Only use when you are certain of the exact tool name and its expected input shape.\\n' +\n '- Prefer using the normal tool calling mechanism when possible.\\n' +\n '- Very useful in batch-tool-use or when orchestrating complex workflows programmatically.\\n' +\n '- The call still goes through full permission checks and capability validation.',\n permission: 'confirm',\n mutating: true,\n timeoutMs: 60_000,\n capabilities: ['tool.mutate.any'],\n icon: 'meta',\n inputSchema: {\n type: 'object',\n properties: {\n tool: {\n type: 'string',\n description: 'The exact registered name of the tool to invoke (e.g. \"bash\", \"read\", \"codebase-search\").',\n },\n input: {\n type: 'object',\n description: 'The input object matching the target tool\\'s inputSchema.',\n },\n },\n required: ['tool'],\n },\n async execute(input, ctx, opts) {\n const start = Date.now();\n\n if (!input?.tool) {\n return {\n tool: 'unknown',\n success: false,\n error: 'tool_use: tool name is required',\n executionMs: 0,\n };\n }\n\n const tool = ctx.tools.find((t: Tool) => t.name === input.tool);\n if (!tool) {\n return {\n tool: input.tool,\n success: false,\n error: `tool_use: tool \"${input.tool}\" not found`,\n executionMs: Date.now() - start,\n };\n }\n\n // `deny` is a hard policy gate \u2014 bypassing it through a meta-tool\n // would defeat the whole point of the permission system. Keep this\n // check even though the outer `tool_use` already requires `confirm`.\n if (tool.permission === 'deny') {\n return {\n tool: input.tool,\n success: false,\n error: `tool_use: tool \"${input.tool}\" is denied by policy`,\n executionMs: Date.now() - start,\n };\n }\n\n // Note: inner `permission === 'confirm'` is intentionally NOT short-\n // circuited here. The outer `tool_use` itself has `permission: 'confirm'`,\n // so the user already saw the full args (including which inner tool will\n // run, and with what input) before approving the meta-call. Duplicating\n // the check inside execute() turned every confirm-tool dispatch through\n // `tool_use` into a hard failure \u2014 the model would see \"requires\n // confirmation\" with no way to proceed, even after the user said yes.\n // `batch_tool_use` already follows this same model.\n\n try {\n const result = await tool.execute(input.input, ctx, opts);\n return {\n tool: input.tool,\n success: true,\n result,\n executionMs: Date.now() - start,\n };\n } catch (e) {\n return {\n tool: input.tool,\n success: false,\n error: e instanceof Error ? e.message : String(e),\n executionMs: Date.now() - start,\n };\n }\n },\n};\n"],
5
+ "mappings": ";AAeO,IAAM,cAAiD;AAAA,EAC5D,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aACE;AAAA,EAEF,WACE;AAAA,EAKF,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc,CAAC,iBAAiB;AAAA,EAChC,MAAM;AAAA,EACN,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,OAAO;AAAA,QACL,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,MAAM;AAAA,EACnB;AAAA,EACA,MAAM,QAAQ,OAAO,KAAK,MAAM;AAC9B,UAAM,QAAQ,KAAK,IAAI;AAEvB,QAAI,CAAC,OAAO,MAAM;AAChB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAEA,UAAM,OAAO,IAAI,MAAM,KAAK,CAAC,MAAY,EAAE,SAAS,MAAM,IAAI;AAC9D,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS;AAAA,QACT,OAAO,mBAAmB,MAAM,IAAI;AAAA,QACpC,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B;AAAA,IACF;AAKA,QAAI,KAAK,eAAe,QAAQ;AAC9B,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS;AAAA,QACT,OAAO,mBAAmB,MAAM,IAAI;AAAA,QACpC,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B;AAAA,IACF;AAWA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,QAAQ,MAAM,OAAO,KAAK,IAAI;AACxD,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS;AAAA,QACT;AAAA,QACA,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B;AAAA,IACF,SAAS,GAAG;AACV,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,SAAS;AAAA,QACT,OAAO,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AAAA,QAChD,aAAa,KAAK,IAAI,IAAI;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
package/dist/tree.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { Tool } from '@wrongstack/core';
2
-
1
+ import type { Tool } from '@wrongstack/core';
3
2
  interface TreeInput {
4
3
  path?: string | undefined;
5
4
  depth?: number | undefined;
@@ -16,6 +15,6 @@ interface TreeOutput {
16
15
  truncated: boolean;
17
16
  path: string;
18
17
  }
19
- declare const treeTool: Tool<TreeInput, TreeOutput>;
20
-
21
- export { treeTool };
18
+ export declare const treeTool: Tool<TreeInput, TreeOutput>;
19
+ export {};
20
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAsC,MAAM,kBAAkB,CAAC;AAgBjF,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnC;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,UAAU,CAgJhD,CAAC"}
package/dist/tree.js CHANGED
@@ -1,9 +1,11 @@
1
- import * as Core from '@wrongstack/core';
2
- import { expectDefined } from '@wrongstack/core';
3
- import * as fs from 'node:fs/promises';
4
- import * as path from 'node:path';
5
-
6
1
  // src/tree.ts
2
+ import { expectDefined } from "@wrongstack/core";
3
+ import * as fs from "node:fs/promises";
4
+ import * as path2 from "node:path";
5
+
6
+ // src/_util.ts
7
+ import * as path from "node:path";
8
+ import * as Core from "@wrongstack/core";
7
9
  function resolvePath(input, ctx) {
8
10
  return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);
9
11
  }
@@ -197,7 +199,7 @@ async function walkDir(dir, depth, opts) {
197
199
  opts.lines.push(opts.prefix + branch + displayName);
198
200
  if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {
199
201
  const childPrefix = opts.prefix + connector;
200
- await walkDir(path.join(dir, entry.name), depth + 1, {
202
+ await walkDir(path2.join(dir, entry.name), depth + 1, {
201
203
  ...opts,
202
204
  prefix: childPrefix,
203
205
  isLast
@@ -205,7 +207,7 @@ async function walkDir(dir, depth, opts) {
205
207
  }
206
208
  }
207
209
  }
208
-
209
- export { treeTool };
210
+ export {
211
+ treeTool
212
+ };
210
213
  //# sourceMappingURL=tree.js.map
211
- //# sourceMappingURL=tree.js.map
package/dist/tree.js.map CHANGED
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../src/_util.ts","../src/tree.ts"],"names":["path2"],"mappings":"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","file":"tree.js","sourcesContent":["import { createHash } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as Core from '@wrongstack/core';\nimport type { Context } from '@wrongstack/core';\n\n/**\n * sha-256 hex of a UTF-8 string. Used by the file tools to record a content\n * hash alongside the mtime in `ctx.recordRead` — the hash is the authoritative\n * staleness arbiter for `edit` (mtime has a 2 s tolerance window on Windows).\n */\nexport function sha256hex(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n/** Detected package manager for a project directory. */\nexport type PackageManager = 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Detect the project's package manager by inspecting lockfiles in `cwd`.\n * Order: pnpm → yarn → npm (default). Missing or unreadable directories fall\n * back to `npm` rather than throwing, so a `safeResolve`-checked cwd that\n * happens to be empty never aborts the tool.\n */\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(`${cwd}/pnpm-lock.yaml`);\n return 'pnpm';\n } catch {\n /* not pnpm */\n }\n try {\n await stat(`${cwd}/yarn.lock`);\n return 'yarn';\n } catch {\n /* not yarn */\n }\n return 'npm';\n}\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);\n}\n\n/**\n * Roots every file tool may always reach, even in restricted mode: the\n * project root and the user-global `~/.wrongstack` directory (config, memory,\n * sessions, skills). `~/.wrongstack` honors the `WRONGSTACK_HOME` override.\n */\nfunction allowedRoots(ctx: Context): string[] {\n return [path.resolve(ctx.projectRoot), path.resolve(Core.wstackGlobalRoot())];\n}\n\n/** True if `target` is `root` itself or nested inside any of `roots`. */\nfunction isInsideAny(target: string, roots: string[]): boolean {\n return roots.some((root) => {\n const rel = path.relative(root, target);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n });\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const target = path.resolve(absPath);\n // Unrestricted filesystem access: skip the project-root containment check.\n if (ctx.allowOutsideProjectRoot) return target;\n if (isInsideAny(target, allowedRoots(ctx))) return target;\n throw new Error(`Path \"${absPath}\" is outside project root \"${path.resolve(ctx.projectRoot)}\"`);\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\n/**\n * Defense against in-root→out-of-root symlink escape (CWE-59). `safeResolve`\n * only does a syntactic `../` check, so a symlink that lives *inside* the\n * project root but points outside still passes it. This resolves the path\n * through `fs.realpath` and re-verifies containment against the realpath of\n * the project root (comparing like-for-like, since the root itself may be a\n * symlink — macOS `/var`→`/private/var`, Windows 8.3 short names). For a path\n * that does not exist yet (e.g. a `write` to a new file) the nearest existing\n * ancestor directory is checked instead. Throws if the real target escapes.\n *\n * Mirrors the per-file guard already used in `replace.ts`/`grep.ts`; applied\n * to single-file `read`/`edit`/`write` it throws (rather than skips) because\n * the caller named exactly one file.\n */\nexport async function assertRealInsideRoot(absPath: string, ctx: Context): Promise<void> {\n // Unrestricted filesystem access: no symlink-escape check to perform.\n if (ctx.allowOutsideProjectRoot) return;\n // Compare like-for-like against the realpath of each always-allowed root\n // (project root + ~/.wrongstack), since a root may itself be a symlink.\n const realRoots = await Promise.all(\n allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r))),\n );\n let probe = absPath;\n for (;;) {\n let real: string;\n try {\n real = await fsp.realpath(probe);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const parent = path.dirname(probe);\n if (parent === probe) return; // reached fs root without escaping\n probe = parent;\n continue;\n }\n throw err;\n }\n if (isInsideAny(real, realRoots)) return;\n throw new Error(\n `Path \"${absPath}\" resolves through a symlink outside project root \"${realRoots[0]}\"`,\n );\n }\n}\n\n/** `safeResolve` + symlink realpath containment check. Async. */\nexport async function safeResolveReal(input: string, ctx: Context): Promise<string> {\n const abs = safeResolve(input, ctx);\n await assertRealInsideRoot(abs, ctx);\n return abs;\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n…[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]…\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n\n// ─── Command-output normalization (token-saving) ────────────────────────────\n//\n// Raw process output is full of tokens the model gains nothing from: ANSI\n// escapes, carriage-return progress spam, runs of identical warning lines, and\n// huge tails of build noise. These helpers strip that noise before the output\n// reaches the LLM. They are scoped to COMMAND tools (bash/git/exec and the\n// _spawn-stream consumers) — never applied to structured/code outputs.\n\n/** Unified byte cap for all command tool output fed to the model. */\nexport const COMMAND_OUTPUT_MAX_BYTES = 32_768;\n\n/** Runs of >= this many identical consecutive lines are collapsed. */\nconst REPEAT_RUN_THRESHOLD = 3;\n\n/**\n * Collapse carriage-return overwrites the way a terminal would: `\\r\\n` becomes\n * `\\n`, and a bare `\\r` (progress redraw) keeps only the text after the LAST\n * `\\r` on its physical line. Without this, a single progress bar that redraws\n * 200 times explodes into 200 lines.\n */\nexport function collapseCarriageReturns(text: string): string {\n const lf = text.replace(/\\r\\n/g, '\\n');\n if (!lf.includes('\\r')) return lf;\n return lf\n .split('\\n')\n .map((line) => (line.includes('\\r') ? line.slice(line.lastIndexOf('\\r') + 1) : line))\n .join('\\n');\n}\n\n/**\n * Collapse a run of `minRun`+ identical consecutive lines into the line once\n * plus a marker. Consecutive-only — it never reorders or dedups non-adjacent\n * lines, so diffs/source stay intact.\n */\nexport function collapseConsecutiveDuplicates(text: string, minRun = REPEAT_RUN_THRESHOLD): string {\n const lines = text.split('\\n');\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n let j = i + 1;\n while (j < lines.length && lines[j] === lines[i]) j++;\n const run = j - i;\n if (run >= minRun) {\n out.push(lines[i]!, `… ⟨repeated ${run}×⟩`);\n } else {\n for (let k = i; k < j; k++) out.push(lines[k]!);\n }\n i = j;\n }\n return out.join('\\n');\n}\n\n/** Largest prefix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeHeadBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(0, mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(0, lo);\n}\n\n/** Largest suffix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeTailBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(s.length - mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(s.length - lo);\n}\n\n/**\n * Truncate to `maxBytes` keeping BOTH ends — the head (what ran / early context)\n * and the tail (errors and summaries usually land last), biased ~45/55 toward\n * the tail. The result never exceeds `maxBytes`.\n */\nexport function truncateHeadTail(s: string, maxBytes: number): string {\n const total = Buffer.byteLength(s, 'utf8');\n if (total <= maxBytes) return s;\n // Reserve a fixed allowance for the marker so the final string can't exceed\n // the cap even though the dropped-byte count's digit width varies.\n const MARKER_RESERVE = 64;\n const avail = Math.max(0, maxBytes - MARKER_RESERVE);\n const headBudget = Math.floor(avail * 0.45);\n const head = takeHeadBytes(s, headBudget);\n const tail = takeTailBytes(s, avail - Buffer.byteLength(head, 'utf8'));\n const kept = Buffer.byteLength(head, 'utf8') + Buffer.byteLength(tail, 'utf8');\n return `${head}\\n…[truncated ${total - kept} bytes]…\\n${tail}`;\n}\n\n/**\n * Full token-saving pipeline for command tool output: strip ANSI → collapse\n * carriage-return progress → trim trailing whitespace → collapse identical\n * consecutive lines → squeeze blank-line runs → head+tail truncate to the cap.\n */\nexport function normalizeCommandOutput(\n raw: string,\n opts: { maxBytes?: number | undefined } = {},\n): string {\n if (!raw) return raw;\n let text = Core.stripAnsi(raw);\n text = collapseCarriageReturns(text);\n text = text.replace(/[ \\t]+$/gm, ''); // trailing whitespace per line\n text = collapseConsecutiveDuplicates(text);\n text = text.replace(/\\n{3,}/g, '\\n\\n'); // >=2 blank lines → 1\n return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);\n}\n","import { expectDefined } from '@wrongstack/core';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool, ToolProgressEvent, ToolStreamEvent } from '@wrongstack/core';\nimport { safeResolve } from './_util.js';\nconst DEFAULT_IGNORE = [\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n 'coverage',\n '__pycache__',\n '.wrongstack',\n '.ssh',\n '.gnupg',\n '.aws',\n];\n\ninterface TreeInput {\n path?: string | undefined;\n depth?: number | undefined;\n glob?: string | undefined;\n exclude?: string[] | undefined;\n show_files?: boolean | undefined;\n show_dirs?: boolean | undefined;\n show_hidden?: boolean | undefined;\n}\n\ninterface TreeOutput {\n tree: string;\n total_files: number;\n total_dirs: number;\n truncated: boolean;\n path: string;\n}\n\nexport const treeTool: Tool<TreeInput, TreeOutput> = {\n name: 'tree',\n category: 'Filesystem',\n description:\n 'Display a directory tree of the project (or a subpath). This is the recommended way to explore the high-level structure of a codebase before reading specific files.',\n usageHint:\n 'BEST PRACTICE FOR INITIAL EXPLORATION:\\n\\n' +\n '- Call early when working with an unfamiliar project or module.\\n' +\n '- Tune `depth` (default 3) and use `glob`/`exclude` to focus the view.\\n' +\n '- Prefer this over raw `bash find` or `glob` + manual reading when you need a quick structural overview.\\n' +\n 'Output is truncated for very large trees.',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'tree',\n timeoutMs: 15_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Root directory to display the tree from (defaults to project root).',\n },\n depth: {\n type: 'integer',\n description: 'Maximum directory depth to traverse (default 3, use 0 for unlimited).',\n minimum: 0,\n maximum: 20,\n },\n glob: {\n type: 'string',\n description: 'Only include files matching this glob pattern.',\n },\n exclude: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of directory names to completely ignore.',\n },\n show_files: {\n type: 'boolean',\n description: 'Whether to show individual files (default true).',\n },\n show_dirs: {\n type: 'boolean',\n description: 'Whether to show directories (default true).',\n },\n show_hidden: {\n type: 'boolean',\n description: 'Show hidden files starting with . (default: false)',\n },\n },\n },\n async execute(input, ctx, opts) {\n let final: TreeOutput | undefined;\n const executeStream = treeTool.executeStream;\n if (!executeStream) throw new Error('treeTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('tree: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx): AsyncGenerator<ToolStreamEvent<TreeOutput>> {\n const basePath = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const maxDepth = input.depth ?? 3;\n const showFiles = input.show_files ?? true;\n const showDirs = input.show_dirs ?? true;\n const showHidden = input.show_hidden ?? false;\n const exclude = new Set([...DEFAULT_IGNORE, ...(input.exclude ?? [])]);\n const filterGlob = input.glob;\n\n const lines: string[] = [basePath];\n const totals = { totalFiles: { value: 0 }, totalDirs: { value: 0 } };\n\n // Walker pushes progress into an async queue; the generator drains it.\n const queue: ToolProgressEvent[] = [];\n const FLUSH_EVERY = 200; // emit metric every 200 entries seen\n let lastEmittedTotal = 0;\n\n const tickProgress = () => {\n const seen = totals.totalFiles.value + totals.totalDirs.value;\n if (seen - lastEmittedTotal >= FLUSH_EVERY) {\n queue.push({\n type: 'metric',\n text: `${seen} entries`,\n data: { files: totals.totalFiles.value, dirs: totals.totalDirs.value },\n });\n lastEmittedTotal = seen;\n }\n };\n\n const walkPromise = walkDir(basePath, 0, {\n maxDepth,\n exclude,\n showFiles,\n showDirs,\n showHidden,\n filterGlob,\n lines,\n prefix: '',\n isLast: true,\n totalFiles: totals.totalFiles,\n totalDirs: totals.totalDirs,\n onProgress: tickProgress,\n });\n\n // Race the walk against periodic flushes — yield metrics while it runs.\n let walkDone = false;\n walkPromise.finally(() => {\n walkDone = true;\n });\n\n while (!walkDone || queue.length > 0) {\n if (queue.length > 0) {\n yield expectDefined(queue.shift());\n } else {\n // Race the walk completion against a short tick so we don't busy-\n // spin while the producer fills the queue. Previously the\n // setTimeout was never cleared when walkPromise won — one stray\n // timer per drain iteration accumulated on the event loop.\n let pollTimer: ReturnType<typeof setTimeout> | undefined;\n const poll = new Promise<void>((r) => {\n pollTimer = setTimeout(r, 50);\n });\n try {\n await Promise.race([walkPromise, poll]).catch(() => undefined);\n } finally {\n if (pollTimer) clearTimeout(pollTimer);\n }\n }\n }\n await walkPromise; // surface any error\n\n yield {\n type: 'final',\n output: {\n tree: lines.join('\\n'),\n total_files: totals.totalFiles.value,\n total_dirs: totals.totalDirs.value,\n truncated: false,\n path: basePath,\n },\n };\n },\n};\n\ninterface WalkOptions {\n maxDepth: number;\n exclude: Set<string>;\n showFiles: boolean;\n showDirs: boolean;\n showHidden: boolean;\n filterGlob?: string | undefined;\n lines: string[];\n prefix: string;\n isLast: boolean;\n totalFiles: { value: number };\n totalDirs: { value: number };\n onProgress?: (() => void) | undefined;\n}\n\nasync function walkDir(dir: string, depth: number, opts: WalkOptions): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => [] as import('node:fs').Dirent[]);\n\n const filtered = entries.filter((e) => {\n if (!opts.showHidden && e.name.startsWith('.')) return false;\n if (opts.exclude.has(e.name)) return false;\n return true;\n });\n\n if (depth > 0) {\n const dirCount = filtered.filter((e) => e.isDirectory()).length;\n const fileCount = filtered.filter((e) => e.isFile()).length;\n opts.totalDirs.value += dirCount;\n opts.totalFiles.value += fileCount;\n opts.onProgress?.();\n }\n\n const items = filtered.sort((a, b) => {\n if (a.isDirectory() && !b.isDirectory()) return -1;\n if (!a.isDirectory() && b.isDirectory()) return 1;\n return a.name.localeCompare(b.name);\n });\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i];\n /* v8 ignore next -- i is bounded by items.length, so entry is always defined; defensive. */\n if (!entry) continue;\n const isLast = i === items.length - 1;\n const connector = opts.isLast ? ' ' : '│ ';\n const branch = isLast ? '└── ' : '├── ';\n const displayName = entry.name + (entry.isDirectory() ? '/' : '');\n\n if (!opts.showDirs && entry.isDirectory()) continue;\n if (!opts.showFiles && entry.isFile()) continue;\n\n opts.lines.push(opts.prefix + branch + displayName);\n\n if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {\n const childPrefix = opts.prefix + connector;\n await walkDir(path.join(dir, entry.name), depth + 1, {\n ...opts,\n prefix: childPrefix,\n isLast,\n });\n }\n }\n}\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tree.ts", "../src/_util.ts"],
4
+ "sourcesContent": ["import { expectDefined } from '@wrongstack/core';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { Tool, ToolProgressEvent, ToolStreamEvent } from '@wrongstack/core';\nimport { safeResolve } from './_util.js';\nconst DEFAULT_IGNORE = [\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n 'coverage',\n '__pycache__',\n '.wrongstack',\n '.ssh',\n '.gnupg',\n '.aws',\n];\n\ninterface TreeInput {\n path?: string | undefined;\n depth?: number | undefined;\n glob?: string | undefined;\n exclude?: string[] | undefined;\n show_files?: boolean | undefined;\n show_dirs?: boolean | undefined;\n show_hidden?: boolean | undefined;\n}\n\ninterface TreeOutput {\n tree: string;\n total_files: number;\n total_dirs: number;\n truncated: boolean;\n path: string;\n}\n\nexport const treeTool: Tool<TreeInput, TreeOutput> = {\n name: 'tree',\n category: 'Filesystem',\n description:\n 'Display a directory tree of the project (or a subpath). This is the recommended way to explore the high-level structure of a codebase before reading specific files.',\n usageHint:\n 'BEST PRACTICE FOR INITIAL EXPLORATION:\\n\\n' +\n '- Call early when working with an unfamiliar project or module.\\n' +\n '- Tune `depth` (default 3) and use `glob`/`exclude` to focus the view.\\n' +\n '- Prefer this over raw `bash find` or `glob` + manual reading when you need a quick structural overview.\\n' +\n 'Output is truncated for very large trees.',\n permission: 'auto',\n mutating: false,\n capabilities: ['fs.read'],\n icon: 'tree',\n timeoutMs: 15_000,\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Root directory to display the tree from (defaults to project root).',\n },\n depth: {\n type: 'integer',\n description: 'Maximum directory depth to traverse (default 3, use 0 for unlimited).',\n minimum: 0,\n maximum: 20,\n },\n glob: {\n type: 'string',\n description: 'Only include files matching this glob pattern.',\n },\n exclude: {\n type: 'array',\n items: { type: 'string' },\n description: 'List of directory names to completely ignore.',\n },\n show_files: {\n type: 'boolean',\n description: 'Whether to show individual files (default true).',\n },\n show_dirs: {\n type: 'boolean',\n description: 'Whether to show directories (default true).',\n },\n show_hidden: {\n type: 'boolean',\n description: 'Show hidden files starting with . (default: false)',\n },\n },\n },\n async execute(input, ctx, opts) {\n let final: TreeOutput | undefined;\n const executeStream = treeTool.executeStream;\n if (!executeStream) throw new Error('treeTool: stream execution unavailable');\n for await (const ev of executeStream(input, ctx, opts)) {\n if (ev.type === 'final') final = ev.output;\n }\n if (!final) throw new Error('tree: stream ended without final event');\n return final;\n },\n async *executeStream(input, ctx): AsyncGenerator<ToolStreamEvent<TreeOutput>> {\n const basePath = input.path ? safeResolve(input.path, ctx) : ctx.cwd;\n const maxDepth = input.depth ?? 3;\n const showFiles = input.show_files ?? true;\n const showDirs = input.show_dirs ?? true;\n const showHidden = input.show_hidden ?? false;\n const exclude = new Set([...DEFAULT_IGNORE, ...(input.exclude ?? [])]);\n const filterGlob = input.glob;\n\n const lines: string[] = [basePath];\n const totals = { totalFiles: { value: 0 }, totalDirs: { value: 0 } };\n\n // Walker pushes progress into an async queue; the generator drains it.\n const queue: ToolProgressEvent[] = [];\n const FLUSH_EVERY = 200; // emit metric every 200 entries seen\n let lastEmittedTotal = 0;\n\n const tickProgress = () => {\n const seen = totals.totalFiles.value + totals.totalDirs.value;\n if (seen - lastEmittedTotal >= FLUSH_EVERY) {\n queue.push({\n type: 'metric',\n text: `${seen} entries`,\n data: { files: totals.totalFiles.value, dirs: totals.totalDirs.value },\n });\n lastEmittedTotal = seen;\n }\n };\n\n const walkPromise = walkDir(basePath, 0, {\n maxDepth,\n exclude,\n showFiles,\n showDirs,\n showHidden,\n filterGlob,\n lines,\n prefix: '',\n isLast: true,\n totalFiles: totals.totalFiles,\n totalDirs: totals.totalDirs,\n onProgress: tickProgress,\n });\n\n // Race the walk against periodic flushes \u2014 yield metrics while it runs.\n let walkDone = false;\n walkPromise.finally(() => {\n walkDone = true;\n });\n\n while (!walkDone || queue.length > 0) {\n if (queue.length > 0) {\n yield expectDefined(queue.shift());\n } else {\n // Race the walk completion against a short tick so we don't busy-\n // spin while the producer fills the queue. Previously the\n // setTimeout was never cleared when walkPromise won \u2014 one stray\n // timer per drain iteration accumulated on the event loop.\n let pollTimer: ReturnType<typeof setTimeout> | undefined;\n const poll = new Promise<void>((r) => {\n pollTimer = setTimeout(r, 50);\n });\n try {\n await Promise.race([walkPromise, poll]).catch(() => undefined);\n } finally {\n if (pollTimer) clearTimeout(pollTimer);\n }\n }\n }\n await walkPromise; // surface any error\n\n yield {\n type: 'final',\n output: {\n tree: lines.join('\\n'),\n total_files: totals.totalFiles.value,\n total_dirs: totals.totalDirs.value,\n truncated: false,\n path: basePath,\n },\n };\n },\n};\n\ninterface WalkOptions {\n maxDepth: number;\n exclude: Set<string>;\n showFiles: boolean;\n showDirs: boolean;\n showHidden: boolean;\n filterGlob?: string | undefined;\n lines: string[];\n prefix: string;\n isLast: boolean;\n totalFiles: { value: number };\n totalDirs: { value: number };\n onProgress?: (() => void) | undefined;\n}\n\nasync function walkDir(dir: string, depth: number, opts: WalkOptions): Promise<void> {\n const entries = await fs\n .readdir(dir, { withFileTypes: true })\n .catch(() => [] as import('node:fs').Dirent[]);\n\n const filtered = entries.filter((e) => {\n if (!opts.showHidden && e.name.startsWith('.')) return false;\n if (opts.exclude.has(e.name)) return false;\n return true;\n });\n\n if (depth > 0) {\n const dirCount = filtered.filter((e) => e.isDirectory()).length;\n const fileCount = filtered.filter((e) => e.isFile()).length;\n opts.totalDirs.value += dirCount;\n opts.totalFiles.value += fileCount;\n opts.onProgress?.();\n }\n\n const items = filtered.sort((a, b) => {\n if (a.isDirectory() && !b.isDirectory()) return -1;\n if (!a.isDirectory() && b.isDirectory()) return 1;\n return a.name.localeCompare(b.name);\n });\n\n for (let i = 0; i < items.length; i++) {\n const entry = items[i];\n /* v8 ignore next -- i is bounded by items.length, so entry is always defined; defensive. */\n if (!entry) continue;\n const isLast = i === items.length - 1;\n const connector = opts.isLast ? ' ' : '\u2502 ';\n const branch = isLast ? '\u2514\u2500\u2500 ' : '\u251C\u2500\u2500 ';\n const displayName = entry.name + (entry.isDirectory() ? '/' : '');\n\n if (!opts.showDirs && entry.isDirectory()) continue;\n if (!opts.showFiles && entry.isFile()) continue;\n\n opts.lines.push(opts.prefix + branch + displayName);\n\n if (entry.isDirectory() && (opts.maxDepth === 0 || depth < opts.maxDepth)) {\n const childPrefix = opts.prefix + connector;\n await walkDir(path.join(dir, entry.name), depth + 1, {\n ...opts,\n prefix: childPrefix,\n isLast,\n });\n }\n }\n}\n", "import { createHash } from 'node:crypto';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as Core from '@wrongstack/core';\nimport type { Context } from '@wrongstack/core';\n\n/**\n * sha-256 hex of a UTF-8 string. Used by the file tools to record a content\n * hash alongside the mtime in `ctx.recordRead` \u2014 the hash is the authoritative\n * staleness arbiter for `edit` (mtime has a 2 s tolerance window on Windows).\n */\nexport function sha256hex(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n/** Detected package manager for a project directory. */\nexport type PackageManager = 'pnpm' | 'yarn' | 'npm';\n\n/**\n * Detect the project's package manager by inspecting lockfiles in `cwd`.\n * Order: pnpm \u2192 yarn \u2192 npm (default). Missing or unreadable directories fall\n * back to `npm` rather than throwing, so a `safeResolve`-checked cwd that\n * happens to be empty never aborts the tool.\n */\nexport async function detectPackageManager(cwd: string): Promise<PackageManager> {\n const { stat } = await import('node:fs/promises');\n try {\n await stat(`${cwd}/pnpm-lock.yaml`);\n return 'pnpm';\n } catch {\n /* not pnpm */\n }\n try {\n await stat(`${cwd}/yarn.lock`);\n return 'yarn';\n } catch {\n /* not yarn */\n }\n return 'npm';\n}\n\nexport function resolvePath(input: string, ctx: Context): string {\n return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.workingDir ?? ctx.cwd, input);\n}\n\n/**\n * Roots every file tool may always reach, even in restricted mode: the\n * project root and the user-global `~/.wrongstack` directory (config, memory,\n * sessions, skills). `~/.wrongstack` honors the `WRONGSTACK_HOME` override.\n */\nfunction allowedRoots(ctx: Context): string[] {\n return [path.resolve(ctx.projectRoot), path.resolve(Core.wstackGlobalRoot())];\n}\n\n/** True if `target` is `root` itself or nested inside any of `roots`. */\nfunction isInsideAny(target: string, roots: string[]): boolean {\n return roots.some((root) => {\n const rel = path.relative(root, target);\n return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));\n });\n}\n\nexport function ensureInsideRoot(absPath: string, ctx: Context): string {\n const target = path.resolve(absPath);\n // Unrestricted filesystem access: skip the project-root containment check.\n if (ctx.allowOutsideProjectRoot) return target;\n if (isInsideAny(target, allowedRoots(ctx))) return target;\n throw new Error(`Path \"${absPath}\" is outside project root \"${path.resolve(ctx.projectRoot)}\"`);\n}\n\nexport function safeResolve(input: string, ctx: Context): string {\n return ensureInsideRoot(resolvePath(input, ctx), ctx);\n}\n\n/**\n * Defense against in-root\u2192out-of-root symlink escape (CWE-59). `safeResolve`\n * only does a syntactic `../` check, so a symlink that lives *inside* the\n * project root but points outside still passes it. This resolves the path\n * through `fs.realpath` and re-verifies containment against the realpath of\n * the project root (comparing like-for-like, since the root itself may be a\n * symlink \u2014 macOS `/var`\u2192`/private/var`, Windows 8.3 short names). For a path\n * that does not exist yet (e.g. a `write` to a new file) the nearest existing\n * ancestor directory is checked instead. Throws if the real target escapes.\n *\n * Mirrors the per-file guard already used in `replace.ts`/`grep.ts`; applied\n * to single-file `read`/`edit`/`write` it throws (rather than skips) because\n * the caller named exactly one file.\n */\nexport async function assertRealInsideRoot(absPath: string, ctx: Context): Promise<void> {\n // Unrestricted filesystem access: no symlink-escape check to perform.\n if (ctx.allowOutsideProjectRoot) return;\n // Compare like-for-like against the realpath of each always-allowed root\n // (project root + ~/.wrongstack), since a root may itself be a symlink.\n const realRoots = await Promise.all(\n allowedRoots(ctx).map((r) => fsp.realpath(r).catch(() => path.resolve(r))),\n );\n let probe = absPath;\n for (;;) {\n let real: string;\n try {\n real = await fsp.realpath(probe);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n const parent = path.dirname(probe);\n if (parent === probe) return; // reached fs root without escaping\n probe = parent;\n continue;\n }\n throw err;\n }\n if (isInsideAny(real, realRoots)) return;\n throw new Error(\n `Path \"${absPath}\" resolves through a symlink outside project root \"${realRoots[0]}\"`,\n );\n }\n}\n\n/** `safeResolve` + symlink realpath containment check. Async. */\nexport async function safeResolveReal(input: string, ctx: Context): Promise<string> {\n const abs = safeResolve(input, ctx);\n await assertRealInsideRoot(abs, ctx);\n return abs;\n}\n\nexport function truncateMiddle(s: string, max: number): string {\n if (Buffer.byteLength(s, 'utf8') <= max) return s;\n const half = Math.floor(max / 2);\n return (\n s.slice(0, half) +\n `\\n\u2026[truncated ${Buffer.byteLength(s, 'utf8') - max} bytes from middle]\u2026\\n` +\n s.slice(-half)\n );\n}\n\nexport function isBinaryBuffer(buf: Buffer): boolean {\n const len = Math.min(buf.length, 8192);\n for (let i = 0; i < len; i++) {\n if (buf[i] === 0) return true;\n }\n return false;\n}\n\n// \u2500\u2500\u2500 Command-output normalization (token-saving) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// Raw process output is full of tokens the model gains nothing from: ANSI\n// escapes, carriage-return progress spam, runs of identical warning lines, and\n// huge tails of build noise. These helpers strip that noise before the output\n// reaches the LLM. They are scoped to COMMAND tools (bash/git/exec and the\n// _spawn-stream consumers) \u2014 never applied to structured/code outputs.\n\n/** Unified byte cap for all command tool output fed to the model. */\nexport const COMMAND_OUTPUT_MAX_BYTES = 32_768;\n\n/** Runs of >= this many identical consecutive lines are collapsed. */\nconst REPEAT_RUN_THRESHOLD = 3;\n\n/**\n * Collapse carriage-return overwrites the way a terminal would: `\\r\\n` becomes\n * `\\n`, and a bare `\\r` (progress redraw) keeps only the text after the LAST\n * `\\r` on its physical line. Without this, a single progress bar that redraws\n * 200 times explodes into 200 lines.\n */\nexport function collapseCarriageReturns(text: string): string {\n const lf = text.replace(/\\r\\n/g, '\\n');\n if (!lf.includes('\\r')) return lf;\n return lf\n .split('\\n')\n .map((line) => (line.includes('\\r') ? line.slice(line.lastIndexOf('\\r') + 1) : line))\n .join('\\n');\n}\n\n/**\n * Collapse a run of `minRun`+ identical consecutive lines into the line once\n * plus a marker. Consecutive-only \u2014 it never reorders or dedups non-adjacent\n * lines, so diffs/source stay intact.\n */\nexport function collapseConsecutiveDuplicates(text: string, minRun = REPEAT_RUN_THRESHOLD): string {\n const lines = text.split('\\n');\n const out: string[] = [];\n let i = 0;\n while (i < lines.length) {\n let j = i + 1;\n while (j < lines.length && lines[j] === lines[i]) j++;\n const run = j - i;\n if (run >= minRun) {\n out.push(lines[i]!, `\u2026 \u27E8repeated ${run}\u00D7\u27E9`);\n } else {\n for (let k = i; k < j; k++) out.push(lines[k]!);\n }\n i = j;\n }\n return out.join('\\n');\n}\n\n/** Largest prefix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeHeadBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(0, mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(0, lo);\n}\n\n/** Largest suffix of `s` whose UTF-8 byte length is <= `maxBytes`. */\nfunction takeTailBytes(s: string, maxBytes: number): string {\n if (maxBytes <= 0) return '';\n /* v8 ignore next -- only caller (truncateHeadTail) passes a budget smaller than s; defensive. */\n if (Buffer.byteLength(s, 'utf8') <= maxBytes) return s;\n let lo = 0;\n let hi = s.length;\n while (lo < hi) {\n const mid = Math.ceil((lo + hi) / 2);\n if (Buffer.byteLength(s.slice(s.length - mid), 'utf8') <= maxBytes) lo = mid;\n else hi = mid - 1;\n }\n return s.slice(s.length - lo);\n}\n\n/**\n * Truncate to `maxBytes` keeping BOTH ends \u2014 the head (what ran / early context)\n * and the tail (errors and summaries usually land last), biased ~45/55 toward\n * the tail. The result never exceeds `maxBytes`.\n */\nexport function truncateHeadTail(s: string, maxBytes: number): string {\n const total = Buffer.byteLength(s, 'utf8');\n if (total <= maxBytes) return s;\n // Reserve a fixed allowance for the marker so the final string can't exceed\n // the cap even though the dropped-byte count's digit width varies.\n const MARKER_RESERVE = 64;\n const avail = Math.max(0, maxBytes - MARKER_RESERVE);\n const headBudget = Math.floor(avail * 0.45);\n const head = takeHeadBytes(s, headBudget);\n const tail = takeTailBytes(s, avail - Buffer.byteLength(head, 'utf8'));\n const kept = Buffer.byteLength(head, 'utf8') + Buffer.byteLength(tail, 'utf8');\n return `${head}\\n\u2026[truncated ${total - kept} bytes]\u2026\\n${tail}`;\n}\n\n/**\n * Full token-saving pipeline for command tool output: strip ANSI \u2192 collapse\n * carriage-return progress \u2192 trim trailing whitespace \u2192 collapse identical\n * consecutive lines \u2192 squeeze blank-line runs \u2192 head+tail truncate to the cap.\n */\nexport function normalizeCommandOutput(\n raw: string,\n opts: { maxBytes?: number | undefined } = {},\n): string {\n if (!raw) return raw;\n let text = Core.stripAnsi(raw);\n text = collapseCarriageReturns(text);\n text = text.replace(/[ \\t]+$/gm, ''); // trailing whitespace per line\n text = collapseConsecutiveDuplicates(text);\n text = text.replace(/\\n{3,}/g, '\\n\\n'); // >=2 blank lines \u2192 1\n return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["path"]
7
+ }
@@ -1,5 +1,4 @@
1
- import { Tool } from '@wrongstack/core';
2
-
1
+ import type { Tool } from '@wrongstack/core';
3
2
  interface TypecheckInput {
4
3
  project?: string | undefined;
5
4
  cwd?: string | undefined;
@@ -16,6 +15,6 @@ interface TypecheckOutput {
16
15
  output: string;
17
16
  truncated: boolean;
18
17
  }
19
- declare const typecheckTool: Tool<TypecheckInput, TypecheckOutput>;
20
-
21
- export { typecheckTool };
18
+ export declare const typecheckTool: Tool<TypecheckInput, TypecheckOutput>;
19
+ export {};
20
+ //# sourceMappingURL=typecheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typecheck.d.ts","sourceRoot":"","sources":["../src/typecheck.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAmB,MAAM,kBAAkB,CAAC;AAK9D,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5B;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,cAAc,EAAE,eAAe,CA6G/D,CAAC"}