jinzd-ai-cli 0.4.194 → 0.4.196

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-ZVMXIRBH.js";
4
+ } from "./chunk-WM2WVHKT.js";
5
5
  import "./chunk-TZQHYZKT.js";
6
- import "./chunk-ZEHHAE3B.js";
6
+ import "./chunk-PK7MMIKC.js";
7
7
  import {
8
8
  atomicWriteFileSync
9
9
  } from "./chunk-IW3Q7AE5.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  VERSION
5
- } from "./chunk-ZEHHAE3B.js";
5
+ } from "./chunk-PK7MMIKC.js";
6
6
 
7
7
  // src/diagnostics/crash-log.ts
8
8
  import {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-ZEHHAE3B.js";
4
+ } from "./chunk-PK7MMIKC.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-ZJX6ZU5D.js";
4
+ } from "./chunk-PREP4QF5.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-ZEHHAE3B.js";
14
+ } from "./chunk-PK7MMIKC.js";
15
15
 
16
16
  // src/mcp/client.ts
17
17
  import { spawn } from "child_process";
@@ -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.194";
9
+ var VERSION = "0.4.196";
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
  CONFIG_DIR_NAME
4
- } from "./chunk-ZEHHAE3B.js";
4
+ } from "./chunk-PK7MMIKC.js";
5
5
  import {
6
6
  atomicWriteFileSync
7
7
  } from "./chunk-IW3Q7AE5.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.194";
4
+ var VERSION = "0.4.196";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -5,15 +5,15 @@ import {
5
5
  } from "./chunk-T2NL5ZIA.js";
6
6
  import {
7
7
  runTestsTool
8
- } from "./chunk-3KCEPI4E.js";
8
+ } from "./chunk-DXWNQA7R.js";
9
9
  import {
10
10
  runTool
11
- } from "./chunk-CKBBAXCA.js";
11
+ } from "./chunk-MJAQ7GYG.js";
12
12
  import {
13
13
  getDangerLevel,
14
14
  isFileWriteTool,
15
15
  runLeanAgentLoop
16
- } from "./chunk-ZRG2FPC6.js";
16
+ } from "./chunk-YZH2QQXJ.js";
17
17
  import {
18
18
  EnvLoader,
19
19
  NetworkError,
@@ -26,7 +26,7 @@ import {
26
26
  SUBAGENT_ALLOWED_TOOLS,
27
27
  SUBAGENT_DEFAULT_MAX_ROUNDS,
28
28
  SUBAGENT_MAX_ROUNDS_LIMIT
29
- } from "./chunk-ZEHHAE3B.js";
29
+ } from "./chunk-PK7MMIKC.js";
30
30
  import {
31
31
  fileCheckpoints
32
32
  } from "./chunk-4BKXL7SM.js";
