@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,667 @@
1
+ /**
2
+ * Bootspring Context Command
3
+ * View, search, and manage project context files
4
+ *
5
+ * Commands:
6
+ * show Show context summary (default)
7
+ * validate Validate project setup
8
+ * refresh Regenerate context files
9
+ * list List all context files
10
+ * read <type> Read a context file
11
+ * search <query> Search across context files
12
+ * agent <name> Show context for an agent
13
+ * index Rebuild context index
14
+ * types Show available context types
15
+ * agents Show agent to context mapping
16
+ *
17
+ * @package bootspring
18
+ * @module cli/context
19
+ */
20
+
21
+ // Import JS modules with type interfaces
22
+ interface Config {
23
+ _projectRoot: string;
24
+ }
25
+
26
+ interface ConfigModule {
27
+ load(): Config;
28
+ }
29
+
30
+ interface ContextProject {
31
+ name: string;
32
+ version: string;
33
+ description?: string;
34
+ }
35
+
36
+ interface ContextStack {
37
+ framework: string;
38
+ language: string;
39
+ database: string;
40
+ hosting: string;
41
+ }
42
+
43
+ interface ContextPlugin {
44
+ provider: string;
45
+ }
46
+
47
+ interface ContextState {
48
+ phase: string;
49
+ health: string;
50
+ todos: number;
51
+ lastGenerated?: string;
52
+ }
53
+
54
+ interface ContextGit {
55
+ initialized: boolean;
56
+ branch?: string;
57
+ hasRemote: boolean;
58
+ }
59
+
60
+ interface Context {
61
+ project: ContextProject;
62
+ stack: ContextStack;
63
+ plugins: Record<string, ContextPlugin>;
64
+ state: ContextState;
65
+ git: ContextGit;
66
+ }
67
+
68
+ interface ValidationCheck {
69
+ status: 'pass' | 'fail' | 'warn' | 'info';
70
+ name: string;
71
+ message: string;
72
+ }
73
+
74
+ interface ValidationResult {
75
+ checks: ValidationCheck[];
76
+ percentage: number;
77
+ score: number;
78
+ maxScore: number;
79
+ valid: boolean;
80
+ }
81
+
82
+ interface ContextModule {
83
+ get(options: { config: Config }): Context;
84
+ validate(options: { config: Config }): ValidationResult;
85
+ }
86
+
87
+ interface ContextFile {
88
+ type: string;
89
+ exists: boolean;
90
+ path: string;
91
+ isDirectory?: boolean;
92
+ fileCount?: number;
93
+ size?: number;
94
+ modifiedRelative?: string;
95
+ content?: string;
96
+ metadata?: {
97
+ size: number;
98
+ modifiedRelative: string;
99
+ };
100
+ files?: Array<{ path: string; size: number }>;
101
+ }
102
+
103
+ interface SearchMatch {
104
+ line: number;
105
+ preview: string;
106
+ }
107
+
108
+ interface SearchResult {
109
+ type: string;
110
+ file: string;
111
+ matches?: SearchMatch[];
112
+ matchType?: string;
113
+ }
114
+
115
+ interface AgentContext {
116
+ files: Array<ContextFile & { files?: Array<{ path: string }> }>;
117
+ summary: string[];
118
+ }
119
+
120
+ interface ContextIndex {
121
+ files: unknown[];
122
+ agents: Record<string, unknown>;
123
+ lastUpdated: string;
124
+ }
125
+
126
+ interface ContextLoaderModule {
127
+ list(options: { config: Config }): ContextFile[];
128
+ load(type: string): ContextFile & { error?: string };
129
+ search(query: string, options: { limit?: number }): SearchResult[];
130
+ getAgentContext(agentName: string): AgentContext;
131
+ getAgentMap(): Record<string, string[]>;
132
+ buildIndex(): ContextIndex;
133
+ getLocations(): Record<string, string>;
134
+ }
135
+
136
+ interface GenerateModule {
137
+ run(args: string[]): void;
138
+ }
139
+
140
+ interface ParsedArgs {
141
+ _: string[];
142
+ all?: boolean;
143
+ limit?: string;
144
+ metadata?: boolean;
145
+ full?: boolean;
146
+ agent?: string;
147
+ preview?: boolean;
148
+ }
149
+
150
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
151
+ const config = require('../../core/config') as ConfigModule;
152
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
153
+ const context = require('../../core/context') as ContextModule;
154
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
155
+ const contextLoader = require('../../core/context-loader') as ContextLoaderModule;
156
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
157
+ const utils = require('../../core/utils') as typeof import('../core/utils');
158
+
159
+ /**
160
+ * Show project context summary
161
+ */
162
+ export function showContext(): void {
163
+ const cfg = config.load();
164
+ const ctx = context.get({ config: cfg });
165
+
166
+ console.log(`
167
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Context${utils.COLORS.reset}
168
+ ${utils.COLORS.dim}Project: ${cfg._projectRoot}${utils.COLORS.reset}
169
+ `);
170
+
171
+ // Project Info
172
+ console.log(`${utils.COLORS.bold}Project${utils.COLORS.reset}`);
173
+ console.log(` Name: ${ctx.project.name}`);
174
+ console.log(` Version: ${ctx.project.version}`);
175
+ if (ctx.project.description) {
176
+ console.log(` Description: ${ctx.project.description}`);
177
+ }
178
+ console.log();
179
+
180
+ // Stack
181
+ console.log(`${utils.COLORS.bold}Stack${utils.COLORS.reset}`);
182
+ console.log(` Framework: ${utils.COLORS.cyan}${ctx.stack.framework}${utils.COLORS.reset}`);
183
+ console.log(` Language: ${ctx.stack.language}`);
184
+ console.log(` Database: ${ctx.stack.database}`);
185
+ console.log(` Hosting: ${ctx.stack.hosting}`);
186
+ console.log();
187
+
188
+ // Plugins
189
+ const plugins = Object.keys(ctx.plugins);
190
+ if (plugins.length > 0) {
191
+ console.log(`${utils.COLORS.bold}Enabled Plugins${utils.COLORS.reset}`);
192
+ for (const [name, plugin] of Object.entries(ctx.plugins)) {
193
+ console.log(` ${utils.COLORS.green}●${utils.COLORS.reset} ${name} (${plugin.provider})`);
194
+ }
195
+ console.log();
196
+ }
197
+
198
+ // State
199
+ const healthColor = ctx.state.health === 'good' ? utils.COLORS.green :
200
+ ctx.state.health === 'fair' ? utils.COLORS.yellow :
201
+ utils.COLORS.red;
202
+
203
+ console.log(`${utils.COLORS.bold}State${utils.COLORS.reset}`);
204
+ console.log(` Phase: ${ctx.state.phase}`);
205
+ console.log(` Health: ${healthColor}${ctx.state.health}${utils.COLORS.reset}`);
206
+ console.log(` Open Todos: ${ctx.state.todos}`);
207
+ if (ctx.state.lastGenerated) {
208
+ console.log(` Context Updated: ${utils.formatRelativeTime(new Date(ctx.state.lastGenerated))}`);
209
+ }
210
+ console.log();
211
+
212
+ // Git
213
+ if (ctx.git.initialized) {
214
+ console.log(`${utils.COLORS.bold}Git${utils.COLORS.reset}`);
215
+ console.log(` Branch: ${ctx.git.branch || 'unknown'}`);
216
+ console.log(` Remote: ${ctx.git.hasRemote ? 'configured' : 'not configured'}`);
217
+ console.log();
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Validate project context
223
+ */
224
+ export function validateContext(): void {
225
+ const cfg = config.load();
226
+ const validation = context.validate({ config: cfg });
227
+
228
+ console.log(`
229
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Context Validation${utils.COLORS.reset}
230
+ `);
231
+
232
+ for (const check of validation.checks) {
233
+ const icon = check.status === 'pass' ? utils.COLORS.green + '✓' :
234
+ check.status === 'fail' ? utils.COLORS.red + '✗' :
235
+ check.status === 'warn' ? utils.COLORS.yellow + '⚠' :
236
+ utils.COLORS.dim + 'ℹ';
237
+ console.log(` ${icon}${utils.COLORS.reset} ${check.name}`);
238
+ console.log(` ${utils.COLORS.dim}${check.message}${utils.COLORS.reset}`);
239
+ }
240
+
241
+ console.log();
242
+
243
+ // Score bar
244
+ const barWidth = 30;
245
+ const filled = Math.round((validation.percentage / 100) * barWidth);
246
+ const empty = barWidth - filled;
247
+ const scoreColor = validation.percentage >= 80 ? utils.COLORS.green :
248
+ validation.percentage >= 50 ? utils.COLORS.yellow :
249
+ utils.COLORS.red;
250
+
251
+ console.log(`${utils.COLORS.bold}Score${utils.COLORS.reset}`);
252
+ console.log(` ${scoreColor}${'█'.repeat(filled)}${utils.COLORS.dim}${'░'.repeat(empty)}${utils.COLORS.reset} ${validation.percentage}%`);
253
+ console.log(` ${validation.score}/${validation.maxScore} checks passed`);
254
+ console.log();
255
+
256
+ if (validation.valid) {
257
+ utils.print.success('Context validation passed');
258
+ } else {
259
+ utils.print.warning('Context needs attention - fix the issues above');
260
+ utils.print.dim('Run "bootspring generate" to regenerate context');
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Refresh project context
266
+ */
267
+ export function refreshContext(): void {
268
+ console.log(`
269
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Context Refresh${utils.COLORS.reset}
270
+ `);
271
+
272
+ utils.print.info('Refreshing context...');
273
+
274
+ // This triggers a regeneration
275
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
276
+ const generateModule = require('./generate') as GenerateModule;
277
+ generateModule.run([]);
278
+ }
279
+
280
+ /**
281
+ * List all context files
282
+ */
283
+ export function listContext(args: string[]): void {
284
+ const parsedArgs = utils.parseArgs(args) as ParsedArgs;
285
+ utils.print.header('Project Context Files');
286
+
287
+ const cfg = config.load();
288
+ const contextList = contextLoader.list({ config: cfg });
289
+
290
+ // Group by category
291
+ const categories: Record<string, string[]> = {
292
+ 'Root Files': ['seed', 'claude', 'todo', 'readme', 'changelog'],
293
+ 'Planning': ['plan', 'prd', 'architecture', 'decisions', 'roadmap'],
294
+ 'Business': ['business_plan', 'pitch_deck', 'competitive', 'market', 'financial'],
295
+ 'Legal': ['terms', 'privacy', 'legal_checklist'],
296
+ 'Code Context': ['mvp_source', 'mvp_references'],
297
+ 'System': ['logs', 'context_index']
298
+ };
299
+
300
+ for (const [category, types] of Object.entries(categories)) {
301
+ const categoryItems = contextList.filter(c => types.includes(c.type));
302
+ const existingCount = categoryItems.filter(c => c.exists).length;
303
+
304
+ if (existingCount > 0 || parsedArgs.all) {
305
+ console.log(`\n${utils.COLORS.bold}${category}${utils.COLORS.reset}`);
306
+
307
+ for (const item of categoryItems) {
308
+ if (item.exists) {
309
+ const icon = item.isDirectory ? '📁' : '📄';
310
+ const size = item.isDirectory
311
+ ? `${item.fileCount} files`
312
+ : formatSize(item.size || 0);
313
+ const modified = item.modifiedRelative || '';
314
+
315
+ console.log(` ${utils.COLORS.green}${icon}${utils.COLORS.reset} ${item.type.padEnd(20)} ${item.path}`);
316
+ console.log(` ${utils.COLORS.dim}${size}${modified ? ` • ${modified}` : ''}${utils.COLORS.reset}`);
317
+ } else if (parsedArgs.all) {
318
+ console.log(` ${utils.COLORS.dim}○ ${item.type.padEnd(20)} ${item.path} (not found)${utils.COLORS.reset}`);
319
+ }
320
+ }
321
+ }
322
+ }
323
+
324
+ // Summary
325
+ const total = contextList.length;
326
+ const existing = contextList.filter(c => c.exists).length;
327
+ console.log(`\n${utils.COLORS.dim}Found ${existing}/${total} context files${utils.COLORS.reset}`);
328
+
329
+ if (!parsedArgs.all) {
330
+ utils.print.dim('Use --all to show missing files');
331
+ }
332
+ }
333
+
334
+ /**
335
+ * Read a specific context file
336
+ */
337
+ export function readContext(args: string[]): void {
338
+ const parsedArgs = utils.parseArgs(args) as ParsedArgs;
339
+ const contextType = parsedArgs._[0];
340
+
341
+ if (!contextType) {
342
+ utils.print.error('Please specify a context type');
343
+ utils.print.dim('Example: bootspring context read seed');
344
+ utils.print.dim('Run "bootspring context types" to see available types');
345
+ return;
346
+ }
347
+
348
+ const loaded = contextLoader.load(contextType);
349
+
350
+ if (!loaded.exists) {
351
+ if (loaded.error) {
352
+ utils.print.error(loaded.error);
353
+ } else {
354
+ utils.print.warning(`Context "${contextType}" not found at: ${loaded.path}`);
355
+ }
356
+ return;
357
+ }
358
+
359
+ utils.print.header(`Context: ${contextType}`);
360
+ console.log(`${utils.COLORS.dim}Path: ${loaded.path}${utils.COLORS.reset}\n`);
361
+
362
+ if (loaded.files) {
363
+ // Directory listing
364
+ console.log(`${utils.COLORS.bold}Files (${loaded.fileCount}):${utils.COLORS.reset}\n`);
365
+
366
+ const limit = parsedArgs.limit ? parseInt(parsedArgs.limit, 10) : 20;
367
+ const files = loaded.files.slice(0, limit);
368
+
369
+ for (const file of files) {
370
+ console.log(` ${file.path} ${utils.COLORS.dim}(${formatSize(file.size)})${utils.COLORS.reset}`);
371
+ }
372
+
373
+ if (loaded.fileCount && loaded.fileCount > limit) {
374
+ utils.print.dim(`\n... and ${loaded.fileCount - limit} more files`);
375
+ }
376
+ } else {
377
+ // File content
378
+ if (parsedArgs.metadata && loaded.metadata) {
379
+ console.log(`${utils.COLORS.bold}Metadata:${utils.COLORS.reset}`);
380
+ console.log(` Size: ${formatSize(loaded.metadata.size)}`);
381
+ console.log(` Modified: ${loaded.metadata.modifiedRelative}`);
382
+ console.log('');
383
+ }
384
+
385
+ // Print content (truncate if very long unless --full is passed)
386
+ const content = loaded.content || '';
387
+ const maxLines = parsedArgs.full ? Infinity : 100;
388
+ const lines = content.split('\n');
389
+
390
+ if (lines.length > maxLines) {
391
+ console.log(lines.slice(0, maxLines).join('\n'));
392
+ utils.print.dim(`\n... truncated (${lines.length - maxLines} more lines)`);
393
+ utils.print.dim('Use --full to see entire file');
394
+ } else {
395
+ console.log(content);
396
+ }
397
+ }
398
+ }
399
+
400
+ /**
401
+ * Search across context files
402
+ */
403
+ export function searchContext(args: string[]): void {
404
+ const parsedArgs = utils.parseArgs(args) as ParsedArgs;
405
+ const query = parsedArgs._[0];
406
+
407
+ if (!query) {
408
+ utils.print.error('Please specify a search query');
409
+ utils.print.dim('Example: bootspring context search "authentication"');
410
+ return;
411
+ }
412
+
413
+ utils.print.header(`Searching for: ${query}`);
414
+
415
+ const limit = parsedArgs.limit ? parseInt(parsedArgs.limit, 10) : 20;
416
+ const results = contextLoader.search(query, { limit });
417
+
418
+ if (results.length === 0) {
419
+ utils.print.warning('No results found');
420
+ return;
421
+ }
422
+
423
+ console.log(`${utils.COLORS.dim}Found ${results.length} result(s)${utils.COLORS.reset}\n`);
424
+
425
+ for (const result of results) {
426
+ console.log(`${utils.COLORS.bold}${result.type}${utils.COLORS.reset}: ${result.file}`);
427
+
428
+ if (result.matches) {
429
+ for (const match of result.matches) {
430
+ console.log(` ${utils.COLORS.dim}L${match.line}:${utils.COLORS.reset} ${highlightMatch(match.preview, query)}`);
431
+ }
432
+ } else if (result.matchType === 'filename') {
433
+ console.log(` ${utils.COLORS.dim}(filename match)${utils.COLORS.reset}`);
434
+ }
435
+ console.log('');
436
+ }
437
+ }
438
+
439
+ /**
440
+ * Show context for a specific agent
441
+ */
442
+ export function showAgentContext(args: string[]): void {
443
+ const parsedArgs = utils.parseArgs(args) as ParsedArgs;
444
+ const agentName = parsedArgs.agent || parsedArgs._[0];
445
+
446
+ if (!agentName) {
447
+ utils.print.error('Please specify an agent name');
448
+ utils.print.dim('Example: bootspring context agent frontend-expert');
449
+ utils.print.dim('Run "bootspring context agents" to see agent mappings');
450
+ return;
451
+ }
452
+
453
+ const agentContext = contextLoader.getAgentContext(agentName);
454
+
455
+ if (agentContext.files.length === 0) {
456
+ utils.print.warning(`No context available for agent: ${agentName}`);
457
+
458
+ const agentMap = contextLoader.getAgentMap();
459
+ if (!agentMap[agentName]) {
460
+ utils.print.dim('This agent is not in the context mapping.');
461
+ } else {
462
+ utils.print.dim('The mapped context files do not exist yet.');
463
+ }
464
+ return;
465
+ }
466
+
467
+ utils.print.header(`Context for: ${agentName}`);
468
+ console.log(`${utils.COLORS.dim}${agentContext.summary.join(' | ')}${utils.COLORS.reset}\n`);
469
+
470
+ for (const file of agentContext.files) {
471
+ if (file.isDirectory) {
472
+ console.log(`${utils.COLORS.bold}📁 ${file.type}${utils.COLORS.reset} (${file.fileCount} files)`);
473
+ if (file.files && file.files.length > 0) {
474
+ for (const f of file.files.slice(0, 5)) {
475
+ console.log(` ${utils.COLORS.dim}${f.path}${utils.COLORS.reset}`);
476
+ }
477
+ if (file.fileCount && file.fileCount > 5) {
478
+ console.log(` ${utils.COLORS.dim}... and ${file.fileCount - 5} more${utils.COLORS.reset}`);
479
+ }
480
+ }
481
+ } else {
482
+ console.log(`${utils.COLORS.bold}📄 ${file.type}${utils.COLORS.reset}: ${file.path}`);
483
+ if (file.metadata) {
484
+ console.log(` ${utils.COLORS.dim}${formatSize(file.metadata.size)} • ${file.metadata.modifiedRelative}${utils.COLORS.reset}`);
485
+ }
486
+
487
+ // Show preview
488
+ if (parsedArgs.preview && file.content) {
489
+ const preview = file.content.split('\n').slice(0, 5).join('\n');
490
+ console.log(` ${utils.COLORS.dim}---${utils.COLORS.reset}`);
491
+ console.log(` ${preview.split('\n').map(l => utils.COLORS.dim + l + utils.COLORS.reset).join('\n ')}`);
492
+ }
493
+ }
494
+ console.log('');
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Build/rebuild context index
500
+ */
501
+ export function buildIndex(): void {
502
+ const spinner = utils.createSpinner('Building context index...').start();
503
+
504
+ try {
505
+ const index = contextLoader.buildIndex();
506
+
507
+ spinner.succeed('Context index built');
508
+
509
+ console.log(`\n${utils.COLORS.bold}Index Summary:${utils.COLORS.reset}`);
510
+ console.log(` Files indexed: ${index.files.length}`);
511
+ console.log(` Agents mapped: ${Object.keys(index.agents).length}`);
512
+ console.log(` Last updated: ${index.lastUpdated}`);
513
+ } catch (error) {
514
+ spinner.fail(`Failed to build index: ${(error as Error).message}`);
515
+ }
516
+ }
517
+
518
+ /**
519
+ * Show available context types
520
+ */
521
+ export function showTypes(): void {
522
+ utils.print.header('Available Context Types');
523
+
524
+ const locations = contextLoader.getLocations();
525
+
526
+ const headers = ['Type', 'Path'];
527
+ const rows = Object.entries(locations).map(([type, path]) => [type, path]);
528
+
529
+ console.log(utils.createTable(headers, rows));
530
+ }
531
+
532
+ /**
533
+ * Show agent to context mapping
534
+ */
535
+ export function showAgentMap(): void {
536
+ utils.print.header('Agent Context Mapping');
537
+
538
+ const agentMap = contextLoader.getAgentMap();
539
+
540
+ for (const [agent, types] of Object.entries(agentMap)) {
541
+ console.log(`${utils.COLORS.bold}${agent}${utils.COLORS.reset}`);
542
+ console.log(` ${utils.COLORS.dim}${types.join(', ')}${utils.COLORS.reset}`);
543
+ }
544
+ }
545
+
546
+ /**
547
+ * Format file size
548
+ */
549
+ function formatSize(bytes: number): string {
550
+ if (bytes < 1024) return `${bytes}B`;
551
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
552
+ return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
553
+ }
554
+
555
+ /**
556
+ * Highlight search match in text
557
+ */
558
+ function highlightMatch(text: string, query: string): string {
559
+ const regex = new RegExp(`(${query})`, 'gi');
560
+ return text.replace(regex, `${utils.COLORS.yellow}$1${utils.COLORS.reset}`);
561
+ }
562
+
563
+ /**
564
+ * Show context help
565
+ */
566
+ function showHelp(): void {
567
+ console.log(`
568
+ ${utils.COLORS.cyan}${utils.COLORS.bold}⚡ Bootspring Context${utils.COLORS.reset}
569
+ ${utils.COLORS.dim}View, search, and manage project context${utils.COLORS.reset}
570
+
571
+ ${utils.COLORS.bold}Usage:${utils.COLORS.reset}
572
+ bootspring context <command> [options]
573
+
574
+ ${utils.COLORS.bold}Commands:${utils.COLORS.reset}
575
+ ${utils.COLORS.cyan}show${utils.COLORS.reset} Show context summary (default)
576
+ ${utils.COLORS.cyan}validate${utils.COLORS.reset} Validate project setup
577
+ ${utils.COLORS.cyan}refresh${utils.COLORS.reset} Regenerate context files
578
+ ${utils.COLORS.cyan}list${utils.COLORS.reset} List all context files
579
+ ${utils.COLORS.cyan}read <type>${utils.COLORS.reset} Read a context file
580
+ ${utils.COLORS.cyan}search <query>${utils.COLORS.reset} Search across context files
581
+ ${utils.COLORS.cyan}agent <name>${utils.COLORS.reset} Show context for an agent
582
+ ${utils.COLORS.cyan}index${utils.COLORS.reset} Rebuild context index
583
+ ${utils.COLORS.cyan}types${utils.COLORS.reset} Show available context types
584
+ ${utils.COLORS.cyan}agents${utils.COLORS.reset} Show agent to context mapping
585
+
586
+ ${utils.COLORS.bold}Options:${utils.COLORS.reset}
587
+ --all Show all files (including missing)
588
+ --full Show full file content (no truncation)
589
+ --preview Show content preview
590
+ --limit=<n> Limit results
591
+ --metadata Show file metadata
592
+
593
+ ${utils.COLORS.bold}Examples:${utils.COLORS.reset}
594
+ bootspring context
595
+ bootspring context list --all
596
+ bootspring context read seed
597
+ bootspring context search "authentication"
598
+ bootspring context agent frontend-expert
599
+ `);
600
+ }
601
+
602
+ /**
603
+ * Run context command
604
+ */
605
+ export async function run(args: string[]): Promise<void> {
606
+ const subcommand = args[0] || 'show';
607
+ const subArgs = args.slice(1);
608
+
609
+ switch (subcommand) {
610
+ case 'show':
611
+ showContext();
612
+ break;
613
+
614
+ case 'validate':
615
+ case 'check':
616
+ validateContext();
617
+ break;
618
+
619
+ case 'refresh':
620
+ case 'regenerate':
621
+ refreshContext();
622
+ break;
623
+
624
+ case 'list':
625
+ case 'ls':
626
+ listContext(subArgs);
627
+ break;
628
+
629
+ case 'read':
630
+ case 'cat':
631
+ case 'get':
632
+ readContext(subArgs);
633
+ break;
634
+
635
+ case 'search':
636
+ case 'find':
637
+ searchContext(subArgs);
638
+ break;
639
+
640
+ case 'agent':
641
+ showAgentContext(subArgs);
642
+ break;
643
+
644
+ case 'index':
645
+ case 'reindex':
646
+ buildIndex();
647
+ break;
648
+
649
+ case 'types':
650
+ showTypes();
651
+ break;
652
+
653
+ case 'agents':
654
+ showAgentMap();
655
+ break;
656
+
657
+ case 'help':
658
+ case '-h':
659
+ case '--help':
660
+ showHelp();
661
+ break;
662
+
663
+ default:
664
+ utils.print.error(`Unknown subcommand: ${subcommand}`);
665
+ showHelp();
666
+ }
667
+ }