@wrongstack/tools 0.256.1 → 0.257.2
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 +6 -6
- package/dist/audit.js.map +1 -1
- package/dist/bash.js +1 -3
- package/dist/bash.js.map +1 -1
- package/dist/batch-tool-use.js +1 -1
- package/dist/batch-tool-use.js.map +1 -1
- package/dist/builtin.js +76 -146
- package/dist/builtin.js.map +1 -1
- package/dist/document.js +4 -8
- package/dist/document.js.map +1 -1
- package/dist/exec.js +5 -5
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +15 -91
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +6 -6
- package/dist/format.js.map +1 -1
- package/dist/git.js +2 -2
- package/dist/git.js.map +1 -1
- package/dist/index.js +73 -143
- package/dist/index.js.map +1 -1
- package/dist/install.js +5 -5
- package/dist/install.js.map +1 -1
- package/dist/lint.js +7 -7
- package/dist/lint.js.map +1 -1
- package/dist/logs.js +4 -2
- package/dist/logs.js.map +1 -1
- package/dist/outdated.js +1 -1
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +76 -146
- package/dist/pack.js.map +1 -1
- package/dist/patch.js +4 -2
- package/dist/patch.js.map +1 -1
- package/dist/process-registry.js +1 -1
- package/dist/process-registry.js.map +1 -1
- package/dist/search.js +15 -64
- package/dist/search.js.map +1 -1
- package/dist/test.js +5 -5
- package/dist/test.js.map +1 -1
- package/dist/tool-search.d.ts +2 -0
- package/dist/tool-search.js.map +1 -1
- package/dist/typecheck.d.ts +2 -0
- package/dist/typecheck.js +12 -7
- package/dist/typecheck.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs4 from 'node:fs/promises';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { resolve, sep, dirname, join } from 'node:path';
|
|
4
4
|
import * as Core from '@wrongstack/core';
|
|
5
|
-
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, expectDefined, buildChildEnv, loadPlan, setPlanItemStatus, savePlan, loadTasks, saveTasks, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, emptyTaskFile, formatTaskList, formatPlan, recordPackageAction, detectPackageEcosystem, mutateTasks, emptyPlan, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
5
|
+
import { atomicWrite, unifiedDiff, detectNewlineStyle, normalizeToLf, toStyle, compileGlob, expectDefined, buildChildEnv, isPrivateIPv4, isPrivateIPv6, loadPlan, setPlanItemStatus, savePlan, loadTasks, saveTasks, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, emptyTaskFile, formatTaskList, formatPlan, recordPackageAction, detectPackageEcosystem, mutateTasks, emptyPlan, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } 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 fs7 from 'node:fs';
|
|
@@ -10,6 +10,7 @@ import { statSync, mkdirSync, createWriteStream, writeFileSync } from 'node:fs';
|
|
|
10
10
|
import * as dns from 'node:dns/promises';
|
|
11
11
|
import * as net from 'node:net';
|
|
12
12
|
import { Agent } from 'undici';
|
|
13
|
+
import TurndownService from 'turndown';
|
|
13
14
|
import { createRequire } from 'node:module';
|
|
14
15
|
import { fileURLToPath } from 'node:url';
|
|
15
16
|
import { Worker } from 'node:worker_threads';
|
|
@@ -1297,7 +1298,7 @@ var SENSITIVE_FLAG_PATTERNS = [
|
|
|
1297
1298
|
// --flag=value or --flag "value" (value captured up to next space or comma)
|
|
1298
1299
|
/--(?:token|password|passwd|pwd|secret|api[-_]?key|api[-_]?secret|auth|credential|private[-_]?key|access[-_]?key|github[-_]?token|gh[-_]?token|bearer|jwt|oauth|pin|pincode|passphrase|access[-_]?token)(?:[=\s,][^\s]*)?/gi,
|
|
1299
1300
|
// -f "value" style short flags
|
|
1300
|
-
/(?<!\w)-t(?:\s+|\s*=\s*)[^\s,]
|
|
1301
|
+
/(?<!\w)-t(?:\s+|\s*=\s*)[^\s,]+/,
|
|
1301
1302
|
/(?<!\w)-p(?:ssword)?(?:\s+|\s*=\s*)[^\s,]+/gi,
|
|
1302
1303
|
// env var–style secrets: TOKEN=x, API_KEY=y, etc.
|
|
1303
1304
|
/(?:TOKEN|API_KEY|API_SECRET|AUTH_TOKEN|GITHUB_TOKEN|GH_TOKEN|BEARER|JWT|OAUTH|CREDENTIAL|SECRET|PRIVATE_KEY|PASSWORD|PASSWD)\s*[=:]\s*[^\s,]+/gi,
|
|
@@ -1433,8 +1434,8 @@ var ProcessRegistryImpl = class {
|
|
|
1433
1434
|
if (p.killed) return true;
|
|
1434
1435
|
if (p.protected) return false;
|
|
1435
1436
|
const { force = false, graceMs = DEFAULT_GRACE_MS } = opts;
|
|
1436
|
-
const
|
|
1437
|
-
if (
|
|
1437
|
+
const isWin3 = os.platform() === "win32";
|
|
1438
|
+
if (isWin3) {
|
|
1438
1439
|
const liveRealChild = p.child.exitCode === null && typeof p.child.pid === "number";
|
|
1439
1440
|
if (liveRealChild && killWin32Tree(pid)) {
|
|
1440
1441
|
const fallback = setTimeout(() => {
|
|
@@ -1603,11 +1604,11 @@ var bashTool = {
|
|
|
1603
1604
|
}));
|
|
1604
1605
|
}
|
|
1605
1606
|
const timeoutMs = Math.max(1, Math.min(input.timeout_ms ?? DEFAULT_TIMEOUT_MS, 6e5));
|
|
1606
|
-
const
|
|
1607
|
+
const isWin3 = os.platform() === "win32";
|
|
1607
1608
|
const shell = (() => {
|
|
1608
|
-
const explicit = process.env[
|
|
1609
|
+
const explicit = process.env[isWin3 ? "WRONGSTACK_COMSPEC" : "WRONGSTACK_SHELL"];
|
|
1609
1610
|
if (explicit) return explicit;
|
|
1610
|
-
if (
|
|
1611
|
+
if (isWin3) return process.env["COMSPEC"] ?? "cmd.exe";
|
|
1611
1612
|
const fromEnv = process.env["SHELL"];
|
|
1612
1613
|
if (fromEnv) {
|
|
1613
1614
|
const name = fromEnv.split("/").pop() ?? "";
|
|
@@ -1615,9 +1616,9 @@ var bashTool = {
|
|
|
1615
1616
|
}
|
|
1616
1617
|
return "/bin/bash";
|
|
1617
1618
|
})();
|
|
1618
|
-
const args =
|
|
1619
|
+
const args = isWin3 ? ["/c", input.command] : ["-c", input.command];
|
|
1619
1620
|
const env = buildChildEnv(ctx.session?.id);
|
|
1620
|
-
const detached = !
|
|
1621
|
+
const detached = !isWin3;
|
|
1621
1622
|
const startedAt = Date.now();
|
|
1622
1623
|
if (input.background) {
|
|
1623
1624
|
let buf2 = "";
|
|
@@ -1633,7 +1634,7 @@ var bashTool = {
|
|
|
1633
1634
|
// apply: the child gets a hidden console that grandchildren inherit.
|
|
1634
1635
|
// Windows children survive parent exit either way. POSIX keeps
|
|
1635
1636
|
// detached for the process-group kill semantics.
|
|
1636
|
-
detached: !
|
|
1637
|
+
detached: !isWin3,
|
|
1637
1638
|
windowsHide: true,
|
|
1638
1639
|
signal: opts.signal
|
|
1639
1640
|
});
|
|
@@ -1663,8 +1664,6 @@ var bashTool = {
|
|
|
1663
1664
|
};
|
|
1664
1665
|
child2.stdout?.on("data", onBgData);
|
|
1665
1666
|
child2.stderr?.on("data", onBgData);
|
|
1666
|
-
child2.stdout?.unref?.();
|
|
1667
|
-
child2.stderr?.unref?.();
|
|
1668
1667
|
child2.on("close", () => {
|
|
1669
1668
|
registry.afterCall(Date.now() - startedAt, false, bypassBreaker);
|
|
1670
1669
|
});
|
|
@@ -1686,7 +1685,7 @@ var bashTool = {
|
|
|
1686
1685
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1687
1686
|
detached,
|
|
1688
1687
|
windowsHide: true,
|
|
1689
|
-
...
|
|
1688
|
+
...isWin3 ? {} : { signal: opts.signal }
|
|
1690
1689
|
});
|
|
1691
1690
|
const pid = child.pid;
|
|
1692
1691
|
if (typeof pid === "number") {
|
|
@@ -1705,7 +1704,7 @@ var bashTool = {
|
|
|
1705
1704
|
const timers = [];
|
|
1706
1705
|
const spool = createOutputSpool({ tool: "bash", thresholdBytes: MAX_OUTPUT });
|
|
1707
1706
|
function killWithTimeout(child2, timeoutMs2) {
|
|
1708
|
-
if (
|
|
1707
|
+
if (isWin3) {
|
|
1709
1708
|
if (typeof child2.pid === "number" && child2.exitCode === null && killWin32Tree(child2.pid)) {
|
|
1710
1709
|
const fallback = setTimeout(() => {
|
|
1711
1710
|
if (child2.exitCode === null) {
|
|
@@ -1761,7 +1760,7 @@ var bashTool = {
|
|
|
1761
1760
|
timers.push(timer);
|
|
1762
1761
|
timer.unref?.();
|
|
1763
1762
|
const onAbort = () => killWithTimeout(child, 2e3);
|
|
1764
|
-
if (
|
|
1763
|
+
if (isWin3) {
|
|
1765
1764
|
if (opts.signal.aborted) onAbort();
|
|
1766
1765
|
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
1767
1766
|
}
|
|
@@ -1857,7 +1856,7 @@ var bashTool = {
|
|
|
1857
1856
|
} finally {
|
|
1858
1857
|
for (const t of timers) clearTimeout(t);
|
|
1859
1858
|
spool.finalize();
|
|
1860
|
-
if (
|
|
1859
|
+
if (isWin3) opts.signal.removeEventListener("abort", onAbort);
|
|
1861
1860
|
child.stdout?.off("data", onData);
|
|
1862
1861
|
child.stderr?.off("data", onData);
|
|
1863
1862
|
child.stdout?.destroy();
|
|
@@ -1871,7 +1870,7 @@ var bashTool = {
|
|
|
1871
1870
|
};
|
|
1872
1871
|
function resolveWin32Command(cmd) {
|
|
1873
1872
|
if (process.platform !== "win32") return cmd;
|
|
1874
|
-
if (cmd.includes("/") || cmd.includes("\\") || path.extname(cmd)) {
|
|
1873
|
+
if (cmd.includes("/") || cmd.includes("\\") || path.extname(cmd.replace(/\//g, "\\"))) {
|
|
1875
1874
|
return cmd;
|
|
1876
1875
|
}
|
|
1877
1876
|
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
@@ -1891,6 +1890,7 @@ function resolveWin32Command(cmd) {
|
|
|
1891
1890
|
}
|
|
1892
1891
|
|
|
1893
1892
|
// src/exec.ts
|
|
1893
|
+
var isWin = process.platform === "win32";
|
|
1894
1894
|
var ALLOWED_COMMANDS = {
|
|
1895
1895
|
node: ["--version", "-r", "--input-type=module"],
|
|
1896
1896
|
npm: ["--version", "list", "pkg", "doctor", "view", "outdated", "audit"],
|
|
@@ -2099,7 +2099,6 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
2099
2099
|
const startedAt = Date.now();
|
|
2100
2100
|
const spool = createOutputSpool({ tool: `exec-${cmd}`, thresholdBytes: MAX_OUTPUT2 });
|
|
2101
2101
|
const resolved = resolveWin32Command(cmd);
|
|
2102
|
-
const isWin = process.platform === "win32";
|
|
2103
2102
|
const needsShell = isWin && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
2104
2103
|
const child = spawn(resolved, args, {
|
|
2105
2104
|
cwd,
|
|
@@ -2175,6 +2174,16 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
2175
2174
|
});
|
|
2176
2175
|
});
|
|
2177
2176
|
}
|
|
2177
|
+
var TD = new TurndownService({
|
|
2178
|
+
// Use `# Title` for headings, not setext underline style (`Title\n=====`).
|
|
2179
|
+
headingStyle: "atx",
|
|
2180
|
+
// Don't wrap code blocks in <pre> — render them as triple-backtick blocks.
|
|
2181
|
+
codeBlockStyle: "fenced"
|
|
2182
|
+
});
|
|
2183
|
+
TD.addRule("stripDangerousElements", {
|
|
2184
|
+
filter: ["script", "style", "noscript"],
|
|
2185
|
+
replacement: () => ""
|
|
2186
|
+
});
|
|
2178
2187
|
var MAX_BYTES2 = 131072;
|
|
2179
2188
|
var TIMEOUT_MS = 2e4;
|
|
2180
2189
|
var ALLOW_PRIVATE = process.env["WRONGSTACK_FETCH_ALLOW_PRIVATE"] === "1";
|
|
@@ -2209,7 +2218,7 @@ function guardedLookup(hostname, options, callback) {
|
|
|
2209
2218
|
);
|
|
2210
2219
|
return;
|
|
2211
2220
|
}
|
|
2212
|
-
const first = list
|
|
2221
|
+
const first = list.at(0);
|
|
2213
2222
|
if (!first) {
|
|
2214
2223
|
callback(
|
|
2215
2224
|
Object.assign(new Error(`fetch: no address for ${hostname}`), { code: "ENOTFOUND" })
|
|
@@ -2349,7 +2358,7 @@ var fetchTool = {
|
|
|
2349
2358
|
pendingBytes += value.byteLength;
|
|
2350
2359
|
chunks.push(value);
|
|
2351
2360
|
if (pendingBytes >= FLUSH_AT) {
|
|
2352
|
-
const recent = Buffer.from(value).toString("
|
|
2361
|
+
const recent = Buffer.from(value).toString("utf-8");
|
|
2353
2362
|
yield {
|
|
2354
2363
|
type: "partial_output",
|
|
2355
2364
|
text: recent,
|
|
@@ -2364,7 +2373,7 @@ var fetchTool = {
|
|
|
2364
2373
|
const format = input.format ?? (ct.includes("text/html") ? "markdown" : "text");
|
|
2365
2374
|
let content;
|
|
2366
2375
|
if (format === "raw") content = text;
|
|
2367
|
-
else if (format === "markdown" && ct.includes("text/html")) content =
|
|
2376
|
+
else if (format === "markdown" && ct.includes("text/html")) content = TD.turndown(text);
|
|
2368
2377
|
else if (ct.includes("application/json")) content = prettyJson(text);
|
|
2369
2378
|
else content = text;
|
|
2370
2379
|
yield {
|
|
@@ -2410,67 +2419,6 @@ async function assertNotPrivate(hostname) {
|
|
|
2410
2419
|
}
|
|
2411
2420
|
}
|
|
2412
2421
|
}
|
|
2413
|
-
function isPrivateIPv4(addr) {
|
|
2414
|
-
const parts = addr.split(".").map((p) => Number.parseInt(p, 10));
|
|
2415
|
-
if (parts.length !== 4 || parts.some((n) => Number.isNaN(n) || n < 0 || n > 255)) {
|
|
2416
|
-
return true;
|
|
2417
|
-
}
|
|
2418
|
-
const [a, b, c] = parts;
|
|
2419
|
-
if (a === 0) return true;
|
|
2420
|
-
if (a === 10) return true;
|
|
2421
|
-
if (a === 127) return true;
|
|
2422
|
-
if (a === 169 && b === 254) return true;
|
|
2423
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
2424
|
-
if (a === 192 && b === 168) return true;
|
|
2425
|
-
if (a === 192 && b === 0 && c === 0) return true;
|
|
2426
|
-
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
2427
|
-
if (a >= 224) return true;
|
|
2428
|
-
return false;
|
|
2429
|
-
}
|
|
2430
|
-
function isPrivateIPv6(addr) {
|
|
2431
|
-
const lower = addr.toLowerCase();
|
|
2432
|
-
if (lower === "::" || lower === "::1") return true;
|
|
2433
|
-
const groups = expandIPv6(lower);
|
|
2434
|
-
if (!groups) return true;
|
|
2435
|
-
if (groups[0] === 0 && groups[1] === 0 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && groups[5] === 65535) {
|
|
2436
|
-
const a = (groups[6] ?? 0) >> 8;
|
|
2437
|
-
const b = (groups[6] ?? 0) & 255;
|
|
2438
|
-
const c = (groups[7] ?? 0) >> 8;
|
|
2439
|
-
const d = (groups[7] ?? 0) & 255;
|
|
2440
|
-
return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
|
|
2441
|
-
}
|
|
2442
|
-
const high = groups[0] ?? 0;
|
|
2443
|
-
if ((high & 65024) === 64512) return true;
|
|
2444
|
-
if ((high & 65472) === 65152) return true;
|
|
2445
|
-
if ((high & 65280) === 65280) return true;
|
|
2446
|
-
return false;
|
|
2447
|
-
}
|
|
2448
|
-
function expandIPv6(addr) {
|
|
2449
|
-
const parts = addr.split("::");
|
|
2450
|
-
if (parts.length > 2) return null;
|
|
2451
|
-
const parseGroups = (s) => {
|
|
2452
|
-
if (s === "") return [];
|
|
2453
|
-
const out = [];
|
|
2454
|
-
for (const g of s.split(":")) {
|
|
2455
|
-
if (g.length === 0 || g.length > 4) return null;
|
|
2456
|
-
const n = Number.parseInt(g, 16);
|
|
2457
|
-
if (Number.isNaN(n) || n < 0 || n > 65535) return null;
|
|
2458
|
-
out.push(n);
|
|
2459
|
-
}
|
|
2460
|
-
return out;
|
|
2461
|
-
};
|
|
2462
|
-
if (parts.length === 1) {
|
|
2463
|
-
const groups = parseGroups(parts[0] ?? "");
|
|
2464
|
-
if (!groups || groups.length !== 8) return null;
|
|
2465
|
-
return groups;
|
|
2466
|
-
}
|
|
2467
|
-
const head = parseGroups(parts[0] ?? "");
|
|
2468
|
-
const tail = parseGroups(parts[1] ?? "");
|
|
2469
|
-
if (!head || !tail) return null;
|
|
2470
|
-
const fill = 8 - head.length - tail.length;
|
|
2471
|
-
if (fill < 0) return null;
|
|
2472
|
-
return [...head, ...new Array(fill).fill(0), ...tail];
|
|
2473
|
-
}
|
|
2474
2422
|
function prettyJson(s) {
|
|
2475
2423
|
try {
|
|
2476
2424
|
return JSON.stringify(JSON.parse(s), null, 2);
|
|
@@ -2478,32 +2426,6 @@ function prettyJson(s) {
|
|
|
2478
2426
|
return s;
|
|
2479
2427
|
}
|
|
2480
2428
|
}
|
|
2481
|
-
function htmlToMarkdown(html) {
|
|
2482
|
-
let s = html;
|
|
2483
|
-
s = s.replace(/<script[\s\S]*?<\/script>/gi, "");
|
|
2484
|
-
s = s.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
2485
|
-
s = s.replace(/<noscript[\s\S]*?<\/noscript>/gi, "");
|
|
2486
|
-
s = s.replace(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi, (_m, n, c) => {
|
|
2487
|
-
return "\n" + "#".repeat(Number(n)) + " " + stripTags(c).trim() + "\n";
|
|
2488
|
-
});
|
|
2489
|
-
s = s.replace(/<(strong|b)[^>]*>([\s\S]*?)<\/\1>/gi, "**$2**");
|
|
2490
|
-
s = s.replace(/<(em|i)[^>]*>([\s\S]*?)<\/\1>/gi, "*$2*");
|
|
2491
|
-
s = s.replace(/<a [^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi, (_m, href, text) => {
|
|
2492
|
-
const safe = /^(https?|ftps?):\/\//i.test(href) && !/^(javascript|data|vbscript):/i.test(href);
|
|
2493
|
-
return safe ? `[${text}](${href})` : text;
|
|
2494
|
-
});
|
|
2495
|
-
s = s.replace(/<pre[^>]*>([\s\S]*?)<\/pre>/gi, (_m, c) => "\n```\n" + stripTags(c) + "\n```\n");
|
|
2496
|
-
s = s.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, "`$1`");
|
|
2497
|
-
s = s.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, "- $1\n");
|
|
2498
|
-
s = s.replace(/<br\s*\/?>/gi, "\n");
|
|
2499
|
-
s = s.replace(/<\/p>/gi, "\n\n");
|
|
2500
|
-
s = stripTags(s);
|
|
2501
|
-
s = s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ");
|
|
2502
|
-
return s.replace(/\n{3,}/g, "\n\n").trim();
|
|
2503
|
-
}
|
|
2504
|
-
function stripTags(s) {
|
|
2505
|
-
return s.replace(/<[^>]+>/g, "");
|
|
2506
|
-
}
|
|
2507
2429
|
var DEFAULT_NUM = 10;
|
|
2508
2430
|
var MAX_RESULTS = 50;
|
|
2509
2431
|
var TIMEOUT_MS2 = 15e3;
|
|
@@ -2588,7 +2510,8 @@ async function duckduckgoSearch(query2, num, signal) {
|
|
|
2588
2510
|
source: "duckduckgo",
|
|
2589
2511
|
truncated: results.length >= num
|
|
2590
2512
|
};
|
|
2591
|
-
} catch {
|
|
2513
|
+
} catch (err) {
|
|
2514
|
+
console.log(JSON.stringify({ level: "debug", event: "search_failed", query: query2, error: err instanceof Error ? err.message : String(err) }));
|
|
2592
2515
|
return {
|
|
2593
2516
|
query: query2,
|
|
2594
2517
|
results: [{ title: "Search unavailable", url: "", snippet: "Could not reach DuckDuckGo" }],
|
|
@@ -2610,11 +2533,11 @@ function parseDuckDuckGo(html, num) {
|
|
|
2610
2533
|
const snippetRegex = /<a class="result-link"[^>]+href="([^"]+)"[^>]*>([^<]+)<\/a>/gi;
|
|
2611
2534
|
const snippet2Regex = /<a class="result-snippet"[^>]*>([^<]+)<\/a>/gi;
|
|
2612
2535
|
const linkMatches = takeFrom(
|
|
2613
|
-
[...html.matchAll(snippetRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title:
|
|
2536
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title: stripTags(expectDefined(m[2])) })),
|
|
2614
2537
|
num
|
|
2615
2538
|
);
|
|
2616
2539
|
const snippetMatches = takeFrom(
|
|
2617
|
-
[...html.matchAll(snippet2Regex)].filter((m) => m[1]).map((m) =>
|
|
2540
|
+
[...html.matchAll(snippet2Regex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
2618
2541
|
num
|
|
2619
2542
|
);
|
|
2620
2543
|
for (let i = 0; i < linkMatches.length && i < num; i++) {
|
|
@@ -2645,15 +2568,15 @@ function parseGoogleResults(html, num) {
|
|
|
2645
2568
|
const urlRegex = /<cite[^>]*>([^<]+)<\/cite>/gi;
|
|
2646
2569
|
const snippetRegex = /<span[^>]*class="[^"]*aXCZ0b[^>]*>([^<]+)<\/span>/gi;
|
|
2647
2570
|
const titles = takeFrom(
|
|
2648
|
-
[...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) =>
|
|
2571
|
+
[...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
2649
2572
|
num
|
|
2650
2573
|
);
|
|
2651
2574
|
const urls = takeFrom(
|
|
2652
|
-
[...html.matchAll(urlRegex)].filter((m) => m[1]).map((m) =>
|
|
2575
|
+
[...html.matchAll(urlRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1])).replace(/^\*(https?:\/\/[^\s]+).*$/, "$1")).filter((u) => u.startsWith("http")),
|
|
2653
2576
|
num
|
|
2654
2577
|
);
|
|
2655
2578
|
const snippets = takeFrom(
|
|
2656
|
-
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) =>
|
|
2579
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
2657
2580
|
num
|
|
2658
2581
|
);
|
|
2659
2582
|
for (let i = 0; i < Math.min(titles.length, num); i++) {
|
|
@@ -2682,11 +2605,11 @@ function parseBingResults(html, num) {
|
|
|
2682
2605
|
const titleRegex = /<h2[^>]*>\s*<a[^>]+href="([^"]+)"[^>]*>([^<]+)<\/a>\s*<\/h2>/gi;
|
|
2683
2606
|
const snippetRegex = /<p[^>]*class="[^"]*b_paractl[^"]*"[^>]*>([^<]+)<\/p>/gi;
|
|
2684
2607
|
const entries = takeFrom(
|
|
2685
|
-
[...html.matchAll(titleRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title:
|
|
2608
|
+
[...html.matchAll(titleRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title: stripTags(expectDefined(m[2])) })),
|
|
2686
2609
|
num
|
|
2687
2610
|
);
|
|
2688
2611
|
const snippets = takeFrom(
|
|
2689
|
-
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) =>
|
|
2612
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
2690
2613
|
num
|
|
2691
2614
|
);
|
|
2692
2615
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -2716,7 +2639,7 @@ async function fetchWithTimeout(url, signal, timeoutMs) {
|
|
|
2716
2639
|
function anySignal(...signals) {
|
|
2717
2640
|
return AbortSignal.any(signals);
|
|
2718
2641
|
}
|
|
2719
|
-
function
|
|
2642
|
+
function stripTags(html) {
|
|
2720
2643
|
return html.replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").trim();
|
|
2721
2644
|
}
|
|
2722
2645
|
var todoTool = {
|
|
@@ -3222,7 +3145,7 @@ function buildArgs(input) {
|
|
|
3222
3145
|
...files.length ? ["--", ...files] : []
|
|
3223
3146
|
];
|
|
3224
3147
|
case "branch":
|
|
3225
|
-
return input.branch ? ["branch", ...input.branch.startsWith("-") ? [] : [input.branch]] : ["branch"];
|
|
3148
|
+
return input.branch ? ["branch", ...input.branch.startsWith("-") || input.branch.includes(" --") ? [] : [input.branch]] : ["branch"];
|
|
3226
3149
|
case "checkout":
|
|
3227
3150
|
return [
|
|
3228
3151
|
"checkout",
|
|
@@ -3238,7 +3161,7 @@ function buildArgs(input) {
|
|
|
3238
3161
|
case "fetch":
|
|
3239
3162
|
return ["fetch", ...input.branch ? [input.branch] : ["--all"]];
|
|
3240
3163
|
case "reset":
|
|
3241
|
-
return ["reset"];
|
|
3164
|
+
return ["reset", ...files.length ? ["--", ...files] : []];
|
|
3242
3165
|
case "worktree":
|
|
3243
3166
|
switch (input.worktreeAction) {
|
|
3244
3167
|
case "list":
|
|
@@ -3383,14 +3306,16 @@ function extractDiffTargets(patch) {
|
|
|
3383
3306
|
const out = [];
|
|
3384
3307
|
const re = /^\+\+\+\s+([^\t\r\n]+)/gm;
|
|
3385
3308
|
for (const m of patch.matchAll(re)) {
|
|
3386
|
-
const
|
|
3309
|
+
const raw = m[1];
|
|
3310
|
+
if (!raw) continue;
|
|
3311
|
+
const target = raw.length > 4096 ? raw.slice(0, 4096).trim() : raw.trim();
|
|
3387
3312
|
if (!target || target === "/dev/null") continue;
|
|
3388
3313
|
out.push(target);
|
|
3389
3314
|
}
|
|
3390
3315
|
return out;
|
|
3391
3316
|
}
|
|
3392
3317
|
function stripPathComponents(p, strip) {
|
|
3393
|
-
const parts = p.replace(/\\/g, "/").split("/");
|
|
3318
|
+
const parts = p.replace(/\\/g, "/").split("/").filter((s) => s !== "" && s !== ".");
|
|
3394
3319
|
if (parts.length <= strip) return void 0;
|
|
3395
3320
|
return parts.slice(strip).join("/");
|
|
3396
3321
|
}
|
|
@@ -3862,6 +3787,7 @@ async function walkDir(dir, depth, opts) {
|
|
|
3862
3787
|
}
|
|
3863
3788
|
}
|
|
3864
3789
|
}
|
|
3790
|
+
var isWin2 = process.platform === "win32";
|
|
3865
3791
|
async function* spawnStream(opts) {
|
|
3866
3792
|
const max = opts.maxBytes ?? 2e5;
|
|
3867
3793
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
@@ -3872,14 +3798,13 @@ async function* spawnStream(opts) {
|
|
|
3872
3798
|
let error;
|
|
3873
3799
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
3874
3800
|
const cmd = resolveWin32Command(opts.cmd);
|
|
3875
|
-
const
|
|
3876
|
-
const needsShell = isWin && (cmd.endsWith(".cmd") || cmd.endsWith(".bat"));
|
|
3801
|
+
const needsShell = isWin2 && (cmd.endsWith(".cmd") || cmd.endsWith(".bat"));
|
|
3877
3802
|
const child = spawn(cmd, opts.args, {
|
|
3878
3803
|
cwd: opts.cwd,
|
|
3879
3804
|
env: buildChildEnv(),
|
|
3880
3805
|
stdio: ["ignore", "pipe", "pipe"],
|
|
3881
3806
|
windowsHide: true,
|
|
3882
|
-
...
|
|
3807
|
+
...isWin2 ? {} : { signal: opts.signal },
|
|
3883
3808
|
...needsShell ? { shell: true, windowsVerbatimArguments: true } : {}
|
|
3884
3809
|
});
|
|
3885
3810
|
const registry = getProcessRegistry();
|
|
@@ -4085,8 +4010,8 @@ var lintTool = {
|
|
|
4085
4010
|
}
|
|
4086
4011
|
const cmd = detected === "biome" ? "biome" : detected;
|
|
4087
4012
|
const result = yield* spawnStream({ cmd, args, cwd, signal: opts.signal, maxBytes: 1e5 });
|
|
4088
|
-
const errors =
|
|
4089
|
-
const warnings =
|
|
4013
|
+
const errors = [...result.stdout.matchAll(/\berror\b/gi)].length;
|
|
4014
|
+
const warnings = [...result.stdout.matchAll(/\bwarning\b/gi)].length;
|
|
4090
4015
|
yield {
|
|
4091
4016
|
type: "final",
|
|
4092
4017
|
output: {
|
|
@@ -4190,7 +4115,7 @@ var formatTool = {
|
|
|
4190
4115
|
signal: opts.signal,
|
|
4191
4116
|
maxBytes: 1e5
|
|
4192
4117
|
});
|
|
4193
|
-
const changed =
|
|
4118
|
+
const changed = [...result.stdout.matchAll(/\bchanged\b/gi)].length;
|
|
4194
4119
|
yield {
|
|
4195
4120
|
type: "final",
|
|
4196
4121
|
output: {
|
|
@@ -4238,6 +4163,10 @@ var typecheckTool = {
|
|
|
4238
4163
|
all: {
|
|
4239
4164
|
type: "boolean",
|
|
4240
4165
|
description: "Type-check all projects (pnpm -r) (default: false)"
|
|
4166
|
+
},
|
|
4167
|
+
json: {
|
|
4168
|
+
type: "boolean",
|
|
4169
|
+
description: "Emit JSON output from tsc (default: false)"
|
|
4241
4170
|
}
|
|
4242
4171
|
}
|
|
4243
4172
|
},
|
|
@@ -4265,6 +4194,7 @@ var typecheckTool = {
|
|
|
4265
4194
|
if (tsconfig) args.push("--project", tsconfig);
|
|
4266
4195
|
project = tsconfig ?? "default";
|
|
4267
4196
|
}
|
|
4197
|
+
if (input.json) args.push("--json");
|
|
4268
4198
|
yield { type: "log", text: `tsc ${args.join(" ")}`, data: { project } };
|
|
4269
4199
|
const result = yield* spawnStream({
|
|
4270
4200
|
cmd: "npx",
|
|
@@ -4273,8 +4203,8 @@ var typecheckTool = {
|
|
|
4273
4203
|
signal: opts.signal,
|
|
4274
4204
|
maxBytes: 2e5
|
|
4275
4205
|
});
|
|
4276
|
-
const errors =
|
|
4277
|
-
const warnings =
|
|
4206
|
+
const errors = [...result.stdout.matchAll(/\berror\b/gi)].length;
|
|
4207
|
+
const warnings = [...result.stdout.matchAll(/\bwarning\b/gi)].length;
|
|
4278
4208
|
yield {
|
|
4279
4209
|
type: "final",
|
|
4280
4210
|
output: {
|
|
@@ -4678,7 +4608,7 @@ function parseAuditOutput(json, exitCode) {
|
|
|
4678
4608
|
total,
|
|
4679
4609
|
summary,
|
|
4680
4610
|
output: json,
|
|
4681
|
-
truncated: json.length
|
|
4611
|
+
truncated: json.length > 1e5
|
|
4682
4612
|
};
|
|
4683
4613
|
} catch {
|
|
4684
4614
|
return {
|
|
@@ -4914,9 +4844,11 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
4914
4844
|
child.stderr?.on("data", (c) => {
|
|
4915
4845
|
if (stderr.length < MAX) stderr += c.toString();
|
|
4916
4846
|
});
|
|
4917
|
-
child.stdout?.on("error", () => {
|
|
4847
|
+
child.stdout?.on("error", (e) => {
|
|
4848
|
+
console.log(JSON.stringify({ level: "debug", event: "pipe_error", stream: "stdout", error: e.message }));
|
|
4918
4849
|
});
|
|
4919
|
-
child.stderr?.on("error", () => {
|
|
4850
|
+
child.stderr?.on("error", (e) => {
|
|
4851
|
+
console.log(JSON.stringify({ level: "debug", event: "pipe_error", stream: "stderr", error: e.message }));
|
|
4920
4852
|
});
|
|
4921
4853
|
child.on("close", () => {
|
|
4922
4854
|
const output = stdout + stderr;
|
|
@@ -5036,10 +4968,6 @@ var documentTool = {
|
|
|
5036
4968
|
enum: ["jsdoc", "tsdoc", "block"],
|
|
5037
4969
|
description: "Documentation style (default: jsdoc)"
|
|
5038
4970
|
},
|
|
5039
|
-
overwrite: {
|
|
5040
|
-
type: "boolean",
|
|
5041
|
-
description: "Overwrite existing docstrings (default: false)"
|
|
5042
|
-
},
|
|
5043
4971
|
cwd: { type: "string", description: "Working directory (default: cwd)" }
|
|
5044
4972
|
}
|
|
5045
4973
|
},
|
|
@@ -5097,10 +5025,10 @@ async function resolveFiles2(filesInput, cwd) {
|
|
|
5097
5025
|
}
|
|
5098
5026
|
function processFile(content, absPath, _style, _overwrite, target) {
|
|
5099
5027
|
const results = [];
|
|
5100
|
-
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)
|
|
5101
|
-
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s
|
|
5102
|
-
const classRegex = /class\s+(\w+)
|
|
5103
|
-
const typeRegex = /(?:type|interface)\s+(\w+)\s*[=<]
|
|
5028
|
+
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/;
|
|
5029
|
+
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*=>/;
|
|
5030
|
+
const classRegex = /class\s+(\w+)/;
|
|
5031
|
+
const typeRegex = /(?:type|interface)\s+(\w+)\s*[=<]/;
|
|
5104
5032
|
const allMatches = [];
|
|
5105
5033
|
if (target === "all" || target === "function") {
|
|
5106
5034
|
for (const m of content.matchAll(functionRegex)) {
|
|
@@ -5545,7 +5473,7 @@ var batchToolUseTool = {
|
|
|
5545
5473
|
failed = allResults.filter((r) => !r.success).length;
|
|
5546
5474
|
} else {
|
|
5547
5475
|
for (const call of input.calls) {
|
|
5548
|
-
const result = await executeSingle(call, ctx, opts);
|
|
5476
|
+
const result = await executeSingle(call, ctx, opts ?? { signal: void 0 });
|
|
5549
5477
|
results.push(result);
|
|
5550
5478
|
if (result.success) {
|
|
5551
5479
|
succeeded++;
|
|
@@ -8911,6 +8839,7 @@ var taskTool = {
|
|
|
8911
8839
|
const promoteMeta = { count: 0, title: "" };
|
|
8912
8840
|
const planifyMeta = { title: "", details: "" };
|
|
8913
8841
|
let didPlanify = false;
|
|
8842
|
+
let todosToReplace = null;
|
|
8914
8843
|
const file = await mutateTasks(taskPath, sessionId, async (f) => {
|
|
8915
8844
|
switch (input.action) {
|
|
8916
8845
|
case "show":
|
|
@@ -8966,7 +8895,7 @@ var taskTool = {
|
|
|
8966
8895
|
}
|
|
8967
8896
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8968
8897
|
const newTask = {
|
|
8969
|
-
id: `task_${Date.now()}_${
|
|
8898
|
+
id: `task_${Date.now()}_${randomUUID().slice(0, 8)}`,
|
|
8970
8899
|
title: t.title,
|
|
8971
8900
|
description: t.description,
|
|
8972
8901
|
type: t.type || "feature",
|
|
@@ -9043,7 +8972,7 @@ var taskTool = {
|
|
|
9043
8972
|
});
|
|
9044
8973
|
}
|
|
9045
8974
|
}
|
|
9046
|
-
|
|
8975
|
+
todosToReplace = todos;
|
|
9047
8976
|
promoteMeta.count = todos.length;
|
|
9048
8977
|
promoteMeta.title = match.title;
|
|
9049
8978
|
break;
|
|
@@ -9075,6 +9004,7 @@ var taskTool = {
|
|
|
9075
9004
|
}
|
|
9076
9005
|
return f;
|
|
9077
9006
|
});
|
|
9007
|
+
if (todosToReplace) ctx.state.replaceTodos(todosToReplace);
|
|
9078
9008
|
if (early) return early;
|
|
9079
9009
|
if (didPlanify) {
|
|
9080
9010
|
const { title, details } = planifyMeta;
|