@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,639 @@
1
+ /**
2
+ * Bootspring Checkpoint Command
3
+ * Manage project checkpoints and milestones
4
+ *
5
+ * Commands:
6
+ * status Show all checkpoints with status
7
+ * complete <name> Mark a checkpoint as complete manually
8
+ * history View checkpoint completion timeline
9
+ * sync Re-scan files to detect completed items
10
+ * init Initialize checkpoint tracking
11
+ *
12
+ * @package bootspring
13
+ * @command checkpoint
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const config = require('../core/config');
19
+ const utils = require('../core/utils');
20
+ const projectState = require('../core/project-state');
21
+ const checkpointEngine = require('../core/checkpoint-engine');
22
+ const telemetry = require('../core/telemetry');
23
+ const { scanFilesForCheckpoints, pushCheckpointsToServer } = require('./checkpoint-utils');
24
+
25
+ // ============================================================================
26
+ // Command Handlers
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Show checkpoint status
31
+ * @param {string} projectRoot - Project root directory
32
+ * @param {object} options - Options
33
+ */
34
+ async function handleStatus(projectRoot, options = {}) {
35
+ // Auto-sync checkpoints before showing status
36
+ checkpointEngine.syncCheckpoints(projectRoot);
37
+
38
+ // Auto-push to server if authenticated (non-blocking)
39
+ pushCheckpointsToServer(projectRoot, { quiet: true, autoSync: true, skipMetrics: true }).catch(() => {});
40
+
41
+ const status = checkpointEngine.getCheckpointStatus(projectRoot);
42
+
43
+ if (!status.exists) {
44
+ console.log(`
45
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Project Checkpoints${utils.COLORS.reset}
46
+
47
+ ${utils.COLORS.yellow}No checkpoint tracking found.${utils.COLORS.reset}
48
+
49
+ ${utils.COLORS.bold}Get started:${utils.COLORS.reset}
50
+ bootspring checkpoint init Initialize checkpoint tracking
51
+ bootspring preseed init Start with document generation
52
+ `);
53
+ return;
54
+ }
55
+
56
+ // Output as JSON if requested
57
+ if (options.json) {
58
+ console.log(JSON.stringify(status, null, 2));
59
+ return;
60
+ }
61
+
62
+ // Type badge
63
+ const typeBadge = getTypeBadge(status.projectType);
64
+ const autoTagNote = status.autoTagged ? ` ${utils.COLORS.dim}(auto-tagged by ${status.taggedBy})${utils.COLORS.reset}` : '';
65
+
66
+ console.log(`
67
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Project Checkpoints${utils.COLORS.reset}
68
+
69
+ ${utils.COLORS.bold}Project Type:${utils.COLORS.reset} ${typeBadge}${autoTagNote}
70
+
71
+ ${utils.COLORS.bold}Progress:${utils.COLORS.reset} ${status.completed}/${status.total} (${status.percentage}%)
72
+ ${checkpointEngine.getColoredProgressBar(status.percentage, 30)}
73
+ `);
74
+
75
+ // Show all checkpoints
76
+ console.log(`${utils.COLORS.bold}Checkpoints:${utils.COLORS.reset}`);
77
+
78
+ for (const checkpoint of status.checkpoints) {
79
+ const icon = checkpoint.completed
80
+ ? `${utils.COLORS.green}✓${utils.COLORS.reset}`
81
+ : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
82
+
83
+ const label = checkpoint.completed
84
+ ? checkpoint.label
85
+ : `${utils.COLORS.dim}${checkpoint.label}${utils.COLORS.reset}`;
86
+
87
+ const completedInfo = checkpoint.completed && status.checkpoints.find(c => c.id === checkpoint.id)
88
+ ? ` ${utils.COLORS.dim}(${checkpoint.reason})${utils.COLORS.reset}`
89
+ : '';
90
+
91
+ console.log(` ${icon} ${label}${completedInfo}`);
92
+ }
93
+
94
+ // Show next steps
95
+ const nextSteps = checkpointEngine.getNextSteps(projectRoot);
96
+ if (nextSteps.length > 0) {
97
+ console.log(`\n${utils.COLORS.bold}Next Steps:${utils.COLORS.reset}`);
98
+ for (const step of nextSteps) {
99
+ console.log(` ${utils.COLORS.cyan}→${utils.COLORS.reset} ${step.action}`);
100
+ }
101
+ }
102
+
103
+ console.log();
104
+
105
+ // Emit telemetry
106
+ telemetry.emitEvent('checkpoint:status', {
107
+ projectType: status.projectType,
108
+ completed: status.completed,
109
+ total: status.total,
110
+ percentage: status.percentage
111
+ }, { projectRoot });
112
+ }
113
+
114
+ /**
115
+ * Get type badge
116
+ * @param {string} projectType - Project type
117
+ * @returns {string} Formatted badge
118
+ */
119
+ function getTypeBadge(projectType) {
120
+ const badges = {
121
+ development: `${utils.COLORS.cyan}[DEV]${utils.COLORS.reset}`,
122
+ content: `${utils.COLORS.magenta}[CONTENT]${utils.COLORS.reset}`,
123
+ business: `${utils.COLORS.yellow}[BUSINESS]${utils.COLORS.reset}`
124
+ };
125
+ return badges[projectType] || badges.development;
126
+ }
127
+
128
+ /**
129
+ * Initialize checkpoint tracking
130
+ * @param {string} projectRoot - Project root directory
131
+ * @param {object} options - Options
132
+ */
133
+ function handleInit(projectRoot, options = {}) {
134
+ const existingState = projectState.loadState(projectRoot);
135
+
136
+ if (existingState && !options.force) {
137
+ utils.print.warning('Checkpoint tracking already initialized.');
138
+ utils.print.dim('Use --force to reinitialize.');
139
+ console.log();
140
+ handleStatus(projectRoot);
141
+ return;
142
+ }
143
+
144
+ // Determine project type
145
+ let projectType = options.type;
146
+ if (!projectType) {
147
+ projectType = projectState.detectProjectType(projectRoot);
148
+ utils.print.info(`Auto-detected project type: ${projectType}`);
149
+ }
150
+
151
+ // Initialize state
152
+ const state = projectState.initState(projectRoot, {
153
+ projectType,
154
+ autoTagged: false
155
+ });
156
+
157
+ // Run initial sync
158
+ const syncResult = checkpointEngine.syncCheckpoints(projectRoot, { verbose: true });
159
+
160
+ utils.print.success('Checkpoint tracking initialized!');
161
+ console.log();
162
+
163
+ // Show status
164
+ handleStatus(projectRoot);
165
+
166
+ // Emit telemetry
167
+ telemetry.emitEvent('checkpoint:init', {
168
+ projectType,
169
+ initialCompleted: syncResult.completed
170
+ }, { projectRoot });
171
+ }
172
+
173
+ /**
174
+ * Complete a checkpoint manually
175
+ * @param {string} projectRoot - Project root directory
176
+ * @param {string} checkpointId - Checkpoint ID
177
+ * @param {object} options - Options
178
+ */
179
+ function handleComplete(projectRoot, checkpointId, options = {}) {
180
+ if (!checkpointId) {
181
+ utils.print.error('Please specify a checkpoint to complete.');
182
+ console.log(`\n${utils.COLORS.bold}Usage:${utils.COLORS.reset} bootspring checkpoint complete <checkpoint-id>`);
183
+ console.log(`\n${utils.COLORS.bold}Available checkpoints:${utils.COLORS.reset}`);
184
+
185
+ const state = projectState.loadState(projectRoot);
186
+ if (state) {
187
+ const defs = projectState.getCheckpointDefinitions(state.projectType);
188
+ for (const def of defs) {
189
+ const completed = state.checkpoints[def.id]?.completed;
190
+ const icon = completed ? `${utils.COLORS.green}✓${utils.COLORS.reset}` : `${utils.COLORS.dim}○${utils.COLORS.reset}`;
191
+ console.log(` ${icon} ${def.id} - ${def.label}`);
192
+ }
193
+ }
194
+ console.log();
195
+ return;
196
+ }
197
+
198
+ const state = projectState.loadState(projectRoot);
199
+ if (!state) {
200
+ utils.print.error('Checkpoint tracking not initialized.');
201
+ utils.print.dim('Run: bootspring checkpoint init');
202
+ return;
203
+ }
204
+
205
+ // Check if checkpoint exists
206
+ const defs = projectState.getCheckpointDefinitions(state.projectType);
207
+ const checkpoint = defs.find(c => c.id === checkpointId);
208
+
209
+ if (!checkpoint) {
210
+ utils.print.error(`Unknown checkpoint: ${checkpointId}`);
211
+ console.log(`\n${utils.COLORS.bold}Available checkpoints:${utils.COLORS.reset}`);
212
+ for (const def of defs) {
213
+ console.log(` - ${def.id}`);
214
+ }
215
+ console.log();
216
+ return;
217
+ }
218
+
219
+ // Check if already completed
220
+ if (state.checkpoints[checkpointId]?.completed) {
221
+ utils.print.warning(`Checkpoint "${checkpoint.label}" is already completed.`);
222
+ return;
223
+ }
224
+
225
+ // Complete the checkpoint
226
+ const updatedState = projectState.completeCheckpoint(projectRoot, checkpointId, {
227
+ completedBy: 'manual',
228
+ notes: options.notes || 'Manually marked as complete'
229
+ });
230
+
231
+ if (updatedState) {
232
+ utils.print.success(`Completed: ${checkpoint.label}`);
233
+
234
+ // Show progress
235
+ const progress = projectState.getCheckpointProgress(projectRoot);
236
+ console.log(`\nProgress: ${progress.completed}/${progress.total} (${progress.percentage}%)`);
237
+ console.log(checkpointEngine.getColoredProgressBar(progress.percentage, 30));
238
+ console.log();
239
+
240
+ // Emit telemetry
241
+ telemetry.emitEvent('checkpoint:complete', {
242
+ checkpointId,
243
+ label: checkpoint.label,
244
+ method: 'manual'
245
+ }, { projectRoot });
246
+ } else {
247
+ utils.print.error('Failed to complete checkpoint.');
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Show checkpoint history
253
+ * @param {string} projectRoot - Project root directory
254
+ * @param {object} options - Options
255
+ */
256
+ function handleHistory(projectRoot, options = {}) {
257
+ const history = projectState.getCheckpointHistory(projectRoot);
258
+
259
+ if (history.length === 0) {
260
+ console.log(`
261
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Checkpoint History${utils.COLORS.reset}
262
+
263
+ ${utils.COLORS.dim}No checkpoint completions recorded yet.${utils.COLORS.reset}
264
+ `);
265
+ return;
266
+ }
267
+
268
+ // Output as JSON if requested
269
+ if (options.json) {
270
+ console.log(JSON.stringify(history, null, 2));
271
+ return;
272
+ }
273
+
274
+ const state = projectState.loadState(projectRoot);
275
+ const defs = state ? projectState.getCheckpointDefinitions(state.projectType) : [];
276
+
277
+ console.log(`
278
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Checkpoint History${utils.COLORS.reset}
279
+ `);
280
+
281
+ // Group by date
282
+ const byDate = {};
283
+ for (const record of history) {
284
+ const date = new Date(record.timestamp).toLocaleDateString();
285
+ if (!byDate[date]) {
286
+ byDate[date] = [];
287
+ }
288
+ byDate[date].push(record);
289
+ }
290
+
291
+ // Display grouped
292
+ for (const [date, records] of Object.entries(byDate)) {
293
+ console.log(`${utils.COLORS.bold}${date}${utils.COLORS.reset}`);
294
+
295
+ for (const record of records) {
296
+ const checkpoint = defs.find(d => d.id === record.checkpointId);
297
+ const label = checkpoint?.label || record.checkpointId;
298
+ const time = new Date(record.timestamp).toLocaleTimeString();
299
+
300
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${time} - ${label}`);
301
+ if (record.notes) {
302
+ console.log(` ${utils.COLORS.dim}${record.notes}${utils.COLORS.reset}`);
303
+ }
304
+ }
305
+ console.log();
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Sync checkpoints from files
311
+ * @param {string} projectRoot - Project root directory
312
+ * @param {object} options - Options
313
+ */
314
+ async function handleSync(projectRoot, options = {}) {
315
+ const spinner = utils.createSpinner('Scanning for completed checkpoints...');
316
+ spinner.start();
317
+
318
+ const result = checkpointEngine.syncCheckpoints(projectRoot, {
319
+ dryRun: options.dryRun,
320
+ verbose: false
321
+ });
322
+
323
+ if (result.changes.length === 0) {
324
+ spinner.info('No new checkpoints detected.');
325
+ } else {
326
+ spinner.succeed(`Found ${result.changes.length} new checkpoint(s)!`);
327
+ console.log();
328
+
329
+ for (const change of result.changes) {
330
+ if (change.type === 'completed') {
331
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${change.label}`);
332
+ console.log(` ${utils.COLORS.dim}${change.reason}${utils.COLORS.reset}`);
333
+ }
334
+ }
335
+ console.log();
336
+ }
337
+
338
+ // Show progress
339
+ console.log(`${utils.COLORS.bold}Progress:${utils.COLORS.reset} ${result.completed}/${result.total} (${Math.round((result.completed / result.total) * 100)}%)`);
340
+ console.log(checkpointEngine.getColoredProgressBar(Math.round((result.completed / result.total) * 100), 30));
341
+ console.log();
342
+
343
+ if (options.dryRun) {
344
+ utils.print.dim('Dry run - no changes were saved.');
345
+ } else {
346
+ // Auto-push to server if authenticated
347
+ try {
348
+ const pushResult = await pushCheckpointsToServer(projectRoot, { quiet: true, autoSync: true });
349
+ if (pushResult.success) {
350
+ utils.print.success('Synced to dashboard automatically');
351
+ }
352
+ } catch {
353
+ // Silent fail - push is best-effort
354
+ }
355
+ }
356
+
357
+ // Emit telemetry
358
+ telemetry.emitEvent('checkpoint:sync', {
359
+ changes: result.changes.length,
360
+ completed: result.completed,
361
+ total: result.total
362
+ }, { projectRoot });
363
+ }
364
+
365
+ /**
366
+ * Set project type
367
+ * @param {string} projectRoot - Project root directory
368
+ * @param {string} type - Project type
369
+ */
370
+ function handleType(projectRoot, type) {
371
+ const validTypes = Object.values(projectState.PROJECT_TYPES);
372
+
373
+ if (!type) {
374
+ // Show current type
375
+ const state = projectState.loadState(projectRoot);
376
+ if (!state) {
377
+ utils.print.error('Checkpoint tracking not initialized.');
378
+ return;
379
+ }
380
+
381
+ console.log(`
382
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Project Type${utils.COLORS.reset}
383
+
384
+ Current type: ${getTypeBadge(state.projectType)}
385
+ `);
386
+
387
+ console.log(`${utils.COLORS.bold}Available types:${utils.COLORS.reset}`);
388
+ for (const t of validTypes) {
389
+ const badge = getTypeBadge(t);
390
+ const current = t === state.projectType ? ' (current)' : '';
391
+ console.log(` ${badge} ${t}${current}`);
392
+ }
393
+ console.log();
394
+
395
+ console.log(`${utils.COLORS.bold}Change type:${utils.COLORS.reset}`);
396
+ console.log(' bootspring checkpoint type <type>');
397
+ console.log();
398
+ return;
399
+ }
400
+
401
+ if (!validTypes.includes(type)) {
402
+ utils.print.error(`Invalid project type: ${type}`);
403
+ console.log(`\n${utils.COLORS.bold}Valid types:${utils.COLORS.reset} ${validTypes.join(', ')}`);
404
+ return;
405
+ }
406
+
407
+ const updatedState = projectState.setProjectType(projectRoot, type);
408
+
409
+ if (updatedState) {
410
+ utils.print.success(`Project type changed to: ${type}`);
411
+
412
+ // Sync checkpoints for new type
413
+ const syncResult = checkpointEngine.syncCheckpoints(projectRoot, { verbose: true });
414
+ console.log(`\nCheckpoints: ${syncResult.completed}/${syncResult.total} complete`);
415
+
416
+ telemetry.emitEvent('checkpoint:type-change', {
417
+ newType: type
418
+ }, { projectRoot });
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Push checkpoints to dashboard
424
+ * Sends raw file scan data - server evaluates checkpoints and calculates scores
425
+ * @param {string} projectRoot - Project root directory
426
+ * @param {object} options - Options
427
+ */
428
+ async function handlePush(projectRoot, options = {}) {
429
+ const spinner = utils.createSpinner('Scanning and syncing to dashboard...');
430
+ spinner.start();
431
+
432
+ try {
433
+ const result = await pushCheckpointsToServer(projectRoot, { quiet: false });
434
+
435
+ if (!result.success) {
436
+ if (result.reason === 'not_authenticated') {
437
+ spinner.fail('Not authenticated. Run: bootspring auth login');
438
+ } else if (result.reason === 'no_project') {
439
+ spinner.fail('No project selected. Run: bootspring switch <project>');
440
+ } else {
441
+ spinner.fail('Failed to sync checkpoints');
442
+ }
443
+ return;
444
+ }
445
+
446
+ spinner.succeed('Checkpoints synced to dashboard!');
447
+
448
+ // Display server-evaluated results
449
+ console.log(`
450
+ ${utils.COLORS.bold}Sync Summary:${utils.COLORS.reset}
451
+ Project Type: ${result.projectType}
452
+ Checkpoints: ${result.progress?.completed}/${result.progress?.total} (${result.progress?.percentage}%)
453
+ Health Score: ${result.healthScore}%
454
+ Last Sync: ${result.lastSyncAt ? new Date(result.lastSyncAt).toLocaleString() : 'Now'}
455
+ `);
456
+
457
+ // Show health breakdown
458
+ if (result.healthBreakdown) {
459
+ console.log(`${utils.COLORS.bold}Health Breakdown:${utils.COLORS.reset}`);
460
+ for (const [key, value] of Object.entries(result.healthBreakdown)) {
461
+ const label = key.charAt(0).toUpperCase() + key.slice(1).replace(/([A-Z])/g, ' $1');
462
+ console.log(` ${label}: ${value}%`);
463
+ }
464
+ console.log();
465
+ }
466
+
467
+ // Emit telemetry
468
+ telemetry.emitEvent('checkpoint:push', {
469
+ healthScore: result.healthScore,
470
+ checkpointsCompleted: result.progress?.completed
471
+ }, { projectRoot });
472
+
473
+ } catch (error) {
474
+ spinner.fail(`Failed to sync: ${error.message}`);
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Detect project type automatically
480
+ * @param {string} projectRoot - Project root directory
481
+ */
482
+ function handleDetect(projectRoot) {
483
+ const detectedType = projectState.detectProjectType(projectRoot);
484
+ const state = projectState.loadState(projectRoot);
485
+ const currentType = state?.projectType;
486
+
487
+ console.log(`
488
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Project Type Detection${utils.COLORS.reset}
489
+
490
+ Detected type: ${getTypeBadge(detectedType)}
491
+ `);
492
+
493
+ if (currentType && currentType !== detectedType) {
494
+ console.log(`Current type: ${getTypeBadge(currentType)}`);
495
+ console.log(`\n${utils.COLORS.bold}To change:${utils.COLORS.reset} bootspring checkpoint type ${detectedType}`);
496
+ } else if (!currentType) {
497
+ console.log(`${utils.COLORS.bold}To initialize:${utils.COLORS.reset} bootspring checkpoint init --type=${detectedType}`);
498
+ } else {
499
+ console.log(`${utils.COLORS.dim}Current type matches detected type.${utils.COLORS.reset}`);
500
+ }
501
+ console.log();
502
+ }
503
+
504
+ /**
505
+ * Show help
506
+ */
507
+ function showHelp() {
508
+ console.log(`
509
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Checkpoints${utils.COLORS.reset}
510
+ ${utils.COLORS.dim}Track project milestones and progress${utils.COLORS.reset}
511
+
512
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
513
+ bootspring checkpoint [command] [options]
514
+
515
+ ${utils.COLORS.bold}Commands:${utils.COLORS.reset}
516
+ status Show all checkpoints with status (default)
517
+ init Initialize checkpoint tracking
518
+ complete <id> Mark a checkpoint as complete
519
+ history View checkpoint completion timeline
520
+ sync Re-scan files to detect completed items
521
+ type [type] Show or set project type
522
+ detect Auto-detect project type from files
523
+ push Sync checkpoints to dashboard
524
+
525
+ ${utils.COLORS.bold}Options:${utils.COLORS.reset}
526
+ --json Output as JSON
527
+ --force Force reinitialize
528
+ --dry-run Don't save changes (for sync)
529
+ --type=<type> Set project type (dev, content, business)
530
+ --notes="..." Add notes when completing
531
+
532
+ ${utils.COLORS.bold}Project Types:${utils.COLORS.reset}
533
+ development Software development projects
534
+ content Content/editorial projects
535
+ business Business planning projects
536
+
537
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
538
+ bootspring checkpoint # Show status
539
+ bootspring checkpoint init # Initialize tracking
540
+ bootspring checkpoint complete prd # Complete the PRD checkpoint
541
+ bootspring checkpoint sync # Detect completed items
542
+ bootspring checkpoint type business # Change to business type
543
+ `);
544
+ }
545
+
546
+ // ============================================================================
547
+ // Main Runner
548
+ // ============================================================================
549
+
550
+ /**
551
+ * Run checkpoint command
552
+ * @param {Array} args - Command arguments
553
+ */
554
+ async function run(args) {
555
+ const cfg = config.load();
556
+ const projectRoot = cfg._projectRoot;
557
+
558
+ // Parse arguments
559
+ const parsed = utils.parseArgs(args);
560
+ const subcommand = parsed._[0] || 'status';
561
+ const options = {
562
+ json: parsed.json || false,
563
+ force: parsed.force || false,
564
+ dryRun: parsed['dry-run'] || parsed.dryRun || false,
565
+ type: parsed.type || null,
566
+ notes: parsed.notes || null
567
+ };
568
+
569
+ switch (subcommand) {
570
+ case 'status':
571
+ case 'show':
572
+ case 's':
573
+ handleStatus(projectRoot, options);
574
+ break;
575
+
576
+ case 'init':
577
+ case 'initialize':
578
+ handleInit(projectRoot, options);
579
+ break;
580
+
581
+ case 'complete':
582
+ case 'done':
583
+ case 'c':
584
+ handleComplete(projectRoot, parsed._[1], options);
585
+ break;
586
+
587
+ case 'history':
588
+ case 'log':
589
+ case 'h':
590
+ handleHistory(projectRoot, options);
591
+ break;
592
+
593
+ case 'sync':
594
+ case 'scan':
595
+ handleSync(projectRoot, options);
596
+ break;
597
+
598
+ case 'type':
599
+ case 't':
600
+ handleType(projectRoot, parsed._[1] || options.type);
601
+ break;
602
+
603
+ case 'detect':
604
+ case 'd':
605
+ handleDetect(projectRoot);
606
+ break;
607
+
608
+ case 'push':
609
+ case 'upload':
610
+ await handlePush(projectRoot, options);
611
+ break;
612
+
613
+ case 'help':
614
+ case '-h':
615
+ case '--help':
616
+ showHelp();
617
+ break;
618
+
619
+ default:
620
+ utils.print.error(`Unknown subcommand: ${subcommand}`);
621
+ showHelp();
622
+ }
623
+ }
624
+
625
+ // ============================================================================
626
+ // Exports
627
+ // ============================================================================
628
+
629
+ module.exports = {
630
+ run,
631
+ // Utility exports for programmatic use
632
+ handleStatus,
633
+ handleInit,
634
+ handleComplete,
635
+ handleHistory,
636
+ handleSync,
637
+ handleType,
638
+ handleDetect
639
+ };