@girardmedia/bootspring 2.4.0 → 2.5.1

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 (59) hide show
  1. package/README.md +9 -403
  2. package/bin/bootspring.js +1 -96
  3. package/dist/cli/index.js +64302 -0
  4. package/dist/cli-launcher.js +92 -0
  5. package/dist/core/index.d.ts +2088 -5538
  6. package/dist/core/index.js +2 -0
  7. package/dist/core.js +21066 -5402
  8. package/dist/mcp/index.d.ts +357 -1
  9. package/dist/mcp/index.js +2 -0
  10. package/dist/mcp-server.js +51899 -1973
  11. package/package.json +27 -60
  12. package/scripts/postinstall.cjs +144 -0
  13. package/LICENSE +0 -29
  14. package/dist/cli/index.cjs +0 -20161
  15. package/generators/api-docs.js +0 -827
  16. package/generators/decisions.js +0 -655
  17. package/generators/generate.js +0 -595
  18. package/generators/health.js +0 -942
  19. package/generators/index.ts +0 -82
  20. package/generators/presets/full.js +0 -28
  21. package/generators/presets/index.js +0 -12
  22. package/generators/presets/minimal.js +0 -29
  23. package/generators/presets/standard.js +0 -28
  24. package/generators/questionnaire.js +0 -414
  25. package/generators/sections/advanced.js +0 -136
  26. package/generators/sections/ai.js +0 -106
  27. package/generators/sections/auth.js +0 -89
  28. package/generators/sections/backend.js +0 -146
  29. package/generators/sections/business.js +0 -118
  30. package/generators/sections/content.js +0 -300
  31. package/generators/sections/deployment.js +0 -139
  32. package/generators/sections/features.js +0 -122
  33. package/generators/sections/frontend.js +0 -118
  34. package/generators/sections/identity.js +0 -76
  35. package/generators/sections/index.js +0 -40
  36. package/generators/sections/instructions.js +0 -146
  37. package/generators/sections/payments.js +0 -104
  38. package/generators/sections/plugins.js +0 -142
  39. package/generators/sections/pre-build.js +0 -130
  40. package/generators/sections/security.js +0 -127
  41. package/generators/sections/technical.js +0 -171
  42. package/generators/sections/testing.js +0 -125
  43. package/generators/sections/workflow.js +0 -104
  44. package/generators/sprint.js +0 -675
  45. package/generators/templates/agents.template.js +0 -199
  46. package/generators/templates/assistant-context.template.js +0 -83
  47. package/generators/templates/build-planning.template.js +0 -704
  48. package/generators/templates/claude.template.js +0 -379
  49. package/generators/templates/content.template.js +0 -819
  50. package/generators/templates/index.js +0 -16
  51. package/generators/templates/planning.template.js +0 -515
  52. package/generators/templates/seed.template.js +0 -109
  53. package/generators/visual-doc-generator.js +0 -910
  54. package/scripts/postinstall.js +0 -197
  55. /package/{claude-commands → assets/claude-commands}/agent.md +0 -0
  56. /package/{claude-commands → assets/claude-commands}/bs.md +0 -0
  57. /package/{claude-commands → assets/claude-commands}/build.md +0 -0
  58. /package/{claude-commands → assets/claude-commands}/skill.md +0 -0
  59. /package/{claude-commands → assets/claude-commands}/todo.md +0 -0
