@girardmedia/bootspring 2.2.0 → 2.3.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/README.md +2 -2
- package/bin/bootspring.js +35 -96
- package/claude-commands/agent.md +34 -0
- package/claude-commands/bs.md +31 -0
- package/claude-commands/build.md +25 -0
- package/claude-commands/skill.md +31 -0
- package/claude-commands/todo.md +25 -0
- package/dist/cli/index.cjs +17808 -0
- package/dist/core/index.d.ts +5814 -0
- package/dist/core.js +5780 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp-server.js +2299 -0
- package/generators/api-docs.js +2 -2
- package/generators/decisions.js +3 -3
- package/generators/health.js +16 -16
- package/generators/sprint.js +2 -2
- package/package.json +27 -59
- package/core/api-client.d.ts +0 -69
- package/core/api-client.js +0 -1482
- package/core/auth.d.ts +0 -98
- package/core/auth.js +0 -737
- package/core/build-orchestrator.js +0 -508
- package/core/build-state.js +0 -612
- package/core/config.d.ts +0 -106
- package/core/config.js +0 -1328
- package/core/context-loader.js +0 -580
- package/core/context.d.ts +0 -61
- package/core/context.js +0 -327
- package/core/entitlements.d.ts +0 -70
- package/core/entitlements.js +0 -322
- package/core/index.d.ts +0 -53
- package/core/index.js +0 -62
- package/core/mcp-config.js +0 -115
- package/core/policies.d.ts +0 -43
- package/core/policies.js +0 -113
- package/core/policy-matrix.js +0 -303
- package/core/project-activity.js +0 -175
- package/core/redaction.d.ts +0 -5
- package/core/redaction.js +0 -63
- package/core/self-update.js +0 -259
- package/core/session.js +0 -353
- package/core/task-extractor.js +0 -1098
- package/core/telemetry.d.ts +0 -55
- package/core/telemetry.js +0 -617
- package/core/tier-enforcement.js +0 -928
- package/core/utils.d.ts +0 -90
- package/core/utils.js +0 -455
- package/core/validation.js +0 -572
- package/mcp/server.d.ts +0 -57
- package/mcp/server.js +0 -264
package/core/utils.d.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bootspring Utils Types
|
|
3
|
-
* @module core/utils
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface Spinner {
|
|
7
|
-
start(): Spinner;
|
|
8
|
-
stop(): Spinner;
|
|
9
|
-
succeed(text?: string): Spinner;
|
|
10
|
-
fail(text?: string): Spinner;
|
|
11
|
-
warn(text?: string): Spinner;
|
|
12
|
-
info(text?: string): Spinner;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ParsedArgs {
|
|
16
|
-
_: string[];
|
|
17
|
-
[key: string]: string | boolean | string[] | undefined;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** ANSI color codes */
|
|
21
|
-
export const COLORS: {
|
|
22
|
-
reset: string;
|
|
23
|
-
bold: string;
|
|
24
|
-
dim: string;
|
|
25
|
-
red: string;
|
|
26
|
-
green: string;
|
|
27
|
-
yellow: string;
|
|
28
|
-
blue: string;
|
|
29
|
-
cyan: string;
|
|
30
|
-
magenta: string;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/** Print helpers */
|
|
34
|
-
export const print: {
|
|
35
|
-
success(message: string): void;
|
|
36
|
-
error(message: string): void;
|
|
37
|
-
warning(message: string): void;
|
|
38
|
-
info(message: string): void;
|
|
39
|
-
dim(message: string): void;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Parse command line arguments
|
|
44
|
-
* @param args - Arguments array
|
|
45
|
-
* @returns Parsed arguments object
|
|
46
|
-
*/
|
|
47
|
-
export function parseArgs(args: string[]): ParsedArgs;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Create a CLI spinner
|
|
51
|
-
* @param text - Spinner text
|
|
52
|
-
* @returns Spinner instance
|
|
53
|
-
*/
|
|
54
|
-
export function createSpinner(text: string): Spinner;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Format date for display
|
|
58
|
-
* @param date - Date to format
|
|
59
|
-
* @returns Formatted date string
|
|
60
|
-
*/
|
|
61
|
-
export function formatDate(date: Date | string | number): string;
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Format relative time
|
|
65
|
-
* @param date - Date to format
|
|
66
|
-
* @returns Relative time string (e.g., "2 hours ago")
|
|
67
|
-
*/
|
|
68
|
-
export function formatRelativeTime(date: Date | string | number): string;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Check if file exists
|
|
72
|
-
* @param filePath - Path to check
|
|
73
|
-
* @returns True if file exists
|
|
74
|
-
*/
|
|
75
|
-
export function fileExists(filePath: string): boolean;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Read file contents
|
|
79
|
-
* @param filePath - Path to read
|
|
80
|
-
* @returns File contents or null
|
|
81
|
-
*/
|
|
82
|
-
export function readFile(filePath: string): string | null;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Create a formatted table
|
|
86
|
-
* @param headers - Table headers
|
|
87
|
-
* @param rows - Table rows
|
|
88
|
-
* @returns Formatted table string
|
|
89
|
-
*/
|
|
90
|
-
export function createTable(headers: string[], rows: string[][]): string;
|
package/core/utils.js
DELETED
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bootspring Utilities
|
|
3
|
-
* Shared utility functions
|
|
4
|
-
*
|
|
5
|
-
* @package bootspring
|
|
6
|
-
* @module core/utils
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
|
|
12
|
-
// ANSI color codes
|
|
13
|
-
const COLORS = {
|
|
14
|
-
reset: '\x1b[0m',
|
|
15
|
-
bold: '\x1b[1m',
|
|
16
|
-
dim: '\x1b[2m',
|
|
17
|
-
italic: '\x1b[3m',
|
|
18
|
-
underline: '\x1b[4m',
|
|
19
|
-
|
|
20
|
-
// Foreground
|
|
21
|
-
black: '\x1b[30m',
|
|
22
|
-
red: '\x1b[31m',
|
|
23
|
-
green: '\x1b[32m',
|
|
24
|
-
yellow: '\x1b[33m',
|
|
25
|
-
blue: '\x1b[34m',
|
|
26
|
-
magenta: '\x1b[35m',
|
|
27
|
-
cyan: '\x1b[36m',
|
|
28
|
-
white: '\x1b[37m',
|
|
29
|
-
|
|
30
|
-
// Background
|
|
31
|
-
bgBlack: '\x1b[40m',
|
|
32
|
-
bgRed: '\x1b[41m',
|
|
33
|
-
bgGreen: '\x1b[42m',
|
|
34
|
-
bgYellow: '\x1b[43m',
|
|
35
|
-
bgBlue: '\x1b[44m',
|
|
36
|
-
bgMagenta: '\x1b[45m',
|
|
37
|
-
bgCyan: '\x1b[46m',
|
|
38
|
-
bgWhite: '\x1b[47m'
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Styled console output
|
|
43
|
-
*/
|
|
44
|
-
const print = {
|
|
45
|
-
info: (msg) => console.log(`${COLORS.cyan}ℹ${COLORS.reset} ${msg}`),
|
|
46
|
-
success: (msg) => console.log(`${COLORS.green}✓${COLORS.reset} ${msg}`),
|
|
47
|
-
warning: (msg) => console.log(`${COLORS.yellow}⚠${COLORS.reset} ${msg}`),
|
|
48
|
-
error: (msg) => console.log(`${COLORS.red}✗${COLORS.reset} ${msg}`),
|
|
49
|
-
debug: (msg) => process.env.DEBUG && console.log(`${COLORS.dim}⋯ ${msg}${COLORS.reset}`),
|
|
50
|
-
header: (msg) => console.log(`\n${COLORS.bold}${COLORS.cyan}${msg}${COLORS.reset}\n`),
|
|
51
|
-
dim: (msg) => console.log(`${COLORS.dim}${msg}${COLORS.reset}`),
|
|
52
|
-
brand: (msg) => console.log(`${COLORS.cyan}⚡${COLORS.reset} ${msg}`)
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Create a spinner for async operations
|
|
57
|
-
* @param {string} message - Spinner message
|
|
58
|
-
* @returns {object} Spinner controller
|
|
59
|
-
*/
|
|
60
|
-
function createSpinner(message) {
|
|
61
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
62
|
-
let frameIndex = 0;
|
|
63
|
-
let interval = null;
|
|
64
|
-
const isTTY = process.stdout.isTTY;
|
|
65
|
-
|
|
66
|
-
// Helper to clear line safely
|
|
67
|
-
const clearLine = () => {
|
|
68
|
-
if (isTTY && process.stdout.clearLine) {
|
|
69
|
-
process.stdout.clearLine(0);
|
|
70
|
-
process.stdout.cursorTo(0);
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
start() {
|
|
76
|
-
if (isTTY) {
|
|
77
|
-
process.stdout.write(`${COLORS.cyan}${frames[0]}${COLORS.reset} ${message}`);
|
|
78
|
-
interval = setInterval(() => {
|
|
79
|
-
frameIndex = (frameIndex + 1) % frames.length;
|
|
80
|
-
clearLine();
|
|
81
|
-
process.stdout.write(`${COLORS.cyan}${frames[frameIndex]}${COLORS.reset} ${message}`);
|
|
82
|
-
}, 80);
|
|
83
|
-
}
|
|
84
|
-
return this;
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
succeed(text = message) {
|
|
88
|
-
if (interval) clearInterval(interval);
|
|
89
|
-
clearLine();
|
|
90
|
-
console.log(`${COLORS.green}✓${COLORS.reset} ${text}`);
|
|
91
|
-
return this;
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
fail(text = message) {
|
|
95
|
-
if (interval) clearInterval(interval);
|
|
96
|
-
clearLine();
|
|
97
|
-
console.log(`${COLORS.red}✗${COLORS.reset} ${text}`);
|
|
98
|
-
return this;
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
warn(text = message) {
|
|
102
|
-
if (interval) clearInterval(interval);
|
|
103
|
-
clearLine();
|
|
104
|
-
console.log(`${COLORS.yellow}⚠${COLORS.reset} ${text}`);
|
|
105
|
-
return this;
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
info(text = message) {
|
|
109
|
-
if (interval) clearInterval(interval);
|
|
110
|
-
clearLine();
|
|
111
|
-
console.log(`${COLORS.cyan}ℹ${COLORS.reset} ${text}`);
|
|
112
|
-
return this;
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
stop() {
|
|
116
|
-
if (interval) clearInterval(interval);
|
|
117
|
-
clearLine();
|
|
118
|
-
return this;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Ensure directory exists
|
|
125
|
-
* @param {string} dirPath - Directory path
|
|
126
|
-
* @returns {boolean} Success status
|
|
127
|
-
*/
|
|
128
|
-
function ensureDir(dirPath) {
|
|
129
|
-
try {
|
|
130
|
-
if (!fs.existsSync(dirPath)) {
|
|
131
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
|
-
} catch {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Read file safely
|
|
141
|
-
* @param {string} filepath - File path
|
|
142
|
-
* @param {string} [defaultValue=null] - Default value if file doesn't exist
|
|
143
|
-
* @returns {string|null} File contents or default value (null if not found)
|
|
144
|
-
*/
|
|
145
|
-
function readFile(filepath, defaultValue = null) {
|
|
146
|
-
try {
|
|
147
|
-
return fs.readFileSync(filepath, 'utf-8');
|
|
148
|
-
} catch {
|
|
149
|
-
return defaultValue;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Write file safely
|
|
155
|
-
* @param {string} filepath - File path
|
|
156
|
-
* @param {string} content - File content
|
|
157
|
-
* @returns {boolean} Success status
|
|
158
|
-
*/
|
|
159
|
-
function writeFile(filepath, content) {
|
|
160
|
-
try {
|
|
161
|
-
const dir = path.dirname(filepath);
|
|
162
|
-
ensureDir(dir);
|
|
163
|
-
fs.writeFileSync(filepath, content, 'utf-8');
|
|
164
|
-
return true;
|
|
165
|
-
} catch {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Check if file exists
|
|
172
|
-
* @param {string} filepath - File path
|
|
173
|
-
* @returns {boolean} Exists status
|
|
174
|
-
*/
|
|
175
|
-
function fileExists(filepath) {
|
|
176
|
-
try {
|
|
177
|
-
return fs.existsSync(filepath);
|
|
178
|
-
} catch {
|
|
179
|
-
return false;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Get file modification time
|
|
185
|
-
* @param {string} filepath - File path
|
|
186
|
-
* @returns {Date|null} Modification date or null
|
|
187
|
-
*/
|
|
188
|
-
function getFileTime(filepath) {
|
|
189
|
-
try {
|
|
190
|
-
const stats = fs.statSync(filepath);
|
|
191
|
-
return stats.mtime;
|
|
192
|
-
} catch {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Format date as ISO string without time
|
|
199
|
-
* @param {Date} date - Date object
|
|
200
|
-
* @returns {string} Formatted date
|
|
201
|
-
*/
|
|
202
|
-
function formatDate(date = new Date()) {
|
|
203
|
-
return date.toISOString().split('T')[0];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Format date as relative time
|
|
208
|
-
* @param {Date} date - Date object
|
|
209
|
-
* @returns {string} Relative time string
|
|
210
|
-
*/
|
|
211
|
-
function formatRelativeTime(date) {
|
|
212
|
-
const now = new Date();
|
|
213
|
-
const diff = now - date;
|
|
214
|
-
const seconds = Math.floor(diff / 1000);
|
|
215
|
-
const minutes = Math.floor(seconds / 60);
|
|
216
|
-
const hours = Math.floor(minutes / 60);
|
|
217
|
-
const days = Math.floor(hours / 24);
|
|
218
|
-
|
|
219
|
-
if (days > 0) return `${days} day${days > 1 ? 's' : ''} ago`;
|
|
220
|
-
if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''} ago`;
|
|
221
|
-
if (minutes > 0) return `${minutes} minute${minutes > 1 ? 's' : ''} ago`;
|
|
222
|
-
return 'just now';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Slugify a string
|
|
227
|
-
* @param {string} str - Input string
|
|
228
|
-
* @returns {string} Slugified string
|
|
229
|
-
*/
|
|
230
|
-
function slugify(str) {
|
|
231
|
-
return str
|
|
232
|
-
.toLowerCase()
|
|
233
|
-
.trim()
|
|
234
|
-
.replace(/[^\w\s-]/g, '')
|
|
235
|
-
.replace(/[\s_-]+/g, '-')
|
|
236
|
-
.replace(/^-+|-+$/g, '');
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Truncate string with ellipsis
|
|
241
|
-
* @param {string} str - Input string
|
|
242
|
-
* @param {number} length - Max length
|
|
243
|
-
* @returns {string} Truncated string
|
|
244
|
-
*/
|
|
245
|
-
function truncate(str, length = 50) {
|
|
246
|
-
if (str.length <= length) return str;
|
|
247
|
-
return str.slice(0, length - 3) + '...';
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Parse command line arguments
|
|
252
|
-
* @param {string[]} args - Argument array
|
|
253
|
-
* @returns {object} Parsed arguments { _: positional, ...flags }
|
|
254
|
-
*/
|
|
255
|
-
function parseArgs(args) {
|
|
256
|
-
const result = { _: [] };
|
|
257
|
-
|
|
258
|
-
for (let i = 0; i < args.length; i++) {
|
|
259
|
-
const arg = args[i];
|
|
260
|
-
|
|
261
|
-
if (arg.startsWith('--')) {
|
|
262
|
-
const key = arg.slice(2);
|
|
263
|
-
const nextArg = args[i + 1];
|
|
264
|
-
|
|
265
|
-
if (key.includes('=')) {
|
|
266
|
-
const [k, v] = key.split('=');
|
|
267
|
-
result[k] = v;
|
|
268
|
-
} else if (nextArg && !nextArg.startsWith('-')) {
|
|
269
|
-
result[key] = nextArg;
|
|
270
|
-
i++;
|
|
271
|
-
} else {
|
|
272
|
-
result[key] = true;
|
|
273
|
-
}
|
|
274
|
-
} else if (arg.startsWith('-') && arg.length === 2) {
|
|
275
|
-
// Short flag (e.g., -v, -n)
|
|
276
|
-
const key = arg.slice(1);
|
|
277
|
-
const nextArg = args[i + 1];
|
|
278
|
-
|
|
279
|
-
// Check if next argument is a value (not another flag)
|
|
280
|
-
if (nextArg && !nextArg.startsWith('-')) {
|
|
281
|
-
result[key] = nextArg;
|
|
282
|
-
i++;
|
|
283
|
-
} else {
|
|
284
|
-
result[key] = true;
|
|
285
|
-
}
|
|
286
|
-
} else if (arg.startsWith('-')) {
|
|
287
|
-
// Combined short flags (e.g., -abc) - treat each as boolean
|
|
288
|
-
const keys = arg.slice(1).split('');
|
|
289
|
-
for (const key of keys) {
|
|
290
|
-
result[key] = true;
|
|
291
|
-
}
|
|
292
|
-
} else {
|
|
293
|
-
result._.push(arg);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
return result;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Create a simple table for console output
|
|
302
|
-
* @param {string[]} headers - Table headers
|
|
303
|
-
* @param {string[][]} rows - Table rows
|
|
304
|
-
* @returns {string} Formatted table
|
|
305
|
-
*/
|
|
306
|
-
function createTable(headers, rows) {
|
|
307
|
-
const widths = headers.map((h, i) => {
|
|
308
|
-
const colValues = [h, ...rows.map(r => String(r[i] || ''))];
|
|
309
|
-
return Math.max(...colValues.map(v => v.length));
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
const separator = widths.map(w => '─'.repeat(w + 2)).join('┼');
|
|
313
|
-
const formatRow = (row) => row.map((cell, i) => ` ${String(cell).padEnd(widths[i])} `).join('│');
|
|
314
|
-
|
|
315
|
-
const lines = [
|
|
316
|
-
formatRow(headers),
|
|
317
|
-
separator,
|
|
318
|
-
...rows.map(formatRow)
|
|
319
|
-
];
|
|
320
|
-
|
|
321
|
-
return lines.join('\n');
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Deep clone an object
|
|
326
|
-
* @param {object} obj - Object to clone
|
|
327
|
-
* @returns {object} Cloned object
|
|
328
|
-
*/
|
|
329
|
-
function deepClone(obj) {
|
|
330
|
-
return JSON.parse(JSON.stringify(obj));
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Check if running in CI environment
|
|
335
|
-
* @returns {boolean} CI status
|
|
336
|
-
*/
|
|
337
|
-
function isCI() {
|
|
338
|
-
return !!(
|
|
339
|
-
process.env.CI ||
|
|
340
|
-
process.env.CONTINUOUS_INTEGRATION ||
|
|
341
|
-
process.env.GITHUB_ACTIONS ||
|
|
342
|
-
process.env.GITLAB_CI ||
|
|
343
|
-
process.env.CIRCLECI ||
|
|
344
|
-
process.env.TRAVIS
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Get package.json from project
|
|
350
|
-
* @param {string} projectRoot - Project root path
|
|
351
|
-
* @returns {object|null} Package.json contents or null
|
|
352
|
-
*/
|
|
353
|
-
function getPackageJson(projectRoot) {
|
|
354
|
-
const pkgPath = path.join(projectRoot, 'package.json');
|
|
355
|
-
try {
|
|
356
|
-
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
357
|
-
} catch {
|
|
358
|
-
return null;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Check if running in MCP context (AI assistant integration only)
|
|
364
|
-
* @returns {boolean} MCP status
|
|
365
|
-
*/
|
|
366
|
-
function isMCPContext() {
|
|
367
|
-
return !!(
|
|
368
|
-
process.env.BOOTSPRING_MCP ||
|
|
369
|
-
process.env.MCP_SERVER ||
|
|
370
|
-
process.env.CLAUDE_CODE_MCP
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* Print MCP recommendation message and return false if not in MCP context.
|
|
376
|
-
* This is a soft gate - callers should provide degraded functionality.
|
|
377
|
-
* @param {string} feature - Feature name that benefits from MCP
|
|
378
|
-
* @param {Object} options - Configuration options
|
|
379
|
-
* @param {boolean} options.silent - Don't print any message
|
|
380
|
-
* @param {boolean} options.brief - Print brief message instead of full
|
|
381
|
-
* @returns {boolean} True if in MCP context, false otherwise
|
|
382
|
-
*/
|
|
383
|
-
function requireMCP(feature, options = {}) {
|
|
384
|
-
if (isMCPContext()) {
|
|
385
|
-
return true;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (options.silent) {
|
|
389
|
-
return false;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if (options.brief) {
|
|
393
|
-
console.log(`${COLORS.dim}Note: ${feature} has enhanced features when used with MCP integration.${COLORS.reset}`);
|
|
394
|
-
console.log(`${COLORS.dim}Run "bootspring mcp" for setup instructions.${COLORS.reset}\n`);
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
console.log(`
|
|
399
|
-
${COLORS.yellow}${COLORS.bold}Limited Mode - MCP Integration Recommended${COLORS.reset}
|
|
400
|
-
|
|
401
|
-
${feature} works in CLI mode but has enhanced features through MCP integration.
|
|
402
|
-
MCP enables real-time AI-assisted workflows and deeper integration.
|
|
403
|
-
|
|
404
|
-
${COLORS.bold}Current Mode:${COLORS.reset} CLI (limited functionality)
|
|
405
|
-
${COLORS.bold}Enhanced Mode:${COLORS.reset} MCP (full AI integration)
|
|
406
|
-
|
|
407
|
-
${COLORS.bold}To enable full features:${COLORS.reset}
|
|
408
|
-
1. Start the MCP server:
|
|
409
|
-
${COLORS.cyan}bootspring mcp start${COLORS.reset}
|
|
410
|
-
|
|
411
|
-
2. Add Bootspring to your AI client's MCP configuration
|
|
412
|
-
|
|
413
|
-
${COLORS.bold}Documentation:${COLORS.reset}
|
|
414
|
-
https://bootspring.com/docs/mcp-setup
|
|
415
|
-
|
|
416
|
-
${COLORS.dim}Run "bootspring mcp" for server options${COLORS.reset}
|
|
417
|
-
`);
|
|
418
|
-
|
|
419
|
-
return false;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
/**
|
|
423
|
-
* Print a warning about MCP-only features (non-blocking)
|
|
424
|
-
* Use this when a command works without MCP but has reduced functionality
|
|
425
|
-
* @param {string} feature - Feature with limited functionality
|
|
426
|
-
*/
|
|
427
|
-
function warnMCPLimited(feature) {
|
|
428
|
-
if (isMCPContext()) return;
|
|
429
|
-
|
|
430
|
-
console.log(`${COLORS.dim}Note: ${feature} - some features require MCP integration.${COLORS.reset}`);
|
|
431
|
-
console.log(`${COLORS.dim}Run "bootspring mcp" for setup instructions.${COLORS.reset}\n`);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
module.exports = {
|
|
435
|
-
COLORS,
|
|
436
|
-
print,
|
|
437
|
-
createSpinner,
|
|
438
|
-
ensureDir,
|
|
439
|
-
readFile,
|
|
440
|
-
writeFile,
|
|
441
|
-
fileExists,
|
|
442
|
-
getFileTime,
|
|
443
|
-
formatDate,
|
|
444
|
-
formatRelativeTime,
|
|
445
|
-
slugify,
|
|
446
|
-
truncate,
|
|
447
|
-
parseArgs,
|
|
448
|
-
createTable,
|
|
449
|
-
deepClone,
|
|
450
|
-
isCI,
|
|
451
|
-
getPackageJson,
|
|
452
|
-
isMCPContext,
|
|
453
|
-
requireMCP,
|
|
454
|
-
warnMCPLimited
|
|
455
|
-
};
|