gitnexus 1.6.4-rc.2 → 1.6.4-rc.21
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 +35 -0
- package/dist/_shared/index.d.ts +1 -1
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +1 -1
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +22 -14
- package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/finalize-algorithm.js +298 -37
- package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts +23 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.js +36 -2
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +47 -3
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/types.js +10 -2
- package/dist/_shared/scope-resolution/types.js.map +1 -1
- package/dist/cli/analyze.d.ts +6 -0
- package/dist/cli/analyze.js +35 -0
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.js +31 -0
- package/dist/cli/index.js +13 -0
- package/dist/cli/setup.js +2 -2
- package/dist/core/embeddings/config.d.ts +2 -0
- package/dist/core/embeddings/config.js +36 -0
- package/dist/core/embeddings/embedder.js +11 -6
- package/dist/core/embeddings/embedding-pipeline.d.ts +7 -1
- package/dist/core/embeddings/embedding-pipeline.js +93 -29
- package/dist/core/embeddings/exact-search.d.ts +15 -0
- package/dist/core/embeddings/exact-search.js +27 -0
- package/dist/core/embeddings/types.d.ts +4 -0
- package/dist/core/embeddings/types.js +2 -0
- package/dist/core/group/config-parser.js +2 -0
- package/dist/core/group/matching.d.ts +3 -3
- package/dist/core/group/matching.js +46 -6
- package/dist/core/group/storage.js +2 -0
- package/dist/core/group/sync.js +1 -1
- package/dist/core/group/types.d.ts +18 -0
- package/dist/core/ingestion/call-processor.d.ts +3 -3
- package/dist/core/ingestion/call-processor.js +58 -65
- package/dist/core/ingestion/constants.d.ts +4 -3
- package/dist/core/ingestion/constants.js +8 -3
- package/dist/core/ingestion/finalize-orchestrator.js +6 -3
- package/dist/core/ingestion/heritage-processor.js +2 -2
- package/dist/core/ingestion/import-processor.js +1 -1
- package/dist/core/ingestion/language-provider.d.ts +8 -0
- package/dist/core/ingestion/languages/csharp/captures.js +4 -1
- package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +14 -13
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +62 -50
- package/dist/core/ingestion/languages/python/captures.js +9 -1
- package/dist/core/ingestion/languages/python/index.d.ts +1 -1
- package/dist/core/ingestion/languages/python/index.js +1 -1
- package/dist/core/ingestion/languages/python/simple-hooks.d.ts +3 -1
- package/dist/core/ingestion/languages/python/simple-hooks.js +8 -0
- package/dist/core/ingestion/languages/python.js +28 -1
- package/dist/core/ingestion/languages/swift.js +14 -0
- package/dist/core/ingestion/languages/typescript/arity-metadata.d.ts +59 -0
- package/dist/core/ingestion/languages/typescript/arity-metadata.js +103 -0
- package/dist/core/ingestion/languages/typescript/arity.d.ts +37 -0
- package/dist/core/ingestion/languages/typescript/arity.js +54 -0
- package/dist/core/ingestion/languages/typescript/cache-stats.d.ts +17 -0
- package/dist/core/ingestion/languages/typescript/cache-stats.js +28 -0
- package/dist/core/ingestion/languages/typescript/captures.d.ts +28 -0
- package/dist/core/ingestion/languages/typescript/captures.js +451 -0
- package/dist/core/ingestion/languages/typescript/import-decomposer.d.ts +49 -0
- package/dist/core/ingestion/languages/typescript/import-decomposer.js +371 -0
- package/dist/core/ingestion/languages/typescript/import-target.d.ts +50 -0
- package/dist/core/ingestion/languages/typescript/import-target.js +61 -0
- package/dist/core/ingestion/languages/typescript/index.d.ts +94 -0
- package/dist/core/ingestion/languages/typescript/index.js +94 -0
- package/dist/core/ingestion/languages/typescript/interpret.d.ts +35 -0
- package/dist/core/ingestion/languages/typescript/interpret.js +317 -0
- package/dist/core/ingestion/languages/typescript/merge-bindings.d.ts +62 -0
- package/dist/core/ingestion/languages/typescript/merge-bindings.js +158 -0
- package/dist/core/ingestion/languages/typescript/query.d.ts +77 -0
- package/dist/core/ingestion/languages/typescript/query.js +778 -0
- package/dist/core/ingestion/languages/typescript/receiver-binding.d.ts +59 -0
- package/dist/core/ingestion/languages/typescript/receiver-binding.js +171 -0
- package/dist/core/ingestion/languages/typescript/scope-resolver.d.ts +16 -0
- package/dist/core/ingestion/languages/typescript/scope-resolver.js +113 -0
- package/dist/core/ingestion/languages/typescript/simple-hooks.d.ts +71 -0
- package/dist/core/ingestion/languages/typescript/simple-hooks.js +131 -0
- package/dist/core/ingestion/languages/typescript.js +19 -0
- package/dist/core/ingestion/method-extractors/configs/swift.js +3 -4
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +14 -1
- package/dist/core/ingestion/parsing-processor.js +20 -9
- package/dist/core/ingestion/pipeline-phases/processes.js +9 -4
- package/dist/core/ingestion/pipeline-phases/tools.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/tools.js +10 -4
- package/dist/core/ingestion/registry-primary-flag.d.ts +3 -1
- package/dist/core/ingestion/registry-primary-flag.js +4 -1
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +5 -2
- package/dist/core/ingestion/scope-extractor-bridge.js +7 -2
- package/dist/core/ingestion/scope-extractor.js +19 -18
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +73 -11
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +48 -10
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +283 -14
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +23 -2
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +109 -37
- package/dist/core/ingestion/scope-resolution/passes/mro.js +3 -1
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +13 -5
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +11 -2
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +8 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +21 -5
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.d.ts +39 -0
- package/dist/core/ingestion/scope-resolution/pipeline/validate-bindings-immutability.js +65 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +54 -11
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +105 -30
- package/dist/core/ingestion/type-extractors/swift.js +7 -4
- package/dist/core/ingestion/utils/ast-helpers.d.ts +2 -0
- package/dist/core/ingestion/utils/ast-helpers.js +12 -0
- package/dist/core/ingestion/utils/env.d.ts +10 -0
- package/dist/core/ingestion/utils/env.js +14 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +1 -0
- package/dist/core/ingestion/workers/parse-worker.js +15 -9
- package/dist/core/ingestion/workers/worker-pool.d.ts +11 -4
- package/dist/core/ingestion/workers/worker-pool.js +244 -48
- package/dist/core/lbug/extension-loader.d.ts +86 -0
- package/dist/core/lbug/extension-loader.js +184 -0
- package/dist/core/lbug/lbug-adapter.d.ts +18 -17
- package/dist/core/lbug/lbug-adapter.js +45 -73
- package/dist/core/lbug/pool-adapter.js +10 -28
- package/dist/core/platform/capabilities.d.ts +24 -0
- package/dist/core/platform/capabilities.js +54 -0
- package/dist/core/run-analyze.js +36 -9
- package/dist/core/search/bm25-index.d.ts +0 -17
- package/dist/core/search/bm25-index.js +10 -118
- package/dist/core/search/fts-indexes.d.ts +1 -0
- package/dist/core/search/fts-indexes.js +7 -0
- package/dist/core/search/fts-schema.d.ts +6 -0
- package/dist/core/search/fts-schema.js +7 -0
- package/dist/mcp/core/embedder.js +11 -4
- package/dist/mcp/local/local-backend.js +50 -15
- package/dist/server/api.d.ts +5 -0
- package/dist/server/api.js +113 -0
- package/hooks/claude/gitnexus-hook.cjs +11 -1
- package/package.json +6 -5
- package/scripts/build-tree-sitter-dart.cjs +42 -0
- package/scripts/build-tree-sitter-proto.cjs +1 -1
- package/scripts/build.js +22 -2
- package/scripts/install-duckdb-extension.mjs +37 -0
- package/vendor/tree-sitter-dart/README.md +18 -0
- package/vendor/tree-sitter-dart/binding.gyp +31 -0
- package/vendor/tree-sitter-dart/bindings/node/binding.cc +20 -0
- package/vendor/tree-sitter-dart/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-dart/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-dart/grammar.js +2895 -0
- package/vendor/tree-sitter-dart/package.json +18 -0
- package/vendor/tree-sitter-dart/queries/highlights.scm +246 -0
- package/vendor/tree-sitter-dart/queries/tags.scm +92 -0
- package/vendor/tree-sitter-dart/queries/test.scm +1 -0
- package/vendor/tree-sitter-dart/src/grammar.json +12459 -0
- package/vendor/tree-sitter-dart/src/node-types.json +15055 -0
- package/vendor/tree-sitter-dart/src/parser.c +196127 -0
- package/vendor/tree-sitter-dart/src/scanner.c +130 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/array.h +290 -0
- package/vendor/tree-sitter-dart/src/tree_sitter/parser.h +265 -0
- package/vendor/tree-sitter-swift/LICENSE +21 -0
- package/vendor/tree-sitter-swift/README.md +139 -0
- package/vendor/tree-sitter-swift/bindings/node/index.d.ts +28 -0
- package/vendor/tree-sitter-swift/bindings/node/index.js +7 -0
- package/vendor/tree-sitter-swift/package.json +28 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
- package/vendor/tree-sitter-swift/src/node-types.json +30694 -0
- package/web/assets/agent-DaprsFSX.js +597 -0
- package/web/assets/architecture-YZFGNWBL-S5CXDPWN-DEdGaPg2.js +1 -0
- package/web/assets/architectureDiagram-EMZXCZ2Q-Domyk_gO.js +36 -0
- package/web/assets/blockDiagram-IGV67L2C-B_2kD7tM.js +132 -0
- package/web/assets/c4Diagram-DFAF54RM-BhJJW8Gg.js +10 -0
- package/web/assets/chunk-3GS5O3IE-jlWIjPsl.js +231 -0
- package/web/assets/chunk-3YCYZ6SJ-Blq_IzZs.js +1 -0
- package/web/assets/chunk-6NTNNK5N-DyPc58pp.js +1 -0
- package/web/assets/chunk-7RZVMHOQ-BdIU-RGO.js +321 -0
- package/web/assets/chunk-A34GCYZU-BI2i_LdU.js +1 -0
- package/web/assets/chunk-AEOMTBSW-D7qjBMHW.js +1 -0
- package/web/assets/chunk-CilyBKbf.js +1 -0
- package/web/assets/chunk-DJ7UZH7F-i11ywiBl.js +1 -0
- package/web/assets/chunk-DKKBVRCY-1SffGI1N.js +4 -0
- package/web/assets/chunk-DU5LTGQ6-DaPeiwD5.js +1 -0
- package/web/assets/chunk-FXACKDTF-uhhi2PC2.js +159 -0
- package/web/assets/chunk-H3VCZNTA-IchcISDt.js +1 -0
- package/web/assets/chunk-HN6EAY2L-D7ZFMNrB.js +1 -0
- package/web/assets/chunk-KSICW3F5-C2tZmXwv.js +15 -0
- package/web/assets/chunk-O5ABG6QK-Bt-Km84H.js +1 -0
- package/web/assets/chunk-PK6DOVAG-ChlWY0BQ.js +206 -0
- package/web/assets/chunk-RNJOYNJ4-B724K7cW.js +1 -0
- package/web/assets/chunk-RWUO3TPN-DYn1XriD.js +1 -0
- package/web/assets/chunk-TBF5ZNIQ-DKtDz6ae.js +1 -0
- package/web/assets/chunk-TU3PZOEN-DE5Qhc0N.js +1 -0
- package/web/assets/chunk-TYMNRAUI-g1h33cq-.js +1 -0
- package/web/assets/chunk-VELTKBKT-C9dVN39o.js +1 -0
- package/web/assets/chunk-W7ZLLLMY-Du-Hb9yb.js +1 -0
- package/web/assets/chunk-WSB5WSVC-B123clsZ.js +1 -0
- package/web/assets/chunk-XGPFEOL4-BR7Eue38.js +1 -0
- package/web/assets/classDiagram-PPOCWD7C-BglfKSs_.js +1 -0
- package/web/assets/classDiagram-v2-23LJLIIU-BSzTM28O.js +1 -0
- package/web/assets/context-builder-CqQNhRj1.js +15 -0
- package/web/assets/cose-bilkent-PNC4W37J-DCfErU-A.js +1 -0
- package/web/assets/dagre-E77IOHMT-tDRRhDoN.js +4 -0
- package/web/assets/diagram-H7BISOXX-CUVHlmAh.js +43 -0
- package/web/assets/diagram-JC5VWROH-BoyOxulB.js +24 -0
- package/web/assets/diagram-LXUTUG65-osr9hb7N.js +10 -0
- package/web/assets/diagram-WEHSV5V5-d8nUqS39.js +24 -0
- package/web/assets/erDiagram-GCSMX5X6-b-IwOhPS.js +85 -0
- package/web/assets/flowDiagram-OTCZ4VVT-Ott2Q0AP.js +162 -0
- package/web/assets/ganttDiagram-MUNLMDZQ-BYtgN_5s.js +292 -0
- package/web/assets/gitGraph-7Q5UKJZL-54BCDZD5-CFyBIGZq.js +1 -0
- package/web/assets/gitGraphDiagram-3HKGZ4G3-CsVD2gn4.js +106 -0
- package/web/assets/index-BleGLU8S.css +2 -0
- package/web/assets/index-C_xK08EW.js +885 -0
- package/web/assets/info-OMHHGYJF-BF2H5H6G-yjAxKEzh.js +1 -0
- package/web/assets/infoDiagram-MN7RKWGX-DXK0Unn5.js +2 -0
- package/web/assets/ishikawaDiagram-YMYX4NHK-CXsnC2FA.js +70 -0
- package/web/assets/journeyDiagram-SO5T7YLQ-BzZ07B-X.js +139 -0
- package/web/assets/kanban-definition-LJHFXRCJ-C6_EpAd9.js +89 -0
- package/web/assets/katex-GD7MH7QM-CJiOjBBJ.js +261 -0
- package/web/assets/mindmap-definition-2EUWGEK5-CCYGWZ1m.js +96 -0
- package/web/assets/packet-4T2RLAQJ-EV4IVRXR-B8k4E3IT.js +1 -0
- package/web/assets/pie-ZZUOXDRM-N23DN5KN-DdvfY118.js +1 -0
- package/web/assets/pieDiagram-3IATQBI2-RyvRlQb4.js +30 -0
- package/web/assets/quadrantDiagram-E256RVCF-Bfb6sxCx.js +7 -0
- package/web/assets/radar-PYXPWWZC-P6TP7ZYP-1EEDC_yU.js +1 -0
- package/web/assets/requirementDiagram-M5DCFWZL-DjvHDyvN.js +84 -0
- package/web/assets/sankeyDiagram-L3NBLAOT-CBCbbl8s.js +10 -0
- package/web/assets/sequenceDiagram-ZOUHS735-BscU8TUR.js +157 -0
- package/web/assets/stateDiagram-MLPALWAM-CJusEK2D.js +1 -0
- package/web/assets/stateDiagram-v2-B5LQ5ZB2-DImJ3PXD.js +1 -0
- package/web/assets/timeline-definition-5SPVSISX-DigPA1X8.js +120 -0
- package/web/assets/treeView-SZITEDCU-5DXDK3XO-CzPDt3aG.js +1 -0
- package/web/assets/treemap-W4RFUUIX-WYLRDWKO-B9Iqiorr.js +1 -0
- package/web/assets/vennDiagram-IE5QUKF5-C91UkZIf.js +34 -0
- package/web/assets/wardley-RL74JXVD-BCRCBASE-x42Qw7hp.js +1 -0
- package/web/assets/wardleyDiagram-XU3VSMPF-DloBhI0U.js +20 -0
- package/web/assets/xychartDiagram-ZHJ5623Y-BGWJvgwI.js +7 -0
- package/web/index.html +21 -0
- package/scripts/patch-tree-sitter-swift.cjs +0 -78
|
@@ -15,7 +15,7 @@ import Ruby from 'tree-sitter-ruby';
|
|
|
15
15
|
import { createRequire } from 'node:module';
|
|
16
16
|
import { SupportedLanguages } from '../../../_shared/index.js';
|
|
17
17
|
import { getProvider } from '../languages/index.js';
|
|
18
|
-
import { getTreeSitterBufferSize, TREE_SITTER_MAX_BUFFER } from '../constants.js';
|
|
18
|
+
import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from '../constants.js';
|
|
19
19
|
// tree-sitter-swift is an optionalDependency — may not be installed
|
|
20
20
|
const _require = createRequire(import.meta.url);
|
|
21
21
|
let Swift = null;
|
|
@@ -452,7 +452,7 @@ const processBatch = (files, onProgress) => {
|
|
|
452
452
|
}
|
|
453
453
|
let totalProcessed = 0;
|
|
454
454
|
let lastReported = 0;
|
|
455
|
-
const PROGRESS_INTERVAL = 100
|
|
455
|
+
const PROGRESS_INTERVAL = Math.max(1, Math.min(100, Math.ceil(files.length / 10)));
|
|
456
456
|
const onFileProcessed = onProgress
|
|
457
457
|
? () => {
|
|
458
458
|
totalProcessed++;
|
|
@@ -519,6 +519,9 @@ const processBatch = (files, onProgress) => {
|
|
|
519
519
|
}
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
|
+
if (onProgress && totalProcessed !== lastReported) {
|
|
523
|
+
onProgress(totalProcessed);
|
|
524
|
+
}
|
|
522
525
|
return result;
|
|
523
526
|
};
|
|
524
527
|
const ROUTE_HTTP_METHODS = new Set([
|
|
@@ -1001,7 +1004,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1001
1004
|
}
|
|
1002
1005
|
for (const file of files) {
|
|
1003
1006
|
// Skip files larger than the max tree-sitter buffer (32 MB)
|
|
1004
|
-
if (file.content
|
|
1007
|
+
if (getTreeSitterContentByteLength(file.content) > TREE_SITTER_MAX_BUFFER)
|
|
1005
1008
|
continue;
|
|
1006
1009
|
// Vue SFC preprocessing: extract <script> block content
|
|
1007
1010
|
let parseContent = file.content;
|
|
@@ -1019,7 +1022,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1019
1022
|
let tree;
|
|
1020
1023
|
try {
|
|
1021
1024
|
tree = parser.parse(parseContent, undefined, {
|
|
1022
|
-
bufferSize: getTreeSitterBufferSize(parseContent
|
|
1025
|
+
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
1023
1026
|
});
|
|
1024
1027
|
}
|
|
1025
1028
|
catch (err) {
|
|
@@ -1048,7 +1051,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1048
1051
|
parentPort.postMessage({ type: 'warning', message });
|
|
1049
1052
|
else
|
|
1050
1053
|
console.warn(message);
|
|
1051
|
-
});
|
|
1054
|
+
}, tree);
|
|
1052
1055
|
if (parsedFile !== undefined)
|
|
1053
1056
|
result.parsedFiles.push(parsedFile);
|
|
1054
1057
|
// Pre-pass: extract heritage from query matches to build parentMap for buildTypeEnv.
|
|
@@ -1612,10 +1615,12 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1612
1615
|
}
|
|
1613
1616
|
}
|
|
1614
1617
|
}
|
|
1615
|
-
// Append #<paramCount> to
|
|
1616
|
-
//
|
|
1618
|
+
// Append #<paramCount> to owned callable IDs to disambiguate overloads.
|
|
1619
|
+
// Top-level Function IDs stay stable; functions inside an owner may overload.
|
|
1617
1620
|
// When same-arity collisions exist, append ~type1,type2 for further disambiguation.
|
|
1618
|
-
const needsAritySuffix = nodeLabel === 'Method' ||
|
|
1621
|
+
const needsAritySuffix = nodeLabel === 'Method' ||
|
|
1622
|
+
nodeLabel === 'Constructor' ||
|
|
1623
|
+
(nodeLabel === 'Function' && enclosingClassId !== null);
|
|
1619
1624
|
let arityTag = needsAritySuffix && arityForId !== undefined ? `#${arityForId}` : '';
|
|
1620
1625
|
if (arityTag && defMethodMap && defMethodInfo) {
|
|
1621
1626
|
const groups = buildCollisionGroups(defMethodMap);
|
|
@@ -1668,8 +1673,9 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1668
1673
|
result.toolDefs.push({
|
|
1669
1674
|
filePath: file.path,
|
|
1670
1675
|
toolName: nodeName,
|
|
1671
|
-
description: dec.arg || '',
|
|
1676
|
+
description: (dec.arg || description || '').slice(0, 200),
|
|
1672
1677
|
lineNumber: definitionNode.startPosition.row + lineOffset,
|
|
1678
|
+
handlerNodeId: nodeId,
|
|
1673
1679
|
});
|
|
1674
1680
|
}
|
|
1675
1681
|
fileDecorators.delete(checkLine);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export interface WorkerPool {
|
|
2
2
|
/**
|
|
3
|
-
* Dispatch items across workers. Items are split into
|
|
4
|
-
*
|
|
5
|
-
* and results are concatenated back in order.
|
|
3
|
+
* Dispatch items across workers. Items are split into bounded jobs, each job
|
|
4
|
+
* is committed independently, and stalled jobs are split/retried locally.
|
|
6
5
|
*/
|
|
7
6
|
dispatch<TInput, TResult>(items: TInput[], onProgress?: (filesProcessed: number) => void): Promise<TResult[]>;
|
|
8
7
|
/** Terminate all workers. Must be called when done. */
|
|
@@ -10,7 +9,15 @@ export interface WorkerPool {
|
|
|
10
9
|
/** Number of workers in the pool */
|
|
11
10
|
readonly size: number;
|
|
12
11
|
}
|
|
12
|
+
export interface WorkerPoolOptions {
|
|
13
|
+
subBatchSize?: number;
|
|
14
|
+
subBatchMaxBytes?: number;
|
|
15
|
+
subBatchIdleTimeoutMs?: number;
|
|
16
|
+
maxTimeoutRetries?: number;
|
|
17
|
+
timeoutBackoffFactor?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function resolveWorkerPoolOptions(options?: WorkerPoolOptions): Required<WorkerPoolOptions>;
|
|
13
20
|
/**
|
|
14
21
|
* Create a pool of worker threads.
|
|
15
22
|
*/
|
|
16
|
-
export declare const createWorkerPool: (workerUrl: URL, poolSize?: number) => WorkerPool;
|
|
23
|
+
export declare const createWorkerPool: (workerUrl: URL, poolSize?: number, options?: WorkerPoolOptions) => WorkerPool;
|
|
@@ -7,13 +7,83 @@ import { fileURLToPath } from 'node:url';
|
|
|
7
7
|
* Keeps structured-clone memory bounded per sub-batch.
|
|
8
8
|
*/
|
|
9
9
|
const SUB_BATCH_SIZE = 1500;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
10
|
+
const SUB_BATCH_MAX_BYTES = 8 * 1024 * 1024;
|
|
11
|
+
const DEFAULT_SUB_BATCH_IDLE_TIMEOUT_MS = 30_000;
|
|
12
|
+
const DEFAULT_TIMEOUT_RETRIES = 1;
|
|
13
|
+
const DEFAULT_TIMEOUT_BACKOFF_FACTOR = 2;
|
|
14
|
+
function positiveInteger(value) {
|
|
15
|
+
const parsed = typeof value === 'string' ? Number(value) : value;
|
|
16
|
+
return typeof parsed === 'number' && Number.isFinite(parsed) && parsed > 0
|
|
17
|
+
? Math.floor(parsed)
|
|
18
|
+
: undefined;
|
|
19
|
+
}
|
|
20
|
+
function nonNegativeInteger(value) {
|
|
21
|
+
const parsed = typeof value === 'string' ? Number(value) : value;
|
|
22
|
+
return typeof parsed === 'number' && Number.isFinite(parsed) && parsed >= 0
|
|
23
|
+
? Math.floor(parsed)
|
|
24
|
+
: undefined;
|
|
25
|
+
}
|
|
26
|
+
export function resolveWorkerPoolOptions(options = {}) {
|
|
27
|
+
return {
|
|
28
|
+
subBatchSize: positiveInteger(options.subBatchSize) ?? SUB_BATCH_SIZE,
|
|
29
|
+
subBatchMaxBytes: positiveInteger(options.subBatchMaxBytes) ??
|
|
30
|
+
positiveInteger(process.env.GITNEXUS_WORKER_SUB_BATCH_MAX_BYTES) ??
|
|
31
|
+
SUB_BATCH_MAX_BYTES,
|
|
32
|
+
subBatchIdleTimeoutMs: positiveInteger(options.subBatchIdleTimeoutMs) ??
|
|
33
|
+
positiveInteger(process.env.GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS) ??
|
|
34
|
+
DEFAULT_SUB_BATCH_IDLE_TIMEOUT_MS,
|
|
35
|
+
maxTimeoutRetries: nonNegativeInteger(options.maxTimeoutRetries) ?? DEFAULT_TIMEOUT_RETRIES,
|
|
36
|
+
timeoutBackoffFactor: positiveInteger(options.timeoutBackoffFactor) ?? DEFAULT_TIMEOUT_BACKOFF_FACTOR,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function estimateItemBytes(item) {
|
|
40
|
+
if (typeof item !== 'object' || item === null)
|
|
41
|
+
return 0;
|
|
42
|
+
const content = item.content;
|
|
43
|
+
return typeof content === 'string' ? Buffer.byteLength(content, 'utf8') : 0;
|
|
44
|
+
}
|
|
45
|
+
function itemPath(item) {
|
|
46
|
+
if (typeof item !== 'object' || item === null)
|
|
47
|
+
return undefined;
|
|
48
|
+
const path = item.path;
|
|
49
|
+
return typeof path === 'string' ? path : undefined;
|
|
50
|
+
}
|
|
51
|
+
function createJobs(items, maxItems, maxBytes, timeoutMs) {
|
|
52
|
+
const jobs = [];
|
|
53
|
+
let startIndex = 0;
|
|
54
|
+
let batch = [];
|
|
55
|
+
let batchBytes = 0;
|
|
56
|
+
const flush = () => {
|
|
57
|
+
if (batch.length === 0)
|
|
58
|
+
return;
|
|
59
|
+
jobs.push({
|
|
60
|
+
startIndex,
|
|
61
|
+
items: batch,
|
|
62
|
+
estimatedBytes: batchBytes,
|
|
63
|
+
attempt: 0,
|
|
64
|
+
splitDepth: 0,
|
|
65
|
+
timeoutMs,
|
|
66
|
+
});
|
|
67
|
+
startIndex += batch.length;
|
|
68
|
+
batch = [];
|
|
69
|
+
batchBytes = 0;
|
|
70
|
+
};
|
|
71
|
+
for (const item of items) {
|
|
72
|
+
const itemBytes = estimateItemBytes(item);
|
|
73
|
+
const wouldExceedItems = batch.length >= maxItems;
|
|
74
|
+
const wouldExceedBytes = batch.length > 0 && batchBytes + itemBytes > maxBytes;
|
|
75
|
+
if (wouldExceedItems || wouldExceedBytes)
|
|
76
|
+
flush();
|
|
77
|
+
batch.push(item);
|
|
78
|
+
batchBytes += itemBytes;
|
|
79
|
+
}
|
|
80
|
+
flush();
|
|
81
|
+
return jobs;
|
|
82
|
+
}
|
|
13
83
|
/**
|
|
14
84
|
* Create a pool of worker threads.
|
|
15
85
|
*/
|
|
16
|
-
export const createWorkerPool = (workerUrl, poolSize) => {
|
|
86
|
+
export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
17
87
|
// Validate worker script exists before spawning to prevent uncaught
|
|
18
88
|
// MODULE_NOT_FOUND crashes in worker threads (e.g. when running from src/ via vitest)
|
|
19
89
|
const workerPath = fileURLToPath(workerUrl);
|
|
@@ -21,102 +91,228 @@ export const createWorkerPool = (workerUrl, poolSize) => {
|
|
|
21
91
|
throw new Error(`Worker script not found: ${workerPath}`);
|
|
22
92
|
}
|
|
23
93
|
const size = poolSize ?? Math.min(8, Math.max(1, os.cpus().length - 1));
|
|
94
|
+
const poolOptions = resolveWorkerPoolOptions(options);
|
|
24
95
|
const workers = [];
|
|
96
|
+
let poolBroken = false;
|
|
97
|
+
let poolFailure;
|
|
25
98
|
for (let i = 0; i < size; i++) {
|
|
26
99
|
workers.push(new Worker(workerUrl));
|
|
27
100
|
}
|
|
28
101
|
const dispatch = (items, onProgress) => {
|
|
102
|
+
if (poolBroken) {
|
|
103
|
+
const reason = poolFailure ? `: ${poolFailure.message}` : '';
|
|
104
|
+
return Promise.reject(new Error(`Worker pool is unavailable after a previous failure${reason}`));
|
|
105
|
+
}
|
|
29
106
|
if (items.length === 0)
|
|
30
107
|
return Promise.resolve([]);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
108
|
+
if (workers.length === 0)
|
|
109
|
+
return Promise.reject(new Error('Worker pool has no active workers'));
|
|
110
|
+
const jobs = createJobs(items, poolOptions.subBatchSize, poolOptions.subBatchMaxBytes, poolOptions.subBatchIdleTimeoutMs);
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const results = [];
|
|
113
|
+
const inFlightProgress = new Array(workers.length).fill(0);
|
|
114
|
+
let completedFiles = 0;
|
|
115
|
+
let activeWorkers = 0;
|
|
116
|
+
let stopped = false;
|
|
117
|
+
let maxReported = 0;
|
|
118
|
+
const reportProgress = () => {
|
|
119
|
+
if (!onProgress)
|
|
120
|
+
return;
|
|
121
|
+
const inFlight = inFlightProgress.reduce((sum, value) => sum + value, 0);
|
|
122
|
+
const next = Math.min(items.length, Math.max(maxReported, completedFiles + inFlight));
|
|
123
|
+
if (next === maxReported)
|
|
124
|
+
return;
|
|
125
|
+
maxReported = next;
|
|
126
|
+
onProgress(next);
|
|
127
|
+
};
|
|
128
|
+
const replaceWorker = async (workerIndex) => {
|
|
129
|
+
const worker = workers[workerIndex];
|
|
130
|
+
await worker?.terminate().catch(() => undefined);
|
|
131
|
+
if (!stopped)
|
|
132
|
+
workers[workerIndex] = new Worker(workerUrl);
|
|
133
|
+
};
|
|
134
|
+
const fail = async (err) => {
|
|
135
|
+
poolBroken = true;
|
|
136
|
+
poolFailure = err;
|
|
137
|
+
if (stopped)
|
|
138
|
+
return;
|
|
139
|
+
stopped = true;
|
|
140
|
+
await Promise.all(workers.map((worker) => worker.terminate().catch(() => undefined)));
|
|
141
|
+
reject(err);
|
|
142
|
+
};
|
|
143
|
+
const maybeDone = () => {
|
|
144
|
+
if (stopped)
|
|
145
|
+
return;
|
|
146
|
+
if (jobs.length === 0 && activeWorkers === 0) {
|
|
147
|
+
stopped = true;
|
|
148
|
+
results.sort((a, b) => a.startIndex - b.startIndex);
|
|
149
|
+
if (onProgress && maxReported < items.length)
|
|
150
|
+
onProgress(items.length);
|
|
151
|
+
resolve(results.map((result) => result.data));
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const requeueAfterTimeout = (workerIndex, job, lastProgress) => {
|
|
155
|
+
const nextTimeout = Math.ceil(job.timeoutMs * poolOptions.timeoutBackoffFactor);
|
|
156
|
+
if (job.items.length > 1) {
|
|
157
|
+
const midpoint = Math.ceil(job.items.length / 2);
|
|
158
|
+
const firstItems = job.items.slice(0, midpoint);
|
|
159
|
+
const secondItems = job.items.slice(midpoint);
|
|
160
|
+
const first = {
|
|
161
|
+
startIndex: job.startIndex,
|
|
162
|
+
items: firstItems,
|
|
163
|
+
estimatedBytes: firstItems.reduce((sum, item) => sum + estimateItemBytes(item), 0),
|
|
164
|
+
attempt: job.attempt,
|
|
165
|
+
splitDepth: job.splitDepth + 1,
|
|
166
|
+
timeoutMs: nextTimeout,
|
|
167
|
+
};
|
|
168
|
+
const second = {
|
|
169
|
+
startIndex: job.startIndex + midpoint,
|
|
170
|
+
items: secondItems,
|
|
171
|
+
estimatedBytes: secondItems.reduce((sum, item) => sum + estimateItemBytes(item), 0),
|
|
172
|
+
attempt: job.attempt,
|
|
173
|
+
splitDepth: job.splitDepth + 1,
|
|
174
|
+
timeoutMs: nextTimeout,
|
|
175
|
+
};
|
|
176
|
+
console.warn(`Worker ${workerIndex} parse job idle timeout after ${job.timeoutMs / 1000}s ` +
|
|
177
|
+
`(${job.items.length} items, ${job.estimatedBytes} bytes, last progress: ${lastProgress}). ` +
|
|
178
|
+
`Splitting into ${first.items.length}/${second.items.length} item jobs with ` +
|
|
179
|
+
`${nextTimeout / 1000}s timeout.`);
|
|
180
|
+
// Preserve intuitive retry order; final result order is still enforced by startIndex sort.
|
|
181
|
+
jobs.unshift(first, second);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
const nextAttempt = job.attempt + 1;
|
|
185
|
+
if (nextAttempt <= poolOptions.maxTimeoutRetries) {
|
|
186
|
+
console.warn(`Worker ${workerIndex} parse job idle timeout after ${job.timeoutMs / 1000}s ` +
|
|
187
|
+
`(single item, attempt ${nextAttempt}/${poolOptions.maxTimeoutRetries + 1}). ` +
|
|
188
|
+
`Retrying with ${nextTimeout / 1000}s timeout.`);
|
|
189
|
+
jobs.unshift({
|
|
190
|
+
...job,
|
|
191
|
+
attempt: nextAttempt,
|
|
192
|
+
timeoutMs: nextTimeout,
|
|
193
|
+
});
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
void fail(new Error(`Worker ${workerIndex} parse job idle timeout after ${job.timeoutMs / 1000}s ` +
|
|
197
|
+
`(single item${itemPath(job.items[0]) ? `: ${itemPath(job.items[0])}` : ''}, ` +
|
|
198
|
+
`${job.estimatedBytes} bytes, last progress: ${lastProgress}). ` +
|
|
199
|
+
`Analyze will retry through sequential fallback. Increase with ` +
|
|
200
|
+
`--worker-timeout or GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS.`));
|
|
201
|
+
return false;
|
|
202
|
+
};
|
|
203
|
+
const runWorker = (workerIndex) => {
|
|
204
|
+
if (stopped)
|
|
205
|
+
return;
|
|
206
|
+
const job = jobs.shift();
|
|
207
|
+
if (!job) {
|
|
208
|
+
maybeDone();
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
activeWorkers++;
|
|
212
|
+
inFlightProgress[workerIndex] = 0;
|
|
213
|
+
const worker = workers[workerIndex];
|
|
40
214
|
let settled = false;
|
|
41
|
-
let
|
|
215
|
+
let waitingForFlush = false;
|
|
216
|
+
let idleTimer = null;
|
|
217
|
+
let lastProgress = 0;
|
|
42
218
|
const cleanup = () => {
|
|
43
|
-
if (
|
|
44
|
-
clearTimeout(
|
|
219
|
+
if (idleTimer)
|
|
220
|
+
clearTimeout(idleTimer);
|
|
45
221
|
worker.removeListener('message', handler);
|
|
46
222
|
worker.removeListener('error', errorHandler);
|
|
47
223
|
worker.removeListener('exit', exitHandler);
|
|
48
224
|
};
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
225
|
+
const finishJob = () => {
|
|
226
|
+
activeWorkers--;
|
|
227
|
+
inFlightProgress[workerIndex] = 0;
|
|
228
|
+
runWorker(workerIndex);
|
|
229
|
+
maybeDone();
|
|
230
|
+
};
|
|
231
|
+
const resetIdleTimer = () => {
|
|
232
|
+
if (idleTimer)
|
|
233
|
+
clearTimeout(idleTimer);
|
|
234
|
+
idleTimer = setTimeout(async () => {
|
|
53
235
|
if (!settled) {
|
|
54
236
|
settled = true;
|
|
55
237
|
cleanup();
|
|
56
|
-
|
|
238
|
+
activeWorkers--;
|
|
239
|
+
inFlightProgress[workerIndex] = 0;
|
|
240
|
+
const shouldContinue = requeueAfterTimeout(workerIndex, job, lastProgress);
|
|
241
|
+
if (!shouldContinue)
|
|
242
|
+
return;
|
|
243
|
+
await replaceWorker(workerIndex);
|
|
244
|
+
reportProgress();
|
|
245
|
+
runWorker(workerIndex);
|
|
246
|
+
maybeDone();
|
|
57
247
|
}
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
let subBatchIdx = 0;
|
|
61
|
-
const sendNextSubBatch = () => {
|
|
62
|
-
const start = subBatchIdx * SUB_BATCH_SIZE;
|
|
63
|
-
if (start >= chunk.length) {
|
|
64
|
-
worker.postMessage({ type: 'flush' });
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
const subBatch = chunk.slice(start, start + SUB_BATCH_SIZE);
|
|
68
|
-
subBatchIdx++;
|
|
69
|
-
resetSubBatchTimer();
|
|
70
|
-
worker.postMessage({ type: 'sub-batch', files: subBatch });
|
|
248
|
+
}, job.timeoutMs);
|
|
71
249
|
};
|
|
72
250
|
const handler = (msg) => {
|
|
73
|
-
if (settled)
|
|
251
|
+
if (settled || stopped)
|
|
74
252
|
return;
|
|
75
253
|
if (msg.type === 'progress') {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
254
|
+
const bounded = Math.min(job.items.length, Math.max(0, msg.filesProcessed));
|
|
255
|
+
inFlightProgress[workerIndex] = bounded;
|
|
256
|
+
lastProgress = bounded;
|
|
257
|
+
resetIdleTimer();
|
|
258
|
+
reportProgress();
|
|
81
259
|
}
|
|
82
260
|
else if (msg.type === 'warning') {
|
|
261
|
+
resetIdleTimer();
|
|
83
262
|
console.warn(msg.message);
|
|
84
263
|
}
|
|
85
264
|
else if (msg.type === 'sub-batch-done') {
|
|
86
|
-
|
|
265
|
+
waitingForFlush = true;
|
|
266
|
+
resetIdleTimer();
|
|
267
|
+
worker.postMessage({ type: 'flush' });
|
|
87
268
|
}
|
|
88
269
|
else if (msg.type === 'error') {
|
|
89
270
|
settled = true;
|
|
90
271
|
cleanup();
|
|
91
|
-
|
|
272
|
+
void fail(new Error(`Worker ${workerIndex} error: ${msg.error}`));
|
|
92
273
|
}
|
|
93
274
|
else if (msg.type === 'result') {
|
|
275
|
+
if (!waitingForFlush) {
|
|
276
|
+
settled = true;
|
|
277
|
+
cleanup();
|
|
278
|
+
void fail(new Error(`Worker ${workerIndex} protocol error: result before flush`));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
94
281
|
settled = true;
|
|
95
282
|
cleanup();
|
|
96
|
-
|
|
283
|
+
results.push({ startIndex: job.startIndex, data: msg.data });
|
|
284
|
+
completedFiles += job.items.length;
|
|
285
|
+
reportProgress();
|
|
286
|
+
finishJob();
|
|
97
287
|
}
|
|
98
288
|
};
|
|
99
289
|
const errorHandler = (err) => {
|
|
100
290
|
if (!settled) {
|
|
101
291
|
settled = true;
|
|
102
292
|
cleanup();
|
|
103
|
-
|
|
293
|
+
void fail(err);
|
|
104
294
|
}
|
|
105
295
|
};
|
|
106
296
|
const exitHandler = (code) => {
|
|
107
297
|
if (!settled) {
|
|
108
298
|
settled = true;
|
|
109
299
|
cleanup();
|
|
110
|
-
|
|
300
|
+
void fail(new Error(`Worker ${workerIndex} exited with code ${code}. Likely OOM or native addon failure.`));
|
|
111
301
|
}
|
|
112
302
|
};
|
|
113
303
|
worker.on('message', handler);
|
|
114
304
|
worker.once('error', errorHandler);
|
|
115
305
|
worker.once('exit', exitHandler);
|
|
116
|
-
|
|
117
|
-
|
|
306
|
+
resetIdleTimer();
|
|
307
|
+
if (stopped) {
|
|
308
|
+
cleanup();
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
worker.postMessage({ type: 'sub-batch', files: job.items });
|
|
312
|
+
};
|
|
313
|
+
for (let i = 0; i < workers.length; i++)
|
|
314
|
+
runWorker(i);
|
|
118
315
|
});
|
|
119
|
-
return Promise.all(promises);
|
|
120
316
|
};
|
|
121
317
|
const terminate = async () => {
|
|
122
318
|
await Promise.all(workers.map((w) => w.terminate()));
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle policy for an optional DuckDB extension.
|
|
3
|
+
*
|
|
4
|
+
* - `auto` — try `LOAD`, fall back to one bounded out-of-process `INSTALL`
|
|
5
|
+
* attempt per process if `LOAD` fails. Default for analyze.
|
|
6
|
+
* - `load-only`— try `LOAD` only; never spawn an installer. Used by serve/MCP
|
|
7
|
+
* read paths so user queries never block on a network install.
|
|
8
|
+
* - `never` — skip the extension entirely. Operators can use this to
|
|
9
|
+
* forcibly disable optional search features.
|
|
10
|
+
*/
|
|
11
|
+
export type ExtensionInstallPolicy = 'auto' | 'load-only' | 'never';
|
|
12
|
+
export interface ExtensionInstallResult {
|
|
13
|
+
success: boolean;
|
|
14
|
+
timedOut: boolean;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/** Snapshot of one optional extension's resolved capability state. */
|
|
18
|
+
export interface ExtensionCapability {
|
|
19
|
+
name: string;
|
|
20
|
+
loaded: boolean;
|
|
21
|
+
/** Human-readable reason when `loaded` is false. */
|
|
22
|
+
reason?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Per-call overrides applied on top of `ExtensionManager` defaults. */
|
|
25
|
+
export interface ExtensionEnsureOptions {
|
|
26
|
+
policy?: ExtensionInstallPolicy;
|
|
27
|
+
installTimeoutMs?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface ExtensionManagerOptions {
|
|
30
|
+
policy?: ExtensionInstallPolicy;
|
|
31
|
+
installTimeoutMs?: number;
|
|
32
|
+
installExtension?: (extensionName: string, timeoutMs: number) => Promise<ExtensionInstallResult>;
|
|
33
|
+
warn?: (message: string) => void;
|
|
34
|
+
}
|
|
35
|
+
export declare const getExtensionInstallTimeoutMs: () => number;
|
|
36
|
+
export declare const getExtensionInstallChildProcessArgs: (extensionName: string) => string[];
|
|
37
|
+
/**
|
|
38
|
+
* Run `INSTALL <extension>` in a short-lived child Node process so the parent
|
|
39
|
+
* event loop is never blocked by DuckDB's synchronous network call.
|
|
40
|
+
*
|
|
41
|
+
* The child opens its own scratch LadybugDB, executes the install, and exits.
|
|
42
|
+
* If the child exceeds `timeoutMs` the parent kills it with SIGKILL and
|
|
43
|
+
* resolves with `timedOut: true`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const installDuckDbExtensionOutOfProcess: (extensionName: string, timeoutMs?: number) => Promise<ExtensionInstallResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Centralized lifecycle manager for optional LadybugDB extensions.
|
|
48
|
+
*
|
|
49
|
+
* Always tries `LOAD EXTENSION <name>` first — it is per-connection,
|
|
50
|
+
* idempotent, and never touches the network. If `LOAD` fails and the active
|
|
51
|
+
* policy permits, the manager runs a single bounded out-of-process `INSTALL`
|
|
52
|
+
* attempt per process and retries `LOAD`. Capability outcomes are cached so
|
|
53
|
+
* unavailable extensions degrade search features without ever blocking
|
|
54
|
+
* subsequent analyze or query calls.
|
|
55
|
+
*
|
|
56
|
+
* Policy precedence (most specific wins):
|
|
57
|
+
* per-call `opts.policy` → constructor `options.policy` → env → `auto`
|
|
58
|
+
*/
|
|
59
|
+
export declare class ExtensionManager {
|
|
60
|
+
private readonly options;
|
|
61
|
+
private readonly capabilities;
|
|
62
|
+
private readonly installAttempted;
|
|
63
|
+
private readonly warnedKeys;
|
|
64
|
+
constructor(options?: ExtensionManagerOptions);
|
|
65
|
+
/** Reset cached capability and install state. Test-only. */
|
|
66
|
+
reset(): void;
|
|
67
|
+
/** Snapshot of currently-known optional extension capabilities. */
|
|
68
|
+
getCapabilities(): ExtensionCapability[];
|
|
69
|
+
/**
|
|
70
|
+
* Ensure an optional extension is loaded on the supplied connection.
|
|
71
|
+
*
|
|
72
|
+
* Returns `true` when the extension is usable on `query`, `false` when it
|
|
73
|
+
* is unavailable. Never throws on install failure — analyze and query
|
|
74
|
+
* paths are expected to degrade gracefully.
|
|
75
|
+
*/
|
|
76
|
+
ensure(query: (sql: string) => Promise<unknown>, name: string, label: string, opts?: ExtensionEnsureOptions): Promise<boolean>;
|
|
77
|
+
private tryLoad;
|
|
78
|
+
private markLoaded;
|
|
79
|
+
private markUnavailable;
|
|
80
|
+
}
|
|
81
|
+
/** Process-wide singleton shared by core and pool adapters. */
|
|
82
|
+
export declare const extensionManager: ExtensionManager;
|
|
83
|
+
/** Snapshot of which optional DuckDB extensions are loaded in this process. */
|
|
84
|
+
export declare const getExtensionCapabilities: () => ExtensionCapability[];
|
|
85
|
+
/** Test-only: clear the singleton's cached capability and install state. */
|
|
86
|
+
export declare const resetExtensionState: () => void;
|