jinzd-ai-cli 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/dist/index.js +213 -84
  2. package/package.json +11 -7
package/dist/index.js CHANGED
@@ -100,7 +100,7 @@ var EnvLoader = class {
100
100
  };
101
101
 
102
102
  // src/core/constants.ts
103
- var VERSION = "0.1.0";
103
+ var VERSION = "0.1.2";
104
104
  var CONFIG_DIR_NAME = ".aicli";
105
105
  var CONFIG_FILE_NAME = "config.json";
106
106
  var HISTORY_DIR_NAME = "history";
@@ -1188,13 +1188,65 @@ var SessionManager = class {
1188
1188
  }
1189
1189
  return metas.sort((a, b) => b.updated.getTime() - a.updated.getTime());
1190
1190
  }
1191
+ /**
1192
+ * 跨 session 全文搜索。
1193
+ * 遍历所有历史 JSON 文件,逐条匹配消息内容(不区分大小写),
1194
+ * 每个 session 最多返回 3 条匹配片段,全局最多 maxResults 个 session。
1195
+ */
1196
+ searchMessages(query, maxResults = 20) {
1197
+ if (!existsSync2(this.historyDir)) return [];
1198
+ const q = query.toLowerCase();
1199
+ const files = readdirSync(this.historyDir).filter((f) => f.endsWith(".json")).map((f) => join2(this.historyDir, f));
1200
+ const results = [];
1201
+ for (const filePath of files) {
1202
+ if (results.length >= maxResults) break;
1203
+ try {
1204
+ const data = JSON.parse(readFileSync2(filePath, "utf-8"));
1205
+ const messages = data.messages ?? [];
1206
+ const matches = [];
1207
+ for (const msg of messages) {
1208
+ if (matches.length >= 3) break;
1209
+ let text = "";
1210
+ if (typeof msg.content === "string") {
1211
+ text = msg.content;
1212
+ } else if (Array.isArray(msg.content)) {
1213
+ text = msg.content.filter((p) => p.type === "text").map((p) => p.text ?? "").join("");
1214
+ }
1215
+ const lowerText = text.toLowerCase();
1216
+ const idx = lowerText.indexOf(q);
1217
+ if (idx !== -1) {
1218
+ const start = Math.max(0, idx - 30);
1219
+ const end = Math.min(text.length, idx + query.length + 60);
1220
+ const snippet = (start > 0 ? "\u2026" : "") + text.slice(start, end).replace(/\n/g, " ") + (end < text.length ? "\u2026" : "");
1221
+ matches.push({ role: msg.role, snippet });
1222
+ }
1223
+ }
1224
+ if (matches.length > 0) {
1225
+ results.push({
1226
+ sessionMeta: {
1227
+ id: data.id,
1228
+ provider: data.provider,
1229
+ model: data.model,
1230
+ messageCount: messages.length,
1231
+ created: new Date(data.created),
1232
+ updated: new Date(data.updated),
1233
+ title: data.title
1234
+ },
1235
+ matches
1236
+ });
1237
+ }
1238
+ } catch {
1239
+ }
1240
+ }
1241
+ return results.sort((a, b) => b.sessionMeta.updated.getTime() - a.sessionMeta.updated.getTime());
1242
+ }
1191
1243
  };
1192
1244
 
1193
1245
  // src/repl/repl.ts
1194
1246
  import * as readline from "readline";
1195
1247
  import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
1196
1248
  import { join as join7, resolve as resolve3, extname as extname2 } from "path";
1197
- import chalk5 from "chalk";
1249
+ import chalk6 from "chalk";
1198
1250
 
1199
1251
  // src/repl/renderer.ts
1200
1252
  import chalk from "chalk";
@@ -1258,21 +1310,49 @@ var Renderer = class {
1258
1310
  console.log();
1259
1311
  }
