kcode-pi 0.1.19 → 0.1.23

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.
@@ -0,0 +1,209 @@
1
+ # KCode 用户指南
2
+
3
+ 本文说明 KCode 的安装、初始化、启动、模型配置和升级。Harness 阶段细节见 [Harness 工作流](HARNESS_WORKFLOW.md),所有命令和工具参数见 [命令参考](COMMAND_REFERENCE.md)。
4
+
5
+ ## 安装
6
+
7
+ 环境要求:
8
+
9
+ - Node.js `>=22.19.0`
10
+ - npm
11
+ - Windows 推荐使用 Windows Terminal
12
+ - 不需要安装 Python。KCode 随包工具使用 Node/TypeScript 实现;只有业务项目或外部脚本明确依赖 Python 时才需要另行安装。
13
+
14
+ 全局安装:
15
+
16
+ ```powershell
17
+ npm install -g kcode-pi
18
+ ```
19
+
20
+ 安装后使用全局命令:
21
+
22
+ ```powershell
23
+ kcode
24
+ ```
25
+
26
+ ## 初始化业务项目
27
+
28
+ 先在终端进入你的实际业务项目根目录,不是 KCode 源码目录。
29
+
30
+ 初始化项目级配置:
31
+
32
+ ```powershell
33
+ kcode init
34
+ ```
35
+
36
+ `init` 会登记 KCode package,并生成项目常驻上下文:
37
+
38
+ ```text
39
+ .pi/settings.json
40
+ .pi/kd/PROJECT_CONTEXT.md
41
+ ```
42
+
43
+ 项目结构变化后刷新上下文:
44
+
45
+ ```powershell
46
+ kcode context --refresh
47
+ ```
48
+
49
+ 检查环境:
50
+
51
+ ```powershell
52
+ kcode doctor
53
+ kcode doctor --deep
54
+ ```
55
+
56
+ 修复项目级配置:
57
+
58
+ ```powershell
59
+ kcode repair
60
+ ```
61
+
62
+ 查看版本:
63
+
64
+ ```powershell
65
+ kcode version
66
+ ```
67
+
68
+ 完整终端命令说明见 [命令参考](COMMAND_REFERENCE.md#终端命令)。
69
+
70
+ ## 启动 KCode
71
+
72
+ ```powershell
73
+ kcode start
74
+ ```
75
+
76
+ `kcode start` 会先确保 `.pi/settings.json` 已登记当前安装的 KCode package,然后启动随包 Pi CLI。
77
+
78
+ `start` 后面的参数会原样透传给 Pi CLI:
79
+
80
+ ```powershell
81
+ kcode start --provider openai --model gpt-4o
82
+ ```
83
+
84
+ ## 配置模型
85
+
86
+ 首次启动 Pi 时,如果看到:
87
+
88
+ ```text
89
+ Warning: No models available.
90
+ ```
91
+
92
+ 说明还没有配置模型供应商。进入 `kcode start` 后输入:
93
+
94
+ ```text
95
+ /login
96
+ ```
97
+
98
+ 选择供应商并登录或填写 API Key。常见选择包括:
99
+
100
+ ```text
101
+ ChatGPT Plus/Pro (Codex)
102
+ Claude Pro/Max
103
+ GitHub Copilot
104
+ OpenAI
105
+ Anthropic
106
+ DeepSeek
107
+ Gemini
108
+ ```
109
+
110
+ 也可以在 PowerShell 中设置环境变量后再启动:
111
+
112
+ ```powershell
113
+ $env:OPENAI_API_KEY="sk-..."
114
+ kcode start
115
+ ```
116
+
117
+ 登录或配置完成后,在 Pi 中选择模型:
118
+
119
+ ```text
120
+ /model
121
+ ```
122
+
123
+ KCode 在 Pi 内注册的 `/kd-*` 命令见 [命令参考](COMMAND_REFERENCE.md#pi-内命令)。
124
+
125
+ ## 自定义模型供应商
126
+
127
+ 如果你的模型服务是企业网关、代理服务、Ollama、LM Studio、vLLM,或其他 OpenAI-compatible endpoint,不需要改 KCode。Pi 原生支持通过用户级配置文件添加自定义供应商:
128
+
129
+ ```powershell
130
+ notepad $env:USERPROFILE\.pi\agent\models.json
131
+ ```
132
+
133
+ 写入或合并:
134
+
135
+ ```json
136
+ {
137
+ "providers": {
138
+ "corp-ai": {
139
+ "baseUrl": "https://ai.example.com/v1",
140
+ "api": "openai-completions",
141
+ "apiKey": "$CORP_AI_API_KEY",
142
+ "compat": {
143
+ "supportsDeveloperRole": false,
144
+ "supportsReasoningEffort": false
145
+ },
146
+ "models": [
147
+ {
148
+ "id": "corp-coder",
149
+ "name": "Corp Coder",
150
+ "reasoning": false,
151
+ "input": ["text"],
152
+ "contextWindow": 128000,
153
+ "maxTokens": 16384,
154
+ "cost": {
155
+ "input": 0,
156
+ "output": 0,
157
+ "cacheRead": 0,
158
+ "cacheWrite": 0
159
+ }
160
+ }
161
+ ]
162
+ }
163
+ }
164
+ }
165
+ ```
166
+
167
+ 再设置 API Key 并启动:
168
+
169
+ ```powershell
170
+ $env:CORP_AI_API_KEY="sk-..."
171
+ kcode start
172
+ ```
173
+
174
+ 也可以直接指定:
175
+
176
+ ```powershell
177
+ kcode start --provider corp-ai --model corp-coder
178
+ ```
179
+
180
+ ## 升级
181
+
182
+ 查看当前安装版本:
183
+
184
+ ```powershell
185
+ kcode version
186
+ npm ls -g kcode-pi --depth=0
187
+ ```
188
+
189
+ 查看 npm 最新版本:
190
+
191
+ ```powershell
192
+ npm view kcode-pi version
193
+ ```
194
+
195
+ 升级:
196
+
197
+ ```powershell
198
+ npm install -g kcode-pi@latest
199
+ kcode version
200
+ ```
201
+
202
+ 升级后建议在业务项目根目录执行:
203
+
204
+ ```powershell
205
+ kcode init
206
+ kcode doctor --deep
207
+ ```
208
+
209
+ 如果升级失败或仍加载旧版本,见 [故障排查](TROUBLESHOOTING.md)。
@@ -25,9 +25,6 @@ import { tddProductionWriteBlockReason } from "../src/harness/tdd-policy.ts";
25
25
  import { readProjectContext } from "../src/context/project-context.ts";
26
26
  import { windowsPathHint } from "../src/platform/path.ts";
27
27
 
28
- const KINGDEE_INTENT_PATTERN =
29
- /金蝶|苍穹|星瀚|星空|旗舰|企业版|单据|表单|列表|插件|操作插件|校验器|反写|转换|工作流|基础资料|动态对象|DynamicObject|BOS|Cosmic|IronPython|Python\s*插件|py\s*插件|kd_|KSQL/i;
30
-
31
28
  function requireRun(cwd: string): ReturnType<typeof readActiveRun> {
32
29
  return readActiveRun(cwd);
33
30
  }
@@ -48,7 +45,7 @@ function parseArtifactArgs(args: string, currentPhase: KdPhase): { phase: KdPhas
48
45
  }
49
46
 
50
47
  function parseStartArgs(args: string): { goal: string; product?: string; version?: string } {
51
- const tokens = args.trim().split(/\s+/).filter(Boolean);
48
+ const tokens = tokenizeArgs(args);
52
49
  const goal: string[] = [];
53
50
  let product: string | undefined;
54
51
  let version: string | undefined;
@@ -66,7 +63,19 @@ function parseStartArgs(args: string): { goal: string; product?: string; version
66
63
  goal.push(token);
67
64
  }
68
65
 
69
- return { goal: goal.join(" "), product, version };
66
+ const goalText = goal.join(" ");
67
+ return { goal: goalText, product, version };
68
+ }
69
+
70
+ function tokenizeArgs(args: string): string[] {
71
+ const tokens: string[] = [];
72
+ const pattern = /"([^"]*)"|'([^']*)'|(\S+)/g;
73
+ let match: RegExpExecArray | null;
74
+ while ((match = pattern.exec(args)) !== null) {
75
+ const token = match[1] ?? match[2] ?? match[3];
76
+ if (token) tokens.push(token);
77
+ }
78
+ return tokens;
70
79
  }
