gitnexus 1.3.9 → 1.3.11
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/README.md +194 -194
- package/dist/cli/ai-context.js +105 -87
- package/dist/cli/analyze.js +8 -0
- package/dist/cli/index.js +15 -25
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/setup.js +17 -19
- package/dist/core/augmentation/engine.js +20 -20
- package/dist/core/embeddings/embedding-pipeline.js +26 -26
- package/dist/core/ingestion/ast-cache.js +3 -2
- package/dist/core/ingestion/cluster-enricher.js +16 -16
- package/dist/core/ingestion/pipeline.js +23 -2
- package/dist/core/ingestion/tree-sitter-queries.js +484 -484
- package/dist/core/ingestion/workers/worker-pool.js +8 -0
- package/dist/core/kuzu/kuzu-adapter.js +11 -11
- package/dist/core/kuzu/schema.js +287 -287
- package/dist/core/search/bm25-index.js +7 -6
- package/dist/core/search/hybrid-search.js +3 -3
- package/dist/core/wiki/graph-queries.js +52 -52
- package/dist/core/wiki/html-viewer.js +192 -192
- package/dist/core/wiki/prompts.js +82 -82
- package/dist/mcp/compatible-stdio-transport.d.ts +25 -0
- package/dist/mcp/compatible-stdio-transport.js +200 -0
- package/dist/mcp/core/kuzu-adapter.js +6 -18
- package/dist/mcp/local/local-backend.js +128 -128
- package/dist/mcp/resources.js +42 -42
- package/dist/mcp/server.js +18 -18
- package/dist/mcp/tools.js +86 -86
- package/hooks/claude/gitnexus-hook.cjs +238 -155
- package/hooks/claude/pre-tool-use.sh +79 -79
- package/hooks/claude/session-start.sh +42 -42
- package/package.json +96 -96
- package/scripts/patch-tree-sitter-swift.cjs +74 -74
- package/skills/gitnexus-cli.md +82 -82
- package/skills/gitnexus-debugging.md +89 -89
- package/skills/gitnexus-exploring.md +78 -78
- package/skills/gitnexus-guide.md +64 -64
- package/skills/gitnexus-impact-analysis.md +97 -97
- package/skills/gitnexus-pr-review.md +163 -163
- package/skills/gitnexus-refactoring.md +121 -121
- package/vendor/leiden/index.cjs +355 -355
- package/vendor/leiden/utils.cjs +392 -392
|
@@ -5,98 +5,98 @@
|
|
|
5
5
|
* Templates use {{PLACEHOLDER}} substitution.
|
|
6
6
|
*/
|
|
7
7
|
// ─── Grouping Prompt ──────────────────────────────────────────────────
|
|
8
|
-
export const GROUPING_SYSTEM_PROMPT = `You are a documentation architect. Given a list of source files with their exported symbols, group them into logical documentation modules.
|
|
9
|
-
|
|
10
|
-
Rules:
|
|
11
|
-
- Each module should represent a cohesive feature, layer, or domain
|
|
12
|
-
- Every file must appear in exactly one module
|
|
13
|
-
- Module names should be human-readable (e.g. "Authentication", "Database Layer", "API Routes")
|
|
14
|
-
- Aim for 5-15 modules for a typical project. Fewer for small projects, more for large ones
|
|
15
|
-
- Group by functionality, not by file type or directory structure alone
|
|
8
|
+
export const GROUPING_SYSTEM_PROMPT = `You are a documentation architect. Given a list of source files with their exported symbols, group them into logical documentation modules.
|
|
9
|
+
|
|
10
|
+
Rules:
|
|
11
|
+
- Each module should represent a cohesive feature, layer, or domain
|
|
12
|
+
- Every file must appear in exactly one module
|
|
13
|
+
- Module names should be human-readable (e.g. "Authentication", "Database Layer", "API Routes")
|
|
14
|
+
- Aim for 5-15 modules for a typical project. Fewer for small projects, more for large ones
|
|
15
|
+
- Group by functionality, not by file type or directory structure alone
|
|
16
16
|
- Do NOT create modules for tests, configs, or non-source files`;
|
|
17
|
-
export const GROUPING_USER_PROMPT = `Group these source files into documentation modules.
|
|
18
|
-
|
|
19
|
-
**Files and their exports:**
|
|
20
|
-
{{FILE_LIST}}
|
|
21
|
-
|
|
22
|
-
**Directory structure:**
|
|
23
|
-
{{DIRECTORY_TREE}}
|
|
24
|
-
|
|
25
|
-
Respond with ONLY a JSON object mapping module names to file path arrays. No markdown, no explanation.
|
|
26
|
-
Example format:
|
|
27
|
-
{
|
|
28
|
-
"Authentication": ["src/auth/login.ts", "src/auth/session.ts"],
|
|
29
|
-
"Database": ["src/db/connection.ts", "src/db/models.ts"]
|
|
17
|
+
export const GROUPING_USER_PROMPT = `Group these source files into documentation modules.
|
|
18
|
+
|
|
19
|
+
**Files and their exports:**
|
|
20
|
+
{{FILE_LIST}}
|
|
21
|
+
|
|
22
|
+
**Directory structure:**
|
|
23
|
+
{{DIRECTORY_TREE}}
|
|
24
|
+
|
|
25
|
+
Respond with ONLY a JSON object mapping module names to file path arrays. No markdown, no explanation.
|
|
26
|
+
Example format:
|
|
27
|
+
{
|
|
28
|
+
"Authentication": ["src/auth/login.ts", "src/auth/session.ts"],
|
|
29
|
+
"Database": ["src/db/connection.ts", "src/db/models.ts"]
|
|
30
30
|
}`;
|
|
31
31
|
// ─── Leaf Module Prompt ───────────────────────────────────────────────
|
|
32
|
-
export const MODULE_SYSTEM_PROMPT = `You are a technical documentation writer. Write clear, developer-focused documentation for a code module.
|
|
33
|
-
|
|
34
|
-
Rules:
|
|
35
|
-
- Reference actual function names, class names, and code patterns — do NOT invent APIs
|
|
36
|
-
- Use the call graph and execution flow data for accuracy, but do NOT mechanically list every edge
|
|
37
|
-
- Include Mermaid diagrams only when they genuinely help understanding. Keep them small (5-10 nodes max)
|
|
38
|
-
- Structure the document however makes sense for this module — there is no mandatory format
|
|
32
|
+
export const MODULE_SYSTEM_PROMPT = `You are a technical documentation writer. Write clear, developer-focused documentation for a code module.
|
|
33
|
+
|
|
34
|
+
Rules:
|
|
35
|
+
- Reference actual function names, class names, and code patterns — do NOT invent APIs
|
|
36
|
+
- Use the call graph and execution flow data for accuracy, but do NOT mechanically list every edge
|
|
37
|
+
- Include Mermaid diagrams only when they genuinely help understanding. Keep them small (5-10 nodes max)
|
|
38
|
+
- Structure the document however makes sense for this module — there is no mandatory format
|
|
39
39
|
- Write for a developer who needs to understand and contribute to this code`;
|
|
40
|
-
export const MODULE_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module.
|
|
41
|
-
|
|
42
|
-
## Source Code
|
|
43
|
-
|
|
44
|
-
{{SOURCE_CODE}}
|
|
45
|
-
|
|
46
|
-
## Call Graph & Execution Flows (reference for accuracy)
|
|
47
|
-
|
|
48
|
-
Internal calls: {{INTRA_CALLS}}
|
|
49
|
-
Outgoing calls: {{OUTGOING_CALLS}}
|
|
50
|
-
Incoming calls: {{INCOMING_CALLS}}
|
|
51
|
-
Execution flows: {{PROCESSES}}
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
40
|
+
export const MODULE_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module.
|
|
41
|
+
|
|
42
|
+
## Source Code
|
|
43
|
+
|
|
44
|
+
{{SOURCE_CODE}}
|
|
45
|
+
|
|
46
|
+
## Call Graph & Execution Flows (reference for accuracy)
|
|
47
|
+
|
|
48
|
+
Internal calls: {{INTRA_CALLS}}
|
|
49
|
+
Outgoing calls: {{OUTGOING_CALLS}}
|
|
50
|
+
Incoming calls: {{INCOMING_CALLS}}
|
|
51
|
+
Execution flows: {{PROCESSES}}
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
55
|
Write comprehensive documentation for this module. Cover its purpose, how it works, its key components, and how it connects to the rest of the codebase. Use whatever structure best fits this module — you decide the sections and headings. Include a Mermaid diagram only if it genuinely clarifies the architecture.`;
|
|
56
56
|
// ─── Parent Module Prompt ─────────────────────────────────────────────
|
|
57
|
-
export const PARENT_SYSTEM_PROMPT = `You are a technical documentation writer. Write a summary page for a module that contains sub-modules. Synthesize the children's documentation — do not re-read source code.
|
|
58
|
-
|
|
59
|
-
Rules:
|
|
60
|
-
- Reference actual components from the child modules
|
|
61
|
-
- Focus on how the sub-modules work together, not repeating their individual docs
|
|
62
|
-
- Keep it concise — the reader can click through to child pages for detail
|
|
57
|
+
export const PARENT_SYSTEM_PROMPT = `You are a technical documentation writer. Write a summary page for a module that contains sub-modules. Synthesize the children's documentation — do not re-read source code.
|
|
58
|
+
|
|
59
|
+
Rules:
|
|
60
|
+
- Reference actual components from the child modules
|
|
61
|
+
- Focus on how the sub-modules work together, not repeating their individual docs
|
|
62
|
+
- Keep it concise — the reader can click through to child pages for detail
|
|
63
63
|
- Include a Mermaid diagram only if it genuinely clarifies how the sub-modules relate`;
|
|
64
|
-
export const PARENT_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module, which contains these sub-modules:
|
|
65
|
-
|
|
66
|
-
{{CHILDREN_DOCS}}
|
|
67
|
-
|
|
68
|
-
Cross-module calls: {{CROSS_MODULE_CALLS}}
|
|
69
|
-
Shared execution flows: {{CROSS_PROCESSES}}
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
64
|
+
export const PARENT_USER_PROMPT = `Write documentation for the **{{MODULE_NAME}}** module, which contains these sub-modules:
|
|
65
|
+
|
|
66
|
+
{{CHILDREN_DOCS}}
|
|
67
|
+
|
|
68
|
+
Cross-module calls: {{CROSS_MODULE_CALLS}}
|
|
69
|
+
Shared execution flows: {{CROSS_PROCESSES}}
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
73
|
Write a concise overview of this module group. Explain its purpose, how the sub-modules fit together, and the key workflows that span them. Link to sub-module pages (e.g. \`[Sub-module Name](sub-module-slug.md)\`) rather than repeating their content. Use whatever structure fits best.`;
|
|
74
74
|
// ─── Overview Prompt ──────────────────────────────────────────────────
|
|
75
|
-
export const OVERVIEW_SYSTEM_PROMPT = `You are a technical documentation writer. Write the top-level overview page for a repository wiki. This is the first page a new developer sees.
|
|
76
|
-
|
|
77
|
-
Rules:
|
|
78
|
-
- Be clear and welcoming — this is the entry point to the entire codebase
|
|
79
|
-
- Reference actual module names so readers can navigate to their docs
|
|
80
|
-
- Include a high-level Mermaid architecture diagram showing only the most important modules and their relationships (max 10 nodes). A new dev should grasp it in 10 seconds
|
|
81
|
-
- Do NOT create module index tables or list every module with descriptions — just link to module pages naturally within the text
|
|
75
|
+
export const OVERVIEW_SYSTEM_PROMPT = `You are a technical documentation writer. Write the top-level overview page for a repository wiki. This is the first page a new developer sees.
|
|
76
|
+
|
|
77
|
+
Rules:
|
|
78
|
+
- Be clear and welcoming — this is the entry point to the entire codebase
|
|
79
|
+
- Reference actual module names so readers can navigate to their docs
|
|
80
|
+
- Include a high-level Mermaid architecture diagram showing only the most important modules and their relationships (max 10 nodes). A new dev should grasp it in 10 seconds
|
|
81
|
+
- Do NOT create module index tables or list every module with descriptions — just link to module pages naturally within the text
|
|
82
82
|
- Use the inter-module edges and execution flow data for accuracy, but do NOT dump them raw`;
|
|
83
|
-
export const OVERVIEW_USER_PROMPT = `Write the overview page for this repository's wiki.
|
|
84
|
-
|
|
85
|
-
## Project Info
|
|
86
|
-
|
|
87
|
-
{{PROJECT_INFO}}
|
|
88
|
-
|
|
89
|
-
## Module Summaries
|
|
90
|
-
|
|
91
|
-
{{MODULE_SUMMARIES}}
|
|
92
|
-
|
|
93
|
-
## Reference Data (for accuracy — do not reproduce verbatim)
|
|
94
|
-
|
|
95
|
-
Inter-module call edges: {{MODULE_EDGES}}
|
|
96
|
-
Key system flows: {{TOP_PROCESSES}}
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
83
|
+
export const OVERVIEW_USER_PROMPT = `Write the overview page for this repository's wiki.
|
|
84
|
+
|
|
85
|
+
## Project Info
|
|
86
|
+
|
|
87
|
+
{{PROJECT_INFO}}
|
|
88
|
+
|
|
89
|
+
## Module Summaries
|
|
90
|
+
|
|
91
|
+
{{MODULE_SUMMARIES}}
|
|
92
|
+
|
|
93
|
+
## Reference Data (for accuracy — do not reproduce verbatim)
|
|
94
|
+
|
|
95
|
+
Inter-module call edges: {{MODULE_EDGES}}
|
|
96
|
+
Key system flows: {{TOP_PROCESSES}}
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
100
|
Write a clear overview of this project: what it does, how it's architected, and the key end-to-end flows. Include a simple Mermaid architecture diagram (max 10 nodes, big-picture only). Link to module pages (e.g. \`[Module Name](module-slug.md)\`) naturally in the text rather than listing them in a table. If project config was provided, include brief setup instructions. Structure the page however reads best.`;
|
|
101
101
|
// ─── Template Substitution Helper ─────────────────────────────────────
|
|
102
102
|
/**
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Transport, TransportSendOptions } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
2
|
+
import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
export type StdioFraming = 'content-length' | 'newline';
|
|
4
|
+
export declare class CompatibleStdioServerTransport implements Transport {
|
|
5
|
+
private readonly _stdin;
|
|
6
|
+
private readonly _stdout;
|
|
7
|
+
private _readBuffer;
|
|
8
|
+
private _started;
|
|
9
|
+
private _framing;
|
|
10
|
+
onmessage?: (message: JSONRPCMessage) => void;
|
|
11
|
+
onerror?: (error: Error) => void;
|
|
12
|
+
onclose?: () => void;
|
|
13
|
+
constructor(_stdin?: NodeJS.ReadableStream, _stdout?: NodeJS.WritableStream);
|
|
14
|
+
private readonly _ondata;
|
|
15
|
+
private readonly _onerror;
|
|
16
|
+
start(): Promise<void>;
|
|
17
|
+
private detectFraming;
|
|
18
|
+
private discardBufferedInput;
|
|
19
|
+
private readContentLengthMessage;
|
|
20
|
+
private readNewlineMessage;
|
|
21
|
+
private readMessage;
|
|
22
|
+
private processReadBuffer;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
function deserializeMessage(raw) {
|
|
4
|
+
return JSONRPCMessageSchema.parse(JSON.parse(raw));
|
|
5
|
+
}
|
|
6
|
+
function serializeNewlineMessage(message) {
|
|
7
|
+
return `${JSON.stringify(message)}\n`;
|
|
8
|
+
}
|
|
9
|
+
function serializeContentLengthMessage(message) {
|
|
10
|
+
const body = JSON.stringify(message);
|
|
11
|
+
return `Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n${body}`;
|
|
12
|
+
}
|
|
13
|
+
function findHeaderEnd(buffer) {
|
|
14
|
+
const crlfEnd = buffer.indexOf('\r\n\r\n');
|
|
15
|
+
if (crlfEnd !== -1) {
|
|
16
|
+
return { index: crlfEnd, separatorLength: 4 };
|
|
17
|
+
}
|
|
18
|
+
const lfEnd = buffer.indexOf('\n\n');
|
|
19
|
+
if (lfEnd !== -1) {
|
|
20
|
+
return { index: lfEnd, separatorLength: 2 };
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function looksLikeContentLength(buffer) {
|
|
25
|
+
if (buffer.length < 14) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const probe = buffer.toString('utf8', 0, Math.min(buffer.length, 32));
|
|
29
|
+
return /^content-length\s*:/i.test(probe);
|
|
30
|
+
}
|
|
31
|
+
const MAX_BUFFER_SIZE = 10 * 1024 * 1024; // 10 MB — generous for JSON-RPC
|
|
32
|
+
export class CompatibleStdioServerTransport {
|
|
33
|
+
_stdin;
|
|
34
|
+
_stdout;
|
|
35
|
+
_readBuffer;
|
|
36
|
+
_started = false;
|
|
37
|
+
_framing = null;
|
|
38
|
+
onmessage;
|
|
39
|
+
onerror;
|
|
40
|
+
onclose;
|
|
41
|
+
constructor(_stdin = process.stdin, _stdout = process.stdout) {
|
|
42
|
+
this._stdin = _stdin;
|
|
43
|
+
this._stdout = _stdout;
|
|
44
|
+
}
|
|
45
|
+
_ondata = (chunk) => {
|
|
46
|
+
this._readBuffer = this._readBuffer ? Buffer.concat([this._readBuffer, chunk]) : chunk;
|
|
47
|
+
if (this._readBuffer.length > MAX_BUFFER_SIZE) {
|
|
48
|
+
this.onerror?.(new Error(`Read buffer exceeded maximum size (${MAX_BUFFER_SIZE} bytes)`));
|
|
49
|
+
this.discardBufferedInput();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.processReadBuffer();
|
|
53
|
+
};
|
|
54
|
+
_onerror = (error) => {
|
|
55
|
+
this.onerror?.(error);
|
|
56
|
+
};
|
|
57
|
+
async start() {
|
|
58
|
+
if (this._started) {
|
|
59
|
+
throw new Error('CompatibleStdioServerTransport already started!');
|
|
60
|
+
}
|
|
61
|
+
this._started = true;
|
|
62
|
+
this._stdin.on('data', this._ondata);
|
|
63
|
+
this._stdin.on('error', this._onerror);
|
|
64
|
+
}
|
|
65
|
+
detectFraming() {
|
|
66
|
+
if (!this._readBuffer || this._readBuffer.length === 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
const firstByte = this._readBuffer[0];
|
|
70
|
+
if (firstByte === 0x7b || firstByte === 0x5b) {
|
|
71
|
+
return 'newline';
|
|
72
|
+
}
|
|
73
|
+
if (looksLikeContentLength(this._readBuffer)) {
|
|
74
|
+
return 'content-length';
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
discardBufferedInput() {
|
|
79
|
+
this._readBuffer = undefined;
|
|
80
|
+
this._framing = null;
|
|
81
|
+
}
|
|
82
|
+
readContentLengthMessage() {
|
|
83
|
+
if (!this._readBuffer) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
const header = findHeaderEnd(this._readBuffer);
|
|
87
|
+
if (header === null) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const headerText = this._readBuffer
|
|
91
|
+
.toString('utf8', 0, header.index)
|
|
92
|
+
.replace(/\r\n/g, '\n')
|
|
93
|
+
.replace(/\r/g, '\n');
|
|
94
|
+
const match = headerText.match(/(?:^|\n)content-length\s*:\s*(\d+)/i);
|
|
95
|
+
if (!match) {
|
|
96
|
+
this.discardBufferedInput();
|
|
97
|
+
throw new Error('Missing Content-Length header from MCP client');
|
|
98
|
+
}
|
|
99
|
+
const contentLength = Number.parseInt(match[1], 10);
|
|
100
|
+
if (!Number.isFinite(contentLength) || contentLength < 0) {
|
|
101
|
+
this.discardBufferedInput();
|
|
102
|
+
throw new Error('Invalid Content-Length header from MCP client');
|
|
103
|
+
}
|
|
104
|
+
if (contentLength > MAX_BUFFER_SIZE) {
|
|
105
|
+
this.discardBufferedInput();
|
|
106
|
+
throw new Error(`Content-Length ${contentLength} exceeds maximum allowed size (${MAX_BUFFER_SIZE} bytes)`);
|
|
107
|
+
}
|
|
108
|
+
const bodyStart = header.index + header.separatorLength;
|
|
109
|
+
const bodyEnd = bodyStart + contentLength;
|
|
110
|
+
if (this._readBuffer.length < bodyEnd) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const body = this._readBuffer.toString('utf8', bodyStart, bodyEnd);
|
|
114
|
+
this._readBuffer = this._readBuffer.subarray(bodyEnd);
|
|
115
|
+
return deserializeMessage(body);
|
|
116
|
+
}
|
|
117
|
+
readNewlineMessage() {
|
|
118
|
+
if (!this._readBuffer) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
while (true) {
|
|
122
|
+
const newlineIndex = this._readBuffer.indexOf('\n');
|
|
123
|
+
if (newlineIndex === -1) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const line = this._readBuffer.toString('utf8', 0, newlineIndex).replace(/\r$/, '');
|
|
127
|
+
this._readBuffer = this._readBuffer.subarray(newlineIndex + 1);
|
|
128
|
+
if (line.trim().length === 0) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
return deserializeMessage(line);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
readMessage() {
|
|
135
|
+
if (!this._readBuffer || this._readBuffer.length === 0) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
if (this._framing === null) {
|
|
139
|
+
this._framing = this.detectFraming();
|
|
140
|
+
if (this._framing === null) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return this._framing === 'content-length'
|
|
145
|
+
? this.readContentLengthMessage()
|
|
146
|
+
: this.readNewlineMessage();
|
|
147
|
+
}
|
|
148
|
+
processReadBuffer() {
|
|
149
|
+
while (true) {
|
|
150
|
+
try {
|
|
151
|
+
const message = this.readMessage();
|
|
152
|
+
if (message === null) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
this.onmessage?.(message);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
this.onerror?.(error);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async close() {
|
|
164
|
+
this._stdin.off('data', this._ondata);
|
|
165
|
+
this._stdin.off('error', this._onerror);
|
|
166
|
+
const remainingDataListeners = this._stdin.listenerCount('data');
|
|
167
|
+
if (remainingDataListeners === 0) {
|
|
168
|
+
this._stdin.pause();
|
|
169
|
+
}
|
|
170
|
+
this._started = false;
|
|
171
|
+
this._readBuffer = undefined;
|
|
172
|
+
this.onclose?.();
|
|
173
|
+
}
|
|
174
|
+
send(message, _options) {
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
if (!this._started) {
|
|
177
|
+
reject(new Error('Transport is closed'));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const payload = this._framing === 'newline'
|
|
181
|
+
? serializeNewlineMessage(message)
|
|
182
|
+
: serializeContentLengthMessage(message);
|
|
183
|
+
const onError = (error) => {
|
|
184
|
+
this._stdout.removeListener('error', onError);
|
|
185
|
+
reject(error);
|
|
186
|
+
};
|
|
187
|
+
this._stdout.on('error', onError);
|
|
188
|
+
if (this._stdout.write(payload)) {
|
|
189
|
+
this._stdout.removeListener('error', onError);
|
|
190
|
+
resolve();
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this._stdout.once('drain', () => {
|
|
194
|
+
this._stdout.removeListener('error', onError);
|
|
195
|
+
resolve();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -64,26 +64,14 @@ function evictLRU() {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
67
|
+
* Remove a repo from the pool without calling native close methods.
|
|
68
|
+
*
|
|
69
|
+
* KuzuDB's native .closeSync() triggers N-API destructor hooks that
|
|
70
|
+
* segfault on Linux/macOS. Pool databases are opened read-only, so
|
|
71
|
+
* there is no WAL to flush — just deleting the pool entry and letting
|
|
72
|
+
* the GC (or process exit) reclaim native resources is safe.
|
|
68
73
|
*/
|
|
69
74
|
function closeOne(repoId) {
|
|
70
|
-
const entry = pool.get(repoId);
|
|
71
|
-
if (!entry)
|
|
72
|
-
return;
|
|
73
|
-
for (const conn of entry.available) {
|
|
74
|
-
try {
|
|
75
|
-
conn.close();
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
console.error('GitNexus [pool:close-conn]:', e instanceof Error ? e.message : e);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
entry.db.close();
|
|
83
|
-
}
|
|
84
|
-
catch (e) {
|
|
85
|
-
console.error('GitNexus [pool:close-db]:', e instanceof Error ? e.message : e);
|
|
86
|
-
}
|
|
87
75
|
pool.delete(repoId);
|
|
88
76
|
}
|
|
89
77
|
/**
|