@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.
- package/bin/bootspring.js +157 -83
- 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/core/index.d.ts +5814 -0
- package/dist/core.js +5779 -0
- package/dist/index.js +93883 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp-server.js +2298 -0
- package/generators/api-docs.js +3 -3
- package/generators/decisions.js +14 -14
- package/generators/health.js +6 -6
- package/generators/sprint.js +4 -4
- package/generators/templates/build-planning.template.js +2 -2
- package/generators/visual-doc-generator.js +1 -1
- package/package.json +22 -68
- package/cli/agent.js +0 -799
- package/cli/auth.js +0 -896
- package/cli/billing.js +0 -320
- package/cli/build.js +0 -1442
- package/cli/dashboard.js +0 -123
- package/cli/init.js +0 -669
- package/cli/mcp.js +0 -240
- package/cli/orchestrator.js +0 -240
- package/cli/project.js +0 -825
- package/cli/quality.js +0 -281
- package/cli/skill.js +0 -503
- package/cli/switch.js +0 -453
- package/cli/todo.js +0 -629
- package/cli/update.js +0 -132
- 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/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
|
-
};
|