jinzd-ai-cli 0.4.125 → 0.4.127

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.
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-BMXOYPFZ.js";
4
+ } from "./chunk-SHP2ARZL.js";
5
5
  import "./chunk-2ZD3YTVM.js";
6
- import "./chunk-GMBLOBW7.js";
6
+ import "./chunk-ENVOODPW.js";
7
7
  import "./chunk-PDX44BCA.js";
8
8
 
9
9
  // src/cli/batch.ts
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  VERSION
5
- } from "./chunk-GMBLOBW7.js";
5
+ } from "./chunk-ENVOODPW.js";
6
6
 
7
7
  // src/diagnostics/crash-log.ts
8
8
  import {
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.125";
9
+ var VERSION = "0.4.127";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  schemaToJsonSchema
4
- } from "./chunk-4XI7RRIW.js";
4
+ } from "./chunk-KE7O7Y24.js";
5
5
  import {
6
6
  AuthError,
7
7
  ProviderError,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.125";
4
+ var VERSION = "0.4.127";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CONFIG_DIR_NAME
4
- } from "./chunk-GMBLOBW7.js";
4
+ } from "./chunk-ENVOODPW.js";
5
5
 
6
6
  // src/diagnostics/tool-stats.ts
7
7
  import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-GMBLOBW7.js";
4
+ } from "./chunk-ENVOODPW.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  truncateForPersist
4
- } from "./chunk-6XPEB6PR.js";
4
+ } from "./chunk-ZCARD5BR.js";
5
5
  import {
6
6
  APP_NAME,
7
7
  CONFIG_DIR_NAME,
@@ -11,7 +11,7 @@ import {
11
11
  MCP_PROTOCOL_VERSION,
12
12
  MCP_TOOL_PREFIX,
13
13
  VERSION
14
- } from "./chunk-GMBLOBW7.js";
14
+ } from "./chunk-ENVOODPW.js";
15
15
  import {
16
16
  redactJson
17
17
  } from "./chunk-7ZJN4KLV.js";
