@aipack-ai/cli 1.1.5 → 1.1.7

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.
@@ -5,7 +5,7 @@ import path from "path";
5
5
  // package.json
6
6
  var package_default = {
7
7
  name: "@aipack-ai/cli",
8
- version: "1.1.5",
8
+ version: "1.1.7",
9
9
  description: "aipack CLI - \u57FA\u4E8E @aipack-ai/agent \u7684\u7EC8\u7AEF AI \u52A9\u624B",
10
10
  type: "module",
11
11
  main: "./dist/index.js",
@@ -69,6 +69,7 @@ function encodeDir(p) {
69
69
  }
70
70
 
71
71
  // src/args.ts
72
+ import chalk from "chalk";
72
73
  var VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "max"];
73
74
  function isValidThinkingLevel(level) {
74
75
  return VALID_THINKING_LEVELS.includes(level);
@@ -169,79 +170,82 @@ function parseArgs(args) {
169
170
  return result;
170
171
  }
171
172
  function printHelp() {
172
- console.log(`${APP_NAME} ${VERSION} - \u57FA\u4E8E @aipack-ai/agent \u7684\u7EC8\u7AEF AI \u52A9\u624B
173
-
174
- ${"\u7528\u6CD5:"}
175
- ${APP_NAME} [\u9009\u9879] [@\u6587\u4EF6...] [\u6D88\u606F...]
176
-
177
- ${"\u5B50\u547D\u4EE4:"}
178
- ${APP_NAME} approvals list \u5217\u51FA\u672A\u51B3\u5BA1\u6279\u5355
179
- ${APP_NAME} approvals approve <id> \u6279\u51C6\u5BA1\u6279\u5355
180
- ${APP_NAME} approvals deny <id> \u9A73\u56DE\u5BA1\u6279\u5355
181
- ${APP_NAME} --list-models [\u641C\u7D22] \u5217\u51FA\u53EF\u7528\u6A21\u578B
182
-
183
- ${"\u6A21\u5F0F:"}
184
- (\u9ED8\u8BA4) \u4EA4\u4E92\u6A21\u5F0F\uFF08REPL\uFF09
185
- --print, -p [\u6D88\u606F] \u975E\u4EA4\u4E92\uFF1A\u5904\u7406\u4E00\u6B21\u63D0\u793A\u540E\u9000\u51FA\uFF08\u652F\u6301\u7BA1\u9053 stdin\uFF09
186
- --mode json \u4EE5 JSON \u884C\u8F93\u51FA\u5168\u90E8\u6D41\u5F0F\u4E8B\u4EF6
187
-
188
- ${"\u6A21\u578B\u9009\u9879:"}
189
- --provider <\u540D\u79F0> \u63D0\u4F9B\u5546\uFF08openai/deepseek/anthropic/google...\uFF09
190
- --model <id> \u6A21\u578B ID\uFF0C\u652F\u6301 provider/id \u7EC4\u5408\u5199\u6CD5
191
- --api-key <key> API Key\uFF08\u8986\u76D6\u73AF\u5883\u53D8\u91CF\uFF09
192
- --thinking <\u7EA7\u522B> \u601D\u8003\u7EA7\u522B: off/minimal/low/medium/high/max
173
+ const c = chalk;
174
+ const title = c.bold.cyan(`${APP_NAME} ${VERSION}`);
175
+ const head = (s) => c.bold.magenta(s);
176
+ const opt = (flag, desc) => ` ${c.green(flag.padEnd(28))} ${c.dim(desc)}`;
177
+ console.log(`${title} ${c.dim("\xB7 \u7EC8\u7AEF AI \u7F16\u7A0B\u52A9\u624B")}
193
178
 
194
- ${"\u4F1A\u8BDD\u9009\u9879:"}
195
- --continue, -c \u7EE7\u7EED\u5F53\u524D\u76EE\u5F55\u6700\u8FD1\u7684\u4F1A\u8BDD
196
- --resume, -r \u6D4F\u89C8\u5E76\u9009\u62E9\u5386\u53F2\u4F1A\u8BDD
197
- --session <\u540D\u79F0> \u4F7F\u7528\u6307\u5B9A\u4F1A\u8BDD
198
- --name, -n <\u540D\u79F0> \u4E3A\u65B0\u4F1A\u8BDD\u547D\u540D
199
- --session-dir <\u76EE\u5F55> \u81EA\u5B9A\u4E49\u4F1A\u8BDD\u5B58\u50A8\u76EE\u5F55
200
- --no-session \u4E34\u65F6\u4F1A\u8BDD\uFF08\u4E0D\u6301\u4E45\u5316\uFF09
179
+ ${head("\u7528\u6CD5:")}
180
+ ${c.cyan(APP_NAME)} ${c.dim("[\u9009\u9879]")} ${c.yellow("[@\u6587\u4EF6...]")} ${c.dim("[\u6D88\u606F...]")}
201
181
 
202
- ${"\u5DE5\u5177\u9009\u9879:"}
203
- --tools, -t <\u5217\u8868> \u5DE5\u5177\u767D\u540D\u5355\uFF08\u9017\u53F7\u5206\u9694\uFF09
204
- --exclude-tools, -xt <\u5217\u8868> \u5DE5\u5177\u9ED1\u540D\u5355\uFF08\u9017\u53F7\u5206\u9694\uFF09
205
- --no-tools, -nt \u7981\u7528\u5168\u90E8\u5DE5\u5177
206
- --safe \u4FDD\u5B88\u6A21\u5F0F\uFF1A\u5199\u6587\u4EF6/shell \u5168\u90E8\u4EBA\u5DE5\u786E\u8BA4
182
+ ${head("\u5B50\u547D\u4EE4:")}
183
+ ${opt("approvals list", "\u5217\u51FA\u672A\u51B3\u5BA1\u6279\u5355")}
184
+ ${opt("approvals approve <id>", "\u6279\u51C6\u5BA1\u6279\u5355")}
185
+ ${opt("approvals deny <id>", "\u9A73\u56DE\u5BA1\u6279\u5355")}
186
+ ${opt("--list-models [\u641C\u7D22]", "\u5217\u51FA\u53EF\u7528\u6A21\u578B\uFF08\u6807\u6CE8 API Key \u914D\u7F6E\u72B6\u6001\uFF09")}
207
187
 
208
- \u5185\u7F6E\u5DE5\u5177: read, write, edit, bash, find, grep, ls
209
- \u9ED8\u8BA4\u6743\u9650: \u8BFB\u5199\u6587\u4EF6\u9759\u9ED8\u653E\u884C\uFF08\u5DE5\u4F5C\u533A\u8303\u56F4\u5185\uFF09\uFF1Bbash \u4EC5\u5371\u9669\u547D\u4EE4
210
- \uFF08sudo\u3001rm -rf ~\u3001\u78C1\u76D8\u5199\u5165\u3001\u8FDC\u7A0B\u811A\u672C\u7BA1\u9053\u7B49\uFF09\u9700\u786E\u8BA4
188
+ ${head("\u6A21\u5F0F:")}
189
+ ${opt("(\u9ED8\u8BA4)", "\u4EA4\u4E92\u6A21\u5F0F\uFF08REPL\uFF09\uFF0C\u652F\u6301\u659C\u6760\u547D\u4EE4\u4E0E\u591A\u884C\u8F93\u5165")}
190
+ ${opt("--print, -p [\u6D88\u606F]", "\u975E\u4EA4\u4E92\uFF1A\u5904\u7406\u4E00\u6B21\u63D0\u793A\u540E\u9000\u51FA\uFF08\u652F\u6301\u7BA1\u9053 stdin\uFF09")}
191
+ ${opt("--mode json", "\u4EE5 JSON \u884C\u8F93\u51FA\u5168\u90E8\u6D41\u5F0F\u4E8B\u4EF6")}
211
192
 
212
- ${"\u5176\u4ED6:"}
213
- --no-compaction \u5173\u95ED\u4E0A\u4E0B\u6587\u538B\u7F29\uFF08\u957F\u4F1A\u8BDD\u53EF\u80FD\u6EA2\u51FA\uFF09
214
- --compaction-config <\u6587\u4EF6> \u538B\u7F29\u914D\u7F6E JSON\uFF08\u8986\u76D6\u9ED8\u8BA4\u9608\u503C\uFF09
215
- --system-prompt <\u6587\u672C> \u66FF\u6362\u9ED8\u8BA4\u7CFB\u7EDF\u63D0\u793A\u8BCD
216
- --append-system-prompt <\u6587\u672C> \u8FFD\u52A0\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u53EF\u591A\u6B21\uFF09
217
- --help, -h \u663E\u793A\u5E2E\u52A9
218
- --version, -v \u663E\u793A\u7248\u672C
193
+ ${head("\u6A21\u578B\u9009\u9879:")}
194
+ ${opt("--provider <\u540D\u79F0>", "\u63D0\u4F9B\u5546\uFF08openai/deepseek/anthropic/google...\uFF09")}
195
+ ${opt("--model <id>", "\u6A21\u578B ID\uFF0C\u652F\u6301 provider/id \u7EC4\u5408\u5199\u6CD5")}
196
+ ${opt("--api-key <key>", "API Key\uFF08\u8986\u76D6\u73AF\u5883\u53D8\u91CF\uFF09")}
197
+ ${opt("--thinking <\u7EA7\u522B>", "\u601D\u8003\u7EA7\u522B: off/minimal/low/medium/high/max")}
219
198
 
220
- ${"\u793A\u4F8B:"}
221
- # \u4EA4\u4E92\u6A21\u5F0F
222
- ${APP_NAME}
199
+ ${head("\u4F1A\u8BDD\u9009\u9879:")}
200
+ ${opt("--continue, -c", "\u7EE7\u7EED\u5F53\u524D\u76EE\u5F55\u6700\u8FD1\u7684\u4F1A\u8BDD")}
201
+ ${opt("--resume, -r", "\u6D4F\u89C8\u5E76\u9009\u62E9\u5386\u53F2\u4F1A\u8BDD")}
202
+ ${opt("--session <\u540D\u79F0>", "\u4F7F\u7528\u6307\u5B9A\u4F1A\u8BDD")}
203
+ ${opt("--name, -n <\u540D\u79F0>", "\u4E3A\u65B0\u4F1A\u8BDD\u547D\u540D")}
204
+ ${opt("--session-dir <\u76EE\u5F55>", "\u81EA\u5B9A\u4E49\u4F1A\u8BDD\u5B58\u50A8\u76EE\u5F55")}
205
+ ${opt("--no-session", "\u4E34\u65F6\u4F1A\u8BDD\uFF08\u4E0D\u6301\u4E45\u5316\uFF09")}
223
206
 
224
- # \u975E\u4EA4\u4E92\u5355\u6B21\u63D0\u95EE\uFF08\u652F\u6301\u7BA1\u9053\uFF09
225
- cat README.md | ${APP_NAME} -p "\u603B\u7ED3\u8FD9\u6BB5\u6587\u672C"
207
+ ${head("\u5DE5\u5177\u4E0E\u6743\u9650:")}
208
+ ${opt("--tools, -t <\u5217\u8868>", "\u5DE5\u5177\u767D\u540D\u5355\uFF08\u9017\u53F7\u5206\u9694\uFF09")}
209
+ ${opt("--exclude-tools, -xt <\u5217\u8868>", "\u5DE5\u5177\u9ED1\u540D\u5355\uFF08\u9017\u53F7\u5206\u9694\uFF09")}
210
+ ${opt("--no-tools, -nt", "\u7981\u7528\u5168\u90E8\u5DE5\u5177")}
211
+ ${opt("--safe", "\u4FDD\u5B88\u6A21\u5F0F\uFF1A\u5199\u6587\u4EF6/shell \u5168\u90E8\u4EBA\u5DE5\u786E\u8BA4")}
226
212
 
227
- # \u6307\u5B9A\u6A21\u578B
228
- ${APP_NAME} --provider deepseek --model deepseek-chat "\u4F60\u597D"
213
+ ${c.dim("\u5185\u7F6E\u5DE5\u5177:")} read \xB7 write \xB7 edit \xB7 bash \xB7 find \xB7 grep \xB7 ls
214
+ ${c.dim("\u9ED8\u8BA4\u6743\u9650:")} \u8BFB/\u5199\u6587\u4EF6\u9759\u9ED8\u653E\u884C\uFF08\u5DE5\u4F5C\u533A\u8303\u56F4\uFF09\uFF1Bbash \u4EC5\u5371\u9669\u547D\u4EE4\u9700\u786E\u8BA4
215
+ ${c.dim("\uFF08rm \u5220\u9664\u3001sudo\u3001\u78C1\u76D8\u5199\u5165\u3001\u8FDC\u7A0B\u811A\u672C\u7BA1\u9053\u7B49\uFF1B\u5371\u9669\u547D\u4EE4\u6BCF\u6B21\u91CD\u786E\u8BA4\uFF09")}
229
216
 
230
- # provider/id \u7EC4\u5408\u5199\u6CD5
231
- ${APP_NAME} --model anthropic/claude-sonnet-4-20250514 "\u5E2E\u6211\u91CD\u6784\u4EE3\u7801"
217
+ ${head("\u4E0A\u4E0B\u6587\u538B\u7F29:")}
218
+ ${opt("--no-compaction", "\u5173\u95ED\u4E0A\u4E0B\u6587\u538B\u7F29\uFF08\u957F\u4F1A\u8BDD\u53EF\u80FD\u6EA2\u51FA\uFF09")}
219
+ ${opt("--compaction-config <\u6587\u4EF6>", "\u538B\u7F29\u914D\u7F6E JSON\uFF08\u8986\u76D6\u9ED8\u8BA4\u9608\u503C\uFF09")}
232
220
 
233
- # \u9644\u5E26\u6587\u4EF6\u4E0A\u4E0B\u6587
234
- ${APP_NAME} @package.json "\u5206\u6790\u8FD9\u4E2A\u6587\u4EF6\u7684\u4F9D\u8D56"
221
+ ${head("\u5176\u4ED6:")}
222
+ ${opt("--system-prompt <\u6587\u672C>", "\u66FF\u6362\u9ED8\u8BA4\u7CFB\u7EDF\u63D0\u793A\u8BCD")}
223
+ ${opt("--append-system-prompt <\u6587\u672C>", "\u8FFD\u52A0\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u53EF\u591A\u6B21\uFF09")}
224
+ ${opt("--help, -h", "\u663E\u793A\u672C\u5E2E\u52A9")}
225
+ ${opt("--version, -v", "\u663E\u793A\u7248\u672C")}
235
226
 
236
- # \u7EE7\u7EED\u4E0A\u6B21\u4F1A\u8BDD
237
- ${APP_NAME} -c "\u6211\u4EEC\u521A\u624D\u804A\u5230\u54EA\u91CC\u4E86\uFF1F"
227
+ ${head("\u4EA4\u4E92\u6A21\u5F0F:")}
228
+ ${c.dim("\xB7 \u591A\u884C\u8F93\u5165\uFF1A\u884C\u5C3E\u4EE5")} ${c.yellow("\\")} ${c.dim("\u7EED\u884C\uFF0C\u7A7A\u884C\u63D0\u4EA4")}
229
+ ${c.dim("\xB7 \u659C\u6760\u547D\u4EE4\uFF1A/help /model /thinking /clear /compact /sessions /quit")}
230
+ ${c.dim("\xB7 Ctrl+C \u4E2D\u65AD\u8FD0\u884C\uFF0C\u8FDE\u6309\u4E24\u6B21\u9000\u51FA")}
238
231
 
239
- # \u53EA\u8BFB\u6A21\u5F0F
240
- ${APP_NAME} --tools read -p "\u5BA1\u67E5 src/ \u4E0B\u7684\u4EE3\u7801"
232
+ ${head("\u793A\u4F8B:")}
233
+ ${c.dim("# \u4EA4\u4E92\u6A21\u5F0F")}
234
+ ${c.cyan(APP_NAME)}
235
+ ${c.dim("# \u7BA1\u9053\u5355\u6B21\u63D0\u95EE")}
236
+ ${c.yellow("cat README.md")} ${c.dim("|")} ${c.cyan(APP_NAME)} ${c.green("-p")} ${c.yellow('"\u603B\u7ED3\u8FD9\u6BB5\u6587\u672C"')}
237
+ ${c.dim("# \u6307\u5B9A\u6A21\u578B\uFF08provider/id\uFF09")}
238
+ ${c.cyan(APP_NAME)} ${c.green("--model")} ${c.yellow("deepseek/deepseek-chat")} ${c.yellow('"\u4F60\u597D"')}
239
+ ${c.dim("# \u9644\u5E26\u6587\u4EF6\u4E0A\u4E0B\u6587\uFF08\u56FE\u7247\u8D70\u591A\u6A21\u6001\uFF09")}
240
+ ${c.cyan(APP_NAME)} ${c.yellow("@package.json")} ${c.yellow('"\u5206\u6790\u4F9D\u8D56"')}
241
+ ${c.dim("# \u7EE7\u7EED\u4E0A\u6B21\u4F1A\u8BDD")}
242
+ ${c.cyan(APP_NAME)} ${c.green("-c")} ${c.yellow('"\u6211\u4EEC\u521A\u624D\u804A\u5230\u54EA\u91CC\u4E86\uFF1F"')}
243
+ ${c.dim("# \u53EA\u8BFB\u5BA1\u67E5")}
244
+ ${c.cyan(APP_NAME)} ${c.green("-t")} ${c.yellow("read,find,grep")} ${c.green("-p")} ${c.yellow('"\u5BA1\u67E5 src/"')}
241
245
 
242
- ${"\u73AF\u5883\u53D8\u91CF:"}
243
- OPENAI_API_KEY / DEEPSEEK_API_KEY / ANTHROPIC_API_KEY / GOOGLE_API_KEY ...
244
- AIPACK_CONFIG_DIR \u914D\u7F6E\u76EE\u5F55\uFF08\u9ED8\u8BA4 ~/.aipack\uFF09
246
+ ${head("\u73AF\u5883\u53D8\u91CF:")}
247
+ ${c.dim("OPENAI_API_KEY / DEEPSEEK_API_KEY / ANTHROPIC_API_KEY / GOOGLE_API_KEY ...")}
248
+ ${c.dim("AIPACK_CONFIG_DIR")} ${c.dim("\u2192")} ${c.dim("\u914D\u7F6E\u76EE\u5F55\uFF08\u9ED8\u8BA4 ~/.aipack\uFF09")}
245
249
  `);
246
250
  }
247
251
 
@@ -702,13 +706,21 @@ function splitModelSpec(args) {
702
706
  return { provider: args.provider, modelId: args.model };
703
707
  }
704
708
  function detectDefaultProvider() {
709
+ const PRIORITY = ["deepseek"];
710
+ for (const pid of PRIORITY) {
711
+ if (hasProviderConfigured(pid)) {
712
+ const models = getBuiltinModels(pid);
713
+ if (models.length > 0) return { id: pid, modelId: models[0].id };
714
+ }
715
+ }
705
716
  for (const p of getBuiltinProviders()) {
717
+ if (PRIORITY.includes(p.id)) continue;
706
718
  if (hasProviderConfigured(p.id)) {
707
719
  const models = getBuiltinModels(p.id);
708
720
  if (models.length > 0) return { id: p.id, modelId: models[0].id };
709
721
  }
710
722
  }
711
- return { id: "openai", modelId: "gpt-4o-mini" };
723
+ return { id: "deepseek", modelId: "deepseek-chat" };
712
724
  }
713
725
  function buildCustomModel(providerId, modelId) {
714
726
  const meta = BUILTIN_PROVIDERS.find((p) => p.id === providerId);
@@ -945,11 +957,92 @@ ${stdinText.trim()}
945
957
  return { text: parts.join("\n\n"), media };
946
958
  }
947
959
 
948
- // src/modes/print.ts
960
+ // src/spinner.ts
949
961
  import chalk2 from "chalk";
962
+ var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
963
+ var INTERVAL_MS = 80;
964
+ var activeSpinner = null;
965
+ function pauseActiveSpinner() {
966
+ activeSpinner?.pause();
967
+ }
968
+ function resumeActiveSpinner() {
969
+ activeSpinner?.resume();
970
+ }
971
+ var Spinner = class {
972
+ timer = null;
973
+ frameIdx = 0;
974
+ prefix = "";
975
+ /** 是否处于暂停态(曾活动但被临时挂起) */
976
+ paused = false;
977
+ /** 是否正在旋转;非 TTY 下 start 永远不真正起效 */
978
+ get active() {
979
+ return this.timer !== null;
980
+ }
981
+ start(prefix) {
982
+ if (this.timer) this.stop();
983
+ if (!process.stdout.isTTY) return;
984
+ this.prefix = prefix;
985
+ this.frameIdx = 0;
986
+ this.paused = false;
987
+ activeSpinner = this;
988
+ this.render();
989
+ this.timer = setInterval(() => {
990
+ this.frameIdx = (this.frameIdx + 1) % FRAMES.length;
991
+ this.render();
992
+ }, INTERVAL_MS);
993
+ }
994
+ /** 中途切换前缀文本(如 tool_start → tool_end 之间) */
995
+ message(prefix) {
996
+ if (!this.timer) return;
997
+ this.prefix = prefix;
998
+ this.render();
999
+ }
1000
+ /** 暂停动画:清掉定时器与行,但保留"应继续"状态供 resume */
1001
+ pause() {
1002
+ if (!this.timer) return;
1003
+ clearInterval(this.timer);
1004
+ this.timer = null;
1005
+ this.paused = true;
1006
+ process.stdout.write("\r\x1B[2K");
1007
+ }
1008
+ /** 恢复暂停的动画 */
1009
+ resume() {
1010
+ if (!this.paused) return;
1011
+ this.paused = false;
1012
+ if (!process.stdout.isTTY) return;
1013
+ this.frameIdx = 0;
1014
+ this.render();
1015
+ this.timer = setInterval(() => {
1016
+ this.frameIdx = (this.frameIdx + 1) % FRAMES.length;
1017
+ this.render();
1018
+ }, INTERVAL_MS);
1019
+ }
1020
+ /** 停止动画:清除行;可选写一行结果摘要 */
1021
+ stop(summary) {
1022
+ if (this.timer) {
1023
+ clearInterval(this.timer);
1024
+ this.timer = null;
1025
+ process.stdout.write("\r\x1B[2K");
1026
+ }
1027
+ this.paused = false;
1028
+ if (activeSpinner === this) activeSpinner = null;
1029
+ if (summary) {
1030
+ process.stdout.write(`${summary}
1031
+ `);
1032
+ }
1033
+ }
1034
+ render() {
1035
+ const frame = chalk2.cyan(FRAMES[this.frameIdx]);
1036
+ const text = this.prefix ? `${frame} ${chalk2.dim(this.prefix)}` : frame;
1037
+ process.stdout.write(`\r\x1B[2K${text}`);
1038
+ }
1039
+ };
1040
+
1041
+ // src/modes/print.ts
1042
+ import chalk4 from "chalk";
950
1043
 
951
1044
  // src/modes/render.ts
952
- import chalk from "chalk";
1045
+ import chalk3 from "chalk";
953
1046
  var ChunkRenderer = class {
954
1047
  constructor(opts = {}) {
955
1048
  this.opts = opts;
@@ -957,47 +1050,84 @@ var ChunkRenderer = class {
957
1050
  opts;
958
1051
  thinkingShown = false;
959
1052
  inTool = false;
1053
+ /** 当前工具起始时间(用于结束时显示耗时) */
1054
+ toolStartedAt = 0;
1055
+ spinner = new Spinner();
960
1056
  render(chunk) {
961
1057
  const err = this.opts.toolStream ?? process.stdout;
962
1058
  switch (chunk.type) {
963
1059
  case "text":
1060
+ if (this.spinner.active || this.inTool) {
1061
+ this.spinner.stop();
1062
+ this.inTool = false;
1063
+ }
964
1064
  if (chunk.content) process.stdout.write(chunk.content);
965
1065
  break;
966
1066
  case "thinking": {
967
1067
  if (this.opts.showThinking && chunk.content) {
968
- process.stdout.write(chalk.dim(chunk.content));
1068
+ process.stdout.write(chalk3.dim(chunk.content));
969
1069
  } else if (!this.thinkingShown) {
970
1070
  this.thinkingShown = true;
971
- err.write(chalk.dim(" (\u601D\u8003\u4E2D...)\n"));
1071
+ if (process.stdout.isTTY) {
1072
+ this.spinner.start("\u601D\u8003\u4E2D");
1073
+ } else {
1074
+ err.write(chalk3.dim(" (\u601D\u8003\u4E2D...)\n"));
1075
+ }
972
1076
  }
973
1077
  break;
974
1078
  }
975
1079
  case "tool_start":
976
1080
  this.inTool = true;
977
- err.write(chalk.cyan(`
1081
+ this.toolStartedAt = Date.now();
1082
+ if (process.stdout.isTTY) {
1083
+ this.spinner.start(`\u6267\u884C ${chunk.toolName ?? "\u5DE5\u5177"}`);
1084
+ } else {
1085
+ err.write(chalk3.cyan(`
978
1086
  \u2699 ${chunk.toolName} `));
1087
+ }
979
1088
  break;
980
1089
  case "tool_end":
981
1090
  if (this.inTool) {
982
- err.write(chunk.isError ? chalk.red(" \u2717\n") : chalk.green(" \u2713\n"));
1091
+ const elapsed = this.toolStartedAt ? Date.now() - this.toolStartedAt : 0;
1092
+ const timeStr = elapsed > 0 ? chalk3.dim(` ${formatElapsed(elapsed)}`) : "";
1093
+ if (process.stdout.isTTY) {
1094
+ const mark = chunk.isError ? chalk3.red("\u2717") : chalk3.green("\u2713");
1095
+ this.spinner.stop(`${chalk3.cyan("\u2699")} ${chunk.toolName ?? ""} ${mark}${timeStr}`);
1096
+ } else {
1097
+ err.write(chunk.isError ? chalk3.red(" \u2717\n") : chalk3.green(" \u2713\n"));
1098
+ }
983
1099
  this.inTool = false;
984
1100
  }
985
1101
  break;
986
1102
  case "error":
987
- err.write(chalk.red(`
1103
+ this.spinner.stop();
1104
+ this.inTool = false;
1105
+ err.write(chalk3.red(`
988
1106
  \u9519\u8BEF: ${chunk.content ?? "\u672A\u77E5\u9519\u8BEF"}
989
1107
  `));
990
1108
  break;
991
1109
  case "done":
1110
+ this.spinner.stop();
1111
+ this.inTool = false;
992
1112
  process.stdout.write("\n");
993
1113
  break;
994
1114
  }
995
1115
  }
996
1116
  reset() {
1117
+ this.spinner.stop();
997
1118
  this.thinkingShown = false;
998
1119
  this.inTool = false;
1120
+ this.toolStartedAt = 0;
999
1121
  }
1000
1122
  };
1123
+ function formatElapsed(ms) {
1124
+ if (ms < 1e3) return `${ms}ms`;
1125
+ const s = ms / 1e3;
1126
+ if (s < 60) return `${s.toFixed(1)}s`;
1127
+ const m = Math.floor(s / 60);
1128
+ const rem = Math.round(s % 60);
1129
+ return `${m}m ${String(rem).padStart(2, "0")}s`;
1130
+ }
1001
1131
 
1002
1132
  // src/modes/print.ts
1003
1133
  async function runPrintMode(runtime, request) {
@@ -1011,13 +1141,13 @@ async function runPrintMode(runtime, request) {
1011
1141
  renderer.render(chunk);
1012
1142
  }
1013
1143
  } catch (err) {
1014
- process.stderr.write(chalk2.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}
1144
+ process.stderr.write(chalk4.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}
1015
1145
  `));
1016
1146
  process.exitCode = 1;
1017
1147
  return;
1018
1148
  }
1019
1149
  if (usage && (usage.input || usage.output)) {
1020
- process.stderr.write(chalk2.dim(`tokens: \u2191${(usage.input ?? 0).toLocaleString()} \u2193${(usage.output ?? 0).toLocaleString()}
1150
+ process.stderr.write(chalk4.dim(`tokens: \u2191${(usage.input ?? 0).toLocaleString()} \u2193${(usage.output ?? 0).toLocaleString()}
1021
1151
  `));
1022
1152
  }
1023
1153
  if (error) process.exitCode = 1;
@@ -1056,9 +1186,41 @@ async function runJsonMode(runtime, request) {
1056
1186
  }
1057
1187
  }
1058
1188
 
1189
+ // src/banner.ts
1190
+ import chalk5 from "chalk";
1191
+ import { getBuiltinProviders as getBuiltinProviders2, hasProviderConfigured as hasProviderConfigured2 } from "@aipack-ai/agent";
1192
+ function printStartupBanner(opts) {
1193
+ const title = chalk5.bold(`${APP_NAME} ${VERSION}`);
1194
+ const session = chalk5.dim(
1195
+ `\u4F1A\u8BDD: ${opts.sessionKey}${opts.ephemeral ? " (\u4E34\u65F6)" : ""}`
1196
+ );
1197
+ const modelTag = opts.customModel ? `${opts.modelLabel} ${chalk5.yellow("(\u81EA\u5B9A\u4E49)")}` : opts.modelLabel;
1198
+ const model = chalk5.dim(`\u6A21\u578B: ${modelTag}`);
1199
+ const apiKeyHint = detectApiKeyHint();
1200
+ console.log(title);
1201
+ console.log(session);
1202
+ console.log(model);
1203
+ if (apiKeyHint) {
1204
+ console.log(apiKeyHint);
1205
+ }
1206
+ console.log(
1207
+ chalk5.dim("\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\uFF0CCtrl+C \u4E2D\u65AD\u8FD0\u884C\uFF0C\u8FDE\u6309\u4E24\u6B21\u9000\u51FA") + "\n"
1208
+ );
1209
+ }
1210
+ function detectApiKeyHint() {
1211
+ const configured = getBuiltinProviders2().filter(
1212
+ (p) => hasProviderConfigured2(p.id)
1213
+ );
1214
+ if (configured.length === 0) {
1215
+ const providers = getBuiltinProviders2().slice(0, 4).map((p) => ` export ${p.envVar}=sk-...`).join("\n");
1216
+ return "\n" + chalk5.yellow("\u26A0 \u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 API Key\uFF0CAI \u8C03\u7528\u5C06\u5931\u8D25\u3002") + "\n" + chalk5.dim("\u4EFB\u9009\u4E00\u4E2A\u63D0\u4F9B\u5546\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF\uFF1A") + "\n" + providers + "\n" + chalk5.dim("\u67E5\u770B\u5168\u90E8\u6A21\u578B\uFF1Aaipack --list-models") + "\n";
1217
+ }
1218
+ return null;
1219
+ }
1220
+
1059
1221
  // src/modes/interactive.ts
1060
1222
  import readline2 from "readline";
1061
- import chalk3 from "chalk";
1223
+ import chalk6 from "chalk";
1062
1224
  import {
1063
1225
  getBuiltinModels as getBuiltinModels2,
1064
1226
  adaptAiModel as adaptAiModel2
@@ -1099,6 +1261,7 @@ async function runInteractiveMode(opts) {
1099
1261
  const renderer = new ChunkRenderer();
1100
1262
  let busy = false;
1101
1263
  let sigintCount = 0;
1264
+ let pendingMultiline = [];
1102
1265
  let finish;
1103
1266
  const finished = new Promise((resolve) => {
1104
1267
  finish = resolve;
@@ -1106,26 +1269,37 @@ async function runInteractiveMode(opts) {
1106
1269
  function cleanup() {
1107
1270
  finish();
1108
1271
  }
1272
+ function buildPrompt() {
1273
+ const id = model.aiModel.id;
1274
+ return chalk6.blue(`${chalk6.dim("aipack")} ${chalk6.cyan(id)}${chalk6.blue(">")} `);
1275
+ }
1109
1276
  let rl;
1110
1277
  let recreating = false;
1111
1278
  function setupRl() {
1112
1279
  rl = readline2.createInterface({
1113
1280
  input: process.stdin,
1114
1281
  output: process.stdout,
1115
- prompt: chalk3.blue("aipack> ")
1282
+ prompt: buildPrompt()
1116
1283
  });
1117
1284
  rl.on("SIGINT", () => {
1118
1285
  if (busy) {
1119
- console.log(chalk3.yellow("\n\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C..."));
1286
+ console.log(chalk6.yellow("\n\u4E2D\u65AD\u5F53\u524D\u8FD0\u884C..."));
1120
1287
  runtime.abort(activeKey);
1121
1288
  return;
1122
1289
  }
1290
+ if (pendingMultiline.length > 0) {
1291
+ pendingMultiline = [];
1292
+ rl.setPrompt(buildPrompt());
1293
+ console.log(chalk6.dim("\uFF08\u5DF2\u53D6\u6D88\u591A\u884C\u8F93\u5165\uFF09"));
1294
+ rl.prompt();
1295
+ return;
1296
+ }
1123
1297
  sigintCount++;
1124
1298
  if (sigintCount >= 2) {
1125
- console.log(chalk3.dim("\n\u518D\u89C1"));
1299
+ console.log(chalk6.dim("\n\u518D\u89C1"));
1126
1300
  rl.close();
1127
1301
  } else {
1128
- console.log(chalk3.dim("\uFF08\u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA\uFF09"));
1302
+ console.log(chalk6.dim("\uFF08\u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA\uFF09"));
1129
1303
  rl.prompt();
1130
1304
  setTimeout(() => {
1131
1305
  sigintCount = 0;
@@ -1151,25 +1325,47 @@ async function runInteractiveMode(opts) {
1151
1325
  sessionKey: activeKey,
1152
1326
  ephemeral: args.noSession
1153
1327
  };
1328
+ let turnUsage = { input: 0, output: 0 };
1329
+ let toolsUsed = [];
1154
1330
  try {
1155
1331
  for await (const chunk of runtime.stream(request)) {
1156
1332
  renderer.render(chunk);
1157
1333
  if (chunk.type === "done" && chunk.result?.usage) {
1158
1334
  const u = chunk.result.usage;
1159
- usageTotal.input += u.input ?? 0;
1160
- usageTotal.output += u.output ?? 0;
1335
+ turnUsage.input = u.input ?? 0;
1336
+ turnUsage.output = u.output ?? 0;
1337
+ usageTotal.input += turnUsage.input;
1338
+ usageTotal.output += turnUsage.output;
1339
+ toolsUsed = chunk.result.toolsUsed ?? [];
1161
1340
  }
1162
1341
  }
1163
- if (usageTotal.input > 0 || usageTotal.output > 0) {
1164
- console.log(chalk3.dim(` tokens: \u2191${usageTotal.input.toLocaleString()} \u2193${usageTotal.output.toLocaleString()}\uFF08\u7D2F\u8BA1\uFF09`));
1165
- }
1342
+ printTurnStats(turnUsage, toolsUsed);
1166
1343
  } catch (err) {
1167
- console.log(chalk3.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}`));
1344
+ console.log(chalk6.red(`\u9519\u8BEF: ${err instanceof Error ? err.message : String(err)}`));
1168
1345
  } finally {
1169
1346
  busy = false;
1170
1347
  rl.prompt();
1171
1348
  }
1172
1349
  }
1350
+ function printTurnStats(turn, tools) {
1351
+ const parts = [];
1352
+ if (turn.input > 0 || turn.output > 0) {
1353
+ parts.push(
1354
+ chalk6.dim(`\u672C\u8F6E \u2191${turn.input.toLocaleString()} \u2193${turn.output.toLocaleString()}`)
1355
+ );
1356
+ parts.push(
1357
+ chalk6.dim(
1358
+ `\u7D2F\u8BA1 \u2191${usageTotal.input.toLocaleString()} \u2193${usageTotal.output.toLocaleString()}`
1359
+ )
1360
+ );
1361
+ }
1362
+ if (tools.length > 0) {
1363
+ parts.push(chalk6.dim(`\u5DE5\u5177 ${tools.join(", ")}`));
1364
+ }
1365
+ if (parts.length > 0) {
1366
+ console.log(` ${parts.join(chalk6.dim(" \xB7 "))}`);
1367
+ }
1368
+ }
1173
1369
  async function handleCommand(line) {
1174
1370
  const spaceIdx = line.indexOf(" ");
1175
1371
  const cmd = (spaceIdx === -1 ? line : line.slice(0, spaceIdx)).toLowerCase();
@@ -1184,8 +1380,8 @@ async function runInteractiveMode(opts) {
1184
1380
  return;
1185
1381
  case "/model": {
1186
1382
  if (!rest) {
1187
- console.log(chalk3.dim(`\u5F53\u524D\u6A21\u578B: ${model.aiModel.provider}/${model.aiModel.id}`));
1188
- console.log(chalk3.dim("\u7528\u6CD5: /model provider/model-id\uFF08\u5982 /model deepseek/deepseek-chat\uFF09"));
1383
+ console.log(chalk6.dim(`\u5F53\u524D\u6A21\u578B: ${model.aiModel.provider}/${model.aiModel.id}`));
1384
+ console.log(chalk6.dim("\u7528\u6CD5: /model provider/model-id\uFF08\u5982 /model deepseek/deepseek-chat\uFF09"));
1189
1385
  break;
1190
1386
  }
1191
1387
  const slash = rest.indexOf("/");
@@ -1193,168 +1389,188 @@ async function runInteractiveMode(opts) {
1193
1389
  const id = slash === -1 ? rest : rest.slice(slash + 1);
1194
1390
  const found = getBuiltinModels2(provider).find((m) => m.id === id);
1195
1391
  if (!found) {
1196
- console.log(chalk3.yellow(`\u672A\u627E\u5230\u5185\u7F6E\u6A21\u578B ${provider}/${id}\uFF0C\u53EF\u7528:`));
1392
+ console.log(chalk6.yellow(`\u672A\u627E\u5230\u5185\u7F6E\u6A21\u578B ${provider}/${id}\uFF0C\u53EF\u7528:`));
1197
1393
  console.log(getBuiltinModels2(provider).map((m) => ` ${m.id}`).join("\n") || " (\u65E0)");
1198
1394
  break;
1199
1395
  }
1200
1396
  runtime.setModel(adaptAiModel2(found));
1201
1397
  model.aiModel = found;
1202
1398
  model.custom = false;
1203
- console.log(chalk3.green(`\u5DF2\u5207\u6362\u5230 ${provider}/${id}`));
1399
+ console.log(chalk6.green(`\u5DF2\u5207\u6362\u5230 ${provider}/${id}`));
1204
1400
  break;
1205
1401
  }
1206
1402
  case "/thinking": {
1207
1403
  if (!VALID_THINKING.has(rest)) {
1208
- console.log(chalk3.dim("\u7528\u6CD5: /thinking <off|minimal|low|medium|high|max>"));
1404
+ console.log(chalk6.dim("\u7528\u6CD5: /thinking <off|minimal|low|medium|high|max>"));
1209
1405
  break;
1210
1406
  }
1211
1407
  runtime.setThinkingLevel(rest);
1212
- console.log(chalk3.green(`\u601D\u8003\u7EA7\u522B: ${rest}`));
1408
+ console.log(chalk6.green(`\u601D\u8003\u7EA7\u522B: ${rest}`));
1213
1409
  break;
1214
1410
  }
1215
1411
  case "/system": {
1216
1412
  if (!rest) {
1217
- console.log(chalk3.dim("\u7528\u6CD5: /system <\u65B0\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD>"));
1413
+ console.log(chalk6.dim("\u7528\u6CD5: /system <\u65B0\u7684\u7CFB\u7EDF\u63D0\u793A\u8BCD>"));
1218
1414
  break;
1219
1415
  }
1220
1416
  runtime.setSystemPrompt(rest);
1221
- console.log(chalk3.green("\u7CFB\u7EDF\u63D0\u793A\u8BCD\u5DF2\u66F4\u65B0"));
1417
+ console.log(chalk6.green("\u7CFB\u7EDF\u63D0\u793A\u8BCD\u5DF2\u66F4\u65B0"));
1222
1418
  break;
1223
1419
  }
1224
1420
  case "/session":
1225
- console.log(`\u4F1A\u8BDD key: ${chalk3.cyan(activeKey)}`);
1421
+ console.log(`\u4F1A\u8BDD key: ${chalk6.cyan(activeKey)}`);
1226
1422
  console.log(`\u6D88\u606F\u6570: ${runtime.getMessages(activeKey).length}`);
1227
- console.log(`\u6301\u4E45\u5316: ${args.noSession ? chalk3.yellow("\u5426\uFF08--no-session\uFF09") : chalk3.green(storage ? "\u662F" : "\u5426\uFF08\u65E0\u5B58\u50A8\uFF09")}`);
1423
+ console.log(`\u6301\u4E45\u5316: ${args.noSession ? chalk6.yellow("\u5426\uFF08--no-session\uFF09") : chalk6.green(storage ? "\u662F" : "\u5426\uFF08\u65E0\u5B58\u50A8\uFF09")}`);
1228
1424
  break;
1229
1425
  case "/sessions": {
1230
1426
  if (!storage) {
1231
- console.log(chalk3.yellow("\u5F53\u524D\u4E3A\u4E34\u65F6\u4F1A\u8BDD\uFF0C\u65E0\u6301\u4E45\u5316\u5B58\u50A8"));
1427
+ console.log(chalk6.yellow("\u5F53\u524D\u4E3A\u4E34\u65F6\u4F1A\u8BDD\uFF0C\u65E0\u6301\u4E45\u5316\u5B58\u50A8"));
1232
1428
  break;
1233
1429
  }
1234
1430
  const sessions = await listSessionsByRecency(storage);
1235
1431
  if (sessions.length === 0) {
1236
- console.log(chalk3.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF09"));
1432
+ console.log(chalk6.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF09"));
1237
1433
  break;
1238
1434
  }
1239
- console.log(sessions.slice(0, 10).map((s, i) => `${s === activeKey ? chalk3.green("\u25B8 ") : " "}${i + 1}. ${s}`).join("\n"));
1240
- console.log(chalk3.dim("\u5207\u6362: \u9000\u51FA\u540E\u7528 aipack --session <key> \u6062\u590D"));
1435
+ console.log(sessions.slice(0, 10).map((s, i) => `${s === activeKey ? chalk6.green("\u25B8 ") : " "}${i + 1}. ${s}`).join("\n"));
1436
+ console.log(chalk6.dim("\u5207\u6362: \u9000\u51FA\u540E\u7528 aipack --session <key> \u6062\u590D"));
1241
1437
  break;
1242
1438
  }
1243
1439
  case "/clear":
1244
1440
  runtime.clearSession(activeKey);
1245
1441
  usageTotal = { input: 0, output: 0 };
1246
- console.log(chalk3.green("\u4F1A\u8BDD\u5DF2\u6E05\u7A7A\uFF08\u4EC5\u5185\u5B58\uFF09"));
1442
+ console.log(chalk6.green("\u4F1A\u8BDD\u5DF2\u6E05\u7A7A\uFF08\u4EC5\u5185\u5B58\uFF09"));
1247
1443
  break;
1248
1444
  case "/compact": {
1249
- console.log(chalk3.dim("\u538B\u7F29\u4F1A\u8BDD\u5386\u53F2..."));
1445
+ console.log(chalk6.dim("\u538B\u7F29\u4F1A\u8BDD\u5386\u53F2..."));
1250
1446
  const mode = await runtime.compact(activeKey);
1251
1447
  if (mode === null) {
1252
- console.log(chalk3.yellow("\u65E0\u53EF\u538B\u7F29\u5185\u5BB9\uFF08\u6D88\u606F\u8FC7\u5C11\u6216\u538B\u7F29\u5DF2\u901A\u8FC7 --no-compaction \u5173\u95ED\uFF09"));
1448
+ console.log(chalk6.yellow("\u65E0\u53EF\u538B\u7F29\u5185\u5BB9\uFF08\u6D88\u606F\u8FC7\u5C11\u6216\u538B\u7F29\u5DF2\u901A\u8FC7 --no-compaction \u5173\u95ED\uFF09"));
1253
1449
  } else {
1254
- console.log(chalk3.green(`\u5DF2\u5B8C\u6210${mode === "summary" ? "\u6458\u8981\u538B\u7F29" : "\u622A\u65AD\u538B\u7F29"}\uFF0C\u6D88\u606F\u6570: ${runtime.getMessages(activeKey).length}`));
1450
+ console.log(chalk6.green(`\u5DF2\u5B8C\u6210${mode === "summary" ? "\u6458\u8981\u538B\u7F29" : "\u622A\u65AD\u538B\u7F29"}\uFF0C\u6D88\u606F\u6570: ${runtime.getMessages(activeKey).length}`));
1255
1451
  }
1256
1452
  break;
1257
1453
  }
1258
1454
  case "/tools":
1259
- console.log(chalk3.dim("\u5185\u7F6E\u5DE5\u5177: read, write, edit, bash, find, grep, ls"));
1260
- console.log(chalk3.dim("\u901A\u8FC7 --tools / --exclude-tools / --no-tools \u914D\u7F6E\u542F\u505C"));
1455
+ console.log(chalk6.dim("\u5185\u7F6E\u5DE5\u5177: read, write, edit, bash, find, grep, ls"));
1456
+ console.log(chalk6.dim("\u901A\u8FC7 --tools / --exclude-tools / --no-tools \u914D\u7F6E\u542F\u505C"));
1261
1457
  break;
1262
1458
  case "/mcp": {
1263
1459
  if (!mcp) {
1264
- console.log(chalk3.yellow("\u672A\u914D\u7F6E MCP server\uFF08\u5728 .mcp.json / ~/.aipack/mcp.json \u4E2D\u914D\u7F6E\uFF09"));
1460
+ console.log(chalk6.yellow("\u672A\u914D\u7F6E MCP server\uFF08\u5728 .mcp.json / ~/.aipack/mcp.json \u4E2D\u914D\u7F6E\uFF09"));
1265
1461
  break;
1266
1462
  }
1267
1463
  if (rest === "refresh") {
1268
- console.log(chalk3.dim("\u5237\u65B0 MCP \u5DE5\u5177\u5217\u8868..."));
1464
+ console.log(chalk6.dim("\u5237\u65B0 MCP \u5DE5\u5177\u5217\u8868..."));
1269
1465
  const diags2 = await mcp.refresh();
1270
1466
  if (diags2.length > 0) {
1271
- for (const d of diags2) console.log(` ${chalk3[d.type === "error" ? "red" : d.type === "warning" ? "yellow" : "cyan"](d.type)} [${d.server}] ${d.message}`);
1467
+ for (const d of diags2) console.log(` ${chalk6[d.type === "error" ? "red" : d.type === "warning" ? "yellow" : "cyan"](d.type)} [${d.server}] ${d.message}`);
1272
1468
  }
1273
- console.log(chalk3.green("\u5237\u65B0\u5B8C\u6210"));
1469
+ console.log(chalk6.green("\u5237\u65B0\u5B8C\u6210"));
1274
1470
  break;
1275
1471
  }
1276
1472
  const statuses = mcp.registry.getStatus();
1277
1473
  if (statuses.length === 0) {
1278
- console.log(chalk3.dim("\uFF08\u65E0 MCP server\uFF09"));
1474
+ console.log(chalk6.dim("\uFF08\u65E0 MCP server\uFF09"));
1279
1475
  break;
1280
1476
  }
1281
1477
  for (const s of statuses) {
1282
- const flag = s.connected ? chalk3.green("\u25CF") : chalk3.red("\u25CB");
1283
- const err = s.error ? chalk3.red(` ${s.error}`) : "";
1284
- console.log(`${flag} ${chalk3.cyan(s.name)} ${s.transport} ${s.toolCount} \u5DE5\u5177${err}`);
1478
+ const flag = s.connected ? chalk6.green("\u25CF") : chalk6.red("\u25CB");
1479
+ const err = s.error ? chalk6.red(` ${s.error}`) : "";
1480
+ console.log(`${flag} ${chalk6.cyan(s.name)} ${s.transport} ${s.toolCount} \u5DE5\u5177${err}`);
1285
1481
  }
1286
1482
  const diags = mcp.diagnostics;
1287
1483
  if (diags.length > 0) {
1288
- console.log(chalk3.dim("\u8BCA\u65AD:"));
1484
+ console.log(chalk6.dim("\u8BCA\u65AD:"));
1289
1485
  for (const d of diags) console.log(` ${d.type} [${d.server}] ${d.message}`);
1290
1486
  }
1291
1487
  break;
1292
1488
  }
1293
1489
  case "/approvals": {
1294
1490
  if (!approvalManager) {
1295
- console.log(chalk3.yellow("\u5BA1\u6279\u672A\u542F\u7528\uFF08\u5728 aipack.config.js \u4E2D\u914D\u7F6E approvals.enabled: true\uFF09"));
1491
+ console.log(chalk6.yellow("\u5BA1\u6279\u672A\u542F\u7528\uFF08\u5728 aipack.config.js \u4E2D\u914D\u7F6E approvals.enabled: true\uFF09"));
1296
1492
  break;
1297
1493
  }
1298
1494
  const pending = approvalManager.list();
1299
1495
  if (pending.length === 0) {
1300
- console.log(chalk3.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\uFF09"));
1496
+ console.log(chalk6.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\uFF09"));
1301
1497
  break;
1302
1498
  }
1303
1499
  for (const p of pending) {
1304
- console.log(`${chalk3.cyan(p.id)} ${p.request.toolName} ${chalk3.dim(new Date(p.createdAt).toLocaleString())}${p.restored ? chalk3.yellow(" (\u5B64\u513F)") : ""}`);
1500
+ console.log(`${chalk6.cyan(p.id)} ${p.request.toolName} ${chalk6.dim(new Date(p.createdAt).toLocaleString())}${p.restored ? chalk6.yellow(" (\u5B64\u513F)") : ""}`);
1305
1501
  }
1306
1502
  break;
1307
1503
  }
1308
1504
  case "/approve":
1309
1505
  case "/deny": {
1310
1506
  if (!approvalManager) {
1311
- console.log(chalk3.yellow("\u5BA1\u6279\u672A\u542F\u7528"));
1507
+ console.log(chalk6.yellow("\u5BA1\u6279\u672A\u542F\u7528"));
1312
1508
  break;
1313
1509
  }
1314
1510
  if (!rest) {
1315
- console.log(chalk3.dim(`\u7528\u6CD5: ${cmd} <\u5BA1\u6279\u5355 id>`));
1511
+ console.log(chalk6.dim(`\u7528\u6CD5: ${cmd} <\u5BA1\u6279\u5355 id>`));
1316
1512
  break;
1317
1513
  }
1318
1514
  const ok = approvalManager.resolve(rest, cmd === "/approve");
1319
- console.log(ok ? chalk3.green("\u5DF2\u751F\u6548") : chalk3.yellow("\u5BA1\u6279\u5355\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97"));
1515
+ console.log(ok ? chalk6.green("\u5DF2\u751F\u6548") : chalk6.yellow("\u5BA1\u6279\u5355\u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97"));
1320
1516
  break;
1321
1517
  }
1322
1518
  default:
1323
- console.log(chalk3.yellow(`\u672A\u77E5\u547D\u4EE4: ${cmd}\uFF08/help \u67E5\u770B\u5168\u90E8\uFF09`));
1519
+ console.log(chalk6.yellow(`\u672A\u77E5\u547D\u4EE4: ${cmd}\uFF08/help \u67E5\u770B\u5168\u90E8\uFF09`));
1324
1520
  }
1325
1521
  }
1326
1522
  function printSlashHelp() {
1327
- console.log(`${chalk3.bold("\u547D\u4EE4:")}
1328
- /model [provider/id] \u5207\u6362\u6A21\u578B\uFF08\u65E0\u53C2\u663E\u793A\u5F53\u524D\uFF09
1329
- /thinking <\u7EA7\u522B> off/minimal/low/medium/high/max
1330
- /system <\u6587\u672C> \u66FF\u6362\u7CFB\u7EDF\u63D0\u793A\u8BCD
1331
- /session \u5F53\u524D\u4F1A\u8BDD\u4FE1\u606F
1332
- /sessions \u5217\u51FA\u5386\u53F2\u4F1A\u8BDD
1333
- /clear \u6E05\u7A7A\u5F53\u524D\u4F1A\u8BDD\uFF08\u4EC5\u5185\u5B58\uFF09
1334
- /compact \u624B\u52A8\u538B\u7F29\u4F1A\u8BDD\u5386\u53F2\uFF08\u91CA\u653E\u4E0A\u4E0B\u6587\u7A7A\u95F4\uFF09
1335
- /approvals \u672A\u51B3\u5BA1\u6279\u5355
1336
- /approve <id> \u6279\u51C6
1337
- /deny <id> \u9A73\u56DE
1338
- /mcp [refresh] MCP server \u8FDE\u63A5\u72B6\u6001 / \u70ED\u5237\u65B0\u5DE5\u5177\u5217\u8868
1339
- /quit \u9000\u51FA\uFF08Ctrl+C \u53CC\u51FB\uFF09`);
1523
+ console.log(`${chalk6.bold.magenta("\u659C\u6760\u547D\u4EE4:")}
1524
+ ${chalk6.green("/model [provider/id]")} \u5207\u6362\u6A21\u578B\uFF08\u65E0\u53C2\u663E\u793A\u5F53\u524D\uFF09
1525
+ ${chalk6.green("/thinking <\u7EA7\u522B>")} ${chalk6.dim("off/minimal/low/medium/high/max")}
1526
+ ${chalk6.green("/system <\u6587\u672C>")} \u66FF\u6362\u7CFB\u7EDF\u63D0\u793A\u8BCD
1527
+ ${chalk6.green("/session")} \u5F53\u524D\u4F1A\u8BDD\u4FE1\u606F
1528
+ ${chalk6.green("/sessions")} \u5217\u51FA\u5386\u53F2\u4F1A\u8BDD
1529
+ ${chalk6.green("/clear")} \u6E05\u7A7A\u5F53\u524D\u4F1A\u8BDD\uFF08\u4EC5\u5185\u5B58\uFF09
1530
+ ${chalk6.green("/compact")} \u624B\u52A8\u538B\u7F29\u4F1A\u8BDD\u5386\u53F2\uFF08\u91CA\u653E\u4E0A\u4E0B\u6587\u7A7A\u95F4\uFF09
1531
+ ${chalk6.green("/tools")} \u67E5\u770B\u5DE5\u5177\u96C6\u4E0E\u6743\u9650\u914D\u7F6E
1532
+ ${chalk6.green("/mcp [refresh]")} MCP server \u72B6\u6001 / \u70ED\u5237\u65B0\u5DE5\u5177\u5217\u8868
1533
+ ${chalk6.green("/approvals")} \u672A\u51B3\u5BA1\u6279\u5355
1534
+ ${chalk6.green("/approve <id>")} \u6279\u51C6
1535
+ ${chalk6.green("/deny <id>")} \u9A73\u56DE
1536
+ ${chalk6.green("/quit")} \u9000\u51FA\uFF08Ctrl+C \u53CC\u51FB\uFF09
1537
+
1538
+ ${chalk6.dim("\u8F93\u5165\u63D0\u793A:")}
1539
+ ${chalk6.dim("\xB7 \u666E\u901A\u6587\u672C\u76F4\u63A5\u53D1\u9001\uFF1B\u884C\u5C3E\u4EE5")} ${chalk6.yellow("\\")} ${chalk6.dim("\u7EED\u884C\uFF0C\u7A7A\u884C\u63D0\u4EA4\u591A\u884C")}
1540
+ ${chalk6.dim("\xB7")} ${chalk6.yellow("@\u6587\u4EF6")} ${chalk6.dim("\u53EF\u9644\u52A0\u6587\u4EF6\u4E0A\u4E0B\u6587\uFF08\u56FE\u7247\u81EA\u52A8\u8D70\u591A\u6A21\u6001\uFF09")}`);
1340
1541
  }
1341
1542
  async function onLine(line) {
1342
1543
  const text = line.trim();
1343
1544
  if (!text) {
1545
+ if (pendingMultiline.length > 0) {
1546
+ const joined = pendingMultiline.join("\n");
1547
+ pendingMultiline = [];
1548
+ await send(joined);
1549
+ } else {
1550
+ rl.prompt();
1551
+ }
1552
+ return;
1553
+ }
1554
+ if (!text.startsWith("/") && text.endsWith("\\") && !text.endsWith("\\\\")) {
1555
+ pendingMultiline.push(text.slice(0, -1));
1556
+ rl.setPrompt(chalk6.dim("\u2026 "));
1344
1557
  rl.prompt();
1345
1558
  return;
1346
1559
  }
1560
+ const full = pendingMultiline.length > 0 ? [...pendingMultiline, text].join("\n") : text;
1561
+ pendingMultiline = [];
1562
+ rl.setPrompt(buildPrompt());
1347
1563
  if (busy) {
1348
- console.log(chalk3.dim("\uFF08\u8FD0\u884C\u4E2D\uFF0C\u8F93\u5165\u88AB\u5FFD\u7565\uFF1BCtrl+C \u4E2D\u65AD\uFF09"));
1564
+ console.log(chalk6.dim("\uFF08\u8FD0\u884C\u4E2D\uFF0C\u8F93\u5165\u88AB\u5FFD\u7565\uFF1BCtrl+C \u4E2D\u65AD\uFF09"));
1349
1565
  rl.prompt();
1350
1566
  return;
1351
1567
  }
1352
- if (text.startsWith("/")) {
1353
- await handleCommand(text);
1568
+ if (full.startsWith("/")) {
1569
+ await handleCommand(full);
1354
1570
  rl.prompt();
1355
1571
  return;
1356
1572
  }
1357
- await send(text);
1573
+ await send(full);
1358
1574
  }
1359
1575
  if (opts.confirmRef) {
1360
1576
  opts.confirmRef.fn = async (req) => {
@@ -1368,10 +1584,12 @@ async function runInteractiveMode(opts) {
1368
1584
  }
1369
1585
  };
1370
1586
  }
1371
- const modelLabel = `${model.aiModel.provider}/${model.aiModel.id}${model.custom ? chalk3.yellow(" (\u81EA\u5B9A\u4E49)") : ""}`;
1372
- console.log(chalk3.bold(`${APP_NAME} ${VERSION}`) + chalk3.dim(` \u4F1A\u8BDD: ${activeKey}${args.noSession ? " (\u4E34\u65F6)" : ""}`));
1373
- console.log(chalk3.dim(`\u6A21\u578B: ${modelLabel}`));
1374
- console.log(chalk3.dim("\u8F93\u5165 /help \u67E5\u770B\u547D\u4EE4\uFF0CCtrl+C \u4E2D\u65AD\u8FD0\u884C\uFF0C\u8FDE\u6309\u4E24\u6B21\u9000\u51FA\n"));
1587
+ printStartupBanner({
1588
+ sessionKey: activeKey,
1589
+ ephemeral: args.noSession,
1590
+ modelLabel: `${model.aiModel.provider}/${model.aiModel.id}`,
1591
+ customModel: model.custom
1592
+ });
1375
1593
  setupRl();
1376
1594
  if (opts.initialMessages && opts.initialMessages.length > 0) {
1377
1595
  await send(opts.initialMessages.join("\n"));
@@ -1381,14 +1599,14 @@ async function runInteractiveMode(opts) {
1381
1599
  async function pickSessionInteractively(storage, currentKey) {
1382
1600
  const sessions = await listSessionsByRecency(storage);
1383
1601
  if (sessions.length === 0) {
1384
- console.log(chalk3.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF0C\u5C06\u65B0\u5EFA\uFF09"));
1602
+ console.log(chalk6.dim("\uFF08\u65E0\u5386\u53F2\u4F1A\u8BDD\uFF0C\u5C06\u65B0\u5EFA\uFF09"));
1385
1603
  return void 0;
1386
1604
  }
1387
- console.log(chalk3.bold("\u9009\u62E9\u4F1A\u8BDD:"));
1605
+ console.log(chalk6.bold("\u9009\u62E9\u4F1A\u8BDD:"));
1388
1606
  sessions.slice(0, 15).forEach((s, i) => {
1389
- console.log(`${s === currentKey ? chalk3.green("\u25B8 ") : " "}${i + 1}. ${s}`);
1607
+ console.log(`${s === currentKey ? chalk6.green("\u25B8 ") : " "}${i + 1}. ${s}`);
1390
1608
  });
1391
- console.log(chalk3.dim(" n. \u65B0\u4F1A\u8BDD"));
1609
+ console.log(chalk6.dim(" n. \u65B0\u4F1A\u8BDD"));
1392
1610
  const answer = await ask("\u7F16\u53F7: ");
1393
1611
  if (answer === "" || answer.toLowerCase() === "n") return void 0;
1394
1612
  const idx = Number.parseInt(answer, 10);
@@ -1399,7 +1617,7 @@ async function pickSessionInteractively(storage, currentKey) {
1399
1617
  }
1400
1618
 
1401
1619
  // src/select.ts
1402
- import chalk4 from "chalk";
1620
+ import chalk7 from "chalk";
1403
1621
  async function select(question, options, defaultIndex = 0) {
1404
1622
  const stdin = process.stdin;
1405
1623
  const out = process.stdout;
@@ -1413,7 +1631,7 @@ async function select(question, options, defaultIndex = 0) {
1413
1631
  function render() {
1414
1632
  for (let i = 0; i < options.length; i++) {
1415
1633
  const opt = options[i];
1416
- const line = i === selected ? `${chalk4.cyan("\u276F ")}${chalk4.bold(opt.label)}` : ` ${opt.label}`;
1634
+ const line = i === selected ? `${chalk7.cyan("\u276F ")}${chalk7.bold(opt.label)}` : ` ${opt.label}`;
1417
1635
  out.write(`\x1B[2K\r${line}
1418
1636
  `);
1419
1637
  }
@@ -1429,7 +1647,7 @@ async function select(question, options, defaultIndex = 0) {
1429
1647
  for (let i = 0; i < options.length; i++) out.write("\x1B[2K\r\n");
1430
1648
  out.write(`\x1B[${options.length}A`);
1431
1649
  const chosen = options.find((o) => o.value === value);
1432
- const summary = chosen ? chalk4.green(`\u2713 ${chosen.label}`) : chalk4.dim("\u5DF2\u53D6\u6D88");
1650
+ const summary = chosen ? chalk7.green(`\u2713 ${chosen.label}`) : chalk7.dim("\u5DF2\u53D6\u6D88");
1433
1651
  out.write(`\x1B[2K\r ${summary}
1434
1652
  `);
1435
1653
  resolve(value);
@@ -1457,7 +1675,7 @@ async function select(question, options, defaultIndex = 0) {
1457
1675
  }
1458
1676
  render();
1459
1677
  }
1460
- out.write(`${chalk4.yellow("?")} ${chalk4.bold(question)}
1678
+ out.write(`${chalk7.yellow("?")} ${chalk7.bold(question)}
1461
1679
  `);
1462
1680
  render();
1463
1681
  stdin.on("data", onData);
@@ -1466,8 +1684,10 @@ async function select(question, options, defaultIndex = 0) {
1466
1684
 
1467
1685
  // src/confirm.ts
1468
1686
  var DANGEROUS_PATTERNS = [
1469
- // 递归删除根/家目录(rm -rf /、rm -rf ~、rm -rf /* 等;正常子目录不受影响)
1687
+ // 递归删除根/家目录(rm -rf /、rm -rf ~、rm -rf /* 等)——最严重,优先匹配
1470
1688
  [/rm\s+[^;|&]*[rf][^;|&]*\s+(\/|~|\$HOME)(\/?\*|\s|$)/, "\u9012\u5F52\u5220\u9664\u6839/\u5BB6\u76EE\u5F55"],
1689
+ // 任何 rm 删除(单文件 / 子目录递归)——删除不可撤销,一律确认
1690
+ [/\brm\b/, "\u5220\u9664\u6587\u4EF6"],
1471
1691
  [/\bsudo(\s|$)/, "\u63D0\u6743\u6267\u884C"],
1472
1692
  [/\bmkfs(\s|\.)/, "\u683C\u5F0F\u5316\u78C1\u76D8"],
1473
1693
  [/\bdd\s+[^;|]*of=\/dev\//, "\u5199\u5165\u78C1\u76D8\u8BBE\u5907"],
@@ -1497,21 +1717,31 @@ function createToolConfirmHandler(options = {}) {
1497
1717
  const alwaysAllowed = /* @__PURE__ */ new Set();
1498
1718
  return async (req) => {
1499
1719
  if (!process.stdin.isTTY) return false;
1500
- const key = req.permissions.length > 0 ? [...req.permissions].sort().join(",") : `tool:${req.toolName}`;
1501
- if (alwaysAllowed.has(key)) return true;
1502
1720
  const args = req.args;
1503
1721
  const command = typeof args?.command === "string" ? args.command : "";
1504
- if (autoApproveSafe && command && !isDangerousCommand(command)) {
1505
- return true;
1506
- }
1507
1722
  const dangerReason = command ? isDangerousCommand(command) : null;
1723
+ const key = req.permissions.length > 0 ? [...req.permissions].sort().join(",") : `tool:${req.toolName}`;
1724
+ if (!dangerReason) {
1725
+ if (alwaysAllowed.has(key)) return true;
1726
+ if (autoApproveSafe && command) return true;
1727
+ }
1508
1728
  const summary = command || summarizeArgs(req);
1509
1729
  const question = dangerReason ? `\u5371\u9669\u547D\u4EE4\uFF08${dangerReason}\uFF09\uFF1A${summary}` : summary ? `\u5141\u8BB8\u6267\u884C ${req.toolName}\uFF1A${summary}` : `\u5141\u8BB8\u6267\u884C ${req.toolName}`;
1510
- const choice = await select(question, [
1730
+ const options2 = dangerReason ? [
1731
+ { label: "\u5141\u8BB8", value: "once" },
1732
+ { label: "\u62D2\u7EDD", value: "deny" }
1733
+ ] : [
1511
1734
  { label: "\u5141\u8BB8", value: "once" },
1512
1735
  { label: "\u603B\u662F\u5141\u8BB8\uFF08\u672C\u4F1A\u8BDD\uFF09", value: "always" },
1513
1736
  { label: "\u62D2\u7EDD", value: "deny" }
1514
- ]);
1737
+ ];
1738
+ pauseActiveSpinner();
1739
+ let choice;
1740
+ try {
1741
+ choice = await select(question, options2);
1742
+ } finally {
1743
+ resumeActiveSpinner();
1744
+ }
1515
1745
  if (choice === "always") {
1516
1746
  alwaysAllowed.add(key);
1517
1747
  return true;
@@ -1521,11 +1751,11 @@ function createToolConfirmHandler(options = {}) {
1521
1751
  }
1522
1752
 
1523
1753
  // src/cli.ts
1524
- import chalk7 from "chalk";
1754
+ import chalk10 from "chalk";
1525
1755
 
1526
1756
  // src/commands/approvals.ts
1527
1757
  import path5 from "path";
1528
- import chalk5 from "chalk";
1758
+ import chalk8 from "chalk";
1529
1759
  import { FileApprovalStore as FileApprovalStore2, createApprovalManager as createApprovalManager2 } from "@aipack-ai/agent";
1530
1760
  function createStore() {
1531
1761
  return new FileApprovalStore2({
@@ -1542,7 +1772,7 @@ async function handleApprovalsCommand(args) {
1542
1772
  if (sub === "list") {
1543
1773
  const pending = await store.load();
1544
1774
  if (pending.length === 0) {
1545
- console.log(chalk5.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\u5355\uFF09"));
1775
+ console.log(chalk8.dim("\uFF08\u65E0\u672A\u51B3\u5BA1\u6279\u5355\uFF09"));
1546
1776
  return 0;
1547
1777
  }
1548
1778
  for (const p of pending) {
@@ -1553,7 +1783,7 @@ async function handleApprovalsCommand(args) {
1553
1783
  if (sub === "approve" || sub === "deny") {
1554
1784
  const id = rest[0];
1555
1785
  if (!id) {
1556
- console.error(chalk5.red(`\u7528\u6CD5: aipack approvals ${sub} <id>`));
1786
+ console.error(chalk8.red(`\u7528\u6CD5: aipack approvals ${sub} <id>`));
1557
1787
  return 1;
1558
1788
  }
1559
1789
  const manager = createApprovalManager2({ store });
@@ -1561,26 +1791,26 @@ async function handleApprovalsCommand(args) {
1561
1791
  const ok = manager.resolve(id, sub === "approve");
1562
1792
  manager.close();
1563
1793
  if (!ok) {
1564
- console.error(chalk5.yellow(`\u5BA1\u6279\u5355 ${id} \u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97`));
1794
+ console.error(chalk8.yellow(`\u5BA1\u6279\u5355 ${id} \u4E0D\u5B58\u5728\u6216\u5DF2\u7ED3\u7B97`));
1565
1795
  return 1;
1566
1796
  }
1567
- console.log(chalk5.green(`\u5DF2${sub === "approve" ? "\u6279\u51C6" : "\u9A73\u56DE"} ${id}`));
1797
+ console.log(chalk8.green(`\u5DF2${sub === "approve" ? "\u6279\u51C6" : "\u9A73\u56DE"} ${id}`));
1568
1798
  return 0;
1569
1799
  }
1570
1800
  printUsage();
1571
- console.error(chalk5.red(`\u672A\u77E5\u5B50\u547D\u4EE4: ${sub}`));
1801
+ console.error(chalk8.red(`\u672A\u77E5\u5B50\u547D\u4EE4: ${sub}`));
1572
1802
  return 1;
1573
1803
  }
1574
1804
  function printApproval(p) {
1575
1805
  const created = new Date(p.createdAt).toLocaleString();
1576
- const expires = p.expiresAt ? chalk5.dim(` \u8FC7\u671F ${new Date(p.expiresAt).toLocaleTimeString()}`) : "";
1577
- console.log(`${chalk5.cyan(p.id)} ${chalk5.bold(p.toolName)} ${chalk5.dim(created)}${expires}`);
1806
+ const expires = p.expiresAt ? chalk8.dim(` \u8FC7\u671F ${new Date(p.expiresAt).toLocaleTimeString()}`) : "";
1807
+ console.log(`${chalk8.cyan(p.id)} ${chalk8.bold(p.toolName)} ${chalk8.dim(created)}${expires}`);
1578
1808
  if (p.permissions.length > 0) {
1579
- console.log(chalk5.dim(` \u80FD\u529B: ${p.permissions.join(", ")}`));
1809
+ console.log(chalk8.dim(` \u80FD\u529B: ${p.permissions.join(", ")}`));
1580
1810
  }
1581
1811
  const argsStr = JSON.stringify(p.args);
1582
1812
  if (argsStr && argsStr !== "{}") {
1583
- console.log(chalk5.dim(` \u53C2\u6570: ${argsStr.length > 120 ? `${argsStr.slice(0, 120)}\u2026` : argsStr}`));
1813
+ console.log(chalk8.dim(` \u53C2\u6570: ${argsStr.length > 120 ? `${argsStr.slice(0, 120)}\u2026` : argsStr}`));
1584
1814
  }
1585
1815
  }
1586
1816
  function printUsage() {
@@ -1591,33 +1821,33 @@ function printUsage() {
1591
1821
  }
1592
1822
 
1593
1823
  // src/commands/models.ts
1594
- import chalk6 from "chalk";
1595
- import { getBuiltinProviders as getBuiltinProviders2, getBuiltinModels as getBuiltinModels3, hasProviderConfigured as hasProviderConfigured2 } from "@aipack-ai/agent";
1824
+ import chalk9 from "chalk";
1825
+ import { getBuiltinProviders as getBuiltinProviders3, getBuiltinModels as getBuiltinModels3, hasProviderConfigured as hasProviderConfigured3 } from "@aipack-ai/agent";
1596
1826
  function listModels(search) {
1597
1827
  const term = typeof search === "string" ? search.toLowerCase() : void 0;
1598
1828
  let total = 0;
1599
- for (const provider of getBuiltinProviders2()) {
1829
+ for (const provider of getBuiltinProviders3()) {
1600
1830
  const models = getBuiltinModels3(provider.id);
1601
1831
  const matched = term ? models.filter((m) => m.id.toLowerCase().includes(term) || m.name.toLowerCase().includes(term) || provider.id.includes(term)) : models;
1602
1832
  if (matched.length === 0) continue;
1603
- const configured = hasProviderConfigured2(provider.id);
1604
- const badge = configured ? chalk6.green("\u2713") : chalk6.dim("\xB7");
1605
- console.log(`${badge} ${chalk6.bold(provider.name)} ${chalk6.dim(`(${provider.id})`)}`);
1833
+ const configured = hasProviderConfigured3(provider.id);
1834
+ const badge = configured ? chalk9.green("\u2713") : chalk9.dim("\xB7");
1835
+ console.log(`${badge} ${chalk9.bold(provider.name)} ${chalk9.dim(`(${provider.id})`)}`);
1606
1836
  for (const m of matched) {
1607
1837
  const flags = [
1608
- m.reasoning ? chalk6.dim("\u63A8\u7406") : null,
1838
+ m.reasoning ? chalk9.dim("\u63A8\u7406") : null,
1609
1839
  `${m.contextWindow / 1e3 | 0}k`
1610
1840
  ].filter(Boolean).join(" ");
1611
- console.log(` ${m.id.padEnd(44)} ${chalk6.dim(flags)}`);
1841
+ console.log(` ${m.id.padEnd(44)} ${chalk9.dim(flags)}`);
1612
1842
  total++;
1613
1843
  }
1614
1844
  }
1615
- console.log(chalk6.dim(`
1845
+ console.log(chalk9.dim(`
1616
1846
  \u5171 ${total} \u4E2A\u6A21\u578B\u3002\u2713 = \u5DF2\u914D\u7F6E API Key\uFF08${getEnvHint()}\uFF09`));
1617
1847
  return 0;
1618
1848
  }
1619
1849
  function getEnvHint() {
1620
- const provider = getBuiltinProviders2().find((p) => hasProviderConfigured2(p.id));
1850
+ const provider = getBuiltinProviders3().find((p) => hasProviderConfigured3(p.id));
1621
1851
  return provider ? `${provider.envVar} \u5DF2\u8BBE\u7F6E` : "\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 API Key";
1622
1852
  }
1623
1853
 
@@ -1638,12 +1868,12 @@ async function main(argv) {
1638
1868
  }
1639
1869
  const errors = args.diagnostics.filter((d) => d.type === "error");
1640
1870
  if (errors.length > 0) {
1641
- for (const e of errors) console.error(chalk7.red(e.message));
1871
+ for (const e of errors) console.error(chalk10.red(e.message));
1642
1872
  printHelp();
1643
1873
  return 1;
1644
1874
  }
1645
1875
  for (const w of args.diagnostics.filter((d) => d.type === "warning")) {
1646
- console.error(chalk7.yellow(w.message));
1876
+ console.error(chalk10.yellow(w.message));
1647
1877
  }
1648
1878
  if (args.listModels !== void 0) {
1649
1879
  return listModels(args.listModels);
@@ -1655,7 +1885,7 @@ async function main(argv) {
1655
1885
  const initial = await buildInitialMessage(args.messages, args.fileArgs, stdinText);
1656
1886
  const isNonInteractive = args.print || args.mode === "json";
1657
1887
  if (isNonInteractive && !initial.text.trim() && initial.media.length === 0) {
1658
- console.error(chalk7.red("\u975E\u4EA4\u4E92\u6A21\u5F0F\u9700\u8981\u63D0\u4F9B\u6D88\u606F\uFF08\u4F4D\u7F6E\u53C2\u6570\u3001@\u6587\u4EF6\u6216\u7BA1\u9053 stdin\uFF09"));
1888
+ console.error(chalk10.red("\u975E\u4EA4\u4E92\u6A21\u5F0F\u9700\u8981\u63D0\u4F9B\u6D88\u606F\uFF08\u4F4D\u7F6E\u53C2\u6570\u3001@\u6587\u4EF6\u6216\u7BA1\u9053 stdin\uFF09"));
1659
1889
  return 1;
1660
1890
  }
1661
1891
  const toolConfirm = createToolConfirmHandler({ autoApproveSafe: !args.safe });
@@ -1670,7 +1900,7 @@ async function main(argv) {
1670
1900
  confirmFn: (req) => confirmRef.fn(req)
1671
1901
  });
1672
1902
  } catch (err) {
1673
- console.error(chalk7.red(`\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`));
1903
+ console.error(chalk10.red(`\u521D\u59CB\u5316\u5931\u8D25: ${err instanceof Error ? err.message : String(err)}`));
1674
1904
  return 1;
1675
1905
  }
1676
1906
  try {
@@ -1733,8 +1963,12 @@ export {
1733
1963
  resolveSessionKey,
1734
1964
  buildRuntime,
1735
1965
  buildInitialMessage,
1966
+ pauseActiveSpinner,
1967
+ resumeActiveSpinner,
1968
+ Spinner,
1736
1969
  runPrintMode,
1737
1970
  runJsonMode,
1971
+ printStartupBanner,
1738
1972
  runInteractiveMode,
1739
1973
  pickSessionInteractively,
1740
1974
  select,
@@ -1742,4 +1976,4 @@ export {
1742
1976
  createToolConfirmHandler,
1743
1977
  main
1744
1978
  };
1745
- //# sourceMappingURL=chunk-CERFOZ2L.js.map
1979
+ //# sourceMappingURL=chunk-FPVG4EUX.js.map