jinzd-ai-cli 0.4.263 → 0.4.265

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 (41) hide show
  1. package/README.md +59 -37
  2. package/README.zh-CN.md +63 -41
  3. package/dist/{batch-AN47AYCZ.js → batch-C7SHXRQ2.js} +2 -2
  4. package/dist/{chunk-VT6NRDD2.js → chunk-23SJVOQD.js} +6 -2
  5. package/dist/{chunk-QMB7QYZC.js → chunk-2MR7EP24.js} +1 -1
  6. package/dist/chunk-5C76XDDF.js +78 -0
  7. package/dist/chunk-6YZEZFX5.js +40 -0
  8. package/dist/{chunk-TL5MD5XU.js → chunk-AUEX6RNY.js} +17 -1
  9. package/dist/{chunk-MTZ6XHJD.js → chunk-CVI3LSGR.js} +2 -2
  10. package/dist/{chunk-B27MLWFJ.js → chunk-E3JRGJCJ.js} +4 -4
  11. package/dist/{chunk-MJICIIBW.js → chunk-IFTUBTDA.js} +1 -1
  12. package/dist/{chunk-VUZAKIZ5.js → chunk-LZBD2VGJ.js} +1 -1
  13. package/dist/{chunk-3RHY2HF7.js → chunk-M2RKBTVZ.js} +1 -1
  14. package/dist/{chunk-7YCA2BD3.js → chunk-NJLPA6S4.js} +1 -1
  15. package/dist/{chunk-GMZTY7DA.js → chunk-NOS3QV7G.js} +13 -8
  16. package/dist/{chunk-GKI7B4BD.js → chunk-TJBG4F2R.js} +24 -95
  17. package/dist/{chunk-QG4NG7KJ.js → chunk-V4D7YD24.js} +9 -2
  18. package/dist/{chunk-3ARPAVNV.js → chunk-VOIOUJXI.js} +11 -3
  19. package/dist/{chunk-WM4VTGAF.js → chunk-X6NWK2YK.js} +1 -1
  20. package/dist/{chunk-VKBGOFEO.js → chunk-Y7KJPNQI.js} +1 -1
  21. package/dist/{chunk-XST4N2JM.js → chunk-YDTYBUAB.js} +1 -1
  22. package/dist/{chunk-5K2LFD7D.js → chunk-YXYOLPDB.js} +1 -1
  23. package/dist/{ci-JTO7LN5S.js → ci-TDXLI3OM.js} +6 -5
  24. package/dist/{ci-format-2VGHOLBA.js → ci-format-AFX2LP4Y.js} +2 -2
  25. package/dist/{constants-HLSJL5HQ.js → constants-66TQEDGO.js} +1 -1
  26. package/dist/{doctor-cli-JML4FGH4.js → doctor-cli-GMCOGCDR.js} +5 -5
  27. package/dist/electron-server.js +57 -12
  28. package/dist/{hub-6EYFGJRT.js → hub-2YXETHPY.js} +8 -4
  29. package/dist/{hub-server-QGUSMN22.js → hub-server-RF6LURXY.js} +3 -1
  30. package/dist/index.js +123 -546
  31. package/dist/{persistent-memory-MPBPSZDN.js → persistent-memory-2DKCETB7.js} +2 -2
  32. package/dist/{persistent-memory-ANIMO5CF.js → persistent-memory-WTZO5CQ7.js} +2 -2
  33. package/dist/{pr-XE7NGT6U.js → pr-Y2LDG3R7.js} +15 -10
  34. package/dist/{run-tests-TF7UPUWW.js → run-tests-FIUGDIDL.js} +2 -2
  35. package/dist/{run-tests-ME5KED57.js → run-tests-PWTNSUVP.js} +2 -2
  36. package/dist/{server-VKA4FR2Z.js → server-OZ4RFDFH.js} +25 -15
  37. package/dist/{server-BIYJEJK3.js → server-ZCG5QD6P.js} +6 -5
  38. package/dist/setup-wizard-S55ICNHH.js +483 -0
  39. package/dist/{task-orchestrator-2RAKLFWN.js → task-orchestrator-Q2L6JEUX.js} +10 -7
  40. package/dist/{usage-5F5Q3GGR.js → usage-SDL5Z4CS.js} +3 -3
  41. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- CostTracker
