@zhuan-ai/zhuanspec 2.2.4 → 2.4.8

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 (103) hide show
  1. package/bin/zhuanspec-hook.js +3 -0
  2. package/dist/cli/hooks.d.ts +14 -0
  3. package/dist/cli/hooks.js +465 -0
  4. package/dist/cli/index.js +100 -0
  5. package/dist/commands/artifact-workflow.js +15 -34
  6. package/dist/commands/design.d.ts +42 -0
  7. package/dist/commands/design.js +337 -0
  8. package/dist/commands/progress.d.ts +32 -0
  9. package/dist/commands/progress.js +278 -0
  10. package/dist/commands/review.d.ts +32 -0
  11. package/dist/commands/review.js +472 -0
  12. package/dist/commands/validate.d.ts +14 -0
  13. package/dist/commands/validate.js +161 -10
  14. package/dist/core/archive.d.ts +1 -0
  15. package/dist/core/archive.js +45 -3
  16. package/dist/core/completions/command-registry.js +67 -0
  17. package/dist/core/configurators/slash/amazon-q.js +32 -2
  18. package/dist/core/configurators/slash/antigravity.js +8 -2
  19. package/dist/core/configurators/slash/auggie.js +16 -1
  20. package/dist/core/configurators/slash/base.js +1 -1
  21. package/dist/core/configurators/slash/claude.d.ts +4 -0
  22. package/dist/core/configurators/slash/claude.js +56 -1
  23. package/dist/core/configurators/slash/cline.js +8 -2
  24. package/dist/core/configurators/slash/codebuddy.js +22 -1
  25. package/dist/core/configurators/slash/codex.js +21 -0
  26. package/dist/core/configurators/slash/costrict.js +15 -0
  27. package/dist/core/configurators/slash/crush.js +22 -1
  28. package/dist/core/configurators/slash/cursor.js +22 -1
  29. package/dist/core/configurators/slash/factory.js +16 -1
  30. package/dist/core/configurators/slash/gemini.js +8 -2
  31. package/dist/core/configurators/slash/github-copilot.js +19 -1
  32. package/dist/core/configurators/slash/iflow.js +22 -1
  33. package/dist/core/configurators/slash/kilocode.js +4 -1
  34. package/dist/core/configurators/slash/opencode.js +27 -0
  35. package/dist/core/configurators/slash/qoder.d.ts +4 -0
  36. package/dist/core/configurators/slash/qoder.js +59 -1
  37. package/dist/core/configurators/slash/qwen.js +8 -2
  38. package/dist/core/configurators/slash/roocode.js +8 -2
  39. package/dist/core/configurators/slash/windsurf.js +8 -2
  40. package/dist/core/dashboard/metrics.d.ts +33 -0
  41. package/dist/core/dashboard/metrics.js +114 -0
  42. package/dist/core/hooks/collect-knowledge.d.ts +16 -0
  43. package/dist/core/hooks/collect-knowledge.js +203 -0
  44. package/dist/core/hooks/context-load-hook.d.ts +25 -0
  45. package/dist/core/hooks/context-load-hook.js +159 -0
  46. package/dist/core/hooks/deviation-check.d.ts +27 -0
  47. package/dist/core/hooks/deviation-check.js +403 -0
  48. package/dist/core/hooks/deviation-handler.d.ts +43 -0
  49. package/dist/core/hooks/deviation-handler.js +98 -0
  50. package/dist/core/hooks/init.d.ts +14 -0
  51. package/dist/core/hooks/init.js +244 -0
  52. package/dist/core/hooks/notify-milestone.d.ts +14 -0
  53. package/dist/core/hooks/notify-milestone.js +170 -0
  54. package/dist/core/hooks/post-apply.d.ts +29 -0
  55. package/dist/core/hooks/post-apply.js +173 -0
  56. package/dist/core/hooks/post-archive.d.ts +7 -0
  57. package/dist/core/hooks/post-archive.js +208 -0
  58. package/dist/core/hooks/pre-apply.d.ts +34 -0
  59. package/dist/core/hooks/pre-apply.js +139 -0
  60. package/dist/core/hooks/pre-archive.d.ts +7 -0
  61. package/dist/core/hooks/pre-archive.js +50 -0
  62. package/dist/core/hooks/record-progress.d.ts +49 -0
  63. package/dist/core/hooks/record-progress.js +494 -0
  64. package/dist/core/hooks/review-hooks.d.ts +89 -0
  65. package/dist/core/hooks/review-hooks.js +345 -0
  66. package/dist/core/hooks/review-orchestrator.d.ts +40 -0
  67. package/dist/core/hooks/review-orchestrator.js +146 -0
  68. package/dist/core/hooks/summarize.d.ts +15 -0
  69. package/dist/core/hooks/summarize.js +282 -0
  70. package/dist/core/hooks/user-input-hook.d.ts +25 -0
  71. package/dist/core/hooks/user-input-hook.js +179 -0
  72. package/dist/core/init.d.ts +8 -0
  73. package/dist/core/init.js +251 -23
  74. package/dist/core/parsers/requirement-blocks.js +13 -10
  75. package/dist/core/templates/agents-template.d.ts +1 -1
  76. package/dist/core/templates/agents-template.js +510 -243
  77. package/dist/core/templates/index.d.ts +1 -0
  78. package/dist/core/templates/index.js +1 -0
  79. package/dist/core/templates/skill-templates.js +46 -152
  80. package/dist/core/templates/slash-command-templates.d.ts +1 -1
  81. package/dist/core/templates/slash-command-templates.js +352 -20
  82. package/dist/core/templates/tasks-template.d.ts +7 -0
  83. package/dist/core/templates/tasks-template.js +130 -24
  84. package/dist/core/templates/tdd-tasks-template.d.ts +3 -0
  85. package/dist/core/templates/tdd-tasks-template.js +91 -38
  86. package/dist/core/templates/test-cases-template.d.ts +41 -0
  87. package/dist/core/templates/test-cases-template.js +128 -0
  88. package/dist/core/validation/strict-rules.d.ts +44 -5
  89. package/dist/core/validation/strict-rules.js +302 -8
  90. package/dist/core/validation/validator.js +52 -2
  91. package/dist/core/view.d.ts +1 -0
  92. package/dist/core/view.js +60 -2
  93. package/dist/mcp/index.d.ts +28 -0
  94. package/dist/mcp/index.js +31 -0
  95. package/dist/utils/file-system.d.ts +1 -0
  96. package/dist/utils/file-system.js +11 -0
  97. package/dist/utils/item-discovery.js +24 -2
  98. package/dist/utils/phase-utils.d.ts +36 -0
  99. package/dist/utils/phase-utils.js +117 -0
  100. package/package.json +22 -23
  101. package/schemas/spec-driven/schema.yaml +45 -31
  102. package/schemas/spec-driven/templates/spec.md +142 -5
  103. package/schemas/spec-driven/templates/tasks.md +73 -9
