gitnexus 1.6.10-rc.2 → 1.6.10-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 +56 -12
- package/dist/cli/analyze.js +166 -5
- package/dist/cli/clean.js +17 -3
- package/dist/cli/cli-message.d.ts +1 -1
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/doctor.js +76 -3
- package/dist/cli/embeddings.d.ts +12 -0
- package/dist/cli/embeddings.js +49 -0
- package/dist/cli/help-i18n.js +4 -0
- package/dist/cli/i18n/en.d.ts +10 -5
- package/dist/cli/i18n/en.js +10 -5
- package/dist/cli/i18n/resources.d.ts +15 -5
- package/dist/cli/i18n/zh-CN.d.ts +5 -0
- package/dist/cli/i18n/zh-CN.js +10 -5
- package/dist/cli/index.js +12 -1
- package/dist/core/augmentation/engine.js +4 -3
- package/dist/core/embeddings/embedder.js +16 -2
- package/dist/core/embeddings/embedding-pipeline.d.ts +20 -0
- package/dist/core/embeddings/embedding-pipeline.js +10 -2
- package/dist/core/embeddings/http-client.d.ts +28 -1
- package/dist/core/embeddings/http-client.js +107 -15
- package/dist/core/embeddings/node-module-compat.d.ts +23 -0
- package/dist/core/embeddings/node-module-compat.js +23 -0
- package/dist/core/embeddings/onnxruntime-common-resolver.js +6 -3
- package/dist/core/embeddings/onnxruntime-node-resolver.js +31 -5
- package/dist/core/embeddings/runtime-install.d.ts +119 -0
- package/dist/core/embeddings/runtime-install.js +372 -0
- package/dist/core/embeddings/runtime-support.d.ts +48 -17
- package/dist/core/embeddings/runtime-support.js +96 -0
- package/dist/core/group/extractors/http-patterns/python.js +246 -108
- package/dist/core/group/extractors/manifest-extractor.js +4 -0
- package/dist/core/incremental/escalation-gate.d.ts +38 -0
- package/dist/core/incremental/escalation-gate.js +48 -0
- package/dist/core/incremental/shadow-candidates.d.ts +3 -3
- package/dist/core/incremental/shadow-candidates.js +3 -3
- package/dist/core/incremental/subgraph-extract.d.ts +2 -2
- package/dist/core/incremental/subgraph-extract.js +2 -2
- package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
- package/dist/core/ingestion/cobol-processor.js +27 -26
- package/dist/core/ingestion/community-processor.d.ts +51 -1
- package/dist/core/ingestion/community-processor.js +316 -63
- package/dist/core/ingestion/emit-references.js +3 -2
- package/dist/core/ingestion/languages/cpp/captures.js +157 -74
- package/dist/core/ingestion/markdown-processor.js +3 -2
- package/dist/core/ingestion/parsing-processor.d.ts +3 -1
- package/dist/core/ingestion/parsing-processor.js +4 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +42 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +83 -0
- package/dist/core/ingestion/route-extractors/constant-resolver.js +131 -0
- package/dist/core/ingestion/route-extractors/python-const-resolver.d.ts +75 -0
- package/dist/core/ingestion/route-extractors/python-const-resolver.js +299 -0
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
- package/dist/core/ingestion/tree-sitter-queries.js +12 -1
- package/dist/core/ingestion/utils/line-base.d.ts +20 -0
- package/dist/core/ingestion/utils/line-base.js +20 -0
- package/dist/core/ingestion/utils/symbol-labels.d.ts +21 -0
- package/dist/core/ingestion/utils/symbol-labels.js +45 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +34 -0
- package/dist/core/ingestion/workers/parse-worker.js +40 -5
- package/dist/core/ingestion/workers/result-merge.js +4 -0
- package/dist/core/ingestion/workers/worker-pool.d.ts +14 -0
- package/dist/core/ingestion/workers/worker-pool.js +85 -5
- package/dist/core/lbug/csv-generator.js +8 -2
- package/dist/core/lbug/cypher-escape.d.ts +20 -0
- package/dist/core/lbug/cypher-escape.js +20 -0
- package/dist/core/lbug/extension-load-error.d.ts +67 -0
- package/dist/core/lbug/extension-load-error.js +320 -0
- package/dist/core/lbug/extension-loader.d.ts +17 -2
- package/dist/core/lbug/extension-loader.js +38 -13
- package/dist/core/lbug/lbug-adapter.d.ts +147 -1
- package/dist/core/lbug/lbug-adapter.js +390 -70
- package/dist/core/lbug/lbug-config.d.ts +28 -0
- package/dist/core/lbug/lbug-config.js +114 -4
- package/dist/core/lbug/native-check.d.ts +22 -0
- package/dist/core/lbug/native-check.js +66 -0
- package/dist/core/lbug/pool-adapter.js +10 -1
- package/dist/core/lbug/sidecar-recovery.d.ts +172 -0
- package/dist/core/lbug/sidecar-recovery.js +418 -16
- package/dist/core/platform/capabilities.js +27 -1
- package/dist/core/run-analyze.js +470 -108
- package/dist/core/search/fts-indexes.d.ts +7 -0
- package/dist/core/search/fts-indexes.js +37 -0
- package/dist/core/tree-sitter/safe-parse.d.ts +8 -3
- package/dist/core/tree-sitter/safe-parse.js +21 -7
- package/dist/core/wiki/graph-queries.js +6 -5
- package/dist/mcp/core/embedder.js +16 -2
- package/dist/mcp/local/line-display.d.ts +22 -0
- package/dist/mcp/local/line-display.js +3 -0
- package/dist/mcp/local/local-backend.d.ts +14 -0
- package/dist/mcp/local/local-backend.js +63 -19
- package/dist/mcp/local/pdg-impact.d.ts +5 -3
- package/dist/mcp/local/pdg-impact.js +5 -2
- package/dist/mcp/resources.js +1 -0
- package/dist/mcp/tools.js +1 -1
- package/dist/server/analyze-launch.d.ts +6 -0
- package/dist/server/analyze-launch.js +82 -6
- package/dist/server/api.d.ts +30 -0
- package/dist/server/api.js +63 -21
- package/dist/storage/parse-cache.js +1 -1
- package/dist/storage/repo-manager.d.ts +65 -1
- package/dist/storage/repo-manager.js +18 -1
- package/hooks/antigravity/gitnexus-antigravity-hook.cjs +50 -3
- package/hooks/claude/gitnexus-hook.cjs +59 -9
- package/package.json +5 -3
- package/scripts/cross-platform-tests.ts +43 -0
- package/scripts/ensure-fts.ts +32 -0
- package/scripts/install-duckdb-extension.mjs +85 -24
- package/scripts/run-cross-platform.ts +46 -6
- package/scripts/shard-arg.ts +30 -0
- package/web/assets/ProcessFlowModal-Dna7GkwO.js +22 -0
- package/web/assets/{agent-Dli_x7bU.js → agent-DNYDy-KA.js} +49 -49
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +1 -0
- package/web/assets/architectureDiagram-UL44E2DR-BU5ZRITg.js +36 -0
- package/web/assets/{blockDiagram-7IZFK4PR-BkWhpzWB.js → blockDiagram-7IZFK4PR-Dut1BpTV.js} +2 -2
- package/web/assets/{c4Diagram-Y2BXMSZH-DtBvpzWD.js → c4Diagram-Y2BXMSZH-DOXVs7-C.js} +2 -2
- package/web/assets/chunk-2T2R6R2M-pkw2oXHH.js +4 -0
- package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +1 -0
- package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +321 -0
- package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +159 -0
- package/web/assets/{chunk-6764PJDD-DpIS7hxD.js → chunk-6764PJDD-C7xxk063.js} +1 -1
- package/web/assets/{chunk-67TQ5CYL-4sNPJU1q.js → chunk-67TQ5CYL-zxhDWgyF.js} +3 -3
- package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +32 -0
- package/web/assets/chunk-7J6CGLKN-AmkN8jJN.js +10 -0
- package/web/assets/chunk-7W6UQGC5-pyKGssV3.js +1 -0
- package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +1 -0
- package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +1 -0
- package/web/assets/{chunk-INKRHTLW-Nu4ri9P-.js → chunk-INKRHTLW-D9BM9HWZ.js} +1 -1
- package/web/assets/chunk-J5EP6P6S-L19oz55R.js +1 -0
- package/web/assets/{chunk-KGFNY3KK-JGMJvKCK.js → chunk-KGFNY3KK-tD2F6wxK.js} +1 -1
- package/web/assets/chunk-KGYTTC2M-zm6n242I.js +1 -0
- package/web/assets/{chunk-KRXBNO2N-BW5o0KUN.js → chunk-KRXBNO2N-C-UNuKKf.js} +1 -1
- package/web/assets/{chunk-LCXTWHL2-CfLLCywY.js → chunk-LCXTWHL2-Ba9JK-6F.js} +2 -2
- package/web/assets/{chunk-LII3EMHJ-D-jm-dLa.js → chunk-LII3EMHJ-EGx-eBIu.js} +1 -1
- package/web/assets/chunk-LRIF4GLE-C3_PqUBq.js +1 -0
- package/web/assets/{chunk-QA3QBVWF-BgRW3SXd.js → chunk-QA3QBVWF-D4cSJBf6.js} +1 -1
- package/web/assets/chunk-RERM46MO-B5dAdWpP.js +1 -0
- package/web/assets/{chunk-RG4AUYOV-CqWzWsV3.js → chunk-RG4AUYOV-OqBBMwuQ.js} +4 -4
- package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +1 -0
- package/web/assets/chunk-RLI5ZMPA-CkXZ0y0U.js +1 -0
- package/web/assets/{chunk-T2UQINTJ-DSBqkzH7.js → chunk-T2UQINTJ-BJusEiGe.js} +1 -1
- package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +1 -0
- package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +1 -0
- package/web/assets/{chunk-UY5QBCOK-DyF0vyGd.js → chunk-UY5QBCOK-BCpUlARQ.js} +1 -1
- package/web/assets/chunk-VU6ZFW4Y-BeXVk45_.js +2 -0
- package/web/assets/{chunk-W44A43WB-JqMLIpR0.js → chunk-W44A43WB-BN8EQc_u.js} +1 -1
- package/web/assets/{chunk-ZXARS5L4-CxN8oiwI.js → chunk-ZXARS5L4-BI_qR2Nm.js} +1 -1
- package/web/assets/classDiagram-KGZ6W3CR-D9zSIg0x.js +1 -0
- package/web/assets/classDiagram-v2-72OJOZXJ-D9zSIg0x.js +1 -0
- package/web/assets/cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js +1 -0
- package/web/assets/dagre-ND4H6XIP-CpcV5kbl.js +4 -0
- package/web/assets/diagram-3NCE3AQN-6SMxBRpj.js +43 -0
- package/web/assets/diagram-GF46GFSD-BZEdNcRZ.js +24 -0
- package/web/assets/{diagram-HNR7UZ2L-DFCfd5LI.js → diagram-HNR7UZ2L-DxKW2a2Y.js} +2 -2
- package/web/assets/diagram-QXG6HAR7-HfTHcXX_.js +24 -0
- package/web/assets/diagram-WEQXMOUZ-CyijUS8r.js +10 -0
- package/web/assets/{erDiagram-L5TCEMPS-8X1y6R4Y.js → erDiagram-L5TCEMPS-D0fvpWEX.js} +3 -3
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +1 -0
- package/web/assets/flowDiagram-H6V6AXG4-Bvr9bbhk.js +162 -0
- package/web/assets/{ganttDiagram-JCBTUEKG-D3iL2Aet.js → ganttDiagram-JCBTUEKG-TzODrLzv.js} +2 -2
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +1 -0
- package/web/assets/gitGraphDiagram-S2ZK5IYY-ONQSwJIY.js +106 -0
- package/web/assets/index-B4eB4dNZ.js +575 -0
- package/web/assets/index-CX_fADmQ.css +2 -0
- package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +1 -0
- package/web/assets/infoDiagram-3YFTVSEB-DIPVUIQ6.js +2 -0
- package/web/assets/{ishikawaDiagram-BNXS4ZKH-DfYpxnE5.js → ishikawaDiagram-BNXS4ZKH-BLjivjXL.js} +3 -3
- package/web/assets/{journeyDiagram-M6C3CM3L-CvArszLo.js → journeyDiagram-M6C3CM3L-Cetgs3NH.js} +3 -3
- package/web/assets/{kanban-definition-75IXJCU3-CpfVLLf9.js → kanban-definition-75IXJCU3-DMlCaIpf.js} +5 -5
- package/web/assets/{katex-K3KEBU37-CTc5BslQ.js → katex-K3KEBU37-qRQBy-EZ.js} +2 -2
- package/web/assets/{mindmap-definition-2TDM6QVE-DypvbOMQ.js → mindmap-definition-2TDM6QVE-B4GbXQBc.js} +3 -3
- package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +1 -0
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +1 -0
- package/web/assets/{pieDiagram-CU6KROY3-s27EFWgP.js → pieDiagram-CU6KROY3-D3YC_xyg.js} +2 -2
- package/web/assets/{quadrantDiagram-VICAPDV7-yXSZ2lLz.js → quadrantDiagram-VICAPDV7-B1TQnlm0.js} +2 -2
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +1 -0
- package/web/assets/{requirementDiagram-JXO7QTGE-CWhqInuf.js → requirementDiagram-JXO7QTGE-f8wczLQf.js} +3 -3
- package/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/web/assets/{sankeyDiagram-URQDO5SZ-1qEjlFIB.js → sankeyDiagram-URQDO5SZ-BTxzG5j0.js} +2 -2
- package/web/assets/{sequenceDiagram-VS2MUI6T-RyTlZ5cR.js → sequenceDiagram-VS2MUI6T-DuamM-IR.js} +5 -5
- package/web/assets/src-BNCXICdA.js +1 -0
- package/web/assets/stateDiagram-7D4R322I-Ch2pEUcw.js +1 -0
- package/web/assets/stateDiagram-v2-36443NZ5-7ANuoZLL.js +1 -0
- package/web/assets/{timeline-definition-O6YCAMPW-DrrqLYAf.js → timeline-definition-O6YCAMPW-07BR8R8G.js} +3 -3
- package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +1 -0
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +1 -0
- package/web/assets/{vennDiagram-MWXL3ELB-B0RkWAim.js → vennDiagram-MWXL3ELB-BQX2ossk.js} +4 -4
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +1 -0
- package/web/assets/{wardleyDiagram-CUQ6CDDI-boUxiQ5F.js → wardleyDiagram-CUQ6CDDI-CGIJBBiK.js} +3 -3
- package/web/assets/{xychartDiagram-N2JHSOCM-BOLm0eNm.js → xychartDiagram-N2JHSOCM-B3HNMuWp.js} +4 -4
- package/web/index.html +17 -10
- package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +0 -1
- package/web/assets/architectureDiagram-UL44E2DR-dEkqUZN9.js +0 -36
- package/web/assets/chunk-3SSMPTDK-B4_etUhr.js +0 -321
- package/web/assets/chunk-7W6UQGC5-KyEG0HQg.js +0 -1
- package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +0 -161
- package/web/assets/classDiagram-KGZ6W3CR-CMne4tG9.js +0 -1
- package/web/assets/classDiagram-v2-72OJOZXJ-CMne4tG9.js +0 -1
- package/web/assets/cose-bilkent-UX7MHV2Q-D71wNYRJ.js +0 -1
- package/web/assets/dagre-ND4H6XIP-Co5rRx9X.js +0 -4
- package/web/assets/diagram-3NCE3AQN-DBp4O00j.js +0 -43
- package/web/assets/diagram-GF46GFSD-6N_8yS0i.js +0 -24
- package/web/assets/diagram-QXG6HAR7-Di093rFg.js +0 -24
- package/web/assets/diagram-WEQXMOUZ-DZWi4SUN.js +0 -10
- package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +0 -1
- package/web/assets/flowDiagram-H6V6AXG4-CMpY8Ufn.js +0 -162
- package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +0 -1
- package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +0 -106
- package/web/assets/index-KctnI3Vq.js +0 -635
- package/web/assets/index-_lgn7hs5.css +0 -2
- package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +0 -1
- package/web/assets/infoDiagram-3YFTVSEB-BaLMZkUg.js +0 -2
- package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +0 -1
- package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +0 -1
- package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +0 -1
- package/web/assets/stateDiagram-7D4R322I-DTjVfX4A.js +0 -1
- package/web/assets/stateDiagram-v2-36443NZ5-xY9_k9_Q.js +0 -1
- package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +0 -1
- package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +0 -1
- package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +0 -1
|
@@ -751,6 +751,7 @@ export function extractORMQueries(filePath, content, out) {
|
|
|
751
751
|
// per file; this module does not re-export it. Downstream consumers
|
|
752
752
|
// import the function and its types directly from `route-extractors/`.
|
|
753
753
|
import { extractFastAPIRouterBindings } from '../route-extractors/fastapi-router-bindings.js';
|
|
754
|
+
import { extractPythonModuleConstants, parseConstOperands, } from '../route-extractors/python-const-resolver.js';
|
|
754
755
|
/**
|
|
755
756
|
* Report a non-fatal worker issue to the pool over IPC so a caught error is not
|
|
756
757
|
* invisible to the operator (#2264). The pool logs it on the main thread AND
|
|
@@ -813,7 +814,7 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
813
814
|
try {
|
|
814
815
|
tree = parseSourceSafe(parser, parseContent, undefined, {
|
|
815
816
|
bufferSize: getTreeSitterBufferSize(parseContent),
|
|
816
|
-
});
|
|
817
|
+
}, file.path);
|
|
817
818
|
}
|
|
818
819
|
catch (err) {
|
|
819
820
|
reportWarning(`Failed to parse file ${file.path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -986,6 +987,12 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
986
987
|
if (captureMap['decorator'] && captureMap['decorator.name']) {
|
|
987
988
|
const decoratorName = captureMap['decorator.name'].text;
|
|
988
989
|
const decoratorArg = captureMap['decorator.arg']?.text;
|
|
990
|
+
// #2391: the first positional arg captured as either a string node
|
|
991
|
+
// (`arg_str`, present even for the empty-string literal `""` which has no
|
|
992
|
+
// `string_content`) or a non-literal expression (`arg_expr`: an
|
|
993
|
+
// identifier or a `+`-concatenation).
|
|
994
|
+
const decoratorArgStr = captureMap['decorator.arg_str'];
|
|
995
|
+
const decoratorArgExpr = captureMap['decorator.arg_expr'];
|
|
989
996
|
const decoratorReceiver = captureMap['decorator.receiver']?.text;
|
|
990
997
|
const decoratorNode = captureMap['decorator'];
|
|
991
998
|
// Store by the decorator's end line — the definition follows immediately after
|
|
@@ -994,19 +1001,39 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
994
1001
|
arg: decoratorArg,
|
|
995
1002
|
});
|
|
996
1003
|
if (ROUTE_DECORATOR_NAMES.has(decoratorName)) {
|
|
997
|
-
const routePath = decoratorArg || '';
|
|
998
1004
|
const method = decoratorName.replace('Mapping', '').toUpperCase();
|
|
999
1005
|
const httpMethod = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(method)
|
|
1000
1006
|
? method
|
|
1001
1007
|
: 'GET';
|
|
1002
|
-
|
|
1008
|
+
const base = {
|
|
1003
1009
|
filePath: file.path,
|
|
1004
|
-
routePath,
|
|
1005
1010
|
httpMethod,
|
|
1006
1011
|
decoratorName,
|
|
1007
1012
|
lineNumber: decoratorNode.startPosition.row + lineOffset,
|
|
1008
1013
|
...(decoratorReceiver ? { decoratorReceiver } : {}),
|
|
1009
|
-
}
|
|
1014
|
+
};
|
|
1015
|
+
if (decoratorArgStr) {
|
|
1016
|
+
// String-literal path (the fast path, unchanged). Empty-string
|
|
1017
|
+
// literal `""` has no `string_content` → `decoratorArg` undefined →
|
|
1018
|
+
// routePath '' (a valid path under an APIRouter prefix).
|
|
1019
|
+
result.decoratorRoutes.push({ ...base, routePath: decoratorArg ?? '' });
|
|
1020
|
+
}
|
|
1021
|
+
else if (decoratorArgExpr) {
|
|
1022
|
+
// #2391 non-literal path (imported/composed constant). Emit the raw
|
|
1023
|
+
// expression + its operands for cross-file resolution in parse-impl;
|
|
1024
|
+
// `routePath` stays empty until resolved (or the route is dropped).
|
|
1025
|
+
const operands = decoratorArgExpr.type === 'identifier'
|
|
1026
|
+
? [{ kind: 'ref', name: decoratorArgExpr.text }]
|
|
1027
|
+
: parseConstOperands(decoratorArgExpr);
|
|
1028
|
+
result.decoratorRoutes.push({
|
|
1029
|
+
...base,
|
|
1030
|
+
routePath: '',
|
|
1031
|
+
routePathExpr: decoratorArgExpr.text,
|
|
1032
|
+
...(operands ? { routePathOperands: operands } : {}),
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
// Otherwise the first arg is absent or an unsupported shape
|
|
1036
|
+
// (attribute access, call, …) → skip; never a phantom `POST /`.
|
|
1010
1037
|
}
|
|
1011
1038
|
// MCP/RPC tool detection: @mcp.tool(), @app.tool(), @server.tool()
|
|
1012
1039
|
if (decoratorName === 'tool') {
|
|
@@ -1839,6 +1866,14 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
|
|
|
1839
1866
|
// came from a `@router.<verb>` decorator. Python-only.
|
|
1840
1867
|
if (language === SupportedLanguages.Python) {
|
|
1841
1868
|
extractFastAPIRouterBindings(file.path, parseContent, result.routerIncludes, result.routerImports, (result.routerModuleAliases ??= []), (result.routerConstructorPrefixes ??= []));
|
|
1869
|
+
// #2391: harvest module-level string constants + from-imports so parse-impl
|
|
1870
|
+
// can resolve non-literal decorator route paths cross-file. Only emit for
|
|
1871
|
+
// files that carry something resolvable (a constant definition or an import
|
|
1872
|
+
// binding) to keep the aggregate bounded on large repos.
|
|
1873
|
+
const constants = extractPythonModuleConstants(tree);
|
|
1874
|
+
if (constants.literals.size > 0 || constants.exprs.size > 0 || constants.imports.size > 0) {
|
|
1875
|
+
(result.moduleConstants ??= []).push({ filePath: file.path, constants });
|
|
1876
|
+
}
|
|
1842
1877
|
}
|
|
1843
1878
|
// Language-specific decorator route extraction via provider hook.
|
|
1844
1879
|
// The provider's extractDecoratorRoutes walks the AST for framework-specific
|
|
@@ -32,6 +32,10 @@ export const mergeResult = (target, src) => {
|
|
|
32
32
|
target.routerModuleAliases ??= [];
|
|
33
33
|
appendAll(target.routerModuleAliases, src.routerModuleAliases);
|
|
34
34
|
}
|
|
35
|
+
if (src.moduleConstants) {
|
|
36
|
+
target.moduleConstants ??= [];
|
|
37
|
+
appendAll(target.moduleConstants, src.moduleConstants);
|
|
38
|
+
}
|
|
35
39
|
if (src.springTypes) {
|
|
36
40
|
target.springTypes ??= [];
|
|
37
41
|
appendAll(target.springTypes, src.springTypes);
|
|
@@ -135,6 +135,19 @@ export interface WorkerPoolOptions {
|
|
|
135
135
|
pdg?: boolean;
|
|
136
136
|
/** Per-function source-line cap for worker-side CFG construction (0 ⇒ no cap). */
|
|
137
137
|
pdgMaxFunctionLines?: number;
|
|
138
|
+
/**
|
|
139
|
+
* Max wall time `terminate()` waits for a retired worker that has NOT yet
|
|
140
|
+
* reached a JS-visible safe point before giving up on terminating it
|
|
141
|
+
* (#2432). Terminating a worker thread that is inside an N-API call aborts
|
|
142
|
+
* the whole process (`Napi::Error` → `std::terminate` → SIGABRT) — and the
|
|
143
|
+
* same abort fires at plain process exit, so the drain is what makes
|
|
144
|
+
* shutdown safe. On expiry the worker is left running (unref'd, with its
|
|
145
|
+
* at-safe-point terminate listener still armed) and a diagnostic is logged.
|
|
146
|
+
* Default 30000ms — above the C++ capture budget
|
|
147
|
+
* (`GITNEXUS_CPP_CAPTURE_BUDGET_MS`, 20000ms) so the drain converges for
|
|
148
|
+
* the known pathological class. 0 ⇒ no wait (test hook).
|
|
149
|
+
*/
|
|
150
|
+
shutdownDrainMs?: number;
|
|
138
151
|
}
|
|
139
152
|
export declare class WorkerPoolDispatchError extends Error {
|
|
140
153
|
/**
|
|
@@ -193,6 +206,7 @@ interface ResolvedWorkerPoolOptions {
|
|
|
193
206
|
maxRespawnsPerSlot: number;
|
|
194
207
|
maxCumulativeTimeoutMs: number;
|
|
195
208
|
consecutiveFailureThreshold: number;
|
|
209
|
+
shutdownDrainMs: number;
|
|
196
210
|
}
|
|
197
211
|
export declare function resolveWorkerPoolOptions(options?: WorkerPoolOptions, poolSize?: number): ResolvedWorkerPoolOptions;
|
|
198
212
|
/**
|
|
@@ -231,6 +231,8 @@ function nonNegativeInteger(value) {
|
|
|
231
231
|
? Math.floor(parsed)
|
|
232
232
|
: undefined;
|
|
233
233
|
}
|
|
234
|
+
/** See {@link WorkerPoolOptions.shutdownDrainMs}. */
|
|
235
|
+
const DEFAULT_SHUTDOWN_DRAIN_MS = 30_000;
|
|
234
236
|
export function resolveWorkerPoolOptions(options = {}, poolSize) {
|
|
235
237
|
const subBatchIdleTimeoutMs = positiveInteger(options.subBatchIdleTimeoutMs) ??
|
|
236
238
|
positiveInteger(process.env.GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS) ??
|
|
@@ -252,6 +254,9 @@ export function resolveWorkerPoolOptions(options = {}, poolSize) {
|
|
|
252
254
|
consecutiveFailureThreshold: positiveInteger(options.consecutiveFailureThreshold) ??
|
|
253
255
|
positiveInteger(process.env.GITNEXUS_WORKER_CONSECUTIVE_FAILURE_THRESHOLD) ??
|
|
254
256
|
Math.max(DEFAULT_CONSECUTIVE_FAILURE_THRESHOLD_FLOOR, poolSize ?? 0),
|
|
257
|
+
shutdownDrainMs: nonNegativeInteger(options.shutdownDrainMs) ??
|
|
258
|
+
nonNegativeInteger(process.env.GITNEXUS_WORKER_SHUTDOWN_DRAIN_MS) ??
|
|
259
|
+
DEFAULT_SHUTDOWN_DRAIN_MS,
|
|
255
260
|
};
|
|
256
261
|
}
|
|
257
262
|
/**
|
|
@@ -608,13 +613,50 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
|
608
613
|
// Set by `terminate()` (below). Also read by the self-healing startup loop so
|
|
609
614
|
// a terminate during startup aborts pending backoff/retries (#1741).
|
|
610
615
|
let terminated = false;
|
|
616
|
+
/** Resolves `true` when `promise` settles within `ms`, else `false`. The
|
|
617
|
+
* timer is unref'd so an expiring drain never holds the process open. */
|
|
618
|
+
const settledWithin = (promise, ms) => {
|
|
619
|
+
if (ms <= 0)
|
|
620
|
+
return Promise.resolve(false);
|
|
621
|
+
return new Promise((resolve) => {
|
|
622
|
+
const timer = setTimeout(() => resolve(false), ms);
|
|
623
|
+
timer.unref?.();
|
|
624
|
+
void promise.then(() => {
|
|
625
|
+
clearTimeout(timer);
|
|
626
|
+
resolve(true);
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
};
|
|
611
630
|
const terminateTrackedWorkers = async (liveWorkers) => {
|
|
612
631
|
const retired = Array.from(retiredWorkers);
|
|
613
632
|
await Promise.all([
|
|
614
633
|
...liveWorkers.map((worker) => worker?.terminate().catch(() => undefined)),
|
|
615
|
-
...retired.map((record) =>
|
|
634
|
+
...retired.map(async (record) => {
|
|
635
|
+
// #2432: a retired worker that has not reached a JS-visible safe
|
|
636
|
+
// point may be inside an N-API call — terminating it aborts the
|
|
637
|
+
// WHOLE process (`Napi::Error` → std::terminate → SIGABRT). Drain:
|
|
638
|
+
// wait (bounded) for its safe point; on expiry leave it running —
|
|
639
|
+
// it is unref'd and its at-safe-point terminate listener stays
|
|
640
|
+
// armed — and log which file wedged it.
|
|
641
|
+
if (!record.safeToTerminate) {
|
|
642
|
+
const drained = await settledWithin(record.safePoint, poolOptions.shutdownDrainMs);
|
|
643
|
+
if (!drained) {
|
|
644
|
+
logger.warn({
|
|
645
|
+
workerIndex: record.workerIndex,
|
|
646
|
+
reason: record.reason,
|
|
647
|
+
drainMs: poolOptions.shutdownDrainMs,
|
|
648
|
+
}, `Worker ${record.workerIndex} is still inside native code after the ` +
|
|
649
|
+
`${poolOptions.shutdownDrainMs}ms shutdown drain; leaving it un-terminated ` +
|
|
650
|
+
`to avoid a native abort (#2432). It will be terminated at its next safe point.`);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
await record.terminate();
|
|
655
|
+
}),
|
|
616
656
|
]);
|
|
617
|
-
|
|
657
|
+
// Undrained records stay tracked so a repeated shutdown call can retry
|
|
658
|
+
// their (now possibly safe) terminate; record.terminate() removes each
|
|
659
|
+
// drained record via its cleanup.
|
|
618
660
|
};
|
|
619
661
|
for (let i = 0; i < size; i++) {
|
|
620
662
|
workers[i] = spawnAndCapture(workerUrl);
|
|
@@ -788,6 +830,18 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
|
788
830
|
const retireWorkerAfterTimeout = (worker, workerIndex, reason) => {
|
|
789
831
|
let cleaned = false;
|
|
790
832
|
let terminateStarted = false;
|
|
833
|
+
let resolveSafePoint;
|
|
834
|
+
const safePoint = new Promise((resolve) => {
|
|
835
|
+
resolveSafePoint = resolve;
|
|
836
|
+
});
|
|
837
|
+
// A message/messageerror proves the worker is executing JS again; an
|
|
838
|
+
// exit/error means the thread is gone. Either way `worker.terminate()`
|
|
839
|
+
// can no longer land mid-N-API call (#2432), so shutdown's drain may
|
|
840
|
+
// stop waiting.
|
|
841
|
+
function markSafeToTerminate() {
|
|
842
|
+
record.safeToTerminate = true;
|
|
843
|
+
resolveSafePoint();
|
|
844
|
+
}
|
|
791
845
|
function cleanupRetired() {
|
|
792
846
|
if (cleaned)
|
|
793
847
|
return;
|
|
@@ -806,6 +860,7 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
|
806
860
|
await worker.terminate().catch(() => undefined);
|
|
807
861
|
}
|
|
808
862
|
function terminateWhenBackInJs() {
|
|
863
|
+
markSafeToTerminate();
|
|
809
864
|
void terminateRetired();
|
|
810
865
|
}
|
|
811
866
|
function onRetiredMessage(raw) {
|
|
@@ -816,8 +871,14 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
|
816
871
|
terminateWhenBackInJs();
|
|
817
872
|
}
|
|
818
873
|
}
|
|
819
|
-
const onRetiredError = () =>
|
|
820
|
-
|
|
874
|
+
const onRetiredError = () => {
|
|
875
|
+
markSafeToTerminate();
|
|
876
|
+
cleanupRetired();
|
|
877
|
+
};
|
|
878
|
+
const onRetiredExit = () => {
|
|
879
|
+
markSafeToTerminate();
|
|
880
|
+
cleanupRetired();
|
|
881
|
+
};
|
|
821
882
|
const onRetiredMessageError = () => terminateWhenBackInJs();
|
|
822
883
|
const record = {
|
|
823
884
|
worker,
|
|
@@ -825,6 +886,8 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
|
825
886
|
reason,
|
|
826
887
|
cleanup: cleanupRetired,
|
|
827
888
|
terminate: terminateRetired,
|
|
889
|
+
safeToTerminate: false,
|
|
890
|
+
safePoint,
|
|
828
891
|
};
|
|
829
892
|
retiredWorkers.add(record);
|
|
830
893
|
worker.on('message', onRetiredMessage);
|
|
@@ -890,8 +953,25 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
|
|
|
890
953
|
const liveWorkers = workers.slice();
|
|
891
954
|
for (let i = 0; i < workers.length; i++)
|
|
892
955
|
workers[i] = undefined;
|
|
956
|
+
// #2432: a live worker with a job in flight may be inside an N-API
|
|
957
|
+
// call — direct terminate risks the same native abort as the retired
|
|
958
|
+
// case. Route busy workers through the retire path (terminate at
|
|
959
|
+
// their next JS-visible safe point); idle workers are parked in the
|
|
960
|
+
// JS event loop and terminate safely right away.
|
|
961
|
+
const idleWorkers = [];
|
|
962
|
+
for (let i = 0; i < liveWorkers.length; i++) {
|
|
963
|
+
const worker = liveWorkers[i];
|
|
964
|
+
if (worker === undefined)
|
|
965
|
+
continue;
|
|
966
|
+
if (busySlots.has(i)) {
|
|
967
|
+
retireWorkerAfterTimeout(worker, i, 'circuit breaker tripped with job in flight');
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
idleWorkers.push(worker);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
893
973
|
activeSlots.clear();
|
|
894
|
-
void terminateTrackedWorkers(
|
|
974
|
+
void terminateTrackedWorkers(idleWorkers);
|
|
895
975
|
};
|
|
896
976
|
const maybeDone = () => {
|
|
897
977
|
if (stopped)
|
|
@@ -17,6 +17,7 @@ import path from 'path';
|
|
|
17
17
|
import { NODE_TABLES } from './schema.js';
|
|
18
18
|
import { RelPairRouter } from './rel-pair-routing.js';
|
|
19
19
|
import { parseTruthyEnv } from '../ingestion/utils/env.js';
|
|
20
|
+
import { SYMBOL_NODE_LABELS } from '../ingestion/utils/symbol-labels.js';
|
|
20
21
|
import { applyCjkSegmentationIfEnabled } from '../search/cjk-segmentation.js';
|
|
21
22
|
/**
|
|
22
23
|
* Deterministic output ordering — optional (out-of-core / windowed-resolve
|
|
@@ -187,6 +188,10 @@ class FileContentCache {
|
|
|
187
188
|
export const normalizeFtsText = (text) => text.replace(/[\r\n\t]+/g, ' ');
|
|
188
189
|
/** Composes both FTS-text transforms for the `description` column — one place for the six emission sites below to call, instead of repeating the composition. */
|
|
189
190
|
const formatFtsDescription = (description) => normalizeFtsText(applyCjkSegmentationIfEnabled(description));
|
|
191
|
+
// Labels that get exact source-span content (no ±2 window). Single source of
|
|
192
|
+
// truth in `symbol-labels.ts` — see there for why the exactness depends on the
|
|
193
|
+
// 0-based line invariant. Kept as a named alias to read intent at the use site.
|
|
194
|
+
const EXACT_SYMBOL_CONTENT_LABELS = SYMBOL_NODE_LABELS;
|
|
190
195
|
const extractContent = async (node, contentCache) => {
|
|
191
196
|
const filePath = node.properties.filePath;
|
|
192
197
|
const content = await contentCache.get(filePath);
|
|
@@ -209,8 +214,9 @@ const extractContent = async (node, contentCache) => {
|
|
|
209
214
|
if (startLine === undefined || endLine === undefined)
|
|
210
215
|
return '';
|
|
211
216
|
const lines = content.split('\n');
|
|
212
|
-
const
|
|
213
|
-
const
|
|
217
|
+
const exactSymbolContent = EXACT_SYMBOL_CONTENT_LABELS.has(node.label);
|
|
218
|
+
const start = Math.max(0, exactSymbolContent ? startLine : startLine - 2);
|
|
219
|
+
const end = Math.min(lines.length - 1, exactSymbolContent ? endLine : endLine + 2);
|
|
214
220
|
const snippet = lines.slice(start, end + 1).join('\n');
|
|
215
221
|
const MAX_SNIPPET = 5000;
|
|
216
222
|
const capped = snippet.length > MAX_SNIPPET ? snippet.slice(0, MAX_SNIPPET) + '\n... [truncated]' : snippet;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape a value for embedding in a single-quoted Cypher string literal.
|
|
3
|
+
*
|
|
4
|
+
* LadybugDB's parser uses backslash escapes and REJECTS SQL-style `''`
|
|
5
|
+
* doubling — `'we''ird'` is a parser error, not an escaped quote (#2409
|
|
6
|
+
* review). Every call site that used doubling produced a query that never
|
|
7
|
+
* parsed; the failures were invisible wherever the site swallowed errors
|
|
8
|
+
* (per-file deletes skipping quoted paths, importer BFS returning [],
|
|
9
|
+
* augment/wiki batch lookups silently missing rows).
|
|
10
|
+
*
|
|
11
|
+
* Backslashes are escaped first, then quotes — reversing the order would
|
|
12
|
+
* double the backslash that the quote escape just introduced. For values
|
|
13
|
+
* inside single-quoted literals only; table/label names go through
|
|
14
|
+
* `escapeTableName` in lbug-adapter instead.
|
|
15
|
+
*
|
|
16
|
+
* NOT for CSV emission: the COPY path (csv-generator.ts) quotes fields for
|
|
17
|
+
* LadybugDB's CSV reader (`ESCAPE='"'`), a different grammar with its own
|
|
18
|
+
* rules — its `''` usages are not this bug.
|
|
19
|
+
*/
|
|
20
|
+
export declare const escapeCypherString: (value: string) => string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escape a value for embedding in a single-quoted Cypher string literal.
|
|
3
|
+
*
|
|
4
|
+
* LadybugDB's parser uses backslash escapes and REJECTS SQL-style `''`
|
|
5
|
+
* doubling — `'we''ird'` is a parser error, not an escaped quote (#2409
|
|
6
|
+
* review). Every call site that used doubling produced a query that never
|
|
7
|
+
* parsed; the failures were invisible wherever the site swallowed errors
|
|
8
|
+
* (per-file deletes skipping quoted paths, importer BFS returning [],
|
|
9
|
+
* augment/wiki batch lookups silently missing rows).
|
|
10
|
+
*
|
|
11
|
+
* Backslashes are escaped first, then quotes — reversing the order would
|
|
12
|
+
* double the backslash that the quote escape just introduced. For values
|
|
13
|
+
* inside single-quoted literals only; table/label names go through
|
|
14
|
+
* `escapeTableName` in lbug-adapter instead.
|
|
15
|
+
*
|
|
16
|
+
* NOT for CSV emission: the COPY path (csv-generator.ts) quotes fields for
|
|
17
|
+
* LadybugDB's CSV reader (`ESCAPE='"'`), a different grammar with its own
|
|
18
|
+
* rules — its `''` usages are not this bug.
|
|
19
|
+
*/
|
|
20
|
+
export const escapeCypherString = (value) => value.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type ExtensionLoadErrorKind = 'missing_file' | 'corrupt_file' | 'missing_dependency' | 'unknown';
|
|
2
|
+
export interface ExtensionLoadDiagnosis {
|
|
3
|
+
readonly kind: ExtensionLoadErrorKind;
|
|
4
|
+
/** Actionable, literal-English remedy suited to the class. */
|
|
5
|
+
readonly remedy: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* On-disk file corruption / wrong-platform. FORCE INSTALL re-downloads.
|
|
9
|
+
* Kept byte-identical to `FILE_CORRUPTION_SIGNATURES` in
|
|
10
|
+
* scripts/install-duckdb-extension.mjs (that `.mjs` cannot import this `.ts`;
|
|
11
|
+
* the duplication is deliberate — the two serve different call sites). Note
|
|
12
|
+
* `/not a valid/i` already covers Windows error 193 ("is not a valid Win32
|
|
13
|
+
* application"), so a truncated Windows download is caught here, before the
|
|
14
|
+
* missing-dependency branch.
|
|
15
|
+
*/
|
|
16
|
+
export declare const FILE_CORRUPTION_SIGNATURES: readonly RegExp[];
|
|
17
|
+
/**
|
|
18
|
+
* Classify a collapsed LadybugDB LOAD error. Order is most-specific-first and is
|
|
19
|
+
* load-bearing: corrupt-file is tested before missing-dependency so a truncated
|
|
20
|
+
* Windows download (error 193, matched by `/not a valid/i`) routes to
|
|
21
|
+
* FORCE-reinstall rather than to the runtime-install remedy.
|
|
22
|
+
*/
|
|
23
|
+
export declare function classifyExtensionLoadError(reason: string | undefined | null): ExtensionLoadDiagnosis;
|
|
24
|
+
/** Well-formedness of the extension binary for the host platform + arch. */
|
|
25
|
+
export type ExtensionBinaryState = 'absent' | 'corrupt' | 'valid' | 'indeterminate';
|
|
26
|
+
/**
|
|
27
|
+
* Pull the extension file path out of lbug's load error. lbug's wrapper is
|
|
28
|
+
* English regardless of OS language — `Failed to load library: {path} which is
|
|
29
|
+
* needed by extension: {name}` (real lbug), or the quoted `Failed to load
|
|
30
|
+
* library '{path}': {reason}` variant — so the path is recoverable in any locale.
|
|
31
|
+
* Only paths ending in `.lbug_extension` are accepted, so a regex misfire can
|
|
32
|
+
* never point the inspector at an arbitrary file.
|
|
33
|
+
*/
|
|
34
|
+
export declare function extractExtensionPath(reason: string | undefined | null): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* A structural verdict on a binary header. `indeterminate` means the probe could
|
|
37
|
+
* not prove validity OR corruption from what it read (e.g. the PE header sits past
|
|
38
|
+
* the BINARY_HEADER_BYTES window) — the caller defers to the string classifier
|
|
39
|
+
* rather than assert a false verdict.
|
|
40
|
+
*/
|
|
41
|
+
type HeaderVerdict = 'valid' | 'corrupt' | 'indeterminate';
|
|
42
|
+
/**
|
|
43
|
+
* Decide whether a binary header is a well-formed shared library for the given
|
|
44
|
+
* platform + architecture — using only the file's structure, no localized text.
|
|
45
|
+
* Pure and injectable (platform/arch as params) so every format+arch combination
|
|
46
|
+
* is unit-testable regardless of the host it runs on.
|
|
47
|
+
*/
|
|
48
|
+
export declare function classifyBinaryHeader(buf: Buffer, bytesRead: number, platform: NodeJS.Platform, arch: string): HeaderVerdict;
|
|
49
|
+
/**
|
|
50
|
+
* Best-effort language-independent inspection of the extension file. Reads the
|
|
51
|
+
* header and classifies it; never throws — a missing file is `absent`, an
|
|
52
|
+
* unreadable one is `indeterminate`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function inspectExtensionBinary(extensionPath: string | null | undefined): ExtensionBinaryState;
|
|
55
|
+
/**
|
|
56
|
+
* Diagnose a LadybugDB load failure, preferring a LANGUAGE-INDEPENDENT structural
|
|
57
|
+
* check of the extension binary over the localized error text:
|
|
58
|
+
* - file absent → missing_file
|
|
59
|
+
* - present but malformed → corrupt_file (bad magic / wrong architecture)
|
|
60
|
+
* - present and well-formed → missing_dependency (a valid binary the loader rejected)
|
|
61
|
+
* The path comes from lbug's own English wrapper, so this holds in any OS display
|
|
62
|
+
* language. When the file cannot be located or read, it falls back to the string
|
|
63
|
+
* classifier (which still carries the language-independent hedged fallback). This
|
|
64
|
+
* is the entry point every surface should call.
|
|
65
|
+
*/
|
|
66
|
+
export declare function diagnoseExtensionLoad(reason: string | undefined | null): ExtensionLoadDiagnosis;
|
|
67
|
+
export {};
|