@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/pack.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn, execFileSync, spawnSync } from 'node:child_process';
|
|
2
2
|
import * as Core from '@wrongstack/core';
|
|
3
|
-
import { buildChildEnv, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, compileGlob, expectDefined, recordPackageAction, detectPackageEcosystem, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, loadTasks, emptyTaskFile, saveTasks, formatTaskList, formatPlan, mutateTasks, loadPlan, emptyPlan, savePlan, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
3
|
+
import { buildChildEnv, detectNewlineStyle, normalizeToLf, toStyle, atomicWrite, unifiedDiff, isPrivateIPv4, isPrivateIPv6, compileGlob, expectDefined, recordPackageAction, detectPackageEcosystem, mutatePlan, clearPlan, getPlanTemplate, addPlanItem, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, loadTasks, emptyTaskFile, saveTasks, formatTaskList, formatPlan, mutateTasks, loadPlan, emptyPlan, savePlan, computeTaskItemProgress, wstackGlobalRoot, resolveWstackPaths, truncate } from '@wrongstack/core';
|
|
4
4
|
import * as fs from 'node:fs';
|
|
5
5
|
import { statSync, mkdirSync, createWriteStream, writeFileSync } from 'node:fs';
|
|
6
6
|
import * as fs14 from 'node:fs/promises';
|
|
@@ -14,6 +14,7 @@ import * as ts from 'typescript';
|
|
|
14
14
|
import * as dns from 'node:dns/promises';
|
|
15
15
|
import * as net from 'node:net';
|
|
16
16
|
import { Agent } from 'undici';
|
|
17
|
+
import TurndownService from 'turndown';
|
|
17
18
|
import { randomUUID } from 'node:crypto';
|
|
18
19
|
|
|
19
20
|
// src/_spawn-stream.ts
|
|
@@ -277,7 +278,7 @@ var SENSITIVE_FLAG_PATTERNS = [
|
|
|
277
278
|
// --flag=value or --flag "value" (value captured up to next space or comma)
|
|
278
279
|
/--(?: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,
|
|
279
280
|
// -f "value" style short flags
|
|
280
|
-
/(?<!\w)-t(?:\s+|\s*=\s*)[^\s,]
|
|
281
|
+
/(?<!\w)-t(?:\s+|\s*=\s*)[^\s,]+/,
|
|
281
282
|
/(?<!\w)-p(?:ssword)?(?:\s+|\s*=\s*)[^\s,]+/gi,
|
|
282
283
|
// env var–style secrets: TOKEN=x, API_KEY=y, etc.
|
|
283
284
|
/(?:TOKEN|API_KEY|API_SECRET|AUTH_TOKEN|GITHUB_TOKEN|GH_TOKEN|BEARER|JWT|OAUTH|CREDENTIAL|SECRET|PRIVATE_KEY|PASSWORD|PASSWD)\s*[=:]\s*[^\s,]+/gi,
|
|
@@ -413,8 +414,8 @@ var ProcessRegistryImpl = class {
|
|
|
413
414
|
if (p.killed) return true;
|
|
414
415
|
if (p.protected) return false;
|
|
415
416
|
const { force = false, graceMs = DEFAULT_GRACE_MS } = opts;
|
|
416
|
-
const
|
|
417
|
-
if (
|
|
417
|
+
const isWin3 = os.platform() === "win32";
|
|
418
|
+
if (isWin3) {
|
|
418
419
|
const liveRealChild = p.child.exitCode === null && typeof p.child.pid === "number";
|
|
419
420
|
if (liveRealChild && killWin32Tree(pid)) {
|
|
420
421
|
const fallback = setTimeout(() => {
|
|
@@ -502,7 +503,7 @@ function getProcessRegistry() {
|
|
|
502
503
|
}
|
|
503
504
|
function resolveWin32Command(cmd) {
|
|
504
505
|
if (process.platform !== "win32") return cmd;
|
|
505
|
-
if (cmd.includes("/") || cmd.includes("\\") || path3.extname(cmd)) {
|
|
506
|
+
if (cmd.includes("/") || cmd.includes("\\") || path3.extname(cmd.replace(/\//g, "\\"))) {
|
|
506
507
|
return cmd;
|
|
507
508
|
}
|
|
508
509
|
const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
|
|
@@ -522,6 +523,7 @@ function resolveWin32Command(cmd) {
|
|
|
522
523
|
}
|
|
523
524
|
|
|
524
525
|
// src/_spawn-stream.ts
|
|
526
|
+
var isWin = process.platform === "win32";
|
|
525
527
|
async function* spawnStream(opts) {
|
|
526
528
|
const max = opts.maxBytes ?? 2e5;
|
|
527
529
|
const flushAt = opts.flushBytes ?? 4 * 1024;
|
|
@@ -532,7 +534,6 @@ async function* spawnStream(opts) {
|
|
|
532
534
|
let error;
|
|
533
535
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
534
536
|
const cmd = resolveWin32Command(opts.cmd);
|
|
535
|
-
const isWin = process.platform === "win32";
|
|
536
537
|
const needsShell = isWin && (cmd.endsWith(".cmd") || cmd.endsWith(".bat"));
|
|
537
538
|
const child = spawn(cmd, opts.args, {
|
|
538
539
|
cwd: opts.cwd,
|
|
@@ -909,7 +910,7 @@ function parseAuditOutput(json, exitCode) {
|
|
|
909
910
|
total,
|
|
910
911
|
summary,
|
|
911
912
|
output: json,
|
|
912
|
-
truncated: json.length
|
|
913
|
+
truncated: json.length > 1e5
|
|
913
914
|
};
|
|
914
915
|
} catch {
|
|
915
916
|
return {
|
|
@@ -1002,11 +1003,11 @@ var bashTool = {
|
|
|
1002
1003
|
}));
|
|
1003
1004
|
}
|
|
1004
1005
|
const timeoutMs = Math.max(1, Math.min(input.timeout_ms ?? DEFAULT_TIMEOUT_MS, 6e5));
|
|
1005
|
-
const
|
|
1006
|
+
const isWin3 = os.platform() === "win32";
|
|
1006
1007
|
const shell = (() => {
|
|
1007
|
-
const explicit = process.env[
|
|
1008
|
+
const explicit = process.env[isWin3 ? "WRONGSTACK_COMSPEC" : "WRONGSTACK_SHELL"];
|
|
1008
1009
|
if (explicit) return explicit;
|
|
1009
|
-
if (
|
|
1010
|
+
if (isWin3) return process.env["COMSPEC"] ?? "cmd.exe";
|
|
1010
1011
|
const fromEnv = process.env["SHELL"];
|
|
1011
1012
|
if (fromEnv) {
|
|
1012
1013
|
const name = fromEnv.split("/").pop() ?? "";
|
|
@@ -1014,9 +1015,9 @@ var bashTool = {
|
|
|
1014
1015
|
}
|
|
1015
1016
|
return "/bin/bash";
|
|
1016
1017
|
})();
|
|
1017
|
-
const args =
|
|
1018
|
+
const args = isWin3 ? ["/c", input.command] : ["-c", input.command];
|
|
1018
1019
|
const env = buildChildEnv(ctx.session?.id);
|
|
1019
|
-
const detached = !
|
|
1020
|
+
const detached = !isWin3;
|
|
1020
1021
|
const startedAt = Date.now();
|
|
1021
1022
|
if (input.background) {
|
|
1022
1023
|
let buf2 = "";
|
|
@@ -1032,7 +1033,7 @@ var bashTool = {
|
|
|
1032
1033
|
// apply: the child gets a hidden console that grandchildren inherit.
|
|
1033
1034
|
// Windows children survive parent exit either way. POSIX keeps
|
|
1034
1035
|
// detached for the process-group kill semantics.
|
|
1035
|
-
detached: !
|
|
1036
|
+
detached: !isWin3,
|
|
1036
1037
|
windowsHide: true,
|
|
1037
1038
|
signal: opts.signal
|
|
1038
1039
|
});
|
|
@@ -1062,8 +1063,6 @@ var bashTool = {
|
|
|
1062
1063
|
};
|
|
1063
1064
|
child2.stdout?.on("data", onBgData);
|
|
1064
1065
|
child2.stderr?.on("data", onBgData);
|
|
1065
|
-
child2.stdout?.unref?.();
|
|
1066
|
-
child2.stderr?.unref?.();
|
|
1067
1066
|
child2.on("close", () => {
|
|
1068
1067
|
registry.afterCall(Date.now() - startedAt, false, bypassBreaker);
|
|
1069
1068
|
});
|
|
@@ -1085,7 +1084,7 @@ var bashTool = {
|
|
|
1085
1084
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1086
1085
|
detached,
|
|
1087
1086
|
windowsHide: true,
|
|
1088
|
-
...
|
|
1087
|
+
...isWin3 ? {} : { signal: opts.signal }
|
|
1089
1088
|
});
|
|
1090
1089
|
const pid = child.pid;
|
|
1091
1090
|
if (typeof pid === "number") {
|
|
@@ -1104,7 +1103,7 @@ var bashTool = {
|
|
|
1104
1103
|
const timers = [];
|
|
1105
1104
|
const spool = createOutputSpool({ tool: "bash", thresholdBytes: MAX_OUTPUT });
|
|
1106
1105
|
function killWithTimeout(child2, timeoutMs2) {
|
|
1107
|
-
if (
|
|
1106
|
+
if (isWin3) {
|
|
1108
1107
|
if (typeof child2.pid === "number" && child2.exitCode === null && killWin32Tree(child2.pid)) {
|
|
1109
1108
|
const fallback = setTimeout(() => {
|
|
1110
1109
|
if (child2.exitCode === null) {
|
|
@@ -1160,7 +1159,7 @@ var bashTool = {
|
|
|
1160
1159
|
timers.push(timer);
|
|
1161
1160
|
timer.unref?.();
|
|
1162
1161
|
const onAbort = () => killWithTimeout(child, 2e3);
|
|
1163
|
-
if (
|
|
1162
|
+
if (isWin3) {
|
|
1164
1163
|
if (opts.signal.aborted) onAbort();
|
|
1165
1164
|
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
1166
1165
|
}
|
|
@@ -1256,7 +1255,7 @@ var bashTool = {
|
|
|
1256
1255
|
} finally {
|
|
1257
1256
|
for (const t of timers) clearTimeout(t);
|
|
1258
1257
|
spool.finalize();
|
|
1259
|
-
if (
|
|
1258
|
+
if (isWin3) opts.signal.removeEventListener("abort", onAbort);
|
|
1260
1259
|
child.stdout?.off("data", onData);
|
|
1261
1260
|
child.stderr?.off("data", onData);
|
|
1262
1261
|
child.stdout?.destroy();
|
|
@@ -1326,7 +1325,7 @@ var batchToolUseTool = {
|
|
|
1326
1325
|
failed = allResults.filter((r) => !r.success).length;
|
|
1327
1326
|
} else {
|
|
1328
1327
|
for (const call of input.calls) {
|
|
1329
|
-
const result = await executeSingle(call, ctx, opts);
|
|
1328
|
+
const result = await executeSingle(call, ctx, opts ?? { signal: void 0 });
|
|
1330
1329
|
results.push(result);
|
|
1331
1330
|
if (result.success) {
|
|
1332
1331
|
succeeded++;
|
|
@@ -4272,10 +4271,6 @@ var documentTool = {
|
|
|
4272
4271
|
enum: ["jsdoc", "tsdoc", "block"],
|
|
4273
4272
|
description: "Documentation style (default: jsdoc)"
|
|
4274
4273
|
},
|
|
4275
|
-
overwrite: {
|
|
4276
|
-
type: "boolean",
|
|
4277
|
-
description: "Overwrite existing docstrings (default: false)"
|
|
4278
|
-
},
|
|
4279
4274
|
cwd: { type: "string", description: "Working directory (default: cwd)" }
|
|
4280
4275
|
}
|
|
4281
4276
|
},
|
|
@@ -4333,10 +4328,10 @@ async function resolveFiles(filesInput, cwd) {
|
|
|
4333
4328
|
}
|
|
4334
4329
|
function processFile(content, absPath, _style, _overwrite, target) {
|
|
4335
4330
|
const results = [];
|
|
4336
|
-
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)
|
|
4337
|
-
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s
|
|
4338
|
-
const classRegex = /class\s+(\w+)
|
|
4339
|
-
const typeRegex = /(?:type|interface)\s+(\w+)\s*[=<]
|
|
4331
|
+
const functionRegex = /(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/;
|
|
4332
|
+
const arrowRegex = /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(([^)]*)\)\s*=>/;
|
|
4333
|
+
const classRegex = /class\s+(\w+)/;
|
|
4334
|
+
const typeRegex = /(?:type|interface)\s+(\w+)\s*[=<]/;
|
|
4340
4335
|
const allMatches = [];
|
|
4341
4336
|
if (target === "all" || target === "function") {
|
|
4342
4337
|
for (const m of content.matchAll(functionRegex)) {
|
|
@@ -4510,6 +4505,7 @@ function findSimilarity(haystack, needle) {
|
|
|
4510
4505
|
}
|
|
4511
4506
|
return line;
|
|
4512
4507
|
}
|
|
4508
|
+
var isWin2 = process.platform === "win32";
|
|
4513
4509
|
var ALLOWED_COMMANDS = {
|
|
4514
4510
|
node: ["--version", "-r", "--input-type=module"],
|
|
4515
4511
|
npm: ["--version", "list", "pkg", "doctor", "view", "outdated", "audit"],
|
|
@@ -4718,14 +4714,13 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4718
4714
|
const startedAt = Date.now();
|
|
4719
4715
|
const spool = createOutputSpool({ tool: `exec-${cmd}`, thresholdBytes: MAX_OUTPUT2 });
|
|
4720
4716
|
const resolved = resolveWin32Command(cmd);
|
|
4721
|
-
const
|
|
4722
|
-
const needsShell = isWin && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
4717
|
+
const needsShell = isWin2 && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
4723
4718
|
const child = spawn(resolved, args, {
|
|
4724
4719
|
cwd,
|
|
4725
4720
|
env: buildChildEnv(sessionId),
|
|
4726
4721
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4727
4722
|
windowsHide: true,
|
|
4728
|
-
...
|
|
4723
|
+
...isWin2 ? {} : { signal },
|
|
4729
4724
|
...needsShell ? { shell: true, windowsVerbatimArguments: true } : {}
|
|
4730
4725
|
});
|
|
4731
4726
|
const registry = getProcessRegistry();
|
|
@@ -4744,7 +4739,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4744
4739
|
if (typeof pid === "number") registry.kill(pid, { force: true });
|
|
4745
4740
|
else child.kill("SIGTERM");
|
|
4746
4741
|
};
|
|
4747
|
-
if (
|
|
4742
|
+
if (isWin2) {
|
|
4748
4743
|
if (signal.aborted) onAbort();
|
|
4749
4744
|
else signal.addEventListener("abort", onAbort, { once: true });
|
|
4750
4745
|
}
|
|
@@ -4760,7 +4755,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4760
4755
|
});
|
|
4761
4756
|
child.on("close", (code) => {
|
|
4762
4757
|
clearTimeout(timer);
|
|
4763
|
-
if (
|
|
4758
|
+
if (isWin2) signal.removeEventListener("abort", onAbort);
|
|
4764
4759
|
if (typeof pid === "number") registry.unregister(pid);
|
|
4765
4760
|
const durationMs = Date.now() - startedAt;
|
|
4766
4761
|
const exitCode = killed ? 124 : code ?? 1;
|
|
@@ -4778,7 +4773,7 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4778
4773
|
});
|
|
4779
4774
|
child.on("error", (err) => {
|
|
4780
4775
|
clearTimeout(timer);
|
|
4781
|
-
if (
|
|
4776
|
+
if (isWin2) signal.removeEventListener("abort", onAbort);
|
|
4782
4777
|
if (typeof pid === "number") registry.unregister(pid);
|
|
4783
4778
|
registry.afterCall(Date.now() - startedAt, true);
|
|
4784
4779
|
spool.finalize();
|
|
@@ -4794,6 +4789,16 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
4794
4789
|
});
|
|
4795
4790
|
});
|
|
4796
4791
|
}
|
|
4792
|
+
var TD = new TurndownService({
|
|
4793
|
+
// Use `# Title` for headings, not setext underline style (`Title\n=====`).
|
|
4794
|
+
headingStyle: "atx",
|
|
4795
|
+
// Don't wrap code blocks in <pre> — render them as triple-backtick blocks.
|
|
4796
|
+
codeBlockStyle: "fenced"
|
|
4797
|
+
});
|
|
4798
|
+
TD.addRule("stripDangerousElements", {
|
|
4799
|
+
filter: ["script", "style", "noscript"],
|
|
4800
|
+
replacement: () => ""
|
|
4801
|
+
});
|
|
4797
4802
|
var MAX_BYTES = 131072;
|
|
4798
4803
|
var TIMEOUT_MS = 2e4;
|
|
4799
4804
|
var ALLOW_PRIVATE = process.env["WRONGSTACK_FETCH_ALLOW_PRIVATE"] === "1";
|
|
@@ -4828,7 +4833,7 @@ function guardedLookup(hostname, options, callback) {
|
|
|
4828
4833
|
);
|
|
4829
4834
|
return;
|
|
4830
4835
|
}
|
|
4831
|
-
const first = list
|
|
4836
|
+
const first = list.at(0);
|
|
4832
4837
|
if (!first) {
|
|
4833
4838
|
callback(
|
|
4834
4839
|
Object.assign(new Error(`fetch: no address for ${hostname}`), { code: "ENOTFOUND" })
|
|
@@ -4968,7 +4973,7 @@ var fetchTool = {
|
|
|
4968
4973
|
pendingBytes += value.byteLength;
|
|
4969
4974
|
chunks.push(value);
|
|
4970
4975
|
if (pendingBytes >= FLUSH_AT) {
|
|
4971
|
-
const recent = Buffer.from(value).toString("
|
|
4976
|
+
const recent = Buffer.from(value).toString("utf-8");
|
|
4972
4977
|
yield {
|
|
4973
4978
|
type: "partial_output",
|
|
4974
4979
|
text: recent,
|
|
@@ -4983,7 +4988,7 @@ var fetchTool = {
|
|
|
4983
4988
|
const format = input.format ?? (ct.includes("text/html") ? "markdown" : "text");
|
|
4984
4989
|
let content;
|
|
4985
4990
|
if (format === "raw") content = text;
|
|
4986
|
-
else if (format === "markdown" && ct.includes("text/html")) content =
|
|
4991
|
+
else if (format === "markdown" && ct.includes("text/html")) content = TD.turndown(text);
|
|
4987
4992
|
else if (ct.includes("application/json")) content = prettyJson(text);
|
|
4988
4993
|
else content = text;
|
|
4989
4994
|
yield {
|
|
@@ -5029,67 +5034,6 @@ async function assertNotPrivate(hostname) {
|
|
|
5029
5034
|
}
|
|
5030
5035
|
}
|
|
5031
5036
|
}
|
|
5032
|
-
function isPrivateIPv4(addr) {
|
|
5033
|
-
const parts = addr.split(".").map((p) => Number.parseInt(p, 10));
|
|
5034
|
-
if (parts.length !== 4 || parts.some((n) => Number.isNaN(n) || n < 0 || n > 255)) {
|
|
5035
|
-
return true;
|
|
5036
|
-
}
|
|
5037
|
-
const [a, b, c] = parts;
|
|
5038
|
-
if (a === 0) return true;
|
|
5039
|
-
if (a === 10) return true;
|
|
5040
|
-
if (a === 127) return true;
|
|
5041
|
-
if (a === 169 && b === 254) return true;
|
|
5042
|
-
if (a === 172 && b >= 16 && b <= 31) return true;
|
|
5043
|
-
if (a === 192 && b === 168) return true;
|
|
5044
|
-
if (a === 192 && b === 0 && c === 0) return true;
|
|
5045
|
-
if (a === 100 && b >= 64 && b <= 127) return true;
|
|
5046
|
-
if (a >= 224) return true;
|
|
5047
|
-
return false;
|
|
5048
|
-
}
|
|
5049
|
-
function isPrivateIPv6(addr) {
|
|
5050
|
-
const lower = addr.toLowerCase();
|
|
5051
|
-
if (lower === "::" || lower === "::1") return true;
|
|
5052
|
-
const groups = expandIPv6(lower);
|
|
5053
|
-
if (!groups) return true;
|
|
5054
|
-
if (groups[0] === 0 && groups[1] === 0 && groups[2] === 0 && groups[3] === 0 && groups[4] === 0 && groups[5] === 65535) {
|
|
5055
|
-
const a = (groups[6] ?? 0) >> 8;
|
|
5056
|
-
const b = (groups[6] ?? 0) & 255;
|
|
5057
|
-
const c = (groups[7] ?? 0) >> 8;
|
|
5058
|
-
const d = (groups[7] ?? 0) & 255;
|
|
5059
|
-
return isPrivateIPv4(`${a}.${b}.${c}.${d}`);
|
|
5060
|
-
}
|
|
5061
|
-
const high = groups[0] ?? 0;
|
|
5062
|
-
if ((high & 65024) === 64512) return true;
|
|
5063
|
-
if ((high & 65472) === 65152) return true;
|
|
5064
|
-
if ((high & 65280) === 65280) return true;
|
|
5065
|
-
return false;
|
|
5066
|
-
}
|
|
5067
|
-
function expandIPv6(addr) {
|
|
5068
|
-
const parts = addr.split("::");
|
|
5069
|
-
if (parts.length > 2) return null;
|
|
5070
|
-
const parseGroups = (s) => {
|
|
5071
|
-
if (s === "") return [];
|
|
5072
|
-
const out = [];
|
|
5073
|
-
for (const g of s.split(":")) {
|
|
5074
|
-
if (g.length === 0 || g.length > 4) return null;
|
|
5075
|
-
const n = Number.parseInt(g, 16);
|
|
5076
|
-
if (Number.isNaN(n) || n < 0 || n > 65535) return null;
|
|
5077
|
-
out.push(n);
|
|
5078
|
-
}
|
|
5079
|
-
return out;
|
|
5080
|
-
};
|
|
5081
|
-
if (parts.length === 1) {
|
|
5082
|
-
const groups = parseGroups(parts[0] ?? "");
|
|
5083
|
-
if (!groups || groups.length !== 8) return null;
|
|
5084
|
-
return groups;
|
|
5085
|
-
}
|
|
5086
|
-
const head = parseGroups(parts[0] ?? "");
|
|
5087
|
-
const tail = parseGroups(parts[1] ?? "");
|
|
5088
|
-
if (!head || !tail) return null;
|
|
5089
|
-
const fill = 8 - head.length - tail.length;
|
|
5090
|
-
if (fill < 0) return null;
|
|
5091
|
-
return [...head, ...new Array(fill).fill(0), ...tail];
|
|
5092
|
-
}
|
|
5093
5037
|
function prettyJson(s) {
|
|
5094
5038
|
try {
|
|
5095
5039
|
return JSON.stringify(JSON.parse(s), null, 2);
|
|
@@ -5097,32 +5041,6 @@ function prettyJson(s) {
|
|
|
5097
5041
|
return s;
|
|
5098
5042
|
}
|
|
5099
5043
|
}
|
|
5100
|
-
function htmlToMarkdown(html) {
|
|
5101
|
-
let s = html;
|
|
5102
|
-
s = s.replace(/<script[\s\S]*?<\/script>/gi, "");
|
|
5103
|
-
s = s.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
5104
|
-
s = s.replace(/<noscript[\s\S]*?<\/noscript>/gi, "");
|
|
5105
|
-
s = s.replace(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi, (_m, n, c) => {
|
|
5106
|
-
return "\n" + "#".repeat(Number(n)) + " " + stripTags(c).trim() + "\n";
|
|
5107
|
-
});
|
|
5108
|
-
s = s.replace(/<(strong|b)[^>]*>([\s\S]*?)<\/\1>/gi, "**$2**");
|
|
5109
|
-
s = s.replace(/<(em|i)[^>]*>([\s\S]*?)<\/\1>/gi, "*$2*");
|
|
5110
|
-
s = s.replace(/<a [^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi, (_m, href, text) => {
|
|
5111
|
-
const safe = /^(https?|ftps?):\/\//i.test(href) && !/^(javascript|data|vbscript):/i.test(href);
|
|
5112
|
-
return safe ? `[${text}](${href})` : text;
|
|
5113
|
-
});
|
|
5114
|
-
s = s.replace(/<pre[^>]*>([\s\S]*?)<\/pre>/gi, (_m, c) => "\n```\n" + stripTags(c) + "\n```\n");
|
|
5115
|
-
s = s.replace(/<code[^>]*>([\s\S]*?)<\/code>/gi, "`$1`");
|
|
5116
|
-
s = s.replace(/<li[^>]*>([\s\S]*?)<\/li>/gi, "- $1\n");
|
|
5117
|
-
s = s.replace(/<br\s*\/?>/gi, "\n");
|
|
5118
|
-
s = s.replace(/<\/p>/gi, "\n\n");
|
|
5119
|
-
s = stripTags(s);
|
|
5120
|
-
s = s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ");
|
|
5121
|
-
return s.replace(/\n{3,}/g, "\n\n").trim();
|
|
5122
|
-
}
|
|
5123
|
-
function stripTags(s) {
|
|
5124
|
-
return s.replace(/<[^>]+>/g, "");
|
|
5125
|
-
}
|
|
5126
5044
|
|
|
5127
5045
|
// src/format.ts
|
|
5128
5046
|
var formatTool = {
|
|
@@ -5198,7 +5116,7 @@ var formatTool = {
|
|
|
5198
5116
|
signal: opts.signal,
|
|
5199
5117
|
maxBytes: 1e5
|
|
5200
5118
|
});
|
|
5201
|
-
const changed =
|
|
5119
|
+
const changed = [...result.stdout.matchAll(/\bchanged\b/gi)].length;
|
|
5202
5120
|
yield {
|
|
5203
5121
|
type: "final",
|
|
5204
5122
|
output: {
|
|
@@ -5397,7 +5315,7 @@ function buildArgs(input) {
|
|
|
5397
5315
|
...files.length ? ["--", ...files] : []
|
|
5398
5316
|
];
|
|
5399
5317
|
case "branch":
|
|
5400
|
-
return input.branch ? ["branch", ...input.branch.startsWith("-") ? [] : [input.branch]] : ["branch"];
|
|
5318
|
+
return input.branch ? ["branch", ...input.branch.startsWith("-") || input.branch.includes(" --") ? [] : [input.branch]] : ["branch"];
|
|
5401
5319
|
case "checkout":
|
|
5402
5320
|
return [
|
|
5403
5321
|
"checkout",
|
|
@@ -5413,7 +5331,7 @@ function buildArgs(input) {
|
|
|
5413
5331
|
case "fetch":
|
|
5414
5332
|
return ["fetch", ...input.branch ? [input.branch] : ["--all"]];
|
|
5415
5333
|
case "reset":
|
|
5416
|
-
return ["reset"];
|
|
5334
|
+
return ["reset", ...files.length ? ["--", ...files] : []];
|
|
5417
5335
|
case "worktree":
|
|
5418
5336
|
switch (input.worktreeAction) {
|
|
5419
5337
|
case "list":
|
|
@@ -6225,8 +6143,8 @@ var lintTool = {
|
|
|
6225
6143
|
}
|
|
6226
6144
|
const cmd = detected === "biome" ? "biome" : detected;
|
|
6227
6145
|
const result = yield* spawnStream({ cmd, args, cwd, signal: opts.signal, maxBytes: 1e5 });
|
|
6228
|
-
const errors =
|
|
6229
|
-
const warnings =
|
|
6146
|
+
const errors = [...result.stdout.matchAll(/\berror\b/gi)].length;
|
|
6147
|
+
const warnings = [...result.stdout.matchAll(/\bwarning\b/gi)].length;
|
|
6230
6148
|
yield {
|
|
6231
6149
|
type: "final",
|
|
6232
6150
|
output: {
|
|
@@ -6365,9 +6283,11 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
|
|
|
6365
6283
|
child.stderr?.on("data", (c) => {
|
|
6366
6284
|
if (stderr.length < MAX) stderr += c.toString();
|
|
6367
6285
|
});
|
|
6368
|
-
child.stdout?.on("error", () => {
|
|
6286
|
+
child.stdout?.on("error", (e) => {
|
|
6287
|
+
console.log(JSON.stringify({ level: "debug", event: "pipe_error", stream: "stdout", error: e.message }));
|
|
6369
6288
|
});
|
|
6370
|
-
child.stderr?.on("error", () => {
|
|
6289
|
+
child.stderr?.on("error", (e) => {
|
|
6290
|
+
console.log(JSON.stringify({ level: "debug", event: "pipe_error", stream: "stderr", error: e.message }));
|
|
6371
6291
|
});
|
|
6372
6292
|
child.on("close", () => {
|
|
6373
6293
|
const output = stdout + stderr;
|
|
@@ -6645,14 +6565,16 @@ function extractDiffTargets(patch) {
|
|
|
6645
6565
|
const out = [];
|
|
6646
6566
|
const re = /^\+\+\+\s+([^\t\r\n]+)/gm;
|
|
6647
6567
|
for (const m of patch.matchAll(re)) {
|
|
6648
|
-
const
|
|
6568
|
+
const raw = m[1];
|
|
6569
|
+
if (!raw) continue;
|
|
6570
|
+
const target = raw.length > 4096 ? raw.slice(0, 4096).trim() : raw.trim();
|
|
6649
6571
|
if (!target || target === "/dev/null") continue;
|
|
6650
6572
|
out.push(target);
|
|
6651
6573
|
}
|
|
6652
6574
|
return out;
|
|
6653
6575
|
}
|
|
6654
6576
|
function stripPathComponents(p, strip) {
|
|
6655
|
-
const parts = p.replace(/\\/g, "/").split("/");
|
|
6577
|
+
const parts = p.replace(/\\/g, "/").split("/").filter((s) => s !== "" && s !== ".");
|
|
6656
6578
|
if (parts.length <= strip) return void 0;
|
|
6657
6579
|
return parts.slice(strip).join("/");
|
|
6658
6580
|
}
|
|
@@ -7444,7 +7366,8 @@ async function duckduckgoSearch(query2, num, signal) {
|
|
|
7444
7366
|
source: "duckduckgo",
|
|
7445
7367
|
truncated: results.length >= num
|
|
7446
7368
|
};
|
|
7447
|
-
} catch {
|
|
7369
|
+
} catch (err) {
|
|
7370
|
+
console.log(JSON.stringify({ level: "debug", event: "search_failed", query: query2, error: err instanceof Error ? err.message : String(err) }));
|
|
7448
7371
|
return {
|
|
7449
7372
|
query: query2,
|
|
7450
7373
|
results: [{ title: "Search unavailable", url: "", snippet: "Could not reach DuckDuckGo" }],
|
|
@@ -7466,11 +7389,11 @@ function parseDuckDuckGo(html, num) {
|
|
|
7466
7389
|
const snippetRegex = /<a class="result-link"[^>]+href="([^"]+)"[^>]*>([^<]+)<\/a>/gi;
|
|
7467
7390
|
const snippet2Regex = /<a class="result-snippet"[^>]*>([^<]+)<\/a>/gi;
|
|
7468
7391
|
const linkMatches = takeFrom(
|
|
7469
|
-
[...html.matchAll(snippetRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title:
|
|
7392
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title: stripTags(expectDefined(m[2])) })),
|
|
7470
7393
|
num
|
|
7471
7394
|
);
|
|
7472
7395
|
const snippetMatches = takeFrom(
|
|
7473
|
-
[...html.matchAll(snippet2Regex)].filter((m) => m[1]).map((m) =>
|
|
7396
|
+
[...html.matchAll(snippet2Regex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
7474
7397
|
num
|
|
7475
7398
|
);
|
|
7476
7399
|
for (let i = 0; i < linkMatches.length && i < num; i++) {
|
|
@@ -7501,15 +7424,15 @@ function parseGoogleResults(html, num) {
|
|
|
7501
7424
|
const urlRegex = /<cite[^>]*>([^<]+)<\/cite>/gi;
|
|
7502
7425
|
const snippetRegex = /<span[^>]*class="[^"]*aXCZ0b[^>]*>([^<]+)<\/span>/gi;
|
|
7503
7426
|
const titles = takeFrom(
|
|
7504
|
-
[...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) =>
|
|
7427
|
+
[...html.matchAll(titleRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
7505
7428
|
num
|
|
7506
7429
|
);
|
|
7507
7430
|
const urls = takeFrom(
|
|
7508
|
-
[...html.matchAll(urlRegex)].filter((m) => m[1]).map((m) =>
|
|
7431
|
+
[...html.matchAll(urlRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1])).replace(/^\*(https?:\/\/[^\s]+).*$/, "$1")).filter((u) => u.startsWith("http")),
|
|
7509
7432
|
num
|
|
7510
7433
|
);
|
|
7511
7434
|
const snippets = takeFrom(
|
|
7512
|
-
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) =>
|
|
7435
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
7513
7436
|
num
|
|
7514
7437
|
);
|
|
7515
7438
|
for (let i = 0; i < Math.min(titles.length, num); i++) {
|
|
@@ -7538,11 +7461,11 @@ function parseBingResults(html, num) {
|
|
|
7538
7461
|
const titleRegex = /<h2[^>]*>\s*<a[^>]+href="([^"]+)"[^>]*>([^<]+)<\/a>\s*<\/h2>/gi;
|
|
7539
7462
|
const snippetRegex = /<p[^>]*class="[^"]*b_paractl[^"]*"[^>]*>([^<]+)<\/p>/gi;
|
|
7540
7463
|
const entries = takeFrom(
|
|
7541
|
-
[...html.matchAll(titleRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title:
|
|
7464
|
+
[...html.matchAll(titleRegex)].filter((m) => m[1] && m[2]).map((m) => ({ url: expectDefined(m[1]), title: stripTags(expectDefined(m[2])) })),
|
|
7542
7465
|
num
|
|
7543
7466
|
);
|
|
7544
7467
|
const snippets = takeFrom(
|
|
7545
|
-
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) =>
|
|
7468
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[1]).map((m) => stripTags(expectDefined(m[1]))),
|
|
7546
7469
|
num
|
|
7547
7470
|
);
|
|
7548
7471
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -7572,7 +7495,7 @@ async function fetchWithTimeout(url, signal, timeoutMs) {
|
|
|
7572
7495
|
function anySignal(...signals) {
|
|
7573
7496
|
return AbortSignal.any(signals);
|
|
7574
7497
|
}
|
|
7575
|
-
function
|
|
7498
|
+
function stripTags(html) {
|
|
7576
7499
|
return html.replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").trim();
|
|
7577
7500
|
}
|
|
7578
7501
|
var setWorkingDirTool = {
|
|
@@ -7727,6 +7650,7 @@ var taskTool = {
|
|
|
7727
7650
|
const promoteMeta = { count: 0, title: "" };
|
|
7728
7651
|
const planifyMeta = { title: "", details: "" };
|
|
7729
7652
|
let didPlanify = false;
|
|
7653
|
+
let todosToReplace = null;
|
|
7730
7654
|
const file = await mutateTasks(taskPath, sessionId, async (f) => {
|
|
7731
7655
|
switch (input.action) {
|
|
7732
7656
|
case "show":
|
|
@@ -7782,7 +7706,7 @@ var taskTool = {
|
|
|
7782
7706
|
}
|
|
7783
7707
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7784
7708
|
const newTask = {
|
|
7785
|
-
id: `task_${Date.now()}_${
|
|
7709
|
+
id: `task_${Date.now()}_${randomUUID().slice(0, 8)}`,
|
|
7786
7710
|
title: t.title,
|
|
7787
7711
|
description: t.description,
|
|
7788
7712
|
type: t.type || "feature",
|
|
@@ -7859,7 +7783,7 @@ var taskTool = {
|
|
|
7859
7783
|
});
|
|
7860
7784
|
}
|
|
7861
7785
|
}
|
|
7862
|
-
|
|
7786
|
+
todosToReplace = todos;
|
|
7863
7787
|
promoteMeta.count = todos.length;
|
|
7864
7788
|
promoteMeta.title = match.title;
|
|
7865
7789
|
break;
|
|
@@ -7891,6 +7815,7 @@ var taskTool = {
|
|
|
7891
7815
|
}
|
|
7892
7816
|
return f;
|
|
7893
7817
|
});
|
|
7818
|
+
if (todosToReplace) ctx.state.replaceTodos(todosToReplace);
|
|
7894
7819
|
if (early) return early;
|
|
7895
7820
|
if (didPlanify) {
|
|
7896
7821
|
const { title, details } = planifyMeta;
|
|
@@ -8655,6 +8580,10 @@ var typecheckTool = {
|
|
|
8655
8580
|
all: {
|
|
8656
8581
|
type: "boolean",
|
|
8657
8582
|
description: "Type-check all projects (pnpm -r) (default: false)"
|
|
8583
|
+
},
|
|
8584
|
+
json: {
|
|
8585
|
+
type: "boolean",
|
|
8586
|
+
description: "Emit JSON output from tsc (default: false)"
|
|
8658
8587
|
}
|
|
8659
8588
|
}
|
|
8660
8589
|
},
|
|
@@ -8682,6 +8611,7 @@ var typecheckTool = {
|
|
|
8682
8611
|
if (tsconfig) args.push("--project", tsconfig);
|
|
8683
8612
|
project = tsconfig ?? "default";
|
|
8684
8613
|
}
|
|
8614
|
+
if (input.json) args.push("--json");
|
|
8685
8615
|
yield { type: "log", text: `tsc ${args.join(" ")}`, data: { project } };
|
|
8686
8616
|
const result = yield* spawnStream({
|
|
8687
8617
|
cmd: "npx",
|
|
@@ -8690,8 +8620,8 @@ var typecheckTool = {
|
|
|
8690
8620
|
signal: opts.signal,
|
|
8691
8621
|
maxBytes: 2e5
|
|
8692
8622
|
});
|
|
8693
|
-
const errors =
|
|
8694
|
-
const warnings =
|
|
8623
|
+
const errors = [...result.stdout.matchAll(/\berror\b/gi)].length;
|
|
8624
|
+
const warnings = [...result.stdout.matchAll(/\bwarning\b/gi)].length;
|
|
8695
8625
|
yield {
|
|
8696
8626
|
type: "final",
|
|
8697
8627
|
output: {
|