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.
@@ -8,7 +8,7 @@ import { platform } from "os";
8
8
  import chalk from "chalk";
9
9
 
10
10
  // src/core/constants.ts
11
- var VERSION = "0.1.45";
11
+ var VERSION = "0.1.46";
12
12
  var APP_NAME = "ai-cli";
13
13
  var CONFIG_DIR_NAME = ".aicli";
14
14
  var CONFIG_FILE_NAME = "config.json";
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-ZF62G7VO.js";
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\uFF0833\u4E2A\uFF09\uFF1A"));
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 chalk3 from "chalk";
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 - Open configuration wizard (API keys, proxy, etc.)",
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: "Open configuration wizard (API keys, proxy, default provider)",
3472
- usage: "/config",
3473
- async execute(_args, ctx) {
3474
- await ctx.runSetupWizard();
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 : ") + chalk3.white(usage.inputTokens.toLocaleString()));
3741
- console.log(theme.dim(" Output tokens : ") + chalk3.white(usage.outputTokens.toLocaleString()));
3742
- console.log(theme.dim(" Total tokens : ") + chalk3.bold.white(totalTokens.toLocaleString()));
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-XB4TDIP3.js");
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(chalk3.white(content));
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 chalk4 from "chalk";
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 ? chalk4.cyan("\u276F ") : " ";
4209
- const label = active ? chalk4.cyan(item.label) : item.label;
4210
- const hint = item.hint ? chalk4.dim(" " + item.hint) : "";
4211
- const num = chalk4.dim(String(absIdx + 1).padStart(2) + " ");
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(chalk4.bold(prompt));
4540
+ lines.push(chalk5.bold(prompt));
4221
4541
  if (windowStart > 0)
4222
- lines.push(chalk4.dim(` \u2191 ${windowStart} more above`));
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(chalk4.dim(` \u2193 ${below} more below`));
4229
- lines.push(chalk4.dim(" \u2191\u2193 move \xB7 Enter select \xB7 Esc cancel"));
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(chalk4.dim(` \u2714 ${result}
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 chalk5 from "chalk";
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(chalk5.cyan("\u2753 ") + chalk5.bold(question));
5721
- process.stdout.write(chalk5.cyan("> "));
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(chalk5.gray("\n(cancelled)\n"));
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 chalk6 from "chalk";
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
- chalk6.bold.cyan("\u{1F4CB} Todo List") + chalk6.dim(` (${completed}/${total} completed)`)
6129
+ chalk7.bold.cyan("\u{1F4CB} Todo List") + chalk7.dim(` (${completed}/${total} completed)`)
5810
6130
  );
5811
- console.log(chalk6.dim(" " + "\u2500".repeat(40)));
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 = chalk6.green(" \u2713 ");
5818
- text = chalk6.strikethrough.gray(todo.title);
6137
+ icon = chalk7.green(" \u2713 ");
6138
+ text = chalk7.strikethrough.gray(todo.title);
5819
6139
  break;
5820
6140
  case "in_progress":
5821
- icon = chalk6.yellow(" \u2192 ");
5822
- text = chalk6.white(todo.title);
6141
+ icon = chalk7.yellow(" \u2192 ");
6142
+ text = chalk7.white(todo.title);
5823
6143
  break;
5824
6144
  case "pending":
5825
6145
  default:
5826
- icon = chalk6.gray(" \u25CB ");
5827
- text = chalk6.gray(todo.title);
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 chalk7 from "chalk";
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 = chalk7.dim(" \u2503 ");
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
- chalk7.red("\u26A0 BLOCKED: ") + `Destructive operation ${chalk7.bold(call.name)} not allowed in sub-agent`
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" ? chalk7.yellow("\u270E Tool: ") : chalk7.bold.cyan("\u2699 Tool: ");
6036
- const roundBadge = this.totalRounds > 0 ? chalk7.dim(` [${this.round}/${this.totalRounds}]`) : "";
6037
- console.log(PREFIX + icon + chalk7.white(call.name) + roundBadge);
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 + chalk7.gray(` ${key}: `) + chalk7.white(valStr));
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 + chalk7.red(`\u26A0 ${name} error: `) + chalk7.gray(content.slice(0, 300))
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 + " " + chalk7.gray(l)).join("\n");
6061
- const moreLines = lines.length > maxLines ? "\n" + PREFIX + chalk7.gray(` ... (${lines.length - maxLines} more lines)`) : "";
6062
- const truncNote = wasTruncated ? "\n" + PREFIX + chalk7.yellow(` \u26A1 \u8F93\u51FA\u5DF2\u622A\u65AD\u81F3 ${MAX_TOOL_OUTPUT_CHARS} \u5B57\u7B26`) : "";
6063
- console.log(PREFIX + chalk7.green("\u2713 Result:"));
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(chalk7.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"));
6094
- console.log(PREFIX + chalk7.bold.magenta("\u{1F916} Sub-Agent Spawned"));
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 + chalk7.gray("Task: ") + chalk7.white(task.slice(0, 120) + (task.length > 120 ? "..." : ""))
6416
+ PREFIX + chalk8.gray("Task: ") + chalk8.white(task.slice(0, 120) + (task.length > 120 ? "..." : ""))
6097
6417
  );
6098
- console.log(PREFIX + chalk7.gray(`Max rounds: ${maxRounds}`));
6099
- console.log(chalk7.dim(" \u2503"));
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 + chalk7.bold.magenta("Sub-Agent Complete"));
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 + chalk7.dim(
6426
+ PREFIX + chalk8.dim(
6107
6427
  `Tokens: ${usage.inputTokens} in / ${usage.outputTokens} out`
6108
6428
  )
6109
6429
  );
6110
6430
  }
6111
- console.log(chalk7.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"));
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
- this.renderer.renderResponse(finalContent);
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",
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-ZF62G7VO.js";
5
+ } from "./chunk-LRU55UAO.js";
6
6
  export {
7
7
  executeTests,
8
8
  runTestsTool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.1.45",
3
+ "version": "0.1.46",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",