@@ -3,7 +3,7 @@ import {
3
3
  detectsHallucinatedFileOp,
4
4
  repairToolCallArguments,
5
5
  schemaToJsonSchema
6
- } from "./chunk-ZRG2FPC6.js";
6
+ } from "./chunk-YZH2QQXJ.js";
7
7
  import {
8
8
  AuthError,
9
9
  ProviderError,
@@ -16,6 +16,17 @@ import Anthropic from "@anthropic-ai/sdk";
16
16
 
17
17
  // src/providers/base.ts
18
18
  var BaseProvider = class {
19
+ /**
20
+ * 该 provider 在「无工具的 content-only 流」里能否可靠产出文档正文(save_last_response
21
+ * tee 模式依赖此能力)。默认 true。DeepSeek/Kimi 覆写为 false:它们带着 agentic 循环的
22
+ * 工具调用惯性,在 content-only 重生成里会复发伪工具调用(DSML / `<tool_call>`),tee
23
+ * 怎么重试都剥不出正文(同 `enableStreamingToolCalls=false` 的同源怪癖)。
24
+ */
25
+ reliableContentOnlyTee = true;
26
+ /** 公开读能力位:host(REPL/Web)据此决定是否跳过注定失败的 tee、直接走 deferred 赛道。 */
27
+ get supportsContentOnlyTee() {
28
+ return this.reliableContentOnlyTee;
29
+ }
19
30
  /**
20
31
  * 将 Message[] 转换为 OpenAI API 格式的消息数组。
21
32
  * content 为 string 时直接传递;为 MessageContentPart[] 时保留数组格式(vision 请求)。
@@ -1384,6 +1395,13 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
1384
1395
  defaultBaseUrl = "https://api.deepseek.com/v1";
1385
1396
  /** 禁用流式工具调用,确保 chatWithTools 覆写(代码块检测)生效 */
1386
1397
  enableStreamingToolCalls = false;
1398
+ /**
1399
+ * content-only tee 不可靠:DeepSeek(尤以 V4 Pro)带着 agentic 循环的工具调用惯性,
1400
+ * 在无工具的重生成流里会复发伪工具调用(DSML / `<tool_call>`),剥不出文档正文。
1401
+ * host 据此跳过注定失败的 tee、直接走 deferred 赛道(普通文本写报告 + 自动落盘),
1402
+ * 省掉一次满上下文往返(v0.4.196)。
1403
+ */
1404
+ reliableContentOnlyTee = false;
1387
1405
  info = {
1388
1406
  id: "deepseek",
1389
1407
  displayName: "DeepSeek",
@@ -1580,6 +1598,9 @@ var KimiProvider = class _KimiProvider extends OpenAICompatibleProvider {
1580
1598
  defaultBaseUrl = "https://api.moonshot.ai/v1";
1581
1599
  // 禁用流式工具调用:Kimi 的 XML 伪调用检测(方案 A)需要完整响应
1582
1600
  enableStreamingToolCalls = false;
1601
+ // content-only tee 不可靠(同 DeepSeek):agentic 惯性下重生成会复发伪工具调用,
1602
+ // 剥不出文档正文。host 据此跳过 tee、直接走 deferred 赛道(v0.4.196)。
1603
+ reliableContentOnlyTee = false;
1583
1604
  /**
1584
1605
  * Kimi K2.x 系列(非 moonshot-v1)只允许 temperature=1。
1585
1606
  * 其他值会收到 400 "invalid temperature: only 1 is allowed for this model"。
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-ZEHHAE3B.js";
11
+ } from "./chunk-PK7MMIKC.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -483,6 +483,11 @@ function isCleanDocumentBody(content) {
483
483
  function teeFileStats(content) {
484
484
  return { lines: content.split("\n").length, bytes: Buffer.byteLength(content, "utf-8") };
485
485
  }
486
+ function freshPriorContent(current, baselineAtTurnStart) {
487
+ if (!current) return void 0;
488
+ if (current === baselineAtTurnStart) return void 0;
489
+ return current;
490
+ }
486
491
  function evaluateTeeContent(rawContent, saveToFile, priorContent) {
487
492
  const fallback = (matched) => {
488
493
  if (priorContent && priorContent !== rawContent && isCleanDocumentBody(priorContent)) {
@@ -1053,6 +1058,7 @@ export {
1053
1058
  TEE_FINAL_USER_NUDGE,
1054
1059
  CONTENT_ONLY_STREAM_REMINDER,
1055
1060
  isCleanDocumentBody,
1061
+ freshPriorContent,
1056
1062
  evaluateTeeContent,
1057
1063
  buildDeferredSaveInstruction,
1058
1064
  teeStreamErrorSummary,
@@ -6,15 +6,15 @@ import {
6
6
  } from "./chunk-HLWUDRBO.js";
7
7
  import {
8
8
  ProviderRegistry
9
- } from "./chunk-2BLBXGOE.js";
10
- import "./chunk-ZRG2FPC6.js";
9
+ } from "./chunk-UA43JQPP.js";
10
+ import "./chunk-YZH2QQXJ.js";
11
11
  import {
12
12
  ConfigManager
13
- } from "./chunk-ZVMXIRBH.js";
13
+ } from "./chunk-WM2WVHKT.js";
14
14
  import "./chunk-TZQHYZKT.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-ZEHHAE3B.js";
17
+ } from "./chunk-PK7MMIKC.js";
18
18
 
19
19
  // src/cli/ci.ts
20
20
  import { execFileSync, execSync } from "child_process";
@@ -36,7 +36,7 @@ import {
36
36
  TEST_TIMEOUT,
37
37
  VERSION,
38
38
  buildUserIdentityPrompt
39
- } from "./chunk-ZEHHAE3B.js";
39
+ } from "./chunk-PK7MMIKC.js";
40
40
  export {
41
41
  AGENTIC_BEHAVIOR_GUIDELINE,
42
42
  APP_NAME,
@@ -2,26 +2,26 @@
2
2
  import {
3
3
  getConfigDirUsage,
4
4
  listRecentCrashes
5
- } from "./chunk-5IVUINDO.js";
5
+ } from "./chunk-DXUS6OZH.js";
6
6
  import {
7
7
  ProviderRegistry
8
- } from "./chunk-2BLBXGOE.js";
8
+ } from "./chunk-UA43JQPP.js";
9
9
  import {
10
10
  getStatsSnapshot,
11
11
  getTopFailingTools,
12
12
  getTopUsedTools,
13
13
  resetStats
14
- } from "./chunk-CKBBAXCA.js";
15
- import "./chunk-ZRG2FPC6.js";
14
+ } from "./chunk-MJAQ7GYG.js";
15
+ import "./chunk-YZH2QQXJ.js";
16
16
  import {
17
17
  ConfigManager
18
- } from "./chunk-ZVMXIRBH.js";
18
+ } from "./chunk-WM2WVHKT.js";
19
19
  import "./chunk-TZQHYZKT.js";
20
20
  import {
21
21
  DEV_STATE_FILE_NAME,
22
22
  MEMORY_FILE_NAME,
23
23
  VERSION
24
- } from "./chunk-ZEHHAE3B.js";
24
+ } from "./chunk-PK7MMIKC.js";
25
25
  import "./chunk-IW3Q7AE5.js";
26
26
 
27
27
  // src/diagnostics/doctor-cli.ts
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-LTBUGDLE.js";
39
+ } from "./chunk-I5GST3DL.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -608,6 +608,17 @@ import Anthropic from "@anthropic-ai/sdk";
608
608
 
609
609
  // src/providers/base.ts
610
610
  var BaseProvider = class {
611
+ /**
612
+ * 该 provider 在「无工具的 content-only 流」里能否可靠产出文档正文(save_last_response
613
+ * tee 模式依赖此能力)。默认 true。DeepSeek/Kimi 覆写为 false:它们带着 agentic 循环的
614
+ * 工具调用惯性,在 content-only 重生成里会复发伪工具调用(DSML / `<tool_call>`),tee
615
+ * 怎么重试都剥不出正文(同 `enableStreamingToolCalls=false` 的同源怪癖)。
616
+ */
617
+ reliableContentOnlyTee = true;
618
+ /** 公开读能力位:host(REPL/Web)据此决定是否跳过注定失败的 tee、直接走 deferred 赛道。 */
619
+ get supportsContentOnlyTee() {
620
+ return this.reliableContentOnlyTee;
621
+ }
611
622
  /**
612
623
  * 将 Message[] 转换为 OpenAI API 格式的消息数组。
613
624
  * content 为 string 时直接传递;为 MessageContentPart[] 时保留数组格式(vision 请求)。
@@ -1974,6 +1985,11 @@ function isCleanDocumentBody(content) {
1974
1985
  function teeFileStats(content) {
1975
1986
  return { lines: content.split("\n").length, bytes: Buffer.byteLength(content, "utf-8") };
1976
1987
  }
1988
+ function freshPriorContent(current, baselineAtTurnStart) {
1989
+ if (!current) return void 0;
1990
+ if (current === baselineAtTurnStart) return void 0;
1991
+ return current;
1992
+ }
1977
1993
  function evaluateTeeContent(rawContent, saveToFile, priorContent) {
1978
1994
  const fallback = (matched) => {
1979
1995
  if (priorContent && priorContent !== rawContent && isCleanDocumentBody(priorContent)) {
@@ -3013,6 +3029,13 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
3013
3029
  defaultBaseUrl = "https://api.deepseek.com/v1";
3014
3030
  /** 禁用流式工具调用,确保 chatWithTools 覆写(代码块检测)生效 */
3015
3031
  enableStreamingToolCalls = false;
3032
+ /**
3033
+ * content-only tee 不可靠:DeepSeek(尤以 V4 Pro)带着 agentic 循环的工具调用惯性,
3034
+ * 在无工具的重生成流里会复发伪工具调用(DSML / `<tool_call>`),剥不出文档正文。
3035
+ * host 据此跳过注定失败的 tee、直接走 deferred 赛道(普通文本写报告 + 自动落盘),
3036
+ * 省掉一次满上下文往返(v0.4.196)。
3037
+ */
3038
+ reliableContentOnlyTee = false;
3016
3039
  info = {
3017
3040
  id: "deepseek",
3018
3041
  displayName: "DeepSeek",
@@ -3209,6 +3232,9 @@ var KimiProvider = class _KimiProvider extends OpenAICompatibleProvider {
3209
3232
  defaultBaseUrl = "https://api.moonshot.ai/v1";
3210
3233
  // 禁用流式工具调用:Kimi 的 XML 伪调用检测(方案 A)需要完整响应
3211
3234
  enableStreamingToolCalls = false;
3235
+ // content-only tee 不可靠(同 DeepSeek):agentic 惯性下重生成会复发伪工具调用,
3236
+ // 剥不出文档正文。host 据此跳过 tee、直接走 deferred 赛道(v0.4.196)。
3237
+ reliableContentOnlyTee = false;
3212
3238
  /**
3213
3239
  * Kimi K2.x 系列(非 moonshot-v1)只允许 temperature=1。
3214
3240
  * 其他值会收到 400 "invalid temperature: only 1 is allowed for this model"。
@@ -12767,6 +12793,7 @@ ${mcpBudgetNote}` : "");
12767
12793
  const ac = new AbortController();
12768
12794
  this.abortController = ac;
12769
12795
  let pendingTeeSave = null;
12796
+ const lastAssistantAtTurnStart = lastAssistantText(apiMessages);
12770
12797
  try {
12771
12798
  const loopResult = await runAgentLoop({
12772
12799
  maxToolRounds,
@@ -12988,6 +13015,18 @@ ${summaryContent}`,
12988
13015
  extraMessages.push(...provider.buildToolResultMessages(toolCalls, results, reasoningContent));
12989
13016
  return "continue";
12990
13017
  }
13018
+ const freshPrior = freshPriorContent(lastAssistantText(apiMessages), lastAssistantAtTurnStart);
13019
+ if (provider.supportsContentOnlyTee === false && !freshPrior) {
13020
+ pendingTeeSave = saveToFile;
13021
+ this.send({ type: "info", message: `\u21AA \u8DF3\u8FC7 tee\uFF08${this.currentProvider} \u4E0D\u64C5\u957F content-only \u751F\u6210\uFF09\uFF0C\u6539\u7528\u666E\u901A\u6587\u672C\u5199\u62A5\u544A\uFF0C\u5C06\u81EA\u52A8\u4FDD\u5B58\u5230 ${saveToFile}` });
13022
+ const results = toolCalls.map((tc) => ({
13023
+ callId: tc.id,
13024
+ content: tc.id === call.id ? buildDeferredSaveInstruction(saveToFile) : "[skipped: write the document as plain text, not via tools]",
13025
+ isError: tc.id === call.id
13026
+ }));
13027
+ extraMessages.push(...provider.buildToolResultMessages(toolCalls, results, reasoningContent));
13028
+ return "continue";
13029
+ }
12991
13030
  const teeResult = await this.runSaveLastResponseTee(
12992
13031
  provider,
12993
13032
  call,
@@ -12998,7 +13037,8 @@ ${summaryContent}`,
12998
13037
  systemPromptVolatile,
12999
13038
  modelParams,
13000
13039
  ac,
13001
- usage
13040
+ usage,
13041
+ freshPrior
13002
13042
  );
13003
13043
  if (teeResult.deferred) pendingTeeSave = saveToFile;
13004
13044
  const teeToolResults = toolCalls.map((tc) => {
@@ -13056,7 +13096,7 @@ ${summaryContent}`,
13056
13096
  * - 同一轮其余 tool_calls 会被标记为 skipped——AI 通常只调一个工具,多并发
13057
13097
  * 场景极少。
13058
13098
  */
13059
- async runSaveLastResponseTee(provider, call, saveToFile, apiMessages, extraMessages, systemPrompt, systemPromptVolatile, modelParams, ac, roundUsage) {
13099
+ async runSaveLastResponseTee(provider, call, saveToFile, apiMessages, extraMessages, systemPrompt, systemPromptVolatile, modelParams, ac, roundUsage, priorContent) {
13060
13100
  let deferred = false;
13061
13101
  this.send({
13062
13102
  type: "tool_call_start",
@@ -13106,7 +13146,7 @@ ${summaryContent}`,
13106
13146
  await new Promise((resolve7, reject) => {
13107
13147
  fileStream.end((err) => err ? reject(err) : resolve7());
13108
13148
  });
13109
- const verdict = evaluateTeeContent(fullContent, saveToFile, lastAssistantText(apiMessages));
13149
+ const verdict = evaluateTeeContent(fullContent, saveToFile, priorContent);
13110
13150
  if (verdict.kind === "reject") {
13111
13151
  cleanupRejectedTeeFile(saveToFile);
13112
13152
  isError = true;
@@ -14180,7 +14220,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
14180
14220
  case "test": {
14181
14221
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
14182
14222
  try {
14183
- const { executeTests } = await import("./run-tests-RFK53W3D.js");
14223
+ const { executeTests } = await import("./run-tests-SRAVIQHP.js");
14184
14224
  const argStr = args.join(" ").trim();
14185
14225
  let testArgs = {};
14186
14226
  if (argStr) {
@@ -154,7 +154,7 @@ ${content}`);
154
154
  }
155
155
  }
156
156
  async function runTaskMode(config, providers, configManager, topic) {
157
- const { TaskOrchestrator } = await import("./task-orchestrator-GJBPVYFW.js");
157
+ const { TaskOrchestrator } = await import("./task-orchestrator-4IPPR3RK.js");
158
158
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
159
159
  let interrupted = false;
160
160
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  saveDevState,
16
16
  sessionHasMeaningfulContent,
17
17
  setupProxy
18
- } from "./chunk-6VMXFFO3.js";
18
+ } from "./chunk-GCQCR6GS.js";
19
19
  import {
20
20
  ToolExecutor,
21
21
  ToolRegistry,
@@ -35,10 +35,10 @@ import {
35
35
  spawnAgentContext,
36
36
  theme,
37
37
  undoStack
38
- } from "./chunk-ZJX6ZU5D.js";
38
+ } from "./chunk-PREP4QF5.js";
39
39
  import "./chunk-T2NL5ZIA.js";
40
40
  import "./chunk-BXP6YZ2P.js";
41
- import "./chunk-3KCEPI4E.js";
41
+ import "./chunk-DXWNQA7R.js";
42
42
  import {
43
43
  SessionManager,
44
44
  getContentText
@@ -55,16 +55,16 @@ import {
55
55
  getConfigDirUsage,
56
56
  listRecentCrashes,
57
57
  writeCrashLog
58
- } from "./chunk-5IVUINDO.js";
58
+ } from "./chunk-DXUS6OZH.js";
59
59
  import {
60
60
  ProviderRegistry
61
- } from "./chunk-2BLBXGOE.js";
61
+ } from "./chunk-UA43JQPP.js";
62
62
  import {
63
63
  getStatsSnapshot,
64
64
  getTopFailingTools,
65
65
  getTopUsedTools,
66
66
  installFlushOnExit
67
- } from "./chunk-CKBBAXCA.js";
67
+ } from "./chunk-MJAQ7GYG.js";
68
68
  import {
69
69
  CONTENT_ONLY_STREAM_REMINDER,
70
70
  TEE_FINAL_USER_NUDGE,
@@ -77,14 +77,15 @@ import {
77
77
  consumeToolCallStream,
78
78
  evaluateTeeContent,
79
79
  extractWrittenFilePaths,
80
+ freshPriorContent,
80
81
  isCleanDocumentBody,
81
82
  runAgentLoop,
82
83
  stripToolCallReminder,
83
84
  teeStreamErrorSummary
84
- } from "./chunk-ZRG2FPC6.js";
85
+ } from "./chunk-YZH2QQXJ.js";
85
86
  import {
86
87
  ConfigManager
87
- } from "./chunk-ZVMXIRBH.js";
88
+ } from "./chunk-WM2WVHKT.js";
88
89
  import {
89
90
  AuthError,
90
91
  ProviderError,
@@ -111,7 +112,7 @@ import {
111
112
  SKILLS_DIR_NAME,
112
113
  VERSION,
113
114
  buildUserIdentityPrompt
114
- } from "./chunk-ZEHHAE3B.js";
115
+ } from "./chunk-PK7MMIKC.js";
115
116
  import {
116
117
  formatGitContextForPrompt,
117
118
  getGitContext,
@@ -1826,7 +1827,7 @@ No tools match "${filter}".
1826
1827
  const { join: join5 } = await import("path");
1827
1828
  const { existsSync: existsSync5 } = await import("fs");
1828
1829
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1829
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-CDVYNTU7.js");
1830
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-K6Z3CTGO.js");
1830
1831
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1831
1832
  const cwd = process.cwd();
1832
1833
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2887,7 +2888,7 @@ ${hint}` : "")
2887
2888
  usage: "/test [command|filter]",
2888
2889
  async execute(args, ctx) {
2889
2890
  try {
2890
- const { executeTests } = await import("./run-tests-A2I3WZ2H.js");
2891
+ const { executeTests } = await import("./run-tests-JI4KLFJ5.js");
2891
2892
  const argStr = args.join(" ").trim();
2892
2893
  let testArgs = {};
2893
2894
  if (argStr) {
@@ -6398,6 +6399,7 @@ ${mcpBudgetNote}` : "");
6398
6399
  let lastToolCallSignature = "";
6399
6400
  let repeatedToolCallCount = 0;
6400
6401
  let pendingTeeSave = null;
6402
+ const lastResponseAtTurnStart = lastResponseStore.content;
6401
6403
  this.setupInterjectionListener();
6402
6404
  try {
6403
6405
  const loopResult = await runAgentLoop({
@@ -6816,6 +6818,22 @@ Tip: You can continue the conversation by asking the AI to proceed.`
6816
6818
  extraMessages.push(...provider.buildToolResultMessages(toolCalls, results, reasoningContent));
6817
6819
  return "continue";
6818
6820
  }
6821
+ if (provider.supportsContentOnlyTee === false && !freshPriorContent(lastResponseStore.content, lastResponseAtTurnStart)) {
6822
+ pendingTeeSave = saveToFile;
6823
+ process.stdout.write(theme.dim(
6824
+ `
6825
+ \u21AA ${this.currentProvider} \u4E0D\u64C5\u957F content-only \u751F\u6210\uFF0C\u8DF3\u8FC7 tee\uFF0C\u6539\u7528\u666E\u901A\u6587\u672C\u5199\u62A5\u544A\uFF08\u5C06\u81EA\u52A8\u4FDD\u5B58\u5230 ${saveToFile}\uFF09
6826
+
6827
+ `
6828
+ ));
6829
+ const results = toolCalls.map((tc) => ({
6830
+ callId: tc.id,
6831
+ content: tc.name === "save_last_response" ? buildDeferredSaveInstruction(saveToFile) : `[skipped: write the document as plain text, not via tools]`,
6832
+ isError: tc.name === "save_last_response"
6833
+ }));
6834
+ extraMessages.push(...provider.buildToolResultMessages(toolCalls, results, reasoningContent));
6835
+ return "continue";
6836
+ }
6819
6837
  const teeAc = this.setupStreamInterrupt();
6820
6838
  try {
6821
6839
  const teeSystemPrompt = stripToolCallReminder(systemPrompt ?? "") + CONTENT_ONLY_STREAM_REMINDER;
@@ -6866,7 +6884,11 @@ Tip: You can continue the conversation by asking the AI to proceed.`
6866
6884
  return "continue";
6867
6885
  }
6868
6886
  if (genUsage) accumulateUsage(usage, genUsage);
6869
- const verdict = evaluateTeeContent(genContent, saveToFile, lastResponseStore.content);
6887
+ const verdict = evaluateTeeContent(
6888
+ genContent,
6889
+ saveToFile,
6890
+ freshPriorContent(lastResponseStore.content, lastResponseAtTurnStart)
6891
+ );
6870
6892
  if (verdict.kind === "reject") {
6871
6893
  cleanupRejectedTeeFile(saveToFile);
6872
6894
  const label = verdict.reason === "meta-narration" ? "meta-narration / leaked reasoning, not document body" : "pseudo-tool-call markup with no usable document body";
@@ -7244,7 +7266,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7244
7266
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7245
7267
  process.exit(1);
7246
7268
  }
7247
- const { startWebServer } = await import("./server-6NLQUZKD.js");
7269
+ const { startWebServer } = await import("./server-JNHAYMDO.js");
7248
7270
  await startWebServer({ port, host: options.host });
7249
7271
  });
7250
7272
  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) => {
@@ -7411,16 +7433,16 @@ program.command("sessions").description("List recent conversation sessions").opt
7411
7433
  console.log(footer + "\n");
7412
7434
  });
7413
7435
  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) => {
7414
- const { runUsageCli } = await import("./usage-7DVISDK2.js");
7436
+ const { runUsageCli } = await import("./usage-EEQI544N.js");
7415
7437
  await runUsageCli(options);
7416
7438
  });
