create-sdd-project 0.2.4 → 0.3.3
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/README.md +10 -10
- package/lib/config.js +1 -1
- package/lib/generator.js +144 -27
- package/lib/init-generator.js +321 -41
- package/lib/init-wizard.js +1 -1
- package/package.json +1 -1
- package/template/.claude/agents/backend-developer.md +1 -1
- package/template/.claude/agents/frontend-developer.md +1 -1
- package/template/.claude/settings.json +1 -1
- package/template/.claude/skills/bug-workflow/SKILL.md +2 -2
- package/template/.claude/skills/development-workflow/SKILL.md +18 -18
- package/template/.claude/skills/development-workflow/references/add-feature-template.md +16 -0
- package/template/.claude/skills/development-workflow/references/branching-strategy.md +1 -1
- package/template/.claude/skills/development-workflow/references/complexity-guide.md +6 -6
- package/template/.claude/skills/development-workflow/references/failure-handling.md +3 -3
- package/template/.claude/skills/development-workflow/references/pr-template.md +3 -3
- package/template/.claude/skills/development-workflow/references/ticket-template.md +3 -3
- package/template/.claude/skills/development-workflow/references/workflow-example.md +7 -7
- package/template/.claude/skills/project-memory/SKILL.md +9 -9
- package/template/.gemini/agents/backend-developer.md +1 -1
- package/template/.gemini/agents/frontend-developer.md +1 -1
- package/template/.gemini/commands/add-feature.toml +2 -0
- package/template/.gemini/commands/next-task.toml +2 -2
- package/template/.gemini/commands/show-progress.toml +2 -2
- package/template/.gemini/commands/start-task.toml +1 -1
- package/template/.gemini/skills/bug-workflow/SKILL.md +4 -4
- package/template/.gemini/skills/development-workflow/SKILL.md +18 -18
- package/template/.gemini/skills/development-workflow/references/add-feature-template.md +16 -0
- package/template/.gemini/skills/development-workflow/references/branching-strategy.md +1 -1
- package/template/.gemini/skills/development-workflow/references/complexity-guide.md +6 -6
- package/template/.gemini/skills/development-workflow/references/failure-handling.md +3 -3
- package/template/.gemini/skills/development-workflow/references/pr-template.md +3 -3
- package/template/.gemini/skills/development-workflow/references/ticket-template.md +3 -3
- package/template/.gemini/skills/development-workflow/references/workflow-example.md +7 -7
- package/template/.gemini/skills/project-memory/SKILL.md +8 -8
- package/template/AGENTS.md +6 -6
- package/template/CLAUDE.md +2 -2
- package/template/ai-specs/specs/base-standards.mdc +8 -8
- package/template/docs/project_notes/product-tracker.md +56 -0
- package/template/.claude/skills/development-workflow/references/sprint-init-template.md +0 -82
- package/template/.gemini/commands/init-sprint.toml +0 -2
- package/template/.gemini/skills/development-workflow/references/sprint-init-template.md +0 -82
- package/template/docs/project_notes/sprint-0-tracker.md +0 -66
package/lib/init-generator.js
CHANGED
|
@@ -35,12 +35,15 @@ function generateInit(config) {
|
|
|
35
35
|
step('Creating ai-specs/specs/ (4 standards files)');
|
|
36
36
|
ensureDir(path.join(dest, 'ai-specs', 'specs'));
|
|
37
37
|
|
|
38
|
-
// base-standards
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
path.join(
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
// base-standards: adapt validation references based on detected stack
|
|
39
|
+
const baseStdPath = path.join(dest, 'ai-specs', 'specs', 'base-standards.mdc');
|
|
40
|
+
if (!fs.existsSync(baseStdPath)) {
|
|
41
|
+
const baseTemplate = fs.readFileSync(path.join(templateDir, 'ai-specs', 'specs', 'base-standards.mdc'), 'utf8');
|
|
42
|
+
const adaptedBase = adaptBaseStandards(baseTemplate, scan, config);
|
|
43
|
+
fs.writeFileSync(baseStdPath, adaptedBase, 'utf8');
|
|
44
|
+
} else {
|
|
45
|
+
skipped.push('ai-specs/specs/base-standards.mdc');
|
|
46
|
+
}
|
|
44
47
|
copyFileIfNotExists(
|
|
45
48
|
path.join(templateDir, 'ai-specs', 'specs', 'documentation-standards.mdc'),
|
|
46
49
|
path.join(dest, 'ai-specs', 'specs', 'documentation-standards.mdc'),
|
|
@@ -72,7 +75,7 @@ function generateInit(config) {
|
|
|
72
75
|
}
|
|
73
76
|
|
|
74
77
|
// 3. Copy and configure docs/
|
|
75
|
-
step('Creating docs/project_notes/ (
|
|
78
|
+
step('Creating docs/project_notes/ (product tracker, memory)');
|
|
76
79
|
ensureDir(path.join(dest, 'docs', 'project_notes'));
|
|
77
80
|
ensureDir(path.join(dest, 'docs', 'specs'));
|
|
78
81
|
ensureDir(path.join(dest, 'docs', 'tickets'));
|
|
@@ -99,14 +102,14 @@ function generateInit(config) {
|
|
|
99
102
|
skipped
|
|
100
103
|
);
|
|
101
104
|
|
|
102
|
-
//
|
|
103
|
-
const trackerPath = path.join(dest, 'docs', 'project_notes', '
|
|
105
|
+
// product-tracker.md — configure and add retrofit tasks
|
|
106
|
+
const trackerPath = path.join(dest, 'docs', 'project_notes', 'product-tracker.md');
|
|
104
107
|
if (!fs.existsSync(trackerPath)) {
|
|
105
|
-
const template = fs.readFileSync(path.join(templateDir, 'docs', 'project_notes', '
|
|
106
|
-
const configured =
|
|
108
|
+
const template = fs.readFileSync(path.join(templateDir, 'docs', 'project_notes', 'product-tracker.md'), 'utf8');
|
|
109
|
+
const configured = configureProductTracker(template, scan);
|
|
107
110
|
fs.writeFileSync(trackerPath, configured, 'utf8');
|
|
108
111
|
} else {
|
|
109
|
-
skipped.push('docs/project_notes/
|
|
112
|
+
skipped.push('docs/project_notes/product-tracker.md');
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
// docs/specs/
|
|
@@ -174,6 +177,9 @@ function generateInit(config) {
|
|
|
174
177
|
removeAgentFiles(dest, BACKEND_AGENTS, config);
|
|
175
178
|
}
|
|
176
179
|
|
|
180
|
+
// 7b. Adapt agent/skill content to match detected stack
|
|
181
|
+
adaptCopiedFiles(dest, scan, config);
|
|
182
|
+
|
|
177
183
|
// 8. Append to .gitignore
|
|
178
184
|
appendGitignore(dest, skipped);
|
|
179
185
|
|
|
@@ -195,7 +201,7 @@ function generateInit(config) {
|
|
|
195
201
|
|
|
196
202
|
// Show review notes
|
|
197
203
|
console.log('');
|
|
198
|
-
console.log(' ⚠ REVIEW BEFORE YOUR FIRST
|
|
204
|
+
console.log(' ⚠ REVIEW BEFORE YOUR FIRST FEATURE:');
|
|
199
205
|
if (config.projectType !== 'frontend') {
|
|
200
206
|
console.log(' - ai-specs/specs/backend-standards.mdc — Architecture section adapted from scan');
|
|
201
207
|
}
|
|
@@ -214,7 +220,7 @@ function generateInit(config) {
|
|
|
214
220
|
} else {
|
|
215
221
|
console.log(` 📝 Test coverage appears low (${fileCount} test files found).`);
|
|
216
222
|
}
|
|
217
|
-
console.log(' Consider
|
|
223
|
+
console.log(' Consider adding retrofit testing as your first feature.');
|
|
218
224
|
}
|
|
219
225
|
|
|
220
226
|
// Prisma schema note
|
|
@@ -226,7 +232,7 @@ function generateInit(config) {
|
|
|
226
232
|
// Done
|
|
227
233
|
console.log(`\nDone! Next steps:`);
|
|
228
234
|
console.log(` git add -A && git commit -m "chore: add SDD DevFlow to existing project"`);
|
|
229
|
-
console.log(` # Open in your AI coding tool and run:
|
|
235
|
+
console.log(` # Open in your AI coding tool and run: add feature "your first feature"\n`);
|
|
230
236
|
}
|
|
231
237
|
|
|
232
238
|
// --- Helpers ---
|
|
@@ -288,8 +294,288 @@ function safeDelete(filePath) {
|
|
|
288
294
|
try { fs.unlinkSync(filePath); } catch { /* ignore */ }
|
|
289
295
|
}
|
|
290
296
|
|
|
297
|
+
// --- Adapt Copied Agent/Skill Files ---
|
|
298
|
+
|
|
299
|
+
function replaceInCopiedFile(dest, relativePath, replacements) {
|
|
300
|
+
const filePath = path.join(dest, relativePath);
|
|
301
|
+
if (!fs.existsSync(filePath)) return;
|
|
302
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
303
|
+
for (const [from, to] of replacements) {
|
|
304
|
+
content = content.replaceAll(from, to);
|
|
305
|
+
}
|
|
306
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function regexReplaceInFile(filePath, replacements) {
|
|
310
|
+
if (!fs.existsSync(filePath)) return;
|
|
311
|
+
let content = fs.readFileSync(filePath, 'utf8');
|
|
312
|
+
for (const [from, to] of replacements) {
|
|
313
|
+
if (from instanceof RegExp) {
|
|
314
|
+
content = content.replace(from, to);
|
|
315
|
+
} else {
|
|
316
|
+
content = content.replaceAll(from, to);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function adaptCopiedFiles(dest, scan, config) {
|
|
323
|
+
const orm = scan.backend.orm || 'your ORM';
|
|
324
|
+
const db = scan.backend.db || 'your database';
|
|
325
|
+
|
|
326
|
+
// Common Zod → generic validation replacements (all agents + skills)
|
|
327
|
+
// Order: most specific first, catch-all last
|
|
328
|
+
const zodReplacements = [
|
|
329
|
+
['Zod data schemas', 'validation schemas'],
|
|
330
|
+
['Zod schemas', 'validation schemas'],
|
|
331
|
+
];
|
|
332
|
+
|
|
333
|
+
// ORM/DB replacements for backend agents
|
|
334
|
+
const ormReplacements = scan.backend.orm && scan.backend.orm !== 'Prisma'
|
|
335
|
+
? [
|
|
336
|
+
['Prisma ORM, and PostgreSQL', `${orm}${db !== 'your database' ? `, and ${db}` : ''}`],
|
|
337
|
+
['Repository implementations (Prisma)', `Repository implementations (${orm})`],
|
|
338
|
+
]
|
|
339
|
+
: [];
|
|
340
|
+
|
|
341
|
+
// Apply to all AI tool directories
|
|
342
|
+
const toolDirs = [];
|
|
343
|
+
if (config.aiTools !== 'gemini') toolDirs.push('.claude');
|
|
344
|
+
if (config.aiTools !== 'claude') toolDirs.push('.gemini');
|
|
345
|
+
|
|
346
|
+
for (const dir of toolDirs) {
|
|
347
|
+
// Backend agents: Zod + ORM replacements
|
|
348
|
+
if (scan.backend.validation !== 'Zod') {
|
|
349
|
+
const backendAgentReplacements = [...zodReplacements, ...ormReplacements];
|
|
350
|
+
replaceInCopiedFile(dest, `${dir}/agents/backend-developer.md`, backendAgentReplacements);
|
|
351
|
+
replaceInCopiedFile(dest, `${dir}/agents/backend-planner.md`, backendAgentReplacements);
|
|
352
|
+
} else if (ormReplacements.length > 0) {
|
|
353
|
+
// Zod detected but different ORM — only ORM replacements
|
|
354
|
+
replaceInCopiedFile(dest, `${dir}/agents/backend-developer.md`, ormReplacements);
|
|
355
|
+
replaceInCopiedFile(dest, `${dir}/agents/backend-planner.md`, ormReplacements);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Multi-purpose agents: Zod replacements only
|
|
359
|
+
if (scan.backend.validation !== 'Zod') {
|
|
360
|
+
replaceInCopiedFile(dest, `${dir}/agents/spec-creator.md`, zodReplacements);
|
|
361
|
+
replaceInCopiedFile(dest, `${dir}/agents/production-code-validator.md`, zodReplacements);
|
|
362
|
+
replaceInCopiedFile(dest, `${dir}/agents/database-architect.md`, zodReplacements);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Skills: Zod replacements
|
|
366
|
+
if (scan.backend.validation !== 'Zod') {
|
|
367
|
+
replaceInCopiedFile(dest, `${dir}/skills/development-workflow/SKILL.md`, zodReplacements);
|
|
368
|
+
replaceInCopiedFile(dest, `${dir}/skills/development-workflow/references/ticket-template.md`, zodReplacements);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Architecture adaptation: DDD-specific content in backend agents
|
|
373
|
+
const arch = scan.srcStructure ? scan.srcStructure.pattern : 'ddd';
|
|
374
|
+
if (arch !== 'ddd') {
|
|
375
|
+
for (const dir of toolDirs) {
|
|
376
|
+
// backend-planner: adapt header, exploration paths, implementation order, rules
|
|
377
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'backend-planner.md'), [
|
|
378
|
+
// Header: remove DDD reference, use generic
|
|
379
|
+
['specializing in Domain-Driven Design (DDD) layered architecture with deep knowledge of',
|
|
380
|
+
'specializing in layered architecture with deep knowledge of'],
|
|
381
|
+
// Exploration paths: replace DDD-specific with generic
|
|
382
|
+
[/4\. Read `shared\/src\/schemas\/` \(if exists\) for current .* data schemas\n/, ''],
|
|
383
|
+
[/5\. Explore `backend\/src\/domain\/` for existing entities and errors\n/,
|
|
384
|
+
'5. Explore the codebase for existing patterns, layer structure, and reusable code\n'],
|
|
385
|
+
[/6\. Explore `backend\/src\/application\/services\/` for existing services\n/, ''],
|
|
386
|
+
[/7\. Explore `backend\/src\/application\/validators\/` for existing validators\n/, ''],
|
|
387
|
+
[/8\. Explore `backend\/src\/infrastructure\/` for existing repositories\n/, ''],
|
|
388
|
+
// Implementation Order
|
|
389
|
+
['following DDD layer order: Domain > Application > Infrastructure > Presentation > Tests',
|
|
390
|
+
'following the layer order defined in backend-standards.mdc'],
|
|
391
|
+
// Rules
|
|
392
|
+
['Follow DDD layer separation: Domain > Application > Infrastructure > Presentation',
|
|
393
|
+
'Follow the layer separation defined in backend-standards.mdc'],
|
|
394
|
+
]);
|
|
395
|
+
// backend-developer: adapt frontmatter, header, exploration, implementation order, rules
|
|
396
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'backend-developer.md'), [
|
|
397
|
+
['follows DDD layered architecture',
|
|
398
|
+
'follows layered architecture'],
|
|
399
|
+
['specializing in Domain-Driven Design (DDD) with',
|
|
400
|
+
'specializing in layered architecture with'],
|
|
401
|
+
[/4\. Read `shared\/src\/schemas\/` \(if exists\) for current .* data schemas\n/, ''],
|
|
402
|
+
// Implementation Order section: replace DDD layers with generic guidance
|
|
403
|
+
['Follow the DDD layer order from the plan:',
|
|
404
|
+
'Follow the layer order from the plan (see backend-standards.mdc for project layers):'],
|
|
405
|
+
[/1\. \*\*Domain Layer\*\*: Entities, value objects, repository interfaces, domain errors\n/,
|
|
406
|
+
'1. **Data Layer**: Models, database operations, data access\n'],
|
|
407
|
+
[/2\. \*\*Application Layer\*\*: Services, validators, DTOs\n/,
|
|
408
|
+
'2. **Business Logic Layer**: Controllers, services, external integrations\n'],
|
|
409
|
+
[/3\. \*\*Infrastructure Layer\*\*: Repository implementations \([^)]*\), external integrations\n/,
|
|
410
|
+
'3. **Presentation Layer**: Routes, handlers, middleware\n'],
|
|
411
|
+
[/4\. \*\*Presentation Layer\*\*: Controllers, routes, middleware\n/,
|
|
412
|
+
'4. **Integration Layer**: Wiring, configuration, server registration\n'],
|
|
413
|
+
// Rules
|
|
414
|
+
['**ALWAYS** follow DDD layer separation',
|
|
415
|
+
'**ALWAYS** follow the layer separation defined in backend-standards.mdc'],
|
|
416
|
+
['**ALWAYS** handle errors with custom domain error classes',
|
|
417
|
+
'**ALWAYS** handle errors following the patterns in backend-standards.mdc'],
|
|
418
|
+
// Documentation
|
|
419
|
+
[/- \*\*MANDATORY\*\*: If modifying a DB schema → update .* schemas in `shared\/src\/schemas\/` BEFORE continuing\n/, ''],
|
|
420
|
+
]);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Agent content: remove frontend/backend-specific references for single-stack projects
|
|
425
|
+
if (config.projectType === 'backend') {
|
|
426
|
+
for (const dir of toolDirs) {
|
|
427
|
+
// spec-creator: remove Frontend Specifications section and UI output format
|
|
428
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'spec-creator.md'), [
|
|
429
|
+
[/### Frontend Specifications\n(?:- [^\n]*\n)+\n/, ''],
|
|
430
|
+
[/### For UI Changes\n```markdown\n(?:[^\n]*\n)*?```\n\n/, ''],
|
|
431
|
+
['Data Model Changes, UI Changes, Edge Cases', 'Data Model Changes, Edge Cases'],
|
|
432
|
+
]);
|
|
433
|
+
// production-code-validator: remove ui-components line from Spec Drift
|
|
434
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'production-code-validator.md'), [
|
|
435
|
+
[/- Components exported\/used that are NOT listed in `docs\/specs\/ui-components\.md`\n/, ''],
|
|
436
|
+
]);
|
|
437
|
+
// code-review-specialist: backend-only standards ref, remove ui-components
|
|
438
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'code-review-specialist.md'), [
|
|
439
|
+
['(`backend-standards.mdc` / `frontend-standards.mdc`)', '(`backend-standards.mdc`)'],
|
|
440
|
+
['(`api-spec.yaml`, `ui-components.md`)', '(`api-spec.yaml`)'],
|
|
441
|
+
]);
|
|
442
|
+
// qa-engineer: remove ui-components from specs, remove frontend test command
|
|
443
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'qa-engineer.md'), [
|
|
444
|
+
['(`api-spec.yaml`, `ui-components.md`)', '(`api-spec.yaml`)'],
|
|
445
|
+
[/- Frontend: `cd frontend && npm test`\n/, ''],
|
|
446
|
+
[/- \*\*Frontend\*\*: Write tests for error states[^\n]*\n/, ''],
|
|
447
|
+
]);
|
|
448
|
+
}
|
|
449
|
+
} else if (config.projectType === 'frontend') {
|
|
450
|
+
for (const dir of toolDirs) {
|
|
451
|
+
// spec-creator: remove Backend Specifications section
|
|
452
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'spec-creator.md'), [
|
|
453
|
+
[/### Backend Specifications\n(?:- [^\n]*\n)+\n/, ''],
|
|
454
|
+
[/### For API Changes\n```yaml\n(?:[^\n]*\n)*?```\n\n/, ''],
|
|
455
|
+
]);
|
|
456
|
+
// code-review-specialist: frontend-only standards ref
|
|
457
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'code-review-specialist.md'), [
|
|
458
|
+
['(`backend-standards.mdc` / `frontend-standards.mdc`)', '(`frontend-standards.mdc`)'],
|
|
459
|
+
['(`api-spec.yaml`, `ui-components.md`)', '(`ui-components.md`)'],
|
|
460
|
+
]);
|
|
461
|
+
// qa-engineer: remove api-spec from specs, remove backend test command
|
|
462
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'qa-engineer.md'), [
|
|
463
|
+
['(`api-spec.yaml`, `ui-components.md`)', '(`ui-components.md`)'],
|
|
464
|
+
[/- Backend: `cd backend && npm test`\n/, ''],
|
|
465
|
+
[/- \*\*Backend\*\*: Write tests for error paths[^\n]*\n/, ''],
|
|
466
|
+
]);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// Skills and templates: remove frontend/backend-specific references
|
|
471
|
+
if (config.projectType === 'backend') {
|
|
472
|
+
for (const dir of toolDirs) {
|
|
473
|
+
// Gemini agents have different text patterns
|
|
474
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'spec-creator.md'), [
|
|
475
|
+
[/\(api-spec\.yaml, ui-components\.md\)/, '(api-spec.yaml)'],
|
|
476
|
+
['Data Model Changes, UI Changes, Edge Cases', 'Data Model Changes, Edge Cases'],
|
|
477
|
+
]);
|
|
478
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'production-code-validator.md'), [
|
|
479
|
+
[/,? components not in ui-components\.md/, ''],
|
|
480
|
+
]);
|
|
481
|
+
// SKILL.md: remove ui-components references
|
|
482
|
+
regexReplaceInFile(path.join(dest, dir, 'skills', 'development-workflow', 'SKILL.md'), [
|
|
483
|
+
[/,? `ui-components\.md`\)/, ')'],
|
|
484
|
+
[/- UI components → `docs\/specs\/ui-components\.md` \(MANDATORY\)\n/, ''],
|
|
485
|
+
]);
|
|
486
|
+
// ticket-template: remove UI Changes section, ui-components from checklists
|
|
487
|
+
regexReplaceInFile(path.join(dest, dir, 'skills', 'development-workflow', 'references', 'ticket-template.md'), [
|
|
488
|
+
[/### UI Changes \(if applicable\)\n\n\[Components to add\/modify\. Reference `docs\/specs\/ui-components\.md`\.\]\n\n/, ''],
|
|
489
|
+
[' / `ui-components.md`', ''],
|
|
490
|
+
]);
|
|
491
|
+
// pr-template: remove ui-components from checklist
|
|
492
|
+
regexReplaceInFile(path.join(dest, dir, 'skills', 'development-workflow', 'references', 'pr-template.md'), [
|
|
493
|
+
[' / ui-components.md', ''],
|
|
494
|
+
]);
|
|
495
|
+
}
|
|
496
|
+
} else if (config.projectType === 'frontend') {
|
|
497
|
+
for (const dir of toolDirs) {
|
|
498
|
+
regexReplaceInFile(path.join(dest, dir, 'agents', 'spec-creator.md'), [
|
|
499
|
+
[/\(api-spec\.yaml, ui-components\.md\)/, '(ui-components.md)'],
|
|
500
|
+
]);
|
|
501
|
+
regexReplaceInFile(path.join(dest, dir, 'skills', 'development-workflow', 'SKILL.md'), [
|
|
502
|
+
[/`api-spec\.yaml`,? /, ''],
|
|
503
|
+
[/- API endpoints → `docs\/specs\/api-spec\.yaml` \(MANDATORY\)\n/, ''],
|
|
504
|
+
]);
|
|
505
|
+
regexReplaceInFile(path.join(dest, dir, 'skills', 'development-workflow', 'references', 'ticket-template.md'), [
|
|
506
|
+
[/### API Changes \(if applicable\)\n\n\[Endpoints to add\/modify\. Reference[^\]]*\]\n\n/, ''],
|
|
507
|
+
['`api-spec.yaml` / ', ''],
|
|
508
|
+
]);
|
|
509
|
+
regexReplaceInFile(path.join(dest, dir, 'skills', 'development-workflow', 'references', 'pr-template.md'), [
|
|
510
|
+
['api-spec.yaml / ', ''],
|
|
511
|
+
]);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// documentation-standards.mdc: remove irrelevant rows based on project type
|
|
516
|
+
const docStdPath = path.join(dest, 'ai-specs', 'specs', 'documentation-standards.mdc');
|
|
517
|
+
if (fs.existsSync(docStdPath)) {
|
|
518
|
+
let content = fs.readFileSync(docStdPath, 'utf8');
|
|
519
|
+
if (config.projectType === 'backend') {
|
|
520
|
+
content = content.replace(/\| `ai-specs\/specs\/frontend-standards\.mdc` \|[^\n]*\n/, '');
|
|
521
|
+
content = content.replace(/\| `docs\/specs\/ui-components\.md` \|[^\n]*\n/, '');
|
|
522
|
+
content = content.replace(/ - UI component changes → `docs\/specs\/ui-components\.md`\n/, '');
|
|
523
|
+
} else if (config.projectType === 'frontend') {
|
|
524
|
+
content = content.replace(/\| `ai-specs\/specs\/backend-standards\.mdc` \|[^\n]*\n/, '');
|
|
525
|
+
content = content.replace(/\| `docs\/specs\/api-spec\.yaml` \|[^\n]*\n/, '');
|
|
526
|
+
}
|
|
527
|
+
fs.writeFileSync(docStdPath, content, 'utf8');
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
291
531
|
// --- Standards Adaptation ---
|
|
292
532
|
|
|
533
|
+
function adaptBaseStandards(template, scan, config) {
|
|
534
|
+
let content = template;
|
|
535
|
+
|
|
536
|
+
// Adapt validation recommendation based on detected library
|
|
537
|
+
const val = scan.backend.validation;
|
|
538
|
+
if (val && val !== 'Zod') {
|
|
539
|
+
content = content.replace(
|
|
540
|
+
'Use runtime validation (Zod recommended).',
|
|
541
|
+
`Use runtime validation (${val}).`
|
|
542
|
+
);
|
|
543
|
+
} else if (!val) {
|
|
544
|
+
content = content.replace(
|
|
545
|
+
'Use runtime validation (Zod recommended).',
|
|
546
|
+
'Use runtime validation at system boundaries.'
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// Adapt Shared Types Strategy section based on project structure
|
|
551
|
+
const hasSharedTypes = scan.frontend.detected && scan.backend.detected;
|
|
552
|
+
if (!hasSharedTypes) {
|
|
553
|
+
// Backend-only or frontend-only: remove entire Shared Types section
|
|
554
|
+
content = content.replace(
|
|
555
|
+
/## 5\. Shared Types Strategy\n\n<!-- CONFIG:.*?-->\n\n[\s\S]*?(?=\n## 6\.)/,
|
|
556
|
+
'## 5. Shared Types Strategy\n\n_Not applicable — single-stack project._\n\n'
|
|
557
|
+
);
|
|
558
|
+
} else if (val !== 'Zod') {
|
|
559
|
+
// Fullstack but not using Zod (or no validation detected): generalize the section
|
|
560
|
+
content = content.replace(
|
|
561
|
+
/## 5\. Shared Types Strategy\n\n<!-- CONFIG:.*?-->\n\nFor projects with backend \+ frontend, use a shared workspace for Zod schemas:\n\n```\n[\s\S]*?```\n\n\*\*Rules:\*\*\n[\s\S]*?(?=\n## 6\.)/,
|
|
562
|
+
`## 5. Shared Types Strategy\n\n<!-- CONFIG: Remove this section if your project has no shared types -->\n\nFor projects with backend + frontend, use a shared workspace for types:\n\n\`\`\`\nproject/\n├── shared/ ← @project/shared (npm workspace)\n│ └── src/types/ ← Shared TypeScript types\n├── backend/ ← imports @project/shared\n└── frontend/ ← imports @project/shared\n\`\`\`\n\n**Rules:**\n- Define shared types in the shared workspace\n- Both apps import from shared — never duplicate type definitions\n- Update shared types FIRST — both apps get changes automatically\n- Wire with npm workspaces + \`tsconfig.json\` paths\n\n`
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
// If Zod detected + fullstack: keep as-is (template default is correct)
|
|
566
|
+
|
|
567
|
+
// Remove frontend/backend references for single-stack projects
|
|
568
|
+
if (config.projectType === 'backend') {
|
|
569
|
+
content = content.replace(/ - \*\*Frontend\*\*: Update `docs\/specs\/ui-components\.md` first\.\n/, '');
|
|
570
|
+
content = content.replace('`backend-standards.mdc` / `frontend-standards.mdc`', '`backend-standards.mdc`');
|
|
571
|
+
} else if (config.projectType === 'frontend') {
|
|
572
|
+
content = content.replace(/ - \*\*Backend\*\*: Update `docs\/specs\/api-spec\.yaml` first\.\n/, '');
|
|
573
|
+
content = content.replace('`backend-standards.mdc` / `frontend-standards.mdc`', '`frontend-standards.mdc`');
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return content;
|
|
577
|
+
}
|
|
578
|
+
|
|
293
579
|
function adaptBackendStandards(template, scan) {
|
|
294
580
|
let content = template;
|
|
295
581
|
|
|
@@ -367,6 +653,11 @@ function adaptBackendStandards(template, scan) {
|
|
|
367
653
|
/## Database Patterns\n\n[\s\S]*?(?=\n## )/,
|
|
368
654
|
`## Database Patterns\n\n<!-- TODO: Add database access patterns for your project. -->\n`
|
|
369
655
|
);
|
|
656
|
+
} else if (scan.backend.orm === 'Mongoose') {
|
|
657
|
+
content = content.replace(
|
|
658
|
+
/## Database Patterns\n\n[\s\S]*?(?=\n## )/,
|
|
659
|
+
`## Database Patterns\n\n### Mongoose Best Practices\n- Define schemas in dedicated model files\n- Use TypeScript interfaces alongside Mongoose schemas for type safety\n- Use \`.lean()\` for read-only queries (returns plain objects, better performance)\n- Use \`.select()\` to limit returned fields on large documents\n- Add indexes for frequently queried fields (\`{ index: true }\` or compound \`schema.index()\`)\n- Use \`.populate()\` sparingly — avoid deep nesting, prefer manual joins for complex queries\n- Use middleware (pre/post hooks) for cross-cutting concerns (timestamps, audit logs)\n- Use transactions (\`session\`) for multi-document operations that must be atomic\n- Always handle \`CastError\` (invalid ObjectId) at the controller/middleware level\n\n### Schema Pattern\n\`\`\`typescript\nimport mongoose, { Schema, Document } from 'mongoose';\n\nexport interface IUser extends Document {\n email: string;\n name: string;\n role: 'user' | 'admin';\n}\n\nconst UserSchema = new Schema<IUser>({\n email: { type: String, required: true, unique: true, index: true },\n name: { type: String, required: true },\n role: { type: String, enum: ['user', 'admin'], default: 'user' },\n}, { timestamps: true });\n\nexport const User = mongoose.model<IUser>('User', UserSchema);\n\`\`\`\n\n`
|
|
660
|
+
);
|
|
370
661
|
} else if (scan.backend.orm !== 'Prisma') {
|
|
371
662
|
content = content.replace(
|
|
372
663
|
/## Database Patterns\n\n[\s\S]*?(?=\n## )/,
|
|
@@ -646,40 +937,29 @@ function configureKeyFacts(template, config, scan) {
|
|
|
646
937
|
return content;
|
|
647
938
|
}
|
|
648
939
|
|
|
649
|
-
// ---
|
|
940
|
+
// --- Product Tracker Configuration ---
|
|
650
941
|
|
|
651
|
-
function
|
|
942
|
+
function configureProductTracker(template, scan) {
|
|
652
943
|
let content = template;
|
|
653
944
|
|
|
654
|
-
//
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
945
|
+
// Determine default feature type based on detected stack
|
|
946
|
+
const featureType = !scan.backend.detected && scan.frontend.detected
|
|
947
|
+
? 'frontend'
|
|
948
|
+
: scan.backend.detected && scan.frontend.detected
|
|
949
|
+
? 'fullstack'
|
|
950
|
+
: 'backend';
|
|
660
951
|
|
|
661
|
-
//
|
|
662
|
-
if (
|
|
663
|
-
content = content.replace(
|
|
664
|
-
/\n### Frontend\n\n\| # \| Task \| Status \| Notes \|\n\|---\|------\|--------\|-------\|\n\| F0\.1 \| \[Task description\] \| ⬚ \| \|\n/,
|
|
665
|
-
''
|
|
666
|
-
);
|
|
667
|
-
}
|
|
668
|
-
if (!scan.backend.detected) {
|
|
669
|
-
content = content.replace(
|
|
670
|
-
/\n### Backend\n\n\| # \| Task \| Status \| Notes \|\n\|---\|------\|--------\|-------\|\n\| B0\.1 \| \[Task description\] \| ⬚ \| \|\n/,
|
|
671
|
-
''
|
|
672
|
-
);
|
|
952
|
+
// Update default feature type in the placeholder row
|
|
953
|
+
if (featureType !== 'backend') {
|
|
954
|
+
content = content.replace('| backend | pending', `| ${featureType} | pending`);
|
|
673
955
|
}
|
|
674
956
|
|
|
675
|
-
// Add retrofit testing
|
|
957
|
+
// Add retrofit testing as first feature if coverage is low
|
|
676
958
|
if (scan.tests.estimatedCoverage === 'none' || scan.tests.estimatedCoverage === 'low') {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
// Insert before Status Legend
|
|
959
|
+
// Use regex to match the F001 placeholder row resiliently (handles column changes)
|
|
680
960
|
content = content.replace(
|
|
681
|
-
|
|
682
|
-
|
|
961
|
+
/\| F001 \|[^\n]*\n/,
|
|
962
|
+
`| F001 | Retrofit: audit and improve test coverage | ${featureType} | pending | — | Recommended — low test coverage detected |\n| F002 | [Feature description] | ${featureType} | pending | — | |\n`
|
|
683
963
|
);
|
|
684
964
|
}
|
|
685
965
|
|
package/lib/init-wizard.js
CHANGED
|
@@ -220,7 +220,7 @@ async function runInitWizard(scanResult) {
|
|
|
220
220
|
|
|
221
221
|
console.log('\n Files to be created:');
|
|
222
222
|
console.log(' ai-specs/specs/ (4 files — standards adapted to your stack)');
|
|
223
|
-
console.log(' docs/project_notes/ (4 files —
|
|
223
|
+
console.log(' docs/project_notes/ (4 files — product tracker, memory)');
|
|
224
224
|
console.log(' docs/specs/ (API spec, UI components)');
|
|
225
225
|
console.log(' docs/tickets/ (.gitkeep)');
|
|
226
226
|
if (config.aiTools !== 'gemini') {
|
package/package.json
CHANGED
|
@@ -57,4 +57,4 @@ Follow the DDD layer order from the plan:
|
|
|
57
57
|
- **ALWAYS** run `npm test` after each TDD cycle to verify
|
|
58
58
|
- **NEVER** skip tests for "simple" code
|
|
59
59
|
- **NEVER** modify code outside the scope of the current ticket
|
|
60
|
-
- **ALWAYS** verify implementation matches the approved spec. If a deviation is needed, document it in the
|
|
60
|
+
- **ALWAYS** verify implementation matches the approved spec. If a deviation is needed, document it in the product tracker's Active Session and ask for approval
|
|
@@ -65,4 +65,4 @@ Follow the logical order from the plan:
|
|
|
65
65
|
- **ALWAYS** run `npm test` after each TDD cycle to verify
|
|
66
66
|
- **NEVER** skip tests for "simple" components
|
|
67
67
|
- **NEVER** modify code outside the scope of the current ticket
|
|
68
|
-
- **ALWAYS** verify implementation matches the approved spec. If a deviation is needed, document it in the
|
|
68
|
+
- **ALWAYS** verify implementation matches the approved spec. If a deviation is needed, document it in the product tracker's Active Session and ask for approval
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"hooks": [
|
|
20
20
|
{
|
|
21
21
|
"type": "command",
|
|
22
|
-
"command": "echo '{\"additionalContext\": \"Context was compacted. BEFORE doing anything else: read the
|
|
22
|
+
"command": "echo '{\"additionalContext\": \"Context was compacted. BEFORE doing anything else: read the product tracker Active Session section (docs/project_notes/product-tracker.md) for context recovery. Follow the Session Recovery protocol in CLAUDE.md.\"}'",
|
|
23
23
|
"statusMessage": "Injecting recovery context..."
|
|
24
24
|
}
|
|
25
25
|
]
|
|
@@ -23,7 +23,7 @@ description: "Handles bug discovery, triage, investigation, and resolution. Invo
|
|
|
23
23
|
|----------|----------|------|
|
|
24
24
|
| Critical | Immediate (<1h) | **C: Hotfix** — Confirm → Branch from main → Minimal fix → Test → Deploy → Document → Post-mortem |
|
|
25
25
|
| High | Same day | **B: Standard** — Triage → Branch → Investigate → Fix (TDD) → Validate → Document → PR |
|
|
26
|
-
| Medium | Within
|
|
26
|
+
| Medium | Within cycle | **A: Quick** — Triage → Investigate → Fix → Test → Document → Commit |
|
|
27
27
|
| Low | Backlog | **A: Quick** or escalate to backlog |
|
|
28
28
|
|
|
29
29
|
**Escalate to `development-workflow`** when: >1 day work, architectural changes needed, or significant refactoring required.
|
|
@@ -99,7 +99,7 @@ Run `production-code-validator`. Ensure no debug code, proper error handling.
|
|
|
99
99
|
|
|
100
100
|
| File | When |
|
|
101
101
|
|------|------|
|
|
102
|
-
| `
|
|
102
|
+
| `product-tracker.md` | Bug being worked on (Active Session) |
|
|
103
103
|
| `bugs.md` | Always |
|
|
104
104
|
| `decisions.md` | If architectural decision made |
|
|
105
105
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: development-workflow
|
|
3
|
-
description: "Orchestrates the complete development workflow for each
|
|
3
|
+
description: "Orchestrates the complete development workflow for each feature. Invoke with: 'start task F001', 'show progress', 'next task', or 'add feature'."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Development Workflow Skill
|
|
@@ -8,7 +8,7 @@ description: "Orchestrates the complete development workflow for each task. Invo
|
|
|
8
8
|
## Quick Reference
|
|
9
9
|
|
|
10
10
|
0. **Spec** — `spec-creator` drafts/updates specs → SPEC APPROVAL (Std/Cplx)
|
|
11
|
-
1. **Setup** — Branch, ticket,
|
|
11
|
+
1. **Setup** — Branch, ticket, product tracker → TICKET APPROVAL (Std/Cplx)
|
|
12
12
|
2. **Plan** — Planner agent writes implementation plan → PLAN APPROVAL (Std/Cplx)
|
|
13
13
|
3. **Implement** — Developer agent, TDD, real-time spec sync
|
|
14
14
|
4. **Finalize** — Tests/lint/build, `production-code-validator` → COMMIT APPROVAL
|
|
@@ -19,19 +19,19 @@ description: "Orchestrates the complete development workflow for each task. Invo
|
|
|
19
19
|
|
|
20
20
|
## Commands
|
|
21
21
|
|
|
22
|
-
- `start task
|
|
23
|
-
- `next task` — Start the next pending
|
|
24
|
-
- `show
|
|
25
|
-
- `
|
|
22
|
+
- `start task F001` — Begin working on a specific feature
|
|
23
|
+
- `next task` — Start the next pending feature from product tracker
|
|
24
|
+
- `show progress` — View feature completion status
|
|
25
|
+
- `add feature "description"` — Add a new feature to the product tracker
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
29
|
## On Skill Start
|
|
30
30
|
|
|
31
|
-
1. Read the
|
|
31
|
+
1. Read the product tracker (`docs/project_notes/product-tracker.md`) → **Active Session** section for context recovery
|
|
32
32
|
2. Read `CLAUDE.md` section 2 → **Autonomy Level**
|
|
33
33
|
3. Read `docs/project_notes/key_facts.md` → **Branching Strategy**
|
|
34
|
-
4. If resuming an active
|
|
34
|
+
4. If resuming an active feature → continue from the step recorded in the tracker's Active Session
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
@@ -47,7 +47,7 @@ Read the **Autonomy Level** from `CLAUDE.md` section 2.
|
|
|
47
47
|
| Commit Approval (Step 4) | Required | Auto | Auto | Auto |
|
|
48
48
|
| Merge Approval (Step 5) | Required | Required | Required | Auto |
|
|
49
49
|
|
|
50
|
-
- **Auto** = proceed without asking; log in
|
|
50
|
+
- **Auto** = proceed without asking; log in product tracker → "Auto-Approved Decisions" table
|
|
51
51
|
- **Required** = ask user explicitly; do NOT continue without approval
|
|
52
52
|
- **Quality gates always run** regardless of level (tests, lint, build, validators)
|
|
53
53
|
|
|
@@ -83,11 +83,11 @@ Ask user to classify complexity before starting. See `references/complexity-guid
|
|
|
83
83
|
|
|
84
84
|
See `references/branching-strategy.md` for details.
|
|
85
85
|
|
|
86
|
-
1. Verify
|
|
87
|
-
2. Create feature branch: `feature
|
|
86
|
+
1. Verify product tracker exists, no active feature, dependencies met
|
|
87
|
+
2. Create feature branch: `feature/<feature-id>-<short-description>`
|
|
88
88
|
3. **Std/Cplx:** Generate ticket from `references/ticket-template.md` → fill `## Spec` section
|
|
89
89
|
4. **Complex:** Also review `decisions.md` for related ADRs
|
|
90
|
-
5. Update
|
|
90
|
+
5. Update product tracker → Active Session: feature, step `1/6 (Setup)`, branch, complexity
|
|
91
91
|
|
|
92
92
|
**→ CHECKPOINT: Ticket Approval** (Std/Cplx only — Simple skips to Step 3)
|
|
93
93
|
|
|
@@ -95,7 +95,7 @@ See `references/branching-strategy.md` for details.
|
|
|
95
95
|
|
|
96
96
|
## Step 2: Plan (Standard/Complex only)
|
|
97
97
|
|
|
98
|
-
1. Use Task tool with planner agent (`backend-planner` for
|
|
98
|
+
1. Use Task tool with planner agent (`backend-planner` for backend features, `frontend-planner` for frontend features)
|
|
99
99
|
2. Agent writes Implementation Plan into ticket's `## Implementation Plan`
|
|
100
100
|
3. Update tracker: step `2/6 (Plan)`
|
|
101
101
|
|
|
@@ -115,7 +115,7 @@ See `references/branching-strategy.md` for details.
|
|
|
115
115
|
- UI components → `docs/specs/ui-components.md` (MANDATORY)
|
|
116
116
|
- Env variables → `.env.example` | ADRs → `decisions.md`
|
|
117
117
|
|
|
118
|
-
**Spec deviation** → document in
|
|
118
|
+
**Spec deviation** → document in product tracker Active Session and ask for approval.
|
|
119
119
|
|
|
120
120
|
Update tracker: step `3/6 (Implement)`, context summary.
|
|
121
121
|
|
|
@@ -154,7 +154,7 @@ Update tracker: step `5/6 (Review)`
|
|
|
154
154
|
## Step 6: Complete
|
|
155
155
|
|
|
156
156
|
1. Delete feature branch (local + remote)
|
|
157
|
-
2. Update
|
|
157
|
+
2. Update product tracker: feature → done, add to Completion Log, update progress
|
|
158
158
|
3. Record bugs in `bugs.md`, decisions in `decisions.md`
|
|
159
159
|
4. Clear Active Session → "No active work"
|
|
160
160
|
|
|
@@ -177,18 +177,18 @@ Update tracker: step `5/6 (Review)`
|
|
|
177
177
|
- `references/ticket-template.md` — Ticket format
|
|
178
178
|
- `references/pr-template.md` — PR template
|
|
179
179
|
- `references/branching-strategy.md` — Branching guide
|
|
180
|
-
- `references/
|
|
180
|
+
- `references/add-feature-template.md` — Add feature to tracker
|
|
181
181
|
- `references/complexity-guide.md` — Complexity classification
|
|
182
182
|
- `references/workflow-example.md` — Full worked example
|
|
183
183
|
- `references/failure-handling.md` — Recovery & rollbacks
|
|
184
184
|
|
|
185
185
|
## Constraints
|
|
186
186
|
|
|
187
|
-
- **One
|
|
187
|
+
- **One feature at a time** — never start a new feature before completing current
|
|
188
188
|
- **TDD mandatory** — all code needs tests
|
|
189
189
|
- **Type safety** — fully typed, no `any`
|
|
190
190
|
- **English only** — all technical artifacts
|
|
191
191
|
- **Memory first** — check `project_notes/` before changes
|
|
192
|
-
- **
|
|
192
|
+
- **Product tracker** — keep Active Session updated at every step
|
|
193
193
|
- **Correct agents** — Backend → `backend-planner` + `backend-developer`, Frontend → `frontend-planner` + `frontend-developer`
|
|
194
194
|
- **Correct base branch** — check `key_facts.md` before creating branches
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Add Feature Template
|
|
2
|
+
|
|
3
|
+
Use this template when running `add feature "description"`.
|
|
4
|
+
|
|
5
|
+
## How to Add a Feature
|
|
6
|
+
|
|
7
|
+
1. Read the product tracker (`docs/project_notes/product-tracker.md`)
|
|
8
|
+
2. Determine the next feature ID (F001, F002, ...)
|
|
9
|
+
3. Add a row to the Features table
|
|
10
|
+
4. Use `start task F001` to begin working on it
|
|
11
|
+
|
|
12
|
+
## Feature ID Convention
|
|
13
|
+
|
|
14
|
+
- **Format:** F001, F002, F003... (sequential)
|
|
15
|
+
- **Type:** backend, frontend, fullstack, infra
|
|
16
|
+
- **Branch:** `feature/<id>-<short-desc>` (e.g., `feature/F001-external-api`)
|