import type { KdPhase } from "./types.ts"; import { PHASE_ARTIFACTS } from "./types.ts"; import { questionForMissingLabel, } from "./prompt-policy.ts"; export function unknownProductReason(declaration: boolean | undefined): string { if (declaration === undefined) { return "不能进入 execute:产品未知,且 PLAN.md 未明确声明是否涉及产品实现、构建、元数据或 SDK 查证。下一步:根据当前需求和项目计划判断范围;涉及产品实现时执行 /kd product ;不涉及时在 PLAN.md 的“产品实现范围”写明“不涉及”及依据。"; } return "不能进入 execute:PLAN.md 声明涉及产品实现、构建、元数据或 SDK 查证,但产品未知。下一步:根据需求、计划或用户回答确认产品,然后执行 /kd product ;无法判断时使用 kd_ask_user 发起产品确认问题。"; } export function unknownRiskReason(): string { return "不能进入 ship:风险等级或风险原因未知。下一步:根据 VERIFY.md 和 SHIP.md 的残余风险执行 /kd risk <原因>,或在风险章节写入真实风险说明后再刷新检查。"; } export function openQuestionsReason(questions: Array<{ id: string; question: string }>): string { const first = questions[0]; if (!first) return "不存在未回答的阻断问题。"; const remaining = questions.length > 1 ? `;另有 ${questions.length - 1} 个历史 open 问题,需先处理当前问题后再逐个处理` : ""; return [ `当前未回答的阻断问题:${first.id} ${first.question}${remaining}`, `下一步:只获取 ${first.id} 的用户答案,然后用 kd_answer_user action=answer id=${first.id} answer=<用户答案> 记录;禁止继续提出其他问题。`, ].join("。"); } export function repairBlockedReason(attempts: number, maxAttempts: number, evidence?: string): string { const evidenceText = evidence ? `,最近失败证据:${evidence}` : ""; return `自动修复已停止:验证失败 ${attempts}/${maxAttempts}${evidenceText}。下一步:回到 plan 调整范围,或重新创建/回答修复问题选择“继续修复”。`; } export function dataSourcePlanBlockedReason(missing: string[]): string { return [ missingSummary("业务数据源上下文", missing), "下一步:停止编码;先读取当前项目、PLAN 和已有 evidence,能从项目元数据、kd_cosmic_metadata、kd_metadata_parse 或已配置数据库 MCP 只读查询取得的事实必须先查证并写入 evidence,仍缺业务决策时再用 kd_ask_user 登记当前数据源事实组问题。", nextQuestionInstruction(missing), "API 文档只能作为调用线索,不能替代这些业务事实。", ].filter(Boolean).join(""); } export function integrationPlanBlockedReason(missing: string[]): string { return [ missingSummary("第三方对接上下文", missing), "下一步:停止编码,使用 kd_ask_user 登记当前第三方对接事实组问题;用户回答并记录后,再重新刷新门禁。", nextQuestionInstruction(missing), "缺少这些信息时禁止生成模板代码。", ].filter(Boolean).join(""); } export function implementationPlanBlockedReason(missing: string[]): string { return [ missingSummary("实现就绪信息", missing), "下一步:禁止生成模板代码,使用 kd_ask_user 登记当前实现契约事实组问题;用户回答并记录后,再重新刷新门禁。", nextQuestionInstruction(missing), "这些字段是所有插件、服务和集成实现的通用输入,不依赖具体业务场景枚举。", ].filter(Boolean).join(""); } export function missingMarkerReason(phase: KdPhase, missing: string[]): string { return `${PHASE_ARTIFACTS[phase]} 缺少必需章节:${missing.join(", ")}。下一步:更新 ${PHASE_ARTIFACTS[phase]},补齐这些章节并写入真实内容。`; } export function missingArtifactsReason(artifacts: string[]): string { return [ `缺少必需产物:${artifacts.join(", ")}`, `下一步:使用 /kd doc <阶段> 创建或更新阶段文档,或按当前阶段要求补写 ${artifacts.join(", ")} 的真实内容后再刷新检查。`, ].join("。"); } export function missingForTargetReason(target: KdPhase, artifacts: string[]): string { const evidence = artifacts.filter((artifact) => artifact.startsWith("evidence/")); const documents = artifacts.filter((artifact) => !artifact.startsWith("evidence/")); const actions: string[] = []; if (documents.length > 0) { actions.push(`补齐阶段文档 ${documents.join(", ")};可使用 /kd doc 创建模板后填入真实分析、计划或验证内容`); } if (evidence.length > 0) { actions.push(evidenceAction(evidence)); } return `不能进入 ${target}:缺少 ${artifacts.join(", ")}。下一步:${actions.join(";")}。`; } export function missingEvidenceReason(artifacts: string[]): string { return `缺少必需证据:${artifacts.join(", ")}。下一步:${evidenceAction(artifacts)}。`; } export function evidenceAction(artifacts: string[]): string { return artifacts.map(evidenceArtifactAction).join(";"); } export function evidenceArtifactAction(artifact: string): string { switch (artifact) { case "evidence/sdk-signature.md": return "运行 kd_sdk_signature,从当前项目真实 SDK jar/dll 查证类、方法、构造器或属性签名,成功后自动写入 evidence/sdk-signature.md"; case "evidence/cosmic-config.txt": return "运行 kd_cosmic_config 生成 evidence/cosmic-config.txt;项目没有 ok-cosmic.json 时使用 KCode 默认配置"; case "evidence/cosmic-metadata.json": return "先从 PLAN、run.facts 或项目文件取得目标 FormId/单据线索;若项目内已有 FKERNELXML/fdata/MCP 导出文件,优先运行 kd_metadata_collect 自动写入 evidence;否则运行 kd_cosmic_metadata 查询目标表单/单据/字段元数据并生成 evidence/cosmic-metadata.json;若项目已配置数据库 MCP 且官方工具不足,使用只读 MCP 查询 t_meta_entitydesign.fdata 后再用 kd_metadata_collect/kd_metadata_parse 解析为 evidence"; case "evidence/data-source.md": return "先查当前项目元数据、BOS/FKERNELXML/fdata 文件或已配置数据库 MCP 的只读元数据结果,并优先用 kd_metadata_collect 或 kcode meta 写入 evidence/data-source.md;仅需预览时再用 kd_metadata_parse;仍缺业务选择时再用 kd_ask_user 提问;证据至少包含目标 FormId/单据或表单、字段/实体标识、表或数据来源、验证来源和测试数据,禁止只引用 API 文档"; case "evidence/cosmic-api.txt": return "运行 kd_cosmic_api 查询相关 Cosmic API 线索并生成 evidence/cosmic-api.txt,再用 kd_sdk_signature 或构建输出确认签名"; case "evidence/ksql-lint.txt": return "运行 kd_ksql_lint 校验 KSQL/SQL 交付内容并生成 evidence/ksql-lint.txt"; case "evidence/verify-pass.md": return "在 verify 阶段运行真实验证命令,并使用 kd_verify_result 记录 Exit: 0 的通过结果,生成 evidence/verify-pass.md"; default: return `运行 PLAN.md 中声明的验证命令,记录命令、Exit、STDOUT/STDERR 或工具输出到 ${artifact}`; } } export function flagshipWriteBlockedReason(path: string): string { return `星空旗舰版代码必须跟随当前项目结构写入 code/ 下,不能写到 ${path}。下一步:读取当前项目 code/ 下的真实模块结构,在 PLAN.md 记录目标源码路径,再把写入路径改为 code/... 下的项目相对路径。`; } export function planWriteBlockedReason(path: string): string { return `PLAN.md 未批准写入 ${path}。下一步:停止写入该文件,回到 plan 阶段检查项目结构和影响范围,把该文件加入 PLAN.md 的 ## 允许修改的文件 和执行步骤;重新通过门禁后再写。`; } export function flagshipPlanNeedsCodePathReason(): string { return "不能进入 execute:星空旗舰版 PLAN.md 必须记录当前项目 code/ 下的实际目标路径。下一步:列出 code/ 下模块,识别当前项目是按云、按应用还是不分模块组织,在 PLAN.md 写明真实目标文件。"; } export function flagshipPlanNeedsSourcePathReason(): string { return "不能进入 execute:PLAN.md 必须记录已检查当前项目结构,并写明实际源码根或目标文件路径。下一步:读取构建文件和 src/lib/bin 等目录,确认源码根后写入 PLAN.md 的 ## 已检查的项目结构、## 目标源码根 / 路径 和 ## 允许修改的文件。"; } export function tddPlanMissingReason(): string { return "PLAN.md 缺少 ## TDD / 红绿检查。下一步:回到 plan 补充该章节,明确红灯证据、绿灯证据、验证命令或无法自动化时的产品验证替代方案;至少写明 evidence/tdd-red.md、evidence/tdd-green.md 和要运行的真实检查。"; } export function tddProductionMissingRedReason(path: string, evidenceName: string): string { return `不能写生产源码 ${path}:缺少红灯证据 ${evidenceName}。下一步:运行一个实现前应失败的检查,例如 kd_sdk_signature 方法不存在检查、元数据/API 检查、编译检查、kd_check、项目已有测试或外部接口最小验证;把命令、非 0 Exit 或失败输出写入 evidence/tdd-red.md 后再写生产源码。`; } export function tddVerifyBlockedReason(reasons: string[]): string { return [ `不能进入 verify:${reasons.join(";")}。`, "修复方式:重新运行 PLAN.md 中声明的同一验证命令或等价的产品验证命令,", "并把命令、Exit、STDOUT/STDERR 或明确的工具输出写入对应 evidence 文件。", ].join(""); } export function redEvidenceInvalidReason(evidenceName: string): string { return `${evidenceName} 内容无效:必须包含真实失败输出或非 0 退出码`; } export function greenEvidenceInvalidReason(evidenceName: string): string { return `${evidenceName} 内容无效:绿灯证据必须同时包含成功结论和 Exit: 0/退出码:0`; } export function sdkSignatureWriteBlockedReason(path: string, evidenceName: string): string { return `不能写生产源码 ${path}:缺少本地 SDK 签名证据 ${evidenceName}。下一步:运行 kd_sdk_signature,从当前项目真实 jar/dll 查证即将使用的 SDK 类、方法、构造器或属性签名;成功生成 evidence/sdk-signature.md 后再写代码。禁止凭记忆或随包知识库猜 SDK API。`; } export function dataSourceWriteBlockedReason(path: string, evidenceName: string): string { return `不能写生产源码 ${path}:缺少真实数据源/元数据证据 ${evidenceName}。下一步:确认目标 FormId、单据/表单、字段/实体、表或数据来源和测试数据;API 文档只能证明调用方式,不能证明当前业务数据源存在。`; } export function integrationWriteBlockedReason(path: string, missing: string[]): string { return `不能写生产源码 ${path}:第三方对接上下文不完整,缺失:${missing.join("、") || "未知"}。下一步:使用 kd_ask_user 询问当前第三方对接事实组,记录后重新刷新门禁。`; } export function implementationWriteBlockedReason(path: string, missing: string[]): string { return `不能写生产源码 ${path}:实现就绪信息不完整,缺失:${missing.join("、") || "未知"}。下一步:使用 kd_ask_user 询问当前实现契约事实组,记录后重新刷新门禁;信息不足时禁止生成模板代码。`; } function nextQuestionInstruction(missing: string[]): string | undefined { const question = questionForMissingLabel(missing[0]); if (!question) return undefined; return `提问工具:kd_ask_user questions=[{ header:"${missing[0]}", factLabel:"${missing[0]}", question:"${question}", reason:"${missing[0]} 缺失会阻塞实现。", contextSummary:"<已读取文件逻辑、当前结论和恢复继续点>", sourceRefs:["<来源文件或证据>"] }]。`; } function missingSummary(scope: string, missing: string[]): string { const first = missing[0] ?? "未知"; const remaining = Math.max(0, missing.length - 1); const remainingText = remaining > 0 ? `;另有 ${remaining} 项同组缺失` : ""; return `不能进入 execute:${scope}不完整,当前缺失:${first}${remainingText}。`; }