@girardmedia/bootspring 2.0.21 → 2.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/bin/bootspring.js +5 -0
  2. package/cli/org.js +474 -0
  3. package/cli/preseed/index.js +16 -0
  4. package/cli/preseed/interactive.js +143 -0
  5. package/cli/preseed/templates.js +227 -0
  6. package/cli/preseed.js +9 -301
  7. package/cli/seed/builders/ai-context-builder.js +85 -0
  8. package/cli/seed/builders/index.js +13 -0
  9. package/cli/seed/builders/seed-builder.js +272 -0
  10. package/cli/seed/extractors/content-extractors.js +383 -0
  11. package/cli/seed/extractors/index.js +47 -0
  12. package/cli/seed/extractors/metadata-extractors.js +167 -0
  13. package/cli/seed/extractors/section-extractor.js +54 -0
  14. package/cli/seed/extractors/stack-extractors.js +228 -0
  15. package/cli/seed/index.js +18 -0
  16. package/cli/seed/utils/folder-structure.js +84 -0
  17. package/cli/seed/utils/index.js +11 -0
  18. package/cli/seed.js +23 -1074
  19. package/core/api-client.js +77 -0
  20. package/core/entitlements.js +36 -0
  21. package/core/organizations.js +223 -0
  22. package/core/policies.js +51 -6
  23. package/core/policy-matrix.js +303 -0
  24. package/core/project-context.js +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.js +3220 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/context-McpJQa_2.d.ts +5710 -0
  29. package/dist/core/index.d.ts +635 -0
  30. package/dist/core/index.js +2593 -0
  31. package/dist/core/index.js.map +1 -0
  32. package/dist/index-QqbeEiDm.d.ts +857 -0
  33. package/dist/index-UiYCgwiH.d.ts +174 -0
  34. package/dist/index.d.ts +453 -0
  35. package/dist/index.js +44228 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp/index.d.ts +1 -0
  38. package/dist/mcp/index.js +41173 -0
  39. package/dist/mcp/index.js.map +1 -0
  40. package/generators/index.ts +82 -0
  41. package/intelligence/orchestrator/config/failure-signatures.js +48 -0
  42. package/intelligence/orchestrator/config/index.js +23 -0
  43. package/intelligence/orchestrator/config/pack-lifecycle.js +262 -0
  44. package/intelligence/orchestrator/config/phases.js +111 -0
  45. package/intelligence/orchestrator/config/remediation.js +150 -0
  46. package/intelligence/orchestrator/config/workflows.js +168 -0
  47. package/intelligence/orchestrator/core/index.js +16 -0
  48. package/intelligence/orchestrator/core/state-manager.js +88 -0
  49. package/intelligence/orchestrator/core/telemetry.js +24 -0
  50. package/intelligence/orchestrator/index.js +17 -0
  51. package/intelligence/orchestrator.js +17 -512
  52. package/mcp/contracts/mcp-contract.v1.json +1 -1
  53. package/package.json +16 -3
  54. package/src/cli/agent.ts +703 -0
  55. package/src/cli/analyze.ts +640 -0
  56. package/src/cli/audit.ts +707 -0
  57. package/src/cli/auth.ts +930 -0
  58. package/src/cli/billing.ts +364 -0
  59. package/src/cli/build.ts +1089 -0
  60. package/src/cli/business.ts +508 -0
  61. package/src/cli/checkpoint-utils.ts +236 -0
  62. package/src/cli/checkpoint.ts +757 -0
  63. package/src/cli/cloud-sync.ts +534 -0
  64. package/src/cli/content.ts +273 -0
  65. package/src/cli/context.ts +667 -0
  66. package/src/cli/dashboard.ts +133 -0
  67. package/src/cli/deploy.ts +704 -0
  68. package/src/cli/doctor.ts +480 -0
  69. package/src/cli/fundraise.ts +494 -0
  70. package/src/cli/generate.ts +346 -0
  71. package/src/cli/github-cmd.ts +566 -0
  72. package/src/cli/health.ts +599 -0
  73. package/src/cli/index.ts +113 -0
  74. package/src/cli/init.ts +838 -0
  75. package/src/cli/legal.ts +495 -0
  76. package/src/cli/log.ts +316 -0
  77. package/src/cli/loop.ts +1660 -0
  78. package/src/cli/manager.ts +878 -0
  79. package/src/cli/mcp.ts +275 -0
  80. package/src/cli/memory.ts +346 -0
  81. package/src/cli/metrics.ts +590 -0
  82. package/src/cli/monitor.ts +960 -0
  83. package/src/cli/mvp.ts +662 -0
  84. package/src/cli/onboard.ts +663 -0
  85. package/src/cli/orchestrator.ts +622 -0
  86. package/src/cli/plugin.ts +483 -0
  87. package/src/cli/prd.ts +671 -0
  88. package/src/cli/preseed-start.ts +1633 -0
  89. package/src/cli/preseed.ts +2434 -0
  90. package/src/cli/project.ts +526 -0
  91. package/src/cli/quality.ts +885 -0
  92. package/src/cli/security.ts +1079 -0
  93. package/src/cli/seed.ts +1224 -0
  94. package/src/cli/skill.ts +537 -0
  95. package/src/cli/suggest.ts +1225 -0
  96. package/src/cli/switch.ts +518 -0
  97. package/src/cli/task.ts +780 -0
  98. package/src/cli/telemetry.ts +172 -0
  99. package/src/cli/todo.ts +627 -0
  100. package/src/cli/types.ts +15 -0
  101. package/src/cli/update.ts +334 -0
  102. package/src/cli/visualize.ts +609 -0
  103. package/src/cli/watch.ts +895 -0
  104. package/src/cli/workspace.ts +709 -0
  105. package/src/core/action-recorder.ts +673 -0
  106. package/src/core/analyze-workflow.ts +1453 -0
  107. package/src/core/api-client.ts +1120 -0
  108. package/src/core/audit-workflow.ts +1681 -0
  109. package/src/core/auth.ts +471 -0
  110. package/src/core/build-orchestrator.ts +509 -0
  111. package/src/core/build-state.ts +621 -0
  112. package/src/core/checkpoint-engine.ts +482 -0
  113. package/src/core/config.ts +1285 -0
  114. package/src/core/context-loader.ts +694 -0
  115. package/src/core/context.ts +410 -0
  116. package/src/core/deploy-workflow.ts +1085 -0
  117. package/src/core/entitlements.ts +322 -0
  118. package/src/core/github-sync.ts +720 -0
  119. package/src/core/index.ts +981 -0
  120. package/src/core/ingest.ts +1186 -0
  121. package/src/core/metrics-engine.ts +886 -0
  122. package/src/core/mvp.ts +847 -0
  123. package/src/core/onboard-workflow.ts +1293 -0
  124. package/src/core/policies.ts +81 -0
  125. package/src/core/preseed-workflow.ts +1163 -0
  126. package/src/core/preseed.ts +1826 -0
  127. package/src/core/project-context.ts +380 -0
  128. package/src/core/project-state.ts +699 -0
  129. package/src/core/r2-sync.ts +691 -0
  130. package/src/core/scaffold.ts +1715 -0
  131. package/src/core/session.ts +286 -0
  132. package/src/core/task-extractor.ts +799 -0
  133. package/src/core/telemetry.ts +371 -0
  134. package/src/core/tier-enforcement.ts +737 -0
  135. package/src/core/utils.ts +437 -0
  136. package/src/index.ts +29 -0
  137. package/src/intelligence/agent-collab.ts +2376 -0
  138. package/src/intelligence/auto-suggest.ts +713 -0
  139. package/src/intelligence/content-gen.ts +1351 -0
  140. package/src/intelligence/cross-project.ts +1692 -0
  141. package/src/intelligence/git-memory.ts +529 -0
  142. package/src/intelligence/index.ts +318 -0
  143. package/src/intelligence/orchestrator.ts +534 -0
  144. package/src/intelligence/prd.ts +466 -0
  145. package/src/intelligence/recommendations.ts +982 -0
  146. package/src/intelligence/workflow-composer.ts +1472 -0
  147. package/src/mcp/capabilities.ts +233 -0
  148. package/src/mcp/index.ts +37 -0
  149. package/src/mcp/registry.ts +1268 -0
  150. package/src/mcp/response-formatter.ts +797 -0
  151. package/src/mcp/server.ts +240 -0
  152. package/src/types/agent.ts +69 -0
  153. package/src/types/config.ts +86 -0
  154. package/src/types/context.ts +77 -0
  155. package/src/types/index.ts +53 -0
  156. package/src/types/mcp.ts +91 -0
  157. package/src/types/skills.ts +47 -0
  158. package/src/types/workflow.ts +155 -0
  159. package/generators/index.js +0 -18
