@wrongstack/tools 0.1.10 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +1 -1
  2. package/dist/audit.js +1 -0
  3. package/dist/audit.js.map +1 -1
  4. package/dist/bash.js +1 -0
  5. package/dist/bash.js.map +1 -1
  6. package/dist/batch-tool-use.js +2 -1
  7. package/dist/batch-tool-use.js.map +1 -1
  8. package/dist/builtin.js +161 -10
  9. package/dist/builtin.js.map +1 -1
  10. package/dist/diff.js +1 -0
  11. package/dist/diff.js.map +1 -1
  12. package/dist/document.js +1 -0
  13. package/dist/document.js.map +1 -1
  14. package/dist/edit.js +1 -0
  15. package/dist/edit.js.map +1 -1
  16. package/dist/exec.js +2 -1
  17. package/dist/exec.js.map +1 -1
  18. package/dist/fetch.js +1 -0
  19. package/dist/fetch.js.map +1 -1
  20. package/dist/format.js +1 -0
  21. package/dist/format.js.map +1 -1
  22. package/dist/git.js +1 -0
  23. package/dist/git.js.map +1 -1
  24. package/dist/glob.js +1 -0
  25. package/dist/glob.js.map +1 -1
  26. package/dist/grep.js +18 -1
  27. package/dist/grep.js.map +1 -1
  28. package/dist/index.d.ts +38 -1
  29. package/dist/index.js +172 -11
  30. package/dist/index.js.map +1 -1
  31. package/dist/install.js +1 -0
  32. package/dist/install.js.map +1 -1
  33. package/dist/json.js +1 -0
  34. package/dist/json.js.map +1 -1
  35. package/dist/lint.js +1 -0
  36. package/dist/lint.js.map +1 -1
  37. package/dist/logs.js +1 -0
  38. package/dist/logs.js.map +1 -1
  39. package/dist/memory.js +2 -0
  40. package/dist/memory.js.map +1 -1
  41. package/dist/mode.js +1 -0
  42. package/dist/mode.js.map +1 -1
  43. package/dist/outdated.js +1 -0
  44. package/dist/outdated.js.map +1 -1
  45. package/dist/pack.d.ts +9 -0
  46. package/dist/pack.js +4216 -0
  47. package/dist/pack.js.map +1 -0
  48. package/dist/patch.js +1 -0
  49. package/dist/patch.js.map +1 -1
  50. package/dist/read.js +1 -0
  51. package/dist/read.js.map +1 -1
  52. package/dist/replace.js +12 -5
  53. package/dist/replace.js.map +1 -1
  54. package/dist/scaffold.js +1 -0
  55. package/dist/scaffold.js.map +1 -1
  56. package/dist/search.js +1 -0
  57. package/dist/search.js.map +1 -1
  58. package/dist/test.js +1 -0
  59. package/dist/test.js.map +1 -1
  60. package/dist/todo.js +1 -0
  61. package/dist/todo.js.map +1 -1
  62. package/dist/tool-help.js +1 -0
  63. package/dist/tool-help.js.map +1 -1
  64. package/dist/tool-search.js +1 -0
  65. package/dist/tool-search.js.map +1 -1
  66. package/dist/tool-use.js +2 -1
  67. package/dist/tool-use.js.map +1 -1
  68. package/dist/tree.js +1 -0
  69. package/dist/tree.js.map +1 -1
  70. package/dist/typecheck.js +1 -0
  71. package/dist/typecheck.js.map +1 -1
  72. package/dist/write.js +1 -0
  73. package/dist/write.js.map +1 -1
  74. package/package.json +6 -2
package/dist/builtin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { spawn } from 'child_process';
2
- import { buildChildEnv, stripAnsi, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, compileGlob } from '@wrongstack/core';
2
+ import { buildChildEnv, stripAnsi, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, compileGlob, loadPlan, emptyPlan, clearPlan, savePlan, removePlanItem, setPlanItemStatus, addPlanItem, formatPlan } from '@wrongstack/core';
3
3
  import * as path from 'path';
4
4
  import { dirname } from 'path';
5
5
  import * as os from 'os';
