@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,167 @@
1
+ /**
2
+ * Metadata Extractors - Extract project name, tagline, problem, solution
3
+ * @package bootspring
4
+ */
5
+
6
+ const { extractSection } = require('./section-extractor');
7
+
8
+ /**
9
+ * Extract project name from preseed documents
10
+ * @param {object} docs - Document map (key: doc name, value: content)
11
+ * @returns {string} Project name or 'My Project' if not found
12
+ */
13
+ function extractProjectName(docs) {
14
+ // Try VISION first
15
+ const visionDoc = docs['VISION'] || docs['vision'];
16
+ if (visionDoc) {
17
+ // Look for "Application Name:" or "**Application Name:**"
18
+ const nameMatch = visionDoc.match(/\*{0,2}Application\s+Name:?\*{0,2}\s*(.+)/i);
19
+ if (nameMatch) return nameMatch[1].trim();
20
+
21
+ // Look for "# ProjectName —" pattern
22
+ const titleMatch = visionDoc.match(/^#\s+([^—\-\n]+)/m);
23
+ if (titleMatch) return titleMatch[1].trim();
24
+ }
25
+
26
+ // Try PRD
27
+ const prdDoc = docs['PRD'] || docs['prd'];
28
+ if (prdDoc) {
29
+ const nameMatch = prdDoc.match(/\*{0,2}Application\s+Name:?\*{0,2}\s*(.+)/i);
30
+ if (nameMatch) return nameMatch[1].trim();
31
+
32
+ const titleMatch = prdDoc.match(/^#\s+([^—\-\n]+)/m);
33
+ if (titleMatch) return titleMatch[1].trim();
34
+ }
35
+
36
+ return 'My Project';
37
+ }
38
+
39
+ /**
40
+ * Extract tagline/description from documents
41
+ * @param {object} docs - Document map
42
+ * @returns {string} Tagline or empty string
43
+ */
44
+ function extractTagline(docs) {
45
+ const visionDoc = docs['VISION'] || docs['vision'];
46
+ if (visionDoc) {
47
+ // Look for "is a..." or "is an..." sentence - capture the whole description
48
+ // Pattern: "is an **agentic AI platform** that makes it simple..."
49
+ const isMatch = visionDoc.match(/is\s+an?\s+\*{0,2}([^*]+?)\*{0,2}\s+that\s+([^.—\n]+)/i);
50
+ if (isMatch) {
51
+ let tagline = `${isMatch[1].trim()} that ${isMatch[2].trim()}`;
52
+ tagline = tagline.replace(/\*+/g, '');
53
+ if (tagline.length > 200) tagline = tagline.slice(0, 200) + '...';
54
+ if (tagline.length > 20) return tagline;
55
+ }
56
+
57
+ // Fallback: just get "is an X" pattern without "that" clause
58
+ const simpleMatch = visionDoc.match(/is\s+an?\s+\*{0,2}([^*\n—:]+?)\*{0,2}(?:\s|—|:|$)/i);
59
+ if (simpleMatch) {
60
+ let tagline = simpleMatch[1].replace(/\*+/g, '').trim();
61
+ if (tagline.length > 200) tagline = tagline.slice(0, 200) + '...';
62
+ if (tagline.length > 10) return tagline;
63
+ }
64
+
65
+ // Look for executive summary first paragraph
66
+ const summarySection = extractSection(visionDoc, 'Executive\\s+Vision|Vision\\s+Summary|Summary', { maxLength: 800 });
67
+ if (summarySection) {
68
+ const firstPara = summarySection.split(/\n\n/)[0].replace(/\*+/g, '').trim();
69
+ if (firstPara.length > 20 && firstPara.length < 250) return firstPara;
70
+ }
71
+ }
72
+ return '';
73
+ }
74
+
75
+ /**
76
+ * Extract problem statement from documents
77
+ * @param {object} docs - Document map
78
+ * @returns {string} Problem statement or empty string
79
+ */
80
+ function extractProblem(docs) {
81
+ const visionDoc = docs['VISION'] || docs['vision'];
82
+ const prdDoc = docs['PRD'] || docs['prd'];
83
+
84
+ // Try VISION first
85
+ if (visionDoc) {
86
+ const problemSection = extractSection(visionDoc, '(The\\s+)?Problem|Pain\\s+Points|Market\\s+Reality', { maxLength: 800 });
87
+ if (problemSection) {
88
+ // Clean up and get first substantial paragraph
89
+ const cleaned = problemSection
90
+ // Remove subsection headers like "### 2.1 The market reality"
91
+ .replace(/^#{1,4}\s+[\d.]+\s+[^\n]+\n/gm, '')
92
+ // Remove section number prefixes like "2.1 " at start of content
93
+ .replace(/^[\d.]+\s+[A-Z][a-z]+\s+[a-z]+\n/m, '')
94
+ // Convert bullet points to flowing text
95
+ .replace(/^[-*]\s+\*{0,2}([^*\n:]+):?\*{0,2}\s*/gm, '$1: ')
96
+ // Remove remaining markdown
97
+ .replace(/\*+/g, '')
98
+ .trim();
99
+
100
+ // Get first substantial paragraph or combine bullet points
101
+ const paragraphs = cleaned.split(/\n\n/).filter(p => p.trim().length > 30);
102
+ if (paragraphs.length > 0) {
103
+ let result = paragraphs[0].replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
104
+ // Limit length
105
+ if (result.length > 500) result = result.slice(0, 500) + '...';
106
+ return result;
107
+ }
108
+ }
109
+ }
110
+
111
+ // Try PRD
112
+ if (prdDoc) {
113
+ const problemSection = extractSection(prdDoc, '(The\\s+)?Problem|Pain\\s+Points', { maxLength: 800 });
114
+ if (problemSection) {
115
+ const cleaned = problemSection
116
+ .replace(/^#{1,4}\s+[\d.]+\s+[^\n]+\n/gm, '')
117
+ .replace(/^[\d.]+\s+[A-Z][a-z]+\s+[a-z]+\n/m, '')
118
+ .replace(/^[-*]\s+\*{0,2}([^*\n:]+):?\*{0,2}\s*/gm, '$1: ')
119
+ .replace(/\*+/g, '')
120
+ .trim();
121
+
122
+ const paragraphs = cleaned.split(/\n\n/).filter(p => p.trim().length > 30);
123
+ if (paragraphs.length > 0) {
124
+ let result = paragraphs[0].replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
125
+ if (result.length > 500) result = result.slice(0, 500) + '...';
126
+ return result;
127
+ }
128
+ }
129
+ }
130
+
131
+ return '';
132
+ }
133
+
134
+ /**
135
+ * Extract solution description from documents
136
+ * @param {object} docs - Document map
137
+ * @returns {string} Solution description or empty string
138
+ */
139
+ function extractSolution(docs) {
140
+ const visionDoc = docs['VISION'] || docs['vision'];
141
+
142
+ if (visionDoc) {
143
+ // Look for "Our Solution" or "The Solution" or "What We Build"
144
+ const solutionSection = extractSection(visionDoc, '(Our\\s+)?Solution|What\\s+We\\s+Build|Core\\s+Product', { maxLength: 1000 });
145
+ if (solutionSection) {
146
+ const paragraphs = solutionSection.split(/\n\n/).filter(p => p.trim().length > 50);
147
+ if (paragraphs.length > 0) {
148
+ return paragraphs[0].replace(/^[#*\d.-]+\s*/gm, '').replace(/\*+/g, '').trim();
149
+ }
150
+ }
151
+
152
+ // Look for "in one sentence" pattern
153
+ const oneLineMatch = visionDoc.match(/in\s+one\s+sentence[:\s]*\*{0,2}([^*\n]+(?:\*{0,2}[^*\n]+)?)/i);
154
+ if (oneLineMatch) {
155
+ return oneLineMatch[1].replace(/\*+/g, '').trim();
156
+ }
157
+ }
158
+
159
+ return '';
160
+ }
161
+
162
+ module.exports = {
163
+ extractProjectName,
164
+ extractTagline,
165
+ extractProblem,
166
+ extractSolution
167
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Section Extractor - Base extraction utility for markdown content
3
+ * @package bootspring
4
+ */
5
+
6
+ /**
7
+ * Extract a section from markdown content by heading
8
+ * @param {string} content - Markdown content to search
9
+ * @param {string} headingPattern - Regex pattern for heading to match
10
+ * @param {object} options - Extraction options
11
+ * @param {number} options.maxLength - Maximum length of extracted content (default: 2000)
12
+ * @param {string} options.stopAt - Pattern to stop extraction at
13
+ * @returns {string|null} Extracted section content or null if not found
14
+ */
15
+ function extractSection(content, headingPattern, options = {}) {
16
+ const { maxLength = 2000, stopAt = null } = options;
17
+
18
+ // Match the heading (## or ### or ####)
19
+ // Wrap headingPattern in non-capturing group to ensure | alternation works correctly
20
+ // Handle optional section numbers like "## 10. Application Structure"
21
+ const headingRegex = new RegExp(`^(#{1,4})\\s*(?:\\d+\\.\\s*)?(?:${headingPattern})[^\\n]*\\n`, 'im');
22
+ const match = content.match(headingRegex);
23
+ if (!match || !match[1]) return null;
24
+
25
+ const startIndex = match.index + match[0].length;
26
+ const headingLevel = match[1].length;
27
+
28
+ // Find the next heading of same or higher level
29
+ const restContent = content.slice(startIndex);
30
+ const nextHeadingRegex = new RegExp(`^#{1,${headingLevel}}\\s+`, 'm');
31
+ const nextMatch = restContent.match(nextHeadingRegex);
32
+
33
+ let sectionContent = nextMatch
34
+ ? restContent.slice(0, nextMatch.index)
35
+ : restContent;
36
+
37
+ // Stop at a specific pattern if provided
38
+ if (stopAt) {
39
+ const stopMatch = sectionContent.match(new RegExp(stopAt, 'i'));
40
+ if (stopMatch) {
41
+ sectionContent = sectionContent.slice(0, stopMatch.index);
42
+ }
43
+ }
44
+
45
+ // Clean and truncate
46
+ sectionContent = sectionContent.trim();
47
+ if (sectionContent.length > maxLength) {
48
+ sectionContent = sectionContent.slice(0, maxLength) + '...';
49
+ }
50
+
51
+ return sectionContent || null;
52
+ }
53
+
54
+ module.exports = { extractSection };
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Stack Extractors - Extract tech stack, integrations, architecture
3
+ * @package bootspring
4
+ */
5
+
6
+ const { extractSection } = require('./section-extractor');
7
+
8
+ /**
9
+ * Extract tech stack from technical spec
10
+ * @param {object} docs - Document map
11
+ * @returns {object} Tech stack configuration
12
+ */
13
+ function extractTechStack(docs) {
14
+ const techDoc = docs['TECHNICAL_SPEC'] || docs['TECHNICAL-SPEC'] || docs['technical_spec'];
15
+
16
+ const stack = {
17
+ framework: 'nextjs',
18
+ language: 'typescript',
19
+ database: 'postgresql',
20
+ styling: 'tailwind',
21
+ uiLibrary: 'shadcn',
22
+ orm: 'prisma',
23
+ auth: 'clerk',
24
+ payments: 'stripe',
25
+ hosting: 'vercel',
26
+ vector: null
27
+ };
28
+
29
+ if (!techDoc) return stack;
30
+
31
+ // Framework detection
32
+ if (techDoc.match(/Next\.?js/i)) stack.framework = 'nextjs';
33
+ else if (techDoc.match(/Nuxt/i)) stack.framework = 'nuxt';
34
+ else if (techDoc.match(/Vue/i)) stack.framework = 'vue';
35
+ else if (techDoc.match(/Remix/i)) stack.framework = 'remix';
36
+ else if (techDoc.match(/\bReact\b/) && !techDoc.match(/Next\.?js/i)) stack.framework = 'react';
37
+ else if (techDoc.match(/Express|Fastify|Hono/i)) stack.framework = 'node';
38
+
39
+ // Language
40
+ if (techDoc.match(/TypeScript/i)) stack.language = 'typescript';
41
+ else if (techDoc.match(/JavaScript/i) && !techDoc.match(/TypeScript/i)) stack.language = 'javascript';
42
+
43
+ // Database
44
+ if (techDoc.match(/Postgres|PostgreSQL/i)) stack.database = 'postgresql';
45
+ else if (techDoc.match(/MongoDB/i)) stack.database = 'mongodb';
46
+ else if (techDoc.match(/MySQL/i)) stack.database = 'mysql';
47
+ else if (techDoc.match(/Supabase/i)) stack.database = 'supabase';
48
+ else if (techDoc.match(/PlanetScale/i)) stack.database = 'planetscale';
49
+ else if (techDoc.match(/Firebase/i)) stack.database = 'firebase';
50
+
51
+ // Vector store
52
+ if (techDoc.match(/pgvector/i)) stack.vector = 'pgvector';
53
+ else if (techDoc.match(/Pinecone/i)) stack.vector = 'pinecone';
54
+ else if (techDoc.match(/Weaviate/i)) stack.vector = 'weaviate';
55
+
56
+ // Styling
57
+ if (techDoc.match(/Tailwind/i)) stack.styling = 'tailwind';
58
+ else if (techDoc.match(/styled-components/i)) stack.styling = 'styled-components';
59
+ else if (techDoc.match(/CSS\s+Modules/i)) stack.styling = 'css-modules';
60
+
61
+ // UI Library
62
+ if (techDoc.match(/Shadcn|shadcn\/ui/i)) stack.uiLibrary = 'shadcn';
63
+ else if (techDoc.match(/Chakra/i)) stack.uiLibrary = 'chakra';
64
+ else if (techDoc.match(/MUI|Material[- ]UI/i)) stack.uiLibrary = 'mui';
65
+ else if (techDoc.match(/Radix/i)) stack.uiLibrary = 'radix';
66
+
67
+ // ORM
68
+ if (techDoc.match(/Prisma/i)) stack.orm = 'prisma';
69
+ else if (techDoc.match(/Drizzle/i)) stack.orm = 'drizzle';
70
+ else if (techDoc.match(/TypeORM/i)) stack.orm = 'typeorm';
71
+
72
+ // Auth
73
+ if (techDoc.match(/Clerk/i)) stack.auth = 'clerk';
74
+ else if (techDoc.match(/NextAuth|Auth\.js/i)) stack.auth = 'nextauth';
75
+ else if (techDoc.match(/Supabase\s+Auth/i)) stack.auth = 'supabase';
76
+ else if (techDoc.match(/Firebase\s+Auth/i)) stack.auth = 'firebase';
77
+
78
+ // Payments
79
+ if (techDoc.match(/Stripe/i)) stack.payments = 'stripe';
80
+ else if (techDoc.match(/Paddle/i)) stack.payments = 'paddle';
81
+ else if (techDoc.match(/Lemon\s*Squeezy/i)) stack.payments = 'lemonsqueezy';
82
+
83
+ // Hosting
84
+ if (techDoc.match(/Vercel/i)) stack.hosting = 'vercel';
85
+ else if (techDoc.match(/Netlify/i)) stack.hosting = 'netlify';
86
+ else if (techDoc.match(/Railway/i)) stack.hosting = 'railway';
87
+ else if (techDoc.match(/Fly\.io/i)) stack.hosting = 'fly';
88
+ else if (techDoc.match(/AWS/i)) stack.hosting = 'aws';
89
+
90
+ return stack;
91
+ }
92
+
93
+ /**
94
+ * Extract third-party integrations from technical spec
95
+ * @param {object} docs - Document map
96
+ * @returns {object} Integrations by category
97
+ */
98
+ function extractIntegrations(docs) {
99
+ const techDoc = docs['TECHNICAL_SPEC'] || docs['TECHNICAL-SPEC'] || docs['technical_spec'];
100
+ const prdDoc = docs['PRD'] || docs['prd'];
101
+ const allDocs = (techDoc || '') + '\n' + (prdDoc || '');
102
+
103
+ const integrations = {
104
+ voice: [],
105
+ email: [],
106
+ calendar: [],
107
+ crm: [],
108
+ payments: [],
109
+ auth: [],
110
+ ai: [],
111
+ other: []
112
+ };
113
+
114
+ // Voice/Telephony
115
+ if (allDocs.match(/\bTwilio\b/i)) integrations.voice.push('Twilio');
116
+ if (allDocs.match(/\bRetell\b/i)) integrations.voice.push('Retell');
117
+ if (allDocs.match(/\bVapi\b/i)) integrations.voice.push('Vapi');
118
+ if (allDocs.match(/\bElevenLabs\b/i)) integrations.voice.push('ElevenLabs');
119
+ if (allDocs.match(/\bDeepgram\b/i)) integrations.voice.push('Deepgram');
120
+
121
+ // Email
122
+ if (allDocs.match(/\bGmail\b/i)) integrations.email.push('Gmail');
123
+ if (allDocs.match(/\bSendGrid\b/i)) integrations.email.push('SendGrid');
124
+ if (allDocs.match(/\bResend\b/i)) integrations.email.push('Resend');
125
+ if (allDocs.match(/\bPostmark\b/i)) integrations.email.push('Postmark');
126
+
127
+ // Calendar
128
+ if (allDocs.match(/Google\s*Calendar/i)) integrations.calendar.push('Google Calendar');
129
+ if (allDocs.match(/\bCalendly\b/i)) integrations.calendar.push('Calendly');
130
+ if (allDocs.match(/\bCal\.com\b/i)) integrations.calendar.push('Cal.com');
131
+
132
+ // CRM
133
+ if (allDocs.match(/\bHubSpot\b/i)) integrations.crm.push('HubSpot');
134
+ if (allDocs.match(/\bSalesforce\b/i)) integrations.crm.push('Salesforce');
135
+ if (allDocs.match(/\bAttio\b/i)) integrations.crm.push('Attio');
136
+ if (allDocs.match(/\bPipedrive\b/i)) integrations.crm.push('Pipedrive');
137
+
138
+ // Payments
139
+ if (allDocs.match(/\bStripe\b/i)) integrations.payments.push('Stripe');
140
+ if (allDocs.match(/\bPaddle\b/i)) integrations.payments.push('Paddle');
141
+
142
+ // Auth
143
+ if (allDocs.match(/\bClerk\b/i)) integrations.auth.push('Clerk');
144
+ if (allDocs.match(/\bNextAuth\b|Auth\.js/i)) integrations.auth.push('NextAuth');
145
+ if (allDocs.match(/\bSupabase\s*Auth/i)) integrations.auth.push('Supabase Auth');
146
+
147
+ // AI/LLM
148
+ if (allDocs.match(/\bOpenAI\b|GPT-4/i)) integrations.ai.push('OpenAI');
149
+ if (allDocs.match(/\bAnthropic\b|Claude/i)) integrations.ai.push('Anthropic');
150
+ if (allDocs.match(/\bGemini\b/i)) integrations.ai.push('Google Gemini');
151
+
152
+ // Other
153
+ if (allDocs.match(/\bZapier\b/i)) integrations.other.push('Zapier');
154
+ if (allDocs.match(/\bSlack\b/i)) integrations.other.push('Slack');
155
+ if (allDocs.match(/\bWhatsApp\b/i)) integrations.other.push('WhatsApp');
156
+
157
+ return integrations;
158
+ }
159
+
160
+ /**
161
+ * Extract core architecture components from technical spec
162
+ * @param {object} docs - Document map
163
+ * @returns {string[]} Array of architecture component descriptions
164
+ */
165
+ function extractArchitecture(docs) {
166
+ const techDoc = docs['TECHNICAL_SPEC'] || docs['TECHNICAL-SPEC'] || docs['technical_spec'];
167
+ if (!techDoc) return [];
168
+
169
+ const components = [];
170
+
171
+ // Strategy 1: Look specifically for "Core system components" section first
172
+ // This is more specific than "Architecture" which may be a high-level overview
173
+ const coreSection = extractSection(techDoc, 'Core\\s+system\\s+components', { maxLength: 1500 });
174
+ if (coreSection) {
175
+ // Extract numbered items like "1) Web App (Next.js)"
176
+ const compMatches = coreSection.match(/^\s*\d+\)\s*(.+)$/gm);
177
+ if (compMatches) {
178
+ compMatches.forEach(m => {
179
+ const match = m.match(/\d+\)\s*(.+)/);
180
+ if (match && match[1]) {
181
+ components.push(match[1].trim());
182
+ }
183
+ });
184
+ }
185
+ }
186
+
187
+ // Strategy 2: If no components found, look within "Architectural Overview" for subsections
188
+ if (components.length === 0) {
189
+ // Search the entire doc for numbered component patterns within Architecture context
190
+ const archMatch = techDoc.match(/(?:Architectural|Architecture)\s+Overview[\s\S]*?Core\s+system\s+components[\s\S]*?(?=##\s+\d+\.|$)/i);
191
+ if (archMatch) {
192
+ const compMatches = archMatch[0].match(/^\s*\d+\)\s*(.+)$/gm);
193
+ if (compMatches) {
194
+ compMatches.forEach(m => {
195
+ const match = m.match(/\d+\)\s*(.+)/);
196
+ if (match && match[1]) {
197
+ components.push(match[1].trim());
198
+ }
199
+ });
200
+ }
201
+ }
202
+ }
203
+
204
+ // Strategy 3: Look for bullet-point architecture components
205
+ if (components.length === 0) {
206
+ const archSection = extractSection(techDoc, 'Architecture|System\\s+Components', { maxLength: 2000 });
207
+ if (archSection) {
208
+ // Look for bold component names like "- **Component Name**"
209
+ const boldMatches = archSection.match(/^\s*[-*]\s+\*{2}([^*]+)\*{2}/gm);
210
+ if (boldMatches) {
211
+ boldMatches.forEach(m => {
212
+ const match = m.match(/\*{2}([^*]+)\*{2}/);
213
+ if (match && match[1] && match[1].length > 3) {
214
+ components.push(match[1].trim());
215
+ }
216
+ });
217
+ }
218
+ }
219
+ }
220
+
221
+ return components.slice(0, 10);
222
+ }
223
+
224
+ module.exports = {
225
+ extractTechStack,
226
+ extractIntegrations,
227
+ extractArchitecture
228
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Seed Module Index - Re-export all seed submodules
3
+ * @package bootspring
4
+ */
5
+
6
+ const extractors = require('./extractors');
7
+ const builders = require('./builders');
8
+ const utils = require('./utils');
9
+
10
+ module.exports = {
11
+ extractors,
12
+ builders,
13
+ utils,
14
+ // Re-export commonly used functions at top level
15
+ ...extractors,
16
+ ...builders,
17
+ ...utils
18
+ };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Folder Structure - Seed folder constants and creation utilities
3
+ * @package bootspring
4
+ */
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+
9
+ /**
10
+ * Seed folder structure
11
+ */
12
+ const SEED_FOLDERS = [
13
+ '.bootspring',
14
+ '.bootspring/inputs',
15
+ '.bootspring/inputs/mvp',
16
+ '.bootspring/inputs/mvp/source',
17
+ '.bootspring/inputs/business',
18
+ '.bootspring/inputs/prd',
19
+ '.bootspring/inputs/prd/features',
20
+ '.bootspring/inputs/designs',
21
+ '.bootspring/inputs/designs/figma-exports',
22
+ '.bootspring/inputs/designs/wireframes',
23
+ '.bootspring/inputs/legal',
24
+ '.bootspring/inputs/api',
25
+ '.bootspring/inputs/data',
26
+ '.bootspring/generated',
27
+ '.bootspring/generated/prd',
28
+ '.bootspring/generated/master-plan',
29
+ '.bootspring/generated/business',
30
+ '.bootspring/generated/architecture',
31
+ '.bootspring/generated/legal',
32
+ '.bootspring/context',
33
+ '.bootspring/logs',
34
+ '.bootspring/logs/agents',
35
+ '.bootspring/logs/decisions',
36
+ '.bootspring/logs/code',
37
+ '.bootspring/config'
38
+ ];
39
+
40
+ /**
41
+ * Create seed folder structure (used by both setup and init)
42
+ * @param {string} projectRoot - Project root path
43
+ * @returns {number} Number of folders created
44
+ */
45
+ function createSeedFolders(projectRoot) {
46
+ let dirsCreated = 0;
47
+
48
+ for (const folder of SEED_FOLDERS) {
49
+ const folderPath = path.join(projectRoot, folder);
50
+ if (!fs.existsSync(folderPath)) {
51
+ fs.mkdirSync(folderPath, { recursive: true });
52
+ dirsCreated++;
53
+ }
54
+ }
55
+
56
+ // Create README for inputs
57
+ const inputsReadmePath = path.join(projectRoot, '.bootspring/inputs/README.md');
58
+ if (!fs.existsSync(inputsReadmePath)) {
59
+ const readme = `# Input Files
60
+
61
+ Drop your existing files here before running \`bootspring seed generate\`.
62
+
63
+ ## Folders
64
+
65
+ | Folder | What to put here |
66
+ |--------|------------------|
67
+ | \`mvp/source/\` | AI-generated MVP code (Lovable, Bolt, V0, etc.) |
68
+ | \`business/\` | Business plans, pitch decks, market research |
69
+ | \`prd/\` | Product requirements documents |
70
+ | \`designs/\` | Figma exports, wireframes, mockups |
71
+ | \`legal/\` | Existing terms, privacy policies |
72
+ | \`api/\` | OpenAPI specs, API documentation |
73
+ | \`data/\` | Sample data, database schemas |
74
+ `;
75
+ fs.writeFileSync(inputsReadmePath, readme);
76
+ }
77
+
78
+ return dirsCreated;
79
+ }
80
+
81
+ module.exports = {
82
+ SEED_FOLDERS,
83
+ createSeedFolders
84
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Seed Utils - Re-export all utility functions
3
+ * @package bootspring
4
+ */
5
+
6
+ const { SEED_FOLDERS, createSeedFolders } = require('./folder-structure');
7
+
8
+ module.exports = {
9
+ SEED_FOLDERS,
10
+ createSeedFolders
11
+ };