@wrongstack/tools 0.9.7 → 0.9.20
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.map +1 -1
- package/dist/bash.js +0 -3
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +67 -30
- 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 +2 -2
- package/dist/codebase-index/index.js +2 -2
- 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 +15 -5
- package/dist/diff.js.map +1 -1
- package/dist/document.js +1 -2
- package/dist/document.js.map +1 -1
- package/dist/edit.js +31 -1
- package/dist/edit.js.map +1 -1
- package/dist/exec.js +0 -3
- package/dist/exec.js.map +1 -1
- package/dist/fetch.d.ts +10 -1
- package/dist/fetch.js +6 -7
- package/dist/fetch.js.map +1 -1
- package/dist/format.js.map +1 -1
- package/dist/glob.js.map +1 -1
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +65 -28
- package/dist/index.js.map +1 -1
- package/dist/install.js.map +1 -1
- package/dist/json.js.map +1 -1
- package/dist/lint.js.map +1 -1
- package/dist/logs.js +4 -0
- package/dist/logs.js.map +1 -1
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +67 -30
- package/dist/pack.js.map +1 -1
- 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 +37 -5
- package/dist/read.js.map +1 -1
- package/dist/replace.js +0 -1
- package/dist/replace.js.map +1 -1
- package/dist/scaffold.js.map +1 -1
- package/dist/search.js +177 -5
- package/dist/search.js.map +1 -1
- package/dist/test.js.map +1 -1
- package/dist/tree.js.map +1 -1
- package/dist/typecheck.js.map +1 -1
- package/dist/write.js +31 -1
- package/dist/write.js.map +1 -1
- package/package.json +2 -2
package/dist/pack.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
2
2
|
import { buildChildEnv, stripAnsi, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, compileGlob, loadPlan, emptyPlan, clearPlan, savePlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, formatPlan } from '@wrongstack/core';
|
|
3
|
+
import * as fs11 from 'node:fs/promises';
|
|
4
|
+
import { stat } from 'node:fs/promises';
|
|
3
5
|
import * as path from 'node:path';
|
|
4
6
|
import { resolve, sep, dirname } from 'node:path';
|
|
5
7
|
import * as os from 'node:os';
|
|
6
|
-
import * as fs11 from 'node:fs/promises';
|
|
7
|
-
import { stat } from 'node:fs/promises';
|
|
8
8
|
import { createRequire } from 'node:module';
|
|
9
9
|
import * as fs from 'node:fs';
|
|
10
10
|
import { statSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
@@ -112,6 +112,36 @@ function ensureInsideRoot(absPath, ctx) {
|
|
|
112
112
|
function safeResolve(input, ctx) {
|
|
113
113
|
return ensureInsideRoot(resolvePath(input, ctx), ctx);
|
|
114
114
|
}
|
|
115
|
+
async function assertRealInsideRoot(absPath, ctx) {
|
|
116
|
+
const realRoot = await fs11.realpath(ctx.projectRoot).catch(() => path.resolve(ctx.projectRoot));
|
|
117
|
+
let probe = absPath;
|
|
118
|
+
for (; ; ) {
|
|
119
|
+
let real;
|
|
120
|
+
try {
|
|
121
|
+
real = await fs11.realpath(probe);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
if (err.code === "ENOENT") {
|
|
124
|
+
const parent = path.dirname(probe);
|
|
125
|
+
if (parent === probe) return;
|
|
126
|
+
probe = parent;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
const rel = path.relative(realRoot, real);
|
|
132
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Path "${absPath}" resolves through a symlink outside project root "${realRoot}"`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async function safeResolveReal(input, ctx) {
|
|
141
|
+
const abs = safeResolve(input, ctx);
|
|
142
|
+
await assertRealInsideRoot(abs, ctx);
|
|
143
|
+
return abs;
|
|
144
|
+
}
|
|
115
145
|
function truncateMiddle(s, max) {
|
|
116
146
|
if (Buffer.byteLength(s, "utf8") <= max) return s;
|
|
117
147
|
const half = Math.floor(max / 2);
|
|
@@ -258,8 +288,6 @@ var CircuitBreaker = class {
|
|
|
258
288
|
lastSlowAt = null;
|
|
259
289
|
/** Timestamp when the breaker was opened (for cooldown calculation). */
|
|
260
290
|
openedAt = null;
|
|
261
|
-
/** Timestamp when the last call ran (for half-open gate). */
|
|
262
|
-
lastCallAt = null;
|
|
263
291
|
constructor(config = {}) {
|
|
264
292
|
this.maxConsecutiveFailures = config.maxConsecutiveFailures ?? DEFAULT_MAX_CONSECUTIVE_FAILURES;
|
|
265
293
|
this.slowCallThresholdMs = config.slowCallThresholdMs ?? DEFAULT_SLOW_CALL_THRESHOLD_MS;
|
|
@@ -317,7 +345,6 @@ var CircuitBreaker = class {
|
|
|
317
345
|
*/
|
|
318
346
|
afterCall(durationMs, failed) {
|
|
319
347
|
const now = Date.now();
|
|
320
|
-
this.lastCallAt = now;
|
|
321
348
|
if (this.state === "half-open") {
|
|
322
349
|
if (failed) {
|
|
323
350
|
this._trip();
|
|
@@ -2112,7 +2139,7 @@ function regexParse(opts) {
|
|
|
2112
2139
|
}
|
|
2113
2140
|
return lo + 1;
|
|
2114
2141
|
}
|
|
2115
|
-
function extractDeclaration(lineIdx,
|
|
2142
|
+
function extractDeclaration(lineIdx, _match) {
|
|
2116
2143
|
const line = lines[lineIdx] ?? "";
|
|
2117
2144
|
return line.trim().slice(0, 500);
|
|
2118
2145
|
}
|
|
@@ -2577,7 +2604,7 @@ async function parseFile(file, content, lang) {
|
|
|
2577
2604
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
2578
2605
|
}
|
|
2579
2606
|
}
|
|
2580
|
-
async function runIndexer(
|
|
2607
|
+
async function runIndexer(_ctx, opts) {
|
|
2581
2608
|
const { projectRoot, force = false, langs, ignore = [] } = opts;
|
|
2582
2609
|
const store = new IndexStore(projectRoot);
|
|
2583
2610
|
const startMs = Date.now();
|
|
@@ -2964,6 +2991,12 @@ var diffTool = {
|
|
|
2964
2991
|
}
|
|
2965
2992
|
};
|
|
2966
2993
|
async function gitDiff(input, ctx, signal) {
|
|
2994
|
+
if (input.a?.startsWith("-")) {
|
|
2995
|
+
throw new Error(`diff: unsafe ref "${input.a}" \u2014 refs may not begin with '-' (flag injection)`);
|
|
2996
|
+
}
|
|
2997
|
+
if (input.b?.startsWith("-")) {
|
|
2998
|
+
throw new Error(`diff: unsafe ref "${input.b}" \u2014 refs may not begin with '-' (flag injection)`);
|
|
2999
|
+
}
|
|
2967
3000
|
const gitDir = findGitDir(ctx.cwd);
|
|
2968
3001
|
if (!gitDir) {
|
|
2969
3002
|
return { diff: "", files: [], truncated: false, mode: "unified" };
|
|
@@ -3002,7 +3035,12 @@ function runGit(args, cwd, signal) {
|
|
|
3002
3035
|
return new Promise((resolve7) => {
|
|
3003
3036
|
let stdout = "";
|
|
3004
3037
|
let stderr = "";
|
|
3005
|
-
const child = spawn("git", args, {
|
|
3038
|
+
const child = spawn("git", args, {
|
|
3039
|
+
cwd,
|
|
3040
|
+
signal,
|
|
3041
|
+
env: buildChildEnv(),
|
|
3042
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
3043
|
+
});
|
|
3006
3044
|
child.stdout?.on("data", (c) => {
|
|
3007
3045
|
stdout += c.toString();
|
|
3008
3046
|
});
|
|
@@ -3013,8 +3051,7 @@ function runGit(args, cwd, signal) {
|
|
|
3013
3051
|
child.on("error", (e) => resolve7({ stdout: "", stderr: e.message, exitCode: 1 }));
|
|
3014
3052
|
});
|
|
3015
3053
|
}
|
|
3016
|
-
async function fileDiff(input, ctx,
|
|
3017
|
-
input.path ? safeResolve(input.path, ctx) : ctx.cwd;
|
|
3054
|
+
async function fileDiff(input, ctx, _signal) {
|
|
3018
3055
|
input.context ?? 3;
|
|
3019
3056
|
const files = input.files ? (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim()).filter(Boolean) : [];
|
|
3020
3057
|
if (files.length === 0) {
|
|
@@ -3043,8 +3080,8 @@ ${formatUnified(lines)}`);
|
|
|
3043
3080
|
mode: input.mode ?? "unified"
|
|
3044
3081
|
};
|
|
3045
3082
|
}
|
|
3046
|
-
function formatUnified(lines,
|
|
3047
|
-
return lines.map((line,
|
|
3083
|
+
function formatUnified(lines, _context) {
|
|
3084
|
+
return lines.map((line, _i) => ` ${line}`).join("\n");
|
|
3048
3085
|
}
|
|
3049
3086
|
var documentTool = {
|
|
3050
3087
|
name: "document",
|
|
@@ -3134,9 +3171,8 @@ async function resolveFiles(filesInput, cwd) {
|
|
|
3134
3171
|
}
|
|
3135
3172
|
return resolved;
|
|
3136
3173
|
}
|
|
3137
|
-
function processFile(content, absPath,
|
|
3174
|
+
function processFile(content, absPath, _style, _overwrite, target) {
|
|
3138
3175
|
const results = [];
|
|
3139
|
-
content.split("\n");
|
|
3140
3176
|
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/g;
|
|
3141
3177
|
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*=>/g;
|
|
3142
3178
|
const classRegex = /class\s+(\w+)/g;
|
|
@@ -3218,7 +3254,7 @@ var editTool = {
|
|
|
3218
3254
|
if (input.old_string === void 0) throw new Error("edit: old_string is required");
|
|
3219
3255
|
if (input.new_string === void 0) throw new Error("edit: new_string is required");
|
|
3220
3256
|
if (input.old_string === "") throw new Error("edit: old_string cannot be empty");
|
|
3221
|
-
const absPath =
|
|
3257
|
+
const absPath = await safeResolveReal(input.path, ctx);
|
|
3222
3258
|
const stat11 = await fs11.stat(absPath).catch((err) => {
|
|
3223
3259
|
if (err.code === "ENOENT") {
|
|
3224
3260
|
throw new Error(`edit: file "${input.path}" does not exist. Use \`write\` instead.`);
|
|
@@ -3603,11 +3639,10 @@ function getPinnedDispatcher() {
|
|
|
3603
3639
|
}
|
|
3604
3640
|
return pinnedAgent;
|
|
3605
3641
|
}
|
|
3606
|
-
async function
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
};
|
|
3642
|
+
async function guardedFetch(url, maxRedirects, signal, headers = {
|
|
3643
|
+
"user-agent": "WrongStack/1.0 (+https://wrongstack.com)",
|
|
3644
|
+
accept: "text/html,application/json;q=0.9,text/plain;q=0.8,*/*;q=0.1"
|
|
3645
|
+
}) {
|
|
3611
3646
|
let redirectCount = 0;
|
|
3612
3647
|
let currentUrl = url;
|
|
3613
3648
|
for (; ; ) {
|
|
@@ -3685,7 +3720,7 @@ var fetchTool = {
|
|
|
3685
3720
|
const timer = setTimeout(() => ctrl.abort(new Error("fetch timeout")), TIMEOUT_MS2);
|
|
3686
3721
|
const combined = combineSignals(opts.signal, ctrl.signal);
|
|
3687
3722
|
try {
|
|
3688
|
-
const res = await
|
|
3723
|
+
const res = await guardedFetch(input.url, 5, combined);
|
|
3689
3724
|
const ct = res.headers.get("content-type") ?? "application/octet-stream";
|
|
3690
3725
|
if (/^image\/|^audio\/|^video\/|application\/octet-stream/.test(ct)) {
|
|
3691
3726
|
throw new Error(`fetch: refusing to read binary content-type "${ct}"`);
|
|
@@ -5050,6 +5085,10 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
5050
5085
|
child.stderr?.on("data", (c) => {
|
|
5051
5086
|
if (stderr.length < MAX) stderr += c.toString();
|
|
5052
5087
|
});
|
|
5088
|
+
child.stdout?.on("error", () => {
|
|
5089
|
+
});
|
|
5090
|
+
child.stderr?.on("error", () => {
|
|
5091
|
+
});
|
|
5053
5092
|
child.on("close", () => {
|
|
5054
5093
|
const output = stdout + stderr;
|
|
5055
5094
|
const entries = parseLogLines(output, filterRe);
|
|
@@ -5515,14 +5554,16 @@ var readTool = {
|
|
|
5515
5554
|
},
|
|
5516
5555
|
async execute(input, ctx) {
|
|
5517
5556
|
if (!input?.path) throw new Error("read: path is required");
|
|
5518
|
-
const absPath =
|
|
5557
|
+
const absPath = await safeResolveReal(input.path, ctx);
|
|
5519
5558
|
let stat11;
|
|
5520
5559
|
try {
|
|
5521
5560
|
stat11 = await fs11.stat(absPath);
|
|
5522
5561
|
} catch (err) {
|
|
5523
5562
|
const code = err.code;
|
|
5524
5563
|
if (code === "ENOENT") throw new Error(`read: file not found "${input.path}"`);
|
|
5525
|
-
throw new Error(
|
|
5564
|
+
throw new Error(
|
|
5565
|
+
`read: failed to stat "${input.path}": ${err instanceof Error ? err.message : String(err)}`
|
|
5566
|
+
);
|
|
5526
5567
|
}
|
|
5527
5568
|
if (!stat11.isFile()) throw new Error(`read: "${input.path}" is not a regular file`);
|
|
5528
5569
|
if (stat11.size > MAX_BYTES2) {
|
|
@@ -5677,7 +5718,6 @@ async function resolveFiles2(filesInput, ctx, extraGlob) {
|
|
|
5677
5718
|
return resolved;
|
|
5678
5719
|
}
|
|
5679
5720
|
async function globFiles(pattern, base, extraGlob) {
|
|
5680
|
-
const { spawn: spawn11 } = await import('node:child_process');
|
|
5681
5721
|
const rgAvailable = await checkRg();
|
|
5682
5722
|
if (rgAvailable) {
|
|
5683
5723
|
try {
|
|
@@ -6119,11 +6159,8 @@ async function fetchWithTimeout(url, signal, timeoutMs) {
|
|
|
6119
6159
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
6120
6160
|
const fetchSignal = anySignal(signal, controller.signal);
|
|
6121
6161
|
try {
|
|
6122
|
-
const res = await
|
|
6123
|
-
|
|
6124
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
6125
|
-
},
|
|
6126
|
-
signal: fetchSignal
|
|
6162
|
+
const res = await guardedFetch(url, 5, fetchSignal, {
|
|
6163
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
6127
6164
|
});
|
|
6128
6165
|
clearTimeout(timer);
|
|
6129
6166
|
return res;
|
|
@@ -6875,7 +6912,7 @@ var writeTool = {
|
|
|
6875
6912
|
async execute(input, ctx) {
|
|
6876
6913
|
if (!input?.path) throw new Error("write: path is required");
|
|
6877
6914
|
if (input.content === void 0) throw new Error("write: content is required");
|
|
6878
|
-
const absPath =
|
|
6915
|
+
const absPath = await safeResolveReal(input.path, ctx);
|
|
6879
6916
|
let existed = false;
|
|
6880
6917
|
let prev = "";
|
|
6881
6918
|
try {
|