@girardmedia/bootspring 2.0.21 → 2.0.23

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 (159) hide show
  1. package/bin/bootspring.js +5 -0
  2. package/cli/org.js +474 -0
  3. package/cli/preseed/index.js +16 -0
  4. package/cli/preseed/interactive.js +143 -0
  5. package/cli/preseed/templates.js +227 -0
  6. package/cli/preseed.js +9 -301
  7. package/cli/seed/builders/ai-context-builder.js +85 -0
  8. package/cli/seed/builders/index.js +13 -0
  9. package/cli/seed/builders/seed-builder.js +272 -0
  10. package/cli/seed/extractors/content-extractors.js +383 -0
  11. package/cli/seed/extractors/index.js +47 -0
  12. package/cli/seed/extractors/metadata-extractors.js +167 -0
  13. package/cli/seed/extractors/section-extractor.js +54 -0
  14. package/cli/seed/extractors/stack-extractors.js +228 -0
  15. package/cli/seed/index.js +18 -0
  16. package/cli/seed/utils/folder-structure.js +84 -0
  17. package/cli/seed/utils/index.js +11 -0
  18. package/cli/seed.js +23 -1074
  19. package/core/api-client.js +77 -0
  20. package/core/entitlements.js +36 -0
  21. package/core/organizations.js +223 -0
  22. package/core/policies.js +51 -6
  23. package/core/policy-matrix.js +303 -0
  24. package/core/project-context.js +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.js +3220 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/context-McpJQa_2.d.ts +5710 -0
  29. package/dist/core/index.d.ts +635 -0
  30. package/dist/core/index.js +2593 -0
  31. package/dist/core/index.js.map +1 -0
  32. package/dist/index-QqbeEiDm.d.ts +857 -0
  33. package/dist/index-UiYCgwiH.d.ts +174 -0
  34. package/dist/index.d.ts +453 -0
  35. package/dist/index.js +44228 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp/index.d.ts +1 -0
  38. package/dist/mcp/index.js +41173 -0
  39. package/dist/mcp/index.js.map +1 -0
  40. package/generators/index.ts +82 -0
  41. package/intelligence/orchestrator/config/failure-signatures.js +48 -0
  42. package/intelligence/orchestrator/config/index.js +23 -0
  43. package/intelligence/orchestrator/config/pack-lifecycle.js +262 -0
  44. package/intelligence/orchestrator/config/phases.js +111 -0
  45. package/intelligence/orchestrator/config/remediation.js +150 -0
  46. package/intelligence/orchestrator/config/workflows.js +168 -0
  47. package/intelligence/orchestrator/core/index.js +16 -0
  48. package/intelligence/orchestrator/core/state-manager.js +88 -0
  49. package/intelligence/orchestrator/core/telemetry.js +24 -0
  50. package/intelligence/orchestrator/index.js +17 -0
  51. package/intelligence/orchestrator.js +17 -512
  52. package/mcp/contracts/mcp-contract.v1.json +1 -1
  53. package/package.json +16 -3
  54. package/src/cli/agent.ts +703 -0
  55. package/src/cli/analyze.ts +640 -0
  56. package/src/cli/audit.ts +707 -0
  57. package/src/cli/auth.ts +930 -0
  58. package/src/cli/billing.ts +364 -0
  59. package/src/cli/build.ts +1089 -0
  60. package/src/cli/business.ts +508 -0
  61. package/src/cli/checkpoint-utils.ts +236 -0
  62. package/src/cli/checkpoint.ts +757 -0
  63. package/src/cli/cloud-sync.ts +534 -0
  64. package/src/cli/content.ts +273 -0
  65. package/src/cli/context.ts +667 -0
  66. package/src/cli/dashboard.ts +133 -0
  67. package/src/cli/deploy.ts +704 -0
  68. package/src/cli/doctor.ts +480 -0
  69. package/src/cli/fundraise.ts +494 -0
  70. package/src/cli/generate.ts +346 -0
  71. package/src/cli/github-cmd.ts +566 -0
  72. package/src/cli/health.ts +599 -0
  73. package/src/cli/index.ts +113 -0
  74. package/src/cli/init.ts +838 -0
  75. package/src/cli/legal.ts +495 -0
  76. package/src/cli/log.ts +316 -0
  77. package/src/cli/loop.ts +1660 -0
  78. package/src/cli/manager.ts +878 -0
  79. package/src/cli/mcp.ts +275 -0
  80. package/src/cli/memory.ts +346 -0
  81. package/src/cli/metrics.ts +590 -0
  82. package/src/cli/monitor.ts +960 -0
  83. package/src/cli/mvp.ts +662 -0
  84. package/src/cli/onboard.ts +663 -0
  85. package/src/cli/orchestrator.ts +622 -0
  86. package/src/cli/plugin.ts +483 -0
  87. package/src/cli/prd.ts +671 -0
  88. package/src/cli/preseed-start.ts +1633 -0
  89. package/src/cli/preseed.ts +2434 -0
  90. package/src/cli/project.ts +526 -0
  91. package/src/cli/quality.ts +885 -0
  92. package/src/cli/security.ts +1079 -0
  93. package/src/cli/seed.ts +1224 -0
  94. package/src/cli/skill.ts +537 -0
  95. package/src/cli/suggest.ts +1225 -0
  96. package/src/cli/switch.ts +518 -0
  97. package/src/cli/task.ts +780 -0
  98. package/src/cli/telemetry.ts +172 -0
  99. package/src/cli/todo.ts +627 -0
  100. package/src/cli/types.ts +15 -0
  101. package/src/cli/update.ts +334 -0
  102. package/src/cli/visualize.ts +609 -0
  103. package/src/cli/watch.ts +895 -0
  104. package/src/cli/workspace.ts +709 -0
  105. package/src/core/action-recorder.ts +673 -0
  106. package/src/core/analyze-workflow.ts +1453 -0
  107. package/src/core/api-client.ts +1120 -0
  108. package/src/core/audit-workflow.ts +1681 -0
  109. package/src/core/auth.ts +471 -0
  110. package/src/core/build-orchestrator.ts +509 -0
  111. package/src/core/build-state.ts +621 -0
  112. package/src/core/checkpoint-engine.ts +482 -0
  113. package/src/core/config.ts +1285 -0
  114. package/src/core/context-loader.ts +694 -0
  115. package/src/core/context.ts +410 -0
  116. package/src/core/deploy-workflow.ts +1085 -0
  117. package/src/core/entitlements.ts +322 -0
  118. package/src/core/github-sync.ts +720 -0
  119. package/src/core/index.ts +981 -0
  120. package/src/core/ingest.ts +1186 -0
  121. package/src/core/metrics-engine.ts +886 -0
  122. package/src/core/mvp.ts +847 -0
  123. package/src/core/onboard-workflow.ts +1293 -0
  124. package/src/core/policies.ts +81 -0
  125. package/src/core/preseed-workflow.ts +1163 -0
  126. package/src/core/preseed.ts +1826 -0
  127. package/src/core/project-context.ts +380 -0
  128. package/src/core/project-state.ts +699 -0
  129. package/src/core/r2-sync.ts +691 -0
  130. package/src/core/scaffold.ts +1715 -0
  131. package/src/core/session.ts +286 -0
  132. package/src/core/task-extractor.ts +799 -0
  133. package/src/core/telemetry.ts +371 -0
  134. package/src/core/tier-enforcement.ts +737 -0
  135. package/src/core/utils.ts +437 -0
  136. package/src/index.ts +29 -0
  137. package/src/intelligence/agent-collab.ts +2376 -0
  138. package/src/intelligence/auto-suggest.ts +713 -0
  139. package/src/intelligence/content-gen.ts +1351 -0
  140. package/src/intelligence/cross-project.ts +1692 -0
  141. package/src/intelligence/git-memory.ts +529 -0
  142. package/src/intelligence/index.ts +318 -0
  143. package/src/intelligence/orchestrator.ts +534 -0
  144. package/src/intelligence/prd.ts +466 -0
  145. package/src/intelligence/recommendations.ts +982 -0
  146. package/src/intelligence/workflow-composer.ts +1472 -0
  147. package/src/mcp/capabilities.ts +233 -0
  148. package/src/mcp/index.ts +37 -0
  149. package/src/mcp/registry.ts +1268 -0
  150. package/src/mcp/response-formatter.ts +797 -0
  151. package/src/mcp/server.ts +240 -0
  152. package/src/types/agent.ts +69 -0
  153. package/src/types/config.ts +86 -0
  154. package/src/types/context.ts +77 -0
  155. package/src/types/index.ts +53 -0
  156. package/src/types/mcp.ts +91 -0
  157. package/src/types/skills.ts +47 -0
  158. package/src/types/workflow.ts +155 -0
  159. package/generators/index.js +0 -18
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Seed Builder - Generate SEED.md from preseed documents
3
+ * @package bootspring
4
+ */
5
+
6
+ const {
7
+ extractProjectName,
8
+ extractTagline,
9
+ extractProblem,
10
+ extractSolution,
11
+ extractTechStack,
12
+ extractMVPFeatures,
13
+ extractTargetUsers,
14
+ extractDatabaseEntities,
15
+ extractImplementationPhases,
16
+ extractIntegrations,
17
+ extractAPIRoutes,
18
+ extractArchitecture
19
+ } = require('../extractors');
20
+
21
+ /**
22
+ * Generate SEED.md content from preseed documents
23
+ * @param {object} docs - Document map (key: doc name, value: content)
24
+ * @param {object} preseedConfig - Optional preseed config for fallback values
25
+ * @returns {string} Generated SEED.md content
26
+ */
27
+ function generateSeedFromPreseed(docs, preseedConfig = {}) {
28
+ // Extract from documents (preferred) with config fallback
29
+ const projectName = extractProjectName(docs) || preseedConfig.identity?.name || 'My Project';
30
+ const tagline = extractTagline(docs) || preseedConfig.identity?.tagline || '';
31
+ const problem = extractProblem(docs) || preseedConfig.problem?.statement || '';
32
+ const solution = extractSolution(docs) || preseedConfig.solution?.description || '';
33
+ const techStack = extractTechStack(docs);
34
+ const mvpFeatures = extractMVPFeatures(docs);
35
+ const targetUsers = extractTargetUsers(docs);
36
+ const dbEntities = extractDatabaseEntities(docs);
37
+ const phases = extractImplementationPhases(docs);
38
+ const integrations = extractIntegrations(docs);
39
+ const apiRoutes = extractAPIRoutes(docs);
40
+ const architecture = extractArchitecture(docs);
41
+
42
+ // Build tech stack YAML with detected values
43
+ let stackYaml = `stack:
44
+ framework: ${techStack.framework}
45
+ language: ${techStack.language}
46
+ database: ${techStack.database}
47
+ hosting: ${techStack.hosting}
48
+
49
+ frontend:
50
+ uiLibrary: ${techStack.uiLibrary}
51
+ styling: ${techStack.styling}
52
+
53
+ backend:
54
+ orm: ${techStack.orm}
55
+ auth: ${techStack.auth}
56
+ payments: ${techStack.payments}`;
57
+
58
+ if (techStack.vector) {
59
+ stackYaml += `
60
+ vector: ${techStack.vector}`;
61
+ }
62
+
63
+ // Build features section
64
+ let featuresSection = '';
65
+ if (mvpFeatures.length > 0) {
66
+ featuresSection = mvpFeatures.map((f, i) => `${i + 1}. ${f}`).join('\n');
67
+ } else {
68
+ featuresSection = `1. User authentication and workspace management
69
+ 2. Core dashboard with analytics
70
+ 3. Data management and CRUD operations
71
+ 4. API endpoints for integrations
72
+ 5. Admin interface and settings`;
73
+ }
74
+
75
+ // Build target users section
76
+ let usersSection = '';
77
+ if (targetUsers.length > 0) {
78
+ usersSection = targetUsers.map(u => `- ${u}`).join('\n');
79
+ }
80
+
81
+ // Build database entities section
82
+ let entitiesSection = '';
83
+ if (dbEntities.length > 0) {
84
+ entitiesSection = dbEntities.map(e => `- \`${e}\``).join('\n');
85
+ }
86
+
87
+ // Build architecture section
88
+ let architectureSection = '';
89
+ if (architecture.length > 0) {
90
+ architectureSection = architecture.map((c, i) => `${i + 1}. ${c}`).join('\n');
91
+ }
92
+
93
+ // Build integrations section
94
+ let integrationsSection = '';
95
+ const intCats = Object.entries(integrations).filter(([_, v]) => v.length > 0);
96
+ if (intCats.length > 0) {
97
+ integrationsSection = intCats.map(([cat, services]) => {
98
+ const catName = cat.charAt(0).toUpperCase() + cat.slice(1);
99
+ return `**${catName}:** ${services.join(', ')}`;
100
+ }).join('\n');
101
+ }
102
+
103
+ // Build phases section
104
+ let phasesSection = '';
105
+ if (phases.length > 0) {
106
+ phasesSection = phases.map(p => {
107
+ let section = `### Phase ${p.phase}: ${p.name}`;
108
+ if (p.deliverables.length > 0) {
109
+ section += '\n' + p.deliverables.map(d => `- ${d}`).join('\n');
110
+ }
111
+ return section;
112
+ }).join('\n\n');
113
+ }
114
+
115
+ // Build API routes section
116
+ let apiRoutesSection = '';
117
+ if (apiRoutes.length > 0) {
118
+ apiRoutesSection = apiRoutes.map(r => `- \`${r}\``).join('\n');
119
+ }
120
+
121
+ const content = `# ${projectName}
122
+
123
+ ${tagline ? `> ${tagline}` : ''}
124
+
125
+ ## Overview
126
+
127
+ ${problem ? `**The Problem:** ${problem}\n\n` : ''}${solution ? `**Our Solution:** ${solution}` : ''}
128
+
129
+ ---
130
+
131
+ ## Tech Stack
132
+
133
+ \`\`\`yaml
134
+ ${stackYaml}
135
+ \`\`\`
136
+
137
+ ---
138
+ ${architecture.length > 0 ? `
139
+ ## Architecture
140
+
141
+ ${architectureSection}
142
+
143
+ ---
144
+ ` : ''}
145
+ ${intCats.length > 0 ? `
146
+ ## Integrations
147
+
148
+ ${integrationsSection}
149
+
150
+ ---
151
+ ` : ''}
152
+ ## MVP Features
153
+
154
+ ${featuresSection}
155
+
156
+ ---
157
+ ${phases.length > 0 ? `
158
+ ## Implementation Phases
159
+
160
+ ${phasesSection}
161
+
162
+ ---
163
+ ` : ''}
164
+ ${targetUsers.length > 0 ? `
165
+ ## Target Users
166
+
167
+ ${usersSection}
168
+
169
+ ---
170
+ ` : ''}
171
+ ${dbEntities.length > 0 ? `
172
+ ## Core Data Entities
173
+
174
+ ${entitiesSection}
175
+
176
+ ---
177
+ ` : ''}
178
+ ${apiRoutes.length > 0 ? `
179
+ ## API Routes
180
+
181
+ ${apiRoutesSection}
182
+
183
+ ---
184
+ ` : ''}
185
+ ## Development Standards
186
+
187
+ ### Code Style
188
+ - Use ${techStack.language === 'typescript' ? 'TypeScript' : 'JavaScript'} for all new code
189
+ - Follow existing naming conventions in the codebase
190
+ - Keep files focused and under 300 lines when possible
191
+
192
+ ### Best Practices
193
+ ${techStack.framework === 'nextjs' ? `- Use Server Components by default
194
+ - Prefer Server Actions over API routes for mutations` : `- Follow ${techStack.framework} best practices`}
195
+ - Use Zod for all input validation
196
+ - Never expose API keys to client-side code
197
+ - Write tests for new features
198
+
199
+ ### Git Commits
200
+ - Use conventional format: \`feat:\`, \`fix:\`, \`docs:\`, \`refactor:\`
201
+ - Keep commits focused and atomic
202
+ - Never commit sensitive data or API keys
203
+
204
+ ---
205
+
206
+ ## Project Structure
207
+
208
+ \`\`\`
209
+ ${projectName.toLowerCase().replace(/\s+/g, '-')}/
210
+ ├── app/ # Next.js App Router
211
+ │ ├── (auth)/ # Auth pages${techStack.auth === 'clerk' ? ' (Clerk)' : ''}
212
+ │ ├── (dashboard)/ # Main dashboard
213
+ │ ├── (marketing)/ # Landing pages
214
+ │ └── api/ # API routes
215
+ ├── components/
216
+ │ ├── ui/ # UI components${techStack.uiLibrary === 'shadcn' ? ' (shadcn/ui)' : ''}
217
+ │ └── [feature]/ # Feature components
218
+ ├── lib/
219
+ │ ├── db.ts # Database client${techStack.orm === 'prisma' ? ' (Prisma)' : ''}
220
+ │ ├── auth.ts # Auth utilities
221
+ │ └── utils.ts # Helpers
222
+ ├── prisma/
223
+ │ └── schema.prisma # Database schema
224
+ └── public/ # Static assets
225
+ \`\`\`
226
+
227
+ ---
228
+
229
+ ## Source Documents
230
+
231
+ This SEED.md was synthesized from:
232
+ ${Object.keys(docs).map(name => `- \`.bootspring/preseed/${name}.md\``).join('\n')}
233
+
234
+ ---
235
+
236
+ *Generated with [Bootspring](https://bootspring.com)*
237
+ `;
238
+
239
+ return content;
240
+ }
241
+
242
+ /**
243
+ * Generate AI enhancement prompt for SEED.md
244
+ * @param {object} docs - Document map
245
+ * @param {object} preseedConfig - Preseed config
246
+ * @returns {string} Enhancement prompt
247
+ */
248
+ function generateEnhancementPrompt(docs, preseedConfig) {
249
+ return `# Enhance SEED.md
250
+
251
+ I've created a basic SEED.md from my preseed documents. Please review and enhance it with:
252
+
253
+ 1. **More specific tech stack recommendations** based on my requirements
254
+ 2. **Detailed file structure** for the project
255
+ 3. **Implementation order** - which features to build first
256
+ 4. **API endpoints** we'll need
257
+ 5. **Database schema** suggestions
258
+ 6. **Third-party services** recommendations
259
+
260
+ Here are my preseed documents for context:
261
+
262
+ ${Object.entries(docs).map(([name, content]) => `## ${name}\n\n${content}`).join('\n\n---\n\n')}
263
+
264
+ ---
265
+
266
+ Please provide an enhanced SEED.md that a developer (or AI assistant) can follow to build this project from scratch.`;
267
+ }
268
+
269
+ module.exports = {
270
+ generateSeedFromPreseed,
271
+ generateEnhancementPrompt
272
+ };
@@ -0,0 +1,383 @@
1
+ /**
2
+ * Content Extractors - Extract features, users, entities, phases, routes
3
+ * @package bootspring
4
+ */
5
+
6
+ const { extractSection } = require('./section-extractor');
7
+
8
+ /**
9
+ * Extract MVP features from PRD
10
+ * @param {object} docs - Document map
11
+ * @returns {string[]} Array of feature names
12
+ */
13
+ function extractMVPFeatures(docs) {
14
+ const prdDoc = docs['PRD'] || docs['prd'];
15
+ if (!prdDoc) return [];
16
+
17
+ const features = [];
18
+
19
+ // Look for MVP Features section
20
+ const mvpSection = extractSection(prdDoc, 'MVP\\s+Features|P1\\s+.*Features|Must\\s+Ship', { maxLength: 5000 });
21
+ if (mvpSection) {
22
+ // Extract feature names from headers like "#### F-001: Feature Name"
23
+ const featureHeaders = mvpSection.match(/^#{1,4}\s+F-\d+:\s*(.+)$/gm);
24
+ if (featureHeaders && featureHeaders.length > 0) {
25
+ featureHeaders.forEach(h => {
26
+ const match = h.match(/F-\d+:\s*(.+)/);
27
+ if (match) features.push(match[1].trim());
28
+ });
29
+ }
30
+ }
31
+
32
+ // Also look for Feature Requirements section
33
+ const featureReqSection = extractSection(prdDoc, 'Feature\\s+Requirements', { maxLength: 5000 });
34
+ if (featureReqSection && features.length === 0) {
35
+ // Look for **FR-XX:** patterns
36
+ const frMatches = featureReqSection.match(/\*{0,2}FR-\d+:?\*{0,2}\s*(.+)/g);
37
+ if (frMatches) {
38
+ frMatches.forEach(m => {
39
+ const match = m.match(/FR-\d+:?\*{0,2}\s*(.+)/);
40
+ if (match) features.push(match[1].replace(/\*+/g, '').trim());
41
+ });
42
+ }
43
+ }
44
+
45
+ // Fallback: look for numbered Core User Journeys
46
+ if (features.length === 0) {
47
+ const journeySection = extractSection(prdDoc, 'Core\\s+User\\s+Journeys|User\\s+Journeys', { maxLength: 3000 });
48
+ if (journeySection) {
49
+ const journeyHeaders = journeySection.match(/^#{1,4}\s+\d+\.\d+\s+Journey\s+\d+\s*[—-]\s*(.+)$/gm);
50
+ if (journeyHeaders) {
51
+ journeyHeaders.forEach(h => {
52
+ const match = h.match(/Journey\s+\d+\s*[—-]\s*(.+)/);
53
+ if (match) features.push(match[1].trim());
54
+ });
55
+ }
56
+ }
57
+ }
58
+
59
+ // Limit to top 15 features
60
+ return features.slice(0, 15);
61
+ }
62
+
63
+ /**
64
+ * Extract target users/personas from documents
65
+ * @param {object} docs - Document map
66
+ * @returns {string[]} Array of persona names
67
+ */
68
+ function extractTargetUsers(docs) {
69
+ const visionDoc = docs['VISION'] || docs['vision'];
70
+ const prdDoc = docs['PRD'] || docs['prd'];
71
+ const audienceDoc = docs['AUDIENCE'] || docs['audience'];
72
+
73
+ const personas = [];
74
+
75
+ // Try AUDIENCE doc first - look for "## X.X Persona PX — Name" pattern
76
+ if (audienceDoc) {
77
+ const personaMatches = audienceDoc.match(/^#{1,4}\s+\d+\.\d+\s+Persona\s+P?\d+\s*[—-]\s*(.+)$/gm);
78
+ if (personaMatches) {
79
+ personaMatches.forEach(m => {
80
+ const match = m.match(/[—-]\s*(.+)/);
81
+ if (match && match[1]) personas.push(match[1].trim());
82
+ });
83
+ }
84
+ // Also look for ICP definitions like "## 3.1 ICP-A: AI Agency Operator"
85
+ if (personas.length === 0) {
86
+ const icpMatches = audienceDoc.match(/^#{1,4}\s+\d+\.\d+\s+ICP-[A-Z]:\s*(.+?)(?:\s*\(|$)/gm);
87
+ if (icpMatches) {
88
+ icpMatches.forEach(m => {
89
+ const match = m.match(/ICP-[A-Z]:\s*(.+?)(?:\s*\(|$)/);
90
+ if (match && match[1]) personas.push(match[1].trim());
91
+ });
92
+ }
93
+ }
94
+ }
95
+
96
+ // Try VISION
97
+ if (visionDoc && personas.length === 0) {
98
+ const targetSection = extractSection(visionDoc, 'Target\\s+Users|Who\\s+This\\s+Is\\s+For', { maxLength: 2000 });
99
+ if (targetSection) {
100
+ // Look for bold text patterns like "- **AI Agencies & AI Arbitrage Specialists**"
101
+ const boldMatches = targetSection.match(/^\s*[-*]\s*\*{2}([^*]+)\*{2}/gm);
102
+ if (boldMatches) {
103
+ boldMatches.forEach(m => {
104
+ const match = m.match(/\*{2}([^*]+)\*{2}/);
105
+ if (match && match[1]) personas.push(match[1].trim());
106
+ });
107
+ }
108
+ }
109
+ }
110
+
111
+ // Try PRD
112
+ if (prdDoc && personas.length === 0) {
113
+ const personaSection = extractSection(prdDoc, 'Personas|Who\\s+We\\s+Serve', { maxLength: 2000 });
114
+ if (personaSection) {
115
+ const personaMatches = personaSection.match(/^#{1,4}\s+\d+\.\d+\s+Persona\s+[A-Z]\s*[—-]\s*(.+)$/gm);
116
+ if (personaMatches) {
117
+ personaMatches.forEach(m => {
118
+ const match = m.match(/[—-]\s*(.+)/);
119
+ if (match && match[1]) personas.push(match[1].trim());
120
+ });
121
+ }
122
+ }
123
+ }
124
+
125
+ return personas.slice(0, 6);
126
+ }
127
+
128
+ /**
129
+ * Extract database entities from technical spec
130
+ * @param {object} docs - Document map
131
+ * @returns {string[]} Array of entity/table names
132
+ */
133
+ function extractDatabaseEntities(docs) {
134
+ const techDoc = docs['TECHNICAL_SPEC'] || docs['TECHNICAL-SPEC'] || docs['technical_spec'];
135
+ if (!techDoc) return [];
136
+
137
+ const entities = [];
138
+
139
+ // Strategy 1: Look specifically for "Key tables" or "Data Model" sections
140
+ // This avoids capturing run types like `interactive_chat` which are not tables
141
+ const tableSection = extractSection(techDoc, 'Key\\s+tables|Data\\s+Model|Database\\s+Schema', { maxLength: 3000 });
142
+ if (tableSection) {
143
+ // Extract backticked table names from bullet points in this specific section
144
+ const bulletTableMatches = tableSection.match(/^\s*[-*]\s*`(\w+)`/gm);
145
+ if (bulletTableMatches) {
146
+ bulletTableMatches.forEach(m => {
147
+ const match = m.match(/`(\w+)`/);
148
+ if (match && match[1] && match[1].length > 2) {
149
+ const word = match[1].toLowerCase();
150
+ // Filter out common non-entity words and known run types
151
+ const skipWords = [
152
+ 'and', 'the', 'for', 'with', 'from', 'optional', 'static', 'primary', 'key', 'index', 'indexes',
153
+ 'interactive_chat', 'widget_chat', 'lead_qualify_async', 'sequence_send_async', 'batch_eval'
154
+ ];
155
+ if (!skipWords.includes(word)) {
156
+ entities.push(match[1]);
157
+ }
158
+ }
159
+ });
160
+ }
161
+ }
162
+
163
+ // Strategy 2: Extract model names from Prisma schema blocks
164
+ if (entities.length === 0) {
165
+ const prismaModels = techDoc.match(/model\s+(\w+)\s*\{/g);
166
+ if (prismaModels) {
167
+ prismaModels.forEach(m => {
168
+ const match = m.match(/model\s+(\w+)/);
169
+ if (match && match[1]) {
170
+ entities.push(match[1]);
171
+ }
172
+ });
173
+ }
174
+ }
175
+
176
+ // Strategy 3: Fallback - look for backticked snake_case names in general text
177
+ // but only if they look like table names (contain underscore or end with 's')
178
+ if (entities.length === 0) {
179
+ const generalMatches = techDoc.match(/`([a-z][a-z_]*(?:_[a-z]+)+)`/g);
180
+ if (generalMatches) {
181
+ generalMatches.forEach(m => {
182
+ const match = m.match(/`([a-z_]+)`/);
183
+ if (match && match[1] && match[1].length > 4) {
184
+ const word = match[1].toLowerCase();
185
+ // Skip known run types
186
+ const runTypes = ['interactive_chat', 'widget_chat', 'lead_qualify_async', 'sequence_send_async', 'batch_eval'];
187
+ if (!runTypes.includes(word) && !entities.includes(match[1])) {
188
+ entities.push(match[1]);
189
+ }
190
+ }
191
+ });
192
+ }
193
+ }
194
+
195
+ // Deduplicate and return
196
+ return [...new Set(entities)].slice(0, 25);
197
+ }
198
+
199
+ /**
200
+ * Extract implementation phases from ROADMAP
201
+ * @param {object} docs - Document map
202
+ * @returns {object[]} Array of phase objects with name and deliverables
203
+ */
204
+ function extractImplementationPhases(docs) {
205
+ const roadmapDoc = docs['ROADMAP'] || docs['roadmap'];
206
+ if (!roadmapDoc) return [];
207
+
208
+ const phases = [];
209
+ const seenPhases = new Set();
210
+
211
+ // Prioritize full phase sections: "## X. Phase N —" (with section number)
212
+ // These have the actual deliverables, unlike brief summaries
213
+ const fullPhaseMatches = roadmapDoc.match(/^##\s+\d+\.\s+Phase\s+\d+\s*[—-]+\s*(.+)$/gm);
214
+
215
+ if (fullPhaseMatches) {
216
+ fullPhaseMatches.forEach(m => {
217
+ const match = m.match(/Phase\s+(\d+)\s*[—-]+\s*(.+)$/);
218
+ if (match && match[1] && match[2]) {
219
+ const phaseNum = match[1];
220
+ if (seenPhases.has(phaseNum)) return;
221
+ seenPhases.add(phaseNum);
222
+
223
+ // Clean up the name - remove parenthetical suffix
224
+ const phaseName = match[2].trim().replace(/\s*\([^)]+\)\s*$/, '').trim();
225
+
226
+ // Try to get deliverables for this phase
227
+ const deliverables = [];
228
+
229
+ // Find the full section for this specific phase (## X. Phase N — until next ## X. Phase)
230
+ const phaseRegex = new RegExp(`##\\s+\\d+\\.\\s+Phase\\s+${phaseNum}\\s*[—-][\\s\\S]*?(?=##\\s+\\d+\\.\\s+Phase\\s+\\d+|$)`, 'i');
231
+ const phaseSectionMatch = roadmapDoc.match(phaseRegex);
232
+
233
+ if (phaseSectionMatch) {
234
+ const phaseContent = phaseSectionMatch[0];
235
+
236
+ // Look for "### X.X Deliverables" subsection
237
+ const deliverablesRegex = /###\s+[\d.]+\s*Deliverables[\s\S]*?(?=###|##|$)/i;
238
+ const deliverablesMatch = phaseContent.match(deliverablesRegex);
239
+
240
+ if (deliverablesMatch) {
241
+ // Extract bullet points
242
+ const bullets = deliverablesMatch[0].match(/^[-*]\s+(.+)$/gm);
243
+ if (bullets) {
244
+ bullets.slice(0, 6).forEach(b => {
245
+ const text = b.replace(/^[-*]\s+/, '').trim();
246
+ if (text.length > 3) deliverables.push(text);
247
+ });
248
+ }
249
+ }
250
+
251
+ // If no deliverables found, try "MVP feature set" or "feature set"
252
+ if (deliverables.length === 0) {
253
+ // Look for #### A) B) C) patterns anywhere in phase content
254
+ const featureHeaders = phaseContent.match(/^####\s+[A-Z]\)\s+(.+)$/gm);
255
+ if (featureHeaders && featureHeaders.length > 0) {
256
+ featureHeaders.slice(0, 6).forEach(h => {
257
+ const hMatch = h.match(/####\s+[A-Z]\)\s+(.+)/);
258
+ if (hMatch && hMatch[1]) {
259
+ // Clean up the title - remove trailing parenthetical like "(prebuilt)"
260
+ const title = hMatch[1].trim();
261
+ deliverables.push(title);
262
+ }
263
+ });
264
+ }
265
+ }
266
+
267
+ // Strategy 3: Look for Exit Criteria items
268
+ if (deliverables.length === 0) {
269
+ const exitCriteriaRegex = /###\s+[\d.]+\s*Exit\s+Criteria[\s\S]*?(?=###|##|$)/i;
270
+ const exitMatch = phaseContent.match(exitCriteriaRegex);
271
+ if (exitMatch) {
272
+ // Extract checkmark items like "- ✅ Description"
273
+ const checkItems = exitMatch[0].match(/^[-*]\s+[✅✓]\s*(.+)$/gm);
274
+ if (checkItems) {
275
+ checkItems.slice(0, 5).forEach(item => {
276
+ const text = item.replace(/^[-*]\s+[✅✓]\s*/, '').trim();
277
+ if (text.length > 5) deliverables.push(text);
278
+ });
279
+ }
280
+ }
281
+ }
282
+
283
+ // Strategy 3: Look for "### X.X Phase goal" and extract key items
284
+ if (deliverables.length === 0) {
285
+ const goalRegex = /###\s+[\d.]+\s*(?:Phase\s+)?goal[\s\S]*?(?=###|$)/i;
286
+ const goalMatch = phaseContent.match(goalRegex);
287
+ if (goalMatch) {
288
+ // Extract bullet points or bold items
289
+ const bullets = goalMatch[0].match(/^[-*]\s+(.+)$/gm);
290
+ if (bullets) {
291
+ bullets.slice(0, 4).forEach(b => {
292
+ const text = b.replace(/^[-*]\s+/, '').trim();
293
+ if (text.length > 3) deliverables.push(text);
294
+ });
295
+ }
296
+ }
297
+ }
298
+ }
299
+
300
+ phases.push({
301
+ phase: phaseNum,
302
+ name: phaseName,
303
+ deliverables
304
+ });
305
+ }
306
+ });
307
+ }
308
+
309
+ return phases.slice(0, 5);
310
+ }
311
+
312
+ /**
313
+ * Extract API routes from PRD/technical spec
314
+ * @param {object} docs - Document map
315
+ * @returns {string[]} Array of route paths
316
+ */
317
+ function extractAPIRoutes(docs) {
318
+ const techDoc = docs['TECHNICAL_SPEC'] || docs['TECHNICAL-SPEC'] || docs['technical_spec'];
319
+
320
+ const routes = [];
321
+
322
+ if (techDoc) {
323
+ // Look for Application Structure section with app/ routes
324
+ const appStructureSection = extractSection(techDoc, 'Application\\s+Structure|Directory\\s+Structure', { maxLength: 3000 });
325
+
326
+ if (appStructureSection) {
327
+ // Extract page routes like "- `/dashboard`" or "- `/agents`" or "- `/agents/[id]`"
328
+ const pageRoutes = appStructureSection.match(/[-*]\s*`\/([\w/[\]]+)`/g);
329
+ if (pageRoutes) {
330
+ pageRoutes.forEach(r => {
331
+ const match = r.match(/`(\/[\w/[\]]+)`/);
332
+ if (match && match[1]) {
333
+ const route = match[1];
334
+ // Skip if it looks like a citation URL
335
+ if (!route.includes('docs/') && !route.includes('guides/')) {
336
+ if (!routes.includes(route)) routes.push(route);
337
+ }
338
+ }
339
+ });
340
+ }
341
+
342
+ // Extract API route handler descriptions like "agents CRUD", "runs endpoints"
343
+ const apiHandlers = appStructureSection.match(/app\/api\/.*?handlers?:[\s\S]*?(?=###|##|$)/i);
344
+ if (apiHandlers) {
345
+ const handlerLines = apiHandlers[0].match(/[-*]\s+(\w[\w\s]+)(?:endpoints?|CRUD|callbacks?|handlers?)?/g);
346
+ if (handlerLines) {
347
+ handlerLines.forEach(line => {
348
+ const match = line.match(/[-*]\s+([\w\s]+)/);
349
+ if (match && match[1]) {
350
+ const name = match[1].trim().split(/\s+/)[0].toLowerCase();
351
+ if (name.length > 2 && !['auth', 'the', 'for', 'and'].includes(name)) {
352
+ const route = `/api/${name}`;
353
+ if (!routes.includes(route)) routes.push(route);
354
+ }
355
+ }
356
+ });
357
+ }
358
+ }
359
+ }
360
+
361
+ // Also look for explicit /api/ routes in backticks
362
+ const explicitRoutes = techDoc.match(/`\/api\/[\w/[\]-]+`/g);
363
+ if (explicitRoutes) {
364
+ explicitRoutes.forEach(r => {
365
+ const route = r.replace(/`/g, '');
366
+ // Skip citation URLs
367
+ if (!route.includes('docs/') && !route.includes('guides/')) {
368
+ if (!routes.includes(route)) routes.push(route);
369
+ }
370
+ });
371
+ }
372
+ }
373
+
374
+ return routes.slice(0, 20);
375
+ }
376
+
377
+ module.exports = {
378
+ extractMVPFeatures,
379
+ extractTargetUsers,
380
+ extractDatabaseEntities,
381
+ extractImplementationPhases,
382
+ extractAPIRoutes
383
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Seed Extractors - Re-export all extraction functions
3
+ * @package bootspring
4
+ */
5
+
6
+ const { extractSection } = require('./section-extractor');
7
+ const {
8
+ extractProjectName,
9
+ extractTagline,
10
+ extractProblem,
11
+ extractSolution
12
+ } = require('./metadata-extractors');
13
+ const {
14
+ extractTechStack,
15
+ extractIntegrations,
16
+ extractArchitecture
17
+ } = require('./stack-extractors');
18
+ const {
19
+ extractMVPFeatures,
20
+ extractTargetUsers,
21
+ extractDatabaseEntities,
22
+ extractImplementationPhases,
23
+ extractAPIRoutes
24
+ } = require('./content-extractors');
25
+
26
+ module.exports = {
27
+ // Section utilities
28
+ extractSection,
29
+
30
+ // Metadata
31
+ extractProjectName,
32
+ extractTagline,
33
+ extractProblem,
34
+ extractSolution,
35
+
36
+ // Tech stack
37
+ extractTechStack,
38
+ extractIntegrations,
39
+ extractArchitecture,
40
+
41
+ // Content
42
+ extractMVPFeatures,
43
+ extractTargetUsers,
44
+ extractDatabaseEntities,
45
+ extractImplementationPhases,
46
+ extractAPIRoutes
47
+ };