@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/core/session.js DELETED
@@ -1,353 +0,0 @@
1
- /**
2
- * Bootspring Session Manager
3
- *
4
- * Manages the current project session context linked to bootspring.com API.
5
- * This tracks which project the CLI is currently working with.
6
- *
7
- * @package bootspring
8
- * @module core/session
9
- */
10
-
11
- const fs = require('fs');
12
- const path = require('path');
13
- const os = require('os');
14
-
15
- const BOOTSPRING_DIR = path.join(os.homedir(), '.bootspring');
16
- const SESSION_FILE = path.join(BOOTSPRING_DIR, 'session.json');
17
- const LOCAL_CONFIG_NAME = '.bootspring.json';
18
-
19
- /**
20
- * Ensure ~/.bootspring directory exists
21
- */
22
- function ensureDir() {
23
- if (!fs.existsSync(BOOTSPRING_DIR)) {
24
- fs.mkdirSync(BOOTSPRING_DIR, { recursive: true, mode: 0o700 });
25
- }
26
- }
27
-
28
- /**
29
- * Get current session data
30
- * @returns {object|null} Session data or null
31
- */
32
- function getSession() {
33
- try {
34
- if (fs.existsSync(SESSION_FILE)) {
35
- return JSON.parse(fs.readFileSync(SESSION_FILE, 'utf-8'));
36
- }
37
- } catch {
38
- // Ignore read errors
39
- }
40
- return null;
41
- }
42
-
43
- /**
44
- * Save session data
45
- * @param {object} session - Session data
46
- */
47
- function saveSession(session) {
48
- ensureDir();
49
- const data = {
50
- ...session,
51
- updatedAt: new Date().toISOString()
52
- };
53
- fs.writeFileSync(SESSION_FILE, JSON.stringify(data, null, 2));
54
- }
55
-
56
- /**
57
- * Clear session
58
- */
59
- function clearSession() {
60
- try {
61
- if (fs.existsSync(SESSION_FILE)) {
62
- fs.unlinkSync(SESSION_FILE);
63
- }
64
- } catch {
65
- // Ignore delete errors
66
- }
67
- }
68
-
69
- /**
70
- * Get current project context
71
- * @returns {object|null} Project context
72
- */
73
- function getCurrentProject() {
74
- const session = getSession();
75
- return session?.project || null;
76
- }
77
-
78
- const PROJECT_SCOPE_MARKERS = [
79
- LOCAL_CONFIG_NAME,
80
- 'bootspring.config.js',
81
- '.git'
82
- ];
83
-
84
- function hasScopeMarker(dir) {
85
- for (const marker of PROJECT_SCOPE_MARKERS) {
86
- if (fs.existsSync(path.join(dir, marker))) {
87
- return true;
88
- }
89
- }
90
- return false;
91
- }
92
-
93
- function normalizeDirPath(dir) {
94
- const resolved = path.resolve(dir);
95
- try {
96
- return fs.realpathSync.native(resolved);
97
- } catch {
98
- try {
99
- return fs.realpathSync(resolved);
100
- } catch {
101
- return resolved;
102
- }
103
- }
104
- }
105
-
106
- function findNearestScopeRoot(startDir) {
107
- let dir = normalizeDirPath(startDir);
108
- for (let i = 0; i < 10; i++) {
109
- if (hasScopeMarker(dir)) {
110
- return dir;
111
- }
112
- const parent = path.dirname(dir);
113
- if (parent === dir) {
114
- break;
115
- }
116
- dir = parent;
117
- }
118
- return null;
119
- }
120
-
121
- function resolveProjectScope(scopeDir) {
122
- const resolvedDir = normalizeDirPath(scopeDir);
123
- const scopeRoot = findNearestScopeRoot(resolvedDir);
124
- if (scopeRoot) {
125
- return { dir: scopeRoot, mode: 'tree' };
126
- }
127
- return { dir: resolvedDir, mode: 'exact' };
128
- }
129
-
130
- function getScopeMode(sessionData, resolvedScopeDir) {
131
- if (sessionData.projectScopeMode === 'exact' || sessionData.projectScopeMode === 'tree') {
132
- return sessionData.projectScopeMode;
133
- }
134
-
135
- // Legacy sessions without explicit mode are treated as tree only when the
136
- // saved scope is clearly a project root. Otherwise, fall back to exact
137
- // matching to prevent cross-folder leakage.
138
- return hasScopeMarker(resolvedScopeDir) ? 'tree' : 'exact';
139
- }
140
-
141
- /**
142
- * Set current project context
143
- * @param {object} project - Project info { id, name, slug, ... }
144
- */
145
- function setCurrentProject(project, scopeDir) {
146
- const session = getSession() || {};
147
-
148
- if (project) {
149
- const scope = resolveProjectScope(scopeDir || process.cwd());
150
- session.project = project;
151
- session.projectScopeDir = scope.dir;
152
- session.projectScopeMode = scope.mode;
153
- } else {
154
- delete session.project;
155
- delete session.projectScopeDir;
156
- delete session.projectScopeMode;
157
- }
158
-
159
- saveSession(session);
160
- }
161
-
162
- /**
163
- * Get recent projects
164
- * @returns {Array} Recent projects
165
- */
166
- function getRecentProjects() {
167
- const session = getSession();
168
- return session?.recentProjects || [];
169
- }
170
-
171
- /**
172
- * Add to recent projects
173
- * @param {object} project - Project to add
174
- */
175
- function addRecentProject(project) {
176
- const session = getSession() || {};
177
- const recent = session.recentProjects || [];
178
-
179
- // Remove if already exists
180
- const filtered = recent.filter(p => p.id !== project.id);
181
-
182
- // Add to front
183
- filtered.unshift({
184
- id: project.id,
185
- name: project.name,
186
- slug: project.slug,
187
- lastUsed: new Date().toISOString()
188
- });
189
-
190
- // Keep only last 10
191
- session.recentProjects = filtered.slice(0, 10);
192
- saveSession(session);
193
- }
194
-
195
- /**
196
- * Check if a local .bootspring.json or bootspring.config.js exists in cwd or ancestors
197
- * @param {string} [startDir] - Starting directory
198
- * @returns {object|null} Local config or null
199
- */
200
- function findLocalConfig(startDir) {
201
- let dir = startDir || process.cwd();
202
-
203
- // Walk up to 10 directories
204
- for (let i = 0; i < 10; i++) {
205
- // First check for .bootspring.json
206
- const jsonConfigPath = path.join(dir, LOCAL_CONFIG_NAME);
207
- if (fs.existsSync(jsonConfigPath)) {
208
- try {
209
- const config = JSON.parse(fs.readFileSync(jsonConfigPath, 'utf-8'));
210
- return {
211
- ...config,
212
- _path: jsonConfigPath,
213
- _dir: dir
214
- };
215
- } catch {
216
- // Continue to check other config files
217
- }
218
- }
219
-
220
- // Also check for bootspring.config.js with projectId
221
- const jsConfigPath = path.join(dir, 'bootspring.config.js');
222
- if (fs.existsSync(jsConfigPath)) {
223
- try {
224
- // Clear require cache to get fresh config
225
- delete require.cache[require.resolve(jsConfigPath)];
226
- const config = require(jsConfigPath);
227
- if (config.projectId) {
228
- return {
229
- projectId: config.projectId,
230
- projectName: config.project?.name || config.name || 'Unknown',
231
- projectSlug: config.project?.slug,
232
- _path: jsConfigPath,
233
- _dir: dir,
234
- _fromJsConfig: true
235
- };
236
- }
237
- } catch {
238
- // Continue searching
239
- }
240
- }
241
-
242
- const parent = path.dirname(dir);
243
- if (parent === dir) break;
244
- dir = parent;
245
- }
246
-
247
- return null;
248
- }
249
-
250
- /**
251
- * Get effective project context (local config > session)
252
- * @returns {object|null} Project context
253
- */
254
- function getEffectiveProject(startDir) {
255
- // First check for local .bootspring.json
256
- const local = findLocalConfig(startDir);
257
- if (local?.projectId) {
258
- return {
259
- id: local.projectId,
260
- name: local.projectName || 'Unknown',
261
- slug: local.projectSlug,
262
- source: 'local',
263
- _localConfig: local
264
- };
265
- }
266
-
267
- const sessionData = getSession();
268
- const sessionProject = sessionData?.project || null;
269
- if (!sessionProject) {
270
- return null;
271
- }
272
-
273
- // Legacy session entries without scope are ignored to prevent cross-folder leakage.
274
- if (!sessionData?.projectScopeDir) {
275
- return null;
276
- }
277
-
278
- const resolvedScopeDir = normalizeDirPath(sessionData.projectScopeDir);
279
- const scopeMode = getScopeMode(sessionData, resolvedScopeDir);
280
- const currentDir = normalizeDirPath(startDir || process.cwd());
281
- const isInScope = (() => {
282
- if (scopeMode === 'exact') {
283
- return currentDir === resolvedScopeDir;
284
- }
285
-
286
- const relativeToScope = path.relative(resolvedScopeDir, currentDir);
287
- return relativeToScope === '' || (!relativeToScope.startsWith('..') && !path.isAbsolute(relativeToScope));
288
- })();
289
-
290
- if (isInScope) {
291
- return {
292
- ...sessionProject,
293
- source: 'session'
294
- };
295
- }
296
-
297
- return null;
298
- }
299
-
300
- /**
301
- * Create a local .bootspring.json file
302
- * @param {string} dir - Directory to create in
303
- * @param {object} project - Project info
304
- */
305
- function createLocalConfig(dir, project) {
306
- const configPath = path.join(dir, LOCAL_CONFIG_NAME);
307
- const config = {
308
- projectId: project.id,
309
- projectName: project.name,
310
- projectSlug: project.slug,
311
- createdAt: new Date().toISOString()
312
- };
313
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
314
- return configPath;
315
- }
316
-
317
- /**
318
- * Get full session state for display
319
- * @returns {object} Session state
320
- */
321
- function getSessionState() {
322
- const session = getSession();
323
- const effective = getEffectiveProject();
324
- const local = findLocalConfig();
325
-
326
- return {
327
- hasSession: !!session,
328
- project: effective,
329
- source: effective?.source || null,
330
- hasLocalConfig: !!local,
331
- localConfigPath: local?._path,
332
- recentProjects: session?.recentProjects || [],
333
- lastUpdated: session?.updatedAt || null
334
- };
335
- }
336
-
337
- module.exports = {
338
- BOOTSPRING_DIR,
339
- SESSION_FILE,
340
- LOCAL_CONFIG_NAME,
341
- ensureDir,
342
- getSession,
343
- saveSession,
344
- clearSession,
345
- getCurrentProject,
346
- setCurrentProject,
347
- getRecentProjects,
348
- addRecentProject,
349
- findLocalConfig,
350
- getEffectiveProject,
351
- createLocalConfig,
352
- getSessionState
353
- };