@girardmedia/bootspring 1.2.0 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/README.md +107 -14
  2. package/bin/bootspring.js +166 -27
  3. package/cli/agent.js +189 -17
  4. package/cli/analyze.js +499 -0
  5. package/cli/audit.js +557 -0
  6. package/cli/auth.js +495 -38
  7. package/cli/billing.js +302 -0
  8. package/cli/build.js +695 -0
  9. package/cli/business.js +109 -26
  10. package/cli/checkpoint-utils.js +168 -0
  11. package/cli/checkpoint.js +639 -0
  12. package/cli/cloud-sync.js +447 -0
  13. package/cli/content.js +198 -0
  14. package/cli/context.js +1 -1
  15. package/cli/deploy.js +543 -0
  16. package/cli/fundraise.js +112 -50
  17. package/cli/github-cmd.js +435 -0
  18. package/cli/health.js +477 -0
  19. package/cli/init.js +84 -13
  20. package/cli/legal.js +107 -95
  21. package/cli/log.js +2 -2
  22. package/cli/loop.js +976 -73
  23. package/cli/manager.js +711 -0
  24. package/cli/metrics.js +480 -0
  25. package/cli/monitor.js +812 -0
  26. package/cli/onboard.js +521 -0
  27. package/cli/orchestrator.js +12 -24
  28. package/cli/prd.js +594 -0
  29. package/cli/preseed-start.js +1483 -0
  30. package/cli/preseed.js +2302 -0
  31. package/cli/project.js +436 -0
  32. package/cli/quality.js +233 -0
  33. package/cli/security.js +913 -0
  34. package/cli/seed.js +1441 -5
  35. package/cli/skill.js +273 -211
  36. package/cli/suggest.js +989 -0
  37. package/cli/switch.js +453 -0
  38. package/cli/visualize.js +527 -0
  39. package/cli/watch.js +769 -0
  40. package/cli/workspace.js +607 -0
  41. package/core/analyze-workflow.js +1134 -0
  42. package/core/api-client.js +535 -22
  43. package/core/audit-workflow.js +1350 -0
  44. package/core/build-orchestrator.js +480 -0
  45. package/core/build-state.js +577 -0
  46. package/core/checkpoint-engine.js +408 -0
  47. package/core/config.js +1109 -26
  48. package/core/context-loader.js +21 -1
  49. package/core/deploy-workflow.js +836 -0
  50. package/core/entitlements.js +93 -22
  51. package/core/github-sync.js +610 -0
  52. package/core/index.js +8 -1
  53. package/core/ingest.js +1111 -0
  54. package/core/metrics-engine.js +768 -0
  55. package/core/onboard-workflow.js +1007 -0
  56. package/core/preseed-workflow.js +934 -0
  57. package/core/preseed.js +1617 -0
  58. package/core/project-context.js +325 -0
  59. package/core/project-state.js +694 -0
  60. package/core/r2-sync.js +583 -0
  61. package/core/scaffold.js +525 -7
  62. package/core/session.js +258 -0
  63. package/core/task-extractor.js +758 -0
  64. package/core/telemetry.js +28 -6
  65. package/core/tier-enforcement.js +737 -0
  66. package/core/utils.js +38 -14
  67. package/generators/questionnaire.js +15 -12
  68. package/generators/sections/ai.js +7 -7
  69. package/generators/sections/content.js +300 -0
  70. package/generators/sections/index.js +3 -0
  71. package/generators/sections/plugins.js +7 -6
  72. package/generators/templates/build-planning.template.js +596 -0
  73. package/generators/templates/content.template.js +819 -0
  74. package/generators/templates/index.js +2 -1
  75. package/hooks/git-autopilot.js +1250 -0
  76. package/hooks/index.js +9 -0
  77. package/intelligence/agent-collab.js +2057 -0
  78. package/intelligence/auto-suggest.js +634 -0
  79. package/intelligence/content-gen.js +1589 -0
  80. package/intelligence/cross-project.js +1647 -0
  81. package/intelligence/index.js +184 -0
  82. package/intelligence/learning/insights.json +517 -7
  83. package/intelligence/learning/pattern-learner.js +1008 -14
  84. package/intelligence/memory/decision-tracker.js +1431 -31
  85. package/intelligence/memory/decisions.jsonl +0 -0
  86. package/intelligence/orchestrator.js +2896 -1
  87. package/intelligence/prd.js +92 -1
  88. package/intelligence/recommendation-weights.json +14 -2
  89. package/intelligence/recommendations.js +463 -9
  90. package/intelligence/workflow-composer.js +1451 -0
  91. package/marketplace/index.d.ts +324 -0
  92. package/marketplace/index.js +1921 -0
  93. package/mcp/contracts/mcp-contract.v1.json +342 -4
  94. package/mcp/registry.js +680 -3
  95. package/mcp/response-formatter.js +23 -0
  96. package/mcp/tools/assist-tool.js +78 -4
  97. package/mcp/tools/autopilot-tool.js +408 -0
  98. package/mcp/tools/content-tool.js +571 -0
  99. package/mcp/tools/dashboard-tool.js +251 -5
  100. package/mcp/tools/mvp-tool.js +344 -0
  101. package/mcp/tools/plugin-tool.js +23 -1
  102. package/mcp/tools/prd-tool.js +579 -0
  103. package/mcp/tools/seed-tool.js +447 -0
  104. package/mcp/tools/skill-tool.js +43 -14
  105. package/mcp/tools/suggest-tool.js +147 -0
  106. package/package.json +15 -6
  107. package/agents/README.md +0 -93
  108. package/agents/ai-integration-expert/context.md +0 -386
  109. package/agents/api-expert/context.md +0 -416
  110. package/agents/architecture-expert/context.md +0 -454
  111. package/agents/auth-expert/context.md +0 -399
  112. package/agents/backend-expert/context.md +0 -483
  113. package/agents/business-strategy-expert/context.md +0 -180
  114. package/agents/code-review-expert/context.md +0 -365
  115. package/agents/competitive-analysis-expert/context.md +0 -239
  116. package/agents/data-modeling-expert/context.md +0 -352
  117. package/agents/database-expert/context.md +0 -250
  118. package/agents/devops-expert/context.md +0 -446
  119. package/agents/email-expert/context.md +0 -379
  120. package/agents/financial-expert/context.md +0 -213
  121. package/agents/frontend-expert/context.md +0 -364
  122. package/agents/fundraising-expert/context.md +0 -257
  123. package/agents/growth-expert/context.md +0 -249
  124. package/agents/index.js +0 -140
  125. package/agents/investor-relations-expert/context.md +0 -266
  126. package/agents/legal-expert/context.md +0 -284
  127. package/agents/marketing-expert/context.md +0 -236
  128. package/agents/monitoring-expert/context.md +0 -362
  129. package/agents/operations-expert/context.md +0 -279
  130. package/agents/partnerships-expert/context.md +0 -286
  131. package/agents/payment-expert/context.md +0 -340
  132. package/agents/performance-expert/context.md +0 -377
  133. package/agents/private-equity-expert/context.md +0 -246
  134. package/agents/railway-expert/context.md +0 -284
  135. package/agents/research-expert/context.md +0 -245
  136. package/agents/sales-expert/context.md +0 -241
  137. package/agents/security-expert/context.md +0 -343
  138. package/agents/testing-expert/context.md +0 -414
  139. package/agents/ui-ux-expert/context.md +0 -448
  140. package/agents/vercel-expert/context.md +0 -426
  141. package/skills/index.js +0 -787
  142. package/skills/patterns/README.md +0 -163
  143. package/skills/patterns/ai/agents.md +0 -281
  144. package/skills/patterns/ai/claude.md +0 -138
  145. package/skills/patterns/ai/embeddings.md +0 -150
  146. package/skills/patterns/ai/rag.md +0 -266
  147. package/skills/patterns/ai/streaming.md +0 -170
  148. package/skills/patterns/ai/structured-output.md +0 -162
  149. package/skills/patterns/ai/tools.md +0 -154
  150. package/skills/patterns/analytics/tracking.md +0 -220
  151. package/skills/patterns/api/errors.md +0 -296
  152. package/skills/patterns/api/graphql.md +0 -440
  153. package/skills/patterns/api/middleware.md +0 -279
  154. package/skills/patterns/api/openapi.md +0 -285
  155. package/skills/patterns/api/rate-limiting.md +0 -231
  156. package/skills/patterns/api/route-handler.md +0 -217
  157. package/skills/patterns/api/server-action.md +0 -249
  158. package/skills/patterns/api/versioning.md +0 -443
  159. package/skills/patterns/api/webhooks.md +0 -247
  160. package/skills/patterns/auth/clerk.md +0 -132
  161. package/skills/patterns/auth/mfa.md +0 -313
  162. package/skills/patterns/auth/nextauth.md +0 -140
  163. package/skills/patterns/auth/oauth.md +0 -237
  164. package/skills/patterns/auth/rbac.md +0 -152
  165. package/skills/patterns/auth/session-management.md +0 -367
  166. package/skills/patterns/auth/session.md +0 -120
  167. package/skills/patterns/database/audit.md +0 -177
  168. package/skills/patterns/database/migrations.md +0 -177
  169. package/skills/patterns/database/pagination.md +0 -230
  170. package/skills/patterns/database/pooling.md +0 -357
  171. package/skills/patterns/database/prisma.md +0 -180
  172. package/skills/patterns/database/relations.md +0 -187
  173. package/skills/patterns/database/seeding.md +0 -246
  174. package/skills/patterns/database/soft-delete.md +0 -153
  175. package/skills/patterns/database/transactions.md +0 -162
  176. package/skills/patterns/deployment/ci-cd.md +0 -231
  177. package/skills/patterns/deployment/docker.md +0 -188
  178. package/skills/patterns/deployment/monitoring.md +0 -387
  179. package/skills/patterns/deployment/vercel.md +0 -160
  180. package/skills/patterns/email/resend.md +0 -143
  181. package/skills/patterns/email/templates.md +0 -245
  182. package/skills/patterns/email/transactional.md +0 -503
  183. package/skills/patterns/email/verification.md +0 -176
  184. package/skills/patterns/files/download.md +0 -243
  185. package/skills/patterns/files/upload.md +0 -239
  186. package/skills/patterns/i18n/nextintl.md +0 -188
  187. package/skills/patterns/logging/structured.md +0 -292
  188. package/skills/patterns/notifications/email-queue.md +0 -248
  189. package/skills/patterns/notifications/push.md +0 -279
  190. package/skills/patterns/payments/checkout.md +0 -303
  191. package/skills/patterns/payments/invoices.md +0 -287
  192. package/skills/patterns/payments/portal.md +0 -245
  193. package/skills/patterns/payments/stripe.md +0 -272
  194. package/skills/patterns/payments/subscriptions.md +0 -300
  195. package/skills/patterns/payments/usage.md +0 -279
  196. package/skills/patterns/performance/caching.md +0 -276
  197. package/skills/patterns/performance/code-splitting.md +0 -233
  198. package/skills/patterns/performance/edge.md +0 -254
  199. package/skills/patterns/performance/isr.md +0 -266
  200. package/skills/patterns/performance/lazy-loading.md +0 -281
  201. package/skills/patterns/realtime/sse.md +0 -327
  202. package/skills/patterns/realtime/websockets.md +0 -336
  203. package/skills/patterns/search/filtering.md +0 -329
  204. package/skills/patterns/search/fulltext.md +0 -260
  205. package/skills/patterns/security/audit-logging.md +0 -444
  206. package/skills/patterns/security/csrf.md +0 -234
  207. package/skills/patterns/security/headers.md +0 -252
  208. package/skills/patterns/security/sanitization.md +0 -258
  209. package/skills/patterns/security/secrets.md +0 -261
  210. package/skills/patterns/security/validation.md +0 -268
  211. package/skills/patterns/security/xss.md +0 -229
  212. package/skills/patterns/seo/metadata.md +0 -252
  213. package/skills/patterns/state/context.md +0 -349
  214. package/skills/patterns/state/react-query.md +0 -313
  215. package/skills/patterns/state/url-state.md +0 -482
  216. package/skills/patterns/state/zustand.md +0 -262
  217. package/skills/patterns/testing/api.md +0 -259
  218. package/skills/patterns/testing/component.md +0 -233
  219. package/skills/patterns/testing/coverage.md +0 -207
  220. package/skills/patterns/testing/fixtures.md +0 -225
  221. package/skills/patterns/testing/integration.md +0 -436
  222. package/skills/patterns/testing/mocking.md +0 -177
  223. package/skills/patterns/testing/playwright.md +0 -162
  224. package/skills/patterns/testing/snapshot.md +0 -175
  225. package/skills/patterns/testing/vitest.md +0 -307
  226. package/skills/patterns/ui/accordions.md +0 -395
  227. package/skills/patterns/ui/cards.md +0 -299
  228. package/skills/patterns/ui/dropdowns.md +0 -476
  229. package/skills/patterns/ui/empty-states.md +0 -320
  230. package/skills/patterns/ui/forms.md +0 -405
  231. package/skills/patterns/ui/inputs.md +0 -319
  232. package/skills/patterns/ui/layouts.md +0 -282
  233. package/skills/patterns/ui/loading.md +0 -291
  234. package/skills/patterns/ui/modals.md +0 -338
  235. package/skills/patterns/ui/navigation.md +0 -374
  236. package/skills/patterns/ui/tables.md +0 -407
  237. package/skills/patterns/ui/toasts.md +0 -300
  238. package/skills/patterns/ui/tooltips.md +0 -396
  239. package/skills/patterns/utils/dates.md +0 -435
  240. package/skills/patterns/utils/errors.md +0 -451
  241. package/skills/patterns/utils/formatting.md +0 -345
  242. package/skills/patterns/utils/validation.md +0 -434
  243. package/templates/bootspring.config.js +0 -83
  244. package/templates/business/business-model-canvas.md +0 -246
  245. package/templates/business/business-plan.md +0 -266
  246. package/templates/business/competitive-analysis.md +0 -312
  247. package/templates/fundraising/data-room-checklist.md +0 -300
  248. package/templates/fundraising/investor-research.md +0 -243
  249. package/templates/fundraising/pitch-deck-outline.md +0 -253
  250. package/templates/legal/gdpr-checklist.md +0 -339
  251. package/templates/legal/privacy-policy.md +0 -285
  252. package/templates/legal/terms-of-service.md +0 -222
  253. package/templates/mcp.json +0 -9