@@ -0,0 +1,208 @@
1
+ import path from 'path';
2
+ import { FileSystemUtils } from '../../utils/file-system.js';
3
+ import { readdirSync, rmSync } from 'fs';
4
+ import chalk from 'chalk';
5
+ import { getBeijingTime, getBeijingTimeForFilename } from './record-progress.js';
6
+ export async function postArchiveHook(options) {
7
+ const output = await runPostArchiveHook(options.archived || '');
8
+ if (options.json) {
9
+ console.log(JSON.stringify(output));
10
+ }
11
+ else if (output.systemMessage) {
12
+ console.log(output.systemMessage);
13
+ }
14
+ }
15
+ async function runPostArchiveHook(archivedChange) {
16
+ if (!archivedChange) {
17
+ return { continue: true, systemMessage: 'Post-archive hook skipped: no archived change provided' };
18
+ }
19
+ const repoRoot = process.cwd();
20
+ const zhuanspecDir = path.join(repoRoot, 'zhuanspec');
21
+ const knowledgeDir = path.join(zhuanspecDir, 'knowledge');
22
+ // 1. Update archive log
23
+ console.log(chalk.gray(' → 更新知识索引...'));
24
+ await FileSystemUtils.createDirectory(knowledgeDir);
25
+ const indexPath = path.join(knowledgeDir, 'index.md');
26
+ const line = `- ${getBeijingTime()} archived: ${archivedChange}`;
27
+ if (await FileSystemUtils.fileExists(indexPath)) {
28
+ const existing = await FileSystemUtils.readFile(indexPath);
29
+ await FileSystemUtils.writeFile(indexPath, `${existing.trimEnd()}\n${line}\n`);
30
+ }
31
+ else {
32
+ await FileSystemUtils.writeFile(indexPath, `# Knowledge Index\n\n## Archive Log\n${line}\n`);
33
+ }
34
+ // 2. Collect change knowledge (extract decisions, best practices, implicit conventions)
35
+ console.log(chalk.gray(' → 提取设计文档中的知识记录...'));
36
+ const knowledgeResult = await collectChangeKnowledge(zhuanspecDir, archivedChange, knowledgeDir);
37
+ if (knowledgeResult.decisions > 0) {
38
+ console.log(chalk.gray(` - 决策记录:${knowledgeResult.decisions} 条`));
39
+ }
40
+ if (knowledgeResult.bestPractices > 0) {
41
+ console.log(chalk.gray(` - 最佳实践:${knowledgeResult.bestPractices} 条`));
42
+ }
43
+ if (knowledgeResult.implicitConventions > 0) {
44
+ console.log(chalk.gray(` - 隐式约定:${knowledgeResult.implicitConventions} 条`));
45
+ }
46
+ // 3. Cleanup temp files
47
+ console.log(chalk.gray(' → 清理临时文件...'));
48
+ const tempFilesCleaned = await cleanupTempFiles(zhuanspecDir);
49
+ if (tempFilesCleaned > 0) {
50
+ console.log(chalk.gray(` - 已清理:${tempFilesCleaned} 个`));
51
+ }
52
+ const totalEntries = knowledgeResult.decisions + knowledgeResult.bestPractices + knowledgeResult.implicitConventions;
53
+ console.log(chalk.green(`✅ 知识收集完成:共 ${totalEntries} 条记录`));
54
+ return {
55
+ continue: true,
56
+ systemMessage: `Post-archive: knowledge updated for ${archivedChange}, ${knowledgeResult.decisions} decisions, ${knowledgeResult.bestPractices} best practices, ${knowledgeResult.implicitConventions} implicit conventions, ${tempFilesCleaned} temp files cleaned`,
57
+ hookSpecificOutput: {
58
+ decisionsCollected: knowledgeResult.decisions,
59
+ bestPracticesCollected: knowledgeResult.bestPractices,
60
+ implicitConventionsCollected: knowledgeResult.implicitConventions,
61
+ tempFilesCleaned,
62
+ },
63
+ };
64
+ }
65
+ /**
66
+ * Extract knowledge records from change directory (proposal.md, tasks.md, design.md, specs/*.md)
67
+ * and save to knowledge subdirectories
68
+ */
69
+ async function collectChangeKnowledge(zhuanspecDir, archivedChange, knowledgeDir) {
70
+ const result = {
71
+ decisions: 0,
72
+ bestPractices: 0,
73
+ implicitConventions: 0,
74
+ };
75
+ // Find archived change directory
76
+ const archiveDir = path.join(zhuanspecDir, 'changes', 'archive', archivedChange);
77
+ // Source files to extract knowledge from (in priority order)
78
+ const sourceFiles = [
79
+ path.join(archiveDir, 'design.md'), // Optional, highest priority
80
+ path.join(archiveDir, 'proposal.md'), // Required
81
+ path.join(archiveDir, 'tasks.md'), // Required
82
+ ];
83
+ // Also check specs subdirectory
84
+ const specsDir = path.join(archiveDir, 'specs');
85
+ if (await FileSystemUtils.directoryExists(specsDir)) {
86
+ try {
87
+ const specEntries = readdirSync(specsDir, { withFileTypes: true });
88
+ for (const entry of specEntries) {
89
+ if (entry.isDirectory()) {
90
+ const specMd = path.join(specsDir, entry.name, 'spec.md');
91
+ if (await FileSystemUtils.fileExists(specMd)) {
92
+ sourceFiles.push(specMd);
93
+ }
94
+ }
95
+ }
96
+ }
97
+ catch {
98
+ // Ignore directory read errors
99
+ }
100
+ }
101
+ // Collect content from all available source files
102
+ let combinedContent = '';
103
+ for (const filePath of sourceFiles) {
104
+ if (await FileSystemUtils.fileExists(filePath)) {
105
+ try {
106
+ const content = await FileSystemUtils.readFile(filePath);
107
+ combinedContent += `\n\n--- Source: ${path.basename(filePath)} ---\n\n${content}`;
108
+ }
109
+ catch {
110
+ // Ignore file read errors
111
+ }
112
+ }
113
+ }
114
+ if (!combinedContent.trim()) {
115
+ return result;
116
+ }
117
+ try {
118
+ // Create knowledge subdirectories
119
+ const decisionsDir = path.join(knowledgeDir, 'decisions');
120
+ const bestPracticesDir = path.join(knowledgeDir, 'best-practices');
121
+ const implicitConventionsDir = path.join(knowledgeDir, 'implicit-conventions');
122
+ await FileSystemUtils.createDirectory(decisionsDir);
123
+ await FileSystemUtils.createDirectory(bestPracticesDir);
124
+ await FileSystemUtils.createDirectory(implicitConventionsDir);
125
+ // Define regex patterns for each knowledge type (Chinese and English)
126
+ const patterns = {
127
+ decisions: /^##\s+(决策|Decision|技术决策|架构决策)[\s\S]*?(?=^##[^#]|$)/gm,
128
+ bestPractices: /^##\s+(最佳实践|Best\s+Practice|Best\s+Practices|推荐做法|建议|注意事项)[\s\S]*?(?=^##[^#]|$)/gm,
129
+ implicitConventions: /^##\s+(隐式约定|Implicit\s+Convention|默认行为|约定|惯例|约定事项)[\s\S]*?(?=^##[^#]|$)/gm,
130
+ };
131
+ const targetDirs = {
132
+ decisions: decisionsDir,
133
+ bestPractices: bestPracticesDir,
134
+ implicitConventions: implicitConventionsDir,
135
+ };
136
+ // Extract and save each knowledge type
137
+ for (const [type, pattern] of Object.entries(patterns)) {
138
+ const matches = combinedContent.matchAll(pattern);
139
+ const entries = [];
140
+ for (const match of matches) {
141
+ const content = match[0].trim();
142
+ if (content.length > 50) {
143
+ entries.push(content);
144
+ }
145
+ }
146
+ if (entries.length > 0) {
147
+ const timestamp = getBeijingTimeForFilename();
148
+ const fileName = `${archivedChange}-${type}-${timestamp}.md`;
149
+ const filePath = path.join(targetDirs[type], fileName);
150
+ const typeLabel = type === 'decisions' ? 'Decision Records' :
151
+ type === 'bestPractices' ? 'Best Practices' :
152
+ 'Implicit Conventions';
153
+ const doc = `# ${typeLabel} from ${archivedChange}
154
+
155
+ Extracted on: ${getBeijingTime()}
156
+
157
+ ${entries.join('\n\n---\n\n')}
158
+ `;
159
+ await FileSystemUtils.writeFile(filePath, doc);
160
+ result[type] = entries.length;
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+ catch {
166
+ return result;
167
+ }
168
+ }
169
+ /**
170
+ * Cleanup temporary files from zhuanspec directory
171
+ */
172
+ async function cleanupTempFiles(zhuanspecDir) {
173
+ const tempPatterns = [
174
+ '.temp-session',
175
+ '.temp-progress',
176
+ '.temp-',
177
+ '.cache-',
178
+ ];
179
+ let cleanedCount = 0;
180
+ try {
181
+ const entries = readdirSync(zhuanspecDir, { withFileTypes: true });
182
+ for (const entry of entries) {
183
+ const name = entry.name;
184
+ // Check if file/directory matches temp patterns
185
+ const isTemp = tempPatterns.some(pattern => name.startsWith(pattern));
186
+ if (isTemp) {
187
+ const fullPath = path.join(zhuanspecDir, name);
188
+ try {
189
+ if (entry.isDirectory()) {
190
+ rmSync(fullPath, { recursive: true, force: true });
191
+ }
192
+ else {
193
+ rmSync(fullPath, { force: true });
194
+ }
195
+ cleanedCount++;
196
+ }
197
+ catch {
198
+ // Ignore cleanup failures
199
+ }
200
+ }
201
+ }
202
+ }
203
+ catch {
204
+ // Directory read failed, return 0
205
+ }
206
+ return cleanedCount;
207
+ }
208
+ //# sourceMappingURL=post-archive.js.map
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Pre-Apply Hook
3
+ *
4
+ * Checks before entering Apply phase:
5
+ * 1. proposal.md exists
6
+ * 2. tasks.md exists
7
+ * 3. specs/ directory exists and non-empty
8
+ * 4. validate --strict passes
9
+ * 5. .approved file exists (Plan Approved gate)
10
+ */
11
+ interface PreApplyOptions {
12
+ json?: boolean;
13
+ change?: string;
14
+ }
15
+ interface HookOutput {
16
+ continue: boolean;
17
+ stopReason?: string;
18
+ systemMessage?: string;
19
+ checks?: {
20
+ proposalExists: boolean;
21
+ tasksExists: boolean;
22
+ specsExists: boolean;
23
+ validationPassed: boolean;
24
+ approved: boolean;
25
+ };
26
+ }
27
+ export declare function preApplyHook(options: PreApplyOptions): Promise<void>;
28
+ /**
29
+ * Check pre-apply conditions for a change directory.
30
+ * This function is exported for use by other hooks (e.g., deviation-check).
31
+ */
32
+ export declare function checkPreApplyConditions(changeDir: string): Promise<HookOutput>;
33
+ export {};
34
+ //# sourceMappingURL=pre-apply.d.ts.map
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Pre-Apply Hook
3
+ *
4
+ * Checks before entering Apply phase:
5
+ * 1. proposal.md exists
6
+ * 2. tasks.md exists
7
+ * 3. specs/ directory exists and non-empty
8
+ * 4. validate --strict passes
9
+ * 5. .approved file exists (Plan Approved gate)
10
+ */
11
+ import path from 'path';
12
+ import { Validator } from '../validation/validator.js';
13
+ import { FileSystemUtils } from '../../utils/file-system.js';
14
+ import { readdirSync } from 'fs';
15
+ export async function preApplyHook(options) {
16
+ const output = await runPreApplyHook(options.change || '');
17
+ if (options.json) {
18
+ console.log(JSON.stringify(output));
19
+ }
20
+ else if (output.systemMessage) {
21
+ if (output.continue) {
22
+ console.log(`✓ ${output.systemMessage}`);
23
+ }
24
+ else {
25
+ console.error(`✗ ${output.systemMessage}`);
26
+ }
27
+ }
28
+ if (!output.continue) {
29
+ process.exit(1);
30
+ }
31
+ }
32
+ async function runPreApplyHook(changeId) {
33
+ if (!changeId) {
34
+ return {
35
+ continue: false,
36
+ stopReason: 'missing-change',
37
+ systemMessage: 'Pre-apply check failed: Missing --change parameter',
38
+ };
39
+ }
40
+ const changeDir = path.join(process.cwd(), 'zhuanspec', 'changes', changeId);
41
+ return await checkPreApplyConditions(changeDir);
42
+ }
43
+ /**
44
+ * Check pre-apply conditions for a change directory.
45
+ * This function is exported for use by other hooks (e.g., deviation-check).
46
+ */
47
+ export async function checkPreApplyConditions(changeDir) {
48
+ const checks = {
49
+ proposalExists: false,
50
+ tasksExists: false,
51
+ specsExists: false,
52
+ validationPassed: false,
53
+ approved: false,
54
+ };
55
+ // Check 1: proposal.md exists
56
+ const proposalPath = path.join(changeDir, 'proposal.md');
57
+ checks.proposalExists = await FileSystemUtils.fileExists(proposalPath);
58
+ if (!checks.proposalExists) {
59
+ return {
60
+ continue: false,
61
+ stopReason: 'missing-proposal',
62
+ systemMessage: 'Pre-apply check failed: missing proposal.md',
63
+ checks,
64
+ };
65
+ }
66
+ // Check 2: tasks.md exists
67
+ const tasksPath = path.join(changeDir, 'tasks.md');
68
+ checks.tasksExists = await FileSystemUtils.fileExists(tasksPath);
69
+ if (!checks.tasksExists) {
70
+ return {
71
+ continue: false,
72
+ stopReason: 'missing-tasks',
73
+ systemMessage: 'Pre-apply check failed: missing tasks.md',
74
+ checks,
75
+ };
76
+ }
77
+ // Check 3: specs/ directory exists and non-empty
78
+ const specsDir = path.join(changeDir, 'specs');
79
+ checks.specsExists = await FileSystemUtils.directoryExists(specsDir);
80
+ if (!checks.specsExists) {
81
+ return {
82
+ continue: false,
83
+ stopReason: 'missing-specs',
84
+ systemMessage: 'Pre-apply check failed: missing specs directory',
85
+ checks,
86
+ };
87
+ }
88
+ // Check specs directory has content
89
+ try {
90
+ const entries = readdirSync(specsDir, { withFileTypes: true });
91
+ const hasContent = entries.some(e => e.isDirectory() || e.name === 'spec.md');
92
+ if (!hasContent) {
93
+ return {
94
+ continue: false,
95
+ stopReason: 'empty-specs',
96
+ systemMessage: 'Pre-apply check failed: specs directory is empty',
97
+ checks,
98
+ };
99
+ }
100
+ }
101
+ catch {
102
+ return {
103
+ continue: false,
104
+ stopReason: 'specs-read-error',
105
+ systemMessage: 'Pre-apply check failed: cannot read specs directory',
106
+ checks,
107
+ };
108
+ }
109
+ // Check 4: validate --strict passes
110
+ const validator = new Validator(true);
111
+ const report = await validator.validateChangeDeltaSpecs(changeDir);
112
+ checks.validationPassed = report.valid;
113
+ if (!checks.validationPassed) {
114
+ const errorCount = report.issues.filter(i => i.level === 'ERROR').length;
115
+ return {
116
+ continue: false,
117
+ stopReason: 'validation-failed',
118
+ systemMessage: `Pre-apply check failed: validate --strict has ${errorCount} errors`,
119
+ checks,
120
+ };
121
+ }
122
+ // Check 5: .approved file exists (Plan Approved gate)
123
+ const approvedPath = path.join(changeDir, '.approved');
124
+ checks.approved = await FileSystemUtils.fileExists(approvedPath);
125
+ if (!checks.approved) {
126
+ return {
127
+ continue: false,
128
+ stopReason: 'not-approved',
129
+ systemMessage: 'Pre-apply check failed: Plan not approved (missing .approved file)',
130
+ checks,
131
+ };
132
+ }
133
+ return {
134
+ continue: true,
135
+ systemMessage: 'Pre-apply check passed - all checks OK',
136
+ checks,
137
+ };
138
+ }
139
+ //# sourceMappingURL=pre-apply.js.map
@@ -0,0 +1,7 @@
1
+ interface PreArchiveOptions {
2
+ json?: boolean;
3
+ change?: string;
4
+ }
5
+ export declare function preArchiveHook(options: PreArchiveOptions): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=pre-archive.d.ts.map
@@ -0,0 +1,50 @@
1
+ import path from 'path';
2
+ import { FileSystemUtils } from '../../utils/file-system.js';
3
+ export async function preArchiveHook(options) {
4
+ const output = await runPreArchiveHook(options.change || '');
5
+ if (options.json) {
6
+ console.log(JSON.stringify(output));
7
+ }
8
+ else if (output.systemMessage) {
9
+ console.log(output.systemMessage);
10
+ }
11
+ if (!output.continue) {
12
+ process.exit(1);
13
+ }
14
+ }
15
+ async function runPreArchiveHook(changeId) {
16
+ if (!changeId) {
17
+ return { continue: false, stopReason: 'missing-change', systemMessage: 'Missing --change for pre-archive check' };
18
+ }
19
+ const changeDir = path.join(process.cwd(), 'zhuanspec', 'changes', changeId);
20
+ const reviewPath = path.join(changeDir, 'metrics', 'review.json');
21
+ const testsPath = path.join(changeDir, 'metrics', 'tests.json');
22
+ const reviewReportPath = path.join(changeDir, 'review-report.md');
23
+ if (!(await FileSystemUtils.fileExists(reviewPath)) ||
24
+ !(await FileSystemUtils.fileExists(testsPath)) ||
25
+ !(await FileSystemUtils.fileExists(reviewReportPath))) {
26
+ return {
27
+ continue: false,
28
+ stopReason: 'review-or-tests-missing',
29
+ systemMessage: 'Pre-archive check failed: missing review.json/tests.json/review-report.md',
30
+ };
31
+ }
32
+ const review = JSON.parse(await FileSystemUtils.readFile(reviewPath));
33
+ const tests = JSON.parse(await FileSystemUtils.readFile(testsPath));
34
+ const reviewPassed = Boolean(review.passed);
35
+ const testPassed = Number(tests.failed ?? 1) === 0;
36
+ const specConsistencyPassed = review?.checks?.specCompliance === true;
37
+ const critical = Number(review?.summary?.critical ?? 0);
38
+ if (!reviewPassed || !testPassed || critical > 0 || !specConsistencyPassed) {
39
+ return {
40
+ continue: false,
41
+ stopReason: 'quality-gate-failed',
42
+ systemMessage: `Pre-archive check failed: review=${reviewPassed}, tests=${testPassed}, specConsistency=${specConsistencyPassed}, critical=${critical}`,
43
+ };
44
+ }
45
+ return {
46
+ continue: true,
47
+ systemMessage: 'Pre-archive check passed',
48
+ };
49
+ }
50
+ //# sourceMappingURL=pre-archive.js.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * PostToolUse Hook - Record Progress
3
+ *
4
+ * This hook runs after Write/Edit operations to:
5
+ * 1. Record the modification to progress.json
6
+ * 2. Update tasks.md status if applicable
7
+ * 3. Track tool calls for metrics
8
+ */
9
+ import { Phase } from '../../utils/phase-utils.js';
10
+ /**
11
+ * Get Beijing time (UTC+8) as ISO string format
12
+ * Returns format: "2026-04-19T18:35:22.934+08:00"
13
+ */
14
+ export declare function getBeijingTime(): string;
15
+ /**
16
+ * Get Beijing time date string for session ID and filenames
17
+ * Returns format: "2026-04-19T18-35-22"
18
+ */
19
+ export declare function getBeijingTimeForFilename(): string;
20
+ interface RecordProgressOptions {
21
+ json?: boolean;
22
+ file?: string;
23
+ tool?: string;
24
+ success?: string;
25
+ }
26
+ export declare function recordProgressHook(options: RecordProgressOptions): Promise<void>;
27
+ /**
28
+ * Initialize progress.json at phase start
29
+ * This function should be called when a change is created, before any files are written.
30
+ * @param changeId - The change ID
31
+ * @param initialPhase - The initial phase to set (default: 'propose')
32
+ */
33
+ export declare function initializeProgress(changeId: string, initialPhase?: Phase): Promise<void>;
34
+ /**
35
+ * Record a hook trigger event
36
+ * This function can be called from other hooks to record their execution
37
+ * @param hookName - The name of the hook (e.g., 'init', 'deviation-check')
38
+ * @param hookPhase - The lifecycle phase (SessionStart, PreToolUse, PostToolUse, Stop)
39
+ * @param success - Whether the hook executed successfully
40
+ * @param options - Additional context (toolName, filePath, message, durationMs)
41
+ */
42
+ export declare function recordHookTrigger(hookName: string, hookPhase: string, success: boolean, options?: {
43
+ toolName?: string;
44
+ filePath?: string;
45
+ message?: string;
46
+ durationMs?: number;
47
+ }): Promise<void>;
48
+ export {};
49
+ //# sourceMappingURL=record-progress.d.ts.map