@zhuan-ai/zhuanspec 1.3.0

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.
Files changed (210) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +461 -0
  3. package/README.zh.md +434 -0
  4. package/bin/zhuanspec.js +3 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.js +356 -0
  7. package/dist/commands/artifact-workflow.d.ts +13 -0
  8. package/dist/commands/artifact-workflow.js +916 -0
  9. package/dist/commands/change.d.ts +35 -0
  10. package/dist/commands/change.js +277 -0
  11. package/dist/commands/completion.d.ts +72 -0
  12. package/dist/commands/completion.js +221 -0
  13. package/dist/commands/config.d.ts +8 -0
  14. package/dist/commands/config.js +198 -0
  15. package/dist/commands/show.d.ts +14 -0
  16. package/dist/commands/show.js +132 -0
  17. package/dist/commands/spec.d.ts +15 -0
  18. package/dist/commands/spec.js +225 -0
  19. package/dist/commands/validate.d.ts +24 -0
  20. package/dist/commands/validate.js +294 -0
  21. package/dist/core/archive.d.ts +30 -0
  22. package/dist/core/archive.js +438 -0
  23. package/dist/core/artifact-graph/graph.d.ts +56 -0
  24. package/dist/core/artifact-graph/graph.js +141 -0
  25. package/dist/core/artifact-graph/index.d.ts +7 -0
  26. package/dist/core/artifact-graph/index.js +13 -0
  27. package/dist/core/artifact-graph/instruction-loader.d.ts +134 -0
  28. package/dist/core/artifact-graph/instruction-loader.js +180 -0
  29. package/dist/core/artifact-graph/resolver.d.ts +61 -0
  30. package/dist/core/artifact-graph/resolver.js +187 -0
  31. package/dist/core/artifact-graph/schema.d.ts +13 -0
  32. package/dist/core/artifact-graph/schema.js +108 -0
  33. package/dist/core/artifact-graph/state.d.ts +12 -0
  34. package/dist/core/artifact-graph/state.js +54 -0
  35. package/dist/core/artifact-graph/types.d.ts +45 -0
  36. package/dist/core/artifact-graph/types.js +43 -0
  37. package/dist/core/completions/command-registry.d.ts +7 -0
  38. package/dist/core/completions/command-registry.js +362 -0
  39. package/dist/core/completions/completion-provider.d.ts +60 -0
  40. package/dist/core/completions/completion-provider.js +102 -0
  41. package/dist/core/completions/factory.d.ts +51 -0
  42. package/dist/core/completions/factory.js +57 -0
  43. package/dist/core/completions/generators/zsh-generator.d.ts +58 -0
  44. package/dist/core/completions/generators/zsh-generator.js +319 -0
  45. package/dist/core/completions/installers/zsh-installer.d.ts +136 -0
  46. package/dist/core/completions/installers/zsh-installer.js +449 -0
  47. package/dist/core/completions/types.d.ts +78 -0
  48. package/dist/core/completions/types.js +2 -0
  49. package/dist/core/config-schema.d.ts +76 -0
  50. package/dist/core/config-schema.js +200 -0
  51. package/dist/core/config.d.ts +16 -0
  52. package/dist/core/config.js +29 -0
  53. package/dist/core/configurators/agents.d.ts +8 -0
  54. package/dist/core/configurators/agents.js +15 -0
  55. package/dist/core/configurators/base.d.ts +7 -0
  56. package/dist/core/configurators/base.js +2 -0
  57. package/dist/core/configurators/claude.d.ts +8 -0
  58. package/dist/core/configurators/claude.js +15 -0
  59. package/dist/core/configurators/cline.d.ts +8 -0
  60. package/dist/core/configurators/cline.js +15 -0
  61. package/dist/core/configurators/codebuddy.d.ts +8 -0
  62. package/dist/core/configurators/codebuddy.js +15 -0
  63. package/dist/core/configurators/costrict.d.ts +8 -0
  64. package/dist/core/configurators/costrict.js +15 -0
  65. package/dist/core/configurators/iflow.d.ts +8 -0
  66. package/dist/core/configurators/iflow.js +15 -0
  67. package/dist/core/configurators/qoder.d.ts +30 -0
  68. package/dist/core/configurators/qoder.js +42 -0
  69. package/dist/core/configurators/qwen.d.ts +24 -0
  70. package/dist/core/configurators/qwen.js +37 -0
  71. package/dist/core/configurators/registry.d.ts +9 -0
  72. package/dist/core/configurators/registry.js +43 -0
  73. package/dist/core/configurators/slash/amazon-q.d.ts +9 -0
  74. package/dist/core/configurators/slash/amazon-q.js +46 -0
  75. package/dist/core/configurators/slash/antigravity.d.ts +9 -0
  76. package/dist/core/configurators/slash/antigravity.js +23 -0
  77. package/dist/core/configurators/slash/auggie.d.ts +9 -0
  78. package/dist/core/configurators/slash/auggie.js +31 -0
  79. package/dist/core/configurators/slash/base.d.ts +19 -0
  80. package/dist/core/configurators/slash/base.js +69 -0
  81. package/dist/core/configurators/slash/claude.d.ts +9 -0
  82. package/dist/core/configurators/slash/claude.js +37 -0
  83. package/dist/core/configurators/slash/cline.d.ts +9 -0
  84. package/dist/core/configurators/slash/cline.js +23 -0
  85. package/dist/core/configurators/slash/codebuddy.d.ts +9 -0
  86. package/dist/core/configurators/slash/codebuddy.js +37 -0
  87. package/dist/core/configurators/slash/codex.d.ts +14 -0
  88. package/dist/core/configurators/slash/codex.js +109 -0
  89. package/dist/core/configurators/slash/costrict.d.ts +9 -0
  90. package/dist/core/configurators/slash/costrict.js +31 -0
  91. package/dist/core/configurators/slash/crush.d.ts +9 -0
  92. package/dist/core/configurators/slash/crush.js +37 -0
  93. package/dist/core/configurators/slash/cursor.d.ts +9 -0
  94. package/dist/core/configurators/slash/cursor.js +37 -0
  95. package/dist/core/configurators/slash/factory.d.ts +10 -0
  96. package/dist/core/configurators/slash/factory.js +35 -0
  97. package/dist/core/configurators/slash/gemini.d.ts +9 -0
  98. package/dist/core/configurators/slash/gemini.js +22 -0
  99. package/dist/core/configurators/slash/github-copilot.d.ts +9 -0
  100. package/dist/core/configurators/slash/github-copilot.js +34 -0
  101. package/dist/core/configurators/slash/iflow.d.ts +9 -0
  102. package/dist/core/configurators/slash/iflow.js +37 -0
  103. package/dist/core/configurators/slash/kilocode.d.ts +9 -0
  104. package/dist/core/configurators/slash/kilocode.js +17 -0
  105. package/dist/core/configurators/slash/opencode.d.ts +12 -0
  106. package/dist/core/configurators/slash/opencode.js +72 -0
  107. package/dist/core/configurators/slash/qoder.d.ts +35 -0
  108. package/dist/core/configurators/slash/qoder.js +76 -0
  109. package/dist/core/configurators/slash/qwen.d.ts +32 -0
  110. package/dist/core/configurators/slash/qwen.js +49 -0
  111. package/dist/core/configurators/slash/registry.d.ts +8 -0
  112. package/dist/core/configurators/slash/registry.js +75 -0
  113. package/dist/core/configurators/slash/roocode.d.ts +9 -0
  114. package/dist/core/configurators/slash/roocode.js +23 -0
  115. package/dist/core/configurators/slash/toml-base.d.ts +10 -0
  116. package/dist/core/configurators/slash/toml-base.js +53 -0
  117. package/dist/core/configurators/slash/windsurf.d.ts +9 -0
  118. package/dist/core/configurators/slash/windsurf.js +23 -0
  119. package/dist/core/converters/json-converter.d.ts +6 -0
  120. package/dist/core/converters/json-converter.js +51 -0
  121. package/dist/core/global-config.d.ts +39 -0
  122. package/dist/core/global-config.js +115 -0
  123. package/dist/core/index.d.ts +2 -0
  124. package/dist/core/index.js +3 -0
  125. package/dist/core/init.d.ts +60 -0
  126. package/dist/core/init.js +861 -0
  127. package/dist/core/list.d.ts +9 -0
  128. package/dist/core/list.js +171 -0
  129. package/dist/core/parsers/change-parser.d.ts +13 -0
  130. package/dist/core/parsers/change-parser.js +193 -0
  131. package/dist/core/parsers/markdown-parser.d.ts +22 -0
  132. package/dist/core/parsers/markdown-parser.js +187 -0
  133. package/dist/core/parsers/requirement-blocks.d.ts +37 -0
  134. package/dist/core/parsers/requirement-blocks.js +201 -0
  135. package/dist/core/project-config.d.ts +34 -0
  136. package/dist/core/project-config.js +79 -0
  137. package/dist/core/schemas/base.schema.d.ts +13 -0
  138. package/dist/core/schemas/base.schema.js +13 -0
  139. package/dist/core/schemas/change.schema.d.ts +73 -0
  140. package/dist/core/schemas/change.schema.js +31 -0
  141. package/dist/core/schemas/index.d.ts +4 -0
  142. package/dist/core/schemas/index.js +4 -0
  143. package/dist/core/schemas/spec.schema.d.ts +18 -0
  144. package/dist/core/schemas/spec.schema.js +15 -0
  145. package/dist/core/skill-discovery.d.ts +24 -0
  146. package/dist/core/skill-discovery.js +153 -0
  147. package/dist/core/specs-apply.d.ts +73 -0
  148. package/dist/core/specs-apply.js +384 -0
  149. package/dist/core/styles/palette.d.ts +7 -0
  150. package/dist/core/styles/palette.js +8 -0
  151. package/dist/core/templates/agents-root-stub.d.ts +2 -0
  152. package/dist/core/templates/agents-root-stub.js +17 -0
  153. package/dist/core/templates/agents-template.d.ts +2 -0
  154. package/dist/core/templates/agents-template.js +706 -0
  155. package/dist/core/templates/claude-template.d.ts +2 -0
  156. package/dist/core/templates/claude-template.js +2 -0
  157. package/dist/core/templates/cline-template.d.ts +2 -0
  158. package/dist/core/templates/cline-template.js +2 -0
  159. package/dist/core/templates/costrict-template.d.ts +2 -0
  160. package/dist/core/templates/costrict-template.js +2 -0
  161. package/dist/core/templates/index.d.ts +17 -0
  162. package/dist/core/templates/index.js +37 -0
  163. package/dist/core/templates/project-template.d.ts +8 -0
  164. package/dist/core/templates/project-template.js +32 -0
  165. package/dist/core/templates/skill-templates.d.ts +103 -0
  166. package/dist/core/templates/skill-templates.js +2131 -0
  167. package/dist/core/templates/slash-command-templates.d.ts +4 -0
  168. package/dist/core/templates/slash-command-templates.js +81 -0
  169. package/dist/core/update.d.ts +4 -0
  170. package/dist/core/update.js +88 -0
  171. package/dist/core/validation/constants.d.ts +34 -0
  172. package/dist/core/validation/constants.js +40 -0
  173. package/dist/core/validation/types.d.ts +18 -0
  174. package/dist/core/validation/types.js +2 -0
  175. package/dist/core/validation/validator.d.ts +33 -0
  176. package/dist/core/validation/validator.js +409 -0
  177. package/dist/core/view.d.ts +8 -0
  178. package/dist/core/view.js +168 -0
  179. package/dist/index.d.ts +3 -0
  180. package/dist/index.js +3 -0
  181. package/dist/utils/change-metadata.d.ts +47 -0
  182. package/dist/utils/change-metadata.js +130 -0
  183. package/dist/utils/change-utils.d.ts +51 -0
  184. package/dist/utils/change-utils.js +100 -0
  185. package/dist/utils/file-system.d.ts +19 -0
  186. package/dist/utils/file-system.js +177 -0
  187. package/dist/utils/index.d.ts +4 -0
  188. package/dist/utils/index.js +5 -0
  189. package/dist/utils/interactive.d.ts +18 -0
  190. package/dist/utils/interactive.js +21 -0
  191. package/dist/utils/item-discovery.d.ts +4 -0
  192. package/dist/utils/item-discovery.js +72 -0
  193. package/dist/utils/match.d.ts +3 -0
  194. package/dist/utils/match.js +22 -0
  195. package/dist/utils/shell-detection.d.ts +20 -0
  196. package/dist/utils/shell-detection.js +41 -0
  197. package/dist/utils/task-progress.d.ts +8 -0
  198. package/dist/utils/task-progress.js +36 -0
  199. package/package.json +81 -0
  200. package/schemas/spec-driven/schema.yaml +205 -0
  201. package/schemas/spec-driven/templates/design.md +19 -0
  202. package/schemas/spec-driven/templates/proposal.md +43 -0
  203. package/schemas/spec-driven/templates/spec.md +8 -0
  204. package/schemas/spec-driven/templates/tasks.md +25 -0
  205. package/schemas/tdd/schema.yaml +213 -0
  206. package/schemas/tdd/templates/docs.md +0 -0
  207. package/schemas/tdd/templates/implementation.md +11 -0
  208. package/schemas/tdd/templates/spec.md +11 -0
  209. package/schemas/tdd/templates/test.md +11 -0
  210. package/scripts/postinstall.js +147 -0
