@girardmedia/bootspring 2.0.21 → 2.0.23

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 (159) hide show
  1. package/bin/bootspring.js +5 -0
  2. package/cli/org.js +474 -0
  3. package/cli/preseed/index.js +16 -0
  4. package/cli/preseed/interactive.js +143 -0
  5. package/cli/preseed/templates.js +227 -0
  6. package/cli/preseed.js +9 -301
  7. package/cli/seed/builders/ai-context-builder.js +85 -0
  8. package/cli/seed/builders/index.js +13 -0
  9. package/cli/seed/builders/seed-builder.js +272 -0
  10. package/cli/seed/extractors/content-extractors.js +383 -0
  11. package/cli/seed/extractors/index.js +47 -0
  12. package/cli/seed/extractors/metadata-extractors.js +167 -0
  13. package/cli/seed/extractors/section-extractor.js +54 -0
  14. package/cli/seed/extractors/stack-extractors.js +228 -0
  15. package/cli/seed/index.js +18 -0
  16. package/cli/seed/utils/folder-structure.js +84 -0
  17. package/cli/seed/utils/index.js +11 -0
  18. package/cli/seed.js +23 -1074
  19. package/core/api-client.js +77 -0
  20. package/core/entitlements.js +36 -0
  21. package/core/organizations.js +223 -0
  22. package/core/policies.js +51 -6
  23. package/core/policy-matrix.js +303 -0
  24. package/core/project-context.js +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.js +3220 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/context-McpJQa_2.d.ts +5710 -0
  29. package/dist/core/index.d.ts +635 -0
  30. package/dist/core/index.js +2593 -0
  31. package/dist/core/index.js.map +1 -0
  32. package/dist/index-QqbeEiDm.d.ts +857 -0
  33. package/dist/index-UiYCgwiH.d.ts +174 -0
  34. package/dist/index.d.ts +453 -0
  35. package/dist/index.js +44228 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp/index.d.ts +1 -0
  38. package/dist/mcp/index.js +41173 -0
  39. package/dist/mcp/index.js.map +1 -0
  40. package/generators/index.ts +82 -0
  41. package/intelligence/orchestrator/config/failure-signatures.js +48 -0
  42. package/intelligence/orchestrator/config/index.js +23 -0
  43. package/intelligence/orchestrator/config/pack-lifecycle.js +262 -0
  44. package/intelligence/orchestrator/config/phases.js +111 -0
  45. package/intelligence/orchestrator/config/remediation.js +150 -0
  46. package/intelligence/orchestrator/config/workflows.js +168 -0
  47. package/intelligence/orchestrator/core/index.js +16 -0
  48. package/intelligence/orchestrator/core/state-manager.js +88 -0
  49. package/intelligence/orchestrator/core/telemetry.js +24 -0
  50. package/intelligence/orchestrator/index.js +17 -0
  51. package/intelligence/orchestrator.js +17 -512
  52. package/mcp/contracts/mcp-contract.v1.json +1 -1
  53. package/package.json +16 -3
  54. package/src/cli/agent.ts +703 -0
  55. package/src/cli/analyze.ts +640 -0
  56. package/src/cli/audit.ts +707 -0
  57. package/src/cli/auth.ts +930 -0
  58. package/src/cli/billing.ts +364 -0
  59. package/src/cli/build.ts +1089 -0
  60. package/src/cli/business.ts +508 -0
  61. package/src/cli/checkpoint-utils.ts +236 -0
  62. package/src/cli/checkpoint.ts +757 -0
  63. package/src/cli/cloud-sync.ts +534 -0
  64. package/src/cli/content.ts +273 -0
  65. package/src/cli/context.ts +667 -0
  66. package/src/cli/dashboard.ts +133 -0
  67. package/src/cli/deploy.ts +704 -0
  68. package/src/cli/doctor.ts +480 -0
  69. package/src/cli/fundraise.ts +494 -0
  70. package/src/cli/generate.ts +346 -0
  71. package/src/cli/github-cmd.ts +566 -0
  72. package/src/cli/health.ts +599 -0
  73. package/src/cli/index.ts +113 -0
  74. package/src/cli/init.ts +838 -0
  75. package/src/cli/legal.ts +495 -0
  76. package/src/cli/log.ts +316 -0
  77. package/src/cli/loop.ts +1660 -0
  78. package/src/cli/manager.ts +878 -0
  79. package/src/cli/mcp.ts +275 -0
  80. package/src/cli/memory.ts +346 -0
  81. package/src/cli/metrics.ts +590 -0
  82. package/src/cli/monitor.ts +960 -0
  83. package/src/cli/mvp.ts +662 -0
  84. package/src/cli/onboard.ts +663 -0
  85. package/src/cli/orchestrator.ts +622 -0
  86. package/src/cli/plugin.ts +483 -0
  87. package/src/cli/prd.ts +671 -0
  88. package/src/cli/preseed-start.ts +1633 -0
  89. package/src/cli/preseed.ts +2434 -0
  90. package/src/cli/project.ts +526 -0
  91. package/src/cli/quality.ts +885 -0
  92. package/src/cli/security.ts +1079 -0
  93. package/src/cli/seed.ts +1224 -0
  94. package/src/cli/skill.ts +537 -0
  95. package/src/cli/suggest.ts +1225 -0
  96. package/src/cli/switch.ts +518 -0
  97. package/src/cli/task.ts +780 -0
  98. package/src/cli/telemetry.ts +172 -0
  99. package/src/cli/todo.ts +627 -0
  100. package/src/cli/types.ts +15 -0
  101. package/src/cli/update.ts +334 -0
  102. package/src/cli/visualize.ts +609 -0
  103. package/src/cli/watch.ts +895 -0
  104. package/src/cli/workspace.ts +709 -0
  105. package/src/core/action-recorder.ts +673 -0
  106. package/src/core/analyze-workflow.ts +1453 -0
  107. package/src/core/api-client.ts +1120 -0
  108. package/src/core/audit-workflow.ts +1681 -0
  109. package/src/core/auth.ts +471 -0
  110. package/src/core/build-orchestrator.ts +509 -0
  111. package/src/core/build-state.ts +621 -0
  112. package/src/core/checkpoint-engine.ts +482 -0
  113. package/src/core/config.ts +1285 -0
  114. package/src/core/context-loader.ts +694 -0
  115. package/src/core/context.ts +410 -0
  116. package/src/core/deploy-workflow.ts +1085 -0
  117. package/src/core/entitlements.ts +322 -0
  118. package/src/core/github-sync.ts +720 -0
  119. package/src/core/index.ts +981 -0
  120. package/src/core/ingest.ts +1186 -0
  121. package/src/core/metrics-engine.ts +886 -0
  122. package/src/core/mvp.ts +847 -0
  123. package/src/core/onboard-workflow.ts +1293 -0
  124. package/src/core/policies.ts +81 -0
  125. package/src/core/preseed-workflow.ts +1163 -0
  126. package/src/core/preseed.ts +1826 -0
  127. package/src/core/project-context.ts +380 -0
  128. package/src/core/project-state.ts +699 -0
  129. package/src/core/r2-sync.ts +691 -0
  130. package/src/core/scaffold.ts +1715 -0
  131. package/src/core/session.ts +286 -0
  132. package/src/core/task-extractor.ts +799 -0
  133. package/src/core/telemetry.ts +371 -0
  134. package/src/core/tier-enforcement.ts +737 -0
  135. package/src/core/utils.ts +437 -0
  136. package/src/index.ts +29 -0
  137. package/src/intelligence/agent-collab.ts +2376 -0
  138. package/src/intelligence/auto-suggest.ts +713 -0
  139. package/src/intelligence/content-gen.ts +1351 -0
  140. package/src/intelligence/cross-project.ts +1692 -0
  141. package/src/intelligence/git-memory.ts +529 -0
  142. package/src/intelligence/index.ts +318 -0
  143. package/src/intelligence/orchestrator.ts +534 -0
  144. package/src/intelligence/prd.ts +466 -0
  145. package/src/intelligence/recommendations.ts +982 -0
  146. package/src/intelligence/workflow-composer.ts +1472 -0
  147. package/src/mcp/capabilities.ts +233 -0
  148. package/src/mcp/index.ts +37 -0
  149. package/src/mcp/registry.ts +1268 -0
  150. package/src/mcp/response-formatter.ts +797 -0
  151. package/src/mcp/server.ts +240 -0
  152. package/src/types/agent.ts +69 -0
  153. package/src/types/config.ts +86 -0
  154. package/src/types/context.ts +77 -0
  155. package/src/types/index.ts +53 -0
  156. package/src/types/mcp.ts +91 -0
  157. package/src/types/skills.ts +47 -0
  158. package/src/types/workflow.ts +155 -0
  159. package/generators/index.js +0 -18
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Bootspring Project Context Enforcement
3
+ *
4
+ * Ensures CLI commands run within a project context.
5
+ * All activity should be tracked to a project for:
6
+ * - Usage billing
7
+ * - Memory/learning isolation
8
+ * - Team collaboration
9
+ * - Audit trails
10
+ *
11
+ * @package bootspring
12
+ * @module core/project-context
13
+ */
14
+
15
+ // Module interfaces
16
+ interface Session {
17
+ getEffectiveProject: () => Project | null;
18
+ }
19
+
20
+ interface Auth {
21
+ isAuthenticated: () => boolean;
22
+ }
23
+
24
+ interface ApiClient {
25
+ listProjects: () => Promise<ProjectListResponse>;
26
+ }
27
+
28
+ interface Project {
29
+ id: string;
30
+ name?: string | undefined;
31
+ slug?: string | undefined;
32
+ role?: string | undefined;
33
+ source?: string | undefined;
34
+ }
35
+
36
+ interface ProjectListResponse {
37
+ owned?: Project[] | undefined;
38
+ shared?: Project[] | undefined;
39
+ projects?: Project[] | undefined;
40
+ }
41
+
42
+ interface ProjectContextError extends Error {
43
+ code?: string | undefined;
44
+ help?: string[] | undefined;
45
+ }
46
+
47
+ interface ValidationError {
48
+ code: string;
49
+ message: string;
50
+ help: string[];
51
+ }
52
+
53
+ interface ValidationResult {
54
+ valid: boolean;
55
+ exempt?: boolean | undefined;
56
+ project?: Project | undefined;
57
+ error?: ValidationError | undefined;
58
+ requiresAccessCheck?: boolean | undefined;
59
+ warning?: string | undefined;
60
+ }
61
+
62
+ interface ValidateOptions {
63
+ projectOverride?: string | undefined;
64
+ }
65
+
66
+ interface ParsedProjectFlag {
67
+ projectOverride: string | null;
68
+ cleanArgs: string[];
69
+ }
70
+
71
+ // Lazy-loaded modules
72
+ let _session: Session | null = null;
73
+ let _auth: Auth | null = null;
74
+ let _api: ApiClient | null = null;
75
+
76
+ function getSession(): Session {
77
+ if (!_session) {
78
+ _session = require('./session') as Session;
79
+ }
80
+ return _session;
81
+ }
82
+
83
+ function getAuth(): Auth {
84
+ if (!_auth) {
85
+ _auth = require('./auth') as Auth;
86
+ }
87
+ return _auth;
88
+ }
89
+
90
+ function getApi(): ApiClient {
91
+ if (!_api) {
92
+ _api = require('./api-client') as ApiClient;
93
+ }
94
+ return _api;
95
+ }
96
+
97
+ // Commands that don't require project context
98
+ export const EXEMPT_COMMANDS = [
99
+ 'auth',
100
+ 'switch',
101
+ 'project',
102
+ 'help',
103
+ 'init',
104
+ 'doctor',
105
+ 'update',
106
+ 'version',
107
+ '--version',
108
+ '-v',
109
+ '--help',
110
+ '-h',
111
+ 'cloud-sync',
112
+ 'skill', // Skills accessible in local mode without project
113
+ 'agent', // Agent list accessible without project
114
+ 'billing', // Billing status/info accessible without project
115
+ 'preseed', // Preseed works locally, auth enhances features
116
+ 'seed', // Seed works locally for scaffolding
117
+ ];
118
+
119
+ // Sub-commands of auth that are exempt
120
+ const EXEMPT_AUTH_SUBCOMMANDS = [
121
+ 'login',
122
+ 'logout',
123
+ 'register',
124
+ 'signup',
125
+ 'status',
126
+ 'whoami',
127
+ 'switch' // auth switch is also exempt
128
+ ];
129
+
130
+ /**
131
+ * Check if a command requires project context
132
+ */
133
+ export function requiresProjectContext(command: string, subcommand?: string): boolean {
134
+ // Check if main command is exempt
135
+ if (EXEMPT_COMMANDS.includes(command)) {
136
+ return false;
137
+ }
138
+
139
+ // Check exempt auth subcommands
140
+ if (command === 'auth' && subcommand && EXEMPT_AUTH_SUBCOMMANDS.includes(subcommand)) {
141
+ return false;
142
+ }
143
+
144
+ return true;
145
+ }
146
+
147
+ /**
148
+ * Get the current project context
149
+ * Returns null if no project is set
150
+ */
151
+ export function getProjectContext(): Project | null {
152
+ return getSession().getEffectiveProject();
153
+ }
154
+
155
+ /**
156
+ * Check if project context is set
157
+ */
158
+ export function hasProjectContext(): boolean {
159
+ return !!getProjectContext();
160
+ }
161
+
162
+ /**
163
+ * Get project ID for API requests
164
+ */
165
+ export function getProjectId(): string | null {
166
+ const project = getProjectContext();
167
+ return project?.id || null;
168
+ }
169
+
170
+ /**
171
+ * Get headers for API requests including project context
172
+ */
173
+ export function getProjectHeaders(): Record<string, string> {
174
+ const projectId = getProjectId();
175
+ const headers: Record<string, string> = {};
176
+
177
+ if (projectId) {
178
+ headers['X-Project-Id'] = projectId;
179
+ }
180
+
181
+ return headers;
182
+ }
183
+
184
+ /**
185
+ * Require project context - throws if not set
186
+ */
187
+ export function requireProject(): Project {
188
+ const project = getProjectContext();
189
+
190
+ if (!project) {
191
+ const error = new Error('No project context set') as ProjectContextError;
192
+ error.code = 'NO_PROJECT_CONTEXT';
193
+ error.help = [
194
+ 'All Bootspring commands require a project context.',
195
+ '',
196
+ 'To set a project:',
197
+ ' bootspring switch # List and select a project',
198
+ ' bootspring switch <name> # Switch to a specific project',
199
+ '',
200
+ 'Or use the --project flag:',
201
+ ' bootspring --project myapp <command>',
202
+ '',
203
+ 'Create a project at: https://bootspring.com/dashboard/projects'
204
+ ];
205
+ throw error;
206
+ }
207
+
208
+ return project;
209
+ }
210
+
211
+ /**
212
+ * Validate project context before running a command
213
+ */
214
+ export function validateForCommand(
215
+ command: string,
216
+ args: string[] = [],
217
+ options: ValidateOptions = {}
218
+ ): ValidationResult {
219
+ const subcommand = args[0];
220
+
221
+ // Check if command is exempt
222
+ if (!requiresProjectContext(command, subcommand)) {
223
+ return { valid: true, exempt: true };
224
+ }
225
+
226
+ // Check if user is authenticated
227
+ if (!getAuth().isAuthenticated()) {
228
+ return {
229
+ valid: false,
230
+ error: {
231
+ code: 'NOT_AUTHENTICATED',
232
+ message: 'Authentication required',
233
+ help: ['Run: bootspring auth login']
234
+ }
235
+ };
236
+ }
237
+
238
+ // Check for project override flag
239
+ if (options.projectOverride) {
240
+ // Validation happens async in validateProjectAccessAsync if needed
241
+ return {
242
+ valid: true,
243
+ project: { id: options.projectOverride, source: 'flag' },
244
+ requiresAccessCheck: true
245
+ };
246
+ }
247
+
248
+ // Check for project context
249
+ const project = getProjectContext();
250
+ if (!project) {
251
+ return {
252
+ valid: false,
253
+ error: {
254
+ code: 'NO_PROJECT_CONTEXT',
255
+ message: 'No project context set',
256
+ help: [
257
+ 'Run: bootspring switch',
258
+ 'Or use: bootspring --project <name> ' + command
259
+ ]
260
+ }
261
+ };
262
+ }
263
+
264
+ return { valid: true, project };
265
+ }
266
+
267
+ /**
268
+ * Format error message for display
269
+ */
270
+ export function formatError(error: ValidationError): string {
271
+ const lines: string[] = [];
272
+ const RED = '\x1b[31m';
273
+ const YELLOW = '\x1b[33m';
274
+ const DIM = '\x1b[2m';
275
+ const RESET = '\x1b[0m';
276
+
277
+ lines.push(`${RED}Error: ${error.message}${RESET}`);
278
+ lines.push('');
279
+
280
+ if (error.help && error.help.length > 0) {
281
+ for (const line of error.help) {
282
+ if (line.startsWith(' ')) {
283
+ lines.push(`${YELLOW}${line}${RESET}`);
284
+ } else {
285
+ lines.push(`${DIM}${line}${RESET}`);
286
+ }
287
+ }
288
+ }
289
+
290
+ return lines.join('\n');
291
+ }
292
+
293
+ /**
294
+ * Parse --project flag from args
295
+ */
296
+ export function parseProjectFlag(args: string[]): ParsedProjectFlag {
297
+ const cleanArgs: string[] = [];
298
+ let projectOverride: string | null = null;
299
+
300
+ for (let i = 0; i < args.length; i++) {
301
+ const arg = args[i];
302
+
303
+ if (arg === '--project' || arg === '-p') {
304
+ // Next arg is the project name/id
305
+ if (i + 1 < args.length) {
306
+ const nextArg = args[i + 1];
307
+ if (nextArg) {
308
+ projectOverride = nextArg;
309
+ }
310
+ i++; // Skip next arg
311
+ }
312
+ } else if (arg && arg.startsWith('--project=')) {
313
+ const value = arg.split('=')[1];
314
+ if (value) {
315
+ projectOverride = value;
316
+ }
317
+ } else if (arg) {
318
+ cleanArgs.push(arg);
319
+ }
320
+ }
321
+
322
+ return { projectOverride, cleanArgs };
323
+ }
324
+
325
+ /**
326
+ * Validate user has access to a project (async)
327
+ * Call this after validateForCommand when requiresAccessCheck is true
328
+ */
329
+ export async function validateProjectAccessAsync(projectId: string): Promise<ValidationResult> {
330
+ try {
331
+ const projects = await getApi().listProjects();
332
+
333
+ // Check both owned and shared projects
334
+ const allProjects = [
335
+ ...(projects.owned || []),
336
+ ...(projects.shared || []),
337
+ ...(projects.projects || []) // fallback for flat list
338
+ ];
339
+
340
+ // Find project by id, slug, or name (case-insensitive)
341
+ const project = allProjects.find(p =>
342
+ p.id === projectId ||
343
+ p.slug === projectId ||
344
+ p.name?.toLowerCase() === projectId.toLowerCase()
345
+ );
346
+
347
+ if (!project) {
348
+ return {
349
+ valid: false,
350
+ error: {
351
+ code: 'PROJECT_NOT_FOUND',
352
+ message: `Project '${projectId}' not found or you don't have access`,
353
+ help: [
354
+ 'Check the project name/id is correct',
355
+ 'Run: bootspring project list',
356
+ 'Or request access from the project owner'
357
+ ]
358
+ }
359
+ };
360
+ }
361
+
362
+ return {
363
+ valid: true,
364
+ project: {
365
+ id: project.id,
366
+ name: project.name,
367
+ slug: project.slug,
368
+ role: project.role || 'owner',
369
+ source: 'flag'
370
+ }
371
+ };
372
+ } catch (_error) {
373
+ // If API call fails, allow access (fail open for offline mode)
374
+ return {
375
+ valid: true,
376
+ project: { id: projectId, source: 'flag' },
377
+ warning: 'Could not verify project access (offline mode)'
378
+ };
379
+ }
380
+ }