@veewo/gitnexus 1.3.11 → 1.4.6-rc
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 +37 -80
- package/dist/benchmark/agent-context/tool-runner.js +2 -2
- package/dist/benchmark/neonspark-candidates.js +3 -3
- package/dist/benchmark/tool-runner.js +2 -2
- package/dist/cli/ai-context.d.ts +2 -1
- package/dist/cli/ai-context.js +16 -12
- package/dist/cli/analyze.d.ts +2 -0
- package/dist/cli/analyze.js +68 -48
- package/dist/cli/augment.js +1 -1
- package/dist/cli/eval-server.d.ts +8 -1
- package/dist/cli/eval-server.js +30 -13
- package/dist/cli/index.js +28 -82
- package/dist/cli/lazy-action.d.ts +6 -0
- package/dist/cli/lazy-action.js +18 -0
- package/dist/cli/mcp.js +3 -1
- package/dist/cli/setup.js +87 -48
- package/dist/cli/setup.test.js +18 -13
- package/dist/cli/skill-gen.d.ts +26 -0
- package/dist/cli/skill-gen.js +549 -0
- package/dist/cli/status.js +13 -4
- package/dist/cli/tool.d.ts +3 -2
- package/dist/cli/tool.js +50 -16
- package/dist/cli/wiki.js +8 -4
- package/dist/config/ignore-service.d.ts +25 -0
- package/dist/config/ignore-service.js +76 -0
- package/dist/config/supported-languages.d.ts +4 -1
- package/dist/config/supported-languages.js +3 -2
- package/dist/core/augmentation/engine.js +94 -67
- package/dist/core/embeddings/embedder.d.ts +1 -1
- package/dist/core/embeddings/embedder.js +1 -1
- package/dist/core/embeddings/embedding-pipeline.d.ts +3 -3
- package/dist/core/embeddings/embedding-pipeline.js +52 -25
- package/dist/core/embeddings/types.d.ts +1 -1
- package/dist/core/graph/types.d.ts +7 -2
- package/dist/core/ingestion/ast-cache.js +3 -2
- package/dist/core/ingestion/call-processor.d.ts +8 -6
- package/dist/core/ingestion/call-processor.js +468 -206
- package/dist/core/ingestion/call-routing.d.ts +53 -0
- package/dist/core/ingestion/call-routing.js +108 -0
- package/dist/core/ingestion/constants.d.ts +16 -0
- package/dist/core/ingestion/constants.js +16 -0
- package/dist/core/ingestion/entry-point-scoring.d.ts +2 -1
- package/dist/core/ingestion/entry-point-scoring.js +116 -23
- package/dist/core/ingestion/export-detection.d.ts +18 -0
- package/dist/core/ingestion/export-detection.js +231 -0
- package/dist/core/ingestion/filesystem-walker.js +4 -3
- package/dist/core/ingestion/framework-detection.d.ts +19 -4
- package/dist/core/ingestion/framework-detection.js +182 -6
- package/dist/core/ingestion/heritage-processor.d.ts +13 -5
- package/dist/core/ingestion/heritage-processor.js +109 -55
- package/dist/core/ingestion/import-processor.d.ts +16 -20
- package/dist/core/ingestion/import-processor.js +199 -579
- package/dist/core/ingestion/language-config.d.ts +46 -0
- package/dist/core/ingestion/language-config.js +167 -0
- package/dist/core/ingestion/mro-processor.d.ts +45 -0
- package/dist/core/ingestion/mro-processor.js +369 -0
- package/dist/core/ingestion/named-binding-extraction.d.ts +61 -0
- package/dist/core/ingestion/named-binding-extraction.js +363 -0
- package/dist/core/ingestion/parsing-processor.d.ts +4 -1
- package/dist/core/ingestion/parsing-processor.js +107 -109
- package/dist/core/ingestion/pipeline.d.ts +6 -3
- package/dist/core/ingestion/pipeline.js +208 -114
- package/dist/core/ingestion/process-processor.js +8 -2
- package/dist/core/ingestion/resolution-context.d.ts +53 -0
- package/dist/core/ingestion/resolution-context.js +132 -0
- package/dist/core/ingestion/resolvers/csharp.d.ts +22 -0
- package/dist/core/ingestion/resolvers/csharp.js +109 -0
- package/dist/core/ingestion/resolvers/go.d.ts +19 -0
- package/dist/core/ingestion/resolvers/go.js +42 -0
- package/dist/core/ingestion/resolvers/index.d.ts +18 -0
- package/dist/core/ingestion/resolvers/index.js +13 -0
- package/dist/core/ingestion/resolvers/jvm.d.ts +23 -0
- package/dist/core/ingestion/resolvers/jvm.js +87 -0
- package/dist/core/ingestion/resolvers/php.d.ts +15 -0
- package/dist/core/ingestion/resolvers/php.js +35 -0
- package/dist/core/ingestion/resolvers/python.d.ts +19 -0
- package/dist/core/ingestion/resolvers/python.js +52 -0
- package/dist/core/ingestion/resolvers/ruby.d.ts +12 -0
- package/dist/core/ingestion/resolvers/ruby.js +15 -0
- package/dist/core/ingestion/resolvers/rust.d.ts +15 -0
- package/dist/core/ingestion/resolvers/rust.js +73 -0
- package/dist/core/ingestion/resolvers/standard.d.ts +28 -0
- package/dist/core/ingestion/resolvers/standard.js +123 -0
- package/dist/core/ingestion/resolvers/utils.d.ts +33 -0
- package/dist/core/ingestion/resolvers/utils.js +122 -0
- package/dist/core/ingestion/symbol-table.d.ts +21 -1
- package/dist/core/ingestion/symbol-table.js +40 -12
- package/dist/core/ingestion/tree-sitter-queries.d.ts +13 -10
- package/dist/core/ingestion/tree-sitter-queries.js +297 -7
- package/dist/core/ingestion/type-env.d.ts +49 -0
- package/dist/core/ingestion/type-env.js +611 -0
- package/dist/core/ingestion/type-extractors/c-cpp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/c-cpp.js +385 -0
- package/dist/core/ingestion/type-extractors/csharp.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/csharp.js +383 -0
- package/dist/core/ingestion/type-extractors/go.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/go.js +467 -0
- package/dist/core/ingestion/type-extractors/index.d.ts +22 -0
- package/dist/core/ingestion/type-extractors/index.js +31 -0
- package/dist/core/ingestion/type-extractors/jvm.d.ts +3 -0
- package/dist/core/ingestion/type-extractors/jvm.js +681 -0
- package/dist/core/ingestion/type-extractors/php.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/php.js +549 -0
- package/dist/core/ingestion/type-extractors/python.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/python.js +406 -0
- package/dist/core/ingestion/type-extractors/ruby.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/ruby.js +389 -0
- package/dist/core/ingestion/type-extractors/rust.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/rust.js +449 -0
- package/dist/core/ingestion/type-extractors/shared.d.ts +133 -0
- package/dist/core/ingestion/type-extractors/shared.js +703 -0
- package/dist/core/ingestion/type-extractors/swift.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/swift.js +137 -0
- package/dist/core/ingestion/type-extractors/types.d.ts +127 -0
- package/dist/core/ingestion/type-extractors/typescript.d.ts +2 -0
- package/dist/core/ingestion/type-extractors/typescript.js +494 -0
- package/dist/core/ingestion/utils.d.ts +103 -0
- package/dist/core/ingestion/utils.js +1085 -4
- package/dist/core/ingestion/workers/parse-worker.d.ts +51 -4
- package/dist/core/ingestion/workers/parse-worker.js +634 -222
- package/dist/core/ingestion/workers/worker-pool.js +8 -0
- package/dist/core/{kuzu → lbug}/csv-generator.d.ts +12 -10
- package/dist/core/{kuzu → lbug}/csv-generator.js +82 -101
- package/dist/core/{kuzu/kuzu-adapter.d.ts → lbug/lbug-adapter.d.ts} +20 -25
- package/dist/core/{kuzu/kuzu-adapter.js → lbug/lbug-adapter.js} +150 -122
- package/dist/core/{kuzu → lbug}/schema.d.ts +4 -4
- package/dist/core/{kuzu → lbug}/schema.js +23 -22
- package/dist/core/lbug/schema.test.d.ts +1 -0
- package/dist/core/search/bm25-index.d.ts +4 -4
- package/dist/core/search/bm25-index.js +12 -11
- package/dist/core/search/hybrid-search.d.ts +2 -2
- package/dist/core/search/hybrid-search.js +6 -6
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -0
- package/dist/core/tree-sitter/parser-loader.js +19 -0
- package/dist/core/wiki/generator.d.ts +2 -2
- package/dist/core/wiki/generator.js +6 -6
- package/dist/core/wiki/graph-queries.d.ts +4 -4
- package/dist/core/wiki/graph-queries.js +7 -7
- 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.d.ts → lbug-adapter.d.ts} +11 -10
- package/dist/mcp/core/lbug-adapter.js +327 -0
- package/dist/mcp/local/local-backend.d.ts +21 -16
- package/dist/mcp/local/local-backend.js +306 -706
- package/dist/mcp/local/unity-parity-seed-loader.d.ts +6 -1
- package/dist/mcp/local/unity-parity-seed-loader.js +119 -9
- package/dist/mcp/local/unity-parity-seed-loader.test.js +95 -7
- package/dist/mcp/resources.js +2 -2
- package/dist/mcp/server.js +28 -13
- package/dist/mcp/staleness.js +2 -2
- package/dist/mcp/tools.js +12 -3
- package/dist/server/api.js +12 -12
- package/dist/server/mcp-http.d.ts +1 -1
- package/dist/server/mcp-http.js +1 -1
- package/dist/storage/git.js +4 -1
- package/dist/storage/repo-manager.d.ts +20 -2
- package/dist/storage/repo-manager.js +74 -4
- package/dist/types/pipeline.d.ts +1 -1
- package/hooks/claude/gitnexus-hook.cjs +149 -46
- package/hooks/claude/pre-tool-use.sh +2 -1
- package/hooks/claude/session-start.sh +0 -0
- package/package.json +20 -4
- package/scripts/patch-tree-sitter-swift.cjs +74 -0
- package/skills/gitnexus-cli.md +8 -8
- package/skills/gitnexus-debugging.md +1 -1
- package/skills/gitnexus-exploring.md +1 -1
- package/skills/gitnexus-guide.md +1 -1
- package/skills/gitnexus-impact-analysis.md +1 -1
- package/skills/gitnexus-pr-review.md +163 -0
- package/skills/gitnexus-refactoring.md +1 -1
- package/dist/cli/claude-hooks.d.ts +0 -22
- package/dist/cli/claude-hooks.js +0 -97
- package/dist/mcp/core/kuzu-adapter.js +0 -231
- /package/dist/core/{kuzu/csv-generator.test.d.ts → ingestion/type-extractors/types.js} +0 -0
- /package/dist/core/{kuzu/relationship-pair-buckets.test.d.ts → lbug/csv-generator.test.d.ts} +0 -0
- /package/dist/core/{kuzu → lbug}/csv-generator.test.js +0 -0
- /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.d.ts +0 -0
- /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.js +0 -0
- /package/dist/core/{kuzu/schema.test.d.ts → lbug/relationship-pair-buckets.test.d.ts} +0 -0
- /package/dist/core/{kuzu → lbug}/relationship-pair-buckets.test.js +0 -0
- /package/dist/core/{kuzu → lbug}/schema.test.js +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* LadybugDB Schema Definitions
|
|
3
3
|
*
|
|
4
4
|
* Hybrid Schema:
|
|
5
5
|
* - Separate node tables for each code element type (File, Function, Class, etc.)
|
|
@@ -22,20 +22,7 @@ export const NODE_TABLES = [
|
|
|
22
22
|
// ============================================================================
|
|
23
23
|
export const REL_TABLE_NAME = 'CodeRelation';
|
|
24
24
|
// Valid relation types
|
|
25
|
-
export const REL_TYPES = [
|
|
26
|
-
'CONTAINS',
|
|
27
|
-
'DEFINES',
|
|
28
|
-
'IMPORTS',
|
|
29
|
-
'CALLS',
|
|
30
|
-
'EXTENDS',
|
|
31
|
-
'IMPLEMENTS',
|
|
32
|
-
'MEMBER_OF',
|
|
33
|
-
'STEP_IN_PROCESS',
|
|
34
|
-
'UNITY_COMPONENT_IN',
|
|
35
|
-
'UNITY_COMPONENT_INSTANCE',
|
|
36
|
-
'UNITY_RESOURCE_SUMMARY',
|
|
37
|
-
'UNITY_SERIALIZED_TYPE_IN',
|
|
38
|
-
];
|
|
25
|
+
export const REL_TYPES = ['CONTAINS', 'DEFINES', 'IMPORTS', 'CALLS', 'EXTENDS', 'IMPLEMENTS', 'HAS_METHOD', 'OVERRIDES', 'MEMBER_OF', 'STEP_IN_PROCESS'];
|
|
39
26
|
// ============================================================================
|
|
40
27
|
// EMBEDDING TABLE
|
|
41
28
|
// ============================================================================
|
|
@@ -104,6 +91,8 @@ CREATE NODE TABLE Method (
|
|
|
104
91
|
isExported BOOLEAN,
|
|
105
92
|
content STRING,
|
|
106
93
|
description STRING,
|
|
94
|
+
parameterCount INT32,
|
|
95
|
+
returnType STRING,
|
|
107
96
|
PRIMARY KEY (id)
|
|
108
97
|
)`;
|
|
109
98
|
export const CODE_ELEMENT_SCHEMA = `
|
|
@@ -229,15 +218,13 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
229
218
|
FROM Function TO \`Impl\`,
|
|
230
219
|
FROM Function TO Interface,
|
|
231
220
|
FROM Function TO \`Constructor\`,
|
|
232
|
-
FROM Function TO \`Property\`,
|
|
233
221
|
FROM Function TO \`Const\`,
|
|
234
222
|
FROM Function TO \`Typedef\`,
|
|
235
223
|
FROM Function TO \`Union\`,
|
|
224
|
+
FROM Function TO \`Property\`,
|
|
236
225
|
FROM Class TO Method,
|
|
237
226
|
FROM Class TO Function,
|
|
238
227
|
FROM Class TO Class,
|
|
239
|
-
FROM Class TO File,
|
|
240
|
-
FROM Class TO CodeElement,
|
|
241
228
|
FROM Class TO Interface,
|
|
242
229
|
FROM Class TO Community,
|
|
243
230
|
FROM Class TO \`Template\`,
|
|
@@ -253,7 +240,6 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
253
240
|
FROM Class TO \`Namespace\`,
|
|
254
241
|
FROM Class TO \`Typedef\`,
|
|
255
242
|
FROM Class TO \`Property\`,
|
|
256
|
-
FROM Class TO \`Delegate\`,
|
|
257
243
|
FROM Method TO Function,
|
|
258
244
|
FROM Method TO Method,
|
|
259
245
|
FROM Method TO Class,
|
|
@@ -269,7 +255,6 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
269
255
|
FROM Method TO Interface,
|
|
270
256
|
FROM Method TO \`Constructor\`,
|
|
271
257
|
FROM Method TO \`Property\`,
|
|
272
|
-
FROM Method TO \`Delegate\`,
|
|
273
258
|
FROM \`Template\` TO \`Template\`,
|
|
274
259
|
FROM \`Template\` TO Function,
|
|
275
260
|
FROM \`Template\` TO Method,
|
|
@@ -290,6 +275,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
290
275
|
FROM Interface TO \`TypeAlias\`,
|
|
291
276
|
FROM Interface TO \`Struct\`,
|
|
292
277
|
FROM Interface TO \`Constructor\`,
|
|
278
|
+
FROM Interface TO \`Property\`,
|
|
293
279
|
FROM \`Struct\` TO Community,
|
|
294
280
|
FROM \`Struct\` TO \`Trait\`,
|
|
295
281
|
FROM \`Struct\` TO \`Struct\`,
|
|
@@ -297,7 +283,13 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
297
283
|
FROM \`Struct\` TO \`Enum\`,
|
|
298
284
|
FROM \`Struct\` TO Function,
|
|
299
285
|
FROM \`Struct\` TO Method,
|
|
286
|
+
FROM \`Struct\` TO Interface,
|
|
287
|
+
FROM \`Struct\` TO \`Constructor\`,
|
|
288
|
+
FROM \`Struct\` TO \`Property\`,
|
|
289
|
+
FROM \`Enum\` TO \`Enum\`,
|
|
300
290
|
FROM \`Enum\` TO Community,
|
|
291
|
+
FROM \`Enum\` TO Class,
|
|
292
|
+
FROM \`Enum\` TO Interface,
|
|
301
293
|
FROM \`Macro\` TO Community,
|
|
302
294
|
FROM \`Macro\` TO Function,
|
|
303
295
|
FROM \`Macro\` TO Method,
|
|
@@ -307,18 +299,26 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
307
299
|
FROM \`Union\` TO Community,
|
|
308
300
|
FROM \`Namespace\` TO Community,
|
|
309
301
|
FROM \`Namespace\` TO \`Struct\`,
|
|
302
|
+
FROM \`Trait\` TO Method,
|
|
303
|
+
FROM \`Trait\` TO \`Constructor\`,
|
|
304
|
+
FROM \`Trait\` TO \`Property\`,
|
|
310
305
|
FROM \`Trait\` TO Community,
|
|
306
|
+
FROM \`Impl\` TO Method,
|
|
307
|
+
FROM \`Impl\` TO \`Constructor\`,
|
|
308
|
+
FROM \`Impl\` TO \`Property\`,
|
|
311
309
|
FROM \`Impl\` TO Community,
|
|
312
310
|
FROM \`Impl\` TO \`Trait\`,
|
|
313
311
|
FROM \`Impl\` TO \`Struct\`,
|
|
314
312
|
FROM \`Impl\` TO \`Impl\`,
|
|
315
313
|
FROM \`TypeAlias\` TO Community,
|
|
316
314
|
FROM \`TypeAlias\` TO \`Trait\`,
|
|
315
|
+
FROM \`TypeAlias\` TO Class,
|
|
317
316
|
FROM \`Const\` TO Community,
|
|
318
317
|
FROM \`Static\` TO Community,
|
|
319
318
|
FROM \`Property\` TO Community,
|
|
320
|
-
FROM \`
|
|
321
|
-
FROM \`
|
|
319
|
+
FROM \`Record\` TO Method,
|
|
320
|
+
FROM \`Record\` TO \`Constructor\`,
|
|
321
|
+
FROM \`Record\` TO \`Property\`,
|
|
322
322
|
FROM \`Record\` TO Community,
|
|
323
323
|
FROM \`Delegate\` TO Community,
|
|
324
324
|
FROM \`Annotation\` TO Community,
|
|
@@ -338,6 +338,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|
|
338
338
|
FROM \`Constructor\` TO \`Namespace\`,
|
|
339
339
|
FROM \`Constructor\` TO \`Module\`,
|
|
340
340
|
FROM \`Constructor\` TO \`Property\`,
|
|
341
|
+
FROM \`Constructor\` TO \`Typedef\`,
|
|
341
342
|
FROM \`Template\` TO Community,
|
|
342
343
|
FROM \`Module\` TO Community,
|
|
343
344
|
FROM Function TO Process,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Full-Text Search via
|
|
2
|
+
* Full-Text Search via LadybugDB FTS
|
|
3
3
|
*
|
|
4
|
-
* Uses
|
|
4
|
+
* Uses LadybugDB's built-in full-text search indexes for keyword-based search.
|
|
5
5
|
* Always reads from the database (no cached state to drift).
|
|
6
6
|
*/
|
|
7
7
|
export interface BM25SearchResult {
|
|
@@ -10,7 +10,7 @@ export interface BM25SearchResult {
|
|
|
10
10
|
rank: number;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Search using
|
|
13
|
+
* Search using LadybugDB's built-in FTS (always fresh, reads from disk)
|
|
14
14
|
*
|
|
15
15
|
* Queries multiple node tables (File, Function, Class, Method) in parallel
|
|
16
16
|
* and merges results by filePath, summing scores for the same file.
|
|
@@ -20,4 +20,4 @@ export interface BM25SearchResult {
|
|
|
20
20
|
* @param repoId - If provided, queries will be routed via the MCP connection pool
|
|
21
21
|
* @returns Ranked search results from FTS indexes
|
|
22
22
|
*/
|
|
23
|
-
export declare const
|
|
23
|
+
export declare const searchFTSFromLbug: (query: string, limit?: number, repoId?: string) => Promise<BM25SearchResult[]>;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Full-Text Search via
|
|
2
|
+
* Full-Text Search via LadybugDB FTS
|
|
3
3
|
*
|
|
4
|
-
* Uses
|
|
4
|
+
* Uses LadybugDB's built-in full-text search indexes for keyword-based search.
|
|
5
5
|
* Always reads from the database (no cached state to drift).
|
|
6
6
|
*/
|
|
7
|
-
import { queryFTS } from '../
|
|
7
|
+
import { queryFTS } from '../lbug/lbug-adapter.js';
|
|
8
8
|
/**
|
|
9
9
|
* Execute a single FTS query via a custom executor (for MCP connection pool).
|
|
10
|
-
* Returns the same shape as core queryFTS.
|
|
10
|
+
* Returns the same shape as core queryFTS (from LadybugDB adapter).
|
|
11
11
|
*/
|
|
12
12
|
async function queryFTSViaExecutor(executor, tableName, indexName, query, limit) {
|
|
13
|
-
|
|
13
|
+
// Escape single quotes and backslashes to prevent Cypher injection
|
|
14
|
+
const escapedQuery = query.replace(/\\/g, '\\\\').replace(/'/g, "''");
|
|
14
15
|
const cypher = `
|
|
15
16
|
CALL QUERY_FTS_INDEX('${tableName}', '${indexName}', '${escapedQuery}', conjunctive := false)
|
|
16
17
|
RETURN node, score
|
|
@@ -33,7 +34,7 @@ async function queryFTSViaExecutor(executor, tableName, indexName, query, limit)
|
|
|
33
34
|
}
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
36
|
-
* Search using
|
|
37
|
+
* Search using LadybugDB's built-in FTS (always fresh, reads from disk)
|
|
37
38
|
*
|
|
38
39
|
* Queries multiple node tables (File, Function, Class, Method) in parallel
|
|
39
40
|
* and merges results by filePath, summing scores for the same file.
|
|
@@ -43,13 +44,13 @@ async function queryFTSViaExecutor(executor, tableName, indexName, query, limit)
|
|
|
43
44
|
* @param repoId - If provided, queries will be routed via the MCP connection pool
|
|
44
45
|
* @returns Ranked search results from FTS indexes
|
|
45
46
|
*/
|
|
46
|
-
export const
|
|
47
|
+
export const searchFTSFromLbug = async (query, limit = 20, repoId) => {
|
|
47
48
|
let fileResults, functionResults, classResults, methodResults, interfaceResults;
|
|
48
49
|
if (repoId) {
|
|
49
50
|
// Use MCP connection pool via dynamic import
|
|
50
|
-
// IMPORTANT:
|
|
51
|
-
//
|
|
52
|
-
const { executeQuery } = await import('../../mcp/core/
|
|
51
|
+
// IMPORTANT: FTS queries run sequentially to avoid connection contention.
|
|
52
|
+
// The MCP pool supports multiple connections, but FTS is best run serially.
|
|
53
|
+
const { executeQuery } = await import('../../mcp/core/lbug-adapter.js');
|
|
53
54
|
const executor = (cypher) => executeQuery(repoId, cypher);
|
|
54
55
|
fileResults = await queryFTSViaExecutor(executor, 'File', 'file_fts', query, limit);
|
|
55
56
|
functionResults = await queryFTSViaExecutor(executor, 'Function', 'function_fts', query, limit);
|
|
@@ -58,7 +59,7 @@ export const searchFTSFromKuzu = async (query, limit = 20, repoId) => {
|
|
|
58
59
|
interfaceResults = await queryFTSViaExecutor(executor, 'Interface', 'interface_fts', query, limit);
|
|
59
60
|
}
|
|
60
61
|
else {
|
|
61
|
-
// Use core
|
|
62
|
+
// Use core lbug adapter (CLI / pipeline context) — also sequential for safety
|
|
62
63
|
fileResults = await queryFTS('File', 'file_fts', query, limit, false).catch(() => []);
|
|
63
64
|
functionResults = await queryFTS('Function', 'function_fts', query, limit, false).catch(() => []);
|
|
64
65
|
classResults = await queryFTS('Class', 'class_fts', query, limit, false).catch(() => []);
|
|
@@ -33,7 +33,7 @@ export interface HybridSearchResult {
|
|
|
33
33
|
export declare const mergeWithRRF: (bm25Results: BM25SearchResult[], semanticResults: SemanticSearchResult[], limit?: number) => HybridSearchResult[];
|
|
34
34
|
/**
|
|
35
35
|
* Check if hybrid search is available
|
|
36
|
-
*
|
|
36
|
+
* LadybugDB FTS is always available once the database is initialized.
|
|
37
37
|
* Semantic search is optional - hybrid works with just FTS if embeddings aren't ready.
|
|
38
38
|
*/
|
|
39
39
|
export declare const isHybridSearchReady: () => boolean;
|
|
@@ -43,7 +43,7 @@ export declare const isHybridSearchReady: () => boolean;
|
|
|
43
43
|
export declare const formatHybridResults: (results: HybridSearchResult[]) => string;
|
|
44
44
|
/**
|
|
45
45
|
* Execute BM25 + semantic search and merge with RRF.
|
|
46
|
-
* Uses
|
|
46
|
+
* Uses LadybugDB FTS for always-fresh BM25 results (no cached data).
|
|
47
47
|
* The semanticSearch function is injected to keep this module environment-agnostic.
|
|
48
48
|
*/
|
|
49
49
|
export declare const hybridSearch: (query: string, limit: number, executeQuery: (cypher: string) => Promise<any[]>, semanticSearch: (executeQuery: (cypher: string) => Promise<any[]>, query: string, k?: number) => Promise<SemanticSearchResult[]>) => Promise<HybridSearchResult[]>;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* This is the same approach used by Elasticsearch, Pinecone, and other
|
|
8
8
|
* production search systems.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { searchFTSFromLbug } from './bm25-index.js';
|
|
11
11
|
/**
|
|
12
12
|
* RRF constant - standard value used in the literature
|
|
13
13
|
* Higher values give more weight to lower-ranked results
|
|
@@ -80,11 +80,11 @@ export const mergeWithRRF = (bm25Results, semanticResults, limit = 10) => {
|
|
|
80
80
|
};
|
|
81
81
|
/**
|
|
82
82
|
* Check if hybrid search is available
|
|
83
|
-
*
|
|
83
|
+
* LadybugDB FTS is always available once the database is initialized.
|
|
84
84
|
* Semantic search is optional - hybrid works with just FTS if embeddings aren't ready.
|
|
85
85
|
*/
|
|
86
86
|
export const isHybridSearchReady = () => {
|
|
87
|
-
return true; // FTS is always available via
|
|
87
|
+
return true; // FTS is always available via LadybugDB when DB is open
|
|
88
88
|
};
|
|
89
89
|
/**
|
|
90
90
|
* Format hybrid results for LLM consumption
|
|
@@ -107,12 +107,12 @@ export const formatHybridResults = (results) => {
|
|
|
107
107
|
};
|
|
108
108
|
/**
|
|
109
109
|
* Execute BM25 + semantic search and merge with RRF.
|
|
110
|
-
* Uses
|
|
110
|
+
* Uses LadybugDB FTS for always-fresh BM25 results (no cached data).
|
|
111
111
|
* The semanticSearch function is injected to keep this module environment-agnostic.
|
|
112
112
|
*/
|
|
113
113
|
export const hybridSearch = async (query, limit, executeQuery, semanticSearch) => {
|
|
114
|
-
// Use
|
|
115
|
-
const bm25Results = await
|
|
114
|
+
// Use LadybugDB FTS for always-fresh BM25 results
|
|
115
|
+
const bm25Results = await searchFTSFromLbug(query, limit);
|
|
116
116
|
const semanticResults = await semanticSearch(executeQuery, query, limit);
|
|
117
117
|
return mergeWithRRF(bm25Results, semanticResults, limit);
|
|
118
118
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Parser from 'tree-sitter';
|
|
2
2
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
3
|
+
export declare const isLanguageAvailable: (language: SupportedLanguages) => boolean;
|
|
3
4
|
export declare const loadParser: () => Promise<Parser>;
|
|
4
5
|
export declare const loadLanguage: (language: SupportedLanguages, filePath?: string) => Promise<void>;
|
|
@@ -9,7 +9,22 @@ import CSharp from 'tree-sitter-c-sharp';
|
|
|
9
9
|
import Go from 'tree-sitter-go';
|
|
10
10
|
import Rust from 'tree-sitter-rust';
|
|
11
11
|
import PHP from 'tree-sitter-php';
|
|
12
|
+
import Ruby from 'tree-sitter-ruby';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
12
14
|
import { SupportedLanguages } from '../../config/supported-languages.js';
|
|
15
|
+
// tree-sitter-swift is an optionalDependency — may not be installed
|
|
16
|
+
const _require = createRequire(import.meta.url);
|
|
17
|
+
let Swift = null;
|
|
18
|
+
try {
|
|
19
|
+
Swift = _require('tree-sitter-swift');
|
|
20
|
+
}
|
|
21
|
+
catch { }
|
|
22
|
+
// tree-sitter-kotlin is an optionalDependency — may not be installed
|
|
23
|
+
let Kotlin = null;
|
|
24
|
+
try {
|
|
25
|
+
Kotlin = _require('tree-sitter-kotlin');
|
|
26
|
+
}
|
|
27
|
+
catch { }
|
|
13
28
|
let parser = null;
|
|
14
29
|
const languageMap = {
|
|
15
30
|
[SupportedLanguages.JavaScript]: JavaScript,
|
|
@@ -22,8 +37,12 @@ const languageMap = {
|
|
|
22
37
|
[SupportedLanguages.CSharp]: CSharp,
|
|
23
38
|
[SupportedLanguages.Go]: Go,
|
|
24
39
|
[SupportedLanguages.Rust]: Rust,
|
|
40
|
+
...(Kotlin ? { [SupportedLanguages.Kotlin]: Kotlin } : {}),
|
|
25
41
|
[SupportedLanguages.PHP]: PHP.php_only,
|
|
42
|
+
[SupportedLanguages.Ruby]: Ruby,
|
|
43
|
+
...(Swift ? { [SupportedLanguages.Swift]: Swift } : {}),
|
|
26
44
|
};
|
|
45
|
+
export const isLanguageAvailable = (language) => language in languageMap;
|
|
27
46
|
export const loadParser = async () => {
|
|
28
47
|
if (parser)
|
|
29
48
|
return parser;
|
|
@@ -36,14 +36,14 @@ export declare class WikiGenerator {
|
|
|
36
36
|
private repoPath;
|
|
37
37
|
private storagePath;
|
|
38
38
|
private wikiDir;
|
|
39
|
-
private
|
|
39
|
+
private lbugPath;
|
|
40
40
|
private llmConfig;
|
|
41
41
|
private maxTokensPerModule;
|
|
42
42
|
private concurrency;
|
|
43
43
|
private options;
|
|
44
44
|
private onProgress;
|
|
45
45
|
private failedModules;
|
|
46
|
-
constructor(repoPath: string, storagePath: string,
|
|
46
|
+
constructor(repoPath: string, storagePath: string, lbugPath: string, llmConfig: LLMConfig, options?: WikiOptions, onProgress?: ProgressCallback);
|
|
47
47
|
private lastPercent;
|
|
48
48
|
/**
|
|
49
49
|
* Create streaming options that report LLM progress to the progress bar.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import fs from 'fs/promises';
|
|
13
13
|
import path from 'path';
|
|
14
|
-
import { execSync } from 'child_process';
|
|
14
|
+
import { execSync, execFileSync } from 'child_process';
|
|
15
15
|
import { initWikiDb, closeWikiDb, getFilesWithExports, getAllFiles, getIntraModuleCallEdges, getInterModuleCallEdges, getProcessesForFiles, getAllProcesses, getInterModuleEdgesForOverview, } from './graph-queries.js';
|
|
16
16
|
import { generateHTMLViewer } from './html-viewer.js';
|
|
17
17
|
import { callLLM, estimateTokens, } from './llm-client.js';
|
|
@@ -25,18 +25,18 @@ export class WikiGenerator {
|
|
|
25
25
|
repoPath;
|
|
26
26
|
storagePath;
|
|
27
27
|
wikiDir;
|
|
28
|
-
|
|
28
|
+
lbugPath;
|
|
29
29
|
llmConfig;
|
|
30
30
|
maxTokensPerModule;
|
|
31
31
|
concurrency;
|
|
32
32
|
options;
|
|
33
33
|
onProgress;
|
|
34
34
|
failedModules = [];
|
|
35
|
-
constructor(repoPath, storagePath,
|
|
35
|
+
constructor(repoPath, storagePath, lbugPath, llmConfig, options = {}, onProgress) {
|
|
36
36
|
this.repoPath = repoPath;
|
|
37
37
|
this.storagePath = storagePath;
|
|
38
38
|
this.wikiDir = path.join(storagePath, WIKI_DIR);
|
|
39
|
-
this.
|
|
39
|
+
this.lbugPath = lbugPath;
|
|
40
40
|
this.options = options;
|
|
41
41
|
this.llmConfig = llmConfig;
|
|
42
42
|
this.maxTokensPerModule = options.maxTokensPerModule ?? DEFAULT_MAX_TOKENS_PER_MODULE;
|
|
@@ -95,7 +95,7 @@ export class WikiGenerator {
|
|
|
95
95
|
}
|
|
96
96
|
// Init graph
|
|
97
97
|
this.onProgress('init', 2, 'Connecting to knowledge graph...');
|
|
98
|
-
await initWikiDb(this.
|
|
98
|
+
await initWikiDb(this.lbugPath);
|
|
99
99
|
let result;
|
|
100
100
|
try {
|
|
101
101
|
if (!forceMode && existingMeta && existingMeta.fromCommit) {
|
|
@@ -561,7 +561,7 @@ export class WikiGenerator {
|
|
|
561
561
|
}
|
|
562
562
|
getChangedFiles(fromCommit, toCommit) {
|
|
563
563
|
try {
|
|
564
|
-
const output =
|
|
564
|
+
const output = execFileSync('git', ['diff', `${fromCommit}..${toCommit}`, '--name-only'], { cwd: this.repoPath }).toString().trim();
|
|
565
565
|
return output ? output.split('\n').filter(Boolean) : [];
|
|
566
566
|
}
|
|
567
567
|
catch {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Graph Queries for Wiki Generation
|
|
3
3
|
*
|
|
4
4
|
* Encapsulated Cypher queries against the GitNexus knowledge graph.
|
|
5
|
-
* Uses the MCP-style pooled
|
|
5
|
+
* Uses the MCP-style pooled lbug-adapter for connection management.
|
|
6
6
|
*/
|
|
7
7
|
export interface FileWithExports {
|
|
8
8
|
filePath: string;
|
|
@@ -30,11 +30,11 @@ export interface ProcessInfo {
|
|
|
30
30
|
}>;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Initialize the
|
|
33
|
+
* Initialize the LadybugDB connection for wiki generation.
|
|
34
34
|
*/
|
|
35
|
-
export declare function initWikiDb(
|
|
35
|
+
export declare function initWikiDb(lbugPath: string): Promise<void>;
|
|
36
36
|
/**
|
|
37
|
-
* Close the
|
|
37
|
+
* Close the LadybugDB connection.
|
|
38
38
|
*/
|
|
39
39
|
export declare function closeWikiDb(): Promise<void>;
|
|
40
40
|
/**
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
* Graph Queries for Wiki Generation
|
|
3
3
|
*
|
|
4
4
|
* Encapsulated Cypher queries against the GitNexus knowledge graph.
|
|
5
|
-
* Uses the MCP-style pooled
|
|
5
|
+
* Uses the MCP-style pooled lbug-adapter for connection management.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { initLbug, executeQuery, closeLbug } from '../../mcp/core/lbug-adapter.js';
|
|
8
8
|
const REPO_ID = '__wiki__';
|
|
9
9
|
/**
|
|
10
|
-
* Initialize the
|
|
10
|
+
* Initialize the LadybugDB connection for wiki generation.
|
|
11
11
|
*/
|
|
12
|
-
export async function initWikiDb(
|
|
13
|
-
await
|
|
12
|
+
export async function initWikiDb(lbugPath) {
|
|
13
|
+
await initLbug(REPO_ID, lbugPath);
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Close the
|
|
16
|
+
* Close the LadybugDB connection.
|
|
17
17
|
*/
|
|
18
18
|
export async function closeWikiDb() {
|
|
19
|
-
await
|
|
19
|
+
await closeLbug(REPO_ID);
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Get all source files with their exported symbol names and types.
|
|
@@ -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
|
+
}
|