@@ -0,0 +1,4 @@
1
+ export type SlashCommandId = 'proposal' | 'apply' | 'archive';
2
+ export declare const slashCommandBodies: Record<SlashCommandId, string>;
3
+ export declare function getSlashCommandBody(id: SlashCommandId): string;
4
+ //# sourceMappingURL=slash-command-templates.d.ts.map
@@ -0,0 +1,81 @@
1
+ const baseGuardrails = `**约束条件**
2
+ - 优先采用简单、最小化的实现,仅在请求或明确需要时添加复杂性。
3
+ - 将更改严格限制在请求的结果范围内。
4
+ - 如果需要额外的 ZhuanSpec 约定或澄清,请参考 \`zhuanspec/AGENTS.md\`(位于 \`zhuanspec/\` 目录内 - 如果看不到,请运行 \`ls zhuanspec\` 或 \`zhuanspec update\`)。`;
5
+ const proposalGuardrails = `${baseGuardrails}\n- **强制澄清要求**:在创建任何提案文件之前,必须首先分析用户请求,识别所有不确定或模糊的方面(范围、技术选择、优先级、验收标准等)。如果发现任何模糊之处,必须停止并使用**选项式交互**(如 \`AskQuestion\` 工具)提问,获得明确答复后才能继续。严禁在不确定的情况下自行推测、假设或创建提案。严禁要求用户手动输入大段文字来回答澄清问题。
6
+ - 识别任何模糊或歧义的细节,使用带预设选项的选择题在编辑文件之前询问必要的后续问题。
7
+ - 在提案阶段不要编写任何代码。仅创建设计文档(proposal.md、tasks.md、design.md 和规范增量)。实施在批准后的应用阶段进行。`;
8
+ const proposalSteps = `**步骤**
9
+ 0. 审查 \`zhuanspec/project.md\`,运行 \`zhuanspec list\` 和 \`zhuanspec list --specs\`,并检查相关代码或文档(例如,通过 \`rg\`/\`ls\`)以将提案建立在当前行为基础上;注意任何需要澄清的空白。
10
+ 1. **强制澄清检查(必须首先执行,不可跳过)**:
11
+ - 仔细分析用户请求,识别所有不确定或模糊的方面:
12
+ * 范围是否明确?(边界、包含/排除的内容)
13
+ * 技术选择是否明确?(框架、库、架构模式)
14
+ * 优先级是否明确?(如果有多个需求)
15
+ * 验收标准是否明确?(如何判断完成)
16
+ * 上下文信息是否充分?(背景、约束、依赖)
17
+ * 实现细节是否明确?(如何获取数据、如何处理错误、如何优化性能)
18
+ * 数据获取来源是否明确?(从数据库、API、文件、外部服务、历史逻辑复用)
19
+ * 服务分层是否明确?(前端、后端、数据库、API、服务、4层架构、3层架构、2层架构、领域模型)
20
+ * 依赖关系是否明确?(依赖哪些服务、依赖哪些库、依赖哪些组件)
21
+ * 其他不明确?(其他不明确的情况)
22
+ - 如果发现任何模糊之处,必须停止并使用**选项式交互**提问:
23
+ * 使用编辑器的结构化问答工具(如 \`AskQuestion\`),将每个问题转化为带 2-5 个预设选项的选择题
24
+ * 每个问题末尾包含"其他"选项作为兜底
25
+ * 尽量将多个问题合并到一次交互中一次性展示
26
+ * 必须等待用户选择答案,不能继续
27
+ * **严禁**要求用户手动输入大段文字来回答
28
+ - 如果用户选择"其他",再针对该问题追问(仍优先使用选项式)
29
+ - **严禁**在不确定的情况下自行推测、假设或创建提案文件
30
+ - 只有在所有模糊点都明确后,才能继续后续步骤
31
+ 2. 选择一个唯一的动词开头的 \`change-id\`,并在 \`zhuanspec/changes/<id>/\` 下搭建 \`proposal.md\`、\`tasks.md\` 和 \`design.md\`(需要时)。
32
+ 3. 将变更映射为具体的功能或要求,将多范围的工作分解为具有明确关系和顺序的不同规范增量。
33
+ 4. 当解决方案跨越多个系统、引入新模式或在提交规范之前需要权衡讨论时,在 \`design.md\` 中捕获架构推理。
34
+ 5. 在 \`changes/<id>/specs/<capability>/spec.md\` 中起草规范增量(每个功能一个文件夹),使用 \`## ADDED|MODIFIED|REMOVED Requirements\`,每个要求至少包含一个 \`#### Scenario:\`,并在相关时交叉引用相关功能。
35
+ 6. **发现可用 Skill 并创建 tasks.md**:
36
+ - 运行 \`zhuanspec skills list --json\` 获取当前环境中可用的 skill 列表及其 description
37
+ - 在 \`proposal.md\` 的 **Skill Mapping** 段中基于 skill description 进行语义匹配:
38
+ - 仔细阅读每个 skill 的 description,理解其具体功能和适用场景
39
+ - 只有当实现区域的实际功能与 skill description 明确匹配时才关联
40
+ - 简单的代码修改(如枚举值增删)应匹配通用编码规范 skill,而非架构级 skill
41
+ - 避免仅因模块名称或文件路径中的关键词而错误匹配
42
+ - 在表格中说明匹配理由
43
+ - 将 \`tasks.md\` 起草为有序的小型、可验证工作项列表
44
+ - 使用 \`@skill:<real-skill-name>\` 标注与 skill 匹配的任务(支持多个:\`@skill:name1,name2\`)
45
+ - 仅当 skill 明确匹配任务时才标注,没有匹配的 skill 可省略标签
46
+ 7. 使用 \`zhuanspec validate <id> --strict\` 进行验证,并在分享提案之前解决所有问题。`;
47
+ const proposalReferences = `**参考**
48
+ - 当验证失败时,使用 \`zhuanspec show <id> --json --deltas-only\` 或 \`zhuanspec show <spec> --type spec\` 检查详细信息。
49
+ - 在编写新要求之前,使用 \`rg -n "Requirement:|Scenario:" zhuanspec/specs\` 搜索现有要求。
50
+ - 使用 \`rg <keyword>\`、\`ls\` 或直接文件读取探索代码库,以便提案与当前实现现实保持一致。`;
51
+ const applySteps = `**步骤**
52
+ 将这些步骤作为待办事项跟踪,逐一完成。
53
+ 1. 阅读 \`changes/<id>/proposal.md\`、\`design.md\`(如果存在)和 \`tasks.md\` 以确认范围和验收标准。
54
+ 2. 按顺序处理任务,保持编辑最小化并专注于请求的变更。如果任务标注了 \`@skill:<skill-name>\`,直接调用对应 skill 获取指导后再实施。
55
+ 3. 在更新状态之前确认完成 - 确保 \`tasks.md\` 中的每个项目都已完成。
56
+ 4. 所有工作完成后更新清单,以便每个任务都标记为 \`- [x]\` 并反映实际情况。
57
+ 5. 需要额外上下文时,参考 \`zhuanspec list\` 或 \`zhuanspec show <item>\`。`;
58
+ const applyReferences = `**参考**
59
+ - 如果在实施过程中需要提案的额外上下文,请使用 \`zhuanspec show <id> --json --deltas-only\`。`;
60
+ const archiveSteps = `**步骤**
61
+ 1. 确定要归档的变更 ID:
62
+ - 如果此提示已包含特定的变更 ID(例如在由斜杠命令参数填充的 \`<ChangeId>\` 块内),请在修剪空白后使用该值。
63
+ - 如果对话中松散地引用了变更(例如通过标题或摘要),运行 \`zhuanspec list\` 以显示可能的 ID,分享相关候选,并确认用户意图是哪一个。
64
+ - 否则,审查对话,运行 \`zhuanspec list\`,并询问用户要归档哪个变更;在继续之前等待确认的变更 ID。
65
+ - 如果您仍然无法识别单个变更 ID,请停止并告诉用户您还无法归档任何内容。
66
+ 2. 通过运行 \`zhuanspec list\`(或 \`zhuanspec show <id>\`)验证变更 ID,如果变更缺失、已归档或尚未准备好归档,则停止。
67
+ 3. 运行 \`zhuanspec archive <id> --yes\`,以便 CLI 移动变更并应用规范更新,无需提示(仅对仅工具类工作使用 \`--skip-specs\`)。
68
+ 4. 审查命令输出以确认目标规范已更新,并且变更已进入 \`changes/archive/\`。
69
+ 5. 使用 \`zhuanspec validate --strict\` 进行验证,如果看起来有问题,使用 \`zhuanspec show <id>\` 进行检查。`;
70
+ const archiveReferences = `**参考**
71
+ - 在归档之前使用 \`zhuanspec list\` 确认变更 ID。
72
+ - 使用 \`zhuanspec list --specs\` 检查刷新的规范,并在移交之前解决任何验证问题。`;
73
+ export const slashCommandBodies = {
74
+ proposal: [proposalGuardrails, proposalSteps, proposalReferences].join('\n\n'),
75
+ apply: [baseGuardrails, applySteps, applyReferences].join('\n\n'),
76
+ archive: [baseGuardrails, archiveSteps, archiveReferences].join('\n\n')
77
+ };
78
+ export function getSlashCommandBody(id) {
79
+ return slashCommandBodies[id];
80
+ }
81
+ //# sourceMappingURL=slash-command-templates.js.map
@@ -0,0 +1,4 @@
1
+ export declare class UpdateCommand {
2
+ execute(projectPath: string): Promise<void>;
3
+ }
4
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1,88 @@
1
+ import path from 'path';
2
+ import { FileSystemUtils } from '../utils/file-system.js';
3
+ import { ZHUANSPEC_DIR_NAME } from './config.js';
4
+ import { ToolRegistry } from './configurators/registry.js';
5
+ import { SlashCommandRegistry } from './configurators/slash/registry.js';
6
+ import { agentsTemplate } from './templates/agents-template.js';
7
+ export class UpdateCommand {
8
+ async execute(projectPath) {
9
+ const resolvedProjectPath = path.resolve(projectPath);
10
+ const zhuanspecDirName = ZHUANSPEC_DIR_NAME;
11
+ const zhuanspecPath = path.join(resolvedProjectPath, zhuanspecDirName);
12
+ // 1. Check zhuanspec directory exists
13
+ if (!await FileSystemUtils.directoryExists(zhuanspecPath)) {
14
+ throw new Error(`未找到 ZhuanSpec 目录。请先运行 'zhuanspec init'。`);
15
+ }
16
+ // 2. Update AGENTS.md (full replacement)
17
+ const agentsPath = path.join(zhuanspecPath, 'AGENTS.md');
18
+ await FileSystemUtils.writeFile(agentsPath, agentsTemplate);
19
+ // 3. Update existing AI tool configuration files only
20
+ const configurators = ToolRegistry.getAll();
21
+ const slashConfigurators = SlashCommandRegistry.getAll();
22
+ const updatedFiles = [];
23
+ const createdFiles = [];
24
+ const failedFiles = [];
25
+ const updatedSlashFiles = [];
26
+ const failedSlashTools = [];
27
+ for (const configurator of configurators) {
28
+ const configFilePath = path.join(resolvedProjectPath, configurator.configFileName);
29
+ const fileExists = await FileSystemUtils.fileExists(configFilePath);
30
+ const shouldConfigure = fileExists || configurator.configFileName === 'AGENTS.md';
31
+ if (!shouldConfigure) {
32
+ continue;
33
+ }
34
+ try {
35
+ if (fileExists && !await FileSystemUtils.canWriteFile(configFilePath)) {
36
+ throw new Error(`权限不足,无法修改 ${configurator.configFileName}`);
37
+ }
38
+ await configurator.configure(resolvedProjectPath, zhuanspecPath);
39
+ updatedFiles.push(configurator.configFileName);
40
+ if (!fileExists) {
41
+ createdFiles.push(configurator.configFileName);
42
+ }
43
+ }
44
+ catch (error) {
45
+ failedFiles.push(configurator.configFileName);
46
+ console.error(`更新 ${configurator.configFileName} 失败:${error instanceof Error ? error.message : String(error)}`);
47
+ }
48
+ }
49
+ for (const slashConfigurator of slashConfigurators) {
50
+ if (!slashConfigurator.isAvailable) {
51
+ continue;
52
+ }
53
+ try {
54
+ const updated = await slashConfigurator.updateExisting(resolvedProjectPath, zhuanspecPath);
55
+ updatedSlashFiles.push(...updated);
56
+ }
57
+ catch (error) {
58
+ failedSlashTools.push(slashConfigurator.toolId);
59
+ console.error(`更新 ${slashConfigurator.toolId} 的斜杠命令失败:${error instanceof Error ? error.message : String(error)}`);
60
+ }
61
+ }
62
+ const summaryParts = [];
63
+ const instructionFiles = ['zhuanspec/AGENTS.md'];
64
+ if (updatedFiles.includes('AGENTS.md')) {
65
+ instructionFiles.push(createdFiles.includes('AGENTS.md') ? 'AGENTS.md (created)' : 'AGENTS.md');
66
+ }
67
+ summaryParts.push(`已更新 ZhuanSpec 说明(${instructionFiles.join(', ')})`);
68
+ const aiToolFiles = updatedFiles.filter((file) => file !== 'AGENTS.md');
69
+ if (aiToolFiles.length > 0) {
70
+ summaryParts.push(`已更新 AI 工具文件:${aiToolFiles.join(', ')}`);
71
+ }
72
+ if (updatedSlashFiles.length > 0) {
73
+ // Normalize to forward slashes for cross-platform log consistency
74
+ const normalized = updatedSlashFiles.map((p) => FileSystemUtils.toPosixPath(p));
75
+ summaryParts.push(`已更新斜杠命令:${normalized.join(', ')}`);
76
+ }
77
+ const failedItems = [
78
+ ...failedFiles,
79
+ ...failedSlashTools.map((toolId) => `斜杠命令刷新(${toolId})`),
80
+ ];
81
+ if (failedItems.length > 0) {
82
+ summaryParts.push(`更新失败:${failedItems.join(', ')}`);
83
+ }
84
+ console.log(summaryParts.join(' | '));
85
+ // No additional notes
86
+ }
87
+ }
88
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Validation threshold constants
3
+ */
4
+ export declare const MIN_WHY_SECTION_LENGTH = 50;
5
+ export declare const MIN_PURPOSE_LENGTH = 50;
6
+ export declare const MAX_WHY_SECTION_LENGTH = 1000;
7
+ export declare const MAX_REQUIREMENT_TEXT_LENGTH = 500;
8
+ export declare const MAX_DELTAS_PER_CHANGE = 10;
9
+ export declare const VALIDATION_MESSAGES: {
10
+ readonly SCENARIO_EMPTY: "Scenario text cannot be empty";
11
+ readonly REQUIREMENT_EMPTY: "Requirement text cannot be empty";
12
+ readonly REQUIREMENT_NO_SHALL: "Requirement must contain SHALL or MUST keyword";
13
+ readonly REQUIREMENT_NO_SCENARIOS: "Requirement must have at least one scenario";
14
+ readonly SPEC_NAME_EMPTY: "Spec name cannot be empty";
15
+ readonly SPEC_PURPOSE_EMPTY: "Purpose section cannot be empty";
16
+ readonly SPEC_NO_REQUIREMENTS: "Spec must have at least one requirement";
17
+ readonly CHANGE_NAME_EMPTY: "Change name cannot be empty";
18
+ readonly CHANGE_WHY_TOO_SHORT: "Why section must be at least 50 characters";
19
+ readonly CHANGE_WHY_TOO_LONG: "Why section should not exceed 1000 characters";
20
+ readonly CHANGE_WHAT_EMPTY: "What Changes section cannot be empty";
21
+ readonly CHANGE_NO_DELTAS: "Change must have at least one delta";
22
+ readonly CHANGE_TOO_MANY_DELTAS: "Consider splitting changes with more than 10 deltas";
23
+ readonly DELTA_SPEC_EMPTY: "Spec name cannot be empty";
24
+ readonly DELTA_DESCRIPTION_EMPTY: "Delta description cannot be empty";
25
+ readonly PURPOSE_TOO_BRIEF: "Purpose section is too brief (less than 50 characters)";
26
+ readonly REQUIREMENT_TOO_LONG: "Requirement text is very long (>500 characters). Consider breaking it down.";
27
+ readonly DELTA_DESCRIPTION_TOO_BRIEF: "Delta description is too brief";
28
+ readonly DELTA_MISSING_REQUIREMENTS: "Delta should include requirements";
29
+ readonly GUIDE_NO_DELTAS: "No deltas found. Ensure your change has a specs/ directory with capability folders (e.g. specs/http-server/spec.md) containing .md files that use delta headers (## ADDED/MODIFIED/REMOVED/RENAMED Requirements) and that each requirement includes at least one \"#### Scenario:\" block. Tip: run \"zhuanspec change show <change-id> --json --deltas-only\" to inspect parsed deltas.";
30
+ readonly GUIDE_MISSING_SPEC_SECTIONS: "Missing required sections. Expected headers: \"## Purpose\" and \"## Requirements\". Example:\n## Purpose\n[brief purpose]\n\n## Requirements\n### Requirement: Clear requirement statement\nUsers SHALL ...\n\n#### Scenario: Descriptive name\n- **WHEN** ...\n- **THEN** ...";
31
+ readonly GUIDE_MISSING_CHANGE_SECTIONS: "Missing required sections. Expected headers: \"## Why\" and \"## What Changes\". Ensure deltas are documented in specs/ using delta headers.";
32
+ readonly GUIDE_SCENARIO_FORMAT: "Scenarios must use level-4 headers. Convert bullet lists into:\n#### Scenario: Short name\n- **WHEN** ...\n- **THEN** ...\n- **AND** ...";
33
+ };
34
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Validation threshold constants
3
+ */
4
+ // Minimum character lengths
5
+ export const MIN_WHY_SECTION_LENGTH = 50;
6
+ export const MIN_PURPOSE_LENGTH = 50;
7
+ // Maximum character/item limits
8
+ export const MAX_WHY_SECTION_LENGTH = 1000;
9
+ export const MAX_REQUIREMENT_TEXT_LENGTH = 500;
10
+ export const MAX_DELTAS_PER_CHANGE = 10;
11
+ // Validation messages
12
+ export const VALIDATION_MESSAGES = {
13
+ // Required content
14
+ SCENARIO_EMPTY: 'Scenario text cannot be empty',
15
+ REQUIREMENT_EMPTY: 'Requirement text cannot be empty',
16
+ REQUIREMENT_NO_SHALL: 'Requirement must contain SHALL or MUST keyword',
17
+ REQUIREMENT_NO_SCENARIOS: 'Requirement must have at least one scenario',
18
+ SPEC_NAME_EMPTY: 'Spec name cannot be empty',
19
+ SPEC_PURPOSE_EMPTY: 'Purpose section cannot be empty',
20
+ SPEC_NO_REQUIREMENTS: 'Spec must have at least one requirement',
21
+ CHANGE_NAME_EMPTY: 'Change name cannot be empty',
22
+ CHANGE_WHY_TOO_SHORT: `Why section must be at least ${MIN_WHY_SECTION_LENGTH} characters`,
23
+ CHANGE_WHY_TOO_LONG: `Why section should not exceed ${MAX_WHY_SECTION_LENGTH} characters`,
24
+ CHANGE_WHAT_EMPTY: 'What Changes section cannot be empty',
25
+ CHANGE_NO_DELTAS: 'Change must have at least one delta',
26
+ CHANGE_TOO_MANY_DELTAS: `Consider splitting changes with more than ${MAX_DELTAS_PER_CHANGE} deltas`,
27
+ DELTA_SPEC_EMPTY: 'Spec name cannot be empty',
28
+ DELTA_DESCRIPTION_EMPTY: 'Delta description cannot be empty',
29
+ // Warnings
30
+ PURPOSE_TOO_BRIEF: `Purpose section is too brief (less than ${MIN_PURPOSE_LENGTH} characters)`,
31
+ REQUIREMENT_TOO_LONG: `Requirement text is very long (>${MAX_REQUIREMENT_TEXT_LENGTH} characters). Consider breaking it down.`,
32
+ DELTA_DESCRIPTION_TOO_BRIEF: 'Delta description is too brief',
33
+ DELTA_MISSING_REQUIREMENTS: 'Delta should include requirements',
34
+ // Guidance snippets (appended to primary messages for remediation)
35
+ GUIDE_NO_DELTAS: 'No deltas found. Ensure your change has a specs/ directory with capability folders (e.g. specs/http-server/spec.md) containing .md files that use delta headers (## ADDED/MODIFIED/REMOVED/RENAMED Requirements) and that each requirement includes at least one "#### Scenario:" block. Tip: run "zhuanspec change show <change-id> --json --deltas-only" to inspect parsed deltas.',
36
+ GUIDE_MISSING_SPEC_SECTIONS: 'Missing required sections. Expected headers: "## Purpose" and "## Requirements". Example:\n## Purpose\n[brief purpose]\n\n## Requirements\n### Requirement: Clear requirement statement\nUsers SHALL ...\n\n#### Scenario: Descriptive name\n- **WHEN** ...\n- **THEN** ...',
37
+ GUIDE_MISSING_CHANGE_SECTIONS: 'Missing required sections. Expected headers: "## Why" and "## What Changes". Ensure deltas are documented in specs/ using delta headers.',
38
+ GUIDE_SCENARIO_FORMAT: 'Scenarios must use level-4 headers. Convert bullet lists into:\n#### Scenario: Short name\n- **WHEN** ...\n- **THEN** ...\n- **AND** ...',
39
+ };
40
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1,18 @@
1
+ export type ValidationLevel = 'ERROR' | 'WARNING' | 'INFO';
2
+ export interface ValidationIssue {
3
+ level: ValidationLevel;
4
+ path: string;
5
+ message: string;
6
+ line?: number;
7
+ column?: number;
8
+ }
9
+ export interface ValidationReport {
10
+ valid: boolean;
11
+ issues: ValidationIssue[];
12
+ summary: {
13
+ errors: number;
14
+ warnings: number;
15
+ info: number;
16
+ };
17
+ }
18
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,33 @@
1
+ import { ValidationReport } from './types.js';
2
+ export declare class Validator {
3
+ private strictMode;
4
+ constructor(strictMode?: boolean);
5
+ validateSpec(filePath: string): Promise<ValidationReport>;
6
+ /**
7
+ * Validate spec content from a string (used for pre-write validation of rebuilt specs)
8
+ */
9
+ validateSpecContent(specName: string, content: string): Promise<ValidationReport>;
10
+ validateChange(filePath: string): Promise<ValidationReport>;
11
+ /**
12
+ * Validate delta-formatted spec files under a change directory.
13
+ * Enforces:
14
+ * - At least one delta across all files
15
+ * - ADDED/MODIFIED: each requirement has SHALL/MUST and at least one scenario
16
+ * - REMOVED: names only; no scenario/description required
17
+ * - RENAMED: pairs well-formed
18
+ * - No duplicates within sections; no cross-section conflicts per spec
19
+ */
20
+ validateChangeDeltaSpecs(changeDir: string): Promise<ValidationReport>;
21
+ private convertZodErrors;
22
+ private applySpecRules;
23
+ private applyChangeRules;
24
+ private enrichTopLevelError;
25
+ private extractNameFromPath;
26
+ private createReport;
27
+ isValid(report: ValidationReport): boolean;
28
+ private extractRequirementText;
29
+ private containsShallOrMust;
30
+ private countScenarios;
31
+ private formatSectionList;
32
+ }
33
+ //# sourceMappingURL=validator.d.ts.map