kcode-pi 0.1.34 → 0.1.35

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.
@@ -8,8 +8,8 @@
8
8
 
9
9
  - Node.js `>=22.19.0`
10
10
  - npm
11
- - Windows 推荐使用 Windows Terminal
12
- - 不需要安装 Python。KCode 随包工具使用 Node/TypeScript 实现;只有业务项目或外部脚本明确依赖 Python 时才需要另行安装。
11
+ - Windows 环境使用 Windows Terminal
12
+ - 无需安装 Python。KCode 随包工具使用 Node/TypeScript 实现;只有业务项目或外部脚本明确依赖 Python 时才另行安装。
13
13
 
14
14
  全局安装:
15
15
 
@@ -25,7 +25,7 @@ kcode
25
25
 
26
26
  ## 初始化业务项目
27
27
 
28
- 先在终端进入你的实际业务项目根目录,不是 KCode 源码目录。
28
+ 在终端进入实际业务项目根目录,不是 KCode 源码目录。
29
29
 
30
30
  初始化项目级配置:
31
31
 
@@ -73,7 +73,7 @@ kcode version
73
73
  kcode start
74
74
  ```
75
75
 
76
- `kcode start` 会先确保 `.pi/settings.json` 已登记当前安装的 KCode package,然后启动随包 Pi CLI。
76
+ `kcode start` 会确保 `.pi/settings.json` 已登记当前安装的 KCode package,然后启动随包 Pi CLI。
77
77
 
78
78
  `start` 后面的参数会原样透传给 Pi CLI:
79
79
 
@@ -83,7 +83,7 @@ kcode start --provider openai --model gpt-4o
83
83
 
84
84
  ## 配置模型
85
85
 
86
- 首次启动 Pi 时,如果看到:
86
+ 首次启动 Pi 时出现以下信息:
87
87
 
88
88
  ```text
89
89
  Warning: No models available.
@@ -107,7 +107,7 @@ DeepSeek
107
107
  Gemini
108
108
  ```
109
109
 
110
- 也可以在 PowerShell 中设置环境变量后再启动:
110
+ 支持在 PowerShell 中设置环境变量后再启动:
111
111
 
112
112
  ```powershell
113
113
  $env:OPENAI_API_KEY="sk-..."
