@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.
- package/README.md +107 -14
- package/bin/bootspring.js +166 -27
- package/cli/agent.js +189 -17
- package/cli/analyze.js +499 -0
- package/cli/audit.js +557 -0
- package/cli/auth.js +495 -38
- package/cli/billing.js +302 -0
- package/cli/build.js +695 -0
- package/cli/business.js +109 -26
- package/cli/checkpoint-utils.js +168 -0
- package/cli/checkpoint.js +639 -0
- package/cli/cloud-sync.js +447 -0
- package/cli/content.js +198 -0
- package/cli/context.js +1 -1
- package/cli/deploy.js +543 -0
- package/cli/fundraise.js +112 -50
- package/cli/github-cmd.js +435 -0
- package/cli/health.js +477 -0
- package/cli/init.js +84 -13
- package/cli/legal.js +107 -95
- package/cli/log.js +2 -2
- package/cli/loop.js +976 -73
- package/cli/manager.js +711 -0
- package/cli/metrics.js +480 -0
- package/cli/monitor.js +812 -0
- package/cli/onboard.js +521 -0
- package/cli/orchestrator.js +12 -24
- package/cli/prd.js +594 -0
- package/cli/preseed-start.js +1483 -0
- package/cli/preseed.js +2302 -0
- package/cli/project.js +436 -0
- package/cli/quality.js +233 -0
- package/cli/security.js +913 -0
- package/cli/seed.js +1441 -5
- package/cli/skill.js +273 -211
- package/cli/suggest.js +989 -0
- package/cli/switch.js +453 -0
- package/cli/visualize.js +527 -0
- package/cli/watch.js +769 -0
- package/cli/workspace.js +607 -0
- package/core/analyze-workflow.js +1134 -0
- package/core/api-client.js +535 -22
- package/core/audit-workflow.js +1350 -0
- package/core/build-orchestrator.js +480 -0
- package/core/build-state.js +577 -0
- package/core/checkpoint-engine.js +408 -0
- package/core/config.js +1109 -26
- package/core/context-loader.js +21 -1
- package/core/deploy-workflow.js +836 -0
- package/core/entitlements.js +93 -22
- package/core/github-sync.js +610 -0
- package/core/index.js +8 -1
- package/core/ingest.js +1111 -0
- package/core/metrics-engine.js +768 -0
- package/core/onboard-workflow.js +1007 -0
- package/core/preseed-workflow.js +934 -0
- package/core/preseed.js +1617 -0
- package/core/project-context.js +325 -0
- package/core/project-state.js +694 -0
- package/core/r2-sync.js +583 -0
- package/core/scaffold.js +525 -7
- package/core/session.js +258 -0
- package/core/task-extractor.js +758 -0
- package/core/telemetry.js +28 -6
- package/core/tier-enforcement.js +737 -0
- package/core/utils.js +38 -14
- package/generators/questionnaire.js +15 -12
- package/generators/sections/ai.js +7 -7
- package/generators/sections/content.js +300 -0
- package/generators/sections/index.js +3 -0
- package/generators/sections/plugins.js +7 -6
- package/generators/templates/build-planning.template.js +596 -0
- package/generators/templates/content.template.js +819 -0
- package/generators/templates/index.js +2 -1
- package/hooks/git-autopilot.js +1250 -0
- package/hooks/index.js +9 -0
- package/intelligence/agent-collab.js +2057 -0
- package/intelligence/auto-suggest.js +634 -0
- package/intelligence/content-gen.js +1589 -0
- package/intelligence/cross-project.js +1647 -0
- package/intelligence/index.js +184 -0
- package/intelligence/learning/insights.json +517 -7
- package/intelligence/learning/pattern-learner.js +1008 -14
- package/intelligence/memory/decision-tracker.js +1431 -31
- package/intelligence/memory/decisions.jsonl +0 -0
- package/intelligence/orchestrator.js +2896 -1
- package/intelligence/prd.js +92 -1
- package/intelligence/recommendation-weights.json +14 -2
- package/intelligence/recommendations.js +463 -9
- package/intelligence/workflow-composer.js +1451 -0
- package/marketplace/index.d.ts +324 -0
- package/marketplace/index.js +1921 -0
- package/mcp/contracts/mcp-contract.v1.json +342 -4
- package/mcp/registry.js +680 -3
- package/mcp/response-formatter.js +23 -0
- package/mcp/tools/assist-tool.js +78 -4
- package/mcp/tools/autopilot-tool.js +408 -0
- package/mcp/tools/content-tool.js +571 -0
- package/mcp/tools/dashboard-tool.js +251 -5
- package/mcp/tools/mvp-tool.js +344 -0
- package/mcp/tools/plugin-tool.js +23 -1
- package/mcp/tools/prd-tool.js +579 -0
- package/mcp/tools/seed-tool.js +447 -0
- package/mcp/tools/skill-tool.js +43 -14
- package/mcp/tools/suggest-tool.js +147 -0
- package/package.json +15 -6
- package/agents/README.md +0 -93
- package/agents/ai-integration-expert/context.md +0 -386
- package/agents/api-expert/context.md +0 -416
- package/agents/architecture-expert/context.md +0 -454
- package/agents/auth-expert/context.md +0 -399
- package/agents/backend-expert/context.md +0 -483
- package/agents/business-strategy-expert/context.md +0 -180
- package/agents/code-review-expert/context.md +0 -365
- package/agents/competitive-analysis-expert/context.md +0 -239
- package/agents/data-modeling-expert/context.md +0 -352
- package/agents/database-expert/context.md +0 -250
- package/agents/devops-expert/context.md +0 -446
- package/agents/email-expert/context.md +0 -379
- package/agents/financial-expert/context.md +0 -213
- package/agents/frontend-expert/context.md +0 -364
- package/agents/fundraising-expert/context.md +0 -257
- package/agents/growth-expert/context.md +0 -249
- package/agents/index.js +0 -140
- package/agents/investor-relations-expert/context.md +0 -266
- package/agents/legal-expert/context.md +0 -284
- package/agents/marketing-expert/context.md +0 -236
- package/agents/monitoring-expert/context.md +0 -362
- package/agents/operations-expert/context.md +0 -279
- package/agents/partnerships-expert/context.md +0 -286
- package/agents/payment-expert/context.md +0 -340
- package/agents/performance-expert/context.md +0 -377
- package/agents/private-equity-expert/context.md +0 -246
- package/agents/railway-expert/context.md +0 -284
- package/agents/research-expert/context.md +0 -245
- package/agents/sales-expert/context.md +0 -241
- package/agents/security-expert/context.md +0 -343
- package/agents/testing-expert/context.md +0 -414
- package/agents/ui-ux-expert/context.md +0 -448
- package/agents/vercel-expert/context.md +0 -426
- package/skills/index.js +0 -787
- package/skills/patterns/README.md +0 -163
- package/skills/patterns/ai/agents.md +0 -281
- package/skills/patterns/ai/claude.md +0 -138
- package/skills/patterns/ai/embeddings.md +0 -150
- package/skills/patterns/ai/rag.md +0 -266
- package/skills/patterns/ai/streaming.md +0 -170
- package/skills/patterns/ai/structured-output.md +0 -162
- package/skills/patterns/ai/tools.md +0 -154
- package/skills/patterns/analytics/tracking.md +0 -220
- package/skills/patterns/api/errors.md +0 -296
- package/skills/patterns/api/graphql.md +0 -440
- package/skills/patterns/api/middleware.md +0 -279
- package/skills/patterns/api/openapi.md +0 -285
- package/skills/patterns/api/rate-limiting.md +0 -231
- package/skills/patterns/api/route-handler.md +0 -217
- package/skills/patterns/api/server-action.md +0 -249
- package/skills/patterns/api/versioning.md +0 -443
- package/skills/patterns/api/webhooks.md +0 -247
- package/skills/patterns/auth/clerk.md +0 -132
- package/skills/patterns/auth/mfa.md +0 -313
- package/skills/patterns/auth/nextauth.md +0 -140
- package/skills/patterns/auth/oauth.md +0 -237
- package/skills/patterns/auth/rbac.md +0 -152
- package/skills/patterns/auth/session-management.md +0 -367
- package/skills/patterns/auth/session.md +0 -120
- package/skills/patterns/database/audit.md +0 -177
- package/skills/patterns/database/migrations.md +0 -177
- package/skills/patterns/database/pagination.md +0 -230
- package/skills/patterns/database/pooling.md +0 -357
- package/skills/patterns/database/prisma.md +0 -180
- package/skills/patterns/database/relations.md +0 -187
- package/skills/patterns/database/seeding.md +0 -246
- package/skills/patterns/database/soft-delete.md +0 -153
- package/skills/patterns/database/transactions.md +0 -162
- package/skills/patterns/deployment/ci-cd.md +0 -231
- package/skills/patterns/deployment/docker.md +0 -188
- package/skills/patterns/deployment/monitoring.md +0 -387
- package/skills/patterns/deployment/vercel.md +0 -160
- package/skills/patterns/email/resend.md +0 -143
- package/skills/patterns/email/templates.md +0 -245
- package/skills/patterns/email/transactional.md +0 -503
- package/skills/patterns/email/verification.md +0 -176
- package/skills/patterns/files/download.md +0 -243
- package/skills/patterns/files/upload.md +0 -239
- package/skills/patterns/i18n/nextintl.md +0 -188
- package/skills/patterns/logging/structured.md +0 -292
- package/skills/patterns/notifications/email-queue.md +0 -248
- package/skills/patterns/notifications/push.md +0 -279
- package/skills/patterns/payments/checkout.md +0 -303
- package/skills/patterns/payments/invoices.md +0 -287
- package/skills/patterns/payments/portal.md +0 -245
- package/skills/patterns/payments/stripe.md +0 -272
- package/skills/patterns/payments/subscriptions.md +0 -300
- package/skills/patterns/payments/usage.md +0 -279
- package/skills/patterns/performance/caching.md +0 -276
- package/skills/patterns/performance/code-splitting.md +0 -233
- package/skills/patterns/performance/edge.md +0 -254
- package/skills/patterns/performance/isr.md +0 -266
- package/skills/patterns/performance/lazy-loading.md +0 -281
- package/skills/patterns/realtime/sse.md +0 -327
- package/skills/patterns/realtime/websockets.md +0 -336
- package/skills/patterns/search/filtering.md +0 -329
- package/skills/patterns/search/fulltext.md +0 -260
- package/skills/patterns/security/audit-logging.md +0 -444
- package/skills/patterns/security/csrf.md +0 -234
- package/skills/patterns/security/headers.md +0 -252
- package/skills/patterns/security/sanitization.md +0 -258
- package/skills/patterns/security/secrets.md +0 -261
- package/skills/patterns/security/validation.md +0 -268
- package/skills/patterns/security/xss.md +0 -229
- package/skills/patterns/seo/metadata.md +0 -252
- package/skills/patterns/state/context.md +0 -349
- package/skills/patterns/state/react-query.md +0 -313
- package/skills/patterns/state/url-state.md +0 -482
- package/skills/patterns/state/zustand.md +0 -262
- package/skills/patterns/testing/api.md +0 -259
- package/skills/patterns/testing/component.md +0 -233
- package/skills/patterns/testing/coverage.md +0 -207
- package/skills/patterns/testing/fixtures.md +0 -225
- package/skills/patterns/testing/integration.md +0 -436
- package/skills/patterns/testing/mocking.md +0 -177
- package/skills/patterns/testing/playwright.md +0 -162
- package/skills/patterns/testing/snapshot.md +0 -175
- package/skills/patterns/testing/vitest.md +0 -307
- package/skills/patterns/ui/accordions.md +0 -395
- package/skills/patterns/ui/cards.md +0 -299
- package/skills/patterns/ui/dropdowns.md +0 -476
- package/skills/patterns/ui/empty-states.md +0 -320
- package/skills/patterns/ui/forms.md +0 -405
- package/skills/patterns/ui/inputs.md +0 -319
- package/skills/patterns/ui/layouts.md +0 -282
- package/skills/patterns/ui/loading.md +0 -291
- package/skills/patterns/ui/modals.md +0 -338
- package/skills/patterns/ui/navigation.md +0 -374
- package/skills/patterns/ui/tables.md +0 -407
- package/skills/patterns/ui/toasts.md +0 -300
- package/skills/patterns/ui/tooltips.md +0 -396
- package/skills/patterns/utils/dates.md +0 -435
- package/skills/patterns/utils/errors.md +0 -451
- package/skills/patterns/utils/formatting.md +0 -345
- package/skills/patterns/utils/validation.md +0 -434
- package/templates/bootspring.config.js +0 -83
- package/templates/business/business-model-canvas.md +0 -246
- package/templates/business/business-plan.md +0 -266
- package/templates/business/competitive-analysis.md +0 -312
- package/templates/fundraising/data-room-checklist.md +0 -300
- package/templates/fundraising/investor-research.md +0 -243
- package/templates/fundraising/pitch-deck-outline.md +0 -253
- package/templates/legal/gdpr-checklist.md +0 -339
- package/templates/legal/privacy-policy.md +0 -285
- package/templates/legal/terms-of-service.md +0 -222
- package/templates/mcp.json +0 -9
package/cli/deploy.js
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootspring Deploy CLI
|
|
3
|
+
*
|
|
4
|
+
* Deploy projects to various hosting platforms with
|
|
5
|
+
* pre-deployment validation and quality checks.
|
|
6
|
+
*
|
|
7
|
+
* @package bootspring
|
|
8
|
+
* @module cli/deploy
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const utils = require('../core/utils');
|
|
14
|
+
const { DeployWorkflowEngine, DEPLOY_TARGETS, DEPLOY_PHASES } = require('../core/deploy-workflow');
|
|
15
|
+
|
|
16
|
+
// Get project root
|
|
17
|
+
const projectRoot = process.cwd();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Show deploy help
|
|
21
|
+
*/
|
|
22
|
+
function showHelp() {
|
|
23
|
+
console.log(`
|
|
24
|
+
${utils.COLORS.bold}Bootspring Deploy${utils.COLORS.reset}
|
|
25
|
+
Deploy your project to production
|
|
26
|
+
|
|
27
|
+
${utils.COLORS.bold}Usage:${utils.COLORS.reset}
|
|
28
|
+
bootspring deploy Deploy to detected/configured target
|
|
29
|
+
bootspring deploy <target> Deploy to specific target
|
|
30
|
+
bootspring deploy status Show deployment status
|
|
31
|
+
bootspring deploy targets List available targets
|
|
32
|
+
bootspring deploy init <target> Initialize deployment config
|
|
33
|
+
bootspring deploy reset Reset deployment state
|
|
34
|
+
|
|
35
|
+
${utils.COLORS.bold}Targets:${utils.COLORS.reset}
|
|
36
|
+
vercel Vercel (recommended for Next.js)
|
|
37
|
+
railway Railway (full-stack apps)
|
|
38
|
+
fly Fly.io (edge deployment)
|
|
39
|
+
netlify Netlify (static sites & serverless)
|
|
40
|
+
docker Docker (build image)
|
|
41
|
+
aws AWS Amplify
|
|
42
|
+
|
|
43
|
+
${utils.COLORS.bold}Options:${utils.COLORS.reset}
|
|
44
|
+
--preview Preview deployment (not production)
|
|
45
|
+
--skip-quality Skip quality checks
|
|
46
|
+
--dry-run Show what would be deployed
|
|
47
|
+
--force Force deployment even with warnings
|
|
48
|
+
|
|
49
|
+
${utils.COLORS.bold}Examples:${utils.COLORS.reset}
|
|
50
|
+
bootspring deploy # Auto-detect and deploy
|
|
51
|
+
bootspring deploy vercel # Deploy to Vercel
|
|
52
|
+
bootspring deploy --preview # Deploy preview
|
|
53
|
+
bootspring deploy init vercel # Create vercel.json
|
|
54
|
+
bootspring deploy targets # List all targets
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Start deployment workflow
|
|
60
|
+
*/
|
|
61
|
+
async function deployStart(args) {
|
|
62
|
+
const target = args._[0] || null;
|
|
63
|
+
const preview = args.preview || false;
|
|
64
|
+
const skipQuality = args['skip-quality'] || false;
|
|
65
|
+
const dryRun = args['dry-run'] || false;
|
|
66
|
+
const force = args.force || false;
|
|
67
|
+
|
|
68
|
+
const workflow = new DeployWorkflowEngine(projectRoot, {
|
|
69
|
+
dryRun,
|
|
70
|
+
skipQuality,
|
|
71
|
+
env: preview ? 'preview' : 'production'
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Check for existing workflow
|
|
75
|
+
if (workflow.hasWorkflow()) {
|
|
76
|
+
workflow.loadState();
|
|
77
|
+
const progress = workflow.getProgress();
|
|
78
|
+
|
|
79
|
+
if (!progress.isComplete) {
|
|
80
|
+
utils.print.info('Existing deployment in progress.');
|
|
81
|
+
console.log(` Progress: ${progress.overall.percentage}% complete`);
|
|
82
|
+
console.log(` Target: ${progress.target || 'not set'}`);
|
|
83
|
+
console.log('');
|
|
84
|
+
utils.print.info('Use "bootspring deploy reset" to start fresh');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Initialize workflow
|
|
90
|
+
utils.print.header('Bootspring Deploy');
|
|
91
|
+
console.log(preview ? 'Preview deployment' : 'Production deployment');
|
|
92
|
+
if (dryRun) {
|
|
93
|
+
console.log(`${utils.COLORS.yellow}[DRY RUN]${utils.COLORS.reset}`);
|
|
94
|
+
}
|
|
95
|
+
console.log('');
|
|
96
|
+
|
|
97
|
+
workflow.initializeWorkflow(target);
|
|
98
|
+
|
|
99
|
+
// Run workflow
|
|
100
|
+
await runWorkflowLoop(workflow, { force, dryRun });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Run the workflow loop
|
|
105
|
+
*/
|
|
106
|
+
async function runWorkflowLoop(workflow, options = {}) {
|
|
107
|
+
while (true) {
|
|
108
|
+
const nextPhaseId = workflow.getNextPhase();
|
|
109
|
+
|
|
110
|
+
if (!nextPhaseId) {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const phase = DEPLOY_PHASES[nextPhaseId];
|
|
115
|
+
|
|
116
|
+
// Run the phase
|
|
117
|
+
workflow.startPhase(nextPhaseId);
|
|
118
|
+
const spinner = utils.createSpinner(`${phase.name}...`).start();
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
let result;
|
|
122
|
+
|
|
123
|
+
switch (nextPhaseId) {
|
|
124
|
+
case 'validate':
|
|
125
|
+
result = await workflow.runValidation();
|
|
126
|
+
if (result.passed) {
|
|
127
|
+
spinner.succeed('Pre-flight validation passed');
|
|
128
|
+
} else {
|
|
129
|
+
spinner.fail('Pre-flight validation failed');
|
|
130
|
+
displayValidationResults(result);
|
|
131
|
+
if (!options.force) {
|
|
132
|
+
utils.print.error('Fix issues above or use --force to continue');
|
|
133
|
+
workflow.failPhase(nextPhaseId, 'Validation failed');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
utils.print.warning('Continuing with --force');
|
|
137
|
+
}
|
|
138
|
+
displayValidationResults(result);
|
|
139
|
+
break;
|
|
140
|
+
|
|
141
|
+
case 'target':
|
|
142
|
+
result = await workflow.detectTarget();
|
|
143
|
+
if (result.selected) {
|
|
144
|
+
const target = workflow.getTargetInfo(result.selected);
|
|
145
|
+
spinner.succeed(`Target: ${target.name}`);
|
|
146
|
+
} else if (result.detected.length > 0) {
|
|
147
|
+
spinner.succeed(`Detected: ${result.detected.map(t => t.name).join(', ')}`);
|
|
148
|
+
// Auto-select first detected
|
|
149
|
+
workflow.setTarget(result.detected[0].id);
|
|
150
|
+
result.selected = result.detected[0].id;
|
|
151
|
+
} else {
|
|
152
|
+
spinner.fail('No deployment target detected');
|
|
153
|
+
displayTargetSelection(result);
|
|
154
|
+
utils.print.error('Run "bootspring deploy init <target>" to configure');
|
|
155
|
+
workflow.failPhase(nextPhaseId, 'No target');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
displayTargetResults(result);
|
|
159
|
+
break;
|
|
160
|
+
|
|
161
|
+
case 'build':
|
|
162
|
+
if (options.dryRun) {
|
|
163
|
+
spinner.info('Build: [DRY RUN] Would run npm run build');
|
|
164
|
+
result = { dryRun: true };
|
|
165
|
+
} else {
|
|
166
|
+
spinner.text = 'Building...';
|
|
167
|
+
result = await workflow.runBuild();
|
|
168
|
+
spinner.succeed('Build successful');
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
|
|
172
|
+
case 'quality':
|
|
173
|
+
result = await workflow.runQualityChecks();
|
|
174
|
+
if (result.skipped) {
|
|
175
|
+
spinner.info('Quality checks skipped');
|
|
176
|
+
} else if (result.passed) {
|
|
177
|
+
spinner.succeed('Quality checks passed');
|
|
178
|
+
} else {
|
|
179
|
+
spinner.warn('Some quality checks failed');
|
|
180
|
+
}
|
|
181
|
+
displayQualityResults(result);
|
|
182
|
+
break;
|
|
183
|
+
|
|
184
|
+
case 'deploy':
|
|
185
|
+
if (options.dryRun) {
|
|
186
|
+
const target = workflow.getTargetInfo(workflow.state.target);
|
|
187
|
+
spinner.info(`Deploy: [DRY RUN] Would run: ${target.deployCmd}`);
|
|
188
|
+
result = { dryRun: true };
|
|
189
|
+
} else {
|
|
190
|
+
spinner.text = 'Deploying...';
|
|
191
|
+
console.log('');
|
|
192
|
+
result = await workflow.runDeploy();
|
|
193
|
+
console.log('');
|
|
194
|
+
spinner.succeed(`Deployed to ${result.target}`);
|
|
195
|
+
if (result.url) {
|
|
196
|
+
console.log(` ${utils.COLORS.green}URL:${utils.COLORS.reset} ${result.url}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
|
|
201
|
+
case 'verify':
|
|
202
|
+
if (options.dryRun) {
|
|
203
|
+
spinner.info('Verification: [DRY RUN] Skipped');
|
|
204
|
+
result = { dryRun: true };
|
|
205
|
+
} else {
|
|
206
|
+
result = await workflow.runVerification();
|
|
207
|
+
if (result.skipped) {
|
|
208
|
+
spinner.info('Verification skipped');
|
|
209
|
+
} else if (result.passed) {
|
|
210
|
+
spinner.succeed(`Verification passed (HTTP ${result.statusCode})`);
|
|
211
|
+
} else {
|
|
212
|
+
spinner.warn('Verification failed');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
|
|
217
|
+
default:
|
|
218
|
+
spinner.warn(`Unknown phase: ${nextPhaseId}`);
|
|
219
|
+
workflow.skipPhase(nextPhaseId);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
workflow.completePhase(nextPhaseId, result);
|
|
224
|
+
|
|
225
|
+
} catch (error) {
|
|
226
|
+
spinner.fail(`Failed: ${error.message}`);
|
|
227
|
+
workflow.failPhase(nextPhaseId, error.message);
|
|
228
|
+
|
|
229
|
+
if (phase.required) {
|
|
230
|
+
utils.print.error('Deployment failed.');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log('');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Deployment complete
|
|
239
|
+
displayCompletionSummary(workflow, options);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Display validation results
|
|
244
|
+
*/
|
|
245
|
+
function displayValidationResults(result) {
|
|
246
|
+
console.log('');
|
|
247
|
+
|
|
248
|
+
for (const [check, passed] of Object.entries(result.checks)) {
|
|
249
|
+
const icon = passed ?
|
|
250
|
+
`${utils.COLORS.green}✓${utils.COLORS.reset}` :
|
|
251
|
+
`${utils.COLORS.yellow}○${utils.COLORS.reset}`;
|
|
252
|
+
console.log(` ${icon} ${formatCheckName(check)}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (result.issues.length > 0) {
|
|
256
|
+
console.log('');
|
|
257
|
+
console.log(` ${utils.COLORS.red}Issues:${utils.COLORS.reset}`);
|
|
258
|
+
for (const issue of result.issues) {
|
|
259
|
+
console.log(` - ${issue}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (result.warnings.length > 0) {
|
|
264
|
+
console.log('');
|
|
265
|
+
console.log(` ${utils.COLORS.yellow}Warnings:${utils.COLORS.reset}`);
|
|
266
|
+
for (const warning of result.warnings) {
|
|
267
|
+
console.log(` - ${warning}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Display target results
|
|
274
|
+
*/
|
|
275
|
+
function displayTargetResults(result) {
|
|
276
|
+
if (result.framework) {
|
|
277
|
+
console.log(` ${utils.COLORS.dim}Framework: ${result.framework}${utils.COLORS.reset}`);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (result.available.length > 0 && !result.selected) {
|
|
281
|
+
console.log('');
|
|
282
|
+
console.log(' Available CLIs:');
|
|
283
|
+
for (const target of result.available.slice(0, 3)) {
|
|
284
|
+
console.log(` ${utils.COLORS.cyan}${target.name}${utils.COLORS.reset}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Display target selection options
|
|
291
|
+
*/
|
|
292
|
+
function displayTargetSelection(result) {
|
|
293
|
+
console.log('');
|
|
294
|
+
console.log('Recommended targets for your project:');
|
|
295
|
+
|
|
296
|
+
for (const rec of result.recommendations.slice(0, 3)) {
|
|
297
|
+
const target = DEPLOY_TARGETS[rec.id];
|
|
298
|
+
console.log(` ${utils.COLORS.cyan}${rec.id}${utils.COLORS.reset} - ${target.description}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
console.log('');
|
|
302
|
+
console.log('Run: bootspring deploy init <target>');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Display quality results
|
|
307
|
+
*/
|
|
308
|
+
function displayQualityResults(result) {
|
|
309
|
+
if (result.skipped) return;
|
|
310
|
+
|
|
311
|
+
console.log('');
|
|
312
|
+
for (const [check, status] of Object.entries(result.checks)) {
|
|
313
|
+
if (status.passed === null) continue;
|
|
314
|
+
|
|
315
|
+
const icon = status.passed ?
|
|
316
|
+
`${utils.COLORS.green}✓${utils.COLORS.reset}` :
|
|
317
|
+
`${utils.COLORS.yellow}○${utils.COLORS.reset}`;
|
|
318
|
+
console.log(` ${icon} ${check}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Display completion summary
|
|
324
|
+
*/
|
|
325
|
+
function displayCompletionSummary(workflow, options) {
|
|
326
|
+
const progress = workflow.getProgress();
|
|
327
|
+
const deployResult = workflow.state.phases.deploy?.result;
|
|
328
|
+
|
|
329
|
+
console.log('');
|
|
330
|
+
|
|
331
|
+
if (options.dryRun) {
|
|
332
|
+
utils.print.info('Dry run complete - no changes made');
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (deployResult?.url) {
|
|
337
|
+
utils.print.success('Deployment successful!');
|
|
338
|
+
console.log('');
|
|
339
|
+
console.log(` ${utils.COLORS.bold}URL:${utils.COLORS.reset} ${deployResult.url}`);
|
|
340
|
+
} else if (deployResult?.success) {
|
|
341
|
+
utils.print.success('Deployment successful!');
|
|
342
|
+
} else {
|
|
343
|
+
utils.print.warning('Deployment completed with warnings');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log('');
|
|
347
|
+
utils.print.info('Next steps:');
|
|
348
|
+
console.log(' 1. Verify your deployment is working');
|
|
349
|
+
console.log(' 2. Set up environment variables if needed');
|
|
350
|
+
console.log(' 3. Configure custom domain (optional)');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Format check name
|
|
355
|
+
*/
|
|
356
|
+
function formatCheckName(name) {
|
|
357
|
+
const names = {
|
|
358
|
+
packageJson: 'package.json exists',
|
|
359
|
+
nodeModules: 'Dependencies installed',
|
|
360
|
+
buildScript: 'Build script available',
|
|
361
|
+
gitClean: 'Git working tree clean',
|
|
362
|
+
envFile: 'Environment file exists'
|
|
363
|
+
};
|
|
364
|
+
return names[name] || name;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Show deployment status
|
|
369
|
+
*/
|
|
370
|
+
async function deployStatus() {
|
|
371
|
+
const workflow = new DeployWorkflowEngine(projectRoot);
|
|
372
|
+
|
|
373
|
+
if (!workflow.hasWorkflow()) {
|
|
374
|
+
utils.print.info('No deployment workflow started.');
|
|
375
|
+
utils.print.info('Run "bootspring deploy" to begin.');
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
workflow.loadState();
|
|
380
|
+
const progress = workflow.getProgress();
|
|
381
|
+
|
|
382
|
+
utils.print.header('Deployment Status');
|
|
383
|
+
|
|
384
|
+
console.log(`Progress: ${progress.overall.percentage}% complete`);
|
|
385
|
+
console.log(`Target: ${progress.target || 'not set'}`);
|
|
386
|
+
console.log(`Started: ${progress.startedAt ? new Date(progress.startedAt).toLocaleString() : 'N/A'}`);
|
|
387
|
+
console.log('');
|
|
388
|
+
|
|
389
|
+
console.log('Phases:');
|
|
390
|
+
for (const phase of progress.phases) {
|
|
391
|
+
const statusIcon = getStatusIcon(phase.status);
|
|
392
|
+
const required = phase.required ? '' : ' (optional)';
|
|
393
|
+
console.log(` ${statusIcon} ${phase.name}${required}`);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (progress.isComplete) {
|
|
397
|
+
console.log('');
|
|
398
|
+
const deployResult = workflow.state.phases.deploy?.result;
|
|
399
|
+
if (deployResult?.url) {
|
|
400
|
+
console.log(`URL: ${deployResult.url}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* List available targets
|
|
407
|
+
*/
|
|
408
|
+
function listTargets() {
|
|
409
|
+
const workflow = new DeployWorkflowEngine(projectRoot);
|
|
410
|
+
|
|
411
|
+
utils.print.header('Deployment Targets');
|
|
412
|
+
console.log('');
|
|
413
|
+
|
|
414
|
+
const targets = workflow.getAllTargets();
|
|
415
|
+
|
|
416
|
+
for (const target of targets) {
|
|
417
|
+
const installed = workflow.checkCliInstalled(target.cli);
|
|
418
|
+
const icon = installed ?
|
|
419
|
+
`${utils.COLORS.green}✓${utils.COLORS.reset}` :
|
|
420
|
+
`${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
421
|
+
|
|
422
|
+
console.log(` ${icon} ${utils.COLORS.cyan}${target.id}${utils.COLORS.reset}`);
|
|
423
|
+
console.log(` ${utils.COLORS.dim}${target.description}${utils.COLORS.reset}`);
|
|
424
|
+
console.log(` CLI: ${target.cli} ${installed ? '(installed)' : '(not installed)'}`);
|
|
425
|
+
console.log('');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
console.log('Install a CLI to enable deployment:');
|
|
429
|
+
console.log(` ${utils.COLORS.dim}npm install -g vercel${utils.COLORS.reset}`);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Initialize deployment config
|
|
434
|
+
*/
|
|
435
|
+
async function deployInit(args) {
|
|
436
|
+
const targetId = args._[1];
|
|
437
|
+
|
|
438
|
+
if (!targetId) {
|
|
439
|
+
utils.print.error('Specify a target: bootspring deploy init <target>');
|
|
440
|
+
console.log('');
|
|
441
|
+
console.log('Available targets: vercel, railway, fly, netlify, docker, aws');
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const workflow = new DeployWorkflowEngine(projectRoot);
|
|
446
|
+
const config = workflow.generateTargetConfig(targetId);
|
|
447
|
+
|
|
448
|
+
if (!config) {
|
|
449
|
+
utils.print.error(`Unknown target: ${targetId}`);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const filePath = path.join(projectRoot, config.file);
|
|
454
|
+
|
|
455
|
+
if (fs.existsSync(filePath)) {
|
|
456
|
+
utils.print.warning(`${config.file} already exists`);
|
|
457
|
+
utils.print.info('Use --force to overwrite');
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const spinner = utils.createSpinner(`Creating ${config.file}...`).start();
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
fs.writeFileSync(filePath, config.content);
|
|
465
|
+
spinner.succeed(`Created ${config.file}`);
|
|
466
|
+
|
|
467
|
+
const target = workflow.getTargetInfo(targetId);
|
|
468
|
+
console.log('');
|
|
469
|
+
utils.print.info('Next steps:');
|
|
470
|
+
console.log(` 1. Install CLI: ${target.installCmd}`);
|
|
471
|
+
console.log(` 2. Login: ${target.cli} login`);
|
|
472
|
+
console.log(` 3. Deploy: bootspring deploy ${targetId}`);
|
|
473
|
+
} catch (error) {
|
|
474
|
+
spinner.fail(`Failed: ${error.message}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Reset deployment workflow
|
|
480
|
+
*/
|
|
481
|
+
async function deployReset() {
|
|
482
|
+
const workflow = new DeployWorkflowEngine(projectRoot);
|
|
483
|
+
|
|
484
|
+
if (!workflow.hasWorkflow()) {
|
|
485
|
+
utils.print.info('No workflow to reset.');
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
workflow.resetWorkflow();
|
|
490
|
+
utils.print.success('Deployment workflow reset.');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Get status icon
|
|
495
|
+
*/
|
|
496
|
+
function getStatusIcon(status) {
|
|
497
|
+
switch (status) {
|
|
498
|
+
case 'completed':
|
|
499
|
+
return `${utils.COLORS.green}✓${utils.COLORS.reset}`;
|
|
500
|
+
case 'in_progress':
|
|
501
|
+
return `${utils.COLORS.cyan}●${utils.COLORS.reset}`;
|
|
502
|
+
case 'failed':
|
|
503
|
+
return `${utils.COLORS.red}✗${utils.COLORS.reset}`;
|
|
504
|
+
case 'skipped':
|
|
505
|
+
return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
506
|
+
default:
|
|
507
|
+
return `${utils.COLORS.dim}○${utils.COLORS.reset}`;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Main entry point
|
|
513
|
+
*/
|
|
514
|
+
async function run(args) {
|
|
515
|
+
const parsedArgs = utils.parseArgs(args);
|
|
516
|
+
const subcommand = parsedArgs._[0];
|
|
517
|
+
|
|
518
|
+
switch (subcommand) {
|
|
519
|
+
case 'status':
|
|
520
|
+
return deployStatus();
|
|
521
|
+
|
|
522
|
+
case 'targets':
|
|
523
|
+
case 'list':
|
|
524
|
+
return listTargets();
|
|
525
|
+
|
|
526
|
+
case 'init':
|
|
527
|
+
return deployInit(parsedArgs);
|
|
528
|
+
|
|
529
|
+
case 'reset':
|
|
530
|
+
return deployReset();
|
|
531
|
+
|
|
532
|
+
case 'help':
|
|
533
|
+
case '--help':
|
|
534
|
+
case '-h':
|
|
535
|
+
return showHelp();
|
|
536
|
+
|
|
537
|
+
default:
|
|
538
|
+
// Start deployment (subcommand might be a target)
|
|
539
|
+
return deployStart(parsedArgs);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
module.exports = { run };
|