7417
7439
  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) => {
7418
- const { runDoctorCli } = await import("./doctor-cli-Q3QFVEWQ.js");
7440
+ const { runDoctorCli } = await import("./doctor-cli-OPFDP5XS.js");
7419
7441
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7420
7442
  });
7421
7443
  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) => {
7422
7444
  try {
7423
- const batch = await import("./batch-XGARS57W.js");
7445
+ const batch = await import("./batch-GRWWEG6A.js");
7424
7446
  switch (action) {
7425
7447
  case "submit":
7426
7448
  if (!arg) {
@@ -7463,7 +7485,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7463
7485
  }
7464
7486
  });
7465
7487
  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) => {
7466
- const { startMcpServer } = await import("./server-RULXWZD4.js");
7488
+ const { startMcpServer } = await import("./server-ZBM2UVWA.js");
7467
7489
  await startMcpServer({
7468
7490
  allowDestructive: !!options.allowDestructive,
7469
7491
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7472,7 +7494,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
7472
7494
  });
7473
7495
  });
7474
7496
  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; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).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)").action(async (options) => {
7475
- const { runCi } = await import("./ci-4TYLP7HF.js");
7497
+ const { runCi } = await import("./ci-PATHTNOQ.js");
7476
7498
  const result = await runCi({
7477
7499
  pr: options.pr,
7478
7500
  base: options.base,
@@ -7618,7 +7640,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7618
7640
  }),
