gitnexus 1.6.10-rc.4 → 1.6.10-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/doctor.js +10 -0
- package/dist/core/group/extractors/manifest-extractor.js +4 -0
- package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
- package/dist/core/ingestion/cobol-processor.js +27 -26
- package/dist/core/ingestion/emit-references.js +3 -2
- package/dist/core/ingestion/markdown-processor.js +3 -2
- 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/lbug/csv-generator.js +8 -2
- 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 +7 -0
- package/dist/core/lbug/extension-loader.js +9 -1
- package/dist/core/run-analyze.js +27 -7
- package/dist/core/search/fts-indexes.js +11 -1
- 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 +8 -0
- package/dist/mcp/local/local-backend.js +40 -16
- 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/storage/repo-manager.d.ts +6 -1
- package/dist/storage/repo-manager.js +6 -1
- package/package.json +1 -1
- package/scripts/cross-platform-tests.ts +5 -0
- package/scripts/install-duckdb-extension.mjs +3 -1
package/dist/cli/doctor.js
CHANGED
|
@@ -5,6 +5,7 @@ import { getLocalEmbeddingRuntimeBlocker, localEmbeddingPrefixUnloadableMessage,
|
|
|
5
5
|
import { isPrefixRuntimeLoadable, resolveEmbeddingRuntime, } from '../core/embeddings/runtime-install.js';
|
|
6
6
|
import { cudaRedirectDoctorStatus } from '../core/embeddings/onnxruntime-node-resolver.js';
|
|
7
7
|
import { checkLbugNative, probeFtsExtensionLoad } from '../core/lbug/native-check.js';
|
|
8
|
+
import { diagnoseExtensionLoad } from '../core/lbug/extension-load-error.js';
|
|
8
9
|
import { getExtensionInstallPolicy } from '../core/lbug/extension-loader.js';
|
|
9
10
|
import { t } from './i18n/index.js';
|
|
10
11
|
function isCombiningMark(codePoint) {
|
|
@@ -116,6 +117,15 @@ export const doctorCommand = async () => {
|
|
|
116
117
|
console.log(` ${label('doctor.labels.fullTextSearch', 18)}${ftsProbe.loaded ? 'available' : 'unavailable'}`);
|
|
117
118
|
if (!ftsProbe.loaded && ftsProbe.reason) {
|
|
118
119
|
console.log(` ${padDisplayEnd('', 18)}${ftsProbe.reason}`);
|
|
120
|
+
// Add an actionable remedy for recognized failure classes (#2374). The
|
|
121
|
+
// Windows missing-dependency case is the point of this: the raw error 126
|
|
122
|
+
// ("specified module could not be found") is opaque, so name the fix (VC++
|
|
123
|
+
// redist, then OpenSSL) instead of leaving the user to reinstall in vain.
|
|
124
|
+
// `unknown`'s remedy is "run doctor", which would be circular here.
|
|
125
|
+
const { kind, remedy } = diagnoseExtensionLoad(ftsProbe.reason);
|
|
126
|
+
if (kind !== 'unknown') {
|
|
127
|
+
console.log(` ${padDisplayEnd('', 18)}${remedy}`);
|
|
128
|
+
}
|
|
119
129
|
}
|
|
120
130
|
console.log(` ${label('doctor.labels.vectorIndex', 18)}${capabilities.vector}`);
|
|
121
131
|
console.log(` ${label('doctor.labels.semanticMode', 18)}${capabilities.semanticMode}`);
|
|
@@ -7,6 +7,10 @@ import { logger } from '../../logger.js';
|
|
|
7
7
|
// reserved-keyword labels `Macro` and `Union`, and LadybugDB's parser rejects
|
|
8
8
|
// a disjunction that names a reserved keyword (#2325) — which the resolver's
|
|
9
9
|
// try/catch then swallowed. `labels(n) IN` has no such collision.
|
|
10
|
+
// This list overlaps `ingestion/utils/symbol-labels.ts` (SYMBOL_NODE_LABELS) but
|
|
11
|
+
// is a deliberate SUBSET — it omits `Namespace`/`Variable`/`Module`. Unifying the
|
|
12
|
+
// two would widen which nodes resolve as contract symbols and must update the
|
|
13
|
+
// #2325 test, so they are intentionally kept separate for now.
|
|
10
14
|
export const CUSTOM_CONTRACT_RESOLVE_QUERY = `MATCH (n)
|
|
11
15
|
WHERE labels(n) IN ['Function','Method','Class','Interface','Struct','Enum','Trait','Constructor','TypeAlias','Impl','Macro','Union','Typedef','Property','Record','Delegate','Annotation','Template','Const','Static','CodeElement']
|
|
12
16
|
AND n.name = $symbolName
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { parseJcl } from './jcl-parser.js';
|
|
19
19
|
import { generateId } from '../../../lib/utils.js';
|
|
20
|
+
import { toZeroBasedLine } from '../utils/line-base.js';
|
|
20
21
|
/**
|
|
21
22
|
* Process JCL files and integrate into the knowledge graph.
|
|
22
23
|
*
|
|
@@ -71,8 +72,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
|
|
|
71
72
|
properties: {
|
|
72
73
|
name: job.name,
|
|
73
74
|
filePath,
|
|
74
|
-
startLine: job.line,
|
|
75
|
-
endLine: job.line,
|
|
75
|
+
startLine: toZeroBasedLine(job.line),
|
|
76
|
+
endLine: toZeroBasedLine(job.line),
|
|
76
77
|
description: `jcl-job${classPart}${msgPart}`,
|
|
77
78
|
},
|
|
78
79
|
});
|
|
@@ -105,8 +106,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
|
|
|
105
106
|
properties: {
|
|
106
107
|
name: step.name,
|
|
107
108
|
filePath,
|
|
108
|
-
startLine: step.line,
|
|
109
|
-
endLine: step.line,
|
|
109
|
+
startLine: toZeroBasedLine(step.line),
|
|
110
|
+
endLine: toZeroBasedLine(step.line),
|
|
110
111
|
description: `jcl-step${pgmPart}${procPart}`,
|
|
111
112
|
},
|
|
112
113
|
});
|
|
@@ -170,8 +171,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
|
|
|
170
171
|
properties: {
|
|
171
172
|
name: dd.dataset,
|
|
172
173
|
filePath,
|
|
173
|
-
startLine: dd.line,
|
|
174
|
-
endLine: dd.line,
|
|
174
|
+
startLine: toZeroBasedLine(dd.line),
|
|
175
|
+
endLine: toZeroBasedLine(dd.line),
|
|
175
176
|
description: `jcl-dataset${dispPart}`,
|
|
176
177
|
},
|
|
177
178
|
});
|
|
@@ -202,8 +203,8 @@ function integrateJclResults(graph, parsed, filePath, moduleNames) {
|
|
|
202
203
|
properties: {
|
|
203
204
|
name: proc.name,
|
|
204
205
|
filePath,
|
|
205
|
-
startLine: proc.line,
|
|
206
|
-
endLine: proc.line,
|
|
206
|
+
startLine: toZeroBasedLine(proc.line),
|
|
207
|
+
endLine: toZeroBasedLine(proc.line),
|
|
207
208
|
description: 'jcl-proc-instream',
|
|
208
209
|
},
|
|
209
210
|
});
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { generateId } from '../../lib/utils.js';
|
|
17
|
+
import { toZeroBasedLine } from './utils/line-base.js';
|
|
17
18
|
import { SupportedLanguages } from '../../_shared/index.js';
|
|
18
19
|
import { preprocessCobolSource, extractCobolSymbolsWithRegex, } from './cobol/cobol-preprocessor.js';
|
|
19
20
|
import { expandCopies } from './cobol/cobol-copy-expander.js';
|
|
@@ -275,8 +276,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
275
276
|
properties: {
|
|
276
277
|
name: extracted.programName,
|
|
277
278
|
filePath,
|
|
278
|
-
startLine: 1,
|
|
279
|
-
endLine: lines.length,
|
|
279
|
+
startLine: toZeroBasedLine(1),
|
|
280
|
+
endLine: toZeroBasedLine(lines.length),
|
|
280
281
|
language: SupportedLanguages.Cobol,
|
|
281
282
|
isExported: true,
|
|
282
283
|
description: metaDesc || undefined,
|
|
@@ -310,8 +311,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
310
311
|
properties: {
|
|
311
312
|
name: prog.name,
|
|
312
313
|
filePath,
|
|
313
|
-
startLine: prog.startLine,
|
|
314
|
-
endLine: prog.endLine,
|
|
314
|
+
startLine: toZeroBasedLine(prog.startLine),
|
|
315
|
+
endLine: toZeroBasedLine(prog.endLine),
|
|
315
316
|
language: SupportedLanguages.Cobol,
|
|
316
317
|
isExported: true,
|
|
317
318
|
description: `nested-program${prog.isCommon ? ' common' : ''}`,
|
|
@@ -349,8 +350,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
349
350
|
properties: {
|
|
350
351
|
name: sec.name,
|
|
351
352
|
filePath,
|
|
352
|
-
startLine: sec.line,
|
|
353
|
-
endLine: nextLine,
|
|
353
|
+
startLine: toZeroBasedLine(sec.line),
|
|
354
|
+
endLine: toZeroBasedLine(nextLine),
|
|
354
355
|
language: SupportedLanguages.Cobol,
|
|
355
356
|
isExported: true,
|
|
356
357
|
},
|
|
@@ -379,8 +380,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
379
380
|
properties: {
|
|
380
381
|
name: para.name,
|
|
381
382
|
filePath,
|
|
382
|
-
startLine: para.line,
|
|
383
|
-
endLine: nextLine,
|
|
383
|
+
startLine: toZeroBasedLine(para.line),
|
|
384
|
+
endLine: toZeroBasedLine(nextLine),
|
|
384
385
|
language: SupportedLanguages.Cobol,
|
|
385
386
|
isExported: true,
|
|
386
387
|
},
|
|
@@ -412,8 +413,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
412
413
|
properties: {
|
|
413
414
|
name: item.name,
|
|
414
415
|
filePath,
|
|
415
|
-
startLine: item.line,
|
|
416
|
-
endLine: item.line,
|
|
416
|
+
startLine: toZeroBasedLine(item.line),
|
|
417
|
+
endLine: toZeroBasedLine(item.line),
|
|
417
418
|
language: SupportedLanguages.Cobol,
|
|
418
419
|
description: `level:${item.level} section:${item.section}${item.pic ? ` pic:${item.pic}` : ''}`,
|
|
419
420
|
},
|
|
@@ -506,8 +507,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
506
507
|
properties: {
|
|
507
508
|
name: `CALL ${call.target}`,
|
|
508
509
|
filePath,
|
|
509
|
-
startLine: call.line,
|
|
510
|
-
endLine: call.line,
|
|
510
|
+
startLine: toZeroBasedLine(call.line),
|
|
511
|
+
endLine: toZeroBasedLine(call.line),
|
|
511
512
|
language: SupportedLanguages.Cobol,
|
|
512
513
|
description: 'dynamic-call (target is a data item, not resolvable statically)',
|
|
513
514
|
},
|
|
@@ -619,8 +620,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
619
620
|
properties: {
|
|
620
621
|
name: `EXEC SQL ${sql.operation}`,
|
|
621
622
|
filePath,
|
|
622
|
-
startLine: sql.line,
|
|
623
|
-
endLine: sql.line,
|
|
623
|
+
startLine: toZeroBasedLine(sql.line),
|
|
624
|
+
endLine: toZeroBasedLine(sql.line),
|
|
624
625
|
language: SupportedLanguages.Cobol,
|
|
625
626
|
description: `tables:[${sql.tables.join(',')}] cursors:[${sql.cursors.join(',')}]`,
|
|
626
627
|
},
|
|
@@ -691,8 +692,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
691
692
|
properties: {
|
|
692
693
|
name: `EXEC CICS ${cics.command}`,
|
|
693
694
|
filePath,
|
|
694
|
-
startLine: cics.line,
|
|
695
|
-
endLine: cics.line,
|
|
695
|
+
startLine: toZeroBasedLine(cics.line),
|
|
696
|
+
endLine: toZeroBasedLine(cics.line),
|
|
696
697
|
language: SupportedLanguages.Cobol,
|
|
697
698
|
description: [
|
|
698
699
|
cics.mapName && `map:${cics.mapName}`,
|
|
@@ -726,8 +727,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
726
727
|
properties: {
|
|
727
728
|
name: `CICS ${cics.command} ${cics.programName}`,
|
|
728
729
|
filePath,
|
|
729
|
-
startLine: cics.line,
|
|
730
|
-
endLine: cics.line,
|
|
730
|
+
startLine: toZeroBasedLine(cics.line),
|
|
731
|
+
endLine: toZeroBasedLine(cics.line),
|
|
731
732
|
language: SupportedLanguages.Cobol,
|
|
732
733
|
description: `cics-dynamic-program (target is data item ${cics.programName})`,
|
|
733
734
|
},
|
|
@@ -879,8 +880,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
879
880
|
properties: {
|
|
880
881
|
name: entry.name,
|
|
881
882
|
filePath,
|
|
882
|
-
startLine: entry.line,
|
|
883
|
-
endLine: entry.line,
|
|
883
|
+
startLine: toZeroBasedLine(entry.line),
|
|
884
|
+
endLine: toZeroBasedLine(entry.line),
|
|
884
885
|
language: SupportedLanguages.Cobol,
|
|
885
886
|
isExported: true,
|
|
886
887
|
description: entry.parameters.length > 0 ? `using:${entry.parameters.join(',')}` : undefined,
|
|
@@ -1014,8 +1015,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
1014
1015
|
properties: {
|
|
1015
1016
|
name: `EXEC DLI ${dli.verb}`,
|
|
1016
1017
|
filePath,
|
|
1017
|
-
startLine: dli.line,
|
|
1018
|
-
endLine: dli.line,
|
|
1018
|
+
startLine: toZeroBasedLine(dli.line),
|
|
1019
|
+
endLine: toZeroBasedLine(dli.line),
|
|
1019
1020
|
language: SupportedLanguages.Cobol,
|
|
1020
1021
|
description: [
|
|
1021
1022
|
dli.segmentName && `segment:${dli.segmentName}`,
|
|
@@ -1148,8 +1149,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
1148
1149
|
properties: {
|
|
1149
1150
|
name: fd.selectName,
|
|
1150
1151
|
filePath,
|
|
1151
|
-
startLine: fd.line,
|
|
1152
|
-
endLine: fd.line,
|
|
1152
|
+
startLine: toZeroBasedLine(fd.line),
|
|
1153
|
+
endLine: toZeroBasedLine(fd.line),
|
|
1153
1154
|
language: SupportedLanguages.Cobol,
|
|
1154
1155
|
description: `assign:${fd.assignTo}${fd.isOptional ? ' optional' : ''}${fd.organization ? ` org:${fd.organization}` : ''}${fd.access ? ` access:${fd.access}` : ''}`,
|
|
1155
1156
|
},
|
|
@@ -1231,8 +1232,8 @@ function mapToGraph(graph, extracted, file, copyResolutions, moduleNodeIds) {
|
|
|
1231
1232
|
properties: {
|
|
1232
1233
|
name: `CANCEL ${cancel.target}`,
|
|
1233
1234
|
filePath,
|
|
1234
|
-
startLine: cancel.line,
|
|
1235
|
-
endLine: cancel.line,
|
|
1235
|
+
startLine: toZeroBasedLine(cancel.line),
|
|
1236
|
+
endLine: toZeroBasedLine(cancel.line),
|
|
1236
1237
|
language: SupportedLanguages.Cobol,
|
|
1237
1238
|
description: 'dynamic-cancel (target is a data item, not resolvable statically)',
|
|
1238
1239
|
},
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
* ancestor scope, and if THAT produces nothing either the edge is
|
|
45
45
|
* skipped (with a count returned in `EmitStats.skippedNoCaller`).
|
|
46
46
|
*/
|
|
47
|
+
import { toZeroBasedLine } from './utils/line-base.js';
|
|
47
48
|
/**
|
|
48
49
|
* Drain `referenceIndex.bySourceScope` into graph edges.
|
|
49
50
|
*
|
|
@@ -95,8 +96,8 @@ export function emitScopeGraph(input) {
|
|
|
95
96
|
properties: {
|
|
96
97
|
name: scope.kind,
|
|
97
98
|
filePath: scope.filePath,
|
|
98
|
-
startLine: scope.range.startLine,
|
|
99
|
-
endLine: scope.range.endLine,
|
|
99
|
+
startLine: toZeroBasedLine(scope.range.startLine),
|
|
100
|
+
endLine: toZeroBasedLine(scope.range.endLine),
|
|
100
101
|
description: `Scope: ${scope.kind}`,
|
|
101
102
|
},
|
|
102
103
|
});
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
import { generateId } from '../../lib/utils.js';
|
|
10
|
+
import { toZeroBasedLine } from './utils/line-base.js';
|
|
10
11
|
const HEADING_RE = /^(#{1,6})\s+(.+)$/;
|
|
11
12
|
const LINK_RE = /\[([^\]]*)\]\(([^)]+)\)/g;
|
|
12
13
|
const MD_EXTENSIONS = new Set(['.md', '.mdx']);
|
|
@@ -59,8 +60,8 @@ export const processMarkdown = (graph, files, allPathSet) => {
|
|
|
59
60
|
properties: {
|
|
60
61
|
name: heading,
|
|
61
62
|
filePath: file.path,
|
|
62
|
-
startLine: lineNum,
|
|
63
|
-
endLine,
|
|
63
|
+
startLine: toZeroBasedLine(lineNum),
|
|
64
|
+
endLine: toZeroBasedLine(endLine),
|
|
64
65
|
level,
|
|
65
66
|
description: `h${level}`,
|
|
66
67
|
},
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a 1-based source line number to the 0-based convention used by
|
|
3
|
+
* GraphNode `startLine`/`endLine`.
|
|
4
|
+
*
|
|
5
|
+
* The graph layer stores line numbers 0-based (tree-sitter `startPosition.row`),
|
|
6
|
+
* and this is load-bearing: the taint/PDG/CFG join and the MCP consumers all add
|
|
7
|
+
* `+ 1` to recover 1-based (see `summary-harvest-driver.ts` — "Function/Method
|
|
8
|
+
* node startLine is 0-based"). Most emitters get 0-based for free from
|
|
9
|
+
* tree-sitter. The exceptions are the regex-based COBOL/JCL processors (their
|
|
10
|
+
* parsers use `lineNum = i + 1`) and the scope-capture path (`Capture` ranges
|
|
11
|
+
* are 1-based per RFC §2.1). Those must convert to 0-based when they build a
|
|
12
|
+
* graph node, or the exact-content slice in `csv-generator.ts` drops the
|
|
13
|
+
* symbol's declaration line (#2379) and reported line numbers are off (#2377).
|
|
14
|
+
*
|
|
15
|
+
* Apply this ONLY at the graph-node `startLine:`/`endLine:` assignment. The
|
|
16
|
+
* parser-internal 1-based values (`.line`, `prog.startLine`) stay 1-based —
|
|
17
|
+
* they feed `L${line}` node/edge IDs and line-range containment checks that
|
|
18
|
+
* must not shift. The clamp guards degenerate inputs (line 0 / empty files).
|
|
19
|
+
*/
|
|
20
|
+
export declare const toZeroBasedLine: (oneBasedLine: number) => number;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a 1-based source line number to the 0-based convention used by
|
|
3
|
+
* GraphNode `startLine`/`endLine`.
|
|
4
|
+
*
|
|
5
|
+
* The graph layer stores line numbers 0-based (tree-sitter `startPosition.row`),
|
|
6
|
+
* and this is load-bearing: the taint/PDG/CFG join and the MCP consumers all add
|
|
7
|
+
* `+ 1` to recover 1-based (see `summary-harvest-driver.ts` — "Function/Method
|
|
8
|
+
* node startLine is 0-based"). Most emitters get 0-based for free from
|
|
9
|
+
* tree-sitter. The exceptions are the regex-based COBOL/JCL processors (their
|
|
10
|
+
* parsers use `lineNum = i + 1`) and the scope-capture path (`Capture` ranges
|
|
11
|
+
* are 1-based per RFC §2.1). Those must convert to 0-based when they build a
|
|
12
|
+
* graph node, or the exact-content slice in `csv-generator.ts` drops the
|
|
13
|
+
* symbol's declaration line (#2379) and reported line numbers are off (#2377).
|
|
14
|
+
*
|
|
15
|
+
* Apply this ONLY at the graph-node `startLine:`/`endLine:` assignment. The
|
|
16
|
+
* parser-internal 1-based values (`.line`, `prog.startLine`) stay 1-based —
|
|
17
|
+
* they feed `L${line}` node/edge IDs and line-range containment checks that
|
|
18
|
+
* must not shift. The clamp guards degenerate inputs (line 0 / empty files).
|
|
19
|
+
*/
|
|
20
|
+
export const toZeroBasedLine = (oneBasedLine) => Math.max(0, oneBasedLine - 1);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { NodeLabel } from '../../../_shared/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Graph-node labels that represent a resolvable code symbol — a definition with
|
|
4
|
+
* its own source span (function, type, member, module-like container).
|
|
5
|
+
*
|
|
6
|
+
* These get EXACT source-span content in the FTS index: `csv-generator.ts`
|
|
7
|
+
* slices exactly `[startLine, endLine]` for them (no ±2 padding), while every
|
|
8
|
+
* other label keeps the context window. That exactness depends on the 0-based
|
|
9
|
+
* `startLine`/`endLine` invariant enforced by `line-base.ts` — the slice is only
|
|
10
|
+
* correct because all emitters store 0-based lines. Keep the two together.
|
|
11
|
+
*
|
|
12
|
+
* Single source of truth so the set can't silently drift the way the inline copy
|
|
13
|
+
* did in #2379.
|
|
14
|
+
*
|
|
15
|
+
* NOTE: `group/extractors/manifest-extractor.ts`'s `CUSTOM_CONTRACT_RESOLVE_QUERY`
|
|
16
|
+
* carries a near-identical hand-list that is intentionally a SUBSET — it excludes
|
|
17
|
+
* `Namespace`, `Variable`, `Module`. Unifying the two needs a contract-resolution
|
|
18
|
+
* behavior check (would widen which nodes resolve as contract symbols), so it is
|
|
19
|
+
* deliberately left separate for now.
|
|
20
|
+
*/
|
|
21
|
+
export declare const SYMBOL_NODE_LABELS: ReadonlySet<NodeLabel>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph-node labels that represent a resolvable code symbol — a definition with
|
|
3
|
+
* its own source span (function, type, member, module-like container).
|
|
4
|
+
*
|
|
5
|
+
* These get EXACT source-span content in the FTS index: `csv-generator.ts`
|
|
6
|
+
* slices exactly `[startLine, endLine]` for them (no ±2 padding), while every
|
|
7
|
+
* other label keeps the context window. That exactness depends on the 0-based
|
|
8
|
+
* `startLine`/`endLine` invariant enforced by `line-base.ts` — the slice is only
|
|
9
|
+
* correct because all emitters store 0-based lines. Keep the two together.
|
|
10
|
+
*
|
|
11
|
+
* Single source of truth so the set can't silently drift the way the inline copy
|
|
12
|
+
* did in #2379.
|
|
13
|
+
*
|
|
14
|
+
* NOTE: `group/extractors/manifest-extractor.ts`'s `CUSTOM_CONTRACT_RESOLVE_QUERY`
|
|
15
|
+
* carries a near-identical hand-list that is intentionally a SUBSET — it excludes
|
|
16
|
+
* `Namespace`, `Variable`, `Module`. Unifying the two needs a contract-resolution
|
|
17
|
+
* behavior check (would widen which nodes resolve as contract symbols), so it is
|
|
18
|
+
* deliberately left separate for now.
|
|
19
|
+
*/
|
|
20
|
+
export const SYMBOL_NODE_LABELS = new Set([
|
|
21
|
+
'Function',
|
|
22
|
+
'Method',
|
|
23
|
+
'Class',
|
|
24
|
+
'Interface',
|
|
25
|
+
'CodeElement',
|
|
26
|
+
'Struct',
|
|
27
|
+
'Enum',
|
|
28
|
+
'Macro',
|
|
29
|
+
'Typedef',
|
|
30
|
+
'Union',
|
|
31
|
+
'Namespace',
|
|
32
|
+
'Trait',
|
|
33
|
+
'Impl',
|
|
34
|
+
'TypeAlias',
|
|
35
|
+
'Const',
|
|
36
|
+
'Static',
|
|
37
|
+
'Variable',
|
|
38
|
+
'Property',
|
|
39
|
+
'Record',
|
|
40
|
+
'Delegate',
|
|
41
|
+
'Annotation',
|
|
42
|
+
'Constructor',
|
|
43
|
+
'Template',
|
|
44
|
+
'Module',
|
|
45
|
+
]);
|
|
@@ -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,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 {};
|