@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
package/cli/suggest.js ADDED
@@ -0,0 +1,989 @@
1
+ /**
2
+ * Bootspring Suggest Command
3
+ * AI-powered recommendations based on telemetry and learning
4
+ *
5
+ * @package bootspring
6
+ * @command suggest
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const config = require('../core/config');
12
+ const utils = require('../core/utils');
13
+ const intelligence = require('../intelligence');
14
+ const telemetry = require('../core/telemetry');
15
+ const entitlements = require('../core/entitlements');
16
+
17
+ // Thin client: skills module may not exist locally
18
+ // Skills are now served from the API
19
+ let skills;
20
+ try {
21
+ skills = require('../skills');
22
+ } catch {
23
+ // Stub for thin client - skills fetched from API
24
+ skills = {
25
+ listSkills: () => [],
26
+ getSkillMetadata: () => null,
27
+ loadSkill: () => null,
28
+ searchSkills: () => [],
29
+ getCategories: () => [],
30
+ hasExternalSkillLibrary: () => false
31
+ };
32
+ }
33
+
34
+ // Lazy load recommendations engine
35
+ let recommendationsEngine = null;
36
+ function getRecommendationsEngine() {
37
+ if (!recommendationsEngine) {
38
+ const { createRecommendationsEngine } = require('../intelligence/recommendations');
39
+ recommendationsEngine = createRecommendationsEngine({
40
+ intelligence,
41
+ telemetry,
42
+ skills,
43
+ entitlements
44
+ });
45
+ }
46
+ return recommendationsEngine;
47
+ }
48
+
49
+ /**
50
+ * Get context from project files
51
+ */
52
+ function getProjectContext(projectRoot) {
53
+ const contextParts = [];
54
+
55
+ // Read CLAUDE.md
56
+ const claudeMdPath = path.join(projectRoot, 'CLAUDE.md');
57
+ if (fs.existsSync(claudeMdPath)) {
58
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
59
+ contextParts.push(content.slice(0, 2000));
60
+ }
61
+
62
+ // Read recent todos
63
+ const todoPath = path.join(projectRoot, 'todo.md');
64
+ if (fs.existsSync(todoPath)) {
65
+ const content = fs.readFileSync(todoPath, 'utf-8');
66
+ const pendingTodos = content.match(/- \[ \].*/g) || [];
67
+ if (pendingTodos.length > 0) {
68
+ contextParts.push('Pending tasks: ' + pendingTodos.slice(0, 5).join(', '));
69
+ }
70
+ }
71
+
72
+ // Read recent workflow state
73
+ const workflows = ['analyze', 'audit', 'deploy'];
74
+ for (const workflow of workflows) {
75
+ const stateFile = path.join(projectRoot, '.bootspring', workflow, 'workflow-state.json');
76
+ if (fs.existsSync(stateFile)) {
77
+ try {
78
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
79
+ const incomplete = Object.entries(state.phases || {})
80
+ .filter(([, p]) => p.status !== 'completed')
81
+ .map(([name]) => name);
82
+ if (incomplete.length > 0) {
83
+ contextParts.push(`${workflow} workflow incomplete: ${incomplete.join(', ')}`);
84
+ }
85
+ } catch {
86
+ // Skip invalid state
87
+ }
88
+ }
89
+ }
90
+
91
+ return contextParts.join('\n\n');
92
+ }
93
+
94
+ /**
95
+ * Format workflow recommendation
96
+ */
97
+ function formatWorkflow(workflow, index) {
98
+ const tierIcon = workflow.tier === 'free' ?
99
+ '' : ` ${utils.COLORS.yellow}[${workflow.tier}]${utils.COLORS.reset}`;
100
+
101
+ let output = ` ${index + 1}. ${utils.COLORS.cyan}${workflow.name}${utils.COLORS.reset}${tierIcon}\n`;
102
+ output += ` ${utils.COLORS.dim}Score: ${workflow.score}${utils.COLORS.reset}\n`;
103
+
104
+ if (workflow.reasons.length > 0) {
105
+ const topReasons = workflow.reasons.slice(0, 3);
106
+ output += ` ${utils.COLORS.dim}${topReasons.join(' • ')}${utils.COLORS.reset}\n`;
107
+ }
108
+
109
+ if (workflow.learningImpact) {
110
+ const { adjustment, breakdown } = workflow.learningImpact;
111
+ const sign = adjustment >= 0 ? '+' : '';
112
+ output += ` ${utils.COLORS.green}Learning: ${sign}${adjustment}${utils.COLORS.reset}`;
113
+ if (breakdown.impactBoost > 0) {
114
+ output += ` ${utils.COLORS.dim}(impact: +${breakdown.impactBoost})${utils.COLORS.reset}`;
115
+ }
116
+ output += '\n';
117
+ }
118
+
119
+ return output;
120
+ }
121
+
122
+ /**
123
+ * Format skill recommendation
124
+ */
125
+ function formatSkill(skill, index) {
126
+ let output = ` ${index + 1}. ${utils.COLORS.cyan}${skill.name || skill.id}${utils.COLORS.reset}\n`;
127
+
128
+ if (skill.description) {
129
+ output += ` ${utils.COLORS.dim}${skill.description.slice(0, 60)}${utils.COLORS.reset}\n`;
130
+ }
131
+
132
+ output += ` ${utils.COLORS.dim}Score: ${skill.score}${utils.COLORS.reset}\n`;
133
+
134
+ return output;
135
+ }
136
+
137
+ /**
138
+ * Show recommendations
139
+ */
140
+ async function showRecommendations(projectRoot, options = {}) {
141
+ const engine = getRecommendationsEngine();
142
+
143
+ const spinner = utils.createSpinner('Analyzing context...').start();
144
+
145
+ try {
146
+ // Get project context
147
+ const contextText = getProjectContext(projectRoot);
148
+
149
+ // Get recommendations
150
+ const result = engine.recommend({
151
+ contextText,
152
+ limit: options.limit || 5,
153
+ accessOptions: {}
154
+ });
155
+
156
+ spinner.stop();
157
+
158
+ console.log(`
159
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Smart Suggestions${utils.COLORS.reset}
160
+ ${utils.COLORS.dim}Based on your project context and history${utils.COLORS.reset}
161
+ `);
162
+
163
+ // Current context
164
+ if (result.context.phase) {
165
+ console.log(`${utils.COLORS.bold}Current Phase${utils.COLORS.reset}`);
166
+ console.log(` ${result.context.phaseName || result.context.phase}`);
167
+ console.log();
168
+ }
169
+
170
+ // Workflow recommendations
171
+ if (result.workflows.length > 0) {
172
+ console.log(`${utils.COLORS.bold}Recommended Workflows${utils.COLORS.reset}`);
173
+ for (let i = 0; i < result.workflows.length; i++) {
174
+ console.log(formatWorkflow(result.workflows[i], i));
175
+ }
176
+ }
177
+
178
+ // Skill recommendations
179
+ if (result.skills.length > 0) {
180
+ console.log(`${utils.COLORS.bold}Recommended Skills${utils.COLORS.reset}`);
181
+ for (let i = 0; i < Math.min(result.skills.length, 3); i++) {
182
+ console.log(formatSkill(result.skills[i], i));
183
+ }
184
+ }
185
+
186
+ // Learning insights
187
+ if (result.learning && !result.learning.usingDefaults) {
188
+ console.log(`${utils.COLORS.bold}Insights from History${utils.COLORS.reset}`);
189
+
190
+ // Anti-patterns to avoid
191
+ if (result.learning.antiPatterns.length > 0) {
192
+ const ap = result.learning.antiPatterns[0];
193
+ if (!ap.is_default) {
194
+ console.log(` ${utils.COLORS.yellow}⚠${utils.COLORS.reset} Avoid: ${ap.decision} (${(ap.failure_rate * 100).toFixed(0)}% failure rate)`);
195
+ }
196
+ }
197
+
198
+ // Top insight
199
+ if (result.learning.insights.length > 0) {
200
+ const insight = result.learning.insights[0];
201
+ console.log(` ${utils.COLORS.green}→${utils.COLORS.reset} ${insight.message}`);
202
+ }
203
+
204
+ // Phase recommendation
205
+ if (result.learning.phaseRecommendation && !result.learning.phaseRecommendation.is_default) {
206
+ const pr = result.learning.phaseRecommendation;
207
+ console.log(` ${utils.COLORS.dim}This phase has ${(pr.success_rate * 100).toFixed(0)}% success rate${utils.COLORS.reset}`);
208
+ }
209
+
210
+ // Impact insights
211
+ if (result.learning.impact?.boostedPatterns?.length > 0) {
212
+ const topPattern = result.learning.impact.boostedPatterns[0];
213
+ console.log(` ${utils.COLORS.green}★${utils.COLORS.reset} High-impact pattern: ${topPattern.type} (${topPattern.averageImpactScore.toFixed(1)} impact score)`);
214
+ }
215
+
216
+ console.log();
217
+ }
218
+
219
+ // General recommendations
220
+ if (result.learning?.generalRecommendations?.length > 0) {
221
+ console.log(`${utils.COLORS.bold}Recommendations${utils.COLORS.reset}`);
222
+ for (const rec of result.learning.generalRecommendations.slice(0, 3)) {
223
+ console.log(` ${utils.COLORS.cyan}→${utils.COLORS.reset} ${rec}`);
224
+ }
225
+ console.log();
226
+ }
227
+
228
+ // Telemetry summary
229
+ console.log(`${utils.COLORS.dim}Based on ${result.telemetryWindow.eventsAnalyzed} events${utils.COLORS.reset}`);
230
+
231
+ if (options.json) {
232
+ return result;
233
+ }
234
+
235
+ } catch (error) {
236
+ spinner.fail('Failed to generate recommendations');
237
+ utils.print.error(error.message);
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Show next action suggestion
243
+ */
244
+ async function showNextAction(projectRoot) {
245
+ const engine = getRecommendationsEngine();
246
+ const contextText = getProjectContext(projectRoot);
247
+
248
+ const result = engine.recommend({
249
+ contextText,
250
+ limit: 1,
251
+ accessOptions: {}
252
+ });
253
+
254
+ console.log(`
255
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Next Action${utils.COLORS.reset}
256
+ `);
257
+
258
+ if (result.workflows.length > 0) {
259
+ const workflow = result.workflows[0];
260
+ console.log(`${utils.COLORS.bold}${workflow.name}${utils.COLORS.reset}`);
261
+
262
+ if (workflow.reasons.length > 0) {
263
+ console.log(`${utils.COLORS.dim}${workflow.reasons[0]}${utils.COLORS.reset}`);
264
+ }
265
+
266
+ // Suggest command
267
+ const commands = {
268
+ 'analyze': 'bootspring analyze',
269
+ 'audit': 'bootspring audit',
270
+ 'deploy': 'bootspring deploy',
271
+ 'preseed': 'bootspring preseed init',
272
+ 'seed': 'bootspring seed scaffold',
273
+ 'onboard': 'bootspring onboard'
274
+ };
275
+
276
+ for (const [key, cmd] of Object.entries(commands)) {
277
+ if (workflow.key?.includes(key) || workflow.name?.toLowerCase().includes(key)) {
278
+ console.log();
279
+ console.log(`${utils.COLORS.cyan}Run:${utils.COLORS.reset} ${cmd}`);
280
+ break;
281
+ }
282
+ }
283
+ } else {
284
+ console.log('No specific suggestions at this time.');
285
+ console.log(`${utils.COLORS.dim}Run 'bootspring health' to check project status${utils.COLORS.reset}`);
286
+ }
287
+
288
+ console.log();
289
+ }
290
+
291
+ /**
292
+ * Show learning stats
293
+ */
294
+ function showLearningStats() {
295
+ console.log(`
296
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Learning Stats${utils.COLORS.reset}
297
+ `);
298
+
299
+ try {
300
+ const patternLearner = require('../intelligence/learning/pattern-learner');
301
+ const insights = patternLearner.analyze();
302
+
303
+ if (insights.using_defaults) {
304
+ console.log(`${utils.COLORS.yellow}No learning data yet${utils.COLORS.reset}`);
305
+ console.log(`${utils.COLORS.dim}Use Bootspring more to build up patterns${utils.COLORS.reset}`);
306
+ return;
307
+ }
308
+
309
+ // Summary
310
+ if (insights.analysis_summary) {
311
+ const summary = insights.analysis_summary;
312
+ console.log(`${utils.COLORS.bold}Summary${utils.COLORS.reset}`);
313
+ console.log(` Total decisions: ${summary.total_decisions || 0}`);
314
+ console.log(` Success rate: ${((summary.success_rate || 0) * 100).toFixed(0)}%`);
315
+ console.log(` Unique patterns: ${summary.unique_patterns || 0}`);
316
+ console.log();
317
+ }
318
+
319
+ // Top insights
320
+ if (insights.insights?.length > 0) {
321
+ console.log(`${utils.COLORS.bold}Top Insights${utils.COLORS.reset}`);
322
+ for (const insight of insights.insights.slice(0, 5)) {
323
+ const icon = insight.level === 'positive' ?
324
+ `${utils.COLORS.green}↑${utils.COLORS.reset}` :
325
+ insight.level === 'negative' ?
326
+ `${utils.COLORS.red}↓${utils.COLORS.reset}` :
327
+ `${utils.COLORS.dim}→${utils.COLORS.reset}`;
328
+ console.log(` ${icon} ${insight.message}`);
329
+ }
330
+ console.log();
331
+ }
332
+
333
+ // Anti-patterns
334
+ const realAntiPatterns = (insights.anti_patterns || []).filter(ap => !ap.is_default);
335
+ if (realAntiPatterns.length > 0) {
336
+ console.log(`${utils.COLORS.bold}Anti-Patterns Detected${utils.COLORS.reset}`);
337
+ for (const ap of realAntiPatterns.slice(0, 3)) {
338
+ console.log(` ${utils.COLORS.yellow}⚠${utils.COLORS.reset} ${ap.decision}: ${(ap.failure_rate * 100).toFixed(0)}% failure rate`);
339
+ }
340
+ console.log();
341
+ }
342
+
343
+ // Correlations
344
+ if (insights.correlations?.length > 0) {
345
+ console.log(`${utils.COLORS.bold}Pattern Correlations${utils.COLORS.reset}`);
346
+ for (const corr of insights.correlations.slice(0, 3)) {
347
+ console.log(` ${utils.COLORS.dim}${corr.decision_a} → ${corr.decision_b} (${corr.occurrences} times)${utils.COLORS.reset}`);
348
+ }
349
+ console.log();
350
+ }
351
+
352
+ } catch (error) {
353
+ console.log(`${utils.COLORS.dim}Learning data not available: ${error.message}${utils.COLORS.reset}`);
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Auto-suggest configuration and display
359
+ */
360
+ function showAutoSuggestConfig(projectRoot) {
361
+ const { AutoSuggest } = require('../intelligence/auto-suggest');
362
+ const autoSuggest = new AutoSuggest(projectRoot);
363
+ const status = autoSuggest.getStatus();
364
+
365
+ console.log(`
366
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Auto-Suggest Configuration${utils.COLORS.reset}
367
+
368
+ ${utils.COLORS.bold}Status${utils.COLORS.reset}
369
+ Enabled: ${status.enabled ? `${utils.COLORS.green}Yes${utils.COLORS.reset}` : `${utils.COLORS.red}No${utils.COLORS.reset}`}
370
+
371
+ ${utils.COLORS.bold}Categories${utils.COLORS.reset}`);
372
+
373
+ for (const [category, enabled] of Object.entries(status.categories)) {
374
+ const icon = enabled ? `${utils.COLORS.green}✓${utils.COLORS.reset}` : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
375
+ console.log(` ${icon} ${category}`);
376
+ }
377
+
378
+ if (status.suppressedCommands.length > 0) {
379
+ console.log(`
380
+ ${utils.COLORS.bold}Suppressed Commands${utils.COLORS.reset}`);
381
+ for (const cmd of status.suppressedCommands) {
382
+ console.log(` ${utils.COLORS.dim}${cmd}${utils.COLORS.reset}`);
383
+ }
384
+ }
385
+
386
+ console.log(`
387
+ ${utils.COLORS.bold}Commands${utils.COLORS.reset}
388
+ bootspring suggest --enable-auto Enable auto-suggestions
389
+ bootspring suggest --disable-auto Disable auto-suggestions
390
+ bootspring suggest --category <name> Toggle category
391
+ bootspring suggest --suppress <cmd> Suppress a command
392
+ `);
393
+ }
394
+
395
+ /**
396
+ * Toggle auto-suggest
397
+ */
398
+ function toggleAutoSuggest(projectRoot, enable) {
399
+ const { AutoSuggest } = require('../intelligence/auto-suggest');
400
+ const autoSuggest = new AutoSuggest(projectRoot);
401
+ autoSuggest.setEnabled(enable);
402
+
403
+ if (enable) {
404
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Auto-suggest enabled`);
405
+ console.log(`${utils.COLORS.dim}Bootspring will suggest relevant commands during Claude Code sessions${utils.COLORS.reset}`);
406
+ } else {
407
+ console.log(`${utils.COLORS.yellow}○${utils.COLORS.reset} Auto-suggest disabled`);
408
+ console.log(`${utils.COLORS.dim}Re-enable with: bootspring suggest --enable-auto${utils.COLORS.reset}`);
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Toggle category
414
+ */
415
+ function toggleCategory(projectRoot, category) {
416
+ const { AutoSuggest } = require('../intelligence/auto-suggest');
417
+ const autoSuggest = new AutoSuggest(projectRoot);
418
+ const status = autoSuggest.getStatus();
419
+
420
+ if (!status.categories.hasOwnProperty(category)) {
421
+ console.log(`${utils.COLORS.red}Unknown category: ${category}${utils.COLORS.reset}`);
422
+ console.log(`Available: ${Object.keys(status.categories).join(', ')}`);
423
+ return;
424
+ }
425
+
426
+ const newState = !status.categories[category];
427
+ autoSuggest.setCategory(category, newState);
428
+
429
+ const icon = newState ? `${utils.COLORS.green}✓${utils.COLORS.reset}` : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
430
+ console.log(`${icon} Category '${category}' ${newState ? 'enabled' : 'disabled'}`);
431
+ }
432
+
433
+ /**
434
+ * Suppress or unsuppress a command
435
+ */
436
+ function suppressCommand(projectRoot, command, suppress = true) {
437
+ const { AutoSuggest } = require('../intelligence/auto-suggest');
438
+ const autoSuggest = new AutoSuggest(projectRoot);
439
+
440
+ if (suppress) {
441
+ autoSuggest.suppressCommand(command);
442
+ console.log(`${utils.COLORS.dim}○${utils.COLORS.reset} Suppressed suggestions for: ${command}`);
443
+ } else {
444
+ autoSuggest.unsuppressCommand(command);
445
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Enabled suggestions for: ${command}`);
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Analyze text for suggestions (for testing/demo)
451
+ */
452
+ function analyzeText(projectRoot, text) {
453
+ const { AutoSuggest } = require('../intelligence/auto-suggest');
454
+ const autoSuggest = new AutoSuggest(projectRoot);
455
+ const suggestions = autoSuggest.analyze(text);
456
+
457
+ if (suggestions.length === 0) {
458
+ console.log(`${utils.COLORS.dim}No suggestions for this input${utils.COLORS.reset}`);
459
+ return;
460
+ }
461
+
462
+ console.log(`
463
+ ${utils.COLORS.cyan}${utils.COLORS.bold}💡 Suggestions${utils.COLORS.reset}
464
+ `);
465
+
466
+ for (const suggestion of suggestions) {
467
+ console.log(` ${utils.COLORS.green}→${utils.COLORS.reset} ${utils.COLORS.bold}${suggestion.command}${utils.COLORS.reset}`);
468
+ console.log(` ${utils.COLORS.dim}${suggestion.description}${utils.COLORS.reset}`);
469
+ console.log(` ${utils.COLORS.dim}Confidence: ${(suggestion.confidence * 100).toFixed(0)}%${utils.COLORS.reset}`);
470
+ console.log();
471
+ }
472
+ }
473
+
474
+ /**
475
+ * Generate AI-ready prompts based on project analysis
476
+ */
477
+ async function generatePrompts(projectRoot, options = {}) {
478
+ const prompts = [];
479
+ const projectState = loadProjectState(projectRoot);
480
+ const checkpoints = projectState?.checkpoints || {};
481
+ const projectType = projectState?.projectType || 'development';
482
+
483
+ // Analyze what's missing and generate prompts
484
+
485
+ // 1. Check for missing planning docs
486
+ const planningDocs = [
487
+ { file: 'planning/PRD.md', checkpoint: 'prd', name: 'Product Requirements Document',
488
+ prompt: `Create a comprehensive PRD.md file in the planning/ folder. Include:
489
+ - Product vision and goals
490
+ - Target users and personas
491
+ - Core features and requirements (prioritized)
492
+ - Success metrics and KPIs
493
+ - Timeline and milestones
494
+ - Out of scope items
495
+
496
+ Base it on the existing project structure and any available context.` },
497
+ { file: 'planning/TECHNICAL_SPEC.md', checkpoint: 'technical_spec', name: 'Technical Specification',
498
+ prompt: `Create a TECHNICAL_SPEC.md file in planning/ folder. Include:
499
+ - System architecture overview
500
+ - Technology stack decisions with rationale
501
+ - Data models and schemas
502
+ - API design patterns
503
+ - Security considerations
504
+ - Performance requirements
505
+ - Integration points` },
506
+ { file: 'planning/ARCHITECTURE.md', checkpoint: 'architecture', name: 'Architecture Document',
507
+ prompt: `Create an ARCHITECTURE.md file in planning/ folder. Include:
508
+ - High-level system diagram (ASCII or Mermaid)
509
+ - Component breakdown and responsibilities
510
+ - Data flow between components
511
+ - External service integrations
512
+ - Deployment architecture
513
+ - Scalability considerations` },
514
+ { file: 'planning/DATABASE_SCHEMA.md', checkpoint: 'database_schema', name: 'Database Schema',
515
+ prompt: `Create a DATABASE_SCHEMA.md file in planning/ folder. Include:
516
+ - Entity relationship diagram (Mermaid or ASCII)
517
+ - Table definitions with columns and types
518
+ - Relationships and foreign keys
519
+ - Indexes for performance
520
+ - Migration strategy
521
+ - Sample queries for common operations` },
522
+ { file: 'planning/API_CONTRACTS.md', checkpoint: 'api_contracts', name: 'API Contracts',
523
+ prompt: `Create an API_CONTRACTS.md file in planning/ folder. Include:
524
+ - RESTful endpoint definitions
525
+ - Request/response schemas (with examples)
526
+ - Authentication requirements
527
+ - Rate limiting policies
528
+ - Error response formats
529
+ - Versioning strategy` },
530
+ { file: 'planning/TEST_PLAN.md', checkpoint: 'tests_planned', name: 'Test Plan',
531
+ prompt: `Create a TEST_PLAN.md file in planning/ folder. Include:
532
+ - Testing strategy (unit, integration, e2e)
533
+ - Test coverage targets
534
+ - Critical paths to test
535
+ - Test data requirements
536
+ - CI/CD integration plan
537
+ - Performance testing approach` }
538
+ ];
539
+
540
+ for (const doc of planningDocs) {
541
+ const filePath = path.join(projectRoot, doc.file);
542
+ if (!fs.existsSync(filePath) && !checkpoints[doc.checkpoint]?.completed) {
543
+ prompts.push({
544
+ category: 'Documentation',
545
+ priority: doc.checkpoint === 'prd' ? 'high' : 'medium',
546
+ title: `Create ${doc.name}`,
547
+ prompt: doc.prompt,
548
+ command: `bootspring checkpoint complete ${doc.checkpoint}`
549
+ });
550
+ }
551
+ }
552
+
553
+ // 2. Check for missing test setup
554
+ const hasTests = fs.existsSync(path.join(projectRoot, '__tests__')) ||
555
+ fs.existsSync(path.join(projectRoot, 'tests')) ||
556
+ fs.existsSync(path.join(projectRoot, 'test'));
557
+ const hasTestConfig = fs.existsSync(path.join(projectRoot, 'vitest.config.ts')) ||
558
+ fs.existsSync(path.join(projectRoot, 'jest.config.js')) ||
559
+ fs.existsSync(path.join(projectRoot, 'vitest.config.js'));
560
+
561
+ if (!hasTests || !hasTestConfig) {
562
+ prompts.push({
563
+ category: 'Quality',
564
+ priority: 'high',
565
+ title: 'Set up test infrastructure',
566
+ prompt: `Set up a comprehensive testing infrastructure for this project:
567
+
568
+ 1. Install vitest and testing utilities
569
+ 2. Create vitest.config.ts with proper configuration
570
+ 3. Set up test directory structure (__tests__/ or tests/)
571
+ 4. Create example unit tests for existing modules
572
+ 5. Add test scripts to package.json
573
+ 6. Configure code coverage reporting
574
+
575
+ Focus on making tests easy to write and maintain.`,
576
+ command: 'npm install -D vitest @vitest/coverage-v8'
577
+ });
578
+ }
579
+
580
+ // 3. Check for CI/CD
581
+ const hasGithubActions = fs.existsSync(path.join(projectRoot, '.github/workflows'));
582
+ if (!hasGithubActions) {
583
+ prompts.push({
584
+ category: 'DevOps',
585
+ priority: 'medium',
586
+ title: 'Add GitHub Actions CI/CD',
587
+ prompt: `Create a GitHub Actions CI/CD pipeline in .github/workflows/ci.yml:
588
+
589
+ 1. Run on push to main and pull requests
590
+ 2. Set up Node.js environment
591
+ 3. Install dependencies (npm ci)
592
+ 4. Run linting (if configured)
593
+ 5. Run tests with coverage
594
+ 6. Build the project
595
+ 7. Add caching for node_modules
596
+
597
+ Make it fast and reliable for developer productivity.`,
598
+ command: 'mkdir -p .github/workflows'
599
+ });
600
+ }
601
+
602
+ // 4. Check for security setup
603
+ const hasEnvExample = fs.existsSync(path.join(projectRoot, '.env.example'));
604
+ if (!hasEnvExample && fs.existsSync(path.join(projectRoot, '.env'))) {
605
+ prompts.push({
606
+ category: 'Security',
607
+ priority: 'high',
608
+ title: 'Create .env.example',
609
+ prompt: `Create a .env.example file documenting all required environment variables:
610
+
611
+ 1. List all env vars from .env (without actual values)
612
+ 2. Add comments explaining each variable
613
+ 3. Group by category (database, auth, external services)
614
+ 4. Include example/placeholder values where helpful
615
+ 5. Document which are required vs optional
616
+
617
+ This helps new developers set up the project securely.`,
618
+ command: null
619
+ });
620
+ }
621
+
622
+ // 5. Check for README quality
623
+ const readmePath = path.join(projectRoot, 'README.md');
624
+ let readmeScore = 0;
625
+ if (fs.existsSync(readmePath)) {
626
+ const readme = fs.readFileSync(readmePath, 'utf-8');
627
+ if (readme.includes('## Installation')) readmeScore++;
628
+ if (readme.includes('## Usage')) readmeScore++;
629
+ if (readme.includes('## Contributing')) readmeScore++;
630
+ if (readme.includes('## License')) readmeScore++;
631
+ if (readme.length > 1000) readmeScore++;
632
+ }
633
+
634
+ if (readmeScore < 3) {
635
+ prompts.push({
636
+ category: 'Documentation',
637
+ priority: 'medium',
638
+ title: 'Improve README.md',
639
+ prompt: `Enhance the README.md to be comprehensive and welcoming:
640
+
641
+ 1. Clear project description and value proposition
642
+ 2. Installation instructions (step by step)
643
+ 3. Quick start / Usage examples
644
+ 4. Configuration options
645
+ 5. Contributing guidelines
646
+ 6. License information
647
+ 7. Links to documentation
648
+ 8. Badges (build status, version, license)
649
+
650
+ Make it easy for new users to understand and get started.`,
651
+ command: null
652
+ });
653
+ }
654
+
655
+ // 6. Check for TypeScript setup
656
+ const hasTypeScript = fs.existsSync(path.join(projectRoot, 'tsconfig.json'));
657
+ const packageJson = loadPackageJson(projectRoot);
658
+ const hasJsFiles = fs.readdirSync(projectRoot).some(f => f.endsWith('.js') && !f.includes('config'));
659
+
660
+ if (!hasTypeScript && hasJsFiles) {
661
+ prompts.push({
662
+ category: 'Quality',
663
+ priority: 'low',
664
+ title: 'Migrate to TypeScript',
665
+ prompt: `Convert this JavaScript project to TypeScript:
666
+
667
+ 1. Install typescript and @types packages
668
+ 2. Create tsconfig.json with strict settings
669
+ 3. Rename .js files to .ts (start with entry points)
670
+ 4. Add type annotations to functions and variables
671
+ 5. Fix type errors iteratively
672
+ 6. Update build scripts
673
+
674
+ Start with the most critical files and expand gradually.`,
675
+ command: 'npm install -D typescript @types/node'
676
+ });
677
+ }
678
+
679
+ // 7. Check for linting
680
+ const hasEslint = fs.existsSync(path.join(projectRoot, '.eslintrc.js')) ||
681
+ fs.existsSync(path.join(projectRoot, '.eslintrc.json')) ||
682
+ fs.existsSync(path.join(projectRoot, 'eslint.config.js'));
683
+
684
+ if (!hasEslint) {
685
+ prompts.push({
686
+ category: 'Quality',
687
+ priority: 'medium',
688
+ title: 'Set up ESLint',
689
+ prompt: `Set up ESLint for code quality and consistency:
690
+
691
+ 1. Install eslint and relevant plugins
692
+ 2. Create eslint.config.js (flat config format)
693
+ 3. Configure rules appropriate for the project
694
+ 4. Add lint script to package.json
695
+ 5. Fix any existing linting issues
696
+ 6. Consider adding Prettier for formatting
697
+
698
+ Use sensible defaults that catch real bugs without being annoying.`,
699
+ command: 'npm install -D eslint'
700
+ });
701
+ }
702
+
703
+ // 8. Project-specific suggestions based on tech stack
704
+ if (packageJson?.dependencies?.next) {
705
+ const hasMiddleware = fs.existsSync(path.join(projectRoot, 'middleware.ts'));
706
+ if (!hasMiddleware) {
707
+ prompts.push({
708
+ category: 'Security',
709
+ priority: 'medium',
710
+ title: 'Add Next.js middleware',
711
+ prompt: `Create a middleware.ts file for Next.js request handling:
712
+
713
+ 1. Set up authentication checks for protected routes
714
+ 2. Add rate limiting headers
715
+ 3. Configure security headers (CSP, HSTS, etc.)
716
+ 4. Handle redirects for legacy URLs
717
+ 5. Add request logging for debugging
718
+
719
+ Keep it performant as middleware runs on every request.`,
720
+ command: null
721
+ });
722
+ }
723
+ }
724
+
725
+ // Group by priority
726
+ const highPriority = prompts.filter(p => p.priority === 'high');
727
+ const mediumPriority = prompts.filter(p => p.priority === 'medium');
728
+ const lowPriority = prompts.filter(p => p.priority === 'low');
729
+
730
+ const limit = options.limit || 5;
731
+ const allPrompts = [...highPriority, ...mediumPriority, ...lowPriority].slice(0, limit);
732
+
733
+ // JSON mode - return data only, no display
734
+ if (options.json) {
735
+ return allPrompts;
736
+ }
737
+
738
+ // Display prompts
739
+ console.log(`
740
+ ${utils.COLORS.cyan}${utils.COLORS.bold}📋 AI-Ready Prompts${utils.COLORS.reset}
741
+ ${utils.COLORS.dim}Copy and paste into Cursor, Claude Code, Codex, etc.${utils.COLORS.reset}
742
+ `);
743
+
744
+ if (prompts.length === 0) {
745
+ console.log(`${utils.COLORS.green}✓${utils.COLORS.reset} Project looks well set up! No urgent suggestions.`);
746
+ console.log(`${utils.COLORS.dim}Run 'bootspring health' for detailed analysis.${utils.COLORS.reset}`);
747
+ return;
748
+ }
749
+
750
+ for (let i = 0; i < allPrompts.length; i++) {
751
+ const p = allPrompts[i];
752
+ const priorityColor = p.priority === 'high' ? utils.COLORS.red :
753
+ p.priority === 'medium' ? utils.COLORS.yellow : utils.COLORS.dim;
754
+ const priorityLabel = p.priority.toUpperCase();
755
+
756
+ console.log(`${utils.COLORS.bold}${i + 1}. ${p.title}${utils.COLORS.reset} ${priorityColor}[${priorityLabel}]${utils.COLORS.reset} ${utils.COLORS.dim}(${p.category})${utils.COLORS.reset}`);
757
+ console.log();
758
+ console.log(`${utils.COLORS.cyan}┌${'─'.repeat(70)}${utils.COLORS.reset}`);
759
+ console.log(`${utils.COLORS.cyan}│${utils.COLORS.reset}`);
760
+
761
+ // Format prompt for display
762
+ const lines = p.prompt.split('\n');
763
+ for (const line of lines) {
764
+ console.log(`${utils.COLORS.cyan}│${utils.COLORS.reset} ${line}`);
765
+ }
766
+
767
+ console.log(`${utils.COLORS.cyan}│${utils.COLORS.reset}`);
768
+ console.log(`${utils.COLORS.cyan}└${'─'.repeat(70)}${utils.COLORS.reset}`);
769
+
770
+ if (p.command) {
771
+ console.log(`${utils.COLORS.dim} After: ${p.command}${utils.COLORS.reset}`);
772
+ }
773
+ console.log();
774
+ }
775
+
776
+ const remaining = prompts.length - limit;
777
+ if (remaining > 0) {
778
+ console.log(`${utils.COLORS.dim}+${remaining} more suggestions. Use --limit to see more.${utils.COLORS.reset}`);
779
+ }
780
+
781
+ console.log(`
782
+ ${utils.COLORS.bold}Quick Copy:${utils.COLORS.reset} Click a prompt box to copy, then paste into your AI assistant.
783
+ ${utils.COLORS.dim}Tip: Use 'bootspring suggest prompts --json' for machine-readable output.${utils.COLORS.reset}
784
+ `);
785
+ }
786
+
787
+ /**
788
+ * Load PROJECT_STATE.json
789
+ */
790
+ function loadProjectState(projectRoot) {
791
+ try {
792
+ const statePath = path.join(projectRoot, 'planning', 'PROJECT_STATE.json');
793
+ if (fs.existsSync(statePath)) {
794
+ return JSON.parse(fs.readFileSync(statePath, 'utf-8'));
795
+ }
796
+ } catch {
797
+ // Ignore errors
798
+ }
799
+ return null;
800
+ }
801
+
802
+ /**
803
+ * Load package.json
804
+ */
805
+ function loadPackageJson(projectRoot) {
806
+ try {
807
+ const pkgPath = path.join(projectRoot, 'package.json');
808
+ if (fs.existsSync(pkgPath)) {
809
+ return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
810
+ }
811
+ } catch {
812
+ // Ignore errors
813
+ }
814
+ return null;
815
+ }
816
+
817
+ /**
818
+ * Show help
819
+ */
820
+ function showHelp() {
821
+ console.log(`
822
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Suggest${utils.COLORS.reset}
823
+ ${utils.COLORS.dim}AI-powered recommendations and auto-suggestions${utils.COLORS.reset}
824
+
825
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
826
+ bootspring suggest [command] [options]
827
+
828
+ ${utils.COLORS.bold}Commands:${utils.COLORS.reset}
829
+ ${utils.COLORS.cyan}(default)${utils.COLORS.reset} Show all recommendations
830
+ ${utils.COLORS.cyan}prompts${utils.COLORS.reset} Generate copy-paste prompts for AI assistants
831
+ ${utils.COLORS.cyan}next${utils.COLORS.reset} Show single next action
832
+ ${utils.COLORS.cyan}learning${utils.COLORS.reset} Show learning statistics
833
+ ${utils.COLORS.cyan}workflows${utils.COLORS.reset} Show workflow recommendations only
834
+ ${utils.COLORS.cyan}skills${utils.COLORS.reset} Show skill recommendations only
835
+ ${utils.COLORS.cyan}config${utils.COLORS.reset} Show auto-suggest configuration
836
+ ${utils.COLORS.cyan}analyze <text>${utils.COLORS.reset} Test auto-suggest on text
837
+
838
+ ${utils.COLORS.bold}Auto-Suggest Options:${utils.COLORS.reset}
839
+ --enable-auto Enable proactive suggestions in Claude Code
840
+ --disable-auto Disable auto-suggestions
841
+ --category <name> Toggle a suggestion category
842
+ --suppress <cmd> Stop suggesting a specific command
843
+ --unsuppress <cmd> Resume suggesting a command
844
+
845
+ ${utils.COLORS.bold}Other Options:${utils.COLORS.reset}
846
+ --limit <n> Number of recommendations (default: 5)
847
+ --json Output as JSON
848
+
849
+ ${utils.COLORS.bold}How Auto-Suggest Works:${utils.COLORS.reset}
850
+ 1. Monitors your messages in Claude Code
851
+ 2. Detects when Bootspring features could help
852
+ 3. Proactively suggests relevant commands
853
+ 4. Learn from your preferences over time
854
+
855
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
856
+ bootspring suggest # Show recommendations
857
+ bootspring suggest prompts # AI-ready prompts for Cursor/Claude Code
858
+ bootspring suggest prompts --limit 10 # Show more prompts
859
+ bootspring suggest next # Single next action
860
+ bootspring suggest --enable-auto # Enable auto-suggestions
861
+ bootspring suggest config # View auto-suggest settings
862
+ bootspring suggest analyze "deploy to vercel"
863
+ `);
864
+ }
865
+
866
+ /**
867
+ * Run suggest command
868
+ */
869
+ async function run(args) {
870
+ const parsedArgs = utils.parseArgs(args);
871
+ const subcommand = parsedArgs._[0];
872
+
873
+ if (subcommand === 'help' || subcommand === '-h' || subcommand === '--help') {
874
+ showHelp();
875
+ return;
876
+ }
877
+
878
+ const cfg = config.load();
879
+ const projectRoot = cfg._projectRoot;
880
+
881
+ // Handle auto-suggest flags first
882
+ if (parsedArgs['enable-auto']) {
883
+ toggleAutoSuggest(projectRoot, true);
884
+ return;
885
+ }
886
+
887
+ if (parsedArgs['disable-auto']) {
888
+ toggleAutoSuggest(projectRoot, false);
889
+ return;
890
+ }
891
+
892
+ if (parsedArgs.category) {
893
+ toggleCategory(projectRoot, parsedArgs.category);
894
+ return;
895
+ }
896
+
897
+ if (parsedArgs.suppress) {
898
+ suppressCommand(projectRoot, parsedArgs.suppress, true);
899
+ return;
900
+ }
901
+
902
+ if (parsedArgs.unsuppress) {
903
+ suppressCommand(projectRoot, parsedArgs.unsuppress, false);
904
+ return;
905
+ }
906
+
907
+ switch (subcommand) {
908
+ case 'prompts':
909
+ case 'prompt':
910
+ case 'ai': {
911
+ const promptResult = await generatePrompts(projectRoot, {
912
+ limit: parsedArgs.limit || 5,
913
+ json: parsedArgs.json
914
+ });
915
+ if (parsedArgs.json && promptResult) {
916
+ console.log(JSON.stringify(promptResult, null, 2));
917
+ }
918
+ break;
919
+ }
920
+
921
+ case 'next':
922
+ await showNextAction(projectRoot);
923
+ break;
924
+
925
+ case 'learning':
926
+ case 'stats':
927
+ showLearningStats();
928
+ break;
929
+
930
+ case 'config':
931
+ case 'auto':
932
+ case 'settings':
933
+ showAutoSuggestConfig(projectRoot);
934
+ break;
935
+
936
+ case 'analyze':
937
+ case 'test': {
938
+ const text = parsedArgs._.slice(1).join(' ');
939
+ if (!text) {
940
+ console.log(`${utils.COLORS.yellow}Usage: bootspring suggest analyze "<text>"${utils.COLORS.reset}`);
941
+ return;
942
+ }
943
+ analyzeText(projectRoot, text);
944
+ break;
945
+ }
946
+
947
+ case 'workflows': {
948
+ const wfResult = await showRecommendations(projectRoot, {
949
+ limit: parsedArgs.limit || 5,
950
+ json: parsedArgs.json
951
+ });
952
+ if (parsedArgs.json) {
953
+ console.log(JSON.stringify({ workflows: wfResult?.workflows || [] }, null, 2));
954
+ }
955
+ break;
956
+ }
957
+
958
+ case 'skills': {
959
+ const skResult = await showRecommendations(projectRoot, {
960
+ limit: parsedArgs.limit || 5,
961
+ json: parsedArgs.json
962
+ });
963
+ if (parsedArgs.json) {
964
+ console.log(JSON.stringify({ skills: skResult?.skills || [] }, null, 2));
965
+ }
966
+ break;
967
+ }
968
+
969
+ default: {
970
+ const result = await showRecommendations(projectRoot, {
971
+ limit: parsedArgs.limit || 5,
972
+ json: parsedArgs.json
973
+ });
974
+ if (parsedArgs.json) {
975
+ console.log(JSON.stringify(result, null, 2));
976
+ }
977
+ }
978
+ }
979
+ }
980
+
981
+ module.exports = {
982
+ run,
983
+ getProjectContext,
984
+ showRecommendations,
985
+ generatePrompts,
986
+ toggleAutoSuggest,
987
+ showAutoSuggestConfig,
988
+ analyzeText
989
+ };