7619
7641
  config.get("customProviders")
7620
7642
  );
7621
- const { startHub } = await import("./hub-UORFAHQ3.js");
7643
+ const { startHub } = await import("./hub-4GYSHUUZ.js");
7622
7644
  await startHub(
7623
7645
  {
7624
7646
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-3KCEPI4E.js";
6
- import "./chunk-ZEHHAE3B.js";
5
+ } from "./chunk-DXWNQA7R.js";
6
+ import "./chunk-PK7MMIKC.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-LTBUGDLE.js";
4
+ } from "./chunk-I5GST3DL.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -19,7 +19,7 @@ import {
19
19
  loadDevState,
20
20
  persistToolRound,
21
21
  setupProxy
22
- } from "./chunk-6VMXFFO3.js";
22
+ } from "./chunk-GCQCR6GS.js";
23
23
  import {
24
24
  ToolExecutor,
25
25
  ToolRegistry,
@@ -38,10 +38,10 @@ import {
38
38
  spawnAgentContext,
39
39
  truncateOutput,
40
40
  undoStack
41
- } from "./chunk-ZJX6ZU5D.js";
41
+ } from "./chunk-PREP4QF5.js";
42
42
  import "./chunk-T2NL5ZIA.js";
43
43
  import "./chunk-BXP6YZ2P.js";
