@wrongstack/core 0.1.0
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/LICENSE +17 -0
- package/dist/defaults/index.d.ts +1082 -0
- package/dist/defaults/index.js +4549 -0
- package/dist/defaults/index.js.map +1 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.js +6410 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/index.d.ts +71 -0
- package/dist/kernel/index.js +361 -0
- package/dist/kernel/index.js.map +1 -0
- package/dist/secret-scrubber-Dax_Ou_o.d.ts +1055 -0
- package/dist/system-prompt-BG3nks8P.d.ts +16 -0
- package/dist/tool-executor-DjnMELMV.d.ts +689 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.js +296 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +88 -0
- package/dist/utils/index.js +461 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/wstack-paths-D24ynAz1.d.ts +56 -0
- package/package.json +46 -0
- package/skills/git-flow/SKILL.md +32 -0
- package/skills/multi-agent/SKILL.md +62 -0
- package/skills/node-modern/SKILL.md +41 -0
- package/skills/prompt-engineering/SKILL.md +28 -0
- package/skills/react-modern/SKILL.md +34 -0
- package/skills/sdd/SKILL.md +78 -0
- package/skills/typescript-strict/SKILL.md +50 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path2 from 'path';
|
|
3
|
+
import { randomBytes, createHash } from 'crypto';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
|
|
6
|
+
// src/utils/atomic-write.ts
|
|
7
|
+
async function atomicWrite(targetPath, content, opts = {}) {
|
|
8
|
+
const dir = path2.dirname(targetPath);
|
|
9
|
+
await fs.mkdir(dir, { recursive: true });
|
|
10
|
+
const tmp = path2.join(dir, `.${path2.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
|
|
11
|
+
try {
|
|
12
|
+
if (typeof content === "string") {
|
|
13
|
+
await fs.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
|
|
14
|
+
} else {
|
|
15
|
+
await fs.writeFile(tmp, content, { flag: "wx" });
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const fh = await fs.open(tmp, "r+");
|
|
19
|
+
await fh.sync();
|
|
20
|
+
await fh.close();
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
let mode;
|
|
24
|
+
try {
|
|
25
|
+
const stat2 = await fs.stat(targetPath);
|
|
26
|
+
mode = stat2.mode & 511;
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
if (mode !== void 0) {
|
|
30
|
+
await fs.chmod(tmp, mode);
|
|
31
|
+
}
|
|
32
|
+
await fs.rename(tmp, targetPath);
|
|
33
|
+
} catch (err) {
|
|
34
|
+
try {
|
|
35
|
+
await fs.unlink(tmp);
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async function ensureDir(dir) {
|
|
42
|
+
await fs.mkdir(dir, { recursive: true });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/utils/safe-json.ts
|
|
46
|
+
function safeParse(input, maxBytes = 5e6) {
|
|
47
|
+
if (input.length > maxBytes) {
|
|
48
|
+
return { ok: false, error: `Input exceeds limit (${maxBytes} bytes)` };
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return { ok: true, value: JSON.parse(input) };
|
|
52
|
+
} catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
error: err instanceof Error ? err.message : String(err)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function safeStringify(value, pretty = false) {
|
|
60
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
61
|
+
const replacer = (_k, v) => {
|
|
62
|
+
if (typeof v === "bigint") return v.toString();
|
|
63
|
+
if (v instanceof Error) {
|
|
64
|
+
return { name: v.name, message: v.message, stack: v.stack };
|
|
65
|
+
}
|
|
66
|
+
if (typeof v === "object" && v !== null) {
|
|
67
|
+
if (seen.has(v)) return "[Circular]";
|
|
68
|
+
seen.add(v);
|
|
69
|
+
}
|
|
70
|
+
return v;
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
return JSON.stringify(value, replacer, pretty ? 2 : void 0) ?? "null";
|
|
74
|
+
} catch (err) {
|
|
75
|
+
return JSON.stringify({
|
|
76
|
+
__serialization_error: err instanceof Error ? err.message : String(err)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function sanitizeJsonString(s) {
|
|
81
|
+
let out = s.trim();
|
|
82
|
+
out = stripSingleLineComments(out);
|
|
83
|
+
out = out.replace(/,(\s*[}\]])/g, "$1");
|
|
84
|
+
try {
|
|
85
|
+
JSON.parse(out);
|
|
86
|
+
return out;
|
|
87
|
+
} catch {
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function stripSingleLineComments(s) {
|
|
92
|
+
let inString = false;
|
|
93
|
+
const chars = [];
|
|
94
|
+
let i = 0;
|
|
95
|
+
while (i < s.length) {
|
|
96
|
+
const c = s[i];
|
|
97
|
+
if (c === '"' && (i === 0 || s[i - 1] !== "\\")) {
|
|
98
|
+
inString = !inString;
|
|
99
|
+
chars.push(c);
|
|
100
|
+
} else if (c === "/" && s[i + 1] === "/" && !inString) {
|
|
101
|
+
while (i < s.length && s[i] !== "\n") i++;
|
|
102
|
+
} else {
|
|
103
|
+
chars.push(c);
|
|
104
|
+
}
|
|
105
|
+
i++;
|
|
106
|
+
}
|
|
107
|
+
return chars.join("");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/utils/newline-normalize.ts
|
|
111
|
+
function detectNewlineStyle(text) {
|
|
112
|
+
let lf = 0;
|
|
113
|
+
let crlf = 0;
|
|
114
|
+
let cr = 0;
|
|
115
|
+
for (let i = 0; i < text.length; i++) {
|
|
116
|
+
const c = text.charCodeAt(i);
|
|
117
|
+
if (c === 13) {
|
|
118
|
+
if (text.charCodeAt(i + 1) === 10) {
|
|
119
|
+
crlf++;
|
|
120
|
+
i++;
|
|
121
|
+
} else {
|
|
122
|
+
cr++;
|
|
123
|
+
}
|
|
124
|
+
} else if (c === 10) {
|
|
125
|
+
lf++;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (crlf > lf && crlf > cr) return "crlf";
|
|
129
|
+
if (cr > lf && cr > crlf) return "cr";
|
|
130
|
+
return "lf";
|
|
131
|
+
}
|
|
132
|
+
function toStyle(text, style) {
|
|
133
|
+
const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
134
|
+
if (style === "lf") return normalized;
|
|
135
|
+
if (style === "crlf") return normalized.replace(/\n/g, "\r\n");
|
|
136
|
+
return normalized.replace(/\n/g, "\r");
|
|
137
|
+
}
|
|
138
|
+
function normalizeToLf(text) {
|
|
139
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/utils/color.ts
|
|
143
|
+
var isColorTty = () => {
|
|
144
|
+
if (process.env.NO_COLOR) return false;
|
|
145
|
+
if (process.env.FORCE_COLOR) return true;
|
|
146
|
+
return Boolean(process.stdout?.isTTY);
|
|
147
|
+
};
|
|
148
|
+
var COLOR = isColorTty();
|
|
149
|
+
var wrap = (open2, close) => (s) => COLOR ? `\x1B[${open2}m${s}\x1B[${close}m` : s;
|
|
150
|
+
var color = {
|
|
151
|
+
reset: wrap("0", "0"),
|
|
152
|
+
bold: wrap("1", "22"),
|
|
153
|
+
dim: wrap("2", "22"),
|
|
154
|
+
italic: wrap("3", "23"),
|
|
155
|
+
underline: wrap("4", "24"),
|
|
156
|
+
red: wrap("31", "39"),
|
|
157
|
+
green: wrap("32", "39"),
|
|
158
|
+
yellow: wrap("33", "39"),
|
|
159
|
+
blue: wrap("34", "39"),
|
|
160
|
+
magenta: wrap("35", "39"),
|
|
161
|
+
cyan: wrap("36", "39"),
|
|
162
|
+
gray: wrap("90", "39"),
|
|
163
|
+
amber: wrap("38;5;214", "39"),
|
|
164
|
+
pink: wrap("38;5;205", "39"),
|
|
165
|
+
bgRed: wrap("41", "49"),
|
|
166
|
+
bgGreen: wrap("42", "49")
|
|
167
|
+
};
|
|
168
|
+
function stripAnsi(s) {
|
|
169
|
+
return s.replace(
|
|
170
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape regex
|
|
171
|
+
/\x1b\[[0-9;]*[A-Za-z]/g,
|
|
172
|
+
""
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/utils/glob-match.ts
|
|
177
|
+
function escapeRegex(s) {
|
|
178
|
+
return s.replace(/[.+^${}()|\\/]/g, "\\$&");
|
|
179
|
+
}
|
|
180
|
+
function compileGlob(pattern) {
|
|
181
|
+
let i = 0;
|
|
182
|
+
let re = "^";
|
|
183
|
+
while (i < pattern.length) {
|
|
184
|
+
const c = pattern[i];
|
|
185
|
+
if (c === "*") {
|
|
186
|
+
if (pattern[i + 1] === "*") {
|
|
187
|
+
re += ".*";
|
|
188
|
+
i += 2;
|
|
189
|
+
if (pattern[i] === "/") i++;
|
|
190
|
+
} else {
|
|
191
|
+
re += "[^/]*";
|
|
192
|
+
i++;
|
|
193
|
+
}
|
|
194
|
+
} else if (c === "?") {
|
|
195
|
+
re += "[^/]";
|
|
196
|
+
i++;
|
|
197
|
+
} else if (c === "[") {
|
|
198
|
+
let cls = "[";
|
|
199
|
+
i++;
|
|
200
|
+
if (pattern[i] === "!" || pattern[i] === "^") {
|
|
201
|
+
cls += "^";
|
|
202
|
+
i++;
|
|
203
|
+
}
|
|
204
|
+
while (i < pattern.length && pattern[i] !== "]") {
|
|
205
|
+
const ch = pattern[i] ?? "";
|
|
206
|
+
if (ch === "\\") {
|
|
207
|
+
cls += "\\\\";
|
|
208
|
+
} else if (ch === "]" || ch === "^") {
|
|
209
|
+
cls += `\\${ch}`;
|
|
210
|
+
} else {
|
|
211
|
+
cls += ch;
|
|
212
|
+
}
|
|
213
|
+
i++;
|
|
214
|
+
}
|
|
215
|
+
cls += "]";
|
|
216
|
+
re += cls;
|
|
217
|
+
i++;
|
|
218
|
+
} else {
|
|
219
|
+
re += escapeRegex(c ?? "");
|
|
220
|
+
i++;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
re += "$";
|
|
224
|
+
return new RegExp(re);
|
|
225
|
+
}
|
|
226
|
+
function matchGlob(pattern, input) {
|
|
227
|
+
return compileGlob(pattern).test(input);
|
|
228
|
+
}
|
|
229
|
+
function matchAny(patterns, input) {
|
|
230
|
+
return patterns.some((p) => matchGlob(p, input));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/utils/diff.ts
|
|
234
|
+
function myersDiff(a, b) {
|
|
235
|
+
const N = a.length;
|
|
236
|
+
const M = b.length;
|
|
237
|
+
const max = N + M;
|
|
238
|
+
if (max === 0) return [];
|
|
239
|
+
const v = /* @__PURE__ */ new Map();
|
|
240
|
+
v.set(1, 0);
|
|
241
|
+
const trace = [];
|
|
242
|
+
for (let d = 0; d <= max; d++) {
|
|
243
|
+
const snapshot = new Map(v);
|
|
244
|
+
trace.push(snapshot);
|
|
245
|
+
for (let k = -d; k <= d; k += 2) {
|
|
246
|
+
const left = v.get(k - 1) ?? -1;
|
|
247
|
+
const right = v.get(k + 1) ?? -1;
|
|
248
|
+
let x;
|
|
249
|
+
if (k === -d || k !== d && left < right) {
|
|
250
|
+
x = right;
|
|
251
|
+
} else {
|
|
252
|
+
x = left + 1;
|
|
253
|
+
}
|
|
254
|
+
let y = x - k;
|
|
255
|
+
while (x < N && y < M && a[x] === b[y]) {
|
|
256
|
+
x++;
|
|
257
|
+
y++;
|
|
258
|
+
}
|
|
259
|
+
v.set(k, x);
|
|
260
|
+
if (x >= N && y >= M) {
|
|
261
|
+
return backtrack(trace, a, b, N, M, d);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return [];
|
|
266
|
+
}
|
|
267
|
+
function backtrack(trace, a, b, N, M, finalD) {
|
|
268
|
+
const edits = [];
|
|
269
|
+
let x = N;
|
|
270
|
+
let y = M;
|
|
271
|
+
for (let d = finalD; d > 0; d--) {
|
|
272
|
+
const v = trace[d];
|
|
273
|
+
if (!v) break;
|
|
274
|
+
const k = x - y;
|
|
275
|
+
const left = v.get(k - 1) ?? -1;
|
|
276
|
+
const right = v.get(k + 1) ?? -1;
|
|
277
|
+
let prevK;
|
|
278
|
+
if (k === -d || k !== d && left < right) {
|
|
279
|
+
prevK = k + 1;
|
|
280
|
+
} else {
|
|
281
|
+
prevK = k - 1;
|
|
282
|
+
}
|
|
283
|
+
const prevX = v.get(prevK) ?? 0;
|
|
284
|
+
const prevY = prevX - prevK;
|
|
285
|
+
while (x > prevX && y > prevY) {
|
|
286
|
+
edits.push({ op: "equal", a: x - 1, b: y - 1, line: a[x - 1] ?? "" });
|
|
287
|
+
x--;
|
|
288
|
+
y--;
|
|
289
|
+
}
|
|
290
|
+
if (d > 0) {
|
|
291
|
+
if (x === prevX) {
|
|
292
|
+
edits.push({ op: "insert", a: x, b: y - 1, line: b[y - 1] ?? "" });
|
|
293
|
+
} else {
|
|
294
|
+
edits.push({ op: "delete", a: x - 1, b: y, line: a[x - 1] ?? "" });
|
|
295
|
+
}
|
|
296
|
+
x = prevX;
|
|
297
|
+
y = prevY;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
while (x > 0 && y > 0) {
|
|
301
|
+
edits.push({ op: "equal", a: x - 1, b: y - 1, line: a[x - 1] ?? "" });
|
|
302
|
+
x--;
|
|
303
|
+
y--;
|
|
304
|
+
}
|
|
305
|
+
return edits.reverse();
|
|
306
|
+
}
|
|
307
|
+
function unifiedDiff(oldText, newText, opts = {}) {
|
|
308
|
+
const context = opts.context ?? 3;
|
|
309
|
+
const a = oldText.split("\n");
|
|
310
|
+
const b = newText.split("\n");
|
|
311
|
+
if (a[a.length - 1] === "") a.pop();
|
|
312
|
+
if (b[b.length - 1] === "") b.pop();
|
|
313
|
+
const edits = myersDiff(a, b);
|
|
314
|
+
if (edits.every((e) => e.op === "equal")) return "";
|
|
315
|
+
const hunks = [];
|
|
316
|
+
let i = 0;
|
|
317
|
+
while (i < edits.length) {
|
|
318
|
+
while (i < edits.length && edits[i]?.op === "equal") i++;
|
|
319
|
+
if (i >= edits.length) break;
|
|
320
|
+
const hunkStart = Math.max(0, i - context);
|
|
321
|
+
const lines = [];
|
|
322
|
+
let aStart = (edits[hunkStart]?.a ?? 0) + 1;
|
|
323
|
+
let bStart = (edits[hunkStart]?.b ?? 0) + 1;
|
|
324
|
+
let aCount = 0;
|
|
325
|
+
let bCount = 0;
|
|
326
|
+
let cursor = hunkStart;
|
|
327
|
+
let trailing = 0;
|
|
328
|
+
while (cursor < edits.length) {
|
|
329
|
+
const e = edits[cursor];
|
|
330
|
+
if (!e) break;
|
|
331
|
+
if (e.op === "equal") {
|
|
332
|
+
trailing++;
|
|
333
|
+
if (trailing > context * 2) break;
|
|
334
|
+
} else {
|
|
335
|
+
trailing = 0;
|
|
336
|
+
}
|
|
337
|
+
if (e.op === "equal") {
|
|
338
|
+
lines.push(` ${e.line}`);
|
|
339
|
+
aCount++;
|
|
340
|
+
bCount++;
|
|
341
|
+
} else if (e.op === "delete") {
|
|
342
|
+
lines.push(`-${e.line}`);
|
|
343
|
+
aCount++;
|
|
344
|
+
} else {
|
|
345
|
+
lines.push(`+${e.line}`);
|
|
346
|
+
bCount++;
|
|
347
|
+
}
|
|
348
|
+
cursor++;
|
|
349
|
+
}
|
|
350
|
+
while (lines.length > 0 && lines[lines.length - 1]?.startsWith(" ") && trailing > context) {
|
|
351
|
+
lines.pop();
|
|
352
|
+
aCount--;
|
|
353
|
+
bCount--;
|
|
354
|
+
trailing--;
|
|
355
|
+
}
|
|
356
|
+
if (aCount === 0) aStart = 0;
|
|
357
|
+
if (bCount === 0) bStart = 0;
|
|
358
|
+
hunks.push({ aStart, bStart, lines });
|
|
359
|
+
i = cursor;
|
|
360
|
+
}
|
|
361
|
+
if (hunks.length === 0) return "";
|
|
362
|
+
let out = "";
|
|
363
|
+
out += `--- ${opts.fromFile ?? "a"}
|
|
364
|
+
`;
|
|
365
|
+
out += `+++ ${opts.toFile ?? "b"}
|
|
366
|
+
`;
|
|
367
|
+
for (const h of hunks) {
|
|
368
|
+
let aCount = 0;
|
|
369
|
+
let bCount = 0;
|
|
370
|
+
for (const l of h.lines) {
|
|
371
|
+
if (l.startsWith(" ")) {
|
|
372
|
+
aCount++;
|
|
373
|
+
bCount++;
|
|
374
|
+
} else if (l.startsWith("-")) aCount++;
|
|
375
|
+
else if (l.startsWith("+")) bCount++;
|
|
376
|
+
}
|
|
377
|
+
out += `@@ -${h.aStart},${aCount} +${h.bStart},${bCount} @@
|
|
378
|
+
`;
|
|
379
|
+
out += `${h.lines.join("\n")}
|
|
380
|
+
`;
|
|
381
|
+
}
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
function projectHash(absRoot) {
|
|
385
|
+
return createHash("sha256").update(path2.resolve(absRoot)).digest("hex").slice(0, 12);
|
|
386
|
+
}
|
|
387
|
+
function resolveWstackPaths(opts) {
|
|
388
|
+
const home = opts.userHome ?? os.homedir();
|
|
389
|
+
const globalRoot = opts.globalRoot ?? path2.join(home, ".wrongstack");
|
|
390
|
+
const hash = projectHash(opts.projectRoot);
|
|
391
|
+
const projectDir = path2.join(globalRoot, "projects", hash);
|
|
392
|
+
return {
|
|
393
|
+
globalRoot,
|
|
394
|
+
globalConfig: path2.join(globalRoot, "config.json"),
|
|
395
|
+
secretsKey: path2.join(globalRoot, ".key"),
|
|
396
|
+
globalMemory: path2.join(globalRoot, "memory.md"),
|
|
397
|
+
globalSkills: path2.join(globalRoot, "skills"),
|
|
398
|
+
cacheDir: path2.join(globalRoot, "cache"),
|
|
399
|
+
modelsCache: path2.join(globalRoot, "cache", "models.dev.json"),
|
|
400
|
+
historyFile: path2.join(globalRoot, "history"),
|
|
401
|
+
logFile: path2.join(globalRoot, "logs", "wrongstack.log"),
|
|
402
|
+
projectDir,
|
|
403
|
+
projectMemory: path2.join(projectDir, "memory.md"),
|
|
404
|
+
projectSessions: path2.join(projectDir, "sessions"),
|
|
405
|
+
projectTrust: path2.join(projectDir, "trust.json"),
|
|
406
|
+
projectMeta: path2.join(projectDir, "meta.json"),
|
|
407
|
+
projectLocalConfig: path2.join(projectDir, "config.local.json"),
|
|
408
|
+
inProjectAgentsFile: path2.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
|
|
409
|
+
inProjectSkills: path2.join(opts.projectRoot, ".wrongstack", "skills"),
|
|
410
|
+
projectHash: hash
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// src/utils/tool-output-serializer.ts
|
|
415
|
+
function createToolOutputSerializer(opts = {}) {
|
|
416
|
+
const capBytes = opts.perIterationOutputCapBytes ?? 1e5;
|
|
417
|
+
function serialize(value) {
|
|
418
|
+
if (typeof value === "string") return value;
|
|
419
|
+
if (value === null || value === void 0) return "";
|
|
420
|
+
if (typeof value === "object") {
|
|
421
|
+
if (Array.isArray(value)) return value.map(serialize).join("\n");
|
|
422
|
+
if ("text" in value) {
|
|
423
|
+
const t = value.text;
|
|
424
|
+
return typeof t === "string" ? t : JSON.stringify(value, null, 2);
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
return JSON.stringify(value, null, 2);
|
|
428
|
+
} catch {
|
|
429
|
+
return String(value);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return String(value);
|
|
433
|
+
}
|
|
434
|
+
function enforceCap(text, remainingBudget) {
|
|
435
|
+
if (remainingBudget <= 0) {
|
|
436
|
+
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
437
|
+
}
|
|
438
|
+
const textBytes = Buffer.byteLength(text, "utf8");
|
|
439
|
+
if (textBytes <= remainingBudget) {
|
|
440
|
+
return { text, newBudget: remainingBudget - textBytes };
|
|
441
|
+
}
|
|
442
|
+
const marker = `
|
|
443
|
+
\u2026[truncated ${textBytes - remainingBudget} bytes]\u2026
|
|
444
|
+
`;
|
|
445
|
+
const markerBytes = Buffer.byteLength(marker, "utf8");
|
|
446
|
+
const available = remainingBudget - markerBytes;
|
|
447
|
+
if (available <= 0) {
|
|
448
|
+
return { text: "[truncated: iteration output cap exceeded]", newBudget: 0 };
|
|
449
|
+
}
|
|
450
|
+
const half = Math.floor(available / 2);
|
|
451
|
+
const first = text.slice(0, half);
|
|
452
|
+
Buffer.byteLength(first, "utf8");
|
|
453
|
+
const second = text.slice(text.length - half);
|
|
454
|
+
return { text: `${first}${marker}${second}`, newBudget: 0 };
|
|
455
|
+
}
|
|
456
|
+
return { serialize, enforceCap, capBytes };
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export { atomicWrite, color, compileGlob, createToolOutputSerializer, detectNewlineStyle, ensureDir, matchAny, matchGlob, normalizeToLf, projectHash, resolveWstackPaths, safeParse, safeStringify, sanitizeJsonString, stripAnsi, toStyle, unifiedDiff };
|
|
460
|
+
//# sourceMappingURL=index.js.map
|
|
461
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/atomic-write.ts","../../src/utils/safe-json.ts","../../src/utils/newline-normalize.ts","../../src/utils/color.ts","../../src/utils/glob-match.ts","../../src/utils/diff.ts","../../src/utils/wstack-paths.ts","../../src/utils/tool-output-serializer.ts"],"names":["path","stat","open"],"mappings":";;;;;;AASA,eAAsB,WAAA,CACpB,UAAA,EACA,OAAA,EACA,IAAA,GAA2B,EAAC,EACb;AACf,EAAA,MAAM,GAAA,GAAWA,cAAQ,UAAU,CAAA;AACnC,EAAA,MAAS,EAAA,CAAA,KAAA,CAAM,GAAA,EAAK,EAAE,SAAA,EAAW,MAAM,CAAA;AACvC,EAAA,MAAM,GAAA,GAAWA,KAAA,CAAA,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAASA,eAAS,UAAU,CAAC,CAAA,CAAA,EAAI,WAAA,CAAY,CAAC,CAAA,CAAE,QAAA,CAAS,KAAK,CAAC,CAAA,IAAA,CAAM,CAAA;AAIhG,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,MAAA,MAAS,EAAA,CAAA,SAAA,CAAU,GAAA,EAAK,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,QAAA,EAAU,IAAA,CAAK,QAAA,IAAY,MAAA,EAAQ,CAAA;AAAA,IACpF,CAAA,MAAO;AACL,MAAA,MAAS,aAAU,GAAA,EAAK,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,IACjD;AACA,IAAA,IAAI;AACF,MAAA,MAAM,EAAA,GAAK,MAAS,EAAA,CAAA,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAClC,MAAA,MAAM,GAAG,IAAA,EAAK;AACd,MAAA,MAAM,GAAG,KAAA,EAAM;AAAA,IACjB,CAAA,CAAA,MAAQ;AAAA,IAER;AAEA,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAMC,KAAAA,GAAO,MAAS,EAAA,CAAA,IAAA,CAAK,UAAU,CAAA;AACrC,MAAA,IAAA,GAAOA,MAAK,IAAA,GAAO,GAAA;AAAA,IACrB,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,IAAI,SAAS,KAAA,CAAA,EAAW;AACtB,MAAA,MAAS,EAAA,CAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAAA,IAC1B;AACA,IAAA,MAAS,EAAA,CAAA,MAAA,CAAO,KAAK,UAAU,CAAA;AAAA,EACjC,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI;AACF,MAAA,MAAS,UAAO,GAAG,CAAA;AAAA,IACrB,CAAA,CAAA,MAAQ;AAAA,IAER;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;AAEA,eAAsB,UAAU,GAAA,EAA4B;AAC1D,EAAA,MAAS,EAAA,CAAA,KAAA,CAAM,GAAA,EAAK,EAAE,SAAA,EAAW,MAAM,CAAA;AACzC;;;ACnDO,SAAS,SAAA,CAAuB,KAAA,EAAe,QAAA,GAAW,GAAA,EAA+B;AAC9F,EAAA,IAAI,KAAA,CAAM,SAAS,QAAA,EAAU;AAC3B,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,CAAA,qBAAA,EAAwB,QAAQ,CAAA,OAAA,CAAA,EAAU;AAAA,EACvE;AACA,EAAA,IAAI;AACF,IAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,OAAO,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,EAAO;AAAA,EACnD,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO;AAAA,MACL,EAAA,EAAI,KAAA;AAAA,MACJ,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACxD;AAAA,EACF;AACF;AAEO,SAAS,aAAA,CAAc,KAAA,EAAgB,MAAA,GAAS,KAAA,EAAe;AACpE,EAAA,MAAM,IAAA,uBAAW,OAAA,EAAQ;AACzB,EAAA,MAAM,QAAA,GAAW,CAAC,EAAA,EAAY,CAAA,KAAwB;AACpD,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,EAAE,QAAA,EAAS;AAC7C,IAAA,IAAI,aAAa,KAAA,EAAO;AACtB,MAAA,OAAO,EAAE,MAAM,CAAA,CAAE,IAAA,EAAM,SAAS,CAAA,CAAE,OAAA,EAAS,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM;AAAA,IAC5D;AACA,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,IAAA,EAAM;AACvC,MAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAW,CAAA,EAAG,OAAO,YAAA;AAClC,MAAA,IAAA,CAAK,IAAI,CAAW,CAAA;AAAA,IACtB;AACA,IAAA,OAAO,CAAA;AAAA,EACT,CAAA;AACA,EAAA,IAAI;AACF,IAAA,OAAO,KAAK,SAAA,CAAU,KAAA,EAAO,UAAU,MAAA,GAAS,CAAA,GAAI,MAAS,CAAA,IAAK,MAAA;AAAA,EACpE,SAAS,GAAA,EAAK;AACZ,IAAA,OAAO,KAAK,SAAA,CAAU;AAAA,MACpB,uBAAuB,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACvE,CAAA;AAAA,EACH;AACF;AAMO,SAAS,mBAAmB,CAAA,EAAmB;AACpD,EAAA,IAAI,GAAA,GAAM,EAAE,IAAA,EAAK;AAMjB,EAAA,GAAA,GAAM,wBAAwB,GAAG,CAAA;AAGjC,EAAA,GAAA,GAAM,GAAA,CAAI,OAAA,CAAQ,cAAA,EAAgB,IAAI,CAAA;AAKtC,EAAA,IAAI;AACF,IAAA,IAAA,CAAK,MAAM,GAAG,CAAA;AACd,IAAA,OAAO,GAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,GAAA;AAAA,EACT;AACF;AAEA,SAAS,wBAAwB,CAAA,EAAmB;AAClD,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,CAAA,GAAI,EAAE,MAAA,EAAQ;AACnB,IAAA,MAAM,CAAA,GAAI,EAAE,CAAC,CAAA;AACb,IAAA,IAAI,CAAA,KAAM,QAAQ,CAAA,KAAM,CAAA,IAAK,EAAE,CAAA,GAAI,CAAC,MAAM,IAAA,CAAA,EAAO;AAC/C,MAAA,QAAA,GAAW,CAAC,QAAA;AACZ,MAAA,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,IACd,CAAA,MAAA,IAAW,MAAM,GAAA,IAAO,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,GAAA,IAAO,CAAC,QAAA,EAAU;AAErD,MAAA,OAAO,IAAI,CAAA,CAAE,MAAA,IAAU,CAAA,CAAE,CAAC,MAAM,IAAA,EAAM,CAAA,EAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,KAAA,CAAM,KAAK,CAAC,CAAA;AAAA,IACd;AACA,IAAA,CAAA,EAAA;AAAA,EACF;AACA,EAAA,OAAO,KAAA,CAAM,KAAK,EAAE,CAAA;AACtB;;;ACrFO,SAAS,mBAAmB,IAAA,EAA4B;AAC7D,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACpC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA;AAC3B,IAAA,IAAI,MAAM,EAAA,EAAM;AACd,MAAA,IAAI,IAAA,CAAK,UAAA,CAAW,CAAA,GAAI,CAAC,MAAM,EAAA,EAAM;AACnC,QAAA,IAAA,EAAA;AACA,QAAA,CAAA,EAAA;AAAA,MACF,CAAA,MAAO;AACL,QAAA,EAAA,EAAA;AAAA,MACF;AAAA,IACF,CAAA,MAAA,IAAW,MAAM,EAAA,EAAM;AACrB,MAAA,EAAA,EAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,IAAI,IAAA,GAAO,EAAA,IAAM,IAAA,GAAO,EAAA,EAAI,OAAO,MAAA;AACnC,EAAA,IAAI,EAAA,GAAK,EAAA,IAAM,EAAA,GAAK,IAAA,EAAM,OAAO,IAAA;AACjC,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,OAAA,CAAQ,MAAc,KAAA,EAA6B;AACjE,EAAA,MAAM,UAAA,GAAa,KAAK,OAAA,CAAQ,OAAA,EAAS,IAAI,CAAA,CAAE,OAAA,CAAQ,OAAO,IAAI,CAAA;AAClE,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,UAAA;AAC3B,EAAA,IAAI,UAAU,MAAA,EAAQ,OAAO,UAAA,CAAW,OAAA,CAAQ,OAAO,MAAM,CAAA;AAC7D,EAAA,OAAO,UAAA,CAAW,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA;AACvC;AAEO,SAAS,cAAc,IAAA,EAAsB;AAClD,EAAA,OAAO,KAAK,OAAA,CAAQ,OAAA,EAAS,IAAI,CAAA,CAAE,OAAA,CAAQ,OAAO,IAAI,CAAA;AACxD;;;ACjCA,IAAM,aAAa,MAAe;AAChC,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,QAAA,EAAU,OAAO,KAAA;AACjC,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,WAAA,EAAa,OAAO,IAAA;AACpC,EAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,MAAA,EAAQ,KAAK,CAAA;AACtC,CAAA;AAEA,IAAM,QAAQ,UAAA,EAAW;AAEzB,IAAM,IAAA,GAAO,CAACC,KAAAA,EAAc,KAAA,KAC1B,CAAC,CAAA,KACC,KAAA,GAAQ,CAAA,KAAA,EAAQA,KAAI,CAAA,CAAA,EAAI,CAAC,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,CAAA,GAAM,CAAA;AAEzC,IAAM,KAAA,GAAQ;AAAA,EACnB,KAAA,EAAO,IAAA,CAAK,GAAA,EAAK,GAAG,CAAA;AAAA,EACpB,IAAA,EAAM,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EACpB,GAAA,EAAK,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EACnB,MAAA,EAAQ,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EACtB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAK,IAAI,CAAA;AAAA,EACzB,GAAA,EAAK,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACpB,KAAA,EAAO,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACtB,MAAA,EAAQ,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACvB,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACrB,OAAA,EAAS,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACxB,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACrB,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACrB,KAAA,EAAO,IAAA,CAAK,UAAA,EAAY,IAAI,CAAA;AAAA,EAC5B,IAAA,EAAM,IAAA,CAAK,UAAA,EAAY,IAAI,CAAA;AAAA,EAC3B,KAAA,EAAO,IAAA,CAAK,IAAA,EAAM,IAAI,CAAA;AAAA,EACtB,OAAA,EAAS,IAAA,CAAK,IAAA,EAAM,IAAI;AAC1B;AAEO,SAAS,UAAU,CAAA,EAAmB;AAC3C,EAAA,OAAO,CAAA,CAAE,OAAA;AAAA;AAAA,IAEP,wBAAA;AAAA,IACA;AAAA,GACF;AACF;;;AC5BA,SAAS,YAAY,CAAA,EAAmB;AACtC,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,iBAAA,EAAmB,MAAM,CAAA;AAC5C;AAEO,SAAS,YAAY,OAAA,EAAyB;AACnD,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,EAAA,GAAK,GAAA;AACT,EAAA,OAAO,CAAA,GAAI,QAAQ,MAAA,EAAQ;AACzB,IAAA,MAAM,CAAA,GAAI,QAAQ,CAAC,CAAA;AACnB,IAAA,IAAI,MAAM,GAAA,EAAK;AACb,MAAA,IAAI,OAAA,CAAQ,CAAA,GAAI,CAAC,CAAA,KAAM,GAAA,EAAK;AAE1B,QAAA,EAAA,IAAM,IAAA;AACN,QAAA,CAAA,IAAK,CAAA;AAEL,QAAA,IAAI,OAAA,CAAQ,CAAC,CAAA,KAAM,GAAA,EAAK,CAAA,EAAA;AAAA,MAC1B,CAAA,MAAO;AAEL,QAAA,EAAA,IAAM,OAAA;AACN,QAAA,CAAA,EAAA;AAAA,MACF;AAAA,IACF,CAAA,MAAA,IAAW,MAAM,GAAA,EAAK;AACpB,MAAA,EAAA,IAAM,MAAA;AACN,MAAA,CAAA,EAAA;AAAA,IACF,CAAA,MAAA,IAAW,MAAM,GAAA,EAAK;AACpB,MAAA,IAAI,GAAA,GAAM,GAAA;AACV,MAAA,CAAA,EAAA;AACA,MAAA,IAAI,QAAQ,CAAC,CAAA,KAAM,OAAO,OAAA,CAAQ,CAAC,MAAM,GAAA,EAAK;AAC5C,QAAA,GAAA,IAAO,GAAA;AACP,QAAA,CAAA,EAAA;AAAA,MACF;AACA,MAAA,OAAO,IAAI,OAAA,CAAQ,MAAA,IAAU,OAAA,CAAQ,CAAC,MAAM,GAAA,EAAK;AAC/C,QAAA,MAAM,EAAA,GAAK,OAAA,CAAQ,CAAC,CAAA,IAAK,EAAA;AAKzB,QAAA,IAAI,OAAO,IAAA,EAAM;AACf,UAAA,GAAA,IAAO,MAAA;AAAA,QACT,CAAA,MAAA,IAAW,EAAA,KAAO,GAAA,IAAO,EAAA,KAAO,GAAA,EAAK;AACnC,UAAA,GAAA,IAAO,KAAK,EAAE,CAAA,CAAA;AAAA,QAChB,CAAA,MAAO;AACL,UAAA,GAAA,IAAO,EAAA;AAAA,QACT;AACA,QAAA,CAAA,EAAA;AAAA,MACF;AACA,MAAA,GAAA,IAAO,GAAA;AACP,MAAA,EAAA,IAAM,GAAA;AACN,MAAA,CAAA,EAAA;AAAA,IACF,CAAA,MAAO;AACL,MAAA,EAAA,IAAM,WAAA,CAAY,KAAK,EAAE,CAAA;AACzB,MAAA,CAAA,EAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,EAAA,IAAM,GAAA;AACN,EAAA,OAAO,IAAI,OAAO,EAAE,CAAA;AACtB;AAEO,SAAS,SAAA,CAAU,SAAiB,KAAA,EAAwB;AACjE,EAAA,OAAO,WAAA,CAAY,OAAO,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA;AACxC;AAEO,SAAS,QAAA,CAAS,UAAoB,KAAA,EAAwB;AACnE,EAAA,OAAO,SAAS,IAAA,CAAK,CAAC,MAAM,SAAA,CAAU,CAAA,EAAG,KAAK,CAAC,CAAA;AACjD;;;AC7DA,SAAS,SAAA,CAAU,GAAa,CAAA,EAAqB;AACnD,EAAA,MAAM,IAAI,CAAA,CAAE,MAAA;AACZ,EAAA,MAAM,IAAI,CAAA,CAAE,MAAA;AACZ,EAAA,MAAM,MAAM,CAAA,GAAI,CAAA;AAChB,EAAA,IAAI,GAAA,KAAQ,CAAA,EAAG,OAAO,EAAC;AAEvB,EAAA,MAAM,CAAA,uBAAQ,GAAA,EAAoB;AAClC,EAAA,CAAA,CAAE,GAAA,CAAI,GAAG,CAAC,CAAA;AACV,EAAA,MAAM,QAA+B,EAAC;AAEtC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,GAAA,EAAK,CAAA,EAAA,EAAK;AAC7B,IAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,CAAC,CAAA;AAC1B,IAAA,KAAA,CAAM,KAAK,QAAQ,CAAA;AACnB,IAAA,KAAA,IAAS,IAAI,CAAC,CAAA,EAAG,CAAA,IAAK,CAAA,EAAG,KAAK,CAAA,EAAG;AAC/B,MAAA,MAAM,IAAA,GAAO,CAAA,CAAE,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,IAAK,EAAA;AAC7B,MAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,IAAK,EAAA;AAC9B,MAAA,IAAI,CAAA;AACJ,MAAA,IAAI,MAAM,CAAC,CAAA,IAAM,CAAA,KAAM,CAAA,IAAK,OAAO,KAAA,EAAQ;AACzC,QAAA,CAAA,GAAI,KAAA;AAAA,MACN,CAAA,MAAO;AACL,QAAA,CAAA,GAAI,IAAA,GAAO,CAAA;AAAA,MACb;AACA,MAAA,IAAI,IAAI,CAAA,GAAI,CAAA;AACZ,MAAA,OAAO,CAAA,GAAI,KAAK,CAAA,GAAI,CAAA,IAAK,EAAE,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,CAAA,EAAG;AACtC,QAAA,CAAA,EAAA;AACA,QAAA,CAAA,EAAA;AAAA,MACF;AACA,MAAA,CAAA,CAAE,GAAA,CAAI,GAAG,CAAC,CAAA;AACV,MAAA,IAAI,CAAA,IAAK,CAAA,IAAK,CAAA,IAAK,CAAA,EAAG;AACpB,QAAA,OAAO,UAAU,KAAA,EAAO,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,EAAC;AACV;AAEA,SAAS,UACP,KAAA,EACA,CAAA,EACA,CAAA,EACA,CAAA,EACA,GACA,MAAA,EACQ;AACR,EAAA,MAAM,QAAgB,EAAC;AACvB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,MAAA,EAAQ,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC/B,IAAA,MAAM,CAAA,GAAI,MAAM,CAAC,CAAA;AACjB,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,MAAM,IAAI,CAAA,GAAI,CAAA;AACd,IAAA,MAAM,IAAA,GAAO,CAAA,CAAE,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,IAAK,EAAA;AAC7B,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,IAAK,EAAA;AAC9B,IAAA,IAAI,KAAA;AACJ,IAAA,IAAI,MAAM,CAAC,CAAA,IAAM,CAAA,KAAM,CAAA,IAAK,OAAO,KAAA,EAAQ;AACzC,MAAA,KAAA,GAAQ,CAAA,GAAI,CAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,KAAA,GAAQ,CAAA,GAAI,CAAA;AAAA,IACd;AACA,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,GAAA,CAAI,KAAK,CAAA,IAAK,CAAA;AAC9B,IAAA,MAAM,QAAQ,KAAA,GAAQ,KAAA;AACtB,IAAA,OAAO,CAAA,GAAI,KAAA,IAAS,CAAA,GAAI,KAAA,EAAO;AAC7B,MAAA,KAAA,CAAM,KAAK,EAAE,EAAA,EAAI,OAAA,EAAS,CAAA,EAAG,IAAI,CAAA,EAAG,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA,GAAI,CAAC,CAAA,IAAK,IAAI,CAAA;AACpE,MAAA,CAAA,EAAA;AACA,MAAA,CAAA,EAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAI,CAAA,EAAG;AACT,MAAA,IAAI,MAAM,KAAA,EAAO;AACf,QAAA,KAAA,CAAM,IAAA,CAAK,EAAE,EAAA,EAAI,QAAA,EAAU,GAAG,CAAA,EAAG,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA,GAAI,CAAC,CAAA,IAAK,IAAI,CAAA;AAAA,MACnE,CAAA,MAAO;AACL,QAAA,KAAA,CAAM,IAAA,CAAK,EAAE,EAAA,EAAI,QAAA,EAAU,GAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA,GAAI,CAAC,CAAA,IAAK,IAAI,CAAA;AAAA,MACnE;AACA,MAAA,CAAA,GAAI,KAAA;AACJ,MAAA,CAAA,GAAI,KAAA;AAAA,IACN;AAAA,EACF;AACA,EAAA,OAAO,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAA,EAAG;AACrB,IAAA,KAAA,CAAM,KAAK,EAAE,EAAA,EAAI,OAAA,EAAS,CAAA,EAAG,IAAI,CAAA,EAAG,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA,GAAI,CAAC,CAAA,IAAK,IAAI,CAAA;AACpE,IAAA,CAAA,EAAA;AACA,IAAA,CAAA,EAAA;AAAA,EACF;AACA,EAAA,OAAO,MAAM,OAAA,EAAQ;AACvB;AAQO,SAAS,WAAA,CACd,OAAA,EACA,OAAA,EACA,IAAA,GAA2B,EAAC,EACpB;AACR,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,CAAA;AAChC,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AAC5B,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,KAAA,CAAM,IAAI,CAAA;AAE5B,EAAA,IAAI,EAAE,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA,KAAM,EAAA,IAAM,GAAA,EAAI;AAClC,EAAA,IAAI,EAAE,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA,KAAM,EAAA,IAAM,GAAA,EAAI;AAClC,EAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,CAAA,EAAG,CAAC,CAAA;AAC5B,EAAA,IAAI,KAAA,CAAM,MAAM,CAAC,CAAA,KAAM,EAAE,EAAA,KAAO,OAAO,GAAG,OAAO,EAAA;AAEjD,EAAA,MAAM,QAA+D,EAAC;AACtE,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,OAAO,CAAA,GAAI,MAAM,MAAA,EAAQ;AACvB,IAAA,OAAO,IAAI,KAAA,CAAM,MAAA,IAAU,MAAM,CAAC,CAAA,EAAG,OAAO,OAAA,EAAS,CAAA,EAAA;AACrD,IAAA,IAAI,CAAA,IAAK,MAAM,MAAA,EAAQ;AACvB,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAI,OAAO,CAAA;AACzC,IAAA,MAAM,QAAkB,EAAC;AACzB,IAAA,IAAI,MAAA,GAAA,CAAU,KAAA,CAAM,SAAS,CAAA,EAAG,KAAK,CAAA,IAAK,CAAA;AAC1C,IAAA,IAAI,MAAA,GAAA,CAAU,KAAA,CAAM,SAAS,CAAA,EAAG,KAAK,CAAA,IAAK,CAAA;AAC1C,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,IAAI,MAAA,GAAS,SAAA;AACb,IAAA,IAAI,QAAA,GAAW,CAAA;AACf,IAAA,OAAO,MAAA,GAAS,MAAM,MAAA,EAAQ;AAC5B,MAAA,MAAM,CAAA,GAAI,MAAM,MAAM,CAAA;AACtB,MAAA,IAAI,CAAC,CAAA,EAAG;AACR,MAAA,IAAI,CAAA,CAAE,OAAO,OAAA,EAAS;AACpB,QAAA,QAAA,EAAA;AACA,QAAA,IAAI,QAAA,GAAW,UAAU,CAAA,EAAG;AAAA,MAC9B,CAAA,MAAO;AACL,QAAA,QAAA,GAAW,CAAA;AAAA,MACb;AACA,MAAA,IAAI,CAAA,CAAE,OAAO,OAAA,EAAS;AACpB,QAAA,KAAA,CAAM,IAAA,CAAK,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AACvB,QAAA,MAAA,EAAA;AACA,QAAA,MAAA,EAAA;AAAA,MACF,CAAA,MAAA,IAAW,CAAA,CAAE,EAAA,KAAO,QAAA,EAAU;AAC5B,QAAA,KAAA,CAAM,IAAA,CAAK,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AACvB,QAAA,MAAA,EAAA;AAAA,MACF,CAAA,MAAO;AACL,QAAA,KAAA,CAAM,IAAA,CAAK,CAAA,CAAA,EAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AACvB,QAAA,MAAA,EAAA;AAAA,MACF;AACA,MAAA,MAAA,EAAA;AAAA,IACF;AAEA,IAAA,OAAO,KAAA,CAAM,MAAA,GAAS,CAAA,IAAK,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,EAAG,UAAA,CAAW,GAAG,CAAA,IAAK,QAAA,GAAW,OAAA,EAAS;AACzF,MAAA,KAAA,CAAM,GAAA,EAAI;AACV,MAAA,MAAA,EAAA;AACA,MAAA,MAAA,EAAA;AACA,MAAA,QAAA,EAAA;AAAA,IACF;AACA,IAAA,IAAI,MAAA,KAAW,GAAG,MAAA,GAAS,CAAA;AAC3B,IAAA,IAAI,MAAA,KAAW,GAAG,MAAA,GAAS,CAAA;AAC3B,IAAA,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA;AACpC,IAAA,CAAA,GAAI,MAAA;AAAA,EACN;AACA,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAE/B,EAAA,IAAI,GAAA,GAAM,EAAA;AACV,EAAA,GAAA,IAAO,CAAA,IAAA,EAAO,IAAA,CAAK,QAAA,IAAY,GAAG;AAAA,CAAA;AAClC,EAAA,GAAA,IAAO,CAAA,IAAA,EAAO,IAAA,CAAK,MAAA,IAAU,GAAG;AAAA,CAAA;AAChC,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,IAAI,MAAA,GAAS,CAAA;AACb,IAAA,KAAA,MAAW,CAAA,IAAK,EAAE,KAAA,EAAO;AACvB,MAAA,IAAI,CAAA,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG;AACrB,QAAA,MAAA,EAAA;AACA,QAAA,MAAA,EAAA;AAAA,MACF,CAAA,MAAA,IAAW,CAAA,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG,MAAA,EAAA;AAAA,WAAA,IACrB,CAAA,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG,MAAA,EAAA;AAAA,IAC9B;AACA,IAAA,GAAA,IAAO,CAAA,IAAA,EAAO,EAAE,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,EAAA,EAAK,CAAA,CAAE,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA;AAAA,CAAA;AACvD,IAAA,GAAA,IAAO,CAAA,EAAG,CAAA,CAAE,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC;AAAA,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,GAAA;AACT;AClIO,SAAS,YAAY,OAAA,EAAyB;AACnD,EAAA,OAAO,UAAA,CAAW,QAAQ,CAAA,CAAE,MAAA,CAAY,KAAA,CAAA,OAAA,CAAQ,OAAO,CAAC,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA,CAAE,KAAA,CAAM,GAAG,EAAE,CAAA;AACrF;AASO,SAAS,mBAAmB,IAAA,EAAsC;AACvE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,IAAe,EAAA,CAAA,OAAA,EAAQ;AACzC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,IAAmB,KAAA,CAAA,IAAA,CAAK,MAAM,aAAa,CAAA;AACnE,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,IAAA,CAAK,WAAW,CAAA;AACzC,EAAA,MAAM,UAAA,GAAkB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,UAAA,EAAY,IAAI,CAAA;AACzD,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,YAAA,EAAmB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,aAAa,CAAA;AAAA,IACjD,UAAA,EAAiB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,MAAM,CAAA;AAAA,IACxC,YAAA,EAAmB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,WAAW,CAAA;AAAA,IAC/C,YAAA,EAAmB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,QAAQ,CAAA;AAAA,IAC5C,QAAA,EAAe,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,OAAO,CAAA;AAAA,IACvC,WAAA,EAAkB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,OAAA,EAAS,iBAAiB,CAAA;AAAA,IAC7D,WAAA,EAAkB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,SAAS,CAAA;AAAA,IAC5C,OAAA,EAAc,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,MAAA,EAAQ,gBAAgB,CAAA;AAAA,IACvD,UAAA;AAAA,IACA,aAAA,EAAoB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,WAAW,CAAA;AAAA,IAChD,eAAA,EAAsB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,UAAU,CAAA;AAAA,IACjD,YAAA,EAAmB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,YAAY,CAAA;AAAA,IAChD,WAAA,EAAkB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,WAAW,CAAA;AAAA,IAC9C,kBAAA,EAAyB,KAAA,CAAA,IAAA,CAAK,UAAA,EAAY,mBAAmB,CAAA;AAAA,IAC7D,mBAAA,EAA0B,KAAA,CAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,eAAe,WAAW,CAAA;AAAA,IAC3E,eAAA,EAAsB,KAAA,CAAA,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,eAAe,QAAQ,CAAA;AAAA,IACpE,WAAA,EAAa;AAAA,GACf;AACF;;;AC9EO,SAAS,0BAAA,CAA2B,IAAA,GAAoC,EAAC,EAAG;AACjF,EAAA,MAAM,QAAA,GAAW,KAAK,0BAAA,IAA8B,GAAA;AAEpD,EAAA,SAAS,UAAU,KAAA,EAAwB;AACzC,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,KAAA;AACtC,IAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,EAAA;AAClD,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG,OAAO,MAAM,GAAA,CAAI,SAAS,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAC/D,MAAA,IAAI,UAAW,KAAA,EAAmC;AAChD,QAAA,MAAM,IAAK,KAAA,CAAkC,IAAA;AAC7C,QAAA,OAAO,OAAO,MAAM,QAAA,GAAW,CAAA,GAAI,KAAK,SAAA,CAAU,KAAA,EAAO,MAAM,CAAC,CAAA;AAAA,MAClE;AACA,MAAA,IAAI;AACF,QAAA,OAAO,IAAA,CAAK,SAAA,CAAU,KAAA,EAAO,IAAA,EAAM,CAAC,CAAA;AAAA,MACtC,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,OAAO,KAAK,CAAA;AAAA,MACrB;AAAA,IACF;AACA,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AAEA,EAAA,SAAS,UAAA,CAAW,MAAc,eAAA,EAA8D;AAC9F,IAAA,IAAI,mBAAmB,CAAA,EAAG;AACxB,MAAA,OAAO,EAAE,IAAA,EAAM,4CAAA,EAA8C,SAAA,EAAW,CAAA,EAAE;AAAA,IAC5E;AACA,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,UAAA,CAAW,IAAA,EAAM,MAAM,CAAA;AAChD,IAAA,IAAI,aAAa,eAAA,EAAiB;AAChC,MAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,eAAA,GAAkB,SAAA,EAAU;AAAA,IACxD;AACA,IAAA,MAAM,MAAA,GAAS;AAAA,iBAAA,EAAiB,YAAY,eAAe,CAAA;AAAA,CAAA;AAC3D,IAAA,MAAM,WAAA,GAAc,MAAA,CAAO,UAAA,CAAW,MAAA,EAAQ,MAAM,CAAA;AACpD,IAAA,MAAM,YAAY,eAAA,GAAkB,WAAA;AACpC,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA,OAAO,EAAE,IAAA,EAAM,4CAAA,EAA8C,SAAA,EAAW,CAAA,EAAE;AAAA,IAC5E;AACA,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,CAAC,CAAA;AACrC,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA;AAChC,IAAsB,MAAA,CAAO,UAAA,CAAW,KAAA,EAAO,MAAM;AACrD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAS,IAAI,CAAA;AAC5C,IAAA,OAAO,EAAE,IAAA,EAAM,CAAA,EAAG,KAAK,CAAA,EAAG,MAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,SAAA,EAAW,CAAA,EAAE;AAAA,EAC5D;AAEA,EAAA,OAAO,EAAE,SAAA,EAAW,UAAA,EAAY,QAAA,EAAS;AAC3C","file":"index.js","sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { randomBytes } from 'node:crypto';\n\nexport interface AtomicWriteOptions {\n mode?: number;\n encoding?: BufferEncoding;\n}\n\nexport async function atomicWrite(\n targetPath: string,\n content: string | Uint8Array,\n opts: AtomicWriteOptions = {},\n): Promise<void> {\n const dir = path.dirname(targetPath);\n await fs.mkdir(dir, { recursive: true });\n const tmp = path.join(dir, `.${path.basename(targetPath)}.${randomBytes(6).toString('hex')}.tmp`);\n\n // Write content to tmp first; 'wx' ensures exclusive creation (fails if\n // tmp already exists — extremely unlikely with 6-byte random suffix).\n try {\n if (typeof content === 'string') {\n await fs.writeFile(tmp, content, { flag: 'wx', encoding: opts.encoding ?? 'utf8' });\n } else {\n await fs.writeFile(tmp, content, { flag: 'wx' });\n }\n try {\n const fh = await fs.open(tmp, 'r+');\n await fh.sync();\n await fh.close();\n } catch {\n // fsync best-effort\n }\n // Now safely read mode from target (if it exists) and apply to tmp before rename\n let mode: number | undefined;\n try {\n const stat = await fs.stat(targetPath);\n mode = stat.mode & 0o777;\n } catch {\n // target may not exist yet; mode stays undefined\n }\n if (mode !== undefined) {\n await fs.chmod(tmp, mode);\n }\n await fs.rename(tmp, targetPath);\n } catch (err) {\n try {\n await fs.unlink(tmp);\n } catch {\n // ignore cleanup error\n }\n throw err;\n }\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await fs.mkdir(dir, { recursive: true });\n}\n","export interface SafeParseResult<T> {\n ok: boolean;\n value?: T;\n error?: string;\n}\n\nexport function safeParse<T = unknown>(input: string, maxBytes = 5_000_000): SafeParseResult<T> {\n if (input.length > maxBytes) {\n return { ok: false, error: `Input exceeds limit (${maxBytes} bytes)` };\n }\n try {\n return { ok: true, value: JSON.parse(input) as T };\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nexport function safeStringify(value: unknown, pretty = false): string {\n const seen = new WeakSet();\n const replacer = (_k: string, v: unknown): unknown => {\n if (typeof v === 'bigint') return v.toString();\n if (v instanceof Error) {\n return { name: v.name, message: v.message, stack: v.stack };\n }\n if (typeof v === 'object' && v !== null) {\n if (seen.has(v as object)) return '[Circular]';\n seen.add(v as object);\n }\n return v;\n };\n try {\n return JSON.stringify(value, replacer, pretty ? 2 : undefined) ?? 'null';\n } catch (err) {\n return JSON.stringify({\n __serialization_error: err instanceof Error ? err.message : String(err),\n });\n }\n}\n\n/** Attempt to parse JSON5-style input and return a valid JSON string.\n * Handles trailing commas, single-line comments, and unquoted keys\n * that are common in provider output.\n */\nexport function sanitizeJsonString(s: string): string {\n let out = s.trim();\n\n // Stage 1: strip single-line comments (// to end of line) that appear\n // outside of string values. This is a heuristic: comments inside strings\n // are preserved because we only strip // when preceded by a char that\n // strongly suggests we're not in a string (quote count modulo 2 is even).\n out = stripSingleLineComments(out);\n\n // Stage 2: strip trailing commas before } or ]\n out = out.replace(/,(\\s*[}\\]])/g, '$1');\n\n // Stage 3: attempt full parse; if it fails, return the stripped version\n // so the caller can decide what to do. Return undefined on parse failure\n // so callers can distinguish \"already valid JSON\" from \"unrecoverable\".\n try {\n JSON.parse(out);\n return out;\n } catch {\n return out; // stripped but still not valid JSON; caller handles it\n }\n}\n\nfunction stripSingleLineComments(s: string): string {\n let inString = false;\n const chars: string[] = [];\n let i = 0;\n while (i < s.length) {\n const c = s[i]!;\n if (c === '\"' && (i === 0 || s[i - 1] !== '\\\\')) {\n inString = !inString;\n chars.push(c);\n } else if (c === '/' && s[i + 1] === '/' && !inString) {\n // skip to end of line\n while (i < s.length && s[i] !== '\\n') i++;\n } else {\n chars.push(c);\n }\n i++;\n }\n return chars.join('');\n}\n","export type NewlineStyle = 'lf' | 'crlf' | 'cr';\n\nexport function detectNewlineStyle(text: string): NewlineStyle {\n let lf = 0;\n let crlf = 0;\n let cr = 0;\n for (let i = 0; i < text.length; i++) {\n const c = text.charCodeAt(i);\n if (c === 0x0d) {\n if (text.charCodeAt(i + 1) === 0x0a) {\n crlf++;\n i++;\n } else {\n cr++;\n }\n } else if (c === 0x0a) {\n lf++;\n }\n }\n if (crlf > lf && crlf > cr) return 'crlf';\n if (cr > lf && cr > crlf) return 'cr';\n return 'lf';\n}\n\nexport function toStyle(text: string, style: NewlineStyle): string {\n const normalized = text.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n if (style === 'lf') return normalized;\n if (style === 'crlf') return normalized.replace(/\\n/g, '\\r\\n');\n return normalized.replace(/\\n/g, '\\r');\n}\n\nexport function normalizeToLf(text: string): string {\n return text.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n}\n","const isColorTty = (): boolean => {\n if (process.env.NO_COLOR) return false;\n if (process.env.FORCE_COLOR) return true;\n return Boolean(process.stdout?.isTTY);\n};\n\nconst COLOR = isColorTty();\n\nconst wrap = (open: string, close: string) =>\n (s: string): string =>\n COLOR ? `\\x1b[${open}m${s}\\x1b[${close}m` : s;\n\nexport const color = {\n reset: wrap('0', '0'),\n bold: wrap('1', '22'),\n dim: wrap('2', '22'),\n italic: wrap('3', '23'),\n underline: wrap('4', '24'),\n red: wrap('31', '39'),\n green: wrap('32', '39'),\n yellow: wrap('33', '39'),\n blue: wrap('34', '39'),\n magenta: wrap('35', '39'),\n cyan: wrap('36', '39'),\n gray: wrap('90', '39'),\n amber: wrap('38;5;214', '39'),\n pink: wrap('38;5;205', '39'),\n bgRed: wrap('41', '49'),\n bgGreen: wrap('42', '49'),\n};\n\nexport function stripAnsi(s: string): string {\n return s.replace(\n // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape regex\n /\\x1b\\[[0-9;]*[A-Za-z]/g,\n '',\n );\n}\n","/**\n * Minimal glob matcher for trust patterns.\n * Supports: *, **, ?, character classes [abc], [a-z], negation [!...] or [^...].\n *\n * Both `[!...]` (shell glob convention) and `[^...]` (regex convention) are\n * accepted because users coming from either world will reach for what they\n * know; rejecting one silently fails open in a security-sensitive context.\n */\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.+^${}()|\\\\/]/g, '\\\\$&');\n}\n\nexport function compileGlob(pattern: string): RegExp {\n let i = 0;\n let re = '^';\n while (i < pattern.length) {\n const c = pattern[i];\n if (c === '*') {\n if (pattern[i + 1] === '*') {\n // ** matches any number of chars including /\n re += '.*';\n i += 2;\n // Skip trailing slash so '**/x' matches 'x'\n if (pattern[i] === '/') i++;\n } else {\n // single * matches any chars except /\n re += '[^/]*';\n i++;\n }\n } else if (c === '?') {\n re += '[^/]';\n i++;\n } else if (c === '[') {\n let cls = '[';\n i++;\n if (pattern[i] === '!' || pattern[i] === '^') {\n cls += '^';\n i++;\n }\n while (i < pattern.length && pattern[i] !== ']') {\n const ch = pattern[i] ?? '';\n // Inside a regex class, only `]`, `\\`, and `^`/`-` at boundaries need\n // escaping. We've already consumed the leading `^`; the rest are\n // literal. Escape `\\` defensively and pass the rest through verbatim\n // so ranges like `a-z` continue to work.\n if (ch === '\\\\') {\n cls += '\\\\\\\\';\n } else if (ch === ']' || ch === '^') {\n cls += `\\\\${ch}`;\n } else {\n cls += ch;\n }\n i++;\n }\n cls += ']';\n re += cls;\n i++; // skip closing ]\n } else {\n re += escapeRegex(c ?? '');\n i++;\n }\n }\n re += '$';\n return new RegExp(re);\n}\n\nexport function matchGlob(pattern: string, input: string): boolean {\n return compileGlob(pattern).test(input);\n}\n\nexport function matchAny(patterns: string[], input: string): boolean {\n return patterns.some((p) => matchGlob(p, input));\n}\n","/**\n * Myers diff with unified-format output. No external dependencies.\n * Operates on arrays of lines (newline-terminated or stripped).\n */\n\ninterface Edit {\n op: 'equal' | 'insert' | 'delete';\n a: number;\n b: number;\n line: string;\n}\n\nfunction myersDiff(a: string[], b: string[]): Edit[] {\n const N = a.length;\n const M = b.length;\n const max = N + M;\n if (max === 0) return [];\n\n const v = new Map<number, number>();\n v.set(1, 0);\n const trace: Map<number, number>[] = [];\n\n for (let d = 0; d <= max; d++) {\n const snapshot = new Map(v);\n trace.push(snapshot);\n for (let k = -d; k <= d; k += 2) {\n const left = v.get(k - 1) ?? -1;\n const right = v.get(k + 1) ?? -1;\n let x: number;\n if (k === -d || (k !== d && left < right)) {\n x = right;\n } else {\n x = left + 1;\n }\n let y = x - k;\n while (x < N && y < M && a[x] === b[y]) {\n x++;\n y++;\n }\n v.set(k, x);\n if (x >= N && y >= M) {\n return backtrack(trace, a, b, N, M, d);\n }\n }\n }\n return [];\n}\n\nfunction backtrack(\n trace: Map<number, number>[],\n a: string[],\n b: string[],\n N: number,\n M: number,\n finalD: number,\n): Edit[] {\n const edits: Edit[] = [];\n let x = N;\n let y = M;\n for (let d = finalD; d > 0; d--) {\n const v = trace[d];\n if (!v) break;\n const k = x - y;\n const left = v.get(k - 1) ?? -1;\n const right = v.get(k + 1) ?? -1;\n let prevK: number;\n if (k === -d || (k !== d && left < right)) {\n prevK = k + 1;\n } else {\n prevK = k - 1;\n }\n const prevX = v.get(prevK) ?? 0;\n const prevY = prevX - prevK;\n while (x > prevX && y > prevY) {\n edits.push({ op: 'equal', a: x - 1, b: y - 1, line: a[x - 1] ?? '' });\n x--;\n y--;\n }\n if (d > 0) {\n if (x === prevX) {\n edits.push({ op: 'insert', a: x, b: y - 1, line: b[y - 1] ?? '' });\n } else {\n edits.push({ op: 'delete', a: x - 1, b: y, line: a[x - 1] ?? '' });\n }\n x = prevX;\n y = prevY;\n }\n }\n while (x > 0 && y > 0) {\n edits.push({ op: 'equal', a: x - 1, b: y - 1, line: a[x - 1] ?? '' });\n x--;\n y--;\n }\n return edits.reverse();\n}\n\nexport interface UnifiedDiffOptions {\n context?: number;\n fromFile?: string;\n toFile?: string;\n}\n\nexport function unifiedDiff(\n oldText: string,\n newText: string,\n opts: UnifiedDiffOptions = {},\n): string {\n const context = opts.context ?? 3;\n const a = oldText.split('\\n');\n const b = newText.split('\\n');\n // Handle trailing newline: split adds an empty string we don't want to diff\n if (a[a.length - 1] === '') a.pop();\n if (b[b.length - 1] === '') b.pop();\n const edits = myersDiff(a, b);\n if (edits.every((e) => e.op === 'equal')) return '';\n\n const hunks: { aStart: number; bStart: number; lines: string[] }[] = [];\n let i = 0;\n while (i < edits.length) {\n while (i < edits.length && edits[i]?.op === 'equal') i++;\n if (i >= edits.length) break;\n const hunkStart = Math.max(0, i - context);\n const lines: string[] = [];\n let aStart = (edits[hunkStart]?.a ?? 0) + 1;\n let bStart = (edits[hunkStart]?.b ?? 0) + 1;\n let aCount = 0;\n let bCount = 0;\n let cursor = hunkStart;\n let trailing = 0;\n while (cursor < edits.length) {\n const e = edits[cursor];\n if (!e) break;\n if (e.op === 'equal') {\n trailing++;\n if (trailing > context * 2) break;\n } else {\n trailing = 0;\n }\n if (e.op === 'equal') {\n lines.push(` ${e.line}`);\n aCount++;\n bCount++;\n } else if (e.op === 'delete') {\n lines.push(`-${e.line}`);\n aCount++;\n } else {\n lines.push(`+${e.line}`);\n bCount++;\n }\n cursor++;\n }\n // Trim trailing context lines beyond `context`\n while (lines.length > 0 && lines[lines.length - 1]?.startsWith(' ') && trailing > context) {\n lines.pop();\n aCount--;\n bCount--;\n trailing--;\n }\n if (aCount === 0) aStart = 0;\n if (bCount === 0) bStart = 0;\n hunks.push({ aStart, bStart, lines });\n i = cursor;\n }\n if (hunks.length === 0) return '';\n\n let out = '';\n out += `--- ${opts.fromFile ?? 'a'}\\n`;\n out += `+++ ${opts.toFile ?? 'b'}\\n`;\n for (const h of hunks) {\n let aCount = 0;\n let bCount = 0;\n for (const l of h.lines) {\n if (l.startsWith(' ')) {\n aCount++;\n bCount++;\n } else if (l.startsWith('-')) aCount++;\n else if (l.startsWith('+')) bCount++;\n }\n out += `@@ -${h.aStart},${aCount} +${h.bStart},${bCount} @@\\n`;\n out += `${h.lines.join('\\n')}\\n`;\n }\n return out;\n}\n","import * as path from 'node:path';\nimport * as os from 'node:os';\nimport { createHash } from 'node:crypto';\n\n/**\n * Path layout. All developer-level state lives in ~/.wrongstack/.\n * Per-project state is keyed by sha256(absoluteProjectRoot).slice(0,12)\n * under ~/.wrongstack/projects/<hash>/.\n *\n * The ONLY thing inside the project tree is the optional\n * .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).\n */\n\nexport interface WstackPaths {\n /** ~/.wrongstack — global root. */\n globalRoot: string;\n /** ~/.wrongstack/config.json */\n globalConfig: string;\n /** ~/.wrongstack/.key — 32 random bytes, mode 0600, AES-GCM key for the secret vault. */\n secretsKey: string;\n /** ~/.wrongstack/memory.md — user-global memory. */\n globalMemory: string;\n /** ~/.wrongstack/skills — user-global skills. */\n globalSkills: string;\n /** ~/.wrongstack/cache — fetched data (models.dev, etc.). */\n cacheDir: string;\n /** ~/.wrongstack/cache/models.dev.json */\n modelsCache: string;\n /** ~/.wrongstack/history — REPL line history. */\n historyFile: string;\n /** ~/.wrongstack/logs/wrongstack.log */\n logFile: string;\n /** ~/.wrongstack/projects/<hash> */\n projectDir: string;\n /** ~/.wrongstack/projects/<hash>/memory.md */\n projectMemory: string;\n /** ~/.wrongstack/projects/<hash>/sessions */\n projectSessions: string;\n /** ~/.wrongstack/projects/<hash>/trust.json */\n projectTrust: string;\n /** ~/.wrongstack/projects/<hash>/meta.json */\n projectMeta: string;\n /** ~/.wrongstack/projects/<hash>/config.local.json — optional override */\n projectLocalConfig: string;\n /** <project>/.wrongstack/AGENTS.md — committed project memory. */\n inProjectAgentsFile: string;\n /** <project>/.wrongstack/skills — committed project skills. */\n inProjectSkills: string;\n /** Stable hash for the project root. */\n projectHash: string;\n}\n\nexport function projectHash(absRoot: string): string {\n return createHash('sha256').update(path.resolve(absRoot)).digest('hex').slice(0, 12);\n}\n\nexport interface WstackPathOptions {\n userHome?: string;\n projectRoot: string;\n /** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */\n globalRoot?: string;\n}\n\nexport function resolveWstackPaths(opts: WstackPathOptions): WstackPaths {\n const home = opts.userHome ?? os.homedir();\n const globalRoot = opts.globalRoot ?? path.join(home, '.wrongstack');\n const hash = projectHash(opts.projectRoot);\n const projectDir = path.join(globalRoot, 'projects', hash);\n return {\n globalRoot,\n globalConfig: path.join(globalRoot, 'config.json'),\n secretsKey: path.join(globalRoot, '.key'),\n globalMemory: path.join(globalRoot, 'memory.md'),\n globalSkills: path.join(globalRoot, 'skills'),\n cacheDir: path.join(globalRoot, 'cache'),\n modelsCache: path.join(globalRoot, 'cache', 'models.dev.json'),\n historyFile: path.join(globalRoot, 'history'),\n logFile: path.join(globalRoot, 'logs', 'wrongstack.log'),\n projectDir,\n projectMemory: path.join(projectDir, 'memory.md'),\n projectSessions: path.join(projectDir, 'sessions'),\n projectTrust: path.join(projectDir, 'trust.json'),\n projectMeta: path.join(projectDir, 'meta.json'),\n projectLocalConfig: path.join(projectDir, 'config.local.json'),\n inProjectAgentsFile: path.join(opts.projectRoot, '.wrongstack', 'AGENTS.md'),\n inProjectSkills: path.join(opts.projectRoot, '.wrongstack', 'skills'),\n projectHash: hash,\n };\n}\n","/**\n * Tool output serialization utilities.\n * Extracted from Agent.executeTools to allow reuse and consistent output handling.\n */\n\nexport interface ToolOutputSerializerOptions {\n perIterationOutputCapBytes?: number;\n estimator?: (text: string) => number;\n}\n\nexport function createToolOutputSerializer(opts: ToolOutputSerializerOptions = {}) {\n const capBytes = opts.perIterationOutputCapBytes ?? 100_000;\n\n function serialize(value: unknown): string {\n if (typeof value === 'string') return value;\n if (value === null || value === undefined) return '';\n if (typeof value === 'object') {\n if (Array.isArray(value)) return value.map(serialize).join('\\n');\n if ('text' in (value as Record<string, unknown>)) {\n const t = (value as Record<string, unknown>).text;\n return typeof t === 'string' ? t : JSON.stringify(value, null, 2);\n }\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n }\n return String(value);\n }\n\n function enforceCap(text: string, remainingBudget: number): { text: string; newBudget: number } {\n if (remainingBudget <= 0) {\n return { text: '[truncated: iteration output cap exceeded]', newBudget: 0 };\n }\n const textBytes = Buffer.byteLength(text, 'utf8');\n if (textBytes <= remainingBudget) {\n return { text, newBudget: remainingBudget - textBytes };\n }\n const marker = `\\n…[truncated ${textBytes - remainingBudget} bytes]…\\n`;\n const markerBytes = Buffer.byteLength(marker, 'utf8');\n const available = remainingBudget - markerBytes;\n if (available <= 0) {\n return { text: '[truncated: iteration output cap exceeded]', newBudget: 0 };\n }\n const half = Math.floor(available / 2);\n const first = text.slice(0, half);\n const textBytesHalf = Buffer.byteLength(first, 'utf8');\n const second = text.slice(text.length - half);\n return { text: `${first}${marker}${second}`, newBudget: 0 };\n }\n\n return { serialize, enforceCap, capBytes };\n}"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path layout. All developer-level state lives in ~/.wrongstack/.
|
|
3
|
+
* Per-project state is keyed by sha256(absoluteProjectRoot).slice(0,12)
|
|
4
|
+
* under ~/.wrongstack/projects/<hash>/.
|
|
5
|
+
*
|
|
6
|
+
* The ONLY thing inside the project tree is the optional
|
|
7
|
+
* .wrongstack/AGENTS.md (committed) and .wrongstack/skills/ (committed).
|
|
8
|
+
*/
|
|
9
|
+
interface WstackPaths {
|
|
10
|
+
/** ~/.wrongstack — global root. */
|
|
11
|
+
globalRoot: string;
|
|
12
|
+
/** ~/.wrongstack/config.json */
|
|
13
|
+
globalConfig: string;
|
|
14
|
+
/** ~/.wrongstack/.key — 32 random bytes, mode 0600, AES-GCM key for the secret vault. */
|
|
15
|
+
secretsKey: string;
|
|
16
|
+
/** ~/.wrongstack/memory.md — user-global memory. */
|
|
17
|
+
globalMemory: string;
|
|
18
|
+
/** ~/.wrongstack/skills — user-global skills. */
|
|
19
|
+
globalSkills: string;
|
|
20
|
+
/** ~/.wrongstack/cache — fetched data (models.dev, etc.). */
|
|
21
|
+
cacheDir: string;
|
|
22
|
+
/** ~/.wrongstack/cache/models.dev.json */
|
|
23
|
+
modelsCache: string;
|
|
24
|
+
/** ~/.wrongstack/history — REPL line history. */
|
|
25
|
+
historyFile: string;
|
|
26
|
+
/** ~/.wrongstack/logs/wrongstack.log */
|
|
27
|
+
logFile: string;
|
|
28
|
+
/** ~/.wrongstack/projects/<hash> */
|
|
29
|
+
projectDir: string;
|
|
30
|
+
/** ~/.wrongstack/projects/<hash>/memory.md */
|
|
31
|
+
projectMemory: string;
|
|
32
|
+
/** ~/.wrongstack/projects/<hash>/sessions */
|
|
33
|
+
projectSessions: string;
|
|
34
|
+
/** ~/.wrongstack/projects/<hash>/trust.json */
|
|
35
|
+
projectTrust: string;
|
|
36
|
+
/** ~/.wrongstack/projects/<hash>/meta.json */
|
|
37
|
+
projectMeta: string;
|
|
38
|
+
/** ~/.wrongstack/projects/<hash>/config.local.json — optional override */
|
|
39
|
+
projectLocalConfig: string;
|
|
40
|
+
/** <project>/.wrongstack/AGENTS.md — committed project memory. */
|
|
41
|
+
inProjectAgentsFile: string;
|
|
42
|
+
/** <project>/.wrongstack/skills — committed project skills. */
|
|
43
|
+
inProjectSkills: string;
|
|
44
|
+
/** Stable hash for the project root. */
|
|
45
|
+
projectHash: string;
|
|
46
|
+
}
|
|
47
|
+
declare function projectHash(absRoot: string): string;
|
|
48
|
+
interface WstackPathOptions {
|
|
49
|
+
userHome?: string;
|
|
50
|
+
projectRoot: string;
|
|
51
|
+
/** Override the global root (e.g. for tests). Default: `${userHome}/.wrongstack`. */
|
|
52
|
+
globalRoot?: string;
|
|
53
|
+
}
|
|
54
|
+
declare function resolveWstackPaths(opts: WstackPathOptions): WstackPaths;
|
|
55
|
+
|
|
56
|
+
export { type WstackPathOptions as W, type WstackPaths as a, projectHash as p, resolveWstackPaths as r };
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wrongstack/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./kernel": {
|
|
13
|
+
"types": "./dist/kernel/index.d.ts",
|
|
14
|
+
"import": "./dist/kernel/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./types": {
|
|
17
|
+
"types": "./dist/types/index.d.ts",
|
|
18
|
+
"import": "./dist/types/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./defaults": {
|
|
21
|
+
"types": "./dist/defaults/index.d.ts",
|
|
22
|
+
"import": "./dist/defaults/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./utils": {
|
|
25
|
+
"types": "./dist/utils/index.d.ts",
|
|
26
|
+
"import": "./dist/utils/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./package.json": "./package.json",
|
|
29
|
+
"./skills/*": "./skills/*"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"skills"
|
|
34
|
+
],
|
|
35
|
+
"wrongstackApiVersion": "0.0.1",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.10.0",
|
|
38
|
+
"tsup": "^8.3.5",
|
|
39
|
+
"typescript": "^5.7.2"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"typecheck": "tsc --noEmit",
|
|
44
|
+
"clean": "rm -rf dist"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-flow
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when proposing, creating, or reviewing git commits, branches,
|
|
5
|
+
and PRs. Covers commit message style, branch hygiene, and safe history operations.
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Git workflow
|
|
10
|
+
|
|
11
|
+
## Commits
|
|
12
|
+
|
|
13
|
+
- Subject line: imperative mood, ≤ 72 chars, no trailing period.
|
|
14
|
+
- Body: explain *why*, not *what* (the diff shows what).
|
|
15
|
+
- Group by intent, not by file.
|
|
16
|
+
|
|
17
|
+
## Branches
|
|
18
|
+
|
|
19
|
+
- One topic per branch. Rebase before merging when safe.
|
|
20
|
+
- Delete branches after merge.
|
|
21
|
+
|
|
22
|
+
## Safety rules
|
|
23
|
+
|
|
24
|
+
- Never `git push --force` to shared branches (use `--force-with-lease` for your own).
|
|
25
|
+
- Never `git reset --hard` without inspecting `git status` first.
|
|
26
|
+
- Don't amend already-pushed commits to shared branches.
|
|
27
|
+
|
|
28
|
+
## PRs
|
|
29
|
+
|
|
30
|
+
- Subject summarizes the change, body links the issue and lists tradeoffs.
|
|
31
|
+
- Keep PRs small: one reviewable change per PR.
|
|
32
|
+
- Self-review the diff before requesting review.
|