@@ -1,704 +0,0 @@
1
- /**
2
- * Bootspring Build Planning Templates
3
- *
4
- * Generates planning artifacts for the autonomous build loop:
5
- * - MASTER_PLAN.md - Vision + phases + progress tracker
6
- * - TODO.md - Checkbox list by phase
7
- * - TASK_QUEUE.md - Ordered tasks with acceptance criteria
8
- * - CONTEXT.md - Condensed context for AI iterations
9
- *
10
- * @package bootspring
11
- * @module generators/templates/build-planning
12
- */
13
-
14
- const fs = require('fs');
15
- const path = require('path');
16
- const DEFAULT_QUEUE_VERSION = '3.0.0';
17
-
18
- /**
19
- * Generate all planning artifacts
20
- * @param {string} projectRoot - Project root path
21
- * @param {object} docs - Source documents
22
- * @param {array} tasks - Extracted tasks
23
- * @param {object} options - Generation options
24
- * @returns {object} Generated file paths
25
- */
26
- function generateAll(projectRoot, docs, tasks, options = {}) {
27
- const planningDir = path.join(projectRoot, 'planning');
28
-
29
- // Ensure planning directory exists
30
- if (!fs.existsSync(planningDir)) {
31
- fs.mkdirSync(planningDir, { recursive: true });
32
- }
33
-
34
- const files = {};
35
-
36
- // Generate MASTER_PLAN.md
37
- const masterPlan = generateMasterPlan(docs, tasks, options);
38
- const masterPlanPath = path.join(planningDir, 'MASTER_PLAN.md');
39
- fs.writeFileSync(masterPlanPath, masterPlan);
40
- files.masterPlan = masterPlanPath;
41
-
42
- // Generate TODO.md
43
- const todo = generateTodo(tasks, options);
44
- const todoPath = path.join(planningDir, 'TODO.md');
45
- fs.writeFileSync(todoPath, todo);
46
- files.todo = todoPath;
47
-
48
- // Generate TASK_QUEUE.md
49
- const queue = generateImplementationQueue(tasks, options);
50
- const queuePath = path.join(planningDir, 'TASK_QUEUE.md');
51
- fs.writeFileSync(queuePath, queue);
52
- files.implementationQueue = queuePath;
53
-
54
- // Generate CONTEXT.md
55
- const context = generateContext(docs, tasks, options);
56
- const contextPath = path.join(planningDir, 'CONTEXT.md');
57
- fs.writeFileSync(contextPath, context);
58
- files.context = contextPath;
59
-
60
- // Generate planning/AGENTS.md for AI coding agents
61
- const agentsContent = generatePlanningAgents(options);
62
- const agentsPath = path.join(planningDir, 'AGENTS.md');
63
- fs.writeFileSync(agentsPath, agentsContent);
64
- files.agents = agentsPath;
65
-
66
- return files;
67
- }
68
-
69
- /**
70
- * Generate AGENTS.md for the planning directory
71
- * Following the open standard for AI coding agents
72
- */
73
- function generatePlanningAgents(options = {}) {
74
- const projectName = options.projectName || 'Project';
75
-
76
- return `# Planning Directory
77
-
78
- You are working on build tasks for ${projectName}. This directory contains build planning files.
79
-
80
- ## Commands
81
-
82
- \`\`\`bash
83
- bootspring build task # Show current task
84
- bootspring build done # Mark task complete, get next
85
- bootspring build skip # Skip current task
86
- bootspring build status # View progress
87
- \`\`\`
88
-
89
- ## Current Task
90
-
91
- Run \`bootspring build task\` to get the current \`in_progress\` task from \`BUILD_STATE.json\`.
92
-
93
- ## Workflow
94
-
95
- 1. Run \`bootspring build task\` to identify the current task ID
96
- 2. Read the matching task in \`TODO.md\` for acceptance criteria
97
- 3. Implement in the main codebase (not in this folder)
98
- 4. Ensure acceptance criteria are met
99
- 5. Run quality checks: \`npm run lint && npm run test\`
100
- 6. Commit your changes
101
- 7. Run \`bootspring build done\`
102
-
103
- ## Files
104
-
105
- | File | Purpose |
106
- |------|---------|
107
- | \`TODO.md\` | **Source of truth** — task checklist with acceptance criteria |
108
- | \`BUILD_STATE.json\` | Build state and current task ID (do not edit directly) |
109
- | \`CONTEXT.md\` | Build context summary |
110
-
111
- ## Boundaries
112
-
113
- **Never:**
114
- - Edit \`BUILD_STATE.json\` directly
115
- - Skip quality checks
116
- - Work on multiple tasks simultaneously
117
- - Implement tasks in this planning folder
118
-
119
- **Always:**
120
- - Follow acceptance criteria exactly
121
- - Run tests before marking complete
122
- - Commit with conventional commit format
123
- `;
124
- }
125
-
126
- /**
127
- * Generate MASTER_PLAN.md
128
- * @param {object} docs - Source documents
129
- * @param {array} tasks - Extracted tasks
130
- * @param {object} options - Options
131
- * @returns {string} MASTER_PLAN.md content
132
- */
133
- function generateMasterPlan(docs, tasks, options = {}) {
134
- const projectName = options.projectName || 'Project';
135
- const phases = groupByPhase(tasks);
136
-
137
- let content = `# ${projectName} - Master Build Plan
138
-
139
- > Generated by Bootspring Autonomous Build System
140
- > Last Updated: ${new Date().toISOString().split('T')[0]}
141
-
142
- ---
143
-
144
- ## Overview
145
-
146
- This master plan guides the autonomous build process from foundation to MVP completion.
147
- Each phase contains specific tasks that will be executed sequentially by the build loop.
148
-
149
- ---
150
-
151
- ## Progress Tracker
152
-
153
- | Phase | Status | Progress | Tasks |
154
- |-------|--------|----------|-------|
155
- `;
156
-
157
- // Add phase progress rows
158
- for (const [phaseName, phaseTasks] of Object.entries(phases)) {
159
- const completed = phaseTasks.filter(t => t.status === 'completed').length;
160
- const total = phaseTasks.length;
161
- const percent = total > 0 ? Math.round((completed / total) * 100) : 0;
162
- const status = completed === 0 ? 'Pending' :
163
- completed === total ? 'Complete' : 'In Progress';
164
-
165
- content += `| ${formatPhaseName(phaseName)} | ${status} | ${percent}% | ${completed}/${total} |\n`;
166
- }
167
-
168
- content += `
169
- ---
170
-
171
- ## Phases
172
-
173
- `;
174
-
175
- // Add phase details
176
- for (const [phaseName, phaseTasks] of Object.entries(phases)) {
177
- const icon = phaseName === 'foundation' ? '1' :
178
- phaseName === 'mvp' ? '2' :
179
- phaseName === 'launch' ? '3' : '4';
180
-
181
- content += `### Phase ${icon}: ${formatPhaseName(phaseName)}
182
-
183
- `;
184
-
185
- // Group tasks by source
186
- const bySource = {};
187
- for (const task of phaseTasks) {
188
- const source = task.source || 'Manual';
189
- if (!bySource[source]) bySource[source] = [];
190
- bySource[source].push(task);
191
- }
192
-
193
- for (const [source, sourceTasks] of Object.entries(bySource)) {
194
- content += `**From ${source}:**\n`;
195
- for (const task of sourceTasks) {
196
- const checkbox = task.status === 'completed' ? '[x]' : '[ ]';
197
- content += `- ${checkbox} ${task.title}\n`;
198
- }
199
- content += '\n';
200
- }
201
-
202
- content += '---\n\n';
203
- }
204
-
205
- // Add exit criteria
206
- content += `## MVP Exit Criteria
207
-
208
- The build loop will exit when:
209
-
210
- 1. All MVP phase tasks are completed
211
- 2. Quality gates pass (tests, lint, typecheck)
212
- 3. Core user journeys are functional
213
- 4. No critical bugs remain
214
-
215
- ---
216
-
217
- ## Build Commands
218
-
219
- \`\`\`bash
220
- # Start the build loop
221
- bootspring seed build --loop
222
-
223
- # Check progress
224
- bootspring build status
225
-
226
- # Pause the build
227
- bootspring build pause
228
-
229
- # Resume building
230
- bootspring build resume
231
-
232
- # View current task
233
- bootspring build task
234
- \`\`\`
235
-
236
- ---
237
-
238
- *Generated by [Bootspring](https://bootspring.com) Autonomous Build System*
239
- `;
240
-
241
- return content;
242
- }
243
-
244
- /**
245
- * Generate TODO.md
246
- * @param {array} tasks - Extracted tasks
247
- * @param {object} options - Options
248
- * @returns {string} TODO.md content
249
- */
250
- function generateTodo(tasks, options = {}) {
251
- const phases = groupByPhase(tasks);
252
- const projectName = options.projectName || 'Project';
253
-
254
- let content = `# ${projectName} - Build Todo
255
-
256
- > Single source of truth for autonomous build execution
257
- > Updated: ${new Date().toISOString().split('T')[0]}
258
-
259
- ---
260
-
261
- ## Program Status
262
-
263
- | Metric | Value |
264
- |---|---:|
265
- | Total Tasks | ${tasks.length} |
266
- | Completed | ${tasks.filter(t => t.status === 'completed').length} |
267
- | Remaining | ${tasks.filter(t => t.status === 'pending').length} |
268
- | In Progress | ${tasks.filter(t => t.status === 'in_progress').length} |
269
-
270
- ---
271
-
272
- `;
273
-
274
- for (const [phaseName, phaseTasks] of Object.entries(phases)) {
275
- const completed = phaseTasks.filter(t => t.status === 'completed').length;
276
- const total = phaseTasks.length;
277
- const percent = total > 0 ? Math.round((completed / total) * 100) : 0;
278
-
279
- content += `## ${formatPhaseName(phaseName)} (${completed}/${total} — ${percent}%)
280
-
281
- `;
282
-
283
- for (const task of phaseTasks) {
284
- const checkbox = task.status === 'completed' ? '[x]' : '[ ]';
285
- const statusTag = task.status === 'completed' ? ' (`completed`)' :
286
- task.status === 'in_progress' ? ' (`in_progress`)' :
287
- task.status === 'blocked' ? ' (`blocked`)' :
288
- task.status === 'skipped' ? ' (`skipped`)' : '';
289
- content += `- ${checkbox} \`${task.id}\` ${task.title}${statusTag}\n`;
290
-
291
- // Source traceability
292
- if (task.source) {
293
- const sourceStr = task.sourceSection
294
- ? `${task.source} (${task.sourceSection})`
295
- : task.source;
296
- content += ` - **Source:** ${sourceStr}\n`;
297
- }
298
-
299
- // Description
300
- if (task.description) {
301
- content += ` - **Description:** ${task.description}\n`;
302
- }
303
-
304
- // Complexity and dependencies
305
- if (task.estimatedComplexity && task.estimatedComplexity !== 'medium') {
306
- content += ` - **Complexity:** ${task.estimatedComplexity}\n`;
307
- }
308
- if (task.dependencies && task.dependencies.length > 0) {
309
- content += ` - **Dependencies:** ${task.dependencies.join(', ')}\n`;
310
- }
311
-
312
- // Acceptance criteria as sub-items (all of them — this is the source of truth)
313
- if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
314
- for (const criteria of task.acceptanceCriteria) {
315
- const subCheckbox = task.status === 'completed' ? '[x]' : '[ ]';
316
- content += ` - ${subCheckbox} ${criteria}\n`;
317
- }
318
- }
319
- }
320
-
321
- content += '\n---\n\n';
322
- }
323
-
324
- content += `*Updated: ${new Date().toISOString()}*
325
- `;
326
-
327
- return content;
328
- }
329
-
330
- /**
331
- * Generate TASK_QUEUE.md
332
- * @param {array} tasks - Extracted tasks
333
- * @param {object} options - Options
334
- * @returns {string} TASK_QUEUE.md content
335
- */
336
- function generateImplementationQueue(tasks, options = {}) {
337
- const projectName = options.projectName || 'Project';
338
- const lastUpdated = options.lastUpdated || new Date().toISOString().split('T')[0];
339
- const queueVersion = options.queueVersion || DEFAULT_QUEUE_VERSION;
340
-
341
- let content = `# ${projectName} - Implementation Queue
342
-
343
- > Ordered task queue for autonomous execution
344
- > **Last Updated:** ${lastUpdated}
345
- > **Current Version:** ${queueVersion}
346
-
347
- ---
348
-
349
- ## Queue Status
350
-
351
- | Position | ID | Task | Phase | Complexity | Status |
352
- |----------|----|----- |-------|------------|--------|
353
- `;
354
-
355
- tasks.forEach((task, index) => {
356
- const statusIcon = task.status === 'completed' ? 'Done' :
357
- task.status === 'in_progress' ? 'Active' :
358
- task.status === 'blocked' ? 'Blocked' : 'Pending';
359
-
360
- content += `| ${index + 1} | ${task.id} | ${truncate(task.title, 40)} | ${formatPhaseName(task.phase)} | ${task.estimatedComplexity || 'medium'} | ${statusIcon} |\n`;
361
- });
362
-
363
- content += `
364
- ---
365
-
366
- ## Task Details
367
-
368
- `;
369
-
370
- for (const task of tasks) {
371
- content += `### ${task.id}: ${task.title}
372
-
373
- **Phase:** ${formatPhaseName(task.phase)}
374
- **Source:** ${task.source || 'Manual'} ${task.sourceSection ? `(${task.sourceSection})` : ''}
375
- **Complexity:** ${task.estimatedComplexity || 'medium'}
376
- **Status:** ${task.status || 'pending'}
377
-
378
- `;
379
-
380
- if (task.description) {
381
- content += `**Description:**
382
- ${task.description}
383
-
384
- `;
385
- }
386
-
387
- if (task.acceptanceCriteria && task.acceptanceCriteria.length > 0) {
388
- content += `**Acceptance Criteria:**
389
- ${task.acceptanceCriteria.map(c => `- [ ] ${c}`).join('\n')}
390
-
391
- `;
392
- }
393
-
394
- if (task.dependencies && task.dependencies.length > 0) {
395
- content += `**Dependencies:** ${task.dependencies.join(', ')}
396
-
397
- `;
398
- }
399
-
400
- content += '---\n\n';
401
- }
402
-
403
- content += `## Execution Guidelines
404
-
405
- 1. **One Task at a Time** - Complete each task fully before moving on
406
- 2. **Quality Gates** - Run tests, lint, and typecheck before marking complete
407
- 3. **Commit Per Task** - Create meaningful commits for each completed task
408
- 4. **Update Status** - Run \`bootspring build done\` to mark the current task complete
409
- 5. **Document Changes** - Update CLAUDE.md with new patterns/decisions
410
-
411
- ---
412
-
413
- *Generated by Bootspring*
414
- `;
415
-
416
- return content;
417
- }
418
-
419
- /**
420
- * Generate CONTEXT.md
421
- * @param {object} docs - Source documents
422
- * @param {array} tasks - Extracted tasks
423
- * @param {object} options - Options
424
- * @returns {string} CONTEXT.md content
425
- */
426
- function generateContext(docs, tasks, options = {}) {
427
- const projectName = options.projectName || 'Project';
428
- const techStack = options.techStack || extractTechStack(docs);
429
-
430
- let content = `# ${projectName} - Build Context
431
-
432
- > Condensed context for AI build iterations
433
- > Read this file at the start of each build task
434
-
435
- ---
436
-
437
- ## Project Identity
438
-
439
- **Name:** ${projectName}
440
- ${options.tagline ? `**Tagline:** ${options.tagline}` : ''}
441
-
442
- ---
443
-
444
- ## Tech Stack
445
-
446
- | Component | Technology |
447
- |-----------|------------|
448
- | Framework | ${techStack.framework || 'Next.js'} |
449
- | Language | ${techStack.language || 'TypeScript'} |
450
- | Database | ${techStack.database || 'PostgreSQL'} |
451
- | ORM | ${techStack.orm || 'Prisma'} |
452
- | UI | ${techStack.uiLibrary || 'shadcn/ui'} |
453
- | Styling | ${techStack.styling || 'Tailwind CSS'} |
454
- | Auth | ${techStack.auth || 'Clerk'} |
455
- | Hosting | ${techStack.hosting || 'Vercel'} |
456
-
457
- ---
458
-
459
- ## Current Build Status
460
-
461
- **Phase:** ${options.currentPhase || 'MVP'}
462
- **Tasks Remaining:** ${tasks.filter(t => t.status !== 'completed').length}
463
- **Tasks Completed:** ${tasks.filter(t => t.status === 'completed').length}
464
-
465
- ---
466
-
467
- ## Key Decisions
468
-
469
- `;
470
-
471
- // Add any decisions from docs
472
- if (docs.TECHNICAL_SPEC || docs.technical_spec) {
473
- content += `### Architecture
474
- - Use Server Components by default
475
- - Prefer Server Actions over API routes for mutations
476
- - Use Zod for input validation
477
- - Never expose API keys to client
478
-
479
- `;
480
- }
481
-
482
- content += `### Code Style
483
- - TypeScript strict mode enabled
484
- - ESLint + Prettier for formatting
485
- - Conventional commits (feat:, fix:, docs:, refactor:)
486
- - Keep files under 300 lines
487
-
488
- ---
489
-
490
- ## MVP Features
491
-
492
- `;
493
-
494
- // Extract unique MVP features
495
- const mvpTasks = tasks.filter(t => t.phase === 'mvp');
496
- const uniqueFeatures = [...new Set(mvpTasks.map(t => t.title))].slice(0, 10);
497
-
498
- uniqueFeatures.forEach((feature, i) => {
499
- content += `${i + 1}. ${feature}\n`;
500
- });
501
-
502
- content += `
503
- ---
504
-
505
- ## File Structure
506
-
507
- \`\`\`
508
- ${projectName.toLowerCase().replace(/\s+/g, '-')}/
509
- ├── app/ # Next.js App Router
510
- │ ├── (auth)/ # Auth pages
511
- │ ├── (dashboard)/ # Main dashboard
512
- │ ├── (marketing)/ # Landing pages
513
- │ └── api/ # API routes
514
- ├── components/
515
- │ ├── ui/ # UI components
516
- │ └── [feature]/ # Feature components
517
- ├── lib/
518
- │ ├── db.ts # Database client
519
- │ ├── auth.ts # Auth utilities
520
- │ └── utils.ts # Helpers
521
- ├── prisma/
522
- │ └── schema.prisma # Database schema
523
- ├── planning/ # Build planning (this folder)
524
- └── public/ # Static assets
525
- \`\`\`
526
-
527
- ---
528
-
529
- ## Build Loop Rules
530
-
531
- When executing a task:
532
-
533
- 1. **Read CLAUDE.md** - Understand project patterns
534
- 2. **Check BUILD_STATE.json** - Know current task and status
535
- 3. **Implement ONE task** - Focus on the current task only
536
- 4. **Run quality checks** - \`npm run lint && npm run test\`
537
- 5. **Commit changes** - Use conventional commits
538
- 6. **Update status** - Run \`bootspring build done\` to advance the build loop
539
-
540
- ---
541
-
542
- ## Exit Signals
543
-
544
- Output these signals for loop control:
545
-
546
- \`\`\`
547
- <loop-status>TASK_COMPLETE</loop-status> # Task done successfully
548
- <loop-status>TASK_BLOCKED</loop-status> # Cannot complete, needs help
549
- <loop-status>ALL_COMPLETE</loop-status> # All MVP tasks done
550
- EXIT_SIGNAL # Stop the loop
551
- \`\`\`
552
-
553
- ---
554
-
555
- *This context is refreshed at the start of each build iteration*
556
- `;
557
-
558
- return content;
559
- }
560
-
561
- /**
562
- * Group tasks by phase
563
- * @param {array} tasks - Tasks to group
564
- * @returns {object} Tasks grouped by phase
565
- */
566
- function groupByPhase(tasks) {
567
- const phases = {
568
- foundation: [],
569
- mvp: [],
570
- launch: [],
571
- other: []
572
- };
573
-
574
- for (const task of tasks) {
575
- const phase = task.phase || 'other';
576
- if (phases[phase]) {
577
- phases[phase].push(task);
578
- } else {
579
- phases.other.push(task);
580
- }
581
- }
582
-
583
- // Remove empty phases
584
- for (const [key, value] of Object.entries(phases)) {
585
- if (value.length === 0) {
586
- delete phases[key];
587
- }
588
- }
589
-
590
- return phases;
591
- }
592
-
593
- /**
594
- * Format phase name for display
595
- * @param {string} phase - Phase name
596
- * @returns {string} Formatted name
597
- */
598
- function formatPhaseName(phase) {
599
- if (!phase) return 'Other';
600
-
601
- const names = {
602
- foundation: 'Foundation',
603
- mvp: 'MVP',
604
- launch: 'Launch',
605
- other: 'Other'
606
- };
607
-
608
- return names[phase] || phase.charAt(0).toUpperCase() + phase.slice(1);
609
- }
610
-
611
- /**
612
- * Truncate string to max length
613
- * @param {string} str - String to truncate
614
- * @param {number} maxLength - Maximum length
615
- * @returns {string} Truncated string
616
- */
617
- function truncate(str, maxLength) {
618
- if (!str) return '';
619
- if (str.length <= maxLength) return str;
620
- return str.slice(0, maxLength - 3) + '...';
621
- }
622
-
623
- /**
624
- * Extract tech stack from docs
625
- * @param {object} docs - Source documents
626
- * @returns {object} Tech stack
627
- */
628
- function extractTechStack(docs) {
629
- const techDoc = docs.TECHNICAL_SPEC || docs.technical_spec || '';
630
- const seedDoc = docs.SEED || docs.seed || '';
631
- const allDocs = techDoc + seedDoc;
632
-
633
- const stack = {
634
- framework: 'nextjs',
635
- language: 'typescript',
636
- database: 'postgresql',
637
- orm: 'prisma',
638
- uiLibrary: 'shadcn',
639
- styling: 'tailwind',
640
- auth: 'clerk',
641
- hosting: 'vercel'
642
- };
643
-
644
- // Framework detection
645
- if (allDocs.match(/Next\.?js/i)) stack.framework = 'Next.js';
646
- else if (allDocs.match(/Remix/i)) stack.framework = 'Remix';
647
- else if (allDocs.match(/Nuxt/i)) stack.framework = 'Nuxt';
648
-
649
- // Database
650
- if (allDocs.match(/Postgres|PostgreSQL/i)) stack.database = 'PostgreSQL';
651
- else if (allDocs.match(/MongoDB/i)) stack.database = 'MongoDB';
652
- else if (allDocs.match(/Supabase/i)) stack.database = 'Supabase';
653
-
654
- // Auth
655
- if (allDocs.match(/\bClerk\b/i)) stack.auth = 'Clerk';
656
- else if (allDocs.match(/NextAuth|Auth\.js/i)) stack.auth = 'NextAuth';
657
-
658
- return stack;
659
- }
660
-
661
- /**
662
- * Update planning files with current state
663
- * @param {string} projectRoot - Project root path
664
- * @param {object} state - Current build state
665
- */
666
- function updateFromState(projectRoot, state) {
667
- if (!state || !state.implementationQueue) return;
668
-
669
- const tasks = state.implementationQueue;
670
- const planningDir = path.join(projectRoot, 'planning');
671
-
672
- // Regenerate TODO.md — the single source of truth
673
- const todo = generateTodo(tasks, { projectName: state.projectName });
674
- fs.writeFileSync(path.join(planningDir, 'TODO.md'), todo);
675
-
676
- // Legacy: also regenerate TASK_QUEUE.md if it already exists (backward compat)
677
- const queuePath = path.join(planningDir, 'TASK_QUEUE.md');
678
- if (fs.existsSync(queuePath)) {
679
- const existingQueue = fs.readFileSync(queuePath, 'utf-8');
680
- const existingVersionMatch = existingQueue.match(/\*\*Current Version:\*\*\s*([^\n]+)/i)
681
- || existingQueue.match(/>\s*Current Version:\s*([^\n]+)/i);
682
- const queueVersion = existingVersionMatch
683
- ? existingVersionMatch[1].trim()
684
- : DEFAULT_QUEUE_VERSION;
685
-
686
- const queue = generateImplementationQueue(tasks, {
687
- projectName: state.projectName,
688
- lastUpdated: new Date().toISOString().split('T')[0],
689
- queueVersion
690
- });
691
- fs.writeFileSync(queuePath, queue);
692
- }
693
- }
694
-
695
- module.exports = {
696
- generateAll,
697
- generateMasterPlan,
698
- generateTodo,
699
- generateImplementationQueue,
700
- generateContext,
701
- groupByPhase,
702
- formatPhaseName,
703
- updateFromState
704
- };