sumulige-claude 1.1.2 → 1.2.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.
- package/.claude/hooks/code-formatter.cjs +7 -2
- package/.claude/hooks/multi-session.cjs +9 -3
- package/.claude/hooks/pre-commit.cjs +0 -0
- package/.claude/hooks/pre-push.cjs +0 -0
- package/.claude/hooks/project-kickoff.cjs +22 -11
- package/.claude/hooks/rag-skill-loader.cjs +7 -0
- package/.claude/hooks/thinking-silent.cjs +9 -3
- package/.claude/hooks/todo-manager.cjs +19 -13
- package/.claude/hooks/verify-work.cjs +10 -4
- package/.claude/quality-gate.json +9 -3
- package/.claude/settings.local.json +16 -1
- package/.claude/templates/hooks/README.md +302 -0
- package/.claude/templates/hooks/hook.sh.template +94 -0
- package/.claude/templates/hooks/user-prompt-submit.cjs.template +116 -0
- package/.claude/templates/hooks/user-response-submit.cjs.template +94 -0
- package/.claude/templates/hooks/validate.js +173 -0
- package/.claude/workflow/document-scanner.js +426 -0
- package/.claude/workflow/knowledge-engine.js +941 -0
- package/.claude/workflow/notebooklm/browser.js +1028 -0
- package/.claude/workflow/phases/phase1-research.js +578 -0
- package/.claude/workflow/phases/phase1-research.ts +465 -0
- package/.claude/workflow/phases/phase2-approve.js +722 -0
- package/.claude/workflow/phases/phase3-plan.js +1200 -0
- package/.claude/workflow/phases/phase4-develop.js +894 -0
- package/.claude/workflow/search-cache.js +230 -0
- package/.claude/workflow/templates/approval.md +315 -0
- package/.claude/workflow/templates/development.md +377 -0
- package/.claude/workflow/templates/planning.md +328 -0
- package/.claude/workflow/templates/research.md +250 -0
- package/.claude/workflow/types.js +37 -0
- package/.claude/workflow/web-search.js +278 -0
- package/.claude-plugin/marketplace.json +2 -2
- package/AGENTS.md +176 -0
- package/CHANGELOG.md +7 -14
- package/cli.js +20 -0
- package/config/quality-gate.json +9 -3
- package/development/cache/web-search/search_1193d605f8eb364651fc2f2041b58a31.json +36 -0
- package/development/cache/web-search/search_3798bf06960edc125f744a1abb5b72c5.json +36 -0
- package/development/cache/web-search/search_37c7d4843a53f0d83f1122a6f908a2a3.json +36 -0
- package/development/cache/web-search/search_44166fa0153709ee168485a22aa0ab40.json +36 -0
- package/development/cache/web-search/search_4deaebb1f77e86a8ca066dc5a49c59fd.json +36 -0
- package/development/cache/web-search/search_94da91789466070a7f545612e73c7372.json +36 -0
- package/development/cache/web-search/search_dd5de8491b8b803a3cb01339cd210fb0.json +36 -0
- package/development/knowledge-base/.index.clean.json +0 -0
- package/development/knowledge-base/.index.json +486 -0
- package/development/knowledge-base/test-best-practices.md +29 -0
- package/development/projects/proj_mkh1pazz_ixmt1/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4jvnb_z7rwf/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4jxkd_ewz5a/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4k84n_ni73k/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4wfyd_u9w88/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4wsbo_iahvf/development/projects/proj_mkh4xbpg_4na5w/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4wsbo_iahvf/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4xulg_1ka8x/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4xwhj_gch8j/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase2/requirements.md +226 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/PRD.md +345 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/TASK_PLAN.md +284 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/prototype/README.md +14 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/DEVELOPMENT_LOG.md +35 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/TASKS.md +34 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/.env.example +5 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/README.md +60 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/package.json +25 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/index.js +70 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/routes/index.js +48 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/health.test.js +20 -0
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/jest.config.js +21 -0
- package/development/projects/proj_mkh7veqg_3lypc/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh7veqg_3lypc/phase2/requirements.md +226 -0
- package/development/projects/proj_mkh7veqg_3lypc/phase3/PRD.md +345 -0
- package/development/projects/proj_mkh7veqg_3lypc/phase3/TASK_PLAN.md +284 -0
- package/development/projects/proj_mkh7veqg_3lypc/phase3/prototype/README.md +14 -0
- package/development/projects/proj_mkh8k8fo_rmqn5/phase1/feasibility-report.md +160 -0
- package/development/projects/proj_mkh8xyhy_1vshq/phase1/feasibility-report.md +178 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase1/feasibility-report.md +377 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase2/requirements.md +442 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase3/api-design.md +800 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase3/architecture.md +625 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase3/data-model.md +830 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase3/risks.md +957 -0
- package/development/projects/proj_mkh8zddd_dhamf/phase3/wbs.md +381 -0
- package/development/todos/.state.json +14 -1
- package/development/todos/INDEX.md +31 -73
- package/development/todos/completed/develop/local-knowledge-index.md +85 -0
- package/development/todos/{active → completed/develop}/todo-system.md +13 -3
- package/development/todos/completed/develop/web-search-integration.md +83 -0
- package/development/todos/completed/test/phase1-e2e-test.md +103 -0
- package/lib/commands.js +388 -0
- package/package.json +3 -2
- package/tests/config-manager.test.js +677 -0
- package/tests/config-validator.test.js +436 -0
- package/tests/errors.test.js +477 -0
- package/tests/manual/phase1-e2e.sh +389 -0
- package/tests/manual/phase2-test-cases.md +311 -0
- package/tests/manual/phase3-test-cases.md +309 -0
- package/tests/manual/phase4-test-cases.md +414 -0
- package/tests/manual/test-cases.md +417 -0
- package/tests/quality-gate.test.js +679 -0
- package/tests/quality-rules.test.js +619 -0
- package/tests/version-check.test.js +75 -0
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2: Approval - Requirements Clarification & Consensus
|
|
3
|
+
*
|
|
4
|
+
* Input: Phase 1 Feasibility Report
|
|
5
|
+
* Output: Phase 2 Requirements Document
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Configuration
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
const PROJECTS_DIR = path.join(process.cwd(), 'development/projects');
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Approval Validator
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
class ApprovalValidator {
|
|
22
|
+
/**
|
|
23
|
+
* Validate a requirements document from markdown content
|
|
24
|
+
*/
|
|
25
|
+
static validateFromMarkdown(content) {
|
|
26
|
+
const checks = [];
|
|
27
|
+
const blockers = [];
|
|
28
|
+
const warnings = [];
|
|
29
|
+
|
|
30
|
+
// Check 1: Has clear requirements
|
|
31
|
+
const hasClearRequirements =
|
|
32
|
+
content.includes('## Requirements') ||
|
|
33
|
+
content.includes('## 需求') ||
|
|
34
|
+
content.includes('## Functional Requirements') ||
|
|
35
|
+
content.includes('## 功能需求') ||
|
|
36
|
+
content.includes('FR-') ||
|
|
37
|
+
content.match(/需求.*[0-9]/);
|
|
38
|
+
|
|
39
|
+
checks.push({
|
|
40
|
+
name: 'Clear Requirements',
|
|
41
|
+
passed: hasClearRequirements,
|
|
42
|
+
message: hasClearRequirements
|
|
43
|
+
? 'Requirements clearly defined'
|
|
44
|
+
: 'Missing clear requirements section'
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (!hasClearRequirements) {
|
|
48
|
+
blockers.push('Add clear, unambiguous requirements with unique IDs (e.g., FR-001)');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check 2: Has acceptance criteria
|
|
52
|
+
const hasAcceptanceCriteria =
|
|
53
|
+
content.includes('Acceptance Criteria') ||
|
|
54
|
+
content.includes('验收标准') ||
|
|
55
|
+
content.includes('acceptance') ||
|
|
56
|
+
content.includes('Given-When-Then') ||
|
|
57
|
+
content.includes('Gherkin');
|
|
58
|
+
|
|
59
|
+
checks.push({
|
|
60
|
+
name: 'Acceptance Criteria',
|
|
61
|
+
passed: hasAcceptanceCriteria,
|
|
62
|
+
message: hasAcceptanceCriteria
|
|
63
|
+
? 'Acceptance criteria found'
|
|
64
|
+
: 'Missing acceptance criteria for requirements'
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!hasAcceptanceCriteria) {
|
|
68
|
+
blockers.push('Add testable acceptance criteria for each requirement');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Check 3: Has technical rationale
|
|
72
|
+
const hasTechRationale =
|
|
73
|
+
content.includes('Technical Rationale') ||
|
|
74
|
+
content.includes('技术依据') ||
|
|
75
|
+
content.includes('Tech Stack') ||
|
|
76
|
+
content.includes('技术选型') ||
|
|
77
|
+
content.includes('Rationale') ||
|
|
78
|
+
content.includes('理由');
|
|
79
|
+
|
|
80
|
+
checks.push({
|
|
81
|
+
name: 'Technical Rationale',
|
|
82
|
+
passed: hasTechRationale,
|
|
83
|
+
message: hasTechRationale
|
|
84
|
+
? 'Technical choices have rationale'
|
|
85
|
+
: 'Missing rationale for technical choices'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (!hasTechRationale) {
|
|
89
|
+
warnings.push('Add rationale explaining why specific technologies were chosen');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Check 4: Has success metrics
|
|
93
|
+
const hasSuccessMetrics =
|
|
94
|
+
content.includes('Success Metrics') ||
|
|
95
|
+
content.includes('成功指标') ||
|
|
96
|
+
content.includes('Metrics') ||
|
|
97
|
+
content.includes('KPI') ||
|
|
98
|
+
content.match(/指标|衡量|Metrics/);
|
|
99
|
+
|
|
100
|
+
checks.push({
|
|
101
|
+
name: 'Success Metrics',
|
|
102
|
+
passed: hasSuccessMetrics,
|
|
103
|
+
message: hasSuccessMetrics
|
|
104
|
+
? 'Success metrics defined'
|
|
105
|
+
: 'Missing quantifiable success metrics'
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!hasSuccessMetrics) {
|
|
109
|
+
warnings.push('Add quantifiable metrics to measure project success');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check 5: Has edge cases
|
|
113
|
+
const hasEdgeCases =
|
|
114
|
+
content.includes('Edge Cases') ||
|
|
115
|
+
content.includes('边缘情况') ||
|
|
116
|
+
content.includes('edge case') ||
|
|
117
|
+
content.includes('boundary') ||
|
|
118
|
+
content.includes('边界') ||
|
|
119
|
+
content.includes('exception');
|
|
120
|
+
|
|
121
|
+
checks.push({
|
|
122
|
+
name: 'Edge Cases',
|
|
123
|
+
passed: hasEdgeCases,
|
|
124
|
+
message: hasEdgeCases
|
|
125
|
+
? 'Edge cases identified'
|
|
126
|
+
: 'Missing edge case analysis'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
if (!hasEdgeCases) {
|
|
130
|
+
warnings.push('Identify edge cases and exception handling');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Calculate score
|
|
134
|
+
const passedChecks = checks.filter(c => c.passed).length;
|
|
135
|
+
const score = Math.round((passedChecks / checks.length) * 100);
|
|
136
|
+
|
|
137
|
+
// Determine if passed (need at least 80% and no blockers)
|
|
138
|
+
const passed = score >= 80 && blockers.length === 0;
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
passed,
|
|
142
|
+
score,
|
|
143
|
+
checks,
|
|
144
|
+
blockers,
|
|
145
|
+
warnings
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Validate a requirements document file
|
|
151
|
+
*/
|
|
152
|
+
static validateFile(filePath) {
|
|
153
|
+
if (!fs.existsSync(filePath)) {
|
|
154
|
+
return {
|
|
155
|
+
passed: false,
|
|
156
|
+
score: 0,
|
|
157
|
+
checks: [],
|
|
158
|
+
blockers: [`File not found: ${filePath}`],
|
|
159
|
+
warnings: []
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
165
|
+
return this.validateFromMarkdown(content);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
return {
|
|
168
|
+
passed: false,
|
|
169
|
+
score: 0,
|
|
170
|
+
checks: [],
|
|
171
|
+
blockers: [`Failed to read file: ${error.message}`],
|
|
172
|
+
warnings: []
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Generate a validation report for display
|
|
179
|
+
*/
|
|
180
|
+
static generateReport(result) {
|
|
181
|
+
const lines = [];
|
|
182
|
+
|
|
183
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
184
|
+
lines.push(' Requirements Document Validation');
|
|
185
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
186
|
+
lines.push('');
|
|
187
|
+
|
|
188
|
+
// Status
|
|
189
|
+
const status = result.passed ? '✅ PASSED' : '❌ FAILED';
|
|
190
|
+
const statusColor = result.passed ? '🟢' : '🔴';
|
|
191
|
+
lines.push(`Status: ${statusColor} ${status} (Score: ${result.score}/100)`);
|
|
192
|
+
lines.push('');
|
|
193
|
+
|
|
194
|
+
// Checks
|
|
195
|
+
lines.push('Quality Checks:');
|
|
196
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
197
|
+
|
|
198
|
+
result.checks.forEach(check => {
|
|
199
|
+
const icon = check.passed ? '✅' : '❌';
|
|
200
|
+
lines.push(` ${icon} ${check.name}: ${check.message || 'Failed'}`);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
lines.push('');
|
|
204
|
+
|
|
205
|
+
// Blockers
|
|
206
|
+
if (result.blockers.length > 0) {
|
|
207
|
+
lines.push('🚫 BLOCKERS (must fix before proceeding):');
|
|
208
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
209
|
+
result.blockers.forEach((blocker, i) => {
|
|
210
|
+
lines.push(` ${i + 1}. ${blocker}`);
|
|
211
|
+
});
|
|
212
|
+
lines.push('');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Warnings
|
|
216
|
+
if (result.warnings.length > 0) {
|
|
217
|
+
lines.push('⚠️ WARNINGS (recommended improvements):');
|
|
218
|
+
lines.push('───────────────────────────────────────────────────────');
|
|
219
|
+
result.warnings.forEach((warning, i) => {
|
|
220
|
+
lines.push(` ${i + 1}. ${warning}`);
|
|
221
|
+
});
|
|
222
|
+
lines.push('');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Recommendation
|
|
226
|
+
if (result.passed) {
|
|
227
|
+
lines.push('🎉 Requirements document meets quality standards! Ready for Phase 3 (Planning).');
|
|
228
|
+
} else {
|
|
229
|
+
lines.push('📝 Requirements need improvements. Address blockers and re-validate.');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
lines.push('');
|
|
233
|
+
lines.push('═══════════════════════════════════════════════════════');
|
|
234
|
+
|
|
235
|
+
return lines.join('\n');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ============================================================================
|
|
240
|
+
// Phase 2 Approval Executor
|
|
241
|
+
// ============================================================================
|
|
242
|
+
|
|
243
|
+
class Phase2ApprovalExecutor {
|
|
244
|
+
constructor(projectId) {
|
|
245
|
+
this.projectId = projectId;
|
|
246
|
+
this.projectDir = path.join(PROJECTS_DIR, projectId);
|
|
247
|
+
this.phaseDir = path.join(this.projectDir, 'phase2');
|
|
248
|
+
this.requirementsPath = path.join(this.phaseDir, 'requirements.md');
|
|
249
|
+
this.phase1ReportPath = path.join(this.projectDir, 'phase1', 'feasibility-report.md');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Ensure project directories exist
|
|
254
|
+
*/
|
|
255
|
+
ensureDirectories() {
|
|
256
|
+
if (!fs.existsSync(this.phaseDir)) {
|
|
257
|
+
fs.mkdirSync(this.phaseDir, { recursive: true });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Read Phase 1 feasibility report
|
|
263
|
+
*/
|
|
264
|
+
readPhase1Report() {
|
|
265
|
+
if (!fs.existsSync(this.phase1ReportPath)) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
return fs.readFileSync(this.phase1ReportPath, 'utf-8');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Extract key information from Phase 1 report
|
|
273
|
+
*/
|
|
274
|
+
extractPhase1Summary(reportContent) {
|
|
275
|
+
const summary = {
|
|
276
|
+
idea: '',
|
|
277
|
+
requirements: '',
|
|
278
|
+
feasibility: '',
|
|
279
|
+
techStack: [],
|
|
280
|
+
timeEstimate: '',
|
|
281
|
+
risks: []
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
if (!reportContent) return summary;
|
|
285
|
+
|
|
286
|
+
// Extract original idea
|
|
287
|
+
const ideaMatch = reportContent.match(/## Original Idea\s+([\s\S]*?)(?=##|\-{10,})/);
|
|
288
|
+
if (ideaMatch) {
|
|
289
|
+
summary.idea = ideaMatch[1].trim();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Extract requirements summary
|
|
293
|
+
const reqMatch = reportContent.match(/## Requirements Summary\s+([\s\S]*?)(?=##)/);
|
|
294
|
+
if (reqMatch) {
|
|
295
|
+
summary.requirements = reqMatch[1].trim();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Extract feasibility assessment
|
|
299
|
+
const feasMatch = reportContent.match(/## Feasibility Assessment\s+([\s\S]*?)(?=##|---)/);
|
|
300
|
+
if (feasMatch) {
|
|
301
|
+
summary.feasibility = feasMatch[1].trim();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Extract tech stack
|
|
305
|
+
const techMatch = reportContent.match(/Recommended Tech Stack\s+([\s\S]*?)(?=##|---)/);
|
|
306
|
+
if (techMatch) {
|
|
307
|
+
summary.techStack = techMatch[1].trim();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Extract time estimate
|
|
311
|
+
const timeMatch = reportContent.match(/Time Estimate[:\s]*([^\n]+)/);
|
|
312
|
+
if (timeMatch) {
|
|
313
|
+
summary.timeEstimate = timeMatch[1].trim();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return summary;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Generate clarification questions based on Phase 1 report
|
|
321
|
+
*/
|
|
322
|
+
generateClarificationQuestions(phase1Summary) {
|
|
323
|
+
return `## Clarification Questions
|
|
324
|
+
|
|
325
|
+
> Based on the feasibility analysis, the following questions need clarification:
|
|
326
|
+
|
|
327
|
+
### Scope & Priorities
|
|
328
|
+
1. **MVP Scope**: What is the minimum viable scope for the first iteration?
|
|
329
|
+
- [ ] Define core features that must be in v1.0
|
|
330
|
+
- [ ] Identify features that can be deferred to later versions
|
|
331
|
+
|
|
332
|
+
2. **Priority Order**: Which features are highest priority?
|
|
333
|
+
- [ ] Rank features by business value
|
|
334
|
+
- [ ] Identify any dependencies between features
|
|
335
|
+
|
|
336
|
+
### Technical Decisions
|
|
337
|
+
3. **Tech Stack Confirmation**: Confirm the recommended technology choices
|
|
338
|
+
- [ ] Frontend: ${phase1Summary.techStack.includes('Frontend') ? 'See Phase 1' : 'To be decided'}
|
|
339
|
+
- [ ] Backend: ${phase1Summary.techStack.includes('Backend') ? 'See Phase 1' : 'To be decided'}
|
|
340
|
+
- [ ] Any constraints or preferences?
|
|
341
|
+
|
|
342
|
+
4. **Integration Points**: Are there existing systems to integrate with?
|
|
343
|
+
- [ ] APIs to connect to
|
|
344
|
+
- [ ] Data migration needs
|
|
345
|
+
- [ ] Third-party service dependencies
|
|
346
|
+
|
|
347
|
+
### Success Definition
|
|
348
|
+
5. **Success Criteria**: How will we know this project is successful?
|
|
349
|
+
- [ ] Define measurable outcomes
|
|
350
|
+
- [ ] Set success metrics for post-launch
|
|
351
|
+
|
|
352
|
+
### Constraints
|
|
353
|
+
6. **Timeline Constraints**: Any deadline requirements?
|
|
354
|
+
- [ ] Hard deadlines (e.g., launch date)
|
|
355
|
+
- [ ] Time constraints for specific phases
|
|
356
|
+
|
|
357
|
+
7. **Resource Constraints**: Any limitations on resources?
|
|
358
|
+
- [ ] Budget constraints
|
|
359
|
+
- [ ] Team size/skills availability
|
|
360
|
+
- [ ] Infrastructure limitations
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
*Add user responses below each question. Once consensus is reached, proceed to requirements definition.*
|
|
364
|
+
`;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Generate requirements document template
|
|
369
|
+
*/
|
|
370
|
+
generateRequirementsTemplate(phase1Summary) {
|
|
371
|
+
const date = new Date().toLocaleDateString();
|
|
372
|
+
const time = new Date().toLocaleTimeString();
|
|
373
|
+
|
|
374
|
+
// Extract basic info from Phase 1
|
|
375
|
+
const idea = phase1Summary.idea || '[From Phase 1 Report]';
|
|
376
|
+
const feasibility = phase1Summary.feasibility || '[From Phase 1 Report]';
|
|
377
|
+
|
|
378
|
+
return `# Requirements Document
|
|
379
|
+
|
|
380
|
+
**Project**: ${this.projectId}
|
|
381
|
+
**Date**: ${date} ${time}
|
|
382
|
+
**Phase**: 2 - Approval
|
|
383
|
+
**Status**: 🚧 In Progress
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Executive Summary
|
|
388
|
+
|
|
389
|
+
> Brief overview of the approved requirements
|
|
390
|
+
|
|
391
|
+
**Based on**: Phase 1 Feasibility Report (\`../phase1/feasibility-report.md\`)
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Phase 1 Summary
|
|
396
|
+
|
|
397
|
+
### Original Idea
|
|
398
|
+
${idea}
|
|
399
|
+
|
|
400
|
+
### Feasibility Assessment
|
|
401
|
+
${feasibility}
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Clarification Questions & Responses
|
|
406
|
+
|
|
407
|
+
${this.generateClarificationQuestions(phase1Summary)}
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Functional Requirements
|
|
412
|
+
|
|
413
|
+
### FR-001: [Requirement Title]
|
|
414
|
+
|
|
415
|
+
**Description**: [Clear, unambiguous description of what the system should do]
|
|
416
|
+
|
|
417
|
+
**Priority**: Must Have / Should Have / Could Have / Won't Have
|
|
418
|
+
|
|
419
|
+
**Acceptance Criteria**:
|
|
420
|
+
- [ ] Given [context], when [action], then [outcome]
|
|
421
|
+
- [ ] Given [context], when [action], then [outcome]
|
|
422
|
+
- [ ] Given [context], when [action], then [outcome]
|
|
423
|
+
|
|
424
|
+
**Dependencies**: [Other requirements or systems this depends on]
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
### FR-002: [Requirement Title]
|
|
429
|
+
|
|
430
|
+
**Description**: [Clear, unambiguous description]
|
|
431
|
+
|
|
432
|
+
**Priority**: Must Have / Should Have / Could Have / Won't Have
|
|
433
|
+
|
|
434
|
+
**Acceptance Criteria**:
|
|
435
|
+
- [ ] Given [context], when [action], then [outcome]
|
|
436
|
+
- [ ] Given [context], when [action], then [outcome]
|
|
437
|
+
|
|
438
|
+
**Dependencies**: [List dependencies]
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Non-Functional Requirements
|
|
443
|
+
|
|
444
|
+
### Performance
|
|
445
|
+
- **Response Time**: [e.g., API requests < 200ms p95]
|
|
446
|
+
- **Throughput**: [e.g., 1000 concurrent users]
|
|
447
|
+
- **Resource Limits**: [e.g., Memory < 512MB]
|
|
448
|
+
|
|
449
|
+
### Security
|
|
450
|
+
- **Authentication**: [e.g., JWT tokens, OAuth 2.0]
|
|
451
|
+
- **Authorization**: [e.g., Role-based access control]
|
|
452
|
+
- **Data Protection**: [e.g., Encryption at rest and in transit]
|
|
453
|
+
|
|
454
|
+
### Reliability
|
|
455
|
+
- **Uptime Target**: [e.g., 99.9% availability]
|
|
456
|
+
- **Failure Handling**: [Graceful degradation strategy]
|
|
457
|
+
|
|
458
|
+
### Maintainability
|
|
459
|
+
- **Code Quality**: [e.g., Test coverage > 80%]
|
|
460
|
+
- **Documentation**: [API documentation, code comments]
|
|
461
|
+
|
|
462
|
+
### Compatibility
|
|
463
|
+
- **Browsers**: [Supported browser versions]
|
|
464
|
+
- **Platforms**: [Supported operating systems]
|
|
465
|
+
- **API Versions**: [Versioning strategy]
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Success Metrics
|
|
470
|
+
|
|
471
|
+
### User Engagement
|
|
472
|
+
| Metric | Target | Measurement Method |
|
|
473
|
+
|--------|--------|-------------------|
|
|
474
|
+
| [e.g., Daily Active Users] | [value] | [analytics tool] |
|
|
475
|
+
| [e.g., Session Duration] | [value] | [analytics tool] |
|
|
476
|
+
|
|
477
|
+
### Technical Performance
|
|
478
|
+
| Metric | Target | Measurement Method |
|
|
479
|
+
|--------|--------|-------------------|
|
|
480
|
+
| [e.g., Page Load Time] | [value] | [monitoring tool] |
|
|
481
|
+
| [e.g., Error Rate] | [value] | [monitoring tool] |
|
|
482
|
+
|
|
483
|
+
### Business Outcomes
|
|
484
|
+
| Metric | Target | Measurement Method |
|
|
485
|
+
|--------|--------|-------------------|
|
|
486
|
+
| [e.g., Conversion Rate] | [value] | [analytics tool] |
|
|
487
|
+
| [e.g., Customer Satisfaction] | [value] | [survey] |
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Edge Cases & Constraints
|
|
492
|
+
|
|
493
|
+
### Edge Cases
|
|
494
|
+
- [Edge Case 1]: [Handling strategy]
|
|
495
|
+
- [Edge Case 2]: [Handling strategy]
|
|
496
|
+
- [Edge Case 3]: [Handling strategy]
|
|
497
|
+
|
|
498
|
+
### Constraints
|
|
499
|
+
- **Technical**: [Technical limitations]
|
|
500
|
+
- **Business**: [Business rules or constraints]
|
|
501
|
+
- **Legal**: [Compliance requirements]
|
|
502
|
+
- **Timeline**: [Deadline constraints]
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## Assumptions & Dependencies
|
|
507
|
+
|
|
508
|
+
### Assumptions
|
|
509
|
+
- [Assumption 1]: [Impact if false]
|
|
510
|
+
- [Assumption 2]: [Impact if false]
|
|
511
|
+
|
|
512
|
+
### Dependencies
|
|
513
|
+
- **Internal**: [Internal system dependencies]
|
|
514
|
+
- **External**: [Third-party services or APIs]
|
|
515
|
+
- **Team**: [Required team roles or skills]
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Out of Scope
|
|
520
|
+
|
|
521
|
+
Explicitly list what is NOT included in this phase:
|
|
522
|
+
|
|
523
|
+
- [Out of Scope Item 1]: [Reason for exclusion]
|
|
524
|
+
- [Out of Scope Item 2]: [Reason for exclusion]
|
|
525
|
+
- [Out of Scope Item 3]: [Reason for exclusion]
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## Approval Checklist
|
|
530
|
+
|
|
531
|
+
- [x] Requirements are clear and unambiguous
|
|
532
|
+
- [ ] Acceptance criteria are testable
|
|
533
|
+
- [ ] Technical rationale is documented
|
|
534
|
+
- [ ] Success metrics are quantifiable
|
|
535
|
+
- [ ] Edge cases are identified
|
|
536
|
+
- [ ] Constraints are documented
|
|
537
|
+
- [ ] Stakeholder consensus achieved
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Next Steps (Phase 3: Planning)
|
|
542
|
+
|
|
543
|
+
1. [ ] Review requirements with all stakeholders
|
|
544
|
+
2. [ ] Run quality gate: \`smc workflow validate ${this.requirementsPath}\`
|
|
545
|
+
3. [ ] Address any blockers identified
|
|
546
|
+
4. [ ] Proceed to Phase 3 for detailed design and planning
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
## Metadata
|
|
551
|
+
|
|
552
|
+
- **Generated**: ${date} ${time}
|
|
553
|
+
- **Phase 1 Report**: \`../phase1/feasibility-report.md\`
|
|
554
|
+
- **Confidence Level**: [To be filled by AI]
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
*This document was generated by the Phase 2 Approval Executor.*
|
|
559
|
+
`;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Execute Phase 2 approval workflow
|
|
564
|
+
*/
|
|
565
|
+
async execute(progressCallback) {
|
|
566
|
+
await progressCallback?.('Initializing Phase 2 approval...', 0, 5);
|
|
567
|
+
|
|
568
|
+
// Ensure directories exist
|
|
569
|
+
this.ensureDirectories();
|
|
570
|
+
|
|
571
|
+
// Step 1: Read Phase 1 report
|
|
572
|
+
await progressCallback?.('Reading Phase 1 feasibility report...', 1, 5);
|
|
573
|
+
const phase1Report = this.readPhase1Report();
|
|
574
|
+
|
|
575
|
+
if (!phase1Report) {
|
|
576
|
+
throw new Error(`Phase 1 report not found: ${this.phase1ReportPath}`);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Step 2: Extract summary
|
|
580
|
+
await progressCallback?.('Analyzing feasibility report...', 2, 5);
|
|
581
|
+
const phase1Summary = this.extractPhase1Summary(phase1Report);
|
|
582
|
+
|
|
583
|
+
// Step 3: Generate requirements template
|
|
584
|
+
await progressCallback?.('Generating requirements document template...', 3, 5);
|
|
585
|
+
|
|
586
|
+
const requirementsTemplate = this.generateRequirementsTemplate(phase1Summary);
|
|
587
|
+
await fs.promises.writeFile(this.requirementsPath, requirementsTemplate, 'utf-8');
|
|
588
|
+
|
|
589
|
+
await progressCallback?.('Phase 2 approval context prepared. Ready for requirements definition.', 4, 5);
|
|
590
|
+
|
|
591
|
+
return {
|
|
592
|
+
projectId: this.projectId,
|
|
593
|
+
requirementsPath: this.requirementsPath,
|
|
594
|
+
phase1Summary,
|
|
595
|
+
nextSteps: [
|
|
596
|
+
'Review and answer clarification questions',
|
|
597
|
+
'Define functional requirements with acceptance criteria',
|
|
598
|
+
'Validate with: smc workflow validate',
|
|
599
|
+
'Proceed to Phase 3'
|
|
600
|
+
]
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Check if requirements document exists
|
|
606
|
+
*/
|
|
607
|
+
requirementsExist() {
|
|
608
|
+
return fs.existsSync(this.requirementsPath);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Read the existing requirements document
|
|
613
|
+
*/
|
|
614
|
+
readRequirements() {
|
|
615
|
+
if (!this.requirementsExist()) return null;
|
|
616
|
+
return fs.readFileSync(this.requirementsPath, 'utf-8');
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Validate the requirements document
|
|
621
|
+
*/
|
|
622
|
+
validateRequirements() {
|
|
623
|
+
return ApprovalValidator.validateFile(this.requirementsPath);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* Get the requirements path
|
|
628
|
+
*/
|
|
629
|
+
getRequirementsPath() {
|
|
630
|
+
return this.requirementsPath;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Get current phase information
|
|
635
|
+
*/
|
|
636
|
+
getPhaseInfo() {
|
|
637
|
+
return {
|
|
638
|
+
phase: 2,
|
|
639
|
+
name: 'Approval',
|
|
640
|
+
description: 'Requirements clarification and consensus',
|
|
641
|
+
input: 'Phase 1 Feasibility Report',
|
|
642
|
+
output: 'Phase 2 Requirements Document',
|
|
643
|
+
status: this.requirementsExist() ? 'In Progress' : 'Not Started',
|
|
644
|
+
files: {
|
|
645
|
+
requirements: this.requirementsPath,
|
|
646
|
+
phase1Report: this.phase1ReportPath
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// ============================================================================
|
|
653
|
+
// Project Management Helpers
|
|
654
|
+
// ============================================================================
|
|
655
|
+
|
|
656
|
+
function getProjectPhaseInfo(projectId, phase) {
|
|
657
|
+
const projectDir = path.join(PROJECTS_DIR, projectId);
|
|
658
|
+
|
|
659
|
+
if (!fs.existsSync(projectDir)) {
|
|
660
|
+
return null;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const phaseDir = path.join(projectDir, `phase${phase}`);
|
|
664
|
+
|
|
665
|
+
return {
|
|
666
|
+
projectId,
|
|
667
|
+
phase,
|
|
668
|
+
phaseDir,
|
|
669
|
+
exists: fs.existsSync(phaseDir),
|
|
670
|
+
files: phase === 1 ? {
|
|
671
|
+
report: path.join(phaseDir, 'feasibility-report.md')
|
|
672
|
+
} : phase === 2 ? {
|
|
673
|
+
requirements: path.join(phaseDir, 'requirements.md')
|
|
674
|
+
} : {}
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function listProjectsWithPhase() {
|
|
679
|
+
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
680
|
+
return [];
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const projects = [];
|
|
684
|
+
const entries = fs.readdirSync(PROJECTS_DIR, { withFileTypes: true });
|
|
685
|
+
|
|
686
|
+
for (const entry of entries) {
|
|
687
|
+
if (entry.isDirectory() && entry.name.startsWith('proj_')) {
|
|
688
|
+
const projectPath = path.join(PROJECTS_DIR, entry.name);
|
|
689
|
+
const phase1Report = path.join(projectPath, 'phase1', 'feasibility-report.md');
|
|
690
|
+
const phase2Requirements = path.join(projectPath, 'phase2', 'requirements.md');
|
|
691
|
+
|
|
692
|
+
let currentPhase = 1;
|
|
693
|
+
let status = 'draft';
|
|
694
|
+
|
|
695
|
+
if (fs.existsSync(phase2Requirements)) {
|
|
696
|
+
currentPhase = 2;
|
|
697
|
+
status = 'in_progress';
|
|
698
|
+
} else if (fs.existsSync(phase1Report)) {
|
|
699
|
+
currentPhase = 1;
|
|
700
|
+
status = 'review';
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
projects.push({
|
|
704
|
+
id: entry.name,
|
|
705
|
+
path: projectPath,
|
|
706
|
+
currentPhase,
|
|
707
|
+
status,
|
|
708
|
+
hasPhase1: fs.existsSync(phase1Report),
|
|
709
|
+
hasPhase2: fs.existsSync(phase2Requirements)
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
return projects.sort((a, b) => b.id.localeCompare(a.id));
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
module.exports = {
|
|
718
|
+
Phase2ApprovalExecutor,
|
|
719
|
+
ApprovalValidator,
|
|
720
|
+
getProjectPhaseInfo,
|
|
721
|
+
listProjectsWithPhase
|
|
722
|
+
};
|