gitnexus 1.6.10-rc.4 → 1.6.10-rc.5
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/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/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
|
@@ -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,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a 0-based GraphNode `startLine`/`endLine` to the 1-based line number
|
|
3
|
+
* shown to humans and LLMs in MCP tool output.
|
|
4
|
+
*
|
|
5
|
+
* Storage is 0-based (tree-sitter `startPosition.row`; see
|
|
6
|
+
* `ingestion/utils/line-base.ts`), which matches editors/`sed`/`less -N` only
|
|
7
|
+
* after `+ 1`. The `context`, `query`, and `impact` tools present line numbers a
|
|
8
|
+
* user cross-references against source, so they convert here at the response
|
|
9
|
+
* boundary (#2377).
|
|
10
|
+
*
|
|
11
|
+
* Apply ONLY to a symbol node's 0-based `startLine`/`endLine`. Do NOT apply to:
|
|
12
|
+
* - BasicBlock / CFG `functionStartLine` and PDG statement lines — already
|
|
13
|
+
* 1-based (they use `startPosition.row + 1`);
|
|
14
|
+
* - the internal `sym.startLine + 1` join params that target the 1-based
|
|
15
|
+
* BasicBlock id space;
|
|
16
|
+
* - raw `cypher` results, which pass LadybugDB columns through verbatim and
|
|
17
|
+
* stay 0-based (documented).
|
|
18
|
+
*
|
|
19
|
+
* `undefined`/`null` pass through so optional line fields stay absent.
|
|
20
|
+
*/
|
|
21
|
+
export declare function toDisplayLine(zeroBasedLine: number): number;
|
|
22
|
+
export declare function toDisplayLine(zeroBasedLine: number | null | undefined): number | undefined;
|
|
@@ -172,6 +172,14 @@ export declare class LocalBackend {
|
|
|
172
172
|
* Cross-repo group tools (CLI). Shares logic with MCP `group_*` handlers.
|
|
173
173
|
*/
|
|
174
174
|
getGroupService(): GroupService;
|
|
175
|
+
/**
|
|
176
|
+
* Adapt local `trace` to the group port. The assembled group/cross-repo trace
|
|
177
|
+
* presents 1-based endpoints (via resolveSymbolForGroup), so convert the hop
|
|
178
|
+
* lines here too — otherwise one response mixes 1-based endpoints with 0-based
|
|
179
|
+
* hops (#2380). Single-repo `trace` dispatches directly (not through this
|
|
180
|
+
* port) and stays 0-based (documented full-parity follow-up).
|
|
181
|
+
*/
|
|
182
|
+
private traceForGroup;
|
|
175
183
|
/**
|
|
176
184
|
* Adapt the shared symbol resolver to the GroupToolPort contract. Used by the
|
|
177
185
|
* cross-repo trace path to locate which member repo an endpoint lives in and
|
|
@@ -10,6 +10,7 @@ import path from 'path';
|
|
|
10
10
|
import { createHash } from 'crypto';
|
|
11
11
|
import { initLbug, executeQuery, executeParameterized, closeLbug, isLbugReady, } from '../../core/lbug/pool-adapter.js';
|
|
12
12
|
import { isValidQueryParams } from '../../core/lbug/query-params.js';
|
|
13
|
+
import { toDisplayLine } from './line-display.js';
|
|
13
14
|
import { isWalCorruptionError, WAL_RECOVERY_SUGGESTION } from '../../core/lbug/lbug-config.js';
|
|
14
15
|
// Embedding imports are lazy (dynamic import) to avoid loading onnxruntime-node
|
|
15
16
|
// at MCP server startup — crashes on unsupported Node ABI versions (#89)
|
|
@@ -453,7 +454,7 @@ export class LocalBackend {
|
|
|
453
454
|
query: (r, p) => this.query(r, p),
|
|
454
455
|
impactByUid: (id, uid, d, o) => this.impactByUid(id, uid, d, o),
|
|
455
456
|
context: (r, p) => this.context(r, p),
|
|
456
|
-
trace: (r, p) => this.
|
|
457
|
+
trace: (r, p) => this.traceForGroup(r, p),
|
|
457
458
|
resolveSymbol: (r, q) => this.resolveSymbolForGroup(r, q),
|
|
458
459
|
pdgFlows: (r, anchor, opts) => this.pdgFlowsForGroup(r, anchor, opts),
|
|
459
460
|
};
|
|
@@ -461,6 +462,23 @@ export class LocalBackend {
|
|
|
461
462
|
}
|
|
462
463
|
return this.groupToolSvc;
|
|
463
464
|
}
|
|
465
|
+
/**
|
|
466
|
+
* Adapt local `trace` to the group port. The assembled group/cross-repo trace
|
|
467
|
+
* presents 1-based endpoints (via resolveSymbolForGroup), so convert the hop
|
|
468
|
+
* lines here too — otherwise one response mixes 1-based endpoints with 0-based
|
|
469
|
+
* hops (#2380). Single-repo `trace` dispatches directly (not through this
|
|
470
|
+
* port) and stays 0-based (documented full-parity follow-up).
|
|
471
|
+
*/
|
|
472
|
+
async traceForGroup(repo, params) {
|
|
473
|
+
const result = await this.trace(repo, params);
|
|
474
|
+
const hops = result.hops;
|
|
475
|
+
if (Array.isArray(hops)) {
|
|
476
|
+
for (const hop of hops) {
|
|
477
|
+
hop.startLine = toDisplayLine(hop.startLine);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return result;
|
|
481
|
+
}
|
|
464
482
|
/**
|
|
465
483
|
* Adapt the shared symbol resolver to the GroupToolPort contract. Used by the
|
|
466
484
|
* cross-repo trace path to locate which member repo an endpoint lives in and
|
|
@@ -478,8 +496,8 @@ export class LocalBackend {
|
|
|
478
496
|
name: s.name,
|
|
479
497
|
type: s.type,
|
|
480
498
|
filePath: s.filePath,
|
|
481
|
-
startLine: s.startLine,
|
|
482
|
-
endLine: s.endLine,
|
|
499
|
+
startLine: toDisplayLine(s.startLine),
|
|
500
|
+
endLine: toDisplayLine(s.endLine),
|
|
483
501
|
},
|
|
484
502
|
};
|
|
485
503
|
}
|
|
@@ -491,7 +509,7 @@ export class LocalBackend {
|
|
|
491
509
|
name: c.name,
|
|
492
510
|
type: c.type,
|
|
493
511
|
filePath: c.filePath,
|
|
494
|
-
startLine: c.startLine,
|
|
512
|
+
startLine: toDisplayLine(c.startLine),
|
|
495
513
|
})),
|
|
496
514
|
};
|
|
497
515
|
}
|
|
@@ -1572,8 +1590,8 @@ export class LocalBackend {
|
|
|
1572
1590
|
name: sym.name,
|
|
1573
1591
|
type: sym.type,
|
|
1574
1592
|
filePath: sym.filePath,
|
|
1575
|
-
startLine: sym.startLine,
|
|
1576
|
-
endLine: sym.endLine,
|
|
1593
|
+
startLine: toDisplayLine(sym.startLine),
|
|
1594
|
+
endLine: toDisplayLine(sym.endLine),
|
|
1577
1595
|
...(module ? { module } : {}),
|
|
1578
1596
|
...(includeContent && content ? { content } : {}),
|
|
1579
1597
|
};
|
|
@@ -1799,8 +1817,11 @@ export class LocalBackend {
|
|
|
1799
1817
|
name: sym.name || sym[1],
|
|
1800
1818
|
type: sym.type || sym[2],
|
|
1801
1819
|
filePath: sym.filePath || sym[3],
|
|
1802
|
-
|
|
1803
|
-
|
|
1820
|
+
// Raw 0-based here — `bm25Search` is only called from `query()`,
|
|
1821
|
+
// whose aggregation loop applies `toDisplayLine` once (see below).
|
|
1822
|
+
// Converting here too would double-shift BM25-matched lines (#2380).
|
|
1823
|
+
startLine: sym.startLine ?? sym[4],
|
|
1824
|
+
endLine: sym.endLine ?? sym[5],
|
|
1804
1825
|
bm25Score: bm25Result.score,
|
|
1805
1826
|
});
|
|
1806
1827
|
}
|
|
@@ -2396,7 +2417,7 @@ export class LocalBackend {
|
|
|
2396
2417
|
name: c.name,
|
|
2397
2418
|
kind: c.type,
|
|
2398
2419
|
filePath: c.filePath,
|
|
2399
|
-
line: c.startLine,
|
|
2420
|
+
line: toDisplayLine(c.startLine),
|
|
2400
2421
|
score: Number(c.score.toFixed(2)),
|
|
2401
2422
|
})),
|
|
2402
2423
|
};
|
|
@@ -2603,8 +2624,8 @@ export class LocalBackend {
|
|
|
2603
2624
|
name: sym.name || sym[1],
|
|
2604
2625
|
kind: symKind,
|
|
2605
2626
|
filePath: sym.filePath || sym[3],
|
|
2606
|
-
startLine: sym.startLine
|
|
2607
|
-
endLine: sym.endLine
|
|
2627
|
+
startLine: toDisplayLine(sym.startLine ?? sym[4]),
|
|
2628
|
+
endLine: toDisplayLine(sym.endLine ?? sym[5]),
|
|
2608
2629
|
...(include_content && (sym.content || sym[6]) ? { content: sym.content || sym[6] } : {}),
|
|
2609
2630
|
...(methodMetadata ? { methodMetadata } : {}),
|
|
2610
2631
|
},
|
|
@@ -2680,7 +2701,7 @@ export class LocalBackend {
|
|
|
2680
2701
|
name: c.name,
|
|
2681
2702
|
kind: c.type,
|
|
2682
2703
|
filePath: c.filePath,
|
|
2683
|
-
line: c.startLine,
|
|
2704
|
+
line: toDisplayLine(c.startLine),
|
|
2684
2705
|
score: Number(c.score.toFixed(2)),
|
|
2685
2706
|
})),
|
|
2686
2707
|
},
|
|
@@ -2698,11 +2719,14 @@ export class LocalBackend {
|
|
|
2698
2719
|
return {
|
|
2699
2720
|
anchorClause: 'a.id STARTS WITH $idPrefix AND a.startLine >= $symStart AND a.startLine <= $symEnd',
|
|
2700
2721
|
queryParams: { idPrefix, symStart: sym.startLine + 1, symEnd: sym.endLine + 1 },
|
|
2722
|
+
// Display anchor is 1-based, matching the ambiguous-candidate branch and
|
|
2723
|
+
// the context/query/impact tools (#2380). This is display-only — the
|
|
2724
|
+
// BasicBlock join above uses the raw `sym.startLine + 1` in `symStart`.
|
|
2701
2725
|
anchor: {
|
|
2702
2726
|
file: sym.filePath,
|
|
2703
2727
|
symbol: sym.name,
|
|
2704
|
-
startLine: sym.startLine,
|
|
2705
|
-
endLine: sym.endLine,
|
|
2728
|
+
startLine: toDisplayLine(sym.startLine),
|
|
2729
|
+
endLine: toDisplayLine(sym.endLine),
|
|
2706
2730
|
},
|
|
2707
2731
|
};
|
|
2708
2732
|
}
|
|
@@ -4036,7 +4060,7 @@ export class LocalBackend {
|
|
|
4036
4060
|
name: c.name,
|
|
4037
4061
|
kind: c.type,
|
|
4038
4062
|
filePath: c.filePath,
|
|
4039
|
-
line: c.startLine,
|
|
4063
|
+
line: toDisplayLine(c.startLine),
|
|
4040
4064
|
score: Number(c.score.toFixed(2)),
|
|
4041
4065
|
})),
|
|
4042
4066
|
};
|
|
@@ -4089,7 +4113,7 @@ export class LocalBackend {
|
|
|
4089
4113
|
name: c.name,
|
|
4090
4114
|
kind: c.type,
|
|
4091
4115
|
filePath: c.filePath,
|
|
4092
|
-
line: c.startLine,
|
|
4116
|
+
line: toDisplayLine(c.startLine),
|
|
4093
4117
|
score: Number(c.score.toFixed(2)),
|
|
4094
4118
|
impactedCount: summary?.impactedCount ?? 0,
|
|
4095
4119
|
risk: summary?.risk ?? 'UNKNOWN',
|
|
@@ -34,8 +34,10 @@ export declare function splitCalleeIds(raw: unknown): string[];
|
|
|
34
34
|
* Contract version of the mode:'pdg' impact result shape. A stable discriminator
|
|
35
35
|
* for external MCP/agent consumers — distinct from the DB INCREMENTAL_SCHEMA_VERSION.
|
|
36
36
|
* Bump on any breaking change to the PDG result fields.
|
|
37
|
+
* v2: `startLine` in the result is now 1-based display (#2380), matching the
|
|
38
|
+
* context/query/impact tools (was 0-based).
|
|
37
39
|
*/
|
|
38
|
-
export declare const PDG_RESULT_VERSION:
|
|
40
|
+
export declare const PDG_RESULT_VERSION: 2;
|
|
39
41
|
/** A reachable dependence block resolved to its source statement. */
|
|
40
42
|
export interface PdgStatement {
|
|
41
43
|
/** 1-based source line where the statement's block starts. */
|
|
@@ -105,7 +107,7 @@ export interface PdgInterproceduralImpact {
|
|
|
105
107
|
export interface PdgImpactBaseResult extends PdgImpactParityFields {
|
|
106
108
|
mode: 'pdg';
|
|
107
109
|
/** Contract version of the mode:'pdg' impact result shape; bump on any breaking change to the PDG result fields. */
|
|
108
|
-
pdgResultVersion:
|
|
110
|
+
pdgResultVersion: 2;
|
|
109
111
|
target: PdgImpactTarget;
|
|
110
112
|
direction: 'upstream' | 'downstream';
|
|
111
113
|
impactedCount: number;
|
|
@@ -172,7 +174,7 @@ export interface PdgImpactDegradedResult extends PdgImpactBaseResult {
|
|
|
172
174
|
export interface PdgImpactErrorResult {
|
|
173
175
|
mode?: 'pdg';
|
|
174
176
|
/** Contract version of the mode:'pdg' impact result shape; bump on any breaking change to the PDG result fields. */
|
|
175
|
-
pdgResultVersion:
|
|
177
|
+
pdgResultVersion: 2;
|
|
176
178
|
error: string;
|
|
177
179
|
target: PdgImpactTarget;
|
|
178
180
|
direction: 'upstream' | 'downstream';
|
|
@@ -9,6 +9,7 @@ import path from 'path';
|
|
|
9
9
|
import { loadMeta } from '../../storage/repo-manager.js';
|
|
10
10
|
import { IMPACT_MAX_DEPTH, PDG_QUERY_DEFAULT_LIMIT, PDG_QUERY_MAX_LIMIT } from '../tools.js';
|
|
11
11
|
import { CALLEES_TRUNCATED_SENTINEL, CALLEE_ID_SEP } from '../../core/ingestion/cfg/emit.js';
|
|
12
|
+
import { toDisplayLine } from './line-display.js';
|
|
12
13
|
import { decodeCallSummary } from '../../core/ingestion/taint/call-summary-codec.js';
|
|
13
14
|
import { decodeReachingDefReason } from '../../core/ingestion/cfg/reaching-def-reason-codec.js';
|
|
14
15
|
import { getProviderForFile } from '../../core/ingestion/languages/index.js';
|
|
@@ -84,8 +85,10 @@ export function splitCalleeIds(raw) {
|
|
|
84
85
|
* Contract version of the mode:'pdg' impact result shape. A stable discriminator
|
|
85
86
|
* for external MCP/agent consumers — distinct from the DB INCREMENTAL_SCHEMA_VERSION.
|
|
86
87
|
* Bump on any breaking change to the PDG result fields.
|
|
88
|
+
* v2: `startLine` in the result is now 1-based display (#2380), matching the
|
|
89
|
+
* context/query/impact tools (was 0-based).
|
|
87
90
|
*/
|
|
88
|
-
export const PDG_RESULT_VERSION =
|
|
91
|
+
export const PDG_RESULT_VERSION = 2;
|
|
89
92
|
/**
|
|
90
93
|
* FU-B-2 intra-block def→use line walk. Given a block's self REACHING_DEF
|
|
91
94
|
* def→use line PAIRS (every `defLine → useLine` step decoded from the edge
|
|
@@ -519,7 +522,7 @@ function assemblePdgImpactResult(input) {
|
|
|
519
522
|
name: s.name,
|
|
520
523
|
type: s.type,
|
|
521
524
|
filePath: s.filePath,
|
|
522
|
-
...(s.startLine !== undefined ? { startLine: s.startLine } : {}),
|
|
525
|
+
...(s.startLine !== undefined ? { startLine: toDisplayLine(s.startLine) } : {}),
|
|
523
526
|
...(s.ambiguous ? { ambiguous: true } : {}),
|
|
524
527
|
...(s.id === null ? { unresolved: true } : {}),
|
|
525
528
|
pdgEvidence: (s.id === null ? 'degraded' : 'owner-projection'),
|
package/dist/mcp/resources.js
CHANGED
|
@@ -365,6 +365,7 @@ additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Nam
|
|
|
365
365
|
|
|
366
366
|
node_properties:
|
|
367
367
|
common: "name (STRING), filePath (STRING), startLine (INT32), endLine (INT32)"
|
|
368
|
+
line_numbers: "startLine/endLine on symbol nodes are 0-BASED (tree-sitter rows) in storage AND in raw Cypher results. The context, query, impact, group/cross-repo trace, and explain/pdg_query (symbol anchor) tools present them 1-BASED (editor / sed / less -N aligned), so a symbol spans editor lines (startLine+1)..(endLine+1) — e.g. sed '<startLine+1>,<endLine+1>!d' <file>. Single-repo trace symbol lines stay 0-BASED for now (full-parity follow-up). content holds the exact symbol span. (BasicBlock / PDG statement lines are separately 1-based.) (#2377, #2380)"
|
|
368
369
|
Method: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isVirtual (BOOL), isOverride (BOOL), isAsync (BOOL), isPartial (BOOL), requiredParameterCount (INT32), parameterTypes (STRING[]), annotations (STRING[])"
|
|
369
370
|
Function: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isAsync (BOOL), parameterTypes (STRING[]), annotations (STRING[])"
|
|
370
371
|
Property: "declaredType (STRING) — the field's type annotation (e.g., 'Address', 'City'). Used for field-access chain resolution."
|
package/dist/mcp/tools.js
CHANGED
|
@@ -379,7 +379,7 @@ MODE (opt-in): "callgraph" (default) walks symbol→symbol edges (CALLS/IMPORTS/
|
|
|
379
379
|
|
|
380
380
|
STATEMENT-ANCHORED PDG SLICE: with mode:'pdg', pass "line" (1-based source line within the target symbol) to seed the dependence slice on the statement at that line and return what depends on it in affectedStatements (line + text). Inter-procedural symbols are still reported through interproceduralByDepth/pdgInterprocedural and the compatibility byDepth bucket. Without "line", pdg returns whole-symbol inter-procedural reach plus local whole-symbol PDG diagnostics.
|
|
381
381
|
|
|
382
|
-
PDG OUTPUT CONTRACT: every mode:'pdg' result (success, empty, degraded, or error) carries pdgResultVersion:
|
|
382
|
+
PDG OUTPUT CONTRACT: every mode:'pdg' result (success, empty, degraded, or error) carries pdgResultVersion:2 — a stable discriminator for external consumers that bumps on any breaking change to the PDG result shape (distinct from the DB schema version). Successful PDG results include mode:'pdg', a full target envelope (id/name/type/filePath), affectedStatements, affectedStatementCount, interproceduralByDepth/pdgInterprocedural for cross-function reach, compatibility byDepth/byDepthCounts, risk:'UNKNOWN', and a note describing the unified contract. Degraded PDG results (no-layer, sub-layer-missing, unknown) keep mode:'pdg', pdgResultVersion:2, target metadata when the target resolves, risk:'UNKNOWN', note/remediation, and empty byDepth parity fields — never a false-safe zero. If depth and limit both bound the slice, truncatedByReasons reports both causes while truncatedBy remains scalar.
|
|
383
383
|
|
|
384
384
|
WHEN TO USE: Before making code changes — especially refactoring, renaming, or modifying shared code. Shows what would break.
|
|
385
385
|
AFTER THIS: Review d=1 items (WILL BREAK). Use context() on high-risk symbols.
|
|
@@ -242,8 +242,13 @@ export interface RepoMeta {
|
|
|
242
242
|
* URL-only id). The incremental writeback preserves unchanged-file rows, so a
|
|
243
243
|
* top-up against a pre-v5 index would strand old url-keyed Route nodes alongside
|
|
244
244
|
* new composite-keyed ones — force a full re-analyze instead.
|
|
245
|
+
* v6: line-number storage flipped to uniform 0-based for the last 1-based
|
|
246
|
+
* GraphNode emitters — COBOL/JCL/markdown/scope (#2377/#2379/#2380). Incremental
|
|
247
|
+
* writeback preserves unchanged-file rows, so a top-up against a pre-v6 index
|
|
248
|
+
* would MIX old 1-based rows with new 0-based ones — and the 1-based MCP display
|
|
249
|
+
* would render the stale rows one line too high — so force a full re-analyze.
|
|
245
250
|
*/
|
|
246
|
-
export declare const INCREMENTAL_SCHEMA_VERSION =
|
|
251
|
+
export declare const INCREMENTAL_SCHEMA_VERSION = 6;
|
|
247
252
|
export interface IndexedRepo {
|
|
248
253
|
repoPath: string;
|
|
249
254
|
storagePath: string;
|
|
@@ -90,8 +90,13 @@ export const registryPathEquals = (a, b) => process.platform === 'win32' ? a.toL
|
|
|
90
90
|
* URL-only id). The incremental writeback preserves unchanged-file rows, so a
|
|
91
91
|
* top-up against a pre-v5 index would strand old url-keyed Route nodes alongside
|
|
92
92
|
* new composite-keyed ones — force a full re-analyze instead.
|
|
93
|
+
* v6: line-number storage flipped to uniform 0-based for the last 1-based
|
|
94
|
+
* GraphNode emitters — COBOL/JCL/markdown/scope (#2377/#2379/#2380). Incremental
|
|
95
|
+
* writeback preserves unchanged-file rows, so a top-up against a pre-v6 index
|
|
96
|
+
* would MIX old 1-based rows with new 0-based ones — and the 1-based MCP display
|
|
97
|
+
* would render the stale rows one line too high — so force a full re-analyze.
|
|
93
98
|
*/
|
|
94
|
-
export const INCREMENTAL_SCHEMA_VERSION =
|
|
99
|
+
export const INCREMENTAL_SCHEMA_VERSION = 6;
|
|
95
100
|
const GITNEXUS_DIR = '.gitnexus';
|
|
96
101
|
const GITNEXUS_EXCLUDE_ENTRY = `${GITNEXUS_DIR}/`;
|
|
97
102
|
export const INDEX_METADATA_FILE = 'gitnexus.json';
|
package/package.json
CHANGED