@wrongstack/tools 0.9.19 → 0.10.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.
- package/dist/audit.js +2 -2
- package/dist/audit.js.map +1 -1
- package/dist/bash.js +86 -19
- package/dist/bash.js.map +1 -1
- package/dist/batch-tool-use.js +2 -2
- package/dist/batch-tool-use.js.map +1 -1
- package/dist/builtin.js +386 -171
- package/dist/builtin.js.map +1 -1
- package/dist/circuit-breaker.d.ts +0 -2
- package/dist/circuit-breaker.js +0 -3
- package/dist/circuit-breaker.js.map +1 -1
- package/dist/codebase-index/index.d.ts +26 -6
- package/dist/codebase-index/index.js +34 -25
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/{codebase-stats-tool-BLhQmPNc.d.ts → codebase-stats-tool-C8ApERbn.d.ts} +0 -11
- package/dist/diff.js +28 -13
- package/dist/diff.js.map +1 -1
- package/dist/document.js +4 -4
- package/dist/document.js.map +1 -1
- package/dist/edit.js +3 -2
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +96 -15
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +13 -6
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +74 -4
- package/dist/format.js.map +1 -1
- package/dist/git.js +81 -8
- package/dist/git.js.map +1 -1
- package/dist/glob.js +15 -5
- package/dist/glob.js.map +1 -1
- package/dist/grep.js +32 -9
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +404 -182
- package/dist/index.js.map +1 -1
- package/dist/install.js +85 -8
- package/dist/install.js.map +1 -1
- package/dist/json.js +2 -2
- package/dist/json.js.map +1 -1
- package/dist/lint.js +74 -4
- package/dist/lint.js.map +1 -1
- package/dist/logs.js +6 -2
- package/dist/logs.js.map +1 -1
- package/dist/memory.js +13 -6
- package/dist/memory.js.map +1 -1
- package/dist/mode.js +4 -4
- package/dist/mode.js.map +1 -1
- package/dist/outdated.js +2 -2
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +387 -172
- package/dist/pack.js.map +1 -1
- package/dist/patch.js +3 -2
- package/dist/patch.js.map +1 -1
- package/dist/process-registry.js +0 -3
- package/dist/process-registry.js.map +1 -1
- package/dist/read.js +16 -5
- package/dist/read.js.map +1 -1
- package/dist/replace.js +3 -3
- package/dist/replace.js.map +1 -1
- package/dist/scaffold.js +3 -2
- package/dist/scaffold.js.map +1 -1
- package/dist/search.js +3 -2
- package/dist/search.js.map +1 -1
- package/dist/test.js +74 -4
- package/dist/test.js.map +1 -1
- package/dist/todo.js +21 -7
- package/dist/todo.js.map +1 -1
- package/dist/tool-help.js +5 -5
- package/dist/tool-help.js.map +1 -1
- package/dist/tool-search.js +2 -2
- package/dist/tool-search.js.map +1 -1
- package/dist/tool-use.js +4 -4
- package/dist/tool-use.js.map +1 -1
- package/dist/tree.js +16 -8
- package/dist/tree.js.map +1 -1
- package/dist/typecheck.js +74 -4
- package/dist/typecheck.js.map +1 -1
- package/dist/write.js +11 -4
- package/dist/write.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs4 from 'node:fs/promises';
|
|
|
2
2
|
import { stat } from 'node:fs/promises';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { resolve, sep, dirname } from 'node:path';
|
|
5
|
-
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, buildChildEnv,
|
|
5
|
+
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, buildChildEnv, loadPlan, emptyPlan, clearPlan, savePlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, formatPlan, stripAnsi, resolveWstackPaths } from '@wrongstack/core';
|
|
6
6
|
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
7
7
|
import * as os from 'node:os';
|
|
8
8
|
import * as dns from 'node:dns/promises';
|
|
@@ -78,24 +78,104 @@ function isBinaryBuffer(buf) {
|
|
|
78
78
|
}
|
|
79
79
|
return false;
|
|
80
80
|
}
|
|
81
|
+
var COMMAND_OUTPUT_MAX_BYTES = 32768;
|
|
82
|
+
var REPEAT_RUN_THRESHOLD = 3;
|
|
83
|
+
function collapseCarriageReturns(text) {
|
|
84
|
+
const lf = text.replace(/\r\n/g, "\n");
|
|
85
|
+
if (!lf.includes("\r")) return lf;
|
|
86
|
+
return lf.split("\n").map((line) => line.includes("\r") ? line.slice(line.lastIndexOf("\r") + 1) : line).join("\n");
|
|
87
|
+
}
|
|
88
|
+
function collapseConsecutiveDuplicates(text, minRun = REPEAT_RUN_THRESHOLD) {
|
|
89
|
+
const lines = text.split("\n");
|
|
90
|
+
const out = [];
|
|
91
|
+
let i = 0;
|
|
92
|
+
while (i < lines.length) {
|
|
93
|
+
let j = i + 1;
|
|
94
|
+
while (j < lines.length && lines[j] === lines[i]) j++;
|
|
95
|
+
const run = j - i;
|
|
96
|
+
if (run >= minRun) {
|
|
97
|
+
out.push(lines[i], `\u2026 \u27E8repeated ${run}\xD7\u27E9`);
|
|
98
|
+
} else {
|
|
99
|
+
for (let k = i; k < j; k++) out.push(lines[k]);
|
|
100
|
+
}
|
|
101
|
+
i = j;
|
|
102
|
+
}
|
|
103
|
+
return out.join("\n");
|
|
104
|
+
}
|
|
105
|
+
function takeHeadBytes(s, maxBytes) {
|
|
106
|
+
if (maxBytes <= 0) return "";
|
|
107
|
+
if (Buffer.byteLength(s, "utf8") <= maxBytes) return s;
|
|
108
|
+
let lo = 0;
|
|
109
|
+
let hi = s.length;
|
|
110
|
+
while (lo < hi) {
|
|
111
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
112
|
+
if (Buffer.byteLength(s.slice(0, mid), "utf8") <= maxBytes) lo = mid;
|
|
113
|
+
else hi = mid - 1;
|
|
114
|
+
}
|
|
115
|
+
return s.slice(0, lo);
|
|
116
|
+
}
|
|
117
|
+
function takeTailBytes(s, maxBytes) {
|
|
118
|
+
if (maxBytes <= 0) return "";
|
|
119
|
+
if (Buffer.byteLength(s, "utf8") <= maxBytes) return s;
|
|
120
|
+
let lo = 0;
|
|
121
|
+
let hi = s.length;
|
|
122
|
+
while (lo < hi) {
|
|
123
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
124
|
+
if (Buffer.byteLength(s.slice(s.length - mid), "utf8") <= maxBytes) lo = mid;
|
|
125
|
+
else hi = mid - 1;
|
|
126
|
+
}
|
|
127
|
+
return s.slice(s.length - lo);
|
|
128
|
+
}
|
|
129
|
+
function truncateHeadTail(s, maxBytes) {
|
|
130
|
+
const total = Buffer.byteLength(s, "utf8");
|
|
131
|
+
if (total <= maxBytes) return s;
|
|
132
|
+
const MARKER_RESERVE = 64;
|
|
133
|
+
const avail = Math.max(0, maxBytes - MARKER_RESERVE);
|
|
134
|
+
const headBudget = Math.floor(avail * 0.45);
|
|
135
|
+
const head = takeHeadBytes(s, headBudget);
|
|
136
|
+
const tail = takeTailBytes(s, avail - Buffer.byteLength(head, "utf8"));
|
|
137
|
+
const kept = Buffer.byteLength(head, "utf8") + Buffer.byteLength(tail, "utf8");
|
|
138
|
+
return `${head}
|
|
139
|
+
\u2026[truncated ${total - kept} bytes]\u2026
|
|
140
|
+
${tail}`;
|
|
141
|
+
}
|
|
142
|
+
function normalizeCommandOutput(raw, opts = {}) {
|
|
143
|
+
if (!raw) return raw;
|
|
144
|
+
let text = stripAnsi(raw);
|
|
145
|
+
text = collapseCarriageReturns(text);
|
|
146
|
+
text = text.replace(/[ \t]+$/gm, "");
|
|
147
|
+
text = collapseConsecutiveDuplicates(text);
|
|
148
|
+
text = text.replace(/\n{3,}/g, "\n\n");
|
|
149
|
+
return truncateHeadTail(text, opts.maxBytes ?? COMMAND_OUTPUT_MAX_BYTES);
|
|
150
|
+
}
|
|
81
151
|
|
|
82
152
|
// src/read.ts
|
|
83
153
|
var MAX_BYTES = 5 * 1024 * 1024;
|
|
84
154
|
var readTool = {
|
|
85
155
|
name: "read",
|
|
86
156
|
category: "Filesystem",
|
|
87
|
-
description: "Read the contents of a file. Lines are 1-indexed
|
|
88
|
-
usageHint: "
|
|
157
|
+
description: "Read the contents of a file with line numbers. This is the primary way to inspect source code, configuration, or any text file before making changes. Lines are returned 1-indexed with a ` N| ` prefix for easy reference in edits.",
|
|
158
|
+
usageHint: "FOUNDATIONAL TOOL \u2014 call this before almost any edit operation.\n\nBest practices:\n- Always read a file before using `edit`, `replace`, or `write` on it (the system often requires it for safety).\n- Use `offset` + `limit` for very large files instead of reading everything at once.\n- Default limit is generous (2000 lines) but can be increased.\n- The output format is designed to be directly usable as context for `edit` operations.",
|
|
89
159
|
permission: "auto",
|
|
90
160
|
mutating: false,
|
|
161
|
+
capabilities: ["fs.read"],
|
|
91
162
|
maxOutputBytes: 262144,
|
|
92
163
|
timeoutMs: 5e3,
|
|
93
164
|
inputSchema: {
|
|
94
165
|
type: "object",
|
|
95
166
|
properties: {
|
|
96
|
-
path: {
|
|
97
|
-
|
|
98
|
-
|
|
167
|
+
path: {
|
|
168
|
+
type: "string",
|
|
169
|
+
description: "Path to the file (relative to project root or absolute within project)."
|
|
170
|
+
},
|
|
171
|
+
offset: {
|
|
172
|
+
type: "integer",
|
|
173
|
+
description: "1-based starting line number. Use together with `limit` for large files."
|
|
174
|
+
},
|
|
175
|
+
limit: {
|
|
176
|
+
type: "integer",
|
|
177
|
+
description: "Maximum number of lines to return (default is 2000)."
|
|
178
|
+
}
|
|
99
179
|
},
|
|
100
180
|
required: ["path"]
|
|
101
181
|
},
|
|
@@ -145,16 +225,23 @@ var readTool = {
|
|
|
145
225
|
var writeTool = {
|
|
146
226
|
name: "write",
|
|
147
227
|
category: "Filesystem",
|
|
148
|
-
description: "Write or overwrite a file. For existing files, prefer `edit`
|
|
149
|
-
usageHint: "Use `write` for new files or
|
|
228
|
+
description: "Write or completely overwrite a file on disk. This is a high-privilege operation. For modifying existing files, you should almost always prefer the `edit` tool instead, because `edit` is safer and works on the last-read version of the file.",
|
|
229
|
+
usageHint: "RULES FOR CORRECT USAGE:\n- Use `write` primarily for **new files** or when you want to replace the entire content.\n- For any existing file, strongly prefer `edit` (it requires a prior `read` in the same session and is more precise).\n- You MUST have called `read` on the file earlier in the conversation before using `write` on an existing path (the system enforces this for safety).\n- The path is resolved relative to the project root and protected against escaping the workspace.",
|
|
150
230
|
permission: "confirm",
|
|
151
231
|
mutating: true,
|
|
152
232
|
timeoutMs: 5e3,
|
|
233
|
+
capabilities: ["fs.write"],
|
|
153
234
|
inputSchema: {
|
|
154
235
|
type: "object",
|
|
155
236
|
properties: {
|
|
156
|
-
path: {
|
|
157
|
-
|
|
237
|
+
path: {
|
|
238
|
+
type: "string",
|
|
239
|
+
description: "Relative path from project root. Must not escape the project."
|
|
240
|
+
},
|
|
241
|
+
content: {
|
|
242
|
+
type: "string",
|
|
243
|
+
description: "The complete new content of the file."
|
|
244
|
+
}
|
|
158
245
|
},
|
|
159
246
|
required: ["path", "content"]
|
|
160
247
|
},
|
|
@@ -202,10 +289,11 @@ var writeTool = {
|
|
|
202
289
|
var editTool = {
|
|
203
290
|
name: "edit",
|
|
204
291
|
category: "Filesystem",
|
|
205
|
-
description: "
|
|
206
|
-
usageHint: "
|
|
292
|
+
description: "Perform a precise, surgical text replacement in a file. This is the preferred tool for modifying existing code. It requires that you have previously called `read` on the file in the current session. Fails safely if the `old_string` appears more than once unless `replace_all` is set.",
|
|
293
|
+
usageHint: "MANDATORY WORKFLOW:\n1. Call `read` on the target file first (in the same conversation).\n2. Use a sufficiently unique `old_string` (include surrounding lines/context if needed).\n3. If the string appears multiple times and you want to change all of them, set `replace_all: true`.\n4. `new_string` must be the exact replacement text.\n\nThis tool is much safer than `write` for existing files because it works against the last-read version.",
|
|
207
294
|
permission: "confirm",
|
|
208
295
|
mutating: true,
|
|
296
|
+
capabilities: ["fs.write"],
|
|
209
297
|
timeoutMs: 5e3,
|
|
210
298
|
inputSchema: {
|
|
211
299
|
type: "object",
|
|
@@ -367,10 +455,11 @@ var DEFAULT_IGNORE = ["node_modules", ".git", "dist", "build", ".next", "coverag
|
|
|
367
455
|
var replaceTool = {
|
|
368
456
|
name: "replace",
|
|
369
457
|
category: "Transform",
|
|
370
|
-
description: "
|
|
371
|
-
usageHint:
|
|
458
|
+
description: "Perform a search-and-replace across multiple files using a regex pattern. This is a powerful bulk transformation tool. Always use `dry_run: true` first on anything non-trivial.",
|
|
459
|
+
usageHint: "DANGEROUS IF USED CARELESSLY \u2014 review the diff output carefully.\n\nRecommended workflow:\n1. Start with `dry_run: true` to see exactly what would change.\n2. Use a specific enough `pattern` (and `glob` / `files`) to avoid accidental broad changes.\n3. `replace_all` controls whether only the first match per file or all matches are replaced.\nThis tool is excellent for large-scale refactors (renaming, import updates, etc.) but must be used with caution.",
|
|
372
460
|
permission: "confirm",
|
|
373
461
|
mutating: true,
|
|
462
|
+
capabilities: ["fs.write"],
|
|
374
463
|
timeoutMs: 3e4,
|
|
375
464
|
inputSchema: {
|
|
376
465
|
type: "object",
|
|
@@ -486,7 +575,6 @@ async function resolveFiles(filesInput, ctx, extraGlob) {
|
|
|
486
575
|
return resolved;
|
|
487
576
|
}
|
|
488
577
|
async function globFiles(pattern, base, extraGlob) {
|
|
489
|
-
const { spawn: spawn11 } = await import('node:child_process');
|
|
490
578
|
const rgAvailable = await checkRg();
|
|
491
579
|
if (rgAvailable) {
|
|
492
580
|
try {
|
|
@@ -563,18 +651,28 @@ var DEFAULT_IGNORE2 = ["node_modules", ".git", "dist", "build", ".next", "covera
|
|
|
563
651
|
var globTool = {
|
|
564
652
|
name: "glob",
|
|
565
653
|
category: "Filesystem",
|
|
566
|
-
description: "Find files matching a glob pattern.
|
|
567
|
-
usageHint: "
|
|
654
|
+
description: "Find files matching a glob pattern. Fast way to discover relevant files before reading, grepping, or editing them.",
|
|
655
|
+
usageHint: "RECOMMENDED FOR SCOPING SEARCHES:\n\n- Use early to get a list of files you actually care about.\n- Combine with `path` and `limit`.\n- Default ignores common build/dependency directories.\nMuch more efficient than shell `find` for most use cases inside the agent.",
|
|
568
656
|
permission: "auto",
|
|
569
657
|
mutating: false,
|
|
658
|
+
capabilities: ["fs.read"],
|
|
570
659
|
maxOutputBytes: 65536,
|
|
571
660
|
timeoutMs: 5e3,
|
|
572
661
|
inputSchema: {
|
|
573
662
|
type: "object",
|
|
574
663
|
properties: {
|
|
575
|
-
pattern: {
|
|
576
|
-
|
|
577
|
-
|
|
664
|
+
pattern: {
|
|
665
|
+
type: "string",
|
|
666
|
+
description: 'Glob pattern to match (e.g. "**/*.ts", "src/**").'
|
|
667
|
+
},
|
|
668
|
+
path: {
|
|
669
|
+
type: "string",
|
|
670
|
+
description: "Base directory to search from (defaults to project root)."
|
|
671
|
+
},
|
|
672
|
+
limit: {
|
|
673
|
+
type: "integer",
|
|
674
|
+
description: "Maximum number of results to return (default 1000, max 5000)."
|
|
675
|
+
}
|
|
578
676
|
},
|
|
579
677
|
required: ["pattern"]
|
|
580
678
|
},
|
|
@@ -638,22 +736,45 @@ var DEFAULT_IGNORE3 = ["node_modules", ".git", "dist", "build", ".next", "covera
|
|
|
638
736
|
var grepTool = {
|
|
639
737
|
name: "grep",
|
|
640
738
|
category: "Search",
|
|
641
|
-
description: "Search
|
|
642
|
-
usageHint: '
|
|
739
|
+
description: "Search across files using a regular expression. This is one of the primary code search tools. Prefers ripgrep for speed and features when available.",
|
|
740
|
+
usageHint: 'POWERFUL CODE SEARCH TOOL:\n\n- `pattern` is a regular expression.\n- Use `output_mode: "content"` (default) to get matching lines with context.\n- Use `"files_with_matches"` when you only need the list of files.\n- Use `"count"` for quick statistics.\n- `glob` and `path` let you narrow the search scope significantly.\n- Always prefer this over `bash grep` when searching code.',
|
|
643
741
|
permission: "auto",
|
|
644
742
|
mutating: false,
|
|
743
|
+
capabilities: ["fs.read"],
|
|
645
744
|
maxOutputBytes: 131072,
|
|
646
745
|
timeoutMs: 1e4,
|
|
647
746
|
inputSchema: {
|
|
648
747
|
type: "object",
|
|
649
748
|
properties: {
|
|
650
|
-
pattern: {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
749
|
+
pattern: {
|
|
750
|
+
type: "string",
|
|
751
|
+
description: "Regular expression pattern to search for in file contents."
|
|
752
|
+
},
|
|
753
|
+
path: {
|
|
754
|
+
type: "string",
|
|
755
|
+
description: "Limit search to this directory or file (relative to project root)."
|
|
756
|
+
},
|
|
757
|
+
glob: {
|
|
758
|
+
type: "string",
|
|
759
|
+
description: 'Glob filter for which files to include (e.g. "**/*.ts", "src/**").'
|
|
760
|
+
},
|
|
761
|
+
output_mode: {
|
|
762
|
+
type: "string",
|
|
763
|
+
enum: ["content", "files_with_matches", "count"],
|
|
764
|
+
description: "Return style: detailed matches, just file list, or count only."
|
|
765
|
+
},
|
|
766
|
+
context_lines: {
|
|
767
|
+
type: "integer",
|
|
768
|
+
description: "How many lines of surrounding context to include with each match."
|
|
769
|
+
},
|
|
770
|
+
case_insensitive: {
|
|
771
|
+
type: "boolean",
|
|
772
|
+
description: "Ignore case when matching."
|
|
773
|
+
},
|
|
774
|
+
limit: {
|
|
775
|
+
type: "integer",
|
|
776
|
+
description: "Maximum number of matches to return."
|
|
777
|
+
}
|
|
657
778
|
},
|
|
658
779
|
required: ["pattern"]
|
|
659
780
|
},
|
|
@@ -918,8 +1039,6 @@ var CircuitBreaker = class {
|
|
|
918
1039
|
lastSlowAt = null;
|
|
919
1040
|
/** Timestamp when the breaker was opened (for cooldown calculation). */
|
|
920
1041
|
openedAt = null;
|
|
921
|
-
/** Timestamp when the last call ran (for half-open gate). */
|
|
922
|
-
lastCallAt = null;
|
|
923
1042
|
constructor(config = {}) {
|
|
924
1043
|
this.maxConsecutiveFailures = config.maxConsecutiveFailures ?? DEFAULT_MAX_CONSECUTIVE_FAILURES;
|
|
925
1044
|
this.slowCallThresholdMs = config.slowCallThresholdMs ?? DEFAULT_SLOW_CALL_THRESHOLD_MS;
|
|
@@ -977,7 +1096,6 @@ var CircuitBreaker = class {
|
|
|
977
1096
|
*/
|
|
978
1097
|
afterCall(durationMs, failed) {
|
|
979
1098
|
const now = Date.now();
|
|
980
|
-
this.lastCallAt = now;
|
|
981
1099
|
if (this.state === "half-open") {
|
|
982
1100
|
if (failed) {
|
|
983
1101
|
this._trip();
|
|
@@ -1254,23 +1372,33 @@ var STREAM_FLUSH_BYTES = 4 * 1024;
|
|
|
1254
1372
|
var bashTool = {
|
|
1255
1373
|
name: "bash",
|
|
1256
1374
|
category: "Shell",
|
|
1257
|
-
description: "
|
|
1258
|
-
usageHint: "
|
|
1375
|
+
description: "Execute an arbitrary command in the user's default shell (bash/zsh/pwsh/cmd). stdout and stderr are merged into one stream. This is the most powerful and dangerous tool \u2014 it gives the model full access to the developer's machine. Prefer specialized tools whenever possible.",
|
|
1376
|
+
usageHint: "SECURITY WARNING: This tool runs with the full privileges of the current user.\n\nBest practices for the model:\n- Strongly prefer `exec` for known safe commands (node, npm, pnpm, tsc, git, etc.).\n- Use bash only when you genuinely need shell features (pipes, redirection, complex one-liners).\n- Prefer single focused commands over huge `&&` chains.\n- Use `background: true` only for long-running processes (dev servers, watchers).\n- The working directory is the project root.\n- Output may be truncated in the middle for very large results.",
|
|
1259
1377
|
permission: "confirm",
|
|
1260
1378
|
mutating: true,
|
|
1261
1379
|
// Trust rules match on the literal `command` string. Without subjectKey
|
|
1262
1380
|
// the policy heuristic would have done the same here, but declaring it
|
|
1263
1381
|
// explicitly removes the implicit cross-tool aliasing.
|
|
1264
1382
|
subjectKey: "command",
|
|
1383
|
+
capabilities: ["shell.arbitrary"],
|
|
1265
1384
|
timeoutMs: 3e4,
|
|
1266
1385
|
maxOutputBytes: MAX_OUTPUT,
|
|
1267
1386
|
estimatedDurationMs: 3e3,
|
|
1268
1387
|
inputSchema: {
|
|
1269
1388
|
type: "object",
|
|
1270
1389
|
properties: {
|
|
1271
|
-
command: {
|
|
1272
|
-
|
|
1273
|
-
|
|
1390
|
+
command: {
|
|
1391
|
+
type: "string",
|
|
1392
|
+
description: "The exact shell command to run. Prefer simple, focused commands."
|
|
1393
|
+
},
|
|
1394
|
+
timeout_ms: {
|
|
1395
|
+
type: "integer",
|
|
1396
|
+
description: "Optional timeout for this specific command in milliseconds."
|
|
1397
|
+
},
|
|
1398
|
+
background: {
|
|
1399
|
+
type: "boolean",
|
|
1400
|
+
description: "If true, launch the process in the background and return the PID immediately."
|
|
1401
|
+
}
|
|
1274
1402
|
},
|
|
1275
1403
|
required: ["command"]
|
|
1276
1404
|
},
|
|
@@ -1352,7 +1480,7 @@ var bashTool = {
|
|
|
1352
1480
|
yield {
|
|
1353
1481
|
type: "final",
|
|
1354
1482
|
output: {
|
|
1355
|
-
output:
|
|
1483
|
+
output: normalizeCommandOutput(buf2),
|
|
1356
1484
|
exit_code: null,
|
|
1357
1485
|
timed_out: false,
|
|
1358
1486
|
pid: pid2
|
|
@@ -1479,11 +1607,10 @@ var bashTool = {
|
|
|
1479
1607
|
if (remainder !== null) {
|
|
1480
1608
|
yield { type: "partial_output", text: remainder };
|
|
1481
1609
|
}
|
|
1482
|
-
const cleaned = stripAnsi(buf).replace(/\r\n?/g, "\n");
|
|
1483
1610
|
yield {
|
|
1484
1611
|
type: "final",
|
|
1485
1612
|
output: {
|
|
1486
|
-
output:
|
|
1613
|
+
output: normalizeCommandOutput(buf),
|
|
1487
1614
|
exit_code: c.code,
|
|
1488
1615
|
timed_out: timedOut
|
|
1489
1616
|
}
|
|
@@ -1604,18 +1731,32 @@ function validateArgs(cmd, args) {
|
|
|
1604
1731
|
var execTool = {
|
|
1605
1732
|
name: "exec",
|
|
1606
1733
|
category: "Shell",
|
|
1607
|
-
description: "
|
|
1608
|
-
usageHint: "
|
|
1734
|
+
description: "Execute a **whitelisted, restricted set of commands** with strict argument validation. This is the **preferred and safer** alternative to the `bash` tool for running development tools (node, npm, pnpm, tsc, git, tests, linters, etc.). It prevents arbitrary command injection and limits what the model can do.",
|
|
1735
|
+
usageHint: "PREFERRED SHELL TOOL for most cases.\n\nUse this instead of `bash` whenever possible.\n- `command` must be one of the allowed commands (node, npm, pnpm, git, tsc, eslint, vitest, etc.).\n- Arguments are passed as a clean array (no shell interpretation).\n- `cwd` is validated to stay inside the project.\n- For anything that requires real shell features (pipes, complex redirection, arbitrary commands), fall back to `bash` (with strong justification).\nThis tool significantly reduces the risk compared to full shell access.",
|
|
1609
1736
|
permission: "confirm",
|
|
1610
1737
|
mutating: true,
|
|
1611
1738
|
timeoutMs: TIMEOUT_MS,
|
|
1739
|
+
capabilities: ["shell.restricted"],
|
|
1612
1740
|
inputSchema: {
|
|
1613
1741
|
type: "object",
|
|
1614
1742
|
properties: {
|
|
1615
|
-
command: {
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1743
|
+
command: {
|
|
1744
|
+
type: "string",
|
|
1745
|
+
description: 'The base command to run. Must be in the internal allowlist (e.g. "node", "pnpm", "git", "tsc").'
|
|
1746
|
+
},
|
|
1747
|
+
args: {
|
|
1748
|
+
type: "array",
|
|
1749
|
+
items: { type: "string" },
|
|
1750
|
+
description: "Arguments passed to the command. Passed as an array (no shell parsing)."
|
|
1751
|
+
},
|
|
1752
|
+
cwd: {
|
|
1753
|
+
type: "string",
|
|
1754
|
+
description: "Optional working directory. Must resolve inside the project root."
|
|
1755
|
+
},
|
|
1756
|
+
timeout: {
|
|
1757
|
+
type: "integer",
|
|
1758
|
+
description: "Per-command timeout in milliseconds."
|
|
1759
|
+
}
|
|
1619
1760
|
},
|
|
1620
1761
|
required: ["command"]
|
|
1621
1762
|
},
|
|
@@ -1724,10 +1865,10 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
1724
1865
|
resolve7({
|
|
1725
1866
|
command: cmd,
|
|
1726
1867
|
args,
|
|
1727
|
-
stdout: stdout
|
|
1728
|
-
stderr: stderr
|
|
1868
|
+
stdout: normalizeCommandOutput(stdout),
|
|
1869
|
+
stderr: normalizeCommandOutput(stderr),
|
|
1729
1870
|
exitCode,
|
|
1730
|
-
truncated: stdout
|
|
1871
|
+
truncated: Buffer.byteLength(stdout, "utf8") > COMMAND_OUTPUT_MAX_BYTES || Buffer.byteLength(stderr, "utf8") > COMMAND_OUTPUT_MAX_BYTES,
|
|
1731
1872
|
allowed: true
|
|
1732
1873
|
});
|
|
1733
1874
|
});
|
|
@@ -1738,10 +1879,10 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
1738
1879
|
resolve7({
|
|
1739
1880
|
command: cmd,
|
|
1740
1881
|
args,
|
|
1741
|
-
stdout: stdout
|
|
1882
|
+
stdout: normalizeCommandOutput(stdout),
|
|
1742
1883
|
stderr: err.message,
|
|
1743
1884
|
exitCode: 1,
|
|
1744
|
-
truncated:
|
|
1885
|
+
truncated: Buffer.byteLength(stdout, "utf8") > COMMAND_OUTPUT_MAX_BYTES,
|
|
1745
1886
|
allowed: true
|
|
1746
1887
|
});
|
|
1747
1888
|
});
|
|
@@ -1831,10 +1972,11 @@ async function guardedFetch(url, maxRedirects, signal, headers = {
|
|
|
1831
1972
|
var fetchTool = {
|
|
1832
1973
|
name: "fetch",
|
|
1833
1974
|
category: "Network",
|
|
1834
|
-
description: "Fetch
|
|
1835
|
-
usageHint: "HTTPS
|
|
1975
|
+
description: "Fetch a URL and return its content. HTML pages are automatically converted to clean markdown. This tool has strong SSRF protections (private IPs, localhost, and cloud metadata endpoints are blocked by default).",
|
|
1976
|
+
usageHint: "Use this when you need external information (documentation, API responses, web pages, etc.).\n\nSecurity notes:\n- Only HTTPS is allowed by default.\n- Internal/private networks are blocked unless explicitly enabled via environment variable.\n- Redirects are followed but re-validated at each hop.\n- Output is capped (128KB by default) to avoid flooding context.\nPrefer this over raw `bash curl` or `bash wget`.",
|
|
1836
1977
|
permission: "confirm",
|
|
1837
1978
|
mutating: false,
|
|
1979
|
+
capabilities: ["net.outbound"],
|
|
1838
1980
|
// Trust rules for fetch match on the literal URL — declare it explicitly
|
|
1839
1981
|
// so a user can trust `https://api.example.com/*` without accidentally
|
|
1840
1982
|
// matching that pattern on any other tool that happens to have a `url`
|
|
@@ -1845,8 +1987,15 @@ var fetchTool = {
|
|
|
1845
1987
|
inputSchema: {
|
|
1846
1988
|
type: "object",
|
|
1847
1989
|
properties: {
|
|
1848
|
-
url: {
|
|
1849
|
-
|
|
1990
|
+
url: {
|
|
1991
|
+
type: "string",
|
|
1992
|
+
description: "The target URL (must use https://)."
|
|
1993
|
+
},
|
|
1994
|
+
format: {
|
|
1995
|
+
type: "string",
|
|
1996
|
+
enum: ["markdown", "text", "raw"],
|
|
1997
|
+
description: 'Output format. "markdown" is recommended for HTML pages.'
|
|
1998
|
+
}
|
|
1850
1999
|
},
|
|
1851
2000
|
required: ["url"]
|
|
1852
2001
|
},
|
|
@@ -2086,10 +2235,11 @@ var TIMEOUT_MS3 = 15e3;
|
|
|
2086
2235
|
var searchTool = {
|
|
2087
2236
|
name: "search",
|
|
2088
2237
|
category: "Search",
|
|
2089
|
-
description: "
|
|
2090
|
-
usageHint: "
|
|
2238
|
+
description: "Perform a web search and return results with title, URL, and snippet. Use this when you need up-to-date external information that is not in the local codebase.",
|
|
2239
|
+
usageHint: "Good for: API documentation, error messages, library usage examples, current best practices.\n\n- Prefer specific queries over very broad ones.\n- Results go through the guarded fetch system (same protections as the `fetch` tool).\n- This is often better than the model trying to recall outdated knowledge.",
|
|
2091
2240
|
permission: "confirm",
|
|
2092
2241
|
mutating: false,
|
|
2242
|
+
capabilities: ["net.outbound"],
|
|
2093
2243
|
timeoutMs: TIMEOUT_MS3,
|
|
2094
2244
|
inputSchema: {
|
|
2095
2245
|
type: "object",
|
|
@@ -2294,8 +2444,8 @@ function stripTags2(html) {
|
|
|
2294
2444
|
var todoTool = {
|
|
2295
2445
|
name: "todo",
|
|
2296
2446
|
category: "Session",
|
|
2297
|
-
description: "
|
|
2298
|
-
usageHint: "
|
|
2447
|
+
description: "Manage the session-level todo list. This is the primary mechanism for tracking multi-step work. The list is fully replaced on every call (not appended).",
|
|
2448
|
+
usageHint: "BEST PRACTICE for complex tasks:\n- At the beginning of a non-trivial task, create a clear todo list with specific, actionable items.\n- Only **one** item should be `in_progress` at any time.\n- Update the list frequently as work progresses (mark items done, add new ones, change status).\n- The system and user can see this list, so keep it honest and up-to-date.\nThis tool is extremely valuable for maintaining focus and giving the user visibility into your plan.",
|
|
2299
2449
|
permission: "auto",
|
|
2300
2450
|
mutating: false,
|
|
2301
2451
|
timeoutMs: 1e3,
|
|
@@ -2307,13 +2457,27 @@ var todoTool = {
|
|
|
2307
2457
|
items: {
|
|
2308
2458
|
type: "object",
|
|
2309
2459
|
properties: {
|
|
2310
|
-
id: {
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2460
|
+
id: {
|
|
2461
|
+
type: "string",
|
|
2462
|
+
description: 'Unique identifier for the todo item (e.g. "1", "auth-flow").'
|
|
2463
|
+
},
|
|
2464
|
+
content: {
|
|
2465
|
+
type: "string",
|
|
2466
|
+
description: "Clear, actionable description of the task."
|
|
2467
|
+
},
|
|
2468
|
+
status: {
|
|
2469
|
+
type: "string",
|
|
2470
|
+
enum: ["pending", "in_progress", "completed"],
|
|
2471
|
+
description: 'Current status. Only one item should be "in_progress" at a time.'
|
|
2472
|
+
},
|
|
2473
|
+
activeForm: {
|
|
2474
|
+
type: "string",
|
|
2475
|
+
description: 'Optional present-tense form shown while the task is active (e.g. "Fixing auth bug").'
|
|
2476
|
+
}
|
|
2314
2477
|
},
|
|
2315
2478
|
required: ["id", "content", "status"]
|
|
2316
|
-
}
|
|
2479
|
+
},
|
|
2480
|
+
description: "The complete new list of todos. This replaces the previous list entirely."
|
|
2317
2481
|
}
|
|
2318
2482
|
},
|
|
2319
2483
|
required: ["todos"]
|
|
@@ -2343,8 +2507,8 @@ var todoTool = {
|
|
|
2343
2507
|
var planTool = {
|
|
2344
2508
|
name: "plan",
|
|
2345
2509
|
category: "Session",
|
|
2346
|
-
description: "
|
|
2347
|
-
usageHint: '
|
|
2510
|
+
description: "Manage a persistent strategic plan for the current session. Unlike todos, plans are meant for higher-level, multi-phase approaches and survive across conversation resumptions. Use this to outline big-picture work, then promote concrete items into the todo list when ready to execute.",
|
|
2511
|
+
usageHint: 'RECOMMENDED FOR COMPLEX, MULTI-PHASE WORK:\n\n- Start by creating a high-level plan with `action: "add"` or using templates (`template_use`).\n- Use `promote` to turn a plan item into actionable todos.\n- Keep plans at the "why and what" level, and todos at the "how and next step" level.\n- Common templates: "new-feature", "bug-fix", "refactor", "release", "security-audit".\n\nThis tool is excellent for maintaining long-term direction across many turns or even multiple sessions.',
|
|
2348
2512
|
permission: "auto",
|
|
2349
2513
|
mutating: false,
|
|
2350
2514
|
timeoutMs: 2e3,
|
|
@@ -2353,22 +2517,29 @@ var planTool = {
|
|
|
2353
2517
|
properties: {
|
|
2354
2518
|
action: {
|
|
2355
2519
|
type: "string",
|
|
2356
|
-
enum: ["show", "add", "start", "done", "remove", "promote", "derive", "template_use", "clear"]
|
|
2520
|
+
enum: ["show", "add", "start", "done", "remove", "promote", "derive", "template_use", "clear"],
|
|
2521
|
+
description: "The operation to perform on the plan board."
|
|
2522
|
+
},
|
|
2523
|
+
title: {
|
|
2524
|
+
type: "string",
|
|
2525
|
+
description: "Title of the plan item. Required for action=add."
|
|
2526
|
+
},
|
|
2527
|
+
details: {
|
|
2528
|
+
type: "string",
|
|
2529
|
+
description: "Additional details or description for a new plan item (action=add)."
|
|
2357
2530
|
},
|
|
2358
|
-
title: { type: "string", description: "Required when action = add." },
|
|
2359
|
-
details: { type: "string", description: "Optional extra context for add." },
|
|
2360
2531
|
target: {
|
|
2361
2532
|
type: "string",
|
|
2362
|
-
description: "
|
|
2533
|
+
description: "Identifier for the target plan item (id, 1-based index, or partial title). Required for most actions except add/show/clear."
|
|
2363
2534
|
},
|
|
2364
2535
|
subtasks: {
|
|
2365
2536
|
type: "array",
|
|
2366
2537
|
items: { type: "string" },
|
|
2367
|
-
description: "
|
|
2538
|
+
description: "List of subtask titles. Used with promote or derive to break a plan item into multiple todos."
|
|
2368
2539
|
},
|
|
2369
2540
|
template: {
|
|
2370
2541
|
type: "string",
|
|
2371
|
-
description: "Template
|
|
2542
|
+
description: "Template identifier when using action=template_use. Common values: new-feature, bug-fix, refactor, release, security-audit."
|
|
2372
2543
|
}
|
|
2373
2544
|
},
|
|
2374
2545
|
required: ["action"]
|
|
@@ -2482,13 +2653,14 @@ var MAX_OUTPUT3 = 1e5;
|
|
|
2482
2653
|
var gitTool = {
|
|
2483
2654
|
name: "git",
|
|
2484
2655
|
category: "Git",
|
|
2485
|
-
description: "
|
|
2486
|
-
usageHint: "
|
|
2656
|
+
description: "Safe wrapper around common git operations. Supports status, log, diff, commit, branch, checkout, stash, push, pull, fetch, reset, worktree, etc. This is the preferred way to interact with git instead of using the raw `bash` or `exec` tools.",
|
|
2657
|
+
usageHint: "ALWAYS prefer this tool over raw shell git commands.\n\nKey fields:\n- `command`: one of the supported subcommands (status, log, diff, commit, etc.)\n- Use `message` only for commit operations.\n- Use `files` array for operations that take paths (status, diff, add, etc.).\n- Non-mutating commands (status, log, diff, branch, fetch) are still permission:confirm for safety.\nNever pass raw git flags through `args` for dangerous operations \u2014 use the structured fields.",
|
|
2487
2658
|
permission: "confirm",
|
|
2488
2659
|
// Conservative: any of these may mutate. The non-mutating commands
|
|
2489
2660
|
// (status/log/diff/branch/fetch) are still gated on `permission: 'confirm'`
|
|
2490
2661
|
// and `MUTATING_SUBCOMMANDS` is consulted at runtime for per-call checks.
|
|
2491
2662
|
mutating: true,
|
|
2663
|
+
capabilities: ["fs.write", "shell.restricted"],
|
|
2492
2664
|
timeoutMs: TIMEOUT_MS4,
|
|
2493
2665
|
inputSchema: {
|
|
2494
2666
|
type: "object",
|
|
@@ -2703,19 +2875,19 @@ function runGit(args, cwd, signal) {
|
|
|
2703
2875
|
child.on("error", (err) => {
|
|
2704
2876
|
resolve7({
|
|
2705
2877
|
command: args[0],
|
|
2706
|
-
stdout,
|
|
2878
|
+
stdout: normalizeCommandOutput(stdout),
|
|
2707
2879
|
stderr: err.message,
|
|
2708
2880
|
exitCode: 1,
|
|
2709
|
-
truncated: stdout
|
|
2881
|
+
truncated: Buffer.byteLength(stdout, "utf8") > COMMAND_OUTPUT_MAX_BYTES
|
|
2710
2882
|
});
|
|
2711
2883
|
});
|
|
2712
2884
|
child.on("close", (code) => {
|
|
2713
2885
|
resolve7({
|
|
2714
2886
|
command: args[0],
|
|
2715
|
-
stdout: stdout
|
|
2716
|
-
stderr: stderr
|
|
2887
|
+
stdout: normalizeCommandOutput(stdout),
|
|
2888
|
+
stderr: normalizeCommandOutput(stderr),
|
|
2717
2889
|
exitCode: code ?? 1,
|
|
2718
|
-
truncated: stdout
|
|
2890
|
+
truncated: Buffer.byteLength(stdout, "utf8") > COMMAND_OUTPUT_MAX_BYTES || Buffer.byteLength(stderr, "utf8") > COMMAND_OUTPUT_MAX_BYTES
|
|
2719
2891
|
});
|
|
2720
2892
|
});
|
|
2721
2893
|
});
|
|
@@ -2723,10 +2895,11 @@ function runGit(args, cwd, signal) {
|
|
|
2723
2895
|
var patchTool = {
|
|
2724
2896
|
name: "patch",
|
|
2725
2897
|
category: "Filesystem",
|
|
2726
|
-
description: "Apply a unified diff patch to
|
|
2727
|
-
usageHint: "
|
|
2898
|
+
description: "Apply a unified diff (patch) to the project. This is the correct tool when you have a diff that needs to be applied precisely, including handling of rejects.",
|
|
2899
|
+
usageHint: "Best used when you already have a diff (from generation, external source, or previous step).\n- Use `dry_run: true` to see what would happen without modifying files.\n- On failure it creates .rej and .orig files for manual review.\nOften cleaner than many small `edit` operations for larger changes.",
|
|
2728
2900
|
permission: "confirm",
|
|
2729
2901
|
mutating: true,
|
|
2902
|
+
capabilities: ["fs.write"],
|
|
2730
2903
|
timeoutMs: 3e4,
|
|
2731
2904
|
inputSchema: {
|
|
2732
2905
|
type: "object",
|
|
@@ -2832,8 +3005,8 @@ function extractPatchedFiles(output) {
|
|
|
2832
3005
|
var jsonTool = {
|
|
2833
3006
|
name: "json",
|
|
2834
3007
|
category: "Data",
|
|
2835
|
-
description: "Parse, query, and
|
|
2836
|
-
usageHint:
|
|
3008
|
+
description: "Parse, pretty-print, query, and convert between JSON, JSON5, and YAML. Supports simple path-based queries.",
|
|
3009
|
+
usageHint: "VERY USEFUL FOR DATA INSPECTION:\n\n- Use on package.json, tsconfig, config files, or any structured data.\n- `query` lets you extract specific values without reading the whole file.\n- Great for validating that a file has the expected structure.\nPrefer this over raw `read` + manual parsing when dealing with configuration or data files.",
|
|
2837
3010
|
permission: "auto",
|
|
2838
3011
|
mutating: false,
|
|
2839
3012
|
timeoutMs: 5e3,
|
|
@@ -2953,28 +3126,44 @@ function toYaml(data, indent = 0) {
|
|
|
2953
3126
|
var diffTool = {
|
|
2954
3127
|
name: "diff",
|
|
2955
3128
|
category: "Filesystem",
|
|
2956
|
-
description: "Show differences between files, commits, or
|
|
2957
|
-
usageHint:
|
|
3129
|
+
description: "Show code differences between files, commits, branches, or staged changes. A safer and more structured alternative to raw `git diff` via shell.",
|
|
3130
|
+
usageHint: 'USE FOR CODE REVIEW AND CHANGE INSPECTION:\n\n- `files` + no `a`/`b` \u2192 diff working tree vs HEAD for those files.\n- `a` and/or `b` \u2192 git-style commit/branch diff.\n- `staged: true` \u2192 only show staged changes.\n- `mode` can be "unified", "stat", or "side-by-side".\nThis tool has important safety guards against flag injection (see previous security findings).',
|
|
2958
3131
|
permission: "auto",
|
|
2959
3132
|
mutating: false,
|
|
3133
|
+
capabilities: ["fs.read"],
|
|
2960
3134
|
timeoutMs: 1e4,
|
|
2961
3135
|
inputSchema: {
|
|
2962
3136
|
type: "object",
|
|
2963
3137
|
properties: {
|
|
2964
|
-
path: {
|
|
3138
|
+
path: {
|
|
3139
|
+
type: "string",
|
|
3140
|
+
description: "Working directory for the diff operation (defaults to project root)."
|
|
3141
|
+
},
|
|
2965
3142
|
files: {
|
|
2966
3143
|
type: "string",
|
|
2967
|
-
description: '
|
|
3144
|
+
description: 'Files or globs to diff (e.g. "src/**/*.ts" or comma-separated list).'
|
|
3145
|
+
},
|
|
3146
|
+
a: {
|
|
3147
|
+
type: "string",
|
|
3148
|
+
description: "First ref/commit/branch for git diff (e.g. HEAD, main, a commit hash)."
|
|
3149
|
+
},
|
|
3150
|
+
b: {
|
|
3151
|
+
type: "string",
|
|
3152
|
+
description: "Second ref/commit/branch for git diff."
|
|
3153
|
+
},
|
|
3154
|
+
staged: {
|
|
3155
|
+
type: "boolean",
|
|
3156
|
+
description: "If true, only show changes that are staged in git."
|
|
2968
3157
|
},
|
|
2969
|
-
a: { type: "string", description: "First commit/branch/ref (for git diff)" },
|
|
2970
|
-
b: { type: "string", description: "Second commit/branch/ref (for git diff)" },
|
|
2971
|
-
staged: { type: "boolean", description: "Diff staged changes only" },
|
|
2972
3158
|
mode: {
|
|
2973
3159
|
type: "string",
|
|
2974
3160
|
enum: ["unified", "side-by-side", "stat"],
|
|
2975
|
-
description:
|
|
3161
|
+
description: 'Output format. "unified" is default, "stat" shows summary only.'
|
|
2976
3162
|
},
|
|
2977
|
-
context: {
|
|
3163
|
+
context: {
|
|
3164
|
+
type: "integer",
|
|
3165
|
+
description: "Number of context lines for unified diffs (default: 3)."
|
|
3166
|
+
}
|
|
2978
3167
|
}
|
|
2979
3168
|
},
|
|
2980
3169
|
async execute(input, ctx, opts) {
|
|
@@ -3045,8 +3234,7 @@ function runGit2(args, cwd, signal) {
|
|
|
3045
3234
|
child.on("error", (e) => resolve7({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
3046
3235
|
});
|
|
3047
3236
|
}
|
|
3048
|
-
async function fileDiff(input, ctx,
|
|
3049
|
-
input.path ? safeResolve(input.path, ctx) : ctx.cwd;
|
|
3237
|
+
async function fileDiff(input, ctx, _signal) {
|
|
3050
3238
|
input.context ?? 3;
|
|
3051
3239
|
const files = input.files ? (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim()).filter(Boolean) : [];
|
|
3052
3240
|
if (files.length === 0) {
|
|
@@ -3075,8 +3263,8 @@ ${formatUnified(lines)}`);
|
|
|
3075
3263
|
mode: input.mode ?? "unified"
|
|
3076
3264
|
};
|
|
3077
3265
|
}
|
|
3078
|
-
function formatUnified(lines,
|
|
3079
|
-
return lines.map((line,
|
|
3266
|
+
function formatUnified(lines, _context) {
|
|
3267
|
+
return lines.map((line, _i) => ` ${line}`).join("\n");
|
|
3080
3268
|
}
|
|
3081
3269
|
var DEFAULT_IGNORE4 = [
|
|
3082
3270
|
"node_modules",
|
|
@@ -3094,34 +3282,41 @@ var DEFAULT_IGNORE4 = [
|
|
|
3094
3282
|
var treeTool = {
|
|
3095
3283
|
name: "tree",
|
|
3096
3284
|
category: "Filesystem",
|
|
3097
|
-
description: "Display directory
|
|
3098
|
-
usageHint: "
|
|
3285
|
+
description: "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.",
|
|
3286
|
+
usageHint: "BEST PRACTICE FOR INITIAL EXPLORATION:\n\n- Call early when working with an unfamiliar project or module.\n- Tune `depth` (default 3) and use `glob`/`exclude` to focus the view.\n- Prefer this over raw `bash find` or `glob` + manual reading when you need a quick structural overview.\nOutput is truncated for very large trees.",
|
|
3099
3287
|
permission: "auto",
|
|
3100
3288
|
mutating: false,
|
|
3289
|
+
capabilities: ["fs.read"],
|
|
3101
3290
|
timeoutMs: 15e3,
|
|
3102
3291
|
inputSchema: {
|
|
3103
3292
|
type: "object",
|
|
3104
3293
|
properties: {
|
|
3105
|
-
path: {
|
|
3294
|
+
path: {
|
|
3295
|
+
type: "string",
|
|
3296
|
+
description: "Root directory to display the tree from (defaults to project root)."
|
|
3297
|
+
},
|
|
3106
3298
|
depth: {
|
|
3107
3299
|
type: "integer",
|
|
3108
|
-
description: "
|
|
3300
|
+
description: "Maximum directory depth to traverse (default 3, use 0 for unlimited).",
|
|
3109
3301
|
minimum: 0,
|
|
3110
3302
|
maximum: 20
|
|
3111
3303
|
},
|
|
3112
|
-
glob: {
|
|
3304
|
+
glob: {
|
|
3305
|
+
type: "string",
|
|
3306
|
+
description: "Only include files matching this glob pattern."
|
|
3307
|
+
},
|
|
3113
3308
|
exclude: {
|
|
3114
3309
|
type: "array",
|
|
3115
3310
|
items: { type: "string" },
|
|
3116
|
-
description: "
|
|
3311
|
+
description: "List of directory names to completely ignore."
|
|
3117
3312
|
},
|
|
3118
3313
|
show_files: {
|
|
3119
3314
|
type: "boolean",
|
|
3120
|
-
description: "
|
|
3315
|
+
description: "Whether to show individual files (default true)."
|
|
3121
3316
|
},
|
|
3122
3317
|
show_dirs: {
|
|
3123
3318
|
type: "boolean",
|
|
3124
|
-
description: "
|
|
3319
|
+
description: "Whether to show directories (default true)."
|
|
3125
3320
|
},
|
|
3126
3321
|
show_hidden: {
|
|
3127
3322
|
type: "boolean",
|
|
@@ -3329,8 +3524,8 @@ async function* spawnStream(opts) {
|
|
|
3329
3524
|
var lintTool = {
|
|
3330
3525
|
name: "lint",
|
|
3331
3526
|
category: "Code Quality",
|
|
3332
|
-
description: "Run
|
|
3333
|
-
usageHint: "
|
|
3527
|
+
description: "Run the project linter (primarily Biome in this repo). Detects style violations, potential bugs, and formatting issues.",
|
|
3528
|
+
usageHint: "RUN OFTEN DURING DEVELOPMENT:\n\n- `fix: true` will automatically correct what it can.\n- Target specific files or globs when you only want to check part of the project.\nThis is a fast and important quality gate. Use it before typecheck in most workflows.",
|
|
3334
3529
|
permission: "confirm",
|
|
3335
3530
|
mutating: false,
|
|
3336
3531
|
timeoutMs: 6e4,
|
|
@@ -3395,7 +3590,7 @@ var lintTool = {
|
|
|
3395
3590
|
files_checked: input.files ? Array.isArray(input.files) ? input.files.length : input.files.split(",").length : 0,
|
|
3396
3591
|
errors,
|
|
3397
3592
|
warnings,
|
|
3398
|
-
output: result.stdout,
|
|
3593
|
+
output: normalizeCommandOutput(result.stdout),
|
|
3399
3594
|
fix_applied: input.fix ?? false,
|
|
3400
3595
|
truncated: result.truncated
|
|
3401
3596
|
}
|
|
@@ -3421,8 +3616,8 @@ async function detectLinter(cwd) {
|
|
|
3421
3616
|
var formatTool = {
|
|
3422
3617
|
name: "format",
|
|
3423
3618
|
category: "Code Quality",
|
|
3424
|
-
description: "Format files
|
|
3425
|
-
usageHint: "
|
|
3619
|
+
description: "Format source files according to project style (Biome). Can also run in check-only mode.",
|
|
3620
|
+
usageHint: "RUN REGULARLY:\n\n- Use on changed files before committing.\n- `check: true` verifies formatting without making changes (useful in CI-like flows).\nThis project has very consistent formatting expectations. Always ensure your changes are formatted.",
|
|
3426
3621
|
permission: "confirm",
|
|
3427
3622
|
mutating: true,
|
|
3428
3623
|
timeoutMs: 6e4,
|
|
@@ -3495,7 +3690,7 @@ var formatTool = {
|
|
|
3495
3690
|
fixer: detected,
|
|
3496
3691
|
files_checked: 0,
|
|
3497
3692
|
files_changed: changed,
|
|
3498
|
-
output: result.stdout || result.stderr || result.error || "",
|
|
3693
|
+
output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ""),
|
|
3499
3694
|
truncated: result.truncated
|
|
3500
3695
|
}
|
|
3501
3696
|
};
|
|
@@ -3518,8 +3713,8 @@ async function detectFixer(cwd) {
|
|
|
3518
3713
|
var typecheckTool = {
|
|
3519
3714
|
name: "typecheck",
|
|
3520
3715
|
category: "Code Quality",
|
|
3521
|
-
description: "Run TypeScript type
|
|
3522
|
-
usageHint: "
|
|
3716
|
+
description: "Run the project's TypeScript type checker (`tsc --noEmit` or equivalent). Essential for verifying type safety before making changes or committing.",
|
|
3717
|
+
usageHint: "ALWAYS RUN BEFORE CONSIDERING WORK COMPLETE:\n\n- Use this to catch type errors early.\n- In monorepos, `all: true` will check every package.\n- This is one of the most important quality gates in this project.\nNever claim a task is done without a clean typecheck (unless the user explicitly says otherwise).",
|
|
3523
3718
|
permission: "confirm",
|
|
3524
3719
|
mutating: false,
|
|
3525
3720
|
timeoutMs: 12e4,
|
|
@@ -3577,7 +3772,7 @@ var typecheckTool = {
|
|
|
3577
3772
|
exit_code: result.exitCode,
|
|
3578
3773
|
errors,
|
|
3579
3774
|
warnings,
|
|
3580
|
-
output: result.stdout || result.stderr || result.error || "",
|
|
3775
|
+
output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ""),
|
|
3581
3776
|
truncated: result.truncated
|
|
3582
3777
|
}
|
|
3583
3778
|
};
|
|
@@ -3598,8 +3793,8 @@ async function findTsConfig(cwd) {
|
|
|
3598
3793
|
var testTool = {
|
|
3599
3794
|
name: "test",
|
|
3600
3795
|
category: "Code Quality",
|
|
3601
|
-
description: "
|
|
3602
|
-
usageHint: "
|
|
3796
|
+
description: "Execute the project's test suite. This is one of the most critical tools for validating that your changes are correct.",
|
|
3797
|
+
usageHint: "ESSENTIAL BEFORE CONSIDERING WORK DONE:\n\n- Use `files` or `grep` to run only relevant tests during development.\n- `coverage: true` is useful when working on critical paths.\nRun tests frequently. A clean test run is usually required before the task can be considered complete.",
|
|
3603
3798
|
permission: "confirm",
|
|
3604
3799
|
mutating: false,
|
|
3605
3800
|
timeoutMs: 12e4,
|
|
@@ -3737,7 +3932,7 @@ function parseResult(runner, result, duration) {
|
|
|
3737
3932
|
passed,
|
|
3738
3933
|
failed,
|
|
3739
3934
|
duration_ms: duration,
|
|
3740
|
-
output: result.stdout || result.error || "",
|
|
3935
|
+
output: normalizeCommandOutput(result.stdout || result.error || ""),
|
|
3741
3936
|
truncated: result.truncated
|
|
3742
3937
|
};
|
|
3743
3938
|
}
|
|
@@ -3746,11 +3941,12 @@ function parseResult(runner, result, duration) {
|
|
|
3746
3941
|
var installTool = {
|
|
3747
3942
|
name: "install",
|
|
3748
3943
|
category: "Package Management",
|
|
3749
|
-
description: "Install
|
|
3750
|
-
usageHint: "
|
|
3944
|
+
description: "Install, update or manage packages using the detected package manager (pnpm/npm/yarn). Strongly preferred over raw shell commands for dependency management because it is structured and safer.",
|
|
3945
|
+
usageHint: "ALWAYS USE THIS INSTEAD OF BASH FOR PACKAGE WORK:\n\n- Empty `packages` \u2192 normal `install` (respects lockfile).\n- Provide names \u2192 adds/updates specific packages.\n- `dry_run: true` for safe preview.\n- Set `save` appropriately.\nThis tool has proper capability declaration and is heavily recommended in the security posture of the project.",
|
|
3751
3946
|
permission: "confirm",
|
|
3752
3947
|
mutating: true,
|
|
3753
3948
|
timeoutMs: 12e4,
|
|
3949
|
+
capabilities: ["package.install", "shell.restricted"],
|
|
3754
3950
|
inputSchema: {
|
|
3755
3951
|
type: "object",
|
|
3756
3952
|
properties: {
|
|
@@ -3761,14 +3957,20 @@ var installTool = {
|
|
|
3761
3957
|
save: {
|
|
3762
3958
|
type: "string",
|
|
3763
3959
|
enum: ["dependency", "dev", "optional"],
|
|
3764
|
-
description:
|
|
3960
|
+
description: 'Where to save the package(s): "dependency", "devDependencies", or "optionalDependencies".'
|
|
3961
|
+
},
|
|
3962
|
+
cwd: {
|
|
3963
|
+
type: "string",
|
|
3964
|
+
description: "Working directory for the install command (must stay inside project)."
|
|
3765
3965
|
},
|
|
3766
|
-
cwd: { type: "string", description: "Working directory (default: cwd)" },
|
|
3767
3966
|
dry_run: {
|
|
3768
3967
|
type: "boolean",
|
|
3769
|
-
description: "
|
|
3968
|
+
description: "If true, show what would be installed without actually modifying package.json or node_modules."
|
|
3770
3969
|
},
|
|
3771
|
-
global: {
|
|
3970
|
+
global: {
|
|
3971
|
+
type: "boolean",
|
|
3972
|
+
description: "Whether to perform a global install (use with caution)."
|
|
3973
|
+
}
|
|
3772
3974
|
}
|
|
3773
3975
|
},
|
|
3774
3976
|
async execute(input, ctx, opts) {
|
|
@@ -3832,7 +4034,7 @@ var installTool = {
|
|
|
3832
4034
|
output: {
|
|
3833
4035
|
packages: pkgList,
|
|
3834
4036
|
exit_code: result.exitCode,
|
|
3835
|
-
output: result.stdout || result.stderr || result.error || "",
|
|
4037
|
+
output: normalizeCommandOutput(result.stdout || result.stderr || result.error || ""),
|
|
3836
4038
|
dry_run: args.includes("--dry-run"),
|
|
3837
4039
|
truncated: result.truncated
|
|
3838
4040
|
}
|
|
@@ -3858,8 +4060,8 @@ async function detectPackageManager(cwd) {
|
|
|
3858
4060
|
var auditTool = {
|
|
3859
4061
|
name: "audit",
|
|
3860
4062
|
category: "Package Management",
|
|
3861
|
-
description: "Run
|
|
3862
|
-
usageHint: "
|
|
4063
|
+
description: "Run a security audit against project dependencies (using pnpm/npm audit). Reports known vulnerabilities with severity.",
|
|
4064
|
+
usageHint: "CRITICAL SECURITY TOOL:\n\n- Run regularly and especially before any release.\n- Use `level` to focus on high/critical issues.\n- `fix` can attempt automatic remediation for some vulnerabilities.\nThis is one of the most important tools for supply chain security.",
|
|
3863
4065
|
permission: "confirm",
|
|
3864
4066
|
mutating: false,
|
|
3865
4067
|
timeoutMs: 6e4,
|
|
@@ -3966,8 +4168,8 @@ function parseAuditOutput(json, exitCode) {
|
|
|
3966
4168
|
var outdatedTool = {
|
|
3967
4169
|
name: "outdated",
|
|
3968
4170
|
category: "Package Management",
|
|
3969
|
-
description: "Check for outdated
|
|
3970
|
-
usageHint: "
|
|
4171
|
+
description: "Check for outdated dependencies in the project. Reports current, wanted (semver range), and latest versions available.",
|
|
4172
|
+
usageHint: "MAINTENANCE & SECURITY TOOL:\n\n- Run periodically or before dependency-related work.\n- Helps surface packages that may need updates for security or features.\n- Safe, read-only operation.\nUse the output to decide on upgrades. Prefer this over manual shell commands for dependency hygiene.",
|
|
3971
4173
|
permission: "auto",
|
|
3972
4174
|
mutating: true,
|
|
3973
4175
|
timeoutMs: 6e4,
|
|
@@ -4076,8 +4278,8 @@ function parseOutdatedOutput(json, exitCode) {
|
|
|
4076
4278
|
var logsTool = {
|
|
4077
4279
|
name: "logs",
|
|
4078
4280
|
category: "Logs",
|
|
4079
|
-
description: "
|
|
4080
|
-
usageHint: "
|
|
4281
|
+
description: "Read or stream logs from files, Docker containers, or systemd services. Useful for debugging running applications.",
|
|
4282
|
+
usageHint: "DEBUGGING TOOL \u2014 USE CAREFULLY IN AUTONOMOUS MODE:\n\n- Prefer `path` for local files or `service` for containers/systemd.\n- `stream: true` = live tail (can be expensive).\n- Always use `filter` (regex) when possible to reduce noise and token usage.\n- Long-running streams should be avoided unless the user explicitly wants live logs.",
|
|
4081
4283
|
permission: "confirm",
|
|
4082
4284
|
mutating: false,
|
|
4083
4285
|
timeoutMs: 3e4,
|
|
@@ -4182,6 +4384,10 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
4182
4384
|
child.stderr?.on("data", (c) => {
|
|
4183
4385
|
if (stderr.length < MAX) stderr += c.toString();
|
|
4184
4386
|
});
|
|
4387
|
+
child.stdout?.on("error", () => {
|
|
4388
|
+
});
|
|
4389
|
+
child.stderr?.on("error", () => {
|
|
4390
|
+
});
|
|
4185
4391
|
child.on("close", () => {
|
|
4186
4392
|
const output = stdout + stderr;
|
|
4187
4393
|
const entries = parseLogLines(output, filterRe);
|
|
@@ -4273,8 +4479,8 @@ function parseLine(line) {
|
|
|
4273
4479
|
var documentTool = {
|
|
4274
4480
|
name: "document",
|
|
4275
4481
|
category: "Project",
|
|
4276
|
-
description: "
|
|
4277
|
-
usageHint: "
|
|
4482
|
+
description: "Automatically generate or update documentation comments (JSDoc/TSDoc style) for code. Can target specific symbols or entire files/directories.",
|
|
4483
|
+
usageHint: "USE FOR IMPROVING CODE DOCUMENTATION:\n\n- Good for adding missing docs to public APIs or complex functions.\n- `overwrite: true` will replace existing documentation (use carefully).\n- You can target specific symbols via `target` or whole files/directories via `files`.\nAlways review the generated documentation before committing \u2014 the model can hallucinate details.",
|
|
4278
4484
|
permission: "confirm",
|
|
4279
4485
|
mutating: true,
|
|
4280
4486
|
timeoutMs: 3e4,
|
|
@@ -4358,9 +4564,8 @@ async function resolveFiles2(filesInput, cwd) {
|
|
|
4358
4564
|
}
|
|
4359
4565
|
return resolved;
|
|
4360
4566
|
}
|
|
4361
|
-
function processFile(content, absPath,
|
|
4567
|
+
function processFile(content, absPath, _style, _overwrite, target) {
|
|
4362
4568
|
const results = [];
|
|
4363
|
-
content.split("\n");
|
|
4364
4569
|
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
|
|
4365
4570
|
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*=>/g;
|
|
4366
4571
|
const classRegex = /class\s+(\w+)/g;
|
|
@@ -4513,10 +4718,11 @@ describe('{{Name}}', () => {
|
|
|
4513
4718
|
var scaffoldTool = {
|
|
4514
4719
|
name: "scaffold",
|
|
4515
4720
|
category: "Project",
|
|
4516
|
-
description: "Generate
|
|
4517
|
-
usageHint: "
|
|
4721
|
+
description: "Generate new files and folder structures from built-in templates or custom definitions. This is the recommended way to bootstrap new packages, components, or modules instead of creating files one by one with `write`.",
|
|
4722
|
+
usageHint: "PREFERRED FOR SCAFFOLDING:\n\n- Use built-in templates when they match your needs (e.g. react-component, npm-package).\n- Supports `dry_run` so you can preview exactly what will be created.\n- Has the powerful `fs.write.outside-project` capability \u2014 review paths carefully.\nMuch cleaner and safer than manually writing multiple files.",
|
|
4518
4723
|
permission: "confirm",
|
|
4519
4724
|
mutating: true,
|
|
4725
|
+
capabilities: ["fs.write.outside-project", "fs.write"],
|
|
4520
4726
|
timeoutMs: 3e4,
|
|
4521
4727
|
inputSchema: {
|
|
4522
4728
|
type: "object",
|
|
@@ -4606,8 +4812,8 @@ function substituteVars(content, name, vars) {
|
|
|
4606
4812
|
var toolSearchTool = {
|
|
4607
4813
|
name: "tool_search",
|
|
4608
4814
|
category: "Meta",
|
|
4609
|
-
description: "Search available tools
|
|
4610
|
-
usageHint: "
|
|
4815
|
+
description: "Search the catalog of available tools. Very useful when you are unsure which tool to use for a task.",
|
|
4816
|
+
usageHint: "SELF-DISCOVERY TOOL:\n\n- Use when you need to find the right tool for a job.\n- `query` searches names and descriptions.\n- You can filter by `tags` (category), `permission`, or `mutating`.\nCall this before guessing tool names. It helps you discover the best tool for the current situation.",
|
|
4611
4817
|
permission: "auto",
|
|
4612
4818
|
mutating: false,
|
|
4613
4819
|
timeoutMs: 1e3,
|
|
@@ -4680,8 +4886,8 @@ var toolSearchTool = {
|
|
|
4680
4886
|
var toolUseTool = {
|
|
4681
4887
|
name: "tool_use",
|
|
4682
4888
|
category: "Meta",
|
|
4683
|
-
description: "
|
|
4684
|
-
usageHint: "
|
|
4889
|
+
description: "Directly execute any registered tool by its exact name, bypassing normal discovery. This is a powerful meta-tool intended for cases where the agent has a clear plan and knows precisely which tool to invoke.",
|
|
4890
|
+
usageHint: "ADVANCED META TOOL \u2014 USE WITH CARE:\n\n- Only use when you are certain of the exact tool name and its expected input shape.\n- Prefer using the normal tool calling mechanism when possible.\n- Very useful in batch-tool-use or when orchestrating complex workflows programmatically.\n- The call still goes through full permission checks and capability validation.",
|
|
4685
4891
|
permission: "confirm",
|
|
4686
4892
|
mutating: true,
|
|
4687
4893
|
timeoutMs: 6e4,
|
|
@@ -4690,11 +4896,11 @@ var toolUseTool = {
|
|
|
4690
4896
|
properties: {
|
|
4691
4897
|
tool: {
|
|
4692
4898
|
type: "string",
|
|
4693
|
-
description:
|
|
4899
|
+
description: 'The exact registered name of the tool to invoke (e.g. "bash", "read", "codebase-search").'
|
|
4694
4900
|
},
|
|
4695
4901
|
input: {
|
|
4696
4902
|
type: "object",
|
|
4697
|
-
description: "
|
|
4903
|
+
description: "The input object matching the target tool's inputSchema."
|
|
4698
4904
|
}
|
|
4699
4905
|
},
|
|
4700
4906
|
required: ["tool"]
|
|
@@ -4749,8 +4955,8 @@ var toolUseTool = {
|
|
|
4749
4955
|
var batchToolUseTool = {
|
|
4750
4956
|
name: "batch_tool_use",
|
|
4751
4957
|
category: "Meta",
|
|
4752
|
-
description: "Execute
|
|
4753
|
-
usageHint: "
|
|
4958
|
+
description: "Execute a batch of tool calls either sequentially or in parallel. Returns structured results for every call.",
|
|
4959
|
+
usageHint: "ADVANCED / POWER USER TOOL:\n\n- Useful when you have a clear list of independent operations to perform.\n- `parallel: true` (default) runs them concurrently for speed.\n- `stop_on_error: true` makes it fail fast on the first error.\nUse with care \u2014 batching many mutating operations can be risky. Prefer explicit sequential steps for important work.",
|
|
4754
4960
|
permission: "confirm",
|
|
4755
4961
|
mutating: true,
|
|
4756
4962
|
timeoutMs: 12e4,
|
|
@@ -4853,8 +5059,8 @@ async function executeSingle(call, ctx, opts) {
|
|
|
4853
5059
|
var toolHelpTool = {
|
|
4854
5060
|
name: "tool_help",
|
|
4855
5061
|
category: "Meta",
|
|
4856
|
-
description: "Get help and usage
|
|
4857
|
-
usageHint: "
|
|
5062
|
+
description: "Get detailed help for one or more tools, including their full schema and usage guidance. This is the best way to understand exactly how to call a specific tool.",
|
|
5063
|
+
usageHint: "USE WHEN YOU NEED PRECISE TOOL INFORMATION:\n\n- Call with a specific `tool` name when you want the full schema and current usageHint.\n- Omit `tool` (or use a broad query) to get an overview of available tools.\n- Different `format` options give you different levels of detail.\nThis tool is extremely valuable for self-correction when you are unsure about a tool's interface.",
|
|
4858
5064
|
permission: "auto",
|
|
4859
5065
|
mutating: false,
|
|
4860
5066
|
timeoutMs: 5e3,
|
|
@@ -4863,16 +5069,16 @@ var toolHelpTool = {
|
|
|
4863
5069
|
properties: {
|
|
4864
5070
|
tool: {
|
|
4865
5071
|
type: "string",
|
|
4866
|
-
description: "
|
|
5072
|
+
description: "Specific tool name to get detailed help for. Omit to get a list of all tools."
|
|
4867
5073
|
},
|
|
4868
5074
|
format: {
|
|
4869
5075
|
type: "string",
|
|
4870
5076
|
enum: ["short", "full", "markdown"],
|
|
4871
|
-
description:
|
|
5077
|
+
description: 'Level of detail: "short" (summary), "full" (with full schema), "markdown" (human readable).'
|
|
4872
5078
|
},
|
|
4873
5079
|
include_examples: {
|
|
4874
5080
|
type: "boolean",
|
|
4875
|
-
description: "
|
|
5081
|
+
description: "Whether to include example usage in the response."
|
|
4876
5082
|
}
|
|
4877
5083
|
}
|
|
4878
5084
|
},
|
|
@@ -4976,16 +5182,23 @@ function rememberTool(memory) {
|
|
|
4976
5182
|
return {
|
|
4977
5183
|
name: "remember",
|
|
4978
5184
|
category: "Session",
|
|
4979
|
-
description: "Persist
|
|
4980
|
-
usageHint:
|
|
5185
|
+
description: "Persist important long-term facts into project or user memory. These memories survive conversation restarts and are available to future sessions.",
|
|
5186
|
+
usageHint: 'USE VERY SPARINGLY \u2014 ONLY FOR HIGH-VALUE RECURRING KNOWLEDGE:\n\n- Good: coding standards, project conventions, user preferences, recurring architecture decisions, important facts.\n- Bad: temporary state, current task progress, one-off notes \u2192 use `todo` or `plan` instead.\n- `scope: "project"` \u2192 visible to all agents on this codebase.\n- `scope: "user"` \u2192 personal to you.\n\nPolluting memory with noise hurts future context quality. Be extremely deliberate.',
|
|
4981
5187
|
permission: "auto",
|
|
4982
5188
|
mutating: true,
|
|
4983
5189
|
timeoutMs: 2e3,
|
|
4984
5190
|
inputSchema: {
|
|
4985
5191
|
type: "object",
|
|
4986
5192
|
properties: {
|
|
4987
|
-
text: {
|
|
4988
|
-
|
|
5193
|
+
text: {
|
|
5194
|
+
type: "string",
|
|
5195
|
+
description: "The fact or note to remember. Keep it concise and factual."
|
|
5196
|
+
},
|
|
5197
|
+
scope: {
|
|
5198
|
+
type: "string",
|
|
5199
|
+
enum: ["project-agents", "project-memory", "user-memory"],
|
|
5200
|
+
description: "Where to store it: project-memory (shared), user-memory (personal), or project-agents."
|
|
5201
|
+
}
|
|
4989
5202
|
},
|
|
4990
5203
|
required: ["text"]
|
|
4991
5204
|
},
|
|
@@ -5001,8 +5214,8 @@ function forgetTool(memory) {
|
|
|
5001
5214
|
return {
|
|
5002
5215
|
name: "forget",
|
|
5003
5216
|
category: "Session",
|
|
5004
|
-
description: "Remove memory entries
|
|
5005
|
-
usageHint: "
|
|
5217
|
+
description: "Remove memory entries that contain the given substring (case-insensitive). Use with caution.",
|
|
5218
|
+
usageHint: "This permanently deletes matching memories in the chosen scope.\n- Provide a reasonably specific `query` to avoid deleting unrelated memories.\n- Always double-check before calling with broad queries.\n- Use `remember` + `forget` together to maintain clean long-term memory.",
|
|
5006
5219
|
permission: "confirm",
|
|
5007
5220
|
mutating: true,
|
|
5008
5221
|
timeoutMs: 2e3,
|
|
@@ -5028,8 +5241,8 @@ function createModeTool(modeStore) {
|
|
|
5028
5241
|
return {
|
|
5029
5242
|
name: "mode",
|
|
5030
5243
|
category: "Session",
|
|
5031
|
-
description: "
|
|
5032
|
-
usageHint: "
|
|
5244
|
+
description: "Manage agent operating modes. Modes change the agent's behavior, personality, and system prompt for different workflows (e.g. coding, security review, planning).",
|
|
5245
|
+
usageHint: "POWERFUL BEHAVIOR CONTROL TOOL:\n\n- Use `list` to see available modes.\n- Use `set <modeId>` to switch the agent into a specific role/mode.\n- Use `get` to check current mode.\n- Use `clear` to return to default behavior.\nSwitching modes is very effective for specialized tasks. The mode change affects how the agent reasons and which guidelines it follows.",
|
|
5033
5246
|
permission: "confirm",
|
|
5034
5247
|
mutating: true,
|
|
5035
5248
|
timeoutMs: 5e3,
|
|
@@ -5039,11 +5252,11 @@ function createModeTool(modeStore) {
|
|
|
5039
5252
|
action: {
|
|
5040
5253
|
type: "string",
|
|
5041
5254
|
enum: ["get", "list", "set", "clear"],
|
|
5042
|
-
description: "
|
|
5255
|
+
description: "The mode operation to perform."
|
|
5043
5256
|
},
|
|
5044
5257
|
mode: {
|
|
5045
5258
|
type: "string",
|
|
5046
|
-
description: "
|
|
5259
|
+
description: "The mode identifier to activate (only required when action=set)."
|
|
5047
5260
|
}
|
|
5048
5261
|
},
|
|
5049
5262
|
required: ["action"]
|
|
@@ -5143,8 +5356,14 @@ function lspKindToInternalKind(k) {
|
|
|
5143
5356
|
}
|
|
5144
5357
|
|
|
5145
5358
|
// src/codebase-index/writer.ts
|
|
5146
|
-
var INDEX_DIR = ".codebase-index";
|
|
5147
5359
|
var DB_FILE = "index.db";
|
|
5360
|
+
function resolveIndexDir(projectRoot, override) {
|
|
5361
|
+
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
5362
|
+
}
|
|
5363
|
+
function codebaseIndexDirOverride(ctx) {
|
|
5364
|
+
const v = ctx.meta?.["codebaseIndexDir"];
|
|
5365
|
+
return typeof v === "string" ? v : void 0;
|
|
5366
|
+
}
|
|
5148
5367
|
var warningSilenced = false;
|
|
5149
5368
|
function silenceSqliteExperimentalWarning() {
|
|
5150
5369
|
if (warningSilenced) return;
|
|
@@ -5172,16 +5391,16 @@ function loadDatabaseSync() {
|
|
|
5172
5391
|
return DatabaseSyncCtor;
|
|
5173
5392
|
}
|
|
5174
5393
|
var IndexStore = class {
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
|
|
5394
|
+
db;
|
|
5395
|
+
/** Absolute path to this project's index directory. */
|
|
5396
|
+
indexDir;
|
|
5397
|
+
constructor(projectRoot, opts = {}) {
|
|
5398
|
+
this.indexDir = resolveIndexDir(projectRoot, opts.indexDir);
|
|
5399
|
+
fs13.mkdirSync(this.indexDir, { recursive: true });
|
|
5179
5400
|
const Database = loadDatabaseSync();
|
|
5180
|
-
this.db = new Database(path.join(
|
|
5401
|
+
this.db = new Database(path.join(this.indexDir, DB_FILE));
|
|
5181
5402
|
this.initSchema();
|
|
5182
5403
|
}
|
|
5183
|
-
projectRoot;
|
|
5184
|
-
db;
|
|
5185
5404
|
initSchema() {
|
|
5186
5405
|
this.db.exec(`
|
|
5187
5406
|
CREATE TABLE IF NOT EXISTS metadata (
|
|
@@ -5372,7 +5591,7 @@ var IndexStore = class {
|
|
|
5372
5591
|
totalFiles,
|
|
5373
5592
|
byLang,
|
|
5374
5593
|
byKind,
|
|
5375
|
-
indexPath:
|
|
5594
|
+
indexPath: this.indexDir,
|
|
5376
5595
|
lastIndexed,
|
|
5377
5596
|
sizeBytes,
|
|
5378
5597
|
version: SCHEMA_VERSION
|
|
@@ -5465,7 +5684,7 @@ var IndexStore = class {
|
|
|
5465
5684
|
}));
|
|
5466
5685
|
}
|
|
5467
5686
|
sizeBytes() {
|
|
5468
|
-
const dbPath = path.join(this.
|
|
5687
|
+
const dbPath = path.join(this.indexDir, DB_FILE);
|
|
5469
5688
|
try {
|
|
5470
5689
|
return fs13.statSync(dbPath).size;
|
|
5471
5690
|
} catch {
|
|
@@ -6275,7 +6494,7 @@ function regexParse(opts) {
|
|
|
6275
6494
|
}
|
|
6276
6495
|
return lo + 1;
|
|
6277
6496
|
}
|
|
6278
|
-
function extractDeclaration(lineIdx,
|
|
6497
|
+
function extractDeclaration(lineIdx, _match) {
|
|
6279
6498
|
const line = lines[lineIdx] ?? "";
|
|
6280
6499
|
return line.trim().slice(0, 500);
|
|
6281
6500
|
}
|
|
@@ -6740,9 +6959,9 @@ async function parseFile(file, content, lang) {
|
|
|
6740
6959
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
6741
6960
|
}
|
|
6742
6961
|
}
|
|
6743
|
-
async function runIndexer(
|
|
6744
|
-
const { projectRoot, force = false, langs, ignore = [] } = opts;
|
|
6745
|
-
const store = new IndexStore(projectRoot);
|
|
6962
|
+
async function runIndexer(_ctx, opts) {
|
|
6963
|
+
const { projectRoot, force = false, langs, ignore = [], indexDir } = opts;
|
|
6964
|
+
const store = new IndexStore(projectRoot, { indexDir });
|
|
6746
6965
|
const startMs = Date.now();
|
|
6747
6966
|
const errors = [];
|
|
6748
6967
|
const langStats = {};
|
|
@@ -6859,8 +7078,8 @@ async function runIndexer(ctx, opts) {
|
|
|
6859
7078
|
var codebaseIndexTool = {
|
|
6860
7079
|
name: "codebase-index",
|
|
6861
7080
|
category: "Project",
|
|
6862
|
-
description: "Build or update the symbol index
|
|
6863
|
-
usageHint: "
|
|
7081
|
+
description: "Build or incrementally update the project-wide symbol index. This powers fast codebase search and understanding. By default it only processes files that have changed since the last indexing run.",
|
|
7082
|
+
usageHint: "IMPORTANT FOR LARGE CODEBASES:\n\n- First run (or after major changes): consider `force: true` for a clean rebuild.\n- Normal usage: call without arguments for fast incremental updates.\n- Use `langs` to restrict to specific languages if you only care about certain parts of the project.\nThis tool is relatively expensive \u2014 do not call it on every turn. Use it when the index is stale or before heavy codebase-search sessions.",
|
|
6864
7083
|
permission: "auto",
|
|
6865
7084
|
mutating: true,
|
|
6866
7085
|
timeoutMs: 12e4,
|
|
@@ -6882,7 +7101,8 @@ var codebaseIndexTool = {
|
|
|
6882
7101
|
const result = await runIndexer(ctx, {
|
|
6883
7102
|
projectRoot: ctx.projectRoot,
|
|
6884
7103
|
force: input.force ?? false,
|
|
6885
|
-
langs: input.langs
|
|
7104
|
+
langs: input.langs,
|
|
7105
|
+
indexDir: codebaseIndexDirOverride(ctx)
|
|
6886
7106
|
});
|
|
6887
7107
|
return result;
|
|
6888
7108
|
}
|
|
@@ -6980,10 +7200,11 @@ var Bm25Index = class {
|
|
|
6980
7200
|
var codebaseSearchTool = {
|
|
6981
7201
|
name: "codebase-search",
|
|
6982
7202
|
category: "Project",
|
|
6983
|
-
description: "
|
|
6984
|
-
usageHint: "
|
|
7203
|
+
description: "Semantic/keyword search over the indexed codebase symbols (functions, classes, interfaces, etc.). Uses BM25 ranking. Much more powerful and structured than raw `grep` for finding code by name or concept.",
|
|
7204
|
+
usageHint: "PREFERRED FOR CODE UNDERSTANDING:\n\n- Use when you need to find where something is defined or used by name.\n- `kind` filter is very useful (e.g. only functions or only interfaces).\n- Combine with `file` filter to scope to a specific directory or module.\nThis is generally better than `grep` when you are looking for symbols rather than arbitrary text patterns.",
|
|
6985
7205
|
permission: "auto",
|
|
6986
7206
|
mutating: false,
|
|
7207
|
+
capabilities: ["fs.read"],
|
|
6987
7208
|
timeoutMs: 1e4,
|
|
6988
7209
|
inputSchema: {
|
|
6989
7210
|
type: "object",
|
|
@@ -7018,7 +7239,7 @@ var codebaseSearchTool = {
|
|
|
7018
7239
|
required: ["query"]
|
|
7019
7240
|
},
|
|
7020
7241
|
async execute(input, ctx) {
|
|
7021
|
-
const store = new IndexStore(ctx.projectRoot);
|
|
7242
|
+
const store = new IndexStore(ctx.projectRoot, { indexDir: codebaseIndexDirOverride(ctx) });
|
|
7022
7243
|
try {
|
|
7023
7244
|
const limit = Math.min(input.limit ?? 20, 100);
|
|
7024
7245
|
const candidates = store.search(input.query, {
|
|
@@ -7063,10 +7284,11 @@ var codebaseSearchTool = {
|
|
|
7063
7284
|
var codebaseStatsTool = {
|
|
7064
7285
|
name: "codebase-stats",
|
|
7065
7286
|
category: "Project",
|
|
7066
|
-
description: "Return statistics about the symbol index
|
|
7067
|
-
usageHint: "
|
|
7287
|
+
description: "Return health and statistics about the current symbol index (total symbols, files, language/kind breakdown, size, last update). Useful to decide whether to re-index.",
|
|
7288
|
+
usageHint: "CALL BEFORE HEAVY CODEBASE-SEARCH WORK:\n\n- Use to see if the index is up-to-date or needs a refresh.\n- No arguments required.\n- Helps avoid wasting tokens on searches against a stale index.\nLightweight and safe to call frequently.",
|
|
7068
7289
|
permission: "auto",
|
|
7069
7290
|
mutating: false,
|
|
7291
|
+
capabilities: ["fs.read"],
|
|
7070
7292
|
timeoutMs: 5e3,
|
|
7071
7293
|
inputSchema: {
|
|
7072
7294
|
type: "object",
|
|
@@ -7074,7 +7296,7 @@ var codebaseStatsTool = {
|
|
|
7074
7296
|
additionalProperties: false
|
|
7075
7297
|
},
|
|
7076
7298
|
async execute(_input, ctx) {
|
|
7077
|
-
const store = new IndexStore(ctx.projectRoot);
|
|
7299
|
+
const store = new IndexStore(ctx.projectRoot, { indexDir: codebaseIndexDirOverride(ctx) });
|
|
7078
7300
|
try {
|
|
7079
7301
|
const stats = store.getStats();
|
|
7080
7302
|
return {
|
|
@@ -7134,7 +7356,7 @@ var builtinTools = [
|
|
|
7134
7356
|
// src/pack.ts
|
|
7135
7357
|
var builtinToolsPack = {
|
|
7136
7358
|
name: "builtin-tools",
|
|
7137
|
-
description: "
|
|
7359
|
+
description: "The complete set of built-in tools that ship with WrongStack. Covers filesystem (read/write/edit/replace/glob/grep/tree), execution (bash/exec/git/install), networking (fetch/search), code quality (lint/test/typecheck/format), planning (todo/plan/memory), and meta tools (tool-search/tool-help/batch-tool-use/codebase-*).",
|
|
7138
7360
|
tools: builtinTools
|
|
7139
7361
|
};
|
|
7140
7362
|
|