@@ -45,6 +45,14 @@ var Session = class _Session {
45
45
  updated;
46
46
  messages = [];
47
47
  title;
48
+ /**
49
+ * 标题是否已由 AI 生成过短摘要(v0.4.126+)。
50
+ * - false / undefined:title 仍是 addMessage 截取的首条用户消息前 50 字(heuristic)
51
+ * - true:已由 maybeGenerateSessionTitle 替换为 AI 摘要,不再二次生成
52
+ *
53
+ * 持久化在 toJSON / fromJSON 中,重启后不会重复请求。
54
+ */
55
+ titleAiGenerated;
48
56
  tokenUsage = {
49
57
  inputTokens: 0,
50
58
  outputTokens: 0,
@@ -104,6 +112,7 @@ var Session = class _Session {
104
112
  clear() {
105
113
  this.messages = [];
106
114
  this.title = void 0;
115
+ this.titleAiGenerated = false;
107
116
  this.tokenUsage = {
108
117
  inputTokens: 0,
109
118
  outputTokens: 0,
@@ -390,6 +399,7 @@ var Session = class _Session {
390
399
  created: this.created.toISOString(),
391
400
  updated: this.updated.toISOString(),
392
401
  title: this.title,
402
+ titleAiGenerated: this.titleAiGenerated ?? false,
393
403
  tokenUsage: { ...this.tokenUsage },
394
404
  checkpoints: this.checkpoints.map((c) => ({
395
405
  name: c.name,
@@ -458,6 +468,7 @@ var Session = class _Session {
458
468
  }
459
469
  const session = new _Session(d.id, d.provider, d.model);
460
470
  session.title = typeof d.title === "string" ? d.title : void 0;
471
+ session.titleAiGenerated = d.titleAiGenerated === true;
461
472
  const created = new Date(d.created);
462
473
  const updated = new Date(d.updated);
463
474
  session.created = isNaN(created.getTime()) ? /* @__PURE__ */ new Date() : created;
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-GMBLOBW7.js";
11
+ } from "./chunk-ENVOODPW.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -157,6 +157,11 @@ var ConfigSchema = z.object({
157
157
  // 当对话估算 token 数超过模型 contextWindow 的 80% 时,自动触发 compact 压缩旧消息
158
158
  // 默认开启。设为 false 则仅在手动 /compact 时压缩
159
159
  autoCompact: z.boolean().default(true),
160
+ // YOLO 模式持久开关(v0.4.126+)
161
+ // true 时 REPL 启动即开启 sessionAutoApprove,等同于每次开 session 都自动跑 `/yolo`。
162
+ // 所有 write / destructive 工具都会跳过确认 —— 仅在完全信任自己当前工作目录时启用。
163
+ // 启动 banner 会显示醒目提示,避免"忘了配置开着"的事故。
164
+ alwaysYolo: z.boolean().default(false),
160
165
  // Agentic 工具调用循环单次对话最大轮次(默认 200)。
161
166
  // 超过此值后 AI 被强制停止调用工具并生成总结。
162
167
  // 建议范围:25(保守)~ 1000(宽松,接近 Claude Code)。
@@ -5,12 +5,12 @@ import {
5
5
  } from "./chunk-3BICTI5M.js";
6
6
  import {
7
7
  runTestsTool
8
- } from "./chunk-IP6IPSZJ.js";
8
+ } from "./chunk-M6NJAJFE.js";
9
9
  import {
10
10
  getDangerLevel,
11
11
  isFileWriteTool,
12
12
  runTool
13
- } from "./chunk-4XI7RRIW.js";
13
+ } from "./chunk-KE7O7Y24.js";
14
14
  import {
15
15
  EnvLoader,
16
16
  NetworkError,
@@ -23,7 +23,7 @@ import {
23
23
  SUBAGENT_ALLOWED_TOOLS,
24
24
  SUBAGENT_DEFAULT_MAX_ROUNDS,
25
25
  SUBAGENT_MAX_ROUNDS_LIMIT
26
- } from "./chunk-GMBLOBW7.js";
26
+ } from "./chunk-ENVOODPW.js";
27
27
  import {
28
28
  fileCheckpoints
29
29
  } from "./chunk-4BKXL7SM.js";
@@ -36,7 +36,7 @@ import {
36
36
  TEST_TIMEOUT,
37
37
  VERSION,
38
38
  buildUserIdentityPrompt
39
- } from "./chunk-GMBLOBW7.js";
39
+ } from "./chunk-ENVOODPW.js";
40
40
  import "./chunk-PDX44BCA.js";
41
41
  export {
42
42
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -2,25 +2,25 @@
2
2
  import {
3
3
  getConfigDirUsage,
4
4
  listRecentCrashes
5
- } from "./chunk-ZL5Q2HP4.js";
5
+ } from "./chunk-4MI7WCPV.js";
6
6
  import {
7
7
  ProviderRegistry
8
- } from "./chunk-5ZHTBFZ4.js";
8
+ } from "./chunk-BA5OHDRY.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-BMXOYPFZ.js";
11
+ } from "./chunk-SHP2ARZL.js";
12
12
  import {
13
13
  getStatsSnapshot,
14
14
  getTopFailingTools,
15
15
  getTopUsedTools,
16
16
  resetStats
17
- } from "./chunk-4XI7RRIW.js";
17
+ } from "./chunk-KE7O7Y24.js";
18
18
  import "./chunk-2ZD3YTVM.js";
19
19
  import {
20
20
  DEV_STATE_FILE_NAME,
21
21
  MEMORY_FILE_NAME,
22
22
  VERSION
23
- } from "./chunk-GMBLOBW7.js";
23
+ } from "./chunk-ENVOODPW.js";
24
24
  import "./chunk-PDX44BCA.js";
25
25
 
26
26
  // src/diagnostics/doctor-cli.ts
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-5242JF4Q.js";
39
+ } from "./chunk-4QTXJBH3.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -208,6 +208,11 @@ var ConfigSchema = z.object({
208
208
  // 当对话估算 token 数超过模型 contextWindow 的 80% 时,自动触发 compact 压缩旧消息