4
- } from "./chunk-QG4NG7KJ.js";
5
2
  import {
6
3
  McpManager,
7
4
  SNAPSHOT_PROMPT,
@@ -17,7 +14,10 @@ import {
17
14
  scanProject,
18
15
  sessionHasMeaningfulContent,
19
16
  setupProxy
20
- } from "./chunk-MTZ6XHJD.js";
17
+ } from "./chunk-CVI3LSGR.js";
18
+ import {
19
+ CostTracker
20
+ } from "./chunk-V4D7YD24.js";
21
21
  import {
22
22
  computeCost,
23
23
  formatCost,
@@ -27,6 +27,12 @@ import {
27
27
  buildReviewPrompt,
28
28
  buildSecurityReviewPrompt
29
29
  } from "./chunk-HLWUDRBO.js";
30
+ import {
31
+ NO_THINKING,
32
+ applyThinkingFlag,
33
+ chatParamsFrom,
34
+ thinkingParamsFor
35
+ } from "./chunk-6YZEZFX5.js";
30
36
  import {
31
37
  ToolExecutor,
32
38
  ToolRegistry,
@@ -38,7 +44,6 @@ import {
38
44
  formatPermissionProfileWarning,
39
45
  getRecentlyDeniedAutoActions,
40
46
  googleSearchContext,
41
- initTheme,
42
47
  isInterrupted,
43
48
  lastResponseStore,
44
49
  renderDiff,
@@ -48,9 +53,8 @@ import {
48
53
  setContextWindow,
49
54
  setMaxOutputCap,
50
55
  spawnAgentContext,
51
- theme,
52
56
  undoStack
53
- } from "./chunk-GKI7B4BD.js";
57
+ } from "./chunk-TJBG4F2R.js";
54
58
  import {
55
59
  addMemoryEntry,
56
60
  backupMemoryStore,
@@ -76,11 +80,15 @@ import {
76
80
  touchMemoryReferences,
77
81
  updateMemoryApproval,
78
82
  updateMemoryEntry
79
- } from "./chunk-VUZAKIZ5.js";
83
+ } from "./chunk-LZBD2VGJ.js";
80
84
  import "./chunk-GLSR2NR3.js";
81
85
  import "./chunk-UUSRWSSX.js";
82
86
  import "./chunk-CKH4KQ4E.js";
83
87
  import "./chunk-BXP6YZ2P.js";
88
+ import {
89
+ initTheme,
90
+ theme
91
+ } from "./chunk-5C76XDDF.js";
84
92
  import {
85
93
  SessionManager,
86
94
  getContentText
@@ -90,14 +98,14 @@ import {
90
98
  formatDoctorReport,
91
99
  loadContextFiles,
92
100
  writeCrashLog
93
- } from "./chunk-B27MLWFJ.js";
101
+ } from "./chunk-E3JRGJCJ.js";
94
102
  import {
95
103
  ProviderRegistry,
96
104
  listBuiltInProviderMetadata
97
- } from "./chunk-TL5MD5XU.js";
105
+ } from "./chunk-AUEX6RNY.js";
98
106
  import {
99
107
  ConfigManager
100
- } from "./chunk-WM4VTGAF.js";
108
+ } from "./chunk-X6NWK2YK.js";
101
109
  import {
102
110
  describePlugin,
103
111
  getActivePluginAssets,
@@ -114,7 +122,7 @@ import {
114
122
  trustHook,
115
123
  trustPlugin,
116
124
  untrustHook
117
- } from "./chunk-QMB7QYZC.js";
125
+ } from "./chunk-2MR7EP24.js";
118
126
  import {
119
127
  CONTENT_ONLY_STREAM_REMINDER,
120
128
  TEE_FINAL_USER_NUDGE,
@@ -148,7 +156,7 @@ import {
148
156
  import {
149
157
  fileCheckpoints
150
158
  } from "./chunk-4BKXL7SM.js";
151
- import "./chunk-XST4N2JM.js";
159
+ import "./chunk-YDTYBUAB.js";
152
160
  import {
153
161
  AGENTIC_BEHAVIOR_GUIDELINE,
154
162
  AUTHOR,
@@ -167,7 +175,7 @@ import {
167
175
  SKILLS_DIR_NAME,
168
176
  VERSION,
169
177
  buildUserIdentityPrompt
170
- } from "./chunk-VKBGOFEO.js";
178
+ } from "./chunk-Y7KJPNQI.js";
171
179
  import {
172
180
  buildChatIndex,
173
181
  clearChatIndex,
@@ -237,7 +245,10 @@ Now produce the title (\u2264 12 Chinese chars or \u2264 6 English words):`,
237
245
  systemPrompt: SYSTEM_PROMPT,
238
246
  stream: false,
239
247
  maxTokens: 40,
240
- temperature: 0.3
248
+ temperature: 0.3,
249
+ // 生成标题不值得付推理成本;显式关而不是靠「未配置即关」的默认兜底——
250
+ // 默认值是产品决策,哪天再变,靠默认的调用点会跟着一起变贵(审计 P0-01)。
251
+ ...NO_THINKING
241
252
  });
242
253
  const title = sanitizeTitle(resp.content);
243
254
  if (!title) return;
@@ -1166,9 +1177,22 @@ function createProviderCommands() {
1166
1177
  }
1167
1178
  if (sub === "status") {
1168
1179
  const mode = ctx.getThinkingMode();
1169
- const label = mode === true ? theme.accent("ON (runtime override)") : mode === false ? theme.dim("OFF (runtime override)") : theme.dim("using config value");
1180
+ const effective = mode ?? ctx.getConfiguredThinking() ?? false;
1181
+ const origin = mode !== null ? "runtime override" : ctx.getConfiguredThinking() !== void 0 ? "from config" : "default";
1182
+ const label = effective ? theme.accent(`ON (${origin})`) : theme.dim(`OFF (${origin})`);
1170
1183
  console.log(` Extended Thinking: ${label}`);
1171
- console.log(` Reasoning effort: ${ctx.getThinkingEffort() ?? "using config/default (high for DeepSeek V4)"}`);
1184
+ if (effective) {
1185
+ const supportsEffort = ctx.getProviderSupportsReasoningEffort();
1186
+ if (supportsEffort) {
1187
+ const effort = ctx.getThinkingEffort() ?? ctx.getConfiguredThinkingEffort();
1188
+ console.log(` Reasoning effort: ${effort ?? "high (provider default)"}`);
1189
+ } else {
1190
+ console.log(theme.dim(` Reasoning effort: n/a for ${ctx.getCurrentProvider()}`));
1191
+ }
1192
+ } else {
1193
+ console.log(theme.dim(" Enable with /think on | low | high | max, or set"));
1194
+ console.log(theme.dim(" modelParams.<model>.thinking in ~/.aicli/config.json"));
1195
+ }
1172
1196
  console.log();
1173
1197
  return;
1174
1198
  }
@@ -1340,12 +1364,12 @@ No tools match "${filter}".
1340
1364
  return;
1341
1365
  }
1342
1366
  if (sub === "install") {
1343
- const input2 = args[1];
1344
- if (!input2) {
1367
+ const input = args[1];
1368
+ if (!input) {
1345
1369
  ctx.renderer.printInfo("Usage: /plugin install <path-to-plugin-dir>");
1346
1370
  return;
1347
1371
  }
1348
- const plugin = installPlugin(configDir, input2);
1372
+ const plugin = installPlugin(configDir, input);
1349
1373
  ctx.renderer.printSuccess(`Installed plugin ${plugin.name}@${plugin.manifest.version}. Run /plugin trust ${plugin.name}, then /plugin enable ${plugin.name}.`);
1350
1374
  return;
1351
1375
  }
@@ -1407,7 +1431,7 @@ No tools match "${filter}".
1407
1431
  const { join: join6 } = await import("path");
1408
1432
  const { existsSync: existsSync6 } = await import("fs");
1409
1433
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1410
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-HLSJL5HQ.js");
1434
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-66TQEDGO.js");
1411
1435
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1412
1436
  const cwd = process.cwd();
1413
1437
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2395,7 +2419,7 @@ function createReviewCommands() {
2395
2419
  usage: "/test [command|filter]",
2396
2420
  async execute(args, ctx) {
2397
2421
  try {
2398
- const { executeTests } = await import("./run-tests-ME5KED57.js");
2422
+ const { executeTests } = await import("./run-tests-PWTNSUVP.js");
2399
2423
  const argStr = args.join(" ").trim();
2400
2424
  let testArgs = {};
2401
2425
  if (argStr) {
@@ -3782,17 +3806,20 @@ ${text}
3782
3806
  }
3783
3807
  const provider = ctx.getCurrentProvider();
3784
3808
  const model = ctx.getCurrentModel();
3785
- const cost = computeCost(provider, model, usage);
3786
3809
  const pricing = getPricing(provider, model);
3810
+ const accrued = ctx.getSessionAccruedCost();
3811
+ const usedAccrual = accrued.usd > 0;
3812
+ const cost = usedAccrual ? accrued.usd : computeCost(provider, model, usage);
3787
3813
  let savings = null;
3788
- if (cost != null && pricing && cacheRead > 0) {
3814
+ const liveCost = computeCost(provider, model, usage);
3815
+ if (liveCost != null && pricing && cacheRead > 0) {
3789
3816
  const costWithoutCache = computeCost(provider, model, {
3790
3817
  inputTokens: usage.inputTokens + cacheRead,
3791
3818
  outputTokens: usage.outputTokens,
3792
3819
  cacheCreationTokens: cacheCreate,
3793
3820
  cacheReadTokens: 0
3794
3821
  });
3795
- if (costWithoutCache != null) savings = costWithoutCache - cost;
3822
+ if (costWithoutCache != null) savings = costWithoutCache - liveCost;
3796
3823
  }
3797
3824
  console.log();
3798
3825
  console.log(theme.heading(" \u{1F4B0} Session Cost & Token Usage"));
@@ -3812,6 +3839,11 @@ ${text}
3812
3839
  console.log(theme.dim(" " + "\u2500".repeat(48)));
3813
3840
  if (cost != null) {
3814
3841
  console.log(theme.dim(" Cost : ") + chalk3.bold.cyan(formatCost(cost).padStart(12)));
3842
+ if (usedAccrual && accrued.incomplete) {
3843
+ console.log(theme.dim(" (partial \u2014 some turns had unknown pricing)"));
3844
+ } else if (!usedAccrual) {
3845
+ console.log(theme.dim(" (estimated at current rates)"));
3846
+ }
3815
3847
  if (savings != null && savings > 0) {
3816
3848
  console.log(
3817
3849
  theme.dim(" Cache savings : ") + chalk3.green(`-${formatCost(savings)}`.padStart(12)) + theme.dim(` (vs no cache)`)
@@ -4484,482 +4516,6 @@ var streamToFileContext = {
4484
4516
  extraMessages: []
4485
4517
  };
4486
4518
 
4487
- // src/repl/setup-wizard.ts
4488
- import { password, select, input, confirm } from "@inquirer/prompts";
4489
- var PROVIDERS = [
4490
- { value: "claude", name: "Claude (Anthropic)" },
4491
- { value: "gemini", name: "Gemini (Google)" },
4492
- { value: "deepseek", name: "DeepSeek" },
4493
- { value: "zhipu", name: "Zhipu (GLM)" },
4494
- { value: "kimi", name: "Kimi (Moonshot AI)" },
4495
- { value: "minimax", name: "MiniMax (\u6D77\u87BA)" },
4496
- { value: "qwen", name: "Qwen (Alibaba Cloud)" },
4497
- { value: "openai", name: "OpenAI" },
4498
- { value: "openrouter", name: "OpenRouter" },
4499
- { value: "ollama", name: "Ollama (Local)" }
4500
- ];
4501
- var NO_KEY_PROVIDERS = /* @__PURE__ */ new Set(["ollama"]);
4502
- var OLLAMA_DEFAULT_HOST = "http://localhost:11434";
4503
- function maskKey(key) {
4504
- if (key.length <= 10) return "****";
4505
- return key.slice(0, 6) + "****" + key.slice(-4);
4506
- }
4507
- function errorMessage(err) {
4508
- if (err instanceof Error && err.message) return err.message;
4509
- return String(err ?? "unknown error");
4510
- }
4511
- var SetupWizard = class {
4512
- constructor(config) {
4513
- this.config = config;
4514
- }
4515
- config;
4516
- async runFirstRun() {
4517
- console.log(theme.heading("\nWelcome to ai-cli!\n"));
4518
- console.log("Let's get to know you first, then set up your AI provider.\n");
4519
- try {
4520
- await this.setupProfile();
4521
- console.log();
4522
- const providerId = await select({
4523
- message: "Which AI provider do you want to set up first?",
4524
- choices: PROVIDERS
4525
- });
4526
- await this.setupProvider(providerId);
4527
- this.config.set("defaultProvider", providerId);
4528
- this.config.save();
4529
- const nickname = this.config.get("userProfile")?.nickname;
4530
- const greeting = nickname ? `Setup complete, ${nickname}!` : "Setup complete!";
4531
- console.log(theme.success(`
4532
- ${greeting} Starting ai-cli...
4533
- `));
4534
- return true;
4535
- } catch (err) {
4536
- const message = errorMessage(err);
4537
- const canceled = /user force closed|interrupted|cancel|aborted/i.test(message);
4538
- if (canceled) {
4539
- console.log(theme.warning("\nSetup canceled. Run aicli config to try again.\n"));
4540
- } else {
4541
- console.log(theme.error(`
4542
- First-run setup failed: ${message}`));
4543
- console.log(theme.dim(`Config directory: ${this.config.getConfigDir()}`));
4544
- console.log(theme.dim("Run aicli config to retry, or aicli doctor to inspect provider/config health.\n"));
4545
- }
4546
- return false;
4547
- }
4548
- }
4549
- async runFull() {
4550
- console.log(theme.heading("\nai-cli Configuration\n"));
4551
- let running = true;
4552
- while (running) {
4553
- const currentProxy = this.config.get("proxy") ?? "";
4554
- const proxyStatus = currentProxy ? theme.success(`[${currentProxy}]`) : theme.dim("[not configured]");
4555
- const googleKeyStatus = this.config.getApiKey("google-search") ? theme.success("[configured]") : theme.dim("[not configured]");
4556
- const profileName = this.config.get("userProfile")?.nickname || this.config.get("userProfile")?.name;
4557
- const profileStatus = profileName ? theme.success(`[${profileName}]`) : theme.dim("[not configured]");
4558
- const yoloOn = this.config.get("alwaysYolo") === true;
4559
- const mcpOff = this.config.get("mcpEnabled") === false;
4560
- const behaviorFlags = [];
4561
- if (yoloOn) behaviorFlags.push("YOLO on");
4562
- if (mcpOff) behaviorFlags.push("MCP off");
4563
- const behaviorStatus = behaviorFlags.length ? theme.warning(`[${behaviorFlags.join(", ")}]`) : theme.dim("[default]");
4564
- const action = await select({
4565
- message: "What would you like to configure?",
4566
- choices: [
4567
- { value: "profile", name: `Edit your profile (identity) ${profileStatus}` },
4568
- { value: "apikey", name: "Manage API key for a provider" },
4569
- { value: "default", name: "Change default provider" },
4570
- { value: "proxy", name: `Configure proxy (HTTP/HTTPS) ${proxyStatus}` },
4571
- { value: "google", name: `Configure Google Search (API Key + CX) ${googleKeyStatus}` },
4572
- { value: "behavior", name: `Behavior toggles (YOLO, MCP, ...) ${behaviorStatus}` },
4573
- { value: "preset", name: "Apply task preset (safe review, workspace coding, local-only, team web)" },
4574
- { value: "done", name: "Done" }
4575
- ]
4576
- });
4577
- if (action === "profile") {
4578
- await this.setupProfile();
4579
- } else if (action === "proxy") {
4580
- await this.setupProxy();
4581
- } else if (action === "google") {
4582
- await this.setupGoogleSearch();
4583
- } else if (action === "behavior") {
4584
- await this.setupBehavior();
4585
- } else if (action === "preset") {
4586
- await this.setupPreset();
4587
- } else if (action === "apikey") {
4588
- const choicesWithStatus = PROVIDERS.map((p) => {
4589
- if (NO_KEY_PROVIDERS.has(p.value)) {
4590
- return { value: p.value, name: `${p.name} ${theme.dim("[no API key needed]")}` };
4591
- }
4592
- const existingKey = this.config.getApiKey(p.value);
4593
- const status = existingKey ? theme.success(`[${maskKey(existingKey)}]`) : theme.dim("[not configured]");
4594
- return { value: p.value, name: `${p.name} ${status}` };
4595
- });
4596
- const providerId = await select({
4597
- message: "Select provider:",
4598
- choices: choicesWithStatus
4599
- });
4600
- await this.setupProvider(providerId);
4601
- } else if (action === "default") {
4602
- const providerId = await select({
4603
- message: "Select default provider:",
4604
- choices: PROVIDERS
4605
- });
4606
- this.config.set("defaultProvider", providerId);
4607
- this.config.save();
4608
- console.log(theme.success(`Default provider set to: ${providerId}
4609
- `));
4610
- } else {
4611
- running = false;
4612
- }
4613
- }
4614
- }
4615
- async setupPreset() {
4616
- const preset = await select({
4617
- message: "Choose a task-oriented preset:",
4618
- choices: [
4619
- { value: "safe-review", name: "Safe review only - read-only tools, network confirm" },
4620
- { value: "workspace-coding", name: "Workspace coding - write in workspace with confirmations" },
4621
- { value: "local-ollama", name: "Local-only Ollama - local provider, external network denied" },
4622
- { value: "team-web", name: "Team Web UI - workspace coding plus auth reminder" }
4623
- ]
4624
- });
4625
- const currentNetwork = this.config.get("networkPolicy");
4626
- if (preset === "safe-review") {
4627
- this.config.set("defaultPermissionProfile", "read-only");
4628
- this.config.set("alwaysYolo", false);
4629
- this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "confirm", tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "confirm", web_search: "confirm", google_search: "confirm", mcp: "confirm" } });
4630
- console.log(theme.success("Preset applied: Safe review only. Writes require denial/confirmation according to the read-only profile."));
4631
- } else if (preset === "workspace-coding") {
4632
- this.config.set("defaultPermissionProfile", "workspace-write");
4633
- this.config.set("alwaysYolo", false);
4634
- this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "confirm", tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "confirm", web_search: "confirm", google_search: "confirm", mcp: "confirm" } });
4635
- console.log(theme.success("Preset applied: Workspace coding. File writes stay inside the workspace and sensitive actions still ask."));
4636
- } else if (preset === "local-ollama") {
4637
- this.config.set("defaultProvider", "ollama");
4638
- this.config.set("defaultPermissionProfile", "workspace-write");
4639
- this.config.set("alwaysYolo", false);
4640
- this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "deny", allowPrivateNetwork: true, tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "deny", web_search: "deny", google_search: "deny", mcp: "confirm" } });
4641
- console.log(theme.success("Preset applied: Local-only Ollama. External web/search is denied; private network is allowed for local services."));
4642
- } else {
4643
- this.config.set("defaultPermissionProfile", "workspace-write");
4644
- this.config.set("alwaysYolo", false);
4645
- this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "confirm", tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "confirm", web_search: "confirm", google_search: "confirm", mcp: "confirm" } });
4646
- console.log(theme.warning("Preset applied: Team Web UI. Start Web with auth enabled and put it behind your normal TLS/reverse proxy boundary."));
4647
- }
4648
- this.config.save();
4649
- console.log(theme.dim("Review changes with aicli doctor or aicli config.\n"));
4650
- }
4651
- async setupProvider(providerId) {
4652
- if (NO_KEY_PROVIDERS.has(providerId)) {
4653
- await this.setupOllama();
4654
- return;
4655
- }
4656
- const provider = PROVIDERS.find((p) => p.value === providerId);
4657
- const displayName = provider?.name ?? providerId;
4658
- const existingKey = this.config.getApiKey(providerId);
4659
- console.log(`
4660
- Managing ${displayName} API Key`);
4661
- if (existingKey) {
4662
- console.log(theme.dim(` Current: ${maskKey(existingKey)}`));
4663
- } else {
4664
- console.log(theme.dim(" Current: (not configured)"));
4665
- }
4666
- const choices = existingKey ? [
4667
- { value: "keep", name: "Keep current key" },
4668
- { value: "fingerprint", name: `Copy masked fingerprint (${maskKey(existingKey)})` },
4669
- { value: "change", name: "Update key" }
4670
- ] : [{ value: "change", name: "Enter key" }, { value: "skip", name: "Skip" }];
4671
- const action = await select({
4672
- message: "Action:",
4673
- choices
4674
- });
4675
- if (action === "fingerprint" && existingKey) {
4676
- console.log(theme.dim(`
4677
- Fingerprint: ${maskKey(existingKey)}`));
4678
- console.log(theme.dim(" Full secrets are not printed. Use Update key to replace it.\n"));
4679
- return;
4680
- } else if (action === "keep" || action === "skip") {
4681
- return;
4682
- }
4683
- const newKey = await password({
4684
- message: `Enter ${displayName} API key:`,
4685
- validate: (val) => val.length > 0 || "API key cannot be empty"
4686
- });
4687
- this.config.setApiKey(providerId, newKey);
4688
- console.log(theme.success(`API key saved for ${displayName}: ${maskKey(newKey)}
4689
- `));
4690
- }
4691
- /** Ollama 专用配置:检测连通性、发现本地模型、可选自定义地址 */
4692
- async setupOllama() {
4693
- console.log(theme.heading("\n\u{1F999} Ollama (Local) Configuration"));
4694
- console.log(theme.dim(" Ollama runs AI models locally \u2014 no API key needed."));
4695
- console.log(theme.dim(" Install: https://ollama.com\n"));
4696
- const customBaseUrls = this.config.get("customBaseUrls") ?? {};
4697
- const currentHost = customBaseUrls["ollama"] ? customBaseUrls["ollama"].replace(/\/v1\/?$/, "") : OLLAMA_DEFAULT_HOST;
4698
- const ollamaHost = await input({
4699
- message: "Ollama server address:",
4700
- default: currentHost,
4701
- validate: (val) => {
4702
- if (!val) return "Address cannot be empty";
4703
- if (!val.startsWith("http://") && !val.startsWith("https://")) {
4704
- return "Must start with http:// or https://";
4705
- }
4706
- return true;
4707
- }
4708
- });
4709
- const host = ollamaHost.replace(/\/+$/, "");
4710
- console.log(theme.dim(`
4711
- Connecting to ${host}...`));
4712
- let models = [];
4713
- try {
4714
- const res = await fetch(`${host}/api/tags`, { signal: AbortSignal.timeout(5e3) });
4715
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
4716
- const data = await res.json();
4717
- models = data.models ?? [];
4718
- } catch {
4719
- console.log(theme.error(` \u2717 Cannot connect to Ollama at ${host}`));
4720
- console.log(theme.dim(" Make sure Ollama is running: ollama serve\n"));
4721
- return;
4722
- }
4723
- if (models.length === 0) {
4724
- console.log(theme.warning(" \u26A0 Ollama is running but no models installed."));
4725
- console.log(theme.dim(" Install a model: ollama pull llama3.1\n"));
4726
- return;
4727
- }
4728
- console.log(theme.success(` \u2713 Connected! Found ${models.length} model(s):
4729
- `));
4730
- for (const m of models) {
4731
- const size = m.details?.parameter_size ?? `${(m.size / 1e9).toFixed(1)}GB`;
4732
- console.log(` \u2022 ${m.name} ${theme.dim(`(${size})`)}`);
4733
- }
4734
- console.log();
4735
- if (host !== OLLAMA_DEFAULT_HOST) {
4736
- const urls = { ...customBaseUrls, ollama: `${host}/v1` };
4737
- this.config.set("customBaseUrls", urls);
4738
- }
4739
- this.config.save();
4740
- console.log(theme.success(" Ollama configured! Use /provider ollama to switch.\n"));
4741
- }
4742
- async setupProxy() {
4743
- const current = this.config.get("proxy") ?? "";
4744
- console.log("\nHTTP/HTTPS Proxy Configuration");
4745
- console.log(theme.dim(" Used for providers that require a proxy (e.g. Gemini in China)"));
4746
- if (current) {
4747
- console.log(theme.dim(` Current: ${current}`));
4748
- }
4749
- const action = await select({
4750
- message: "Action:",
4751
- choices: current ? [
4752
- { value: "keep", name: "Keep current" },
4753
- { value: "change", name: "Update" },
4754
- { value: "clear", name: "Remove proxy" }
4755
- ] : [
4756
- { value: "change", name: "Set proxy" },
4757
- { value: "skip", name: "Skip" }
4758
- ]
4759
- });
4760
- if (action === "keep" || action === "skip") return;
4761
- if (action === "clear") {
4762
- this.config.set("proxy", void 0);
4763
- this.config.save();
4764
- console.log(theme.success("Proxy cleared.\n"));
4765
- return;
4766
- }
4767
- const proxyUrl = await input({
4768
- message: "Enter proxy URL (e.g. http://127.0.0.1:10809):",
4769
- default: current || void 0,
4770
- validate: (val) => {
4771
- if (!val) return "Proxy URL cannot be empty";
4772
- if (!val.startsWith("http://") && !val.startsWith("https://")) {
4773
- return "Must start with http:// or https://";
4774
- }
4775
- return true;
4776
- }
4777
- });
4778
- this.config.set("proxy", proxyUrl);
4779
- this.config.save();
4780
- console.log(theme.success(`Proxy saved: ${proxyUrl}
4781
- `));
4782
- }
4783
- /** Behavior toggles — alwaysYolo, mcpEnabled, and friends (v0.4.126+). */
4784
- async setupBehavior() {
4785
- let running = true;
4786
- while (running) {
4787
- const yoloOn = this.config.get("alwaysYolo") === true;
4788
- const mcpEnabled = this.config.get("mcpEnabled") !== false;
4789
- const yoloStatus = yoloOn ? theme.warning("[ON]") : theme.dim("[off]");
4790
- const mcpStatus = mcpEnabled ? theme.success("[enabled]") : theme.warning("[disabled]");
4791
- console.log(theme.heading("\n\u2699 Behavior Toggles\n"));
4792
- const action = await select({
4793
- message: "Which toggle?",
4794
- choices: [
4795
- { value: "yolo", name: `alwaysYolo ${yoloStatus}` },
4796
- { value: "mcp", name: `mcpEnabled ${mcpStatus}` },
4797
- { value: "done", name: "Done" }
4798
- ]
4799
- });
4800
- if (action === "yolo") {
4801
- await this.toggleAlwaysYolo();
4802
- } else if (action === "mcp") {
4803
- await this.toggleMcpEnabled();
4804
- } else {
4805
- running = false;
4806
- }
4807
- }
4808
- }
4809
- async toggleAlwaysYolo() {
4810
- const current = this.config.get("alwaysYolo") === true;
4811
- console.log(" alwaysYolo: " + (current ? theme.warning("ON") : theme.dim("off")));
4812
- console.log(
4813
- theme.dim(
4814
- " When ON, REPL starts with sessionAutoApprove enabled \u2014 write\n tools (write_file/edit_file, etc.) run without confirmation prompts. Destructive tools still require confirmation. Only enable this\n if you fully trust the working directory you run aicli in.\n"
4815
- )
4816
- );
4817
- const next = await confirm({
4818
- message: current ? "Keep alwaysYolo enabled?" : "Enable alwaysYolo (skip write confirmations; destructive still confirms)?",
4819
- default: current
4820
- });
4821
- if (next === current) {
4822
- console.log(theme.dim(" No change.\n"));
4823
- return;
4824
- }
4825
- this.config.set("alwaysYolo", next);
4826
- this.config.save();
4827
- if (next) {
4828
- console.log(theme.warning(" \u26A1 alwaysYolo enabled \u2014 confirmations will be skipped on next REPL start.\n"));
4829
- } else {
4830
- console.log(theme.success(" alwaysYolo disabled \u2014 confirmations restored on next REPL start.\n"));
4831
- }
4832
- }
4833
- async toggleMcpEnabled() {
4834
- const current = this.config.get("mcpEnabled") !== false;
4835
- console.log(" mcpEnabled: " + (current ? theme.success("enabled") : theme.warning("disabled")));
4836
- console.log(
4837
- theme.dim(
4838
- " Global switch for the MCP (Model Context Protocol) subsystem. When disabled,\n REPL startup skips loadProjectMcpConfig() and mcpManager.connectAll() \u2014\n no MCP servers are spawned, no MCP tools appear in the tool list, faster boot.\n Per-server entries in config.mcpServers are preserved but ignored. Disable this\n if you don't use MCP and want a leaner startup / smaller tool schema.\n"
4839
- )
4840
- );
4841
- const next = await confirm({
4842
- message: current ? "Keep MCP enabled?" : "Re-enable MCP?",
4843
- default: current
4844
- });
4845
- if (next === current) {
4846
- console.log(theme.dim(" No change.\n"));
4847
- return;
4848
- }
4849
- this.config.set("mcpEnabled", next);
4850
- this.config.save();
4851
- if (next) {
4852
- console.log(theme.success(" MCP enabled \u2014 servers will connect on next REPL start.\n"));
4853
- } else {
4854
- console.log(theme.warning(" \u{1F50C} MCP disabled \u2014 no MCP servers will load on next REPL start.\n"));
4855
- }
4856
- }
4857
- async setupGoogleSearch() {
4858
- console.log("\nGoogle Custom Search Configuration");
4859
- console.log(theme.dim(" Enables AI to search the web via google_search tool"));
4860
- console.log(theme.dim(" Requires: API Key + Search Engine ID (cx)"));
4861
- console.log(theme.dim(" Get API Key: https://console.cloud.google.com/apis/credentials"));
4862
- console.log(theme.dim(" Get CX: https://programmablesearchengine.google.com/"));
4863
- const existingKey = this.config.getApiKey("google-search");
4864
- if (existingKey) {
4865
- console.log(theme.dim(`
4866
- API Key: ${maskKey(existingKey)}`));
4867
- } else {
4868
- console.log(theme.dim("\n API Key: (not configured)"));
4869
- }
4870
- const keyAction = await select({
4871
- message: "API Key:",
4872
- choices: existingKey ? [
4873
- { value: "keep", name: "Keep current" },
4874
- { value: "change", name: "Update API Key" }
4875
- ] : [
4876
- { value: "change", name: "Enter API Key" },
4877
- { value: "skip", name: "Skip" }
4878
- ]
4879
- });
4880
- if (keyAction === "change") {
4881
- const newKey = await password({
4882
- message: "Enter Google API Key:",
4883
- validate: (val) => val.length > 0 || "API key cannot be empty"
4884
- });
4885
- this.config.setApiKey("google-search", newKey);
4886
- console.log(theme.success(` API Key saved: ${maskKey(newKey)}`));
4887
- }
4888
- const existingCx = this.config.get("googleSearchEngineId") ?? "";
4889
- if (existingCx) {
4890
- console.log(theme.dim(`
4891
- Search Engine ID: ${existingCx}`));
4892
- } else {
4893
- console.log(theme.dim("\n Search Engine ID: (not configured)"));
4894
- }
4895
- const cxAction = await select({
4896
- message: "Search Engine ID (cx):",
4897
- choices: existingCx ? [
4898
- { value: "keep", name: "Keep current" },
4899
- { value: "change", name: "Update CX" }
4900
- ] : [
4901
- { value: "change", name: "Enter CX" },
4902
- { value: "skip", name: "Skip" }
4903
- ]
4904
- });
4905
- if (cxAction === "change") {
4906
- const newCx = await input({
4907
- message: "Enter Search Engine ID (cx):",
4908
- default: existingCx || void 0,
4909
- validate: (val) => val.length > 0 || "Search Engine ID cannot be empty"
4910
- });
4911
- this.config.set("googleSearchEngineId", newCx);
4912
- this.config.save();
4913
- console.log(theme.success(` Search Engine ID saved: ${newCx}`));
4914
- }
4915
- console.log();
4916
- }
4917
- /** 收集用户身份档案 — aicli 的 "灵魂" 功能 */
4918
- async setupProfile() {
4919
- const existing = this.config.get("userProfile") ?? {};
4920
- console.log(theme.heading("\n\u{1F464} Your Profile"));
4921
- console.log(theme.dim(" This helps AI know who you are \u2014 across all providers and sessions.\n"));
4922
- const name = await input({
4923
- message: "Your name:",
4924
- default: existing.name || void 0
4925
- });
4926
- const nickname = await input({
4927
- message: "Preferred nickname (AI will call you this):",
4928
- default: existing.nickname || void 0
4929
- });
4930
- const role = await input({
4931
- message: 'Your role (e.g. "Full-stack developer", "Student"):',
4932
- default: existing.role || void 0
4933
- });
4934
- const bio = await input({
4935
- message: "Brief intro (1-2 sentences about your background):",
4936
- default: existing.bio || void 0
4937
- });
4938
- const interestsStr = await input({
4939
- message: "Interests / tech stack (comma-separated):",
4940
- default: existing.interests?.join(", ") || void 0
4941
- });
4942
- const locale = await input({
4943
- message: 'Preferred language (e.g. "zh-CN", "en", "ja"):',
4944
- default: existing.locale || void 0
4945
- });
4946
- const profile = {};
4947
- if (name) profile.name = name;
4948
- if (nickname) profile.nickname = nickname;
4949
- if (role) profile.role = role;
4950
- if (bio) profile.bio = bio;
4951
- if (interestsStr) profile.interests = interestsStr.split(",").map((s) => s.trim()).filter(Boolean);
4952
- if (locale) profile.locale = locale;
4953
- if (existing.extra) profile.extra = existing.extra;
4954
- this.config.set("userProfile", profile);
4955
- this.config.save();
4956
- const displayName = nickname || name || "User";
4957
- console.log(theme.success(`
4958
- Profile saved! AI will know you as "${displayName}".
4959
- `));
4960
- }
4961
- };
4962
-
4963
4519
  // src/repl/custom-commands.ts
4964
4520
  import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync, mkdirSync as mkdirSync3 } from "fs";
4965
4521
  import { join as join3, extname } from "path";
@@ -5225,12 +4781,12 @@ var IMAGE_MIME = {
5225
4781
  };
5226
4782
  var MAX_IMAGE_BYTES = 10 * 1024 * 1024;
5227
4783
  var MAX_PATH_SPACE_TOKENS = 8;
5228
- function expandUnquotedPath(input2, pathStart, rawPath, cwd) {
4784
+ function expandUnquotedPath(input, pathStart, rawPath, cwd) {
5229
4785
  const plain = { raw: rawPath, consumed: rawPath.length };
5230
4786
  if (existsSync4(resolve2(cwd, rawPath))) return plain;
5231
4787
  let acc = rawPath;
5232
4788
  let consumed = rawPath.length;
5233
- let rest = input2.slice(pathStart + rawPath.length);
4789
+ let rest = input.slice(pathStart + rawPath.length);
5234
4790
  for (let i = 0; i < MAX_PATH_SPACE_TOKENS; i++) {
5235
4791
  const next = /^([ \t]+)(\S+)/.exec(rest);
5236
4792
  if (!next) break;
@@ -5241,18 +4797,18 @@ function expandUnquotedPath(input2, pathStart, rawPath, cwd) {
5241
4797
  }
5242
4798
  return plain;
5243
4799
  }
5244
- function parseAtReferences(input2, cwd) {
4800
+ function parseAtReferences(input, cwd) {
5245
4801
  const atPattern = /@(?:"([^"]+)"|'([^']+)'|(\S+))/g;
5246
4802
  const refs = [];
5247
4803
  const imageParts = [];
5248
- let textBody = input2;
4804
+ let textBody = input;
5249
4805
  let match;
5250
- while ((match = atPattern.exec(input2)) !== null) {
4806
+ while ((match = atPattern.exec(input)) !== null) {
5251
4807
  let rawPath = match[1] ?? match[2] ?? match[3] ?? "";
5252
4808
  let matchedText = match[0];
5253
4809
  if (match[3] !== void 0) {
5254
4810
  const pathStart = match.index + 1;
5255
- const expanded = expandUnquotedPath(input2, pathStart, rawPath, cwd);
4811
+ const expanded = expandUnquotedPath(input, pathStart, rawPath, cwd);
5256
4812
  if (expanded.consumed > rawPath.length) {
5257
4813
  rawPath = expanded.raw;
5258
4814
  matchedText = "@" + expanded.raw;
@@ -5321,7 +4877,7 @@ function removePreviousGrapheme(line, cursor) {
5321
4877
  cursor: start
5322
4878
  };
5323
4879
  }
5324
- function installUnicodeBackspaceRepair(input2, rl, shouldHandle = () => true) {
4880
+ function installUnicodeBackspaceRepair(input, rl, shouldHandle = () => true) {
5325
4881
  const editable = rl;
5326
4882
  let previous = { line: editable.line, cursor: editable.cursor };
5327
4883
  const onKeypress = (_character, key) => {
@@ -5336,20 +4892,8 @@ function installUnicodeBackspaceRepair(input2, rl, shouldHandle = () => true) {
5336
4892
  }
5337
4893
  previous = current;
5338
4894
  };
5339
- input2.on("keypress", onKeypress);
5340
- return () => input2.off("keypress", onKeypress);
5341
- }
5342
-
5343
- // src/repl/chat-params.ts
5344
- function chatParamsFrom(params) {
5345
- return {
5346
- temperature: params.temperature,
5347
- maxTokens: params.maxTokens,
5348
- timeout: params.timeout,
5349
- thinking: params.thinking,
5350
- thinkingEffort: params.thinkingEffort,
5351
- thinkingBudget: params.thinkingBudget
5352
- };
4895
+ input.on("keypress", onKeypress);
4896
+ return () => input.off("keypress", onKeypress);
5353
4897
  }
5354
4898
 
5355
4899
  // src/core/model-router.ts
@@ -5721,6 +5265,13 @@ var Repl = class {
5721
5265
  /** 本次会话累计 token 用量 */
5722
5266
  sessionTokenUsage = { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
5723
5267
  unknownPricingWarnings = /* @__PURE__ */ new Set();
5268
+ /**
5269
+ * 本会话按**调用时刻**费率累计的成本(美元)。峰谷计价下,事后拿聚合用量现算
5270
+ * 会给出错的数字——闲时跑的会话在峰时查看会被按峰价显示(审计 P3-01)。
5271
+ */
5272
+ sessionAccruedCostUsd = 0;
5273
+ /** 本会话是否出现过定价未知的调用(此时累计值不完整,展示层需据实说明) */
5274
+ sessionCostIncomplete = false;
5724
5275
  /** Fold a single-request TokenUsage (with optional cache fields) into sessionTokenUsage + cost tracker.
5725
5276
  * modelOverride lets the smart router attribute cost to the actually-used model
5726
5277
  * when it differs from the UI-selected currentModel. */
@@ -5738,7 +5289,9 @@ var Repl = class {
5738
5289
  this.renderer.printInfo(`Cost notice: pricing is unknown for ${key}. Tokens are tracked, but cost is excluded from totals. Run aicli usage to review unknown-priced models.`);
5739
5290
  }
5740
5291
  }
5741
- this.costTracker.addCost(this.currentProvider, effectiveModel, u);
5292
+ const priced = this.costTracker.addCost(this.currentProvider, effectiveModel, u);
5293
+ if (priced === null) this.sessionCostIncomplete = true;
5294
+ else this.sessionAccruedCostUsd += priced;
5742
5295
  }
5743
5296
  /** 启动时检测到的 Git 分支(无 git 仓库时为 null) */
5744
5297
  gitBranch = null;
@@ -6160,7 +5713,8 @@ ${ctxLine}` : "")
6160
5713
  const skillTag = activeSkill ? theme.toolCall(`[${activeSkill.meta.name}]`) : "";
6161
5714
  const planTag = this.planMode ? theme.warning("[PLAN]") : "";
6162
5715
  const modelParams = this.getModelParams();
6163
- const thinkTag = modelParams.thinking ? theme.accent(`[THINK:${modelParams.thinkingEffort ?? "high"}]`) : "";
5716
+ const showsEffort = this.providers.get(this.currentProvider)?.supportsReasoningEffort ?? false;
5717
+ const thinkTag = modelParams.thinking ? theme.accent(showsEffort ? `[THINK:${modelParams.thinkingEffort ?? "high"}]` : "[THINK]") : "";
6164
5718
  const promptStr = theme.success(`[${this.currentProvider}]`) + skillTag + planTag + thinkTag + chalk5.white(" > ");
6165
5719
  this.rl.setPrompt(promptStr);
6166
5720
  }
@@ -6488,8 +6042,8 @@ Session '${this.resumeSessionId}' not found.
6488
6042
  let processing = false;
6489
6043
  let pasteTimer = null;
6490
6044
  const PASTE_DEBOUNCE_MS = 50;
6491
- const processInput = async (input2) => {
6492
- if (!input2) {
6045
+ const processInput = async (input) => {
6046
+ if (!input) {
6493
6047
  this.showPrompt();
6494
6048
  return;
6495
6049
  }
@@ -6499,10 +6053,10 @@ Session '${this.resumeSessionId}' not found.
6499
6053
  const savedOutput = rlAny.output;
6500
6054
  rlAny.output = null;
6501
6055
  try {
6502
- if (input2.startsWith("/")) {
6503
- await this.handleCommand(input2);
6056
+ if (input.startsWith("/")) {
6057
+ await this.handleCommand(input);
6504
6058
  } else {
6505
- await this.handleChat(input2);
6059
+ await this.handleChat(input);
6506
6060
  }
6507
6061
  } catch (err) {
6508
6062
  this.renderer.renderError(err);
@@ -7169,7 +6723,13 @@ Session '${this.resumeSessionId}' not found.
7169
6723
  spinner.stop();
7170
6724
  this.renderer.renderResponse(response.content);
7171
6725
  lastResponseStore.content = response.content;
7172
- session.addMessage({ role: "assistant", content: response.content, timestamp: /* @__PURE__ */ new Date() });
6726
+ session.addMessage({
6727
+ role: "assistant",
6728
+ content: response.content,
6729
+ timestamp: /* @__PURE__ */ new Date(),
6730
+ // 非流式路径同样要落 reasoningContent,否则 V4 thinking 的多轮推理断链(审计 P1-02)
6731
+ ...response.reasoningContent ? { reasoningContent: response.reasoningContent } : {}
6732
+ });
7173
6733
  this.events.emit("message.after", { content: response.content });
7174
6734
  if (response.usage) {
7175
6735
  this.addSessionUsage(response.usage, effectiveModel);
@@ -7852,8 +7412,8 @@ Tip: You can continue the conversation by asking the AI to proceed.`
7852
7412
  await this.checkContextPressure();
7853
7413
  }
7854
7414
  }
7855
- async handleCommand(input2) {
7856
- const parts = input2.slice(1).split(" ");
7415
+ async handleCommand(input) {
7416
+ const parts = input.slice(1).split(" ");
7857
7417
  const cmdName = parts[0].toLowerCase();
7858
7418
  const args = parts.slice(1);
7859
7419
  const cmd = this.commands.get(cmdName);
@@ -7949,7 +7509,10 @@ Tip: You can continue the conversation by asking the AI to proceed.`
7949
7509
  cacheCreationTokens: 0,
7950
7510
  cacheReadTokens: 0
7951
7511
  };
7512
+ this.sessionAccruedCostUsd = 0;
7513
+ this.sessionCostIncomplete = false;
7952
7514
  },
7515
+ getSessionAccruedCost: () => ({ usd: this.sessionAccruedCostUsd, incomplete: this.sessionCostIncomplete }),
7953
7516
  getGitBranch: () => this.gitBranch,
7954
7517
  getLastResponse: () => lastResponseStore.content,
7955
7518
  runSetupWizard: async () => {
@@ -7957,6 +7520,7 @@ Tip: You can continue the conversation by asking the AI to proceed.`
7957
7520
  rlAny.output = process.stdout;
7958
7521
  process.stdin.resume();
7959
7522
  try {
7523
+ const { SetupWizard } = await import("./setup-wizard-S55ICNHH.js");
7960
7524
  const wizard = new SetupWizard(this.config);
7961
7525
  await wizard.runFull();
7962
7526
  } finally {
@@ -7977,6 +7541,9 @@ Tip: You can continue the conversation by asking the AI to proceed.`
7977
7541
  this.runtimeThinking = value;
7978
7542
  this.refreshPrompt();
7979
7543
  },
7544
+ getProviderSupportsReasoningEffort: () => this.providers.get(this.currentProvider)?.supportsReasoningEffort ?? false,
7545
+ getConfiguredThinking: () => this.config.get("modelParams")[this.currentModel]?.thinking,
7546
+ getConfiguredThinkingEffort: () => this.config.get("modelParams")[this.currentModel]?.thinkingEffort,
7980
7547
  getThinkingEffort: () => this.runtimeThinkingEffort,
7981
7548
  setThinkingEffort: (value) => {
7982
7549
  this.runtimeThinkingEffort = value;
@@ -8115,7 +7682,7 @@ process.on("unhandledRejection", (reason) => {
8115
7682
  });
8116
7683
  var builtInProviderIds = listBuiltInProviderMetadata().map(({ id }) => id).join("/");
8117
7684
  program.name("aicli").description("Cross-platform REPL-style AI CLI with multi-provider support").version(VERSION);
8118
- program.option("--provider <name>", `AI provider to use (${builtInProviderIds}, or any custom provider)`).option("-m, --model <name>", "Model to use").option("-p, --prompt <text>", "Headless mode: send a single prompt and exit (reads stdin as context if piped)").option("--system <prompt>", "System prompt override (headless mode)").option("--json", "Output result as JSON object (headless mode only)").option("--output-format <format>", "Output format: text (default) | streaming-json (NDJSON per-chunk, headless only)").option("--no-stream", "Disable streaming output").option("--allowed-tools <tools>", "Comma-separated whitelist of tools (e.g. bash,read_file)").option("--blocked-tools <tools>", "Comma-separated blacklist of tools (e.g. bash,write_file)").option("--resume <id>", "Resume a previous session by ID (prefix match supported)").option("--max-tool-rounds <n>", "Max agentic tool-call rounds per conversation (default: 200)").action(async (options) => {
7685
+ program.option("--provider <name>", `AI provider to use (${builtInProviderIds}, or any custom provider)`).option("-m, --model <name>", "Model to use").option("-p, --prompt <text>", "Headless mode: send a single prompt and exit (reads stdin as context if piped)").option("--system <prompt>", "System prompt override (headless mode)").option("--json", "Output result as JSON object (headless mode only)").option("--output-format <format>", "Output format: text (default) | streaming-json (NDJSON per-chunk, headless only)").option("--no-stream", "Disable streaming output").option("--allowed-tools <tools>", "Comma-separated whitelist of tools (e.g. bash,read_file)").option("--blocked-tools <tools>", "Comma-separated blacklist of tools (e.g. bash,write_file)").option("--resume <id>", "Resume a previous session by ID (prefix match supported)").option("--max-tool-rounds <n>", "Max agentic tool-call rounds per conversation (default: 200)").option("--think <mode>", "Thinking for this run: off | on | low | high | max (default: follow config)").action(async (options) => {
8119
7686
  if (options.prompt !== void 0) {
8120
7687
  await runHeadless(options);
8121
7688
  } else {
@@ -8124,6 +7691,7 @@ program.option("--provider <name>", `AI provider to use (${builtInProviderIds},
8124
7691
  });
8125
7692
  program.command("config").description("Configure API keys and preferences").action(async () => {
8126
7693
  const config = new ConfigManager();
7694
+ const { SetupWizard } = await import("./setup-wizard-S55ICNHH.js");
8127
7695
  const wizard = new SetupWizard(config);
8128
7696
  await wizard.runFull();
8129
7697
  console.log("Configuration saved.");
@@ -8162,7 +7730,7 @@ program.command("web").description("Start Web UI server with browser-based chat
8162
7730
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
8163
7731
  process.exit(1);
8164
7732
  }
8165
- const { startWebServer } = await import("./server-VKA4FR2Z.js");
7733
+ const { startWebServer } = await import("./server-OZ4RFDFH.js");
8166
7734
  await startWebServer({ port, host: options.host });
8167
7735
  });
8168
7736
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -8329,11 +7897,11 @@ program.command("sessions").description("List recent conversation sessions").opt
8329
7897
  console.log(footer + "\n");
8330
7898
  });
8331
7899
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
8332
- const { runUsageCli } = await import("./usage-5F5Q3GGR.js");
7900
+ const { runUsageCli } = await import("./usage-SDL5Z4CS.js");
8333
7901
  await runUsageCli(options);
8334
7902
  });
8335
7903
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
8336
- const { runDoctorCli } = await import("./doctor-cli-JML4FGH4.js");
7904
+ const { runDoctorCli } = await import("./doctor-cli-GMCOGCDR.js");
8337
7905
  const argv = process.argv.slice(2);
8338
7906
  await runDoctorCli({
8339
7907
  json: !!options.json || argv.includes("--json"),
@@ -8342,7 +7910,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
8342
7910
  });
8343
7911
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
8344
7912
  try {
8345
- const batch = await import("./batch-AN47AYCZ.js");
7913
+ const batch = await import("./batch-C7SHXRQ2.js");
8346
7914
  switch (action) {
8347
7915
  case "submit":
8348
7916
  if (!arg) {
@@ -8385,7 +7953,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
8385
7953
  }
8386
7954
  });
8387
7955
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
8388
- const { startMcpServer } = await import("./server-BIYJEJK3.js");
7956
+ const { startMcpServer } = await import("./server-ZCG5QD6P.js");
8389
7957
  await startMcpServer({
8390
7958
  allowDestructive: !!options.allowDestructive,
8391
7959
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -8398,7 +7966,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
8398
7966
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
8399
7967
  process.exit(1);
8400
7968
  }
8401
- const { runPrCli } = await import("./pr-XE7NGT6U.js");
7969
+ const { runPrCli } = await import("./pr-Y2LDG3R7.js");
8402
7970
  const result = await runPrCli({
8403
7971
  action,
8404
7972
  target,
@@ -8418,8 +7986,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
8418
7986
  process.exit(result.exitCode);
8419
7987
  });
8420
7988
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number or URL; diff fetched via gh pr diff <value>", (v) => /^#?\d+$/.test(v) ? parseInt(v.replace(/^#/, ""), 10) : v).option("--base <ref>", "Base ref for git diff <ref>...HEAD (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").option("--json", "Output a structured JSON report").option("--markdown", "Output Markdown report (default)").option("--sarif", "Output SARIF 2.1.0 for code scanning artifacts").option("--fail-on-security-high", "Fail when the security review contains HIGH/CRITICAL findings (default)").option("--no-fail-on-security-high", "Do not fail on security HIGH/CRITICAL findings").option("--fail-on-test-failure", "Fail when the report mentions test failures (default)").option("--no-fail-on-test-failure", "Do not fail on test failure findings").option("--fail-on-lint-failure", "Fail when the report mentions lint/typecheck failures (default)").option("--no-fail-on-lint-failure", "Do not fail on lint/typecheck failure findings").action(async (options) => {
8421
- const { runCi } = await import("./ci-JTO7LN5S.js");
8422
- const { formatCiResult } = await import("./ci-format-2VGHOLBA.js");
7989
+ const { runCi } = await import("./ci-TDXLI3OM.js");
7990
+ const { formatCiResult } = await import("./ci-format-AFX2LP4Y.js");
8423
7991
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
8424
7992
  if (formats > 1) {
8425
7993
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -8577,7 +8145,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
8577
8145
  config.get("customProviders"),
8578
8146
  config.getConfigDir()
8579
8147
  );
8580
- const { startHub } = await import("./hub-6EYFGJRT.js");
8148
+ const { startHub } = await import("./hub-2YXETHPY.js");
8581
8149
  await startHub(
8582
8150
  {
8583
8151
  topic: topic ?? "",
@@ -8679,6 +8247,10 @@ ${options.prompt}` : options.prompt;
8679
8247
  const maxTokens = modelParams.maxTokens ?? DEFAULT_MAX_TOKENS;
8680
8248
  const timeout = modelParams.timeout ?? 6e4;
8681
8249
  const temperature = modelParams.temperature;
8250
+ const thinkingParams = applyThinkingFlag(
8251
+ thinkingParamsFor(allModelParams, model),
8252
+ options.think
8253
+ );
8682
8254
  let systemPrompt = options.system;
8683
8255
  if (!systemPrompt) {
8684
8256
  const contextConfig = config.get("context");
@@ -8711,7 +8283,8 @@ ${loaded.mergedContent}` : void 0
8711
8283
  stream: true,
8712
8284
  temperature,
8713
8285
  maxTokens,
8714
- timeout
8286
+ timeout,
8287
+ ...thinkingParams
8715
8288
  });
8716
8289
  let fullContent = "";
8717
8290
  let finalUsage;
@@ -8741,7 +8314,8 @@ ${loaded.mergedContent}` : void 0
8741
8314
  stream: false,
8742
8315
  temperature,
8743
8316
  maxTokens,
8744
- timeout
8317
+ timeout,
8318
+ ...thinkingParams
8745
8319
  });
8746
8320
  const out = {
8747
8321
  content: response.content,
@@ -8758,7 +8332,8 @@ ${loaded.mergedContent}` : void 0
8758
8332
  stream: true,
8759
8333
  temperature,
8760
8334
  maxTokens,
8761
- timeout
8335
+ timeout,
8336
+ ...thinkingParams
8762
8337
  });
8763
8338
  for await (const chunk of stream) {
8764
8339
  if (chunk.done) break;
@@ -8773,7 +8348,8 @@ ${loaded.mergedContent}` : void 0
8773
8348
  stream: false,
8774
8349
  temperature,
8775
8350
  maxTokens,
8776
- timeout
8351
+ timeout,
8352
+ ...thinkingParams
8777
8353
  });
8778
8354
  process.stdout.write(response.content + "\n");
8779
8355
  }
@@ -8789,6 +8365,7 @@ async function startRepl(options) {
8789
8365
  const config = new ConfigManager();
8790
8366
  await setupProxy(config.get("proxy"));
8791
8367
  if (config.isFirstRun()) {
8368
+ const { SetupWizard } = await import("./setup-wizard-S55ICNHH.js");
8792
8369
  const wizard = new SetupWizard(config);
8793
8370
  const configured = await wizard.runFirstRun();
8794
8371
  if (!configured) {