@@ -125,6 +125,7 @@ function isBinaryBuffer(buf) {
125
125
  // src/audit.ts
126
126
  var auditTool = {
127
127
  name: "audit",
128
+ category: "Package Management",
128
129
  description: "Run npm/pnpm security audit. Returns vulnerabilities sorted by severity.",
129
130
  usageHint: "Set `level` to filter minimum severity. `fix` attempts auto-fix. `packages` checks specific packages.",
130
131
  permission: "confirm",
@@ -238,6 +239,7 @@ var STREAM_FLUSH_INTERVAL_MS = 200;
238
239
  var STREAM_FLUSH_BYTES = 4 * 1024;
239
240
  var bashTool = {
240
241
  name: "bash",
242
+ category: "Shell",
241
243
  description: "Run a shell command. stdout and stderr are merged.",
242
244
  usageHint: "Runs via `bash -c` (or `cmd /c` on Windows). Cwd is the project root. Default timeout 30s. Output truncated from the middle if oversized. Use for git, npm, builds, tests.",
243
245
  permission: "confirm",
@@ -417,10 +419,11 @@ var bashTool = {
417
419
  // src/batch-tool-use.ts
418
420
  var batchToolUseTool = {
419
421
  name: "batch_tool_use",
422
+ category: "Meta",
420
423
  description: "Execute multiple tool calls in sequence or parallel. Returns all results.",
421
424
  usageHint: "Set `calls` array with tool names and inputs. `stop_on_error` halts on first failure. `parallel` runs concurrently (default: true).",
422
425
  permission: "confirm",
423
- mutating: false,
426
+ mutating: true,
424
427
  timeoutMs: 12e4,
425
428
  inputSchema: {
426
429
  type: "object",
@@ -518,6 +521,7 @@ async function executeSingle(call, ctx, opts) {
518
521
  }
519
522
  var diffTool = {
520
523
  name: "diff",
524
+ category: "Filesystem",
521
525
  description: "Show differences between files, commits, or branches. Supports staged vs working tree.",
522
526
  usageHint: "Use `files` for file paths, `a`/`b` for commit refs, `staged` for git index. `mode`: unified (default), stat, side-by-side.",
523
527
  permission: "auto",
@@ -634,6 +638,7 @@ function formatUnified(lines, context) {
634
638
  }
635
639
  var documentTool = {
636
640
  name: "document",
641
+ category: "Project",
637
642
  description: "Generate or update documentation comments for functions, classes, and types. Supports JSDoc, TSDoc, and block comments.",
638
643
  usageHint: "Set `target` for what to document. `files` for paths. `style` for comment format. `overwrite` replaces existing docs.",
639
644
  permission: "confirm",
@@ -782,6 +787,7 @@ function processFile(content, absPath, style, overwrite, target) {
782
787
  }
783
788
  var editTool = {
784
789
  name: "edit",
790
+ category: "Filesystem",
785
791
  description: "Make a surgical edit by replacing exact text. Fails if `old_string` is not unique unless `replace_all` is true.",
786
792
  usageHint: "Always `read` the file first. `old_string` must be an EXACT match (whitespace included). If multiple matches exist, either narrow `old_string` with more context or set `replace_all: true`.",
787
793
  permission: "confirm",
@@ -938,10 +944,11 @@ var MAX_OUTPUT2 = 2e5;
938
944
  var TIMEOUT_MS = 3e4;
939
945
  var execTool = {
940
946
  name: "exec",
947
+ category: "Shell",
941
948
  description: "Restricted shell that only runs pre-approved commands with constrained arguments. Safer alternative to `bash`.",
942
949
  usageHint: "Set `command` (must be in allowlist). `args` passed through. For arbitrary shell access use the `bash` tool instead.",
943
950
  permission: "confirm",
944
- mutating: false,
951
+ mutating: true,
945
952
  timeoutMs: TIMEOUT_MS,
946
953
  inputSchema: {
947
954
  type: "object",
@@ -1083,6 +1090,7 @@ async function fetchWithRedirectLimit(url, maxRedirects, signal) {
1083
1090
  }
1084
1091
  var fetchTool = {
1085
1092
  name: "fetch",
1093
+ category: "Network",
1086
1094
  description: "Fetch the contents of a URL. HTML is converted to markdown by default.",
1087
1095
  usageHint: "HTTPS only by default. Localhost and RFC1918 ranges blocked unless WRONGSTACK_FETCH_ALLOW_PRIVATE=1. Max 5 redirects, 20s timeout, 128KB cap.",
1088
1096
  permission: "confirm",
@@ -1331,6 +1339,7 @@ function stripTags(s) {
1331
1339
  // src/format.ts
1332
1340
  var formatTool = {
1333
1341
  name: "format",
1342
+ category: "Code Quality",
1334
1343
  description: "Format files with biome or prettier. Use `check` to verify without modifying.",
1335
1344
  usageHint: "Set `files` (glob or comma-separated). `check` only validates. `fixer` forces tool.",
1336
1345
  permission: "confirm",
@@ -1429,6 +1438,7 @@ var TIMEOUT_MS3 = 3e4;
1429
1438
  var MAX_OUTPUT3 = 1e5;
1430
1439
  var gitTool = {
1431
1440
  name: "git",
1441
+ category: "Git",
1432
1442
  description: "Run git commands. Wraps common operations: status, log, diff, commit, branch, checkout, stash, push, pull, fetch, reset.",
1433
1443
  usageHint: "Prefer built-in subcommands over raw args. `command` is required. `message` for commits. `branch` for checkout/branch. `files` for status/diff. `format` for log.",
1434
1444
  permission: "confirm",
@@ -1593,6 +1603,7 @@ function runGit2(args, cwd, signal) {
1593
1603
  var DEFAULT_IGNORE = ["node_modules", ".git", "dist", "build", ".next", "coverage", ".turbo"];
1594
1604
  var globTool = {
1595
1605
  name: "glob",
1606
+ category: "Filesystem",
1596
1607
  description: "Find files matching a glob pattern. Returns paths sorted by mtime (newest first).",
1597
1608
  usageHint: "Examples: `**/*.ts`, `src/**/*.test.ts`, `*.json`. Common dirs (node_modules, .git, dist) are ignored by default. Returns up to 1000 paths.",
1598
1609
  permission: "auto",
@@ -1709,6 +1720,7 @@ function capSubject(line) {
1709
1720
  var DEFAULT_IGNORE2 = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
1710
1721
  var grepTool = {
1711
1722
  name: "grep",
1723
+ category: "Search",
1712
1724
  description: "Search file contents with a regex. Uses ripgrep when available.",
1713
1725
  usageHint: 'Pattern is regex. Use `output_mode: "content"` for matched lines, `"files_with_matches"` for paths, `"count"` for tallies. `glob` filters files (e.g. `*.ts`).',
1714
1726
  permission: "auto",
@@ -1741,6 +1753,10 @@ var grepTool = {
1741
1753
  const base = input.path ? safeResolve(input.path, ctx) : ctx.cwd;
1742
1754
  const mode = input.output_mode ?? "content";
1743
1755
  const limit = Math.max(1, Math.min(input.limit ?? 200, 2e3));
1756
+ const validation = compileUserRegex(input.pattern, input.case_insensitive ? "i" : "");
1757
+ if (!validation.ok) {
1758
+ throw new Error(`grep: ${validation.reason}`);
1759
+ }
1744
1760
  const rgAvailable = await detectRg(opts.signal);
1745
1761
  if (rgAvailable) {
1746
1762
  try {
@@ -1774,11 +1790,15 @@ async function* runRgStream(input, base, mode, limit, signal) {
1774
1790
  args.push("-n");
1775
1791
  if (input.context_lines) args.push("-C", String(input.context_lines));
1776
1792
  }
1793
+ for (const ignored of DEFAULT_IGNORE2) {
1794
+ args.push("--glob", `!${ignored}/**`, "--glob", `!**/${ignored}/**`);
1795
+ }
1777
1796
  if (input.glob) args.push("--glob", input.glob);
1778
1797
  args.push("--", input.pattern, base);
1779
1798
  const matches = [];
1780
1799
  let buf = "";
1781
1800
  let totalLines = 0;
1801
+ let totalCount = 0;
1782
1802
  let batchSinceFlush = 0;
1783
1803
  const FLUSH_AT = 16;
1784
1804
  const MAX_BUF_BYTES = 1e6;
@@ -1835,6 +1855,7 @@ async function* runRgStream(input, base, mode, limit, signal) {
1835
1855
  for (const line of ready.split("\n")) {
1836
1856
  if (!line) continue;
1837
1857
  totalLines++;
1858
+ if (mode === "count") totalCount += parseRgCountLine(line);
1838
1859
  if (matches.length < limit) {
1839
1860
  matches.push(line);
1840
1861
  pendingBatch.push(line);
@@ -1855,6 +1876,7 @@ async function* runRgStream(input, base, mode, limit, signal) {
1855
1876
  for (const line of buf.split("\n")) {
1856
1877
  if (!line) continue;
1857
1878
  totalLines++;
1879
+ if (mode === "count") totalCount += parseRgCountLine(line);
1858
1880
  if (matches.length < limit) {
1859
1881
  matches.push(line);
1860
1882
  pendingBatch.push(line);
@@ -1873,12 +1895,18 @@ async function* runRgStream(input, base, mode, limit, signal) {
1873
1895
  type: "final",
1874
1896
  output: {
1875
1897
  matches,
1876
- count: totalLines,
1898
+ count: mode === "count" ? totalCount : totalLines,
1877
1899
  truncated: totalLines > limit || bufOverflow,
1878
1900
  used: "rg"
1879
1901
  }
1880
1902
  };
1881
1903
  }
1904
+ function parseRgCountLine(line) {
1905
+ const idx = line.lastIndexOf(":");
1906
+ if (idx === -1) return 0;
1907
+ const n = Number.parseInt(line.slice(idx + 1), 10);
1908
+ return Number.isFinite(n) ? n : 0;
1909
+ }
1882
1910
  async function runNative(input, base, mode, limit, signal) {
1883
1911
  const flags = input.case_insensitive ? "i" : "";
1884
1912
  const compiled = compileUserRegex(input.pattern, flags);
@@ -1955,6 +1983,7 @@ async function runNative(input, base, mode, limit, signal) {
1955
1983
  // src/install.ts
1956
1984
  var installTool = {
1957
1985
  name: "install",
1986
+ category: "Package Management",
1958
1987
  description: "Install npm packages. Detects pnpm/npm/yarn and uses the right package manager.",
1959
1988
  usageHint: "Set `packages` to install. `save` as dependency type. `global` for global install. `dry_run` to preview.",
1960
1989
  permission: "confirm",
@@ -2048,6 +2077,7 @@ async function detectPackageManager(cwd) {
2048
2077
  }
2049
2078
  var jsonTool = {
2050
2079
  name: "json",
2080
+ category: "Data",
2051
2081
  description: "Parse, query, and validate JSON/JSON5/YAML. Use `query` with JMESPath-like paths to extract values.",
2052
2082
  usageHint: 'Provide `file` path or `data` string. `query` supports dot notation (e.g. "results[0].name"). `format` outputs in specified format.',
2053
2083
  permission: "auto",
@@ -2170,6 +2200,7 @@ function toYaml(data, indent = 0) {
2170
2200
  // src/lint.ts
2171
2201
  var lintTool = {
2172
2202
  name: "lint",
2203
+ category: "Code Quality",
2173
2204
  description: "Run a linter on files. Auto-detects biome, eslint, or tslint. Use `fix` to auto-fix issues.",
2174
2205
  usageHint: "Set `files` (glob or comma-separated). `fix` applies corrections. `linter` forces specific tool.",
2175
2206
  permission: "confirm",
@@ -2259,6 +2290,7 @@ async function detectLinter(cwd) {
2259
2290
  }
2260
2291
  var logsTool = {
2261
2292
  name: "logs",
2293
+ category: "Logs",
2262
2294
  description: "Stream or fetch logs from a service or file. Supports Docker, systemd, or plain log files.",
2263
2295
  usageHint: "Set `service` for Docker/systemd, `path` for file. `lines` limits output. `stream` for tail -f behavior. `filter` regex filters lines.",
2264
2296
  permission: "confirm",
@@ -2436,6 +2468,7 @@ function parseLine(line) {
2436
2468
  }
2437
2469
  var outdatedTool = {
2438
2470
  name: "outdated",
2471
+ category: "Package Management",
2439
2472
  description: "Check for outdated npm packages. Shows current, wanted, and latest versions.",
2440
2473
  usageHint: "Set `check` to filter specific packages. `format` as list or table. `include_deprecated` shows deprecated packages.",
2441
2474
  permission: "auto",
@@ -2547,6 +2580,7 @@ function parseOutdatedOutput(json, exitCode) {
2547
2580
  }
2548
2581
  var patchTool = {
2549
2582
  name: "patch",
2583
+ category: "Filesystem",
2550
2584
  description: "Apply a unified diff patch to files. Writes .orig and .rej files on failure.",
2551
2585
  usageHint: "Set `patch` (the diff text). `directory` defaults to cwd. `strip` removes leading path components. `dry_run` previews.",
2552
2586
  permission: "confirm",
@@ -2653,9 +2687,108 @@ function extractPatchedFiles(output) {
2653
2687
  }
2654
2688
  return files;
2655
2689
  }
2690
+ var planTool = {
2691
+ name: "plan",
2692
+ category: "Session",
2693
+ description: "Inspect or edit the strategic plan board for this session. Plans persist across resume (unlike todos). Use this to lay out the multi-step approach before diving in, then mark steps in_progress/done as the work proceeds.",
2694
+ usageHint: "Set action to one of: show | add | start | done | remove | clear. Pass `title` for add. Pass `target` (item id, 1-based index, or title substring) for start/done/remove. Always returns the formatted plan plus open/total counts.",
2695
+ permission: "auto",
2696
+ mutating: false,
2697
+ timeoutMs: 2e3,
2698
+ inputSchema: {
2699
+ type: "object",
2700
+ properties: {
2701
+ action: {
2702
+ type: "string",
2703
+ enum: ["show", "add", "start", "done", "remove", "clear"]
2704
+ },
2705
+ title: { type: "string", description: "Required when action = add." },
2706
+ details: { type: "string", description: "Optional extra context for add." },
2707
+ target: {
2708
+ type: "string",
2709
+ description: "Plan item id, 1-based index, or title substring. Required for start/done/remove."
2710
+ }
2711
+ },
2712
+ required: ["action"]
2713
+ },
2714
+ async execute(input, ctx) {
2715
+ const planPath = ctx.meta["plan.path"];
2716
+ if (typeof planPath !== "string" || !planPath) {
2717
+ return {
2718
+ ok: false,
2719
+ message: "Plan storage path is not configured for this session.",
2720
+ plan: "",
2721
+ count: 0,
2722
+ open: 0
2723
+ };
2724
+ }
2725
+ const sessionId = ctx.session?.id ?? "unknown";
2726
+ let plan = await loadPlan(planPath) ?? emptyPlan(sessionId);
2727
+ switch (input.action) {
2728
+ case "show":
2729
+ break;
2730
+ case "add": {
2731
+ const title = input.title?.trim();
2732
+ if (!title) {
2733
+ return mkResult(plan, false, "add requires `title`.");
2734
+ }
2735
+ ({ plan } = addPlanItem(plan, title, input.details?.trim() || void 0));
2736
+ await savePlan(planPath, plan);
2737
+ break;
2738
+ }
2739
+ case "start":
2740
+ case "done": {
2741
+ if (!input.target) {
2742
+ return mkResult(plan, false, `${input.action} requires \`target\` (id|index|substring).`);
2743
+ }
2744
+ const next = setPlanItemStatus(
2745
+ plan,
2746
+ input.target,
2747
+ input.action === "start" ? "in_progress" : "done"
2748
+ );
2749
+ if (next === plan) {
2750
+ return mkResult(plan, false, `No plan item matched "${input.target}".`);
2751
+ }
2752
+ plan = next;
2753
+ await savePlan(planPath, plan);
2754
+ break;
2755
+ }
2756
+ case "remove": {
2757
+ if (!input.target) {
2758
+ return mkResult(plan, false, "remove requires `target` (id|index|substring).");
2759
+ }
2760
+ const next = removePlanItem(plan, input.target);
2761
+ if (next === plan) {
2762
+ return mkResult(plan, false, `No plan item matched "${input.target}".`);
2763
+ }
2764
+ plan = next;
2765
+ await savePlan(planPath, plan);
2766
+ break;
2767
+ }
2768
+ case "clear":
2769
+ plan = clearPlan(plan);
2770
+ await savePlan(planPath, plan);
2771
+ break;
2772
+ default:
2773
+ return mkResult(plan, false, `Unknown action "${input.action}".`);
2774
+ }
2775
+ return mkResult(plan, true, `Plan ${input.action} ok.`);
2776
+ }
2777
+ };
2778
+ function mkResult(plan, ok, message) {
2779
+ const open = plan.items.filter((i) => i.status !== "done").length;
2780
+ return {
2781
+ ok,
2782
+ message,
2783
+ plan: formatPlan(plan),
2784
+ count: plan.items.length,
2785
+ open
2786
+ };
2787
+ }
2656
2788
  var MAX_BYTES2 = 5 * 1024 * 1024;
2657
2789
  var readTool = {
2658
2790
  name: "read",
2791
+ category: "Filesystem",
2659
2792
  description: "Read the contents of a file. Lines are 1-indexed and prefixed with line numbers.",
2660
2793
  usageHint: "Read a file before editing it. Returns lines numbered like ` 1\u2192content`. Use `offset` and `limit` for large files (default reads up to 2000 lines).",
2661
2794
  permission: "auto",
@@ -2708,6 +2841,7 @@ var readTool = {
2708
2841
  var DEFAULT_IGNORE3 = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
2709
2842
  var replaceTool = {
2710
2843
  name: "replace",
2844
+ category: "Transform",
2711
2845
  description: "Batch replace a pattern across multiple files matched by glob. Returns diff for each modified file.",
2712
2846
  usageHint: 'Use `glob` for broad patterns (e.g. "**/*.ts"). Set `dry_run: true` to preview without modifying. `files` can be a single path, comma-separated list, or glob pattern.',
2713
2847
  permission: "confirm",
@@ -2736,7 +2870,7 @@ var replaceTool = {
2736
2870
  if (input.replacement === void 0) throw new Error("replace: replacement is required");
2737
2871
  if (!input?.files) throw new Error("replace: files is required");
2738
2872
  const replaceAll = input.replace_all ?? true;
2739
- const compiled = compileUserRegex(input.pattern, replaceAll ? "g" : "");
2873
+ const compiled = compileUserRegex(input.pattern, "g");
2740
2874
  if (!compiled.ok) {
2741
2875
  throw new Error(`replace: ${compiled.reason}`);
2742
2876
  }
@@ -2775,11 +2909,17 @@ var replaceTool = {
2775
2909
  const style = detectNewlineStyle(content);
2776
2910
  const contentLf = normalizeToLf(content);
2777
2911
  re.lastIndex = 0;
2778
- const matches = [...contentLf.matchAll(re)];
2779
- if (matches.length === 0) continue;
2780
- const newContentLf = contentLf.replace(re, input.replacement);
2912
+ const allMatches = [...contentLf.matchAll(re)];
2913
+ if (allMatches.length === 0) continue;
2914
+ const matches = replaceAll ? allMatches : allMatches.slice(0, 1);
2915
+ const count = matches.length;
2916
+ let newContentLf = contentLf;
2917
+ for (let i = matches.length - 1; i >= 0; i--) {
2918
+ const m = matches[i];
2919
+ newContentLf = newContentLf.slice(0, m.index) + input.replacement + newContentLf.slice(m.index + m[0].length);
2920
+ }
2781
2921
  re.lastIndex = 0;
2782
- totalReplacements += matches.length;
2922
+ totalReplacements += count;
2783
2923
  if (!dryRun) {
2784
2924
  const newContent = toStyle(newContentLf, style);
2785
2925
  await atomicWrite(realPath, newContent, { mode: stat9.mode & 511 });
@@ -2981,6 +3121,7 @@ describe('{{Name}}', () => {
2981
3121
  };
2982
3122
  var scaffoldTool = {
2983
3123
  name: "scaffold",
3124
+ category: "Project",
2984
3125
  description: "Generate boilerplate code from built-in templates or paths. Creates package.json, source files, tests.",
2985
3126
  usageHint: "Set `template` (npm-package, cli-tool, react-component) and `name`. `vars` for template variables. `dry_run` preview.",
2986
3127
  permission: "confirm",
@@ -3069,6 +3210,7 @@ var MAX_RESULTS = 50;
3069
3210
  var TIMEOUT_MS4 = 15e3;
3070
3211
  var searchTool = {
3071
3212
  name: "search",
3213
+ category: "Search",
3072
3214
  description: "Search the web for information. Returns title, URL, and snippet for each result.",
3073
3215
  usageHint: "Set `num_results` (1-50, default 10). Use `source` to pick engine: duckduckgo (default), google, bing.",
3074
3216
  permission: "confirm",
@@ -3277,6 +3419,7 @@ function stripTags2(html) {
3277
3419
  }
3278
3420
  var testTool = {
3279
3421
  name: "test",
3422
+ category: "Code Quality",
3280
3423
  description: "Run tests with vitest, jest, or mocha. Returns pass/fail counts and output.",
3281
3424
  usageHint: "Set `files` for specific tests. `watch` enables watch mode. `coverage` generates coverage report. `grep` filters by name.",
3282
3425
  permission: "confirm",
@@ -3424,6 +3567,7 @@ function parseResult(runner, result, duration) {
3424
3567
  // src/todo.ts
3425
3568
  var todoTool = {
3426
3569
  name: "todo",
3570
+ category: "Session",
3427
3571
  description: "Replace the current todo list with a new set of items.",
3428
3572
  usageHint: "Use for multi-step tasks. Replace the full list on each call. At most ONE task may be in_progress at a time. Items have id, content, status (pending|in_progress|completed), and optional activeForm.",
3429
3573
  permission: "auto",
@@ -3474,6 +3618,7 @@ var todoTool = {
3474
3618
  // src/tool-help.ts
3475
3619
  var toolHelpTool = {
3476
3620
  name: "tool_help",
3621
+ category: "Meta",
3477
3622
  description: "Get help and usage information for a specific tool or list all available tools.",
3478
3623
  usageHint: "Set `tool` for specific help. Omit to list all tools. `format`: short (one-liner), full (schema), markdown (formatted).",
3479
3624
  permission: "auto",
@@ -3595,6 +3740,7 @@ function formatAllToolsMarkdown(tools) {
3595
3740
  // src/tool-search.ts
3596
3741
  var toolSearchTool = {
3597
3742
  name: "tool_search",
3743
+ category: "Meta",
3598
3744
  description: "Search available tools by name, description, tags, permission level, or mutating flag.",
3599
3745
  usageHint: "Set `query` for keyword search. `tags` to filter by category. `permission` to filter by required permission. `mutating` to filter by mutating flag.",
3600
3746
  permission: "auto",
@@ -3662,10 +3808,11 @@ var toolSearchTool = {
3662
3808
  // src/tool-use.ts
3663
3809
  var toolUseTool = {
3664
3810
  name: "tool_use",
3811
+ category: "Meta",
3665
3812
  description: "Execute a specific tool by name with given input. Useful when the agent knows exactly which tool to call.",
3666
3813
  usageHint: "Set `tool` with exact tool name and `input` with the tool parameters. Returns result or error.",
3667
3814
  permission: "confirm",
3668
- mutating: false,
3815
+ mutating: true,
3669
3816
  timeoutMs: 6e4,
3670
3817
  inputSchema: {
3671
3818
  type: "object",
@@ -3737,6 +3884,7 @@ var DEFAULT_IGNORE4 = [
3737
3884
  ];
3738
3885
  var treeTool = {
3739
3886
  name: "tree",
3887
+ category: "Filesystem",
3740
3888
  description: "Display directory structure as an ASCII tree. Shows files and folders with indentation.",
3741
3889
  usageHint: "Set `path` (default: cwd). `depth` limits nesting (default: 3). `glob` filters files. `exclude` ignores dirs. `show_files` toggles file listing (default: true).",
3742
3890
  permission: "auto",
@@ -3891,6 +4039,7 @@ async function walkDir(dir, depth, opts) {
3891
4039
  }
3892
4040
  var typecheckTool = {
3893
4041
  name: "typecheck",
4042
+ category: "Code Quality",
3894
4043
  description: "Run TypeScript type checking with `tsc --noEmit`. Checks for type errors without compiling.",
3895
4044
  usageHint: "Set `project` for tsconfig path (default: nearest). `strict` enables strictest flags. `all` checks all projects in workspace.",
3896
4045
  permission: "confirm",
@@ -3970,6 +4119,7 @@ async function findTsConfig(cwd) {
3970
4119
  }
3971
4120
  var writeTool = {
3972
4121
  name: "write",
4122
+ category: "Filesystem",
3973
4123
  description: "Write or overwrite a file. For existing files, prefer `edit` over `write`.",
3974
4124
  usageHint: "Use `write` for new files or full replacements. For partial edits use `edit`. Existing files must have been `read` first in this session.",
3975
4125
  permission: "confirm",
@@ -4032,6 +4182,7 @@ var builtinTools = [
4032
4182
  fetchTool,
4033
4183
  searchTool,
4034
4184
  todoTool,
4185
+ planTool,
4035
4186
  gitTool,
4036
4187
  patchTool,
4037
4188
  jsonTool,