@girardmedia/bootspring 2.1.3 → 2.2.1

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.
Files changed (65) hide show
  1. package/bin/bootspring.js +157 -83
  2. package/claude-commands/agent.md +34 -0
  3. package/claude-commands/bs.md +31 -0
  4. package/claude-commands/build.md +25 -0
  5. package/claude-commands/skill.md +31 -0
  6. package/claude-commands/todo.md +25 -0
  7. package/dist/core/index.d.ts +5814 -0
  8. package/dist/core.js +5779 -0
  9. package/dist/index.js +93883 -0
  10. package/dist/mcp/index.d.ts +1 -0
  11. package/dist/mcp-server.js +2298 -0
  12. package/generators/api-docs.js +3 -3
  13. package/generators/decisions.js +14 -14
  14. package/generators/health.js +6 -6
  15. package/generators/sprint.js +4 -4
  16. package/generators/templates/build-planning.template.js +2 -2
  17. package/generators/visual-doc-generator.js +1 -1
  18. package/package.json +22 -68
  19. package/cli/agent.js +0 -799
  20. package/cli/auth.js +0 -896
  21. package/cli/billing.js +0 -320
  22. package/cli/build.js +0 -1442
  23. package/cli/dashboard.js +0 -123
  24. package/cli/init.js +0 -669
  25. package/cli/mcp.js +0 -240
  26. package/cli/orchestrator.js +0 -240
  27. package/cli/project.js +0 -825
  28. package/cli/quality.js +0 -281
  29. package/cli/skill.js +0 -503
  30. package/cli/switch.js +0 -453
  31. package/cli/todo.js +0 -629
  32. package/cli/update.js +0 -132
  33. package/core/api-client.d.ts +0 -69
  34. package/core/api-client.js +0 -1482
  35. package/core/auth.d.ts +0 -98
  36. package/core/auth.js +0 -737
  37. package/core/build-orchestrator.js +0 -508
  38. package/core/build-state.js +0 -612
  39. package/core/config.d.ts +0 -106
  40. package/core/config.js +0 -1328
  41. package/core/context-loader.js +0 -580
  42. package/core/context.d.ts +0 -61
  43. package/core/context.js +0 -327
  44. package/core/entitlements.d.ts +0 -70
  45. package/core/entitlements.js +0 -322
  46. package/core/index.d.ts +0 -53
  47. package/core/index.js +0 -62
  48. package/core/mcp-config.js +0 -115
  49. package/core/policies.d.ts +0 -43
  50. package/core/policies.js +0 -113
  51. package/core/policy-matrix.js +0 -303
  52. package/core/project-activity.js +0 -175
  53. package/core/redaction.d.ts +0 -5
  54. package/core/redaction.js +0 -63
  55. package/core/self-update.js +0 -259
  56. package/core/session.js +0 -353
  57. package/core/task-extractor.js +0 -1098
  58. package/core/telemetry.d.ts +0 -55
  59. package/core/telemetry.js +0 -617
  60. package/core/tier-enforcement.js +0 -928
  61. package/core/utils.d.ts +0 -90
  62. package/core/utils.js +0 -455
  63. package/core/validation.js +0 -572
  64. package/mcp/server.d.ts +0 -57
  65. package/mcp/server.js +0 -264
