@wrongstack/tools 0.32.0 → 0.51.3
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 +15 -15
- package/dist/audit.js.map +1 -1
- package/dist/bash.js +3 -2
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +108 -112
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.js +2 -1
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/diff.js +10 -9
- package/dist/diff.js.map +1 -1
- package/dist/document.js +4 -4
- package/dist/document.js.map +1 -1
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +3 -2
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +4 -2
- package/dist/format.js.map +1 -1
- package/dist/git.js +3 -2
- package/dist/git.js.map +1 -1
- package/dist/glob.js.map +1 -1
- package/dist/grep.js.map +1 -1
- package/dist/index.js +108 -112
- package/dist/index.js.map +1 -1
- package/dist/install.js +17 -16
- package/dist/install.js.map +1 -1
- package/dist/lint.js +3 -2
- package/dist/lint.js.map +1 -1
- package/dist/logs.js.map +1 -1
- package/dist/outdated.js +16 -16
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +108 -112
- package/dist/pack.js.map +1 -1
- package/dist/patch.js.map +1 -1
- package/dist/read.js.map +1 -1
- package/dist/replace.js.map +1 -1
- package/dist/scaffold.js.map +1 -1
- package/dist/test.js +3 -2
- package/dist/test.js.map +1 -1
- package/dist/tree.js.map +1 -1
- package/dist/typecheck.js +3 -2
- package/dist/typecheck.js.map +1 -1
- package/dist/write.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as fs4 from 'node:fs/promises';
|
|
2
|
-
import { stat } from 'node:fs/promises';
|
|
3
2
|
import * as path from 'node:path';
|
|
4
3
|
import { resolve, sep, dirname } from 'node:path';
|
|
5
|
-
import
|
|
4
|
+
import * as Core from '@wrongstack/core';
|
|
5
|
+
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, buildChildEnv, loadPlan, emptyPlan, clearPlan, savePlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, formatPlan, 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';
|
|
@@ -19,6 +19,20 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
19
19
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
20
20
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
21
21
|
});
|
|
22
|
+
async function detectPackageManager(cwd) {
|
|
23
|
+
const { stat: stat10 } = await import('node:fs/promises');
|
|
24
|
+
try {
|
|
25
|
+
await stat10(`${cwd}/pnpm-lock.yaml`);
|
|
26
|
+
return "pnpm";
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
await stat10(`${cwd}/yarn.lock`);
|
|
31
|
+
return "yarn";
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
return "npm";
|
|
35
|
+
}
|
|
22
36
|
function resolvePath(input, ctx) {
|
|
23
37
|
return path.isAbsolute(input) ? path.normalize(input) : path.resolve(ctx.cwd, input);
|
|
24
38
|
}
|
|
@@ -141,7 +155,7 @@ ${tail}`;
|
|
|
141
155
|
}
|
|
142
156
|
function normalizeCommandOutput(raw, opts = {}) {
|
|
143
157
|
if (!raw) return raw;
|
|
144
|
-
let text = stripAnsi(raw);
|
|
158
|
+
let text = Core.stripAnsi(raw);
|
|
145
159
|
text = collapseCarriageReturns(text);
|
|
146
160
|
text = text.replace(/[ \t]+$/gm, "");
|
|
147
161
|
text = collapseConsecutiveDuplicates(text);
|
|
@@ -182,9 +196,9 @@ var readTool = {
|
|
|
182
196
|
async execute(input, ctx) {
|
|
183
197
|
if (!input?.path) throw new Error("read: path is required");
|
|
184
198
|
const absPath = await safeResolveReal(input.path, ctx);
|
|
185
|
-
let
|
|
199
|
+
let stat10;
|
|
186
200
|
try {
|
|
187
|
-
|
|
201
|
+
stat10 = await fs4.stat(absPath);
|
|
188
202
|
} catch (err) {
|
|
189
203
|
const code = err.code;
|
|
190
204
|
if (code === "ENOENT") throw new Error(`read: file not found "${input.path}"`);
|
|
@@ -192,9 +206,9 @@ var readTool = {
|
|
|
192
206
|
`read: failed to stat "${input.path}": ${err instanceof Error ? err.message : String(err)}`
|
|
193
207
|
);
|
|
194
208
|
}
|
|
195
|
-
if (!
|
|
196
|
-
if (
|
|
197
|
-
throw new Error(`read: file too large (${
|
|
209
|
+
if (!stat10.isFile()) throw new Error(`read: "${input.path}" is not a regular file`);
|
|
210
|
+
if (stat10.size > MAX_BYTES) {
|
|
211
|
+
throw new Error(`read: file too large (${stat10.size} bytes, limit ${MAX_BYTES})`);
|
|
198
212
|
}
|
|
199
213
|
const buf = await fs4.readFile(absPath);
|
|
200
214
|
if (isBinaryBuffer(buf)) {
|
|
@@ -206,14 +220,14 @@ var readTool = {
|
|
|
206
220
|
const offset = Math.max(1, input.offset ?? 1);
|
|
207
221
|
const limit = Math.max(0, Math.min(input.limit ?? 2e3, 5e3));
|
|
208
222
|
if (limit === 0) {
|
|
209
|
-
ctx.recordRead(absPath,
|
|
223
|
+
ctx.recordRead(absPath, stat10.mtimeMs);
|
|
210
224
|
return { text: "", total_lines: total, encoding: "utf8", truncated: total > 0 };
|
|
211
225
|
}
|
|
212
226
|
const slice = allLines.slice(offset - 1, offset - 1 + limit);
|
|
213
227
|
const truncated = offset - 1 + slice.length < total;
|
|
214
228
|
const width = String(offset + slice.length - 1).length;
|
|
215
229
|
const numbered = slice.map((line, i) => `${String(offset + i).padStart(width, " ")}\u2192${line}`).join("\n");
|
|
216
|
-
ctx.recordRead(absPath,
|
|
230
|
+
ctx.recordRead(absPath, stat10.mtimeMs);
|
|
217
231
|
return {
|
|
218
232
|
text: numbered,
|
|
219
233
|
total_lines: total,
|
|
@@ -252,12 +266,12 @@ var writeTool = {
|
|
|
252
266
|
let existed = false;
|
|
253
267
|
let prev = "";
|
|
254
268
|
try {
|
|
255
|
-
const
|
|
256
|
-
existed =
|
|
269
|
+
const stat11 = await fs4.stat(absPath);
|
|
270
|
+
existed = stat11.isFile();
|
|
257
271
|
if (existed) {
|
|
258
272
|
if (!ctx.hasRead(absPath)) {
|
|
259
273
|
prev = await fs4.readFile(absPath, "utf8");
|
|
260
|
-
ctx.recordRead(absPath,
|
|
274
|
+
ctx.recordRead(absPath, stat11.mtimeMs);
|
|
261
275
|
} else {
|
|
262
276
|
prev = await fs4.readFile(absPath, "utf8");
|
|
263
277
|
}
|
|
@@ -270,8 +284,8 @@ var writeTool = {
|
|
|
270
284
|
await atomicWrite(absPath, input.content);
|
|
271
285
|
const diff = existed ? unifiedDiff(prev, input.content, { fromFile: input.path, toFile: input.path }) : `+++ ${input.path}
|
|
272
286
|
+ (new file, ${input.content.split("\n").length} lines)`;
|
|
273
|
-
const
|
|
274
|
-
ctx.recordRead(absPath,
|
|
287
|
+
const stat10 = await fs4.stat(absPath);
|
|
288
|
+
ctx.recordRead(absPath, stat10.mtimeMs);
|
|
275
289
|
ctx.session.recordFileChange({
|
|
276
290
|
path: absPath,
|
|
277
291
|
action: existed ? "modified" : "created",
|
|
@@ -311,13 +325,13 @@ var editTool = {
|
|
|
311
325
|
if (input.new_string === void 0) throw new Error("edit: new_string is required");
|
|
312
326
|
if (input.old_string === "") throw new Error("edit: old_string cannot be empty");
|
|
313
327
|
const absPath = await safeResolveReal(input.path, ctx);
|
|
314
|
-
const
|
|
328
|
+
const stat10 = await fs4.stat(absPath).catch((err) => {
|
|
315
329
|
if (err.code === "ENOENT") {
|
|
316
330
|
throw new Error(`edit: file "${input.path}" does not exist. Use \`write\` instead.`);
|
|
317
331
|
}
|
|
318
332
|
throw err;
|
|
319
333
|
});
|
|
320
|
-
if (!
|
|
334
|
+
if (!stat10.isFile()) throw new Error(`edit: "${input.path}" is not a regular file`);
|
|
321
335
|
if (!ctx.hasRead(absPath)) {
|
|
322
336
|
throw new Error(`edit: file "${input.path}" was not read in this session. Read it first.`);
|
|
323
337
|
}
|
|
@@ -511,8 +525,8 @@ var replaceTool = {
|
|
|
511
525
|
}
|
|
512
526
|
const rel = path.relative(realRoot, realPath);
|
|
513
527
|
if (rel.startsWith("..") || path.isAbsolute(rel)) continue;
|
|
514
|
-
const
|
|
515
|
-
if (!
|
|
528
|
+
const stat10 = await fs4.stat(realPath).catch(() => null);
|
|
529
|
+
if (!stat10 || !stat10.isFile()) continue;
|
|
516
530
|
let content;
|
|
517
531
|
try {
|
|
518
532
|
const buf = await fs4.readFile(realPath);
|
|
@@ -537,7 +551,7 @@ var replaceTool = {
|
|
|
537
551
|
totalReplacements += count;
|
|
538
552
|
if (!dryRun) {
|
|
539
553
|
const newContent = toStyle(newContentLf, style);
|
|
540
|
-
await atomicWrite(realPath, newContent, { mode:
|
|
554
|
+
await atomicWrite(realPath, newContent, { mode: stat10.mode & 511 });
|
|
541
555
|
}
|
|
542
556
|
const diff = dryRun || matches.length > 0 ? unifiedDiff(content, toStyle(newContentLf, style), {
|
|
543
557
|
fromFile: absPath,
|
|
@@ -567,8 +581,8 @@ async function resolveFiles(filesInput, ctx, extraGlob) {
|
|
|
567
581
|
const resolved = [];
|
|
568
582
|
for (const p of parts) {
|
|
569
583
|
const absPath = safeResolve(p, ctx);
|
|
570
|
-
const
|
|
571
|
-
if (
|
|
584
|
+
const stat10 = await fs4.stat(absPath).catch(() => null);
|
|
585
|
+
if (stat10?.isFile()) {
|
|
572
586
|
resolved.push(absPath);
|
|
573
587
|
}
|
|
574
588
|
}
|
|
@@ -626,8 +640,8 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
626
640
|
if (DEFAULT_IGNORE.includes(e.name)) continue;
|
|
627
641
|
const full = path.join(dir, e.name);
|
|
628
642
|
try {
|
|
629
|
-
const
|
|
630
|
-
if (
|
|
643
|
+
const stat10 = await fs4.lstat(full);
|
|
644
|
+
if (stat10.isSymbolicLink()) continue;
|
|
631
645
|
} catch {
|
|
632
646
|
continue;
|
|
633
647
|
}
|
|
@@ -976,8 +990,8 @@ async function runNative(input, base, mode, limit, signal) {
|
|
|
976
990
|
if (globRe && !globRe.test(e.name) && !globRe.test(full)) continue;
|
|
977
991
|
if (globRe) globRe.lastIndex = 0;
|
|
978
992
|
try {
|
|
979
|
-
const
|
|
980
|
-
if (
|
|
993
|
+
const stat10 = await fs4.stat(full);
|
|
994
|
+
if (stat10.size > 1e6) continue;
|
|
981
995
|
const head = await fs4.readFile(full);
|
|
982
996
|
if (isBinaryBuffer(head)) continue;
|
|
983
997
|
const text = head.toString("utf8");
|
|
@@ -2510,15 +2524,26 @@ var planTool = {
|
|
|
2510
2524
|
category: "Session",
|
|
2511
2525
|
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.",
|
|
2512
2526
|
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.',
|
|
2513
|
-
permission: "
|
|
2514
|
-
mutating:
|
|
2527
|
+
permission: "confirm",
|
|
2528
|
+
mutating: true,
|
|
2529
|
+
capabilities: ["fs.write"],
|
|
2515
2530
|
timeoutMs: 2e3,
|
|
2516
2531
|
inputSchema: {
|
|
2517
2532
|
type: "object",
|
|
2518
2533
|
properties: {
|
|
2519
2534
|
action: {
|
|
2520
2535
|
type: "string",
|
|
2521
|
-
enum: [
|
|
2536
|
+
enum: [
|
|
2537
|
+
"show",
|
|
2538
|
+
"add",
|
|
2539
|
+
"start",
|
|
2540
|
+
"done",
|
|
2541
|
+
"remove",
|
|
2542
|
+
"promote",
|
|
2543
|
+
"derive",
|
|
2544
|
+
"template_use",
|
|
2545
|
+
"clear"
|
|
2546
|
+
],
|
|
2522
2547
|
description: "The operation to perform on the plan board."
|
|
2523
2548
|
},
|
|
2524
2549
|
title: {
|
|
@@ -2611,7 +2636,12 @@ var planTool = {
|
|
|
2611
2636
|
plan = derived.plan;
|
|
2612
2637
|
await savePlan(planPath, plan);
|
|
2613
2638
|
ctx.state.replaceTodos(derived.todos);
|
|
2614
|
-
return mkResult(
|
|
2639
|
+
return mkResult(
|
|
2640
|
+
plan,
|
|
2641
|
+
true,
|
|
2642
|
+
`${input.action} ok \u2014 ${derived.todos.length} todo(s) created.`,
|
|
2643
|
+
derived.todos
|
|
2644
|
+
);
|
|
2615
2645
|
}
|
|
2616
2646
|
case "template_use": {
|
|
2617
2647
|
const templateName = input.template?.trim();
|
|
@@ -2626,7 +2656,11 @@ var planTool = {
|
|
|
2626
2656
|
({ plan } = addPlanItem(plan, item.title, item.details));
|
|
2627
2657
|
}
|
|
2628
2658
|
await savePlan(planPath, plan);
|
|
2629
|
-
return mkResult(
|
|
2659
|
+
return mkResult(
|
|
2660
|
+
plan,
|
|
2661
|
+
true,
|
|
2662
|
+
`Applied template "${template.name}" \u2014 ${template.items.length} items added.`
|
|
2663
|
+
);
|
|
2630
2664
|
}
|
|
2631
2665
|
case "clear":
|
|
2632
2666
|
plan = clearPlan(plan);
|
|
@@ -2772,8 +2806,8 @@ function findGitDir(cwd, projectRoot) {
|
|
|
2772
2806
|
let dir = cwd;
|
|
2773
2807
|
for (let i = 0; i < 20; i++) {
|
|
2774
2808
|
try {
|
|
2775
|
-
const
|
|
2776
|
-
if (
|
|
2809
|
+
const stat10 = statSync(`${dir}/.git`);
|
|
2810
|
+
if (stat10.isDirectory() || stat10.isFile()) return dir;
|
|
2777
2811
|
} catch {
|
|
2778
2812
|
}
|
|
2779
2813
|
if (dir === root) break;
|
|
@@ -3127,8 +3161,8 @@ function toYaml(data, indent = 0) {
|
|
|
3127
3161
|
var diffTool = {
|
|
3128
3162
|
name: "diff",
|
|
3129
3163
|
category: "Filesystem",
|
|
3130
|
-
description: "Show
|
|
3131
|
-
usageHint: 'USE FOR CODE REVIEW AND CHANGE INSPECTION:\n\n- `files` + no `a`/`b` \u2192
|
|
3164
|
+
description: "Show file content with line numbers, staged/working-tree diffs via git, or commit/branch diffs. A safer and more structured alternative to raw `git diff` via shell.",
|
|
3165
|
+
usageHint: 'USE FOR CODE REVIEW AND CHANGE INSPECTION:\n\n- `files` + no `a`/`b` \u2192 show file content with line numbers (NOT a unified diff; no +/- prefixes).\n- `a` and/or `b` \u2192 git-style commit/branch diff (unified format, real +/- prefixes).\n- `staged: true` \u2192 only show staged changes.\n- `mode` can be "unified", "stat", or "side-by-side" (only affects the git-diff path).\n\nNOTE: For a true file-vs-file unified diff, supply `a` and `b` so the tool delegates to `git diff`. The `files`-only path is a line-numbered dump, not a diff.\n\nThis tool has important safety guards against flag injection (see previous security findings).',
|
|
3132
3166
|
permission: "auto",
|
|
3133
3167
|
mutating: false,
|
|
3134
3168
|
capabilities: ["fs.read"],
|
|
@@ -3205,8 +3239,8 @@ function findGitDir2(cwd) {
|
|
|
3205
3239
|
let dir = cwd;
|
|
3206
3240
|
for (let i = 0; i < 20; i++) {
|
|
3207
3241
|
try {
|
|
3208
|
-
const
|
|
3209
|
-
if (
|
|
3242
|
+
const stat10 = statSync(path.join(dir, ".git"));
|
|
3243
|
+
if (stat10.isDirectory()) return dir;
|
|
3210
3244
|
} catch {
|
|
3211
3245
|
}
|
|
3212
3246
|
const parent = path.dirname(dir);
|
|
@@ -3236,7 +3270,7 @@ function runGit2(args, cwd, signal) {
|
|
|
3236
3270
|
});
|
|
3237
3271
|
}
|
|
3238
3272
|
async function fileDiff(input, ctx, _signal) {
|
|
3239
|
-
input.context
|
|
3273
|
+
void input.context;
|
|
3240
3274
|
const files = input.files ? (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim()).filter(Boolean) : [];
|
|
3241
3275
|
if (files.length === 0) {
|
|
3242
3276
|
return {
|
|
@@ -3249,23 +3283,24 @@ async function fileDiff(input, ctx, _signal) {
|
|
|
3249
3283
|
const results = [];
|
|
3250
3284
|
for (const file of files) {
|
|
3251
3285
|
const absPath = safeResolve(file, ctx);
|
|
3252
|
-
const
|
|
3253
|
-
if (!
|
|
3286
|
+
const stat10 = await fs4.stat(absPath).catch(() => null);
|
|
3287
|
+
if (!stat10?.isFile()) continue;
|
|
3254
3288
|
const content = await fs4.readFile(absPath, "utf8");
|
|
3255
3289
|
const lines = content.split(/\r?\n/);
|
|
3256
|
-
results.push(
|
|
3257
|
-
+++ ${file}
|
|
3258
|
-
${formatUnified(lines)}`);
|
|
3290
|
+
results.push(formatWithLineNumbers(file, lines));
|
|
3259
3291
|
}
|
|
3260
3292
|
return {
|
|
3261
|
-
diff: results.join("\n"),
|
|
3293
|
+
diff: results.join("\n\n"),
|
|
3262
3294
|
files,
|
|
3263
3295
|
truncated: false,
|
|
3264
3296
|
mode: input.mode ?? "unified"
|
|
3265
3297
|
};
|
|
3266
3298
|
}
|
|
3267
|
-
function
|
|
3268
|
-
|
|
3299
|
+
function formatWithLineNumbers(file, lines) {
|
|
3300
|
+
const width = String(lines.length).length;
|
|
3301
|
+
const numbered = lines.map((line, i) => `${String(i + 1).padStart(width)} | ${line}`).join("\n");
|
|
3302
|
+
return `--- ${file} (line-numbered dump, not a unified diff) ---
|
|
3303
|
+
${numbered}`;
|
|
3269
3304
|
}
|
|
3270
3305
|
var DEFAULT_IGNORE4 = [
|
|
3271
3306
|
"node_modules",
|
|
@@ -3599,11 +3634,11 @@ var lintTool = {
|
|
|
3599
3634
|
}
|
|
3600
3635
|
};
|
|
3601
3636
|
async function detectLinter(cwd) {
|
|
3602
|
-
const { stat:
|
|
3637
|
+
const { stat: stat10 } = await import('node:fs/promises');
|
|
3603
3638
|
const checks = ["biome.json", ".eslintrc.json", "tslint.json", ".eslintrc.js", "tsconfig.json"];
|
|
3604
3639
|
for (const f of checks) {
|
|
3605
3640
|
try {
|
|
3606
|
-
await
|
|
3641
|
+
await stat10(`${cwd}/${f}`);
|
|
3607
3642
|
if (f.includes("biome")) return "biome";
|
|
3608
3643
|
if (f.includes("eslint")) return "eslint";
|
|
3609
3644
|
if (f.includes("tslint")) return "tslint";
|
|
@@ -3621,6 +3656,7 @@ var formatTool = {
|
|
|
3621
3656
|
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.",
|
|
3622
3657
|
permission: "confirm",
|
|
3623
3658
|
mutating: true,
|
|
3659
|
+
capabilities: ["fs.write", "shell.exec"],
|
|
3624
3660
|
timeoutMs: 6e4,
|
|
3625
3661
|
inputSchema: {
|
|
3626
3662
|
type: "object",
|
|
@@ -3698,13 +3734,13 @@ var formatTool = {
|
|
|
3698
3734
|
}
|
|
3699
3735
|
};
|
|
3700
3736
|
async function detectFixer(cwd) {
|
|
3701
|
-
const { stat:
|
|
3737
|
+
const { stat: stat10 } = await import('node:fs/promises');
|
|
3702
3738
|
try {
|
|
3703
|
-
await
|
|
3739
|
+
await stat10(`${cwd}/biome.json`);
|
|
3704
3740
|
return "biome";
|
|
3705
3741
|
} catch {
|
|
3706
3742
|
try {
|
|
3707
|
-
await
|
|
3743
|
+
await stat10(`${cwd}/.prettierrc`);
|
|
3708
3744
|
return "prettier";
|
|
3709
3745
|
} catch {
|
|
3710
3746
|
return "biome";
|
|
@@ -3780,11 +3816,11 @@ var typecheckTool = {
|
|
|
3780
3816
|
}
|
|
3781
3817
|
};
|
|
3782
3818
|
async function findTsConfig(cwd) {
|
|
3783
|
-
const { stat:
|
|
3819
|
+
const { stat: stat10 } = await import('node:fs/promises');
|
|
3784
3820
|
const candidates = ["tsconfig.json", "tsconfig.base.json"];
|
|
3785
3821
|
for (const f of candidates) {
|
|
3786
3822
|
try {
|
|
3787
|
-
const s = await
|
|
3823
|
+
const s = await stat10(path.join(cwd, f));
|
|
3788
3824
|
if (s.isFile()) return path.join(cwd, f);
|
|
3789
3825
|
} catch {
|
|
3790
3826
|
}
|
|
@@ -3861,11 +3897,11 @@ var testTool = {
|
|
|
3861
3897
|
}
|
|
3862
3898
|
};
|
|
3863
3899
|
async function detectRunner(cwd) {
|
|
3864
|
-
const { stat:
|
|
3900
|
+
const { stat: stat10 } = await import('node:fs/promises');
|
|
3865
3901
|
const candidates = ["vitest.config.ts", "jest.config.js", ".mocharc.json"];
|
|
3866
3902
|
for (const f of candidates) {
|
|
3867
3903
|
try {
|
|
3868
|
-
await
|
|
3904
|
+
await stat10(path.join(cwd, f));
|
|
3869
3905
|
if (f.includes("vitest")) return "vitest";
|
|
3870
3906
|
if (f.includes("jest")) return "jest";
|
|
3871
3907
|
if (f.includes("mocha")) return "mocha";
|
|
@@ -4042,20 +4078,6 @@ var installTool = {
|
|
|
4042
4078
|
};
|
|
4043
4079
|
}
|
|
4044
4080
|
};
|
|
4045
|
-
async function detectPackageManager(cwd) {
|
|
4046
|
-
const { stat: stat11 } = await import('node:fs/promises');
|
|
4047
|
-
try {
|
|
4048
|
-
await stat11(`${cwd}/pnpm-lock.yaml`);
|
|
4049
|
-
return "pnpm";
|
|
4050
|
-
} catch {
|
|
4051
|
-
try {
|
|
4052
|
-
await stat11(`${cwd}/yarn.lock`);
|
|
4053
|
-
return "yarn";
|
|
4054
|
-
} catch {
|
|
4055
|
-
return "npm";
|
|
4056
|
-
}
|
|
4057
|
-
}
|
|
4058
|
-
}
|
|
4059
4081
|
|
|
4060
4082
|
// src/audit.ts
|
|
4061
4083
|
var auditTool = {
|
|
@@ -4089,7 +4111,7 @@ var auditTool = {
|
|
|
4089
4111
|
},
|
|
4090
4112
|
async *executeStream(input, ctx, opts) {
|
|
4091
4113
|
const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;
|
|
4092
|
-
const manager = await
|
|
4114
|
+
const manager = await detectPackageManager(cwd);
|
|
4093
4115
|
yield { type: "log", text: `Auditing with ${manager}\u2026`, data: { manager } };
|
|
4094
4116
|
const args = ["audit", "--json"];
|
|
4095
4117
|
if (input.fix) args.push("--fix");
|
|
@@ -4107,20 +4129,6 @@ var auditTool = {
|
|
|
4107
4129
|
yield { type: "final", output: parseAuditOutput(result.stdout, result.exitCode) };
|
|
4108
4130
|
}
|
|
4109
4131
|
};
|
|
4110
|
-
async function detectManager(cwd) {
|
|
4111
|
-
const { stat: stat11 } = await import('node:fs/promises');
|
|
4112
|
-
try {
|
|
4113
|
-
await stat11(`${cwd}/pnpm-lock.yaml`);
|
|
4114
|
-
return "pnpm";
|
|
4115
|
-
} catch {
|
|
4116
|
-
}
|
|
4117
|
-
try {
|
|
4118
|
-
await stat11(`${cwd}/yarn.lock`);
|
|
4119
|
-
return "yarn";
|
|
4120
|
-
} catch {
|
|
4121
|
-
}
|
|
4122
|
-
return "npm";
|
|
4123
|
-
}
|
|
4124
4132
|
function parseAuditOutput(json, exitCode) {
|
|
4125
4133
|
if (!json) {
|
|
4126
4134
|
return {
|
|
@@ -4172,7 +4180,7 @@ var outdatedTool = {
|
|
|
4172
4180
|
description: "Check for outdated dependencies in the project. Reports current, wanted (semver range), and latest versions available.",
|
|
4173
4181
|
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.",
|
|
4174
4182
|
permission: "auto",
|
|
4175
|
-
mutating:
|
|
4183
|
+
mutating: false,
|
|
4176
4184
|
timeoutMs: 6e4,
|
|
4177
4185
|
inputSchema: {
|
|
4178
4186
|
type: "object",
|
|
@@ -4195,26 +4203,13 @@ var outdatedTool = {
|
|
|
4195
4203
|
},
|
|
4196
4204
|
async execute(input, ctx, opts) {
|
|
4197
4205
|
const cwd = input.cwd ? safeResolve(input.cwd, ctx) : ctx.cwd;
|
|
4198
|
-
const manager = await
|
|
4206
|
+
const manager = await detectPackageManager(cwd);
|
|
4199
4207
|
const args = ["outdated", "--json"];
|
|
4200
4208
|
if (input.format === "table") args.push("--table");
|
|
4201
4209
|
if (input.include_deprecated) args.push("--include", "deprecated");
|
|
4202
4210
|
return runOutdated(manager, args, cwd, opts.signal);
|
|
4203
4211
|
}
|
|
4204
4212
|
};
|
|
4205
|
-
async function detectManager2(cwd) {
|
|
4206
|
-
try {
|
|
4207
|
-
await stat(`${cwd}/pnpm-lock.yaml`);
|
|
4208
|
-
return "pnpm";
|
|
4209
|
-
} catch {
|
|
4210
|
-
}
|
|
4211
|
-
try {
|
|
4212
|
-
await stat(`${cwd}/yarn.lock`);
|
|
4213
|
-
return "yarn";
|
|
4214
|
-
} catch {
|
|
4215
|
-
}
|
|
4216
|
-
return "npm";
|
|
4217
|
-
}
|
|
4218
4213
|
function runOutdated(manager, args, cwd, signal) {
|
|
4219
4214
|
return new Promise((resolve7) => {
|
|
4220
4215
|
let stdout = "";
|
|
@@ -4480,10 +4475,10 @@ function parseLine(line) {
|
|
|
4480
4475
|
var documentTool = {
|
|
4481
4476
|
name: "document",
|
|
4482
4477
|
category: "Project",
|
|
4483
|
-
description: "
|
|
4484
|
-
usageHint: "USE FOR IMPROVING CODE DOCUMENTATION:\n\n- Good for adding missing docs to public APIs or complex functions.\n-
|
|
4485
|
-
permission: "
|
|
4486
|
-
mutating:
|
|
4478
|
+
description: "Preview documentation comments (JSDoc/TSDoc style) that would be generated for code symbols. Returns a list of candidates with status `skipped` \u2014 the tool is currently a read-only preview and does NOT write to files.",
|
|
4479
|
+
usageHint: "USE FOR IMPROVING CODE DOCUMENTATION:\n\n- Good for adding missing docs to public APIs or complex functions.\n- Currently this is a PREVIEW-ONLY tool: it does not modify files.\n- Use the output to decide which symbols to document manually, or pass the candidates to `edit` / `patch`.\n- `overwrite`, `style`, and `target` parameters are accepted for future expansion but are ignored today.\nAlways review the proposed documentation before applying it \u2014 the model can hallucinate details.",
|
|
4480
|
+
permission: "auto",
|
|
4481
|
+
mutating: false,
|
|
4487
4482
|
timeoutMs: 3e4,
|
|
4488
4483
|
inputSchema: {
|
|
4489
4484
|
type: "object",
|
|
@@ -4558,8 +4553,8 @@ async function resolveFiles2(filesInput, cwd) {
|
|
|
4558
4553
|
for (const f of files) {
|
|
4559
4554
|
const absPath = f.trim().startsWith("/") ? f.trim() : `${cwd}/${f.trim()}`;
|
|
4560
4555
|
try {
|
|
4561
|
-
const
|
|
4562
|
-
if (
|
|
4556
|
+
const stat10 = await fs4.stat(absPath);
|
|
4557
|
+
if (stat10.isFile()) resolved.push(absPath);
|
|
4563
4558
|
} catch {
|
|
4564
4559
|
}
|
|
4565
4560
|
}
|
|
@@ -6987,18 +6982,18 @@ async function runIndexer(_ctx, opts) {
|
|
|
6987
6982
|
for (const meta of store.getAllFileMetas()) existingMeta.set(meta.file, meta);
|
|
6988
6983
|
}
|
|
6989
6984
|
for (const file of files) {
|
|
6990
|
-
let
|
|
6985
|
+
let stat10;
|
|
6991
6986
|
try {
|
|
6992
|
-
|
|
6987
|
+
stat10 = await fs4.stat(file);
|
|
6993
6988
|
} catch {
|
|
6994
6989
|
store.deleteFile(file);
|
|
6995
6990
|
continue;
|
|
6996
6991
|
}
|
|
6997
|
-
if (!
|
|
6992
|
+
if (!stat10.isFile()) continue;
|
|
6998
6993
|
const lang = detectLang(file);
|
|
6999
6994
|
if (!lang) continue;
|
|
7000
6995
|
const meta = existingMeta.get(file);
|
|
7001
|
-
if (!force && meta && meta.mtimeMs === Math.floor(
|
|
6996
|
+
if (!force && meta && meta.mtimeMs === Math.floor(stat10.mtimeMs)) {
|
|
7002
6997
|
langStats[lang] = (langStats[lang] ?? 0) + meta.symbolCount;
|
|
7003
6998
|
symbolsIndexed += meta.symbolCount;
|
|
7004
6999
|
filesIndexed++;
|
|
@@ -7024,7 +7019,7 @@ async function runIndexer(_ctx, opts) {
|
|
|
7024
7019
|
store.upsertFile({
|
|
7025
7020
|
file,
|
|
7026
7021
|
lang,
|
|
7027
|
-
mtimeMs: Math.floor(
|
|
7022
|
+
mtimeMs: Math.floor(stat10.mtimeMs),
|
|
7028
7023
|
symbolCount: 0,
|
|
7029
7024
|
lastIndexed: Date.now()
|
|
7030
7025
|
});
|
|
@@ -7050,7 +7045,7 @@ async function runIndexer(_ctx, opts) {
|
|
|
7050
7045
|
store.upsertFile({
|
|
7051
7046
|
file,
|
|
7052
7047
|
lang,
|
|
7053
|
-
mtimeMs: Math.floor(
|
|
7048
|
+
mtimeMs: Math.floor(stat10.mtimeMs),
|
|
7054
7049
|
symbolCount: count,
|
|
7055
7050
|
lastIndexed: Date.now()
|
|
7056
7051
|
});
|
|
@@ -7081,8 +7076,9 @@ var codebaseIndexTool = {
|
|
|
7081
7076
|
category: "Project",
|
|
7082
7077
|
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.",
|
|
7083
7078
|
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.",
|
|
7084
|
-
permission: "
|
|
7079
|
+
permission: "confirm",
|
|
7085
7080
|
mutating: true,
|
|
7081
|
+
capabilities: ["fs.write.outside-project"],
|
|
7086
7082
|
timeoutMs: 12e4,
|
|
7087
7083
|
inputSchema: {
|
|
7088
7084
|
type: "object",
|