@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.
- package/bin/bootspring.js +5 -0
- package/cli/org.js +474 -0
- package/cli/preseed/index.js +16 -0
- package/cli/preseed/interactive.js +143 -0
- package/cli/preseed/templates.js +227 -0
- package/cli/preseed.js +9 -301
- 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/cli/seed.js +23 -1074
- package/core/api-client.js +77 -0
- package/core/entitlements.js +36 -0
- package/core/organizations.js +223 -0
- package/core/policies.js +51 -6
- package/core/policy-matrix.js +303 -0
- package/core/project-context.js +1 -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 +23 -0
- package/intelligence/orchestrator/config/pack-lifecycle.js +262 -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/intelligence/orchestrator.js +17 -512
- 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,663 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootspring Onboard CLI
|
|
3
|
+
*
|
|
4
|
+
* Layer Bootspring onto existing projects with stack detection,
|
|
5
|
+
* pattern scanning, and configuration generation.
|
|
6
|
+
*
|
|
7
|
+
* @package bootspring
|
|
8
|
+
* @module cli/onboard
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Import JS modules with type interfaces
|
|
12
|
+
interface ParsedArgs {
|
|
13
|
+
_: string[];
|
|
14
|
+
'dry-run'?: boolean | undefined;
|
|
15
|
+
'skip-optional'?: boolean | undefined;
|
|
16
|
+
quick?: boolean | undefined;
|
|
17
|
+
apply?: boolean | undefined;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface PhaseConfig {
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
required: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface TechInfo {
|
|
27
|
+
name: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface StackInfo {
|
|
31
|
+
framework?: TechInfo | undefined;
|
|
32
|
+
language?: TechInfo | undefined;
|
|
33
|
+
database?: TechInfo | undefined;
|
|
34
|
+
hosting?: TechInfo | undefined;
|
|
35
|
+
auth?: TechInfo | undefined;
|
|
36
|
+
payments?: TechInfo | undefined;
|
|
37
|
+
detected: TechInfo[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface StructureStats {
|
|
41
|
+
totalFiles: number;
|
|
42
|
+
totalDirs: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface DetectionResult {
|
|
46
|
+
stack: StackInfo;
|
|
47
|
+
structure: {
|
|
48
|
+
stats: StructureStats;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface ArchitecturePattern {
|
|
53
|
+
name: string;
|
|
54
|
+
confidence: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface PatternResult {
|
|
58
|
+
architecture: {
|
|
59
|
+
patterns: ArchitecturePattern[];
|
|
60
|
+
};
|
|
61
|
+
features?: Record<string, boolean> | undefined;
|
|
62
|
+
quickMode?: boolean | undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface DocInfo {
|
|
66
|
+
file: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface DocResult {
|
|
70
|
+
found: DocInfo[];
|
|
71
|
+
missing: DocInfo[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface ConfigResult {
|
|
75
|
+
files: string[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface BaselineResult {
|
|
79
|
+
timestamp: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface OverallProgress {
|
|
83
|
+
completed: number;
|
|
84
|
+
total: number;
|
|
85
|
+
percentage: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface PhaseProgress {
|
|
89
|
+
name: string;
|
|
90
|
+
status: string;
|
|
91
|
+
required: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
interface WorkflowProgress {
|
|
95
|
+
overall: OverallProgress;
|
|
96
|
+
isComplete: boolean;
|
|
97
|
+
currentPhase?: string | undefined;
|
|
98
|
+
phases: PhaseProgress[];
|
|
99
|
+
startedAt?: string | undefined;
|
|
100
|
+
lastUpdated?: string | undefined;
|
|
101
|
+
detection?: {
|
|
102
|
+
stack?: StackInfo | undefined;
|
|
103
|
+
} | undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface ResumePoint {
|
|
107
|
+
phaseName: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface OnboardWorkflowEngineClass {
|
|
111
|
+
new (projectRoot: string): OnboardWorkflowEngine;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface OnboardWorkflowEngine {
|
|
115
|
+
hasWorkflow(): boolean;
|
|
116
|
+
loadState(): void;
|
|
117
|
+
initializeWorkflow(): void;
|
|
118
|
+
getProgress(): WorkflowProgress;
|
|
119
|
+
getResumePoint(): ResumePoint | null;
|
|
120
|
+
getNextPhase(): string | null;
|
|
121
|
+
startPhase(phaseId: string): void;
|
|
122
|
+
completePhase(phaseId: string, result?: unknown): void;
|
|
123
|
+
failPhase(phaseId: string, error: string): void;
|
|
124
|
+
skipPhase(phaseId: string): void;
|
|
125
|
+
resetWorkflow(): void;
|
|
126
|
+
applyGeneratedFiles(): void;
|
|
127
|
+
runDetection(): Promise<DetectionResult>;
|
|
128
|
+
runPatternScan(): Promise<PatternResult>;
|
|
129
|
+
runQuickPatternScan(): Promise<PatternResult>;
|
|
130
|
+
runDocDiscovery(): Promise<DocResult>;
|
|
131
|
+
runConfigGeneration(): Promise<ConfigResult>;
|
|
132
|
+
runBaselineCapture(): Promise<BaselineResult>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface OnboardWorkflowModule {
|
|
136
|
+
OnboardWorkflowEngine: OnboardWorkflowEngineClass;
|
|
137
|
+
ONBOARD_PHASES: Record<string, PhaseConfig>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
141
|
+
const utils = require('../../core/utils') as typeof import('../core/utils');
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
143
|
+
const onboardWorkflowModule = require('../../core/onboard-workflow') as OnboardWorkflowModule;
|
|
144
|
+
|
|
145
|
+
const { OnboardWorkflowEngine, ONBOARD_PHASES } = onboardWorkflowModule;
|
|
146
|
+
|
|
147
|
+
// Get project root
|
|
148
|
+
const projectRoot = process.cwd();
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Show onboard help
|
|
152
|
+
*/
|
|
153
|
+
function showHelp(): void {
|
|
154
|
+
console.log(`
|
|
155
|
+
${utils.COLORS.bold}Bootspring Onboard${utils.COLORS.reset}
|
|
156
|
+
Layer Bootspring onto existing projects
|
|
157
|
+
|
|
158
|
+
${utils.COLORS.bold}Usage:${utils.COLORS.reset}
|
|
159
|
+
bootspring onboard Start interactive onboarding
|
|
160
|
+
bootspring onboard status Show progress
|
|
161
|
+
bootspring onboard resume Continue from checkpoint
|
|
162
|
+
bootspring onboard detect Run detection only
|
|
163
|
+
bootspring onboard generate Generate config only
|
|
164
|
+
bootspring onboard reset Reset workflow
|
|
165
|
+
|
|
166
|
+
${utils.COLORS.bold}Options:${utils.COLORS.reset}
|
|
167
|
+
--dry-run Preview without changes
|
|
168
|
+
--skip-optional Skip optional phases
|
|
169
|
+
--quick Force fast mode (auto for 500+ files)
|
|
170
|
+
--apply Apply generated files
|
|
171
|
+
|
|
172
|
+
${utils.COLORS.bold}Notes:${utils.COLORS.reset}
|
|
173
|
+
Large codebases (500+ files) automatically use fast mode to skip
|
|
174
|
+
heavy dependency analysis. Use --quick to force it on smaller projects.
|
|
175
|
+
|
|
176
|
+
${utils.COLORS.bold}Examples:${utils.COLORS.reset}
|
|
177
|
+
bootspring onboard Auto-detects and adjusts for codebase size
|
|
178
|
+
bootspring onboard status
|
|
179
|
+
bootspring onboard --dry-run
|
|
180
|
+
`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Start onboarding workflow
|
|
185
|
+
*/
|
|
186
|
+
async function onboardStart(args: ParsedArgs): Promise<void> {
|
|
187
|
+
const workflow = new OnboardWorkflowEngine(projectRoot);
|
|
188
|
+
|
|
189
|
+
// Check for existing workflow
|
|
190
|
+
if (workflow.hasWorkflow()) {
|
|
191
|
+
workflow.loadState();
|
|
192
|
+
const progress = workflow.getProgress();
|
|
193
|
+
|
|
194
|
+
if (!progress.isComplete) {
|
|
195
|
+
utils.print.info('Existing onboarding workflow found.');
|
|
196
|
+
console.log(` Progress: ${progress.overall.percentage}% complete`);
|
|
197
|
+
console.log(` Current phase: ${progress.currentPhase || 'none'}`);
|
|
198
|
+
console.log('');
|
|
199
|
+
utils.print.info('Use "bootspring onboard resume" to continue');
|
|
200
|
+
utils.print.info('Use "bootspring onboard reset" to start fresh');
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Initialize new workflow
|
|
206
|
+
utils.print.header('Bootspring Onboarding');
|
|
207
|
+
console.log('Analyzing your existing codebase...\n');
|
|
208
|
+
|
|
209
|
+
workflow.initializeWorkflow();
|
|
210
|
+
|
|
211
|
+
// Run workflow
|
|
212
|
+
await runWorkflowLoop(workflow, args);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Resume onboarding workflow
|
|
217
|
+
*/
|
|
218
|
+
async function onboardResume(args: ParsedArgs): Promise<void> {
|
|
219
|
+
const workflow = new OnboardWorkflowEngine(projectRoot);
|
|
220
|
+
|
|
221
|
+
if (!workflow.hasWorkflow()) {
|
|
222
|
+
utils.print.error('No existing workflow found.');
|
|
223
|
+
utils.print.info('Run "bootspring onboard" to start.');
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
workflow.loadState();
|
|
228
|
+
const resumePoint = workflow.getResumePoint();
|
|
229
|
+
|
|
230
|
+
if (!resumePoint) {
|
|
231
|
+
utils.print.success('Onboarding workflow already complete!');
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
utils.print.header('Resuming Onboarding');
|
|
236
|
+
console.log(`Continuing from: ${resumePoint.phaseName}`);
|
|
237
|
+
console.log('');
|
|
238
|
+
|
|
239
|
+
await runWorkflowLoop(workflow, args);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Run the workflow loop
|
|
244
|
+
*/
|
|
245
|
+
async function runWorkflowLoop(workflow: OnboardWorkflowEngine, args: ParsedArgs): Promise<void> {
|
|
246
|
+
const dryRun = args['dry-run'] || false;
|
|
247
|
+
const skipOptional = args['skip-optional'] || false;
|
|
248
|
+
const quickMode = args.quick || false;
|
|
249
|
+
|
|
250
|
+
while (true) {
|
|
251
|
+
const nextPhaseId = workflow.getNextPhase();
|
|
252
|
+
|
|
253
|
+
if (!nextPhaseId) {
|
|
254
|
+
// Workflow complete
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const phase = ONBOARD_PHASES[nextPhaseId];
|
|
259
|
+
if (!phase) continue;
|
|
260
|
+
|
|
261
|
+
// Skip optional phases if requested
|
|
262
|
+
if (skipOptional && !phase.required) {
|
|
263
|
+
workflow.skipPhase(nextPhaseId);
|
|
264
|
+
utils.print.dim(`Skipping optional phase: ${phase.name}`);
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Run the phase
|
|
269
|
+
workflow.startPhase(nextPhaseId);
|
|
270
|
+
const spinner = utils.createSpinner(`Running: ${phase.name}`).start();
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
let result: unknown;
|
|
274
|
+
|
|
275
|
+
switch (nextPhaseId) {
|
|
276
|
+
case 'detection': {
|
|
277
|
+
const detectionResult = await workflow.runDetection();
|
|
278
|
+
spinner.succeed(`Detection complete: Found ${detectionResult.stack.detected.length} technologies`);
|
|
279
|
+
displayDetectionResults(detectionResult);
|
|
280
|
+
result = detectionResult;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
case 'patterns': {
|
|
285
|
+
let patternResult: PatternResult;
|
|
286
|
+
if (quickMode) {
|
|
287
|
+
// Quick mode: skip heavy dependency analysis, just detect features
|
|
288
|
+
patternResult = await workflow.runQuickPatternScan();
|
|
289
|
+
spinner.succeed('Quick pattern scan complete');
|
|
290
|
+
} else {
|
|
291
|
+
patternResult = await workflow.runPatternScan();
|
|
292
|
+
if (patternResult.quickMode) {
|
|
293
|
+
// Auto-detected large codebase
|
|
294
|
+
spinner.succeed('Pattern scan complete (large codebase - quick mode)');
|
|
295
|
+
} else {
|
|
296
|
+
spinner.succeed(`Pattern scan complete: ${patternResult.architecture.patterns.length} patterns found`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
displayPatternResults(patternResult);
|
|
300
|
+
result = patternResult;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
case 'docs': {
|
|
305
|
+
const docResult = await workflow.runDocDiscovery();
|
|
306
|
+
spinner.succeed(`Doc discovery complete: ${docResult.found.length} docs found, ${docResult.missing.length} missing`);
|
|
307
|
+
displayDocResults(docResult);
|
|
308
|
+
result = docResult;
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
case 'config': {
|
|
313
|
+
const configResult = await workflow.runConfigGeneration();
|
|
314
|
+
spinner.succeed('Configuration generated');
|
|
315
|
+
displayConfigResults(configResult, dryRun);
|
|
316
|
+
result = configResult;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
case 'baseline': {
|
|
321
|
+
const baselineResult = await workflow.runBaselineCapture();
|
|
322
|
+
spinner.succeed('Baseline captured');
|
|
323
|
+
result = baselineResult;
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
case 'reverse':
|
|
328
|
+
// Skip for now - optional
|
|
329
|
+
spinner.info('Skipping reverse engineering (optional)');
|
|
330
|
+
workflow.skipPhase(nextPhaseId);
|
|
331
|
+
continue;
|
|
332
|
+
|
|
333
|
+
default:
|
|
334
|
+
spinner.warn(`Unknown phase: ${nextPhaseId}`);
|
|
335
|
+
workflow.skipPhase(nextPhaseId);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
workflow.completePhase(nextPhaseId, result);
|
|
340
|
+
|
|
341
|
+
} catch (error) {
|
|
342
|
+
spinner.fail(`Failed: ${(error as Error).message}`);
|
|
343
|
+
workflow.failPhase(nextPhaseId, (error as Error).message);
|
|
344
|
+
|
|
345
|
+
if (phase.required) {
|
|
346
|
+
utils.print.error('Required phase failed. Cannot continue.');
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
console.log('');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Workflow complete
|
|
355
|
+
utils.print.success('Onboarding complete!');
|
|
356
|
+
console.log('');
|
|
357
|
+
|
|
358
|
+
const progress = workflow.getProgress();
|
|
359
|
+
|
|
360
|
+
// Apply files if requested
|
|
361
|
+
const shouldApply = args.apply || false;
|
|
362
|
+
if (shouldApply && !dryRun) {
|
|
363
|
+
utils.print.info('Applying generated files...');
|
|
364
|
+
workflow.applyGeneratedFiles();
|
|
365
|
+
utils.print.success('bootspring.config.js and CLAUDE.md created');
|
|
366
|
+
} else if (!dryRun) {
|
|
367
|
+
utils.print.info('Generated files are in .bootspring/onboard/generated/');
|
|
368
|
+
utils.print.info('Run with --apply to copy them to project root');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Show summary
|
|
372
|
+
console.log('');
|
|
373
|
+
utils.print.header('Summary');
|
|
374
|
+
console.log(` Stack: ${formatStack(progress.detection?.stack)}`);
|
|
375
|
+
console.log(` Phases completed: ${progress.overall.completed}/${progress.overall.total}`);
|
|
376
|
+
console.log('');
|
|
377
|
+
utils.print.info('Next steps:');
|
|
378
|
+
console.log(' 1. Review generated configuration');
|
|
379
|
+
console.log(' 2. Run "bootspring analyze" for deeper insights');
|
|
380
|
+
console.log(' 3. Run "bootspring audit" for quality checks');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Display detection results
|
|
385
|
+
*/
|
|
386
|
+
function displayDetectionResults(result: DetectionResult): void {
|
|
387
|
+
console.log('');
|
|
388
|
+
|
|
389
|
+
if (result.stack.framework) {
|
|
390
|
+
console.log(` ${utils.COLORS.cyan}Framework:${utils.COLORS.reset} ${result.stack.framework.name}`);
|
|
391
|
+
}
|
|
392
|
+
if (result.stack.language) {
|
|
393
|
+
console.log(` ${utils.COLORS.cyan}Language:${utils.COLORS.reset} ${result.stack.language.name}`);
|
|
394
|
+
}
|
|
395
|
+
if (result.stack.database) {
|
|
396
|
+
console.log(` ${utils.COLORS.cyan}Database:${utils.COLORS.reset} ${result.stack.database.name}`);
|
|
397
|
+
}
|
|
398
|
+
if (result.stack.hosting) {
|
|
399
|
+
console.log(` ${utils.COLORS.cyan}Hosting:${utils.COLORS.reset} ${result.stack.hosting.name}`);
|
|
400
|
+
}
|
|
401
|
+
if (result.stack.auth) {
|
|
402
|
+
console.log(` ${utils.COLORS.cyan}Auth:${utils.COLORS.reset} ${result.stack.auth.name}`);
|
|
403
|
+
}
|
|
404
|
+
if (result.stack.payments) {
|
|
405
|
+
console.log(` ${utils.COLORS.cyan}Payments:${utils.COLORS.reset} ${result.stack.payments.name}`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
console.log('');
|
|
409
|
+
console.log(` ${utils.COLORS.dim}Files: ${result.structure.stats.totalFiles} | Dirs: ${result.structure.stats.totalDirs}${utils.COLORS.reset}`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Display pattern results
|
|
414
|
+
*/
|
|
415
|
+
function displayPatternResults(result: PatternResult): void {
|
|
416
|
+
if (result.architecture.patterns.length > 0) {
|
|
417
|
+
console.log('');
|
|
418
|
+
console.log(' Detected patterns:');
|
|
419
|
+
for (const pattern of result.architecture.patterns.slice(0, 3)) {
|
|
420
|
+
console.log(` - ${pattern.name} (${pattern.confidence}%)`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (result.features) {
|
|
425
|
+
const activeFeatures = Object.entries(result.features)
|
|
426
|
+
.filter(([, v]) => v)
|
|
427
|
+
.map(([k]) => k);
|
|
428
|
+
|
|
429
|
+
if (activeFeatures.length > 0) {
|
|
430
|
+
console.log('');
|
|
431
|
+
console.log(' Detected features:');
|
|
432
|
+
console.log(` ${activeFeatures.join(', ')}`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Display documentation results
|
|
439
|
+
*/
|
|
440
|
+
function displayDocResults(result: DocResult): void {
|
|
441
|
+
if (result.found.length > 0) {
|
|
442
|
+
console.log('');
|
|
443
|
+
console.log(' Found documentation:');
|
|
444
|
+
for (const doc of result.found.slice(0, 5)) {
|
|
445
|
+
console.log(` ${utils.COLORS.green}✓${utils.COLORS.reset} ${doc.file}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (result.missing.length > 0) {
|
|
450
|
+
console.log('');
|
|
451
|
+
console.log(' Missing (recommended):');
|
|
452
|
+
for (const doc of result.missing) {
|
|
453
|
+
console.log(` ${utils.COLORS.yellow}○${utils.COLORS.reset} ${doc.file}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Display config generation results
|
|
460
|
+
*/
|
|
461
|
+
function displayConfigResults(result: ConfigResult, dryRun: boolean): void {
|
|
462
|
+
console.log('');
|
|
463
|
+
|
|
464
|
+
if (dryRun) {
|
|
465
|
+
console.log(` ${utils.COLORS.dim}[DRY RUN] Would generate:${utils.COLORS.reset}`);
|
|
466
|
+
} else {
|
|
467
|
+
console.log(' Generated:');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
console.log(' - bootspring.config.js');
|
|
471
|
+
console.log(' - CLAUDE.md');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Format stack for display
|
|
476
|
+
*/
|
|
477
|
+
function formatStack(stack: StackInfo | undefined): string {
|
|
478
|
+
if (!stack) return 'Unknown';
|
|
479
|
+
|
|
480
|
+
const parts: string[] = [];
|
|
481
|
+
if (stack.framework) parts.push(stack.framework.name);
|
|
482
|
+
if (stack.language) parts.push(stack.language.name);
|
|
483
|
+
if (stack.database) parts.push(stack.database.name);
|
|
484
|
+
|
|
485
|
+
return parts.join(' + ') || 'Unknown';
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Show onboard status
|
|
490
|
+
*/
|
|
491
|
+
async function onboardStatus(): Promise<void> {
|
|
492
|
+
const workflow = new OnboardWorkflowEngine(projectRoot);
|
|
493
|
+
|
|
494
|
+
if (!workflow.hasWorkflow()) {
|
|
495
|
+
utils.print.info('No onboarding workflow started.');
|
|
496
|
+
utils.print.info('Run "bootspring onboard" to begin.');
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
workflow.loadState();
|
|
501
|
+
const progress = workflow.getProgress();
|
|
502
|
+
|
|
503
|
+
utils.print.header('Onboarding Status');
|
|
504
|
+
|
|
505
|
+
// Overall progress
|
|
506
|
+
console.log(`Progress: ${progress.overall.percentage}% complete`);
|
|
507
|
+
console.log(`Started: ${progress.startedAt ? new Date(progress.startedAt).toLocaleString() : 'N/A'}`);
|
|
508
|
+
console.log(`Last updated: ${progress.lastUpdated ? utils.formatRelativeTime(new Date(progress.lastUpdated)) : 'N/A'}`);
|
|
509
|
+
console.log('');
|
|
510
|
+
|
|
511
|
+
// Phase status
|
|
512
|
+
console.log('Phases:');
|
|
513
|
+
for (const phase of progress.phases) {
|
|
514
|
+
const statusIcon = getStatusIcon(phase.status);
|
|
515
|
+
const required = phase.required ? '' : ' (optional)';
|
|
516
|
+
console.log(` ${statusIcon} ${phase.name}${required}`);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
console.log('');
|
|
520
|
+
|
|
521
|
+
// Detection summary if available
|
|
522
|
+
if (progress.detection?.stack) {
|
|
523
|
+
console.log('Detected stack:');
|
|
524
|
+
console.log(` ${formatStack(progress.detection.stack)}`);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (!progress.isComplete) {
|
|
528
|
+
console.log('');
|
|
529
|
+
utils.print.info('Run "bootspring onboard resume" to continue');
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Run detection only
|
|
535
|
+
*/
|
|
536
|
+
async function onboardDetect(): Promise<void> {
|
|
537
|
+
const workflow = new OnboardWorkflowEngine(projectRoot);
|
|
538
|
+
workflow.initializeWorkflow();
|
|
539
|
+
|
|
540
|
+
const spinner = utils.createSpinner('Detecting stack...').start();
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
const result = await workflow.runDetection();
|
|
544
|
+
spinner.succeed('Detection complete');
|
|
545
|
+
|
|
546
|
+
displayDetectionResults(result);
|
|
547
|
+
} catch (error) {
|
|
548
|
+
spinner.fail(`Detection failed: ${(error as Error).message}`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Generate config only
|
|
554
|
+
*/
|
|
555
|
+
async function onboardGenerate(args: ParsedArgs): Promise<void> {
|
|
556
|
+
const workflow = new OnboardWorkflowEngine(projectRoot);
|
|
557
|
+
|
|
558
|
+
// Need detection first
|
|
559
|
+
if (!workflow.hasWorkflow()) {
|
|
560
|
+
workflow.initializeWorkflow();
|
|
561
|
+
|
|
562
|
+
const spinner = utils.createSpinner('Running detection first...').start();
|
|
563
|
+
await workflow.runDetection();
|
|
564
|
+
workflow.completePhase('detection');
|
|
565
|
+
|
|
566
|
+
await workflow.runPatternScan();
|
|
567
|
+
workflow.completePhase('patterns');
|
|
568
|
+
|
|
569
|
+
spinner.succeed('Detection complete');
|
|
570
|
+
} else {
|
|
571
|
+
workflow.loadState();
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const spinner = utils.createSpinner('Generating configuration...').start();
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
const result = await workflow.runConfigGeneration();
|
|
578
|
+
spinner.succeed('Configuration generated');
|
|
579
|
+
|
|
580
|
+
displayConfigResults(result, args['dry-run'] || false);
|
|
581
|
+
|
|
582
|
+
if (args.apply) {
|
|
583
|
+
workflow.applyGeneratedFiles();
|
|
584
|
+
utils.print.success('Files applied to project root');
|
|
585
|
+
} else {
|
|
586
|
+
console.log('');
|
|
587
|
+
utils.print.info('Files saved to .bootspring/onboard/generated/');
|
|
588
|
+
utils.print.info('Run with --apply to copy to project root');
|
|
589
|
+
}
|
|
590
|
+
} catch (error) {
|
|
591
|
+
spinner.fail(`Generation failed: ${(error as Error).message}`);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Reset onboard workflow
|
|
597
|
+
*/
|
|
598
|
+
async function onboardReset(): Promise<void> {
|
|
599
|
+
const workflow = new OnboardWorkflowEngine(projectRoot);
|
|
600
|
+
|
|
601
|
+
if (!workflow.hasWorkflow()) {
|
|
602
|
+
utils.print.info('No workflow to reset.');
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
workflow.resetWorkflow();
|
|
607
|
+
utils.print.success('Onboarding workflow reset.');
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Get status icon
|
|
612
|
+
*/
|
|
613
|
+
function getStatusIcon(status: string): string {
|
|
614
|
+
switch (status) {
|
|
615
|
+
case 'completed':
|
|
616
|
+
return `${utils.COLORS.green}✓${utils.COLORS.reset}`;
|
|
617
|
+
case 'in_progress':
|
|
618
|
+
return `${utils.COLORS.cyan}●${utils.COLORS.reset}`;
|
|
619
|
+
case 'failed':
|
|
620
|
+
return `${utils.COLORS.red}✗${utils.COLORS.reset}`;
|
|
621
|
+
case 'skipped':
|
|
622
|
+
return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
623
|
+
default:
|
|
624
|
+
return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Main entry point
|
|
630
|
+
*/
|
|
631
|
+
export async function run(args: string[]): Promise<void> {
|
|
632
|
+
const parsedArgs = utils.parseArgs(args) as ParsedArgs;
|
|
633
|
+
const subcommand = parsedArgs._[0] || 'start';
|
|
634
|
+
|
|
635
|
+
switch (subcommand) {
|
|
636
|
+
case 'start':
|
|
637
|
+
return onboardStart(parsedArgs);
|
|
638
|
+
|
|
639
|
+
case 'status':
|
|
640
|
+
return onboardStatus();
|
|
641
|
+
|
|
642
|
+
case 'resume':
|
|
643
|
+
return onboardResume(parsedArgs);
|
|
644
|
+
|
|
645
|
+
case 'detect':
|
|
646
|
+
return onboardDetect();
|
|
647
|
+
|
|
648
|
+
case 'generate':
|
|
649
|
+
return onboardGenerate(parsedArgs);
|
|
650
|
+
|
|
651
|
+
case 'reset':
|
|
652
|
+
return onboardReset();
|
|
653
|
+
|
|
654
|
+
case 'help':
|
|
655
|
+
case '--help':
|
|
656
|
+
case '-h':
|
|
657
|
+
return showHelp();
|
|
658
|
+
|
|
659
|
+
default:
|
|
660
|
+
// If no subcommand, start workflow
|
|
661
|
+
return onboardStart(parsedArgs);
|
|
662
|
+
}
|
|
663
|
+
}
|