71
80
 
72
81
  function parseProductArgs(args: string): { product: string; version?: string } | undefined {
@@ -87,7 +96,7 @@ function parseRiskArgs(args: string): { risk: KdRisk; reason: string } | undefin
87
96
 
88
97
  function shouldStartHarnessFromInput(text: string): boolean {
89
98
  if (!text.trim() || text.trim().startsWith("/")) return false;
90
- return KINGDEE_INTENT_PATTERN.test(text);
99
+ return true;
91
100
  }
92
101
 
93
102
  function sendWorkflowPrompt(pi: ExtensionAPI, ctx: ExtensionContext, run: NonNullable<ReturnType<typeof readActiveRun>>, userText: string): void {
@@ -103,20 +112,7 @@ function sendWorkflowPrompt(pi: ExtensionAPI, ctx: ExtensionContext, run: NonNul
103
112
  function workflowPromptForRun(cwd: string, run: NonNullable<ReturnType<typeof readActiveRun>>, userText: string): string {
104
113
  const status = formatStatus(cwd, run);
105
114
  const memory = workflowMemoryForRun(cwd, run);
106
- const phaseGuidance: Record<KdPhase, string> = {
107
- discuss:
108
- "当前处于 discuss。先使用 kd-discuss 梳理需求、产品版本、插件类型、目标单据/表单、生命周期、边界和开放问题;不要生成 demo,不要编辑产品代码。",
109
- spec:
110
- "当前处于 spec。先使用 kd-spec 明确验收标准、生命周期、字段/元数据/API 假设和风险;不要编辑产品代码。",
111
- plan:
112
- "当前处于 plan。先使用 kd-plan 检查当前项目结构,写明实际目标路径、要检查和要修改的文件、Kingdee 查证项、验证命令和回滚说明;不要编辑产品代码。",
113
- execute:
114
- "当前处于 execute。只能实现 PLAN.md 中批准的内容。先读取 PLAN.md 和实际项目文件,遵循既有结构写真实可用代码;不要写 demo/sample/scaffold。",
115
- verify:
116
- "当前处于 verify。先使用 kd-verify 收集验证证据,不要继续扩大代码改动。",
117
- ship:
118
- "当前处于 ship。整理发布摘要、验证证据、风险和后续事项,不要继续扩大代码改动。",
119
- };
115
+ const phaseGuidance = phaseGuidanceForRun(run);
120
116
 
121
117
  return [
122
118
  "用户输入:",
@@ -131,10 +127,12 @@ function workflowPromptForRun(cwd: string, run: NonNullable<ReturnType<typeof re
131
127
  "KCode 本次工作流本地文档:",
132
128
  memory,
133
129
  "",
134
- `当前 active run 只属于这个功能点:${run.goal ?? run.id}。如果用户提出的是另一个功能点或无关新需求,必须停止沿用当前阶段,要求用户运行 /kd-start <新需求> 创建新 run,或 /kd-switch <run-id> 切换已有 run。`,
130
+ "需求来源处理:如果用户输入的是本地文件路径,先读取该文件并抽取需求;如果是目录,先列出候选需求文档再读取最相关文件;如果是在线文档链接,先尝试访问或导出可读内容。遇到登录、权限或防下载限制时,只问一个最阻塞问题:请用户提供可访问链接、导出文件路径或关键内容。不要要求用户改写成 KCode 专用格式。",
131
+ "",
132
+ `当前 active run 对应本次需求目标:${run.goal ?? run.id}。如果用户补充的是同一目标下的需求文档或细节,先纳入当前阶段文档;如果是无关目标,再要求用户运行 /kd-start <新需求> 创建新 run,或 /kd-switch <run-id> 切换已有 run。`,
135
133
  "需要用户确认时,kd_question 一次只能问一个当前最阻塞的问题;不要把 FormId、触发时机、库存条件、弹窗内容、插件位置等打包成清单。选项最多 3 个;交互模式下会弹出选择/输入对话并自动记录答案。",
136
134
  "",
137
- phaseGuidance[run.phase],
135
+ phaseGuidance,
138
136
  "必须先理解当前业务项目已有目录、模块、包名、基类和本地封装,再决定文件位置和实现方式。",
139
137
  "禁止凭记忆、模型知识或随包知识库直接编写 SDK 方法调用。Java/C# 代码中出现的 SDK 类、方法、构造器、枚举和属性,必须来自 kd_sdk_signature 对当前项目 jar/dll 的成功结果、项目构建输出或官方元数据证据。",
140
138
  "kd_search、kd_cosmic_api 和随包知识只能用于找线索;没有 evidence/sdk-signature.md 或明确构建证据时,不得进入 execute,也不得写生产源码。",
@@ -147,6 +145,24 @@ function workflowPromptForRun(cwd: string, run: NonNullable<ReturnType<typeof re
147
145
  ].join("\n");
148
146
  }
149
147
 
148
+ function phaseGuidanceForRun(run: NonNullable<ReturnType<typeof readActiveRun>>): string {
149
+ const guidance: Record<KdPhase, string> = {
150
+ discuss:
151
+ "当前处于 discuss。先理解需求来源,判断是一条需求还是一组需求;梳理可确认事实、边界、开放问题和后续需要验证的产品信息;不要编辑产品代码。",
152
+ spec:
153
+ "当前处于 spec。先把需求写成可验收条目;如果是一组需求,明确每条需求的验收标准、依赖、风险和批次关系;不要编辑产品代码。",
154
+ plan:
155
+ "当前处于 plan。先检查当前项目结构,写明真实目标路径、允许修改文件、查证项、验证命令和回滚说明;如果是一组需求,按批次组织计划;必须明确声明是否涉及产品实现、构建、元数据或 SDK 查证;不要编辑产品代码。",
156
+ execute:
157
+ "当前处于 execute。只能实现 PLAN.md 中批准的内容和文件。先读取 PLAN.md 和实际项目文件,遵循既有结构写真实可用代码;不要写 demo/sample/scaffold。",
158
+ verify:
159
+ "当前处于 verify。先使用 kd-verify 收集验证证据,不要继续扩大代码改动。",
160
+ ship:
161
+ "当前处于 ship。整理发布摘要、验证证据、风险和后续事项,不要继续扩大代码改动。",
162
+ };
163
+ return guidance[run.phase];
164
+ }
165
+
150
166
  function workflowMemoryForRun(cwd: string, run: NonNullable<ReturnType<typeof readActiveRun>>): string {
151
167
  const phases = PHASE_ORDER.slice(0, PHASE_ORDER.indexOf(run.phase) + 1);
152
168
  return phases
@@ -318,7 +334,7 @@ export default function (pi: ExtensionAPI) {
318
334
  [
319
335
  `发现未完成 KCode run:${run.goal ?? run.id}`,
320
336
  `阶段:${run.phase},产品:${run.profile?.product ?? run.product ?? "unknown"}`,
321
- "输入 /kd-resume 可接续;输入 /kd-runs 查看其他功能点。",
337
+ "输入 /kd-resume 可接续;输入 /kd-runs 查看其他需求或需求组。",
322
338
  ].join("\n"),
323
339
  "info",
324
340
  );
@@ -333,7 +349,7 @@ export default function (pi: ExtensionAPI) {
333
349
  if (ctx.hasUI) {
334
350
  ctx.ui.notify(`已启动 Kingdee Harness run:${run.id}(${run.profile?.product}/${run.profile?.techStack})`, "info");
335
351
  if (run.profile?.product === "unknown") {
336
- ctx.ui.notify("产品画像未识别。下一步先执行 /kd-product <flagship|cosmic|xinghan|cangqiong|enterprise>。", "warning");
352
+ ctx.ui.notify("产品画像未识别。下一步先执行 /kd-product <flagship|xinghan|cangqiong|enterprise>。", "warning");
337
353
  }
338
354
  }
339
355
  }
@@ -394,19 +410,19 @@ export default function (pi: ExtensionAPI) {
394
410
  });
395
411
 
396
412
  pi.registerCommand("kd-start", {
397
- description: "启动一个 Kingdee Harness run:/kd-start [--product 产品] [--version 版本] <需求>",
413
+ description: "启动一个 Kingdee Harness run:/kd-start [--product 产品] [--version 版本] <需求或需求组>",
398
414
  handler: async (args, ctx) => {
399
415
  const parsed = parseStartArgs(args);
400
416
  const goal = parsed.goal;
401
417
  if (!goal) {
402
- ctx.ui.notify("用法:/kd-start [--product 产品] [--version 版本] <需求>", "error");
418
+ ctx.ui.notify("用法:/kd-start [--product 产品] [--version 版本] <需求或需求组>", "error");
403
419
  return;
404
420
  }
405
421
 
406
422
  const run = createActiveRun(ctx.cwd, goal, parsed.product, parsed.version);
407
423
  ctx.ui.notify(`已启动 Kingdee Harness run:${run.id}(${run.profile?.product}/${run.profile?.techStack})`, "info");
408
424
  if (run.profile?.product === "unknown") {
409
- ctx.ui.notify("产品画像未识别。下一步先执行 /kd-product <flagship|cosmic|xinghan|cangqiong|enterprise>。", "warning");
425
+ ctx.ui.notify("产品画像未识别。下一步先执行 /kd-product <flagship|xinghan|cangqiong|enterprise>。", "warning");
410
426
  }
411
427
  sendWorkflowPrompt(pi, ctx, run, `继续 KCode Harness run ${run.id}:${goal}`);
412
428
  },
@@ -461,12 +477,12 @@ export default function (pi: ExtensionAPI) {
461
477
  }
462
478
 
463
479
  const finished = finishActiveRun(ctx.cwd, run);
464
- ctx.ui.notify(`已完成 Kingdee Harness run:${finished.id}。下一个功能点请使用 /kd-start <需求>。`, "info");
480
+ ctx.ui.notify(`已完成 Kingdee Harness run:${finished.id}。下一个需求或需求组请使用 /kd-start <需求>。`, "info");
465
481
  },
466
482
  });
467
483
 
468
484
  pi.registerCommand("kd-product", {
469
- description: "设置当前金蝶产品画像:/kd-product <flagship|cosmic|xinghan|cangqiong|enterprise> [--version 版本]",
485
+ description: "设置当前金蝶产品画像:/kd-product <flagship|xinghan|cangqiong|enterprise> [--version 版本]",
470
486
  handler: async (args, ctx) => {
471
487
  const run = requireRun(ctx.cwd);
472
488
  if (!run) {
@@ -476,7 +492,7 @@ export default function (pi: ExtensionAPI) {
476
492
 
477
493
  const parsed = parseProductArgs(args);
478
494
  if (!parsed) {
479
- ctx.ui.notify("用法:/kd-product <flagship|cosmic|xinghan|cangqiong|enterprise> [--version 版本]", "error");
495
+ ctx.ui.notify("用法:/kd-product <flagship|xinghan|cangqiong|enterprise> [--version 版本]", "error");
480
496
  return;
481
497
  }
482
498
 
@@ -545,7 +561,7 @@ export default function (pi: ExtensionAPI) {
545
561
  }
546
562
 
547
563
  if (parsed.content && readArtifact(ctx.cwd, run, parsed.phase) !== undefined && !parsed.replace) {
548
- ctx.ui.notify(`拒绝覆盖 ${parsed.phase} 阶段文档。若确认要整体替换,请追加 --replace;追加内容应让 Agent 更新具体章节。`, "warning");
564
+ ctx.ui.notify(`拒绝覆盖 ${parsed.phase} 阶段文档。若确认要整体替换,请追加 --replace;追加内容应让 KCode 更新具体章节。`, "warning");
549
565
  return;
550
566
  }
551
567
 
@@ -1,26 +1,35 @@
1
1
  import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
2
+ import { inspectGate } from "../src/harness/gates.ts";
2
3
  import { readActiveRun } from "../src/harness/state.ts";
3
- import type { ActiveRun } from "../src/harness/types.ts";
4
+ import type { ActiveRun, GateResult } from "../src/harness/types.ts";
4
5
  import { formatProductProfile } from "../src/product/profile.ts";
5
6
 
6
7
  function formatProduct(run: ActiveRun | undefined): string {
7
- return run ? formatProductProfile(run.profile) : "未选择";
8
+ if (!run) return "未选择";
9
+ if (run.profile?.product === "unknown") return "未确认";
10
+ return formatProductProfile(run.profile);
8
11
  }
9
12
 
10
13
  function formatPhase(phase: ActiveRun["phase"] | undefined): string {
11
14
  return phase ?? "空闲";
12
15
  }
13
16
 
14
- function formatGate(run: ActiveRun | undefined): string {
15
- if (!run?.gate) return "门禁:待检查";
16
- if (run.gate.passed) return "门禁:通过";
17
- return `门禁:阻塞${run.gate.reason ? ` - ${run.gate.reason}` : ""}`;
17
+ function formatGate(gate: GateResult | undefined): string {
18
+ if (!gate) return "门禁:待检查";
19
+ return gate.passed ? "门禁:通过" : "门禁:阻塞";
18
20
  }
19
21
 
20
22
  function riskLevel(run: ActiveRun | undefined): string {
21
23
  return run?.riskAssessment?.level ?? "未知";
22
24
  }
23
25
 
26
+ function riskColor(risk: string): "error" | "warning" | "muted" | "success" {
27
+ if (risk === "high") return "error";
28
+ if (risk === "medium") return "warning";
29
+ if (risk === "未知") return "muted";
30
+ return "success";
31
+ }
32
+
24
33
  function padOrTrim(text: string, width: number): string {
25
34
  if (width <= 0) return "";
26
35
  if (text.length > width) return text.slice(0, Math.max(0, width - 1)) + ">";
@@ -45,9 +54,10 @@ export default function (pi: ExtensionAPI) {
45
54
  return {
46
55
  render(width: number): string[] {
47
56
  const run = readActiveRun(ctx.cwd);
57
+ const gateState = run ? inspectGate(ctx.cwd, run) : undefined;
48
58
  const phase = formatPhase(run?.phase);
49
59
  const product = formatProduct(run);
50
- const gate = formatGate(run);
60
+ const gate = formatGate(gateState);
51
61
  const risk = riskLevel(run);
52
62
  const runId = run?.id ?? "无";
53
63
 
@@ -57,9 +67,9 @@ export default function (pi: ExtensionAPI) {
57
67
  theme.fg("muted", " | 产品:"),
58
68
  theme.fg("text", product),
59
69
  theme.fg("muted", " | 风险:"),
60
- theme.fg(risk === "high" ? "error" : risk === "medium" ? "warning" : "success", risk),
70
+ theme.fg(riskColor(risk), risk),
61
71
  theme.fg("muted", " | "),
62
- theme.fg(run?.gate?.passed === false ? "error" : "muted", gate),
72
+ theme.fg(gateState?.passed === false ? "error" : "muted", gate),
63
73
  ].join("");
64
74
 
65
75
  return [
@@ -77,7 +77,7 @@ function sdkLanguageForProfile(profile: ProductProfile, value: string | undefine
77
77
 
78
78
  function rejectNonCosmic(profile: ProductProfile): string | undefined {
79
79
  if (isCosmicFamily(profile)) return undefined;
80
- if (profile.product === "unknown") return "请先提供 Cosmic 家族产品:cangqiong、xinghan、flagshipcosmic。";
80
+ if (profile.product === "unknown") return "请先提供支持 Cosmic 平台能力的产品:cangqiong、xinghan 或 flagship。";
81
81
  return `当前产品 ${profile.product} 使用 ${profile.platform}/${profile.techStack},不适用 Cosmic 官方能力。`;
82
82
  }
83
83
 
@@ -109,7 +109,7 @@ const kdSearchTool = defineTool({
109
109
  description: "搜索 KCode 随包金蝶知识库,包括 SDK、插件生命周期、代码模式和常见实现建议。",
110
110
  parameters: Type.Object({
111
111
  query: Type.String({ description: "要搜索的关键词、API、类名、表名或生命周期术语。" }),
112
- product: Type.Optional(Type.String({ description: "金蝶产品:flagship、cosmic、xinghan、cangqiong 或 enterprise。" })),
112
+ product: Type.Optional(Type.String({ description: "金蝶产品:flagship、xinghan、cangqiong 或 enterprise。" })),
113
113
  edition: Type.Optional(Type.String({ description: "旧参数,等同于 product。优先使用 product。" })),
114
114
  limit: Type.Optional(Type.Number({ description: "最大结果数,默认 5。" })),
115
115
  }),
@@ -120,7 +120,7 @@ const kdSearchTool = defineTool({
120
120
  if (!scopes) {
121
121
  const guidance =
122
122
  profile.product === "unknown"
123
- ? "请先提供 product,例如 flagship、enterprise、cosmic、xinghan 或 cangqiong。"
123
+ ? "请先提供 product,例如 flagship、enterprise、xinghan 或 cangqiong。"
124
124
  : "当前产品画像未配置可搜索知识范围。";
125
125
  return {
126
126
  content: [
@@ -152,7 +152,7 @@ const kdTableTool = defineTool({
152
152
  description: "按表名查询 KCode 随包金蝶表结构,查询结果受产品画像约束。",
153
153
  parameters: Type.Object({
154
154
  table: Type.String({ description: "表名,例如 T_PUR_POORDER。" }),
155
- product: Type.Optional(Type.String({ description: "金蝶产品:flagship、cosmic、xinghan、cangqiong 或 enterprise。" })),
155
+ product: Type.Optional(Type.String({ description: "金蝶产品:flagship、xinghan、cangqiong 或 enterprise。" })),
156
156
  edition: Type.Optional(Type.String({ description: "旧参数,等同于 product。优先使用 product。" })),
157
157
  }),
158
158
 
@@ -236,7 +236,7 @@ const kdCosmicConfigTool = defineTool({
236
236
  label: "KD Cosmic 配置",
237
237
  description: "运行 Cosmic 家族金蝶产品的官方能力配置预检查。",
238
238
  parameters: Type.Object({
239
- product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagshipcosmic。" }),
239
+ product: Type.String({ description: "支持 Cosmic 平台能力的产品:cangqiong、xinghan 或 flagship。" }),
240
240
  config: Type.Optional(Type.String({ description: "可选 ok-cosmic.json 路径。默认按当前工作目录解析。" })),
241
241
  dryRun: Type.Optional(Type.Boolean({ description: "只返回命令,不实际执行。" })),
242
242
  }),
@@ -254,7 +254,7 @@ const kdCosmicMetadataTool = defineTool({
254
254
  label: "KD Cosmic 元数据",
255
255
  description: "查询官方 Cosmic 表单/单据元数据,包括字段、枚举值、操作和 SQL 表信息。",
256
256
  parameters: Type.Object({
257
- product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagshipcosmic。" }),
257
+ product: Type.String({ description: "支持 Cosmic 平台能力的产品:cangqiong、xinghan 或 flagship。" }),
258
258
  form: Type.String({ description: "Form ID、单据 ID 或中文单据名;多个目标可用逗号分隔。" }),
259
259
  config: Type.Optional(Type.String({ description: "可选 ok-cosmic.json 路径。" })),
260
260
  fuzzy: Type.Optional(Type.String({ description: "可选字段关键词,用空格或逗号分隔。" })),
@@ -278,7 +278,7 @@ const kdCosmicApiTool = defineTool({
278
278
  label: "KD Cosmic API",
279
279
  description: "查询随包 Cosmic API 知识,获取类和方法线索;最终签名事实应以 kd_sdk_signature 或项目构建输出为准。",
280
280
  parameters: Type.Object({
281
- product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagshipcosmic。" }),
281
+ product: Type.String({ description: "支持 Cosmic 平台能力的产品:cangqiong、xinghan 或 flagship。" }),
282
282
  mode: Type.String({ description: "查询模式:search、search-method 或 detail。" }),
283
283
  query: Type.String({ description: "类名、方法名或完整限定类名。" }),
284
284
  config: Type.Optional(Type.String({ description: "可选 ok-cosmic.json 路径。" })),
@@ -346,7 +346,7 @@ const kdKsqlLintTool = defineTool({
346
346
  label: "KD KSQL 检查",
347
347
  description: "对生成的 KSQL/SQL 文件运行官方 ok-ksql lint 检查。",
348
348
  parameters: Type.Object({
349
- product: Type.String({ description: "Cosmic 家族产品:cangqiong、xinghan、flagshipcosmic。" }),
349
+ product: Type.String({ description: "支持 Cosmic 平台能力的产品:cangqiong、xinghan 或 flagship。" }),
350
350
  path: Type.String({ description: "SQL/KSQL 文件路径,可为工作区相对路径或绝对路径。" }),
351
351
  dryRun: Type.Optional(Type.Boolean({ description: "只返回命令,不实际执行。" })),
352
352
  }),
@@ -364,7 +364,7 @@ const kdBuildTool = defineTool({
364
364
  label: "KD 构建",
365
365
  description: "按产品画像运行或预览金蝶构建命令,支持 Cosmic Java 和企业版 C# 项目。",
366
366
  parameters: Type.Object({
367
- product: Type.String({ description: "金蝶产品:cangqiong、xinghan、flagship、cosmic 或 enterprise。" }),
367
+ product: Type.String({ description: "金蝶产品:cangqiong、xinghan、flagship 或 enterprise。" }),
368
368
  target: Type.Optional(Type.String({ description: "Java 可提供 Gradle task;C# 可提供 .sln/.csproj 路径。" })),
369
369
  dryRun: Type.Optional(Type.Boolean({ description: "只返回构建命令,不实际执行。" })),
370
370
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kcode-pi",
3
- "version": "0.1.19",
3
+ "version": "0.1.23",
4
4
  "description": "面向金蝶开发的 Pi Coding Agent 启动器、工具包和 Harness 工作流",
5
5
  "type": "module",
6
6
  "private": false,
@@ -63,7 +63,7 @@
63
63
  "smoke:build-debug": "tsx scripts/smoke-build-debug.ts",
64
64
  "smoke:sdk-signature": "tsx scripts/smoke-sdk-signature.ts",
65
65
  "smoke:package": "tsx scripts/smoke-package.ts",
66
- "smoke:kcode-cli": "tsx scripts/smoke-kcode-cli.ts",
66
+ "smoke:kcode-command": "tsx scripts/smoke-kcode-command.ts",
67
67
  "release:check": "tsx scripts/release-check.ts",
68
68
  "kcode": "tsx scripts/kcode.ts",
69
69
  "prepack": "npm run build:cli && npm run smoke:package"
@@ -8,4 +8,9 @@ description: 开始或继续金蝶 Harness 工作流的需求讨论阶段。
8
8
 
9
9
  {{args}}
10
10
 
11
- 请把业务目标、金蝶产品/版本、技术栈、插件类型、目标单据/表单/实体、非目标范围和待确认问题记录到 `CONTEXT.md`。
11
+ 请先读取并理解需求来源,再自行判断这是单需求还是需求组。
12
+
13
+ - 单需求:记录业务目标、可判断的产品/版本、技术栈、目标对象、非目标范围和待确认问题。
14
+ - 需求组:从原始文档抽取需求条目、验收标准、优先级、依赖、批次、共同约束和待确认问题。
15
+
16
+ 不要因为正文里出现产品词就直接落产品画像;只有用户显式指定、文档证据充分,或进入具体产品实现前确认后,才写成已确认产品。
@@ -4,11 +4,11 @@ description: 为当前金蝶 Harness run 编写实施计划。
4
4
 
5
5
  使用 `kd-plan` skill。
6
6
 
7
- 读取 `CONTEXT.md` 和 `SPEC.md`,编写或更新 `PLAN.md`。必须包含已检查的项目结构、需要查看的文件、预计修改的真实路径、必须查证的金蝶 API/元数据、SDK 签名证据、验证命令和回滚说明。Java/C# SDK 方法签名必须来自 `kd_sdk_signature` 当前项目 jar/dll、项目构建输出或官方元数据,不能凭记忆猜。
7
+ 读取 `CONTEXT.md` 和 `SPEC.md`,编写或更新 `PLAN.md`。必须包含已检查的项目结构、需要查看的文件、预计修改的真实路径、是否涉及产品实现/构建/元数据/SDK 查证、必须查证的金蝶 API/元数据、SDK 签名证据、验证命令和回滚说明。Java/C# SDK 方法签名必须来自 `kd_sdk_signature` 当前项目 jar/dll、项目构建输出或官方元数据,不能凭记忆猜。
8
8
 
9
9
  验证命令必须贴近真实项目:
10
10
 
11
- - Java / Cosmic / 苍穹 / 星空旗舰版:优先使用当前项目 Gradle 构建做语法和编译检查,例如 `./gradlew build`、`./gradlew :模块:build` 或 Windows 下的 `.\gradlew.bat build`。
11
+ - 苍穹 / 星瀚 / 星空旗舰版 Java:优先使用当前项目 Gradle 构建做语法和编译检查,例如 `./gradlew build`、`./gradlew :模块:build` 或 Windows 下的 `.\gradlew.bat build`。
12
12
  - C# / 企业版:使用 `dotnet build` 或 `dotnet build <.sln/.csproj>` 做语法和编译检查。
13
13
  - 不要写“Kingdee IDE 中编译”。如果当前机器缺少依赖导致命令无法运行,要记录真实阻塞原因,不能把未执行的编译当作绿灯证据。
14
14
 
@@ -8,7 +8,7 @@ description: 验证当前金蝶实现并收集证据。
8
8
 
9
9
  验证优先使用真实构建命令检查语法和编译:
10
10
 
11
- - Java / Cosmic / 苍穹 / 星空旗舰版:运行当前项目 Gradle 命令,例如 `.\gradlew.bat build`、`.\gradlew.bat :模块:build` 或同等 Gradle task。
11
+ - 苍穹 / 星瀚 / 星空旗舰版 Java:运行当前项目 Gradle 命令,例如 `.\gradlew.bat build`、`.\gradlew.bat :模块:build` 或同等 Gradle task。
12
12
  - C# / 企业版:运行 `dotnet build`、`dotnet build <.sln>` 或 `dotnet build <.csproj>`。
13
13
  - 绿灯证据必须包含实际命令、`Exit: 0` 和输出摘要。不能用“Kingdee IDE 中编译”“需在开发环境验证”替代真实证据。
14
14
 
@@ -1,13 +1,12 @@
1
1
  ---
2
2
  name: kd-cosmic-dev
3
- description: 金蝶 Cosmic 体系 Java 插件开发技能,适用于苍穹、星瀚、星空旗舰版和共享 Cosmic 平台。处理表单、单据、列表、操作、转换、任务、工作流、OpenAPI、元数据、DynamicObject、附件、基础资料、SDK 方法签名等 Cosmic 体系开发时使用。
3
+ description: 金蝶苍穹/Cosmic 平台 Java 插件开发技能,适用于苍穹、星瀚和星空旗舰版。处理表单、单据、列表、操作、转换、任务、工作流、OpenAPI、元数据、DynamicObject、附件、基础资料、SDK 方法签名等平台能力开发时使用。
4
4
  ---
5
5
 
6
6
  # 金蝶 Cosmic 开发
7
7
 
8
- 当需要为 Cosmic 体系产品实现或修改 Java 代码时使用本技能:
8
+ 当需要为以下产品实现或修改 Java 代码时使用本技能:
9
9
 
10
- - `cosmic`
11
10
  - `cangqiong`
12
11
  - `xinghan`
13
12
  - `flagship`
@@ -19,7 +18,7 @@ description: 金蝶 Cosmic 体系 Java 插件开发技能,适用于苍穹、
19
18
  生成或修改代码前:
20
19
 
21
20
  - 先用 `kd_plan_status` 查看当前运行状态。
22
- - 确认产品画像属于 Cosmic 体系。
21
+ - 确认产品画像是 `cangqiong`、`xinghan` 或 `flagship`。
23
22
  - 执行阶段必须已有 `PLAN.md`。
24
23
  - Cosmic 代码生成前必须运行 `kd_cosmic_config`。如果配置检查失败,停止编码并说明缺失配置。
25
24
 
@@ -53,7 +52,7 @@ description: 金蝶 Cosmic 体系 Java 插件开发技能,适用于苍穹、
53
52
  4. 只有插件类型、生命周期方法、字段元数据和 API 签名都明确后,才生成或修改代码。
54
53
  - 遵循项目已有包名、基类、常量、日志风格和 helper 封装。
55
54
  - 星空旗舰版项目先检查当前目录结构,再选择真实目标路径。若存在 `code/`,跟随 `code/` 下既有组织;若不存在,跟随已发现的源码根或目标文件,不要在项目根目录新建 `src/main/java`。
56
- - 优先使用项目本地封装和已批准的 Cosmic helper,再考虑底层 BOS API。
55
+ - 优先使用项目本地封装和已批准的苍穹/Cosmic 平台 helper,再考虑底层 BOS API。
57
56
  - 事件处理器只做当前事件阶段该做的事。
58
57
 
59
58
  5. 验证结果。
@@ -64,7 +63,7 @@ description: 金蝶 Cosmic 体系 Java 插件开发技能,适用于苍穹、
64
63
  ## 硬性规则
65
64
 
66
65
  - 不臆造字段 key、表单 ID、操作名、枚举值、表名或 SDK 方法;本地 SDK 查不到且编译未验证时,不把知识库结果当作最终签名事实。
67
- - 不把 Enterprise C# 命名空间或生命周期假设用于 Cosmic Java。
66
+ - 不把 Enterprise C# 命名空间或生命周期假设用于苍穹/Cosmic 平台 Java。
68
67
  - 星空旗舰版不允许猜目录或写 demo/sample;如果无法判断真实代码位置,先询问或更新计划,不要直接创建新目录。
69
68
  - 不在数据绑定前的初始化阶段操作 UI 控件。
70
69
  - 不在平台期望修改入参数据实体的事务钩子里另起保存。
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: kd-cosmic-review
3
- description: 金蝶 Cosmic 体系 Java 插件和 KSQL 代码审查技能,按官方审查优先级检查代码质量、生命周期、事务、性能、安全、DataSet 泄漏、校验器/操作/表单/列表/转换插件和 KSQL 风险。适用于 Cosmic、苍穹、星瀚、星空旗舰版项目。
3
+ description: 金蝶苍穹/Cosmic 平台 Java 插件和 KSQL 代码审查技能,按官方审查优先级检查代码质量、生命周期、事务、性能、安全、DataSet 泄漏、校验器/操作/表单/列表/转换插件和 KSQL 风险。适用于苍穹、星瀚、星空旗舰版项目。
4
4
  ---
5
5
 
6
6
  # 金蝶 Cosmic 审查
7
7
 
8
- 本技能用于审查 Cosmic 体系 Java 或 KSQL 变更。除非用户明确要求修复,否则只做审查,不直接改代码。
8
+ 本技能用于审查苍穹/Cosmic 平台 Java 或 KSQL 变更。除非用户明确要求修复,否则只做审查,不直接改代码。
9
9
 
10
10
  不要把本技能用于 Enterprise C# 代码;Enterprise 使用通用金蝶检查流程。
11
11