44
- import "./chunk-3KCEPI4E.js";
44
+ import "./chunk-DXWNQA7R.js";
45
45
  import {
46
46
  SessionManager,
47
47
  getContentText
@@ -52,10 +52,10 @@ import {
52
52
  } from "./chunk-V37XOYOE.js";
53
53
  import {
54
54
  ProviderRegistry
55
- } from "./chunk-2BLBXGOE.js";
55
+ } from "./chunk-UA43JQPP.js";
56
56
  import {
57
57
  runTool
58
- } from "./chunk-CKBBAXCA.js";
58
+ } from "./chunk-MJAQ7GYG.js";
59
59
  import {
60
60
  CONTENT_ONLY_STREAM_REMINDER,
61
61
  TEE_FINAL_USER_NUDGE,
@@ -64,15 +64,16 @@ import {
64
64
  buildRoundBudgetHint,
65
65
  consumeToolCallStream,
66
66
  evaluateTeeContent,
67
+ freshPriorContent,
67
68
  getDangerLevel,
68
69
  isCleanDocumentBody,
69
70
  runAgentLoop,
70
71
  stripToolCallReminder,
71
72
  teeStreamErrorSummary
72
- } from "./chunk-ZRG2FPC6.js";
73
+ } from "./chunk-YZH2QQXJ.js";
73
74
  import {
74
75
  ConfigManager
75
- } from "./chunk-ZVMXIRBH.js";
76
+ } from "./chunk-WM2WVHKT.js";
76
77
  import "./chunk-TZQHYZKT.js";
