@zhuan-ai/zhuanspec 1.3.0 → 2.0.0-newApply

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 (188) hide show
  1. package/README.zh.md +1 -1
  2. package/bin/zhuanspec-hook.js +3 -0
  3. package/dist/cli/hooks.d.ts +26 -0
  4. package/dist/cli/hooks.js +558 -0
  5. package/dist/cli/index.js +296 -2
  6. package/dist/commands/accuracy.d.ts +15 -0
  7. package/dist/commands/accuracy.js +159 -0
  8. package/dist/commands/artifact-workflow.js +35 -36
  9. package/dist/commands/change.js +9 -4
  10. package/dist/commands/design.d.ts +53 -0
  11. package/dist/commands/design.js +418 -0
  12. package/dist/commands/knowledge.d.ts +31 -0
  13. package/dist/commands/knowledge.js +354 -0
  14. package/dist/commands/progress.d.ts +137 -0
  15. package/dist/commands/progress.js +893 -0
  16. package/dist/commands/review.d.ts +8 -0
  17. package/dist/commands/review.js +154 -0
  18. package/dist/commands/spec.js +12 -4
  19. package/dist/commands/validate-reports.d.ts +17 -0
  20. package/dist/commands/validate-reports.js +76 -0
  21. package/dist/commands/validate.d.ts +24 -0
  22. package/dist/commands/validate.js +306 -12
  23. package/dist/core/archive.d.ts +23 -12
  24. package/dist/core/archive.js +331 -7
  25. package/dist/core/artifact-graph/instruction-loader.d.ts +3 -1
  26. package/dist/core/artifact-graph/instruction-loader.js +27 -2
  27. package/dist/core/business-assets-sync.d.ts +94 -0
  28. package/dist/core/business-assets-sync.js +562 -0
  29. package/dist/core/completions/command-registry.js +66 -0
  30. package/dist/core/configurators/codex.d.ts +191 -0
  31. package/dist/core/configurators/codex.js +538 -0
  32. package/dist/core/configurators/registry.js +3 -0
  33. package/dist/core/configurators/slash/amazon-q.js +32 -2
  34. package/dist/core/configurators/slash/antigravity.js +8 -2
  35. package/dist/core/configurators/slash/auggie.js +16 -1
  36. package/dist/core/configurators/slash/base.js +1 -1
  37. package/dist/core/configurators/slash/claude.d.ts +4 -0
  38. package/dist/core/configurators/slash/claude.js +56 -1
  39. package/dist/core/configurators/slash/cline.js +8 -2
  40. package/dist/core/configurators/slash/codebuddy.js +22 -1
  41. package/dist/core/configurators/slash/codex.d.ts +39 -8
  42. package/dist/core/configurators/slash/codex.js +158 -91
  43. package/dist/core/configurators/slash/costrict.js +15 -0
  44. package/dist/core/configurators/slash/crush.js +22 -1
  45. package/dist/core/configurators/slash/cursor.js +22 -1
  46. package/dist/core/configurators/slash/factory.js +16 -1
  47. package/dist/core/configurators/slash/gemini.js +8 -2
  48. package/dist/core/configurators/slash/github-copilot.js +19 -1
  49. package/dist/core/configurators/slash/iflow.js +22 -1
  50. package/dist/core/configurators/slash/kilocode.js +4 -1
  51. package/dist/core/configurators/slash/opencode.js +27 -0
  52. package/dist/core/configurators/slash/qoder.d.ts +4 -0
  53. package/dist/core/configurators/slash/qoder.js +59 -1
  54. package/dist/core/configurators/slash/qwen.js +8 -2
  55. package/dist/core/configurators/slash/roocode.js +8 -2
  56. package/dist/core/configurators/slash/windsurf.js +8 -2
  57. package/dist/core/corrections/select-candidates.d.ts +58 -0
  58. package/dist/core/corrections/select-candidates.js +357 -0
  59. package/dist/core/dashboard/metrics.d.ts +42 -0
  60. package/dist/core/dashboard/metrics.js +126 -0
  61. package/dist/core/hooks/collect-knowledge.d.ts +24 -0
  62. package/dist/core/hooks/collect-knowledge.js +179 -0
  63. package/dist/core/hooks/context-load-hook.d.ts +25 -0
  64. package/dist/core/hooks/context-load-hook.js +161 -0
  65. package/dist/core/hooks/deviation-check.d.ts +62 -0
  66. package/dist/core/hooks/deviation-check.js +643 -0
  67. package/dist/core/hooks/deviation-handler.d.ts +44 -0
  68. package/dist/core/hooks/deviation-handler.js +151 -0
  69. package/dist/core/hooks/init.d.ts +14 -0
  70. package/dist/core/hooks/init.js +243 -0
  71. package/dist/core/hooks/knowledge-index.d.ts +136 -0
  72. package/dist/core/hooks/knowledge-index.js +506 -0
  73. package/dist/core/hooks/knowledge-references.d.ts +99 -0
  74. package/dist/core/hooks/knowledge-references.js +1659 -0
  75. package/dist/core/hooks/knowledge-usage.d.ts +90 -0
  76. package/dist/core/hooks/knowledge-usage.js +341 -0
  77. package/dist/core/hooks/notify-milestone.d.ts +14 -0
  78. package/dist/core/hooks/notify-milestone.js +196 -0
  79. package/dist/core/hooks/post-apply.d.ts +33 -0
  80. package/dist/core/hooks/post-apply.js +309 -0
  81. package/dist/core/hooks/post-archive.d.ts +7 -0
  82. package/dist/core/hooks/post-archive.js +312 -0
  83. package/dist/core/hooks/pre-apply.d.ts +34 -0
  84. package/dist/core/hooks/pre-apply.js +147 -0
  85. package/dist/core/hooks/pre-archive.d.ts +7 -0
  86. package/dist/core/hooks/pre-archive.js +49 -0
  87. package/dist/core/hooks/pre-review.d.ts +27 -0
  88. package/dist/core/hooks/pre-review.js +182 -0
  89. package/dist/core/hooks/record-progress.d.ts +418 -0
  90. package/dist/core/hooks/record-progress.js +1653 -0
  91. package/dist/core/hooks/review-hooks.d.ts +133 -0
  92. package/dist/core/hooks/review-hooks.js +852 -0
  93. package/dist/core/hooks/summarize.d.ts +15 -0
  94. package/dist/core/hooks/summarize.js +526 -0
  95. package/dist/core/hooks/tdd-phase-hook.d.ts +59 -0
  96. package/dist/core/hooks/tdd-phase-hook.js +313 -0
  97. package/dist/core/hooks/user-input-hook.d.ts +73 -0
  98. package/dist/core/hooks/user-input-hook.js +547 -0
  99. package/dist/core/init.d.ts +55 -0
  100. package/dist/core/init.js +1065 -43
  101. package/dist/core/metrics/code-accuracy.d.ts +317 -0
  102. package/dist/core/metrics/code-accuracy.js +716 -0
  103. package/dist/core/metrics/knowledge-funnel.d.ts +51 -0
  104. package/dist/core/metrics/knowledge-funnel.js +144 -0
  105. package/dist/core/parsers/requirement-blocks.js +13 -10
  106. package/dist/core/skill-discovery.d.ts +2 -2
  107. package/dist/core/skill-discovery.js +16 -3
  108. package/dist/core/specs-apply.js +19 -8
  109. package/dist/core/styles/palette.d.ts +1 -0
  110. package/dist/core/styles/palette.js +3 -1
  111. package/dist/core/task-graph/execution-planner.d.ts +38 -0
  112. package/dist/core/task-graph/execution-planner.js +237 -0
  113. package/dist/core/task-graph/index.d.ts +13 -0
  114. package/dist/core/task-graph/index.js +16 -0
  115. package/dist/core/task-graph/integration-report-template.d.ts +30 -0
  116. package/dist/core/task-graph/integration-report-template.js +210 -0
  117. package/dist/core/task-graph/mermaid-renderer.d.ts +22 -0
  118. package/dist/core/task-graph/mermaid-renderer.js +128 -0
  119. package/dist/core/task-graph/task-graph.d.ts +74 -0
  120. package/dist/core/task-graph/task-graph.js +219 -0
  121. package/dist/core/task-graph/task-parser.d.ts +27 -0
  122. package/dist/core/task-graph/task-parser.js +168 -0
  123. package/dist/core/task-graph/types.d.ts +139 -0
  124. package/dist/core/task-graph/types.js +7 -0
  125. package/dist/core/task-graph/xml-renderer.d.ts +21 -0
  126. package/dist/core/task-graph/xml-renderer.js +139 -0
  127. package/dist/core/templates/agents-root-stub.d.ts +1 -1
  128. package/dist/core/templates/agents-root-stub.js +29 -0
  129. package/dist/core/templates/agents-template.d.ts +1 -1
  130. package/dist/core/templates/agents-template.js +830 -269
  131. package/dist/core/templates/codex-agents-template.d.ts +53 -0
  132. package/dist/core/templates/codex-agents-template.js +177 -0
  133. package/dist/core/templates/codex-hooks-template.d.ts +116 -0
  134. package/dist/core/templates/codex-hooks-template.js +233 -0
  135. package/dist/core/templates/codex-skills-template.d.ts +39 -0
  136. package/dist/core/templates/codex-skills-template.js +69 -0
  137. package/dist/core/templates/index.d.ts +1 -0
  138. package/dist/core/templates/index.js +1 -0
  139. package/dist/core/templates/skill-templates.js +83 -163
  140. package/dist/core/templates/slash-command-templates.d.ts +1 -1
  141. package/dist/core/templates/slash-command-templates.js +1274 -28
  142. package/dist/core/templates/tasks-template.d.ts +23 -0
  143. package/dist/core/templates/tasks-template.js +285 -0
  144. package/dist/core/templates/tdd-tasks-template.d.ts +21 -0
  145. package/dist/core/templates/tdd-tasks-template.js +259 -0
  146. package/dist/core/templates/test-cases-template.d.ts +48 -0
  147. package/dist/core/templates/test-cases-template.js +135 -0
  148. package/dist/core/update.d.ts +2 -0
  149. package/dist/core/update.js +182 -2
  150. package/dist/core/validation/report-schema.d.ts +74 -0
  151. package/dist/core/validation/report-schema.js +254 -0
  152. package/dist/core/validation/strict-rules.d.ts +202 -0
  153. package/dist/core/validation/strict-rules.js +1698 -0
  154. package/dist/core/validation/types.d.ts +10 -0
  155. package/dist/core/validation/validator.d.ts +5 -0
  156. package/dist/core/validation/validator.js +174 -1
  157. package/dist/core/view.d.ts +1 -0
  158. package/dist/core/view.js +60 -2
  159. package/dist/mcp/index.d.ts +28 -0
  160. package/dist/mcp/index.js +31 -0
  161. package/dist/utils/file-system.d.ts +1 -0
  162. package/dist/utils/file-system.js +11 -0
  163. package/dist/utils/git-repo-detector.d.ts +130 -0
  164. package/dist/utils/git-repo-detector.js +275 -0
  165. package/dist/utils/hook-host.d.ts +47 -0
  166. package/dist/utils/hook-host.js +129 -0
  167. package/dist/utils/hook-merge.d.ts +35 -0
  168. package/dist/utils/hook-merge.js +103 -0
  169. package/dist/utils/index.d.ts +2 -0
  170. package/dist/utils/index.js +2 -0
  171. package/dist/utils/item-discovery.js +28 -5
  172. package/dist/utils/line-diff.d.ts +33 -0
  173. package/dist/utils/line-diff.js +85 -0
  174. package/dist/utils/phase-utils.d.ts +49 -0
  175. package/dist/utils/phase-utils.js +286 -0
  176. package/dist/utils/resolve-root.d.ts +26 -0
  177. package/dist/utils/resolve-root.js +80 -0
  178. package/dist/utils/task-progress.js +8 -0
  179. package/package.json +3 -2
  180. package/schemas/spec-driven/schema.yaml +66 -42
  181. package/schemas/spec-driven/templates/design.md +6 -6
  182. package/schemas/spec-driven/templates/proposal.md +7 -7
  183. package/schemas/spec-driven/templates/spec.md +142 -5
  184. package/schemas/spec-driven/templates/tasks.md +198 -9
  185. package/schemas/tdd/schema.yaml +107 -107
  186. package/schemas/tdd/templates/implementation.md +5 -5
  187. package/schemas/tdd/templates/spec.md +6 -6
  188. package/schemas/tdd/templates/test.md +7 -7
