jinzd-ai-cli 0.1.44 → 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
|
|
@@ -942,11 +975,21 @@ var OpenAICompatibleProvider = class extends BaseProvider {
|
|
|
942
975
|
if (options?.timeout !== void 0) {
|
|
943
976
|
this.defaultTimeout = options.timeout;
|
|
944
977
|
}
|
|
945
|
-
|
|
978
|
+
const clientOptions = {
|
|
946
979
|
apiKey,
|
|
947
980
|
baseURL: options?.baseUrl ?? this.defaultBaseUrl,
|
|
948
981
|
timeout: this.defaultTimeout
|
|
949
|
-
}
|
|
982
|
+
};
|
|
983
|
+
const proxyUrl = options?.proxy;
|
|
984
|
+
if (proxyUrl) {
|
|
985
|
+
try {
|
|
986
|
+
const { ProxyAgent, fetch: undiciFetch } = await import("undici");
|
|
987
|
+
const agent = new ProxyAgent({ uri: proxyUrl });
|
|
988
|
+
clientOptions.fetch = ((url, init) => undiciFetch(url, { ...init, dispatcher: agent }));
|
|
989
|
+
} catch {
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
this.client = new OpenAI(clientOptions);
|
|
950
993
|
}
|
|
951
994
|
/** 将 systemPrompt + messages 合并为 OpenAI messages 数组(system 消息放首位)。 */
|
|
952
995
|
buildMessages(request) {
|
|
@@ -2183,12 +2226,12 @@ var Renderer = class {
|
|
|
2183
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"));
|
|
2184
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"));
|
|
2185
2228
|
console.log(HR);
|
|
2186
|
-
console.log(theme.dim(" REPL \u547D\u4EE4\
|
|
2229
|
+
console.log(theme.dim(" REPL \u547D\u4EE4\uFF0834\u4E2A\uFF09\uFF1A"));
|
|
2187
2230
|
console.log(theme.dim(" /help /about /provider /model /clear /compact /plan /session"));
|
|
2188
2231
|
console.log(theme.dim(" /system /context /status /search /undo /export /copy /cost"));
|
|
2189
2232
|
console.log(theme.dim(" /init /skill /tools /plugins /mcp /config /checkpoint /review"));
|
|
2190
2233
|
console.log(theme.dim(" /commands /test /scaffold /add-dir /memory /doctor /bug /think"));
|
|
2191
|
-
console.log(theme.dim(" /exit"));
|
|
2234
|
+
console.log(theme.dim(" /diff /exit"));
|
|
2192
2235
|
console.log(HR);
|
|
2193
2236
|
console.log(theme.dim(" \u4E3B\u8981\u7279\u6027\uFF1A"));
|
|
2194
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"));
|
|
@@ -2235,6 +2278,9 @@ var Renderer = class {
|
|
|
2235
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"));
|
|
2236
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"));
|
|
2237
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"));
|
|
2238
2284
|
console.log();
|
|
2239
2285
|
}
|
|
2240
2286
|
printPrompt(provider, _model) {
|
|
@@ -2361,6 +2407,40 @@ var Renderer = class {
|
|
|
2361
2407
|
process.stdout.write(finalOutput);
|
|
2362
2408
|
process.stdout.write("\n\n");
|
|
2363
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
|
+
}
|
|
2364
2444
|
renderError(err) {
|
|
2365
2445
|
const message = err instanceof Error ? err.message : String(err);
|
|
2366
2446
|
console.error(theme.error(`
|
|
@@ -2417,7 +2497,7 @@ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as
|
|
|
2417
2497
|
import { execSync as execSync3 } from "child_process";
|
|
2418
2498
|
import { platform } from "os";
|
|
2419
2499
|
import { resolve, dirname as dirname2, join as join5, basename } from "path";
|
|
2420
|
-
import
|
|
2500
|
+
import chalk4 from "chalk";
|
|
2421
2501
|
|
|
2422
2502
|
// src/tools/git-context.ts
|
|
2423
2503
|
import { execSync } from "child_process";
|
|
@@ -2572,6 +2652,10 @@ var UndoStack = class {
|
|
|
2572
2652
|
get depth() {
|
|
2573
2653
|
return this.stack.length;
|
|
2574
2654
|
}
|
|
2655
|
+
/** 返回栈的拷贝(所有文件修改记录),供 /diff 命令使用 */
|
|
2656
|
+
getHistory() {
|
|
2657
|
+
return [...this.stack];
|
|
2658
|
+
}
|
|
2575
2659
|
/** 清空撤销栈(新会话时调用) */
|
|
2576
2660
|
clear() {
|
|
2577
2661
|
this.stack = [];
|
|
@@ -2579,6 +2663,159 @@ var UndoStack = class {
|
|
|
2579
2663
|
};
|
|
2580
2664
|
var undoStack = new UndoStack();
|
|
2581
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
|
+
|
|
2582
2819
|
// src/repl/clipboard.ts
|
|
2583
2820
|
import { execSync as execSync2 } from "child_process";
|
|
2584
2821
|
import { existsSync as existsSync5, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
@@ -2929,7 +3166,7 @@ function createDefaultCommands() {
|
|
|
2929
3166
|
" /tools - List all AI tools available",
|
|
2930
3167
|
" /plugins - Show plugin directory and loaded plugins",
|
|
2931
3168
|
" /mcp [reconnect [id]] - Show MCP servers / reconnect disconnected",
|
|
2932
|
-
" /config
|
|
3169
|
+
" /config [set|get|show] - Config wizard, or get/set values, show all",
|
|
2933
3170
|
" /copy - Copy last AI response to clipboard",
|
|
2934
3171
|
" /cost [reset] - Show session token usage (or reset counters)",
|
|
2935
3172
|
" /init [--force] - Generate AICLI.md by scanning project structure",
|
|
@@ -2943,6 +3180,7 @@ function createDefaultCommands() {
|
|
|
2943
3180
|
" /memory [show|add|clear] - View or edit persistent memory (memory.md)",
|
|
2944
3181
|
" /doctor - Health check (API keys, config, MCP status)",
|
|
2945
3182
|
" /bug [--copy] - Generate bug report template (--copy to clipboard)",
|
|
3183
|
+
" /diff [--stats] - Show all file modifications in this session",
|
|
2946
3184
|
" /exit - Exit"
|
|
2947
3185
|
] : [];
|
|
2948
3186
|
console.log("\nAvailable commands:");
|
|
@@ -3458,10 +3696,45 @@ ${text}
|
|
|
3458
3696
|
},
|
|
3459
3697
|
{
|
|
3460
3698
|
name: "config",
|
|
3461
|
-
description: "
|
|
3462
|
-
usage: "/config",
|
|
3463
|
-
async execute(
|
|
3464
|
-
|
|
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]"));
|
|
3465
3738
|
}
|
|
3466
3739
|
},
|
|
3467
3740
|
{
|
|
@@ -3727,9 +4000,9 @@ ${hint}` : "")
|
|
|
3727
4000
|
console.log();
|
|
3728
4001
|
console.log(theme.heading(" \u{1F4CA} Session Token Usage"));
|
|
3729
4002
|
console.log(theme.dim(" " + "\u2500".repeat(40)));
|
|
3730
|
-
console.log(theme.dim(" Input tokens : ") +
|
|
3731
|
-
console.log(theme.dim(" Output tokens : ") +
|
|
3732
|
-
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()));
|
|
3733
4006
|
console.log(theme.dim(" " + "\u2500".repeat(40)));
|
|
3734
4007
|
const session = ctx.sessions.current;
|
|
3735
4008
|
if (session) {
|
|
@@ -3888,7 +4161,7 @@ ${hint}` : "")
|
|
|
3888
4161
|
description: "Run project tests and show structured report",
|
|
3889
4162
|
usage: "/test [command|filter]",
|
|
3890
4163
|
async execute(args, _ctx) {
|
|
3891
|
-
const { executeTests } = await import("./run-tests-
|
|
4164
|
+
const { executeTests } = await import("./run-tests-V62QUKVZ.js");
|
|
3892
4165
|
const argStr = args.join(" ").trim();
|
|
3893
4166
|
let testArgs = {};
|
|
3894
4167
|
if (argStr) {
|
|
@@ -3999,7 +4272,7 @@ ${hint}` : "")
|
|
|
3999
4272
|
}
|
|
4000
4273
|
const lines = content.split("\n").length;
|
|
4001
4274
|
console.log(theme.heading("\n\u{1F4DD} Persistent Memory:\n") + theme.dim("\u2500".repeat(60)));
|
|
4002
|
-
console.log(
|
|
4275
|
+
console.log(chalk4.white(content));
|
|
4003
4276
|
console.log(theme.dim("\u2500".repeat(60)));
|
|
4004
4277
|
console.log(theme.dim(` ${content.length} chars \xB7 ${lines} lines
|
|
4005
4278
|
`));
|
|
@@ -4158,6 +4431,63 @@ ${text}
|
|
|
4158
4431
|
}
|
|
4159
4432
|
}
|
|
4160
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
|
+
},
|
|
4161
4491
|
{
|
|
4162
4492
|
name: "exit",
|
|
4163
4493
|
description: "Exit the REPL",
|
|
@@ -4170,7 +4500,7 @@ ${text}
|
|
|
4170
4500
|
}
|
|
4171
4501
|
|
|
4172
4502
|
// src/repl/select-list.ts
|
|
4173
|
-
import
|
|
4503
|
+
import chalk5 from "chalk";
|
|
4174
4504
|
var CLEAR_LINE = "\r\x1B[2K";
|
|
4175
4505
|
var MOVE_UP = (n) => n > 0 ? `\x1B[${n}A` : "";
|
|
4176
4506
|
var IGNORE_ENTER_MS = 80;
|
|
@@ -4195,10 +4525,10 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4195
4525
|
handleSequence(seq);
|
|
4196
4526
|
};
|
|
4197
4527
|
const renderLine = (item, active, absIdx) => {
|
|
4198
|
-
const cursor = active ?
|
|
4199
|
-
const label = active ?
|
|
4200
|
-
const hint = item.hint ?
|
|
4201
|
-
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) + " ");
|
|
4202
4532
|
return cursor + num + label + hint;
|
|
4203
4533
|
};
|
|
4204
4534
|
const render = () => {
|
|
@@ -4207,16 +4537,16 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4207
4537
|
const windowEnd = Math.min(windowStart + PAGE, items.length);
|
|
4208
4538
|
const visible = items.slice(windowStart, windowEnd);
|
|
4209
4539
|
const lines = [];
|
|
4210
|
-
lines.push(
|
|
4540
|
+
lines.push(chalk5.bold(prompt));
|
|
4211
4541
|
if (windowStart > 0)
|
|
4212
|
-
lines.push(
|
|
4542
|
+
lines.push(chalk5.dim(` \u2191 ${windowStart} more above`));
|
|
4213
4543
|
visible.forEach(
|
|
4214
4544
|
(item, i) => lines.push(renderLine(item, windowStart + i === selected, windowStart + i))
|
|
4215
4545
|
);
|
|
4216
4546
|
const below = items.length - windowEnd;
|
|
4217
4547
|
if (below > 0)
|
|
4218
|
-
lines.push(
|
|
4219
|
-
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"));
|
|
4220
4550
|
if (lastRenderedLines > 0) {
|
|
4221
4551
|
process.stdout.write(MOVE_UP(lastRenderedLines) + CLEAR_LINE);
|
|
4222
4552
|
for (let i = 1; i < lastRenderedLines; i++)
|
|
@@ -4249,7 +4579,7 @@ function selectFromList(prompt, items, initialIndex = 0) {
|
|
|
4249
4579
|
process.stdout.write(MOVE_UP(lastRenderedLines - 1));
|
|
4250
4580
|
}
|
|
4251
4581
|
if (result !== null) {
|
|
4252
|
-
process.stdout.write(
|
|
4582
|
+
process.stdout.write(chalk5.dim(` \u2714 ${result}
|
|
4253
4583
|
`));
|
|
4254
4584
|
}
|
|
4255
4585
|
resolve5(result);
|
|
@@ -5670,7 +6000,7 @@ ${content}
|
|
|
5670
6000
|
};
|
|
5671
6001
|
|
|
5672
6002
|
// src/tools/builtin/ask-user.ts
|
|
5673
|
-
import
|
|
6003
|
+
import chalk6 from "chalk";
|
|
5674
6004
|
var askUserContext = {
|
|
5675
6005
|
prompting: false
|
|
5676
6006
|
};
|
|
@@ -5707,8 +6037,8 @@ function promptUser(rl, question) {
|
|
|
5707
6037
|
rl.resume();
|
|
5708
6038
|
askUserContext.prompting = true;
|
|
5709
6039
|
console.log();
|
|
5710
|
-
console.log(
|
|
5711
|
-
process.stdout.write(
|
|
6040
|
+
console.log(chalk6.cyan("\u2753 ") + chalk6.bold(question));
|
|
6041
|
+
process.stdout.write(chalk6.cyan("> "));
|
|
5712
6042
|
return new Promise((resolve5) => {
|
|
5713
6043
|
let completed = false;
|
|
5714
6044
|
const cleanup = (answer) => {
|
|
@@ -5725,7 +6055,7 @@ function promptUser(rl, question) {
|
|
|
5725
6055
|
cleanup(line);
|
|
5726
6056
|
};
|
|
5727
6057
|
askUserContext.cancelFn = () => {
|
|
5728
|
-
process.stdout.write(
|
|
6058
|
+
process.stdout.write(chalk6.gray("\n(cancelled)\n"));
|
|
5729
6059
|
cleanup(null);
|
|
5730
6060
|
};
|
|
5731
6061
|
rl.once("line", onLine);
|
|
@@ -5733,7 +6063,7 @@ function promptUser(rl, question) {
|
|
|
5733
6063
|
}
|
|
5734
6064
|
|
|
5735
6065
|
// src/tools/builtin/write-todos.ts
|
|
5736
|
-
import
|
|
6066
|
+
import chalk7 from "chalk";
|
|
5737
6067
|
var VALID_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
|
|
5738
6068
|
var currentTodos = [];
|
|
5739
6069
|
var writeTodosTool = {
|
|
@@ -5796,25 +6126,25 @@ function renderTodoList(todos) {
|
|
|
5796
6126
|
const total = todos.length;
|
|
5797
6127
|
console.log();
|
|
5798
6128
|
console.log(
|
|
5799
|
-
|
|
6129
|
+
chalk7.bold.cyan("\u{1F4CB} Todo List") + chalk7.dim(` (${completed}/${total} completed)`)
|
|
5800
6130
|
);
|
|
5801
|
-
console.log(
|
|
6131
|
+
console.log(chalk7.dim(" " + "\u2500".repeat(40)));
|
|
5802
6132
|
for (const todo of todos) {
|
|
5803
6133
|
let icon;
|
|
5804
6134
|
let text;
|
|
5805
6135
|
switch (todo.status) {
|
|
5806
6136
|
case "completed":
|
|
5807
|
-
icon =
|
|
5808
|
-
text =
|
|
6137
|
+
icon = chalk7.green(" \u2713 ");
|
|
6138
|
+
text = chalk7.strikethrough.gray(todo.title);
|
|
5809
6139
|
break;
|
|
5810
6140
|
case "in_progress":
|
|
5811
|
-
icon =
|
|
5812
|
-
text =
|
|
6141
|
+
icon = chalk7.yellow(" \u2192 ");
|
|
6142
|
+
text = chalk7.white(todo.title);
|
|
5813
6143
|
break;
|
|
5814
6144
|
case "pending":
|
|
5815
6145
|
default:
|
|
5816
|
-
icon =
|
|
5817
|
-
text =
|
|
6146
|
+
icon = chalk7.gray(" \u25CB ");
|
|
6147
|
+
text = chalk7.gray(todo.title);
|
|
5818
6148
|
break;
|
|
5819
6149
|
}
|
|
5820
6150
|
console.log(icon + text);
|
|
@@ -5940,7 +6270,7 @@ function formatResults(query, data, requested) {
|
|
|
5940
6270
|
}
|
|
5941
6271
|
|
|
5942
6272
|
// src/tools/builtin/spawn-agent.ts
|
|
5943
|
-
import
|
|
6273
|
+
import chalk8 from "chalk";
|
|
5944
6274
|
var spawnAgentContext = {
|
|
5945
6275
|
provider: null,
|
|
5946
6276
|
model: "",
|
|
@@ -5948,7 +6278,7 @@ var spawnAgentContext = {
|
|
|
5948
6278
|
modelParams: {},
|
|
5949
6279
|
configManager: null
|
|
5950
6280
|
};
|
|
5951
|
-
var PREFIX =
|
|
6281
|
+
var PREFIX = chalk8.dim(" \u2503 ");
|
|
5952
6282
|
var MAX_TOOL_OUTPUT_CHARS = 12e3;
|
|
5953
6283
|
function truncateOutput(content, toolName) {
|
|
5954
6284
|
if (content.length <= MAX_TOOL_OUTPUT_CHARS) return content;
|
|
@@ -5986,7 +6316,7 @@ var SubAgentExecutor = class {
|
|
|
5986
6316
|
const dangerLevel = getDangerLevel(call.name, call.arguments);
|
|
5987
6317
|
if (dangerLevel === "destructive") {
|
|
5988
6318
|
this.printPrefixed(
|
|
5989
|
-
|
|
6319
|
+
chalk8.red("\u26A0 BLOCKED: ") + `Destructive operation ${chalk8.bold(call.name)} not allowed in sub-agent`
|
|
5990
6320
|
);
|
|
5991
6321
|
return {
|
|
5992
6322
|
callId: call.id,
|
|
@@ -6022,9 +6352,9 @@ var SubAgentExecutor = class {
|
|
|
6022
6352
|
}
|
|
6023
6353
|
printToolCall(call, dangerLevel) {
|
|
6024
6354
|
console.log(PREFIX);
|
|
6025
|
-
const icon = dangerLevel === "write" ?
|
|
6026
|
-
const roundBadge = this.totalRounds > 0 ?
|
|
6027
|
-
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);
|
|
6028
6358
|
for (const [key, val] of Object.entries(call.arguments)) {
|
|
6029
6359
|
let valStr;
|
|
6030
6360
|
if (Array.isArray(val)) {
|
|
@@ -6035,22 +6365,22 @@ var SubAgentExecutor = class {
|
|
|
6035
6365
|
} else {
|
|
6036
6366
|
valStr = String(val);
|
|
6037
6367
|
}
|
|
6038
|
-
console.log(PREFIX +
|
|
6368
|
+
console.log(PREFIX + chalk8.gray(` ${key}: `) + chalk8.white(valStr));
|
|
6039
6369
|
}
|
|
6040
6370
|
}
|
|
6041
6371
|
printToolResult(name, content, isError, wasTruncated) {
|
|
6042
6372
|
if (isError) {
|
|
6043
6373
|
console.log(
|
|
6044
|
-
PREFIX +
|
|
6374
|
+
PREFIX + chalk8.red(`\u26A0 ${name} error: `) + chalk8.gray(content.slice(0, 300))
|
|
6045
6375
|
);
|
|
6046
6376
|
} else {
|
|
6047
6377
|
const lines = content.split("\n");
|
|
6048
6378
|
const maxLines = name === "run_interactive" ? 40 : 8;
|
|
6049
6379
|
const preview = lines.slice(0, maxLines);
|
|
6050
|
-
const prefixedPreview = preview.map((l) => PREFIX + " " +
|
|
6051
|
-
const moreLines = lines.length > maxLines ? "\n" + PREFIX +
|
|
6052
|
-
const truncNote = wasTruncated ? "\n" + PREFIX +
|
|
6053
|
-
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:"));
|
|
6054
6384
|
console.log(prefixedPreview + moreLines + truncNote);
|
|
6055
6385
|
}
|
|
6056
6386
|
}
|
|
@@ -6080,25 +6410,25 @@ ${task}
|
|
|
6080
6410
|
}
|
|
6081
6411
|
function printSubAgentHeader(task, maxRounds) {
|
|
6082
6412
|
console.log();
|
|
6083
|
-
console.log(
|
|
6084
|
-
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"));
|
|
6085
6415
|
console.log(
|
|
6086
|
-
PREFIX +
|
|
6416
|
+
PREFIX + chalk8.gray("Task: ") + chalk8.white(task.slice(0, 120) + (task.length > 120 ? "..." : ""))
|
|
6087
6417
|
);
|
|
6088
|
-
console.log(PREFIX +
|
|
6089
|
-
console.log(
|
|
6418
|
+
console.log(PREFIX + chalk8.gray(`Max rounds: ${maxRounds}`));
|
|
6419
|
+
console.log(chalk8.dim(" \u2503"));
|
|
6090
6420
|
}
|
|
6091
6421
|
function printSubAgentFooter(usage) {
|
|
6092
6422
|
console.log(PREFIX);
|
|
6093
|
-
console.log(PREFIX +
|
|
6423
|
+
console.log(PREFIX + chalk8.bold.magenta("Sub-Agent Complete"));
|
|
6094
6424
|
if (usage.inputTokens > 0 || usage.outputTokens > 0) {
|
|
6095
6425
|
console.log(
|
|
6096
|
-
PREFIX +
|
|
6426
|
+
PREFIX + chalk8.dim(
|
|
6097
6427
|
`Tokens: ${usage.inputTokens} in / ${usage.outputTokens} out`
|
|
6098
6428
|
)
|
|
6099
6429
|
);
|
|
6100
6430
|
}
|
|
6101
|
-
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"));
|
|
6102
6432
|
console.log();
|
|
6103
6433
|
}
|
|
6104
6434
|
var spawnAgentTool = {
|
|
@@ -6347,159 +6677,6 @@ var ToolRegistry = class {
|
|
|
6347
6677
|
import chalk9 from "chalk";
|
|
6348
6678
|
import { existsSync as existsSync15, readFileSync as readFileSync9 } from "fs";
|
|
6349
6679
|
|
|
6350
|
-
// src/tools/diff-utils.ts
|
|
6351
|
-
import chalk8 from "chalk";
|
|
6352
|
-
function renderDiff(oldText, newText, opts = {}) {
|
|
6353
|
-
const contextLines = opts.contextLines ?? 3;
|
|
6354
|
-
const maxLines = opts.maxLines ?? 120;
|
|
6355
|
-
const filePath = opts.filePath ?? "";
|
|
6356
|
-
const oldLines = oldText.split("\n");
|
|
6357
|
-
const newLines = newText.split("\n");
|
|
6358
|
-
const hunks = computeHunks(oldLines, newLines, contextLines);
|
|
6359
|
-
if (hunks.length === 0) {
|
|
6360
|
-
return chalk8.dim(" (no changes)");
|
|
6361
|
-
}
|
|
6362
|
-
const output = [];
|
|
6363
|
-
if (filePath) {
|
|
6364
|
-
output.push(chalk8.bold.white(`--- ${filePath} (before)`));
|
|
6365
|
-
output.push(chalk8.bold.white(`+++ ${filePath} (after)`));
|
|
6366
|
-
}
|
|
6367
|
-
let totalDisplayed = 0;
|
|
6368
|
-
for (const hunk of hunks) {
|
|
6369
|
-
if (totalDisplayed >= maxLines) {
|
|
6370
|
-
output.push(chalk8.dim(` ... (diff truncated, too many changes)`));
|
|
6371
|
-
break;
|
|
6372
|
-
}
|
|
6373
|
-
output.push(
|
|
6374
|
-
chalk8.cyan(
|
|
6375
|
-
`@@ -${hunk.oldStart + 1},${hunk.oldCount} +${hunk.newStart + 1},${hunk.newCount} @@`
|
|
6376
|
-
)
|
|
6377
|
-
);
|
|
6378
|
-
for (const line of hunk.lines) {
|
|
6379
|
-
if (totalDisplayed >= maxLines) break;
|
|
6380
|
-
totalDisplayed++;
|
|
6381
|
-
if (line.type === "context") {
|
|
6382
|
-
output.push(chalk8.dim(` ${line.text}`));
|
|
6383
|
-
} else if (line.type === "remove") {
|
|
6384
|
-
output.push(chalk8.red(`- ${line.text}`));
|
|
6385
|
-
} else {
|
|
6386
|
-
output.push(chalk8.green(`+ ${line.text}`));
|
|
6387
|
-
}
|
|
6388
|
-
}
|
|
6389
|
-
}
|
|
6390
|
-
return output.join("\n");
|
|
6391
|
-
}
|
|
6392
|
-
function computeHunks(oldLines, newLines, contextLines) {
|
|
6393
|
-
const edits = diffLines(oldLines, newLines);
|
|
6394
|
-
if (edits.every((e) => e.type === "context")) return [];
|
|
6395
|
-
const hunks = [];
|
|
6396
|
-
let i = 0;
|
|
6397
|
-
while (i < edits.length) {
|
|
6398
|
-
if (edits[i].type === "context") {
|
|
6399
|
-
i++;
|
|
6400
|
-
continue;
|
|
6401
|
-
}
|
|
6402
|
-
const start = Math.max(0, i - contextLines);
|
|
6403
|
-
let end = i;
|
|
6404
|
-
while (end < edits.length) {
|
|
6405
|
-
if (edits[end].type !== "context") {
|
|
6406
|
-
end++;
|
|
6407
|
-
} else {
|
|
6408
|
-
let hasMoreChange = false;
|
|
6409
|
-
for (let j = end + 1; j < Math.min(edits.length, end + contextLines * 2 + 1); j++) {
|
|
6410
|
-
if (edits[j].type !== "context") {
|
|
6411
|
-
hasMoreChange = true;
|
|
6412
|
-
break;
|
|
6413
|
-
}
|
|
6414
|
-
}
|
|
6415
|
-
if (hasMoreChange) {
|
|
6416
|
-
end++;
|
|
6417
|
-
} else {
|
|
6418
|
-
break;
|
|
6419
|
-
}
|
|
6420
|
-
}
|
|
6421
|
-
}
|
|
6422
|
-
end = Math.min(edits.length, end + contextLines);
|
|
6423
|
-
const hunkEdits = edits.slice(start, end);
|
|
6424
|
-
let oldStart = 0;
|
|
6425
|
-
let newStart = 0;
|
|
6426
|
-
for (let k = 0; k < start; k++) {
|
|
6427
|
-
if (edits[k].type !== "add") oldStart++;
|
|
6428
|
-
if (edits[k].type !== "remove") newStart++;
|
|
6429
|
-
}
|
|
6430
|
-
let oldCount = 0;
|
|
6431
|
-
let newCount = 0;
|
|
6432
|
-
for (const e of hunkEdits) {
|
|
6433
|
-
if (e.type !== "add") oldCount++;
|
|
6434
|
-
if (e.type !== "remove") newCount++;
|
|
6435
|
-
}
|
|
6436
|
-
hunks.push({
|
|
6437
|
-
oldStart,
|
|
6438
|
-
oldCount,
|
|
6439
|
-
newStart,
|
|
6440
|
-
newCount,
|
|
6441
|
-
lines: hunkEdits.map((e) => ({ type: e.type, text: e.text }))
|
|
6442
|
-
});
|
|
6443
|
-
i = end;
|
|
6444
|
-
}
|
|
6445
|
-
return hunks;
|
|
6446
|
-
}
|
|
6447
|
-
function diffLines(oldLines, newLines) {
|
|
6448
|
-
const n = oldLines.length;
|
|
6449
|
-
const m = newLines.length;
|
|
6450
|
-
if (n * m > 25e4) {
|
|
6451
|
-
return simpleDiff(oldLines, newLines);
|
|
6452
|
-
}
|
|
6453
|
-
const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
6454
|
-
for (let i2 = 1; i2 <= n; i2++) {
|
|
6455
|
-
for (let j2 = 1; j2 <= m; j2++) {
|
|
6456
|
-
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
6457
|
-
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
6458
|
-
} else {
|
|
6459
|
-
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
6460
|
-
}
|
|
6461
|
-
}
|
|
6462
|
-
}
|
|
6463
|
-
const result = [];
|
|
6464
|
-
let i = n;
|
|
6465
|
-
let j = m;
|
|
6466
|
-
while (i > 0 || j > 0) {
|
|
6467
|
-
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
6468
|
-
result.unshift({ type: "context", text: oldLines[i - 1] });
|
|
6469
|
-
i--;
|
|
6470
|
-
j--;
|
|
6471
|
-
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
6472
|
-
result.unshift({ type: "add", text: newLines[j - 1] });
|
|
6473
|
-
j--;
|
|
6474
|
-
} else {
|
|
6475
|
-
result.unshift({ type: "remove", text: oldLines[i - 1] });
|
|
6476
|
-
i--;
|
|
6477
|
-
}
|
|
6478
|
-
}
|
|
6479
|
-
return result;
|
|
6480
|
-
}
|
|
6481
|
-
function simpleDiff(oldLines, newLines) {
|
|
6482
|
-
const result = [];
|
|
6483
|
-
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
6484
|
-
for (let i = 0; i < maxLen; i++) {
|
|
6485
|
-
const o = oldLines[i];
|
|
6486
|
-
const n = newLines[i];
|
|
6487
|
-
if (o !== void 0 && n !== void 0) {
|
|
6488
|
-
if (o === n) {
|
|
6489
|
-
result.push({ type: "context", text: o });
|
|
6490
|
-
} else {
|
|
6491
|
-
result.push({ type: "remove", text: o });
|
|
6492
|
-
result.push({ type: "add", text: n });
|
|
6493
|
-
}
|
|
6494
|
-
} else if (o !== void 0) {
|
|
6495
|
-
result.push({ type: "remove", text: o });
|
|
6496
|
-
} else if (n !== void 0) {
|
|
6497
|
-
result.push({ type: "add", text: n });
|
|
6498
|
-
}
|
|
6499
|
-
}
|
|
6500
|
-
return result;
|
|
6501
|
-
}
|
|
6502
|
-
|
|
6503
6680
|
// src/tools/hooks.ts
|
|
6504
6681
|
import { execSync as execSync5 } from "child_process";
|
|
6505
6682
|
function runHook(template, vars) {
|
|
@@ -9425,7 +9602,16 @@ Session '${this.resumeSessionId}' not found.
|
|
|
9425
9602
|
if ("content" in result) {
|
|
9426
9603
|
spinner.stop();
|
|
9427
9604
|
const finalContent = result.content;
|
|
9428
|
-
|
|
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
|
+
}
|
|
9429
9615
|
lastResponseStore.content = finalContent;
|
|
9430
9616
|
session.addMessage({
|
|
9431
9617
|
role: "assistant",
|
|
@@ -9892,7 +10078,8 @@ async function runHeadless(options) {
|
|
|
9892
10078
|
(id) => config.getApiKey(id),
|
|
9893
10079
|
(id) => ({
|
|
9894
10080
|
baseUrl: config.get("customBaseUrls")[id],
|
|
9895
|
-
timeout: config.get("timeouts")[id]
|
|
10081
|
+
timeout: config.get("timeouts")[id],
|
|
10082
|
+
proxy: config.get("proxy")
|
|
9896
10083
|
}),
|
|
9897
10084
|
config.get("customProviders")
|
|
9898
10085
|
);
|
|
@@ -10030,7 +10217,8 @@ async function startRepl(options) {
|
|
|
10030
10217
|
(id) => config.getApiKey(id),
|
|
10031
10218
|
(id) => ({
|
|
10032
10219
|
baseUrl: config.get("customBaseUrls")[id],
|
|
10033
|
-
timeout: config.get("timeouts")[id]
|
|
10220
|
+
timeout: config.get("timeouts")[id],
|
|
10221
|
+
proxy: config.get("proxy")
|
|
10034
10222
|
}),
|
|
10035
10223
|
config.get("customProviders")
|
|
10036
10224
|
);
|