jinzd-ai-cli 0.1.45 → 0.1.47
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/index.js
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
30
30
|
VERSION,
|
|
31
31
|
runTestsTool
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-ZUZDWQVG.js";
|
|
33
33
|
|
|
34
34
|
// src/index.ts
|
|
35
35
|
import { program } from "commander";
|
|
@@ -313,6 +313,39 @@ ${err}`
|
|
|
313
313
|
getDefaultProvider() {
|
|
314
314
|
return EnvLoader.getDefaultProvider() ?? this.config.defaultProvider;
|
|
315
315
|
}
|
|
316
|
+
/** 点分路径读取配置值,如 `ui.theme` → config.ui.theme */
|
|
317
|
+
getByPath(path) {
|
|
318
|
+
const keys = path.split(".");
|
|
319
|
+
let current = this.config;
|
|
320
|
+
for (const key of keys) {
|
|
321
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
322
|
+
current = current[key];
|
|
323
|
+
}
|
|
324
|
+
return current;
|
|
325
|
+
}
|
|
326
|
+
/** 点分路径写入配置值,自动类型转换(boolean/number/string)并持久化 */
|
|
327
|
+
setByPath(path, rawValue) {
|
|
328
|
+
const keys = path.split(".");
|
|
329
|
+
if (keys.length === 0) return;
|
|
330
|
+
let value = rawValue;
|
|
331
|
+
if (rawValue === "true") value = true;
|
|
332
|
+
else if (rawValue === "false") value = false;
|
|
333
|
+
else if (rawValue !== "" && !isNaN(Number(rawValue))) value = Number(rawValue);
|
|
334
|
+
let current = this.config;
|
|
335
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
336
|
+
const key = keys[i];
|
|
337
|
+
if (current[key] == null || typeof current[key] !== "object") {
|
|
338
|
+
current[key] = {};
|
|
339
|
+
}
|
|
340
|
+
current = current[key];
|
|
341
|
+
}
|
|
342
|
+
current[keys[keys.length - 1]] = value;
|
|
343
|
+
this.save();
|
|
344
|
+
}
|
|
345
|
+
/** 获取完整配置对象的 JSON 字符串 */
|
|
346
|
+
toJSON() {
|
|
347
|
+
return JSON.stringify(this.config, null, 2);
|
|
348
|
+
}
|
|
316
349
|
};
|
|
317
350
|
|
|
318
351
|
// src/providers/claude.ts
|
|
@@ -1891,7 +1924,12 @@ var SessionManager = class {
|
|
|
1891
1924
|
if (!existsSync2(filePath)) {
|
|
1892
1925
|
throw new Error(`Session ${id} not found`);
|
|
1893
1926
|
}
|
|
1894
|
-
|
|
1927
|
+
let data;
|
|
1928
|
+
try {
|
|
1929
|
+
data = JSON.parse(readFileSync2(filePath, "utf-8"));
|
|
1930
|
+
} catch (err) {
|
|
1931
|
+
throw new Error(`Session ${id} is corrupted: ${err instanceof Error ? err.message : String(err)}`);
|
|
1932
|
+
}
|
|
1895
1933
|
const session = Session.fromJSON(data);
|
|
1896
1934
|
this._current = session;
|
|
1897
1935
|
return session;
|
|
@@ -2193,12 +2231,12 @@ var Renderer = class {
|
|
|
2193
2231
|
console.log(tool("spawn_agent", "\u59D4\u6D3E\u72EC\u7ACB\u5B50\u4EE3\u7406\u6267\u884C\u7279\u5B9A\u4EFB\u52A1\uFF08\u9694\u79BB\u5BF9\u8BDD + \u81EA\u52A8\u5DE5\u5177\u8C03\u7528\u5FAA\u73AF\uFF09"));
|
|
2194
2232
|
console.log(tool("run_tests", "\u8FD0\u884C\u9879\u76EE\u6D4B\u8BD5\u5E76\u8FD4\u56DE\u7ED3\u6784\u5316\u62A5\u544A\uFF08\u81EA\u52A8\u68C0\u6D4B Maven/npm/pytest \u7B49\uFF09"));
|
|
2195
2233
|
console.log(HR);
|
|
2196
|
-
console.log(theme.dim(" REPL \u547D\u4EE4\
|
|
2234
|
+
console.log(theme.dim(" REPL \u547D\u4EE4\uFF0834\u4E2A\uFF09\uFF1A"));
|
|
2197
2235
|
console.log(theme.dim(" /help /about /provider /model /clear /compact /plan /session"));
|
|
2198
2236
|
console.log(theme.dim(" /system /context /status /search /undo /export /copy /cost"));
|
|
2199
2237
|
console.log(theme.dim(" /init /skill /tools /plugins /mcp /config /checkpoint /review"));
|
|
2200
2238
|
console.log(theme.dim(" /commands /test /scaffold /add-dir /memory /doctor /bug /think"));
|
|
2201
|
-
console.log(theme.dim(" /exit"));
|
|
2239
|
+
console.log(theme.dim(" /diff /exit"));
|
|
2202
2240
|
console.log(HR);
|
|
2203
2241
|
console.log(theme.dim(" \u4E3B\u8981\u7279\u6027\uFF1A"));
|
|
2204
2242
|
console.log(feat("Agentic \u5FAA\u73AF\uFF08\u6700\u591A 25 \u8F6E\u5DE5\u5177\u8C03\u7528\uFF0C\u6700\u7EC8\u56DE\u7B54\u6D41\u5F0F\u8F93\u51FA\uFF09"));
|
|
@@ -2245,6 +2283,9 @@ var Renderer = class {
|
|
|
2245
2283
|
console.log(feat("Extended Thinking\uFF1AClaude \u6DF1\u5EA6\u63A8\u7406\u6A21\u5F0F\uFF0C/think \u8FD0\u884C\u65F6\u5207\u6362\uFF0Cthinking \u5757\u6298\u53E0\u663E\u793A"));
|
|
2246
2284
|
console.log(feat("theme \u5168\u8986\u76D6\uFF1A\u5168\u90E8\u7EC8\u7AEF\u8F93\u51FA\u7EDF\u4E00\u4F7F\u7528\u8BED\u4E49\u8272\u69FD\uFF0Cdark/light/custom \u4E00\u952E\u5207\u6362"));
|
|
2247
2285
|
console.log(feat("edit_file \u667A\u80FD\u63D0\u793A\uFF1A\u5339\u914D\u5931\u8D25\u65F6\u663E\u793A did you mean \u76F8\u4F3C\u884C + ignore_whitespace \u5BB9\u9519\u6A21\u5F0F"));
|
|
2286
|
+
console.log(feat("/config set|get|show\uFF1AREPL \u5185\u5FEB\u6377\u8BFB\u5199\u914D\u7F6E\uFF0C\u65E0\u9700\u8FDB\u5165\u5411\u5BFC\uFF08\u70B9\u5206\u8DEF\u5F84 + \u81EA\u52A8\u7C7B\u578B\u8F6C\u6362\uFF09"));
|
|
2287
|
+
console.log(feat("\u5DE5\u5177\u8C03\u7528\u6700\u7EC8\u56DE\u7B54\u6D41\u5F0F\u5316\uFF1A\u6A21\u62DF\u6253\u5B57\u673A\u6548\u679C\u9010\u5757\u8F93\u51FA\uFF0C\u96F6\u989D\u5916 API \u8C03\u7528\uFF0C\u652F\u6301 Escape \u4E2D\u65AD"));
|
|
2288
|
+
console.log(feat("/diff \u547D\u4EE4\uFF1A\u663E\u793A\u5F53\u524D session \u5185\u6240\u6709\u6587\u4EF6\u4FEE\u6539\u7684\u6C47\u603B diff\uFF08\u5408\u5E76\u540C\u6587\u4EF6\u591A\u6B21\u4FEE\u6539\uFF09"));
|
|
2248
2289
|
console.log();
|
|
2249
2290
|
}
|
|
2250
2291
|
printPrompt(provider, _model) {
|
|
@@ -2371,6 +2412,40 @@ var Renderer = class {
|
|
|
2371
2412
|
process.stdout.write(finalOutput);
|
|
2372
2413
|
process.stdout.write("\n\n");
|
|
2373
2414
|
}
|
|
2415
|
+
/**
|
|
2416
|
+
* 将已有 content 以模拟流式效果逐块输出(打字机体验),零额外 API 调用。
|
|
2417
|
+
* 支持 AbortSignal 中断。
|
|
2418
|
+
*/
|
|
2419
|
+
async renderContentAsStream(content, options) {
|
|
2420
|
+
process.stdout.write(theme.accent("Assistant: "));
|
|
2421
|
+
let displayed = content;
|
|
2422
|
+
if (content.includes("<think>")) {
|
|
2423
|
+
let hasThinking = false;
|
|
2424
|
+
displayed = content.replace(/<think>[\s\S]*?<\/think>/g, () => {
|
|
2425
|
+
hasThinking = true;
|
|
2426
|
+
return "";
|
|
2427
|
+
}).trimStart();
|
|
2428
|
+
if (hasThinking) {
|
|
2429
|
+
process.stdout.write(theme.dim("\n\u{1F4AD} Thinking...\n"));
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
const CHUNK_SIZE = 12;
|
|
2433
|
+
const DELAY_MS = 8;
|
|
2434
|
+
let pos = 0;
|
|
2435
|
+
while (pos < displayed.length) {
|
|
2436
|
+
if (options?.signal?.aborted) {
|
|
2437
|
+
process.stdout.write(theme.dim("\n[interrupted]"));
|
|
2438
|
+
break;
|
|
2439
|
+
}
|
|
2440
|
+
const end = Math.min(pos + CHUNK_SIZE, displayed.length);
|
|
2441
|
+
process.stdout.write(displayed.slice(pos, end));
|
|
2442
|
+
pos = end;
|
|
2443
|
+
if (pos < displayed.length) {
|
|
2444
|
+
await new Promise((resolve5) => setTimeout(resolve5, DELAY_MS));
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
process.stdout.write("\n\n");
|
|
2448
|
+
}
|
|
2374
2449
|
renderError(err) {
|
|
2375
2450
|
const message = err instanceof Error ? err.message : String(err);
|
|
2376
2451
|
console.error(theme.error(`
|
|
@@ -2427,7 +2502,7 @@ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as
|
|
|
2427
2502
|
import { execSync as execSync3 } from "child_process";
|
|
2428
2503
|
import { platform } from "os";
|
|
2429
2504
|
import { resolve, dirname as dirname2, join as join5, basename } from "path";
|
|
2430
|
-
import
|
|
2505
|
+
import chalk4 from "chalk";
|
|
2431
2506
|
|
|
2432
2507
|
// src/tools/git-context.ts
|
|
2433
2508
|
import { execSync } from "child_process";
|
|
@@ -2582,6 +2657,10 @@ var UndoStack = class {
|
|
|
2582
2657
|
get depth() {
|
|
2583
2658
|
return this.stack.length;
|
|
2584
2659
|
}
|
|
2660
|
+
/** 返回栈的拷贝(所有文件修改记录),供 /diff 命令使用 */
|
|
2661
|
+
getHistory() {
|
|
2662
|
+
return [...this.stack];
|
|
2663
|
+
}
|
|
2585
2664
|
/** 清空撤销栈(新会话时调用) */
|
|
2586
2665
|
clear() {
|
|
2587
2666
|
this.stack = [];
|
|
@@ -2589,6 +2668,159 @@ var UndoStack = class {
|
|
|
2589
2668
|
};
|
|
2590
2669
|
var undoStack = new UndoStack();
|
|
2591
2670
|
|
|
2671
|
+
// src/tools/diff-utils.ts
|
|
2672
|
+
import chalk3 from "chalk";
|
|
2673
|
+
function renderDiff(oldText, newText, opts = {}) {
|
|
2674
|
+
const contextLines = opts.contextLines ?? 3;
|
|
2675
|
+
const maxLines = opts.maxLines ?? 120;
|
|
2676
|
+
const filePath = opts.filePath ?? "";
|
|
2677
|
+
const oldLines = oldText.split("\n");
|
|
2678
|
+
const newLines = newText.split("\n");
|
|
2679
|
+
const hunks = computeHunks(oldLines, newLines, contextLines);
|
|
2680
|
+
if (hunks.length === 0) {
|
|
2681
|
+
return chalk3.dim(" (no changes)");
|
|
2682
|
+
}
|
|
2683
|
+
const output = [];
|
|
2684
|
+
if (filePath) {
|
|
2685
|
+
output.push(chalk3.bold.white(`--- ${filePath} (before)`));
|
|
2686
|
+
output.push(chalk3.bold.white(`+++ ${filePath} (after)`));
|
|
2687
|
+
}
|
|
2688
|
+
let totalDisplayed = 0;
|
|
2689
|
+
for (const hunk of hunks) {
|
|
2690
|
+
if (totalDisplayed >= maxLines) {
|
|
2691
|
+
output.push(chalk3.dim(` ... (diff truncated, too many changes)`));
|
|
2692
|
+
break;
|
|
2693
|
+
}
|
|
2694
|
+
output.push(
|
|
2695
|
+
chalk3.cyan(
|
|
2696
|
+
`@@ -${hunk.oldStart + 1},${hunk.oldCount} +${hunk.newStart + 1},${hunk.newCount} @@`
|
|
2697
|
+
)
|
|
2698
|
+
);
|
|
2699
|
+
for (const line of hunk.lines) {
|
|
2700
|
+
if (totalDisplayed >= maxLines) break;
|
|
2701
|
+
totalDisplayed++;
|
|
2702
|
+
if (line.type === "context") {
|
|
2703
|
+
output.push(chalk3.dim(` ${line.text}`));
|
|
2704
|
+
} else if (line.type === "remove") {
|
|
2705
|
+
output.push(chalk3.red(`- ${line.text}`));
|
|
2706
|
+
} else {
|
|
2707
|
+
output.push(chalk3.green(`+ ${line.text}`));
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
return output.join("\n");
|
|
2712
|
+
}
|
|
2713
|
+
function computeHunks(oldLines, newLines, contextLines) {
|
|
2714
|
+
const edits = diffLines(oldLines, newLines);
|
|
2715
|
+
if (edits.every((e) => e.type === "context")) return [];
|
|
2716
|
+
const hunks = [];
|
|
2717
|
+
let i = 0;
|
|
2718
|
+
while (i < edits.length) {
|
|
2719
|
+
if (edits[i].type === "context") {
|
|
2720
|
+
i++;
|
|
2721
|
+
continue;
|
|
2722
|
+
}
|
|
2723
|
+
const start = Math.max(0, i - contextLines);
|
|
2724
|
+
let end = i;
|
|
2725
|
+
while (end < edits.length) {
|
|
2726
|
+
if (edits[end].type !== "context") {
|
|
2727
|
+
end++;
|
|
2728
|
+
} else {
|
|
2729
|
+
let hasMoreChange = false;
|
|
2730
|
+
for (let j = end + 1; j < Math.min(edits.length, end + contextLines * 2 + 1); j++) {
|
|
2731
|
+
if (edits[j].type !== "context") {
|
|
2732
|
+
hasMoreChange = true;
|
|
2733
|
+
break;
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
if (hasMoreChange) {
|
|
2737
|
+
end++;
|
|
2738
|
+
} else {
|
|
2739
|
+
break;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
end = Math.min(edits.length, end + contextLines);
|
|
2744
|
+
const hunkEdits = edits.slice(start, end);
|
|
2745
|
+
let oldStart = 0;
|
|
2746
|
+
let newStart = 0;
|
|
2747
|
+
for (let k = 0; k < start; k++) {
|
|
2748
|
+
if (edits[k].type !== "add") oldStart++;
|
|
2749
|
+
if (edits[k].type !== "remove") newStart++;
|
|
2750
|
+
}
|
|
2751
|
+
let oldCount = 0;
|
|
2752
|
+
let newCount = 0;
|
|
2753
|
+
for (const e of hunkEdits) {
|
|
2754
|
+
if (e.type !== "add") oldCount++;
|
|
2755
|
+
if (e.type !== "remove") newCount++;
|
|
2756
|
+
}
|
|
2757
|
+
hunks.push({
|
|
2758
|
+
oldStart,
|
|
2759
|
+
oldCount,
|
|
2760
|
+
newStart,
|
|
2761
|
+
newCount,
|
|
2762
|
+
lines: hunkEdits.map((e) => ({ type: e.type, text: e.text }))
|
|
2763
|
+
});
|
|
2764
|
+
i = end;
|
|
2765
|
+
}
|
|
2766
|
+
return hunks;
|
|
2767
|
+
}
|
|
2768
|
+
function diffLines(oldLines, newLines) {
|
|
2769
|
+
const n = oldLines.length;
|
|
2770
|
+
const m = newLines.length;
|
|
2771
|
+
if (n * m > 25e4) {
|
|
2772
|
+
return simpleDiff(oldLines, newLines);
|
|
2773
|
+
}
|
|
2774
|
+
const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
2775
|
+
for (let i2 = 1; i2 <= n; i2++) {
|
|
2776
|
+
for (let j2 = 1; j2 <= m; j2++) {
|
|
2777
|
+
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
2778
|
+
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
2779
|
+
} else {
|
|
2780
|
+
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
const result = [];
|
|
2785
|
+
let i = n;
|
|
2786
|
+
let j = m;
|
|
2787
|
+
while (i > 0 || j > 0) {
|
|
2788
|
+
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
2789
|
+
result.unshift({ type: "context", text: oldLines[i - 1] });
|
|
2790
|
+
i--;
|
|
2791
|
+
j--;
|
|
2792
|
+
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
2793
|
+
result.unshift({ type: "add", text: newLines[j - 1] });
|
|
2794
|
+
j--;
|
|
2795
|
+
} else {
|
|
2796
|
+
result.unshift({ type: "remove", text: oldLines[i - 1] });
|
|
2797
|
+
i--;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
return result;
|
|
2801
|
+
}
|
|
2802
|
+
function simpleDiff(oldLines, newLines) {
|
|
2803
|
+
const result = [];
|
|
2804
|
+
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
2805
|
+
for (let i = 0; i < maxLen; i++) {
|
|
2806
|
+
const o = oldLines[i];
|
|
2807
|
+
const n = newLines[i];
|
|
2808
|
+
if (o !== void 0 && n !== void 0) {
|
|
2809
|
+
if (o === n) {
|
|
2810
|
+
result.push({ type: "context", text: o });
|
|
2811
|
+
} else {
|
|
2812
|
+
result.push({ type: "remove", text: o });
|
|
2813
|
+
result.push({ type: "add", text: n });
|
|
2814
|
+
}
|
|
2815
|
+
} else if (o !== void 0) {
|
|
2816
|
+
result.push({ type: "remove", text: o });
|
|
2817
|
+
} else if (n !== void 0) {
|
|
2818
|
+
result.push({ type: "add", text: n });
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
return result;
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2592
2824
|
// src/repl/clipboard.ts
|
|
2593
2825
|
import { execSync as execSync2 } from "child_process";
|
|
2594
2826
|
import { existsSync as existsSync5, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
@@ -2723,8 +2955,15 @@ function scanDirTree(dir, maxDepth = 2, maxEntries = 80) {
|
|
|
2723
2955
|
}
|
|
2724
2956
|
const filtered = entries.filter((e) => !e.startsWith(".") && !SCAN_SKIP_DIRS.has(e));
|
|
2725
2957
|
const sorted = filtered.sort((a, b) => {
|
|
2726
|
-
|
|
2727
|
-
|
|
2958
|
+
let aIsDir = false, bIsDir = false;
|
|
2959
|
+
try {
|
|
2960
|
+
aIsDir = statSync2(join5(d, a)).isDirectory();
|
|
2961
|
+
} catch {
|
|
2962
|
+
}
|
|
2963
|
+
try {
|
|
2964
|
+
bIsDir = statSync2(join5(d, b)).isDirectory();
|
|
2965
|
+
} catch {
|
|
2966
|
+
}
|
|
2728
2967
|
if (aIsDir !== bIsDir) return aIsDir ? -1 : 1;
|
|
2729
2968
|
return a.localeCompare(b);
|
|
2730
2969
|
});
|
|
@@ -2939,7 +3178,7 @@ function createDefaultCommands() {
|
|
|
2939
3178
|
" /tools - List all AI tools available",
|
|
2940
3179
|
" /plugins - Show plugin directory and loaded plugins",
|
|
2941
3180
|
" /mcp [reconnect [id]] - Show MCP servers / reconnect disconnected",
|
|
2942
|
-
" /config
|
|
3181
|
+
" /config [set|get|show] - Config wizard, or get/set values, show all",
|
|
2943
3182
|
" /copy - Copy last AI response to clipboard",
|
|
2944
3183
|
" /cost [reset] - Show session token usage (or reset counters)",
|
|
2945
3184
|
" /init [--force] - Generate AICLI.md by scanning project structure",
|
|
@@ -2953,6 +3192,7 @@ function createDefaultCommands() {
|
|
|
2953
3192
|
" /memory [show|add|clear] - View or edit persistent memory (memory.md)",
|
|
2954
3193
|
" /doctor - Health check (API keys, config, MCP status)",
|
|
2955
3194
|
" /bug [--copy] - Generate bug report template (--copy to clipboard)",
|
|
3195
|
+
" /diff [--stats] - Show all file modifications in this session",
|
|
2956
3196
|
" /exit - Exit"
|
|
2957
3197
|
] : [];
|
|
2958
3198
|
console.log("\nAvailable commands:");
|
|
@@ -3468,10 +3708,45 @@ ${text}
|
|
|
3468
3708
|
},
|
|
3469
3709
|
{
|
|
3470
3710
|
name: "config",
|
|
3471
|
-
description: "
|
|
3472
|
-
usage: "/config",
|
|
3473
|
-
async execute(
|
|
3474
|
-
|
|
3711
|
+
description: "Configuration: wizard, get/set values, show all",
|
|
3712
|
+
usage: "/config [set <path> <value> | get <path> | show]",
|
|
3713
|
+
async execute(args, ctx) {
|
|
3714
|
+
const sub = args[0]?.toLowerCase();
|
|
3715
|
+
const config = ctx.config;
|
|
3716
|
+
if (!sub) {
|
|
3717
|
+
await ctx.runSetupWizard();
|
|
3718
|
+
return;
|
|
3719
|
+
}
|
|
3720
|
+
if (sub === "show") {
|
|
3721
|
+
console.log(config.toJSON());
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3724
|
+
if (sub === "get") {
|
|
3725
|
+
const path = args[1]?.trim();
|
|
3726
|
+
if (!path) {
|
|
3727
|
+
console.log(theme.warning("Usage: /config get <path> (e.g. ui.theme)"));
|
|
3728
|
+
return;
|
|
3729
|
+
}
|
|
3730
|
+
const val = config.getByPath(path);
|
|
3731
|
+
if (val === void 0) {
|
|
3732
|
+
console.log(theme.dim(` ${path} = (undefined)`));
|
|
3733
|
+
} else {
|
|
3734
|
+
console.log(theme.dim(` ${path} = `) + chalk4.white(typeof val === "object" ? JSON.stringify(val) : String(val)));
|
|
3735
|
+
}
|
|
3736
|
+
return;
|
|
3737
|
+
}
|
|
3738
|
+
if (sub === "set") {
|
|
3739
|
+
const path = args[1]?.trim();
|
|
3740
|
+
const value = args.slice(2).join(" ").trim();
|
|
3741
|
+
if (!path || value === "") {
|
|
3742
|
+
console.log(theme.warning("Usage: /config set <path> <value> (e.g. ui.theme light)"));
|
|
3743
|
+
return;
|
|
3744
|
+
}
|
|
3745
|
+
config.setByPath(path, value);
|
|
3746
|
+
console.log(theme.success(` \u2713 Set ${path} = ${value}`));
|
|
3747
|
+
return;
|
|
3748
|
+
}
|
|
3749
|
+
console.log(theme.warning("Usage: /config [set <path> <value> | get <path> | show]"));
|
|
3475
3750
|
}
|
|
3476
3751
|
},
|
|
3477
3752
|
{
|
|
@@ -3737,9 +4012,9 @@ ${hint}` : "")
|
|
|
3737
4012
|
console.log();
|
|
3738
4013
|
console.log(theme.heading(" \u{1F4CA} Session Token Usage"));
|
|
3739
4014
|
console.log(theme.dim(" " + "\u2500".repeat(40)));
|
|
3740
|
-
console.log(theme.dim(" Input tokens : ") +
|
|
3741
|
-
console.log(theme.dim(" Output tokens : ") +
|
|
3742
|
-
console.log(theme.dim(" Total tokens : ") +
|
|
4015
|
+
console.log(theme.dim(" Input tokens : ") + chalk4.white(usage.inputTokens.toLocaleString()));
|
|
4016
|
+
console.log(theme.dim(" Output tokens : ") + chalk4.white(usage.outputTokens.toLocaleString()));
|
|
4017
|
+
console.log(theme.dim(" Total tokens : ") + chalk4.bold.white(totalTokens.toLocaleString()));
|
|
3743
4018
|
console.log(theme.dim(" " + "\u2500".repeat(40)));
|
|
3744
4019
|
const session = ctx.sessions.current;
|
|
3745
4020
|
if (session) {
|
|
@@ -3898,7 +4173,7 @@ ${hint}` : "")
|
|
|
3898
4173
|
description: "Run project tests and show structured report",
|
|
3899
4174
|
usage: "/test [command|filter]",
|
|
3900
4175
|
async execute(args, _ctx) {
|
|
3901
|
-
const { executeTests } = await import("./run-tests-
|
|
4176
|
+
const { executeTests } = await import("./run-tests-EM3QNRWV.js");
|
|
3902
4177
|
const argStr = args.join(" ").trim();
|
|
3903
4178
|
let testArgs = {};
|
|
3904
4179
|
if (argStr) {
|
|
@@ -4009,7 +4284,7 @@ ${hint}` : "")
|
|
|
4009
4284
|
}
|
|
4010
4285
|
const lines = content.split("\n").length;
|
|
4011
4286
|
console.log(theme.heading("\n\u{1F4DD} Persistent Memory:\n") + theme.dim("\u2500".repeat(60)));
|
|
4012
|
-
console.log(
|
|
4287
|
+
console.log(chalk4.white(content));
|
|
4013
4288
|
console.log(theme.dim("\u2500".repeat(60)));
|
|
4014
4289
|
console.log(theme.dim(` ${content.length} chars \xB7 ${lines} lines
|
|
4015
4290
|
`));
|
|
@@ -4168,6 +4443,63 @@ ${text}
|
|
|
4168
4443
|
}
|
|
4169
4444
|
}
|
|
4170
4445
|
},
|
|
4446
|
+
{
|
|
4447
|
+
name: "diff",
|
|
4448
|
+
description: "Show all file modifications in this session",
|
|
4449
|
+
usage: "/diff [--stats]",
|
|
4450
|
+
execute(args) {
|
|
4451
|
+
const history = undoStack.getHistory();
|
|
4452
|
+
if (history.length === 0) {
|
|
4453
|
+
console.log(theme.dim("No file modifications in this session."));
|
|
4454
|
+
return;
|
|
4455
|
+
}
|
|
4456
|
+
const fileMap = /* @__PURE__ */ new Map();
|
|
4457
|
+
for (const entry of history) {
|
|
4458
|
+
if (!fileMap.has(entry.filePath)) {
|
|
4459
|
+
fileMap.set(entry.filePath, { earliest: entry.previousContent });
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
const statsOnly = args[0]?.toLowerCase() === "--stats";
|
|
4463
|
+
let newFiles = 0;
|
|
4464
|
+
let modifiedFiles = 0;
|
|
4465
|
+
for (const [filePath, { earliest }] of fileMap) {
|
|
4466
|
+
const currentContent = existsSync6(filePath) ? (() => {
|
|
4467
|
+
try {
|
|
4468
|
+
return readFileSync4(filePath, "utf-8");
|
|
4469
|
+
} catch {
|
|
4470
|
+
return null;
|
|
4471
|
+
}
|
|
4472
|
+
})() : null;
|
|
4473
|
+
const isNew = earliest === null;
|
|
4474
|
+
if (isNew) newFiles++;
|
|
4475
|
+
else modifiedFiles++;
|
|
4476
|
+
if (statsOnly) continue;
|
|
4477
|
+
if (isNew) {
|
|
4478
|
+
console.log(theme.success(`
|
|
4479
|
+
\u{1F4C4} [NEW] ${filePath}`));
|
|
4480
|
+
if (currentContent !== null) {
|
|
4481
|
+
const lines = currentContent.split("\n").length;
|
|
4482
|
+
console.log(theme.dim(` ${lines} lines`));
|
|
4483
|
+
} else {
|
|
4484
|
+
console.log(theme.dim(" (file was deleted after creation)"));
|
|
4485
|
+
}
|
|
4486
|
+
} else {
|
|
4487
|
+
console.log(theme.accent(`
|
|
4488
|
+
\u{1F4DD} [MODIFIED] ${filePath}`));
|
|
4489
|
+
const oldText = earliest ?? "";
|
|
4490
|
+
const newText = currentContent ?? "";
|
|
4491
|
+
if (oldText === newText) {
|
|
4492
|
+
console.log(theme.dim(" (no net change)"));
|
|
4493
|
+
} else {
|
|
4494
|
+
console.log(renderDiff(oldText, newText, { filePath, maxLines: 80 }));
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
}
|
|
4498
|
+
console.log(theme.heading(`
|
|
4499
|
+
Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modified`));
|
|
4500
|
+
console.log();
|
|
4501
|
+
}
|
|
4502
|
+
},
|
|
4171
4503
|
{
|
|
4172
4504
|
name: "exit",
|
|
4173
4505
|
description: "Exit the REPL",
|
|
@@ -4180,7 +4512,7 @@ ${text}
|
|
|
4180
4512
|
}
|
|
4181
4513
|
|
|
4182
4514
|
// src/repl/select-list.ts
|
|
4183
|
-
import
|
|
4515
|
+
import chalk5 from "chalk";
|
|
4184
4516
|
var CLEAR_LINE = "\r\x1B[2K";
|
|
4185
4517
|
var MOVE_UP = (n) => n > 0 ? `\x1B[${n}A` : "";
|
|
4186
4518
|
var IGNORE_ENTER_MS = 80;
|
|
@@ -4205,10 +4537,10 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4205
4537
|
handleSequence(seq);
|
|
4206
4538
|
};
|
|
4207
4539
|
const renderLine = (item, active, absIdx) => {
|
|
4208
|
-
const cursor = active ?
|
|
4209
|
-
const label = active ?
|
|
4210
|
-
const hint = item.hint ?
|
|
4211
|
-
const num =
|
|
4540
|
+
const cursor = active ? chalk5.cyan("\u276F ") : " ";
|
|
4541
|
+
const label = active ? chalk5.cyan(item.label) : item.label;
|
|
4542
|
+
const hint = item.hint ? chalk5.dim(" " + item.hint) : "";
|
|
4543
|
+
const num = chalk5.dim(String(absIdx + 1).padStart(2) + " ");
|
|
4212
4544
|
return cursor + num + label + hint;
|
|
4213
4545
|
};
|
|
4214
4546
|
const render = () => {
|
|
@@ -4217,16 +4549,16 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4217
4549
|
const windowEnd = Math.min(windowStart + PAGE, items.length);
|
|
4218
4550
|
const visible = items.slice(windowStart, windowEnd);
|
|
4219
4551
|
const lines = [];
|
|
4220
|
-
lines.push(
|
|
4552
|
+
lines.push(chalk5.bold(prompt));
|
|
4221
4553
|
if (windowStart > 0)
|
|
4222
|
-
lines.push(
|
|
4554
|
+
lines.push(chalk5.dim(` \u2191 ${windowStart} more above`));
|
|
4223
4555
|
visible.forEach(
|
|
4224
4556
|
(item, i) => lines.push(renderLine(item, windowStart + i === selected, windowStart + i))
|
|
4225
4557
|
);
|
|
4226
4558
|
const below = items.length - windowEnd;
|
|
4227
4559
|
if (below > 0)
|
|
4228
|
-
lines.push(
|
|
4229
|
-
lines.push(
|
|
4560
|
+
lines.push(chalk5.dim(` \u2193 ${below} more below`));
|
|
4561
|
+
lines.push(chalk5.dim(" \u2191\u2193 move \xB7 Enter select \xB7 Esc cancel"));
|
|
4230
4562
|
if (lastRenderedLines > 0) {
|
|
4231
4563
|
process.stdout.write(MOVE_UP(lastRenderedLines) + CLEAR_LINE);
|
|
4232
4564
|
for (let i = 1; i < lastRenderedLines; i++)
|
|
@@ -4259,7 +4591,7 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4259
4591
|
process.stdout.write(MOVE_UP(lastRenderedLines - 1));
|
|
4260
4592
|
}
|
|
4261
4593
|
if (result !== null) {
|
|
4262
|
-
process.stdout.write(
|
|
4594
|
+
process.stdout.write(chalk5.dim(` \u2714 ${result}
|
|
4263
4595
|
`));
|
|
4264
4596
|
}
|
|
4265
4597
|
resolve5(result);
|
|
@@ -5680,7 +6012,7 @@ ${content}
|
|
|
5680
6012
|
};
|
|
5681
6013
|
|
|
5682
6014
|
// src/tools/builtin/ask-user.ts
|
|
5683
|
-
import
|
|
6015
|
+
import chalk6 from "chalk";
|
|
5684
6016
|
var askUserContext = {
|
|
5685
6017
|
prompting: false
|
|
5686
6018
|
};
|
|
@@ -5717,8 +6049,8 @@ function promptUser(rl, question) {
|
|
|
5717
6049
|
rl.resume();
|
|
5718
6050
|
askUserContext.prompting = true;
|
|
5719
6051
|
console.log();
|
|
5720
|
-
console.log(
|
|
5721
|
-
process.stdout.write(
|
|
6052
|
+
console.log(chalk6.cyan("\u2753 ") + chalk6.bold(question));
|
|
6053
|
+
process.stdout.write(chalk6.cyan("> "));
|
|
5722
6054
|
return new Promise((resolve5) => {
|
|
5723
6055
|
let completed = false;
|
|
5724
6056
|
const cleanup = (answer) => {
|
|
@@ -5735,7 +6067,7 @@ function promptUser(rl, question) {
|
|
|
5735
6067
|
cleanup(line);
|
|
5736
6068
|
};
|
|
5737
6069
|
askUserContext.cancelFn = () => {
|
|
5738
|
-
process.stdout.write(
|
|
6070
|
+
process.stdout.write(chalk6.gray("\n(cancelled)\n"));
|
|
5739
6071
|
cleanup(null);
|
|
5740
6072
|
};
|
|
5741
6073
|
rl.once("line", onLine);
|
|
@@ -5743,7 +6075,7 @@ function promptUser(rl, question) {
|
|
|
5743
6075
|
}
|
|
5744
6076
|
|
|
5745
6077
|
// src/tools/builtin/write-todos.ts
|
|
5746
|
-
import
|
|
6078
|
+
import chalk7 from "chalk";
|
|
5747
6079
|
var VALID_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
|
|
5748
6080
|
var currentTodos = [];
|
|
5749
6081
|
var writeTodosTool = {
|
|
@@ -5806,25 +6138,25 @@ function renderTodoList(todos) {
|
|
|
5806
6138
|
const total = todos.length;
|
|
5807
6139
|
console.log();
|
|
5808
6140
|
console.log(
|
|
5809
|
-
|
|
6141
|
+
chalk7.bold.cyan("\u{1F4CB} Todo List") + chalk7.dim(` (${completed}/${total} completed)`)
|
|
5810
6142
|
);
|
|
5811
|
-
console.log(
|
|
6143
|
+
console.log(chalk7.dim(" " + "\u2500".repeat(40)));
|
|
5812
6144
|
for (const todo of todos) {
|
|
5813
6145
|
let icon;
|
|
5814
6146
|
let text;
|
|
5815
6147
|
switch (todo.status) {
|
|
5816
6148
|
case "completed":
|
|
5817
|
-
icon =
|
|
5818
|
-
text =
|
|
6149
|
+
icon = chalk7.green(" \u2713 ");
|
|
6150
|
+
text = chalk7.strikethrough.gray(todo.title);
|
|
5819
6151
|
break;
|
|
5820
6152
|
case "in_progress":
|
|
5821
|
-
icon =
|
|
5822
|
-
text =
|
|
6153
|
+
icon = chalk7.yellow(" \u2192 ");
|
|
6154
|
+
text = chalk7.white(todo.title);
|
|
5823
6155
|
break;
|
|
5824
6156
|
case "pending":
|
|
5825
6157
|
default:
|
|
5826
|
-
icon =
|
|
5827
|
-
text =
|
|
6158
|
+
icon = chalk7.gray(" \u25CB ");
|
|
6159
|
+
text = chalk7.gray(todo.title);
|
|
5828
6160
|
break;
|
|
5829
6161
|
}
|
|
5830
6162
|
console.log(icon + text);
|
|
@@ -5950,7 +6282,7 @@ function formatResults(query, data, requested) {
|
|
|
5950
6282
|
}
|
|
5951
6283
|
|
|
5952
6284
|
// src/tools/builtin/spawn-agent.ts
|
|
5953
|
-
import
|
|
6285
|
+
import chalk8 from "chalk";
|
|
5954
6286
|
var spawnAgentContext = {
|
|
5955
6287
|
provider: null,
|
|
5956
6288
|
model: "",
|
|
@@ -5958,7 +6290,7 @@ var spawnAgentContext = {
|
|
|
5958
6290
|
modelParams: {},
|
|
5959
6291
|
configManager: null
|
|
5960
6292
|
};
|
|
5961
|
-
var PREFIX =
|
|
6293
|
+
var PREFIX = chalk8.dim(" \u2503 ");
|
|
5962
6294
|
var MAX_TOOL_OUTPUT_CHARS = 12e3;
|
|
5963
6295
|
function truncateOutput(content, toolName) {
|
|
5964
6296
|
if (content.length <= MAX_TOOL_OUTPUT_CHARS) return content;
|
|
@@ -5996,7 +6328,7 @@ var SubAgentExecutor = class {
|
|
|
5996
6328
|
const dangerLevel = getDangerLevel(call.name, call.arguments);
|
|
5997
6329
|
if (dangerLevel === "destructive") {
|
|
5998
6330
|
this.printPrefixed(
|
|
5999
|
-
|
|
6331
|
+
chalk8.red("\u26A0 BLOCKED: ") + `Destructive operation ${chalk8.bold(call.name)} not allowed in sub-agent`
|
|
6000
6332
|
);
|
|
6001
6333
|
return {
|
|
6002
6334
|
callId: call.id,
|
|
@@ -6032,9 +6364,9 @@ var SubAgentExecutor = class {
|
|
|
6032
6364
|
}
|
|
6033
6365
|
printToolCall(call, dangerLevel) {
|
|
6034
6366
|
console.log(PREFIX);
|
|
6035
|
-
const icon = dangerLevel === "write" ?
|
|
6036
|
-
const roundBadge = this.totalRounds > 0 ?
|
|
6037
|
-
console.log(PREFIX + icon +
|
|
6367
|
+
const icon = dangerLevel === "write" ? chalk8.yellow("\u270E Tool: ") : chalk8.bold.cyan("\u2699 Tool: ");
|
|
6368
|
+
const roundBadge = this.totalRounds > 0 ? chalk8.dim(` [${this.round}/${this.totalRounds}]`) : "";
|
|
6369
|
+
console.log(PREFIX + icon + chalk8.white(call.name) + roundBadge);
|
|
6038
6370
|
for (const [key, val] of Object.entries(call.arguments)) {
|
|
6039
6371
|
let valStr;
|
|
6040
6372
|
if (Array.isArray(val)) {
|
|
@@ -6045,22 +6377,22 @@ var SubAgentExecutor = class {
|
|
|
6045
6377
|
} else {
|
|
6046
6378
|
valStr = String(val);
|
|
6047
6379
|
}
|
|
6048
|
-
console.log(PREFIX +
|
|
6380
|
+
console.log(PREFIX + chalk8.gray(` ${key}: `) + chalk8.white(valStr));
|
|
6049
6381
|
}
|
|
6050
6382
|
}
|
|
6051
6383
|
printToolResult(name, content, isError, wasTruncated) {
|
|
6052
6384
|
if (isError) {
|
|
6053
6385
|
console.log(
|
|
6054
|
-
PREFIX +
|
|
6386
|
+
PREFIX + chalk8.red(`\u26A0 ${name} error: `) + chalk8.gray(content.slice(0, 300))
|
|
6055
6387
|
);
|
|
6056
6388
|
} else {
|
|
6057
6389
|
const lines = content.split("\n");
|
|
6058
6390
|
const maxLines = name === "run_interactive" ? 40 : 8;
|
|
6059
6391
|
const preview = lines.slice(0, maxLines);
|
|
6060
|
-
const prefixedPreview = preview.map((l) => PREFIX + " " +
|
|
6061
|
-
const moreLines = lines.length > maxLines ? "\n" + PREFIX +
|
|
6062
|
-
const truncNote = wasTruncated ? "\n" + PREFIX +
|
|
6063
|
-
console.log(PREFIX +
|
|
6392
|
+
const prefixedPreview = preview.map((l) => PREFIX + " " + chalk8.gray(l)).join("\n");
|
|
6393
|
+
const moreLines = lines.length > maxLines ? "\n" + PREFIX + chalk8.gray(` ... (${lines.length - maxLines} more lines)`) : "";
|
|
6394
|
+
const truncNote = wasTruncated ? "\n" + PREFIX + chalk8.yellow(` \u26A1 \u8F93\u51FA\u5DF2\u622A\u65AD\u81F3 ${MAX_TOOL_OUTPUT_CHARS} \u5B57\u7B26`) : "";
|
|
6395
|
+
console.log(PREFIX + chalk8.green("\u2713 Result:"));
|
|
6064
6396
|
console.log(prefixedPreview + moreLines + truncNote);
|
|
6065
6397
|
}
|
|
6066
6398
|
}
|
|
@@ -6090,25 +6422,25 @@ ${task}
|
|
|
6090
6422
|
}
|
|
6091
6423
|
function printSubAgentHeader(task, maxRounds) {
|
|
6092
6424
|
console.log();
|
|
6093
|
-
console.log(
|
|
6094
|
-
console.log(PREFIX +
|
|
6425
|
+
console.log(chalk8.dim(" \u250F\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
6426
|
+
console.log(PREFIX + chalk8.bold.magenta("\u{1F916} Sub-Agent Spawned"));
|
|
6095
6427
|
console.log(
|
|
6096
|
-
PREFIX +
|
|
6428
|
+
PREFIX + chalk8.gray("Task: ") + chalk8.white(task.slice(0, 120) + (task.length > 120 ? "..." : ""))
|
|
6097
6429
|
);
|
|
6098
|
-
console.log(PREFIX +
|
|
6099
|
-
console.log(
|
|
6430
|
+
console.log(PREFIX + chalk8.gray(`Max rounds: ${maxRounds}`));
|
|
6431
|
+
console.log(chalk8.dim(" \u2503"));
|
|
6100
6432
|
}
|
|
6101
6433
|
function printSubAgentFooter(usage) {
|
|
6102
6434
|
console.log(PREFIX);
|
|
6103
|
-
console.log(PREFIX +
|
|
6435
|
+
console.log(PREFIX + chalk8.bold.magenta("Sub-Agent Complete"));
|
|
6104
6436
|
if (usage.inputTokens > 0 || usage.outputTokens > 0) {
|
|
6105
6437
|
console.log(
|
|
6106
|
-
PREFIX +
|
|
6438
|
+
PREFIX + chalk8.dim(
|
|
6107
6439
|
`Tokens: ${usage.inputTokens} in / ${usage.outputTokens} out`
|
|
6108
6440
|
)
|
|
6109
6441
|
);
|
|
6110
6442
|
}
|
|
6111
|
-
console.log(
|
|
6443
|
+
console.log(chalk8.dim(" \u2517\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
|
|
6112
6444
|
console.log();
|
|
6113
6445
|
}
|
|
6114
6446
|
var spawnAgentTool = {
|
|
@@ -6357,159 +6689,6 @@ var ToolRegistry = class {
|
|
|
6357
6689
|
import chalk9 from "chalk";
|
|
6358
6690
|
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
6359
6691
|
|
|
6360
|
-
// src/tools/diff-utils.ts
|
|
6361
|
-
import chalk8 from "chalk";
|
|
6362
|
-
function renderDiff(oldText, newText, opts = {}) {
|
|
6363
|
-
const contextLines = opts.contextLines ?? 3;
|
|
6364
|
-
const maxLines = opts.maxLines ?? 120;
|
|
6365
|
-
const filePath = opts.filePath ?? "";
|
|
6366
|
-
const oldLines = oldText.split("\n");
|
|
6367
|
-
const newLines = newText.split("\n");
|
|
6368
|
-
const hunks = computeHunks(oldLines, newLines, contextLines);
|
|
6369
|
-
if (hunks.length === 0) {
|
|
6370
|
-
return chalk8.dim(" (no changes)");
|
|
6371
|
-
}
|
|
6372
|
-
const output = [];
|
|
6373
|
-
if (filePath) {
|
|
6374
|
-
output.push(chalk8.bold.white(`--- ${filePath} (before)`));
|
|
6375
|
-
output.push(chalk8.bold.white(`+++ ${filePath} (after)`));
|
|
6376
|
-
}
|
|
6377
|
-
let totalDisplayed = 0;
|
|
6378
|
-
for (const hunk of hunks) {
|
|
6379
|
-
if (totalDisplayed >= maxLines) {
|
|
6380
|
-
output.push(chalk8.dim(` ... (diff truncated, too many changes)`));
|
|
6381
|
-
break;
|
|
6382
|
-
}
|
|
6383
|
-
output.push(
|
|
6384
|
-
chalk8.cyan(
|
|
6385
|
-
`@@ -${hunk.oldStart + 1},${hunk.oldCount} +${hunk.newStart + 1},${hunk.newCount} @@`
|
|
6386
|
-
)
|
|
6387
|
-
);
|
|
6388
|
-
for (const line of hunk.lines) {
|
|
6389
|
-
if (totalDisplayed >= maxLines) break;
|
|
6390
|
-
totalDisplayed++;
|
|
6391
|
-
if (line.type === "context") {
|
|
6392
|
-
output.push(chalk8.dim(` ${line.text}`));
|
|
6393
|
-
} else if (line.type === "remove") {
|
|
6394
|
-
output.push(chalk8.red(`- ${line.text}`));
|
|
6395
|
-
} else {
|
|
6396
|
-
output.push(chalk8.green(`+ ${line.text}`));
|
|
6397
|
-
}
|
|
6398
|
-
}
|
|
6399
|
-
}
|
|
6400
|
-
return output.join("\n");
|
|
6401
|
-
}
|
|
6402
|
-
function computeHunks(oldLines, newLines, contextLines) {
|
|
6403
|
-
const edits = diffLines(oldLines, newLines);
|
|
6404
|
-
if (edits.every((e) => e.type === "context")) return [];
|
|
6405
|
-
const hunks = [];
|
|
6406
|
-
let i = 0;
|
|
6407
|
-
while (i < edits.length) {
|
|
6408
|
-
if (edits[i].type === "context") {
|
|
6409
|
-
i++;
|
|
6410
|
-
continue;
|
|
6411
|
-
}
|
|
6412
|
-
const start = Math.max(0, i - contextLines);
|
|
6413
|
-
let end = i;
|
|
6414
|
-
while (end < edits.length) {
|
|
6415
|
-
if (edits[end].type !== "context") {
|
|
6416
|
-
end++;
|
|
6417
|
-
} else {
|
|
6418
|
-
let hasMoreChange = false;
|
|
6419
|
-
for (let j = end + 1; j < Math.min(edits.length, end + contextLines * 2 + 1); j++) {
|
|
6420
|
-
if (edits[j].type !== "context") {
|
|
6421
|
-
hasMoreChange = true;
|
|
6422
|
-
break;
|
|
6423
|
-
}
|
|
6424
|
-
}
|
|
6425
|
-
if (hasMoreChange) {
|
|
6426
|
-
end++;
|
|
6427
|
-
} else {
|
|
6428
|
-
break;
|
|
6429
|
-
}
|
|
6430
|
-
}
|
|
6431
|
-
}
|
|
6432
|
-
end = Math.min(edits.length, end + contextLines);
|
|
6433
|
-
const hunkEdits = edits.slice(start, end);
|
|
6434
|
-
let oldStart = 0;
|
|
6435
|
-
let newStart = 0;
|
|
6436
|
-
for (let k = 0; k < start; k++) {
|
|
6437
|
-
if (edits[k].type !== "add") oldStart++;
|
|
6438
|
-
if (edits[k].type !== "remove") newStart++;
|
|
6439
|
-
}
|
|
6440
|
-
let oldCount = 0;
|
|
6441
|
-
let newCount = 0;
|
|
6442
|
-
for (const e of hunkEdits) {
|
|
6443
|
-
if (e.type !== "add") oldCount++;
|
|
6444
|
-
if (e.type !== "remove") newCount++;
|
|
6445
|
-
}
|
|
6446
|
-
hunks.push({
|
|
6447
|
-
oldStart,
|
|
6448
|
-
oldCount,
|
|
6449
|
-
newStart,
|
|
6450
|
-
newCount,
|
|
6451
|
-
lines: hunkEdits.map((e) => ({ type: e.type, text: e.text }))
|
|
6452
|
-
});
|
|
6453
|
-
i = end;
|
|
6454
|
-
}
|
|
6455
|
-
return hunks;
|
|
6456
|
-
}
|
|
6457
|
-
function diffLines(oldLines, newLines) {
|
|
6458
|
-
const n = oldLines.length;
|
|
6459
|
-
const m = newLines.length;
|
|
6460
|
-
if (n * m > 25e4) {
|
|
6461
|
-
return simpleDiff(oldLines, newLines);
|
|
6462
|
-
}
|
|
6463
|
-
const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
6464
|
-
for (let i2 = 1; i2 <= n; i2++) {
|
|
6465
|
-
for (let j2 = 1; j2 <= m; j2++) {
|
|
6466
|
-
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
6467
|
-
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
6468
|
-
} else {
|
|
6469
|
-
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
6470
|
-
}
|
|
6471
|
-
}
|
|
6472
|
-
}
|
|
6473
|
-
const result = [];
|
|
6474
|
-
let i = n;
|
|
6475
|
-
let j = m;
|
|
6476
|
-
while (i > 0 || j > 0) {
|
|
6477
|
-
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
6478
|
-
result.unshift({ type: "context", text: oldLines[i - 1] });
|
|
6479
|
-
i--;
|
|
6480
|
-
j--;
|
|
6481
|
-
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
6482
|
-
result.unshift({ type: "add", text: newLines[j - 1] });
|
|
6483
|
-
j--;
|
|
6484
|
-
} else {
|
|
6485
|
-
result.unshift({ type: "remove", text: oldLines[i - 1] });
|
|
6486
|
-
i--;
|
|
6487
|
-
}
|
|
6488
|
-
}
|
|
6489
|
-
return result;
|
|
6490
|
-
}
|
|
6491
|
-
function simpleDiff(oldLines, newLines) {
|
|
6492
|
-
const result = [];
|
|
6493
|
-
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
6494
|
-
for (let i = 0; i < maxLen; i++) {
|
|
6495
|
-
const o = oldLines[i];
|
|
6496
|
-
const n = newLines[i];
|
|
6497
|
-
if (o !== void 0 && n !== void 0) {
|
|
6498
|
-
if (o === n) {
|
|
6499
|
-
result.push({ type: "context", text: o });
|
|
6500
|
-
} else {
|
|
6501
|
-
result.push({ type: "remove", text: o });
|
|
6502
|
-
result.push({ type: "add", text: n });
|
|
6503
|
-
}
|
|
6504
|
-
} else if (o !== void 0) {
|
|
6505
|
-
result.push({ type: "remove", text: o });
|
|
6506
|
-
} else if (n !== void 0) {
|
|
6507
|
-
result.push({ type: "add", text: n });
|
|
6508
|
-
}
|
|
6509
|
-
}
|
|
6510
|
-
return result;
|
|
6511
|
-
}
|
|
6512
|
-
|
|
6513
6692
|
// src/tools/hooks.ts
|
|
6514
6693
|
import { execSync as execSync5 } from "child_process";
|
|
6515
6694
|
function runHook(template, vars) {
|
|
@@ -8939,17 +9118,17 @@ Session '${this.resumeSessionId}' not found.
|
|
|
8939
9118
|
this.renderer.renderError(err);
|
|
8940
9119
|
} finally {
|
|
8941
9120
|
processing = false;
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
9121
|
+
if (this.running) {
|
|
9122
|
+
rlAny.output = savedOutput;
|
|
9123
|
+
const rlInternal = this.rl;
|
|
9124
|
+
rlInternal.line = "";
|
|
9125
|
+
rlInternal.cursor = 0;
|
|
9126
|
+
rlInternal.paused = false;
|
|
9127
|
+
process.stdin.resume();
|
|
9128
|
+
this.showPrompt();
|
|
9129
|
+
} else {
|
|
9130
|
+
resolve5();
|
|
9131
|
+
}
|
|
8953
9132
|
}
|
|
8954
9133
|
});
|
|
8955
9134
|
this.rl.on("close", () => {
|
|
@@ -9435,7 +9614,16 @@ Session '${this.resumeSessionId}' not found.
|
|
|
9435
9614
|
if ("content" in result) {
|
|
9436
9615
|
spinner.stop();
|
|
9437
9616
|
const finalContent = result.content;
|
|
9438
|
-
|
|
9617
|
+
if (useStreaming) {
|
|
9618
|
+
const streamAc = this.setupStreamInterrupt();
|
|
9619
|
+
try {
|
|
9620
|
+
await this.renderer.renderContentAsStream(finalContent, { signal: streamAc.signal });
|
|
9621
|
+
} finally {
|
|
9622
|
+
this.teardownStreamInterrupt();
|
|
9623
|
+
}
|
|
9624
|
+
} else {
|
|
9625
|
+
this.renderer.renderResponse(finalContent);
|
|
9626
|
+
}
|
|
9439
9627
|
lastResponseStore.content = finalContent;
|
|
9440
9628
|
session.addMessage({
|
|
9441
9629
|
role: "assistant",
|