1260
1312
  printAbout() {
1313
+ const HR = chalk.dim(" " + "\u2500".repeat(56));
1314
+ const label = (s) => chalk.gray(` ${s.padEnd(6)}`);
1315
+ const tool = (name, desc) => chalk.cyan(` ${name.padEnd(22)}`) + chalk.dim(desc);
1316
+ const feat = (s) => chalk.dim(" \u2726 ") + chalk.white(s);
1261
1317
  console.log();
1262
- console.log(chalk.bold.cyan(" \u{1F916} ai-cli") + chalk.gray(` v${VERSION}`));
1263
- console.log(chalk.dim(" " + "\u2500".repeat(50)));
1264
- console.log(chalk.gray(" \u7B80\u4ECB ") + chalk.white(DESCRIPTION));
1265
- console.log(chalk.dim(" " + "\u2500".repeat(50)));
1266
- console.log(chalk.gray(" \u4F5C\u8005 ") + chalk.yellow(AUTHOR));
1267
- console.log(chalk.gray(" \u90AE\u7BB1 ") + chalk.cyan(AUTHOR_EMAIL));
1268
- console.log(chalk.dim(" " + "\u2500".repeat(50)));
1269
- console.log(chalk.gray(" \u652F\u6301\u7684 Provider\uFF1A"));
1318
+ console.log(
1319
+ chalk.bold.cyan(" \u{1F916} ai-cli") + chalk.gray(` v${VERSION}`) + chalk.dim(" \u2014 \u8DE8\u5E73\u53F0 REPL \u98CE\u683C AI \u5BF9\u8BDD\u5DE5\u5177")
1320
+ );
1321
+ console.log(HR);
1322
+ console.log(label("\u63CF\u8FF0") + chalk.white(DESCRIPTION));
1323
+ console.log(label("\u4F5C\u8005") + chalk.yellow(AUTHOR) + chalk.dim(" <" + AUTHOR_EMAIL + ">"));
1324
+ console.log(HR);
1325
+ console.log(chalk.gray(" \u652F\u6301\u7684 Provider\uFF086\u4E2A\uFF09\uFF1A"));
1270
1326
  console.log(chalk.dim(" DeepSeek \xB7 Kimi (Moonshot) \xB7 Claude (Anthropic)"));
1271
1327
  console.log(chalk.dim(" Gemini (Google) \xB7 \u667A\u8C31\u6E05\u8A00 \xB7 \u81EA\u5B9A\u4E49 OpenAI \u517C\u5BB9"));
1272
- console.log(chalk.dim(" " + "\u2500".repeat(50)));
1273
- console.log(chalk.gray(" \u5DE5\u5177\u80FD\u529B\uFF1A"));
1274
- console.log(chalk.dim(" bash \xB7 read_file \xB7 write_file \xB7 edit_file"));
1275
- console.log(chalk.dim(" grep_files \xB7 list_dir \xB7 run_interactive"));
1328
+ console.log(HR);
1329
+ console.log(chalk.gray(" Agentic \u5DE5\u5177\uFF0810\u4E2A\uFF09\uFF1A"));
1330
+ console.log(tool("bash", "\u6267\u884C Shell \u547D\u4EE4\uFF08PowerShell/bash\uFF0CWindows \u5F3A\u5236 UTF-8\uFF09"));
1331
+ console.log(tool("read_file", "\u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9"));
1332
+ console.log(tool("write_file", "\u5199\u5165\u6587\u4EF6\uFF08\u5371\u9669\u7EA7 write\uFF0C\u9700\u786E\u8BA4\uFF09"));
1333
+ console.log(tool("edit_file", "\u7CBE\u786E\u5B57\u7B26\u4E32\u66FF\u6362\u7F16\u8F91\u6587\u4EF6\uFF08\u9700\u786E\u8BA4\uFF09"));
1334
+ console.log(tool("list_dir", "\u5217\u51FA\u76EE\u5F55\u5185\u5BB9"));
1335
+ console.log(tool("grep_files", "\u6B63\u5219\u641C\u7D22\u6587\u4EF6\u5185\u5BB9"));
1336
+ console.log(tool("glob_files", "\u6309 glob \u6A21\u5F0F\u5339\u914D\u6587\u4EF6\u8DEF\u5F84"));
1337
+ console.log(tool("run_interactive", "\u8FD0\u884C\u9700\u8981 stdin \u4EA4\u4E92\u7684\u7A0B\u5E8F\uFF08spawn \u76F4\u8FDE\uFF09"));
1338
+ console.log(tool("web_fetch", "\u6293\u53D6\u7F51\u9875\u5185\u5BB9\uFF08\u8F6C Markdown\uFF09"));
1339
+ console.log(tool("save_last_response", "\u4FDD\u5B58 AI \u56DE\u7B54\u5230\u6587\u4EF6\uFF08tee \u6D41\u5F0F\u5199\u76D8\uFF09"));
1340
+ console.log(HR);
1341
+ console.log(chalk.gray(" REPL \u547D\u4EE4\uFF0814\u4E2A\uFF09\uFF1A"));
1342
+ console.log(chalk.dim(" /help /about /provider /model /clear /session"));
1343
+ console.log(chalk.dim(" /system /context /status /search /undo /export"));
1344
+ console.log(chalk.dim(" /tools /exit"));
1345
+ console.log(HR);
1346
+ console.log(chalk.gray(" \u4E3B\u8981\u7279\u6027\uFF1A"));
1347
+ console.log(feat("Agentic \u5FAA\u73AF\uFF08\u6700\u591A 20 \u8F6E\u5DE5\u5177\u8C03\u7528\uFF0C\u6700\u7EC8\u56DE\u7B54\u6D41\u5F0F\u8F93\u51FA\uFF09"));
1348
+ console.log(feat("\u591A\u6A21\u6001\u8F93\u5165\uFF1A@\u6587\u4EF6\u8DEF\u5F84 \u5185\u8054\u56FE\u7247\uFF08base64\uFF09\u6216\u6587\u672C\u5230\u6D88\u606F"));
1349
+ console.log(feat("Git \u4E0A\u4E0B\u6587\u611F\u77E5\uFF1A\u542F\u52A8\u81EA\u52A8\u6CE8\u5165\u5206\u652F\u540D\u4E0E\u6587\u4EF6\u53D8\u66F4\u72B6\u6001"));
1350
+ console.log(feat("\u9879\u76EE\u4E0A\u4E0B\u6587\u6587\u4EF6\uFF1A\u81EA\u52A8\u52A0\u8F7D AICLI.md / CLAUDE.md"));
1351
+ console.log(feat("\u8DE8 session \u5386\u53F2\u5168\u6587\u641C\u7D22\uFF08/search <\u5173\u952E\u8BCD>\uFF09"));
1352
+ console.log(feat("\u6587\u4EF6\u64CD\u4F5C\u64A4\u9500\uFF08/undo\uFF0C\u652F\u6301 write_file / edit_file\uFF09"));
1353
+ console.log(feat("Thinking \u6A21\u5F0F\u6298\u53E0\uFF08<think> \u5757\u81EA\u52A8\u6298\u53E0\uFF0CGLM-5 \u7B49\uFF09"));
1354
+ console.log(feat("Token \u7528\u91CF\u8FFD\u8E2A\uFF08\u6BCF\u6B21\u56DE\u590D + session \u7D2F\u8BA1\uFF09"));
1355
+ console.log(feat("\u72EC\u7ACB\u53EF\u6267\u884C\u6587\u4EF6\u6253\u5305\uFF08~56MB\uFF0C\u65E0\u9700 Node.js \u73AF\u5883\uFF09"));
1276
1356
  console.log();
1277
1357
  }
