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
@@ -1,499 +0,0 @@
1
- import type { TestInfo, ChangeAnalysis, TestValidationResult, PredictedFailure, Assertion } from '../../types/documentation.js';
2
- import type { TestIndexer } from './test-indexer.js';
3
- import type { Tier2Storage } from '../../storage/tier2.js';
4
-
5
- interface FunctionChange {
6
- name: string;
7
- changeType: 'added' | 'removed' | 'modified' | 'signature_changed';
8
- oldSignature?: string;
9
- newSignature?: string;
10
- }
11
-
12
- interface ParsedChange {
13
- addedLines: string[];
14
- removedLines: string[];
15
- modifiedFunctions: FunctionChange[];
16
- exportChanges: { added: string[]; removed: string[] };
17
- }
18
-
19
- export class ChangeValidator {
20
- private testIndexer: TestIndexer;
21
- private tier2: Tier2Storage;
22
-
23
- constructor(testIndexer: TestIndexer, tier2: Tier2Storage) {
24
- this.testIndexer = testIndexer;
25
- this.tier2 = tier2;
26
- }
27
-
28
- analyzeChange(code: string, file: string): ChangeAnalysis {
29
- // Get existing file content from tier2
30
- const existingFile = this.tier2.getFile(file);
31
- const existingContent = existingFile?.preview || '';
32
-
33
- // Parse changes
34
- const parsed = this.parseCodeChange(existingContent, code);
35
-
36
- // Find affected functions
37
- const functions = parsed.modifiedFunctions.map(f => f.name);
38
-
39
- // Get tests that cover this file
40
- const testsForFile = this.testIndexer.getTestsForFile(file);
41
-
42
- // Get tests that cover any of the modified functions
43
- const testsForFunctions = functions.flatMap(fn => this.testIndexer.getTestsForFunction(fn));
44
-
45
- // Combine and dedupe affected tests
46
- const affectedTestIds = new Set<string>();
47
- const affectedTests: TestInfo[] = [];
48
-
49
- for (const test of [...testsForFile, ...testsForFunctions]) {
50
- if (!affectedTestIds.has(test.id)) {
51
- affectedTestIds.add(test.id);
52
- affectedTests.push(test);
53
- }
54
- }
55
-
56
- // Determine change type
57
- const changeType = this.determineChangeType(parsed);
58
-
59
- // Calculate risk level
60
- const risk = this.calculateRisk(parsed, affectedTests);
61
-
62
- // Calculate test coverage percentage
63
- const coveredFunctions = new Set<string>();
64
- for (const test of affectedTests) {
65
- for (const fn of test.coversFunctions) {
66
- coveredFunctions.add(fn);
67
- }
68
- }
69
- const testCoverage = functions.length > 0
70
- ? Math.round((coveredFunctions.size / functions.length) * 100)
71
- : affectedTests.length > 0 ? 100 : 0;
72
-
73
- // Generate reasoning
74
- const reasoning = this.generateReasoning(parsed, affectedTests, risk);
75
-
76
- return {
77
- file,
78
- functions,
79
- type: changeType,
80
- affectedTests,
81
- testCoverage,
82
- risk,
83
- reasoning
84
- };
85
- }
86
-
87
- predictFailures(analysis: ChangeAnalysis, newCode: string): PredictedFailure[] {
88
- const failures: PredictedFailure[] = [];
89
-
90
- for (const test of analysis.affectedTests) {
91
- // Check each assertion in the test
92
- for (const assertion of test.assertions) {
93
- const prediction = this.predictAssertionFailure(assertion, newCode, analysis);
94
- if (prediction) {
95
- failures.push(prediction);
96
- }
97
- }
98
-
99
- // If no specific assertion failures, check for general issues
100
- if (!failures.some(f => f.test.id === test.id)) {
101
- const generalPrediction = this.predictGeneralFailure(test, analysis, newCode);
102
- if (generalPrediction) {
103
- failures.push(generalPrediction);
104
- }
105
- }
106
- }
107
-
108
- return failures;
109
- }
110
-
111
- validateChange(code: string, file: string): TestValidationResult {
112
- const analysis = this.analyzeChange(code, file);
113
- const predictedFailures = this.predictFailures(analysis, code);
114
-
115
- // Categorize tests
116
- const wouldPass: TestInfo[] = [];
117
- const wouldFail: PredictedFailure[] = predictedFailures;
118
- const uncertain: TestInfo[] = [];
119
-
120
- const failingTestIds = new Set(predictedFailures.map(f => f.test.id));
121
-
122
- for (const test of analysis.affectedTests) {
123
- if (failingTestIds.has(test.id)) {
124
- continue; // Already in wouldFail
125
- }
126
-
127
- // Determine if test would likely pass or is uncertain
128
- const coverage = this.assessTestCoverage(test, code, file);
129
- if (coverage.confident) {
130
- wouldPass.push(test);
131
- } else {
132
- uncertain.push(test);
133
- }
134
- }
135
-
136
- // Generate suggested test updates
137
- const suggestedTestUpdates = this.generateTestUpdates(predictedFailures, analysis);
138
-
139
- // Determine if change is safe
140
- const safe = predictedFailures.length === 0 &&
141
- analysis.risk !== 'high' &&
142
- (analysis.testCoverage >= 50 || analysis.affectedTests.length === 0);
143
-
144
- return {
145
- safe,
146
- relatedTests: analysis.affectedTests,
147
- wouldPass,
148
- wouldFail: predictedFailures,
149
- uncertain,
150
- suggestedTestUpdates,
151
- coveragePercent: analysis.testCoverage
152
- };
153
- }
154
-
155
- private parseCodeChange(oldCode: string, newCode: string): ParsedChange {
156
- const oldLines = oldCode.split('\n');
157
- const newLines = newCode.split('\n');
158
-
159
- const addedLines: string[] = [];
160
- const removedLines: string[] = [];
161
-
162
- // Simple diff: lines in new but not in old
163
- const oldSet = new Set(oldLines.map(l => l.trim()));
164
- const newSet = new Set(newLines.map(l => l.trim()));
165
-
166
- for (const line of newLines) {
167
- if (!oldSet.has(line.trim()) && line.trim()) {
168
- addedLines.push(line);
169
- }
170
- }
171
-
172
- for (const line of oldLines) {
173
- if (!newSet.has(line.trim()) && line.trim()) {
174
- removedLines.push(line);
175
- }
176
- }
177
-
178
- // Detect function changes
179
- const oldFunctions = this.extractFunctions(oldCode);
180
- const newFunctions = this.extractFunctions(newCode);
181
- const modifiedFunctions: FunctionChange[] = [];
182
-
183
- const oldFuncMap = new Map(oldFunctions.map(f => [f.name, f]));
184
- const newFuncMap = new Map(newFunctions.map(f => [f.name, f]));
185
-
186
- // Find removed functions
187
- for (const [name, func] of oldFuncMap) {
188
- if (!newFuncMap.has(name)) {
189
- modifiedFunctions.push({
190
- name,
191
- changeType: 'removed',
192
- oldSignature: func.signature
193
- });
194
- }
195
- }
196
-
197
- // Find added and modified functions
198
- for (const [name, func] of newFuncMap) {
199
- const oldFunc = oldFuncMap.get(name);
200
- if (!oldFunc) {
201
- modifiedFunctions.push({
202
- name,
203
- changeType: 'added',
204
- newSignature: func.signature
205
- });
206
- } else if (oldFunc.signature !== func.signature) {
207
- modifiedFunctions.push({
208
- name,
209
- changeType: 'signature_changed',
210
- oldSignature: oldFunc.signature,
211
- newSignature: func.signature
212
- });
213
- } else if (oldFunc.body !== func.body) {
214
- modifiedFunctions.push({
215
- name,
216
- changeType: 'modified',
217
- oldSignature: oldFunc.signature,
218
- newSignature: func.signature
219
- });
220
- }
221
- }
222
-
223
- // Detect export changes
224
- const oldExports = this.extractExports(oldCode);
225
- const newExports = this.extractExports(newCode);
226
-
227
- const addedExports = newExports.filter(e => !oldExports.includes(e));
228
- const removedExports = oldExports.filter(e => !newExports.includes(e));
229
-
230
- return {
231
- addedLines,
232
- removedLines,
233
- modifiedFunctions,
234
- exportChanges: { added: addedExports, removed: removedExports }
235
- };
236
- }
237
-
238
- private extractFunctions(code: string): Array<{ name: string; signature: string; body: string }> {
239
- const functions: Array<{ name: string; signature: string; body: string }> = [];
240
-
241
- // JavaScript/TypeScript function patterns
242
- const patterns = [
243
- // Function declaration
244
- /function\s+(\w+)\s*\(([^)]*)\)[^{]*\{/g,
245
- // Arrow function
246
- /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(([^)]*)\)\s*(?::\s*\w+)?\s*=>/g,
247
- // Method
248
- /(\w+)\s*\(([^)]*)\)\s*(?::\s*\w+)?\s*\{/g,
249
- // Python function
250
- /def\s+(\w+)\s*\(([^)]*)\)\s*(?:->\s*\w+)?\s*:/g,
251
- // Go function
252
- /func\s+(\w+)\s*\(([^)]*)\)/g
253
- ];
254
-
255
- for (const pattern of patterns) {
256
- let match;
257
- while ((match = pattern.exec(code)) !== null) {
258
- const name = match[1];
259
- const params = match[2];
260
- const signature = `${name}(${params})`;
261
-
262
- // Extract a simple body representation (first 200 chars after signature)
263
- const bodyStart = match.index + match[0].length;
264
- const body = code.slice(bodyStart, bodyStart + 200);
265
-
266
- functions.push({ name: name ?? '', signature, body });
267
- }
268
- }
269
-
270
- return functions;
271
- }
272
-
273
- private extractExports(code: string): string[] {
274
- const exports: string[] = [];
275
-
276
- // ES6 exports
277
- const exportPatterns = [
278
- /export\s+(?:default\s+)?(?:function|class|const|let|var)\s+(\w+)/g,
279
- /export\s*\{\s*([^}]+)\s*\}/g,
280
- /module\.exports\s*=\s*\{\s*([^}]+)\s*\}/g,
281
- /module\.exports\.(\w+)\s*=/g
282
- ];
283
-
284
- for (const pattern of exportPatterns) {
285
- let match;
286
- while ((match = pattern.exec(code)) !== null) {
287
- const captured = match[1];
288
- if (!captured) continue;
289
- if (captured.includes(',')) {
290
- // Multiple exports
291
- const names = captured.split(',').map(s => {
292
- const parts = s.trim().split(/\s+as\s+/);
293
- return parts[0] ?? '';
294
- }).filter(Boolean);
295
- exports.push(...names);
296
- } else {
297
- exports.push(captured.trim());
298
- }
299
- }
300
- }
301
-
302
- return exports;
303
- }
304
-
305
- private determineChangeType(parsed: ParsedChange): 'refactor' | 'add' | 'delete' | 'modify' {
306
- const hasAdditions = parsed.addedLines.length > 0 || parsed.modifiedFunctions.some(f => f.changeType === 'added');
307
- const hasDeletions = parsed.removedLines.length > 0 || parsed.modifiedFunctions.some(f => f.changeType === 'removed');
308
- const hasModifications = parsed.modifiedFunctions.some(f => f.changeType === 'modified' || f.changeType === 'signature_changed');
309
-
310
- if (hasDeletions && !hasAdditions) return 'delete';
311
- if (hasAdditions && !hasDeletions && !hasModifications) return 'add';
312
- if (hasModifications || (hasAdditions && hasDeletions)) return 'modify';
313
-
314
- return 'refactor';
315
- }
316
-
317
- private calculateRisk(parsed: ParsedChange, affectedTests: TestInfo[]): 'low' | 'medium' | 'high' {
318
- let riskScore = 0;
319
-
320
- // Removed exports are high risk
321
- if (parsed.exportChanges.removed.length > 0) {
322
- riskScore += 30;
323
- }
324
-
325
- // Signature changes are medium-high risk
326
- const signatureChanges = parsed.modifiedFunctions.filter(f => f.changeType === 'signature_changed');
327
- riskScore += signatureChanges.length * 20;
328
-
329
- // Removed functions are high risk
330
- const removedFunctions = parsed.modifiedFunctions.filter(f => f.changeType === 'removed');
331
- riskScore += removedFunctions.length * 25;
332
-
333
- // No test coverage is risky
334
- if (affectedTests.length === 0 && parsed.modifiedFunctions.length > 0) {
335
- riskScore += 20;
336
- }
337
-
338
- // Many affected tests might indicate broad impact
339
- if (affectedTests.length > 10) {
340
- riskScore += 15;
341
- }
342
-
343
- if (riskScore >= 50) return 'high';
344
- if (riskScore >= 25) return 'medium';
345
- return 'low';
346
- }
347
-
348
- private generateReasoning(parsed: ParsedChange, affectedTests: TestInfo[], risk: 'low' | 'medium' | 'high'): string {
349
- const reasons: string[] = [];
350
-
351
- if (parsed.modifiedFunctions.length > 0) {
352
- const types = parsed.modifiedFunctions.map(f => f.changeType);
353
- if (types.includes('removed')) {
354
- reasons.push(`${types.filter(t => t === 'removed').length} function(s) removed`);
355
- }
356
- if (types.includes('signature_changed')) {
357
- reasons.push(`${types.filter(t => t === 'signature_changed').length} function signature(s) changed`);
358
- }
359
- if (types.includes('modified')) {
360
- reasons.push(`${types.filter(t => t === 'modified').length} function body(ies) modified`);
361
- }
362
- if (types.includes('added')) {
363
- reasons.push(`${types.filter(t => t === 'added').length} function(s) added`);
364
- }
365
- }
366
-
367
- if (parsed.exportChanges.removed.length > 0) {
368
- reasons.push(`${parsed.exportChanges.removed.length} export(s) removed: ${parsed.exportChanges.removed.join(', ')}`);
369
- }
370
-
371
- if (affectedTests.length > 0) {
372
- reasons.push(`${affectedTests.length} test(s) may be affected`);
373
- } else {
374
- reasons.push('No tests cover this code');
375
- }
376
-
377
- return reasons.join('. ') + '.';
378
- }
379
-
380
- private predictAssertionFailure(
381
- assertion: Assertion,
382
- newCode: string,
383
- analysis: ChangeAnalysis
384
- ): PredictedFailure | null {
385
- // Check if the assertion subject is affected by the change
386
- const subject = assertion.subject;
387
-
388
- // Check if subject function was removed or signature changed
389
- for (const func of analysis.functions) {
390
- if (subject.includes(func)) {
391
- // Check if this function had breaking changes
392
- const funcInfo = this.tier2.searchSymbols(func, undefined, 1);
393
- if (funcInfo.length === 0) {
394
- // Function might have been removed
395
- return {
396
- test: analysis.affectedTests.find(t => t.assertions.some(a => a.code === assertion.code))!,
397
- assertion,
398
- reason: `Function '${func}' appears to be removed or renamed`,
399
- confidence: 80,
400
- suggestedFix: `Update test to use the new function name or remove the test if functionality is removed`
401
- };
402
- }
403
- }
404
- }
405
-
406
- // Check if expected value might have changed
407
- if (assertion.expected) {
408
- // Look for the expected value in the old code but not in new
409
- const expectedInCode = newCode.includes(assertion.expected);
410
- if (!expectedInCode && assertion.type === 'equality') {
411
- return {
412
- test: analysis.affectedTests.find(t => t.assertions.some(a => a.code === assertion.code))!,
413
- assertion,
414
- reason: `Expected value '${assertion.expected}' may have changed`,
415
- confidence: 60,
416
- suggestedFix: `Review and update the expected value in the assertion`
417
- };
418
- }
419
- }
420
-
421
- return null;
422
- }
423
-
424
- private predictGeneralFailure(
425
- test: TestInfo,
426
- analysis: ChangeAnalysis,
427
- newCode: string
428
- ): PredictedFailure | null {
429
- // Check if any covered functions were removed
430
- for (const fn of test.coversFunctions) {
431
- const inNewCode = newCode.includes(fn);
432
- if (!inNewCode) {
433
- return {
434
- test,
435
- reason: `Test calls '${fn}' which may have been removed or renamed`,
436
- confidence: 70,
437
- suggestedFix: `Update test to use the new function name or remove the test`
438
- };
439
- }
440
- }
441
-
442
- // Check for signature changes affecting this test
443
- for (const fn of test.coversFunctions) {
444
- if (analysis.functions.includes(fn)) {
445
- // Function was modified
446
- return {
447
- test,
448
- reason: `Test uses '${fn}' which has been modified`,
449
- confidence: 40,
450
- suggestedFix: `Review test assertions after code changes`
451
- };
452
- }
453
- }
454
-
455
- return null;
456
- }
457
-
458
- private assessTestCoverage(test: TestInfo, newCode: string, file: string): { confident: boolean } {
459
- // Check if all covered functions still exist
460
- let allFunctionsExist = true;
461
- for (const fn of test.coversFunctions) {
462
- if (!newCode.includes(fn)) {
463
- allFunctionsExist = false;
464
- break;
465
- }
466
- }
467
-
468
- // Check if file is still covered
469
- const coversFile = test.coversFiles.some(f =>
470
- file.includes(f) || f.includes(file.replace(/\.[^.]+$/, ''))
471
- );
472
-
473
- return {
474
- confident: allFunctionsExist && coversFile
475
- };
476
- }
477
-
478
- private generateTestUpdates(
479
- failures: PredictedFailure[],
480
- analysis: ChangeAnalysis
481
- ): Array<{ file: string; testName: string; line: number; before: string; after: string; reason: string }> {
482
- const updates: Array<{ file: string; testName: string; line: number; before: string; after: string; reason: string }> = [];
483
-
484
- for (const failure of failures) {
485
- if (failure.assertion && failure.suggestedFix) {
486
- updates.push({
487
- file: failure.test.file,
488
- testName: failure.test.name,
489
- line: failure.assertion.line,
490
- before: failure.assertion.code,
491
- after: `// TODO: ${failure.suggestedFix}\n${failure.assertion.code}`,
492
- reason: failure.reason
493
- });
494
- }
495
- }
496
-
497
- return updates;
498
- }
499
- }
@@ -1,5 +0,0 @@
1
- export { TestAwareness } from './test-awareness.js';
2
- export { TestIndexer } from './test-indexer.js';
3
- export { TestParser } from './test-parser.js';
4
- export { ChangeValidator } from './change-validator.js';
5
- export { TestSuggester } from './test-suggester.js';
package/src/index.ts DELETED
@@ -1,90 +0,0 @@
1
- import { MCPServer } from './server/mcp.js';
2
- import { HTTPServer } from './server/http.js';
3
- import { getDefaultConfig, parseArgs } from './utils/config.js';
4
- import { executeCLI, printHelp } from './cli/commands.js';
5
-
6
- function parseServeArgs(args: string[]): { projectPath: string; port: number } {
7
- let projectPath = process.cwd();
8
- let port = 3333;
9
-
10
- for (let i = 0; i < args.length; i++) {
11
- const arg = args[i];
12
- const nextArg = args[i + 1];
13
- if ((arg === '--project' || arg === '-p') && nextArg) {
14
- projectPath = nextArg;
15
- i++;
16
- } else if (arg === '--port' && nextArg) {
17
- port = parseInt(nextArg) || 3333;
18
- i++;
19
- }
20
- }
21
-
22
- return { projectPath, port };
23
- }
24
-
25
- async function main(): Promise<void> {
26
- const args = process.argv.slice(2);
27
-
28
- // Check for CLI commands first
29
- const firstArg = args[0];
30
- const cliCommands = ['init', 'projects', 'export', 'help', '--help', '-h'];
31
-
32
- if (firstArg && cliCommands.includes(firstArg)) {
33
- // Handle CLI commands
34
- executeCLI(args);
35
- return;
36
- }
37
-
38
- // Handle serve command - start HTTP API server
39
- if (firstArg === 'serve') {
40
- const { projectPath, port } = parseServeArgs(args.slice(1));
41
- const config = getDefaultConfig(projectPath);
42
-
43
- console.log('NeuronLayer HTTP API starting...');
44
- console.log(`Project: ${config.projectPath}`);
45
- console.log(`Data directory: ${config.dataDir}`);
46
- console.log('');
47
-
48
- const server = new HTTPServer(config, port);
49
- try {
50
- await server.start();
51
- } catch (error) {
52
- console.error('Failed to start HTTP server:', error);
53
- process.exit(1);
54
- }
55
- return;
56
- }
57
-
58
- // No arguments and not piped - show help
59
- if (args.length === 0 && process.stdin.isTTY) {
60
- printHelp();
61
- console.log('\nTo start as MCP server, use: neuronlayer --project <path>');
62
- console.log('To start HTTP API, use: neuronlayer serve --project <path>\n');
63
- return;
64
- }
65
-
66
- // Parse command line arguments for MCP server mode
67
- const { projectPath } = parseArgs(args);
68
-
69
- // Get configuration
70
- const config = getDefaultConfig(projectPath);
71
-
72
- console.error('NeuronLayer starting...');
73
- console.error(`Project: ${config.projectPath}`);
74
- console.error(`Data directory: ${config.dataDir}`);
75
-
76
- // Create and start MCP server
77
- const server = new MCPServer(config);
78
-
79
- try {
80
- await server.start();
81
- } catch (error) {
82
- console.error('Failed to start NeuronLayer:', error);
83
- process.exit(1);
84
- }
85
- }
86
-
87
- main().catch((error) => {
88
- console.error('Unhandled error:', error);
89
- process.exit(1);
90
- });