@wrongstack/tools 0.318.0 → 0.319.1
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/_edit-match.d.ts +1 -3
- package/dist/_util.d.ts +20 -0
- package/dist/audit.js +4 -4
- package/dist/bash.js +2 -2
- package/dist/builtin.d.ts +10 -0
- package/dist/builtin.js +46 -44
- package/dist/{chunk-TKA4VEX2.js → chunk-2OXHS3KZ.js} +17 -5
- package/dist/{chunk-X5K3U6GI.js → chunk-3M7LLN7W.js} +71 -7
- package/dist/{chunk-4AEZIFOW.js → chunk-5EUJF3WC.js} +36 -8
- package/dist/{chunk-CVALEVGA.js → chunk-64VIJPFV.js} +34 -13
- package/dist/{chunk-ZE6KLBUO.js → chunk-6AAOT4PW.js} +58 -10
- package/dist/{chunk-A6BRWIXN.js → chunk-6IEBD27U.js} +20 -5
- package/dist/{chunk-HTYEO67J.js → chunk-AKHYMB4V.js} +36 -12
- package/dist/{chunk-4E42D7UF.js → chunk-ATSKPZUK.js} +2 -2
- package/dist/{chunk-H6AWAZ2Y.js → chunk-B4HTSV6Z.js} +57 -6
- package/dist/{chunk-5ZYEGP2P.js → chunk-BK732J7I.js} +72 -27
- package/dist/{chunk-WI3VDXHD.js → chunk-BSJSNVGA.js} +108 -19
- package/dist/{chunk-UKGMDCXT.js → chunk-C2DQKVLO.js} +61 -28
- package/dist/{chunk-CIFAIIHI.js → chunk-CFLJFDYV.js} +100 -58
- package/dist/{chunk-JJQB6R7Y.js → chunk-CMOUCKGC.js} +6 -6
- package/dist/{chunk-MX25MTDJ.js → chunk-DC4KMPJO.js} +2 -2
- package/dist/{chunk-VZLX2JZG.js → chunk-DP6CXMJZ.js} +3 -3
- package/dist/{chunk-3QQSBUXR.js → chunk-EADULOZV.js} +36 -12
- package/dist/{chunk-6RNIFLG4.js → chunk-ELRRTWNP.js} +38 -6
- package/dist/{chunk-CPSAF2AU.js → chunk-FQNXYA6W.js} +45 -6
- package/dist/{chunk-ZZT45EHF.js → chunk-GMZYW52L.js} +3 -3
- package/dist/{chunk-ZLTFLC25.js → chunk-IIF5HIVF.js} +2 -2
- package/dist/{chunk-EMRGN4KM.js → chunk-IU4DV2PA.js} +18 -8
- package/dist/{chunk-AGUSOFNI.js → chunk-IWS56OY7.js} +30 -7
- package/dist/{chunk-MRZOVQ5D.js → chunk-IYKXK356.js} +98 -11
- package/dist/{chunk-6GZPSWP3.js → chunk-JDPQOR7C.js} +14 -7
- package/dist/{chunk-BLCSYKNN.js → chunk-KY4PXYSO.js} +10 -15
- package/dist/{chunk-WJYXMB2R.js → chunk-LOBRWKCR.js} +63 -14
- package/dist/{chunk-J5SKD6LN.js → chunk-MNP3GE7H.js} +38 -27
- package/dist/{chunk-S2GBLQ5S.js → chunk-O44IMQCN.js} +31 -7
- package/dist/{chunk-P7ZQ2FAJ.js → chunk-OG2BEUBY.js} +69 -34
- package/dist/{chunk-K23JNFE3.js → chunk-OTINMOKK.js} +233 -45
- package/dist/{chunk-PQTONQ4P.js → chunk-QPNYDH5B.js} +19 -5
- package/dist/{chunk-UE3UBMCP.js → chunk-RLMX75EM.js} +19 -8
- package/dist/{chunk-3U4H6ZRF.js → chunk-RNWUCZ2U.js} +53 -25
- package/dist/{chunk-YF3D5INN.js → chunk-RTZWBNTY.js} +121 -91
- package/dist/{chunk-SOG7XIRF.js → chunk-TTZOK6IY.js} +2 -2
- package/dist/{chunk-6GVXZCQV.js → chunk-UDVKRX5R.js} +2 -2
- package/dist/{chunk-CPVLVQYT.js → chunk-UQQS3VNT.js} +43 -9
- package/dist/{chunk-VB3MJGCV.js → chunk-VD2LV5WO.js} +82 -13
- package/dist/{chunk-5WNDJHT6.js → chunk-VPALDFYM.js} +2 -2
- package/dist/{chunk-FJEQZHZN.js → chunk-W2CECGTG.js} +24 -14
- package/dist/{chunk-CISOLTOP.js → chunk-X5FOFGXX.js} +72 -33
- package/dist/{chunk-CWALNI6K.js → chunk-X6KXNHUO.js} +1 -1
- package/dist/{chunk-EEOFQDT6.js → chunk-XRNN44QY.js} +46 -2
- package/dist/{chunk-EOOFNYIT.js → chunk-YOKD4GWJ.js} +67 -27
- package/dist/{chunk-D33S4RQG.js → chunk-ZUFHAHTE.js} +18 -6
- package/dist/codebase-index/generic-parser.d.ts +8 -1
- package/dist/codebase-index/index.js +9 -9
- package/dist/codebase-index/parser-worker-script.js +3 -3
- package/dist/codebase-index/project-server.js +5 -5
- package/dist/codebase-index/worker.js +4 -4
- package/dist/codebase-index/writer-refs.d.ts +1 -1
- package/dist/design.d.ts +1 -1
- package/dist/design.js +1 -1
- package/dist/diff.js +3 -2
- package/dist/document.js +2 -2
- package/dist/e2e.js +2 -2
- package/dist/edit.js +8 -8
- package/dist/exec.js +2 -2
- package/dist/fetch.js +2 -2
- package/dist/format.js +4 -4
- package/dist/{generic-parser-VUXDIAOZ.js → generic-parser-WFMIRHBX.js} +2 -2
- package/dist/git.js +2 -2
- package/dist/glob.js +2 -2
- package/dist/grep.d.ts +2 -0
- package/dist/grep.js +4 -2
- package/dist/index.js +46 -46
- package/dist/install.js +4 -4
- package/dist/json.js +2 -2
- package/dist/kanban-tool-types.d.ts +2 -0
- package/dist/kanban.js +2 -2
- package/dist/languages/index.js +2 -2
- package/dist/{legacy-bridge-SFNXIRAP.js → legacy-bridge-3T7SR4SK.js} +4 -4
- package/dist/lint.js +4 -4
- package/dist/logs.js +2 -2
- package/dist/outdated.js +4 -2
- package/dist/pack.js +45 -45
- package/dist/{parser-dispatch-X62UWXJS.js → parser-dispatch-QGC4HSP5.js} +4 -4
- package/dist/patch.js +8 -8
- package/dist/plan.js +4 -4
- package/dist/{py-parser-TDXSQZBC.js → py-parser-RFWG2HYI.js} +3 -3
- package/dist/read.js +8 -8
- package/dist/replace.js +9 -8
- package/dist/scaffold.js +2 -2
- package/dist/search.js +1 -1
- package/dist/session-kanban.js +1 -1
- package/dist/task.js +4 -4
- package/dist/test.js +4 -4
- package/dist/todo.js +3 -3
- package/dist/tool-tier.js +46 -46
- package/dist/{tree-sitter-parser-AIERW3YI.js → tree-sitter-parser-GILYQLS4.js} +2 -2
- package/dist/tree.js +2 -2
- package/dist/typecheck.js +4 -4
- package/dist/write.js +8 -8
- package/package.json +5 -5
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
tryLegacyCodeOperation
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ATSKPZUK.js";
|
|
4
4
|
import {
|
|
5
5
|
spawnStream
|
|
6
6
|
} from "./chunk-ZHH3BEWU.js";
|
|
7
7
|
import {
|
|
8
8
|
normalizeCommandOutput,
|
|
9
9
|
safeResolveReal
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ZUFHAHTE.js";
|
|
11
11
|
|
|
12
12
|
// src/test.ts
|
|
13
13
|
import * as path from "node:path";
|
|
14
|
+
import { ToolValidationError } from "@wrongstack/core/types";
|
|
14
15
|
var testTool = {
|
|
15
16
|
name: "test",
|
|
16
17
|
category: "Code Quality",
|
|
@@ -57,6 +58,14 @@ var testTool = {
|
|
|
57
58
|
async *executeStream(input, ctx, opts) {
|
|
58
59
|
const cwd = input.cwd ? await safeResolveReal(input.cwd, ctx) : ctx.cwd;
|
|
59
60
|
const signal = opts?.signal ?? ctx.signal ?? new AbortController().signal;
|
|
61
|
+
signal.throwIfAborted();
|
|
62
|
+
const VALID_RUNNERS = /* @__PURE__ */ new Set(["vitest", "jest", "mocha", "auto", "none"]);
|
|
63
|
+
if (input.runner !== void 0 && !VALID_RUNNERS.has(input.runner)) {
|
|
64
|
+
throw new ToolValidationError({
|
|
65
|
+
message: `test: unsupported runner "${input.runner}". Allowed runners: vitest, jest, mocha, auto, none`,
|
|
66
|
+
field: "runner"
|
|
67
|
+
});
|
|
68
|
+
}
|
|
60
69
|
const runner = input.runner ?? "auto";
|
|
61
70
|
if (runner === "auto") {
|
|
62
71
|
const bridge = await tryLegacyCodeOperation("test", {
|
|
@@ -83,7 +92,7 @@ var testTool = {
|
|
|
83
92
|
}
|
|
84
93
|
}
|
|
85
94
|
const detected = runner === "auto" ? await detectRunner(cwd) : runner;
|
|
86
|
-
if (!detected) {
|
|
95
|
+
if (!detected || detected === "none") {
|
|
87
96
|
yield {
|
|
88
97
|
type: "final",
|
|
89
98
|
output: {
|
|
@@ -115,7 +124,21 @@ var testTool = {
|
|
|
115
124
|
};
|
|
116
125
|
async function detectRunner(cwd) {
|
|
117
126
|
const { stat } = await import("node:fs/promises");
|
|
118
|
-
const candidates = [
|
|
127
|
+
const candidates = [
|
|
128
|
+
"vitest.config.ts",
|
|
129
|
+
"vitest.config.js",
|
|
130
|
+
"vitest.config.mjs",
|
|
131
|
+
"vitest.config.mts",
|
|
132
|
+
"vitest.config.cjs",
|
|
133
|
+
"vitest.config.cts",
|
|
134
|
+
"jest.config.ts",
|
|
135
|
+
"jest.config.js",
|
|
136
|
+
"jest.config.mjs",
|
|
137
|
+
"jest.config.cjs",
|
|
138
|
+
".mocharc.json",
|
|
139
|
+
".mocharc.js",
|
|
140
|
+
".mocharc.cjs"
|
|
141
|
+
];
|
|
119
142
|
for (const f of candidates) {
|
|
120
143
|
try {
|
|
121
144
|
await stat(path.join(cwd, f));
|
|
@@ -129,7 +152,8 @@ async function detectRunner(cwd) {
|
|
|
129
152
|
}
|
|
130
153
|
function buildArgs(runner, input) {
|
|
131
154
|
const args = [];
|
|
132
|
-
const
|
|
155
|
+
const rawTimeout = typeof input.timeout === "number" && Number.isFinite(input.timeout) && input.timeout > 0 ? Math.floor(input.timeout) : 3e4;
|
|
156
|
+
const timeout = Math.max(100, rawTimeout);
|
|
133
157
|
switch (runner) {
|
|
134
158
|
case "vitest":
|
|
135
159
|
args.push(input.watch ? "watch" : "run");
|
|
@@ -152,8 +176,10 @@ function buildArgs(runner, input) {
|
|
|
152
176
|
break;
|
|
153
177
|
}
|
|
154
178
|
if (input.files) {
|
|
155
|
-
const files = Array.isArray(input.files) ? input.files : input.files.split(",");
|
|
156
|
-
|
|
179
|
+
const files = (Array.isArray(input.files) ? input.files : input.files.split(",")).map((f) => f.trim().replace(/\\/g, "/")).filter(Boolean);
|
|
180
|
+
if (files.length > 0) {
|
|
181
|
+
args.push("--", ...files);
|
|
182
|
+
}
|
|
157
183
|
}
|
|
158
184
|
return args;
|
|
159
185
|
}
|
|
@@ -175,7 +201,15 @@ function parseResult(runner, result, duration) {
|
|
|
175
201
|
tests_run = Number.parseInt(suitesMatch?.[1] ?? "0", 10);
|
|
176
202
|
passed = Number.parseInt(passedMatch?.[1] ?? "0", 10);
|
|
177
203
|
failed = Number.parseInt(failedMatch?.[1] ?? "0", 10);
|
|
204
|
+
} else if (runner === "mocha") {
|
|
205
|
+
const passedMatch = out.match(/(\d+)\s+passing/);
|
|
206
|
+
const failedMatch = out.match(/(\d+)\s+failing/);
|
|
207
|
+
if (passedMatch?.[1]) passed = Number.parseInt(passedMatch[1], 10);
|
|
208
|
+
if (failedMatch?.[1]) failed = Number.parseInt(failedMatch[1], 10);
|
|
209
|
+
tests_run = passed + failed;
|
|
178
210
|
}
|
|
211
|
+
const rawOutput = result.stdout && result.stderr ? `${result.stdout}
|
|
212
|
+
${result.stderr}` : result.stdout || result.stderr || result.error || "";
|
|
179
213
|
return {
|
|
180
214
|
runner,
|
|
181
215
|
exit_code: result.exitCode,
|
|
@@ -187,7 +221,7 @@ function parseResult(runner, result, duration) {
|
|
|
187
221
|
// already parsed above and the FULL log is on disk (spool marker rides
|
|
188
222
|
// the stdout tail). Failures keep the standard command-output cap so
|
|
189
223
|
// the agent sees the failure details inline.
|
|
190
|
-
output: normalizeCommandOutput(
|
|
224
|
+
output: normalizeCommandOutput(rawOutput, {
|
|
191
225
|
maxBytes: result.exitCode === 0 ? 4096 : void 0
|
|
192
226
|
}),
|
|
193
227
|
truncated: result.truncated
|
|
@@ -197,4 +231,4 @@ function parseResult(runner, result, duration) {
|
|
|
197
231
|
export {
|
|
198
232
|
testTool
|
|
199
233
|
};
|
|
200
|
-
//# sourceMappingURL=chunk-
|
|
234
|
+
//# sourceMappingURL=chunk-UQQS3VNT.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-Q5JPPCZC.js";
|
|
5
5
|
import {
|
|
6
6
|
safeResolveReal
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZUFHAHTE.js";
|
|
8
8
|
|
|
9
9
|
// src/json.ts
|
|
10
10
|
import * as fs from "node:fs/promises";
|
|
@@ -19,9 +19,18 @@ var JsonFileTooLargeError = class extends Error {
|
|
|
19
19
|
this.name = "JsonFileTooLargeError";
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
+
var JsonFileIsDirectoryError = class extends Error {
|
|
23
|
+
constructor(filePath) {
|
|
24
|
+
super(`json: "${filePath}" is a directory, not a file`);
|
|
25
|
+
this.name = "JsonFileIsDirectoryError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
22
28
|
async function readJsonFileBounded(filePath, ctx) {
|
|
23
29
|
const resolved = await safeResolveReal(filePath, ctx);
|
|
24
30
|
const stat2 = await fs.stat(resolved);
|
|
31
|
+
if (stat2.isDirectory()) {
|
|
32
|
+
throw new JsonFileIsDirectoryError(filePath);
|
|
33
|
+
}
|
|
25
34
|
if (stat2.size > MAX_JSON_FILE_BYTES) {
|
|
26
35
|
throw new JsonFileTooLargeError(filePath, stat2.size);
|
|
27
36
|
}
|
|
@@ -82,8 +91,26 @@ var jsonTool = {
|
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
},
|
|
85
|
-
async execute(input, ctx) {
|
|
94
|
+
async execute(input, ctx, opts) {
|
|
95
|
+
const signal = opts?.signal ?? ctx?.signal;
|
|
96
|
+
signal?.throwIfAborted();
|
|
86
97
|
const action = input.action ?? "parse";
|
|
98
|
+
const ALLOWED_ACTIONS = /* @__PURE__ */ new Set([
|
|
99
|
+
"parse",
|
|
100
|
+
"query",
|
|
101
|
+
"validate",
|
|
102
|
+
"transform",
|
|
103
|
+
"merge"
|
|
104
|
+
]);
|
|
105
|
+
if (input.action !== void 0 && !ALLOWED_ACTIONS.has(input.action)) {
|
|
106
|
+
return {
|
|
107
|
+
data: null,
|
|
108
|
+
formatted: "",
|
|
109
|
+
type: "unknown",
|
|
110
|
+
action: String(input.action),
|
|
111
|
+
error: `Unknown action "${input.action}". Allowed actions: parse, query, validate, transform, merge`
|
|
112
|
+
};
|
|
113
|
+
}
|
|
87
114
|
switch (action) {
|
|
88
115
|
case "query":
|
|
89
116
|
return executeQuery(input, ctx);
|
|
@@ -111,7 +138,7 @@ async function executeParse(input, ctx) {
|
|
|
111
138
|
formatted: "",
|
|
112
139
|
type: "unknown",
|
|
113
140
|
action: "parse",
|
|
114
|
-
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read file"
|
|
141
|
+
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read file"
|
|
115
142
|
};
|
|
116
143
|
}
|
|
117
144
|
} else if (input.data) {
|
|
@@ -188,7 +215,7 @@ async function executeQuery(input, ctx) {
|
|
|
188
215
|
formatted: "",
|
|
189
216
|
type: "unknown",
|
|
190
217
|
action: "query",
|
|
191
|
-
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read/parse file"
|
|
218
|
+
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read/parse file"
|
|
192
219
|
};
|
|
193
220
|
}
|
|
194
221
|
} else if (input.data) {
|
|
@@ -254,7 +281,7 @@ async function executeValidate(input, ctx) {
|
|
|
254
281
|
formatted: "",
|
|
255
282
|
type: "unknown",
|
|
256
283
|
action: "validate",
|
|
257
|
-
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read/parse file"
|
|
284
|
+
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read/parse file"
|
|
258
285
|
};
|
|
259
286
|
}
|
|
260
287
|
} else if (input.data) {
|
|
@@ -320,7 +347,7 @@ async function executeTransform(input, ctx) {
|
|
|
320
347
|
formatted: "",
|
|
321
348
|
type: "unknown",
|
|
322
349
|
action: "transform",
|
|
323
|
-
error: error instanceof JsonFileTooLargeError ? error.message : "Could not read/parse file"
|
|
350
|
+
error: error instanceof JsonFileTooLargeError || error instanceof JsonFileIsDirectoryError ? error.message : "Could not read/parse file"
|
|
324
351
|
};
|
|
325
352
|
}
|
|
326
353
|
} else if (input.data) {
|
|
@@ -409,6 +436,9 @@ function jmespathSearch(data, query) {
|
|
|
409
436
|
const dotMatch = query.match(/^([a-zA-Z_][a-zA-Z0-9_]*)(?:\.(.+))?$/);
|
|
410
437
|
if (dotMatch) {
|
|
411
438
|
const key = dotMatch[1];
|
|
439
|
+
if (key === "__proto__" || key === "prototype" || key === "constructor") {
|
|
440
|
+
return void 0;
|
|
441
|
+
}
|
|
412
442
|
const rest = dotMatch[2];
|
|
413
443
|
const val = data?.[key];
|
|
414
444
|
if (rest === void 0) return val;
|
|
@@ -539,9 +569,23 @@ function validateJsonSchema(data, schema) {
|
|
|
539
569
|
if (typeof value === "number" && s["maximum"] !== void 0 && value > s["maximum"]) {
|
|
540
570
|
errors.push(`${path}: above maximum ${s["maximum"]}`);
|
|
541
571
|
}
|
|
542
|
-
if (Array.isArray(value) && s["items"]
|
|
543
|
-
|
|
544
|
-
|
|
572
|
+
if (Array.isArray(value) && s["items"]) {
|
|
573
|
+
if (Array.isArray(s["items"])) {
|
|
574
|
+
for (let i = 0; i < Math.min(value.length, s["items"].length); i++) {
|
|
575
|
+
check(value[i], s["items"][i], `${path}[${i}]`);
|
|
576
|
+
}
|
|
577
|
+
} else if (typeof s["items"] === "object" && s["items"] !== null) {
|
|
578
|
+
for (let i = 0; i < value.length; i++) {
|
|
579
|
+
check(value[i], s["items"], `${path}[${i}]`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && Array.isArray(s["required"])) {
|
|
584
|
+
const obj = value;
|
|
585
|
+
for (const req of s["required"]) {
|
|
586
|
+
if (typeof req === "string" && !(req in obj)) {
|
|
587
|
+
errors.push(`${path}: missing required property "${req}"`);
|
|
588
|
+
}
|
|
545
589
|
}
|
|
546
590
|
}
|
|
547
591
|
if (typeof value === "object" && value !== null && !Array.isArray(value) && s["properties"]) {
|
|
@@ -559,6 +603,9 @@ function simpleQuery(data, path) {
|
|
|
559
603
|
let current = data;
|
|
560
604
|
for (const part of parts) {
|
|
561
605
|
if (current === null || current === void 0) return void 0;
|
|
606
|
+
if (part === "__proto__" || part === "prototype" || part === "constructor") {
|
|
607
|
+
return void 0;
|
|
608
|
+
}
|
|
562
609
|
const idx = Number(part);
|
|
563
610
|
if (!Number.isNaN(idx) && Array.isArray(current)) {
|
|
564
611
|
current = current[idx];
|
|
@@ -585,7 +632,7 @@ function toYaml(data, indent = 0) {
|
|
|
585
632
|
if (typeof data === "boolean") return String(data) + "\n";
|
|
586
633
|
if (typeof data === "number") return String(data) + "\n";
|
|
587
634
|
if (typeof data === "string") {
|
|
588
|
-
if (data.includes("\n") || data.includes(":") || data.includes("#")) {
|
|
635
|
+
if (data.includes("\n") || data.includes(":") || data.includes("#") || data.startsWith("-")) {
|
|
589
636
|
return `"${data.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"
|
|
590
637
|
`;
|
|
591
638
|
}
|
|
@@ -594,12 +641,34 @@ function toYaml(data, indent = 0) {
|
|
|
594
641
|
if (Array.isArray(data)) {
|
|
595
642
|
if (data.length === 0) return "[]\n";
|
|
596
643
|
const prefix = " ".repeat(indent);
|
|
597
|
-
return data.map((item) =>
|
|
644
|
+
return data.map((item) => {
|
|
645
|
+
if (typeof item === "object" && item !== null && !Array.isArray(item)) {
|
|
646
|
+
const itemEntries = Object.entries(item);
|
|
647
|
+
if (itemEntries.length === 0) return `${prefix}- {}
|
|
648
|
+
`;
|
|
649
|
+
const [firstK, firstV] = itemEntries[0];
|
|
650
|
+
const rest = itemEntries.slice(1);
|
|
651
|
+
let itemYaml = `${prefix}- ${firstK}: ${toYaml(firstV, indent + 2).trimStart()}`;
|
|
652
|
+
for (const [k, v] of rest) {
|
|
653
|
+
itemYaml += `${prefix} ${k}: ${toYaml(v, indent + 2)}`;
|
|
654
|
+
}
|
|
655
|
+
return itemYaml;
|
|
656
|
+
}
|
|
657
|
+
return `${prefix}- ${toYaml(item, indent + 1).trimStart()}`;
|
|
658
|
+
}).join("");
|
|
598
659
|
}
|
|
599
660
|
if (typeof data === "object") {
|
|
600
661
|
const prefix = " ".repeat(indent);
|
|
601
662
|
const entries = Object.entries(data);
|
|
602
|
-
|
|
663
|
+
if (entries.length === 0) return "{}\n";
|
|
664
|
+
return entries.map(([k, v]) => {
|
|
665
|
+
const safeKey = /[:#\s]/.test(k) ? `"${k.replace(/"/g, '\\"')}"` : k;
|
|
666
|
+
if (typeof v === "object" && v !== null && (Array.isArray(v) ? v.length > 0 : Object.keys(v).length > 0)) {
|
|
667
|
+
return `${prefix}${safeKey}:
|
|
668
|
+
${toYaml(v, indent + 1)}`;
|
|
669
|
+
}
|
|
670
|
+
return `${prefix}${safeKey}: ${toYaml(v, indent + 1)}`;
|
|
671
|
+
}).join("");
|
|
603
672
|
}
|
|
604
673
|
return String(data) + "\n";
|
|
605
674
|
}
|
|
@@ -607,4 +676,4 @@ function toYaml(data, indent = 0) {
|
|
|
607
676
|
export {
|
|
608
677
|
jsonTool
|
|
609
678
|
};
|
|
610
|
-
//# sourceMappingURL=chunk-
|
|
679
|
+
//# sourceMappingURL=chunk-VD2LV5WO.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
safeResolveReal
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ZUFHAHTE.js";
|
|
4
4
|
|
|
5
5
|
// src/e2e.ts
|
|
6
6
|
import { open, readdir } from "node:fs/promises";
|
|
@@ -422,4 +422,4 @@ export {
|
|
|
422
422
|
discoverE2EProjects,
|
|
423
423
|
e2ePlanTool
|
|
424
424
|
};
|
|
425
|
-
//# sourceMappingURL=chunk-
|
|
425
|
+
//# sourceMappingURL=chunk-VPALDFYM.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
applySessionKanbanTaskToSource,
|
|
3
3
|
taskFileToSerializedGraph
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-X6KXNHUO.js";
|
|
5
5
|
|
|
6
6
|
// src/kanban.ts
|
|
7
7
|
import { stripLifecycleIssues as stripLifecycleIssues2 } from "@wrongstack/kanban";
|
|
@@ -349,7 +349,7 @@ async function handleKanbanBoardAction(projectRoot, input, ctx) {
|
|
|
349
349
|
assignedAgent: input.agentId,
|
|
350
350
|
status: input.status,
|
|
351
351
|
priority: input.priority,
|
|
352
|
-
label: input.labels?.[0],
|
|
352
|
+
label: input.label ?? input.labels?.[0],
|
|
353
353
|
chainId: input.chainId
|
|
354
354
|
});
|
|
355
355
|
return { ok: true, message: `${tasks.length} task(s) matched.`, tasks };
|
|
@@ -360,7 +360,7 @@ async function handleKanbanBoardAction(projectRoot, input, ctx) {
|
|
|
360
360
|
boardId: input.boardId,
|
|
361
361
|
assignedAgent: input.agentId,
|
|
362
362
|
priority: input.priority,
|
|
363
|
-
label: input.labels?.[0],
|
|
363
|
+
label: input.label ?? input.labels?.[0],
|
|
364
364
|
chainId: input.chainId,
|
|
365
365
|
limit: input.limit
|
|
366
366
|
});
|
|
@@ -373,7 +373,7 @@ async function handleKanbanBoardAction(projectRoot, input, ctx) {
|
|
|
373
373
|
assignedAgent: input.agentId,
|
|
374
374
|
status: input.status,
|
|
375
375
|
priority: input.priority,
|
|
376
|
-
label: input.labels?.[0],
|
|
376
|
+
label: input.label ?? input.labels?.[0],
|
|
377
377
|
chainId: input.chainId
|
|
378
378
|
});
|
|
379
379
|
return {
|
|
@@ -2070,29 +2070,39 @@ var kanbanTool = {
|
|
|
2070
2070
|
timeoutMs: 3e4,
|
|
2071
2071
|
inputSchema: KANBAN_INPUT_SCHEMA,
|
|
2072
2072
|
async execute(input, ctx, _opts) {
|
|
2073
|
+
const signal = _opts?.signal ?? ctx.signal ?? new AbortController().signal;
|
|
2074
|
+
if (signal.aborted) return fail("Operation aborted.");
|
|
2075
|
+
if (!input || typeof input !== "object" || typeof input.action !== "string" || !input.action.trim()) {
|
|
2076
|
+
return fail("kanban: action is required and must be a non-empty string.");
|
|
2077
|
+
}
|
|
2078
|
+
const normalizedInput = {
|
|
2079
|
+
...input,
|
|
2080
|
+
action: input.action.trim()
|
|
2081
|
+
};
|
|
2073
2082
|
const projectRoot = ctx.projectRoot;
|
|
2074
2083
|
if (!projectRoot) return fail("No project root is available.");
|
|
2075
|
-
const withPresence = createKanbanPresenceWrapper(projectRoot,
|
|
2084
|
+
const withPresence = createKanbanPresenceWrapper(projectRoot, normalizedInput, ctx);
|
|
2076
2085
|
try {
|
|
2077
2086
|
const result = await (async () => {
|
|
2078
|
-
const decompositionResult = await handleKanbanDecompositionAction(projectRoot,
|
|
2087
|
+
const decompositionResult = await handleKanbanDecompositionAction(projectRoot, normalizedInput, ctx);
|
|
2079
2088
|
if (decompositionResult !== void 0) return decompositionResult;
|
|
2080
|
-
const boardResult = await handleKanbanBoardAction(projectRoot,
|
|
2089
|
+
const boardResult = await handleKanbanBoardAction(projectRoot, normalizedInput, ctx);
|
|
2081
2090
|
if (boardResult !== void 0) return boardResult;
|
|
2082
|
-
const lifecycleResult = await handleKanbanLifecycleAction(projectRoot,
|
|
2091
|
+
const lifecycleResult = await handleKanbanLifecycleAction(projectRoot, normalizedInput, ctx);
|
|
2083
2092
|
if (lifecycleResult !== void 0) return lifecycleResult;
|
|
2084
2093
|
const contractResult = await handleKanbanContractAction(
|
|
2085
2094
|
projectRoot,
|
|
2086
|
-
|
|
2087
|
-
|
|
2095
|
+
normalizedInput,
|
|
2096
|
+
normalizedInput.author ?? normalizedInput.agentId,
|
|
2088
2097
|
ctx.eventSessionId?.() ?? ctx.session?.id ?? "default-session"
|
|
2089
2098
|
);
|
|
2090
2099
|
if (contractResult !== void 0) return contractResult;
|
|
2091
|
-
const detailResult = await handleKanbanDetailAction(projectRoot,
|
|
2100
|
+
const detailResult = await handleKanbanDetailAction(projectRoot, normalizedInput, ctx);
|
|
2092
2101
|
if (detailResult !== void 0) return detailResult;
|
|
2093
|
-
return fail(`Unknown kanban action: ${
|
|
2102
|
+
return fail(`Unknown kanban action: ${normalizedInput.action}`);
|
|
2094
2103
|
})();
|
|
2095
|
-
return
|
|
2104
|
+
if (signal.aborted) return fail("Operation aborted.");
|
|
2105
|
+
return await withPresence(result);
|
|
2096
2106
|
} catch (err) {
|
|
2097
2107
|
return fail(stripLifecycleIssues2(err instanceof Error ? err.message : String(err)));
|
|
2098
2108
|
}
|
|
@@ -2108,4 +2118,4 @@ export {
|
|
|
2108
2118
|
recordKanbanVerificationEvidence,
|
|
2109
2119
|
kanbanTool
|
|
2110
2120
|
};
|
|
2111
|
-
//# sourceMappingURL=chunk-
|
|
2121
|
+
//# sourceMappingURL=chunk-W2CECGTG.js.map
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compileUserRegex
|
|
3
3
|
} from "./chunk-Q5JPPCZC.js";
|
|
4
|
+
import {
|
|
5
|
+
mapWithConcurrency
|
|
6
|
+
} from "./chunk-NWZ6XGBJ.js";
|
|
4
7
|
import {
|
|
5
8
|
enqueueReindex
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-DP6CXMJZ.js";
|
|
7
10
|
import {
|
|
8
11
|
isBinaryBuffer,
|
|
9
12
|
safeResolveReal,
|
|
10
13
|
sha256hex,
|
|
11
14
|
truncateDiffPayload
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ZUFHAHTE.js";
|
|
13
16
|
|
|
14
17
|
// src/replace.ts
|
|
15
18
|
import { spawn } from "node:child_process";
|
|
@@ -27,7 +30,7 @@ import {
|
|
|
27
30
|
unifiedDiff
|
|
28
31
|
} from "@wrongstack/core/utils";
|
|
29
32
|
var MAX_DIFF_BYTES = 262144;
|
|
30
|
-
var DEFAULT_IGNORE = ["node_modules", ".git", "dist", "build", ".next", "coverage"];
|
|
33
|
+
var DEFAULT_IGNORE = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "coverage"]);
|
|
31
34
|
var replaceTool = {
|
|
32
35
|
name: "replace",
|
|
33
36
|
category: "Transform",
|
|
@@ -96,54 +99,51 @@ var replaceTool = {
|
|
|
96
99
|
const re = compiled.regex;
|
|
97
100
|
const globRe = input.glob ? compileGlob(input.glob) : null;
|
|
98
101
|
const dryRun = input.dry_run ?? true;
|
|
99
|
-
const
|
|
100
|
-
const fileList = await resolveFiles(filesInput, ctx, globRe);
|
|
102
|
+
const fileList = await resolveFiles(input.files, ctx, globRe);
|
|
101
103
|
const realRoot = await fs.realpath(ctx.projectRoot).catch(() => ctx.projectRoot);
|
|
102
|
-
const
|
|
103
|
-
let totalReplacements = 0;
|
|
104
|
-
let diffBytesUsed = 0;
|
|
105
|
-
let diffsOmitted = 0;
|
|
106
|
-
let diffsTruncated = 0;
|
|
107
|
-
for (const absPath of fileList) {
|
|
104
|
+
const fileResults = await mapWithConcurrency(fileList, 16, async (absPath) => {
|
|
108
105
|
signal?.throwIfAborted();
|
|
109
106
|
const lstat2 = await fs.lstat(absPath).catch((err) => {
|
|
110
107
|
if (err.code === "ENOENT") return null;
|
|
111
108
|
throw err;
|
|
112
109
|
});
|
|
113
|
-
if (!lstat2?.isFile())
|
|
114
|
-
if (lstat2.isSymbolicLink())
|
|
110
|
+
if (!lstat2?.isFile()) return null;
|
|
111
|
+
if (lstat2.isSymbolicLink()) return null;
|
|
115
112
|
let realPath;
|
|
116
113
|
try {
|
|
117
114
|
realPath = await fs.realpath(absPath);
|
|
118
115
|
} catch {
|
|
119
|
-
|
|
116
|
+
return null;
|
|
120
117
|
}
|
|
121
118
|
const rel = path.relative(realRoot, realPath);
|
|
122
|
-
if (rel.startsWith("..") || path.isAbsolute(rel))
|
|
119
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) return null;
|
|
123
120
|
const stat2 = await fs.stat(realPath).catch(() => null);
|
|
124
|
-
if (!stat2?.isFile())
|
|
121
|
+
if (!stat2?.isFile()) return null;
|
|
125
122
|
let content;
|
|
126
123
|
try {
|
|
127
124
|
const buf = await fs.readFile(realPath);
|
|
128
|
-
if (isBinaryBuffer(buf))
|
|
125
|
+
if (isBinaryBuffer(buf)) return null;
|
|
129
126
|
content = buf.toString("utf8");
|
|
130
127
|
} catch {
|
|
131
|
-
|
|
128
|
+
return null;
|
|
132
129
|
}
|
|
133
130
|
const style = detectNewlineStyle(content);
|
|
134
131
|
const contentLf = normalizeToLf(content);
|
|
135
132
|
re.lastIndex = 0;
|
|
136
133
|
const allMatches = [...contentLf.matchAll(re)];
|
|
137
|
-
if (allMatches.length === 0)
|
|
134
|
+
if (allMatches.length === 0) return null;
|
|
138
135
|
const matches = replaceAll ? allMatches : allMatches.slice(0, 1);
|
|
139
136
|
const count = matches.length;
|
|
140
|
-
let newContentLf =
|
|
141
|
-
|
|
137
|
+
let newContentLf = "";
|
|
138
|
+
let lastIdx = 0;
|
|
139
|
+
for (let i = 0; i < matches.length; i++) {
|
|
142
140
|
const m = expectDefined(matches[i]);
|
|
143
|
-
|
|
141
|
+
const matchIdx = expectDefined(m.index);
|
|
142
|
+
newContentLf += contentLf.slice(lastIdx, matchIdx) + expandReplacement(input.replacement, m);
|
|
143
|
+
lastIdx = matchIdx + m[0].length;
|
|
144
144
|
}
|
|
145
|
+
newContentLf += contentLf.slice(lastIdx);
|
|
145
146
|
re.lastIndex = 0;
|
|
146
|
-
totalReplacements += count;
|
|
147
147
|
if (!dryRun) {
|
|
148
148
|
const newContent = toStyle(newContentLf, style);
|
|
149
149
|
await atomicWrite(realPath, newContent, { mode: stat2.mode & 511 });
|
|
@@ -158,10 +158,27 @@ var replaceTool = {
|
|
|
158
158
|
after: newContent
|
|
159
159
|
});
|
|
160
160
|
}
|
|
161
|
-
|
|
161
|
+
const isIdentical = newContentLf === contentLf;
|
|
162
|
+
const rawDiff = dryRun || matches.length > 0 ? isIdentical ? "(no-op: replacement produced identical content)" : unifiedDiff(content, toStyle(newContentLf, style), {
|
|
162
163
|
fromFile: absPath,
|
|
163
164
|
toFile: absPath
|
|
164
165
|
}) : void 0;
|
|
166
|
+
return {
|
|
167
|
+
path: absPath,
|
|
168
|
+
replacements: count,
|
|
169
|
+
rawDiff,
|
|
170
|
+
isIdentical
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
const results = [];
|
|
174
|
+
let totalReplacements = 0;
|
|
175
|
+
let diffBytesUsed = 0;
|
|
176
|
+
let diffsOmitted = 0;
|
|
177
|
+
let diffsTruncated = 0;
|
|
178
|
+
for (const item of fileResults) {
|
|
179
|
+
if (!item) continue;
|
|
180
|
+
totalReplacements += item.replacements;
|
|
181
|
+
let diff = item.rawDiff;
|
|
165
182
|
if (diff !== void 0) {
|
|
166
183
|
const remaining = MAX_DIFF_BYTES - diffBytesUsed;
|
|
167
184
|
if (remaining <= 0) {
|
|
@@ -175,8 +192,8 @@ var replaceTool = {
|
|
|
175
192
|
}
|
|
176
193
|
}
|
|
177
194
|
results.push({
|
|
178
|
-
path:
|
|
179
|
-
replacements:
|
|
195
|
+
path: item.path,
|
|
196
|
+
replacements: item.replacements,
|
|
180
197
|
diff
|
|
181
198
|
});
|
|
182
199
|
}
|
|
@@ -189,13 +206,25 @@ var replaceTool = {
|
|
|
189
206
|
} catch {
|
|
190
207
|
}
|
|
191
208
|
}
|
|
209
|
+
const hasIdentical = fileResults.some((r) => r?.isIdentical);
|
|
192
210
|
const overBudget = diffsOmitted > 0 || diffsTruncated > 0;
|
|
211
|
+
const notes = [];
|
|
212
|
+
if (overBudget) {
|
|
213
|
+
notes.push(
|
|
214
|
+
`Diff payload exceeded the 256 KiB output budget: ${diffsTruncated} diff(s) truncated, ${diffsOmitted} diff(s) omitted. Replacement counts are complete; use the read tool to inspect individual files.`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (hasIdentical && !overBudget) {
|
|
218
|
+
notes.push(
|
|
219
|
+
"Some replacements produced content identical to existing files (see no-op diff)."
|
|
220
|
+
);
|
|
221
|
+
}
|
|
193
222
|
return {
|
|
194
223
|
files_modified: results.length,
|
|
195
224
|
total_replacements: totalReplacements,
|
|
196
225
|
results,
|
|
197
226
|
dry_run: dryRun,
|
|
198
|
-
note:
|
|
227
|
+
note: notes.length > 0 ? notes.join("\n") : void 0
|
|
199
228
|
};
|
|
200
229
|
}
|
|
201
230
|
};
|
|
@@ -246,7 +275,7 @@ function passesExtraGlob(extraGlob, name, full, base) {
|
|
|
246
275
|
}
|
|
247
276
|
async function resolveFiles(filesInput, ctx, extraGlob) {
|
|
248
277
|
const base = ctx.cwd;
|
|
249
|
-
const parts = filesInput.trim().split(",").map((s) => s.trim()).filter(Boolean);
|
|
278
|
+
const parts = Array.isArray(filesInput) ? filesInput.map((s) => s.trim()).filter(Boolean) : filesInput.trim().split(",").map((s) => s.trim()).filter(Boolean);
|
|
250
279
|
const resolved = [];
|
|
251
280
|
for (const p of parts) {
|
|
252
281
|
if (p.includes("*") || p.includes("?")) {
|
|
@@ -326,8 +355,14 @@ function spawnRgFind(pattern, base) {
|
|
|
326
355
|
return {
|
|
327
356
|
promise: new Promise((resolve, reject) => {
|
|
328
357
|
child.on("error", reject);
|
|
329
|
-
child.on("close", () => {
|
|
330
|
-
|
|
358
|
+
child.on("close", (code) => {
|
|
359
|
+
if (code !== 0 && code !== null) {
|
|
360
|
+
reject(new Error(`rg exited with code ${code}`));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
resolve(
|
|
364
|
+
buf.split(/\r?\n/).map((s) => s.trim()).filter(Boolean)
|
|
365
|
+
);
|
|
331
366
|
});
|
|
332
367
|
})
|
|
333
368
|
};
|
|
@@ -342,8 +377,9 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
342
377
|
} catch {
|
|
343
378
|
return;
|
|
344
379
|
}
|
|
380
|
+
const subdirs = [];
|
|
345
381
|
for (const e of entries) {
|
|
346
|
-
if (DEFAULT_IGNORE.
|
|
382
|
+
if (DEFAULT_IGNORE.has(e.name)) continue;
|
|
347
383
|
const full = path.join(dir, e.name);
|
|
348
384
|
try {
|
|
349
385
|
const stat2 = await fs.lstat(full);
|
|
@@ -352,7 +388,7 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
352
388
|
continue;
|
|
353
389
|
}
|
|
354
390
|
if (e.isDirectory()) {
|
|
355
|
-
|
|
391
|
+
subdirs.push(full);
|
|
356
392
|
} else if (e.isFile()) {
|
|
357
393
|
const name = e.name;
|
|
358
394
|
const rel = path.relative(base, full).split(path.sep).join("/");
|
|
@@ -365,6 +401,9 @@ async function globNative(pattern, base, extraGlob) {
|
|
|
365
401
|
globRe.lastIndex = 0;
|
|
366
402
|
}
|
|
367
403
|
}
|
|
404
|
+
if (subdirs.length > 0) {
|
|
405
|
+
await mapWithConcurrency(subdirs, 16, (subdir) => walk(subdir));
|
|
406
|
+
}
|
|
368
407
|
};
|
|
369
408
|
await walk(base);
|
|
370
409
|
return results;
|
|
@@ -374,4 +413,4 @@ export {
|
|
|
374
413
|
replaceTool,
|
|
375
414
|
__resetRgDetectionForTests
|
|
376
415
|
};
|
|
377
|
-
//# sourceMappingURL=chunk-
|
|
416
|
+
//# sourceMappingURL=chunk-X5FOFGXX.js.map
|