clixad 0.0.1-beta.42 → 0.0.1-beta.43
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.
|
@@ -2319,6 +2319,94 @@ function diffStat(lines) {
|
|
|
2319
2319
|
}
|
|
2320
2320
|
return { added, removed };
|
|
2321
2321
|
}
|
|
2322
|
+
var MAX_VIEW_ROWS = 2e3;
|
|
2323
|
+
function diffView(path, before, after, opts = {}) {
|
|
2324
|
+
const context = opts.context ?? 3;
|
|
2325
|
+
if (opts.created) {
|
|
2326
|
+
const lines2 = splitLines(after);
|
|
2327
|
+
const rows2 = lines2.slice(0, MAX_VIEW_ROWS).map((text, i) => ({ kind: "add", line: i + 1, text }));
|
|
2328
|
+
if (lines2.length > MAX_VIEW_ROWS) rows2.push({ kind: "gap", count: lines2.length - MAX_VIEW_ROWS });
|
|
2329
|
+
return { kind: "diff", path, created: true, added: after === "" ? 0 : lines2.length, removed: 0, rows: rows2 };
|
|
2330
|
+
}
|
|
2331
|
+
const lines = diffLines(splitLines(before), splitLines(after));
|
|
2332
|
+
const { added, removed } = diffStat(lines);
|
|
2333
|
+
const keep = new Array(lines.length).fill(false);
|
|
2334
|
+
lines.forEach((l, i) => {
|
|
2335
|
+
if (l.kind === "ctx") return;
|
|
2336
|
+
for (let k = Math.max(0, i - context); k <= Math.min(lines.length - 1, i + context); k++) keep[k] = true;
|
|
2337
|
+
});
|
|
2338
|
+
const rows = [];
|
|
2339
|
+
let skipped = 0;
|
|
2340
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2341
|
+
if (!keep[i]) {
|
|
2342
|
+
skipped++;
|
|
2343
|
+
continue;
|
|
2344
|
+
}
|
|
2345
|
+
if (skipped > 0 && rows.length > 0) rows.push({ kind: "gap", count: skipped });
|
|
2346
|
+
skipped = 0;
|
|
2347
|
+
if (rows.length >= MAX_VIEW_ROWS) {
|
|
2348
|
+
rows.push({ kind: "gap", count: lines.length - i });
|
|
2349
|
+
break;
|
|
2350
|
+
}
|
|
2351
|
+
rows.push({ ...lines[i] });
|
|
2352
|
+
}
|
|
2353
|
+
return { kind: "diff", path, created: false, added, removed, rows };
|
|
2354
|
+
}
|
|
2355
|
+
function diffTint(env = process.env) {
|
|
2356
|
+
if (env.NO_COLOR) return "none";
|
|
2357
|
+
if (env.COLORTERM === "truecolor" || env.COLORTERM === "24bit") return "truecolor";
|
|
2358
|
+
if (/256/.test(env.TERM ?? "")) return "256";
|
|
2359
|
+
if (env.TERM === "dumb") return "none";
|
|
2360
|
+
return "basic";
|
|
2361
|
+
}
|
|
2362
|
+
var TINTS = {
|
|
2363
|
+
truecolor: {
|
|
2364
|
+
add: "\x1B[48;2;28;62;38m",
|
|
2365
|
+
del: "\x1B[48;2;78;32;36m",
|
|
2366
|
+
addSign: "\x1B[38;2;126;231;135m",
|
|
2367
|
+
delSign: "\x1B[38;2;255;123;114m",
|
|
2368
|
+
off: R
|
|
2369
|
+
},
|
|
2370
|
+
"256": { add: "\x1B[48;5;22m", del: "\x1B[48;5;52m", addSign: "\x1B[92m", delSign: "\x1B[91m", off: R },
|
|
2371
|
+
basic: { add: GREEN, del: RED, addSign: "", delSign: "", off: R },
|
|
2372
|
+
none: { add: "", del: "", addSign: "", delSign: "", off: "" }
|
|
2373
|
+
};
|
|
2374
|
+
function renderDiffRows(view, width, opts) {
|
|
2375
|
+
const tint = TINTS[opts.tint ?? "basic"];
|
|
2376
|
+
const max = opts.maxRows ?? Number.POSITIVE_INFINITY;
|
|
2377
|
+
const numbers = view.rows.filter((r) => r.kind !== "gap");
|
|
2378
|
+
const gutter = Math.max(3, ...numbers.map((r) => String(r.line).length));
|
|
2379
|
+
const fit = (text) => {
|
|
2380
|
+
const cut2 = opts.measure(text) > width ? opts.cut(text, width) : text;
|
|
2381
|
+
return cut2 + " ".repeat(Math.max(0, width - opts.measure(cut2)));
|
|
2382
|
+
};
|
|
2383
|
+
const rows = [];
|
|
2384
|
+
let more = 0;
|
|
2385
|
+
for (const row of view.rows) {
|
|
2386
|
+
if (rows.length >= max) {
|
|
2387
|
+
if (row.kind !== "gap") more++;
|
|
2388
|
+
continue;
|
|
2389
|
+
}
|
|
2390
|
+
if (row.kind === "gap") {
|
|
2391
|
+
const dim = tint === TINTS.none ? "" : DIM;
|
|
2392
|
+
rows.push(`${dim}${opts.cut(`${" ".repeat(gutter)} \u22EF ${row.count} unchanged line${row.count === 1 ? "" : "s"}`, width)}${tint.off}`);
|
|
2393
|
+
continue;
|
|
2394
|
+
}
|
|
2395
|
+
const text = row.text.replace(/\t/g, " ");
|
|
2396
|
+
const no = String(row.line).padStart(gutter);
|
|
2397
|
+
if (row.kind === "ctx") {
|
|
2398
|
+
rows.push(`${tint === TINTS.none ? "" : DIM}${opts.cut(`${no} ${text}`, width)}${tint.off}`);
|
|
2399
|
+
continue;
|
|
2400
|
+
}
|
|
2401
|
+
const sign = row.kind === "add" ? "+" : "-";
|
|
2402
|
+
const bg2 = row.kind === "add" ? tint.add : tint.del;
|
|
2403
|
+
const signColor = row.kind === "add" ? tint.addSign : tint.delSign;
|
|
2404
|
+
const body = fit(`${no} ${sign} ${text}`);
|
|
2405
|
+
const at = gutter + 1;
|
|
2406
|
+
rows.push(`${bg2}${body.slice(0, at)}${signColor}${sign}${signColor ? "\x1B[39m" : ""}${body.slice(at + 1)}${tint.off}`);
|
|
2407
|
+
}
|
|
2408
|
+
return { rows, more };
|
|
2409
|
+
}
|
|
2322
2410
|
function renderDiff(oldText, newText, opts = {}) {
|
|
2323
2411
|
const context = opts.context ?? 3;
|
|
2324
2412
|
const maxLines = opts.maxLines ?? 40;
|
|
@@ -3618,13 +3706,16 @@ ${body2}` + (pdf.text.length > MAX_FILE_BYTES ? "\n\u2026 [truncated]" : "");
|
|
|
3618
3706
|
const abs = safeResolve(ctx.root, requireString(args.path, "write_file", "path"));
|
|
3619
3707
|
const content = requireString(args.content, "write_file", "content");
|
|
3620
3708
|
const name = rel(ctx.root, abs);
|
|
3621
|
-
const
|
|
3709
|
+
const existed = existsSync2(abs);
|
|
3710
|
+
const before = existed ? fsCall(`cannot write ${name}`, () => readFileSync3(abs, "utf8")) : "";
|
|
3622
3711
|
const preview = renderDiff(before, content) || "(no change)";
|
|
3712
|
+
const view = diffView(name, before, content, { created: !existed });
|
|
3623
3713
|
await gate(ctx, {
|
|
3624
3714
|
tool: "write_file",
|
|
3625
3715
|
signature: `write:${name}`,
|
|
3626
3716
|
summary: `${before ? "overwrite" : "create"} ${name}`,
|
|
3627
3717
|
preview,
|
|
3718
|
+
view,
|
|
3628
3719
|
path: name,
|
|
3629
3720
|
root: ctx.root
|
|
3630
3721
|
});
|
|
@@ -3632,6 +3723,7 @@ ${body2}` + (pdf.text.length > MAX_FILE_BYTES ? "\n\u2026 [truncated]" : "");
|
|
|
3632
3723
|
mkdirSync2(dirname2(abs), { recursive: true });
|
|
3633
3724
|
writeFileSync2(abs, content, "utf8");
|
|
3634
3725
|
});
|
|
3726
|
+
ctx.present?.(view);
|
|
3635
3727
|
return `wrote ${content.length} bytes to ${name}`;
|
|
3636
3728
|
},
|
|
3637
3729
|
/**
|
|
@@ -3661,15 +3753,18 @@ ${body2}` + (pdf.text.length > MAX_FILE_BYTES ? "\n\u2026 [truncated]" : "");
|
|
|
3661
3753
|
}
|
|
3662
3754
|
const after = before.split(oldString).join(newString);
|
|
3663
3755
|
const preview = renderDiff(before, after) || "(no change)";
|
|
3756
|
+
const view = diffView(name, before, after);
|
|
3664
3757
|
await gate(ctx, {
|
|
3665
3758
|
tool: "edit_file",
|
|
3666
3759
|
signature: `write:${name}`,
|
|
3667
3760
|
summary: `edit ${name}`,
|
|
3668
3761
|
preview,
|
|
3762
|
+
view,
|
|
3669
3763
|
path: name,
|
|
3670
3764
|
root: ctx.root
|
|
3671
3765
|
});
|
|
3672
3766
|
fsCall(`cannot edit ${name}`, () => writeFileSync2(abs, after, "utf8"));
|
|
3767
|
+
ctx.present?.(view);
|
|
3673
3768
|
return `edited ${name} (${count > 1 ? `${count} occurrences` : "1 occurrence"})`;
|
|
3674
3769
|
},
|
|
3675
3770
|
/**
|
|
@@ -5316,6 +5411,9 @@ async function runAgent(client, task, opts) {
|
|
|
5316
5411
|
mcp: opts.mcp,
|
|
5317
5412
|
shells: opts.shells,
|
|
5318
5413
|
attach: (image) => pendingImages.push(image),
|
|
5414
|
+
// A placeholder that says writes are shown at this depth; each call gets
|
|
5415
|
+
// its own (`executeToolCall`), which puts the view on its result event.
|
|
5416
|
+
...depth === 0 ? { present: () => void 0 } : {},
|
|
5319
5417
|
// The recursion guard, and the whole of it: a sub-agent runs at depth 1 and
|
|
5320
5418
|
// is handed no way to start another.
|
|
5321
5419
|
...depth === 0 ? { spawn: runSubAgent } : {}
|
|
@@ -5511,9 +5609,13 @@ async function executeToolCall(ctx, call, emit) {
|
|
|
5511
5609
|
}
|
|
5512
5610
|
emit({ type: "tool_call", id, name, args });
|
|
5513
5611
|
const search = ctx.webSearch;
|
|
5612
|
+
let view;
|
|
5514
5613
|
const scoped = {
|
|
5515
5614
|
...ctx,
|
|
5516
5615
|
onOutput: (chunk) => emit({ type: "tool_output", id, chunk }),
|
|
5616
|
+
// Only where something draws it: a sub-agent's writes are not shown, and
|
|
5617
|
+
// `ctx.present` is how this run says whether anybody is watching.
|
|
5618
|
+
...ctx.present ? { present: (v) => view = v } : {},
|
|
5517
5619
|
// Reported against this call the moment it is charged, so the row says
|
|
5518
5620
|
// what it cost and the balance on screen moves with it.
|
|
5519
5621
|
...search ? {
|
|
@@ -5533,7 +5635,7 @@ async function executeToolCall(ctx, call, emit) {
|
|
|
5533
5635
|
};
|
|
5534
5636
|
try {
|
|
5535
5637
|
const result = await dispatch(scoped, name, args);
|
|
5536
|
-
emit({ type: "tool_result", id, name, result, ok: true });
|
|
5638
|
+
emit({ type: "tool_result", id, name, result, ok: true, ...view ? { view } : {} });
|
|
5537
5639
|
return result;
|
|
5538
5640
|
} catch (err) {
|
|
5539
5641
|
if (err instanceof ToolError) {
|
|
@@ -6457,6 +6559,8 @@ export {
|
|
|
6457
6559
|
webSearchCostLine,
|
|
6458
6560
|
freeHelpLine,
|
|
6459
6561
|
freeAlternativeLine,
|
|
6562
|
+
diffTint,
|
|
6563
|
+
renderDiffRows,
|
|
6460
6564
|
shells,
|
|
6461
6565
|
TodoList,
|
|
6462
6566
|
loadMcpConfig,
|
package/dist/clixad.mjs
CHANGED
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
takeConfigNotices,
|
|
54
54
|
toolSchemaFor,
|
|
55
55
|
usd
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-T7SUUKJC.mjs";
|
|
57
57
|
|
|
58
58
|
// src/tui/load.ts
|
|
59
59
|
import * as nodeModule from "node:module";
|
|
@@ -132,7 +132,7 @@ async function withProductionReact(load) {
|
|
|
132
132
|
}
|
|
133
133
|
function loadTui() {
|
|
134
134
|
boundInkCaches();
|
|
135
|
-
return withProductionReact(() => import("./tui-
|
|
135
|
+
return withProductionReact(() => import("./tui-773NJ4FQ.mjs"));
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// src/title.ts
|