gitnexus-mcp 0.1.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.
- package/dist/bridge/daemon-client.d.ts +77 -0
- package/dist/bridge/daemon-client.d.ts.map +1 -0
- package/dist/bridge/daemon-client.js +135 -0
- package/dist/bridge/daemon-client.js.map +1 -0
- package/dist/bridge/protocol.d.ts +28 -0
- package/dist/bridge/protocol.d.ts.map +1 -0
- package/dist/bridge/protocol.js +18 -0
- package/dist/bridge/protocol.js.map +1 -0
- package/dist/bridge/websocket-server.d.ts +85 -0
- package/dist/bridge/websocket-server.d.ts.map +1 -0
- package/dist/bridge/websocket-server.js +180 -0
- package/dist/bridge/websocket-server.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +56 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/daemon.d.ts +37 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +173 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/generate-guidance.d.ts +13 -0
- package/dist/commands/generate-guidance.d.ts.map +1 -0
- package/dist/commands/generate-guidance.js +140 -0
- package/dist/commands/generate-guidance.js.map +1 -0
- package/dist/commands/serve.d.ts +13 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +23 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/setup.d.ts +8 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +48 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/config/detect-ides.d.ts +12 -0
- package/dist/config/detect-ides.d.ts.map +1 -0
- package/dist/config/detect-ides.js +81 -0
- package/dist/config/detect-ides.js.map +1 -0
- package/dist/config/inject-config.d.ts +9 -0
- package/dist/config/inject-config.d.ts.map +1 -0
- package/dist/config/inject-config.js +65 -0
- package/dist/config/inject-config.js.map +1 -0
- package/dist/config/paths.d.ts +16 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +32 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/mcp/server.d.ts +21 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +183 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +24 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +166 -0
- package/dist/mcp/tools.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Client
|
|
3
|
+
*
|
|
4
|
+
* WebSocket client that connects to the GitNexus daemon.
|
|
5
|
+
* Used by `serve` command to route tool calls through the daemon to the browser.
|
|
6
|
+
* Also receives codebase context for MCP resource exposure.
|
|
7
|
+
*/
|
|
8
|
+
export interface BridgeMessage {
|
|
9
|
+
id: string;
|
|
10
|
+
method?: string;
|
|
11
|
+
params?: any;
|
|
12
|
+
result?: any;
|
|
13
|
+
error?: {
|
|
14
|
+
message: string;
|
|
15
|
+
};
|
|
16
|
+
type?: string;
|
|
17
|
+
context?: CodebaseContext;
|
|
18
|
+
agentName?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Codebase context from browser
|
|
22
|
+
*/
|
|
23
|
+
export interface CodebaseContext {
|
|
24
|
+
projectName: string;
|
|
25
|
+
stats: {
|
|
26
|
+
fileCount: number;
|
|
27
|
+
functionCount: number;
|
|
28
|
+
classCount: number;
|
|
29
|
+
interfaceCount: number;
|
|
30
|
+
methodCount: number;
|
|
31
|
+
};
|
|
32
|
+
hotspots: Array<{
|
|
33
|
+
name: string;
|
|
34
|
+
type: string;
|
|
35
|
+
filePath: string;
|
|
36
|
+
connections: number;
|
|
37
|
+
}>;
|
|
38
|
+
folderTree: string;
|
|
39
|
+
}
|
|
40
|
+
export declare class DaemonClient {
|
|
41
|
+
private port;
|
|
42
|
+
private ws;
|
|
43
|
+
private pendingRequests;
|
|
44
|
+
private requestId;
|
|
45
|
+
private _context;
|
|
46
|
+
private contextListeners;
|
|
47
|
+
private agentName;
|
|
48
|
+
constructor(port?: number, agentName?: string);
|
|
49
|
+
private detectAgent;
|
|
50
|
+
/**
|
|
51
|
+
* Connect to the daemon
|
|
52
|
+
*/
|
|
53
|
+
connect(): Promise<void>;
|
|
54
|
+
private handleMessage;
|
|
55
|
+
/**
|
|
56
|
+
* Get current codebase context
|
|
57
|
+
*/
|
|
58
|
+
get context(): CodebaseContext | null;
|
|
59
|
+
/**
|
|
60
|
+
* Listen for context changes
|
|
61
|
+
*/
|
|
62
|
+
onContextChange(listener: (context: CodebaseContext | null) => void): () => boolean;
|
|
63
|
+
private notifyContextListeners;
|
|
64
|
+
/**
|
|
65
|
+
* Check if connected to daemon
|
|
66
|
+
*/
|
|
67
|
+
get isConnected(): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Call a tool (routed through daemon to browser)
|
|
70
|
+
*/
|
|
71
|
+
callTool(method: string, params: any): Promise<any>;
|
|
72
|
+
/**
|
|
73
|
+
* Disconnect from daemon
|
|
74
|
+
*/
|
|
75
|
+
disconnect(): void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=daemon-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-client.d.ts","sourceRoot":"","sources":["../../src/bridge/daemon-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,qBAAa,YAAY;IAQX,OAAO,CAAC,IAAI;IAPxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,eAAe,CAA2C;IAClE,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,gBAAgB,CAA6D;IACrF,OAAO,CAAC,SAAS,CAAS;gBAEN,IAAI,GAAE,MAAc,EAAE,SAAS,CAAC,EAAE,MAAM;IAK5D,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAkC9B,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,IAAI,OAAO,IAAI,eAAe,GAAG,IAAI,CAEpC;IAED;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI;IAKnE,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAuBzD;;OAEG;IACH,UAAU;CAIX"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Client
|
|
3
|
+
*
|
|
4
|
+
* WebSocket client that connects to the GitNexus daemon.
|
|
5
|
+
* Used by `serve` command to route tool calls through the daemon to the browser.
|
|
6
|
+
* Also receives codebase context for MCP resource exposure.
|
|
7
|
+
*/
|
|
8
|
+
import WebSocket from 'ws';
|
|
9
|
+
export class DaemonClient {
|
|
10
|
+
port;
|
|
11
|
+
ws = null;
|
|
12
|
+
pendingRequests = new Map();
|
|
13
|
+
requestId = 0;
|
|
14
|
+
_context = null;
|
|
15
|
+
contextListeners = new Set();
|
|
16
|
+
agentName;
|
|
17
|
+
constructor(port = 54319, agentName) {
|
|
18
|
+
this.port = port;
|
|
19
|
+
// Detect agent from environment or use provided name
|
|
20
|
+
this.agentName = agentName || process.env.GITNEXUS_AGENT || this.detectAgent();
|
|
21
|
+
}
|
|
22
|
+
detectAgent() {
|
|
23
|
+
// Try to detect agent from environment clues
|
|
24
|
+
if (process.env.CURSOR_SESSION_ID)
|
|
25
|
+
return 'Cursor';
|
|
26
|
+
if (process.env.CLAUDE_CODE)
|
|
27
|
+
return 'Claude Code';
|
|
28
|
+
if (process.env.WINDSURF_SESSION)
|
|
29
|
+
return 'Windsurf';
|
|
30
|
+
return 'Unknown';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Connect to the daemon
|
|
34
|
+
*/
|
|
35
|
+
async connect() {
|
|
36
|
+
return new Promise((resolve, reject) => {
|
|
37
|
+
// Connect to /mcp path so daemon knows this is an MCP client
|
|
38
|
+
this.ws = new WebSocket(`ws://localhost:${this.port}/mcp`);
|
|
39
|
+
this.ws.on('open', () => {
|
|
40
|
+
resolve();
|
|
41
|
+
});
|
|
42
|
+
this.ws.on('error', (error) => {
|
|
43
|
+
reject(error);
|
|
44
|
+
});
|
|
45
|
+
this.ws.on('message', (data) => {
|
|
46
|
+
try {
|
|
47
|
+
const msg = JSON.parse(data.toString());
|
|
48
|
+
this.handleMessage(msg);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
console.error('Failed to parse message:', error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.ws.on('close', () => {
|
|
55
|
+
this.ws = null;
|
|
56
|
+
this._context = null;
|
|
57
|
+
// Reject all pending requests
|
|
58
|
+
for (const { reject } of this.pendingRequests.values()) {
|
|
59
|
+
reject(new Error('Connection closed'));
|
|
60
|
+
}
|
|
61
|
+
this.pendingRequests.clear();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
handleMessage(msg) {
|
|
66
|
+
// Handle context update from daemon
|
|
67
|
+
if (msg.type === 'context_update' && msg.context) {
|
|
68
|
+
this._context = msg.context;
|
|
69
|
+
this.notifyContextListeners();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Response from daemon (originally from browser)
|
|
73
|
+
if (msg.id && this.pendingRequests.has(msg.id)) {
|
|
74
|
+
const { resolve, reject } = this.pendingRequests.get(msg.id);
|
|
75
|
+
this.pendingRequests.delete(msg.id);
|
|
76
|
+
if (msg.error) {
|
|
77
|
+
reject(new Error(msg.error.message));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
resolve(msg.result);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get current codebase context
|
|
86
|
+
*/
|
|
87
|
+
get context() {
|
|
88
|
+
return this._context;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Listen for context changes
|
|
92
|
+
*/
|
|
93
|
+
onContextChange(listener) {
|
|
94
|
+
this.contextListeners.add(listener);
|
|
95
|
+
return () => this.contextListeners.delete(listener);
|
|
96
|
+
}
|
|
97
|
+
notifyContextListeners() {
|
|
98
|
+
this.contextListeners.forEach(listener => listener(this._context));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if connected to daemon
|
|
102
|
+
*/
|
|
103
|
+
get isConnected() {
|
|
104
|
+
return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Call a tool (routed through daemon to browser)
|
|
108
|
+
*/
|
|
109
|
+
async callTool(method, params) {
|
|
110
|
+
if (!this.isConnected) {
|
|
111
|
+
throw new Error('Not connected to daemon');
|
|
112
|
+
}
|
|
113
|
+
const id = `req_${++this.requestId}`;
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
116
|
+
const msg = { id, method, params, agentName: this.agentName };
|
|
117
|
+
this.ws.send(JSON.stringify(msg));
|
|
118
|
+
// Timeout after 30 seconds
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
if (this.pendingRequests.has(id)) {
|
|
121
|
+
this.pendingRequests.delete(id);
|
|
122
|
+
reject(new Error('Request timeout'));
|
|
123
|
+
}
|
|
124
|
+
}, 30000);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Disconnect from daemon
|
|
129
|
+
*/
|
|
130
|
+
disconnect() {
|
|
131
|
+
this.ws?.close();
|
|
132
|
+
this.ws = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=daemon-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-client.js","sourceRoot":"","sources":["../../src/bridge/daemon-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Protocol Types
|
|
3
|
+
*
|
|
4
|
+
* JSON-RPC-like protocol for communication between bridge and browser.
|
|
5
|
+
*/
|
|
6
|
+
export interface ToolCallRequest {
|
|
7
|
+
id: string;
|
|
8
|
+
method: string;
|
|
9
|
+
params: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
export interface ToolCallResponse {
|
|
12
|
+
id: string;
|
|
13
|
+
result?: any;
|
|
14
|
+
error?: {
|
|
15
|
+
code?: number;
|
|
16
|
+
message: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export type BridgeMessage = ToolCallRequest | ToolCallResponse;
|
|
20
|
+
/**
|
|
21
|
+
* Check if message is a request (has method)
|
|
22
|
+
*/
|
|
23
|
+
export declare function isRequest(msg: BridgeMessage): msg is ToolCallRequest;
|
|
24
|
+
/**
|
|
25
|
+
* Check if message is a response (has result or error)
|
|
26
|
+
*/
|
|
27
|
+
export declare function isResponse(msg: BridgeMessage): msg is ToolCallResponse;
|
|
28
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/bridge/protocol.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAE/D;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,GAAG,IAAI,eAAe,CAEpE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,aAAa,GAAG,GAAG,IAAI,gBAAgB,CAEtE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge Protocol Types
|
|
3
|
+
*
|
|
4
|
+
* JSON-RPC-like protocol for communication between bridge and browser.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Check if message is a request (has method)
|
|
8
|
+
*/
|
|
9
|
+
export function isRequest(msg) {
|
|
10
|
+
return 'method' in msg;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Check if message is a response (has result or error)
|
|
14
|
+
*/
|
|
15
|
+
export function isResponse(msg) {
|
|
16
|
+
return 'result' in msg || 'error' in msg;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../src/bridge/protocol.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAkB;IAC1C,OAAO,QAAQ,IAAI,GAAG,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,GAAkB;IAC3C,OAAO,QAAQ,IAAI,GAAG,IAAI,OAAO,IAAI,GAAG,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Bridge
|
|
3
|
+
*
|
|
4
|
+
* WebSocket server that connects to the GitNexus browser tab.
|
|
5
|
+
* Relays tool calls from MCP server to browser and returns results.
|
|
6
|
+
*/
|
|
7
|
+
export interface BridgeMessage {
|
|
8
|
+
id: string;
|
|
9
|
+
method?: string;
|
|
10
|
+
params?: any;
|
|
11
|
+
result?: any;
|
|
12
|
+
error?: {
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
15
|
+
type?: 'context' | string;
|
|
16
|
+
agentName?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Codebase context sent from the GitNexus browser app
|
|
20
|
+
*/
|
|
21
|
+
export interface CodebaseContext {
|
|
22
|
+
projectName: string;
|
|
23
|
+
stats: {
|
|
24
|
+
fileCount: number;
|
|
25
|
+
functionCount: number;
|
|
26
|
+
classCount: number;
|
|
27
|
+
interfaceCount: number;
|
|
28
|
+
methodCount: number;
|
|
29
|
+
};
|
|
30
|
+
hotspots: Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
type: string;
|
|
33
|
+
filePath: string;
|
|
34
|
+
connections: number;
|
|
35
|
+
}>;
|
|
36
|
+
folderTree: string;
|
|
37
|
+
}
|
|
38
|
+
export declare class WebSocketBridge {
|
|
39
|
+
private port;
|
|
40
|
+
private wss;
|
|
41
|
+
private client;
|
|
42
|
+
private pendingRequests;
|
|
43
|
+
private requestId;
|
|
44
|
+
private started;
|
|
45
|
+
private _context;
|
|
46
|
+
private contextListeners;
|
|
47
|
+
private agentName;
|
|
48
|
+
constructor(port?: number, agentName?: string);
|
|
49
|
+
private detectAgent;
|
|
50
|
+
/**
|
|
51
|
+
* Start the WebSocket server (handles port-in-use gracefully)
|
|
52
|
+
*/
|
|
53
|
+
start(): Promise<boolean>;
|
|
54
|
+
private handleMessage;
|
|
55
|
+
/**
|
|
56
|
+
* Check if browser is connected
|
|
57
|
+
*/
|
|
58
|
+
get isConnected(): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Latest context received from browser (if any)
|
|
61
|
+
*/
|
|
62
|
+
get context(): CodebaseContext | null;
|
|
63
|
+
/**
|
|
64
|
+
* Listen for context changes
|
|
65
|
+
*/
|
|
66
|
+
onContextChange(listener: (context: CodebaseContext | null) => void): () => boolean;
|
|
67
|
+
private notifyContextListeners;
|
|
68
|
+
/**
|
|
69
|
+
* Check if server started successfully
|
|
70
|
+
*/
|
|
71
|
+
get isStarted(): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Call a tool in the browser
|
|
74
|
+
*/
|
|
75
|
+
callTool(method: string, params: any): Promise<any>;
|
|
76
|
+
/**
|
|
77
|
+
* Close the WebSocket server
|
|
78
|
+
*/
|
|
79
|
+
close(): void;
|
|
80
|
+
/**
|
|
81
|
+
* MCP server calls this on shutdown
|
|
82
|
+
*/
|
|
83
|
+
disconnect(): void;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=websocket-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/bridge/websocket-server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAsBD,qBAAa,eAAe;IAUd,OAAO,CAAC,IAAI;IATxB,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,eAAe,CAA2C;IAClE,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,gBAAgB,CAA6D;IACrF,OAAO,CAAC,SAAS,CAAS;gBAEN,IAAI,GAAE,MAAc,EAAE,SAAS,CAAC,EAAE,MAAM;IAI5D,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAyD/B,OAAO,CAAC,aAAa;IAqBrB;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,eAAe,GAAG,IAAI,CAEpC;IAED;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI;IAKnE,OAAO,CAAC,sBAAsB;IAI9B;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IAuBzD;;OAEG;IACH,KAAK;IAIL;;OAEG;IACH,UAAU;CAGX"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Bridge
|
|
3
|
+
*
|
|
4
|
+
* WebSocket server that connects to the GitNexus browser tab.
|
|
5
|
+
* Relays tool calls from MCP server to browser and returns results.
|
|
6
|
+
*/
|
|
7
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
8
|
+
import { createServer as createNetServer } from 'net';
|
|
9
|
+
/**
|
|
10
|
+
* Check if a port is available
|
|
11
|
+
*/
|
|
12
|
+
async function isPortAvailable(port) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
const server = createNetServer();
|
|
15
|
+
server.once('error', () => resolve(false));
|
|
16
|
+
server.once('listening', () => {
|
|
17
|
+
server.close();
|
|
18
|
+
resolve(true);
|
|
19
|
+
});
|
|
20
|
+
server.listen(port);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export class WebSocketBridge {
|
|
24
|
+
port;
|
|
25
|
+
wss = null;
|
|
26
|
+
client = null;
|
|
27
|
+
pendingRequests = new Map();
|
|
28
|
+
requestId = 0;
|
|
29
|
+
started = false;
|
|
30
|
+
_context = null;
|
|
31
|
+
contextListeners = new Set();
|
|
32
|
+
agentName;
|
|
33
|
+
constructor(port = 54319, agentName) {
|
|
34
|
+
this.port = port;
|
|
35
|
+
this.agentName = agentName || process.env.GITNEXUS_AGENT || this.detectAgent();
|
|
36
|
+
}
|
|
37
|
+
detectAgent() {
|
|
38
|
+
// Try to detect agent from environment clues
|
|
39
|
+
if (process.env.CURSOR_SESSION_ID)
|
|
40
|
+
return 'Cursor';
|
|
41
|
+
if (process.env.CLAUDE_CODE)
|
|
42
|
+
return 'Claude Code';
|
|
43
|
+
if (process.env.WINDSURF_SESSION)
|
|
44
|
+
return 'Windsurf';
|
|
45
|
+
return 'Unknown';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Start the WebSocket server (handles port-in-use gracefully)
|
|
49
|
+
*/
|
|
50
|
+
async start() {
|
|
51
|
+
const available = await isPortAvailable(this.port);
|
|
52
|
+
if (!available) {
|
|
53
|
+
// Port already in use - another instance is handling browser connections
|
|
54
|
+
// This is OK - we can still run MCP server for stdio communication
|
|
55
|
+
console.error(`Port ${this.port} in use. Browser bridge running elsewhere.`);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
this.wss = new WebSocketServer({ port: this.port });
|
|
60
|
+
this.wss.on('connection', (ws) => {
|
|
61
|
+
// Only allow one browser connection at a time
|
|
62
|
+
if (this.client) {
|
|
63
|
+
this.client.close();
|
|
64
|
+
}
|
|
65
|
+
this.client = ws;
|
|
66
|
+
// Clear context until browser sends an update
|
|
67
|
+
this._context = null;
|
|
68
|
+
this.notifyContextListeners();
|
|
69
|
+
ws.on('message', (data) => {
|
|
70
|
+
try {
|
|
71
|
+
const msg = JSON.parse(data.toString());
|
|
72
|
+
this.handleMessage(msg);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.error('Failed to parse message:', error);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
ws.on('close', () => {
|
|
79
|
+
if (this.client === ws) {
|
|
80
|
+
this.client = null;
|
|
81
|
+
this._context = null;
|
|
82
|
+
this.notifyContextListeners();
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
ws.on('error', (error) => {
|
|
86
|
+
console.error('WebSocket error:', error);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
this.wss.on('listening', () => {
|
|
90
|
+
this.started = true;
|
|
91
|
+
resolve(true);
|
|
92
|
+
});
|
|
93
|
+
this.wss.on('error', (error) => {
|
|
94
|
+
console.error('WebSocket server error:', error);
|
|
95
|
+
resolve(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
handleMessage(msg) {
|
|
100
|
+
// Browser can proactively send codebase context
|
|
101
|
+
if (msg.type === 'context' && msg.params) {
|
|
102
|
+
this._context = msg.params;
|
|
103
|
+
this.notifyContextListeners();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// This is a response to a pending request
|
|
107
|
+
if (msg.id && this.pendingRequests.has(msg.id)) {
|
|
108
|
+
const { resolve, reject } = this.pendingRequests.get(msg.id);
|
|
109
|
+
this.pendingRequests.delete(msg.id);
|
|
110
|
+
if (msg.error) {
|
|
111
|
+
reject(new Error(msg.error.message));
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
resolve(msg.result);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Check if browser is connected
|
|
120
|
+
*/
|
|
121
|
+
get isConnected() {
|
|
122
|
+
return this.client !== null && this.client.readyState === WebSocket.OPEN;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Latest context received from browser (if any)
|
|
126
|
+
*/
|
|
127
|
+
get context() {
|
|
128
|
+
return this._context;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Listen for context changes
|
|
132
|
+
*/
|
|
133
|
+
onContextChange(listener) {
|
|
134
|
+
this.contextListeners.add(listener);
|
|
135
|
+
return () => this.contextListeners.delete(listener);
|
|
136
|
+
}
|
|
137
|
+
notifyContextListeners() {
|
|
138
|
+
this.contextListeners.forEach((listener) => listener(this._context));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Check if server started successfully
|
|
142
|
+
*/
|
|
143
|
+
get isStarted() {
|
|
144
|
+
return this.started;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Call a tool in the browser
|
|
148
|
+
*/
|
|
149
|
+
async callTool(method, params) {
|
|
150
|
+
if (!this.isConnected) {
|
|
151
|
+
throw new Error('GitNexus browser not connected. Open GitNexus and enable MCP toggle.');
|
|
152
|
+
}
|
|
153
|
+
const id = `req_${++this.requestId}`;
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
156
|
+
const msg = { id, method, params, agentName: this.agentName };
|
|
157
|
+
this.client.send(JSON.stringify(msg));
|
|
158
|
+
// Timeout after 30 seconds
|
|
159
|
+
setTimeout(() => {
|
|
160
|
+
if (this.pendingRequests.has(id)) {
|
|
161
|
+
this.pendingRequests.delete(id);
|
|
162
|
+
reject(new Error('Request timeout'));
|
|
163
|
+
}
|
|
164
|
+
}, 30000);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Close the WebSocket server
|
|
169
|
+
*/
|
|
170
|
+
close() {
|
|
171
|
+
this.wss?.close();
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* MCP server calls this on shutdown
|
|
175
|
+
*/
|
|
176
|
+
disconnect() {
|
|
177
|
+
this.close();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=websocket-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-server.js","sourceRoot":"","sources":["../../src/bridge/websocket-server.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GitNexus MCP CLI
|
|
4
|
+
*
|
|
5
|
+
* Bridge between external AI agents (Cursor, Claude Code, Windsurf)
|
|
6
|
+
* and GitNexus code intelligence running in the browser.
|
|
7
|
+
*/
|
|
8
|
+
import { serveCommand } from './commands/serve.js';
|
|
9
|
+
/**
|
|
10
|
+
* Minimal CLI:
|
|
11
|
+
* - Default: start MCP stdio server + local browser WebSocket bridge
|
|
12
|
+
* - Optional: `serve` alias, and `--port <port>`
|
|
13
|
+
*
|
|
14
|
+
* This is designed for MCP clients (Cursor/Claude/Windsurf) which spawn this
|
|
15
|
+
* process automatically; users should not need to run commands manually.
|
|
16
|
+
*/
|
|
17
|
+
function parsePort(argv) {
|
|
18
|
+
const portFlagIndex = argv.findIndex((a) => a === '--port' || a === '-p');
|
|
19
|
+
if (portFlagIndex !== -1) {
|
|
20
|
+
const value = argv[portFlagIndex + 1];
|
|
21
|
+
if (value)
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
// Support `--port=54319`
|
|
25
|
+
const portEq = argv.find((a) => a.startsWith('--port='));
|
|
26
|
+
if (portEq)
|
|
27
|
+
return portEq.split('=')[1] || '54319';
|
|
28
|
+
return '54319';
|
|
29
|
+
}
|
|
30
|
+
async function main() {
|
|
31
|
+
const argv = process.argv.slice(2);
|
|
32
|
+
const first = argv[0];
|
|
33
|
+
const port = parsePort(argv);
|
|
34
|
+
// Allow `gitnexus-mcp serve` for compatibility, but default to serve anyway
|
|
35
|
+
if (!first || first === 'serve') {
|
|
36
|
+
await serveCommand({ port });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Minimal help for unknown commands
|
|
40
|
+
if (first === '--help' || first === '-h') {
|
|
41
|
+
// eslint-disable-next-line no-console
|
|
42
|
+
console.log('gitnexus-mcp\n\nUsage:\n gitnexus-mcp [serve] [--port <port>]\n');
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
// eslint-disable-next-line no-console
|
|
46
|
+
console.error(`Unknown command: ${first}`);
|
|
47
|
+
// eslint-disable-next-line no-console
|
|
48
|
+
console.error('Usage: gitnexus-mcp [serve] [--port <port>]');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
main().catch((err) => {
|
|
52
|
+
// eslint-disable-next-line no-console
|
|
53
|
+
console.error(err instanceof Error ? err.message : err);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD;;;;;;;GAOG;AAEH,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAC1E,IAAI,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;IAC1B,CAAC;IACD,yBAAyB;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IACzD,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IACnD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAE7B,4EAA4E;IAC5E,IAAI,CAAC,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QAChC,MAAM,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7B,OAAO;IACT,CAAC;IAED,oCAAoC;IACpC,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACzC,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,oBAAoB,KAAK,EAAE,CAAC,CAAC;IAC3C,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon Command
|
|
3
|
+
*
|
|
4
|
+
* Runs a persistent daemon that acts as the central hub for:
|
|
5
|
+
* - Browser connections (GitNexus web app)
|
|
6
|
+
* - MCP server connections (from AI tools like Cursor, Antigravity)
|
|
7
|
+
*
|
|
8
|
+
* This allows multiple AI tools to share the same browser bridge.
|
|
9
|
+
* Also stores codebase context sent by the browser for MCP resource exposure.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Codebase context sent from browser
|
|
13
|
+
*/
|
|
14
|
+
interface CodebaseContext {
|
|
15
|
+
projectName: string;
|
|
16
|
+
stats: {
|
|
17
|
+
fileCount: number;
|
|
18
|
+
functionCount: number;
|
|
19
|
+
classCount: number;
|
|
20
|
+
interfaceCount: number;
|
|
21
|
+
methodCount: number;
|
|
22
|
+
};
|
|
23
|
+
hotspots: Array<{
|
|
24
|
+
name: string;
|
|
25
|
+
type: string;
|
|
26
|
+
filePath: string;
|
|
27
|
+
connections: number;
|
|
28
|
+
}>;
|
|
29
|
+
folderTree: string;
|
|
30
|
+
}
|
|
31
|
+
interface DaemonOptions {
|
|
32
|
+
port: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function getCodebaseContext(): CodebaseContext | null;
|
|
35
|
+
export declare function daemonCommand(options: DaemonOptions): Promise<void>;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=daemon.d.ts.map
|