@@ -124,7 +124,7 @@ KCode 在 Pi 内注册的 `/kd-*` 命令见 [命令参考](COMMAND_REFERENCE.md#
124
124
 
125
125
  ## 自定义模型供应商
126
126
 
127
- 如果你的模型服务是企业网关、代理服务、Ollama、LM Studio、vLLM,或其他 OpenAI-compatible endpoint,不需要改 KCode。Pi 原生支持通过用户级配置文件添加自定义供应商:
127
+ 模型服务为企业网关、代理服务、Ollama、LM Studio、vLLM 或其他 OpenAI-compatible endpoint 时,无需修改 KCode。Pi 原生支持通过用户级配置文件添加自定义供应商:
128
128
 
129
129
  ```powershell
130
130
  notepad $env:USERPROFILE\.pi\agent\models.json
@@ -171,7 +171,7 @@ $env:CORP_AI_API_KEY="sk-..."
171
171
  kcode start
172
172
  ```
173
173
 
174
- 也可以直接指定:
174
+ 支持直接指定:
175
175
 
176
176
  ```powershell
177
177
  kcode start --provider corp-ai --model corp-coder
@@ -199,11 +199,11 @@ npm install -g kcode-pi@latest
199
199
  kcode version
200
200
  ```
201
201
 
202
- 升级后建议在业务项目根目录执行:
202
+ 升级后在业务项目根目录执行:
203
203
 
204
204
  ```powershell
205
205
  kcode init
206
206
  kcode doctor --deep
207
207
  ```
208
208
 
209
- 如果升级失败或仍加载旧版本,见 [故障排查](TROUBLESHOOTING.md)
209
+ 升级失败或仍加载旧版本时,按 [故障排查](TROUBLESHOOTING.md) 处理。
@@ -22,6 +22,7 @@ import type { KdRisk } from "../src/harness/types.ts";
22
22
  import { readArtifact } from "../src/harness/artifacts.ts";
23
23
  import { flagshipWriteBlockReason, isSourceLikePath, planWriteBlockReason } from "../src/harness/path-policy.ts";
24
24
  import { sdkSignatureProductionWriteBlockReason } from "../src/harness/sdk-policy.ts";
25
+ import { dataSourceProductionWriteBlockReason } from "../src/harness/data-source-policy.ts";
25
26
  import { tddProductionWriteBlockReason } from "../src/harness/tdd-policy.ts";
26
27
  import { windowsPathHint } from "../src/platform/path.ts";
27
28
  import { repairPromptForRun, workflowPromptForRun } from "../src/harness/prompt.ts";
@@ -137,14 +138,15 @@ function codeWriteBlockReason(cwd: string, path: string | undefined): string | u
137
138
 
138
139
  const run = readActiveRun(cwd);
139
140
  if (!run) {
140
- return "KCode 工作流未启动,不能直接写产品代码。下一步:先用自然语言说明需求让 KCode 自动进入 discuss,或手动运行 /kd-start <需求> 创建 run;完成 discuss -> spec -> plan -> execute 后再写生产源码。";
141
+ return "KCode 工作流未启动,禁止直接写产品代码。执行指令:使用自然语言需求启动 discuss,或执行 /kd-start <需求> 创建 run;完成 discuss -> spec -> plan -> execute 后再写生产源码。";
141
142
  }
142
143
 
143
144
  if (run.phase !== "execute") {
144
- return `当前 KCode 阶段是 ${run.phase},不能写产品代码。下一步:先完成当前阶段文档和门禁,用 /kd-advance 推进到 execute;如果发现计划不完整,更新 PLAN.md,而不是直接写代码。`;
145
+ return `当前 KCode 阶段是 ${run.phase},禁止写产品代码。执行指令:完成当前阶段文档和门禁,使用 /kd-advance 推进到 execute;计划不完整时更新 PLAN.md,禁止直接写代码。`;
145
146
  }
146
147
 
147
148
  return (
149
+ dataSourceProductionWriteBlockReason(cwd, run, path) ??
148
150
  sdkSignatureProductionWriteBlockReason(cwd, run, path) ??
149
151
  tddProductionWriteBlockReason(cwd, run, path) ??
150
152
  planWriteBlockReason(cwd, run, path, readArtifact(cwd, run, "plan") ?? "")
@@ -154,7 +156,7 @@ function codeWriteBlockReason(cwd: string, path: string | undefined): string | u
154
156
  const kdPlanStatusTool = defineTool({
155
157
  name: "kd_plan_status",
156
158
  label: "KD 状态",
157
- description: "查看当前金蝶 Harness run、当前阶段、必需文档和门禁状态。",
159
+ description: "输出当前金蝶 Harness run、当前阶段、必需文档和门禁状态。",
158
160
  parameters: Type.Object({}),
159
161
 
160
162
  async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
@@ -170,22 +172,22 @@ const kdQuestionTool = defineTool({
170
172
  name: "kd_question",
171
173
  label: "KD 问题",
172
174
  description:
173
- "创建、回答或列出金蝶 Harness 结构化问题。每次只记录一个最阻塞的短问题。",
175
+ "创建、回答或列出金蝶 Harness 结构化问题。每次必须只记录一个最阻塞的短问题。",
174
176
  parameters: Type.Object({
175
177
  action: Type.Optional(Type.String({ description: "操作类型:ask、answer 或 list,默认 ask。" })),
176
178
  id: Type.Optional(Type.String({ description: "回答问题时的问题编号,例如 Q-001。" })),
177
- question: Type.Optional(Type.String({ description: "提问内容。使用一个短问题。" })),
179
+ question: Type.Optional(Type.String({ description: "提问内容;必须是一个短问题。" })),
178
180
  answer: Type.Optional(Type.String({ description: "用户答案,action=answer 时使用。" })),
179
- reason: Type.Optional(Type.String({ description: "说明为什么这个问题会阻塞当前阶段。" })),
180
- choices: Type.Optional(Type.Array(Type.String(), { description: "可选项,最多 3 个简短选项。" })),
181
- blocking: Type.Optional(Type.Boolean({ description: "是否阻塞阶段推进,默认 true。" })),
181
+ reason: Type.Optional(Type.String({ description: "当前阶段阻塞原因。" })),
182
+ choices: Type.Optional(Type.Array(Type.String(), { description: "候选答案;最多 3 个简短选项。" })),
183
+ blocking: Type.Optional(Type.Boolean({ description: "控制问题是否阻塞阶段推进,默认 true。" })),
182
184
  }),
183
185
 
184
186
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
185
187
  const run = readActiveRun(ctx.cwd);
186
188
  if (!run) {
187
189
  return {
188
- content: [{ type: "text", text: "当前没有 active Kingdee Harness run。请先使用 /kd-start <需求> 创建。" }],
190
+ content: [{ type: "text", text: "当前没有 active Kingdee Harness run。使用 /kd-start <需求> 创建。" }],
189
191
  details: { error: "no-active-run" },
190
192
  };
191
193
  }
@@ -199,7 +201,7 @@ const kdQuestionTool = defineTool({
199
201
  if (action === "answer") {
200
202
  if (!params.id || !params.answer) {
201
203
  return {
202
- content: [{ type: "text", text: "kd_question action=answer 需要同时提供 id 和 answer。" }],
204
+ content: [{ type: "text", text: "kd_question action=answer 必须同时提供 id 和 answer。" }],
203
205
  details: { error: "missing-answer-params" },
204
206
  };
205
207
  }
@@ -220,14 +222,14 @@ const kdQuestionTool = defineTool({
220
222
 
221
223
  if (action !== "ask") {
222
224
  return {
223
- content: [{ type: "text", text: `未知 kd_question action:${params.action}。请使用 ask、answerlist。` }],
225
+ content: [{ type: "text", text: `未知 kd_question action:${params.action}。有效值:ask、answerlist。` }],
224
226
  details: { error: "unknown-action", action: params.action },
225
227
  };
226
228
  }
227
229
 
228
230
  if (!params.question?.trim()) {
229
231
  return {
230
- content: [{ type: "text", text: "kd_question action=ask 需要提供 question。" }],
232
+ content: [{ type: "text", text: "kd_question action=ask 必须提供 question。" }],
231
233
  details: { error: "missing-question" },
232
234
  };
233
235
  }
@@ -240,11 +242,11 @@ const kdQuestionTool = defineTool({
240
242
  text: [
241
243
  batchProblem,
242
244
  "",
243
- "kd_question 一次只登记一个当前最阻塞的问题。",
244
- "请先问第一个必须确认的问题,例如:",
245
+ "kd_question 一次必须只登记一个当前最阻塞的问题。",
246
+ "登记第一个必须确认的问题,例如:",
245
247
  "kd_question action=ask question=\"采购入库单 Form ID 是否为 pur_receivebill?\" choices=[\"是\", \"不是\"]",
246
248
  "",
247
- "注意:交互模式下会弹出选择/输入对话并自动记录;非交互模式下用户在对话中回答后再用 kd_question action=answer 记录。",
249
+ "交互模式弹出选择/输入对话并自动记录;非交互模式必须由用户在对话中回答,再用 kd_question action=answer 记录。",
248
250
  ].join("\n"),
249
251
  },
250
252
  ],
@@ -272,7 +274,7 @@ const kdQuestionTool = defineTool({
272
274
  }
273
275
  }
274
276
 
275
- const text = `${formatQuestionCard(question)}\n\n未获得交互式答案;在用户回答前,该问题会保持 open。`;
277
+ const text = `${formatQuestionCard(question)}\n\n未记录交互式答案;该问题保持 open,直至用户回答。`;
276
278
  return { content: [{ type: "text", text }], details: { question, gate: readActiveRun(ctx.cwd)?.gate, answered: false } };
277
279
  },
278
280
  });
@@ -281,7 +283,7 @@ function createKdVerifyResultTool(pi: ExtensionAPI) {
281
283
  return defineTool({
282
284
  name: "kd_verify_result",
283
285
  label: "KD 验证结果",
284
- description: "记录当前 verify 命令结果。失败时自动写失败证据并回到 execute 修复;成功时记录通过证据并尝试推进。",
286
+ description: "记录当前 verify 命令结果。失败时自动写失败证据并回到 execute 修复;成功时记录通过证据并推进门禁。",
285
287
  parameters: Type.Object({
286
288
  command: Type.String({ description: "实际执行的验证命令。" }),
287
289
  exitCode: Type.Number({ description: "验证命令退出码。" }),
@@ -294,7 +296,7 @@ function createKdVerifyResultTool(pi: ExtensionAPI) {
294
296
  const run = readActiveRun(ctx.cwd);
295
297
  if (!run) {
296
298
  return {
297
- content: [{ type: "text", text: "当前没有 active Kingdee Harness run。请先使用 /kd-start <需求> 创建。" }],
299
+ content: [{ type: "text", text: "当前没有 active Kingdee Harness run。使用 /kd-start <需求> 创建。" }],
298
300
  details: { error: "no-active-run" },
299
301
  };
300
302
  }
@@ -326,7 +328,7 @@ export default function (pi: ExtensionAPI) {
326
328
  [
327
329
  `发现未完成 KCode run:${run.goal ?? run.id}`,
328
330
  `阶段:${run.phase},产品:${run.profile?.product ?? run.product ?? "unknown"}`,
329
- "输入 /kd-resume 可接续;输入 /kd-runs 查看其他需求或需求组。",
331
+ "执行 /kd-resume 接续;执行 /kd-runs 输出其他需求或需求组。",
330
332
  ].join("\n"),
331
333
  "info",
332
334
  );
@@ -342,7 +344,7 @@ export default function (pi: ExtensionAPI) {
342
344
  if (ctx.hasUI) {
343
345
  ctx.ui.notify(`已启动 Kingdee Harness run:${run.id}(${run.profile?.product}/${run.profile?.techStack})`, "info");
344
346
  if (run.profile?.product === "unknown") {
345
- ctx.ui.notify("产品画像未识别。下一步先执行 /kd-product <flagship|xinghan|cangqiong|enterprise>。", "warning");
347
+ ctx.ui.notify("产品画像未识别。执行指令:执行 /kd-product <flagship|xinghan|cangqiong|enterprise>。", "warning");
346
348
  }
347
349
  }
348
350
  }
@@ -360,7 +362,7 @@ export default function (pi: ExtensionAPI) {
360
362
  const path = typeof input.path === "string" ? input.path : undefined;
361
363
  const hint = path ? windowsPathHint(path) : undefined;
362
364
  if (hint && ["read", "write", "edit"].includes(event.toolName)) {
363
- const reason = `当前是 Windows 工作区,路径 ${path} 不是本项目使用的路径形式。下一步:改用项目相对路径;如果必须使用绝对路径,使用 Windows 路径 ${hint}。`;
365
+ const reason = `当前是 Windows 工作区,路径 ${path} 不是本项目使用的路径形式。执行指令:改用项目相对路径;必须使用绝对路径时,使用 Windows 路径 ${hint}。`;
364
366
  if (ctx.hasUI) ctx.ui.notify(reason, "warning");
365
367
  return { block: true, reason };
366
368
  }
@@ -369,7 +371,7 @@ export default function (pi: ExtensionAPI) {
369
371
  if (event.toolName === "read" && path) {
370
372
  const ext = path.toLowerCase().split(".").pop();
371
373
  if (ext === "pdf" || ext === "docx" || ext === "doc" || ext === "xlsx" || ext === "xls" || ext === "csv") {
372
- const reason = `read 工具无法解析 .${ext} 二进制格式。下一步:改用 kd_doc_read 工具读取此文件,参数 path="${path}"。`;
374
+ const reason = `read 工具无法解析 .${ext} 二进制格式。执行指令:改用 kd_doc_read 工具读取此文件,参数 path="${path}"。`;
373
375
  if (ctx.hasUI) ctx.ui.notify(reason, "info");
374
376
  return { block: true, reason };
375
377
  }
@@ -379,6 +381,7 @@ export default function (pi: ExtensionAPI) {
379
381
  if (subagentRole) {
380
382
  const run = readActiveRun(ctx.cwd);
381
383
  const sourceWriteBlock =
384
+ dataSourceProductionWriteBlockReason(ctx.cwd, run, path) ??
382
385
  sdkSignatureProductionWriteBlockReason(ctx.cwd, run, path) ??
383
386
  tddProductionWriteBlockReason(ctx.cwd, run, path) ??
384
387
  planWriteBlockReason(ctx.cwd, run, path, run ? (readArtifact(ctx.cwd, run, "plan") ?? "") : "") ??
@@ -408,14 +411,14 @@ export default function (pi: ExtensionAPI) {
408
411
  });
409
412
 
410
413
  pi.registerCommand("kd-status", {
411
- description: "查看当前 Kingdee Harness run 和门禁状态",
414
+ description: "输出当前 Kingdee Harness run 和门禁状态",
412
415
  handler: async (_args, ctx) => {
413
416
  ctx.ui.notify(formatStatus(ctx.cwd, readActiveRun(ctx.cwd)), "info");
414
417
  },
415
418
  });
416
419
 
417
420
  pi.registerCommand("kd-runs", {
418
- description: "列出当前项目的 Kingdee Harness run",
421
+ description: "输出当前项目的 Kingdee Harness run 列表",
419
422
  handler: async (_args, ctx) => {
420
423
  const active = readActiveRun(ctx.cwd);
421
424
  ctx.ui.notify(formatRuns(listRuns(ctx.cwd), active?.id), "info");
@@ -423,11 +426,11 @@ export default function (pi: ExtensionAPI) {
423
426
  });
424
427
 
425
428
  pi.registerCommand("kd-gate", {
426
- description: "刷新并查看当前 Kingdee Harness 门禁",
429
+ description: "刷新并输出当前 Kingdee Harness 门禁",
427
430
  handler: async (_args, ctx) => {
428
431
  const run = requireRun(ctx.cwd);
429
432
  if (!run) {
430
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
433
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
431
434
  return;
432
435
  }
433
436
  const refreshed = refreshGate(ctx.cwd, run);
@@ -436,7 +439,7 @@ export default function (pi: ExtensionAPI) {
436
439
  });
437
440
 
438
441
  pi.registerCommand("kd-start", {
439
- description: "启动一个 Kingdee Harness run:/kd-start [--product 产品] [--version 版本] <需求或需求组>",
442
+ description: "创建 Kingdee Harness run:/kd-start [--product 产品] [--version 版本] <需求或需求组>",
440
443
  handler: async (args, ctx) => {
441
444
  const parsed = parseStartArgs(args);
442
445
  const goal = parsed.goal;
@@ -448,7 +451,7 @@ export default function (pi: ExtensionAPI) {
448
451
  const run = createActiveRun(ctx.cwd, goal, parsed.product, parsed.version);
449
452
  ctx.ui.notify(`已启动 Kingdee Harness run:${run.id}(${run.profile?.product}/${run.profile?.techStack})`, "info");
450
453
  if (run.profile?.product === "unknown") {
451
- ctx.ui.notify("产品画像未识别。下一步先执行 /kd-product <flagship|xinghan|cangqiong|enterprise>。", "warning");
454
+ ctx.ui.notify("产品画像未识别。执行指令:执行 /kd-product <flagship|xinghan|cangqiong|enterprise>。", "warning");
452
455
  }
453
456
  sendWorkflowPrompt(pi, ctx, run, `继续 KCode Harness run ${run.id}:${goal}`);
454
457
  },
@@ -459,7 +462,7 @@ export default function (pi: ExtensionAPI) {
459
462
  handler: async (args, ctx) => {
460
463
  const run = requireRun(ctx.cwd);
461
464
  if (!run) {
462
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求> 或 /kd-runs。", "error");
465
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求> 或 /kd-runs。", "error");
463
466
  return;
464
467
  }
465
468
 
@@ -475,7 +478,7 @@ export default function (pi: ExtensionAPI) {
475
478
  });
476
479
 
477
480
  pi.registerCommand("kd-switch", {
478
- description: "切换当前 active Kingdee Harness run:/kd-switch <run-id>",
481
+ description: "设置当前 active Kingdee Harness run:/kd-switch <run-id>",
479
482
  handler: async (args, ctx) => {
480
483
  const id = args.trim();
481
484
  if (!id) {
@@ -485,7 +488,7 @@ export default function (pi: ExtensionAPI) {
485
488
 
486
489
  const run = switchActiveRun(ctx.cwd, id);
487
490
  if (!run) {
488
- ctx.ui.notify(`未找到 Kingdee Harness run:${id}。请用 /kd-runs 查看列表。`, "error");
491
+ ctx.ui.notify(`未找到 Kingdee Harness run:${id}。使用 /kd-runs 查看列表。`, "error");
489
492
  return;
490
493
  }
491
494
 
@@ -498,12 +501,12 @@ export default function (pi: ExtensionAPI) {
498
501
  handler: async (_args, ctx) => {
499
502
  const run = requireRun(ctx.cwd);
500
503
  if (!run) {
501
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
504
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
502
505
  return;
503
506
  }
504
507
 
505
508
  const finished = finishActiveRun(ctx.cwd, run);
506
- ctx.ui.notify(`已完成 Kingdee Harness run:${finished.id}。下一个需求或需求组请使用 /kd-start <需求>。`, "info");
509
+ ctx.ui.notify(`已完成 Kingdee Harness run:${finished.id}。下一个需求或需求组使用 /kd-start <需求>。`, "info");
507
510
  },
508
511
  });
509
512
 
@@ -512,7 +515,7 @@ export default function (pi: ExtensionAPI) {
512
515
  handler: async (args, ctx) => {
513
516
  const run = requireRun(ctx.cwd);
514
517
  if (!run) {
515
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
518
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
516
519
  return;
517
520
  }
518
521
 
@@ -533,7 +536,7 @@ export default function (pi: ExtensionAPI) {
533
536
  handler: async (args, ctx) => {
534
537
  const run = requireRun(ctx.cwd);
535
538
  if (!run) {
536
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
539
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
537
540
  return;
538
541
  }
539
542
 
@@ -554,7 +557,7 @@ export default function (pi: ExtensionAPI) {
554
557
  handler: async (args, ctx) => {
555
558
  const run = requireRun(ctx.cwd);
556
559
  if (!run) {
557
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
560
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
558
561
  return;
559
562
  }
560
563
 
@@ -562,7 +565,7 @@ export default function (pi: ExtensionAPI) {
562
565
  let requested: KdPhase | undefined;
563
566
  if (requestedText) {
564
567
  if (!isKdPhase(requestedText)) {
565
- ctx.ui.notify(`未知阶段 "${requestedText}"。可用阶段:${PHASE_ORDER.join(", ")}`, "error");
568
+ ctx.ui.notify(`未知阶段 "${requestedText}"。有效阶段:${PHASE_ORDER.join(", ")}`, "error");
566
569
  return;
567
570
  }
568
571
  requested = requestedText;
@@ -574,11 +577,11 @@ export default function (pi: ExtensionAPI) {
574
577
  });
575
578
 
576
579
  pi.registerCommand("kd-artifact", {
577
- description: "创建阶段文档,或显式覆盖阶段文档:/kd-artifact [阶段] [内容] [--replace]",
580
+ description: "创建阶段文档,或使用 --replace 显式覆盖阶段文档:/kd-artifact [阶段] [内容] [--replace]",
578
581
  handler: async (args, ctx) => {
579
582
  const run = requireRun(ctx.cwd);
580
583
  if (!run) {
581
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
584
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
582
585
  return;
583
586
  }
584
587
 
@@ -589,7 +592,7 @@ export default function (pi: ExtensionAPI) {
589
592
  }
590
593
 
591
594
  if (parsed.content && readArtifact(ctx.cwd, run, parsed.phase) !== undefined && !parsed.replace) {
592
- ctx.ui.notify(`拒绝覆盖 ${parsed.phase} 阶段文档。若确认要整体替换,请追加 --replace;追加内容应让 KCode 更新具体章节。`, "warning");
595
+ ctx.ui.notify(`拒绝覆盖 ${parsed.phase} 阶段文档。确认整体替换时追加 --replace;追加内容必须让 KCode 更新具体章节。`, "warning");
593
596
  return;
594
597
  }
595
598
 
@@ -606,7 +609,7 @@ export default function (pi: ExtensionAPI) {
606
609
  handler: async (args, ctx) => {
607
610
  const run = requireRun(ctx.cwd);
608
611
  if (!run) {
609
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
612
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
610
613
  return;
611
614
  }
612
615
  const [id, ...answerParts] = args.trim().split(/\s+/);
@@ -631,7 +634,7 @@ export default function (pi: ExtensionAPI) {
631
634
  handler: async (args, ctx) => {
632
635
  const run = requireRun(ctx.cwd);
633
636
  if (!run) {
634
- ctx.ui.notify("当前没有 active Kingdee Harness run。请使用 /kd-start <需求>。", "error");
637
+ ctx.ui.notify("当前没有 active Kingdee Harness run。使用 /kd-start <需求>。", "error");
635
638
  return;
636
639
  }
637
640
  const [exitCodeText, ...commandParts] = args.trim().split(/\s+/);
@@ -665,7 +668,7 @@ function formatQuestions(run: NonNullable<ReturnType<typeof readActiveRun>>): st
665
668
  }
666
669
 
667
670
  function formatRuns(runs: NonNullable<ReturnType<typeof readActiveRun>>[], activeId?: string): string {
668
- if (runs.length === 0) return "当前项目没有 Kingdee Harness run。请使用 /kd-start <需求> 创建。";
671
+ if (runs.length === 0) return "当前项目没有 Kingdee Harness run。使用 /kd-start <需求> 创建。";
669
672
  return runs
670
673
  .map((run) =>
671
674
  [
@@ -687,7 +690,7 @@ function formatQuestionCard(question: NonNullable<NonNullable<ReturnType<typeof
687
690
  question.choices?.length ? `选项:${question.choices.join(" | ")}` : undefined,
688
691
  question.answer ? `答案:${question.answer}` : undefined,
689
692
  question.status === "open"
690
- ? `如果有弹窗,请直接回答;否则请在对话中回复,并用 kd_question action=answer id=${question.id} answer=<答案> 记录。`
693
+ ? `交互弹窗出现时直接回答;无弹窗时在对话中回复,并使用 kd_question action=answer id=${question.id} answer=<答案> 记录。`
691
694
  : undefined,
692
695
  ];
693
696
  return lines.filter(Boolean).join("\n");
@@ -703,14 +706,14 @@ async function askQuestionInteractively(
703
706
  const normalizedChoices = choices?.map((choice) => choice.trim()).filter(Boolean) ?? [];
704
707
  try {
705
708
  if (normalizedChoices.length === 0) {
706
- return (await ctx.ui.input(question, "请输入答案"))?.trim() || undefined;
709
+ return (await ctx.ui.input(question, "输入答案"))?.trim() || undefined;
707
710
  }
708
711
 
709
- const customChoice = "其他,自定义输入";
712
+ const customChoice = "自定义输入";
710
713
  const selected = await ctx.ui.select(question, [...normalizedChoices, customChoice]);
711
714
  if (!selected) return undefined;
712
715
  if (selected !== customChoice) return selected;
713
- return (await ctx.ui.input(question, "请输入答案"))?.trim() || undefined;
716
+ return (await ctx.ui.input(question, "输入答案"))?.trim() || undefined;
714
717
  } catch {
715
718
  return undefined;
716
719
  }
@@ -721,8 +724,8 @@ function questionBatchProblem(question: string, choices?: string[]): string | un
721
724
  const numberedItems = text.split(/\r?\n/).filter((line) => /^\s*(\d+[\.\)、)]|[-*]\s+)/.test(line)).length;
722
725
  if (numberedItems >= 2) return "kd_question 拒绝了批量清单式问题。";
723
726
  if ((text.match(/[??]/g) ?? []).length > 1) return "kd_question 拒绝了一次包含多个问题的提问。";
724
- if (text.length > 220) return "kd_question 拒绝了过长问题。请只问当前最小的阻塞问题。";
725
- if ((choices?.length ?? 0) > 3) return "kd_question 拒绝了过多选项。最多提供 3 个简短选项。";
727
+ if (text.length > 220) return "kd_question 拒绝了过长问题。问题必须聚焦当前最小阻塞项。";
728
+ if ((choices?.length ?? 0) > 3) return "kd_question 拒绝了过多选项。最多 3 个简短选项。";
726
729
  if (choices?.some((choice) => choice.length > 40 || /[\r\n??]/.test(choice))) {
727
730
  return "kd_question 拒绝了复杂选项。选项必须是短标签,不能嵌套问题。";
728
731
  }
@@ -186,7 +186,7 @@ export default function (pi: ExtensionAPI) {
186
186
  description: "恢复 KCode 金蝶标题栏",
187
187
  handler: async (_args, ctx) => {
188
188
  if (ctx.mode !== "tui") return;
189
- ctx.ui.notify("请重启会话或重新加载扩展以恢复 KCode 标题栏。", "info");
189
+ ctx.ui.notify("重启会话或重新加载扩展以恢复 KCode 标题栏。", "info");
190
190
  },
191
191
  });
192
192
 
@@ -246,7 +246,7 @@ async function runChainedAgents(
246
246
 
247
247
  function formatModeResult(mode: "single" | "parallel" | "chain", results: ChildAgentResult[], limit: number): string {
248
248
  const succeeded = results.filter((result) => result.exitCode === 0).length;
249
- const header = `子 agent ${mode} 完成:${succeeded}/${results.length} succeeded`;
249
+ const header = `子 agent ${mode} 完成:${succeeded}/${results.length} 成功`;
250
250
  const sections = results.map((result, index) => {
251
251
  const output = truncateOutput(result.output || result.stderr || "(子 agent 无输出)", limit);
252
252
  return [