@girardmedia/bootspring 2.5.0 → 2.5.2

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