1278
1358
  printPrompt(provider, _model) {
@@ -1416,6 +1496,7 @@ Error: ${message}
1416
1496
  // src/repl/commands/index.ts
1417
1497
  import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
1418
1498
  import { resolve, dirname as dirname2 } from "path";
1499
+ import chalk2 from "chalk";
1419
1500
 
1420
1501
  // src/tools/undo-stack.ts
1421
1502
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, unlinkSync, existsSync as existsSync3 } from "fs";
@@ -1524,6 +1605,7 @@ function createDefaultCommands() {
1524
1605
  " /system <prompt> - Set system prompt",
1525
1606
  " /context - Show or reload project context file",
1526
1607
  " /status - Show current status",
1608
+ " /search <keyword> - Search across all session histories",
1527
1609
  " /undo - Undo the last file write/edit operation",
1528
1610
  " /export [md|json] [file] - Export session to file (default: auto-named .md)",
1529
1611
  " /tools - List all AI tools available",
@@ -1849,6 +1931,40 @@ ${text}
1849
1931
  console.log();
1850
1932
  }
1851
1933
  },
1934
+ {
1935
+ name: "search",
1936
+ description: "Search across all session histories",
1937
+ usage: "/search <keyword>",
1938
+ execute(args, ctx) {
1939
+ const query = args.join(" ").trim();
1940
+ if (!query) {
1941
+ ctx.renderer.renderError("Usage: /search <keyword>");
1942
+ return;
1943
+ }
1944
+ const results = ctx.sessions.searchMessages(query);
1945
+ if (results.length === 0) {
1946
+ ctx.renderer.printInfo(`No sessions found containing "${query}".`);
1947
+ return;
1948
+ }
1949
+ console.log(`
1950
+ ${chalk2.bold(`Found ${results.length} session(s) containing "${query}"`)}
1951
+ `);
1952
+ for (const r of results) {
1953
+ const { sessionMeta, matches } = r;
1954
+ const dateStr = sessionMeta.updated.toLocaleDateString();
1955
+ console.log(
1956
+ ` ${chalk2.cyan(sessionMeta.id.slice(0, 8))}` + chalk2.dim(` [${dateStr}] ${sessionMeta.provider} / ${sessionMeta.model}`) + (sessionMeta.title ? `
1957
+ ${chalk2.dim(" " + sessionMeta.title)}` : "")
1958
+ );
1959
+ for (const m of matches) {
1960
+ const icon = m.role === "user" ? "\u{1F464}" : "\u{1F916}";
1961
+ console.log(` ${icon} ${chalk2.yellow(m.snippet)}`);
1962
+ }
1963
+ console.log();
1964
+ }
1965
+ console.log(chalk2.dim(" Use /session load <id> to resume a session.\n"));
1966
+ }
1967
+ },
1852
1968
  {
1853
1969
  name: "undo",
1854
1970
  description: "Undo the last file write or edit operation",
@@ -1883,7 +1999,7 @@ ${text}
1883
1999
  }
1884
2000
 
1885
2001
  // src/repl/select-list.ts
1886
- import chalk2 from "chalk";
2002
+ import chalk3 from "chalk";
1887
2003
  var CLEAR_LINE = "\r\x1B[2K";
1888
2004
  var MOVE_UP = (n) => n > 0 ? `\x1B[${n}A` : "";
1889
2005
  var IGNORE_ENTER_MS = 80;
@@ -1908,10 +2024,10 @@ function selectFromList(prompt, items, initialIndex = 0) {
1908
2024
  handleSequence(seq);
1909
2025
  };
1910
2026
  const renderLine = (item, active, absIdx) => {
1911
- const cursor = active ? chalk2.cyan("\u276F ") : " ";
1912
- const label = active ? chalk2.cyan(item.label) : item.label;
1913
- const hint = item.hint ? chalk2.dim(" " + item.hint) : "";
1914
- const num = chalk2.dim(String(absIdx + 1).padStart(2) + " ");
2027
+ const cursor = active ? chalk3.cyan("\u276F ") : " ";
2028
+ const label = active ? chalk3.cyan(item.label) : item.label;
2029
+ const hint = item.hint ? chalk3.dim(" " + item.hint) : "";
2030
+ const num = chalk3.dim(String(absIdx + 1).padStart(2) + " ");
1915
2031
  return cursor + num + label + hint;
1916
2032
  };