package/README.zh.md CHANGED
@@ -415,7 +415,7 @@ npm install -g ./distributions/fission-ai-zhuanspec-1.0.0.tgz
415
415
 
416
416
  1. **升级包**
417
417
  ```bash
418
- npm install -g @fission-ai/zhuanspec@latest
418
+ npm install -g @zhuan-ai/zhuanspec@latest
419
419
  ```
420
420
  2. **刷新代理说明**
421
421
  - 在每个项目内运行 `zhuanspec update` 以重新生成 AI 指导并确保最新的斜杠命令处于活动状态。
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import '../dist/cli/hooks.js';
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ZhuanSpec Hooks CLI Entry Point
4
+ *
5
+ * This CLI provides hook commands for Claude Code integration:
6
+ * - init: SessionStart hook - Initialize ZhuanSpec environment
7
+ * - deviation-check: PreToolUse hook - Check for proposal deviations
8
+ * - record-progress: PostToolUse hook - Record task progress
9
+ * - collect-knowledge: PostToolUse hook - Collect knowledge from interactions
10
+ * - summarize: Stop hook - Summarize session progress
11
+ * - review-*: Review phase hooks - Check skill outputs and control fix loops
12
+ */
13
+ /**
14
+ * Phase Transition Check - Unified function for phase transition validation
15
+ */
16
+ export declare function runPhaseTransitionCheck(options: {
17
+ from?: string;
18
+ to?: string;
19
+ change?: string;
20
+ }): Promise<{
21
+ continue: boolean;
22
+ systemMessage?: string;
23
+ checks?: Record<string, boolean>;
24
+ requiresUserConfirmation?: boolean;
25
+ }>;
26
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1,558 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ZhuanSpec Hooks CLI Entry Point
4
+ *
5
+ * This CLI provides hook commands for Claude Code integration:
6
+ * - init: SessionStart hook - Initialize ZhuanSpec environment
7
+ * - deviation-check: PreToolUse hook - Check for proposal deviations
8
+ * - record-progress: PostToolUse hook - Record task progress
9
+ * - collect-knowledge: PostToolUse hook - Collect knowledge from interactions
10
+ * - summarize: Stop hook - Summarize session progress
11
+ * - review-*: Review phase hooks - Check skill outputs and control fix loops
12
+ */
13
+ import { Command } from 'commander';
14
+ import { initHook } from '../core/hooks/init.js';
15
+ import { deviationCheckHook } from '../core/hooks/deviation-check.js';
16
+ import { recordProgressHook, initializeProgress } from '../core/hooks/record-progress.js';
17
+ import { collectKnowledgeHook } from '../core/hooks/collect-knowledge.js';
18
+ import { knowledgeUsageHook } from '../core/hooks/knowledge-usage.js';
19
+ import { knowledgeReferencesHook } from '../core/hooks/knowledge-references.js';
20
+ import { summarizeHook } from '../core/hooks/summarize.js';
21
+ import { runUserInputHook } from '../core/hooks/user-input-hook.js';
22
+ import { preArchiveHook } from '../core/hooks/pre-archive.js';
23
+ import { postArchiveHook } from '../core/hooks/post-archive.js';
24
+ import { preApplyHook, checkPreApplyConditions } from '../core/hooks/pre-apply.js';
25
+ import { postApplyHook, executePostApply } from '../core/hooks/post-apply.js';
26
+ import { codeReviewResultCheck, unitTestResultCheck, specConsistencyResultCheck, generateReviewReport, } from '../core/hooks/review-hooks.js';
27
+ import path from 'path';
28
+ import { FileSystemUtils } from '../utils/file-system.js';
29
+ import { resolveZhuanSpecRoot } from '../utils/resolve-root.js';
30
+ const program = new Command();
31
+ program
32
+ .name('zhuanspec-hook')
33
+ .description('ZhuanSpec hooks for Claude Code integration')
34
+ .version('1.0.0');
35
+ // SessionStart hook
36
+ program
37
+ .command('init')
38
+ .description('SessionStart hook - Initialize ZhuanSpec environment')
39
+ .option('--json', 'Output as JSON for Claude Code consumption')
40
+ .action(async (options) => {
41
+ await initHook(options);
42
+ });
43
+ // PreToolUse hook
44
+ program
45
+ .command('deviation-check')
46
+ .description('PreToolUse hook - Check for proposal deviations before Write/Edit')
47
+ .option('--json', 'Output as JSON for Claude Code consumption')
48
+ .option('--file <path>', 'File being modified')
49
+ .option('--tool <name>', 'Tool being used (Write/Edit)')
50
+ .option('--trigger <type>', 'Trigger type: pre-tool|post-prompt|resume')
51
+ .option('--prompt <text>', 'Prompt content for post-prompt checks')
52
+ .action(async (options) => {
53
+ // v2.15.16 Sprint 3:'post-prompt' 分支已由 user-input-hook 接管,此处保留参数仅为
54
+ // 兼容 v2.15.14 及更早版本的 .claude/settings.json(未执行过 zhuanspec update)。
55
+ // 收到 post-prompt 时直接 no-op 返回,避免破坏 UserPromptSubmit 事件链。
56
+ if (options.trigger === 'post-prompt') {
57
+ if (options.json) {
58
+ console.log(JSON.stringify({ continue: true, hookSpecificOutput: { hookEventName: 'UserPromptSubmit' } }));
59
+ }
60
+ return;
61
+ }
62
+ const { trigger, ...rest } = options;
63
+ await deviationCheckHook({ ...rest, trigger: trigger });
64
+ });
65
+ // PostToolUse hook - record progress
66
+ program
67
+ .command('record-progress')
68
+ .description('PostToolUse hook - Record task progress after Write/Edit')
69
+ .option('--json', 'Output as JSON for Claude Code consumption')
70
+ .option('--file <path>', 'File that was modified')
71
+ .option('--tool <name>', 'Tool that was used (Write/Edit)')
72
+ .option('--success <boolean>', 'Whether the operation succeeded')
73
+ .action(async (options) => {
74
+ await recordProgressHook(options);
75
+ });
76
+ // Initialize progress - create progress.json at Propose phase start
77
+ program
78
+ .command('init-progress')
79
+ .description('Initialize progress.json for a change at Propose phase start')
80
+ .option('--change <id>', 'Change ID')
81
+ .action(async (options) => {
82
+ if (!options.change) {
83
+ console.error('Error: --change <id> is required');
84
+ process.exit(1);
85
+ }
86
+ await initializeProgress(options.change);
87
+ console.log(`✓ Progress initialized for change: ${options.change}`);
88
+ });
89
+ // PostToolUse hook - collect knowledge
90
+ program
91
+ .command('collect-knowledge')
92
+ .description('PostToolUse hook - Collect knowledge from interactions')
93
+ .option('--json', 'Output as JSON for Claude Code consumption')
94
+ .option('--file <path>', 'File that was modified')
95
+ .option('--content <string>', 'Content that was written')
96
+ .action(async (options) => {
97
+ await collectKnowledgeHook(options);
98
+ });
99
+ // PostToolUse hook - knowledge usage(引用上报,旁路指标)
100
+ program
101
+ .command('knowledge-usage')
102
+ .description('PostToolUse hook - 记录 AI 引用 knowledge/ 知识文件的次数(旁路指标)')
103
+ .option('--json', 'Output as JSON for Claude Code consumption')
104
+ .option('--file <path>', 'File that was read (override stdin tool_input.file_path)')
105
+ .action(async (options) => {
106
+ await knowledgeUsageHook(options);
107
+ });
108
+ // PostToolUse hook - knowledge references(知识溯源记录)
109
+ program
110
+ .command('knowledge-references')
111
+ .description('PostToolUse hook - Record knowledge references during tech-design/proposal/apply')
112
+ .option('--json', 'Output as JSON for Claude Code consumption')
113
+ .action(async (options) => {
114
+ await knowledgeReferencesHook(options);
115
+ });
116
+ // Stop hook
117
+ program
118
+ .command('summarize')
119
+ .description('Stop hook - Summarize session progress')
120
+ .option('--json', 'Output as JSON for Claude Code consumption')
121
+ .action(async (options) => {
122
+ await summarizeHook(options);
123
+ });
124
+ // UserPromptSubmit hook - record user input & activate correctionContext from phaseBaselines
125
+ program
126
+ .command('user-input')
127
+ .description('UserPromptSubmit hook - Record user input and activate correction context post-baseline')
128
+ .option('--json', 'Output as JSON for Claude Code consumption (envelope printed regardless)')
129
+ .action(async () => {
130
+ await runUserInputHook();
131
+ });
132
+ program
133
+ .command('pre-archive')
134
+ .description('Pre-archive quality gate')
135
+ .option('--json', 'Output as JSON for Claude Code consumption')
136
+ .option('--change <id>', 'Change ID to validate before archive')
137
+ .action(async (options) => {
138
+ await preArchiveHook(options);
139
+ });
140
+ program
141
+ .command('post-archive')
142
+ .description('Post-archive knowledge update')
143
+ .option('--json', 'Output as JSON for Claude Code consumption')
144
+ .option('--archived <id>', 'Archived change ID')
145
+ .action(async (options) => {
146
+ await postArchiveHook(options);
147
+ });
148
+ // Pre-Apply hook - quality gate before entering Apply phase
149
+ program
150
+ .command('pre-apply')
151
+ .description('Pre-Apply quality gate - validate change readiness before Apply phase')
152
+ .option('--json', 'Output as JSON for Claude Code consumption')
153
+ .option('--change <id>', 'Change ID to validate')
154
+ .action(async (options) => {
155
+ await preApplyHook(options);
156
+ });
157
+ // Post-Apply hook - deviation detection and auto-trigger review
158
+ program
159
+ .command('post-apply')
160
+ .description('Post-Apply hook - detect deviations and trigger automatic review')
161
+ .option('--json', 'Output as JSON for Claude Code consumption')
162
+ .option('--change <id>', 'Change ID that was applied')
163
+ .action(async (options) => {
164
+ await postApplyHook(options);
165
+ });
166
+ // Phase Transition Check - Unified phase transition quality gate
167
+ program
168
+ .command('phase-transition-check')
169
+ .description('Check phase transition conditions before moving to next phase')
170
+ .option('--json', 'Output as JSON for Claude Code consumption')
171
+ .option('--from <phase>', 'Current phase: propose|apply|review')
172
+ .option('--to <phase>', 'Target phase: apply|review|archive')
173
+ .option('--change <id>', 'Change ID being transitioned')
174
+ .action(async (options) => {
175
+ const result = await runPhaseTransitionCheck(options);
176
+ if (options.json) {
177
+ console.log(JSON.stringify(result));
178
+ }
179
+ else {
180
+ console.log(result.systemMessage || '');
181
+ if (!result.continue) {
182
+ process.exit(1);
183
+ }
184
+ }
185
+ });
186
+ // ============================================================
187
+ // Review Phase Hooks - Check skill outputs and control fix loops
188
+ // ============================================================
189
+ // Code Review Result Check - Hook after code-review-expert skill
190
+ program
191
+ .command('review-code-check')
192
+ .description('Check code-review-expert skill output and decide fix loop')
193
+ .option('--json', 'Output as JSON for Claude Code consumption')
194
+ .option('--change <id>', 'Change ID being reviewed')
195
+ .option('--output <json>', 'Skill output JSON (passed via stdin or option)')
196
+ .action(async (options) => {
197
+ const result = await codeReviewResultCheck(options.change || '', options.output ? JSON.parse(options.output) : undefined);
198
+ if (options.json) {
199
+ console.log(JSON.stringify(result));
200
+ }
201
+ else {
202
+ console.log(`Code Review: ${result.pass ? '✅ PASS' : '❌ FAIL'}`);
203
+ if (result.fixPrompt) {
204
+ console.log(result.fixPrompt);
205
+ }
206
+ if (!result.pass && result.nextAction === 'stop') {
207
+ process.exit(1);
208
+ }
209
+ }
210
+ });
211
+ // Unit Test Result Check - Hook after generate-mockito-unit-test-skill
212
+ program
213
+ .command('review-unit-test-check')
214
+ .description('Check unit test skill output and decide fix loop')
215
+ .option('--json', 'Output as JSON for Claude Code consumption')
216
+ .option('--change <id>', 'Change ID being reviewed')
217
+ .option('--output <json>', 'Skill output JSON')
218
+ .action(async (options) => {
219
+ const result = await unitTestResultCheck(options.change || '', options.output ? JSON.parse(options.output) : undefined);
220
+ if (options.json) {
221
+ console.log(JSON.stringify(result));
222
+ }
223
+ else {
224
+ console.log(`Unit Test: ${result.pass ? '✅ PASS' : '❌ FAIL'}`);
225
+ console.log(`Coverage: ${result.metrics.coverage || 0}%`);
226
+ if (result.fixPrompt) {
227
+ console.log(result.fixPrompt);
228
+ }
229
+ if (!result.pass && result.nextAction === 'stop') {
230
+ process.exit(1);
231
+ }
232
+ }
233
+ });
234
+ // Spec-Code Consistency Check - Hook after spec-code-consistency check
235
+ program
236
+ .command('review-spec-check')
237
+ .description('Check spec-code consistency output and decide fix loop')
238
+ .option('--json', 'Output as JSON for Claude Code consumption')
239
+ .option('--change <id>', 'Change ID being reviewed')
240
+ .option('--output <json>', 'Skill output JSON')
241
+ .action(async (options) => {
242
+ const result = await specConsistencyResultCheck(options.change || '', options.output ? JSON.parse(options.output) : undefined);
243
+ if (options.json) {
244
+ console.log(JSON.stringify(result));
245
+ }
246
+ else {
247
+ console.log(`Spec-Code Consistency: ${result.pass ? '✅ PASS' : '❌ FAIL'}`);
248
+ console.log(`Consistency Rate: ${result.metrics.consistencyRate || 0}%`);
249
+ if (result.fixPrompt) {
250
+ console.log(result.fixPrompt);
251
+ }
252
+ if (!result.pass && result.nextAction === 'stop') {
253
+ process.exit(1);
254
+ }
255
+ }
256
+ });
257
+ // Generate Review Report - Combine all three check results
258
+ program
259
+ .command('review-report')
260
+ .description('Generate review report from all three check results')
261
+ .option('--json', 'Output as JSON for Claude Code consumption')
262
+ .option('--change <id>', 'Change ID being reviewed')
263
+ .action(async (options) => {
264
+ const changeId = options.change || '';
265
+ // Run all three checks
266
+ const codeReviewResult = await codeReviewResultCheck(changeId);
267
+ const unitTestResult = await unitTestResultCheck(changeId);
268
+ const specConsistencyResult = await specConsistencyResultCheck(changeId);
269
+ // Generate report
270
+ const report = await generateReviewReport(changeId, {
271
+ codeReview: codeReviewResult,
272
+ unitTest: unitTestResult,
273
+ specConsistency: specConsistencyResult,
274
+ });
275
+ if (options.json) {
276
+ console.log(JSON.stringify({
277
+ changeId,
278
+ overallPass: codeReviewResult.pass && unitTestResult.pass && specConsistencyResult.pass,
279
+ codeReview: codeReviewResult,
280
+ unitTest: unitTestResult,
281
+ specConsistency: specConsistencyResult,
282
+ reportPath: `zhuanspec/changes/${changeId}/review/review-report.md`,
283
+ }));
284
+ }
285
+ else {
286
+ console.log(report);
287
+ const overallPass = codeReviewResult.pass && unitTestResult.pass && specConsistencyResult.pass;
288
+ if (!overallPass) {
289
+ console.log('\n❌ Review NOT passed. Please fix issues before archiving.');
290
+ process.exit(1);
291
+ }
292
+ else {
293
+ console.log('\n✅ Review passed. Ready for Phase 4 (Archive).');
294
+ }
295
+ }
296
+ });
297
+ // Diagnostic command - inspect hook registration and trigger map
298
+ program
299
+ .command('status')
300
+ .description('Show hook registration status and trigger mapping')
301
+ .option('--json', 'Output as JSON')
302
+ .action(async (options) => {
303
+ const summary = await collectHookStatus();
304
+ if (options.json) {
305
+ console.log(JSON.stringify(summary, null, 2));
306
+ return;
307
+ }
308
+ console.log(`settings: ${summary.settingsPath}`);
309
+ console.log(`settings exists: ${summary.settingsExists ? 'yes' : 'no'}`);
310
+ console.log('\n直接注册(Claude 生命周期 hooks):');
311
+ if (summary.registeredLifecycleHooks.length === 0) {
312
+ console.log('- 无');
313
+ }
314
+ else {
315
+ for (const item of summary.registeredLifecycleHooks) {
316
+ console.log(`- ${item.phase}: ${item.command}`);
317
+ }
318
+ }
319
+ console.log('\n重复注册检测:');
320
+ if (summary.duplicates.length === 0) {
321
+ console.log('- 未发现重复');
322
+ }
323
+ else {
324
+ for (const item of summary.duplicates) {
325
+ console.log(`- ${item.phase}: ${item.command} (x${item.count})`);
326
+ }
327
+ }
328
+ console.log('\n间接触发(阶段门禁与 Review 链路):');
329
+ for (const item of summary.phaseCommands) {
330
+ console.log(`- ${item.command}: ${item.trigger}`);
331
+ }
332
+ });
333
+ /**
334
+ * Phase Transition Check - Unified function for phase transition validation
335
+ */
336
+ export async function runPhaseTransitionCheck(options) {
337
+ const cwd = resolveZhuanSpecRoot();
338
+ const changeId = options.change || process.env.ZHUANSPEC_CHANGE_ID || '';
339
+ const fromPhase = options.from || process.env.ZHUANSPEC_PHASE || 'idle';
340
+ const toPhase = options.to || '';
341
+ if (!changeId) {
342
+ return {
343
+ continue: false,
344
+ systemMessage: 'Phase transition check skipped: no change ID provided',
345
+ };
346
+ }
347
+ const changeDir = path.join(cwd, 'zhuanspec', 'changes', changeId);
348
+ // Determine target phase if not specified
349
+ let targetPhase = toPhase;
350
+ if (!targetPhase) {
351
+ switch (fromPhase) {
352
+ case 'propose':
353
+ targetPhase = 'apply';
354
+ break;
355
+ case 'apply':
356
+ targetPhase = 'review';
357
+ break;
358
+ case 'review':
359
+ targetPhase = 'archive';
360
+ break;
361
+ default:
362
+ targetPhase = 'apply';
363
+ }
364
+ }
365
+ // === Phase 准确率确认门禅(Task 4)===
366
+ // 规则:上一 phase 存在 phaseAccuracy 桶但未 confirmed 时阻断,
367
+ // systemMessage 指引 AI 调 AskUserQuestion 与 show-phase-accuracy / override-phase / confirm-phase 纠正。
368
+ // 绕过方式:环境变量 ZHUANSPEC_SKIP_ACCURACY_CONFIRM=1(CI/自动化用)。
369
+ const SKIP_CONFIRM = process.env.ZHUANSPEC_SKIP_ACCURACY_CONFIRM === '1';
370
+ const CONFIRMABLE_PHASES = new Set(['techDesign', 'propose', 'apply', 'review']);
371
+ if (!SKIP_CONFIRM && CONFIRMABLE_PHASES.has(fromPhase)) {
372
+ try {
373
+ const progressPath = path.join(changeDir, 'metrics', 'progress.json');
374
+ if (await FileSystemUtils.fileExists(progressPath)) {
375
+ const progressRaw = await FileSystemUtils.readFile(progressPath);
376
+ const progress = JSON.parse(progressRaw);
377
+ const buckets = progress.accuracy?.phaseAccuracy?.filter(b => b.phase === fromPhase) ?? [];
378
+ if (buckets.length > 0) {
379
+ const unconfirmed = buckets.filter(b => !b.confirmed);
380
+ if (unconfirmed.length > 0) {
381
+ // 聚合展示
382
+ const aiTotal = buckets.reduce((s, b) => s + (b.aiTotalLines || 0), 0);
383
+ const correction = buckets.reduce((s, b) => s + (b.userCorrectionLines || 0), 0);
384
+ const avgRate = buckets.length > 0
385
+ ? buckets.reduce((s, b) => s + (b.accuracyRate || 0), 0) / buckets.length
386
+ : 1;
387
+ const rateStr = (avgRate * 100).toFixed(2);
388
+ return {
389
+ continue: false,
390
+ requiresUserConfirmation: true,
391
+ systemMessage: [
392
+ `✗ Phase transition blocked: ${fromPhase} → ${targetPhase}`,
393
+ '',
394
+ `阶段 ${fromPhase} 的准确率尚未被用户确认(桶数=${buckets.length},未确认=${unconfirmed.length})。`,
395
+ `当前数据:rate=${rateStr}%, AI产出=${aiTotal} 行, 用户纠偏=${correction} 行`,
396
+ '',
397
+ '请按以下步骤完成确认:',
398
+ `1. 查看详细数据:zhuanspec progress show-phase-accuracy ${changeId} ${fromPhase}`,
399
+ `2. 向用户提问(AskUserQuestion 或宿主等效工具):`,
400
+ ` 问题:“${fromPhase} 阶段准确率为 ${rateStr}%(AI 产出 ${aiTotal} 行,纠偏 ${correction} 行),是否正确?”`,
401
+ ` 选项A 准确或已内消 → zhuanspec progress confirm-phase ${changeId} ${fromPhase}`,
402
+ ` 选项B 需纠正 → 询问正确率 rate 与原因 reason`,
403
+ ` → zhuanspec progress override-phase ${changeId} ${fromPhase} --rate <0..1> --reason <text>`,
404
+ ` → zhuanspec progress confirm-phase ${changeId} ${fromPhase}`,
405
+ '3. 确认完成后重新运行 phase-transition-check。',
406
+ '',
407
+ '绕过本门禅(CI/自动化):设置 ZHUANSPEC_SKIP_ACCURACY_CONFIRM=1。',
408
+ ].join('\n'),
409
+ };
410
+ }
411
+ }
412
+ // 历史数据 / 无桶:跳过此门禅(fall-through 继续其他检查)
413
+ }
414
+ }
415
+ catch {
416
+ // 读取 progress.json 失败不阻断原有检查链路
417
+ }
418
+ }
419
+ // Execute appropriate pre-check based on target phase
420
+ switch (targetPhase) {
421
+ case 'apply':
422
+ // Propose → Apply: Run pre-apply checks
423
+ const preApplyResult = await checkPreApplyConditions(changeDir);
424
+ if (preApplyResult.continue) {
425
+ return {
426
+ continue: true,
427
+ systemMessage: `✓ Phase transition approved: ${fromPhase} → ${targetPhase}\n\nAll pre-apply checks passed. You may now proceed to Apply phase.`,
428
+ checks: preApplyResult.checks,
429
+ };
430
+ }
431
+ return {
432
+ continue: false,
433
+ systemMessage: `✗ Phase transition blocked: ${fromPhase} → ${targetPhase}\n\n${preApplyResult.systemMessage}`,
434
+ checks: preApplyResult.checks,
435
+ };
436
+ case 'review':
437
+ // Apply → Review: Run post-apply deviation check
438
+ const postApplyResult = await executePostApply(changeDir, cwd);
439
+ if (postApplyResult.hookSpecificOutput?.deviationDetected) {
440
+ return {
441
+ continue: false,
442
+ systemMessage: `✗ Phase transition blocked: ${fromPhase} → ${targetPhase}\n\nDeviation detected: ${postApplyResult.hookSpecificOutput.deviationFiles?.length || 0} files outside proposal scope.\nPlease update proposal (Reverse Sync) before proceeding to Review.`,
443
+ };
444
+ }
445
+ return {
446
+ continue: true,
447
+ systemMessage: `✓ Phase transition approved: ${fromPhase} → ${targetPhase}\n\nNo deviations detected. Review phase can proceed.`,
448
+ };
449
+ case 'archive':
450
+ // Review → Archive: Check for review completion
451
+ const reviewDir = path.join(changeDir, 'review');
452
+ const reviewPath = path.join(reviewDir, 'code-review-result.json');
453
+ const testsPath = path.join(reviewDir, 'unit-test-result.json');
454
+ const reportPath = path.join(reviewDir, 'review-report.md');
455
+ const checks = {
456
+ reviewCompleted: false,
457
+ testsCompleted: false,
458
+ reportExists: false,
459
+ };
460
+ checks.reviewCompleted = await FileSystemUtils.fileExists(reviewPath);
461
+ checks.testsCompleted = await FileSystemUtils.fileExists(testsPath);
462
+ checks.reportExists = await FileSystemUtils.fileExists(reportPath);
463
+ if (!checks.reviewCompleted || !checks.testsCompleted || !checks.reportExists) {
464
+ const missing = [];
465
+ if (!checks.reviewCompleted)
466
+ missing.push('review/code-review-result.json');
467
+ if (!checks.testsCompleted)
468
+ missing.push('review/unit-test-result.json');
469
+ if (!checks.reportExists)
470
+ missing.push('review/review-report.md');
471
+ return {
472
+ continue: false,
473
+ systemMessage: `✗ Phase transition blocked: ${fromPhase} → ${targetPhase}\n\nMissing review artifacts:\n${missing.map(m => `- ${m}`).join('\n')}\n\nPlease complete Review phase before archiving.`,
474
+ checks,
475
+ };
476
+ }
477
+ return {
478
+ continue: true,
479
+ systemMessage: `✓ Phase transition approved: ${fromPhase} → ${targetPhase}\n\nAll review artifacts present. Archive phase can proceed.`,
480
+ checks,
481
+ };
482
+ default:
483
+ return {
484
+ continue: false,
485
+ systemMessage: `Unknown target phase: ${targetPhase}`,
486
+ };
487
+ }
488
+ }
489
+ async function collectHookStatus() {
490
+ const cwd = resolveZhuanSpecRoot();
491
+ const settingsPath = path.join(cwd, '.claude', 'settings.json');
492
+ const settingsExists = await FileSystemUtils.fileExists(settingsPath);
493
+ const registeredLifecycleHooks = [];
494
+ const duplicates = [];
495
+ if (settingsExists) {
496
+ try {
497
+ const content = await FileSystemUtils.readFile(settingsPath);
498
+ const parsed = JSON.parse(content);
499
+ const hooks = parsed.hooks ?? {};
500
+ for (const [phase, phaseConfigs] of Object.entries(hooks)) {
501
+ if (!Array.isArray(phaseConfigs))
502
+ continue;
503
+ const commandCounts = new Map();
504
+ for (const phaseConfig of phaseConfigs) {
505
+ const hooksArray = phaseConfig.hooks;
506
+ if (!Array.isArray(hooksArray))
507
+ continue;
508
+ for (const hookItem of hooksArray) {
509
+ const command = hookItem.command;
510
+ if (typeof command !== 'string')
511
+ continue;
512
+ registeredLifecycleHooks.push({ phase, command });
513
+ commandCounts.set(command, (commandCounts.get(command) ?? 0) + 1);
514
+ }
515
+ }
516
+ for (const [command, count] of commandCounts.entries()) {
517
+ if (count > 1) {
518
+ duplicates.push({ phase, command, count });
519
+ }
520
+ }
521
+ }
522
+ }
523
+ catch {
524
+ // Keep defaults; command should still provide guidance.
525
+ }
526
+ }
527
+ const phaseCommands = [
528
+ {
529
+ command: 'zhuanspec-hook pre-apply',
530
+ trigger: '由 deviation-check 内部调用 checkPreApplyConditions(Propose → Apply 前门禁)',
531
+ },
532
+ {
533
+ command: 'zhuanspec-hook post-apply',
534
+ trigger: '由 summarize/executePostApply 间接触发(Apply 完成后偏差检测与 review 触发)',
535
+ },
536
+ {
537
+ command: 'zhuanspec-hook review-code-check',
538
+ trigger: '由 zhuanspec review 结果链路调用(代码审查结果判定)',
539
+ },
540
+ {
541
+ command: 'zhuanspec-hook review-unit-test-check',
542
+ trigger: '由 zhuanspec review 结果链路调用(单测结果判定)',
543
+ },
544
+ {
545
+ command: 'zhuanspec-hook review-spec-check',
546
+ trigger: '由 zhuanspec review 结果链路调用(Spec/Code 一致性判定)',
547
+ },
548
+ ];
549
+ return {
550
+ settingsPath,
551
+ settingsExists,
552
+ registeredLifecycleHooks,
553
+ duplicates,
554
+ phaseCommands,
555
+ };
556
+ }
557
+ program.parse();
558
+ //# sourceMappingURL=hooks.js.map