kcode-pi 0.1.40 → 0.1.43
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.
- package/dist/harness/prompt-policy.d.ts +5 -0
- package/dist/harness/prompt-policy.js +44 -1
- package/docs/CHANGELOG.md +39 -0
- package/docs/COMMAND_REFERENCE.md +2 -2
- package/docs/HARNESS_WORKFLOW.md +2 -1
- package/extensions/kingdee-harness.ts +12 -1
- package/package.json +1 -1
- package/prompts/kd-discuss.md +13 -5
- package/prompts/kd-execute.md +16 -4
- package/prompts/kd-plan.md +14 -4
- package/prompts/kd-ship.md +14 -3
- package/prompts/kd-spec.md +15 -3
- package/prompts/kd-verify.md +15 -3
- package/skills/kd-cosmic-dev/SKILL.md +2 -2
- package/skills/kd-cosmic-review/SKILL.md +2 -2
- package/skills/kd-cosmic-unittest/SKILL.md +3 -3
- package/skills/kd-discuss/SKILL.md +2 -0
- package/skills/kd-execute/SKILL.md +3 -0
- package/skills/kd-plan/SKILL.md +3 -0
- package/skills/kd-ship/SKILL.md +2 -1
- package/skills/kd-spec/SKILL.md +5 -2
- package/skills/kd-verify/SKILL.md +2 -0
- package/src/harness/messages.ts +21 -15
- package/src/harness/prompt-policy.ts +49 -1
- package/src/harness/prompt.ts +26 -1
- package/src/harness/question-memory.ts +13 -9
- package/src/platform/path.ts +13 -1
|
@@ -10,6 +10,11 @@ export declare const DATA_SOURCE_CONTEXT_FIELDS: ContractField[];
|
|
|
10
10
|
export declare const INTEGRATION_CONTEXT_FIELDS: ContractField[];
|
|
11
11
|
export declare const PROJECT_PERSISTENT_RULES: string[];
|
|
12
12
|
export declare const PROMPT_STYLE_RULES: string[];
|
|
13
|
+
export declare const PROMPT_DECISION_PROTOCOL: string[];
|
|
14
|
+
export declare const PROMPT_FACT_PROTOCOL: string[];
|
|
15
|
+
export declare const PROMPT_QUESTION_PROTOCOL: string[];
|
|
16
|
+
export declare const PROMPT_OUTPUT_CONTRACT: string[];
|
|
17
|
+
export declare const PROMPT_PROHIBITED_BEHAVIORS: string[];
|
|
13
18
|
export declare const CORE_WORKFLOW_CONSTRAINTS: string[];
|
|
14
19
|
export declare const PHASE_GUIDANCE: Record<KdPhase, string>;
|
|
15
20
|
export declare const PLAN_REQUIRED_CHECK_LINES: string[];
|
|
@@ -133,6 +133,7 @@ export const INTEGRATION_CONTEXT_FIELDS = [
|
|
|
133
133
|
export const PROJECT_PERSISTENT_RULES = [
|
|
134
134
|
"计划或编辑代码前必须读取本文件;本文件过期时先运行 `kcode context --refresh`。",
|
|
135
135
|
"信息不足时禁止开始编码。必须先登记一个最阻塞的结构化问题,获得可核验答案后再继续;禁止输出 demo/sample/scaffold、模板代码或占位实现。",
|
|
136
|
+
"任何时刻最多只能存在一个 open blocking question;已有未回答阻断问题时,必须先记录用户答案,禁止继续提出、登记或展示其他问题。",
|
|
136
137
|
"API 文档、SDK 文档和知识库只能证明技术用法,不能替代业务事实。FormId、单据/表单标识、字段/实体/分录标识、插件类型与事件、SQL/KSQL 表名和数据库字段名必须来自用户确认、项目元数据或 evidence。",
|
|
137
138
|
`产品代码实现前必须具备通用实现契约:${IMPLEMENTATION_CONTRACT_FIELDS.map((field) => field.label).join("、")}。`,
|
|
138
139
|
`涉及业务数据源时必须具备数据源上下文:${DATA_SOURCE_CONTEXT_FIELDS.map((field) => field.label).join("、")}。`,
|
|
@@ -142,10 +143,12 @@ export const PROJECT_PERSISTENT_RULES = [
|
|
|
142
143
|
"`run.facts` 是唯一结构化事实源;已回答 questions 仅为审计记录,禁止在读取状态时从历史 question 反推事实。",
|
|
143
144
|
"`factLabel` 必须使用集中定义的事实标签或别名;未知标签、占位答案、口头确认语、待确认/TODO/TBD/按实际环境等不能解除门禁。",
|
|
144
145
|
"用户回答 open question 后,先用 `kd_question action=answer` 写入答案;用户更正事实时用 `kd_question action=revise`,禁止重复询问已确认事实。",
|
|
146
|
+
"门禁提示只暴露当前最阻塞缺失事实;后续待确认项只能在当前问题回答后重新刷新门禁逐项生成,禁止一次性向用户展开完整问题清单。",
|
|
145
147
|
"企业版 Python 插件通常没有本地构建可替代验证;BOS 注册、外部系统操作、人工功能测试和生产环境验证必须由用户提供可核验证据并记录来源。",
|
|
146
148
|
"提示语集中管理为正式工程指令;禁止口语化、闲聊式、鼓励式提示词进入运行时规则。",
|
|
147
149
|
"工具使用必须匹配当前会话实际可用工具和操作系统;Windows 默认使用 PowerShell、`rg`、`Get-ChildItem`、`Get-Content`,禁止假设 bash 可用。",
|
|
148
150
|
"Windows 查找文件和目录时优先使用 `kd_find_file`、`kd_list_dir` 或 PowerShell;禁止用 Linux find/ls 语法反复调用 Pi 内置 bash。",
|
|
151
|
+
"写入或编辑文件时禁止使用当前工作区外的绝对路径;生产源码必须使用当前业务项目相对路径,并受 PLAN.md 批准文件约束。",
|
|
149
152
|
"文件定位必须使用真实搜索或目录读取结果;工具不可用时明确说明阻塞原因和需要用户执行的命令,禁止猜测路径、反复自述工具失败或用 kd_subagent 代替基础文件搜索。",
|
|
150
153
|
"不做旧状态迁移兼容或旧问题答案推断;坏状态只过滤,缺失事实必须重新提问确认。",
|
|
151
154
|
];
|
|
@@ -154,6 +157,45 @@ export const PROMPT_STYLE_RULES = [
|
|
|
154
157
|
"事实不足时生成阻断问题;禁止输出模板代码、占位实现或基于猜测的业务标识。",
|
|
155
158
|
"每次只提出一个最阻塞问题;问题必须指向可验证事实、数据标识或验收证据。",
|
|
156
159
|
"引用顺序:当前项目文件、PLAN/SPEC、元数据 evidence、SDK 签名、验证输出。",
|
|
160
|
+
"响应必须说明当前阶段、门禁结论、采用的事实来源和唯一下一动作;禁止同时给出多个并行动作让用户选择。",
|
|
161
|
+
];
|
|
162
|
+
export const PROMPT_DECISION_PROTOCOL = [
|
|
163
|
+
"先读取 Harness 状态、当前阶段资料、已问已答事实和项目上下文;禁止只根据用户最后一句话行动。",
|
|
164
|
+
"先判断用户输入是否是在回答 open blocking question;如是,唯一动作是调用 `kd_question action=answer` 记录答案。",
|
|
165
|
+
"再判断当前阶段门禁是否阻塞;阻塞时只执行门禁要求的唯一下一动作,禁止绕过阶段推进。",
|
|
166
|
+
"再判断是否缺少可核验事实;缺失时只登记当前最阻塞的一个问题,禁止展开后续问题。",
|
|
167
|
+
"只有在阶段、门禁、事实和证据均满足时,才允许进入计划、编码、验证或交付动作。",
|
|
168
|
+
];
|
|
169
|
+
export const PROMPT_FACT_PROTOCOL = [
|
|
170
|
+
"`run.facts` 是结构化事实唯一来源;`questions` 仅为问答审计记录。",
|
|
171
|
+
"业务事实必须有来源分类:用户明确回答、项目元数据/evidence、当前项目文件、验证输出。",
|
|
172
|
+
"API/SDK 文档只作为技术用法线索;不得补全 FormId、字段标识、实体标识、表名、接口字段映射、并发策略或验收数据。",
|
|
173
|
+
"事实值包含待确认、未知、按实际环境、TODO/TBD、可以、好的、是/否等内容时,视为无效事实。",
|
|
174
|
+
"同一事实存在冲突时,停止推进并使用 `kd_question action=revise` 或登记一个最阻塞更正问题。",
|
|
175
|
+
];
|
|
176
|
+
export const PROMPT_QUESTION_PROTOCOL = [
|
|
177
|
+
"任何时刻最多存在一个 open blocking question。",
|
|
178
|
+
"已有 open blocking question 时,禁止继续提问、禁止输出问题清单、禁止登记新问题;唯一动作是获取并记录该问题答案。",
|
|
179
|
+
"`kd_question action=ask` 的问题文本只能包含一个事实点,不能使用编号列表、多个问号或复合事实。",
|
|
180
|
+
"带 `factLabel` 的问题必须使用集中定义标签或别名;产品类型不是 factLabel。",
|
|
181
|
+
"问题登记后停止推进,等待用户回答;不得在同一轮继续生成方案、计划或代码。",
|
|
182
|
+
];
|
|
183
|
+
export const PROMPT_OUTPUT_CONTRACT = [
|
|
184
|
+
"阻塞时输出:阻塞原因、唯一下一动作、需要使用的工具或命令;不得输出实现方案或代码片段。",
|
|
185
|
+
"提问时输出:只登记或展示一个问题;不得附带后续问题预告清单。",
|
|
186
|
+
"计划时输出:目标路径、允许修改文件、查证项、验证命令、回滚方式和 evidence 要求。",
|
|
187
|
+
"执行时输出:仅说明已修改文件、证据文件和验证结果;不得把未验证内容写成已完成。",
|
|
188
|
+
"验证失败时输出:失败证据、定位结论、下一轮修复边界;不得直接跳到 ship。",
|
|
189
|
+
];
|
|
190
|
+
export const PROMPT_PROHIBITED_BEHAVIORS = [
|
|
191
|
+
"禁止根据 API 文档、SDK 记忆或知识库推断业务数据源。",
|
|
192
|
+
"禁止生成 demo/sample/scaffold、占位实现、伪代码或仅可手工替换的模板。",
|
|
193
|
+
"禁止一次性向用户索要多项业务信息。",
|
|
194
|
+
"禁止重复询问已确认事实或已存在 open blocking question 的问题。",
|
|
195
|
+
"禁止猜测路径、包名、类名、FormId、字段、实体、SQL 表名、数据库字段名或接口字段映射。",
|
|
196
|
+
"禁止写入或编辑当前工作区外的绝对路径。",
|
|
197
|
+
"禁止用子 agent、shell 失败自述或自由文本计划绕过门禁。",
|
|
198
|
+
"禁止将外部系统操作、BOS 注册、人工功能测试或生产验证描述为 LLM 已完成。",
|
|
157
199
|
];
|
|
158
200
|
export const CORE_WORKFLOW_CONSTRAINTS = [
|
|
159
201
|
"产品代码只在 execute 阶段写入,并限于 PLAN.md 批准的文件。",
|
|
@@ -161,6 +203,7 @@ export const CORE_WORKFLOW_CONSTRAINTS = [
|
|
|
161
203
|
"业务数据源未知时禁止编码;确认目标 FormId/单据或表单、插件类型和事件、字段/实体/分录标识、数据读取写入方式后再编码;SQL/KSQL 同步确认表名和数据库字段名。",
|
|
162
204
|
"第三方对接确认接口文档、对接方向、触发时机、认证配置、字段映射、并发/幂等、重试超时限流、错误补偿、日志脱敏和验收样例后再编码。",
|
|
163
205
|
"事实缺失时使用 kd_question 登记一个最阻塞问题;禁止用 API 文档、SDK 知识库或推测替代业务事实。",
|
|
206
|
+
"已有 open blocking question 时禁止继续提问;先记录该问题答案,再根据刷新后的门禁决定下一问。",
|
|
164
207
|
"用户输入是在回答 open question 时,必须先调用 kd_question action=answer 记录答案,再继续推进或登记下一个问题。",
|
|
165
208
|
"同一 factLabel 已有当前事实时禁止重复提问;用户明确更正时使用 kd_question action=revise 记录新事实和更正原因。",
|
|
166
209
|
"run.facts 是唯一结构化事实源;questions 仅作为问答审计记录,禁止从历史 question 反推门禁事实。",
|
|
@@ -169,7 +212,7 @@ export const CORE_WORKFLOW_CONSTRAINTS = [
|
|
|
169
212
|
"Java/Cosmic 使用当前项目 Gradle;C#/企业版使用 dotnet build。",
|
|
170
213
|
"evidence 必须记录命令、Exit 和关键输出;命令无法运行时记录阻塞原因。",
|
|
171
214
|
"外部系统操作、BOS 注册、人工功能测试和生产环境验证不能由 LLM 代办;必须要求用户提供验证结果或可核验证据,并记录证据来源。",
|
|
172
|
-
"Windows
|
|
215
|
+
"Windows 路径规则:读取可使用工作区内绝对路径;写入和编辑必须使用当前工作区内路径,默认使用项目相对路径。禁止写入 C:\\Users、Desktop 或其他非当前工作区路径。",
|
|
173
216
|
"工具规则:按当前会话实际 shell 和工具执行;Windows 不假设 bash,优先用 kd_find_file/kd_list_dir/PowerShell;禁止猜路径或用 kd_subagent 代替基础搜索失败。",
|
|
174
217
|
];
|
|
175
218
|
export const PHASE_GUIDANCE = {
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,45 @@
|
|
|
6
6
|
|
|
7
7
|
- 暂无。
|
|
8
8
|
|
|
9
|
+
## 0.1.43 - 2026-06-07
|
|
10
|
+
|
|
11
|
+
### 修复
|
|
12
|
+
|
|
13
|
+
- `write`/`edit` 工具调用新增工作区外绝对路径拦截,禁止直接写入 `C:/Users`、Desktop 或其他非当前工作区路径。
|
|
14
|
+
- Windows 路径规则补充为写入必须使用当前项目相对路径或工作区内路径,避免外部绝对路径触发上游写入超时。
|
|
15
|
+
- Harness smoke 增加 `C:/Users/...` 外部路径判定回归测试。
|
|
16
|
+
|
|
17
|
+
### 验证
|
|
18
|
+
|
|
19
|
+
- `npm run check`
|
|
20
|
+
- `npm run smoke:harness`
|
|
21
|
+
|
|
22
|
+
## 0.1.42 - 2026-06-07
|
|
23
|
+
|
|
24
|
+
### 改进
|
|
25
|
+
|
|
26
|
+
- 将运行时提示词工程化为集中协议:执行顺序、事实处理、提问、输出契约和禁止行为。
|
|
27
|
+
- 六个阶段入口 prompt 改为正式工程指令,统一要求读取状态、事实、门禁并只执行唯一下一动作。
|
|
28
|
+
- 核心 Harness skills 补充单问题门禁、事实来源、禁止模板代码、人工验证边界和企业版 Python 验证要求。
|
|
29
|
+
|
|
30
|
+
### 验证
|
|
31
|
+
|
|
32
|
+
- `npm run check`
|
|
33
|
+
- `npm run smoke:harness`
|
|
34
|
+
|
|
35
|
+
## 0.1.41 - 2026-06-07
|
|
36
|
+
|
|
37
|
+
### 修复
|
|
38
|
+
|
|
39
|
+
- `kd_question` 增加全局 open blocking 门禁:已有未回答阻断问题时,禁止继续登记第二个问题。
|
|
40
|
+
- 数据源、实现契约和第三方对接门禁只输出当前最阻塞缺失事实和唯一允许的提问命令,不再把完整问题清单作为下一步展示给 LLM。
|
|
41
|
+
- 项目持久规则和命令文档明确:用户回答当前问题并记录后,才能刷新门禁生成下一问。
|
|
42
|
+
|
|
43
|
+
### 验证
|
|
44
|
+
|
|
45
|
+
- `npm run check`
|
|
46
|
+
- `npm run smoke:harness`
|
|
47
|
+
|
|
9
48
|
## 0.1.40 - 2026-06-07
|
|
10
49
|
|
|
11
50
|
### 修复
|
|
@@ -310,7 +310,7 @@ kd_question action=revise factLabel="目标 FormId/单据或表单标识" answer
|
|
|
310
310
|
kd_question action=list
|
|
311
311
|
```
|
|
312
312
|
|
|
313
|
-
一次只能登记一个当前最阻塞的问题,最多 3
|
|
313
|
+
一次只能登记一个当前最阻塞的问题,最多 3 个简短选项。已有任意 open blocking 问题时,`action=ask` 会拒绝登记新问题,必须先用 `action=answer` 记录当前问题答案。`action=ask` 只登记 open 问题,不弹出输入框、不在工具调用内继续追问。
|
|
314
314
|
使用 `action=labels` 查看合法 `factLabel`。产品类型/产品画像不是 `factLabel`,应使用 `/kd-product <产品>` 或先登记无 `factLabel` 的产品确认问题。
|
|
315
315
|
|
|
316
316
|
结构化事实参数:
|
|
@@ -322,7 +322,7 @@ proposedFactValue 可选,确认题候选事实值;用户回答 是/yes 时
|
|
|
322
322
|
|
|
323
323
|
门禁只消费当前结构化事实。没有 `factLabel` 的问答只作为上下文记录,不直接解除数据源、字段、接口等事实缺口。
|
|
324
324
|
|
|
325
|
-
`factLabel` 必须使用 KCode 集中定义的实现契约、数据源上下文或第三方对接事实标签,允许使用这些标签的别名并自动规范为正式标签。同一 `factLabel` 已有 open
|
|
325
|
+
`factLabel` 必须使用 KCode 集中定义的实现契约、数据源上下文或第三方对接事实标签,允许使用这些标签的别名并自动规范为正式标签。同一 `factLabel` 已有 open 问题时禁止重复提问;已有任意 open blocking 问题时也禁止继续提问;已有当前事实时禁止再次提问,必须使用 `action=revise` 显式修订。`待确认`、`未知`、`按实际环境`、`TODO/TBD`、单独“是/否”和“可以/好的”等口头确认不会解除开放事实问题。带 `proposedFactValue` 的确认题只接受明确肯定或明确否定。
|
|
326
326
|
|
|
327
327
|
当前只有一个 open blocking 问题时,用户下一条普通短答会自动记录为该问题答案;命令、疑问句和明显的新任务不会自动记录。
|
|
328
328
|
|
package/docs/HARNESS_WORKFLOW.md
CHANGED
|
@@ -108,11 +108,12 @@ evidence/index.json
|
|
|
108
108
|
|
|
109
109
|
- 一次只问一个当前最阻塞的问题。
|
|
110
110
|
- 问题登记后保持 open;用户回答后必须用 `/kd-answer` 或 `kd_question action=answer` 记录。
|
|
111
|
+
- 任意时刻最多只能有一个 open blocking 问题;该问题回答前,禁止登记、展示或继续追问其他问题。
|
|
111
112
|
- 需要解除门禁事实缺口的问题必须带结构化 `factLabel`;确认题必须用 `proposedFactValue` 表示候选事实值。
|
|
112
113
|
- 同一 `factLabel` 已有 open 问题或当前事实时禁止重复提问;用户更正事实时使用 `kd_question action=revise`,旧事实会标记为 superseded。
|
|
113
114
|
- 当前只有一个 open blocking 问题时,用户下一条普通短答会自动记录;占位答案不会解除门禁。
|
|
114
115
|
- 数据源 FormId、字段/实体、插件事件和读写方式必须来自结构化 facts 或 evidence;PLAN 自由文本不能单独证明这些事实。
|
|
115
|
-
-
|
|
116
|
+
- 得到答案并刷新门禁后,再决定下一个必要问题;门禁提示不得一次性展开完整问题清单。
|
|
116
117
|
|
|
117
118
|
## 多个需求
|
|
118
119
|
|
|
@@ -26,7 +26,7 @@ import { flagshipWriteBlockReason, isSourceLikePath, planWriteBlockReason } from
|
|
|
26
26
|
import { sdkSignatureProductionWriteBlockReason } from "../src/harness/sdk-policy.ts";
|
|
27
27
|
import { dataSourceProductionWriteBlockReason } from "../src/harness/data-source-policy.ts";
|
|
28
28
|
import { tddProductionWriteBlockReason } from "../src/harness/tdd-policy.ts";
|
|
29
|
-
import { windowsPathHint } from "../src/platform/path.ts";
|
|
29
|
+
import { isExternalAbsolutePath, isPathInsideWorkspace, windowsPathHint } from "../src/platform/path.ts";
|
|
30
30
|
import { repairPromptForRun, workflowPromptForRun } from "../src/harness/prompt.ts";
|
|
31
31
|
import { recordVerifyResult, type VerifyResultOutcome } from "../src/harness/repair.ts";
|
|
32
32
|
import { isSubagentChild, subagentRoleFromEnv, subagentToolCallBlockReason } from "../src/harness/delegation.ts";
|
|
@@ -157,6 +157,12 @@ function codeWriteBlockReason(cwd: string, path: string | undefined): string | u
|
|
|
157
157
|
);
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
+
function externalWriteBlockReason(cwd: string, toolName: string, path: string | undefined): string | undefined {
|
|
161
|
+
if (!path || !["write", "edit"].includes(toolName)) return undefined;
|
|
162
|
+
if (!isExternalAbsolutePath(path) || isPathInsideWorkspace(cwd, path)) return undefined;
|
|
163
|
+
return `拒绝写入工作区外绝对路径 ${path}。执行指令:先确认当前业务项目根目录;生产源码必须使用当前项目相对路径,并受 PLAN.md 批准文件、execute 阶段和证据门禁约束。禁止直接写入 C:/Users、Desktop 或其他非当前工作区路径。`;
|
|
164
|
+
}
|
|
165
|
+
|
|
160
166
|
const kdPlanStatusTool = defineTool({
|
|
161
167
|
name: "kd_plan_status",
|
|
162
168
|
label: "KD 状态",
|
|
@@ -427,6 +433,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
427
433
|
pi.on("tool_call", (event, ctx) => {
|
|
428
434
|
const input = event.input as Record<string, unknown>;
|
|
429
435
|
const path = typeof input.path === "string" ? input.path : undefined;
|
|
436
|
+
const externalWriteReason = externalWriteBlockReason(ctx.cwd, event.toolName, path);
|
|
437
|
+
if (externalWriteReason) {
|
|
438
|
+
if (ctx.hasUI) ctx.ui.notify(externalWriteReason, "warning");
|
|
439
|
+
return { block: true, reason: externalWriteReason };
|
|
440
|
+
}
|
|
430
441
|
const hint = path ? windowsPathHint(path) : undefined;
|
|
431
442
|
if (hint && ["read", "write", "edit"].includes(event.toolName)) {
|
|
432
443
|
const reason = `当前是 Windows 工作区,路径 ${path} 不是本项目使用的路径形式。执行指令:改用项目相对路径;必须使用绝对路径时,使用 Windows 路径 ${hint}。`;
|
package/package.json
CHANGED
package/prompts/kd-discuss.md
CHANGED
|
@@ -4,13 +4,21 @@ description: 开始或继续金蝶 Harness 工作流的需求讨论阶段。
|
|
|
4
4
|
|
|
5
5
|
使用 `kd-discuss` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
执行需求讨论阶段。输入:
|
|
8
8
|
|
|
9
9
|
{{args}}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
执行协议:
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
13
|
+
- 读取当前 Harness 状态、项目上下文和已问已答事实。
|
|
14
|
+
- 判定输入是单需求还是需求组;依据必须来自用户输入、需求文档或项目文件。
|
|
15
|
+
- 单需求只记录业务目标、已确认产品/版本、技术栈、目标对象、非目标范围和一个最阻塞待确认问题。
|
|
16
|
+
- 需求组只抽取需求条目、验收标准、优先级、依赖、批次和共同约束;缺失事实按最阻塞项逐个确认。
|
|
17
|
+
- 产品画像只有在用户显式指定、文档证据充分或用户确认后才能落为已确认事实。
|
|
18
|
+
- 信息不足时只登记一个 open blocking question;禁止输出问题清单、实现方案或代码。
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
输出契约:
|
|
21
|
+
|
|
22
|
+
- 已更新的 `CONTEXT.md` 路径和摘要。
|
|
23
|
+
- 当前门禁结论。
|
|
24
|
+
- 唯一下一动作。
|
package/prompts/kd-execute.md
CHANGED
|
@@ -4,10 +4,22 @@ description: 在 Harness 门禁约束下执行当前金蝶实施计划。
|
|
|
4
4
|
|
|
5
5
|
使用 `kd-execute` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
执行实施阶段。输入:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
{{args}}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
执行协议:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- 读取当前 run、门禁、`PLAN.md`、已问已答事实和 evidence 状态。
|
|
14
|
+
- 门禁未通过时停止编码,只执行门禁指定的唯一下一动作。
|
|
15
|
+
- 只修改 `PLAN.md` 批准的文件;新增文件必须先回到 plan 批准。
|
|
16
|
+
- 写生产源码前必须已有红灯证据、真实数据源/元数据证据和 SDK 签名证据。
|
|
17
|
+
- 实现后更新 `EXECUTION.md`,记录步骤结果、变更文件、偏离计划说明和 evidence。
|
|
18
|
+
- 验证命令无法运行时记录真实阻塞原因、应运行命令和残余风险,不得声明验证通过。
|
|
19
|
+
|
|
20
|
+
输出契约:
|
|
21
|
+
|
|
22
|
+
- 修改文件列表。
|
|
23
|
+
- evidence 路径和验证命令结果。
|
|
24
|
+
- 当前门禁结论。
|
|
25
|
+
- 唯一下一动作。
|
package/prompts/kd-plan.md
CHANGED
|
@@ -4,10 +4,20 @@ description: 为当前金蝶 Harness run 编写实施计划。
|
|
|
4
4
|
|
|
5
5
|
使用 `kd-plan` skill。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
执行实施计划阶段。输入:
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
{{args}}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
执行协议:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
- 读取当前 run、`CONTEXT.md`、`SPEC.md`、已问已答事实和项目结构。
|
|
14
|
+
- `PLAN.md` 必须写明真实目标路径、允许修改文件、实现契约、数据源/元数据查证项、SDK 签名查证项、验证命令、回滚说明和 evidence 要求。
|
|
15
|
+
- 验证命令按产品选择:Cosmic Java 使用当前项目 Gradle;企业版 C# 使用 `dotnet build`;企业版 Python 记录 BOS 注册和用户功能测试证据要求。
|
|
16
|
+
- 命令无法运行时记录真实阻塞原因和用户应运行的具体命令。
|
|
17
|
+
- 缺少关键事实时只登记一个最阻塞问题;禁止写可替换模板计划。
|
|
18
|
+
|
|
19
|
+
输出契约:
|
|
20
|
+
|
|
21
|
+
- 已更新的 `PLAN.md` 路径和摘要。
|
|
22
|
+
- 门禁结论。
|
|
23
|
+
- 唯一下一动作。
|
package/prompts/kd-ship.md
CHANGED
|
@@ -4,8 +4,19 @@ description: 验证后整理金蝶交付摘要。
|
|
|
4
4
|
|
|
5
5
|
使用 `kd-ship` skill。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
用户补充说明:
|
|
7
|
+
执行交付整理阶段。输入:
|
|
10
8
|
|
|
11
9
|
{{args}}
|
|
10
|
+
|
|
11
|
+
执行协议:
|
|
12
|
+
|
|
13
|
+
- 读取当前 run、`CONTEXT.md`、`SPEC.md`、`PLAN.md`、`EXECUTION.md`、`VERIFY.md`、evidence 和风险评估。
|
|
14
|
+
- 缺少 `VERIFY.md`、验证证据或风险说明时停止交付,只执行门禁指定的唯一下一动作。
|
|
15
|
+
- `SHIP.md` 必须说明行为变化、修改文件、验证证据、残余风险、人工验证边界和后续事项。
|
|
16
|
+
- 不得把未执行验证、外部系统操作或用户未提供的结果写成已完成。
|
|
17
|
+
|
|
18
|
+
输出契约:
|
|
19
|
+
|
|
20
|
+
- 已更新的 `SHIP.md` 路径和摘要。
|
|
21
|
+
- 验证证据和风险结论。
|
|
22
|
+
- 唯一下一动作。
|
package/prompts/kd-spec.md
CHANGED
|
@@ -4,8 +4,20 @@ description: 为当前金蝶 Harness run 编写需求规格文档。
|
|
|
4
4
|
|
|
5
5
|
使用 `kd-spec` skill。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
用户补充说明:
|
|
7
|
+
执行需求规格阶段。输入:
|
|
10
8
|
|
|
11
9
|
{{args}}
|
|
10
|
+
|
|
11
|
+
执行协议:
|
|
12
|
+
|
|
13
|
+
- 读取当前 run、`CONTEXT.md`、已问已答事实和门禁状态。
|
|
14
|
+
- 只把可核验事实写入 `SPEC.md`;未知事实写成阻塞项,不得用假设补齐。
|
|
15
|
+
- `SPEC.md` 必须包含验收标准、生命周期/扩展点、数据对象、字段/实体标识、异常行为、性能约束、依赖和风险。
|
|
16
|
+
- 缺少产品、FormId、字段/实体、插件事件、读写方式、接口契约或验收数据时,只登记一个最阻塞问题。
|
|
17
|
+
- 禁止输出代码、模板实现或多个待答问题。
|
|
18
|
+
|
|
19
|
+
输出契约:
|
|
20
|
+
|
|
21
|
+
- 已更新的 `SPEC.md` 路径和摘要。
|
|
22
|
+
- 未解决阻塞项或门禁通过结论。
|
|
23
|
+
- 唯一下一动作。
|
package/prompts/kd-verify.md
CHANGED
|
@@ -4,8 +4,20 @@ description: 验证当前金蝶实现并收集证据。
|
|
|
4
4
|
|
|
5
5
|
使用 `kd-verify` skill。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
用户补充说明:
|
|
7
|
+
执行验证阶段。输入:
|
|
10
8
|
|
|
11
9
|
{{args}}
|
|
10
|
+
|
|
11
|
+
执行协议:
|
|
12
|
+
|
|
13
|
+
- 读取当前 run、`PLAN.md`、`EXECUTION.md` 和 evidence。
|
|
14
|
+
- 只执行或记录 `PLAN.md` 声明的验证命令;替代命令必须说明等价依据。
|
|
15
|
+
- 验证命令完成后必须调用 `kd_verify_result` 记录 `command`、`exitCode`、关键 stdout/stderr 和结论。
|
|
16
|
+
- 外部系统、BOS 注册、人工功能测试和生产验证不能由 LLM 代办;只记录用户提供的证据来源、测试数据和结果。
|
|
17
|
+
- 验证失败时进入修复循环,不得进入 ship。
|
|
18
|
+
|
|
19
|
+
输出契约:
|
|
20
|
+
|
|
21
|
+
- `kd_verify_result` 记录结果。
|
|
22
|
+
- 通过或失败证据路径。
|
|
23
|
+
- 唯一下一动作。
|
|
@@ -46,7 +46,7 @@ description: 金蝶苍穹/Cosmic 平台 Java 插件开发技能,适用于苍
|
|
|
46
46
|
3. 通过官方适配器验证产品事实。
|
|
47
47
|
- 代码引用字段、表单 ID、单据名称、枚举/下拉值、实体 ID、操作编码、SQL 字段时,使用 `kd_cosmic_metadata`。
|
|
48
48
|
- 类名、方法名、方法签名、继承关系、Override 签名不确定时,优先使用 `kd_sdk_signature` 从当前项目实际 SDK jar 中验证;`kd_cosmic_api` 只作为随包知识线索和兜底。
|
|
49
|
-
-
|
|
49
|
+
- 多个表单或字段能够合并查询时,合并为一次元数据查询。
|
|
50
50
|
- 元数据查询和 API 签名查询互不依赖时并行执行。
|
|
51
51
|
|
|
52
52
|
4. 只有插件类型、生命周期方法、字段元数据和 API 签名都明确后,才生成或修改代码。
|
|
@@ -64,7 +64,7 @@ description: 金蝶苍穹/Cosmic 平台 Java 插件开发技能,适用于苍
|
|
|
64
64
|
|
|
65
65
|
- 不臆造字段 key、表单 ID、操作名、枚举值、表名或 SDK 方法;本地 SDK 查不到且编译未验证时,不把知识库结果当作最终签名事实。
|
|
66
66
|
- 不把 Enterprise C# 命名空间或生命周期假设用于苍穹/Cosmic 平台 Java。
|
|
67
|
-
- 星空旗舰版不允许猜目录或写 demo/sample
|
|
67
|
+
- 星空旗舰版不允许猜目录或写 demo/sample;无法判断真实代码位置时,先登记阻塞问题或更新计划,不得直接创建新目录。
|
|
68
68
|
- 不在数据绑定前的初始化阶段操作 UI 控件。
|
|
69
69
|
- 不在平台期望修改入参数据实体的事务钩子里另起保存。
|
|
70
70
|
- 不在循环中查询或保存,除非计划中明确说明无法批量处理并接受风险。
|
|
@@ -26,7 +26,7 @@ description: 金蝶苍穹/Cosmic 平台 Java 插件和 KSQL 代码审查技能
|
|
|
26
26
|
|
|
27
27
|
- P0:阻断问题,可能导致崩溃、数据损坏、事务失效、安全暴露、严重资源泄漏或核心功能不可用。
|
|
28
28
|
- P1:高风险问题,可能影响生产性能、稳定性、扩展性或可维护性。
|
|
29
|
-
- P2
|
|
29
|
+
- P2:规范和可维护性问题,应在计划窗口修复。
|
|
30
30
|
|
|
31
31
|
## P0 重点
|
|
32
32
|
|
|
@@ -79,7 +79,7 @@ description: 金蝶苍穹/Cosmic 平台 Java 插件和 KSQL 代码审查技能
|
|
|
79
79
|
- 文件和行号。
|
|
80
80
|
- 具体问题。
|
|
81
81
|
- 为什么在 Cosmic 中有风险。
|
|
82
|
-
-
|
|
82
|
+
- 修复指令。
|
|
83
83
|
|
|
84
84
|
随后说明:
|
|
85
85
|
|
|
@@ -51,7 +51,7 @@ description: 金蝶 Cosmic 体系 Java 单元测试生成和审查技能,适
|
|
|
51
51
|
- 需要构造的 `DynamicObject` 字段和集合结构。
|
|
52
52
|
- 被测代码中应由测试暴露而不是绕过的 bug。
|
|
53
53
|
|
|
54
|
-
POJO
|
|
54
|
+
POJO 或简单枚举场景允许在说明依据后直接实现。
|
|
55
55
|
|
|
56
56
|
## 测试质量规则
|
|
57
57
|
|
|
@@ -70,7 +70,7 @@ POJO 或简单枚举场景可以简要说明后直接实现。
|
|
|
70
70
|
|
|
71
71
|
- 优先使用项目已有 `DynamicObjectMocker`、`CommonMockObject`、`BaseTest`、`BasePluginTest`。
|
|
72
72
|
- `DataSet` 和查询行只 mock 实际 select 并读取的字段。
|
|
73
|
-
-
|
|
73
|
+
- 查询别名里包含点号且平台 mocker 无法安全表示时,使用 mock 的 `DynamicObject`。
|
|
74
74
|
- 对 `kd.bos.db.DB`,遵循项目已有 Class defrost 后再静态 mock 的模式。
|
|
75
75
|
- 对带分布式缓存行为的 helper,先搜索已有测试中的专用 mock helper,不直接 `mockStatic`。
|
|
76
76
|
|
|
@@ -79,7 +79,7 @@ POJO 或简单枚举场景可以简要说明后直接实现。
|
|
|
79
79
|
写完测试后:
|
|
80
80
|
|
|
81
81
|
- 使用 `kd_build` 或计划中的命令运行最窄可行 Gradle test 任务。
|
|
82
|
-
-
|
|
82
|
+
- 本机缺少业务 jar 或本地配置导致 Gradle 不能运行时,明确说明真实阻塞原因,并给出应运行的 Gradle task。
|
|
83
83
|
- 存在 harness run 时,把测试文件和验证结果写入 `.pi/kd/runs/<run-id>/EXECUTION.md`。
|
|
84
84
|
|
|
85
85
|
## 输出要求
|
|
@@ -21,5 +21,7 @@ Rules:
|
|
|
21
21
|
- Do not invent SDK APIs, table names, or lifecycle methods.
|
|
22
22
|
- If the product/version, tech stack, or target object is unknown, mark it as an open question.
|
|
23
23
|
- Ask unresolved questions one at a time. When using `kd_question`, ask only the single most blocking question and use at most 3 short choices; never submit a numbered checklist of questions.
|
|
24
|
+
- If any open blocking question already exists, do not ask or list another question; record the current answer first.
|
|
25
|
+
- Treat API/SDK documentation as technical evidence only; it cannot establish FormId, fields, entities, plugin events, table names, integration mappings, concurrency policy, or acceptance data.
|
|
24
26
|
- Never apply enterprise C# rules to Java products, or Java/Cosmic plugin rules to enterprise C#.
|
|
25
27
|
- Keep context concise; detailed design belongs in `SPEC.md`.
|
|
@@ -17,6 +17,8 @@ Rules:
|
|
|
17
17
|
|
|
18
18
|
- Do not broaden scope silently.
|
|
19
19
|
- Do not rewrite unrelated modules.
|
|
20
|
+
- Do not write code when implementation contract, data source context, SDK signature evidence, TDD red evidence, or PLAN-approved paths are missing.
|
|
21
|
+
- Do not use API documentation or bundled knowledge to fill business identifiers; stop and ask one blocking question or collect metadata evidence.
|
|
20
22
|
- For 星空旗舰版, edit only the real target path recorded in `PLAN.md` after inspecting the project. If `code/` exists, follow its actual layout; if it does not, follow the discovered source root or existing target file. Do not create demo/sample code or root-level `src/main/java` by guesswork.
|
|
21
23
|
- Do not mark work complete until verification runs.
|
|
22
24
|
- Do not skip planned steps. Every `STEP-###` in `PLAN.md` must be marked complete in `EXECUTION.md` with a real `evidence/...` file before entering verify.
|
|
@@ -26,3 +28,4 @@ Rules:
|
|
|
26
28
|
- Do not add JUnit, Mockito, NUnit, xUnit, or any extra test jar/framework only to satisfy the gate. Use existing approved project test infrastructure if it already exists.
|
|
27
29
|
- If the command cannot run, record the blocker instead of marking verification passed.
|
|
28
30
|
- If implementation needs a plan change, update `PLAN.md` first.
|
|
31
|
+
- External BOS registration, third-party system operation, and manual functional tests must be recorded as user-provided evidence; do not claim the LLM completed them.
|
package/skills/kd-plan/SKILL.md
CHANGED
|
@@ -22,6 +22,7 @@ Goal:
|
|
|
22
22
|
- Do not plan to add third-party test jars or frameworks only for red/green checks. For Kingdee plugin work, prefer `kd_sdk_signature` against current project jars/dlls, metadata checks, compile/build checks, existing project tests, or minimal external-interface tests.
|
|
23
23
|
- Define validation commands and expected evidence.
|
|
24
24
|
- Add rollback or containment notes for medium/high risk work.
|
|
25
|
+
- For enterprise Python plugins, do not invent a local build step; require BOS registration and user-provided functional test evidence in `VERIFY.md`.
|
|
25
26
|
|
|
26
27
|
Gate:
|
|
27
28
|
|
|
@@ -32,3 +33,5 @@ Gate:
|
|
|
32
33
|
- A plan without structured `STEP-001` execution steps is incomplete.
|
|
33
34
|
- A plan without TDD red/green checks is incomplete.
|
|
34
35
|
- A plan that relies on unverified Kingdee API names is incomplete; bundled knowledge alone is not enough when local SDK jars/dlls or compile evidence are available.
|
|
36
|
+
- A plan that lacks implementation contract, data source context, integration context, or acceptance data must stop at one blocking question; do not create a broad question list.
|
|
37
|
+
- A plan that writes demo/sample/scaffold or placeholder paths is invalid.
|
package/skills/kd-ship/SKILL.md
CHANGED
|
@@ -19,4 +19,5 @@ Rules:
|
|
|
19
19
|
- Do not claim completion without verification evidence.
|
|
20
20
|
- Keep the handoff concise and decision-oriented.
|
|
21
21
|
- If verification is partial, say so clearly.
|
|
22
|
-
|
|
22
|
+
- Do not describe external system operation, BOS registration, manual functional testing, or production validation as completed unless the user supplied verifiable evidence.
|
|
23
|
+
- Include remaining manual validation boundaries and residual risk explicitly.
|
package/skills/kd-spec/SKILL.md
CHANGED
|
@@ -18,6 +18,9 @@ Goal:
|
|
|
18
18
|
Rules:
|
|
19
19
|
|
|
20
20
|
- Separate confirmed facts from assumptions.
|
|
21
|
-
-
|
|
21
|
+
- Write only verifiable facts into the specification; unresolved business identifiers must become a single blocking question.
|
|
22
|
+
- Mark every API/table assumption as requiring lookup with local metadata, SDK signature, build output, or product evidence. Bundled knowledge alone is only a clue.
|
|
22
23
|
- Do not edit product code in this phase.
|
|
23
|
-
- If acceptance criteria are vague, ask targeted questions one at a time
|
|
24
|
+
- If acceptance criteria are vague, ask targeted questions one at a time. When using `kd_question`, ask only the single most blocking question and use at most 3 short choices; never submit a numbered checklist of questions.
|
|
25
|
+
- If any open blocking question already exists, stop and record the answer before continuing.
|
|
26
|
+
- Do not generate implementation templates, sample code, or pseudo-code in `SPEC.md`.
|
|
@@ -22,3 +22,5 @@ Rules:
|
|
|
22
22
|
- If validation cannot run, state the exact blocker.
|
|
23
23
|
- Do not hand-edit `VERIFY.md` as the primary result path; `kd_verify_result` owns pass/failure evidence and the repair loop.
|
|
24
24
|
- Do not ship while verification evidence is missing.
|
|
25
|
+
- Do not convert skipped external/BOS/manual validation into a pass. Record user-provided evidence source, test data, environment, and result.
|
|
26
|
+
- If validation fails, keep the run in the repair loop; do not summarize delivery or mark residual risk as low.
|
package/src/harness/messages.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type { KdPhase } from "./types.ts";
|
|
2
2
|
import { PHASE_ARTIFACTS } from "./types.ts";
|
|
3
3
|
import {
|
|
4
|
-
DATA_SOURCE_CONTEXT_FIELDS,
|
|
5
|
-
IMPLEMENTATION_CONTRACT_FIELDS,
|
|
6
|
-
INTEGRATION_CONTEXT_FIELDS,
|
|
7
|
-
fieldLabels,
|
|
8
4
|
questionForMissingLabel,
|
|
9
5
|
} from "./prompt-policy.ts";
|
|
10
6
|
|
|
@@ -20,9 +16,12 @@ export function unknownRiskReason(): string {
|
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
export function openQuestionsReason(questions: Array<{ id: string; question: string }>): string {
|
|
19
|
+
const first = questions[0];
|
|
20
|
+
if (!first) return "不存在未回答的阻断问题。";
|
|
21
|
+
const remaining = questions.length > 1 ? `;另有 ${questions.length - 1} 个历史 open 问题,需先处理当前问题后再逐个处理` : "";
|
|
23
22
|
return [
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
`当前未回答的阻断问题:${first.id} ${first.question}${remaining}`,
|
|
24
|
+
`下一步:只获取 ${first.id} 的用户答案,然后用 kd_question action=answer id=${first.id} answer=<用户答案> 记录;禁止继续提出其他问题。`,
|
|
26
25
|
].join("。");
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -33,8 +32,8 @@ export function repairBlockedReason(attempts: number, maxAttempts: number, evide
|
|
|
33
32
|
|
|
34
33
|
export function dataSourcePlanBlockedReason(missing: string[]): string {
|
|
35
34
|
return [
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
missingSummary("业务数据源上下文", missing),
|
|
36
|
+
"下一步:停止编码,只登记当前最阻塞问题;用户回答并记录后,再重新刷新门禁决定下一问。",
|
|
38
37
|
nextQuestionInstruction(missing),
|
|
39
38
|
"API 文档只能作为调用线索,不能替代这些业务事实。",
|
|
40
39
|
].filter(Boolean).join("");
|
|
@@ -42,8 +41,8 @@ export function dataSourcePlanBlockedReason(missing: string[]): string {
|
|
|
42
41
|
|
|
43
42
|
export function integrationPlanBlockedReason(missing: string[]): string {
|
|
44
43
|
return [
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
missingSummary("第三方对接上下文", missing),
|
|
45
|
+
"下一步:停止编码,只登记当前最阻塞问题;用户回答并记录后,再重新刷新门禁决定下一问。",
|
|
47
46
|
nextQuestionInstruction(missing),
|
|
48
47
|
"缺少这些信息时禁止生成模板代码。",
|
|
49
48
|
].filter(Boolean).join("");
|
|
@@ -51,8 +50,8 @@ export function integrationPlanBlockedReason(missing: string[]): string {
|
|
|
51
50
|
|
|
52
51
|
export function implementationPlanBlockedReason(missing: string[]): string {
|
|
53
52
|
return [
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
missingSummary("实现就绪信息", missing),
|
|
54
|
+
"下一步:禁止生成模板代码,只登记当前最阻塞问题;用户回答并记录后,再重新刷新门禁决定下一问。",
|
|
56
55
|
nextQuestionInstruction(missing),
|
|
57
56
|
"这些字段是所有插件、服务和集成实现的通用输入,不依赖具体业务场景枚举。",
|
|
58
57
|
].filter(Boolean).join("");
|
|
@@ -158,15 +157,22 @@ export function dataSourceWriteBlockedReason(path: string, evidenceName: string)
|
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
export function integrationWriteBlockedReason(path: string, missing: string[]): string {
|
|
161
|
-
return `不能写生产源码 ${path}
|
|
160
|
+
return `不能写生产源码 ${path}:第三方对接上下文不完整,当前最阻塞缺失:${missing[0] ?? "未知"}。下一步:只确认当前缺失事实,记录后重新刷新门禁;禁止一次性向用户索要完整清单。`;
|
|
162
161
|
}
|
|
163
162
|
|
|
164
163
|
export function implementationWriteBlockedReason(path: string, missing: string[]): string {
|
|
165
|
-
return `不能写生产源码 ${path}
|
|
164
|
+
return `不能写生产源码 ${path}:实现就绪信息不完整,当前最阻塞缺失:${missing[0] ?? "未知"}。下一步:只确认当前缺失事实,记录后重新刷新门禁;信息不足时继续提问,禁止生成模板代码。`;
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
function nextQuestionInstruction(missing: string[]): string | undefined {
|
|
169
168
|
const question = questionForMissingLabel(missing[0]);
|
|
170
169
|
if (!question) return undefined;
|
|
171
|
-
return
|
|
170
|
+
return `唯一允许的阻断问题命令:kd_question action=ask factLabel="${missing[0]}" question="${question}" reason="${missing[0]} 缺失会阻塞实现。"。`;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function missingSummary(scope: string, missing: string[]): string {
|
|
174
|
+
const first = missing[0] ?? "未知";
|
|
175
|
+
const remaining = Math.max(0, missing.length - 1);
|
|
176
|
+
const remainingText = remaining > 0 ? `;另有 ${remaining} 项待后续逐项确认,本轮不得向用户展开` : "";
|
|
177
|
+
return `不能进入 execute:${scope}不完整,当前最阻塞缺失:${first}${remainingText}。`;
|
|
172
178
|
}
|
|
@@ -145,6 +145,7 @@ export const INTEGRATION_CONTEXT_FIELDS: ContractField[] = [
|
|
|
145
145
|
export const PROJECT_PERSISTENT_RULES = [
|
|
146
146
|
"计划或编辑代码前必须读取本文件;本文件过期时先运行 `kcode context --refresh`。",
|
|
147
147
|
"信息不足时禁止开始编码。必须先登记一个最阻塞的结构化问题,获得可核验答案后再继续;禁止输出 demo/sample/scaffold、模板代码或占位实现。",
|
|
148
|
+
"任何时刻最多只能存在一个 open blocking question;已有未回答阻断问题时,必须先记录用户答案,禁止继续提出、登记或展示其他问题。",
|
|
148
149
|
"API 文档、SDK 文档和知识库只能证明技术用法,不能替代业务事实。FormId、单据/表单标识、字段/实体/分录标识、插件类型与事件、SQL/KSQL 表名和数据库字段名必须来自用户确认、项目元数据或 evidence。",
|
|
149
150
|
`产品代码实现前必须具备通用实现契约:${IMPLEMENTATION_CONTRACT_FIELDS.map((field) => field.label).join("、")}。`,
|
|
150
151
|
`涉及业务数据源时必须具备数据源上下文:${DATA_SOURCE_CONTEXT_FIELDS.map((field) => field.label).join("、")}。`,
|
|
@@ -154,10 +155,12 @@ export const PROJECT_PERSISTENT_RULES = [
|
|
|
154
155
|
"`run.facts` 是唯一结构化事实源;已回答 questions 仅为审计记录,禁止在读取状态时从历史 question 反推事实。",
|
|
155
156
|
"`factLabel` 必须使用集中定义的事实标签或别名;未知标签、占位答案、口头确认语、待确认/TODO/TBD/按实际环境等不能解除门禁。",
|
|
156
157
|
"用户回答 open question 后,先用 `kd_question action=answer` 写入答案;用户更正事实时用 `kd_question action=revise`,禁止重复询问已确认事实。",
|
|
158
|
+
"门禁提示只暴露当前最阻塞缺失事实;后续待确认项只能在当前问题回答后重新刷新门禁逐项生成,禁止一次性向用户展开完整问题清单。",
|
|
157
159
|
"企业版 Python 插件通常没有本地构建可替代验证;BOS 注册、外部系统操作、人工功能测试和生产环境验证必须由用户提供可核验证据并记录来源。",
|
|
158
160
|
"提示语集中管理为正式工程指令;禁止口语化、闲聊式、鼓励式提示词进入运行时规则。",
|
|
159
161
|
"工具使用必须匹配当前会话实际可用工具和操作系统;Windows 默认使用 PowerShell、`rg`、`Get-ChildItem`、`Get-Content`,禁止假设 bash 可用。",
|
|
160
162
|
"Windows 查找文件和目录时优先使用 `kd_find_file`、`kd_list_dir` 或 PowerShell;禁止用 Linux find/ls 语法反复调用 Pi 内置 bash。",
|
|
163
|
+
"写入或编辑文件时禁止使用当前工作区外的绝对路径;生产源码必须使用当前业务项目相对路径,并受 PLAN.md 批准文件约束。",
|
|
161
164
|
"文件定位必须使用真实搜索或目录读取结果;工具不可用时明确说明阻塞原因和需要用户执行的命令,禁止猜测路径、反复自述工具失败或用 kd_subagent 代替基础文件搜索。",
|
|
162
165
|
"不做旧状态迁移兼容或旧问题答案推断;坏状态只过滤,缺失事实必须重新提问确认。",
|
|
163
166
|
];
|
|
@@ -167,6 +170,50 @@ export const PROMPT_STYLE_RULES = [
|
|
|
167
170
|
"事实不足时生成阻断问题;禁止输出模板代码、占位实现或基于猜测的业务标识。",
|
|
168
171
|
"每次只提出一个最阻塞问题;问题必须指向可验证事实、数据标识或验收证据。",
|
|
169
172
|
"引用顺序:当前项目文件、PLAN/SPEC、元数据 evidence、SDK 签名、验证输出。",
|
|
173
|
+
"响应必须说明当前阶段、门禁结论、采用的事实来源和唯一下一动作;禁止同时给出多个并行动作让用户选择。",
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
export const PROMPT_DECISION_PROTOCOL = [
|
|
177
|
+
"先读取 Harness 状态、当前阶段资料、已问已答事实和项目上下文;禁止只根据用户最后一句话行动。",
|
|
178
|
+
"先判断用户输入是否是在回答 open blocking question;如是,唯一动作是调用 `kd_question action=answer` 记录答案。",
|
|
179
|
+
"再判断当前阶段门禁是否阻塞;阻塞时只执行门禁要求的唯一下一动作,禁止绕过阶段推进。",
|
|
180
|
+
"再判断是否缺少可核验事实;缺失时只登记当前最阻塞的一个问题,禁止展开后续问题。",
|
|
181
|
+
"只有在阶段、门禁、事实和证据均满足时,才允许进入计划、编码、验证或交付动作。",
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
export const PROMPT_FACT_PROTOCOL = [
|
|
185
|
+
"`run.facts` 是结构化事实唯一来源;`questions` 仅为问答审计记录。",
|
|
186
|
+
"业务事实必须有来源分类:用户明确回答、项目元数据/evidence、当前项目文件、验证输出。",
|
|
187
|
+
"API/SDK 文档只作为技术用法线索;不得补全 FormId、字段标识、实体标识、表名、接口字段映射、并发策略或验收数据。",
|
|
188
|
+
"事实值包含待确认、未知、按实际环境、TODO/TBD、可以、好的、是/否等内容时,视为无效事实。",
|
|
189
|
+
"同一事实存在冲突时,停止推进并使用 `kd_question action=revise` 或登记一个最阻塞更正问题。",
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
export const PROMPT_QUESTION_PROTOCOL = [
|
|
193
|
+
"任何时刻最多存在一个 open blocking question。",
|
|
194
|
+
"已有 open blocking question 时,禁止继续提问、禁止输出问题清单、禁止登记新问题;唯一动作是获取并记录该问题答案。",
|
|
195
|
+
"`kd_question action=ask` 的问题文本只能包含一个事实点,不能使用编号列表、多个问号或复合事实。",
|
|
196
|
+
"带 `factLabel` 的问题必须使用集中定义标签或别名;产品类型不是 factLabel。",
|
|
197
|
+
"问题登记后停止推进,等待用户回答;不得在同一轮继续生成方案、计划或代码。",
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
export const PROMPT_OUTPUT_CONTRACT = [
|
|
201
|
+
"阻塞时输出:阻塞原因、唯一下一动作、需要使用的工具或命令;不得输出实现方案或代码片段。",
|
|
202
|
+
"提问时输出:只登记或展示一个问题;不得附带后续问题预告清单。",
|
|
203
|
+
"计划时输出:目标路径、允许修改文件、查证项、验证命令、回滚方式和 evidence 要求。",
|
|
204
|
+
"执行时输出:仅说明已修改文件、证据文件和验证结果;不得把未验证内容写成已完成。",
|
|
205
|
+
"验证失败时输出:失败证据、定位结论、下一轮修复边界;不得直接跳到 ship。",
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
export const PROMPT_PROHIBITED_BEHAVIORS = [
|
|
209
|
+
"禁止根据 API 文档、SDK 记忆或知识库推断业务数据源。",
|
|
210
|
+
"禁止生成 demo/sample/scaffold、占位实现、伪代码或仅可手工替换的模板。",
|
|
211
|
+
"禁止一次性向用户索要多项业务信息。",
|
|
212
|
+
"禁止重复询问已确认事实或已存在 open blocking question 的问题。",
|
|
213
|
+
"禁止猜测路径、包名、类名、FormId、字段、实体、SQL 表名、数据库字段名或接口字段映射。",
|
|
214
|
+
"禁止写入或编辑当前工作区外的绝对路径。",
|
|
215
|
+
"禁止用子 agent、shell 失败自述或自由文本计划绕过门禁。",
|
|
216
|
+
"禁止将外部系统操作、BOS 注册、人工功能测试或生产验证描述为 LLM 已完成。",
|
|
170
217
|
];
|
|
171
218
|
|
|
172
219
|
export const CORE_WORKFLOW_CONSTRAINTS = [
|
|
@@ -175,6 +222,7 @@ export const CORE_WORKFLOW_CONSTRAINTS = [
|
|
|
175
222
|
"业务数据源未知时禁止编码;确认目标 FormId/单据或表单、插件类型和事件、字段/实体/分录标识、数据读取写入方式后再编码;SQL/KSQL 同步确认表名和数据库字段名。",
|
|
176
223
|
"第三方对接确认接口文档、对接方向、触发时机、认证配置、字段映射、并发/幂等、重试超时限流、错误补偿、日志脱敏和验收样例后再编码。",
|
|
177
224
|
"事实缺失时使用 kd_question 登记一个最阻塞问题;禁止用 API 文档、SDK 知识库或推测替代业务事实。",
|
|
225
|
+
"已有 open blocking question 时禁止继续提问;先记录该问题答案,再根据刷新后的门禁决定下一问。",
|
|
178
226
|
"用户输入是在回答 open question 时,必须先调用 kd_question action=answer 记录答案,再继续推进或登记下一个问题。",
|
|
179
227
|
"同一 factLabel 已有当前事实时禁止重复提问;用户明确更正时使用 kd_question action=revise 记录新事实和更正原因。",
|
|
180
228
|
"run.facts 是唯一结构化事实源;questions 仅作为问答审计记录,禁止从历史 question 反推门禁事实。",
|
|
@@ -183,7 +231,7 @@ export const CORE_WORKFLOW_CONSTRAINTS = [
|
|
|
183
231
|
"Java/Cosmic 使用当前项目 Gradle;C#/企业版使用 dotnet build。",
|
|
184
232
|
"evidence 必须记录命令、Exit 和关键输出;命令无法运行时记录阻塞原因。",
|
|
185
233
|
"外部系统操作、BOS 注册、人工功能测试和生产环境验证不能由 LLM 代办;必须要求用户提供验证结果或可核验证据,并记录证据来源。",
|
|
186
|
-
"Windows
|
|
234
|
+
"Windows 路径规则:读取可使用工作区内绝对路径;写入和编辑必须使用当前工作区内路径,默认使用项目相对路径。禁止写入 C:\\Users、Desktop 或其他非当前工作区路径。",
|
|
187
235
|
"工具规则:按当前会话实际 shell 和工具执行;Windows 不假设 bash,优先用 kd_find_file/kd_list_dir/PowerShell;禁止猜路径或用 kd_subagent 代替基础搜索失败。",
|
|
188
236
|
];
|
|
189
237
|
|
package/src/harness/prompt.ts
CHANGED
|
@@ -4,7 +4,17 @@ import { delegationGuidanceForWorkflow, shouldInjectDelegationGuidance } from ".
|
|
|
4
4
|
import { formatStatus } from "./format.ts";
|
|
5
5
|
import type { ActiveRun, KdPhase } from "./types.ts";
|
|
6
6
|
import { PHASE_ORDER } from "./types.ts";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
CORE_WORKFLOW_CONSTRAINTS,
|
|
9
|
+
PHASE_GUIDANCE,
|
|
10
|
+
PROMPT_DECISION_PROTOCOL,
|
|
11
|
+
PROMPT_FACT_PROTOCOL,
|
|
12
|
+
PROMPT_OUTPUT_CONTRACT,
|
|
13
|
+
PROMPT_PROHIBITED_BEHAVIORS,
|
|
14
|
+
PROMPT_QUESTION_PROTOCOL,
|
|
15
|
+
PROMPT_STYLE_RULES,
|
|
16
|
+
formatPromptLines,
|
|
17
|
+
} from "./prompt-policy.ts";
|
|
8
18
|
import { formatQuestionMemory } from "./question-memory.ts";
|
|
9
19
|
|
|
10
20
|
export function workflowPromptForRun(cwd: string, run: ActiveRun, userText: string): string {
|
|
@@ -33,6 +43,21 @@ export function workflowPromptForRun(cwd: string, run: ActiveRun, userText: stri
|
|
|
33
43
|
"当前阶段任务:",
|
|
34
44
|
phaseGuidance,
|
|
35
45
|
"",
|
|
46
|
+
"执行顺序协议:",
|
|
47
|
+
...formatPromptLines(PROMPT_DECISION_PROTOCOL),
|
|
48
|
+
"",
|
|
49
|
+
"事实处理协议:",
|
|
50
|
+
...formatPromptLines(PROMPT_FACT_PROTOCOL),
|
|
51
|
+
"",
|
|
52
|
+
"提问协议:",
|
|
53
|
+
...formatPromptLines(PROMPT_QUESTION_PROTOCOL),
|
|
54
|
+
"",
|
|
55
|
+
"输出契约:",
|
|
56
|
+
...formatPromptLines(PROMPT_OUTPUT_CONTRACT),
|
|
57
|
+
"",
|
|
58
|
+
"禁止行为:",
|
|
59
|
+
...formatPromptLines(PROMPT_PROHIBITED_BEHAVIORS),
|
|
60
|
+
"",
|
|
36
61
|
"工程指令风格:",
|
|
37
62
|
...formatPromptLines(PROMPT_STYLE_RULES),
|
|
38
63
|
"",
|
|
@@ -96,16 +96,20 @@ export function factFromAnsweredQuestion(question: KdQuestion, now = new Date().
|
|
|
96
96
|
|
|
97
97
|
export function questionAskBlockReason(run: ActiveRun, input: { factLabel?: string }): string | undefined {
|
|
98
98
|
const rawLabel = input.factLabel?.trim();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (open) {
|
|
99
|
+
const label = rawLabel ? canonicalFactLabel(rawLabel) : undefined;
|
|
100
|
+
if (rawLabel && !label) return [`未知 factLabel:${rawLabel}。必须使用 KCode 集中定义的实现契约、数据源上下文或第三方对接事实标签。`, "", "执行 `kd_question action=labels` 查看完整合法标签。", "", formatFactLabelCatalog()].join("\n");
|
|
101
|
+
const openBlocking = (Array.isArray(run.questions) ? run.questions : []).filter((question) => question.status === "open" && question.blocking);
|
|
102
|
+
const sameFactOpen = label
|
|
103
|
+
? openBlocking.find((question) => question.factLabel && factKey(question.factLabel) === factKey(label))
|
|
104
|
+
: undefined;
|
|
105
|
+
const open = sameFactOpen ?? openBlocking[0];
|
|
106
|
+
if (open && sameFactOpen && label) {
|
|
107
107
|
return `事实标签 ${label} 已有未回答问题 ${open.id},禁止重复提问。下一步:获取用户答案后用 kd_question action=answer id=${open.id} answer=<答案> 记录。`;
|
|
108
108
|
}
|
|
109
|
+
if (open) {
|
|
110
|
+
return `已有未回答阻断问题 ${open.id}:${open.question}。禁止继续登记其他问题。下一步:只获取该问题答案,并用 kd_question action=answer id=${open.id} answer=<答案> 记录。`;
|
|
111
|
+
}
|
|
112
|
+
if (!label) return undefined;
|
|
109
113
|
const fact = currentFactForLabel(run, label);
|
|
110
114
|
if (fact) {
|
|
111
115
|
return `事实标签 ${label} 已确认为 ${fact.value},禁止重复提问。用户明确更正时使用 kd_question action=revise factLabel="${label}" answer="<新值>" reason="<更正原因>"。`;
|
|
@@ -128,7 +132,7 @@ export function questionFactLabelMismatchReason(input: { question: string; factL
|
|
|
128
132
|
].join("\n");
|
|
129
133
|
}
|
|
130
134
|
if (asksOtherFact && conjunction) {
|
|
131
|
-
return `问题文本包含多个结构化事实,但 factLabel 只能是一个:${label}
|
|
135
|
+
return `问题文本包含多个结构化事实,但 factLabel 只能是一个:${label}。必须拆成单事实问题,并且每次只登记当前最阻塞的一个。`;
|
|
132
136
|
}
|
|
133
137
|
return undefined;
|
|
134
138
|
}
|
package/src/platform/path.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isAbsolute, resolve } from "node:path";
|
|
1
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
2
2
|
|
|
3
3
|
const WINDOWS_DRIVE_RE = /^[a-zA-Z]:[\\/]/;
|
|
4
4
|
|
|
@@ -7,6 +7,18 @@ export function resolveWorkspacePath(cwd: string, inputPath: string): string {
|
|
|
7
7
|
return isAbsolute(normalized) || WINDOWS_DRIVE_RE.test(normalized) ? resolve(normalized) : resolve(cwd, normalized);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export function isExternalAbsolutePath(inputPath: string): boolean {
|
|
11
|
+
const normalized = normalizeExternalPath(inputPath);
|
|
12
|
+
return isAbsolute(normalized) || WINDOWS_DRIVE_RE.test(normalized);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isPathInsideWorkspace(cwd: string, inputPath: string): boolean {
|
|
16
|
+
const workspace = resolve(cwd);
|
|
17
|
+
const target = resolveWorkspacePath(cwd, inputPath);
|
|
18
|
+
const rel = relative(workspace, target);
|
|
19
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
20
|
+
}
|
|
21
|
+
|
|
10
22
|
export function normalizeExternalPath(inputPath: string): string {
|
|
11
23
|
let value = inputPath.trim();
|
|
12
24
|
if (value.startsWith("file://")) {
|