package/cli/mcp.js DELETED
@@ -1,240 +0,0 @@
1
- /**
2
- * Bootspring MCP Command
3
- * Manage the hosted MCP proxy configuration.
4
- */
5
-
6
- const config = require('../core/config');
7
- const utils = require('../core/utils');
8
- const api = require('../core/api-client');
9
- const auth = require('../core/auth');
10
- const { ensureProjectMcpConfig } = require('../core/mcp-config');
11
- const { redactErrorMessage } = require('../core/redaction');
12
-
13
- const C = utils.COLORS;
14
-
15
- async function startServer() {
16
- const server = require('../mcp/server.js');
17
- await server.main();
18
- }
19
-
20
- function generateConfig() {
21
- const cfg = config.load();
22
- const spinner = utils.createSpinner('Generating .mcp.json').start();
23
- const result = ensureProjectMcpConfig(cfg._projectRoot, { createIfMissing: true });
24
-
25
- if (result.status === 'created') {
26
- spinner.succeed(`Created ${result.path}`);
27
- } else if (result.status === 'updated' || result.status === 'added') {
28
- spinner.succeed(`Updated ${result.path}`);
29
- } else if (result.status === 'unchanged') {
30
- spinner.succeed(`Already configured ${result.path}`);
31
- } else {
32
- spinner.fail(`Failed to configure .mcp.json${result.error ? `: ${result.error.message}` : ''}`);
33
- }
34
- }
35
-
36
- async function showStatus() {
37
- const cfg = config.load();
38
- console.log(`\n${C.cyan}${C.bold}Bootspring MCP Proxy${C.reset}\n`);
39
- console.log(` Project root: ${cfg._projectRoot}`);
40
- console.log(` Config file: ${cfg._configPath || 'not found'}`);
41
- console.log(` Authenticated: ${auth.isAuthenticated() ? 'yes' : 'no'}`);
42
-
43
- if (!auth.isAuthenticated()) {
44
- console.log(`\n${C.dim}Run 'bootspring auth login' to view hosted tools and resources.${C.reset}\n`);
45
- return;
46
- }
47
-
48
- try {
49
- const [toolsResponse, resourcesResponse] = await Promise.all([
50
- api.listMcpTools(),
51
- api.listMcpResources()
52
- ]);
53
-
54
- const tools = toolsResponse.tools || [];
55
- const resources = resourcesResponse.resources || [];
56
-
57
- console.log(`\n${C.bold}Hosted Tools${C.reset}`);
58
- tools.forEach((tool) => console.log(` ${C.cyan}${tool.name}${C.reset} ${C.dim}${tool.description}${C.reset}`));
59
-
60
- console.log(`\n${C.bold}Hosted Resources${C.reset}`);
61
- resources.forEach((resource) => console.log(` ${C.cyan}${resource.uri}${C.reset} ${C.dim}${resource.description}${C.reset}`));
62
- console.log();
63
- } catch (error) {
64
- console.log(`\n${C.red}Failed to load hosted MCP metadata: ${redactErrorMessage(error)}${C.reset}\n`);
65
- }
66
- }
67
-
68
- async function testMcp() {
69
- console.log(`\n${C.cyan}${C.bold}Bootspring MCP Test${C.reset}\n`);
70
-
71
- if (!auth.isAuthenticated()) {
72
- console.log(`${C.yellow}Authentication required${C.reset}`);
73
- console.log(`${C.dim}Run 'bootspring auth login' first${C.reset}\n`);
74
- return;
75
- }
76
-
77
- const toolSpinner = utils.createSpinner('Checking hosted tools').start();
78
- try {
79
- const toolsResponse = await api.listMcpTools();
80
- const count = (toolsResponse.tools || []).length;
81
- toolSpinner.succeed(`Loaded ${count} hosted tool${count === 1 ? '' : 's'}`);
82
- } catch (error) {
83
- toolSpinner.fail(redactErrorMessage(error));
84
- return;
85
- }
86
-
87
- const resourceSpinner = utils.createSpinner('Checking hosted resources').start();
88
- try {
89
- const resourcesResponse = await api.listMcpResources();
90
- const count = (resourcesResponse.resources || []).length;
91
- resourceSpinner.succeed(`Loaded ${count} hosted resource${count === 1 ? '' : 's'}`);
92
- } catch (error) {
93
- resourceSpinner.fail(redactErrorMessage(error));
94
- return;
95
- }
96
-
97
- const connectorSpinner = utils.createSpinner('Checking managed connectors').start();
98
- try {
99
- const connectorsResponse = await api.listMcpConnectors();
100
- const count = (connectorsResponse.connectors || []).length;
101
- connectorSpinner.succeed(`Loaded ${count} managed connector${count === 1 ? '' : 's'}`);
102
- } catch (error) {
103
- connectorSpinner.fail(redactErrorMessage(error));
104
- }
105
-
106
- console.log();
107
- }
108
-
109
- async function listConnectors() {
110
- console.log(`\n${C.cyan}${C.bold}Managed Connectors${C.reset}\n`);
111
-
112
- if (!auth.isAuthenticated()) {
113
- console.log(`${C.yellow}Authentication required${C.reset}`);
114
- console.log(`${C.dim}Run 'bootspring auth login' first${C.reset}\n`);
115
- return;
116
- }
117
-
118
- const spinner = utils.createSpinner('Fetching connectors').start();
119
- try {
120
- const response = await api.listMcpConnectors();
121
- const connectors = response.connectors || [];
122
- spinner.stop();
123
-
124
- if (connectors.length === 0) {
125
- console.log(`${C.dim}No managed connectors available.${C.reset}\n`);
126
- return;
127
- }
128
-
129
- connectors.forEach((connector) => {
130
- const status = connector.active
131
- ? `${C.green}active${C.reset}`
132
- : connector.accessible
133
- ? `${C.dim}available${C.reset}`
134
- : `${C.yellow}requires ${connector.requiredTier}${C.reset}`;
135
-
136
- console.log(` ${C.cyan}${connector.id}${C.reset}`);
137
- console.log(` ${connector.description}`);
138
- console.log(` Status: ${status}`);
139
- console.log();
140
- });
141
- } catch (error) {
142
- spinner.fail(redactErrorMessage(error));
143
- console.log();
144
- }
145
- }
146
-
147
- async function toggleConnector(connectorId, enabled) {
148
- if (!connectorId) {
149
- console.log(`${C.red}Connector id required${C.reset}`);
150
- console.log(`${C.dim}Usage: bootspring mcp connectors ${enabled ? 'enable' : 'disable'} <id>${C.reset}\n`);
151
- return;
152
- }
153
-
154
- const spinner = utils.createSpinner(`${enabled ? 'Enabling' : 'Disabling'} ${connectorId}`).start();
155
- try {
156
- const response = await api.setMcpConnectorEnabled(connectorId, enabled);
157
- const updated = response.updated;
158
- spinner.succeed(`${updated?.name || connectorId} ${enabled ? 'enabled' : 'disabled'}`);
159
- } catch (error) {
160
- spinner.fail(redactErrorMessage(error));
161
- }
162
-
163
- console.log();
164
- }
165
-
166
- async function handleConnectors(args) {
167
- const action = args[0];
168
-
169
- if (!action || action === 'list') {
170
- await listConnectors();
171
- return;
172
- }
173
-
174
- if (action === 'enable') {
175
- await toggleConnector(args[1], true);
176
- return;
177
- }
178
-
179
- if (action === 'disable') {
180
- await toggleConnector(args[1], false);
181
- return;
182
- }
183
-
184
- console.log(`${C.red}Unknown connector action: ${action}${C.reset}\n`);
185
- }
186
-
187
- function showHelp() {
188
- console.log(`
189
- ${C.cyan}${C.bold}Bootspring MCP${C.reset}
190
-
191
- ${C.bold}Usage:${C.reset}
192
- bootspring mcp
193
- bootspring mcp status
194
- bootspring mcp test
195
- bootspring mcp config
196
- bootspring mcp connectors
197
- `);
198
- }
199
-
200
- async function run(args) {
201
- const subcommand = args[0];
202
-
203
- if (!subcommand) {
204
- await startServer();
205
- return;
206
- }
207
-
208
- switch (subcommand) {
209
- case 'status':
210
- await showStatus();
211
- break;
212
- case 'test':
213
- await testMcp();
214
- break;
215
- case 'config':
216
- case 'init':
217
- case 'setup':
218
- generateConfig();
219
- break;
220
- case 'connectors':
221
- case 'connector':
222
- await handleConnectors(args.slice(1));
223
- break;
224
- case 'help':
225
- case '-h':
226
- case '--help':
227
- showHelp();
228
- break;
229
- default:
230
- console.log(`${C.red}Unknown subcommand: ${subcommand}${C.reset}\n`);
231
- showHelp();
232
- }
233
- }
234
-
235
- module.exports = {
236
- run,
237
- startServer,
238
- showStatus,
239
- testMcp
240
- };
@@ -1,240 +0,0 @@
1
- /**
2
- * Bootspring Orchestrator Command
3
- * Thin client for hosted workflow orchestration.
4
- */
5
-
6
- const api = require('../core/api-client');
7
- const auth = require('../core/auth');
8
- const config = require('../core/config');
9
- const utils = require('../core/utils');
10
-
11
- const C = utils.COLORS;
12
-
13
- function buildProjectContext() {
14
- const cfg = config.load();
15
- const techStack = [
16
- cfg.stack?.framework,
17
- cfg.stack?.language,
18
- cfg.stack?.database,
19
- cfg.stack?.hosting
20
- ].filter(Boolean);
21
-
22
- return {
23
- name: cfg.project?.name,
24
- projectType: cfg.stack?.framework || 'unknown',
25
- techStack,
26
- cwd: process.cwd()
27
- };
28
- }
29
-
30
- function requireAuth() {
31
- if (auth.isAuthenticated()) {
32
- return true;
33
- }
34
-
35
- console.log(`${C.yellow}Not logged in${C.reset}`);
36
- console.log(`${C.dim}Run 'bootspring auth login' first${C.reset}\n`);
37
- return false;
38
- }
39
-
40
- async function listWorkflows() {
41
- console.log(`\n${C.cyan}${C.bold}Hosted Workflows${C.reset}\n`);
42
- const response = await api.listWorkflows();
43
- const workflows = response.workflows || [];
44
-
45
- if (workflows.length === 0) {
46
- console.log(`${C.dim}No workflows available for your account.${C.reset}\n`);
47
- return;
48
- }
49
-
50
- for (const workflow of workflows) {
51
- const suffix = workflow.accessible ? '' : ` ${C.yellow}(Upgrade Required)${C.reset}`;
52
- console.log(` ${C.cyan}${workflow.id}${C.reset}${suffix}`);
53
- console.log(` ${C.dim}${workflow.description}${C.reset}\n`);
54
- }
55
- }
56
-
57
- async function showWorkflow(id) {
58
- if (!id) {
59
- await listWorkflows();
60
- return;
61
- }
62
-
63
- const response = await api.getWorkflow(id);
64
- const workflow = response.workflow || response;
65
-
66
- console.log(`\n${C.cyan}${C.bold}${workflow.name || workflow.id}${C.reset}\n`);
67
- console.log(`${workflow.description || 'No description available.'}\n`);
68
-
69
- if (Array.isArray(workflow.steps) && workflow.steps.length > 0) {
70
- console.log(`${C.bold}Steps${C.reset}`);
71
- workflow.steps.forEach((step, index) => {
72
- const label = step.name || step.title || `Step ${index + 1}`;
73
- console.log(` ${index + 1}. ${label}`);
74
- });
75
- console.log();
76
- }
77
-
78
- if (Array.isArray(workflow.agents) && workflow.agents.length > 0) {
79
- console.log(`${C.bold}Agents${C.reset}`);
80
- console.log(` ${workflow.agents.join(', ')}`);
81
- console.log();
82
- }
83
- }
84
-
85
- async function analyze(task) {
86
- console.log(`\n${C.cyan}${C.bold}Orchestrator Analysis${C.reset}\n`);
87
- const response = await api.analyzeContext(buildProjectContext(), task || '', []);
88
- const recommendations = response.recommendations || {};
89
- const workflows = recommendations.workflows || [];
90
- const agents = recommendations.agents || [];
91
-
92
- if (workflows.length === 0 && agents.length === 0) {
93
- console.log(`${C.dim}No hosted recommendations were returned.${C.reset}\n`);
94
- return;
95
- }
96
-
97
- if (workflows.length > 0) {
98
- console.log(`${C.bold}Recommended Workflows${C.reset}`);
99
- workflows.forEach((workflow) => {
100
- console.log(` ${C.cyan}${workflow.id || workflow.name}${C.reset} ${C.dim}(score ${workflow.score || 0})${C.reset}`);
101
- });
102
- console.log();
103
- }
104
-
105
- if (agents.length > 0) {
106
- console.log(`${C.bold}Suggested Agents${C.reset}`);
107
- agents.forEach((agent) => {
108
- console.log(` ${C.cyan}${agent.id}${C.reset} ${C.dim}${agent.reason}${C.reset}`);
109
- });
110
- console.log();
111
- }
112
- }
113
-
114
- async function suggest(task) {
115
- console.log(`\n${C.cyan}${C.bold}Hosted Suggestions${C.reset}\n`);
116
- const response = await api.getSuggestions({ task, cwd: process.cwd() }, 'agent');
117
- const suggestions = response.suggestions || [];
118
-
119
- if (suggestions.length === 0) {
120
- console.log(`${C.dim}No suggestions returned.${C.reset}\n`);
121
- return;
122
- }
123
-
124
- suggestions.forEach((suggestion) => {
125
- if (suggestion.agent) {
126
- console.log(` ${C.cyan}${suggestion.agent}${C.reset} ${C.dim}${suggestion.reason || ''}${C.reset}`);
127
- return;
128
- }
129
-
130
- if (suggestion.step?.name) {
131
- console.log(` ${C.cyan}${suggestion.step.name}${C.reset} ${C.dim}${suggestion.message || ''}${C.reset}`);
132
- return;
133
- }
134
-
135
- console.log(` ${C.cyan}${suggestion.type || 'suggestion'}${C.reset} ${C.dim}${JSON.stringify(suggestion)}${C.reset}`);
136
- });
137
-
138
- console.log();
139
- }
140
-
141
- async function startWorkflow(id) {
142
- if (!id) {
143
- console.log(`${C.red}Workflow id required${C.reset}`);
144
- console.log(`${C.dim}Usage: bootspring orchestrator start <workflow-id>${C.reset}\n`);
145
- return;
146
- }
147
-
148
- const response = await api.startWorkflow(id, buildProjectContext(), {});
149
- const execution = response.execution || {};
150
-
151
- console.log(`\n${C.cyan}${C.bold}Workflow Started${C.reset}\n`);
152
- console.log(`${response.message || `Started ${id}`}\n`);
153
-
154
- if (Array.isArray(execution.steps) && execution.steps.length > 0) {
155
- console.log(`${C.bold}Steps${C.reset}`);
156
- execution.steps.forEach((step, index) => {
157
- console.log(` ${index + 1}. ${step.name || step.title || `Step ${index + 1}`}`);
158
- });
159
- console.log();
160
- }
161
- }
162
-
163
- async function status() {
164
- const response = await api.listWorkflows();
165
- const workflows = response.workflows || [];
166
- const accessible = workflows.filter((workflow) => workflow.accessible).length;
167
-
168
- console.log(`\n${C.cyan}${C.bold}Orchestrator Status${C.reset}\n`);
169
- console.log(` Tier: ${auth.getTier()}`);
170
- console.log(` Hosted workflows: ${workflows.length}`);
171
- console.log(` Accessible: ${accessible}\n`);
172
- }
173
-
174
- function showHelp() {
175
- console.log(`
176
- ${C.cyan}${C.bold}Bootspring Orchestrator${C.reset}
177
-
178
- ${C.bold}Usage:${C.reset}
179
- bootspring orchestrator <command> [args]
180
-
181
- ${C.bold}Commands:${C.reset}
182
- ${C.cyan}workflows${C.reset} List hosted workflows
183
- ${C.cyan}workflow${C.reset} <id> Show workflow details
184
- ${C.cyan}analyze${C.reset} <task> Analyze project context
185
- ${C.cyan}suggest${C.reset} <task> Get hosted suggestions
186
- ${C.cyan}start${C.reset} <id> Start a hosted workflow
187
- ${C.cyan}status${C.reset} Show orchestrator access
188
- `);
189
- }
190
-
191
- async function run(args) {
192
- const subcommand = args[0] || 'status';
193
- const param = args.slice(1).join(' ');
194
-
195
- if (subcommand === 'help' || subcommand === '-h' || subcommand === '--help') {
196
- showHelp();
197
- return;
198
- }
199
-
200
- if (!requireAuth()) {
201
- return;
202
- }
203
-
204
- try {
205
- switch (subcommand) {
206
- case 'workflows':
207
- case 'list':
208
- await listWorkflows();
209
- break;
210
- case 'workflow':
211
- await showWorkflow(args[1]);
212
- break;
213
- case 'analyze':
214
- await analyze(param);
215
- break;
216
- case 'suggest':
217
- await suggest(param);
218
- break;
219
- case 'start':
220
- await startWorkflow(args[1]);
221
- break;
222
- case 'status':
223
- await status();
224
- break;
225
- default:
226
- console.log(`${C.red}Unknown subcommand: ${subcommand}${C.reset}\n`);
227
- showHelp();
228
- }
229
- } catch (error) {
230
- if (error.status === 403) {
231
- console.log(`${C.yellow}This feature requires a paid Bootspring plan.${C.reset}`);
232
- console.log(`${C.dim}Upgrade: https://bootspring.com/pricing${C.reset}\n`);
233
- return;
234
- }
235
-
236
- throw error;
237
- }
238
- }
239
-
240
- module.exports = { run };