1917
2033
  const render = () => {
@@ -1920,16 +2036,16 @@ function selectFromList(prompt, items, initialIndex = 0) {
1920
2036
  const windowEnd = Math.min(windowStart + PAGE, items.length);
1921
2037
  const visible = items.slice(windowStart, windowEnd);
1922
2038
  const lines = [];
1923
- lines.push(chalk2.bold(prompt));
2039
+ lines.push(chalk3.bold(prompt));
1924
2040
  if (windowStart > 0)
1925
- lines.push(chalk2.dim(` \u2191 ${windowStart} more above`));
2041
+ lines.push(chalk3.dim(` \u2191 ${windowStart} more above`));
1926
2042
  visible.forEach(
1927
2043
  (item, i) => lines.push(renderLine(item, windowStart + i === selected, windowStart + i))
1928
2044
  );
1929
2045
  const below = items.length - windowEnd;
1930
2046
  if (below > 0)
1931
- lines.push(chalk2.dim(` \u2193 ${below} more below`));
1932
- lines.push(chalk2.dim(" \u2191\u2193 move \xB7 Enter select \xB7 Esc cancel"));
2047
+ lines.push(chalk3.dim(` \u2193 ${below} more below`));
2048
+ lines.push(chalk3.dim(" \u2191\u2193 move \xB7 Enter select \xB7 Esc cancel"));
1933
2049
  if (lastRenderedLines > 0) {
1934
2050
  process.stdout.write(MOVE_UP(lastRenderedLines) + CLEAR_LINE);
1935
2051
  for (let i = 1; i < lastRenderedLines; i++)
@@ -1962,7 +2078,7 @@ function selectFromList(prompt, items, initialIndex = 0) {
1962
2078
  process.stdout.write(MOVE_UP(lastRenderedLines - 1));
1963
2079
  }
1964
2080
  if (result !== null) {
1965
- process.stdout.write(chalk2.dim(` \u2714 ${result}
2081
+ process.stdout.write(chalk3.dim(` \u2714 ${result}
1966
2082
  `));
1967
2083
  }
1968
2084
  resolve4(result);
@@ -2794,9 +2910,21 @@ var runInteractiveTool = {
2794
2910
  async execute(args) {
2795
2911
  const executable = String(args["executable"] ?? "").trim();
2796
2912
  const rawArgs = args["args"];
2797
- const cmdArgs = Array.isArray(rawArgs) ? rawArgs.map(String) : typeof rawArgs === "string" && rawArgs.trim() ? [rawArgs.trim()] : [];
2913
+ let argsTypeWarning = "";
2914
+ const cmdArgs = Array.isArray(rawArgs) ? rawArgs.map(String) : typeof rawArgs === "string" && rawArgs.trim() ? (() => {
2915
+ argsTypeWarning = `[Warning] "args" should be an array but got string: ${JSON.stringify(rawArgs)}. Applied fallback.
2916
+ `;
2917
+ process.stderr.write(argsTypeWarning);
2918
+ return [rawArgs.trim()];
2919
+ })() : [];
2798
2920
  const rawStdin = args["stdin_lines"];
2799
- const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String) : typeof rawStdin === "string" && rawStdin.trim() ? rawStdin.split(",").map((s) => s.trim()).filter(Boolean) : [];
2921
+ let stdinTypeWarning = "";
2922
+ const stdinLines = Array.isArray(rawStdin) ? rawStdin.map(String) : typeof rawStdin === "string" && rawStdin.trim() ? (() => {
2923
+ stdinTypeWarning = `[Warning] "stdin_lines" should be an array but got string: ${JSON.stringify(rawStdin.slice(0, 80))}. Applied fallback.
2924
+ `;
2925
+ process.stderr.write(stdinTypeWarning);
2926
+ return rawStdin.split(",").map((s) => s.trim()).filter(Boolean);
2927
+ })() : [];
2800
2928
  const timeout = Number(args["timeout"] ?? 2e4);
2801
2929
  if (!executable) {
2802
2930
  throw new Error("executable is required");
@@ -2808,6 +2936,7 @@ var runInteractiveTool = {
2808
2936
  PYTHONIOENCODING: "utf-8",
2809
2937
  PYTHONDONTWRITEBYTECODE: "1"
2810
2938
  };
2939
+ const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
2811
2940
  return new Promise((resolve4) => {
2812
2941
  const child = spawn(executable, cmdArgs.map(String), {
2813
2942
  cwd: process.cwd(),
@@ -2838,23 +2967,23 @@ var runInteractiveTool = {
2838
2967
  setTimeout(writeNextLine, 400);
2839
2968
  const timer = setTimeout(() => {
2840
2969
  child.kill();
2841
- resolve4(`[Timeout after ${timeout}ms]
2970
+ resolve4(`${prefixWarnings}[Timeout after ${timeout}ms]
2842
2971
  ${buildOutput(stdout, stderr)}`);
2843
2972
  }, timeout);
2844
2973
  child.on("close", (code) => {
2845
2974
  clearTimeout(timer);
2846
2975
  const output = buildOutput(stdout, stderr);
2847
2976
  if (code !== 0 && code !== null) {
2848
- resolve4(`Exit code ${code}:
2977
+ resolve4(`${prefixWarnings}Exit code ${code}:
2849
2978
  ${output}`);
2850
2979
  } else {
2851
- resolve4(output || "(no output)");
2980
+ resolve4(`${prefixWarnings}${output || "(no output)"}`);
2852
2981
  }
2853
2982
  });
2854
2983
  child.on("error", (err) => {
2855
2984
  clearTimeout(timer);
2856
2985
  resolve4(
2857
- `Failed to start process "${executable}": ${err.message}
2986
+ `${prefixWarnings}Failed to start process "${executable}": ${err.message}
2858
2987
  Hint: On Windows, use the full path to the executable, e.g.:
2859
2988
  C:\\Users\\Jinzd\\anaconda3\\envs\\python312\\python.exe`
2860
2989
  );
@@ -3075,7 +3204,7 @@ var ToolRegistry = class {
3075
3204
  };
3076
3205
 
3077
3206
  // src/tools/executor.ts
3078
- import chalk4 from "chalk";
3207
+ import chalk5 from "chalk";
3079
3208
  import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
3080
3209
 
3081
3210
  // src/tools/types.ts
@@ -3096,7 +3225,7 @@ function getDangerLevel(toolName, args) {
3096
3225
  }
3097
3226
 
3098
3227
  // src/tools/diff-utils.ts
3099
- import chalk3 from "chalk";
3228
+ import chalk4 from "chalk";
3100
3229
  function renderDiff(oldText, newText, opts = {}) {
3101
3230
  const contextLines = opts.contextLines ?? 3;
3102
3231
  const maxLines = opts.maxLines ?? 120;
@@ -3105,21 +3234,21 @@ function renderDiff(oldText, newText, opts = {}) {
3105
3234
  const newLines = newText.split("\n");
3106
3235
  const hunks = computeHunks(oldLines, newLines, contextLines);
3107
3236
  if (hunks.length === 0) {
3108
- return chalk3.dim(" (no changes)");
3237
+ return chalk4.dim(" (no changes)");
3109
3238
  }
3110
3239
  const output = [];
3111
3240
  if (filePath) {
3112
- output.push(chalk3.bold.white(`--- ${filePath} (before)`));
3113
- output.push(chalk3.bold.white(`+++ ${filePath} (after)`));
3241
+ output.push(chalk4.bold.white(`--- ${filePath} (before)`));
3242
+ output.push(chalk4.bold.white(`+++ ${filePath} (after)`));
3114
3243
  }
3115
3244
  let totalDisplayed = 0;
3116
3245
  for (const hunk of hunks) {
3117
3246
  if (totalDisplayed >= maxLines) {
3118
- output.push(chalk3.dim(` ... (diff truncated, too many changes)`));
3247
+ output.push(chalk4.dim(` ... (diff truncated, too many changes)`));
3119
3248
  break;
3120
3249
  }
3121
3250
  output.push(
3122
- chalk3.cyan(
3251
+ chalk4.cyan(
3123
3252
  `@@ -${hunk.oldStart + 1},${hunk.oldCount} +${hunk.newStart + 1},${hunk.newCount} @@`
3124
3253
  )
3125
3254
  );
@@ -3127,11 +3256,11 @@ function renderDiff(oldText, newText, opts = {}) {
3127
3256
  if (totalDisplayed >= maxLines) break;
3128
3257
  totalDisplayed++;
3129
3258
  if (line.type === "context") {
3130
- output.push(chalk3.dim(` ${line.text}`));
3259
+ output.push(chalk4.dim(` ${line.text}`));
3131
3260
  } else if (line.type === "remove") {
3132
- output.push(chalk3.red(`- ${line.text}`));
3261
+ output.push(chalk4.red(`- ${line.text}`));
3133
3262
  } else {
3134
- output.push(chalk3.green(`+ ${line.text}`));
3263
+ output.push(chalk4.green(`+ ${line.text}`));
3135
3264
  }
3136
3265
  }
3137
3266
  }
@@ -3344,9 +3473,9 @@ var ToolExecutor = class {
3344
3473
  printToolCall(call) {
3345
3474
  const dangerLevel = getDangerLevel(call.name, call.arguments);
3346
3475
  console.log();
3347
- const icon = dangerLevel === "write" ? chalk4.yellow("\u270E Tool: ") : chalk4.bold.cyan("\u2699 Tool: ");
3348
- const roundBadge = this.totalRounds > 0 ? chalk4.dim(` [${this.round}/${this.totalRounds}]`) : "";
3349
- console.log(icon + chalk4.white(call.name) + roundBadge);
3476
+ const icon = dangerLevel === "write" ? chalk5.yellow("\u270E Tool: ") : chalk5.bold.cyan("\u2699 Tool: ");
3477
+ const roundBadge = this.totalRounds > 0 ? chalk5.dim(` [${this.round}/${this.totalRounds}]`) : "";
3478
+ console.log(icon + chalk5.white(call.name) + roundBadge);
3350
3479
  for (const [key, val] of Object.entries(call.arguments)) {
3351
3480
  let valStr;
3352
3481
  if (Array.isArray(val)) {
@@ -3357,7 +3486,7 @@ var ToolExecutor = class {
3357
3486
  } else {
3358
3487
  valStr = String(val);
3359
3488
  }
3360
- console.log(chalk4.gray(` ${key}: `) + chalk4.white(valStr));
3489
+ console.log(chalk5.gray(` ${key}: `) + chalk5.white(valStr));
3361
3490
  }
3362
3491
  }
3363
3492
  /**
@@ -3379,19 +3508,19 @@ var ToolExecutor = class {
3379
3508
  return;
3380
3509
  }
3381
3510
  if (oldContent === newContent) {
3382
- console.log(chalk4.dim(" (file content unchanged)"));
3511
+ console.log(chalk5.dim(" (file content unchanged)"));
3383
3512
  return;
3384
3513
  }
3385
3514
  const diff = renderDiff(oldContent, newContent, { filePath, contextLines: 3 });
3386
- console.log(chalk4.dim(" \u2500\u2500 diff preview \u2500\u2500"));
3515
+ console.log(chalk5.dim(" \u2500\u2500 diff preview \u2500\u2500"));
3387
3516
  console.log(diff);
3388
3517
  console.log();
3389
3518
  } else {
3390
3519
  const lines = newContent.split("\n");
3391
- const preview = lines.slice(0, 20).map((l) => chalk4.green(`+ ${l}`)).join("\n");
3392
- const more = lines.length > 20 ? chalk4.dim(`
3520
+ const preview = lines.slice(0, 20).map((l) => chalk5.green(`+ ${l}`)).join("\n");
3521
+ const more = lines.length > 20 ? chalk5.dim(`
3393
3522
  ... (+${lines.length - 20} more lines)`) : "";
3394
- console.log(chalk4.dim(" \u2500\u2500 new file preview \u2500\u2500"));
3523
+ console.log(chalk5.dim(" \u2500\u2500 new file preview \u2500\u2500"));
3395
3524
  console.log(preview + more);
3396
3525
  console.log();
3397
3526
  }
@@ -3406,17 +3535,17 @@ var ToolExecutor = class {
3406
3535
  String(newStr ?? ""),
3407
3536
  { filePath, contextLines: 2 }
3408
3537
  );
3409
- console.log(chalk4.dim(" \u2500\u2500 diff preview \u2500\u2500"));
3538
+ console.log(chalk5.dim(" \u2500\u2500 diff preview \u2500\u2500"));
3410
3539
  console.log(diff);
3411
3540
  console.log();
3412
3541
  } else if (call.arguments["insert_after_line"] !== void 0) {
3413
3542
  const line = Number(call.arguments["insert_after_line"]);
3414
3543
  const insertContent = String(call.arguments["insert_content"] ?? "");
3415
3544
  const insertLines = insertContent.split("\n");
3416
- const preview = insertLines.slice(0, 5).map((l) => chalk4.green(`+ ${l}`)).join("\n");
3417
- const more = insertLines.length > 5 ? chalk4.dim(`
3545
+ const preview = insertLines.slice(0, 5).map((l) => chalk5.green(`+ ${l}`)).join("\n");
3546
+ const more = insertLines.length > 5 ? chalk5.dim(`
3418
3547
  ... (+${insertLines.length - 5} more lines)`) : "";
3419
- console.log(chalk4.dim(` \u2500\u2500 insert after line ${line} \u2500\u2500`));
3548
+ console.log(chalk5.dim(` \u2500\u2500 insert after line ${line} \u2500\u2500`));
3420
3549
  console.log(preview + more);
3421
3550
  console.log();
3422
3551
  } else if (call.arguments["delete_from_line"] !== void 0) {
@@ -3430,10 +3559,10 @@ var ToolExecutor = class {
3430
3559
  }
3431
3560
  const fileLines = fileContent.split("\n");
3432
3561
  const deleted = fileLines.slice(from - 1, to);
3433
- const preview = deleted.slice(0, 5).map((l) => chalk4.red(`- ${l}`)).join("\n");
3434
- const more = deleted.length > 5 ? chalk4.dim(`
3562
+ const preview = deleted.slice(0, 5).map((l) => chalk5.red(`- ${l}`)).join("\n");
3563
+ const more = deleted.length > 5 ? chalk5.dim(`
3435
3564
  ... (-${deleted.length - 5} more lines)`) : "";
3436
- console.log(chalk4.dim(` \u2500\u2500 delete lines ${from}\u2013${to} \u2500\u2500`));
3565
+ console.log(chalk5.dim(` \u2500\u2500 delete lines ${from}\u2013${to} \u2500\u2500`));
3437
3566
  console.log(preview + more);
3438
3567
  console.log();
3439
3568
  }
@@ -3441,27 +3570,27 @@ var ToolExecutor = class {
3441
3570
  }
3442
3571
  printToolResult(name, content, isError, wasTruncated) {
3443
3572
  if (isError) {
3444
- console.log(chalk4.red(`\u26A0 ${name} error: `) + chalk4.gray(content.slice(0, 300)));
3573
+ console.log(chalk5.red(`\u26A0 ${name} error: `) + chalk5.gray(content.slice(0, 300)));
3445
3574
  } else {
3446
3575
  const lines = content.split("\n");
3447
3576
  const maxLines = name === "run_interactive" ? 40 : 8;
3448
3577
  const preview = lines.slice(0, maxLines).join("\n");
3449
- const moreLines = lines.length > maxLines ? chalk4.gray(`
3578
+ const moreLines = lines.length > maxLines ? chalk5.gray(`
3450
3579
  ... (${lines.length - maxLines} more lines)`) : "";
3451
- const truncatedNote = wasTruncated ? chalk4.yellow(`
3580
+ const truncatedNote = wasTruncated ? chalk5.yellow(`
3452
3581
  \u26A1 \u8F93\u51FA\u5DF2\u622A\u65AD\u81F3 ${MAX_TOOL_OUTPUT_CHARS} \u5B57\u7B26\u540E\u8FD4\u56DE\u7ED9 AI`) : "";
3453
- console.log(chalk4.green("\u2713 Result: ") + chalk4.gray(preview) + moreLines + truncatedNote);
3582
+ console.log(chalk5.green("\u2713 Result: ") + chalk5.gray(preview) + moreLines + truncatedNote);
3454
3583
  }
3455
3584
  console.log();
3456
3585
  }
3457
3586
  confirm(call, level) {
3458
- const color = level === "destructive" ? chalk4.red : chalk4.yellow;
3587
+ const color = level === "destructive" ? chalk5.red : chalk5.yellow;
3459
3588
  const label = level === "destructive" ? "\u26A0 DESTRUCTIVE" : "\u270E Write";
3460
3589
  console.log();
3461
- console.log(color(`${label} operation: `) + chalk4.bold(call.name));
3590
+ console.log(color(`${label} operation: `) + chalk5.bold(call.name));
3462
3591
  for (const [key, val] of Object.entries(call.arguments)) {
3463
3592
  const valStr = typeof val === "string" && val.length > 200 ? val.slice(0, 200) + "..." : String(val);
3464
- console.log(chalk4.gray(` ${key}: `) + valStr);
3593
+ console.log(chalk5.gray(` ${key}: `) + valStr);
3465
3594
  }
3466
3595
  if (!this.rl) {
3467
3596
  process.stdout.write(color("No readline: auto-rejected.\n"));
@@ -3485,7 +3614,7 @@ var ToolExecutor = class {
3485
3614
  };
3486
3615
  const onLine = (line) => cleanup(line.trim().toLowerCase());
3487
3616
  this.cancelConfirmFn = () => {
3488
- process.stdout.write(chalk4.gray("\n(cancelled)\n"));
3617
+ process.stdout.write(chalk5.gray("\n(cancelled)\n"));
3489
3618
  cleanup("n");
3490
3619
  };
3491
3620
  rl.once("line", onLine);
@@ -3740,7 +3869,7 @@ ${this.activeSystemPrompt}`;
3740
3869
  return dateTimeInfo;
3741
3870
  }
3742
3871
  refreshPrompt() {
3743
- const promptStr = chalk5.green(`[${this.currentProvider}]`) + chalk5.white(" > ");
3872
+ const promptStr = chalk6.green(`[${this.currentProvider}]`) + chalk6.white(" > ");
3744
3873
  this.rl.setPrompt(promptStr);
3745
3874
  }
3746
3875
  showPrompt() {
@@ -3771,14 +3900,14 @@ ${this.activeSystemPrompt}`;
3771
3900
  this.renderer.printWelcome(this.currentProvider, this.currentModel, welcomeModelInfo?.contextWindow);
3772
3901
  if (ctx) {
3773
3902
  process.stdout.write(
3774
- chalk5.dim(` \u{1F4C4} Project context loaded: ${ctx.filePath} (${ctx.content.length} chars)
3903
+ chalk6.dim(` \u{1F4C4} Project context loaded: ${ctx.filePath} (${ctx.content.length} chars)
3775
3904
  `)
3776
3905
  );
3777
3906
  }
3778
3907
  if (gitCtx) {
3779
- const statusSummary = gitCtx.stagedFiles.length + gitCtx.changedFiles.length > 0 ? chalk5.yellow(` (${gitCtx.stagedFiles.length} staged, ${gitCtx.changedFiles.length} modified)`) : chalk5.dim(" (clean)");
3908
+ const statusSummary = gitCtx.stagedFiles.length + gitCtx.changedFiles.length > 0 ? chalk6.yellow(` (${gitCtx.stagedFiles.length} staged, ${gitCtx.changedFiles.length} modified)`) : chalk6.dim(" (clean)");
3780
3909
  process.stdout.write(
3781
- chalk5.dim(` \u{1F500} Git branch: `) + chalk5.cyan(gitCtx.branch) + statusSummary + "\n"
3910
+ chalk6.dim(` \u{1F500} Git branch: `) + chalk6.cyan(gitCtx.branch) + statusSummary + "\n"
3782
3911
  );
3783
3912
  }
3784
3913
  this.rl.on("SIGINT", () => {
@@ -3839,13 +3968,13 @@ ${this.activeSystemPrompt}`;
3839
3968
  const { parts, hasImage, refs } = parseAtReferences(userInput, process.cwd());
3840
3969
  for (const ref of refs) {
3841
3970
  if (ref.type === "notfound") {
3842
- process.stdout.write(chalk5.yellow(` \u26A0 File not found: ${ref.path}
3971
+ process.stdout.write(chalk6.yellow(` \u26A0 File not found: ${ref.path}
3843
3972
  `));
3844
3973
  } else if (ref.type === "image") {
3845
- process.stdout.write(chalk5.dim(` \u{1F4CE} Image: ${ref.path}
3974
+ process.stdout.write(chalk6.dim(` \u{1F4CE} Image: ${ref.path}
3846
3975
  `));
3847
3976
  } else {
3848
- process.stdout.write(chalk5.dim(` \u{1F4C4} File: ${ref.path}
3977
+ process.stdout.write(chalk6.dim(` \u{1F4C4} File: ${ref.path}
3849
3978
  `));
3850
3979
  }
3851
3980
  }
@@ -3854,13 +3983,13 @@ ${this.activeSystemPrompt}`;
3854
3983
  const visionHint = this.getVisionModelHint();
3855
3984
  if (visionHint) {
3856
3985
  process.stdout.write(
3857
- chalk5.yellow(` \u2716 Vision not supported \u2013 ${visionHint}
3986
+ chalk6.yellow(` \u2716 Vision not supported \u2013 ${visionHint}
3858
3987
  `)
3859
3988
  );
3860
3989
  return;
3861
3990
  }
3862
3991
  process.stdout.write(
3863
- chalk5.dim(` \u{1F5BC} Vision request \u2013 sending image to ${this.currentProvider}
3992
+ chalk6.dim(` \u{1F5BC} Vision request \u2013 sending image to ${this.currentProvider}
3864
3993
  `)
3865
3994
  );
3866
3995
  }
@@ -4171,14 +4300,14 @@ ${this.activeSystemPrompt}`;
4171
4300
  this.events.emit("session.end", { sessionId });
4172
4301
  }
4173
4302
  this.rl.close();
4174
- console.log(chalk5.gray("\nGoodbye!"));
4303
+ console.log(chalk6.gray("\nGoodbye!"));
4175
4304
  process.exit(0);
4176
4305
  }
4177
4306
  };
4178
4307
 
4179
4308
  // src/repl/setup-wizard.ts
4180
4309
  import { password, select } from "@inquirer/prompts";
4181
- import chalk6 from "chalk";
4310
+ import chalk7 from "chalk";
4182
4311
  var PROVIDERS = [
4183
4312
  { value: "claude", name: "Claude (Anthropic)" },
4184
4313
  { value: "gemini", name: "Gemini (Google)" },
@@ -4195,7 +4324,7 @@ var SetupWizard = class {
4195
4324
  this.config = config;
4196
4325
  }
4197
4326
  async runFirstRun() {
4198
- console.log(chalk6.bold.cyan("\nWelcome to ai-cli!\n"));
4327
+ console.log(chalk7.bold.cyan("\nWelcome to ai-cli!\n"));
4199
4328
  console.log("Let's set up your first AI provider.\n");
4200
4329
  try {
4201
4330
  const providerId = await select({
@@ -4205,14 +4334,14 @@ var SetupWizard = class {
4205
4334
  await this.setupProvider(providerId);
4206
4335
  this.config.set("defaultProvider", providerId);
4207
4336
  this.config.save();
4208
- console.log(chalk6.green("\nSetup complete! Starting ai-cli...\n"));
4337
+ console.log(chalk7.green("\nSetup complete! Starting ai-cli...\n"));
4209
4338
  return true;
4210
4339
  } catch {
4211
4340
  return false;
4212
4341
  }
4213
4342
  }
4214
4343
  async runFull() {
4215
- console.log(chalk6.bold.cyan("\nai-cli Configuration\n"));
4344
+ console.log(chalk7.bold.cyan("\nai-cli Configuration\n"));
4216
4345
  let running = true;
4217
4346
  while (running) {
4218
4347
  const action = await select({
@@ -4226,7 +4355,7 @@ var SetupWizard = class {
4226
4355
  if (action === "apikey") {
4227
4356
  const choicesWithStatus = PROVIDERS.map((p) => {
4228
4357
  const existingKey = this.config.getApiKey(p.value);
4229
- const status = existingKey ? chalk6.green(`[${maskKey(existingKey)}]`) : chalk6.gray("[\u672A\u914D\u7F6E]");
4358
+ const status = existingKey ? chalk7.green(`[${maskKey(existingKey)}]`) : chalk7.gray("[\u672A\u914D\u7F6E]");
4230
4359
  return { value: p.value, name: `${p.name} ${status}` };
4231
4360
  });
4232
4361
  const providerId = await select({
@@ -4241,7 +4370,7 @@ var SetupWizard = class {
4241
4370
  });
4242
4371
  this.config.set("defaultProvider", providerId);
4243
4372
  this.config.save();
4244
- console.log(chalk6.green(`Default provider set to: ${providerId}
4373
+ console.log(chalk7.green(`Default provider set to: ${providerId}
4245
4374
  `));
4246
4375
  } else {
4247
4376
  running = false;
@@ -4255,9 +4384,9 @@ var SetupWizard = class {
4255
4384
  console.log(`
4256
4385
  Managing ${displayName} API Key`);
4257
4386
  if (existingKey) {
4258
- console.log(chalk6.gray(` Current: ${maskKey(existingKey)}`));
4387
+ console.log(chalk7.gray(` Current: ${maskKey(existingKey)}`));
4259
4388
  } else {
4260
- console.log(chalk6.gray(" Current: (\u672A\u914D\u7F6E)"));
4389
+ console.log(chalk7.gray(" Current: (\u672A\u914D\u7F6E)"));
4261
4390
  }
4262
4391
  const choices = existingKey ? [
4263
4392
  { value: "keep", name: "\u4FDD\u6301\u4E0D\u53D8 (keep current key)" },
@@ -4269,7 +4398,7 @@ Managing ${displayName} API Key`);
4269
4398
  choices
4270
4399
  });
4271
4400
  if (action === "show" && existingKey) {
4272
- console.log(chalk6.yellow(`
4401
+ console.log(chalk7.yellow(`
4273
4402
  \u5B8C\u6574 Key: ${existingKey}
4274
4403
  `));
4275
4404
  const updateAfterShow = await select({
@@ -4288,7 +4417,7 @@ Managing ${displayName} API Key`);
4288
4417
  validate: (val) => val.length > 0 || "API key cannot be empty"
4289
4418
  });
4290
4419
  this.config.setApiKey(providerId, newKey);
4291
- console.log(chalk6.green(`API key saved for ${displayName}: ${maskKey(newKey)}
4420
+ console.log(chalk7.green(`API key saved for ${displayName}: ${maskKey(newKey)}
4292
4421
  `));
4293
4422
  }
4294
4423
  };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {
8
- "aicli": "./dist/index.js"
8
+ "aicli": "dist/index.js"
9
9
  },
10
10
  "publishConfig": {
11
11
  "access": "public",
@@ -23,16 +23,20 @@
23
23
  "test:watch": "vitest",
24
24
  "lint": "eslint src",
25
25
  "prepublishOnly": "npm run build",
26
- "pack:win": "npm run build && npx pkg dist-cjs/index.cjs --target node22-win-x64 --output release/ai-cli-win.exe --compress GZip --options no-deprecation",
27
- "pack:mac": "npm run build && npx pkg dist-cjs/index.cjs --target node22-macos-arm64 --output release/ai-cli-mac --compress GZip --options no-deprecation",
26
+ "pack:win": "npm run build && npx pkg dist-cjs/index.cjs --target node22-win-x64 --output release/ai-cli-win.exe --compress GZip --options no-deprecation",
27
+ "pack:mac": "npm run build && npx pkg dist-cjs/index.cjs --target node22-macos-arm64 --output release/ai-cli-mac --compress GZip --options no-deprecation",
28
28
  "pack:mac-x64": "npm run build && npx pkg dist-cjs/index.cjs --target node22-macos-x64 --output release/ai-cli-mac-x64 --compress GZip --options no-deprecation",
29
- "pack:linux": "npm run build && npx pkg dist-cjs/index.cjs --target node22-linux-x64 --output release/ai-cli-linux --compress GZip --options no-deprecation",
30
- "pack:all": "npm run build && npx pkg dist-cjs/index.cjs --target node22-win-x64,node22-macos-arm64,node22-linux-x64 --out-path release --compress GZip --options no-deprecation"
29
+ "pack:linux": "npm run build && npx pkg dist-cjs/index.cjs --target node22-linux-x64 --output release/ai-cli-linux --compress GZip --options no-deprecation",
30
+ "pack:all": "npm run build && npx pkg dist-cjs/index.cjs --target node22-win-x64,node22-macos-arm64,node22-linux-x64 --out-path release --compress GZip --options no-deprecation"
31
31
  },
32
32
  "pkg": {
33
33
  "scripts": "dist-cjs/index.cjs",
34
34
  "assets": [],
35
- "targets": ["node22-win-x64", "node22-macos-arm64", "node22-linux-x64"],
35
+ "targets": [
36
+ "node22-win-x64",
37
+ "node22-macos-arm64",
38
+ "node22-linux-x64"
39
+ ],
36
40
  "outputPath": "release",
37
41
  "options": "no-deprecation"
38
42
  },