@girardmedia/bootspring 1.1.0
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/LICENSE +21 -0
- package/README.md +255 -0
- package/agents/README.md +93 -0
- package/agents/api-expert/context.md +416 -0
- package/agents/architecture-expert/context.md +454 -0
- package/agents/backend-expert/context.md +483 -0
- package/agents/code-review-expert/context.md +365 -0
- package/agents/database-expert/context.md +250 -0
- package/agents/devops-expert/context.md +446 -0
- package/agents/frontend-expert/context.md +364 -0
- package/agents/index.js +140 -0
- package/agents/performance-expert/context.md +377 -0
- package/agents/security-expert/context.md +343 -0
- package/agents/testing-expert/context.md +414 -0
- package/agents/ui-ux-expert/context.md +448 -0
- package/agents/vercel-expert/context.md +426 -0
- package/bin/bootspring.js +310 -0
- package/cli/agent.js +337 -0
- package/cli/context.js +194 -0
- package/cli/dashboard.js +150 -0
- package/cli/generate.js +294 -0
- package/cli/init.js +410 -0
- package/cli/loop.js +421 -0
- package/cli/mcp.js +241 -0
- package/cli/memory.js +303 -0
- package/cli/orchestrator.js +400 -0
- package/cli/plugin.js +451 -0
- package/cli/quality.js +332 -0
- package/cli/skill.js +369 -0
- package/cli/task.js +628 -0
- package/cli/telemetry.js +114 -0
- package/cli/todo.js +614 -0
- package/cli/update.js +312 -0
- package/core/config.js +245 -0
- package/core/context.js +329 -0
- package/core/entitlements.js +209 -0
- package/core/index.js +43 -0
- package/core/policies.js +68 -0
- package/core/telemetry.js +247 -0
- package/core/utils.js +380 -0
- package/dashboard/server.js +818 -0
- package/docs/integrations/claude-code.md +42 -0
- package/docs/integrations/codex.md +42 -0
- package/docs/mcp-api-platform.md +102 -0
- package/generators/generate.js +598 -0
- package/generators/index.js +18 -0
- package/hooks/context-detector.js +177 -0
- package/hooks/index.js +35 -0
- package/hooks/prompt-enhancer.js +289 -0
- package/intelligence/git-memory.js +551 -0
- package/intelligence/index.js +59 -0
- package/intelligence/orchestrator.js +964 -0
- package/intelligence/prd.js +447 -0
- package/intelligence/recommendation-weights.json +18 -0
- package/intelligence/recommendations.js +234 -0
- package/mcp/capabilities.js +71 -0
- package/mcp/contracts/mcp-contract.v1.json +497 -0
- package/mcp/registry.js +213 -0
- package/mcp/response-formatter.js +462 -0
- package/mcp/server.js +99 -0
- package/mcp/tools/agent-tool.js +137 -0
- package/mcp/tools/capabilities-tool.js +54 -0
- package/mcp/tools/context-tool.js +49 -0
- package/mcp/tools/dashboard-tool.js +58 -0
- package/mcp/tools/generate-tool.js +46 -0
- package/mcp/tools/loop-tool.js +134 -0
- package/mcp/tools/memory-tool.js +180 -0
- package/mcp/tools/orchestrator-tool.js +232 -0
- package/mcp/tools/plugin-tool.js +76 -0
- package/mcp/tools/quality-tool.js +47 -0
- package/mcp/tools/skill-tool.js +233 -0
- package/mcp/tools/telemetry-tool.js +95 -0
- package/mcp/tools/todo-tool.js +133 -0
- package/package.json +98 -0
- package/plugins/index.js +141 -0
- package/quality/index.js +380 -0
- package/quality/lint-budgets.json +19 -0
- package/skills/index.js +787 -0
- package/skills/patterns/README.md +163 -0
- package/skills/patterns/api/route-handler.md +217 -0
- package/skills/patterns/api/server-action.md +249 -0
- package/skills/patterns/auth/clerk.md +132 -0
- package/skills/patterns/database/prisma.md +180 -0
- package/skills/patterns/payments/stripe.md +272 -0
- package/skills/patterns/security/validation.md +268 -0
- package/skills/patterns/testing/vitest.md +307 -0
- package/templates/bootspring.config.js +83 -0
- package/templates/mcp.json +9 -0
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bootspring Intelligence Orchestrator
|
|
5
|
+
*
|
|
6
|
+
* Coordinates agent execution based on:
|
|
7
|
+
* - Project lifecycle phase
|
|
8
|
+
* - Detected events and triggers
|
|
9
|
+
* - Task requirements
|
|
10
|
+
* - Agent collaboration patterns
|
|
11
|
+
*
|
|
12
|
+
* @package bootspring
|
|
13
|
+
* @module intelligence/orchestrator
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const telemetry = require('../core/telemetry');
|
|
19
|
+
|
|
20
|
+
// Paths (resolved relative to bootspring package)
|
|
21
|
+
function getPaths() {
|
|
22
|
+
// Find the bootspring directory
|
|
23
|
+
let bootspringDir = __dirname;
|
|
24
|
+
while (!fs.existsSync(path.join(bootspringDir, 'package.json')) && bootspringDir !== '/') {
|
|
25
|
+
bootspringDir = path.dirname(bootspringDir);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const projectRoot = process.cwd();
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
bootspringDir,
|
|
32
|
+
projectRoot,
|
|
33
|
+
agentsDir: path.join(bootspringDir, 'agents', 'profiles'),
|
|
34
|
+
statePath: path.join(projectRoot, '.bootspring', 'orchestrator-state.json'),
|
|
35
|
+
roadmapPath: path.join(projectRoot, 'ROADMAP.md')
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Colors
|
|
40
|
+
const c = {
|
|
41
|
+
reset: '\x1b[0m',
|
|
42
|
+
bold: '\x1b[1m',
|
|
43
|
+
dim: '\x1b[2m',
|
|
44
|
+
green: '\x1b[32m',
|
|
45
|
+
blue: '\x1b[34m',
|
|
46
|
+
yellow: '\x1b[33m',
|
|
47
|
+
cyan: '\x1b[36m',
|
|
48
|
+
red: '\x1b[31m',
|
|
49
|
+
magenta: '\x1b[35m'
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Agent lifecycle phase mapping
|
|
54
|
+
* Maps project phases to recommended agents
|
|
55
|
+
*/
|
|
56
|
+
const PHASE_AGENTS = {
|
|
57
|
+
1: {
|
|
58
|
+
name: 'Foundation',
|
|
59
|
+
description: 'Initial setup, planning, and architecture decisions',
|
|
60
|
+
primary: ['architecture-expert', 'database-expert'],
|
|
61
|
+
supporting: ['security-expert', 'devops-expert']
|
|
62
|
+
},
|
|
63
|
+
2: {
|
|
64
|
+
name: 'Requirements',
|
|
65
|
+
description: 'Data modeling, research, and specification',
|
|
66
|
+
primary: ['database-expert', 'api-expert'],
|
|
67
|
+
supporting: ['testing-expert']
|
|
68
|
+
},
|
|
69
|
+
3: {
|
|
70
|
+
name: 'Design',
|
|
71
|
+
description: 'UI/UX, database schema, API contracts',
|
|
72
|
+
primary: ['frontend-expert', 'ui-ux-expert', 'database-expert', 'api-expert'],
|
|
73
|
+
supporting: ['security-expert']
|
|
74
|
+
},
|
|
75
|
+
4: {
|
|
76
|
+
name: 'Implementation',
|
|
77
|
+
description: 'Core feature development',
|
|
78
|
+
primary: ['backend-expert', 'frontend-expert', 'database-expert'],
|
|
79
|
+
supporting: ['performance-expert', 'code-review-expert']
|
|
80
|
+
},
|
|
81
|
+
5: {
|
|
82
|
+
name: 'Testing',
|
|
83
|
+
description: 'Quality assurance and security review',
|
|
84
|
+
primary: ['testing-expert', 'security-expert', 'code-review-expert'],
|
|
85
|
+
supporting: ['performance-expert']
|
|
86
|
+
},
|
|
87
|
+
6: {
|
|
88
|
+
name: 'Deployment',
|
|
89
|
+
description: 'CI/CD, infrastructure, and monitoring',
|
|
90
|
+
primary: ['devops-expert', 'vercel-expert'],
|
|
91
|
+
supporting: ['security-expert', 'performance-expert']
|
|
92
|
+
},
|
|
93
|
+
7: {
|
|
94
|
+
name: 'Launch',
|
|
95
|
+
description: 'Go-live and post-launch optimization',
|
|
96
|
+
primary: ['devops-expert', 'performance-expert'],
|
|
97
|
+
supporting: ['security-expert']
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Technical context triggers
|
|
103
|
+
* Maps keywords to recommended agents
|
|
104
|
+
*/
|
|
105
|
+
const TECHNICAL_TRIGGERS = {
|
|
106
|
+
'api': {
|
|
107
|
+
agents: ['api-expert', 'backend-expert', 'security-expert'],
|
|
108
|
+
indicators: ['api', 'endpoint', 'REST', 'GraphQL', 'route', 'handler'],
|
|
109
|
+
skills: ['api/route-handler', 'api/server-action']
|
|
110
|
+
},
|
|
111
|
+
'database': {
|
|
112
|
+
agents: ['database-expert', 'backend-expert'],
|
|
113
|
+
indicators: ['database', 'schema', 'prisma', 'migration', 'query', 'model', 'sql'],
|
|
114
|
+
skills: ['database/prisma']
|
|
115
|
+
},
|
|
116
|
+
'frontend': {
|
|
117
|
+
agents: ['frontend-expert', 'ui-ux-expert'],
|
|
118
|
+
indicators: ['component', 'react', 'tailwind', 'ui', 'ux', 'page', 'layout', 'css'],
|
|
119
|
+
skills: []
|
|
120
|
+
},
|
|
121
|
+
'authentication': {
|
|
122
|
+
agents: ['security-expert', 'backend-expert'],
|
|
123
|
+
indicators: ['auth', 'login', 'signup', 'session', 'clerk', 'jwt', 'oauth', 'password'],
|
|
124
|
+
skills: ['auth/clerk', 'auth/nextauth']
|
|
125
|
+
},
|
|
126
|
+
'security': {
|
|
127
|
+
agents: ['security-expert'],
|
|
128
|
+
indicators: ['security', 'vulnerability', 'OWASP', 'xss', 'csrf', 'injection', 'sanitize'],
|
|
129
|
+
skills: []
|
|
130
|
+
},
|
|
131
|
+
'performance': {
|
|
132
|
+
agents: ['performance-expert', 'database-expert'],
|
|
133
|
+
indicators: ['performance', 'speed', 'optimization', 'cache', 'slow', 'memory', 'bundle'],
|
|
134
|
+
skills: []
|
|
135
|
+
},
|
|
136
|
+
'deployment': {
|
|
137
|
+
agents: ['devops-expert', 'vercel-expert'],
|
|
138
|
+
indicators: ['deploy', 'CI/CD', 'docker', 'kubernetes', 'production', 'vercel', 'hosting'],
|
|
139
|
+
skills: []
|
|
140
|
+
},
|
|
141
|
+
'testing': {
|
|
142
|
+
agents: ['testing-expert', 'code-review-expert'],
|
|
143
|
+
indicators: ['test', 'jest', 'vitest', 'playwright', 'coverage', 'spec', 'mock'],
|
|
144
|
+
skills: ['testing/vitest']
|
|
145
|
+
},
|
|
146
|
+
'payments': {
|
|
147
|
+
agents: ['backend-expert', 'security-expert'],
|
|
148
|
+
indicators: ['stripe', 'payment', 'subscription', 'checkout', 'billing', 'invoice'],
|
|
149
|
+
skills: ['payments/stripe']
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Predefined workflows for common scenarios
|
|
155
|
+
*/
|
|
156
|
+
const WORKFLOWS = {
|
|
157
|
+
'feature-development': {
|
|
158
|
+
name: 'Feature Development',
|
|
159
|
+
description: 'End-to-end feature implementation workflow',
|
|
160
|
+
tier: 'free',
|
|
161
|
+
pack: null,
|
|
162
|
+
outcomes: ['Feature shipped with tests and review complete'],
|
|
163
|
+
completionSignals: ['PR merged', 'Tests passing in CI', 'Security/perf review completed'],
|
|
164
|
+
phases: [
|
|
165
|
+
{ name: 'Design', agents: ['ui-ux-expert', 'frontend-expert', 'api-expert'], duration: '1-2 days' },
|
|
166
|
+
{ name: 'Implementation', agents: ['backend-expert', 'frontend-expert', 'database-expert'], duration: '2-5 days' },
|
|
167
|
+
{ name: 'Testing', agents: ['testing-expert', 'code-review-expert'], duration: '1-2 days' },
|
|
168
|
+
{ name: 'Review', agents: ['security-expert', 'performance-expert'], duration: '1 day' }
|
|
169
|
+
]
|
|
170
|
+
},
|
|
171
|
+
'security-audit': {
|
|
172
|
+
name: 'Security Audit',
|
|
173
|
+
description: 'Comprehensive security review',
|
|
174
|
+
tier: 'free',
|
|
175
|
+
pack: null,
|
|
176
|
+
outcomes: ['Critical/high vulnerabilities remediated'],
|
|
177
|
+
completionSignals: ['Security findings closed', 'Post-fix verification complete'],
|
|
178
|
+
phases: [
|
|
179
|
+
{ name: 'Code Review', agents: ['code-review-expert', 'security-expert'], duration: '2-3 days' },
|
|
180
|
+
{ name: 'Vulnerability Scan', agents: ['security-expert'], duration: '1 day' },
|
|
181
|
+
{ name: 'Remediation', agents: ['security-expert', 'backend-expert'], duration: '2-5 days' }
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
'performance-optimization': {
|
|
185
|
+
name: 'Performance Optimization',
|
|
186
|
+
description: 'Full performance review and optimization',
|
|
187
|
+
tier: 'free',
|
|
188
|
+
pack: null,
|
|
189
|
+
outcomes: ['Performance regressions reduced and hotspots addressed'],
|
|
190
|
+
completionSignals: ['Baseline captured', 'Improvement report documented'],
|
|
191
|
+
phases: [
|
|
192
|
+
{ name: 'Analysis', agents: ['performance-expert'], duration: '1-2 days' },
|
|
193
|
+
{ name: 'Database', agents: ['database-expert', 'performance-expert'], duration: '2-3 days' },
|
|
194
|
+
{ name: 'Frontend', agents: ['frontend-expert', 'performance-expert'], duration: '2-3 days' },
|
|
195
|
+
{ name: 'Infrastructure', agents: ['devops-expert'], duration: '1-2 days' }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
'api-development': {
|
|
199
|
+
name: 'API Development',
|
|
200
|
+
description: 'Design and implement new API endpoints',
|
|
201
|
+
tier: 'free',
|
|
202
|
+
pack: null,
|
|
203
|
+
outcomes: ['API endpoints delivered with security and test coverage'],
|
|
204
|
+
completionSignals: ['Contract approved', 'API tests passing', 'Auth/rate limits verified'],
|
|
205
|
+
phases: [
|
|
206
|
+
{ name: 'Design', agents: ['api-expert', 'database-expert'], duration: '1 day' },
|
|
207
|
+
{ name: 'Implementation', agents: ['backend-expert', 'api-expert'], duration: '2-3 days' },
|
|
208
|
+
{ name: 'Security', agents: ['security-expert'], duration: '1 day' },
|
|
209
|
+
{ name: 'Testing', agents: ['testing-expert'], duration: '1 day' }
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
'database-migration': {
|
|
213
|
+
name: 'Database Migration',
|
|
214
|
+
description: 'Schema changes and data migration',
|
|
215
|
+
tier: 'free',
|
|
216
|
+
pack: null,
|
|
217
|
+
outcomes: ['Migration completed safely with rollback readiness'],
|
|
218
|
+
completionSignals: ['Migration rehearsed', 'Rollback tested', 'Data integrity checks passing'],
|
|
219
|
+
phases: [
|
|
220
|
+
{ name: 'Schema Design', agents: ['database-expert'], duration: '1 day' },
|
|
221
|
+
{ name: 'Migration Plan', agents: ['database-expert', 'devops-expert'], duration: '1 day' },
|
|
222
|
+
{ name: 'Implementation', agents: ['database-expert', 'backend-expert'], duration: '2-3 days' },
|
|
223
|
+
{ name: 'Verification', agents: ['testing-expert'], duration: '1 day' }
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
'launch-preparation': {
|
|
227
|
+
name: 'Launch Preparation',
|
|
228
|
+
description: 'Pre-launch checklist and deployment',
|
|
229
|
+
tier: 'free',
|
|
230
|
+
pack: null,
|
|
231
|
+
outcomes: ['Launch readiness validated across quality, security, and ops'],
|
|
232
|
+
completionSignals: ['Release checklist complete', 'Monitoring configured', 'Rollback plan confirmed'],
|
|
233
|
+
phases: [
|
|
234
|
+
{ name: 'Testing', agents: ['testing-expert', 'performance-expert'], duration: '2-3 days' },
|
|
235
|
+
{ name: 'Security', agents: ['security-expert'], duration: '1-2 days' },
|
|
236
|
+
{ name: 'Deployment', agents: ['devops-expert', 'vercel-expert'], duration: '1 day' },
|
|
237
|
+
{ name: 'Monitoring', agents: ['devops-expert', 'performance-expert'], duration: '1 day' }
|
|
238
|
+
]
|
|
239
|
+
},
|
|
240
|
+
'launch-pack': {
|
|
241
|
+
name: 'Launch Pack',
|
|
242
|
+
description: 'Premium guided launch workflow from freeze to production validation',
|
|
243
|
+
tier: 'pro',
|
|
244
|
+
pack: 'launch',
|
|
245
|
+
outcomes: ['Production launch completed with no P0 regressions in first 48h'],
|
|
246
|
+
completionSignals: ['Change freeze checklist complete', 'Launch playbook executed', 'Post-launch metrics healthy'],
|
|
247
|
+
phases: [
|
|
248
|
+
{ name: 'Readiness Gate', agents: ['testing-expert', 'security-expert', 'performance-expert'], duration: '1-2 days' },
|
|
249
|
+
{ name: 'Cutover Plan', agents: ['devops-expert', 'architecture-expert'], duration: '1 day' },
|
|
250
|
+
{ name: 'Go-Live', agents: ['devops-expert', 'vercel-expert'], duration: 'same day' },
|
|
251
|
+
{ name: 'Stabilization', agents: ['performance-expert', 'backend-expert'], duration: '2 days' }
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
'reliability-pack': {
|
|
255
|
+
name: 'Reliability Pack',
|
|
256
|
+
description: 'Premium reliability hardening workflow for incidents and regressions',
|
|
257
|
+
tier: 'pro',
|
|
258
|
+
pack: 'reliability',
|
|
259
|
+
outcomes: ['Error budget burn reduced and top incident classes mitigated'],
|
|
260
|
+
completionSignals: ['SLOs defined', 'Top 3 failure modes mitigated', 'Runbooks verified in drill'],
|
|
261
|
+
phases: [
|
|
262
|
+
{ name: 'Reliability Baseline', agents: ['performance-expert', 'devops-expert'], duration: '1 day' },
|
|
263
|
+
{ name: 'Failure Mode Audit', agents: ['security-expert', 'backend-expert'], duration: '1-2 days' },
|
|
264
|
+
{ name: 'Resilience Implementation', agents: ['backend-expert', 'database-expert'], duration: '2-4 days' },
|
|
265
|
+
{ name: 'Game Day Validation', agents: ['testing-expert', 'devops-expert'], duration: '1 day' }
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
'growth-pack': {
|
|
269
|
+
name: 'Growth Pack',
|
|
270
|
+
description: 'Premium experimentation workflow for activation and conversion improvements',
|
|
271
|
+
tier: 'pro',
|
|
272
|
+
pack: 'growth',
|
|
273
|
+
outcomes: ['Primary growth KPI improved with statistically valid experiment result'],
|
|
274
|
+
completionSignals: ['North-star metric selected', 'Experiment shipped', 'Readout documented with decision'],
|
|
275
|
+
phases: [
|
|
276
|
+
{ name: 'Metric Design', agents: ['architecture-expert', 'frontend-expert'], duration: '1 day' },
|
|
277
|
+
{ name: 'Instrumentation', agents: ['backend-expert', 'api-expert'], duration: '1-2 days' },
|
|
278
|
+
{ name: 'Experiment Build', agents: ['frontend-expert', 'backend-expert'], duration: '2-3 days' },
|
|
279
|
+
{ name: 'Analysis & Decision', agents: ['code-review-expert', 'architecture-expert'], duration: '1 day' }
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Load orchestrator state from project
|
|
286
|
+
*/
|
|
287
|
+
function loadState() {
|
|
288
|
+
const paths = getPaths();
|
|
289
|
+
|
|
290
|
+
if (fs.existsSync(paths.statePath)) {
|
|
291
|
+
try {
|
|
292
|
+
return JSON.parse(fs.readFileSync(paths.statePath, 'utf8'));
|
|
293
|
+
} catch (e) {
|
|
294
|
+
return createDefaultState();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return createDefaultState();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Create default orchestrator state
|
|
302
|
+
*/
|
|
303
|
+
function createDefaultState() {
|
|
304
|
+
return {
|
|
305
|
+
lastAnalysis: null,
|
|
306
|
+
currentPhase: 1,
|
|
307
|
+
activeWorkflow: null,
|
|
308
|
+
workflowStep: 0,
|
|
309
|
+
workflowSignals: {},
|
|
310
|
+
recentAgents: [],
|
|
311
|
+
suggestions: [],
|
|
312
|
+
history: []
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function emitWorkflowTelemetry(event, payload = {}) {
|
|
317
|
+
const paths = getPaths();
|
|
318
|
+
try {
|
|
319
|
+
telemetry.emitEvent(event, payload, { projectRoot: paths.projectRoot });
|
|
320
|
+
} catch {
|
|
321
|
+
// Telemetry should not block workflow execution.
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function getWorkflowSignalProgress(workflowName, state = null) {
|
|
326
|
+
const workflow = WORKFLOWS[workflowName];
|
|
327
|
+
if (!workflow) return null;
|
|
328
|
+
|
|
329
|
+
const activeState = state || loadState();
|
|
330
|
+
const completed = new Set(activeState.workflowSignals?.[workflowName] || []);
|
|
331
|
+
const signals = workflow.completionSignals || [];
|
|
332
|
+
const pending = signals.filter(signal => !completed.has(signal));
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
workflow: workflowName,
|
|
336
|
+
totalSignals: signals.length,
|
|
337
|
+
completedSignals: Array.from(completed),
|
|
338
|
+
pendingSignals: pending
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function resolveSignal(workflow, signalRef, stateSignals = []) {
|
|
343
|
+
const signals = workflow.completionSignals || [];
|
|
344
|
+
if (signals.length === 0) return null;
|
|
345
|
+
|
|
346
|
+
const completedSet = new Set(stateSignals);
|
|
347
|
+
const trimmed = String(signalRef || '').trim();
|
|
348
|
+
if (!trimmed) {
|
|
349
|
+
return signals.find(signal => !completedSet.has(signal)) || null;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const byIndex = Number(trimmed);
|
|
353
|
+
if (Number.isInteger(byIndex) && byIndex >= 1 && byIndex <= signals.length) {
|
|
354
|
+
return signals[byIndex - 1];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const lower = trimmed.toLowerCase();
|
|
358
|
+
return signals.find(signal => signal.toLowerCase().includes(lower)) || null;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Save orchestrator state
|
|
363
|
+
*/
|
|
364
|
+
function saveState(state) {
|
|
365
|
+
const paths = getPaths();
|
|
366
|
+
|
|
367
|
+
// Ensure .bootspring directory exists
|
|
368
|
+
const stateDir = path.dirname(paths.statePath);
|
|
369
|
+
if (!fs.existsSync(stateDir)) {
|
|
370
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
state.lastUpdated = new Date().toISOString();
|
|
374
|
+
fs.writeFileSync(paths.statePath, JSON.stringify(state, null, 2));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get current phase from ROADMAP.md
|
|
379
|
+
*/
|
|
380
|
+
function getCurrentPhase() {
|
|
381
|
+
const paths = getPaths();
|
|
382
|
+
|
|
383
|
+
try {
|
|
384
|
+
if (!fs.existsSync(paths.roadmapPath)) return 1;
|
|
385
|
+
|
|
386
|
+
const content = fs.readFileSync(paths.roadmapPath, 'utf8');
|
|
387
|
+
|
|
388
|
+
for (let i = 1; i <= 7; i++) {
|
|
389
|
+
const phaseRegex = new RegExp(`## Phase ${i}[\\s\\S]*?(?=## Phase|$)`, 'i');
|
|
390
|
+
const match = content.match(phaseRegex);
|
|
391
|
+
if (match) {
|
|
392
|
+
const incomplete = match[0].match(/- \[ \]/g);
|
|
393
|
+
if (incomplete && incomplete.length > 0) {
|
|
394
|
+
return i;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return 7;
|
|
399
|
+
} catch (e) {
|
|
400
|
+
return 1;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Get the AGENTS object from cli/agent.js
|
|
406
|
+
*/
|
|
407
|
+
function getAgentsRegistry() {
|
|
408
|
+
try {
|
|
409
|
+
const agentModule = require('../cli/agent');
|
|
410
|
+
return agentModule.AGENTS || {};
|
|
411
|
+
} catch (e) {
|
|
412
|
+
// Fallback to checking files
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Check if an agent exists
|
|
419
|
+
*/
|
|
420
|
+
function agentExists(agentName) {
|
|
421
|
+
// First try the AGENTS registry
|
|
422
|
+
const registry = getAgentsRegistry();
|
|
423
|
+
if (registry) {
|
|
424
|
+
return agentName in registry;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// Fallback to checking files
|
|
428
|
+
const paths = getPaths();
|
|
429
|
+
const agentFile = path.join(paths.agentsDir, `${agentName}.md`);
|
|
430
|
+
return fs.existsSync(agentFile);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Get list of available agents
|
|
435
|
+
*/
|
|
436
|
+
function getAvailableAgents() {
|
|
437
|
+
// First try the AGENTS registry
|
|
438
|
+
const registry = getAgentsRegistry();
|
|
439
|
+
if (registry) {
|
|
440
|
+
return Object.keys(registry);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Fallback to checking files
|
|
444
|
+
const paths = getPaths();
|
|
445
|
+
|
|
446
|
+
if (!fs.existsSync(paths.agentsDir)) {
|
|
447
|
+
return [];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return fs.readdirSync(paths.agentsDir)
|
|
451
|
+
.filter(f => f.endsWith('.md'))
|
|
452
|
+
.map(f => f.replace('.md', ''));
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Analyze context and suggest agents
|
|
457
|
+
*/
|
|
458
|
+
function analyzeContext(input = '') {
|
|
459
|
+
const state = loadState();
|
|
460
|
+
const currentPhase = getCurrentPhase();
|
|
461
|
+
const suggestions = [];
|
|
462
|
+
const matchedSkills = [];
|
|
463
|
+
|
|
464
|
+
// Add phase-based agents
|
|
465
|
+
const phaseConfig = PHASE_AGENTS[currentPhase];
|
|
466
|
+
if (phaseConfig) {
|
|
467
|
+
phaseConfig.primary.forEach(agent => {
|
|
468
|
+
if (agentExists(agent)) {
|
|
469
|
+
suggestions.push({
|
|
470
|
+
agent,
|
|
471
|
+
reason: `Phase ${currentPhase} (${phaseConfig.name}) - primary agent`,
|
|
472
|
+
priority: 'high',
|
|
473
|
+
source: 'phase'
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Analyze input for technical triggers
|
|
480
|
+
const inputLower = input.toLowerCase();
|
|
481
|
+
|
|
482
|
+
Object.entries(TECHNICAL_TRIGGERS).forEach(([context, config]) => {
|
|
483
|
+
const matches = config.indicators.filter(ind => inputLower.includes(ind.toLowerCase()));
|
|
484
|
+
if (matches.length > 0) {
|
|
485
|
+
config.agents.forEach(agent => {
|
|
486
|
+
if (agentExists(agent) && !suggestions.find(s => s.agent === agent)) {
|
|
487
|
+
suggestions.push({
|
|
488
|
+
agent,
|
|
489
|
+
reason: `Detected ${context} context (matched: ${matches.join(', ')})`,
|
|
490
|
+
priority: matches.length >= 2 ? 'high' : 'medium',
|
|
491
|
+
source: 'trigger'
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// Collect matching skills
|
|
497
|
+
if (config.skills) {
|
|
498
|
+
matchedSkills.push(...config.skills);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// Sort by priority
|
|
504
|
+
const priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
505
|
+
suggestions.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
|
|
506
|
+
|
|
507
|
+
// Update state
|
|
508
|
+
state.currentPhase = currentPhase;
|
|
509
|
+
state.lastAnalysis = new Date().toISOString();
|
|
510
|
+
state.suggestions = suggestions;
|
|
511
|
+
saveState(state);
|
|
512
|
+
|
|
513
|
+
return {
|
|
514
|
+
phase: currentPhase,
|
|
515
|
+
phaseConfig,
|
|
516
|
+
suggestions,
|
|
517
|
+
skills: [...new Set(matchedSkills)],
|
|
518
|
+
input: input.substring(0, 100)
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Get workflow by name
|
|
524
|
+
*/
|
|
525
|
+
function getWorkflow(name) {
|
|
526
|
+
return WORKFLOWS[name] || null;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* List all workflows
|
|
531
|
+
*/
|
|
532
|
+
function listWorkflows() {
|
|
533
|
+
return Object.entries(WORKFLOWS).map(([key, workflow]) => ({
|
|
534
|
+
key,
|
|
535
|
+
name: workflow.name,
|
|
536
|
+
description: workflow.description,
|
|
537
|
+
phaseCount: workflow.phases.length,
|
|
538
|
+
tier: workflow.tier || 'free',
|
|
539
|
+
pack: workflow.pack || null,
|
|
540
|
+
outcomes: workflow.outcomes || [],
|
|
541
|
+
completionSignals: workflow.completionSignals || []
|
|
542
|
+
}));
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Start a workflow
|
|
547
|
+
*/
|
|
548
|
+
function startWorkflow(workflowName) {
|
|
549
|
+
const workflow = WORKFLOWS[workflowName];
|
|
550
|
+
|
|
551
|
+
if (!workflow) {
|
|
552
|
+
return { success: false, error: `Unknown workflow: ${workflowName}` };
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const state = loadState();
|
|
556
|
+
state.activeWorkflow = workflowName;
|
|
557
|
+
state.workflowStep = 0;
|
|
558
|
+
state.workflowSignals = state.workflowSignals || {};
|
|
559
|
+
state.workflowSignals[workflowName] = state.workflowSignals[workflowName] || [];
|
|
560
|
+
state.history.push({
|
|
561
|
+
action: 'workflow_start',
|
|
562
|
+
workflow: workflowName,
|
|
563
|
+
timestamp: new Date().toISOString()
|
|
564
|
+
});
|
|
565
|
+
saveState(state);
|
|
566
|
+
emitWorkflowTelemetry('workflow_started', {
|
|
567
|
+
workflow: workflowName,
|
|
568
|
+
tier: workflow.tier || 'free',
|
|
569
|
+
pack: workflow.pack || null,
|
|
570
|
+
phaseCount: workflow.phases.length
|
|
571
|
+
});
|
|
572
|
+
if ((workflow.tier || 'free') !== 'free') {
|
|
573
|
+
emitWorkflowTelemetry('premium_unlocked', {
|
|
574
|
+
capability: 'workflow_pack',
|
|
575
|
+
workflow: workflowName,
|
|
576
|
+
tier: workflow.tier || 'free',
|
|
577
|
+
pack: workflow.pack || null,
|
|
578
|
+
source: 'workflow_start'
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return {
|
|
583
|
+
success: true,
|
|
584
|
+
workflowKey: workflowName,
|
|
585
|
+
workflow: workflow.name,
|
|
586
|
+
currentPhase: workflow.phases[0],
|
|
587
|
+
totalPhases: workflow.phases.length,
|
|
588
|
+
completionSignals: workflow.completionSignals || []
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Advance workflow to next step
|
|
594
|
+
*/
|
|
595
|
+
function advanceWorkflow() {
|
|
596
|
+
const state = loadState();
|
|
597
|
+
|
|
598
|
+
if (!state.activeWorkflow) {
|
|
599
|
+
return { success: false, error: 'No active workflow' };
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const workflow = WORKFLOWS[state.activeWorkflow];
|
|
603
|
+
const activeWorkflowName = state.activeWorkflow;
|
|
604
|
+
state.workflowStep += 1;
|
|
605
|
+
|
|
606
|
+
if (state.workflowStep >= workflow.phases.length) {
|
|
607
|
+
// Workflow complete
|
|
608
|
+
state.history.push({
|
|
609
|
+
action: 'workflow_complete',
|
|
610
|
+
workflow: state.activeWorkflow,
|
|
611
|
+
timestamp: new Date().toISOString()
|
|
612
|
+
});
|
|
613
|
+
state.activeWorkflow = null;
|
|
614
|
+
state.workflowStep = 0;
|
|
615
|
+
saveState(state);
|
|
616
|
+
const signalProgress = getWorkflowSignalProgress(activeWorkflowName, state);
|
|
617
|
+
emitWorkflowTelemetry('workflow_completed', {
|
|
618
|
+
workflow: activeWorkflowName,
|
|
619
|
+
tier: workflow.tier || 'free',
|
|
620
|
+
pack: workflow.pack || null,
|
|
621
|
+
phaseCount: workflow.phases.length,
|
|
622
|
+
completedSignalCount: signalProgress?.completedSignals?.length || 0,
|
|
623
|
+
totalSignalCount: signalProgress?.totalSignals || 0
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
return { success: true, complete: true };
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
saveState(state);
|
|
630
|
+
emitWorkflowTelemetry('workflow_step_advanced', {
|
|
631
|
+
workflow: activeWorkflowName,
|
|
632
|
+
tier: workflow.tier || 'free',
|
|
633
|
+
pack: workflow.pack || null,
|
|
634
|
+
step: state.workflowStep + 1,
|
|
635
|
+
totalSteps: workflow.phases.length,
|
|
636
|
+
phaseName: workflow.phases[state.workflowStep]?.name
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
return {
|
|
640
|
+
success: true,
|
|
641
|
+
complete: false,
|
|
642
|
+
currentPhase: workflow.phases[state.workflowStep],
|
|
643
|
+
step: state.workflowStep + 1,
|
|
644
|
+
totalSteps: workflow.phases.length
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function markWorkflowCheckpoint(workflowName, signalRef = '') {
|
|
649
|
+
const state = loadState();
|
|
650
|
+
const targetWorkflow = workflowName || state.activeWorkflow;
|
|
651
|
+
if (!targetWorkflow) {
|
|
652
|
+
return { success: false, error: 'No workflow provided and no active workflow' };
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
const workflow = WORKFLOWS[targetWorkflow];
|
|
656
|
+
if (!workflow) {
|
|
657
|
+
return { success: false, error: `Unknown workflow: ${targetWorkflow}` };
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
state.workflowSignals = state.workflowSignals || {};
|
|
661
|
+
const existing = state.workflowSignals[targetWorkflow] || [];
|
|
662
|
+
const signal = resolveSignal(workflow, signalRef, existing);
|
|
663
|
+
if (!signal) {
|
|
664
|
+
return {
|
|
665
|
+
success: false,
|
|
666
|
+
error: `Signal not found for workflow: ${targetWorkflow}`,
|
|
667
|
+
availableSignals: workflow.completionSignals || []
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const alreadyCompleted = existing.includes(signal);
|
|
672
|
+
if (!alreadyCompleted) {
|
|
673
|
+
existing.push(signal);
|
|
674
|
+
state.workflowSignals[targetWorkflow] = existing;
|
|
675
|
+
state.history.push({
|
|
676
|
+
action: 'workflow_checkpoint',
|
|
677
|
+
workflow: targetWorkflow,
|
|
678
|
+
signal,
|
|
679
|
+
timestamp: new Date().toISOString()
|
|
680
|
+
});
|
|
681
|
+
saveState(state);
|
|
682
|
+
emitWorkflowTelemetry('workflow_checkpoint_completed', {
|
|
683
|
+
workflow: targetWorkflow,
|
|
684
|
+
tier: workflow.tier || 'free',
|
|
685
|
+
pack: workflow.pack || null,
|
|
686
|
+
signal
|
|
687
|
+
});
|
|
688
|
+
if (workflow.pack) {
|
|
689
|
+
emitWorkflowTelemetry('pack_signal_checkpoint', {
|
|
690
|
+
workflow: targetWorkflow,
|
|
691
|
+
pack: workflow.pack,
|
|
692
|
+
signal
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return {
|
|
698
|
+
success: true,
|
|
699
|
+
workflow: targetWorkflow,
|
|
700
|
+
signal,
|
|
701
|
+
alreadyCompleted,
|
|
702
|
+
progress: getWorkflowSignalProgress(targetWorkflow, state)
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Display analysis results
|
|
708
|
+
*/
|
|
709
|
+
function displayAnalysis(analysis) {
|
|
710
|
+
console.log(`\n${c.cyan}+--------------------------------------------------------+${c.reset}`);
|
|
711
|
+
console.log(`${c.cyan}|${c.reset}${c.bold} Bootspring Intelligence Analysis ${c.reset}${c.cyan}|${c.reset}`);
|
|
712
|
+
console.log(`${c.cyan}+--------------------------------------------------------+${c.reset}\n`);
|
|
713
|
+
|
|
714
|
+
console.log(`${c.bold}Current Phase:${c.reset} ${analysis.phase} - ${analysis.phaseConfig?.name || 'Unknown'}`);
|
|
715
|
+
if (analysis.phaseConfig?.description) {
|
|
716
|
+
console.log(`${c.dim}${analysis.phaseConfig.description}${c.reset}`);
|
|
717
|
+
}
|
|
718
|
+
console.log('');
|
|
719
|
+
|
|
720
|
+
if (analysis.suggestions.length === 0) {
|
|
721
|
+
console.log(`${c.yellow}No specific agent suggestions for this context${c.reset}`);
|
|
722
|
+
console.log(`${c.dim}Try adding more context about what you're working on${c.reset}`);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
console.log(`${c.bold}Suggested Agents:${c.reset}\n`);
|
|
727
|
+
|
|
728
|
+
const high = analysis.suggestions.filter(s => s.priority === 'high');
|
|
729
|
+
const medium = analysis.suggestions.filter(s => s.priority === 'medium');
|
|
730
|
+
|
|
731
|
+
if (high.length > 0) {
|
|
732
|
+
console.log(` ${c.green}High Priority:${c.reset}`);
|
|
733
|
+
high.forEach(s => {
|
|
734
|
+
console.log(` ${c.green}*${c.reset} ${s.agent}`);
|
|
735
|
+
console.log(` ${c.dim}${s.reason}${c.reset}`);
|
|
736
|
+
});
|
|
737
|
+
console.log('');
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (medium.length > 0) {
|
|
741
|
+
console.log(` ${c.yellow}Medium Priority:${c.reset}`);
|
|
742
|
+
medium.forEach(s => {
|
|
743
|
+
console.log(` ${c.yellow}*${c.reset} ${s.agent}`);
|
|
744
|
+
console.log(` ${c.dim}${s.reason}${c.reset}`);
|
|
745
|
+
});
|
|
746
|
+
console.log('');
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (analysis.skills.length > 0) {
|
|
750
|
+
console.log(`${c.bold}Relevant Skills:${c.reset}`);
|
|
751
|
+
analysis.skills.forEach(skill => {
|
|
752
|
+
console.log(` ${c.cyan}*${c.reset} ${skill}`);
|
|
753
|
+
});
|
|
754
|
+
console.log('');
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
console.log(`${c.dim}Invoke an agent: bootspring agent invoke <name>${c.reset}`);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Display workflow details
|
|
762
|
+
*/
|
|
763
|
+
function displayWorkflow(workflowName) {
|
|
764
|
+
const workflow = WORKFLOWS[workflowName];
|
|
765
|
+
|
|
766
|
+
if (!workflow) {
|
|
767
|
+
console.log(`${c.red}Unknown workflow: ${workflowName}${c.reset}`);
|
|
768
|
+
console.log('Available: ' + Object.keys(WORKFLOWS).join(', '));
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
console.log(`\n${c.cyan}+--------------------------------------------------------+${c.reset}`);
|
|
773
|
+
console.log(`${c.cyan}|${c.reset}${c.bold} Workflow: ${workflow.name.padEnd(41)}${c.reset}${c.cyan}|${c.reset}`);
|
|
774
|
+
console.log(`${c.cyan}+--------------------------------------------------------+${c.reset}\n`);
|
|
775
|
+
|
|
776
|
+
console.log(`${c.bold}Description:${c.reset} ${workflow.description}\n`);
|
|
777
|
+
console.log(`${c.bold}Phases:${c.reset}\n`);
|
|
778
|
+
|
|
779
|
+
workflow.phases.forEach((phase, i) => {
|
|
780
|
+
const isLast = i === workflow.phases.length - 1;
|
|
781
|
+
const prefix = isLast ? '\\--' : '|--';
|
|
782
|
+
const line = isLast ? ' ' : '| ';
|
|
783
|
+
|
|
784
|
+
console.log(` ${prefix} ${c.cyan}${phase.name}${c.reset} ${c.dim}(${phase.duration})${c.reset}`);
|
|
785
|
+
phase.agents.forEach((agent, j) => {
|
|
786
|
+
const agentPrefix = j === phase.agents.length - 1 ? '\\-' : '|-';
|
|
787
|
+
const exists = agentExists(agent);
|
|
788
|
+
const status = exists ? `${c.green}*${c.reset}` : `${c.red}o${c.reset}`;
|
|
789
|
+
console.log(` ${line} ${agentPrefix} ${status} ${agent}`);
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
console.log('');
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Display orchestrator status
|
|
798
|
+
*/
|
|
799
|
+
function displayStatus() {
|
|
800
|
+
const state = loadState();
|
|
801
|
+
const currentPhase = getCurrentPhase();
|
|
802
|
+
const availableAgents = getAvailableAgents();
|
|
803
|
+
|
|
804
|
+
console.log(`\n${c.cyan}+--------------------------------------------------------+${c.reset}`);
|
|
805
|
+
console.log(`${c.cyan}|${c.reset}${c.bold} Orchestrator Status ${c.reset}${c.cyan}|${c.reset}`);
|
|
806
|
+
console.log(`${c.cyan}+--------------------------------------------------------+${c.reset}\n`);
|
|
807
|
+
|
|
808
|
+
console.log(`${c.bold}Current Phase:${c.reset} ${currentPhase} - ${PHASE_AGENTS[currentPhase]?.name || 'Unknown'}`);
|
|
809
|
+
console.log(`${c.bold}Last Analysis:${c.reset} ${state.lastAnalysis || 'Never'}`);
|
|
810
|
+
console.log(`${c.bold}Active Workflow:${c.reset} ${state.activeWorkflow || 'None'}`);
|
|
811
|
+
|
|
812
|
+
if (state.activeWorkflow) {
|
|
813
|
+
const workflow = WORKFLOWS[state.activeWorkflow];
|
|
814
|
+
console.log(`${c.bold}Workflow Step:${c.reset} ${state.workflowStep + 1}/${workflow.phases.length}`);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (state.suggestions.length > 0) {
|
|
818
|
+
console.log(`\n${c.bold}Last Suggestions:${c.reset}`);
|
|
819
|
+
state.suggestions.slice(0, 5).forEach(s => {
|
|
820
|
+
console.log(` * ${s.agent} (${s.priority})`);
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
console.log(`\n${c.bold}Agent Inventory:${c.reset} ${availableAgents.length} agents available`);
|
|
825
|
+
console.log('');
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Show help
|
|
830
|
+
*/
|
|
831
|
+
function showHelp() {
|
|
832
|
+
console.log(`
|
|
833
|
+
${c.bold}Bootspring Intelligence Orchestrator${c.reset}
|
|
834
|
+
|
|
835
|
+
${c.cyan}Usage:${c.reset}
|
|
836
|
+
node orchestrator.js <command> [options]
|
|
837
|
+
|
|
838
|
+
${c.cyan}Commands:${c.reset}
|
|
839
|
+
analyze [context] Analyze context and suggest agents
|
|
840
|
+
suggest [context] Alias for analyze
|
|
841
|
+
workflow <name> Show workflow details
|
|
842
|
+
workflows List available workflows
|
|
843
|
+
start <workflow> Start a workflow
|
|
844
|
+
next Advance to next workflow step
|
|
845
|
+
status Show orchestrator status
|
|
846
|
+
agents List available agents
|
|
847
|
+
help Show this help
|
|
848
|
+
|
|
849
|
+
${c.cyan}Examples:${c.reset}
|
|
850
|
+
node orchestrator.js analyze "building authentication api"
|
|
851
|
+
node orchestrator.js workflow feature-development
|
|
852
|
+
node orchestrator.js start feature-development
|
|
853
|
+
node orchestrator.js status
|
|
854
|
+
`);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// CLI execution
|
|
858
|
+
if (require.main === module) {
|
|
859
|
+
const args = process.argv.slice(2);
|
|
860
|
+
const command = args[0] || 'help';
|
|
861
|
+
|
|
862
|
+
switch (command) {
|
|
863
|
+
case 'analyze':
|
|
864
|
+
case 'suggest': {
|
|
865
|
+
const context = args.slice(1).join(' ');
|
|
866
|
+
const analysis = analyzeContext(context);
|
|
867
|
+
displayAnalysis(analysis);
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
case 'workflow': {
|
|
872
|
+
const workflowName = args[1];
|
|
873
|
+
if (!workflowName) {
|
|
874
|
+
console.log(`\n${c.bold}Available Workflows:${c.reset}\n`);
|
|
875
|
+
listWorkflows().forEach(w => {
|
|
876
|
+
console.log(` ${c.cyan}${w.key}${c.reset} - ${w.description}`);
|
|
877
|
+
});
|
|
878
|
+
console.log('');
|
|
879
|
+
} else {
|
|
880
|
+
displayWorkflow(workflowName);
|
|
881
|
+
}
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
case 'workflows':
|
|
886
|
+
console.log(`\n${c.bold}Available Workflows:${c.reset}\n`);
|
|
887
|
+
listWorkflows().forEach(w => {
|
|
888
|
+
console.log(` ${c.cyan}${w.key}${c.reset}`);
|
|
889
|
+
console.log(` ${w.description}`);
|
|
890
|
+
console.log(` ${c.dim}${w.phaseCount} phases${c.reset}\n`);
|
|
891
|
+
});
|
|
892
|
+
break;
|
|
893
|
+
|
|
894
|
+
case 'start': {
|
|
895
|
+
const startName = args[1];
|
|
896
|
+
if (!startName) {
|
|
897
|
+
console.log(`${c.red}Usage: orchestrator.js start <workflow-name>${c.reset}`);
|
|
898
|
+
} else {
|
|
899
|
+
const result = startWorkflow(startName);
|
|
900
|
+
if (result.success) {
|
|
901
|
+
console.log(`${c.green}Started workflow:${c.reset} ${result.workflow}`);
|
|
902
|
+
console.log(`${c.bold}Current Phase:${c.reset} ${result.currentPhase.name}`);
|
|
903
|
+
console.log(`${c.bold}Agents:${c.reset} ${result.currentPhase.agents.join(', ')}`);
|
|
904
|
+
} else {
|
|
905
|
+
console.log(`${c.red}Error: ${result.error}${c.reset}`);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
case 'next': {
|
|
912
|
+
const advanceResult = advanceWorkflow();
|
|
913
|
+
if (advanceResult.success) {
|
|
914
|
+
if (advanceResult.complete) {
|
|
915
|
+
console.log(`${c.green}Workflow complete!${c.reset}`);
|
|
916
|
+
} else {
|
|
917
|
+
console.log(`${c.green}Advanced to step ${advanceResult.step}/${advanceResult.totalSteps}${c.reset}`);
|
|
918
|
+
console.log(`${c.bold}Phase:${c.reset} ${advanceResult.currentPhase.name}`);
|
|
919
|
+
console.log(`${c.bold}Agents:${c.reset} ${advanceResult.currentPhase.agents.join(', ')}`);
|
|
920
|
+
}
|
|
921
|
+
} else {
|
|
922
|
+
console.log(`${c.red}Error: ${advanceResult.error}${c.reset}`);
|
|
923
|
+
}
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
case 'status':
|
|
928
|
+
displayStatus();
|
|
929
|
+
break;
|
|
930
|
+
|
|
931
|
+
case 'agents': {
|
|
932
|
+
const agents = getAvailableAgents();
|
|
933
|
+
console.log(`\n${c.bold}Available Agents (${agents.length}):${c.reset}\n`);
|
|
934
|
+
agents.forEach(agent => {
|
|
935
|
+
console.log(` * ${agent}`);
|
|
936
|
+
});
|
|
937
|
+
console.log('');
|
|
938
|
+
break;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
case 'help':
|
|
942
|
+
default:
|
|
943
|
+
showHelp();
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Export for use as module
|
|
948
|
+
module.exports = {
|
|
949
|
+
analyzeContext,
|
|
950
|
+
getWorkflow,
|
|
951
|
+
listWorkflows,
|
|
952
|
+
startWorkflow,
|
|
953
|
+
advanceWorkflow,
|
|
954
|
+
markWorkflowCheckpoint,
|
|
955
|
+
getWorkflowSignalProgress,
|
|
956
|
+
loadState,
|
|
957
|
+
saveState,
|
|
958
|
+
getCurrentPhase,
|
|
959
|
+
agentExists,
|
|
960
|
+
getAvailableAgents,
|
|
961
|
+
PHASE_AGENTS,
|
|
962
|
+
TECHNICAL_TRIGGERS,
|
|
963
|
+
WORKFLOWS
|
|
964
|
+
};
|