neuronlayer 0.1.8 → 0.1.9
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.
- package/README.md +94 -269
- package/dist/index.js +309 -39
- package/package.json +2 -2
- package/src/cli/commands.ts +76 -21
- package/src/core/adr-exporter.ts +4 -4
- package/src/core/engine.ts +7 -7
- package/src/core/ghost-mode.ts +1 -1
- package/src/core/project-manager.ts +2 -2
- package/src/core/refresh/index.ts +1 -1
- package/src/index.ts +44 -3
- package/src/indexing/indexer.ts +3 -3
- package/src/server/gateways/index.ts +473 -473
- package/src/server/gateways/memory-ghost.ts +343 -343
- package/src/server/gateways/memory-query.ts +452 -452
- package/src/server/gateways/memory-record.ts +346 -346
- package/src/server/gateways/memory-review.ts +410 -410
- package/src/server/gateways/memory-status.ts +517 -517
- package/src/server/gateways/memory-verify.ts +392 -392
- package/src/server/http.ts +228 -0
- package/src/server/mcp.ts +6 -6
- package/src/server/resources.ts +85 -85
- package/src/server/tools.ts +2460 -2460
- package/src/types/index.ts +2 -2
- package/src/utils/config.ts +5 -4
package/dist/index.js
CHANGED
|
@@ -24634,7 +24634,7 @@ var ADRExporter = class {
|
|
|
24634
24634
|
lines.push("");
|
|
24635
24635
|
lines.push("---");
|
|
24636
24636
|
lines.push("");
|
|
24637
|
-
lines.push("*Generated by
|
|
24637
|
+
lines.push("*Generated by NeuronLayer*");
|
|
24638
24638
|
writeFileSync3(indexPath, lines.join("\n"));
|
|
24639
24639
|
return indexPath;
|
|
24640
24640
|
}
|
|
@@ -24681,7 +24681,7 @@ ${decision.supersededBy ? `## Superseded By
|
|
|
24681
24681
|
This decision has been superseded by [ADR ${decision.supersededBy}](./${decision.supersededBy}.md).
|
|
24682
24682
|
` : ""}
|
|
24683
24683
|
---
|
|
24684
|
-
*Exported from
|
|
24684
|
+
*Exported from NeuronLayer*
|
|
24685
24685
|
`;
|
|
24686
24686
|
}
|
|
24687
24687
|
// Nygard format (original ADR format)
|
|
@@ -24715,7 +24715,7 @@ ${decision.files.length > 0 ? `## Related Files
|
|
|
24715
24715
|
${decision.files.map((f) => `- ${f}`).join("\n")}
|
|
24716
24716
|
` : ""}
|
|
24717
24717
|
---
|
|
24718
|
-
*Exported from
|
|
24718
|
+
*Exported from NeuronLayer*
|
|
24719
24719
|
`;
|
|
24720
24720
|
}
|
|
24721
24721
|
// Simple format
|
|
@@ -24737,7 +24737,7 @@ ${decision.files.length > 0 ? `## Related Files
|
|
|
24737
24737
|
${decision.files.map((f) => `- \`${f}\``).join("\n")}
|
|
24738
24738
|
` : ""}
|
|
24739
24739
|
---
|
|
24740
|
-
*Exported from
|
|
24740
|
+
*Exported from NeuronLayer*
|
|
24741
24741
|
`;
|
|
24742
24742
|
}
|
|
24743
24743
|
getExistingADRFiles(dir) {
|
|
@@ -33760,7 +33760,7 @@ var ActivityGate = class {
|
|
|
33760
33760
|
};
|
|
33761
33761
|
|
|
33762
33762
|
// src/core/engine.ts
|
|
33763
|
-
var
|
|
33763
|
+
var NeuronLayerEngine = class {
|
|
33764
33764
|
config;
|
|
33765
33765
|
db;
|
|
33766
33766
|
tier1;
|
|
@@ -33929,7 +33929,7 @@ var MemoryLayerEngine = class {
|
|
|
33929
33929
|
}
|
|
33930
33930
|
async initialize() {
|
|
33931
33931
|
if (this.initialized) return;
|
|
33932
|
-
console.error(`Initializing
|
|
33932
|
+
console.error(`Initializing NeuronLayer for: ${this.config.projectPath}`);
|
|
33933
33933
|
try {
|
|
33934
33934
|
this.initializationStatus = "indexing";
|
|
33935
33935
|
await this.indexer.performInitialIndex();
|
|
@@ -33952,7 +33952,7 @@ var MemoryLayerEngine = class {
|
|
|
33952
33952
|
this.activityGate.startIdleMonitoring(1e4);
|
|
33953
33953
|
this.initialized = true;
|
|
33954
33954
|
this.initializationStatus = "ready";
|
|
33955
|
-
console.error("
|
|
33955
|
+
console.error("NeuronLayer initialized");
|
|
33956
33956
|
} catch (error2) {
|
|
33957
33957
|
this.initializationStatus = "error";
|
|
33958
33958
|
throw error2;
|
|
@@ -34904,7 +34904,7 @@ ${description}`;
|
|
|
34904
34904
|
return this.codeVerifier.checkDependencies(code);
|
|
34905
34905
|
}
|
|
34906
34906
|
shutdown() {
|
|
34907
|
-
console.error("Shutting down
|
|
34907
|
+
console.error("Shutting down NeuronLayer...");
|
|
34908
34908
|
this.indexer.stopWatching();
|
|
34909
34909
|
this.activityGate.shutdown();
|
|
34910
34910
|
this.tier1.save();
|
|
@@ -37119,7 +37119,7 @@ var standaloneDefinitions = [
|
|
|
37119
37119
|
},
|
|
37120
37120
|
{
|
|
37121
37121
|
name: "discover_projects",
|
|
37122
|
-
description: "Find git repositories on the system. Use when user wants to add/register a project to
|
|
37122
|
+
description: "Find git repositories on the system. Use when user wants to add/register a project to NeuronLayer.",
|
|
37123
37123
|
inputSchema: {
|
|
37124
37124
|
type: "object",
|
|
37125
37125
|
properties: {}
|
|
@@ -38430,13 +38430,13 @@ async function handleToolCall(engine, toolName, args) {
|
|
|
38430
38430
|
// src/server/resources.ts
|
|
38431
38431
|
var resourceDefinitions = [
|
|
38432
38432
|
{
|
|
38433
|
-
uri: "
|
|
38433
|
+
uri: "neuronlayer://decisions/recent",
|
|
38434
38434
|
name: "Recent Decisions",
|
|
38435
38435
|
description: "Last 10 architectural decisions made in this project",
|
|
38436
38436
|
mimeType: "application/json"
|
|
38437
38437
|
},
|
|
38438
38438
|
{
|
|
38439
|
-
uri: "
|
|
38439
|
+
uri: "neuronlayer://project/overview",
|
|
38440
38440
|
name: "Project Overview",
|
|
38441
38441
|
description: "High-level project summary including languages, files, and structure",
|
|
38442
38442
|
mimeType: "text/markdown"
|
|
@@ -38444,7 +38444,7 @@ var resourceDefinitions = [
|
|
|
38444
38444
|
];
|
|
38445
38445
|
async function handleResourceRead(engine, uri) {
|
|
38446
38446
|
switch (uri) {
|
|
38447
|
-
case "
|
|
38447
|
+
case "neuronlayer://decisions/recent": {
|
|
38448
38448
|
const decisions = engine.getRecentDecisions(10);
|
|
38449
38449
|
const contents = JSON.stringify(
|
|
38450
38450
|
decisions.map((d) => ({
|
|
@@ -38460,7 +38460,7 @@ async function handleResourceRead(engine, uri) {
|
|
|
38460
38460
|
);
|
|
38461
38461
|
return { contents, mimeType: "application/json" };
|
|
38462
38462
|
}
|
|
38463
|
-
case "
|
|
38463
|
+
case "neuronlayer://project/overview": {
|
|
38464
38464
|
const summary = engine.getProjectSummary();
|
|
38465
38465
|
const markdown = `# ${summary.name}
|
|
38466
38466
|
|
|
@@ -38500,7 +38500,7 @@ var MCPServer = class {
|
|
|
38500
38500
|
server;
|
|
38501
38501
|
engine;
|
|
38502
38502
|
constructor(config2) {
|
|
38503
|
-
this.engine = new
|
|
38503
|
+
this.engine = new NeuronLayerEngine(config2);
|
|
38504
38504
|
this.server = new Server(
|
|
38505
38505
|
{
|
|
38506
38506
|
name: "neuronlayer",
|
|
@@ -38587,7 +38587,7 @@ var MCPServer = class {
|
|
|
38587
38587
|
async start() {
|
|
38588
38588
|
const transport = new StdioServerTransport();
|
|
38589
38589
|
await this.server.connect(transport);
|
|
38590
|
-
console.error("
|
|
38590
|
+
console.error("NeuronLayer MCP server started");
|
|
38591
38591
|
this.engine.initialize().catch((err) => {
|
|
38592
38592
|
console.error("Engine initialization error:", err);
|
|
38593
38593
|
});
|
|
@@ -38605,6 +38605,201 @@ var MCPServer = class {
|
|
|
38605
38605
|
}
|
|
38606
38606
|
};
|
|
38607
38607
|
|
|
38608
|
+
// src/server/http.ts
|
|
38609
|
+
import { createServer } from "http";
|
|
38610
|
+
var HTTPServer = class {
|
|
38611
|
+
engine;
|
|
38612
|
+
server = null;
|
|
38613
|
+
port;
|
|
38614
|
+
constructor(config2, port = 3333) {
|
|
38615
|
+
this.engine = new NeuronLayerEngine(config2);
|
|
38616
|
+
this.port = port;
|
|
38617
|
+
}
|
|
38618
|
+
async start() {
|
|
38619
|
+
await this.engine.initialize();
|
|
38620
|
+
this.server = createServer((req, res) => {
|
|
38621
|
+
this.handleRequest(req, res);
|
|
38622
|
+
});
|
|
38623
|
+
this.server.listen(this.port, () => {
|
|
38624
|
+
console.log(`NeuronLayer HTTP API running at http://localhost:${this.port}`);
|
|
38625
|
+
console.log("");
|
|
38626
|
+
console.log("Endpoints:");
|
|
38627
|
+
console.log(" GET /status - Project status and stats");
|
|
38628
|
+
console.log(" GET /search?q=... - Search code semantically");
|
|
38629
|
+
console.log(" GET /dependencies?file= - Get file dependencies");
|
|
38630
|
+
console.log(" GET /impact?file= - Impact analysis");
|
|
38631
|
+
console.log(" GET /circular - Find circular dependencies");
|
|
38632
|
+
console.log(" GET /decisions - List all decisions");
|
|
38633
|
+
console.log(" POST /decisions - Record a new decision");
|
|
38634
|
+
console.log(" GET /symbols?file= - Get symbols in a file");
|
|
38635
|
+
});
|
|
38636
|
+
process.on("SIGINT", () => {
|
|
38637
|
+
this.shutdown();
|
|
38638
|
+
process.exit(0);
|
|
38639
|
+
});
|
|
38640
|
+
process.on("SIGTERM", () => {
|
|
38641
|
+
this.shutdown();
|
|
38642
|
+
process.exit(0);
|
|
38643
|
+
});
|
|
38644
|
+
}
|
|
38645
|
+
async handleRequest(req, res) {
|
|
38646
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
38647
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
38648
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
38649
|
+
if (req.method === "OPTIONS") {
|
|
38650
|
+
res.writeHead(200);
|
|
38651
|
+
res.end();
|
|
38652
|
+
return;
|
|
38653
|
+
}
|
|
38654
|
+
const url2 = new URL(req.url || "/", `http://localhost:${this.port}`);
|
|
38655
|
+
const path = url2.pathname;
|
|
38656
|
+
try {
|
|
38657
|
+
let result;
|
|
38658
|
+
switch (path) {
|
|
38659
|
+
case "/":
|
|
38660
|
+
case "/status": {
|
|
38661
|
+
const summary = this.engine.getProjectSummary();
|
|
38662
|
+
const status = this.engine.getInitializationStatus();
|
|
38663
|
+
result = {
|
|
38664
|
+
project: summary.name,
|
|
38665
|
+
status: status.status,
|
|
38666
|
+
files: summary.totalFiles,
|
|
38667
|
+
lines: summary.totalLines,
|
|
38668
|
+
languages: summary.languages,
|
|
38669
|
+
decisions: summary.recentDecisions.length
|
|
38670
|
+
};
|
|
38671
|
+
break;
|
|
38672
|
+
}
|
|
38673
|
+
case "/search": {
|
|
38674
|
+
const query = url2.searchParams.get("q");
|
|
38675
|
+
if (!query) {
|
|
38676
|
+
this.sendError(res, 400, "Missing query parameter: q");
|
|
38677
|
+
return;
|
|
38678
|
+
}
|
|
38679
|
+
const limit = parseInt(url2.searchParams.get("limit") || "10");
|
|
38680
|
+
const results = await this.engine.search(query, limit);
|
|
38681
|
+
result = results.map((r) => ({
|
|
38682
|
+
file: r.file,
|
|
38683
|
+
preview: r.preview,
|
|
38684
|
+
similarity: r.similarity,
|
|
38685
|
+
lines: `${r.lineStart}-${r.lineEnd}`
|
|
38686
|
+
}));
|
|
38687
|
+
break;
|
|
38688
|
+
}
|
|
38689
|
+
case "/dependencies": {
|
|
38690
|
+
const file2 = url2.searchParams.get("file");
|
|
38691
|
+
if (!file2) {
|
|
38692
|
+
this.sendError(res, 400, "Missing query parameter: file");
|
|
38693
|
+
return;
|
|
38694
|
+
}
|
|
38695
|
+
const deps = this.engine.getFileDependencies(file2);
|
|
38696
|
+
result = deps;
|
|
38697
|
+
break;
|
|
38698
|
+
}
|
|
38699
|
+
case "/impact": {
|
|
38700
|
+
const file2 = url2.searchParams.get("file");
|
|
38701
|
+
if (!file2) {
|
|
38702
|
+
this.sendError(res, 400, "Missing query parameter: file");
|
|
38703
|
+
return;
|
|
38704
|
+
}
|
|
38705
|
+
const depth = parseInt(url2.searchParams.get("depth") || "3");
|
|
38706
|
+
const dependents = this.engine.getTransitiveDependents(file2, depth);
|
|
38707
|
+
const circular = this.engine.findCircularDependencies();
|
|
38708
|
+
const fileCircular = circular.filter((chain) => chain.includes(file2));
|
|
38709
|
+
result = {
|
|
38710
|
+
file: file2,
|
|
38711
|
+
direct_dependents: dependents.filter((d) => d.depth === 1).length,
|
|
38712
|
+
total_affected: dependents.length,
|
|
38713
|
+
risk_level: dependents.length > 10 ? "high" : dependents.length > 5 ? "medium" : "low",
|
|
38714
|
+
affected_files: dependents.slice(0, 20),
|
|
38715
|
+
circular_dependencies: fileCircular
|
|
38716
|
+
};
|
|
38717
|
+
break;
|
|
38718
|
+
}
|
|
38719
|
+
case "/circular": {
|
|
38720
|
+
const chains = this.engine.findCircularDependencies();
|
|
38721
|
+
result = {
|
|
38722
|
+
count: chains.length,
|
|
38723
|
+
chains: chains.slice(0, 10)
|
|
38724
|
+
};
|
|
38725
|
+
break;
|
|
38726
|
+
}
|
|
38727
|
+
case "/decisions": {
|
|
38728
|
+
if (req.method === "POST") {
|
|
38729
|
+
const body = await this.readBody(req);
|
|
38730
|
+
const data = JSON.parse(body);
|
|
38731
|
+
if (!data.title || !data.description) {
|
|
38732
|
+
this.sendError(res, 400, "Missing required fields: title, description");
|
|
38733
|
+
return;
|
|
38734
|
+
}
|
|
38735
|
+
const decision = await this.engine.recordDecision(
|
|
38736
|
+
data.title,
|
|
38737
|
+
data.description,
|
|
38738
|
+
data.files || [],
|
|
38739
|
+
data.tags || []
|
|
38740
|
+
);
|
|
38741
|
+
result = decision;
|
|
38742
|
+
} else {
|
|
38743
|
+
const decisions = this.engine.getRecentDecisions(50);
|
|
38744
|
+
result = decisions.map((d) => ({
|
|
38745
|
+
id: d.id,
|
|
38746
|
+
title: d.title,
|
|
38747
|
+
description: d.description,
|
|
38748
|
+
files: d.files,
|
|
38749
|
+
tags: d.tags,
|
|
38750
|
+
created: d.createdAt,
|
|
38751
|
+
status: d.status
|
|
38752
|
+
}));
|
|
38753
|
+
}
|
|
38754
|
+
break;
|
|
38755
|
+
}
|
|
38756
|
+
case "/symbols": {
|
|
38757
|
+
const file2 = url2.searchParams.get("file");
|
|
38758
|
+
if (!file2) {
|
|
38759
|
+
this.sendError(res, 400, "Missing query parameter: file");
|
|
38760
|
+
return;
|
|
38761
|
+
}
|
|
38762
|
+
const symbols = this.engine.getSymbols(file2);
|
|
38763
|
+
result = symbols;
|
|
38764
|
+
break;
|
|
38765
|
+
}
|
|
38766
|
+
default:
|
|
38767
|
+
this.sendError(res, 404, `Unknown endpoint: ${path}`);
|
|
38768
|
+
return;
|
|
38769
|
+
}
|
|
38770
|
+
this.sendJSON(res, 200, result);
|
|
38771
|
+
} catch (error2) {
|
|
38772
|
+
const message = error2 instanceof Error ? error2.message : "Unknown error";
|
|
38773
|
+
this.sendError(res, 500, message);
|
|
38774
|
+
}
|
|
38775
|
+
}
|
|
38776
|
+
readBody(req) {
|
|
38777
|
+
return new Promise((resolve3, reject) => {
|
|
38778
|
+
let body = "";
|
|
38779
|
+
req.on("data", (chunk) => {
|
|
38780
|
+
body += chunk;
|
|
38781
|
+
});
|
|
38782
|
+
req.on("end", () => resolve3(body));
|
|
38783
|
+
req.on("error", reject);
|
|
38784
|
+
});
|
|
38785
|
+
}
|
|
38786
|
+
sendJSON(res, status, data) {
|
|
38787
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
38788
|
+
res.end(JSON.stringify(data, null, 2));
|
|
38789
|
+
}
|
|
38790
|
+
sendError(res, status, message) {
|
|
38791
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
38792
|
+
res.end(JSON.stringify({ error: message }));
|
|
38793
|
+
}
|
|
38794
|
+
shutdown() {
|
|
38795
|
+
console.log("Shutting down HTTP server...");
|
|
38796
|
+
this.engine.shutdown();
|
|
38797
|
+
if (this.server) {
|
|
38798
|
+
this.server.close();
|
|
38799
|
+
}
|
|
38800
|
+
}
|
|
38801
|
+
};
|
|
38802
|
+
|
|
38608
38803
|
// src/utils/config.ts
|
|
38609
38804
|
import { join as join14, resolve as resolve2 } from "path";
|
|
38610
38805
|
function getDefaultConfig(projectPath) {
|
|
@@ -38612,12 +38807,13 @@ function getDefaultConfig(projectPath) {
|
|
|
38612
38807
|
return {
|
|
38613
38808
|
projectPath: normalizedPath,
|
|
38614
38809
|
// Store in project directory (standard practice like .git/, .vscode/)
|
|
38615
|
-
dataDir: join14(normalizedPath, ".
|
|
38810
|
+
dataDir: join14(normalizedPath, ".neuronlayer"),
|
|
38616
38811
|
maxTokens: 6e3,
|
|
38617
38812
|
embeddingModel: "Xenova/all-MiniLM-L6-v2",
|
|
38618
38813
|
// Fallback model, faster and smaller
|
|
38619
38814
|
watchIgnore: [
|
|
38620
|
-
// =====
|
|
38815
|
+
// ===== NeuronLayer =====
|
|
38816
|
+
"**/.neuronlayer/**",
|
|
38621
38817
|
"**/.memorylayer/**",
|
|
38622
38818
|
// ===== Version Control =====
|
|
38623
38819
|
"**/.git/**",
|
|
@@ -38784,7 +38980,7 @@ function listProjects() {
|
|
|
38784
38980
|
if (projects.length === 0) {
|
|
38785
38981
|
return {
|
|
38786
38982
|
success: true,
|
|
38787
|
-
message: 'No projects registered. Use "
|
|
38983
|
+
message: 'No projects registered. Use "neuronlayer projects add <path>" to add one.'
|
|
38788
38984
|
};
|
|
38789
38985
|
}
|
|
38790
38986
|
const lines = ["Registered Projects:", ""];
|
|
@@ -38864,7 +39060,7 @@ function discoverProjects() {
|
|
|
38864
39060
|
lines.push(` ${path}`);
|
|
38865
39061
|
lines.push("");
|
|
38866
39062
|
}
|
|
38867
|
-
lines.push('Use "
|
|
39063
|
+
lines.push('Use "neuronlayer projects add <path>" to register a project.');
|
|
38868
39064
|
return {
|
|
38869
39065
|
success: true,
|
|
38870
39066
|
message: lines.join("\n"),
|
|
@@ -38878,7 +39074,7 @@ function exportDecisions(projectPath, options = {}) {
|
|
|
38878
39074
|
if (!activeProject) {
|
|
38879
39075
|
return {
|
|
38880
39076
|
success: false,
|
|
38881
|
-
message: 'No project specified and no active project. Use "
|
|
39077
|
+
message: 'No project specified and no active project. Use "neuronlayer projects switch <id>" first.'
|
|
38882
39078
|
};
|
|
38883
39079
|
}
|
|
38884
39080
|
targetPath = activeProject.path;
|
|
@@ -38887,7 +39083,7 @@ function exportDecisions(projectPath, options = {}) {
|
|
|
38887
39083
|
if (!projectInfo) {
|
|
38888
39084
|
return {
|
|
38889
39085
|
success: false,
|
|
38890
|
-
message: `Project not registered: ${targetPath}. Use "
|
|
39086
|
+
message: `Project not registered: ${targetPath}. Use "neuronlayer projects add ${targetPath}" first.`
|
|
38891
39087
|
};
|
|
38892
39088
|
}
|
|
38893
39089
|
let dbPath = join15(projectInfo.dataDir, "neuronlayer.db");
|
|
@@ -38934,7 +39130,7 @@ function showProject(projectId) {
|
|
|
38934
39130
|
if (!project) {
|
|
38935
39131
|
return {
|
|
38936
39132
|
success: false,
|
|
38937
|
-
message: projectId ? `Project not found: ${projectId}` : 'No active project. Use "
|
|
39133
|
+
message: projectId ? `Project not found: ${projectId}` : 'No active project. Use "neuronlayer projects switch <id>" first.'
|
|
38938
39134
|
};
|
|
38939
39135
|
}
|
|
38940
39136
|
const lines = [
|
|
@@ -38980,6 +39176,29 @@ function configureMCPClient(clientName, configPath, serverName, projectPath) {
|
|
|
38980
39176
|
return { success: false, message: `${clientName}: Failed - ${err instanceof Error ? err.message : String(err)}` };
|
|
38981
39177
|
}
|
|
38982
39178
|
}
|
|
39179
|
+
function configureProjectMCP(configPath, projectPath) {
|
|
39180
|
+
let config2 = { mcpServers: {} };
|
|
39181
|
+
try {
|
|
39182
|
+
if (existsSync14(configPath)) {
|
|
39183
|
+
const content = readFileSync11(configPath, "utf-8");
|
|
39184
|
+
config2 = JSON.parse(content);
|
|
39185
|
+
}
|
|
39186
|
+
} catch {
|
|
39187
|
+
}
|
|
39188
|
+
if (!config2.mcpServers) {
|
|
39189
|
+
config2.mcpServers = {};
|
|
39190
|
+
}
|
|
39191
|
+
config2.mcpServers["neuronlayer"] = {
|
|
39192
|
+
command: "npx",
|
|
39193
|
+
args: ["-y", "neuronlayer", "--project", "."]
|
|
39194
|
+
};
|
|
39195
|
+
try {
|
|
39196
|
+
writeFileSync5(configPath, JSON.stringify(config2, null, 2));
|
|
39197
|
+
return { success: true, message: `Claude Code: ${configPath} (project-local)` };
|
|
39198
|
+
} catch (err) {
|
|
39199
|
+
return { success: false, message: `Claude Code: Failed - ${err instanceof Error ? err.message : String(err)}` };
|
|
39200
|
+
}
|
|
39201
|
+
}
|
|
38983
39202
|
function initProject(projectPath) {
|
|
38984
39203
|
const targetPath = projectPath || process.cwd();
|
|
38985
39204
|
const addResult = addProject(targetPath);
|
|
@@ -39012,11 +39231,23 @@ function initProject(projectPath) {
|
|
|
39012
39231
|
} else {
|
|
39013
39232
|
failedClients.push(openCodeResult.message);
|
|
39014
39233
|
}
|
|
39015
|
-
const claudeCodeConfigPath = join15(
|
|
39016
|
-
const claudeCodeResult =
|
|
39234
|
+
const claudeCodeConfigPath = join15(targetPath, ".mcp.json");
|
|
39235
|
+
const claudeCodeResult = configureProjectMCP(claudeCodeConfigPath, targetPath);
|
|
39017
39236
|
if (claudeCodeResult.success) {
|
|
39018
39237
|
configuredClients.push(claudeCodeResult.message);
|
|
39019
39238
|
}
|
|
39239
|
+
let cursorConfigPath;
|
|
39240
|
+
if (platform === "win32") {
|
|
39241
|
+
cursorConfigPath = join15(homedir2(), "AppData", "Roaming", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
|
|
39242
|
+
} else if (platform === "darwin") {
|
|
39243
|
+
cursorConfigPath = join15(homedir2(), "Library", "Application Support", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
|
|
39244
|
+
} else {
|
|
39245
|
+
cursorConfigPath = join15(homedir2(), ".config", "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
|
|
39246
|
+
}
|
|
39247
|
+
const cursorResult = configureMCPClient("Cursor", cursorConfigPath, serverName, targetPath);
|
|
39248
|
+
if (cursorResult.success) {
|
|
39249
|
+
configuredClients.push(cursorResult.message);
|
|
39250
|
+
}
|
|
39020
39251
|
let message = `
|
|
39021
39252
|
NeuronLayer initialized!
|
|
39022
39253
|
|
|
@@ -39043,14 +39274,15 @@ Restart your AI tools to activate.`;
|
|
|
39043
39274
|
}
|
|
39044
39275
|
function printHelp() {
|
|
39045
39276
|
console.log(`
|
|
39046
|
-
|
|
39277
|
+
NeuronLayer CLI - Code Intelligence for AI Coding Assistants
|
|
39047
39278
|
|
|
39048
39279
|
USAGE:
|
|
39049
|
-
|
|
39280
|
+
neuronlayer [command] [options]
|
|
39050
39281
|
|
|
39051
39282
|
COMMANDS:
|
|
39052
|
-
init [path] Initialize project + auto-configure
|
|
39053
|
-
|
|
39283
|
+
init [path] Initialize project + auto-configure AI tools
|
|
39284
|
+
serve [options] Start HTTP API server (for non-MCP tools)
|
|
39285
|
+
(no command) Start MCP server
|
|
39054
39286
|
projects list List all registered projects
|
|
39055
39287
|
projects add <path> Add a project to the registry
|
|
39056
39288
|
projects remove <id> Remove a project from the registry
|
|
@@ -39062,6 +39294,7 @@ COMMANDS:
|
|
|
39062
39294
|
|
|
39063
39295
|
OPTIONS:
|
|
39064
39296
|
--project, -p <path> Path to the project directory
|
|
39297
|
+
--port <number> Port for HTTP server (default: 3333)
|
|
39065
39298
|
--output, -o <dir> Output directory for exports
|
|
39066
39299
|
--format <type> ADR format: madr, nygard, simple
|
|
39067
39300
|
|
|
@@ -39074,19 +39307,23 @@ EXAMPLES:
|
|
|
39074
39307
|
neuronlayer --project /path/to/project
|
|
39075
39308
|
|
|
39076
39309
|
# List all projects
|
|
39077
|
-
|
|
39310
|
+
neuronlayer projects list
|
|
39078
39311
|
|
|
39079
39312
|
# Add a new project
|
|
39080
|
-
|
|
39313
|
+
neuronlayer projects add /path/to/my-project
|
|
39081
39314
|
|
|
39082
39315
|
# Switch active project
|
|
39083
|
-
|
|
39316
|
+
neuronlayer projects switch abc123
|
|
39084
39317
|
|
|
39085
39318
|
# Export decisions to ADR files
|
|
39086
|
-
|
|
39319
|
+
neuronlayer export --format madr
|
|
39087
39320
|
|
|
39088
39321
|
# Discover projects
|
|
39089
|
-
|
|
39322
|
+
neuronlayer projects discover
|
|
39323
|
+
|
|
39324
|
+
# Start HTTP API server (for tools without MCP support)
|
|
39325
|
+
neuronlayer serve --project /path/to/project
|
|
39326
|
+
neuronlayer serve --port 8080
|
|
39090
39327
|
|
|
39091
39328
|
For more information, visit: https://github.com/abhisavakar/neuronlayer
|
|
39092
39329
|
`);
|
|
@@ -39116,7 +39353,7 @@ function executeCLI(args) {
|
|
|
39116
39353
|
const path = args[2];
|
|
39117
39354
|
if (!path) {
|
|
39118
39355
|
console.error("Error: Project path required.");
|
|
39119
|
-
console.error("Usage:
|
|
39356
|
+
console.error("Usage: neuronlayer projects add <path>");
|
|
39120
39357
|
process.exit(1);
|
|
39121
39358
|
}
|
|
39122
39359
|
const result = addProject(path);
|
|
@@ -39128,7 +39365,7 @@ function executeCLI(args) {
|
|
|
39128
39365
|
const id = args[2];
|
|
39129
39366
|
if (!id) {
|
|
39130
39367
|
console.error("Error: Project ID required.");
|
|
39131
|
-
console.error("Usage:
|
|
39368
|
+
console.error("Usage: neuronlayer projects remove <id>");
|
|
39132
39369
|
process.exit(1);
|
|
39133
39370
|
}
|
|
39134
39371
|
const result = removeProject(id);
|
|
@@ -39140,7 +39377,7 @@ function executeCLI(args) {
|
|
|
39140
39377
|
const id = args[2];
|
|
39141
39378
|
if (!id) {
|
|
39142
39379
|
console.error("Error: Project ID required.");
|
|
39143
|
-
console.error("Usage:
|
|
39380
|
+
console.error("Usage: neuronlayer projects switch <id>");
|
|
39144
39381
|
process.exit(1);
|
|
39145
39382
|
}
|
|
39146
39383
|
const result = switchProject(id);
|
|
@@ -39191,6 +39428,22 @@ function executeCLI(args) {
|
|
|
39191
39428
|
}
|
|
39192
39429
|
|
|
39193
39430
|
// src/index.ts
|
|
39431
|
+
function parseServeArgs(args) {
|
|
39432
|
+
let projectPath = process.cwd();
|
|
39433
|
+
let port = 3333;
|
|
39434
|
+
for (let i = 0; i < args.length; i++) {
|
|
39435
|
+
const arg = args[i];
|
|
39436
|
+
const nextArg = args[i + 1];
|
|
39437
|
+
if ((arg === "--project" || arg === "-p") && nextArg) {
|
|
39438
|
+
projectPath = nextArg;
|
|
39439
|
+
i++;
|
|
39440
|
+
} else if (arg === "--port" && nextArg) {
|
|
39441
|
+
port = parseInt(nextArg) || 3333;
|
|
39442
|
+
i++;
|
|
39443
|
+
}
|
|
39444
|
+
}
|
|
39445
|
+
return { projectPath, port };
|
|
39446
|
+
}
|
|
39194
39447
|
async function main() {
|
|
39195
39448
|
const args = process.argv.slice(2);
|
|
39196
39449
|
const firstArg = args[0];
|
|
@@ -39199,21 +39452,38 @@ async function main() {
|
|
|
39199
39452
|
executeCLI(args);
|
|
39200
39453
|
return;
|
|
39201
39454
|
}
|
|
39455
|
+
if (firstArg === "serve") {
|
|
39456
|
+
const { projectPath: projectPath2, port } = parseServeArgs(args.slice(1));
|
|
39457
|
+
const config3 = getDefaultConfig(projectPath2);
|
|
39458
|
+
console.log("NeuronLayer HTTP API starting...");
|
|
39459
|
+
console.log(`Project: ${config3.projectPath}`);
|
|
39460
|
+
console.log(`Data directory: ${config3.dataDir}`);
|
|
39461
|
+
console.log("");
|
|
39462
|
+
const server2 = new HTTPServer(config3, port);
|
|
39463
|
+
try {
|
|
39464
|
+
await server2.start();
|
|
39465
|
+
} catch (error2) {
|
|
39466
|
+
console.error("Failed to start HTTP server:", error2);
|
|
39467
|
+
process.exit(1);
|
|
39468
|
+
}
|
|
39469
|
+
return;
|
|
39470
|
+
}
|
|
39202
39471
|
if (args.length === 0 && process.stdin.isTTY) {
|
|
39203
39472
|
printHelp();
|
|
39204
|
-
console.log("\nTo start as MCP server, use:
|
|
39473
|
+
console.log("\nTo start as MCP server, use: neuronlayer --project <path>");
|
|
39474
|
+
console.log("To start HTTP API, use: neuronlayer serve --project <path>\n");
|
|
39205
39475
|
return;
|
|
39206
39476
|
}
|
|
39207
39477
|
const { projectPath } = parseArgs(args);
|
|
39208
39478
|
const config2 = getDefaultConfig(projectPath);
|
|
39209
|
-
console.error("
|
|
39479
|
+
console.error("NeuronLayer starting...");
|
|
39210
39480
|
console.error(`Project: ${config2.projectPath}`);
|
|
39211
39481
|
console.error(`Data directory: ${config2.dataDir}`);
|
|
39212
39482
|
const server = new MCPServer(config2);
|
|
39213
39483
|
try {
|
|
39214
39484
|
await server.start();
|
|
39215
39485
|
} catch (error2) {
|
|
39216
|
-
console.error("Failed to start
|
|
39486
|
+
console.error("Failed to start NeuronLayer:", error2);
|
|
39217
39487
|
process.exit(1);
|
|
39218
39488
|
}
|
|
39219
39489
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neuronlayer",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.9",
|
|
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": {
|