77
78
  import {
78
79
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -92,7 +93,7 @@ import {
92
93
  SKILLS_DIR_NAME,
93
94
  VERSION,
94
95
  buildUserIdentityPrompt
95
- } from "./chunk-ZEHHAE3B.js";
96
+ } from "./chunk-PK7MMIKC.js";
96
97
  import {
97
98
  formatGitContextForPrompt,
98
99
  getGitContext,
@@ -1026,6 +1027,7 @@ ${mcpBudgetNote}` : "");
1026
1027
  const ac = new AbortController();
1027
1028
  this.abortController = ac;
1028
1029
  let pendingTeeSave = null;
1030
+ const lastAssistantAtTurnStart = lastAssistantText(apiMessages);
1029
1031
  try {
1030
1032
  const loopResult = await runAgentLoop({
1031
1033
  maxToolRounds,
@@ -1247,6 +1249,18 @@ ${summaryContent}`,
1247
1249
  extraMessages.push(...provider.buildToolResultMessages(toolCalls, results, reasoningContent));
1248
1250
  return "continue";
1249
1251
  }
1252
+ const freshPrior = freshPriorContent(lastAssistantText(apiMessages), lastAssistantAtTurnStart);
1253
+ if (provider.supportsContentOnlyTee === false && !freshPrior) {
1254
+ pendingTeeSave = saveToFile;
1255
+ this.send({ type: "info", message: `\u21AA \u8DF3\u8FC7 tee\uFF08${this.currentProvider} \u4E0D\u64C5\u957F content-only \u751F\u6210\uFF09\uFF0C\u6539\u7528\u666E\u901A\u6587\u672C\u5199\u62A5\u544A\uFF0C\u5C06\u81EA\u52A8\u4FDD\u5B58\u5230 ${saveToFile}` });
1256
+ const results = toolCalls.map((tc) => ({
1257
+ callId: tc.id,
1258
+ content: tc.id === call.id ? buildDeferredSaveInstruction(saveToFile) : "[skipped: write the document as plain text, not via tools]",
1259
+ isError: tc.id === call.id
1260
+ }));
1261
+ extraMessages.push(...provider.buildToolResultMessages(toolCalls, results, reasoningContent));
1262
+ return "continue";
1263
+ }
1250
1264
  const teeResult = await this.runSaveLastResponseTee(
1251
1265
  provider,
1252
1266
  call,
@@ -1257,7 +1271,8 @@ ${summaryContent}`,
1257
1271
  systemPromptVolatile,
1258
1272
  modelParams,
1259
1273
  ac,
1260
- usage
1274
+ usage,
1275
+ freshPrior
1261
1276
  );
1262
1277
  if (teeResult.deferred) pendingTeeSave = saveToFile;
1263
1278
  const teeToolResults = toolCalls.map((tc) => {
@@ -1315,7 +1330,7 @@ ${summaryContent}`,
1315
1330
  * - 同一轮其余 tool_calls 会被标记为 skipped——AI 通常只调一个工具,多并发
1316
1331
  * 场景极少。
1317
1332
  */
1318
- async runSaveLastResponseTee(provider, call, saveToFile, apiMessages, extraMessages, systemPrompt, systemPromptVolatile, modelParams, ac, roundUsage) {
1333
+ async runSaveLastResponseTee(provider, call, saveToFile, apiMessages, extraMessages, systemPrompt, systemPromptVolatile, modelParams, ac, roundUsage, priorContent) {
1319
1334
  let deferred = false;
1320
1335
  this.send({
1321
1336
  type: "tool_call_start",
@@ -1365,7 +1380,7 @@ ${summaryContent}`,
1365
1380
  await new Promise((resolve3, reject) => {
1366
1381
  fileStream.end((err) => err ? reject(err) : resolve3());
1367
1382
  });
1368
- const verdict = evaluateTeeContent(fullContent, saveToFile, lastAssistantText(apiMessages));
1383
+ const verdict = evaluateTeeContent(fullContent, saveToFile, priorContent);
1369
1384
  if (verdict.kind === "reject") {
1370
1385
  cleanupRejectedTeeFile(saveToFile);
1371
1386
  isError = true;
@@ -2439,7 +2454,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2439
2454
  case "test": {
2440
2455
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2441
2456
  try {
2442
- const { executeTests } = await import("./run-tests-A2I3WZ2H.js");
2457
+ const { executeTests } = await import("./run-tests-JI4KLFJ5.js");
2443
2458
  const argStr = args.join(" ").trim();
2444
2459
  let testArgs = {};
2445
2460
  if (argStr) {
@@ -1,21 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-ZJX6ZU5D.js";
4
+ } from "./chunk-PREP4QF5.js";
5
5
  import "./chunk-T2NL5ZIA.js";
6
6
  import "./chunk-BXP6YZ2P.js";
7
- import "./chunk-3KCEPI4E.js";
7
+ import "./chunk-DXWNQA7R.js";
8
8
  import {
9
9
  runTool
10
- } from "./chunk-CKBBAXCA.js";
10
+ } from "./chunk-MJAQ7GYG.js";
11
11
  import {
12
12
  getDangerLevel,
13
13
  schemaToJsonSchema
14
- } from "./chunk-ZRG2FPC6.js";
14
+ } from "./chunk-YZH2QQXJ.js";
15
15
  import "./chunk-TZQHYZKT.js";
16
16
  import {
17
17
  VERSION
18
- } from "./chunk-ZEHHAE3B.js";
18
+ } from "./chunk-PK7MMIKC.js";
19
19
  import "./chunk-4BKXL7SM.js";
20
20
  import "./chunk-TB4W4Y4T.js";
21
21
  import "./chunk-KHYD3WXE.js";
@@ -3,21 +3,21 @@ import {
3
3
  ToolRegistry,
4
4
  googleSearchContext,
5
5
  truncateOutput
6
- } from "./chunk-ZJX6ZU5D.js";
6
+ } from "./chunk-PREP4QF5.js";
7
7
  import "./chunk-T2NL5ZIA.js";
8
8
  import "./chunk-BXP6YZ2P.js";
9
- import "./chunk-3KCEPI4E.js";
9
+ import "./chunk-DXWNQA7R.js";
10
10
  import {
11
11
  runTool
12
- } from "./chunk-CKBBAXCA.js";
12
+ } from "./chunk-MJAQ7GYG.js";
13
13
  import {
14
14
  getDangerLevel,
15
15
  runLeanAgentLoop
16
- } from "./chunk-ZRG2FPC6.js";
16
+ } from "./chunk-YZH2QQXJ.js";
17
17
  import "./chunk-TZQHYZKT.js";
18
18
  import {
19
19
  SUBAGENT_ALLOWED_TOOLS
20
- } from "./chunk-ZEHHAE3B.js";
20
+ } from "./chunk-PK7MMIKC.js";
21
21
  import "./chunk-4BKXL7SM.js";
22
22
  import "./chunk-TB4W4Y4T.js";
23
23
  import "./chunk-KHYD3WXE.js";
@@ -8,9 +8,9 @@ import {
8
8
  } from "./chunk-V37XOYOE.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-ZVMXIRBH.js";
11
+ } from "./chunk-WM2WVHKT.js";
12
12
  import "./chunk-TZQHYZKT.js";
13
- import "./chunk-ZEHHAE3B.js";
13
+ import "./chunk-PK7MMIKC.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
15
 
16
16
  // src/cli/usage.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.194",
3
+ "version": "0.4.196",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",