@girardmedia/bootspring 2.0.21 → 2.0.22
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.
- package/cli/preseed/index.js +16 -0
- package/cli/preseed/interactive.js +143 -0
- package/cli/preseed/templates.js +227 -0
- package/cli/seed/builders/ai-context-builder.js +85 -0
- package/cli/seed/builders/index.js +13 -0
- package/cli/seed/builders/seed-builder.js +272 -0
- package/cli/seed/extractors/content-extractors.js +383 -0
- package/cli/seed/extractors/index.js +47 -0
- package/cli/seed/extractors/metadata-extractors.js +167 -0
- package/cli/seed/extractors/section-extractor.js +54 -0
- package/cli/seed/extractors/stack-extractors.js +228 -0
- package/cli/seed/index.js +18 -0
- package/cli/seed/utils/folder-structure.js +84 -0
- package/cli/seed/utils/index.js +11 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +3220 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/context-McpJQa_2.d.ts +5710 -0
- package/dist/core/index.d.ts +635 -0
- package/dist/core/index.js +2593 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index-QqbeEiDm.d.ts +857 -0
- package/dist/index-UiYCgwiH.d.ts +174 -0
- package/dist/index.d.ts +453 -0
- package/dist/index.js +44228 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +41173 -0
- package/dist/mcp/index.js.map +1 -0
- package/generators/index.ts +82 -0
- package/intelligence/orchestrator/config/failure-signatures.js +48 -0
- package/intelligence/orchestrator/config/index.js +20 -0
- package/intelligence/orchestrator/config/phases.js +111 -0
- package/intelligence/orchestrator/config/remediation.js +150 -0
- package/intelligence/orchestrator/config/workflows.js +168 -0
- package/intelligence/orchestrator/core/index.js +16 -0
- package/intelligence/orchestrator/core/state-manager.js +88 -0
- package/intelligence/orchestrator/core/telemetry.js +24 -0
- package/intelligence/orchestrator/index.js +17 -0
- package/mcp/contracts/mcp-contract.v1.json +1 -1
- package/package.json +16 -3
- package/src/cli/agent.ts +703 -0
- package/src/cli/analyze.ts +640 -0
- package/src/cli/audit.ts +707 -0
- package/src/cli/auth.ts +930 -0
- package/src/cli/billing.ts +364 -0
- package/src/cli/build.ts +1089 -0
- package/src/cli/business.ts +508 -0
- package/src/cli/checkpoint-utils.ts +236 -0
- package/src/cli/checkpoint.ts +757 -0
- package/src/cli/cloud-sync.ts +534 -0
- package/src/cli/content.ts +273 -0
- package/src/cli/context.ts +667 -0
- package/src/cli/dashboard.ts +133 -0
- package/src/cli/deploy.ts +704 -0
- package/src/cli/doctor.ts +480 -0
- package/src/cli/fundraise.ts +494 -0
- package/src/cli/generate.ts +346 -0
- package/src/cli/github-cmd.ts +566 -0
- package/src/cli/health.ts +599 -0
- package/src/cli/index.ts +113 -0
- package/src/cli/init.ts +838 -0
- package/src/cli/legal.ts +495 -0
- package/src/cli/log.ts +316 -0
- package/src/cli/loop.ts +1660 -0
- package/src/cli/manager.ts +878 -0
- package/src/cli/mcp.ts +275 -0
- package/src/cli/memory.ts +346 -0
- package/src/cli/metrics.ts +590 -0
- package/src/cli/monitor.ts +960 -0
- package/src/cli/mvp.ts +662 -0
- package/src/cli/onboard.ts +663 -0
- package/src/cli/orchestrator.ts +622 -0
- package/src/cli/plugin.ts +483 -0
- package/src/cli/prd.ts +671 -0
- package/src/cli/preseed-start.ts +1633 -0
- package/src/cli/preseed.ts +2434 -0
- package/src/cli/project.ts +526 -0
- package/src/cli/quality.ts +885 -0
- package/src/cli/security.ts +1079 -0
- package/src/cli/seed.ts +1224 -0
- package/src/cli/skill.ts +537 -0
- package/src/cli/suggest.ts +1225 -0
- package/src/cli/switch.ts +518 -0
- package/src/cli/task.ts +780 -0
- package/src/cli/telemetry.ts +172 -0
- package/src/cli/todo.ts +627 -0
- package/src/cli/types.ts +15 -0
- package/src/cli/update.ts +334 -0
- package/src/cli/visualize.ts +609 -0
- package/src/cli/watch.ts +895 -0
- package/src/cli/workspace.ts +709 -0
- package/src/core/action-recorder.ts +673 -0
- package/src/core/analyze-workflow.ts +1453 -0
- package/src/core/api-client.ts +1120 -0
- package/src/core/audit-workflow.ts +1681 -0
- package/src/core/auth.ts +471 -0
- package/src/core/build-orchestrator.ts +509 -0
- package/src/core/build-state.ts +621 -0
- package/src/core/checkpoint-engine.ts +482 -0
- package/src/core/config.ts +1285 -0
- package/src/core/context-loader.ts +694 -0
- package/src/core/context.ts +410 -0
- package/src/core/deploy-workflow.ts +1085 -0
- package/src/core/entitlements.ts +322 -0
- package/src/core/github-sync.ts +720 -0
- package/src/core/index.ts +981 -0
- package/src/core/ingest.ts +1186 -0
- package/src/core/metrics-engine.ts +886 -0
- package/src/core/mvp.ts +847 -0
- package/src/core/onboard-workflow.ts +1293 -0
- package/src/core/policies.ts +81 -0
- package/src/core/preseed-workflow.ts +1163 -0
- package/src/core/preseed.ts +1826 -0
- package/src/core/project-context.ts +380 -0
- package/src/core/project-state.ts +699 -0
- package/src/core/r2-sync.ts +691 -0
- package/src/core/scaffold.ts +1715 -0
- package/src/core/session.ts +286 -0
- package/src/core/task-extractor.ts +799 -0
- package/src/core/telemetry.ts +371 -0
- package/src/core/tier-enforcement.ts +737 -0
- package/src/core/utils.ts +437 -0
- package/src/index.ts +29 -0
- package/src/intelligence/agent-collab.ts +2376 -0
- package/src/intelligence/auto-suggest.ts +713 -0
- package/src/intelligence/content-gen.ts +1351 -0
- package/src/intelligence/cross-project.ts +1692 -0
- package/src/intelligence/git-memory.ts +529 -0
- package/src/intelligence/index.ts +318 -0
- package/src/intelligence/orchestrator.ts +534 -0
- package/src/intelligence/prd.ts +466 -0
- package/src/intelligence/recommendations.ts +982 -0
- package/src/intelligence/workflow-composer.ts +1472 -0
- package/src/mcp/capabilities.ts +233 -0
- package/src/mcp/index.ts +37 -0
- package/src/mcp/registry.ts +1268 -0
- package/src/mcp/response-formatter.ts +797 -0
- package/src/mcp/server.ts +240 -0
- package/src/types/agent.ts +69 -0
- package/src/types/config.ts +86 -0
- package/src/types/context.ts +77 -0
- package/src/types/index.ts +53 -0
- package/src/types/mcp.ts +91 -0
- package/src/types/skills.ts +47 -0
- package/src/types/workflow.ts +155 -0
- package/generators/index.js +0 -18
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootspring Analyze CLI
|
|
3
|
+
*
|
|
4
|
+
* Deep codebase analysis for understanding architecture,
|
|
5
|
+
* dependencies, patterns, and code flows.
|
|
6
|
+
*
|
|
7
|
+
* @package bootspring
|
|
8
|
+
* @module cli/analyze
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Import JS modules with type interfaces
|
|
12
|
+
interface ParsedArgs {
|
|
13
|
+
_: string[];
|
|
14
|
+
depth?: string | undefined;
|
|
15
|
+
phase?: string | undefined;
|
|
16
|
+
include?: string | undefined;
|
|
17
|
+
exclude?: string | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface AnalysisDepthConfig {
|
|
21
|
+
description: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface PhaseConfig {
|
|
25
|
+
name: string;
|
|
26
|
+
description: string;
|
|
27
|
+
required: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface StructureResult {
|
|
31
|
+
totalFiles: number;
|
|
32
|
+
totalDirs: number;
|
|
33
|
+
structureType?: { pattern: string } | undefined;
|
|
34
|
+
keyDirectories: string[];
|
|
35
|
+
entryPoints: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface ArchitectureResult {
|
|
39
|
+
patterns: Array<{ name: string; confidence: number }>;
|
|
40
|
+
layers: string[];
|
|
41
|
+
modules: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface DependencyResult {
|
|
45
|
+
skipped?: boolean | undefined;
|
|
46
|
+
fileCount: number;
|
|
47
|
+
circularCount: number;
|
|
48
|
+
unusedCount: number;
|
|
49
|
+
externalPackages: number;
|
|
50
|
+
mostImported: Array<{ file: string; importCount: number }>;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface PatternResult {
|
|
54
|
+
designPatterns: number;
|
|
55
|
+
antiPatterns: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface FlowResult {
|
|
59
|
+
entryPoints: number;
|
|
60
|
+
apiEndpoints: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
interface ComponentResult {
|
|
64
|
+
total: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface ReportResult {
|
|
68
|
+
reportPath: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface OverallProgress {
|
|
72
|
+
completed: number;
|
|
73
|
+
total: number;
|
|
74
|
+
percentage: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface PhaseProgress {
|
|
78
|
+
name: string;
|
|
79
|
+
status: string;
|
|
80
|
+
required: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface WorkflowProgress {
|
|
84
|
+
overall: OverallProgress;
|
|
85
|
+
isComplete: boolean;
|
|
86
|
+
currentPhase?: string | undefined;
|
|
87
|
+
depth: string;
|
|
88
|
+
phases: PhaseProgress[];
|
|
89
|
+
startedAt?: string | undefined;
|
|
90
|
+
lastUpdated?: string | undefined;
|
|
91
|
+
summary?: {
|
|
92
|
+
reportPath?: string | undefined;
|
|
93
|
+
} | undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface ResumePoint {
|
|
97
|
+
phaseName: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface AnalyzeWorkflowEngineClass {
|
|
101
|
+
new (projectRoot: string, options?: { depth?: string | undefined }): AnalyzeWorkflowEngine;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface AnalyzeWorkflowEngine {
|
|
105
|
+
hasWorkflow(): boolean;
|
|
106
|
+
loadState(): void;
|
|
107
|
+
initializeWorkflow(depth: string): void;
|
|
108
|
+
getProgress(): WorkflowProgress;
|
|
109
|
+
getResumePoint(): ResumePoint | null;
|
|
110
|
+
getNextPhase(): string | null;
|
|
111
|
+
startPhase(phaseId: string): void;
|
|
112
|
+
completePhase(phaseId: string, result: unknown): void;
|
|
113
|
+
failPhase(phaseId: string, error: string): void;
|
|
114
|
+
skipPhase(phaseId: string): void;
|
|
115
|
+
resetWorkflow(): void;
|
|
116
|
+
runStructureMapping(): Promise<StructureResult>;
|
|
117
|
+
runArchitectureAnalysis(): Promise<ArchitectureResult>;
|
|
118
|
+
runDependencyAnalysis(): Promise<DependencyResult>;
|
|
119
|
+
runPatternDetection(): Promise<PatternResult>;
|
|
120
|
+
runFlowTracing(): Promise<FlowResult>;
|
|
121
|
+
runComponentAnalysis(): Promise<ComponentResult>;
|
|
122
|
+
runReportGeneration(): Promise<ReportResult>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
interface AnalyzeWorkflowModule {
|
|
126
|
+
AnalyzeWorkflowEngine: AnalyzeWorkflowEngineClass;
|
|
127
|
+
ANALYZE_PHASES: Record<string, PhaseConfig>;
|
|
128
|
+
ANALYSIS_DEPTH: Record<string, AnalysisDepthConfig>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
132
|
+
const utils = require('../../core/utils') as typeof import('../core/utils');
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
134
|
+
const analyzeWorkflowModule = require('../../core/analyze-workflow') as AnalyzeWorkflowModule;
|
|
135
|
+
|
|
136
|
+
const { AnalyzeWorkflowEngine, ANALYZE_PHASES, ANALYSIS_DEPTH } = analyzeWorkflowModule;
|
|
137
|
+
|
|
138
|
+
// Get project root
|
|
139
|
+
const projectRoot = process.cwd();
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Show analyze help
|
|
143
|
+
*/
|
|
144
|
+
function showHelp(): void {
|
|
145
|
+
console.log(`
|
|
146
|
+
${utils.COLORS.bold}Bootspring Analyze${utils.COLORS.reset}
|
|
147
|
+
Deep codebase analysis for understanding
|
|
148
|
+
|
|
149
|
+
${utils.COLORS.bold}Usage:${utils.COLORS.reset}
|
|
150
|
+
bootspring analyze Full analysis
|
|
151
|
+
bootspring analyze status Show progress
|
|
152
|
+
bootspring analyze resume Continue from checkpoint
|
|
153
|
+
bootspring analyze reset Reset workflow
|
|
154
|
+
|
|
155
|
+
${utils.COLORS.bold}Options:${utils.COLORS.reset}
|
|
156
|
+
--depth=<level> Analysis depth: shallow, standard, deep
|
|
157
|
+
--phase=<phase> Run specific phase only
|
|
158
|
+
--include=<glob> Include pattern (e.g., "src/**")
|
|
159
|
+
--exclude=<glob> Exclude pattern
|
|
160
|
+
|
|
161
|
+
${utils.COLORS.bold}Depth Levels:${utils.COLORS.reset}
|
|
162
|
+
shallow Quick scan - structure and architecture only
|
|
163
|
+
standard Standard analysis with patterns and dependencies
|
|
164
|
+
deep Comprehensive with flow tracing and components
|
|
165
|
+
|
|
166
|
+
${utils.COLORS.bold}Notes:${utils.COLORS.reset}
|
|
167
|
+
Large codebases (500+ files) automatically skip heavy dependency
|
|
168
|
+
analysis for performance. Use --depth=deep to force full analysis.
|
|
169
|
+
|
|
170
|
+
${utils.COLORS.bold}Examples:${utils.COLORS.reset}
|
|
171
|
+
bootspring analyze Auto-adjusts for codebase size
|
|
172
|
+
bootspring analyze --depth=shallow
|
|
173
|
+
bootspring analyze --depth=deep
|
|
174
|
+
bootspring analyze status
|
|
175
|
+
`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Start analysis workflow
|
|
180
|
+
*/
|
|
181
|
+
async function analyzeStart(args: ParsedArgs): Promise<void> {
|
|
182
|
+
const depth = args.depth || 'standard';
|
|
183
|
+
|
|
184
|
+
if (!ANALYSIS_DEPTH[depth]) {
|
|
185
|
+
utils.print.error(`Unknown depth level: ${depth}`);
|
|
186
|
+
utils.print.info('Valid options: shallow, standard, deep');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const workflow = new AnalyzeWorkflowEngine(projectRoot, { depth });
|
|
191
|
+
|
|
192
|
+
// Check for existing workflow
|
|
193
|
+
if (workflow.hasWorkflow()) {
|
|
194
|
+
workflow.loadState();
|
|
195
|
+
const progress = workflow.getProgress();
|
|
196
|
+
|
|
197
|
+
if (!progress.isComplete) {
|
|
198
|
+
utils.print.info('Existing analysis workflow found.');
|
|
199
|
+
console.log(` Progress: ${progress.overall.percentage}% complete`);
|
|
200
|
+
console.log(` Current phase: ${progress.currentPhase || 'none'}`);
|
|
201
|
+
console.log('');
|
|
202
|
+
utils.print.info('Use "bootspring analyze resume" to continue');
|
|
203
|
+
utils.print.info('Use "bootspring analyze reset" to start fresh');
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Initialize new workflow
|
|
209
|
+
utils.print.header('Codebase Analysis');
|
|
210
|
+
const depthConfig = ANALYSIS_DEPTH[depth];
|
|
211
|
+
console.log(`Analysis depth: ${depth} (${depthConfig?.description || 'unknown'})`);
|
|
212
|
+
console.log('');
|
|
213
|
+
|
|
214
|
+
workflow.initializeWorkflow(depth);
|
|
215
|
+
|
|
216
|
+
// Run workflow
|
|
217
|
+
await runWorkflowLoop(workflow);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Resume analysis workflow
|
|
222
|
+
*/
|
|
223
|
+
async function analyzeResume(): Promise<void> {
|
|
224
|
+
const workflow = new AnalyzeWorkflowEngine(projectRoot);
|
|
225
|
+
|
|
226
|
+
if (!workflow.hasWorkflow()) {
|
|
227
|
+
utils.print.error('No existing workflow found.');
|
|
228
|
+
utils.print.info('Run "bootspring analyze" to start.');
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
workflow.loadState();
|
|
233
|
+
const resumePoint = workflow.getResumePoint();
|
|
234
|
+
|
|
235
|
+
if (!resumePoint) {
|
|
236
|
+
utils.print.success('Analysis workflow already complete!');
|
|
237
|
+
displayCompletionSummary(workflow);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
utils.print.header('Resuming Analysis');
|
|
242
|
+
console.log(`Continuing from: ${resumePoint.phaseName}`);
|
|
243
|
+
console.log('');
|
|
244
|
+
|
|
245
|
+
await runWorkflowLoop(workflow);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Run the workflow loop
|
|
250
|
+
*/
|
|
251
|
+
async function runWorkflowLoop(workflow: AnalyzeWorkflowEngine): Promise<void> {
|
|
252
|
+
while (true) {
|
|
253
|
+
const nextPhaseId = workflow.getNextPhase();
|
|
254
|
+
|
|
255
|
+
if (!nextPhaseId) {
|
|
256
|
+
// Workflow complete
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const phase = ANALYZE_PHASES[nextPhaseId];
|
|
261
|
+
if (!phase) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Run the phase
|
|
266
|
+
workflow.startPhase(nextPhaseId);
|
|
267
|
+
const spinner = utils.createSpinner(`Running: ${phase.name}`).start();
|
|
268
|
+
|
|
269
|
+
try {
|
|
270
|
+
let result: unknown;
|
|
271
|
+
|
|
272
|
+
switch (nextPhaseId) {
|
|
273
|
+
case 'structure': {
|
|
274
|
+
const structureResult = await workflow.runStructureMapping();
|
|
275
|
+
spinner.succeed(`Structure mapped: ${structureResult.totalFiles} files, ${structureResult.totalDirs} directories`);
|
|
276
|
+
displayStructureResults(structureResult);
|
|
277
|
+
result = structureResult;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
case 'architecture': {
|
|
282
|
+
const archResult = await workflow.runArchitectureAnalysis();
|
|
283
|
+
spinner.succeed(`Architecture analyzed: ${archResult.patterns.length} patterns found`);
|
|
284
|
+
displayArchitectureResults(archResult);
|
|
285
|
+
result = archResult;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
case 'dependencies': {
|
|
290
|
+
const depResult = await workflow.runDependencyAnalysis();
|
|
291
|
+
if (depResult.skipped) {
|
|
292
|
+
spinner.succeed(`Dependencies skipped: Large codebase (${depResult.fileCount} files)`);
|
|
293
|
+
console.log('');
|
|
294
|
+
console.log(` ${utils.COLORS.dim}Use --depth=deep to force full analysis${utils.COLORS.reset}`);
|
|
295
|
+
} else {
|
|
296
|
+
spinner.succeed(`Dependencies analyzed: ${depResult.fileCount} files`);
|
|
297
|
+
displayDependencyResults(depResult);
|
|
298
|
+
}
|
|
299
|
+
result = depResult;
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
case 'patterns': {
|
|
304
|
+
const patternResult = await workflow.runPatternDetection();
|
|
305
|
+
spinner.succeed('Pattern detection complete');
|
|
306
|
+
displayPatternResults(patternResult);
|
|
307
|
+
result = patternResult;
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
case 'flows': {
|
|
312
|
+
const flowResult = await workflow.runFlowTracing();
|
|
313
|
+
spinner.succeed(`Flow tracing complete: ${flowResult.entryPoints} entry points, ${flowResult.apiEndpoints} API endpoints`);
|
|
314
|
+
result = flowResult;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
case 'components': {
|
|
319
|
+
const componentResult = await workflow.runComponentAnalysis();
|
|
320
|
+
spinner.succeed(`Component analysis complete: ${componentResult.total} components`);
|
|
321
|
+
result = componentResult;
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
case 'report': {
|
|
326
|
+
const reportResult = await workflow.runReportGeneration();
|
|
327
|
+
spinner.succeed('Report generated');
|
|
328
|
+
displayReportResults(reportResult);
|
|
329
|
+
result = reportResult;
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
default:
|
|
334
|
+
spinner.warn(`Unknown phase: ${nextPhaseId}`);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
workflow.completePhase(nextPhaseId, result);
|
|
339
|
+
|
|
340
|
+
} catch (error) {
|
|
341
|
+
spinner.fail(`Failed: ${(error as Error).message}`);
|
|
342
|
+
workflow.failPhase(nextPhaseId, (error as Error).message);
|
|
343
|
+
|
|
344
|
+
if (phase.required) {
|
|
345
|
+
utils.print.error('Required phase failed. Cannot continue.');
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
console.log('');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Workflow complete
|
|
354
|
+
displayCompletionSummary(workflow);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Display structure results
|
|
359
|
+
*/
|
|
360
|
+
function displayStructureResults(result: StructureResult): void {
|
|
361
|
+
console.log('');
|
|
362
|
+
console.log(` ${utils.COLORS.cyan}Structure:${utils.COLORS.reset} ${result.structureType?.pattern || 'flat'}`);
|
|
363
|
+
|
|
364
|
+
if (result.keyDirectories.length > 0) {
|
|
365
|
+
console.log(` ${utils.COLORS.cyan}Key dirs:${utils.COLORS.reset} ${result.keyDirectories.slice(0, 5).join(', ')}`);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (result.entryPoints > 0) {
|
|
369
|
+
console.log(` ${utils.COLORS.cyan}Entry points:${utils.COLORS.reset} ${result.entryPoints}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Display architecture results
|
|
375
|
+
*/
|
|
376
|
+
function displayArchitectureResults(result: ArchitectureResult): void {
|
|
377
|
+
if (result.patterns.length > 0) {
|
|
378
|
+
console.log('');
|
|
379
|
+
console.log(' Detected patterns:');
|
|
380
|
+
for (const pattern of result.patterns.slice(0, 3)) {
|
|
381
|
+
console.log(` - ${pattern.name} (${pattern.confidence}%)`);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (result.layers.length > 0) {
|
|
386
|
+
console.log('');
|
|
387
|
+
console.log(` ${utils.COLORS.cyan}Layers:${utils.COLORS.reset} ${result.layers.join(', ')}`);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (result.modules > 0) {
|
|
391
|
+
console.log(` ${utils.COLORS.cyan}Modules:${utils.COLORS.reset} ${result.modules}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Display dependency results
|
|
397
|
+
*/
|
|
398
|
+
function displayDependencyResults(result: DependencyResult): void {
|
|
399
|
+
console.log('');
|
|
400
|
+
|
|
401
|
+
if (result.circularCount > 0) {
|
|
402
|
+
console.log(` ${utils.COLORS.yellow}⚠${utils.COLORS.reset} Circular dependencies: ${result.circularCount}`);
|
|
403
|
+
} else {
|
|
404
|
+
console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} No circular dependencies`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (result.unusedCount > 0) {
|
|
408
|
+
console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} Potentially unused packages: ${result.unusedCount}`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
console.log(` ${utils.COLORS.cyan}External packages:${utils.COLORS.reset} ${result.externalPackages}`);
|
|
412
|
+
|
|
413
|
+
if (result.mostImported.length > 0) {
|
|
414
|
+
console.log('');
|
|
415
|
+
console.log(' Most imported files:');
|
|
416
|
+
for (const file of result.mostImported.slice(0, 3)) {
|
|
417
|
+
console.log(` - ${file.file} (${file.importCount} imports)`);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Display pattern results
|
|
424
|
+
*/
|
|
425
|
+
function displayPatternResults(result: PatternResult): void {
|
|
426
|
+
console.log('');
|
|
427
|
+
console.log(` ${utils.COLORS.cyan}Design patterns:${utils.COLORS.reset} ${result.designPatterns}`);
|
|
428
|
+
console.log(` ${utils.COLORS.cyan}Anti-patterns:${utils.COLORS.reset} ${result.antiPatterns}`);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Display report results
|
|
433
|
+
*/
|
|
434
|
+
function displayReportResults(result: ReportResult): void {
|
|
435
|
+
console.log('');
|
|
436
|
+
utils.print.success(`Report saved to: ${result.reportPath}`);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Display completion summary
|
|
441
|
+
*/
|
|
442
|
+
function displayCompletionSummary(workflow: AnalyzeWorkflowEngine): void {
|
|
443
|
+
const progress = workflow.getProgress();
|
|
444
|
+
|
|
445
|
+
console.log('');
|
|
446
|
+
utils.print.success('Analysis complete!');
|
|
447
|
+
console.log('');
|
|
448
|
+
|
|
449
|
+
// Show summary
|
|
450
|
+
utils.print.header('Summary');
|
|
451
|
+
console.log(` Phases completed: ${progress.overall.completed}/${progress.overall.total}`);
|
|
452
|
+
console.log(` Depth: ${progress.depth}`);
|
|
453
|
+
|
|
454
|
+
if (progress.summary?.reportPath) {
|
|
455
|
+
console.log('');
|
|
456
|
+
console.log(' Reports generated:');
|
|
457
|
+
console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${progress.summary.reportPath}`);
|
|
458
|
+
console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} .bootspring/analyze/reports/architecture.md`);
|
|
459
|
+
console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} .bootspring/analyze/reports/dependencies.md`);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
console.log('');
|
|
463
|
+
utils.print.info('Next steps:');
|
|
464
|
+
console.log(' 1. Review the analysis report');
|
|
465
|
+
console.log(' 2. Run "bootspring audit" for quality & security checks');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Show analysis status
|
|
470
|
+
*/
|
|
471
|
+
async function analyzeStatus(): Promise<void> {
|
|
472
|
+
const workflow = new AnalyzeWorkflowEngine(projectRoot);
|
|
473
|
+
|
|
474
|
+
if (!workflow.hasWorkflow()) {
|
|
475
|
+
utils.print.info('No analysis workflow started.');
|
|
476
|
+
utils.print.info('Run "bootspring analyze" to begin.');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
workflow.loadState();
|
|
481
|
+
const progress = workflow.getProgress();
|
|
482
|
+
|
|
483
|
+
utils.print.header('Analysis Status');
|
|
484
|
+
|
|
485
|
+
// Overall progress
|
|
486
|
+
console.log(`Progress: ${progress.overall.percentage}% complete`);
|
|
487
|
+
console.log(`Depth: ${progress.depth}`);
|
|
488
|
+
console.log(`Started: ${progress.startedAt ? new Date(progress.startedAt).toLocaleString() : 'N/A'}`);
|
|
489
|
+
console.log(`Last updated: ${progress.lastUpdated ? utils.formatRelativeTime(new Date(progress.lastUpdated)) : 'N/A'}`);
|
|
490
|
+
console.log('');
|
|
491
|
+
|
|
492
|
+
// Phase status
|
|
493
|
+
console.log('Phases:');
|
|
494
|
+
for (const phase of progress.phases) {
|
|
495
|
+
const statusIcon = getStatusIcon(phase.status);
|
|
496
|
+
const required = phase.required ? '' : ' (optional)';
|
|
497
|
+
console.log(` ${statusIcon} ${phase.name}${required}`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (progress.summary?.reportPath) {
|
|
501
|
+
console.log('');
|
|
502
|
+
console.log(`Report: ${progress.summary.reportPath}`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (!progress.isComplete) {
|
|
506
|
+
console.log('');
|
|
507
|
+
utils.print.info('Run "bootspring analyze resume" to continue');
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Run specific phase
|
|
513
|
+
*/
|
|
514
|
+
async function analyzePhase(args: ParsedArgs): Promise<void> {
|
|
515
|
+
const phaseId = args.phase;
|
|
516
|
+
|
|
517
|
+
if (!phaseId || !ANALYZE_PHASES[phaseId]) {
|
|
518
|
+
utils.print.error(`Unknown phase: ${phaseId}`);
|
|
519
|
+
console.log('');
|
|
520
|
+
console.log('Available phases:');
|
|
521
|
+
for (const [id, phase] of Object.entries(ANALYZE_PHASES)) {
|
|
522
|
+
console.log(` ${id}: ${phase.description}`);
|
|
523
|
+
}
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const workflow = new AnalyzeWorkflowEngine(projectRoot);
|
|
528
|
+
|
|
529
|
+
if (!workflow.hasWorkflow()) {
|
|
530
|
+
workflow.initializeWorkflow('standard');
|
|
531
|
+
} else {
|
|
532
|
+
workflow.loadState();
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const phase = ANALYZE_PHASES[phaseId];
|
|
536
|
+
if (!phase) return;
|
|
537
|
+
|
|
538
|
+
const spinner = utils.createSpinner(`Running: ${phase.name}`).start();
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
let result: unknown;
|
|
542
|
+
|
|
543
|
+
switch (phaseId) {
|
|
544
|
+
case 'structure':
|
|
545
|
+
result = await workflow.runStructureMapping();
|
|
546
|
+
break;
|
|
547
|
+
case 'architecture':
|
|
548
|
+
result = await workflow.runArchitectureAnalysis();
|
|
549
|
+
break;
|
|
550
|
+
case 'dependencies':
|
|
551
|
+
result = await workflow.runDependencyAnalysis();
|
|
552
|
+
break;
|
|
553
|
+
case 'patterns':
|
|
554
|
+
result = await workflow.runPatternDetection();
|
|
555
|
+
break;
|
|
556
|
+
case 'flows':
|
|
557
|
+
result = await workflow.runFlowTracing();
|
|
558
|
+
break;
|
|
559
|
+
case 'components':
|
|
560
|
+
result = await workflow.runComponentAnalysis();
|
|
561
|
+
break;
|
|
562
|
+
case 'report':
|
|
563
|
+
result = await workflow.runReportGeneration();
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
spinner.succeed(`${phase.name} complete`);
|
|
568
|
+
console.log('');
|
|
569
|
+
console.log('Result:', JSON.stringify(result, null, 2));
|
|
570
|
+
|
|
571
|
+
} catch (error) {
|
|
572
|
+
spinner.fail(`Failed: ${(error as Error).message}`);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* Reset analysis workflow
|
|
578
|
+
*/
|
|
579
|
+
async function analyzeReset(): Promise<void> {
|
|
580
|
+
const workflow = new AnalyzeWorkflowEngine(projectRoot);
|
|
581
|
+
|
|
582
|
+
if (!workflow.hasWorkflow()) {
|
|
583
|
+
utils.print.info('No workflow to reset.');
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
workflow.resetWorkflow();
|
|
588
|
+
utils.print.success('Analysis workflow reset.');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Get status icon
|
|
593
|
+
*/
|
|
594
|
+
function getStatusIcon(status: string): string {
|
|
595
|
+
switch (status) {
|
|
596
|
+
case 'completed':
|
|
597
|
+
return `${utils.COLORS.green}✓${utils.COLORS.reset}`;
|
|
598
|
+
case 'in_progress':
|
|
599
|
+
return `${utils.COLORS.cyan}●${utils.COLORS.reset}`;
|
|
600
|
+
case 'failed':
|
|
601
|
+
return `${utils.COLORS.red}✗${utils.COLORS.reset}`;
|
|
602
|
+
case 'skipped':
|
|
603
|
+
return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
604
|
+
default:
|
|
605
|
+
return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Main entry point
|
|
611
|
+
*/
|
|
612
|
+
export async function run(args: string[]): Promise<void> {
|
|
613
|
+
const parsedArgs = utils.parseArgs(args) as ParsedArgs;
|
|
614
|
+
const subcommand = parsedArgs._[0];
|
|
615
|
+
|
|
616
|
+
// Handle --phase flag
|
|
617
|
+
if (parsedArgs.phase) {
|
|
618
|
+
return analyzePhase(parsedArgs);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
switch (subcommand) {
|
|
622
|
+
case 'status':
|
|
623
|
+
return analyzeStatus();
|
|
624
|
+
|
|
625
|
+
case 'resume':
|
|
626
|
+
return analyzeResume();
|
|
627
|
+
|
|
628
|
+
case 'reset':
|
|
629
|
+
return analyzeReset();
|
|
630
|
+
|
|
631
|
+
case 'help':
|
|
632
|
+
case '--help':
|
|
633
|
+
case '-h':
|
|
634
|
+
return showHelp();
|
|
635
|
+
|
|
636
|
+
default:
|
|
637
|
+
// Start analysis
|
|
638
|
+
return analyzeStart(parsedArgs);
|
|
639
|
+
}
|
|
640
|
+
}
|