neuronlayer 0.1.9 → 0.2.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.

Potentially problematic release.


This version of neuronlayer might be problematic. Click here for more details.

Files changed (81) hide show
  1. package/README.md +3 -2
  2. package/dist/index.js +172 -90
  3. package/dist/index.js.map +7 -0
  4. package/package.json +6 -1
  5. package/esbuild.config.js +0 -26
  6. package/src/cli/commands.ts +0 -573
  7. package/src/core/adr-exporter.ts +0 -253
  8. package/src/core/architecture/architecture-enforcement.ts +0 -228
  9. package/src/core/architecture/duplicate-detector.ts +0 -288
  10. package/src/core/architecture/index.ts +0 -6
  11. package/src/core/architecture/pattern-learner.ts +0 -306
  12. package/src/core/architecture/pattern-library.ts +0 -403
  13. package/src/core/architecture/pattern-validator.ts +0 -324
  14. package/src/core/change-intelligence/bug-correlator.ts +0 -544
  15. package/src/core/change-intelligence/change-intelligence.ts +0 -264
  16. package/src/core/change-intelligence/change-tracker.ts +0 -334
  17. package/src/core/change-intelligence/fix-suggester.ts +0 -340
  18. package/src/core/change-intelligence/index.ts +0 -5
  19. package/src/core/code-verifier.ts +0 -843
  20. package/src/core/confidence/confidence-scorer.ts +0 -251
  21. package/src/core/confidence/conflict-checker.ts +0 -289
  22. package/src/core/confidence/index.ts +0 -5
  23. package/src/core/confidence/source-tracker.ts +0 -263
  24. package/src/core/confidence/warning-detector.ts +0 -241
  25. package/src/core/context-rot/compaction.ts +0 -284
  26. package/src/core/context-rot/context-health.ts +0 -243
  27. package/src/core/context-rot/context-rot-prevention.ts +0 -213
  28. package/src/core/context-rot/critical-context.ts +0 -221
  29. package/src/core/context-rot/drift-detector.ts +0 -255
  30. package/src/core/context-rot/index.ts +0 -7
  31. package/src/core/context.ts +0 -263
  32. package/src/core/decision-extractor.ts +0 -339
  33. package/src/core/decisions.ts +0 -69
  34. package/src/core/deja-vu.ts +0 -421
  35. package/src/core/engine.ts +0 -1646
  36. package/src/core/feature-context.ts +0 -726
  37. package/src/core/ghost-mode.ts +0 -465
  38. package/src/core/learning.ts +0 -519
  39. package/src/core/living-docs/activity-tracker.ts +0 -296
  40. package/src/core/living-docs/architecture-generator.ts +0 -428
  41. package/src/core/living-docs/changelog-generator.ts +0 -348
  42. package/src/core/living-docs/component-generator.ts +0 -230
  43. package/src/core/living-docs/doc-engine.ts +0 -134
  44. package/src/core/living-docs/doc-validator.ts +0 -282
  45. package/src/core/living-docs/index.ts +0 -8
  46. package/src/core/project-manager.ts +0 -301
  47. package/src/core/refresh/activity-gate.ts +0 -256
  48. package/src/core/refresh/git-staleness-checker.ts +0 -108
  49. package/src/core/refresh/index.ts +0 -27
  50. package/src/core/summarizer.ts +0 -290
  51. package/src/core/test-awareness/change-validator.ts +0 -499
  52. package/src/core/test-awareness/index.ts +0 -5
  53. package/src/index.ts +0 -90
  54. package/src/indexing/ast.ts +0 -868
  55. package/src/indexing/embeddings.ts +0 -85
  56. package/src/indexing/indexer.ts +0 -270
  57. package/src/indexing/watcher.ts +0 -78
  58. package/src/server/gateways/aggregator.ts +0 -374
  59. package/src/server/gateways/index.ts +0 -473
  60. package/src/server/gateways/memory-ghost.ts +0 -343
  61. package/src/server/gateways/memory-query.ts +0 -452
  62. package/src/server/gateways/memory-record.ts +0 -346
  63. package/src/server/gateways/memory-review.ts +0 -410
  64. package/src/server/gateways/memory-status.ts +0 -517
  65. package/src/server/gateways/memory-verify.ts +0 -392
  66. package/src/server/gateways/router.ts +0 -434
  67. package/src/server/gateways/types.ts +0 -610
  68. package/src/server/http.ts +0 -228
  69. package/src/server/mcp.ts +0 -154
  70. package/src/server/resources.ts +0 -85
  71. package/src/server/tools.ts +0 -2460
  72. package/src/storage/database.ts +0 -271
  73. package/src/storage/tier1.ts +0 -135
  74. package/src/storage/tier2.ts +0 -972
  75. package/src/storage/tier3.ts +0 -123
  76. package/src/types/documentation.ts +0 -619
  77. package/src/types/index.ts +0 -222
  78. package/src/utils/config.ts +0 -194
  79. package/src/utils/files.ts +0 -117
  80. package/src/utils/time.ts +0 -37
  81. package/src/utils/tokens.ts +0 -52
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "neuronlayer",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server that gives AI assistants persistent understanding of your codebase",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
8
8
  "neuronlayer": "dist/index.js"