209
209
  // 默认开启。设为 false 则仅在手动 /compact 时压缩
210
210
  autoCompact: z.boolean().default(true),
211
+ // YOLO 模式持久开关(v0.4.126+)
212
+ // true 时 REPL 启动即开启 sessionAutoApprove,等同于每次开 session 都自动跑 `/yolo`。
213
+ // 所有 write / destructive 工具都会跳过确认 —— 仅在完全信任自己当前工作目录时启用。
214
+ // 启动 banner 会显示醒目提示,避免"忘了配置开着"的事故。
215
+ alwaysYolo: z.boolean().default(false),
211
216
  // Agentic 工具调用循环单次对话最大轮次(默认 200)。
212
217
  // 超过此值后 AI 被强制停止调用工具并生成总结。
213
218
  // 建议范围:25(保守)~ 1000(宽松,接近 Claude Code)。
@@ -2951,6 +2956,14 @@ var Session = class _Session {
2951
2956
  updated;
2952
2957
  messages = [];
2953
2958
  title;
2959
+ /**
2960
+ * 标题是否已由 AI 生成过短摘要(v0.4.126+)。
2961
+ * - false / undefined:title 仍是 addMessage 截取的首条用户消息前 50 字(heuristic)
2962
+ * - true:已由 maybeGenerateSessionTitle 替换为 AI 摘要,不再二次生成
2963
+ *
2964
+ * 持久化在 toJSON / fromJSON 中,重启后不会重复请求。
2965
+ */
2966
+ titleAiGenerated;
2954
2967
  tokenUsage = {
2955
2968
  inputTokens: 0,
2956
2969
  outputTokens: 0,
@@ -3010,6 +3023,7 @@ var Session = class _Session {
3010
3023
  clear() {
3011
3024
  this.messages = [];
3012
3025
  this.title = void 0;
3026
+ this.titleAiGenerated = false;
3013
3027
  this.tokenUsage = {
3014
3028
  inputTokens: 0,
3015
3029
  outputTokens: 0,
@@ -3296,6 +3310,7 @@ var Session = class _Session {
3296
3310
  created: this.created.toISOString(),
3297
3311
  updated: this.updated.toISOString(),
3298
3312
  title: this.title,
3313
+ titleAiGenerated: this.titleAiGenerated ?? false,
3299
3314
  tokenUsage: { ...this.tokenUsage },
3300
3315
  checkpoints: this.checkpoints.map((c) => ({
3301
3316
  name: c.name,
@@ -3364,6 +3379,7 @@ var Session = class _Session {
3364
3379
  }
3365
3380
  const session = new _Session(d.id, d.provider, d.model);
3366
3381
  session.title = typeof d.title === "string" ? d.title : void 0;
3382
+ session.titleAiGenerated = d.titleAiGenerated === true;
3367
3383
  const created = new Date(d.created);
3368
3384
  const updated = new Date(d.updated);
3369
3385
  session.created = isNaN(created.getTime()) ? /* @__PURE__ */ new Date() : created;
@@ -12203,7 +12219,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
12203
12219
  case "test": {
12204
12220
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
12205
12221
  try {
12206
- const { executeTests } = await import("./run-tests-VX33IWWD.js");
12222
+ const { executeTests } = await import("./run-tests-NTQOVARA.js");
12207
12223
  const argStr = args.join(" ").trim();
12208
12224
  let testArgs = {};
12209
12225
  if (argStr) {
@@ -386,7 +386,7 @@ ${content}`);
386
386
  }
387
387
  }
388
388
  async function runTaskMode(config, providers, configManager, topic) {
389
- const { TaskOrchestrator } = await import("./task-orchestrator-IXBSUOVM.js");
389
+ const { TaskOrchestrator } = await import("./task-orchestrator-QHOYTOVN.js");
390
390
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
391
391
  let interrupted = false;
392
392
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -16,12 +16,12 @@ import {
16
16
  saveDevState,
17
17
  sessionHasMeaningfulContent,
18
18
  setupProxy
19
- } from "./chunk-OC3QPVR4.js";
19
+ } from "./chunk-QNGN5IFK.js";
20
20
  import {
21
21
  getConfigDirUsage,
22
22
  listRecentCrashes,
23
23
  writeCrashLog
24
- } from "./chunk-ZL5Q2HP4.js";
24
+ } from "./chunk-4MI7WCPV.js";
25
25
  import {
26
26
  CONTENT_ONLY_STREAM_REMINDER,
27
27
  HALLUCINATION_CORRECTION_MESSAGE,
@@ -39,10 +39,10 @@ import {
39
39
  looksLikeDocumentBody,
40
40
  stripPseudoToolCalls,
41
41
  stripToolCallReminder
42
- } from "./chunk-5ZHTBFZ4.js";
42
+ } from "./chunk-BA5OHDRY.js";
43
43
  import {
44
44
  ConfigManager
45
- } from "./chunk-BMXOYPFZ.js";
45
+ } from "./chunk-SHP2ARZL.js";
46
46
  import {
47
47
  ToolExecutor,
48
48
  ToolRegistry,
@@ -61,16 +61,16 @@ import {
61
61
  spawnAgentContext,
62
62
  theme,
63
63
  undoStack
64
- } from "./chunk-6XPEB6PR.js";
64
+ } from "./chunk-ZCARD5BR.js";
65
65
  import "./chunk-3BICTI5M.js";
66
66
  import "./chunk-2DXY7UGF.js";
67
- import "./chunk-IP6IPSZJ.js";
67
+ import "./chunk-M6NJAJFE.js";
68
68
  import {
69
69
  getStatsSnapshot,
70
70
  getTopFailingTools,
71
71
  getTopUsedTools,
72
72
  installFlushOnExit
73
- } from "./chunk-4XI7RRIW.js";
73
+ } from "./chunk-KE7O7Y24.js";
74
74
  import "./chunk-2ZD3YTVM.js";
75
75
  import {
76
76
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -93,7 +93,7 @@ import {
93
93
  SKILLS_DIR_NAME,
94
94
  VERSION,
95
95
  buildUserIdentityPrompt
96
- } from "./chunk-GMBLOBW7.js";
96
+ } from "./chunk-ENVOODPW.js";
97
97
  import {
98
98
  formatGitContextForPrompt,
99
99
  getGitContext,
@@ -1748,7 +1748,7 @@ No tools match "${filter}".
1748
1748
  const { join: join6 } = await import("path");
1749
1749
  const { existsSync: existsSync6 } = await import("fs");
1750
1750
  const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
1751
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-QBA3BYQM.js");
1751
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-ASHQ3TNS.js");
1752
1752
  const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
1753
1753
  const cwd = process.cwd();
1754
1754
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2809,7 +2809,7 @@ ${hint}` : "")
2809
2809
  usage: "/test [command|filter]",
2810
2810
  async execute(args, ctx) {
2811
2811
  try {
2812
- const { executeTests } = await import("./run-tests-27C4WSR6.js");
2812
+ const { executeTests } = await import("./run-tests-L5JPWMTU.js");
2813
2813
  const argStr = args.join(" ").trim();
2814
2814
  let testArgs = {};
2815
2815
  if (argStr) {
@@ -3678,7 +3678,7 @@ var streamToFileContext = {
3678
3678
  };
3679
3679
 
3680
3680
  // src/repl/setup-wizard.ts
3681
- import { password, select, input } from "@inquirer/prompts";
3681
+ import { password, select, input, confirm } from "@inquirer/prompts";
3682
3682
  var PROVIDERS = [
3683
3683
  { value: "claude", name: "Claude (Anthropic)" },
3684
3684
  { value: "gemini", name: "Gemini (Google)" },
@@ -3731,6 +3731,8 @@ ${greeting} Starting ai-cli...
3731
3731
  const googleKeyStatus = this.config.getApiKey("google-search") ? theme.success("[configured]") : theme.dim("[not configured]");
3732
3732
  const profileName = this.config.get("userProfile")?.nickname || this.config.get("userProfile")?.name;
3733
3733
  const profileStatus = profileName ? theme.success(`[${profileName}]`) : theme.dim("[not configured]");
3734
+ const yoloOn = this.config.get("alwaysYolo") === true;
3735
+ const behaviorStatus = yoloOn ? theme.warning("[YOLO on]") : theme.dim("[default]");
3734
3736
  const action = await select({
3735
3737
  message: "What would you like to configure?",
3736
3738
  choices: [
@@ -3739,6 +3741,7 @@ ${greeting} Starting ai-cli...
3739
3741
  { value: "default", name: "Change default provider" },
3740
3742
  { value: "proxy", name: `Configure proxy (HTTP/HTTPS) ${proxyStatus}` },
3741
3743
  { value: "google", name: `Configure Google Search (API Key + CX) ${googleKeyStatus}` },
3744
+ { value: "behavior", name: `Behavior toggles (YOLO, ...) ${behaviorStatus}` },
3742
3745
  { value: "done", name: "Done" }
3743
3746
  ]
3744
3747
  });
@@ -3748,6 +3751,8 @@ ${greeting} Starting ai-cli...
3748
3751
  await this.setupProxy();
3749
3752
  } else if (action === "google") {
3750
3753
  await this.setupGoogleSearch();
3754
+ } else if (action === "behavior") {
3755
+ await this.setupBehavior();
3751
3756
  } else if (action === "apikey") {
3752
3757
  const choicesWithStatus = PROVIDERS.map((p) => {
3753
3758
  if (NO_KEY_PROVIDERS.has(p.value)) {
@@ -3915,6 +3920,32 @@ Managing ${displayName} API Key`);
3915
3920
  console.log(theme.success(`Proxy saved: ${proxyUrl}
3916
3921
  `));
3917
3922
  }
3923
+ /** Behavior toggles — alwaysYolo and friends (v0.4.126+). */
3924
+ async setupBehavior() {
3925
+ const current = this.config.get("alwaysYolo") === true;
3926
+ console.log(theme.heading("\n\u2699 Behavior Toggles\n"));
3927
+ console.log(" alwaysYolo: " + (current ? theme.warning("ON") : theme.dim("off")));
3928
+ console.log(
3929
+ theme.dim(
3930
+ " When ON, REPL starts with sessionAutoApprove enabled \u2014 all write/destructive\n tools (edit_file, bash, etc.) run without confirmation prompts. Only enable this\n if you fully trust the working directory you run aicli in.\n"
3931
+ )
3932
+ );
3933
+ const next = await confirm({
3934
+ message: current ? "Keep alwaysYolo enabled?" : "Enable alwaysYolo (skip ALL write/destructive confirmations)?",
3935
+ default: current
3936
+ });
3937
+ if (next === current) {
3938
+ console.log(theme.dim(" No change.\n"));
3939
+ return;
3940
+ }
3941
+ this.config.set("alwaysYolo", next);
3942
+ this.config.save();
3943
+ if (next) {
3944
+ console.log(theme.warning(" \u26A1 alwaysYolo enabled \u2014 confirmations will be skipped on next REPL start.\n"));
3945
+ } else {
3946
+ console.log(theme.success(" alwaysYolo disabled \u2014 confirmations restored on next REPL start.\n"));
3947
+ }
3948
+ }
3918
3949
  async setupGoogleSearch() {
3919
3950
  console.log("\nGoogle Custom Search Configuration");
3920
3951
  console.log(theme.dim(" Enables AI to search the web via google_search tool"));
@@ -4460,6 +4491,9 @@ var Repl = class {
4460
4491
  permissionRules: this.config.get("permissionRules") ?? [],
4461
4492
  defaultPermission: this.config.get("defaultPermission") ?? "confirm"
4462
4493
  });
4494
+ if (this.config.get("alwaysYolo") === true) {
4495
+ this.toolExecutor.sessionAutoApprove = true;
4496
+ }
4463
4497
  if (options?.allowedTools) this.allowedTools = options.allowedTools;
4464
4498
  if (options?.blockedTools) this.blockedTools = options.blockedTools;
4465
4499
  if (options?.resumeSessionId) this.resumeSessionId = options.resumeSessionId;
@@ -5199,6 +5233,11 @@ Session '${this.resumeSessionId}' not found.
5199
5233
  const welcomeModelInfo = welcomeProvider?.info.models.find((m) => m.id === this.currentModel);
5200
5234
  const profileNickname = this.config.get("userProfile")?.nickname || this.config.get("userProfile")?.name;
5201
5235
  this.renderer.printWelcome(this.currentProvider, this.currentModel, welcomeModelInfo?.contextWindow, profileNickname);
5236
+ if (this.toolExecutor.sessionAutoApprove && this.config.get("alwaysYolo") === true) {
5237
+ process.stdout.write(
5238
+ theme.warning(" \u26A1 YOLO mode ON (alwaysYolo=true in config) \u2014 all write/destructive tools auto-approved.\n")
5239
+ );
5240
+ }
5202
5241
  const cfgOutputCap = this.config.get("maxToolOutputChars");
5203
5242
  if (typeof cfgOutputCap === "number" && cfgOutputCap > 0) setMaxOutputCap(cfgOutputCap);
5204
5243
  if (welcomeModelInfo?.contextWindow) setContextWindow(welcomeModelInfo.contextWindow);
@@ -5544,6 +5583,7 @@ Session '${this.resumeSessionId}' not found.
5544
5583
  }
5545
5584
  await this.sessions.save();
5546
5585
  }
5586
+ void this.maybeGenerateSessionTitle(session, routingDecision.model);
5547
5587
  this.costTracker.save();
5548
5588
  const budgetWarning = this.costTracker.checkBudget(this.config.get("monthlyBudget"));
5549
5589
  if (budgetWarning) {
@@ -6125,6 +6165,63 @@ Session '${this.resumeSessionId}' not found.
6125
6165
  finishReason
6126
6166
  };
6127
6167
  }
6168
+ /**
6169
+ * 首轮 AI 回复后异步生成简短摘要标题,替换 addMessage 的截断 heuristic(v0.4.126+)。
6170
+ *
6171
+ * 触发条件:
6172
+ * - session 尚未有 AI 生成的标题(titleAiGenerated !== true)
6173
+ * - 有至少一条用户消息 + 一条带文本的 assistant 消息
6174
+ *
6175
+ * 用当前 provider 的 chat() 接口做一次轻量调用,最多 ~30 tokens。
6176
+ * 失败静默回退到现有截断标题(已经写在 session.title 上),不打扰用户。
6177
+ * 完成后再 save() 一次以持久化新标题。
6178
+ */
6179
+ async maybeGenerateSessionTitle(session, model) {
6180
+ try {
6181
+ if (session.titleAiGenerated) return;
6182
+ const hasUser = session.messages.some((m) => m.role === "user");
6183
+ const firstAssistantText = session.messages.find(
6184
+ (m) => m.role === "assistant" && getContentText(m.content).trim().length > 0
6185
+ );
6186
+ if (!hasUser || !firstAssistantText) return;
6187
+ const provider = this.providers.get(this.currentProvider);
6188
+ const userMsg = session.messages.find((m) => m.role === "user");
6189
+ const userText = userMsg ? getContentText(userMsg.content).slice(0, 800) : "";
6190
+ const aiText = getContentText(firstAssistantText.content).slice(0, 800);
6191
+ const systemPrompt = 'You generate a very short title for a conversation. Rules: output ONLY the title (no quotes, no prefix like "Title:", no trailing punctuation). Length: \u2264 12 Chinese characters, or \u2264 6 English words. Match the language the user used. Capture the topic, not generic words like "question" or "help".';
6192
+ const promptMessages = [
6193
+ {
6194
+ role: "user",
6195
+ content: `User: ${userText}
6196
+
6197
+ Assistant: ${aiText}
6198
+
6199
+ Now produce the title (\u2264 12 Chinese chars or \u2264 6 English words):`,
6200
+ timestamp: /* @__PURE__ */ new Date()
6201
+ }
6202
+ ];
6203
+ const resp = await provider.chat({
6204
+ messages: promptMessages,
6205
+ model,
6206
+ systemPrompt,
6207
+ stream: false,
6208
+ maxTokens: 40,
6209
+ temperature: 0.3
6210
+ });
6211
+ let title = (resp.content ?? "").trim();
6212
+ title = title.replace(/^["'`「『《【\[]+|["'`」』》】\]]+$/g, "").trim();
6213
+ title = title.replace(/^(title|标题)\s*[::]\s*/i, "").trim();
6214
+ title = title.split(/\r?\n/)[0].trim();
6215
+ if (title.length > 40) title = title.slice(0, 40);
6216
+ if (!title) return;
6217
+ session.title = title;
6218
+ session.titleAiGenerated = true;
6219
+ if (this.config.get("session").autoSave) {
6220
+ await this.sessions.save();
6221
+ }
6222
+ } catch {
6223
+ }
6224
+ }
6128
6225
  async handleChatWithTools(provider, messages, modelOverride) {
6129
6226
  const session = this.sessions.current;
6130
6227
  const effectiveModel = modelOverride ?? this.currentModel;
@@ -7176,7 +7273,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7176
7273
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7177
7274
  process.exit(1);
7178
7275
  }
7179
- const { startWebServer } = await import("./server-4PNBZPHM.js");
7276
+ const { startWebServer } = await import("./server-C5LPEJVE.js");
7180
7277
  await startWebServer({ port, host: options.host });
7181
7278
  });
7182
7279
  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) => {
@@ -7343,12 +7440,12 @@ program.command("sessions").description("List recent conversation sessions").opt
7343
7440
  console.log(footer + "\n");
7344
7441
  });
7345
7442
  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) => {
7346
- const { runDoctorCli } = await import("./doctor-cli-3PDBXO2M.js");
7443
+ const { runDoctorCli } = await import("./doctor-cli-L3OA2GYS.js");
7347
7444
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7348
7445
  });
7349
7446
  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) => {
7350
7447
  try {
7351
- const batch = await import("./batch-TCWNELYW.js");
7448
+ const batch = await import("./batch-RAJMYTUL.js");
7352
7449
  switch (action) {
7353
7450
  case "submit":
7354
7451
  if (!arg) {
@@ -7391,7 +7488,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7391
7488
  }
7392
7489
  });
7393
7490
  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) => {
7394
- const { startMcpServer } = await import("./server-KNAD5HBQ.js");
7491
+ const { startMcpServer } = await import("./server-QLH3F7HF.js");
7395
7492
  await startMcpServer({
7396
7493
  allowDestructive: !!options.allowDestructive,
7397
7494
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7518,7 +7615,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7518
7615
  }),
7519
7616
  config.get("customProviders")
7520
7617
  );
7521
- const { startHub } = await import("./hub-RH34TBP2.js");
7618
+ const { startHub } = await import("./hub-QXDG246X.js");
7522
7619
  await startHub(
7523
7620
  {
7524
7621
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-IP6IPSZJ.js";
6
- import "./chunk-GMBLOBW7.js";
5
+ } from "./chunk-M6NJAJFE.js";
6
+ import "./chunk-ENVOODPW.js";
7
7
  import "./chunk-PDX44BCA.js";
8
8
  export {
9
9
  executeTests,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-5242JF4Q.js";
4
+ } from "./chunk-4QTXJBH3.js";
5
5
  import "./chunk-3RG5ZIWI.js";
6
6
  export {
7
7
  executeTests,
@@ -14,7 +14,7 @@ import {
14
14
  loadDevState,
15
15
  persistToolRound,
16
16
  setupProxy
17
- } from "./chunk-OC3QPVR4.js";
17
+ } from "./chunk-QNGN5IFK.js";
18
18
  import {
19
19
  CONTENT_ONLY_STREAM_REMINDER,
20
20
  HALLUCINATION_CORRECTION_MESSAGE,
@@ -28,10 +28,10 @@ import {
28
28
  looksLikeDocumentBody,
29
29
  stripPseudoToolCalls,
30
30
  stripToolCallReminder
31
- } from "./chunk-5ZHTBFZ4.js";
31
+ } from "./chunk-BA5OHDRY.js";
32
32
  import {
33
33
  ConfigManager
34
- } from "./chunk-BMXOYPFZ.js";
34
+ } from "./chunk-SHP2ARZL.js";
35
35
  import {
36
36
  ToolExecutor,
37
37
  ToolRegistry,
@@ -49,14 +49,14 @@ import {
49
49
  spawnAgentContext,
50
50
  truncateOutput,
51
51
  undoStack
52
- } from "./chunk-6XPEB6PR.js";
52
+ } from "./chunk-ZCARD5BR.js";
53
53
  import "./chunk-3BICTI5M.js";
54
54
  import "./chunk-2DXY7UGF.js";
55
- import "./chunk-IP6IPSZJ.js";
55
+ import "./chunk-M6NJAJFE.js";
56
56
  import {
57
57
  getDangerLevel,
58
58
  runTool
59
- } from "./chunk-4XI7RRIW.js";
59
+ } from "./chunk-KE7O7Y24.js";
60
60
  import "./chunk-2ZD3YTVM.js";
61
61
  import {
62
62
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -76,7 +76,7 @@ import {
76
76
  SKILLS_DIR_NAME,
77
77
  VERSION,
78
78
  buildUserIdentityPrompt
79
- } from "./chunk-GMBLOBW7.js";
79
+ } from "./chunk-ENVOODPW.js";
80
80
  import {
81
81
  formatGitContextForPrompt,
82
82
  getGitContext,
@@ -2460,7 +2460,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2460
2460
  case "test": {
2461
2461
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2462
2462
  try {
2463
- const { executeTests } = await import("./run-tests-27C4WSR6.js");
2463
+ const { executeTests } = await import("./run-tests-L5JPWMTU.js");
2464
2464
  const argStr = args.join(" ").trim();
2465
2465
  let testArgs = {};
2466
2466
  if (argStr) {
@@ -1,19 +1,19 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-6XPEB6PR.js";
4
+ } from "./chunk-ZCARD5BR.js";
5
5
  import "./chunk-3BICTI5M.js";
6
6
  import "./chunk-2DXY7UGF.js";
7
- import "./chunk-IP6IPSZJ.js";
7
+ import "./chunk-M6NJAJFE.js";
8
8
  import {
9
9
  getDangerLevel,
10
10
  runTool,
11
11
  schemaToJsonSchema
12
- } from "./chunk-4XI7RRIW.js";
12
+ } from "./chunk-KE7O7Y24.js";
13
13
  import "./chunk-2ZD3YTVM.js";
14
14
  import {
15
15
  VERSION
16
- } from "./chunk-GMBLOBW7.js";
16
+ } from "./chunk-ENVOODPW.js";
17
17
  import "./chunk-4BKXL7SM.js";
18
18
  import "./chunk-7ZJN4KLV.js";
19
19
  import "./chunk-KHYD3WXE.js";
@@ -3,18 +3,18 @@ import {
3
3
  ToolRegistry,
4
4
  googleSearchContext,
5
5
  truncateOutput
6
- } from "./chunk-6XPEB6PR.js";
6
+ } from "./chunk-ZCARD5BR.js";
7
7
  import "./chunk-3BICTI5M.js";
8
8
  import "./chunk-2DXY7UGF.js";
9
- import "./chunk-IP6IPSZJ.js";
9
+ import "./chunk-M6NJAJFE.js";
10
10
  import {
11
11
  getDangerLevel,
12
12
  runTool
13
- } from "./chunk-4XI7RRIW.js";
13
+ } from "./chunk-KE7O7Y24.js";
14
14
  import "./chunk-2ZD3YTVM.js";
15
15
  import {
16
16
  SUBAGENT_ALLOWED_TOOLS
17
- } from "./chunk-GMBLOBW7.js";
17
+ } from "./chunk-ENVOODPW.js";
18
18
  import "./chunk-4BKXL7SM.js";
19
19
  import "./chunk-7ZJN4KLV.js";
20
20
  import "./chunk-KHYD3WXE.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.125",
3
+ "version": "0.4.127",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",