jinzd-ai-cli 0.1.45 → 0.1.46
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-LRU55UAO.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
|
|
@@ -2193,12 +2226,12 @@ var Renderer = class {
|
|
|
2193
2226
|
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
2227
|
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
2228
|
console.log(HR);
|
|
2196
|
-
console.log(theme.dim(" REPL \u547D\u4EE4\
|
|
2229
|
+
console.log(theme.dim(" REPL \u547D\u4EE4\uFF0834\u4E2A\uFF09\uFF1A"));
|
|
2197
2230
|
console.log(theme.dim(" /help /about /provider /model /clear /compact /plan /session"));
|
|
2198
2231
|
console.log(theme.dim(" /system /context /status /search /undo /export /copy /cost"));
|
|
2199
2232
|
console.log(theme.dim(" /init /skill /tools /plugins /mcp /config /checkpoint /review"));
|
|
2200
2233
|
console.log(theme.dim(" /commands /test /scaffold /add-dir /memory /doctor /bug /think"));
|
|
2201
|
-
console.log(theme.dim(" /exit"));
|
|
2234
|
+
console.log(theme.dim(" /diff /exit"));
|
|
2202
2235
|
console.log(HR);
|
|
2203
2236
|
console.log(theme.dim(" \u4E3B\u8981\u7279\u6027\uFF1A"));
|
|
2204
2237
|
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 +2278,9 @@ var Renderer = class {
|
|
|
2245
2278
|
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
2279
|
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
2280
|
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"));
|
|
2281
|
+
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"));
|
|
2282
|
+
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"));
|
|
2283
|
+
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
2284
|
console.log();
|
|
2249
2285
|
}
|
|
2250
2286
|
printPrompt(provider, _model) {
|
|
@@ -2371,6 +2407,40 @@ var Renderer = class {
|
|
|
2371
2407
|
process.stdout.write(finalOutput);
|
|
2372
2408
|
process.stdout.write("\n\n");
|
|
2373
2409
|
}
|
|
2410
|
+
/**
|
|
2411
|
+
* 将已有 content 以模拟流式效果逐块输出(打字机体验),零额外 API 调用。
|
|
2412
|
+
* 支持 AbortSignal 中断。
|
|
2413
|
+
*/
|
|
2414
|
+
async renderContentAsStream(content, options) {
|
|
2415
|
+
process.stdout.write(theme.accent("Assistant: "));
|
|
2416
|
+
let displayed = content;
|
|
2417
|
+
if (content.includes("<think>")) {
|
|
2418
|
+
let hasThinking = false;
|
|
2419
|
+
displayed = content.replace(/<think>[\s\S]*?<\/think>/g, () => {
|
|
2420
|
+
hasThinking = true;
|
|
2421
|
+
return "";
|
|
2422
|
+
}).trimStart();
|
|
2423
|
+
if (hasThinking) {
|
|
2424
|
+
process.stdout.write(theme.dim("\n\u{1F4AD} Thinking...\n"));
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
const CHUNK_SIZE = 12;
|
|
2428
|
+
const DELAY_MS = 8;
|
|
2429
|
+
let pos = 0;
|
|
2430
|
+
while (pos < displayed.length) {
|
|
2431
|
+
if (options?.signal?.aborted) {
|
|
2432
|
+
process.stdout.write(theme.dim("\n[interrupted]"));
|
|
2433
|
+
break;
|
|
2434
|
+
}
|
|
2435
|
+
const end = Math.min(pos + CHUNK_SIZE, displayed.length);
|
|
2436
|
+
process.stdout.write(displayed.slice(pos, end));
|
|
2437
|
+
pos = end;
|
|
2438
|
+
if (pos < displayed.length) {
|
|
2439
|
+
await new Promise((resolve5) => setTimeout(resolve5, DELAY_MS));
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
process.stdout.write("\n\n");
|
|
2443
|
+
}
|
|
2374
2444
|
renderError(err) {
|
|
2375
2445
|
const message = err instanceof Error ? err.message : String(err);
|
|
2376
2446
|
console.error(theme.error(`
|
|
@@ -2427,7 +2497,7 @@ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as
|
|
|
2427
2497
|
import { execSync as execSync3 } from "child_process";
|
|
2428
2498
|
import { platform } from "os";
|
|
2429
2499
|
import { resolve, dirname as dirname2, join as join5, basename } from "path";
|
|
2430
|
-
import
|
|
2500
|
+
import chalk4 from "chalk";
|
|
2431
2501
|
|
|
2432
2502
|
// src/tools/git-context.ts
|
|
2433
2503
|
import { execSync } from "child_process";
|
|
@@ -2582,6 +2652,10 @@ var UndoStack = class {
|
|
|
2582
2652
|
get depth() {
|
|
2583
2653
|
return this.stack.length;
|
|
2584
2654
|
}
|
|
2655
|
+
/** 返回栈的拷贝(所有文件修改记录),供 /diff 命令使用 */
|
|
2656
|
+
getHistory() {
|
|
2657
|
+
return [...this.stack];
|
|
2658
|
+
}
|
|
2585
2659
|
/** 清空撤销栈(新会话时调用) */
|
|
2586
2660
|
clear() {
|
|
2587
2661
|
this.stack = [];
|
|
@@ -2589,6 +2663,159 @@ var UndoStack = class {
|
|
|
2589
2663
|
};
|
|
2590
2664
|
var undoStack = new UndoStack();
|
|
2591
2665
|
|
|
2666
|
+
// src/tools/diff-utils.ts
|
|
2667
|
+
import chalk3 from "chalk";
|
|
2668
|
+
function renderDiff(oldText, newText, opts = {}) {
|
|
2669
|
+
const contextLines = opts.contextLines ?? 3;
|
|
2670
|
+
const maxLines = opts.maxLines ?? 120;
|
|
2671
|
+
const filePath = opts.filePath ?? "";
|
|
2672
|
+
const oldLines = oldText.split("\n");
|
|
2673
|
+
const newLines = newText.split("\n");
|
|
2674
|
+
const hunks = computeHunks(oldLines, newLines, contextLines);
|
|
2675
|
+
if (hunks.length === 0) {
|
|
2676
|
+
return chalk3.dim(" (no changes)");
|
|
2677
|
+
}
|
|
2678
|
+
const output = [];
|
|
2679
|
+
if (filePath) {
|
|
2680
|
+
output.push(chalk3.bold.white(`--- ${filePath} (before)`));
|
|
2681
|
+
output.push(chalk3.bold.white(`+++ ${filePath} (after)`));
|
|
2682
|
+
}
|
|
2683
|
+
let totalDisplayed = 0;
|
|
2684
|
+
for (const hunk of hunks) {
|
|
2685
|
+
if (totalDisplayed >= maxLines) {
|
|
2686
|
+
output.push(chalk3.dim(` ... (diff truncated, too many changes)`));
|
|
2687
|
+
break;
|
|
2688
|
+
}
|
|
2689
|
+
output.push(
|
|
2690
|
+
chalk3.cyan(
|
|
2691
|
+
`@@ -${hunk.oldStart + 1},${hunk.oldCount} +${hunk.newStart + 1},${hunk.newCount} @@`
|
|
2692
|
+
)
|
|
2693
|
+
);
|
|
2694
|
+
for (const line of hunk.lines) {
|
|
2695
|
+
if (totalDisplayed >= maxLines) break;
|
|
2696
|
+
totalDisplayed++;
|
|
2697
|
+
if (line.type === "context") {
|
|
2698
|
+
output.push(chalk3.dim(` ${line.text}`));
|
|
2699
|
+
} else if (line.type === "remove") {
|
|
2700
|
+
output.push(chalk3.red(`- ${line.text}`));
|
|
2701
|
+
} else {
|
|
2702
|
+
output.push(chalk3.green(`+ ${line.text}`));
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
return output.join("\n");
|
|
2707
|
+
}
|
|
2708
|
+
function computeHunks(oldLines, newLines, contextLines) {
|
|
2709
|
+
const edits = diffLines(oldLines, newLines);
|
|
2710
|
+
if (edits.every((e) => e.type === "context")) return [];
|
|
2711
|
+
const hunks = [];
|
|
2712
|
+
let i = 0;
|
|
2713
|
+
while (i < edits.length) {
|
|
2714
|
+
if (edits[i].type === "context") {
|
|
2715
|
+
i++;
|
|
2716
|
+
continue;
|
|
2717
|
+
}
|
|
2718
|
+
const start = Math.max(0, i - contextLines);
|
|
2719
|
+
let end = i;
|
|
2720
|
+
while (end < edits.length) {
|
|
2721
|
+
if (edits[end].type !== "context") {
|
|
2722
|
+
end++;
|
|
2723
|
+
} else {
|
|
2724
|
+
let hasMoreChange = false;
|
|
2725
|
+
for (let j = end + 1; j < Math.min(edits.length, end + contextLines * 2 + 1); j++) {
|
|
2726
|
+
if (edits[j].type !== "context") {
|
|
2727
|
+
hasMoreChange = true;
|
|
2728
|
+
break;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
if (hasMoreChange) {
|
|
2732
|
+
end++;
|
|
2733
|
+
} else {
|
|
2734
|
+
break;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
end = Math.min(edits.length, end + contextLines);
|
|
2739
|
+
const hunkEdits = edits.slice(start, end);
|
|
2740
|
+
let oldStart = 0;
|
|
2741
|
+
let newStart = 0;
|
|
2742
|
+
for (let k = 0; k < start; k++) {
|
|
2743
|
+
if (edits[k].type !== "add") oldStart++;
|
|
2744
|
+
if (edits[k].type !== "remove") newStart++;
|
|
2745
|
+
}
|
|
2746
|
+
let oldCount = 0;
|
|
2747
|
+
let newCount = 0;
|
|
2748
|
+
for (const e of hunkEdits) {
|
|
2749
|
+
if (e.type !== "add") oldCount++;
|
|
2750
|
+
if (e.type !== "remove") newCount++;
|
|
2751
|
+
}
|
|
2752
|
+
hunks.push({
|
|
2753
|
+
oldStart,
|
|
2754
|
+
oldCount,
|
|
2755
|
+
newStart,
|
|
2756
|
+
newCount,
|
|
2757
|
+
lines: hunkEdits.map((e) => ({ type: e.type, text: e.text }))
|
|
2758
|
+
});
|
|
2759
|
+
i = end;
|
|
2760
|
+
}
|
|
2761
|
+
return hunks;
|
|
2762
|
+
}
|
|
2763
|
+
function diffLines(oldLines, newLines) {
|
|
2764
|
+
const n = oldLines.length;
|
|
2765
|
+
const m = newLines.length;
|
|
2766
|
+
if (n * m > 25e4) {
|
|
2767
|
+
return simpleDiff(oldLines, newLines);
|
|
2768
|
+
}
|
|
2769
|
+
const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
2770
|
+
for (let i2 = 1; i2 <= n; i2++) {
|
|
2771
|
+
for (let j2 = 1; j2 <= m; j2++) {
|
|
2772
|
+
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
2773
|
+
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
2774
|
+
} else {
|
|
2775
|
+
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
const result = [];
|
|
2780
|
+
let i = n;
|
|
2781
|
+
let j = m;
|
|
2782
|
+
while (i > 0 || j > 0) {
|
|
2783
|
+
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
2784
|
+
result.unshift({ type: "context", text: oldLines[i - 1] });
|
|
2785
|
+
i--;
|
|
2786
|
+
j--;
|
|
2787
|
+
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
2788
|
+
result.unshift({ type: "add", text: newLines[j - 1] });
|
|
2789
|
+
j--;
|
|
2790
|
+
} else {
|
|
2791
|
+
result.unshift({ type: "remove", text: oldLines[i - 1] });
|
|
2792
|
+
i--;
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
return result;
|
|
2796
|
+
}
|
|
2797
|
+
function simpleDiff(oldLines, newLines) {
|
|
2798
|
+
const result = [];
|
|
2799
|
+
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
2800
|
+
for (let i = 0; i < maxLen; i++) {
|
|
2801
|
+
const o = oldLines[i];
|
|
2802
|
+
const n = newLines[i];
|
|
2803
|
+
if (o !== void 0 && n !== void 0) {
|
|
2804
|
+
if (o === n) {
|
|
2805
|
+
result.push({ type: "context", text: o });
|
|
2806
|
+
} else {
|
|
2807
|
+
result.push({ type: "remove", text: o });
|
|
2808
|
+
result.push({ type: "add", text: n });
|
|
2809
|
+
}
|
|
2810
|
+
} else if (o !== void 0) {
|
|
2811
|
+
result.push({ type: "remove", text: o });
|
|
2812
|
+
} else if (n !== void 0) {
|
|
2813
|
+
result.push({ type: "add", text: n });
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
return result;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2592
2819
|
// src/repl/clipboard.ts
|
|
2593
2820
|
import { execSync as execSync2 } from "child_process";
|
|
2594
2821
|
import { existsSync as existsSync5, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
@@ -2939,7 +3166,7 @@ function createDefaultCommands() {
|
|
|
2939
3166
|
" /tools - List all AI tools available",
|
|
2940
3167
|
" /plugins - Show plugin directory and loaded plugins",
|
|
2941
3168
|
" /mcp [reconnect [id]] - Show MCP servers / reconnect disconnected",
|
|
2942
|
-
" /config
|
|
3169
|
+
" /config [set|get|show] - Config wizard, or get/set values, show all",
|
|
2943
3170
|
" /copy - Copy last AI response to clipboard",
|
|
2944
3171
|
" /cost [reset] - Show session token usage (or reset counters)",
|
|
2945
3172
|
" /init [--force] - Generate AICLI.md by scanning project structure",
|
|
@@ -2953,6 +3180,7 @@ function createDefaultCommands() {
|
|
|
2953
3180
|
" /memory [show|add|clear] - View or edit persistent memory (memory.md)",
|
|
2954
3181
|
" /doctor - Health check (API keys, config, MCP status)",
|
|
2955
3182
|
" /bug [--copy] - Generate bug report template (--copy to clipboard)",
|
|
3183
|
+
" /diff [--stats] - Show all file modifications in this session",
|
|
2956
3184
|
" /exit - Exit"
|
|
2957
3185
|
] : [];
|
|
2958
3186
|
console.log("\nAvailable commands:");
|
|
@@ -3468,10 +3696,45 @@ ${text}
|
|
|
3468
3696
|
},
|
|
3469
3697
|
{
|
|
3470
3698
|
name: "config",
|
|
3471
|
-
description: "
|
|
3472
|
-
usage: "/config",
|
|
3473
|
-
async execute(
|
|
3474
|
-
|
|
3699
|
+
description: "Configuration: wizard, get/set values, show all",
|
|
3700
|
+
usage: "/config [set <path> <value> | get <path> | show]",
|
|
3701
|
+
async execute(args, ctx) {
|
|
3702
|
+
const sub = args[0]?.toLowerCase();
|
|
3703
|
+
const config = ctx.config;
|
|
3704
|
+
if (!sub) {
|
|
3705
|
+
await ctx.runSetupWizard();
|
|
3706
|
+
return;
|
|
3707
|
+
}
|
|
3708
|
+
if (sub === "show") {
|
|
3709
|
+
console.log(config.toJSON());
|
|
3710
|
+
return;
|
|
3711
|
+
}
|
|
3712
|
+
if (sub === "get") {
|
|
3713
|
+
const path = args[1]?.trim();
|
|
3714
|
+
if (!path) {
|
|
3715
|
+
console.log(theme.warning("Usage: /config get <path> (e.g. ui.theme)"));
|
|
3716
|
+
return;
|
|
3717
|
+
}
|
|
3718
|
+
const val = config.getByPath(path);
|
|
3719
|
+
if (val === void 0) {
|
|
3720
|
+
console.log(theme.dim(` ${path} = (undefined)`));
|
|
3721
|
+
} else {
|
|
3722
|
+
console.log(theme.dim(` ${path} = `) + chalk4.white(typeof val === "object" ? JSON.stringify(val) : String(val)));
|
|
3723
|
+
}
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3726
|
+
if (sub === "set") {
|
|
3727
|
+
const path = args[1]?.trim();
|
|
3728
|
+
const value = args.slice(2).join(" ").trim();
|
|
3729
|
+
if (!path || value === "") {
|
|
3730
|
+
console.log(theme.warning("Usage: /config set <path> <value> (e.g. ui.theme light)"));
|
|
3731
|
+
return;
|
|
3732
|
+
}
|
|
3733
|
+
config.setByPath(path, value);
|
|
3734
|
+
console.log(theme.success(` \u2713 Set ${path} = ${value}`));
|
|
3735
|
+
return;
|
|
3736
|
+
}
|
|
3737
|
+
console.log(theme.warning("Usage: /config [set <path> <value> | get <path> | show]"));
|
|
3475
3738
|
}
|
|
3476
3739
|
},
|
|
3477
3740
|
{
|
|
@@ -3737,9 +4000,9 @@ ${hint}` : "")
|
|
|
3737
4000
|
console.log();
|
|
3738
4001
|
console.log(theme.heading(" \u{1F4CA} Session Token Usage"));
|
|
3739
4002
|
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 : ") +
|
|
4003
|
+
console.log(theme.dim(" Input tokens : ") + chalk4.white(usage.inputTokens.toLocaleString()));
|
|
4004
|
+
console.log(theme.dim(" Output tokens : ") + chalk4.white(usage.outputTokens.toLocaleString()));
|
|
4005
|
+
console.log(theme.dim(" Total tokens : ") + chalk4.bold.white(totalTokens.toLocaleString()));
|
|
3743
4006
|
console.log(theme.dim(" " + "\u2500".repeat(40)));
|
|
3744
4007
|
const session = ctx.sessions.current;
|
|
3745
4008
|
if (session) {
|
|
@@ -3898,7 +4161,7 @@ ${hint}` : "")
|
|
|
3898
4161
|
description: "Run project tests and show structured report",
|
|
3899
4162
|
usage: "/test [command|filter]",
|
|
3900
4163
|
async execute(args, _ctx) {
|
|
3901
|
-
const { executeTests } = await import("./run-tests-
|
|
4164
|
+
const { executeTests } = await import("./run-tests-V62QUKVZ.js");
|
|
3902
4165
|
const argStr = args.join(" ").trim();
|
|
3903
4166
|
let testArgs = {};
|
|
3904
4167
|
if (argStr) {
|
|
@@ -4009,7 +4272,7 @@ ${hint}` : "")
|
|
|
4009
4272
|
}
|
|
4010
4273
|
const lines = content.split("\n").length;
|
|
4011
4274
|
console.log(theme.heading("\n\u{1F4DD} Persistent Memory:\n") + theme.dim("\u2500".repeat(60)));
|
|
4012
|
-
console.log(
|
|
4275
|
+
console.log(chalk4.white(content));
|
|
4013
4276
|
console.log(theme.dim("\u2500".repeat(60)));
|
|
4014
4277
|
console.log(theme.dim(` ${content.length} chars \xB7 ${lines} lines
|
|
4015
4278
|
`));
|
|
@@ -4168,6 +4431,63 @@ ${text}
|
|
|
4168
4431
|
}
|
|
4169
4432
|
}
|
|
4170
4433
|
},
|
|
4434
|
+
{
|
|
4435
|
+
name: "diff",
|
|
4436
|
+
description: "Show all file modifications in this session",
|
|
4437
|
+
usage: "/diff [--stats]",
|
|
4438
|
+
execute(args) {
|
|
4439
|
+
const history = undoStack.getHistory();
|
|
4440
|
+
if (history.length === 0) {
|
|
4441
|
+
console.log(theme.dim("No file modifications in this session."));
|
|
4442
|
+
return;
|
|
4443
|
+
}
|
|
4444
|
+
const fileMap = /* @__PURE__ */ new Map();
|
|
4445
|
+
for (const entry of history) {
|
|
4446
|
+
if (!fileMap.has(entry.filePath)) {
|
|
4447
|
+
fileMap.set(entry.filePath, { earliest: entry.previousContent });
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
const statsOnly = args[0]?.toLowerCase() === "--stats";
|
|
4451
|
+
let newFiles = 0;
|
|
4452
|
+
let modifiedFiles = 0;
|
|
4453
|
+
for (const [filePath, { earliest }] of fileMap) {
|
|
4454
|
+
const currentContent = existsSync6(filePath) ? (() => {
|
|
4455
|
+
try {
|
|
4456
|
+
return readFileSync4(filePath, "utf-8");
|
|
4457
|
+
} catch {
|
|
4458
|
+
return null;
|
|
4459
|
+
}
|
|
4460
|
+
})() : null;
|
|
4461
|
+
const isNew = earliest === null;
|
|
4462
|
+
if (isNew) newFiles++;
|
|
4463
|
+
else modifiedFiles++;
|
|
4464
|
+
if (statsOnly) continue;
|
|
4465
|
+
if (isNew) {
|
|
4466
|
+
console.log(theme.success(`
|
|
4467
|
+
\u{1F4C4} [NEW] ${filePath}`));
|
|
4468
|
+
if (currentContent !== null) {
|
|
4469
|
+
const lines = currentContent.split("\n").length;
|
|
4470
|
+
console.log(theme.dim(` ${lines} lines`));
|
|
4471
|
+
} else {
|
|
4472
|
+
console.log(theme.dim(" (file was deleted after creation)"));
|
|
4473
|
+
}
|
|
4474
|
+
} else {
|
|
4475
|
+
console.log(theme.accent(`
|
|
4476
|
+
\u{1F4DD} [MODIFIED] ${filePath}`));
|
|
4477
|
+
const oldText = earliest ?? "";
|
|
4478
|
+
const newText = currentContent ?? "";
|
|
4479
|
+
if (oldText === newText) {
|
|
4480
|
+
console.log(theme.dim(" (no net change)"));
|
|
4481
|
+
} else {
|
|
4482
|
+
console.log(renderDiff(oldText, newText, { filePath, maxLines: 80 }));
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
console.log(theme.heading(`
|
|
4487
|
+
Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modified`));
|
|
4488
|
+
console.log();
|
|
4489
|
+
}
|
|
4490
|
+
},
|
|
4171
4491
|
{
|
|
4172
4492
|
name: "exit",
|
|
4173
4493
|
description: "Exit the REPL",
|
|
@@ -4180,7 +4500,7 @@ ${text}
|
|
|
4180
4500
|
}
|
|
4181
4501
|
|
|
4182
4502
|
// src/repl/select-list.ts
|
|
4183
|
-
import
|
|
4503
|
+
import chalk5 from "chalk";
|
|
4184
4504
|
var CLEAR_LINE = "\r\x1B[2K";
|
|
4185
4505
|
var MOVE_UP = (n) => n > 0 ? `\x1B[${n}A` : "";
|
|
4186
4506
|
var IGNORE_ENTER_MS = 80;
|
|
@@ -4205,10 +4525,10 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4205
4525
|
handleSequence(seq);
|
|
4206
4526
|
};
|
|
4207
4527
|
const renderLine = (item, active, absIdx) => {
|
|
4208
|
-
const cursor = active ?
|
|
4209
|
-
const label = active ?
|
|
4210
|
-
const hint = item.hint ?
|
|
4211
|
-
const num =
|
|
4528
|
+
const cursor = active ? chalk5.cyan("\u276F ") : " ";
|
|
4529
|
+
const label = active ? chalk5.cyan(item.label) : item.label;
|
|
4530
|
+
const hint = item.hint ? chalk5.dim(" " + item.hint) : "";
|
|
4531
|
+
const num = chalk5.dim(String(absIdx + 1).padStart(2) + " ");
|
|
4212
4532
|
return cursor + num + label + hint;
|
|
4213
4533
|
};
|
|
4214
4534
|
const render = () => {
|
|
@@ -4217,16 +4537,16 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4217
4537
|
const windowEnd = Math.min(windowStart + PAGE, items.length);
|
|
4218
4538
|
const visible = items.slice(windowStart, windowEnd);
|
|
4219
4539
|
const lines = [];
|
|
4220
|
-
lines.push(
|
|
4540
|
+
lines.push(chalk5.bold(prompt));
|
|
4221
4541
|
if (windowStart > 0)
|
|
4222
|
-
lines.push(
|
|
4542
|
+
lines.push(chalk5.dim(` \u2191 ${windowStart} more above`));
|
|
4223
4543
|
visible.forEach(
|
|
4224
4544
|
(item, i) => lines.push(renderLine(item, windowStart + i === selected, windowStart + i))
|
|
4225
4545
|
);
|
|
4226
4546
|
const below = items.length - windowEnd;
|
|
4227
4547
|
if (below > 0)
|
|
4228
|
-
lines.push(
|
|
4229
|
-
lines.push(
|
|
4548
|
+
lines.push(chalk5.dim(` \u2193 ${below} more below`));
|
|
4549
|
+
lines.push(chalk5.dim(" \u2191\u2193 move \xB7 Enter select \xB7 Esc cancel"));
|
|
4230
4550
|
if (lastRenderedLines > 0) {
|
|
4231
4551
|
process.stdout.write(MOVE_UP(lastRenderedLines) + CLEAR_LINE);
|
|
4232
4552
|
for (let i = 1; i < lastRenderedLines; i++)
|
|
@@ -4259,7 +4579,7 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4259
4579
|
process.stdout.write(MOVE_UP(lastRenderedLines - 1));
|
|
4260
4580
|
}
|
|
4261
4581
|
if (result !== null) {
|
|
4262
|
-
process.stdout.write(
|
|
4582
|
+
process.stdout.write(chalk5.dim(` \u2714 ${result}
|
|
4263
4583
|
`));
|
|
4264
4584
|
}
|
|
4265
4585
|
resolve5(result);
|
|
@@ -5680,7 +6000,7 @@ ${content}
|
|
|
5680
6000
|
};
|
|
5681
6001
|
|
|
5682
6002
|
// src/tools/builtin/ask-user.ts
|
|
5683
|
-
import
|
|
6003
|
+
import chalk6 from "chalk";
|
|
5684
6004
|
var askUserContext = {
|
|
5685
6005
|
prompting: false
|
|
5686
6006
|
};
|
|
@@ -5717,8 +6037,8 @@ function promptUser(rl, question) {
|
|
|
5717
6037
|
rl.resume();
|
|
5718
6038
|
askUserContext.prompting = true;
|
|
5719
6039
|
console.log();
|
|
5720
|
-
console.log(
|
|
5721
|
-
process.stdout.write(
|
|
6040
|
+
console.log(chalk6.cyan("\u2753 ") + chalk6.bold(question));
|
|
6041
|
+
process.stdout.write(chalk6.cyan("> "));
|
|
5722
6042
|
return new Promise((resolve5) => {
|
|
5723
6043
|
let completed = false;
|
|
5724
6044
|
const cleanup = (answer) => {
|
|
@@ -5735,7 +6055,7 @@ function promptUser(rl, question) {
|
|
|
5735
6055
|
cleanup(line);
|
|
5736
6056
|
};
|
|
5737
6057
|
askUserContext.cancelFn = () => {
|
|
5738
|
-
process.stdout.write(
|
|
6058
|
+
process.stdout.write(chalk6.gray("\n(cancelled)\n"));
|
|
5739
6059
|
cleanup(null);
|
|
5740
6060
|
};
|
|
5741
6061
|
rl.once("line", onLine);
|
|
@@ -5743,7 +6063,7 @@ function promptUser(rl, question) {
|
|
|
5743
6063
|
}
|
|
5744
6064
|
|
|
5745
6065
|
// src/tools/builtin/write-todos.ts
|
|
5746
|
-
import
|
|
6066
|
+
import chalk7 from "chalk";
|
|
5747
6067
|
var VALID_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
|
|
5748
6068
|
var currentTodos = [];
|
|
5749
6069
|
var writeTodosTool = {
|
|
@@ -5806,25 +6126,25 @@ function renderTodoList(todos) {
|
|
|
5806
6126
|
const total = todos.length;
|
|
5807
6127
|
console.log();
|
|
5808
6128
|
console.log(
|
|
5809
|
-
|
|
6129
|
+
chalk7.bold.cyan("\u{1F4CB} Todo List") + chalk7.dim(` (${completed}/${total} completed)`)
|
|
5810
6130
|
);
|
|
5811
|
-
console.log(
|
|
6131
|
+
console.log(chalk7.dim(" " + "\u2500".repeat(40)));
|
|
5812
6132
|
for (const todo of todos) {
|
|
5813
6133
|
let icon;
|
|
5814
6134
|
let text;
|
|
5815
6135
|
switch (todo.status) {
|
|
5816
6136
|
case "completed":
|
|
5817
|
-
icon =
|
|
5818
|
-
text =
|
|
6137
|
+
icon = chalk7.green(" \u2713 ");
|
|
6138
|
+
text = chalk7.strikethrough.gray(todo.title);
|
|
5819
6139
|
break;
|
|
5820
6140
|
case "in_progress":
|
|
5821
|
-
icon =
|
|
5822
|
-
text =
|
|
6141
|
+
icon = chalk7.yellow(" \u2192 ");
|
|
6142
|
+
text = chalk7.white(todo.title);
|
|
5823
6143
|
break;
|
|
5824
6144
|
case "pending":
|
|
5825
6145
|
default:
|
|
5826
|
-
icon =
|
|
5827
|
-
text =
|
|
6146
|
+
icon = chalk7.gray(" \u25CB ");
|
|
6147
|
+
text = chalk7.gray(todo.title);
|
|
5828
6148
|
break;
|
|
5829
6149
|
}
|
|
5830
6150
|
console.log(icon + text);
|
|
@@ -5950,7 +6270,7 @@ function formatResults(query, data, requested) {
|
|
|
5950
6270
|
}
|
|
5951
6271
|
|
|
5952
6272
|
// src/tools/builtin/spawn-agent.ts
|
|
5953
|
-
import
|
|
6273
|
+
import chalk8 from "chalk";
|
|
5954
6274
|
var spawnAgentContext = {
|
|
5955
6275
|
provider: null,
|
|
5956
6276
|
model: "",
|
|
@@ -5958,7 +6278,7 @@ var spawnAgentContext = {
|
|
|
5958
6278
|
modelParams: {},
|
|
5959
6279
|
configManager: null
|
|
5960
6280
|
};
|
|
5961
|
-
var PREFIX =
|
|
6281
|
+
var PREFIX = chalk8.dim(" \u2503 ");
|
|
5962
6282
|
var MAX_TOOL_OUTPUT_CHARS = 12e3;
|
|
5963
6283
|
function truncateOutput(content, toolName) {
|
|
5964
6284
|
if (content.length <= MAX_TOOL_OUTPUT_CHARS) return content;
|
|
@@ -5996,7 +6316,7 @@ var SubAgentExecutor = class {
|
|
|
5996
6316
|
const dangerLevel = getDangerLevel(call.name, call.arguments);
|
|
5997
6317
|
if (dangerLevel === "destructive") {
|
|
5998
6318
|
this.printPrefixed(
|
|
5999
|
-
|
|
6319
|
+
chalk8.red("\u26A0 BLOCKED: ") + `Destructive operation ${chalk8.bold(call.name)} not allowed in sub-agent`
|
|
6000
6320
|
);
|
|
6001
6321
|
return {
|
|
6002
6322
|
callId: call.id,
|
|
@@ -6032,9 +6352,9 @@ var SubAgentExecutor = class {
|
|
|
6032
6352
|
}
|
|
6033
6353
|
printToolCall(call, dangerLevel) {
|
|
6034
6354
|
console.log(PREFIX);
|
|
6035
|
-
const icon = dangerLevel === "write" ?
|
|
6036
|
-
const roundBadge = this.totalRounds > 0 ?
|
|
6037
|
-
console.log(PREFIX + icon +
|
|
6355
|
+
const icon = dangerLevel === "write" ? chalk8.yellow("\u270E Tool: ") : chalk8.bold.cyan("\u2699 Tool: ");
|
|
6356
|
+
const roundBadge = this.totalRounds > 0 ? chalk8.dim(` [${this.round}/${this.totalRounds}]`) : "";
|
|
6357
|
+
console.log(PREFIX + icon + chalk8.white(call.name) + roundBadge);
|
|
6038
6358
|
for (const [key, val] of Object.entries(call.arguments)) {
|
|
6039
6359
|
let valStr;
|
|
6040
6360
|
if (Array.isArray(val)) {
|
|
@@ -6045,22 +6365,22 @@ var SubAgentExecutor = class {
|
|
|
6045
6365
|
} else {
|
|
6046
6366
|
valStr = String(val);
|
|
6047
6367
|
}
|
|
6048
|
-
console.log(PREFIX +
|
|
6368
|
+
console.log(PREFIX + chalk8.gray(` ${key}: `) + chalk8.white(valStr));
|
|
6049
6369
|
}
|
|
6050
6370
|
}
|
|
6051
6371
|
printToolResult(name, content, isError, wasTruncated) {
|
|
6052
6372
|
if (isError) {
|
|
6053
6373
|
console.log(
|
|
6054
|
-
PREFIX +
|
|
6374
|
+
PREFIX + chalk8.red(`\u26A0 ${name} error: `) + chalk8.gray(content.slice(0, 300))
|
|
6055
6375
|
);
|
|
6056
6376
|
} else {
|
|
6057
6377
|
const lines = content.split("\n");
|
|
6058
6378
|
const maxLines = name === "run_interactive" ? 40 : 8;
|
|
6059
6379
|
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 +
|
|
6380
|
+
const prefixedPreview = preview.map((l) => PREFIX + " " + chalk8.gray(l)).join("\n");
|
|
6381
|
+
const moreLines = lines.length > maxLines ? "\n" + PREFIX + chalk8.gray(` ... (${lines.length - maxLines} more lines)`) : "";
|
|
6382
|
+
const truncNote = wasTruncated ? "\n" + PREFIX + chalk8.yellow(` \u26A1 \u8F93\u51FA\u5DF2\u622A\u65AD\u81F3 ${MAX_TOOL_OUTPUT_CHARS} \u5B57\u7B26`) : "";
|
|
6383
|
+
console.log(PREFIX + chalk8.green("\u2713 Result:"));
|
|
6064
6384
|
console.log(prefixedPreview + moreLines + truncNote);
|
|
6065
6385
|
}
|
|
6066
6386
|
}
|
|
@@ -6090,25 +6410,25 @@ ${task}
|
|
|
6090
6410
|
}
|
|
6091
6411
|
function printSubAgentHeader(task, maxRounds) {
|
|
6092
6412
|
console.log();
|
|
6093
|
-
console.log(
|
|
6094
|
-
console.log(PREFIX +
|
|
6413
|
+
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"));
|
|
6414
|
+
console.log(PREFIX + chalk8.bold.magenta("\u{1F916} Sub-Agent Spawned"));
|
|
6095
6415
|
console.log(
|
|
6096
|
-
PREFIX +
|
|
6416
|
+
PREFIX + chalk8.gray("Task: ") + chalk8.white(task.slice(0, 120) + (task.length > 120 ? "..." : ""))
|
|
6097
6417
|
);
|
|
6098
|
-
console.log(PREFIX +
|
|
6099
|
-
console.log(
|
|
6418
|
+
console.log(PREFIX + chalk8.gray(`Max rounds: ${maxRounds}`));
|
|
6419
|
+
console.log(chalk8.dim(" \u2503"));
|
|
6100
6420
|
}
|
|
6101
6421
|
function printSubAgentFooter(usage) {
|
|
6102
6422
|
console.log(PREFIX);
|
|
6103
|
-
console.log(PREFIX +
|
|
6423
|
+
console.log(PREFIX + chalk8.bold.magenta("Sub-Agent Complete"));
|
|
6104
6424
|
if (usage.inputTokens > 0 || usage.outputTokens > 0) {
|
|
6105
6425
|
console.log(
|
|
6106
|
-
PREFIX +
|
|
6426
|
+
PREFIX + chalk8.dim(
|
|
6107
6427
|
`Tokens: ${usage.inputTokens} in / ${usage.outputTokens} out`
|
|
6108
6428
|
)
|
|
6109
6429
|
);
|
|
6110
6430
|
}
|
|
6111
|
-
console.log(
|
|
6431
|
+
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
6432
|
console.log();
|
|
6113
6433
|
}
|
|
6114
6434
|
var spawnAgentTool = {
|
|
@@ -6357,159 +6677,6 @@ var ToolRegistry = class {
|
|
|
6357
6677
|
import chalk9 from "chalk";
|
|
6358
6678
|
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
6359
6679
|
|
|
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
6680
|
// src/tools/hooks.ts
|
|
6514
6681
|
import { execSync as execSync5 } from "child_process";
|
|
6515
6682
|
function runHook(template, vars) {
|
|
@@ -9435,7 +9602,16 @@ Session '${this.resumeSessionId}' not found.
|
|
|
9435
9602
|
if ("content" in result) {
|
|
9436
9603
|
spinner.stop();
|
|
9437
9604
|
const finalContent = result.content;
|
|
9438
|
-
|
|
9605
|
+
if (useStreaming) {
|
|
9606
|
+
const streamAc = this.setupStreamInterrupt();
|
|
9607
|
+
try {
|
|
9608
|
+
await this.renderer.renderContentAsStream(finalContent, { signal: streamAc.signal });
|
|
9609
|
+
} finally {
|
|
9610
|
+
this.teardownStreamInterrupt();
|
|
9611
|
+
}
|
|
9612
|
+
} else {
|
|
9613
|
+
this.renderer.renderResponse(finalContent);
|
|
9614
|
+
}
|
|
9439
9615
|
lastResponseStore.content = finalContent;
|
|
9440
9616
|
session.addMessage({
|
|
9441
9617
|
role: "assistant",
|