9
9
  },
10
+ "files": [
11
+ "dist/**",
12
+ "wasm/**"
13
+ ],
10
14
  "scripts": {
11
15
  "build": "node esbuild.config.js",
12
16
  "dev": "node --watch dist/index.js",
@@ -40,6 +44,7 @@
40
44
  "better-sqlite3": "^11.8.0",
41
45
  "chokidar": "^4.0.0",
42
46
  "glob": "^13.0.0",
47
+ "tree-sitter-wasms": "^0.1.13",
43
48
  "web-tree-sitter": "^0.24.0"
44
49
  },
45
50
  "devDependencies": {
package/esbuild.config.js DELETED
@@ -1,26 +0,0 @@
1
- import { build } from 'esbuild';
2
-
3
- const commonOptions = {
4
- bundle: true,
5
- platform: 'node',
6
- target: 'node18',
7
- format: 'esm',
8
- sourcemap: true,
9
- external: [
10
- 'better-sqlite3', // Native module
11
- '@xenova/transformers', // Large, keep external
12
- 'chokidar', // Uses CommonJS require
13
- 'glob', // Keep external
14
- 'web-tree-sitter' // WASM module
15
- ]
16
- };
17
-
18
- // Build main MCP server
19
- await build({
20
- ...commonOptions,
21
- entryPoints: ['src/index.ts'],
22
- outfile: 'dist/index.js',
23
- banner: { js: '#!/usr/bin/env node' },
24
- });
25
-
26
- console.log('Build complete!');
@@ -1,573 +0,0 @@
1
- import { ProjectManager, type ProjectInfo } from '../core/project-manager.js';
2
- import { ADRExporter } from '../core/adr-exporter.js';
3
- import { initializeDatabase } from '../storage/database.js';
4
- import { Tier2Storage } from '../storage/tier2.js';
5
- import { join } from 'path';
6
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
7
- import { homedir } from 'os';
8
-
9
- const projectManager = new ProjectManager();
10
-
11
- interface CommandResult {
12
- success: boolean;
13
- message: string;
14
- data?: unknown;
15
- }
16
-
17
- // List all projects
18
- export function listProjects(): CommandResult {
19
- const projects = projectManager.listProjects();
20
- const activeProject = projectManager.getActiveProject();
21
-
22
- if (projects.length === 0) {
23
- return {
24
- success: true,
25
- message: 'No projects registered. Use "neuronlayer projects add <path>" to add one.'
26
- };
27
- }
28
-
29
- const lines = ['Registered Projects:', ''];
30
- for (const project of projects) {
31
- const isActive = activeProject?.id === project.id ? ' (active)' : '';
32
- lines.push(` ${project.name}${isActive}`);
33
- lines.push(` ID: ${project.id}`);
34
- lines.push(` Path: ${project.path}`);
35
- lines.push(` Files: ${project.totalFiles}, Decisions: ${project.totalDecisions}`);
36
- lines.push(` Languages: ${project.languages.join(', ') || 'N/A'}`);
37
- lines.push('');
38
- }
39
-
40
- return {
41
- success: true,
42
- message: lines.join('\n'),
43
- data: projects
44
- };
45
- }
46
-
47
- // Add a project
48
- export function addProject(projectPath: string): CommandResult {
49
- try {
50
- const projectInfo = projectManager.registerProject(projectPath);
51
- projectManager.setActiveProject(projectInfo.id);
52
-
53
- return {
54
- success: true,
55
- message: `Project "${projectInfo.name}" registered and set as active.\nID: ${projectInfo.id}\nData directory: ${projectInfo.dataDir}`,
56
- data: projectInfo
57
- };
58
- } catch (error) {
59
- return {
60
- success: false,
61
- message: `Failed to add project: ${error instanceof Error ? error.message : String(error)}`
62
- };
63
- }
64
- }
65
-
66
- // Remove a project
67
- export function removeProject(projectId: string): CommandResult {
68
- const project = projectManager.getProject(projectId);
69
-
70
- if (!project) {
71
- return {
72
- success: false,
73
- message: `Project not found: ${projectId}`
74
- };
75
- }
76
-
77
- const removed = projectManager.removeProject(projectId);
78
-
79
- return {
80
- success: removed,
81
- message: removed
82
- ? `Project "${project.name}" removed from registry.`
83
- : `Failed to remove project.`
84
- };
85
- }
86
-
87
- // Switch to a project
88
- export function switchProject(projectId: string): CommandResult {
89
- const project = projectManager.getProject(projectId);
90
-
91
- if (!project) {
92
- return {
93
- success: false,
94
- message: `Project not found: ${projectId}`
95
- };
96
- }
97
-
98
- const switched = projectManager.setActiveProject(projectId);
99
-
100
- return {
101
- success: switched,
102
- message: switched
103
- ? `Switched to project: ${project.name}`
104
- : `Failed to switch project.`
105
- };
106
- }
107
-
108
- // Discover projects
109
- export function discoverProjects(): CommandResult {
110
- const discovered = projectManager.discoverProjects();
111
-
112
- if (discovered.length === 0) {
113
- return {
114
- success: true,
115
- message: 'No projects discovered in common locations.'
116
- };
117
- }
118
-
119
- const lines = [`Discovered ${discovered.length} potential projects:`, ''];
120
- for (const path of discovered) {
121
- const name = path.split(/[/\\]/).pop();
122
- lines.push(` ${name}`);
123
- lines.push(` ${path}`);
124
- lines.push('');
125
- }
126
- lines.push('Use "neuronlayer projects add <path>" to register a project.');
127
-
128
- return {
129
- success: true,
130
- message: lines.join('\n'),
131
- data: discovered
132
- };
133
- }
134
-
135
- // Export decisions to ADR
136
- export function exportDecisions(
137
- projectPath?: string,
138
- options: { outputDir?: string; format?: 'madr' | 'nygard' | 'simple' } = {}
139
- ): CommandResult {
140
- // Determine project path
141
- let targetPath = projectPath;
142
- if (!targetPath) {
143
- const activeProject = projectManager.getActiveProject();
144
- if (!activeProject) {
145
- return {
146
- success: false,
147
- message: 'No project specified and no active project. Use "neuronlayer projects switch <id>" first.'
148
- };
149
- }
150
- targetPath = activeProject.path;
151
- }
152
-
153
- // Get project info
154
- const projectInfo = projectManager.getProjectByPath(targetPath);
155
- if (!projectInfo) {
156
- return {
157
- success: false,
158
- message: `Project not registered: ${targetPath}. Use "neuronlayer projects add ${targetPath}" first.`
159
- };
160
- }
161
-
162
- // Open database and get decisions (check both new and old names)
163
- let dbPath = join(projectInfo.dataDir, 'neuronlayer.db');
164
- if (!existsSync(dbPath)) {
165
- // Fall back to old name for backwards compatibility
166
- const oldDbPath = join(projectInfo.dataDir, 'memorylayer.db');
167
- if (existsSync(oldDbPath)) {
168
- dbPath = oldDbPath;
169
- } else {
170
- return {
171
- success: false,
172
- message: `Project database not found. Has the project been indexed?`
173
- };
174
- }
175
- }
176
-
177
- const db = initializeDatabase(dbPath);
178
- const tier2 = new Tier2Storage(db);
179
- const decisions = tier2.getAllDecisions();
180
- db.close();
181
-
182
- if (decisions.length === 0) {
183
- return {
184
- success: true,
185
- message: 'No decisions to export.'
186
- };
187
- }
188
-
189
- // Export
190
- const exporter = new ADRExporter(targetPath);
191
- const exportedFiles = exporter.exportAllDecisions(decisions, {
192
- outputDir: options.outputDir,
193
- format: options.format,
194
- includeIndex: true
195
- });
196
-
197
- return {
198
- success: true,
199
- message: `Exported ${exportedFiles.length} ADR files to ${options.outputDir || join(targetPath, 'docs', 'decisions')}`,
200
- data: exportedFiles
201
- };
202
- }
203
-
204
- // Show project info
205
- export function showProject(projectId?: string): CommandResult {
206
- let project: ProjectInfo | null;
207
-
208
- if (projectId) {
209
- project = projectManager.getProject(projectId);
210
- } else {
211
- project = projectManager.getActiveProject();
212
- }
213
-
214
- if (!project) {
215
- return {
216
- success: false,
217
- message: projectId
218
- ? `Project not found: ${projectId}`
219
- : 'No active project. Use "neuronlayer projects switch <id>" first.'
220
- };
221
- }
222
-
223
- const lines = [
224
- `Project: ${project.name}`,
225
- `ID: ${project.id}`,
226
- `Path: ${project.path}`,
227
- `Data Directory: ${project.dataDir}`,
228
- `Files Indexed: ${project.totalFiles}`,
229
- `Decisions: ${project.totalDecisions}`,
230
- `Languages: ${project.languages.join(', ') || 'N/A'}`,
231
- `Last Accessed: ${new Date(project.lastAccessed).toLocaleString()}`
232
- ];
233
-
234
- return {
235
- success: true,
236
- message: lines.join('\n'),
237
- data: project
238
- };
239
- }
240
-
241
- // Helper to configure an MCP client
242
- function configureMCPClient(
243
- clientName: string,
244
- configPath: string,
245
- serverName: string,
246
- projectPath: string
247
- ): { success: boolean; message: string } {
248
- let config: { mcpServers?: Record<string, unknown> } = { mcpServers: {} };
249
-
250
- try {
251
- if (existsSync(configPath)) {
252
- const content = readFileSync(configPath, 'utf-8');
253
- config = JSON.parse(content);
254
- } else {
255
- // Create directory if needed
256
- const sep = process.platform === 'win32' ? '\\' : '/';
257
- const configDir = configPath.substring(0, configPath.lastIndexOf(sep));
258
- mkdirSync(configDir, { recursive: true });
259
- }
260
- } catch {
261
- // Config doesn't exist or is invalid, start fresh
262
- }
263
-
264
- if (!config.mcpServers) {
265
- config.mcpServers = {};
266
- }
267
-
268
- config.mcpServers[serverName] = {
269
- command: 'npx',
270
- args: ['-y', 'neuronlayer', '--project', projectPath]
271
- };
272
-
273
- try {
274
- writeFileSync(configPath, JSON.stringify(config, null, 2));
275
- return { success: true, message: `${clientName}: ${configPath}` };
276
- } catch (err) {
277
- return { success: false, message: `${clientName}: Failed - ${err instanceof Error ? err.message : String(err)}` };
278
- }
279
- }
280
-
281
- // Helper to configure project-local .mcp.json for Claude Code
282
- function configureProjectMCP(
283
- configPath: string,
284
- projectPath: string
285
- ): { success: boolean; message: string } {
286
- let config: { mcpServers?: Record<string, unknown> } = { mcpServers: {} };
287
-
288
- try {
289
- if (existsSync(configPath)) {
290
- const content = readFileSync(configPath, 'utf-8');
291
- config = JSON.parse(content);
292
- }
293
- } catch {
294
- // Config doesn't exist or is invalid, start fresh
295
- }
296
-
297
- if (!config.mcpServers) {
298
- config.mcpServers = {};
299
- }
300
-
301
- // Use simple name since this is project-specific
302
- config.mcpServers['neuronlayer'] = {
303
- command: 'npx',
304
- args: ['-y', 'neuronlayer', '--project', '.']
305
- };
306
-
307
- try {
308
- writeFileSync(configPath, JSON.stringify(config, null, 2));
309
- return { success: true, message: `Claude Code: ${configPath} (project-local)` };
310
- } catch (err) {
311
- return { success: false, message: `Claude Code: Failed - ${err instanceof Error ? err.message : String(err)}` };
312
- }
313
- }
314
-
315
- // Initialize neuronlayer for current project + auto-configure Claude Desktop & OpenCode
316
- export function initProject(projectPath?: string): CommandResult {
317
- const targetPath = projectPath || process.cwd();
318
-
319
- // 1. Register the project
320
- const addResult = addProject(targetPath);
321
- if (!addResult.success) {
322
- return addResult;
323
- }
324
-
325
- const projectInfo = addResult.data as ProjectInfo;
326
- const serverName = `neuronlayer-${projectInfo.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`;
327
- const platform = process.platform;
328
-
329
- const configuredClients: string[] = [];
330
- const failedClients: string[] = [];
331
-
332
- // 2. Configure Claude Desktop
333
- let claudeConfigPath: string;
334
- if (platform === 'win32') {
335
- claudeConfigPath = join(homedir(), 'AppData', 'Roaming', 'Claude', 'claude_desktop_config.json');
336
- } else if (platform === 'darwin') {
337
- claudeConfigPath = join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
338
- } else {
339
- claudeConfigPath = join(homedir(), '.config', 'claude', 'claude_desktop_config.json');
340
- }
341
-
342
- const claudeResult = configureMCPClient('Claude Desktop', claudeConfigPath, serverName, targetPath);
343
- if (claudeResult.success) {
344
- configuredClients.push(claudeResult.message);
345
- } else {
346
- failedClients.push(claudeResult.message);
347
- }
348
-
349
- // 3. Configure OpenCode
350
- const openCodeConfigPath = join(homedir(), '.opencode', 'config.json');
351
- const openCodeResult = configureMCPClient('OpenCode', openCodeConfigPath, serverName, targetPath);
352
- if (openCodeResult.success) {
353
- configuredClients.push(openCodeResult.message);
354
- } else {
355
- failedClients.push(openCodeResult.message);
356
- }
357
-
358
- // 4. Configure Claude Code (CLI) - use project-local .mcp.json
359
- // This ensures only the current project's NeuronLayer connects
360
- const claudeCodeConfigPath = join(targetPath, '.mcp.json');
361
- const claudeCodeResult = configureProjectMCP(claudeCodeConfigPath, targetPath);
362
- if (claudeCodeResult.success) {
363
- configuredClients.push(claudeCodeResult.message);
364
- }
365
-
366
- // 5. Configure Cursor
367
- let cursorConfigPath: string;
368
- if (platform === 'win32') {
369
- cursorConfigPath = join(homedir(), 'AppData', 'Roaming', 'Cursor', 'User', 'globalStorage', 'cursor.mcp', 'mcp.json');
370
- } else if (platform === 'darwin') {
371
- cursorConfigPath = join(homedir(), 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'cursor.mcp', 'mcp.json');
372
- } else {
373
- cursorConfigPath = join(homedir(), '.config', 'Cursor', 'User', 'globalStorage', 'cursor.mcp', 'mcp.json');
374
- }
375
-
376
- const cursorResult = configureMCPClient('Cursor', cursorConfigPath, serverName, targetPath);
377
- if (cursorResult.success) {
378
- configuredClients.push(cursorResult.message);
379
- }
380
-
381
- // Build result message
382
- let message = `
383
- NeuronLayer initialized!
384
-
385
- Project: ${projectInfo.name}
386
- Path: ${targetPath}
387
- Data: ${projectInfo.dataDir}
388
-
389
- Configured MCP Clients:
390
- ${configuredClients.map(c => ' ✓ ' + c).join('\n')}
391
- `;
392
-
393
- if (failedClients.length > 0) {
394
- message += `\nFailed:\n${failedClients.map(c => ' ✗ ' + c).join('\n')}`;
395
- }
396
-
397
- message += `\n\nRestart your AI tools to activate.`;
398
-
399
- return {
400
- success: true,
401
- message: message.trim(),
402
- data: { projectInfo, serverName, configuredClients }
403
- };
404
- }
405
-
406
- // Print help
407
- export function printHelp(): void {
408
- console.log(`
409
- NeuronLayer CLI - Code Intelligence for AI Coding Assistants
410
-
411
- USAGE:
412
- neuronlayer [command] [options]
413
-
414
- COMMANDS:
415
- init [path] Initialize project + auto-configure AI tools
416
- serve [options] Start HTTP API server (for non-MCP tools)
417
- (no command) Start MCP server
418
- projects list List all registered projects
419
- projects add <path> Add a project to the registry
420
- projects remove <id> Remove a project from the registry
421
- projects switch <id> Set a project as active
422
- projects show [id] Show project details
423
- projects discover Discover projects in common locations
424
- export [options] Export decisions to ADR files
425
- help Show this help message
426
-
427
- OPTIONS:
428
- --project, -p <path> Path to the project directory
429
- --port <number> Port for HTTP server (default: 3333)
430
- --output, -o <dir> Output directory for exports
431
- --format <type> ADR format: madr, nygard, simple
432
-
433
- EXAMPLES:
434
- # Quick setup (auto-configures Claude Desktop)
435
- cd /path/to/project
436
- neuronlayer init
437
-
438
- # Start MCP server
439
- neuronlayer --project /path/to/project
440
-
441
- # List all projects
442
- neuronlayer projects list
443
-
444
- # Add a new project
445
- neuronlayer projects add /path/to/my-project
446
-
447
- # Switch active project
448
- neuronlayer projects switch abc123
449
-
450
- # Export decisions to ADR files
451
- neuronlayer export --format madr
452
-
453
- # Discover projects
454
- neuronlayer projects discover
455
-
456
- # Start HTTP API server (for tools without MCP support)
457
- neuronlayer serve --project /path/to/project
458
- neuronlayer serve --port 8080
459
-
460
- For more information, visit: https://github.com/abhisavakar/neuronlayer
461
- `);
462
- }
463
-
464
- // Parse and execute CLI commands
465
- export function executeCLI(args: string[]): void {
466
- const command = args[0];
467
- const subcommand = args[1];
468
-
469
- switch (command) {
470
- case 'help':
471
- case '--help':
472
- case '-h':
473
- printHelp();
474
- break;
475
-
476
- case 'init': {
477
- const path = args[1];
478
- const result = initProject(path);
479
- console.log(result.message);
480
- if (!result.success) process.exit(1);
481
- break;
482
- }
483
-
484
- case 'projects': {
485
- switch (subcommand) {
486
- case 'list':
487
- console.log(listProjects().message);
488
- break;
489
- case 'add': {
490
- const path = args[2];
491
- if (!path) {
492
- console.error('Error: Project path required.');
493
- console.error('Usage: neuronlayer projects add <path>');
494
- process.exit(1);
495
- }
496
- const result = addProject(path);
497
- console.log(result.message);
498
- if (!result.success) process.exit(1);
499
- break;
500
- }
501
- case 'remove': {
502
- const id = args[2];
503
- if (!id) {
504
- console.error('Error: Project ID required.');
505
- console.error('Usage: neuronlayer projects remove <id>');
506
- process.exit(1);
507
- }
508
- const result = removeProject(id);
509
- console.log(result.message);
510
- if (!result.success) process.exit(1);
511
- break;
512
- }
513
- case 'switch': {
514
- const id = args[2];
515
- if (!id) {
516
- console.error('Error: Project ID required.');
517
- console.error('Usage: neuronlayer projects switch <id>');
518
- process.exit(1);
519
- }
520
- const result = switchProject(id);
521
- console.log(result.message);
522
- if (!result.success) process.exit(1);
523
- break;
524
- }
525
- case 'show': {
526
- const id = args[2];
527
- const result = showProject(id);
528
- console.log(result.message);
529
- if (!result.success) process.exit(1);
530
- break;
531
- }
532
- case 'discover':
533
- console.log(discoverProjects().message);
534
- break;
535
- default:
536
- console.error(`Unknown subcommand: ${subcommand}`);
537
- console.error('Available: list, add, remove, switch, show, discover');
538
- process.exit(1);
539
- }
540
- break;
541
- }
542
-
543
- case 'export': {
544
- // Parse export options
545
- let outputDir: string | undefined;
546
- let format: 'madr' | 'nygard' | 'simple' | undefined;
547
-
548
- for (let i = 1; i < args.length; i++) {
549
- const arg = args[i];
550
- const nextArg = args[i + 1];
551
- if ((arg === '--output' || arg === '-o') && nextArg) {
552
- outputDir = nextArg;
553
- i++;
554
- } else if (arg === '--format' && nextArg) {
555
- format = nextArg as 'madr' | 'nygard' | 'simple';
556
- i++;
557
- }
558
- }
559
-
560
- const result = exportDecisions(undefined, { outputDir, format });
561
- console.log(result.message);
562
- if (!result.success) process.exit(1);
563
- break;
564
- }
565
-
566
- default:
567
- // If no command matches, it might be the default MCP server mode
568
- // Return without handling - let main() handle it
569
- return;
570
- }
571
-
572
- process.exit(0);
573
- }