@@ -0,0 +1,1483 @@
1
+ /**
2
+ * Bootspring Preseed Start
3
+ * Intelligent, context-aware entry point for idea-to-app journey
4
+ *
5
+ * Detects:
6
+ * - Environment (CLI, Claude Code/MCP, VS Code)
7
+ * - Auth status and tier
8
+ * - Existing context (files, config, previous progress)
9
+ * - Best path forward based on all signals
10
+ *
11
+ * @package bootspring
12
+ * @module cli/preseed-start
13
+ */
14
+
15
+ const path = require('path');
16
+ const fs = require('fs');
17
+ const readline = require('readline');
18
+ const os = require('os');
19
+ const config = require('../core/config');
20
+ const utils = require('../core/utils');
21
+ const auth = require('../core/auth');
22
+ const session = require('../core/session');
23
+ const apiClient = require('../core/api-client');
24
+
25
+ // ============================================================================
26
+ // Context Detection
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Detect the current environment and capabilities
31
+ */
32
+ function detectEnvironment() {
33
+ const env = {
34
+ // Environment type
35
+ isClaudeCode: !!process.env.CLAUDE_CODE || !!process.env.MCP_SERVER,
36
+ isVSCode: !!process.env.VSCODE_PID || !!process.env.TERM_PROGRAM?.includes('vscode'),
37
+ isCursor: !!process.env.CURSOR_TRACE_ID,
38
+ isInteractive: process.stdin.isTTY && process.stdout.isTTY,
39
+
40
+ // Auth and tier
41
+ isAuthenticated: auth.isAuthenticated(),
42
+ tier: auth.getTier(),
43
+ user: auth.getUser(),
44
+
45
+ // Capabilities based on tier
46
+ capabilities: {
47
+ aiGeneration: false,
48
+ dashboardAccess: false,
49
+ teamCollaboration: false,
50
+ prioritySupport: false,
51
+ unlimitedProjects: false
52
+ },
53
+
54
+ // Platform
55
+ platform: os.platform(),
56
+ shell: process.env.SHELL || 'unknown'
57
+ };
58
+
59
+ // Set capabilities based on tier
60
+ const tier = env.tier;
61
+ if (tier === 'pro' || tier === 'team' || tier === 'enterprise') {
62
+ env.capabilities.aiGeneration = true;
63
+ env.capabilities.dashboardAccess = true;
64
+ }
65
+ if (tier === 'team' || tier === 'enterprise') {
66
+ env.capabilities.teamCollaboration = true;
67
+ }
68
+ if (tier === 'enterprise') {
69
+ env.capabilities.prioritySupport = true;
70
+ env.capabilities.unlimitedProjects = true;
71
+ }
72
+
73
+ return env;
74
+ }
75
+
76
+ /**
77
+ * Detect existing project context
78
+ */
79
+ function detectProjectContext(projectRoot) {
80
+ const context = {
81
+ hasBootspringFolder: false,
82
+ hasPreseedConfig: false,
83
+ hasPreseedDocs: [],
84
+ hasContextFiles: [],
85
+ hasSeedMd: false,
86
+ hasClaudeMd: false,
87
+ hasPackageJson: false,
88
+ projectName: null,
89
+ previousProgress: null,
90
+
91
+ // What we can work with
92
+ existingAssets: []
93
+ };
94
+
95
+ // Check .bootspring folder
96
+ const bootspringDir = path.join(projectRoot, '.bootspring');
97
+ context.hasBootspringFolder = fs.existsSync(bootspringDir);
98
+
99
+ // Check preseed config
100
+ const preseedConfigPath = path.join(bootspringDir, 'preseed', 'PRESEED_CONFIG.json');
101
+ if (fs.existsSync(preseedConfigPath)) {
102
+ context.hasPreseedConfig = true;
103
+ try {
104
+ const cfg = JSON.parse(fs.readFileSync(preseedConfigPath, 'utf-8'));
105
+ context.projectName = cfg.identity?.name;
106
+ } catch {}
107
+ }
108
+
109
+ // Check for preseed documents
110
+ const preseedDir = path.join(bootspringDir, 'preseed');
111
+ if (fs.existsSync(preseedDir)) {
112
+ const files = fs.readdirSync(preseedDir).filter(f => f.endsWith('.md'));
113
+ context.hasPreseedDocs = files;
114
+ }
115
+
116
+ // Check for context files (user uploads, research, etc.)
117
+ const contextDir = path.join(bootspringDir, 'preseed', 'context');
118
+ context.hasDropFiles = [];
119
+ if (fs.existsSync(contextDir)) {
120
+ // Check drop folder first (universal inbox)
121
+ const dropDir = path.join(contextDir, 'drop');
122
+ if (fs.existsSync(dropDir)) {
123
+ const dropFiles = fs.readdirSync(dropDir).filter(f => !f.startsWith('.'));
124
+ if (dropFiles.length > 0) {
125
+ context.hasDropFiles = dropFiles;
126
+ context.existingAssets.push(`${dropFiles.length} file(s) in drop zone`);
127
+ }
128
+ }
129
+
130
+ // Check categorized folders (includes document-specific folders)
131
+ const categories = [
132
+ // General folders
133
+ 'ideas', 'research',
134
+ // Document-specific folders (maps 1:1 to output)
135
+ 'vision', 'audience', 'market', 'competitors', 'business', 'prd', 'technical', 'roadmap'
136
+ ];
137
+ for (const cat of categories) {
138
+ const catDir = path.join(contextDir, cat);
139
+ if (fs.existsSync(catDir)) {
140
+ const files = fs.readdirSync(catDir).filter(f => !f.startsWith('.'));
141
+ if (files.length > 0) {
142
+ context.hasContextFiles.push({ category: cat, files });
143
+ context.existingAssets.push(`${files.length} ${cat} file(s)`);
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ // Check for SEED.md
150
+ context.hasSeedMd = fs.existsSync(path.join(projectRoot, 'SEED.md'));
151
+
152
+ // Check for CLAUDE.md
153
+ context.hasClaudeMd = fs.existsSync(path.join(projectRoot, 'CLAUDE.md'));
154
+
155
+ // Check for package.json (existing project)
156
+ const pkgPath = path.join(projectRoot, 'package.json');
157
+ if (fs.existsSync(pkgPath)) {
158
+ context.hasPackageJson = true;
159
+ try {
160
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
161
+ context.projectName = context.projectName || pkg.name;
162
+ } catch {}
163
+ }
164
+
165
+ // Check for previous wizard progress
166
+ const progressPath = path.join(bootspringDir, 'preseed', '.wizard-progress.json');
167
+ if (fs.existsSync(progressPath)) {
168
+ try {
169
+ context.previousProgress = JSON.parse(fs.readFileSync(progressPath, 'utf-8'));
170
+ } catch {}
171
+ }
172
+
173
+ return context;
174
+ }
175
+
176
+ /**
177
+ * Determine the best starting point based on context
178
+ */
179
+ function determineStartingPoint(env, projectContext) {
180
+ const recommendations = [];
181
+
182
+ // If they have previous progress, offer to resume
183
+ if (projectContext.previousProgress) {
184
+ recommendations.push({
185
+ id: 'resume',
186
+ label: 'Resume where you left off',
187
+ description: `Continue from ${projectContext.previousProgress.lastStep || 'previous session'}`,
188
+ priority: 1
189
+ });
190
+ }
191
+
192
+ // If they have preseed docs, offer to continue to seed
193
+ if (projectContext.hasPreseedDocs.length >= 3) {
194
+ recommendations.push({
195
+ id: 'synthesize',
196
+ label: 'Generate SEED.md from your preseed docs',
197
+ description: `You have ${projectContext.hasPreseedDocs.length} preseed documents ready`,
198
+ priority: 2
199
+ });
200
+ }
201
+
202
+ // If they have files in the drop zone, offer to analyze them
203
+ if (projectContext.hasDropFiles && projectContext.hasDropFiles.length > 0) {
204
+ recommendations.push({
205
+ id: 'analyze-drop',
206
+ label: 'Analyze your drop zone files',
207
+ description: `Process ${projectContext.hasDropFiles.length} file(s) and extract insights`,
208
+ priority: 2
209
+ });
210
+ }
211
+
212
+ // If they have context files, offer to use them
213
+ if (projectContext.hasContextFiles.length > 0) {
214
+ recommendations.push({
215
+ id: 'from-context',
216
+ label: 'Build from your existing materials',
217
+ description: `Use your ${projectContext.existingAssets.join(', ')}`,
218
+ priority: 3
219
+ });
220
+ }
221
+
222
+ // If in Claude Code, highlight MCP capabilities
223
+ if (env.isClaudeCode) {
224
+ recommendations.push({
225
+ id: 'claude-code',
226
+ label: 'Use Claude to build your preseed',
227
+ description: 'Just describe your idea - Claude will create the documents',
228
+ priority: env.capabilities.aiGeneration ? 1 : 4
229
+ });
230
+ }
231
+
232
+ // If they have AI generation capability
233
+ if (env.capabilities.aiGeneration) {
234
+ recommendations.push({
235
+ id: 'ai-wizard',
236
+ label: 'AI-Powered Wizard',
237
+ description: 'Answer questions, AI generates professional documents',
238
+ priority: 2
239
+ });
240
+ }
241
+
242
+ // Always available options
243
+ recommendations.push({
244
+ id: 'guided-wizard',
245
+ label: 'Guided Wizard',
246
+ description: 'Step-by-step questions to capture your idea',
247
+ priority: 5
248
+ });
249
+
250
+ recommendations.push({
251
+ id: 'ai-prompts',
252
+ label: 'Get AI Prompts',
253
+ description: 'Copy prompts to use with Claude, ChatGPT, or any LLM',
254
+ priority: 6
255
+ });
256
+
257
+ recommendations.push({
258
+ id: 'idea-dump',
259
+ label: 'Brain Dump',
260
+ description: 'Just write freely - we\'ll structure it for you',
261
+ priority: 7
262
+ });
263
+
264
+ if (env.capabilities.dashboardAccess) {
265
+ recommendations.push({
266
+ id: 'dashboard',
267
+ label: 'Open Dashboard Studio',
268
+ description: 'Visual editor with AI generation in your browser',
269
+ priority: 4
270
+ });
271
+ }
272
+
273
+ // Sort by priority
274
+ recommendations.sort((a, b) => a.priority - b.priority);
275
+
276
+ return recommendations;
277
+ }
278
+
279
+ // ============================================================================
280
+ // UI Components
281
+ // ============================================================================
282
+
283
+ function createInterface() {
284
+ return readline.createInterface({
285
+ input: process.stdin,
286
+ output: process.stdout
287
+ });
288
+ }
289
+
290
+ function askChoice(rl, options) {
291
+ return new Promise((resolve) => {
292
+ options.forEach((opt, i) => {
293
+ const num = `${i + 1}`.padStart(2, ' ');
294
+ console.log(` ${utils.COLORS.cyan}${num}${utils.COLORS.reset} ${opt.label}`);
295
+ if (opt.description) {
296
+ console.log(` ${utils.COLORS.dim}${opt.description}${utils.COLORS.reset}`);
297
+ }
298
+ });
299
+
300
+ console.log();
301
+ rl.question(`${utils.COLORS.dim}Select [1-${options.length}]:${utils.COLORS.reset} `, (answer) => {
302
+ const index = parseInt(answer, 10) - 1;
303
+ if (index >= 0 && index < options.length) {
304
+ resolve(options[index]);
305
+ } else {
306
+ resolve(options[0]); // Default to first
307
+ }
308
+ });
309
+ });
310
+ }
311
+
312
+ function askText(rl, question, hint = '') {
313
+ return new Promise((resolve) => {
314
+ const hintText = hint ? ` ${utils.COLORS.dim}${hint}${utils.COLORS.reset}` : '';
315
+ rl.question(`${question}${hintText}: `, (answer) => {
316
+ resolve(answer.trim());
317
+ });
318
+ });
319
+ }
320
+
321
+ function displayHeader(env, projectContext) {
322
+ console.log();
323
+ console.log(`${utils.COLORS.cyan}${utils.COLORS.bold} ╔══════════════════════════════════════════════════════════╗${utils.COLORS.reset}`);
324
+ console.log(`${utils.COLORS.cyan}${utils.COLORS.bold} ║${utils.COLORS.reset} ${utils.COLORS.bold}BOOTSPRING PRESEED STUDIO${utils.COLORS.reset} ${utils.COLORS.cyan}${utils.COLORS.bold}║${utils.COLORS.reset}`);
325
+ console.log(`${utils.COLORS.cyan}${utils.COLORS.bold} ║${utils.COLORS.reset} ${utils.COLORS.dim}Transform your idea into a production app${utils.COLORS.reset} ${utils.COLORS.cyan}${utils.COLORS.bold}║${utils.COLORS.reset}`);
326
+ console.log(`${utils.COLORS.cyan}${utils.COLORS.bold} ╚══════════════════════════════════════════════════════════╝${utils.COLORS.reset}`);
327
+ console.log();
328
+
329
+ // Show context badges
330
+ const badges = [];
331
+
332
+ if (env.isAuthenticated) {
333
+ const tierBadge = env.tier === 'free'
334
+ ? `${utils.COLORS.dim}FREE${utils.COLORS.reset}`
335
+ : `${utils.COLORS.green}${env.tier.toUpperCase()}${utils.COLORS.reset}`;
336
+ badges.push(tierBadge);
337
+ } else {
338
+ badges.push(`${utils.COLORS.yellow}NOT LOGGED IN${utils.COLORS.reset}`);
339
+ }
340
+
341
+ if (env.isClaudeCode) {
342
+ badges.push(`${utils.COLORS.magenta}CLAUDE CODE${utils.COLORS.reset}`);
343
+ }
344
+
345
+ if (projectContext.projectName) {
346
+ badges.push(`${utils.COLORS.cyan}${projectContext.projectName}${utils.COLORS.reset}`);
347
+ }
348
+
349
+ console.log(` ${badges.join(' │ ')}`);
350
+ console.log();
351
+ }
352
+
353
+ function displayJourney(projectContext) {
354
+ const stages = [
355
+ { id: 'idea', label: 'Idea', done: true }, // They're here, so they have an idea
356
+ { id: 'preseed', label: 'Preseed', done: projectContext.hasPreseedDocs.length >= 3 },
357
+ { id: 'seed', label: 'Seed', done: projectContext.hasSeedMd },
358
+ { id: 'scaffold', label: 'App', done: projectContext.hasPackageJson && projectContext.hasClaudeMd }
359
+ ];
360
+
361
+ const journeyLine = stages.map((stage, i) => {
362
+ const icon = stage.done ? `${utils.COLORS.green}●${utils.COLORS.reset}` : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
363
+ const label = stage.done ? `${utils.COLORS.green}${stage.label}${utils.COLORS.reset}` : `${utils.COLORS.dim}${stage.label}${utils.COLORS.reset}`;
364
+ const connector = i < stages.length - 1 ? ` ${utils.COLORS.dim}───${utils.COLORS.reset} ` : '';
365
+ return `${icon} ${label}${connector}`;
366
+ }).join('');
367
+
368
+ console.log(` ${utils.COLORS.bold}Your Journey:${utils.COLORS.reset}`);
369
+ console.log(` ${journeyLine}`);
370
+ console.log();
371
+ }
372
+
373
+ // ============================================================================
374
+ // Action Handlers
375
+ // ============================================================================
376
+
377
+ /**
378
+ * Handle the guided wizard flow
379
+ */
380
+ async function handleGuidedWizard(rl, projectRoot, env) {
381
+ console.log(`\n${utils.COLORS.bold}Starting Guided Wizard...${utils.COLORS.reset}\n`);
382
+
383
+ // Import the preseed module and run wizard
384
+ const preseed = require('./preseed');
385
+ await preseed.run(['init']);
386
+ }
387
+
388
+ /**
389
+ * Handle AI prompts generation
390
+ */
391
+ async function handleAIPrompts(rl, projectRoot, env, projectContext) {
392
+ console.log(`\n${utils.COLORS.bold}AI Prompt Generator${utils.COLORS.reset}`);
393
+ console.log(`${utils.COLORS.dim}Get ready-to-use prompts for Claude, ChatGPT, or any LLM${utils.COLORS.reset}\n`);
394
+
395
+ // Check if we have wizard data to personalize prompts
396
+ let wizardData = {};
397
+ const wizardPath = path.join(projectRoot, '.bootspring', 'preseed', 'PRESEED_CONFIG.json');
398
+ if (fs.existsSync(wizardPath)) {
399
+ try {
400
+ wizardData = JSON.parse(fs.readFileSync(wizardPath, 'utf-8'));
401
+ } catch {}
402
+ }
403
+
404
+ // Ask which document they want to generate
405
+ console.log(`${utils.COLORS.bold}Which document do you want to create?${utils.COLORS.reset}\n`);
406
+
407
+ const documents = [
408
+ { id: 'vision', label: 'Vision Document', description: 'Problem, solution, and unique value' },
409
+ { id: 'audience', label: 'Target Audience', description: 'User personas and market segments' },
410
+ { id: 'prd', label: 'Product Requirements', description: 'Features, user stories, MVP scope' },
411
+ { id: 'technical', label: 'Technical Spec', description: 'Architecture and tech stack' },
412
+ { id: 'roadmap', label: 'Roadmap', description: 'Development phases and milestones' },
413
+ { id: 'all', label: 'All Documents', description: 'Get prompts for everything' }
414
+ ];
415
+
416
+ const selected = await askChoice(rl, documents);
417
+
418
+ // Generate the prompt
419
+ const prompt = generateAIPrompt(selected.id, wizardData);
420
+
421
+ console.log(`\n${utils.COLORS.green}━━━ COPY THIS PROMPT ━━━${utils.COLORS.reset}\n`);
422
+ console.log(prompt);
423
+ console.log(`\n${utils.COLORS.green}━━━ END OF PROMPT ━━━${utils.COLORS.reset}\n`);
424
+
425
+ // Offer to save or copy
426
+ console.log(`${utils.COLORS.dim}Paste this prompt into Claude, ChatGPT, or your favorite LLM.${utils.COLORS.reset}`);
427
+ console.log(`${utils.COLORS.dim}Then save the response to: .bootspring/preseed/${selected.id.toUpperCase()}.md${utils.COLORS.reset}\n`);
428
+
429
+ // Save prompt to file for easy access
430
+ const promptsDir = path.join(projectRoot, '.bootspring', 'preseed', 'prompts');
431
+ if (!fs.existsSync(promptsDir)) {
432
+ fs.mkdirSync(promptsDir, { recursive: true });
433
+ }
434
+
435
+ const promptFile = path.join(promptsDir, `${selected.id}-prompt.md`);
436
+ fs.writeFileSync(promptFile, prompt);
437
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Prompt saved to: ${utils.COLORS.cyan}${promptFile}${utils.COLORS.reset}`);
438
+ }
439
+
440
+ /**
441
+ * Generate AI prompt for a document type
442
+ */
443
+ function generateAIPrompt(docType, wizardData) {
444
+ const projectName = wizardData.identity?.name || '[YOUR PROJECT NAME]';
445
+ const tagline = wizardData.identity?.tagline || '[YOUR TAGLINE]';
446
+ const problem = wizardData.problem?.statement || '[THE PROBLEM YOU SOLVE]';
447
+ const solution = wizardData.solution?.description || '[YOUR SOLUTION]';
448
+ const audience = wizardData.audience?.primary || '[YOUR TARGET AUDIENCE]';
449
+
450
+ const prompts = {
451
+ vision: `# Generate a Vision Document
452
+
453
+ I'm building ${projectName} - ${tagline}.
454
+
455
+ **The Problem:**
456
+ ${problem}
457
+
458
+ **My Solution:**
459
+ ${solution}
460
+
461
+ **Target Audience:**
462
+ ${audience}
463
+
464
+ Please create a comprehensive Vision Document that includes:
465
+
466
+ 1. **Executive Summary** - One paragraph overview
467
+ 2. **Problem Statement** - Deep dive into the pain points
468
+ 3. **Solution Overview** - How we solve it uniquely
469
+ 4. **Key Features** - Top 5-7 features with descriptions
470
+ 5. **Value Proposition** - Why users will choose us
471
+ 6. **Success Metrics** - How we'll measure success
472
+
473
+ Format as clean Markdown. Be specific and actionable, not generic.`,
474
+
475
+ audience: `# Generate a Target Audience Document
476
+
477
+ I'm building ${projectName} - ${tagline}.
478
+
479
+ **Our Solution:**
480
+ ${solution}
481
+
482
+ Please create a comprehensive Target Audience Document that includes:
483
+
484
+ 1. **Primary Audience** - Main user segment with demographics
485
+ 2. **Secondary Audiences** - Other potential user groups
486
+ 3. **User Personas** - Create 2-3 detailed personas with:
487
+ - Name, role, background
488
+ - Goals and motivations
489
+ - Pain points and frustrations
490
+ - How our product helps them
491
+ - Quote that captures their perspective
492
+ 4. **Market Segments** - B2B, B2C, enterprise, SMB, etc.
493
+ 5. **Ideal Customer Profile (ICP)** - Specific characteristics
494
+
495
+ Format as clean Markdown with tables where appropriate.`,
496
+
497
+ prd: `# Generate a Product Requirements Document (PRD)
498
+
499
+ I'm building ${projectName} - ${tagline}.
500
+
501
+ **The Problem:**
502
+ ${problem}
503
+
504
+ **Our Solution:**
505
+ ${solution}
506
+
507
+ **Target Audience:**
508
+ ${audience}
509
+
510
+ Please create a comprehensive PRD that includes:
511
+
512
+ 1. **Product Vision** - The north star
513
+ 2. **MVP Scope** - What's in v1.0 vs later
514
+ 3. **Feature List** - Prioritized (P0, P1, P2) with:
515
+ - Feature name
516
+ - Description
517
+ - User value
518
+ - Acceptance criteria
519
+ 4. **User Stories** - 5-10 key stories in "As a... I want... So that..." format
520
+ 5. **Non-Functional Requirements** - Performance, security, scalability
521
+ 6. **Out of Scope** - What we're NOT building in MVP
522
+ 7. **Dependencies & Risks**
523
+
524
+ Format as clean Markdown. Be specific enough that a developer could implement from this.`,
525
+
526
+ technical: `# Generate a Technical Specification
527
+
528
+ I'm building ${projectName} - ${tagline}.
529
+
530
+ **Our Solution:**
531
+ ${solution}
532
+
533
+ Please create a Technical Specification that includes:
534
+
535
+ 1. **Technology Stack Recommendation**
536
+ - Frontend framework and why
537
+ - Backend/API approach
538
+ - Database choice
539
+ - Hosting/deployment
540
+ - Key libraries/tools
541
+
542
+ 2. **Architecture Overview**
543
+ - High-level system design
544
+ - Component diagram (describe in text)
545
+ - Data flow
546
+
547
+ 3. **Data Models** - Key entities and relationships
548
+
549
+ 4. **API Design** - Main endpoints needed
550
+
551
+ 5. **Third-Party Integrations** - What external services
552
+
553
+ 6. **Security Considerations** - Auth, data protection
554
+
555
+ 7. **Scalability Plan** - How it grows
556
+
557
+ Format as clean Markdown with code blocks where helpful.`,
558
+
559
+ roadmap: `# Generate a Product Roadmap
560
+
561
+ I'm building ${projectName} - ${tagline}.
562
+
563
+ **MVP Features:**
564
+ ${wizardData.mvp?.features?.join(', ') || '[LIST YOUR MVP FEATURES]'}
565
+
566
+ Please create a Product Roadmap that includes:
567
+
568
+ 1. **Phase 1: MVP** (Target: 4-6 weeks)
569
+ - Core features to ship
570
+ - Success criteria
571
+ - Key milestones
572
+
573
+ 2. **Phase 2: Growth** (Next 2-3 months)
574
+ - Features to add
575
+ - User acquisition focus
576
+ - Iteration based on feedback
577
+
578
+ 3. **Phase 3: Scale** (3-6 months out)
579
+ - Advanced features
580
+ - Enterprise/team features
581
+ - Platform expansion
582
+
583
+ 4. **Milestone Timeline** - Visual table format
584
+
585
+ 5. **Dependencies & Risks** - What could block progress
586
+
587
+ Format as clean Markdown with a timeline table.`,
588
+
589
+ all: `# Generate Complete Preseed Documentation
590
+
591
+ I'm building ${projectName} - ${tagline}.
592
+
593
+ **The Problem:**
594
+ ${problem}
595
+
596
+ **My Solution:**
597
+ ${solution}
598
+
599
+ **Target Audience:**
600
+ ${audience}
601
+
602
+ Please generate a complete set of preseed documents. For each document, create a separate section:
603
+
604
+ ## 1. VISION.md
605
+ [Generate vision document with problem, solution, value prop]
606
+
607
+ ## 2. AUDIENCE.md
608
+ [Generate audience doc with personas, segments, ICP]
609
+
610
+ ## 3. PRD.md
611
+ [Generate PRD with features, user stories, MVP scope]
612
+
613
+ ## 4. TECHNICAL_SPEC.md
614
+ [Generate tech spec with stack, architecture, data models]
615
+
616
+ ## 5. ROADMAP.md
617
+ [Generate roadmap with phases, milestones, timeline]
618
+
619
+ For each document, be specific and actionable. Use clean Markdown formatting.
620
+ After generating, I'll split these into separate files.`
621
+ };
622
+
623
+ return prompts[docType] || prompts.vision;
624
+ }
625
+
626
+ /**
627
+ * Handle analyzing files dropped in the drop zone
628
+ */
629
+ async function handleAnalyzeDrop(rl, projectRoot, env, projectContext) {
630
+ console.log(`\n${utils.COLORS.cyan}${utils.COLORS.bold}Drop Zone Analysis${utils.COLORS.reset}`);
631
+ console.log(`${utils.COLORS.dim}Analyzing your files to extract preseed insights${utils.COLORS.reset}\n`);
632
+
633
+ const dropDir = path.join(projectRoot, '.bootspring', 'preseed', 'context', 'drop');
634
+ const files = projectContext.hasDropFiles || [];
635
+
636
+ if (files.length === 0) {
637
+ console.log(`${utils.COLORS.yellow}No files found in drop zone.${utils.COLORS.reset}`);
638
+ console.log(`\nAdd files to: ${utils.COLORS.cyan}${dropDir}${utils.COLORS.reset}\n`);
639
+ return;
640
+ }
641
+
642
+ // List files found
643
+ console.log(`${utils.COLORS.bold}Files found:${utils.COLORS.reset}`);
644
+ files.forEach((file, i) => {
645
+ const ext = path.extname(file).toLowerCase();
646
+ const icon = getFileIcon(ext);
647
+ console.log(` ${utils.COLORS.green}${i + 1}.${utils.COLORS.reset} ${icon} ${file}`);
648
+ });
649
+ console.log();
650
+
651
+ // Read content from text-based files
652
+ const fileContents = [];
653
+ const textExtensions = ['.md', '.txt', '.json', '.yaml', '.yml', '.csv'];
654
+
655
+ for (const file of files) {
656
+ const ext = path.extname(file).toLowerCase();
657
+ const filePath = path.join(dropDir, file);
658
+
659
+ if (textExtensions.includes(ext)) {
660
+ try {
661
+ const content = fs.readFileSync(filePath, 'utf-8');
662
+ const truncated = content.length > 5000 ? content.slice(0, 5000) + '\n...[truncated]' : content;
663
+ fileContents.push({
664
+ name: file,
665
+ type: ext,
666
+ content: truncated
667
+ });
668
+ } catch (err) {
669
+ fileContents.push({
670
+ name: file,
671
+ type: ext,
672
+ content: `[Error reading file: ${err.message}]`
673
+ });
674
+ }
675
+ } else {
676
+ // For binary files, just note their presence
677
+ fileContents.push({
678
+ name: file,
679
+ type: ext,
680
+ content: `[Binary file - ${ext} - describe what this file likely contains based on filename]`
681
+ });
682
+ }
683
+ }
684
+
685
+ // Generate the analysis prompt
686
+ const prompt = generateDropAnalysisPrompt(fileContents);
687
+
688
+ console.log(`${utils.COLORS.green}━━━ COPY THIS PROMPT ━━━${utils.COLORS.reset}\n`);
689
+ console.log(prompt);
690
+ console.log(`\n${utils.COLORS.green}━━━ END OF PROMPT ━━━${utils.COLORS.reset}\n`);
691
+
692
+ // Save prompt to file
693
+ const promptsDir = path.join(projectRoot, '.bootspring', 'preseed', 'prompts');
694
+ if (!fs.existsSync(promptsDir)) {
695
+ fs.mkdirSync(promptsDir, { recursive: true });
696
+ }
697
+
698
+ const promptFile = path.join(promptsDir, 'drop-analysis-prompt.md');
699
+ fs.writeFileSync(promptFile, prompt);
700
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Prompt saved to: ${utils.COLORS.cyan}${promptFile}${utils.COLORS.reset}`);
701
+
702
+ console.log(`\n${utils.COLORS.bold}Next steps:${utils.COLORS.reset}`);
703
+ console.log(' 1. Paste this prompt into Claude, ChatGPT, or your LLM');
704
+ console.log(' 2. The AI will analyze your files and create preseed documents');
705
+ console.log(` 3. Save the outputs to ${utils.COLORS.cyan}.bootspring/preseed/${utils.COLORS.reset}`);
706
+ console.log(` 4. Run ${utils.COLORS.cyan}bootspring seed synthesize${utils.COLORS.reset} to create SEED.md\n`);
707
+ }
708
+
709
+ /**
710
+ * Get icon for file type
711
+ */
712
+ function getFileIcon(ext) {
713
+ const icons = {
714
+ '.md': '\u{1F4DD}',
715
+ '.txt': '\u{1F4C4}',
716
+ '.pdf': '\u{1F4D5}',
717
+ '.docx': '\u{1F4D8}',
718
+ '.doc': '\u{1F4D8}',
719
+ '.png': '\u{1F5BC}',
720
+ '.jpg': '\u{1F5BC}',
721
+ '.jpeg': '\u{1F5BC}',
722
+ '.csv': '\u{1F4CA}',
723
+ '.json': '\u{2699}',
724
+ '.yaml': '\u{2699}',
725
+ '.yml': '\u{2699}'
726
+ };
727
+ return icons[ext] || '\u{1F4CE}';
728
+ }
729
+
730
+ /**
731
+ * Generate AI prompt to analyze drop zone files
732
+ */
733
+ function generateDropAnalysisPrompt(fileContents) {
734
+ const fileList = fileContents.map(f => `- ${f.name} (${f.type})`).join('\n');
735
+
736
+ let prompt = `# Analyze My Project Materials
737
+
738
+ I have the following files that describe my project idea. Please analyze them and help me create structured preseed documents.
739
+
740
+ ## Files to Analyze
741
+
742
+ ${fileList}
743
+
744
+ ## File Contents
745
+
746
+ `;
747
+
748
+ for (const file of fileContents) {
749
+ prompt += `### ${file.name}
750
+
751
+ \`\`\`
752
+ ${file.content}
753
+ \`\`\`
754
+
755
+ `;
756
+ }
757
+
758
+ prompt += `## Your Task
759
+
760
+ Based on these materials, please create the following preseed documents:
761
+
762
+ ### 1. VISION.md
763
+ Extract and synthesize:
764
+ - Executive Summary (one paragraph)
765
+ - Problem Statement (what problem does this solve?)
766
+ - Solution Overview (how does it solve the problem?)
767
+ - Key Features (what are the main capabilities?)
768
+ - Value Proposition (why would someone use this?)
769
+
770
+ ### 2. AUDIENCE.md
771
+ Extract and synthesize:
772
+ - Primary Audience (who is this for?)
773
+ - User Personas (2-3 detailed personas if enough info)
774
+ - Market Segments (what types of users/companies?)
775
+
776
+ ### 3. PRD.md
777
+ Extract and synthesize:
778
+ - MVP Features (prioritized list with P0/P1/P2)
779
+ - User Stories (As a..., I want..., so that...)
780
+ - Requirements (functional and non-functional)
781
+
782
+ ### 4. TECHNICAL_SPEC.md (if technical details are present)
783
+ Extract and synthesize:
784
+ - Technology Stack recommendations
785
+ - Architecture overview
786
+ - Integration requirements
787
+
788
+ ### 5. ROADMAP.md
789
+ Extract and synthesize:
790
+ - Phase 1 (MVP scope)
791
+ - Phase 2 (Growth features)
792
+ - Key milestones
793
+
794
+ ## Output Format
795
+
796
+ Please output each document as a separate markdown section that I can copy into individual files. Use clean, professional formatting with headers and bullet points.
797
+
798
+ If information for a section is missing from my materials, note what additional information would be helpful rather than making assumptions.`;
799
+
800
+ return prompt;
801
+ }
802
+
803
+ /**
804
+ * Handle brain dump / idea dump mode
805
+ */
806
+ async function handleIdeaDump(rl, projectRoot) {
807
+ console.log(`\n${utils.COLORS.bold}Brain Dump Mode${utils.COLORS.reset}`);
808
+ console.log(`${utils.COLORS.dim}Just write freely about your idea. Press Enter twice when done.${utils.COLORS.reset}`);
809
+ console.log(`${utils.COLORS.dim}Don't worry about structure - we'll organize it for you.${utils.COLORS.reset}\n`);
810
+
811
+ console.log(`${utils.COLORS.cyan}Start typing your idea:${utils.COLORS.reset}\n`);
812
+
813
+ const lines = [];
814
+ let emptyCount = 0;
815
+
816
+ return new Promise((resolve) => {
817
+ const onLine = (line) => {
818
+ if (line.trim() === '') {
819
+ emptyCount++;
820
+ if (emptyCount >= 2) {
821
+ rl.removeListener('line', onLine);
822
+ processIdeaDump(lines.join('\n'), projectRoot);
823
+ resolve();
824
+ return;
825
+ }
826
+ } else {
827
+ emptyCount = 0;
828
+ }
829
+ lines.push(line);
830
+ };
831
+
832
+ rl.on('line', onLine);
833
+ });
834
+ }
835
+
836
+ /**
837
+ * Process the idea dump into structured format
838
+ */
839
+ function processIdeaDump(text, projectRoot) {
840
+ console.log(`\n${utils.COLORS.bold}Processing your idea...${utils.COLORS.reset}\n`);
841
+
842
+ // Save raw dump
843
+ const dumpDir = path.join(projectRoot, '.bootspring', 'preseed', 'context', 'ideas');
844
+ if (!fs.existsSync(dumpDir)) {
845
+ fs.mkdirSync(dumpDir, { recursive: true });
846
+ }
847
+
848
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
849
+ const dumpFile = path.join(dumpDir, `brain-dump-${timestamp}.md`);
850
+ fs.writeFileSync(dumpFile, `# Brain Dump\n\n${text}\n`);
851
+
852
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Saved to: ${utils.COLORS.cyan}${dumpFile}${utils.COLORS.reset}`);
853
+
854
+ // Generate a prompt for structuring
855
+ const structurePrompt = `# Structure This Idea
856
+
857
+ Here's a brain dump about a product idea. Please extract and organize it into:
858
+
859
+ 1. **Project Identity** - Name ideas, tagline options
860
+ 2. **Problem** - What problem is being solved
861
+ 3. **Solution** - How it's being solved
862
+ 4. **Target Audience** - Who it's for
863
+ 5. **Key Features** - Main capabilities mentioned
864
+ 6. **Unique Value** - What makes it different
865
+
866
+ Here's the brain dump:
867
+
868
+ ---
869
+ ${text}
870
+ ---
871
+
872
+ Please structure this into a JSON format like:
873
+ \`\`\`json
874
+ {
875
+ "identity": { "name": "...", "tagline": "..." },
876
+ "problem": { "statement": "...", "painPoints": [...] },
877
+ "solution": { "description": "...", "keyFeatures": [...] },
878
+ "audience": { "primary": "...", "segments": [...] },
879
+ "uniqueValue": "..."
880
+ }
881
+ \`\`\``;
882
+
883
+ // Save the structuring prompt
884
+ const promptFile = path.join(dumpDir, `structure-prompt-${timestamp}.md`);
885
+ fs.writeFileSync(promptFile, structurePrompt);
886
+
887
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Generated structuring prompt: ${utils.COLORS.cyan}${promptFile}${utils.COLORS.reset}`);
888
+ console.log();
889
+ console.log(`${utils.COLORS.bold}Next steps:${utils.COLORS.reset}`);
890
+ console.log(` 1. Copy the prompt from: ${utils.COLORS.cyan}${promptFile}${utils.COLORS.reset}`);
891
+ console.log(' 2. Paste into Claude or ChatGPT');
892
+ console.log(` 3. Save the JSON response to: ${utils.COLORS.cyan}.bootspring/preseed/PRESEED_CONFIG.json${utils.COLORS.reset}`);
893
+ console.log(` 4. Run: ${utils.COLORS.cyan}bootspring preseed generate${utils.COLORS.reset}`);
894
+ }
895
+
896
+ /**
897
+ * Handle dashboard redirect
898
+ */
899
+ async function handleDashboard(projectRoot, env) {
900
+ const project = session.getEffectiveProject();
901
+
902
+ let url = 'https://bootspring.com/dashboard/projects';
903
+ if (project?.id) {
904
+ url = `https://bootspring.com/dashboard/projects/${project.id}/preseed/studio`;
905
+ }
906
+
907
+ console.log(`\n${utils.COLORS.bold}Opening Dashboard...${utils.COLORS.reset}`);
908
+ console.log(`${utils.COLORS.dim}${url}${utils.COLORS.reset}\n`);
909
+
910
+ // Try to open browser
911
+ const { exec } = require('child_process');
912
+ const command = process.platform === 'darwin' ? 'open' :
913
+ process.platform === 'win32' ? 'start' : 'xdg-open';
914
+
915
+ exec(`${command} "${url}"`, (err) => {
916
+ if (err) {
917
+ console.log(`${utils.COLORS.yellow}Could not open browser automatically.${utils.COLORS.reset}`);
918
+ console.log(`Please visit: ${utils.COLORS.cyan}${url}${utils.COLORS.reset}`);
919
+ }
920
+ });
921
+ }
922
+
923
+ /**
924
+ * Handle Claude Code / MCP mode
925
+ */
926
+ async function handleClaudeCode(rl, projectRoot, env) {
927
+ console.log(`\n${utils.COLORS.magenta}${utils.COLORS.bold}Claude Code Mode${utils.COLORS.reset}`);
928
+ console.log();
929
+ console.log(`${utils.COLORS.dim}You're in Claude Code! You can generate preseed documents directly.${utils.COLORS.reset}`);
930
+ console.log();
931
+ console.log(`${utils.COLORS.bold}Try saying:${utils.COLORS.reset}`);
932
+ console.log();
933
+ console.log(` ${utils.COLORS.cyan}"Help me create preseed documents for my app idea"${utils.COLORS.reset}`);
934
+ console.log(` ${utils.COLORS.cyan}"Generate a vision document for [your idea]"${utils.COLORS.reset}`);
935
+ console.log(` ${utils.COLORS.cyan}"Create a PRD based on my preseed config"${utils.COLORS.reset}`);
936
+ console.log();
937
+
938
+ if (env.capabilities.aiGeneration) {
939
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} AI generation is enabled for your account`);
940
+ } else {
941
+ console.log(`${utils.COLORS.yellow}!${utils.COLORS.reset} Upgrade to Pro for AI-powered document generation`);
942
+ console.log(` ${utils.COLORS.dim}https://bootspring.com/pricing${utils.COLORS.reset}`);
943
+ }
944
+ }
945
+
946
+ /**
947
+ * Handle building from existing context files
948
+ * This synthesizes/merges documents from context folders into preseed output
949
+ */
950
+ async function handleFromContext(rl, projectRoot, env, projectContext) {
951
+ console.log(`\n${utils.COLORS.cyan}${utils.COLORS.bold}Building from your existing materials${utils.COLORS.reset}`);
952
+ console.log(`${utils.COLORS.dim}Synthesizing documents from your context folders...${utils.COLORS.reset}\n`);
953
+
954
+ const contextDir = path.join(projectRoot, '.bootspring', 'preseed', 'context');
955
+ const outputDir = path.join(projectRoot, '.bootspring', 'preseed');
956
+
957
+ // Document type mappings: folder -> output filename
958
+ const docMappings = {
959
+ 'vision': 'VISION.md',
960
+ 'audience': 'AUDIENCE.md',
961
+ 'market': 'MARKET.md',
962
+ 'competitors': 'COMPETITORS.md',
963
+ 'business': 'BUSINESS_MODEL.md',
964
+ 'prd': 'PRD.md',
965
+ 'technical': 'TECHNICAL_SPEC.md',
966
+ 'roadmap': 'ROADMAP.md'
967
+ };
968
+
969
+ const synthesized = [];
970
+ const needsSynthesis = [];
971
+
972
+ // Check each document folder
973
+ for (const [folder, outputFile] of Object.entries(docMappings)) {
974
+ const folderPath = path.join(contextDir, folder);
975
+ if (!fs.existsSync(folderPath)) continue;
976
+
977
+ const files = fs.readdirSync(folderPath).filter(f =>
978
+ !f.startsWith('.') && (f.endsWith('.md') || f.endsWith('.txt'))
979
+ );
980
+
981
+ if (files.length === 0) continue;
982
+
983
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} ${folder}/: ${files.length} file(s)`);
984
+
985
+ // Read all files in this folder
986
+ const contents = [];
987
+ for (const file of files) {
988
+ const filePath = path.join(folderPath, file);
989
+ try {
990
+ const content = fs.readFileSync(filePath, 'utf-8');
991
+ contents.push({
992
+ filename: file,
993
+ content: content
994
+ });
995
+ } catch (err) {
996
+ console.log(` ${utils.COLORS.yellow}!${utils.COLORS.reset} Could not read ${file}`);
997
+ }
998
+ }
999
+
1000
+ if (contents.length === 1) {
1001
+ // Single file - just copy it (with header)
1002
+ const outputPath = path.join(outputDir, outputFile);
1003
+ const header = `<!-- Generated from: ${folder}/${contents[0].filename} -->\n\n`;
1004
+ fs.writeFileSync(outputPath, header + contents[0].content);
1005
+ synthesized.push({ folder, outputFile, files: 1 });
1006
+ } else if (contents.length > 1) {
1007
+ // Multiple files - need to synthesize/merge
1008
+ needsSynthesis.push({
1009
+ folder,
1010
+ outputFile,
1011
+ contents
1012
+ });
1013
+ }
1014
+ }
1015
+
1016
+ // Handle multi-file folders
1017
+ if (needsSynthesis.length > 0) {
1018
+ console.log(`\n${utils.COLORS.green}${utils.COLORS.bold}Multiple source files detected${utils.COLORS.reset}`);
1019
+ console.log(`${utils.COLORS.dim}All files will be read during SEED.md generation - no merge required.${utils.COLORS.reset}\n`);
1020
+
1021
+ for (const item of needsSynthesis) {
1022
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${item.outputFile}: ${item.contents.length} sources will be used`);
1023
+ for (const c of item.contents) {
1024
+ console.log(` ${utils.COLORS.dim}└ ${c.filename}${utils.COLORS.reset}`);
1025
+ }
1026
+ }
1027
+
1028
+ // Ask if they want to merge (optional)
1029
+ console.log();
1030
+ const wantMerge = await askText(rl, `${utils.COLORS.dim}Create merged single-file versions? (optional)${utils.COLORS.reset}`, 'y/N');
1031
+
1032
+ if (wantMerge.toLowerCase() === 'y' || wantMerge.toLowerCase() === 'yes') {
1033
+ // Decision engine - ask about merge preferences
1034
+ console.log(`\n${utils.COLORS.cyan}${utils.COLORS.bold}Merge Settings${utils.COLORS.reset}\n`);
1035
+
1036
+ const mergeStrategy = await askChoice(rl, [
1037
+ { id: 'conservative', label: 'Conservative (Recommended)', description: 'Keep ALL content, only remove exact duplicates' },
1038
+ { id: 'balanced', label: 'Balanced', description: 'Merge similar sections, keep unique content' },
1039
+ { id: 'aggressive', label: 'Aggressive', description: 'Synthesize into most concise version' }
1040
+ ]);
1041
+
1042
+ const conflictResolution = await askChoice(rl, [
1043
+ { id: 'keep-both', label: 'Keep both versions', description: 'When content differs, include both with labels' },
1044
+ { id: 'prefer-detailed', label: 'Prefer more detailed', description: 'When content differs, use the longer/more detailed version' },
1045
+ { id: 'ask-in-prompt', label: 'Flag for review', description: 'Mark conflicts for manual decision' }
1046
+ ]);
1047
+
1048
+ const includeChangelog = await askText(rl, 'Include changelog showing what came from each source?', 'Y/n');
1049
+ const showChangelog = includeChangelog.toLowerCase() !== 'n';
1050
+
1051
+ const mergeConfig = {
1052
+ strategy: mergeStrategy.id,
1053
+ conflictResolution: conflictResolution.id,
1054
+ includeChangelog: showChangelog
1055
+ };
1056
+
1057
+ // Ask how to execute the merge
1058
+ console.log(`\n${utils.COLORS.bold}How do you want to merge?${utils.COLORS.reset}\n`);
1059
+ const mergeMethod = await askChoice(rl, [
1060
+ { id: 'ai-execute', label: 'Have AI execute now (Recommended)', description: 'Claude Code / Cursor / Codex will merge directly' },
1061
+ { id: 'prompts', label: 'Generate prompts only', description: 'Copy prompts to paste into another LLM' }
1062
+ ]);
1063
+
1064
+ const promptsDir = path.join(outputDir, 'prompts');
1065
+ if (!fs.existsSync(promptsDir)) {
1066
+ fs.mkdirSync(promptsDir, { recursive: true });
1067
+ }
1068
+
1069
+ if (mergeMethod.id === 'ai-execute') {
1070
+ // Create a merge manifest for AI execution
1071
+ const manifest = {
1072
+ created: new Date().toISOString(),
1073
+ settings: mergeConfig,
1074
+ tasks: []
1075
+ };
1076
+
1077
+ for (const item of needsSynthesis) {
1078
+ manifest.tasks.push({
1079
+ folder: item.folder,
1080
+ outputFile: item.outputFile,
1081
+ outputPath: path.join(outputDir, item.outputFile),
1082
+ sources: item.contents.map(c => ({
1083
+ filename: c.filename,
1084
+ path: path.join(contextDir, item.folder, c.filename)
1085
+ }))
1086
+ });
1087
+ }
1088
+
1089
+ // Save manifest
1090
+ const manifestPath = path.join(outputDir, 'MERGE_MANIFEST.json');
1091
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
1092
+
1093
+ // Also create a human-readable instruction file
1094
+ let instructions = `# Merge Instructions for AI Assistant
1095
+
1096
+ ## Settings
1097
+ - **Strategy**: ${mergeStrategy.label}
1098
+ - **Conflicts**: ${conflictResolution.label}
1099
+ - **Changelog**: ${showChangelog ? 'Yes' : 'No'}
1100
+
1101
+ ## Rules
1102
+ ${mergeStrategy.id === 'conservative' ? `
1103
+ - NEVER delete unique content from any source
1104
+ - ONLY remove exact duplicate sentences/paragraphs
1105
+ - When in doubt, KEEP the content
1106
+ ` : mergeStrategy.id === 'balanced' ? `
1107
+ - Merge similar sections covering the same topic
1108
+ - Preserve all unique content
1109
+ - Remove clear redundancies
1110
+ ` : `
1111
+ - Synthesize into most concise version
1112
+ - Keep only the strongest version of each point
1113
+ `}
1114
+
1115
+ ## Conflict Resolution
1116
+ ${conflictResolution.id === 'keep-both' ? `
1117
+ - When sources differ, include BOTH versions with labels
1118
+ ` : conflictResolution.id === 'prefer-detailed' ? `
1119
+ - When sources differ, use the MORE DETAILED version
1120
+ ` : `
1121
+ - Mark conflicts with ⚠️ for manual review
1122
+ `}
1123
+
1124
+ ## Tasks
1125
+
1126
+ Please merge the following documents:
1127
+
1128
+ `;
1129
+
1130
+ for (const item of needsSynthesis) {
1131
+ instructions += `### ${item.outputFile}
1132
+ **Sources:**
1133
+ ${item.contents.map(c => `- \`context/${item.folder}/${c.filename}\``).join('\n')}
1134
+
1135
+ **Output:** \`.bootspring/preseed/${item.outputFile}\`
1136
+
1137
+ ---
1138
+
1139
+ `;
1140
+ }
1141
+
1142
+ instructions += `
1143
+ ## How to Execute
1144
+
1145
+ Read each source file, merge according to the rules above, and save to the output path.
1146
+ ${showChangelog ? 'Include a changelog section at the end of each merged document.' : ''}
1147
+ `;
1148
+
1149
+ const instructionsPath = path.join(outputDir, 'MERGE_INSTRUCTIONS.md');
1150
+ fs.writeFileSync(instructionsPath, instructions);
1151
+
1152
+ console.log(`\n${utils.COLORS.green}${utils.COLORS.bold}Ready for AI merge!${utils.COLORS.reset}\n`);
1153
+ console.log(`${utils.COLORS.bold}Files created:${utils.COLORS.reset}`);
1154
+ console.log(` ${utils.COLORS.cyan}●${utils.COLORS.reset} MERGE_MANIFEST.json - Machine-readable task list`);
1155
+ console.log(` ${utils.COLORS.cyan}●${utils.COLORS.reset} MERGE_INSTRUCTIONS.md - Human-readable instructions`);
1156
+ console.log();
1157
+
1158
+ // Automatically run the merge command to output tasks for AI
1159
+ console.log(`${utils.COLORS.bold}Executing merge command...${utils.COLORS.reset}\n`);
1160
+ const preseed = require('./preseed');
1161
+ await preseed.run(['merge']);
1162
+
1163
+ } else {
1164
+ // Original behavior - generate prompts only
1165
+ console.log(`\n${utils.COLORS.yellow}Creating merge prompts...${utils.COLORS.reset}\n`);
1166
+
1167
+ for (const item of needsSynthesis) {
1168
+ const prompt = generateMergePrompt(item.folder, item.outputFile, item.contents, mergeConfig);
1169
+ const promptFile = path.join(promptsDir, `merge-${item.folder}-prompt.md`);
1170
+ fs.writeFileSync(promptFile, prompt);
1171
+
1172
+ console.log(` ${utils.COLORS.cyan}●${utils.COLORS.reset} ${item.outputFile}: merge prompt → ${utils.COLORS.dim}${path.basename(promptFile)}${utils.COLORS.reset}`);
1173
+ }
1174
+
1175
+ console.log(`\n${utils.COLORS.bold}Merge prompts saved to:${utils.COLORS.reset} ${utils.COLORS.cyan}.bootspring/preseed/prompts/${utils.COLORS.reset}`);
1176
+ console.log(`${utils.COLORS.dim}Paste prompts into an LLM, review output, then save to .bootspring/preseed/${utils.COLORS.reset}`);
1177
+ }
1178
+
1179
+ console.log(`\n${utils.COLORS.bold}Your settings:${utils.COLORS.reset}`);
1180
+ console.log(` Strategy: ${utils.COLORS.cyan}${mergeStrategy.label}${utils.COLORS.reset}`);
1181
+ console.log(` Conflicts: ${utils.COLORS.cyan}${conflictResolution.label}${utils.COLORS.reset}`);
1182
+ console.log(` Changelog: ${utils.COLORS.cyan}${showChangelog ? 'Yes' : 'No'}${utils.COLORS.reset}`);
1183
+ } else {
1184
+ console.log(`\n${utils.COLORS.green}✓${utils.COLORS.reset} Keeping all source files - they'll all be used during SEED.md generation.`);
1185
+ }
1186
+ }
1187
+
1188
+ // Summary
1189
+ if (synthesized.length > 0) {
1190
+ console.log(`\n${utils.COLORS.green}${utils.COLORS.bold}Documents created:${utils.COLORS.reset}`);
1191
+ for (const doc of synthesized) {
1192
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${doc.outputFile}`);
1193
+ }
1194
+ }
1195
+
1196
+ // Create/update PRESEED_CONFIG.json with project info extracted from docs
1197
+ console.log(`\n${utils.COLORS.dim}Tip: Run ${utils.COLORS.cyan}bootspring preseed status${utils.COLORS.reset}${utils.COLORS.dim} to see your documents${utils.COLORS.reset}`);
1198
+ }
1199
+
1200
+ /**
1201
+ * Generate a prompt to merge multiple source files into one document
1202
+ */
1203
+ function generateMergePrompt(folder, outputFile, contents, config = {}) {
1204
+ const docType = folder.charAt(0).toUpperCase() + folder.slice(1);
1205
+ const strategy = config.strategy || 'conservative';
1206
+ const conflictRes = config.conflictResolution || 'keep-both';
1207
+ const includeChangelog = config.includeChangelog !== false;
1208
+
1209
+ let prompt = `# Merge ${docType} Documents
1210
+
1211
+ I have ${contents.length} source files for my ${docType} document. Please merge them into a single ${outputFile}.
1212
+
1213
+ ## CRITICAL RULES - READ FIRST
1214
+
1215
+ ${strategy === 'conservative' ? `
1216
+ **CONSERVATIVE MERGE MODE**
1217
+ 1. **NEVER DELETE** unique content from any source
1218
+ 2. **ONLY REMOVE** exact duplicate sentences/paragraphs
1219
+ 3. **PRESERVE** all unique insights, details, and perspectives
1220
+ 4. When in doubt, KEEP the content
1221
+ 5. It's better to have slight redundancy than to lose information
1222
+ ` : strategy === 'balanced' ? `
1223
+ **BALANCED MERGE MODE**
1224
+ 1. Merge similar sections that cover the same topic
1225
+ 2. Preserve all unique content that appears in only one source
1226
+ 3. When content overlaps but differs in detail, keep the more detailed version
1227
+ 4. Remove only clear redundancies
1228
+ ` : `
1229
+ **AGGRESSIVE MERGE MODE**
1230
+ 1. Synthesize into the most concise version
1231
+ 2. Eliminate all redundancy
1232
+ 3. Keep only the strongest/most detailed version of each point
1233
+ 4. Flag any content you're uncertain about removing
1234
+ `}
1235
+
1236
+ ## Conflict Resolution
1237
+
1238
+ ${conflictRes === 'keep-both' ? `
1239
+ When sources have DIFFERENT content on the same topic:
1240
+ - Include BOTH versions
1241
+ - Label them: "[Source A view]" and "[Source B view]"
1242
+ - Let the user decide later which to keep
1243
+ ` : conflictRes === 'prefer-detailed' ? `
1244
+ When sources have DIFFERENT content on the same topic:
1245
+ - Use the MORE DETAILED version
1246
+ - If detail is similar, use the more specific/concrete version
1247
+ - Note in changelog what was not used
1248
+ ` : `
1249
+ When sources have DIFFERENT content on the same topic:
1250
+ - Mark with: "⚠️ CONFLICT - Review needed"
1251
+ - Show both versions inline
1252
+ - User will manually resolve
1253
+ `}
1254
+
1255
+ ## Source Files
1256
+
1257
+ `;
1258
+
1259
+ for (const item of contents) {
1260
+ prompt += `### ${item.filename}
1261
+
1262
+ \`\`\`markdown
1263
+ ${item.content}
1264
+ \`\`\`
1265
+
1266
+ ---
1267
+
1268
+ `;
1269
+ }
1270
+
1271
+ prompt += `## Output Format
1272
+
1273
+ Create a single ${outputFile} with:
1274
+ - Clear structure with headers
1275
+ - All unique content from each source preserved
1276
+ - Clean Markdown formatting
1277
+
1278
+ ${includeChangelog ? `
1279
+ ## REQUIRED: Changelog Section
1280
+
1281
+ At the END of the merged document, include:
1282
+
1283
+ \`\`\`
1284
+ ---
1285
+ ## Merge Changelog
1286
+
1287
+ ### From ${contents[0]?.filename || 'Source 1'}:
1288
+ - [List what was kept from this source]
1289
+
1290
+ ### From ${contents[1]?.filename || 'Source 2'}:
1291
+ - [List what was kept from this source]
1292
+
1293
+ ### Duplicates Removed:
1294
+ - [List any exact duplicates that were deduplicated]
1295
+
1296
+ ### Conflicts Found:
1297
+ - [List any conflicts and how they were resolved]
1298
+ \`\`\`
1299
+
1300
+ This changelog lets the user verify nothing important was lost.
1301
+ ` : ''}
1302
+
1303
+ Remember: The user's original files are preserved. This merge creates a NEW combined version.`;
1304
+
1305
+ return prompt;
1306
+ }
1307
+
1308
+ /**
1309
+ * Handle synthesis of preseed docs into SEED.md
1310
+ */
1311
+ async function handleSynthesize(rl, projectRoot, env, projectContext) {
1312
+ console.log(`\n${utils.COLORS.bold}Synthesize SEED.md${utils.COLORS.reset}`);
1313
+ console.log(`${utils.COLORS.dim}Creating SEED.md from your ${projectContext.hasPreseedDocs.length} preseed documents...${utils.COLORS.reset}\n`);
1314
+
1315
+ // Read all preseed docs
1316
+ const preseedDir = path.join(projectRoot, '.bootspring', 'preseed');
1317
+ const docs = {};
1318
+
1319
+ for (const file of projectContext.hasPreseedDocs) {
1320
+ const filePath = path.join(preseedDir, file);
1321
+ docs[file.replace('.md', '')] = fs.readFileSync(filePath, 'utf-8');
1322
+ }
1323
+
1324
+ // Generate synthesis prompt
1325
+ const synthesisPrompt = `# Synthesize SEED.md
1326
+
1327
+ I have the following preseed documents for my project. Please synthesize them into a single SEED.md file that:
1328
+
1329
+ 1. Provides a complete project overview
1330
+ 2. Defines the technical implementation guide
1331
+ 3. Establishes development standards
1332
+ 4. Creates a clear path from idea to implementation
1333
+
1334
+ Here are my preseed documents:
1335
+
1336
+ ${Object.entries(docs).map(([name, content]) => `## ${name}\n\n${content}`).join('\n\n---\n\n')}
1337
+
1338
+ ---
1339
+
1340
+ Please create a comprehensive SEED.md with:
1341
+
1342
+ 1. **Project Overview** - What we're building
1343
+ 2. **Technical Stack** - Technologies and architecture
1344
+ 3. **Core Features** - What to implement first
1345
+ 4. **Development Standards** - Code style, patterns
1346
+ 5. **File Structure** - How to organize the codebase
1347
+ 6. **Implementation Guide** - Step-by-step build order
1348
+ 7. **Success Criteria** - How to know when it's done
1349
+
1350
+ Make it actionable for a developer or AI assistant to follow.`;
1351
+
1352
+ // Save prompt
1353
+ const promptPath = path.join(preseedDir, 'prompts', 'synthesize-seed-prompt.md');
1354
+ const promptDir = path.dirname(promptPath);
1355
+ if (!fs.existsSync(promptDir)) {
1356
+ fs.mkdirSync(promptDir, { recursive: true });
1357
+ }
1358
+ fs.writeFileSync(promptPath, synthesisPrompt);
1359
+
1360
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Generated synthesis prompt`);
1361
+ console.log();
1362
+ console.log(`${utils.COLORS.bold}Next steps:${utils.COLORS.reset}`);
1363
+ console.log(` 1. Copy prompt from: ${utils.COLORS.cyan}${promptPath}${utils.COLORS.reset}`);
1364
+ console.log(' 2. Paste into Claude or ChatGPT');
1365
+ console.log(` 3. Save response as: ${utils.COLORS.cyan}SEED.md${utils.COLORS.reset} in project root`);
1366
+ console.log(` 4. Run: ${utils.COLORS.cyan}bootspring scaffold${utils.COLORS.reset}`);
1367
+
1368
+ if (env.capabilities.aiGeneration) {
1369
+ console.log();
1370
+ console.log(`${utils.COLORS.green}Tip:${utils.COLORS.reset} You can also use the dashboard for AI-powered synthesis!`);
1371
+ }
1372
+ }
1373
+
1374
+ /**
1375
+ * Handle resume from previous progress
1376
+ */
1377
+ async function handleResume(rl, projectRoot, projectContext) {
1378
+ console.log(`\n${utils.COLORS.bold}Resuming...${utils.COLORS.reset}`);
1379
+ console.log(`${utils.COLORS.dim}Last step: ${projectContext.previousProgress.lastStep}${utils.COLORS.reset}\n`);
1380
+
1381
+ // Load progress and continue wizard
1382
+ const preseed = require('./preseed');
1383
+ await preseed.run(['workflow', 'resume']);
1384
+ }
1385
+
1386
+ // ============================================================================
1387
+ // Main Entry Point
1388
+ // ============================================================================
1389
+
1390
+ /**
1391
+ * Start the preseed journey
1392
+ */
1393
+ async function start(args) {
1394
+ const projectRoot = config.findProjectRoot();
1395
+
1396
+ // Detect context
1397
+ const env = detectEnvironment();
1398
+ const projectContext = detectProjectContext(projectRoot);
1399
+
1400
+ // Display UI
1401
+ displayHeader(env, projectContext);
1402
+ displayJourney(projectContext);
1403
+
1404
+ // Get recommendations
1405
+ const recommendations = determineStartingPoint(env, projectContext);
1406
+
1407
+ // Show options
1408
+ console.log(`${utils.COLORS.bold}How would you like to proceed?${utils.COLORS.reset}\n`);
1409
+
1410
+ const rl = createInterface();
1411
+ const selected = await askChoice(rl, recommendations);
1412
+
1413
+ // Handle selection
1414
+ switch (selected.id) {
1415
+ case 'resume':
1416
+ await handleResume(rl, projectRoot, projectContext);
1417
+ break;
1418
+
1419
+ case 'guided-wizard':
1420
+ rl.close();
1421
+ await handleGuidedWizard(rl, projectRoot, env);
1422
+ break;
1423
+
1424
+ case 'ai-prompts':
1425
+ await handleAIPrompts(rl, projectRoot, env, projectContext);
1426
+ rl.close();
1427
+ break;
1428
+
1429
+ case 'idea-dump':
1430
+ await handleIdeaDump(rl, projectRoot);
1431
+ rl.close();
1432
+ break;
1433
+
1434
+ case 'dashboard':
1435
+ rl.close();
1436
+ await handleDashboard(projectRoot, env);
1437
+ break;
1438
+
1439
+ case 'claude-code':
1440
+ await handleClaudeCode(rl, projectRoot, env);
1441
+ rl.close();
1442
+ break;
1443
+
1444
+ case 'synthesize':
1445
+ await handleSynthesize(rl, projectRoot, env, projectContext);
1446
+ rl.close();
1447
+ break;
1448
+
1449
+ case 'from-context':
1450
+ await handleFromContext(rl, projectRoot, env, projectContext);
1451
+ rl.close();
1452
+ break;
1453
+
1454
+ case 'analyze-drop':
1455
+ await handleAnalyzeDrop(rl, projectRoot, env, projectContext);
1456
+ rl.close();
1457
+ break;
1458
+
1459
+ case 'ai-wizard':
1460
+ rl.close();
1461
+ // If they have AI capability, redirect to dashboard or enhanced CLI
1462
+ if (env.capabilities.aiGeneration) {
1463
+ await handleDashboard(projectRoot, env);
1464
+ } else {
1465
+ console.log(`\n${utils.COLORS.yellow}AI Wizard requires Pro tier.${utils.COLORS.reset}`);
1466
+ console.log(`${utils.COLORS.dim}Upgrade at: https://bootspring.com/pricing${utils.COLORS.reset}\n`);
1467
+ }
1468
+ break;
1469
+
1470
+ default:
1471
+ rl.close();
1472
+ console.log(`\n${utils.COLORS.dim}Starting guided wizard...${utils.COLORS.reset}\n`);
1473
+ await handleGuidedWizard(rl, projectRoot, env);
1474
+ }
1475
+ }
1476
+
1477
+ module.exports = {
1478
+ start,
1479
+ detectEnvironment,
1480
+ detectProjectContext,
1481
+ determineStartingPoint,
1482
+ generateAIPrompt
1483
+ };