@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
package/cli/memory.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bootspring Memory Command
|
|
5
|
+
* View and manage git-based project memory
|
|
6
|
+
*
|
|
7
|
+
* @package bootspring
|
|
8
|
+
* @command memory
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const gitMemory = require('../intelligence/git-memory');
|
|
13
|
+
const utils = require('../core/utils');
|
|
14
|
+
|
|
15
|
+
// Colors
|
|
16
|
+
const c = {
|
|
17
|
+
reset: '\x1b[0m',
|
|
18
|
+
bold: '\x1b[1m',
|
|
19
|
+
dim: '\x1b[2m',
|
|
20
|
+
green: '\x1b[32m',
|
|
21
|
+
blue: '\x1b[34m',
|
|
22
|
+
yellow: '\x1b[33m',
|
|
23
|
+
cyan: '\x1b[36m',
|
|
24
|
+
red: '\x1b[31m',
|
|
25
|
+
magenta: '\x1b[35m'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Display learnings summary
|
|
30
|
+
*/
|
|
31
|
+
function showSummary(options = {}) {
|
|
32
|
+
const { limit = 30, since = '3 months ago' } = options;
|
|
33
|
+
|
|
34
|
+
console.log(`\n${c.cyan}${c.bold}⚡ Project Memory${c.reset}\n`);
|
|
35
|
+
|
|
36
|
+
if (!gitMemory.isGitRepo()) {
|
|
37
|
+
console.log(`${c.red}Not a git repository${c.reset}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const result = gitMemory.extractLearnings({ limit, since });
|
|
42
|
+
|
|
43
|
+
if (result.error) {
|
|
44
|
+
console.log(`${c.red}Error: ${result.error}${c.reset}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (result.learnings.length === 0) {
|
|
49
|
+
console.log(`${c.yellow}No significant learnings found in recent commits${c.reset}`);
|
|
50
|
+
console.log(`${c.dim}Try using more descriptive commit messages${c.reset}`);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Group by category
|
|
55
|
+
const grouped = gitMemory.groupByCategory(result.learnings);
|
|
56
|
+
|
|
57
|
+
console.log(`${c.dim}Extracted ${result.learnings.length} learnings from ${result.total} commits${c.reset}\n`);
|
|
58
|
+
|
|
59
|
+
for (const [category, items] of Object.entries(grouped)) {
|
|
60
|
+
const config = gitMemory.MEMORY_CATEGORIES[category] || { icon: '📝', label: category };
|
|
61
|
+
|
|
62
|
+
console.log(`${c.bold}${config.icon} ${config.label}${c.reset} (${items.length})`);
|
|
63
|
+
|
|
64
|
+
for (const item of items.slice(0, 3)) {
|
|
65
|
+
console.log(` ${c.dim}[${item.hash}]${c.reset} ${item.summary}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (items.length > 3) {
|
|
69
|
+
console.log(` ${c.dim}... and ${items.length - 3} more${c.reset}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log('');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Search learnings
|
|
78
|
+
*/
|
|
79
|
+
function searchMemory(query) {
|
|
80
|
+
console.log(`\n${c.cyan}${c.bold}⚡ Search Memory${c.reset}\n`);
|
|
81
|
+
|
|
82
|
+
if (!query) {
|
|
83
|
+
console.log(`${c.red}Usage: bootspring memory search <query>${c.reset}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = gitMemory.extractLearnings({ limit: 100 });
|
|
88
|
+
const matches = gitMemory.searchLearnings(result.learnings, query);
|
|
89
|
+
|
|
90
|
+
console.log(`${c.dim}Found ${matches.length} matches for "${query}"${c.reset}\n`);
|
|
91
|
+
|
|
92
|
+
for (const match of matches.slice(0, 15)) {
|
|
93
|
+
const icons = match.categories
|
|
94
|
+
.map(cat => gitMemory.MEMORY_CATEGORIES[cat]?.icon || '📝')
|
|
95
|
+
.join('');
|
|
96
|
+
|
|
97
|
+
console.log(`${icons} ${c.bold}${match.summary}${c.reset}`);
|
|
98
|
+
console.log(` ${c.dim}[${match.hash}] ${match.date}${c.reset}`);
|
|
99
|
+
|
|
100
|
+
if (match.details) {
|
|
101
|
+
const preview = match.details.split('\n')[0].slice(0, 80);
|
|
102
|
+
console.log(` ${c.dim}${preview}${c.reset}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.log('');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (matches.length > 15) {
|
|
109
|
+
console.log(`${c.dim}... and ${matches.length - 15} more matches${c.reset}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Show learnings for specific files
|
|
115
|
+
*/
|
|
116
|
+
function showForFiles(files) {
|
|
117
|
+
console.log(`\n${c.cyan}${c.bold}⚡ File Memory${c.reset}\n`);
|
|
118
|
+
|
|
119
|
+
if (!files || files.length === 0) {
|
|
120
|
+
console.log(`${c.red}Usage: bootspring memory files <file1> [file2...]${c.reset}`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const learnings = gitMemory.getLearningsForFiles(files);
|
|
125
|
+
|
|
126
|
+
if (learnings.length === 0) {
|
|
127
|
+
console.log(`${c.yellow}No learnings found for these files${c.reset}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log(`${c.dim}Learnings related to: ${files.join(', ')}${c.reset}\n`);
|
|
132
|
+
|
|
133
|
+
for (const learning of learnings) {
|
|
134
|
+
const icons = learning.categories
|
|
135
|
+
.map(cat => gitMemory.MEMORY_CATEGORIES[cat]?.icon || '📝')
|
|
136
|
+
.join('');
|
|
137
|
+
|
|
138
|
+
console.log(`${icons} ${c.bold}${learning.summary}${c.reset}`);
|
|
139
|
+
console.log(` ${c.dim}[${learning.hash}] File: ${learning.file}${c.reset}`);
|
|
140
|
+
console.log('');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Export learnings to markdown
|
|
146
|
+
*/
|
|
147
|
+
function exportMarkdown(outputPath) {
|
|
148
|
+
const result = gitMemory.extractLearnings({ limit: 50 });
|
|
149
|
+
|
|
150
|
+
if (result.error) {
|
|
151
|
+
console.log(`${c.red}Error: ${result.error}${c.reset}`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const markdown = gitMemory.toMarkdown(result.learnings, {
|
|
156
|
+
title: 'Project Learnings',
|
|
157
|
+
maxPerCategory: 10
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (outputPath) {
|
|
161
|
+
require('fs').writeFileSync(outputPath, markdown);
|
|
162
|
+
console.log(`${c.green}Exported to ${outputPath}${c.reset}`);
|
|
163
|
+
} else {
|
|
164
|
+
console.log(markdown);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Show repo stats
|
|
170
|
+
*/
|
|
171
|
+
function showStats() {
|
|
172
|
+
console.log(`\n${c.cyan}${c.bold}⚡ Repository Stats${c.reset}\n`);
|
|
173
|
+
|
|
174
|
+
const stats = gitMemory.getRepoStats();
|
|
175
|
+
|
|
176
|
+
if (!stats) {
|
|
177
|
+
console.log(`${c.red}Not a git repository${c.reset}`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log(` ${c.bold}Total Commits:${c.reset} ${stats.totalCommits}`);
|
|
182
|
+
console.log(` ${c.bold}Contributors:${c.reset} ${stats.contributors}`);
|
|
183
|
+
console.log(` ${c.bold}Weekly Activity:${c.reset} ${stats.weeklyPace} commits`);
|
|
184
|
+
console.log(` ${c.bold}First Commit:${c.reset} ${stats.firstCommit || 'unknown'}`);
|
|
185
|
+
console.log('');
|
|
186
|
+
|
|
187
|
+
// Show category breakdown
|
|
188
|
+
const result = gitMemory.extractLearnings({ limit: 100 });
|
|
189
|
+
const grouped = gitMemory.groupByCategory(result.learnings);
|
|
190
|
+
|
|
191
|
+
console.log(`${c.bold}Learning Categories:${c.reset}\n`);
|
|
192
|
+
|
|
193
|
+
for (const [category, items] of Object.entries(grouped).sort((a, b) => b[1].length - a[1].length)) {
|
|
194
|
+
const config = gitMemory.MEMORY_CATEGORIES[category] || { icon: '📝', label: category };
|
|
195
|
+
const bar = '█'.repeat(Math.min(items.length, 20));
|
|
196
|
+
console.log(` ${config.icon} ${config.label.padEnd(20)} ${c.cyan}${bar}${c.reset} ${items.length}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
console.log('');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Show help
|
|
204
|
+
*/
|
|
205
|
+
function showHelp() {
|
|
206
|
+
console.log(`
|
|
207
|
+
${c.bold}Bootspring Memory${c.reset}
|
|
208
|
+
|
|
209
|
+
Extract and search project learnings from git history.
|
|
210
|
+
|
|
211
|
+
${c.cyan}Usage:${c.reset}
|
|
212
|
+
bootspring memory <command> [options]
|
|
213
|
+
|
|
214
|
+
${c.cyan}Commands:${c.reset}
|
|
215
|
+
summary Show categorized learning summary (default)
|
|
216
|
+
search <query> Search learnings by keyword
|
|
217
|
+
files <file...> Show learnings for specific files
|
|
218
|
+
export [path] Export learnings to markdown
|
|
219
|
+
stats Show repository statistics
|
|
220
|
+
categories List memory categories
|
|
221
|
+
help Show this help
|
|
222
|
+
|
|
223
|
+
${c.cyan}Options:${c.reset}
|
|
224
|
+
--limit <n> Number of commits to analyze (default: 30)
|
|
225
|
+
--since <date> How far back to look (default: "3 months ago")
|
|
226
|
+
|
|
227
|
+
${c.cyan}Examples:${c.reset}
|
|
228
|
+
bootspring memory summary
|
|
229
|
+
bootspring memory search "authentication"
|
|
230
|
+
bootspring memory files src/api/auth.ts
|
|
231
|
+
bootspring memory export LEARNINGS.md
|
|
232
|
+
bootspring memory stats
|
|
233
|
+
|
|
234
|
+
${c.cyan}Categories:${c.reset}
|
|
235
|
+
${Object.entries(gitMemory.MEMORY_CATEGORIES)
|
|
236
|
+
.map(([key, cfg]) => ` ${cfg.icon} ${key.padEnd(15)} ${cfg.label}`)
|
|
237
|
+
.join('\n')}
|
|
238
|
+
`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Main CLI handler
|
|
243
|
+
*/
|
|
244
|
+
async function run(args) {
|
|
245
|
+
const command = args[0] || 'summary';
|
|
246
|
+
|
|
247
|
+
// Parse options
|
|
248
|
+
const options = {};
|
|
249
|
+
for (let i = 0; i < args.length; i++) {
|
|
250
|
+
if (args[i] === '--limit' && args[i + 1]) {
|
|
251
|
+
options.limit = parseInt(args[i + 1]);
|
|
252
|
+
}
|
|
253
|
+
if (args[i] === '--since' && args[i + 1]) {
|
|
254
|
+
options.since = args[i + 1];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
switch (command) {
|
|
259
|
+
case 'summary':
|
|
260
|
+
case 'show':
|
|
261
|
+
showSummary(options);
|
|
262
|
+
break;
|
|
263
|
+
|
|
264
|
+
case 'search':
|
|
265
|
+
searchMemory(args.slice(1).filter(a => !a.startsWith('--')).join(' '));
|
|
266
|
+
break;
|
|
267
|
+
|
|
268
|
+
case 'files':
|
|
269
|
+
case 'file':
|
|
270
|
+
showForFiles(args.slice(1).filter(a => !a.startsWith('--')));
|
|
271
|
+
break;
|
|
272
|
+
|
|
273
|
+
case 'export':
|
|
274
|
+
exportMarkdown(args[1]);
|
|
275
|
+
break;
|
|
276
|
+
|
|
277
|
+
case 'stats':
|
|
278
|
+
showStats();
|
|
279
|
+
break;
|
|
280
|
+
|
|
281
|
+
case 'categories':
|
|
282
|
+
console.log(`\n${c.bold}Memory Categories:${c.reset}\n`);
|
|
283
|
+
for (const [key, cfg] of Object.entries(gitMemory.MEMORY_CATEGORIES)) {
|
|
284
|
+
console.log(` ${cfg.icon} ${key.padEnd(15)} ${c.dim}${cfg.label}${c.reset}`);
|
|
285
|
+
console.log(` ${c.dim}Patterns: ${cfg.patterns.slice(0, 3).map(p => p.source).join(', ')}...${c.reset}`);
|
|
286
|
+
}
|
|
287
|
+
console.log('');
|
|
288
|
+
break;
|
|
289
|
+
|
|
290
|
+
case 'help':
|
|
291
|
+
case '--help':
|
|
292
|
+
case '-h':
|
|
293
|
+
default:
|
|
294
|
+
showHelp();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// CLI execution
|
|
299
|
+
if (require.main === module) {
|
|
300
|
+
run(process.argv.slice(2));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
module.exports = { run };
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootspring Orchestrator Command
|
|
3
|
+
* Intelligent agent coordination and workflow management
|
|
4
|
+
*
|
|
5
|
+
* @package bootspring
|
|
6
|
+
* @command orchestrator
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const utils = require('../core/utils');
|
|
10
|
+
const entitlements = require('../core/entitlements');
|
|
11
|
+
const telemetry = require('../core/telemetry');
|
|
12
|
+
const intelligence = require('../intelligence');
|
|
13
|
+
|
|
14
|
+
function trackTelemetry(event, payload) {
|
|
15
|
+
try {
|
|
16
|
+
telemetry.emitEvent(event, payload);
|
|
17
|
+
} catch {
|
|
18
|
+
// Do not block CLI flow on telemetry issues.
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Run orchestrator command
|
|
24
|
+
*/
|
|
25
|
+
async function run(args) {
|
|
26
|
+
const parsedArgs = utils.parseArgs(args);
|
|
27
|
+
const subcommand = args[0] || 'help';
|
|
28
|
+
const context = args.slice(1).join(' ');
|
|
29
|
+
const accessOptions = {
|
|
30
|
+
mode: parsedArgs['access-mode'],
|
|
31
|
+
entitled: parsedArgs.entitled,
|
|
32
|
+
tier: parsedArgs.tier
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
switch (subcommand) {
|
|
36
|
+
case 'analyze':
|
|
37
|
+
case 'suggest':
|
|
38
|
+
runAnalyze(context);
|
|
39
|
+
break;
|
|
40
|
+
|
|
41
|
+
case 'workflow':
|
|
42
|
+
runWorkflow(args[1], accessOptions);
|
|
43
|
+
break;
|
|
44
|
+
|
|
45
|
+
case 'workflows':
|
|
46
|
+
runListWorkflows(accessOptions);
|
|
47
|
+
break;
|
|
48
|
+
|
|
49
|
+
case 'start':
|
|
50
|
+
runStartWorkflow(args[1], accessOptions);
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
case 'next':
|
|
54
|
+
runNextStep();
|
|
55
|
+
break;
|
|
56
|
+
|
|
57
|
+
case 'checkpoint':
|
|
58
|
+
if (!args[1]) {
|
|
59
|
+
runCheckpoint(undefined, '', accessOptions);
|
|
60
|
+
} else if (intelligence.getWorkflow(args[1])) {
|
|
61
|
+
runCheckpoint(args[1], args.slice(2).join(' '), accessOptions);
|
|
62
|
+
} else {
|
|
63
|
+
// Convenience: allow `checkpoint <signal>` for active workflow.
|
|
64
|
+
runCheckpoint(undefined, args.slice(1).join(' '), accessOptions);
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
|
|
68
|
+
case 'status':
|
|
69
|
+
runStatus();
|
|
70
|
+
break;
|
|
71
|
+
|
|
72
|
+
case 'agents':
|
|
73
|
+
runListAgents();
|
|
74
|
+
break;
|
|
75
|
+
|
|
76
|
+
case 'help':
|
|
77
|
+
default:
|
|
78
|
+
showHelp();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Analyze context and suggest agents
|
|
84
|
+
*/
|
|
85
|
+
function runAnalyze(context) {
|
|
86
|
+
console.log(`
|
|
87
|
+
${utils.COLORS.cyan}${utils.COLORS.bold}Intelligence Analysis${utils.COLORS.reset}
|
|
88
|
+
`);
|
|
89
|
+
|
|
90
|
+
const analysis = intelligence.analyzeContext(context);
|
|
91
|
+
|
|
92
|
+
console.log(`${utils.COLORS.bold}Current Phase:${utils.COLORS.reset} ${analysis.phase} - ${analysis.phaseConfig?.name || 'Unknown'}`);
|
|
93
|
+
if (analysis.phaseConfig?.description) {
|
|
94
|
+
console.log(`${utils.COLORS.dim}${analysis.phaseConfig.description}${utils.COLORS.reset}`);
|
|
95
|
+
}
|
|
96
|
+
console.log('');
|
|
97
|
+
|
|
98
|
+
if (analysis.suggestions.length === 0) {
|
|
99
|
+
utils.print.warning('No specific agent suggestions for this context');
|
|
100
|
+
utils.print.dim('Try providing more context about what you\'re working on');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log(`${utils.COLORS.bold}Suggested Agents:${utils.COLORS.reset}\n`);
|
|
105
|
+
|
|
106
|
+
const high = analysis.suggestions.filter(s => s.priority === 'high');
|
|
107
|
+
const medium = analysis.suggestions.filter(s => s.priority === 'medium');
|
|
108
|
+
|
|
109
|
+
if (high.length > 0) {
|
|
110
|
+
console.log(` ${utils.COLORS.green}High Priority:${utils.COLORS.reset}`);
|
|
111
|
+
high.forEach(s => {
|
|
112
|
+
console.log(` ${utils.COLORS.green}*${utils.COLORS.reset} ${s.agent}`);
|
|
113
|
+
console.log(` ${utils.COLORS.dim}${s.reason}${utils.COLORS.reset}`);
|
|
114
|
+
});
|
|
115
|
+
console.log('');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (medium.length > 0) {
|
|
119
|
+
console.log(` ${utils.COLORS.yellow}Medium Priority:${utils.COLORS.reset}`);
|
|
120
|
+
medium.forEach(s => {
|
|
121
|
+
console.log(` ${utils.COLORS.yellow}*${utils.COLORS.reset} ${s.agent}`);
|
|
122
|
+
console.log(` ${utils.COLORS.dim}${s.reason}${utils.COLORS.reset}`);
|
|
123
|
+
});
|
|
124
|
+
console.log('');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (analysis.skills.length > 0) {
|
|
128
|
+
console.log(`${utils.COLORS.bold}Relevant Skills:${utils.COLORS.reset}`);
|
|
129
|
+
analysis.skills.forEach(skill => {
|
|
130
|
+
console.log(` ${utils.COLORS.cyan}*${utils.COLORS.reset} ${skill}`);
|
|
131
|
+
});
|
|
132
|
+
console.log('');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
utils.print.dim('Invoke an agent: bootspring agent invoke <name>');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Show workflow details
|
|
140
|
+
*/
|
|
141
|
+
function runWorkflow(name, accessOptions = {}) {
|
|
142
|
+
if (!name) {
|
|
143
|
+
runListWorkflows(accessOptions);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const workflow = intelligence.getWorkflow(name);
|
|
148
|
+
|
|
149
|
+
if (!workflow) {
|
|
150
|
+
utils.print.error(`Unknown workflow: ${name}`);
|
|
151
|
+
const filtered = entitlements.filterAccessibleWorkflows(intelligence.listWorkflows(), accessOptions);
|
|
152
|
+
console.log('Available: ' + filtered.allowed.map(w => w.key).join(', '));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const decision = entitlements.checkWorkflowAccess(workflow, accessOptions);
|
|
157
|
+
if (!decision.allowed) {
|
|
158
|
+
trackTelemetry('premium_prompted', {
|
|
159
|
+
capability: 'workflow_pack',
|
|
160
|
+
workflow: name,
|
|
161
|
+
tier: workflow.tier || 'free',
|
|
162
|
+
mode: decision.context?.mode,
|
|
163
|
+
userTier: decision.context?.tier,
|
|
164
|
+
reason: decision.code
|
|
165
|
+
});
|
|
166
|
+
utils.print.error(decision.reason);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
console.log(`
|
|
171
|
+
${utils.COLORS.cyan}${utils.COLORS.bold}Workflow: ${workflow.name}${utils.COLORS.reset}
|
|
172
|
+
|
|
173
|
+
${utils.COLORS.bold}Description:${utils.COLORS.reset} ${workflow.description}
|
|
174
|
+
${utils.COLORS.bold}Tier:${utils.COLORS.reset} ${workflow.tier || 'free'}
|
|
175
|
+
|
|
176
|
+
${utils.COLORS.bold}Phases:${utils.COLORS.reset}
|
|
177
|
+
`);
|
|
178
|
+
|
|
179
|
+
workflow.phases.forEach((phase, i) => {
|
|
180
|
+
const isLast = i === workflow.phases.length - 1;
|
|
181
|
+
const prefix = isLast ? '\\--' : '|--';
|
|
182
|
+
const line = isLast ? ' ' : '| ';
|
|
183
|
+
|
|
184
|
+
console.log(` ${prefix} ${utils.COLORS.cyan}${phase.name}${utils.COLORS.reset} ${utils.COLORS.dim}(${phase.duration})${utils.COLORS.reset}`);
|
|
185
|
+
phase.agents.forEach((agent, j) => {
|
|
186
|
+
const agentPrefix = j === phase.agents.length - 1 ? '\\-' : '|-';
|
|
187
|
+
const exists = intelligence.agentExists(agent);
|
|
188
|
+
const status = exists ? `${utils.COLORS.green}*${utils.COLORS.reset}` : `${utils.COLORS.red}o${utils.COLORS.reset}`;
|
|
189
|
+
console.log(` ${line} ${agentPrefix} ${status} ${agent}`);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
if (Array.isArray(workflow.completionSignals) && workflow.completionSignals.length > 0) {
|
|
193
|
+
console.log(`\n${utils.COLORS.bold}Completion Signals:${utils.COLORS.reset}`);
|
|
194
|
+
workflow.completionSignals.forEach(signal => {
|
|
195
|
+
console.log(` - ${signal}`);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
console.log('');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* List all workflows
|
|
203
|
+
*/
|
|
204
|
+
function runListWorkflows(accessOptions = {}) {
|
|
205
|
+
console.log(`
|
|
206
|
+
${utils.COLORS.cyan}${utils.COLORS.bold}Available Workflows${utils.COLORS.reset}
|
|
207
|
+
`);
|
|
208
|
+
|
|
209
|
+
const all = intelligence.listWorkflows();
|
|
210
|
+
const { allowed, denied } = entitlements.filterAccessibleWorkflows(all, accessOptions);
|
|
211
|
+
|
|
212
|
+
allowed.forEach(w => {
|
|
213
|
+
console.log(` ${utils.COLORS.cyan}${w.key}${utils.COLORS.reset}`);
|
|
214
|
+
console.log(` ${w.description}`);
|
|
215
|
+
console.log(` ${utils.COLORS.dim}${w.phaseCount} phases | tier: ${w.tier || 'free'}${utils.COLORS.reset}\n`);
|
|
216
|
+
});
|
|
217
|
+
if (denied.length > 0) {
|
|
218
|
+
console.log(`${utils.COLORS.dim}${denied.length} premium workflow(s) hidden by entitlement policy${utils.COLORS.reset}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Start a workflow
|
|
224
|
+
*/
|
|
225
|
+
function runStartWorkflow(name, accessOptions = {}) {
|
|
226
|
+
if (!name) {
|
|
227
|
+
utils.print.error('Usage: bootspring orchestrator start <workflow-name>');
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const workflow = intelligence.getWorkflow(name);
|
|
232
|
+
if (!workflow) {
|
|
233
|
+
utils.print.error(`Unknown workflow: ${name}`);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const decision = entitlements.checkWorkflowAccess(workflow, accessOptions);
|
|
238
|
+
if (!decision.allowed) {
|
|
239
|
+
utils.print.error(decision.reason);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const result = intelligence.startWorkflow(name);
|
|
244
|
+
|
|
245
|
+
if (result.success) {
|
|
246
|
+
utils.print.success(`Started workflow: ${result.workflow}`);
|
|
247
|
+
console.log(`${utils.COLORS.bold}Current Phase:${utils.COLORS.reset} ${result.currentPhase.name}`);
|
|
248
|
+
console.log(`${utils.COLORS.bold}Agents:${utils.COLORS.reset} ${result.currentPhase.agents.join(', ')}`);
|
|
249
|
+
} else {
|
|
250
|
+
utils.print.error(result.error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Advance to next workflow step
|
|
256
|
+
*/
|
|
257
|
+
function runNextStep() {
|
|
258
|
+
const result = intelligence.advanceWorkflow();
|
|
259
|
+
|
|
260
|
+
if (result.success) {
|
|
261
|
+
if (result.complete) {
|
|
262
|
+
utils.print.success('Workflow complete!');
|
|
263
|
+
} else {
|
|
264
|
+
utils.print.success(`Advanced to step ${result.step}/${result.totalSteps}`);
|
|
265
|
+
console.log(`${utils.COLORS.bold}Phase:${utils.COLORS.reset} ${result.currentPhase.name}`);
|
|
266
|
+
console.log(`${utils.COLORS.bold}Agents:${utils.COLORS.reset} ${result.currentPhase.agents.join(', ')}`);
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
utils.print.error(result.error);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Show orchestrator status
|
|
275
|
+
*/
|
|
276
|
+
function runStatus() {
|
|
277
|
+
const state = intelligence.loadState();
|
|
278
|
+
const currentPhase = intelligence.getCurrentPhase();
|
|
279
|
+
const phaseConfig = intelligence.PHASE_AGENTS[currentPhase];
|
|
280
|
+
const agents = intelligence.getAvailableAgents();
|
|
281
|
+
|
|
282
|
+
console.log(`
|
|
283
|
+
${utils.COLORS.cyan}${utils.COLORS.bold}Orchestrator Status${utils.COLORS.reset}
|
|
284
|
+
|
|
285
|
+
${utils.COLORS.bold}Current Phase:${utils.COLORS.reset} ${currentPhase} - ${phaseConfig?.name || 'Unknown'}
|
|
286
|
+
${utils.COLORS.bold}Last Analysis:${utils.COLORS.reset} ${state.lastAnalysis || 'Never'}
|
|
287
|
+
${utils.COLORS.bold}Active Workflow:${utils.COLORS.reset} ${state.activeWorkflow || 'None'}
|
|
288
|
+
`);
|
|
289
|
+
|
|
290
|
+
if (state.activeWorkflow) {
|
|
291
|
+
const workflow = intelligence.getWorkflow(state.activeWorkflow);
|
|
292
|
+
console.log(`${utils.COLORS.bold}Workflow Step:${utils.COLORS.reset} ${state.workflowStep + 1}/${workflow.phases.length}`);
|
|
293
|
+
const progress = intelligence.getWorkflowSignalProgress(state.activeWorkflow, state);
|
|
294
|
+
if (progress) {
|
|
295
|
+
console.log(`${utils.COLORS.bold}Checkpoint Signals:${utils.COLORS.reset} ${progress.completedSignals.length}/${progress.totalSignals}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (state.suggestions.length > 0) {
|
|
300
|
+
console.log(`${utils.COLORS.bold}Last Suggestions:${utils.COLORS.reset}`);
|
|
301
|
+
state.suggestions.slice(0, 5).forEach(s => {
|
|
302
|
+
console.log(` * ${s.agent} (${s.priority})`);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
console.log(`\n${utils.COLORS.bold}Available Agents:${utils.COLORS.reset} ${agents.length}`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function runCheckpoint(workflowName, signalRef, accessOptions = {}) {
|
|
310
|
+
const targetWorkflowName = workflowName || intelligence.loadState().activeWorkflow;
|
|
311
|
+
if (targetWorkflowName) {
|
|
312
|
+
const workflow = intelligence.getWorkflow(targetWorkflowName);
|
|
313
|
+
if (workflow) {
|
|
314
|
+
const decision = entitlements.checkWorkflowAccess(workflow, accessOptions);
|
|
315
|
+
if (!decision.allowed) {
|
|
316
|
+
trackTelemetry('premium_prompted', {
|
|
317
|
+
capability: 'workflow_pack',
|
|
318
|
+
workflow: targetWorkflowName,
|
|
319
|
+
tier: workflow.tier || 'free',
|
|
320
|
+
mode: decision.context?.mode,
|
|
321
|
+
userTier: decision.context?.tier,
|
|
322
|
+
reason: decision.code
|
|
323
|
+
});
|
|
324
|
+
utils.print.error(decision.reason);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const result = intelligence.markWorkflowCheckpoint(workflowName, signalRef);
|
|
331
|
+
if (!result.success) {
|
|
332
|
+
utils.print.error(result.error);
|
|
333
|
+
if (Array.isArray(result.availableSignals) && result.availableSignals.length > 0) {
|
|
334
|
+
utils.print.dim(`Available signals: ${result.availableSignals.join(' | ')}`);
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (result.alreadyCompleted) {
|
|
340
|
+
utils.print.warning(`Signal already completed: ${result.signal}`);
|
|
341
|
+
} else {
|
|
342
|
+
utils.print.success(`Checkpoint completed: ${result.signal}`);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (result.progress) {
|
|
346
|
+
console.log(`${utils.COLORS.bold}Progress:${utils.COLORS.reset} ${result.progress.completedSignals.length}/${result.progress.totalSignals}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* List available agents
|
|
352
|
+
*/
|
|
353
|
+
function runListAgents() {
|
|
354
|
+
const agents = intelligence.getAvailableAgents();
|
|
355
|
+
|
|
356
|
+
console.log(`
|
|
357
|
+
${utils.COLORS.cyan}${utils.COLORS.bold}Available Agents (${agents.length})${utils.COLORS.reset}
|
|
358
|
+
`);
|
|
359
|
+
|
|
360
|
+
agents.forEach(agent => {
|
|
361
|
+
console.log(` * ${agent}`);
|
|
362
|
+
});
|
|
363
|
+
console.log('');
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Show help
|
|
368
|
+
*/
|
|
369
|
+
function showHelp() {
|
|
370
|
+
console.log(`
|
|
371
|
+
${utils.COLORS.cyan}${utils.COLORS.bold}Bootspring Intelligence Orchestrator${utils.COLORS.reset}
|
|
372
|
+
|
|
373
|
+
${utils.COLORS.bold}Usage:${utils.COLORS.reset}
|
|
374
|
+
bootspring orchestrator <command> [options]
|
|
375
|
+
|
|
376
|
+
${utils.COLORS.bold}Commands:${utils.COLORS.reset}
|
|
377
|
+
analyze [context] Analyze context and suggest agents
|
|
378
|
+
suggest [context] Alias for analyze
|
|
379
|
+
workflow <name> Show workflow details
|
|
380
|
+
workflows List available workflows
|
|
381
|
+
start <workflow> Start a workflow
|
|
382
|
+
next Advance to next workflow step
|
|
383
|
+
checkpoint [w] [s] Mark workflow completion signal (workflow optional if active)
|
|
384
|
+
status Show orchestrator status
|
|
385
|
+
agents List available agents
|
|
386
|
+
help Show this help
|
|
387
|
+
--access-mode <m> Entitlement mode: local (default) or server
|
|
388
|
+
--entitled <bool> Entitlement override for premium workflows
|
|
389
|
+
--tier <tier> Tier override: free, pro, team, enterprise
|
|
390
|
+
|
|
391
|
+
${utils.COLORS.bold}Examples:${utils.COLORS.reset}
|
|
392
|
+
bootspring orchestrator analyze "building authentication api"
|
|
393
|
+
bootspring orchestrator workflow feature-development
|
|
394
|
+
bootspring orchestrator start feature-development
|
|
395
|
+
bootspring orchestrator checkpoint launch-pack 1
|
|
396
|
+
bootspring orchestrator status
|
|
397
|
+
`);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
module.exports = { run };
|