@@ -0,0 +1,707 @@
1
+ /**
2
+ * Bootspring Audit CLI
3
+ *
4
+ * Quality, security, and best practices audit for codebases.
5
+ * Generates prioritized recommendations and remediation tasks.
6
+ *
7
+ * @package bootspring
8
+ * @module cli/audit
9
+ */
10
+
11
+ // Import JS modules with type interfaces
12
+ interface ParsedArgs {
13
+ _: string[];
14
+ phase?: string | undefined;
15
+ severity?: string | undefined;
16
+ fix?: boolean | undefined;
17
+ ci?: boolean | undefined;
18
+ }
19
+
20
+ interface PhaseConfig {
21
+ name: string;
22
+ description: string;
23
+ required: boolean;
24
+ }
25
+
26
+ interface QualityResult {
27
+ score: number;
28
+ breakdown: {
29
+ complexity: number;
30
+ maintainability: number;
31
+ documentation: number;
32
+ codeSmells: number;
33
+ };
34
+ totalIssues: number;
35
+ totalFiles: number;
36
+ }
37
+
38
+ interface SecurityResult {
39
+ passed: boolean;
40
+ total: number;
41
+ critical: number;
42
+ high: number;
43
+ medium: number;
44
+ low: number;
45
+ }
46
+
47
+ interface PerformanceResult {
48
+ score: number;
49
+ }
50
+
51
+ interface PracticesResult {
52
+ passed: number;
53
+ total: number;
54
+ checks: Record<string, {
55
+ passed: boolean;
56
+ issues: Array<{ title: string }>;
57
+ }>;
58
+ }
59
+
60
+ interface TechDebtResult {
61
+ todos: number;
62
+ unusedDeps: number;
63
+ testCoverage: number;
64
+ depAnalysisSkipped?: boolean | undefined;
65
+ }
66
+
67
+ interface RecommendationsResult {
68
+ reportPath: string;
69
+ passed: boolean;
70
+ }
71
+
72
+ interface FindingsSummary {
73
+ total: number;
74
+ critical: number;
75
+ high: number;
76
+ medium: number;
77
+ low: number;
78
+ }
79
+
80
+ interface OverallProgress {
81
+ completed: number;
82
+ total: number;
83
+ percentage: number;
84
+ }
85
+
86
+ interface PhaseProgress {
87
+ name: string;
88
+ status: string;
89
+ required: boolean;
90
+ }
91
+
92
+ interface WorkflowProgress {
93
+ overall: OverallProgress;
94
+ isComplete: boolean;
95
+ findings: FindingsSummary;
96
+ phases: PhaseProgress[];
97
+ startedAt?: string | undefined;
98
+ lastUpdated?: string | undefined;
99
+ summary?: {
100
+ reportPath?: string | undefined;
101
+ } | undefined;
102
+ }
103
+
104
+ interface ResumePoint {
105
+ phaseName: string;
106
+ findingsCount: number;
107
+ }
108
+
109
+ interface AuditWorkflowEngineClass {
110
+ new (projectRoot: string, options?: AuditOptions): AuditWorkflowEngine;
111
+ }
112
+
113
+ interface AuditOptions {
114
+ severityFilter?: string | null | undefined;
115
+ ciMode?: boolean | undefined;
116
+ }
117
+
118
+ interface AuditWorkflowEngine {
119
+ hasWorkflow(): boolean;
120
+ loadState(): void;
121
+ initializeWorkflow(): void;
122
+ getProgress(): WorkflowProgress;
123
+ getResumePoint(): ResumePoint | null;
124
+ getNextPhase(): string | null;
125
+ startPhase(phaseId: string): void;
126
+ completePhase(phaseId: string, result: unknown): void;
127
+ failPhase(phaseId: string, error: string): void;
128
+ skipPhase(phaseId: string): void;
129
+ resetWorkflow(): void;
130
+ getExitCode(): number;
131
+ runQualityMetrics(): Promise<QualityResult>;
132
+ runSecurityScan(): Promise<SecurityResult>;
133
+ runPerformanceAnalysis(): Promise<PerformanceResult>;
134
+ runBestPractices(): Promise<PracticesResult>;
135
+ runTechDebtInventory(): Promise<TechDebtResult>;
136
+ runRecommendations(): Promise<RecommendationsResult>;
137
+ }
138
+
139
+ interface AuditWorkflowModule {
140
+ AuditWorkflowEngine: AuditWorkflowEngineClass;
141
+ AUDIT_PHASES: Record<string, PhaseConfig>;
142
+ SEVERITY_LEVELS: Record<string, unknown>;
143
+ }
144
+
145
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
146
+ const utils = require('../../core/utils') as typeof import('../core/utils');
147
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
148
+ const auditWorkflowModule = require('../../core/audit-workflow') as AuditWorkflowModule;
149
+
150
+ const { AuditWorkflowEngine, AUDIT_PHASES } = auditWorkflowModule;
151
+
152
+ // Get project root
153
+ const projectRoot = process.cwd();
154
+
155
+ /**
156
+ * Show audit help
157
+ */
158
+ function showHelp(): void {
159
+ console.log(`
160
+ ${utils.COLORS.bold}Bootspring Audit${utils.COLORS.reset}
161
+ Quality, security, and best practices audit
162
+
163
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
164
+ bootspring audit Full audit
165
+ bootspring audit status Show progress
166
+ bootspring audit resume Continue from checkpoint
167
+ bootspring audit reset Reset workflow
168
+
169
+ ${utils.COLORS.bold}Options:${utils.COLORS.reset}
170
+ --phase=<phase> Run specific phase only
171
+ --severity=<level> Filter by severity (critical, high, medium, low)
172
+ --fix Auto-fix safe issues (where possible)
173
+ --ci CI mode with exit codes
174
+
175
+ ${utils.COLORS.bold}Phases:${utils.COLORS.reset}
176
+ quality Code quality metrics (complexity, duplication)
177
+ security Security scan (secrets, vulnerabilities)
178
+ performance Performance analysis
179
+ practices Best practices checks
180
+ techDebt Tech debt inventory
181
+ recommendations Generate prioritized recommendations
182
+
183
+ ${utils.COLORS.bold}Exit Codes (CI Mode):${utils.COLORS.reset}
184
+ 0 All checks passed
185
+ 1 High severity issues found
186
+ 2 Critical issues found
187
+
188
+ ${utils.COLORS.bold}Notes:${utils.COLORS.reset}
189
+ Large codebases (500+ files) automatically skip heavy dependency
190
+ analysis in the tech debt phase for performance.
191
+
192
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
193
+ bootspring audit Auto-adjusts for codebase size
194
+ bootspring audit --phase=security
195
+ bootspring audit --severity=high
196
+ bootspring audit --ci
197
+ `);
198
+ }
199
+
200
+ /**
201
+ * Start audit workflow
202
+ */
203
+ async function auditStart(args: ParsedArgs): Promise<void> {
204
+ const workflow = new AuditWorkflowEngine(projectRoot, {
205
+ severityFilter: args.severity || null,
206
+ ciMode: args.ci || false
207
+ });
208
+
209
+ // Check for existing workflow
210
+ if (workflow.hasWorkflow()) {
211
+ workflow.loadState();
212
+ const progress = workflow.getProgress();
213
+
214
+ if (!progress.isComplete) {
215
+ utils.print.info('Existing audit workflow found.');
216
+ console.log(` Progress: ${progress.overall.percentage}% complete`);
217
+ console.log(` Findings: ${progress.findings.total}`);
218
+ console.log('');
219
+ utils.print.info('Use "bootspring audit resume" to continue');
220
+ utils.print.info('Use "bootspring audit reset" to start fresh');
221
+ return;
222
+ }
223
+ }
224
+
225
+ // Initialize new workflow
226
+ utils.print.header('Codebase Audit');
227
+ console.log('Running quality, security, and best practices checks...');
228
+ console.log('');
229
+
230
+ workflow.initializeWorkflow();
231
+
232
+ // Run workflow
233
+ await runWorkflowLoop(workflow, args);
234
+ }
235
+
236
+ /**
237
+ * Resume audit workflow
238
+ */
239
+ async function auditResume(args: ParsedArgs): Promise<void> {
240
+ const workflow = new AuditWorkflowEngine(projectRoot);
241
+
242
+ if (!workflow.hasWorkflow()) {
243
+ utils.print.error('No existing workflow found.');
244
+ utils.print.info('Run "bootspring audit" to start.');
245
+ return;
246
+ }
247
+
248
+ workflow.loadState();
249
+ const resumePoint = workflow.getResumePoint();
250
+
251
+ if (!resumePoint) {
252
+ utils.print.success('Audit workflow already complete!');
253
+ displayCompletionSummary(workflow, args);
254
+ return;
255
+ }
256
+
257
+ utils.print.header('Resuming Audit');
258
+ console.log(`Continuing from: ${resumePoint.phaseName}`);
259
+ console.log(`Current findings: ${resumePoint.findingsCount}`);
260
+ console.log('');
261
+
262
+ await runWorkflowLoop(workflow, args);
263
+ }
264
+
265
+ /**
266
+ * Run the workflow loop
267
+ */
268
+ async function runWorkflowLoop(workflow: AuditWorkflowEngine, args: ParsedArgs): Promise<void> {
269
+ while (true) {
270
+ const nextPhaseId = workflow.getNextPhase();
271
+
272
+ if (!nextPhaseId) {
273
+ // Workflow complete
274
+ break;
275
+ }
276
+
277
+ const phase = AUDIT_PHASES[nextPhaseId];
278
+ if (!phase) continue;
279
+
280
+ // Skip optional phases
281
+ if (!phase.required) {
282
+ // For now, skip optional phases in basic flow
283
+ workflow.skipPhase(nextPhaseId);
284
+ continue;
285
+ }
286
+
287
+ // Run the phase
288
+ workflow.startPhase(nextPhaseId);
289
+ const spinner = utils.createSpinner(`Running: ${phase.name}`).start();
290
+
291
+ try {
292
+ let result: unknown;
293
+
294
+ switch (nextPhaseId) {
295
+ case 'quality': {
296
+ const qualityResult = await workflow.runQualityMetrics();
297
+ spinner.succeed(`Quality metrics: Score ${qualityResult.score}/100`);
298
+ displayQualityResults(qualityResult);
299
+ result = qualityResult;
300
+ break;
301
+ }
302
+
303
+ case 'security': {
304
+ const securityResult = await workflow.runSecurityScan();
305
+ if (securityResult.critical > 0) {
306
+ spinner.fail(`Security scan: ${securityResult.critical} CRITICAL issues found`);
307
+ } else if (securityResult.high > 0) {
308
+ spinner.warn(`Security scan: ${securityResult.high} high severity issues found`);
309
+ } else if (securityResult.passed) {
310
+ spinner.succeed('Security scan: PASSED');
311
+ } else {
312
+ spinner.succeed(`Security scan: ${securityResult.total} findings`);
313
+ }
314
+ displaySecurityResults(securityResult);
315
+ result = securityResult;
316
+ break;
317
+ }
318
+
319
+ case 'performance': {
320
+ const perfResult = await workflow.runPerformanceAnalysis();
321
+ spinner.succeed('Performance analysis complete');
322
+ result = perfResult;
323
+ break;
324
+ }
325
+
326
+ case 'practices': {
327
+ const practicesResult = await workflow.runBestPractices();
328
+ spinner.succeed(`Best practices: ${practicesResult.passed}/${practicesResult.total} checks passed`);
329
+ displayPracticesResults(practicesResult);
330
+ result = practicesResult;
331
+ break;
332
+ }
333
+
334
+ case 'techDebt': {
335
+ const techDebtResult = await workflow.runTechDebtInventory();
336
+ if (techDebtResult.depAnalysisSkipped) {
337
+ spinner.succeed(`Tech debt: ${techDebtResult.todos} TODOs (dep analysis skipped - large codebase)`);
338
+ } else {
339
+ spinner.succeed(`Tech debt: ${techDebtResult.todos} TODOs, ${techDebtResult.unusedDeps} unused deps`);
340
+ }
341
+ displayTechDebtResults(techDebtResult);
342
+ result = techDebtResult;
343
+ break;
344
+ }
345
+
346
+ case 'recommendations': {
347
+ const recsResult = await workflow.runRecommendations();
348
+ spinner.succeed('Recommendations generated');
349
+ displayRecommendationsResults(recsResult);
350
+ result = recsResult;
351
+ break;
352
+ }
353
+
354
+ default:
355
+ spinner.warn(`Unknown phase: ${nextPhaseId}`);
356
+ continue;
357
+ }
358
+
359
+ workflow.completePhase(nextPhaseId, result);
360
+
361
+ } catch (error) {
362
+ spinner.fail(`Failed: ${(error as Error).message}`);
363
+ workflow.failPhase(nextPhaseId, (error as Error).message);
364
+
365
+ if (phase.required) {
366
+ utils.print.error('Required phase failed. Cannot continue.');
367
+ return;
368
+ }
369
+ }
370
+
371
+ console.log('');
372
+ }
373
+
374
+ // Workflow complete
375
+ displayCompletionSummary(workflow, args);
376
+ }
377
+
378
+ /**
379
+ * Display quality results
380
+ */
381
+ function displayQualityResults(result: QualityResult): void {
382
+ console.log('');
383
+ console.log(` ${utils.COLORS.cyan}Complexity:${utils.COLORS.reset} ${result.breakdown.complexity}/100`);
384
+ console.log(` ${utils.COLORS.cyan}Maintainability:${utils.COLORS.reset} ${result.breakdown.maintainability}/100`);
385
+ console.log(` ${utils.COLORS.cyan}Documentation:${utils.COLORS.reset} ${result.breakdown.documentation}/100`);
386
+ console.log(` ${utils.COLORS.cyan}Code Smells:${utils.COLORS.reset} ${result.breakdown.codeSmells}/100`);
387
+
388
+ if (result.totalIssues > 0) {
389
+ console.log('');
390
+ console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} ${result.totalIssues} issues found across ${result.totalFiles} files`);
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Display security results
396
+ */
397
+ function displaySecurityResults(result: SecurityResult): void {
398
+ if (result.total > 0) {
399
+ console.log('');
400
+ console.log(' Findings:');
401
+
402
+ if (result.critical > 0) {
403
+ console.log(` ${utils.COLORS.red}●${utils.COLORS.reset} Critical: ${result.critical}`);
404
+ }
405
+ if (result.high > 0) {
406
+ console.log(` ${utils.COLORS.yellow}●${utils.COLORS.reset} High: ${result.high}`);
407
+ }
408
+ if (result.medium > 0) {
409
+ console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} Medium: ${result.medium}`);
410
+ }
411
+ if (result.low > 0) {
412
+ console.log(` ${utils.COLORS.dim}○${utils.COLORS.reset} Low: ${result.low}`);
413
+ }
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Display best practices results
419
+ */
420
+ function displayPracticesResults(result: PracticesResult): void {
421
+ if (result.passed < result.total) {
422
+ console.log('');
423
+ for (const [, check] of Object.entries(result.checks)) {
424
+ if (!check.passed) {
425
+ for (const issue of check.issues.slice(0, 2)) {
426
+ console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} ${issue.title}`);
427
+ }
428
+ }
429
+ }
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Display tech debt results
435
+ */
436
+ function displayTechDebtResults(result: TechDebtResult): void {
437
+ console.log('');
438
+ console.log(` ${utils.COLORS.cyan}Test coverage:${utils.COLORS.reset} ${result.testCoverage}%`);
439
+
440
+ if (result.todos > 0) {
441
+ console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} ${result.todos} TODO/FIXME comments`);
442
+ }
443
+
444
+ if (result.unusedDeps > 0) {
445
+ console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} ${result.unusedDeps} potentially unused dependencies`);
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Display recommendations results
451
+ */
452
+ function displayRecommendationsResults(result: RecommendationsResult): void {
453
+ console.log('');
454
+ utils.print.success(`Report saved to: ${result.reportPath}`);
455
+
456
+ if (!result.passed) {
457
+ console.log('');
458
+ utils.print.warning('Audit found issues that need attention.');
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Display completion summary
464
+ */
465
+ function displayCompletionSummary(workflow: AuditWorkflowEngine, args: ParsedArgs): void {
466
+ const progress = workflow.getProgress();
467
+
468
+ console.log('');
469
+
470
+ // Show audit result
471
+ if (progress.findings.critical > 0) {
472
+ utils.print.error('Audit FAILED: Critical issues found');
473
+ } else if (progress.findings.high > 0) {
474
+ utils.print.warning('Audit completed with high severity issues');
475
+ } else {
476
+ utils.print.success('Audit completed successfully!');
477
+ }
478
+
479
+ console.log('');
480
+
481
+ // Show findings summary
482
+ utils.print.header('Findings Summary');
483
+
484
+ console.log('');
485
+ console.log(` Total findings: ${progress.findings.total}`);
486
+ console.log('');
487
+
488
+ if (progress.findings.critical > 0) {
489
+ console.log(` ${utils.COLORS.red}● Critical:${utils.COLORS.reset} ${progress.findings.critical} ${utils.COLORS.dim}(immediate action required)${utils.COLORS.reset}`);
490
+ }
491
+ if (progress.findings.high > 0) {
492
+ console.log(` ${utils.COLORS.yellow}● High:${utils.COLORS.reset} ${progress.findings.high} ${utils.COLORS.dim}(fix within 1-2 days)${utils.COLORS.reset}`);
493
+ }
494
+ if (progress.findings.medium > 0) {
495
+ console.log(` ${utils.COLORS.yellow}○ Medium:${utils.COLORS.reset} ${progress.findings.medium} ${utils.COLORS.dim}(plan within 1-2 weeks)${utils.COLORS.reset}`);
496
+ }
497
+ if (progress.findings.low > 0) {
498
+ console.log(` ${utils.COLORS.dim}○ Low:${utils.COLORS.reset} ${progress.findings.low} ${utils.COLORS.dim}(add to backlog)${utils.COLORS.reset}`);
499
+ }
500
+
501
+ if (progress.summary?.reportPath) {
502
+ console.log('');
503
+ console.log(' Reports generated:');
504
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${progress.summary.reportPath}`);
505
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} .bootspring/audit/reports/quality.md`);
506
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} .bootspring/audit/reports/security.md`);
507
+ console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} .bootspring/audit/reports/tech-debt.md`);
508
+ }
509
+
510
+ console.log('');
511
+ utils.print.info('Review the detailed report for remediation steps.');
512
+
513
+ // CI mode exit code
514
+ if (args?.ci) {
515
+ const exitCode = workflow.getExitCode();
516
+ process.exitCode = exitCode;
517
+ console.log('');
518
+ console.log(`CI exit code: ${exitCode}`);
519
+ }
520
+ }
521
+
522
+ /**
523
+ * Show audit status
524
+ */
525
+ async function auditStatus(): Promise<void> {
526
+ const workflow = new AuditWorkflowEngine(projectRoot);
527
+
528
+ if (!workflow.hasWorkflow()) {
529
+ utils.print.info('No audit workflow started.');
530
+ utils.print.info('Run "bootspring audit" to begin.');
531
+ return;
532
+ }
533
+
534
+ workflow.loadState();
535
+ const progress = workflow.getProgress();
536
+
537
+ utils.print.header('Audit Status');
538
+
539
+ // Overall progress
540
+ console.log(`Progress: ${progress.overall.percentage}% complete`);
541
+ console.log(`Started: ${progress.startedAt ? new Date(progress.startedAt).toLocaleString() : 'N/A'}`);
542
+ console.log(`Last updated: ${progress.lastUpdated ? utils.formatRelativeTime(new Date(progress.lastUpdated)) : 'N/A'}`);
543
+ console.log('');
544
+
545
+ // Phase status
546
+ console.log('Phases:');
547
+ for (const phase of progress.phases) {
548
+ const statusIcon = getStatusIcon(phase.status);
549
+ const required = phase.required ? '' : ' (optional)';
550
+ console.log(` ${statusIcon} ${phase.name}${required}`);
551
+ }
552
+
553
+ // Findings summary
554
+ if (progress.findings.total > 0) {
555
+ console.log('');
556
+ console.log('Findings so far:');
557
+ console.log(` Critical: ${progress.findings.critical}`);
558
+ console.log(` High: ${progress.findings.high}`);
559
+ console.log(` Medium: ${progress.findings.medium}`);
560
+ console.log(` Low: ${progress.findings.low}`);
561
+ }
562
+
563
+ if (progress.summary?.reportPath) {
564
+ console.log('');
565
+ console.log(`Report: ${progress.summary.reportPath}`);
566
+ }
567
+
568
+ if (!progress.isComplete) {
569
+ console.log('');
570
+ utils.print.info('Run "bootspring audit resume" to continue');
571
+ }
572
+ }
573
+
574
+ /**
575
+ * Run specific phase
576
+ */
577
+ async function auditPhase(args: ParsedArgs): Promise<void> {
578
+ const phaseId = args.phase;
579
+
580
+ if (!phaseId || !AUDIT_PHASES[phaseId]) {
581
+ utils.print.error(`Unknown phase: ${phaseId}`);
582
+ console.log('');
583
+ console.log('Available phases:');
584
+ for (const [id, phase] of Object.entries(AUDIT_PHASES)) {
585
+ console.log(` ${id}: ${phase.description}`);
586
+ }
587
+ return;
588
+ }
589
+
590
+ const workflow = new AuditWorkflowEngine(projectRoot);
591
+
592
+ if (!workflow.hasWorkflow()) {
593
+ workflow.initializeWorkflow();
594
+ } else {
595
+ workflow.loadState();
596
+ }
597
+
598
+ const phase = AUDIT_PHASES[phaseId];
599
+ if (!phase) return;
600
+
601
+ const spinner = utils.createSpinner(`Running: ${phase.name}`).start();
602
+
603
+ try {
604
+ let result: unknown;
605
+
606
+ switch (phaseId) {
607
+ case 'quality':
608
+ result = await workflow.runQualityMetrics();
609
+ break;
610
+ case 'security':
611
+ result = await workflow.runSecurityScan();
612
+ break;
613
+ case 'performance':
614
+ result = await workflow.runPerformanceAnalysis();
615
+ break;
616
+ case 'practices':
617
+ result = await workflow.runBestPractices();
618
+ break;
619
+ case 'techDebt':
620
+ result = await workflow.runTechDebtInventory();
621
+ break;
622
+ case 'recommendations':
623
+ result = await workflow.runRecommendations();
624
+ break;
625
+ }
626
+
627
+ spinner.succeed(`${phase.name} complete`);
628
+ console.log('');
629
+ console.log('Result:', JSON.stringify(result, null, 2));
630
+
631
+ // Show findings for this phase
632
+ const progress = workflow.getProgress();
633
+ if (progress.findings.total > 0) {
634
+ console.log('');
635
+ console.log(`Findings: ${progress.findings.total}`);
636
+ }
637
+
638
+ } catch (error) {
639
+ spinner.fail(`Failed: ${(error as Error).message}`);
640
+ }
641
+ }
642
+
643
+ /**
644
+ * Reset audit workflow
645
+ */
646
+ async function auditReset(): Promise<void> {
647
+ const workflow = new AuditWorkflowEngine(projectRoot);
648
+
649
+ if (!workflow.hasWorkflow()) {
650
+ utils.print.info('No workflow to reset.');
651
+ return;
652
+ }
653
+
654
+ workflow.resetWorkflow();
655
+ utils.print.success('Audit workflow reset.');
656
+ }
657
+
658
+ /**
659
+ * Get status icon
660
+ */
661
+ function getStatusIcon(status: string): string {
662
+ switch (status) {
663
+ case 'completed':
664
+ return `${utils.COLORS.green}✓${utils.COLORS.reset}`;
665
+ case 'in_progress':
666
+ return `${utils.COLORS.cyan}●${utils.COLORS.reset}`;
667
+ case 'failed':
668
+ return `${utils.COLORS.red}✗${utils.COLORS.reset}`;
669
+ case 'skipped':
670
+ return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
671
+ default:
672
+ return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
673
+ }
674
+ }
675
+
676
+ /**
677
+ * Main entry point
678
+ */
679
+ export async function run(args: string[]): Promise<void> {
680
+ const parsedArgs = utils.parseArgs(args) as ParsedArgs;
681
+ const subcommand = parsedArgs._[0];
682
+
683
+ // Handle --phase flag
684
+ if (parsedArgs.phase) {
685
+ return auditPhase(parsedArgs);
686
+ }
687
+
688
+ switch (subcommand) {
689
+ case 'status':
690
+ return auditStatus();
691
+
692
+ case 'resume':
693
+ return auditResume(parsedArgs);
694
+
695
+ case 'reset':
696
+ return auditReset();
697
+
698
+ case 'help':
699
+ case '--help':
700
+ case '-h':
701
+ return showHelp();
702
+
703
+ default:
704
+ // Start audit
705
+ return auditStart(parsedArgs);
706
+ }
707
+ }