gitnexus 1.6.7-rc.1 → 1.6.7-rc.3

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.
Files changed (64) hide show
  1. package/dist/_shared/graph/types.d.ts +18 -2
  2. package/dist/_shared/graph/types.d.ts.map +1 -1
  3. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  4. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  5. package/dist/_shared/lbug/schema-constants.js +10 -0
  6. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  7. package/dist/cli/analyze.js +7 -5
  8. package/dist/cli/optional-grammars.d.ts +18 -4
  9. package/dist/cli/optional-grammars.js +51 -8
  10. package/dist/core/ingestion/languages/dart/query.js +11 -3
  11. package/dist/core/ingestion/languages/kotlin/query.js +11 -3
  12. package/dist/core/ingestion/languages/swift/query.js +11 -3
  13. package/dist/core/ingestion/model/registration-table.js +3 -0
  14. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  15. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  16. package/dist/core/ingestion/pipeline-phases/parse-impl.js +11 -3
  17. package/dist/core/ingestion/pipeline-phases/registry.d.ts +56 -0
  18. package/dist/core/ingestion/pipeline-phases/registry.js +48 -0
  19. package/dist/core/ingestion/pipeline.d.ts +21 -0
  20. package/dist/core/ingestion/pipeline.js +28 -20
  21. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +11 -0
  22. package/dist/core/ingestion/taint/source-sink-config.d.ts +36 -0
  23. package/dist/core/ingestion/taint/source-sink-config.js +16 -0
  24. package/dist/core/ingestion/taint/source-sink-registry.d.ts +27 -0
  25. package/dist/core/ingestion/taint/source-sink-registry.js +35 -0
  26. package/dist/core/ingestion/workers/parse-worker.js +13 -0
  27. package/dist/core/lbug/csv-generator.js +14 -0
  28. package/dist/core/lbug/lbug-adapter.js +12 -0
  29. package/dist/core/lbug/schema.d.ts +2 -1
  30. package/dist/core/lbug/schema.js +22 -0
  31. package/dist/core/tree-sitter/parser-loader.d.ts +8 -0
  32. package/dist/core/tree-sitter/parser-loader.js +70 -0
  33. package/dist/server/api.d.ts +1 -0
  34. package/dist/server/api.js +17 -2
  35. package/package.json +1 -1
  36. package/scripts/spikes/s1-reaching-def-index-bench.ts +151 -0
  37. package/scripts/spikes/s2-postdom-prototype.ts +162 -0
  38. package/web/assets/{agent-EkX7webX.js → agent-CKPMqImC.js} +1 -1
  39. package/web/assets/{architectureDiagram-UL44E2DR-BoczH8cv.js → architectureDiagram-UL44E2DR-D1EXI0zA.js} +1 -1
  40. package/web/assets/{chunk-LCXTWHL2-By5HB3b-.js → chunk-LCXTWHL2-Dfmux4m1.js} +1 -1
  41. package/web/assets/{chunk-RG4AUYOV-BQE_DkpL.js → chunk-RG4AUYOV-CAkzcoRj.js} +1 -1
  42. package/web/assets/{classDiagram-KGZ6W3CR-Dj_02GUH.js → classDiagram-KGZ6W3CR-Bv93af_b.js} +1 -1
  43. package/web/assets/{classDiagram-v2-72OJOZXJ-D-NArMpf.js → classDiagram-v2-72OJOZXJ-CLfEqHUa.js} +1 -1
  44. package/web/assets/{diagram-3NCE3AQN-VXtXDO95.js → diagram-3NCE3AQN-BqAtKUpW.js} +1 -1
  45. package/web/assets/{diagram-GF46GFSD-B1qab2Ah.js → diagram-GF46GFSD-CaBG6n6o.js} +1 -1
  46. package/web/assets/{diagram-QXG6HAR7-BSCHGzzT.js → diagram-QXG6HAR7-CZ-O3rcV.js} +1 -1
  47. package/web/assets/{diagram-WEQXMOUZ-DHtknmNT.js → diagram-WEQXMOUZ-P4lSL4GH.js} +1 -1
  48. package/web/assets/{erDiagram-L5TCEMPS-Db-IYTmm.js → erDiagram-L5TCEMPS-QN2eEP1e.js} +1 -1
  49. package/web/assets/{flowDiagram-H6V6AXG4-BHDoyVoW.js → flowDiagram-H6V6AXG4-CXbXImlN.js} +1 -1
  50. package/web/assets/{index-BR0IhgbR.js → index-CG6q8eTs.js} +6 -6
  51. package/web/assets/{infoDiagram-3YFTVSEB-6h8wbWEe.js → infoDiagram-3YFTVSEB-DmLICZx1.js} +1 -1
  52. package/web/assets/{ishikawaDiagram-BNXS4ZKH-Dx2OkPk1.js → ishikawaDiagram-BNXS4ZKH-6LKOvBfp.js} +1 -1
  53. package/web/assets/{kanban-definition-75IXJCU3-CIIEZfqV.js → kanban-definition-75IXJCU3-DgDi9oJT.js} +1 -1
  54. package/web/assets/{mindmap-definition-2TDM6QVE-DUAqydRq.js → mindmap-definition-2TDM6QVE-CwR5sBB-.js} +1 -1
  55. package/web/assets/{pieDiagram-CU6KROY3-BntYuYZa.js → pieDiagram-CU6KROY3-By8g6f6B.js} +1 -1
  56. package/web/assets/{requirementDiagram-JXO7QTGE-QCD6I29n.js → requirementDiagram-JXO7QTGE-7oDcJ1_J.js} +1 -1
  57. package/web/assets/{sequenceDiagram-VS2MUI6T-DScFwLz2.js → sequenceDiagram-VS2MUI6T-FySeKCUy.js} +1 -1
  58. package/web/assets/{stateDiagram-7D4R322I-AkRAm6Hl.js → stateDiagram-7D4R322I-CB2nABwH.js} +1 -1
  59. package/web/assets/{stateDiagram-v2-36443NZ5-BCK1vigR.js → stateDiagram-v2-36443NZ5-COBGd2RL.js} +1 -1
  60. package/web/assets/{timeline-definition-O6YCAMPW-BvpIVXjX.js → timeline-definition-O6YCAMPW-Ds2CnVZK.js} +1 -1
  61. package/web/assets/{vennDiagram-MWXL3ELB-BYGWk6dK.js → vennDiagram-MWXL3ELB-DUIEwXWp.js} +1 -1
  62. package/web/assets/{wardleyDiagram-CUQ6CDDI-Dk1z7H2T.js → wardleyDiagram-CUQ6CDDI-DEiFPQih.js} +1 -1
  63. package/web/assets/{xychartDiagram-N2JHSOCM-2N6NCSWN.js → xychartDiagram-N2JHSOCM-BUbayhST.js} +1 -1
  64. package/web/index.html +1 -1
@@ -5,7 +5,7 @@
5
5
  * Do NOT add Node.js-specific or browser-specific imports here.
6
6
  */
7
7
  import { SupportedLanguages } from '../languages.js';
8
- export type NodeLabel = 'Project' | 'Package' | 'Module' | 'Folder' | 'File' | 'Class' | 'Function' | 'Method' | 'Variable' | 'Interface' | 'Enum' | 'Decorator' | 'Import' | 'Type' | 'CodeElement' | 'Community' | 'Process' | 'Struct' | 'Macro' | 'Typedef' | 'Union' | 'Namespace' | 'Trait' | 'Impl' | 'TypeAlias' | 'Const' | 'Static' | 'Property' | 'Record' | 'Delegate' | 'Annotation' | 'Constructor' | 'Template' | 'Section' | 'Route' | 'Tool';
8
+ export type NodeLabel = 'Project' | 'Package' | 'Module' | 'Folder' | 'File' | 'Class' | 'Function' | 'Method' | 'Variable' | 'Interface' | 'Enum' | 'Decorator' | 'Import' | 'Type' | 'CodeElement' | 'Community' | 'Process' | 'Struct' | 'Macro' | 'Typedef' | 'Union' | 'Namespace' | 'Trait' | 'Impl' | 'TypeAlias' | 'Const' | 'Static' | 'Property' | 'Record' | 'Delegate' | 'Annotation' | 'Constructor' | 'Template' | 'Section' | 'Route' | 'Tool' | 'BasicBlock';
9
9
  export type NodeProperties = {
10
10
  name: string;
11
11
  filePath: string;
@@ -45,6 +45,7 @@ export type NodeProperties = {
45
45
  responseKeys?: string[];
46
46
  errorKeys?: string[];
47
47
  middleware?: string[];
48
+ text?: string;
48
49
  [key: string]: unknown;
49
50
  };
50
51
  export type RelationshipType = 'CONTAINS' | 'CALLS' | 'INHERITS' | 'METHOD_OVERRIDES' | 'METHOD_IMPLEMENTS' | 'IMPORTS' | 'USES' | 'DEFINES' | 'DECORATES' | 'IMPLEMENTS' | 'EXTENDS' | 'HAS_METHOD' | 'HAS_PROPERTY' | 'ACCESSES' | 'MEMBER_OF' | 'STEP_IN_PROCESS' | 'HANDLES_ROUTE' | 'FETCHES' | 'HANDLES_TOOL' | 'ENTRY_POINT_OF' | 'WRAPS' | 'QUERIES'
@@ -63,7 +64,22 @@ export type RelationshipType = 'CONTAINS' | 'CALLS' | 'INHERITS' | 'METHOD_OVERR
63
64
  * `reason` encodes the event name: `vue-emit: <eventName>`.
64
65
  * Complements `BINDS_EVENT_HANDLER`; a Cypher query joining on the
65
66
  * component File node reveals all (emitter, handler) pairs. */
66
- | 'EMITS_EVENT';
67
+ | 'EMITS_EVENT'
68
+ /** Control-flow edge between two BasicBlock nodes (intra-procedural CFG). */
69
+ | 'CFG'
70
+ /** Data-dependence edge: a definition of `variable` reaches a use of it.
71
+ * The `variable` name is stored in the relation's existing `reason` column
72
+ * (M0/S1 verdict: LadybugDB has no secondary index on relationship
73
+ * properties, so a dedicated indexed column would not speed the
74
+ * variable-filtered path query). */
75
+ | 'REACHING_DEF'
76
+ /** A tainted value flows from source toward sink. */
77
+ | 'TAINTED'
78
+ /** A sanitizer clears taint along a flow. */
79
+ | 'SANITIZES'
80
+ /** Materialized source→sink taint path. Working name — final name/representation
81
+ * is confirmed when M3/M4 emits it; no persisted edge exists before then. */
82
+ | 'TAINT_PATH';
67
83
  export interface GraphNode {
68
84
  id: string;
69
85
  label: NodeLabel;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
@@ -7,10 +7,10 @@
7
7
  * Full DDL schemas remain in each package's own schema.ts because
8
8
  * the CLI uses native LadybugDB and the web uses WASM.
9
9
  */
10
- export declare const NODE_TABLES: readonly ["File", "Folder", "Function", "Class", "Interface", "Method", "CodeElement", "Community", "Process", "Section", "Struct", "Enum", "Macro", "Typedef", "Union", "Namespace", "Trait", "Impl", "TypeAlias", "Const", "Static", "Variable", "Property", "Record", "Delegate", "Annotation", "Constructor", "Template", "Module", "Route", "Tool"];
10
+ export declare const NODE_TABLES: readonly ["File", "Folder", "Function", "Class", "Interface", "Method", "CodeElement", "Community", "Process", "Section", "Struct", "Enum", "Macro", "Typedef", "Union", "Namespace", "Trait", "Impl", "TypeAlias", "Const", "Static", "Variable", "Property", "Record", "Delegate", "Annotation", "Constructor", "Template", "Module", "Route", "Tool", "BasicBlock"];
11
11
  export type NodeTableName = (typeof NODE_TABLES)[number];
12
12
  export declare const REL_TABLE_NAME = "CodeRelation";
13
- export declare const REL_TYPES: readonly ["CONTAINS", "DEFINES", "IMPORTS", "CALLS", "EXTENDS", "IMPLEMENTS", "HAS_METHOD", "HAS_PROPERTY", "ACCESSES", "METHOD_OVERRIDES", "OVERRIDES", "METHOD_IMPLEMENTS", "MEMBER_OF", "STEP_IN_PROCESS", "HANDLES_ROUTE", "FETCHES", "HANDLES_TOOL", "ENTRY_POINT_OF", "WRAPS", "QUERIES"];
13
+ export declare const REL_TYPES: readonly ["CONTAINS", "DEFINES", "IMPORTS", "CALLS", "EXTENDS", "IMPLEMENTS", "HAS_METHOD", "HAS_PROPERTY", "ACCESSES", "METHOD_OVERRIDES", "OVERRIDES", "METHOD_IMPLEMENTS", "MEMBER_OF", "STEP_IN_PROCESS", "HANDLES_ROUTE", "FETCHES", "HANDLES_TOOL", "ENTRY_POINT_OF", "WRAPS", "QUERIES", "CFG", "REACHING_DEF", "TAINTED", "SANITIZES", "TAINT_PATH"];
14
14
  export type RelType = (typeof REL_TYPES)[number];
15
15
  export declare const EMBEDDING_TABLE_NAME = "CodeEmbedding";
16
16
  //# sourceMappingURL=schema-constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-constants.d.ts","sourceRoot":"","sources":["../../src/lbug/schema-constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,WAAW,0VAgCd,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C,eAAO,MAAM,SAAS,iSAqBZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,eAAO,MAAM,oBAAoB,kBAAkB,CAAC"}
1
+ {"version":3,"file":"schema-constants.d.ts","sourceRoot":"","sources":["../../src/lbug/schema-constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,WAAW,wWAkCd,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,cAAc,iBAAiB,CAAC;AAE7C,eAAO,MAAM,SAAS,8VA6BZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD,eAAO,MAAM,oBAAoB,kBAAkB,CAAC"}
@@ -39,6 +39,8 @@ export const NODE_TABLES = [
39
39
  'Module',
40
40
  'Route',
41
41
  'Tool',
42
+ // Taint/PDG substrate (issue #2080) — inert until M1 (#2081) emits blocks.
43
+ 'BasicBlock',
42
44
  ];
43
45
  export const REL_TABLE_NAME = 'CodeRelation';
44
46
  export const REL_TYPES = [
@@ -62,6 +64,14 @@ export const REL_TYPES = [
62
64
  'ENTRY_POINT_OF',
63
65
  'WRAPS',
64
66
  'QUERIES',
67
+ // Taint/PDG substrate (issue #2080) — reserved edge types, emitted by no
68
+ // phase yet (CFG → M1, REACHING_DEF → M2, TAINTED/SANITIZES/TAINT_PATH →
69
+ // M3/M4). REACHING_DEF's variable name rides the relation's `reason` column.
70
+ 'CFG',
71
+ 'REACHING_DEF',
72
+ 'TAINTED',
73
+ 'SANITIZES',
74
+ 'TAINT_PATH',
65
75
  ];
66
76
  export const EMBEDDING_TABLE_NAME = 'CodeEmbedding';
67
77
  //# sourceMappingURL=schema-constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-constants.js","sourceRoot":"","sources":["../../src/lbug/schema-constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,QAAQ;IACR,UAAU;IACV,OAAO;IACP,WAAW;IACX,QAAQ;IACR,aAAa;IACb,WAAW;IACX,SAAS;IACT,SAAS;IACT,QAAQ;IACR,MAAM;IACN,OAAO;IACP,SAAS;IACT,OAAO;IACP,WAAW;IACX,OAAO;IACP,MAAM;IACN,WAAW;IACX,OAAO;IACP,QAAQ;IACR,UAAU;IACV,UAAU;IACV,QAAQ;IACR,UAAU;IACV,YAAY;IACZ,aAAa;IACb,UAAU;IACV,QAAQ;IACR,OAAO;IACP,MAAM;CACE,CAAC;AAIX,MAAM,CAAC,MAAM,cAAc,GAAG,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU;IACV,SAAS;IACT,SAAS;IACT,OAAO;IACP,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,UAAU;IACV,kBAAkB;IAClB,WAAW,EAAE,mEAAmE;IAChF,mBAAmB;IACnB,WAAW;IACX,iBAAiB;IACjB,eAAe;IACf,SAAS;IACT,cAAc;IACd,gBAAgB;IAChB,OAAO;IACP,SAAS;CACD,CAAC;AAIX,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"schema-constants.js","sourceRoot":"","sources":["../../src/lbug/schema-constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM;IACN,QAAQ;IACR,UAAU;IACV,OAAO;IACP,WAAW;IACX,QAAQ;IACR,aAAa;IACb,WAAW;IACX,SAAS;IACT,SAAS;IACT,QAAQ;IACR,MAAM;IACN,OAAO;IACP,SAAS;IACT,OAAO;IACP,WAAW;IACX,OAAO;IACP,MAAM;IACN,WAAW;IACX,OAAO;IACP,QAAQ;IACR,UAAU;IACV,UAAU;IACV,QAAQ;IACR,UAAU;IACV,YAAY;IACZ,aAAa;IACb,UAAU;IACV,QAAQ;IACR,OAAO;IACP,MAAM;IACN,2EAA2E;IAC3E,YAAY;CACJ,CAAC;AAIX,MAAM,CAAC,MAAM,cAAc,GAAG,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU;IACV,SAAS;IACT,SAAS;IACT,OAAO;IACP,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,UAAU;IACV,kBAAkB;IAClB,WAAW,EAAE,mEAAmE;IAChF,mBAAmB;IACnB,WAAW;IACX,iBAAiB;IACjB,eAAe;IACf,SAAS;IACT,cAAc;IACd,gBAAgB;IAChB,OAAO;IACP,SAAS;IACT,yEAAyE;IACzE,yEAAyE;IACzE,6EAA6E;IAC7E,KAAK;IACL,cAAc;IACd,SAAS;IACT,WAAW;IACX,YAAY;CACJ,CAAC;AAIX,MAAM,CAAC,MAAM,oBAAoB,GAAG,eAAe,CAAC"}
@@ -19,7 +19,7 @@ import { getGitRoot, hasGitDir, getDefaultBranch } from '../storage/git.js';
19
19
  import { loadAnalyzeConfig, mergeAnalyzeOptions, resolveDefaultBranch, validateBranchName, GitNexusRcError, } from './analyze-config.js';
20
20
  import { runFullAnalysis } from '../core/run-analyze.js';
21
21
  import { getMaxFileSizeBannerMessage } from '../core/ingestion/utils/max-file-size.js';
22
- import { warnMissingOptionalGrammars } from './optional-grammars.js';
22
+ import { warnMissingOptionalGrammars, getOptionalGrammarExtensions } from './optional-grammars.js';
23
23
  import { glob } from 'glob';
24
24
  import fs from 'fs/promises';
25
25
  import { cliError } from './cli-message.js';
@@ -691,11 +691,13 @@ const analyzeCommandImpl = async (inputPath, cliOptions) => {
691
691
  console.log(' Note: --index-only overrides --skills; community skill files will not be written.\n');
692
692
  }
693
693
  // If the target repo contains files an optional grammar would parse but
694
- // that grammar's native binding is absent, warn before analysis so users
695
- // learn why those files end up unparsed instead of silently getting a
696
- // degraded index.
694
+ // that grammar's native binding is absent (or disabled via
695
+ // GITNEXUS_SKIP_OPTIONAL_GRAMMARS), warn before analysis so users learn why
696
+ // those files end up unparsed instead of silently getting a degraded index.
697
+ // The extension set is derived from OPTIONAL_GRAMMARS so it can't drift.
697
698
  try {
698
- const matches = await glob(['**/*.dart', '**/*.proto'], {
699
+ const optionalGlobs = getOptionalGrammarExtensions().map((e) => `**/*${e}`);
700
+ const matches = await glob(optionalGlobs, {
699
701
  cwd: repoPath,
700
702
  ignore: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/build/**'],
701
703
  dot: false,
@@ -4,19 +4,33 @@
4
4
  * tree-sitter-dart, tree-sitter-proto, and tree-sitter-swift are vendored
5
5
  * under vendor/ and materialized into node_modules/ at postinstall. Dart
6
6
  * and Proto are built from source with node-gyp; Swift ships platform
7
- * prebuilds activated via node-gyp-build. All three can be skipped via
7
+ * prebuilds activated via node-gyp-build. tree-sitter-kotlin is a declared
8
+ * optionalDependency (not vendored). All can be skipped via
8
9
  * GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1 (postinstall scripts), or can silently
9
- * soft-fail when the toolchain is missing (Dart/Proto) or no prebuild
10
- * matches the host platform (Swift).
10
+ * soft-fail when the toolchain is missing (Dart/Proto), when no prebuild
11
+ * matches the host platform (Swift), or when the optional install was
12
+ * skipped or its native build failed (Kotlin).
11
13
  *
12
14
  * Either path produces the same observable: the .node binding is absent
13
15
  * at runtime. This helper detects that condition and surfaces a single
14
- * stderr line per missing grammar so users learn why .dart/.proto/.swift
16
+ * stderr line per missing grammar so users learn why .dart/.proto/.swift/.kt
15
17
  * support is unavailable instead of silently getting a degraded index.
16
18
  */
19
+ /**
20
+ * The file extensions backed by an optional grammar — the single source for
21
+ * the `analyze` preflight glob (so the glob can't drift from this list).
22
+ */
23
+ export declare function getOptionalGrammarExtensions(): string[];
17
24
  export interface MissingGrammar {
18
25
  name: string;
19
26
  extensions: string[];
27
+ /**
28
+ * `missing` — the native binding could not be loaded (not installed / build
29
+ * soft-failed / no prebuild). `skipped` — the binding is fine but the user
30
+ * disabled it via `GITNEXUS_SKIP_OPTIONAL_GRAMMARS`. Drives the warning text
31
+ * so a deliberate opt-out is not told to reinstall.
32
+ */
33
+ reason: 'missing' | 'skipped';
20
34
  }
21
35
  /**
22
36
  * Returns the list of optional grammars whose native binding cannot be
@@ -4,24 +4,51 @@
4
4
  * tree-sitter-dart, tree-sitter-proto, and tree-sitter-swift are vendored
5
5
  * under vendor/ and materialized into node_modules/ at postinstall. Dart
6
6
  * and Proto are built from source with node-gyp; Swift ships platform
7
- * prebuilds activated via node-gyp-build. All three can be skipped via
7
+ * prebuilds activated via node-gyp-build. tree-sitter-kotlin is a declared
8
+ * optionalDependency (not vendored). All can be skipped via
8
9
  * GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1 (postinstall scripts), or can silently
9
- * soft-fail when the toolchain is missing (Dart/Proto) or no prebuild
10
- * matches the host platform (Swift).
10
+ * soft-fail when the toolchain is missing (Dart/Proto), when no prebuild
11
+ * matches the host platform (Swift), or when the optional install was
12
+ * skipped or its native build failed (Kotlin).
11
13
  *
12
14
  * Either path produces the same observable: the .node binding is absent
13
15
  * at runtime. This helper detects that condition and surfaces a single
14
- * stderr line per missing grammar so users learn why .dart/.proto/.swift
16
+ * stderr line per missing grammar so users learn why .dart/.proto/.swift/.kt
15
17
  * support is unavailable instead of silently getting a degraded index.
16
18
  */
17
19
  import { createRequire } from 'module';
20
+ import { SupportedLanguages } from '../_shared/index.js';
21
+ import { isGrammarRuntimeSkipped } from '../core/tree-sitter/parser-loader.js';
18
22
  import { cliWarn } from './cli-message.js';
19
23
  const _require = createRequire(import.meta.url);
20
24
  const OPTIONAL_GRAMMARS = [
21
- { name: 'tree-sitter-dart', pkg: 'tree-sitter-dart', extensions: ['.dart'] },
25
+ {
26
+ name: 'tree-sitter-dart',
27
+ pkg: 'tree-sitter-dart',
28
+ extensions: ['.dart'],
29
+ language: SupportedLanguages.Dart,
30
+ },
22
31
  { name: 'tree-sitter-proto', pkg: 'tree-sitter-proto', extensions: ['.proto'] },
23
- { name: 'tree-sitter-swift', pkg: 'tree-sitter-swift', extensions: ['.swift'] },
32
+ {
33
+ name: 'tree-sitter-swift',
34
+ pkg: 'tree-sitter-swift',
35
+ extensions: ['.swift'],
36
+ language: SupportedLanguages.Swift,
37
+ },
38
+ {
39
+ name: 'tree-sitter-kotlin',
40
+ pkg: 'tree-sitter-kotlin',
41
+ extensions: ['.kt', '.kts'],
42
+ language: SupportedLanguages.Kotlin,
43
+ },
24
44
  ];
45
+ /**
46
+ * The file extensions backed by an optional grammar — the single source for
47
+ * the `analyze` preflight glob (so the glob can't drift from this list).
48
+ */
49
+ export function getOptionalGrammarExtensions() {
50
+ return [...new Set(OPTIONAL_GRAMMARS.flatMap((g) => g.extensions))];
51
+ }
25
52
  /**
26
53
  * Returns the list of optional grammars whose native binding cannot be
27
54
  * loaded. Actually `require()`s the package — `require.resolve` would
@@ -41,6 +68,13 @@ const OPTIONAL_GRAMMARS = [
41
68
  export function detectMissingOptionalGrammars() {
42
69
  const missing = [];
43
70
  for (const g of OPTIONAL_GRAMMARS) {
71
+ // Deliberate runtime opt-out comes first: even an installed binding is
72
+ // treated as unavailable, with a `skipped` reason so the warning says so
73
+ // instead of suggesting a reinstall (#2101 review).
74
+ if (g.language !== undefined && isGrammarRuntimeSkipped(g.language)) {
75
+ missing.push({ name: g.name, extensions: g.extensions, reason: 'skipped' });
76
+ continue;
77
+ }
44
78
  try {
45
79
  _require(g.pkg);
46
80
  }
@@ -59,7 +93,7 @@ export function detectMissingOptionalGrammars() {
59
93
  // there for tool-data stdout output).
60
94
  cliWarn(`GitNexus: optional grammar "${g.name}" is installed but failed to load (${msg.slice(0, 200)}). ${g.extensions.join('/')} files will not be parsed.`, { grammar: g.name, extensions: g.extensions, error: msg });
61
95
  }
62
- missing.push({ name: g.name, extensions: g.extensions });
96
+ missing.push({ name: g.name, extensions: g.extensions, reason: 'missing' });
63
97
  }
64
98
  }
65
99
  return missing;
@@ -86,6 +120,15 @@ export function warnMissingOptionalGrammars(opts) {
86
120
  if (relevantExtensions && !g.extensions.some((e) => relevantExtensions.has(e))) {
87
121
  continue;
88
122
  }
89
- cliWarn(`GitNexus${ctx}: optional grammar "${g.name}" is unavailable — ${g.extensions.join('/')} files will not be parsed. Reinstall without GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1 (and ensure python3, make, g++) to enable.`, { grammar: g.name, extensions: g.extensions, context: opts?.context });
123
+ const exts = g.extensions.join('/');
124
+ const message = g.reason === 'skipped'
125
+ ? `GitNexus${ctx}: optional grammar "${g.name}" is disabled via GITNEXUS_SKIP_OPTIONAL_GRAMMARS — ${exts} files will not be parsed. Unset the variable to re-enable.`
126
+ : `GitNexus${ctx}: optional grammar "${g.name}" is unavailable — ${exts} files will not be parsed. Reinstall without GITNEXUS_SKIP_OPTIONAL_GRAMMARS=1 (and ensure python3, make, g++) to enable.`;
127
+ cliWarn(message, {
128
+ grammar: g.name,
129
+ extensions: g.extensions,
130
+ reason: g.reason,
131
+ context: opts?.context,
132
+ });
90
133
  }
91
134
  }
@@ -22,7 +22,15 @@
22
22
  * - Parameter / return / receiver type bindings and arity metadata.
23
23
  */
24
24
  import Parser from 'tree-sitter';
25
- import Dart from 'tree-sitter-dart';
25
+ import { SupportedLanguages } from '../../../../_shared/index.js';
26
+ // `tree-sitter-dart` is an optional/vendored grammar that may be absent on a
27
+ // default install. Loaded lazily + guarded via parser-loader rather than
28
+ // statically imported: this module is pulled onto the main thread eagerly by
29
+ // the scope-resolution registry and the language-provider index, so a top-level
30
+ // `import Dart from 'tree-sitter-dart'` would throw ERR_MODULE_NOT_FOUND at
31
+ // module-load and crash `analyze` even for repos with no Dart files (#2091,
32
+ // #2093). The grammar is only ever needed inside the lazy getters below.
33
+ import { getLanguageGrammar } from '../../../tree-sitter/parser-loader.js';
26
34
  const DART_SCOPE_QUERY = `
27
35
  ; ── Scopes ───────────────────────────────────────────────────────────────────
28
36
  (program) @scope.module
@@ -130,13 +138,13 @@ let _query = null;
130
138
  export function getDartParser() {
131
139
  if (_parser === null) {
132
140
  _parser = new Parser();
133
- _parser.setLanguage(Dart);
141
+ _parser.setLanguage(getLanguageGrammar(SupportedLanguages.Dart));
134
142
  }
135
143
  return _parser;
136
144
  }
137
145
  export function getDartScopeQuery() {
138
146
  if (_query === null) {
139
- _query = new Parser.Query(Dart, DART_SCOPE_QUERY);
147
+ _query = new Parser.Query(getLanguageGrammar(SupportedLanguages.Dart), DART_SCOPE_QUERY);
140
148
  }
141
149
  return _query;
142
150
  }
@@ -1,5 +1,13 @@
1
1
  import Parser from 'tree-sitter';
2
- import Kotlin from 'tree-sitter-kotlin';
2
+ import { SupportedLanguages } from '../../../../_shared/index.js';
3
+ // `tree-sitter-kotlin` is an optionalDependency that may be absent on a default
4
+ // install (or fail its native build). Loaded lazily + guarded via parser-loader
5
+ // rather than statically imported: this module is pulled onto the main thread
6
+ // eagerly by the scope-resolution registry and the language-provider index, so
7
+ // a top-level `import Kotlin from 'tree-sitter-kotlin'` would throw
8
+ // ERR_MODULE_NOT_FOUND at module-load and crash `analyze` even for repos with no
9
+ // Kotlin files (#2091, #2093). The grammar is only ever needed in the getters.
10
+ import { getLanguageGrammar } from '../../../tree-sitter/parser-loader.js';
3
11
  const KOTLIN_SCOPE_QUERY = `
4
12
  ;; Scopes
5
13
  (source_file) @scope.module
@@ -176,13 +184,13 @@ let query = null;
176
184
  export function getKotlinParser() {
177
185
  if (parser === null) {
178
186
  parser = new Parser();
179
- parser.setLanguage(Kotlin);
187
+ parser.setLanguage(getLanguageGrammar(SupportedLanguages.Kotlin));
180
188
  }
181
189
  return parser;
182
190
  }
183
191
  export function getKotlinScopeQuery() {
184
192
  if (query === null) {
185
- query = new Parser.Query(Kotlin, KOTLIN_SCOPE_QUERY);
193
+ query = new Parser.Query(getLanguageGrammar(SupportedLanguages.Kotlin), KOTLIN_SCOPE_QUERY);
186
194
  }
187
195
  return query;
188
196
  }
@@ -42,7 +42,15 @@
42
42
  * tree-sitter init cost per file.
43
43
  */
44
44
  import Parser from 'tree-sitter';
45
- import Swift from 'tree-sitter-swift';
45
+ import { SupportedLanguages } from '../../../../_shared/index.js';
46
+ // `tree-sitter-swift` is an optional/vendored grammar that may be absent on a
47
+ // default install. It is loaded lazily + guarded via parser-loader rather than
48
+ // statically imported: this module is pulled onto the main thread eagerly by
49
+ // the scope-resolution registry and the language-provider index, so a top-level
50
+ // `import Swift from 'tree-sitter-swift'` would throw ERR_MODULE_NOT_FOUND at
51
+ // module-load and crash `analyze` even for repos with no Swift files (#2091,
52
+ // #2093). The grammar is only ever needed inside the lazy getters below.
53
+ import { getLanguageGrammar } from '../../../tree-sitter/parser-loader.js';
46
54
  const SWIFT_SCOPE_QUERY = `
47
55
  ;; ── Scopes ──────────────────────────────────────────────────────────
48
56
  (source_file) @scope.module
@@ -182,13 +190,13 @@ let _query = null;
182
190
  export function getSwiftParser() {
183
191
  if (_parser === null) {
184
192
  _parser = new Parser();
185
- _parser.setLanguage(Swift);
193
+ _parser.setLanguage(getLanguageGrammar(SupportedLanguages.Swift));
186
194
  }
187
195
  return _parser;
188
196
  }
189
197
  export function getSwiftScopeQuery() {
190
198
  if (_query === null) {
191
- _query = new Parser.Query(Swift, SWIFT_SCOPE_QUERY);
199
+ _query = new Parser.Query(getLanguageGrammar(SupportedLanguages.Swift), SWIFT_SCOPE_QUERY);
192
200
  }
193
201
  return _query;
194
202
  }
@@ -116,6 +116,9 @@ const LABEL_BEHAVIOR = {
116
116
  Section: 'inert',
117
117
  Route: 'inert',
118
118
  Tool: 'inert',
119
+ // Taint/PDG substrate (issue #2080) — a control-flow node, never a
120
+ // symbol-resolution target. Inert: file index only, no owner scope.
121
+ BasicBlock: 'inert',
119
122
  };
120
123
  // ---------------------------------------------------------------------------
121
124
  // Derived runtime collections — all keyed off LABEL_BEHAVIOR
@@ -21,3 +21,4 @@ export { processesPhase, type ProcessesOutput } from './processes.js';
21
21
  export { runPipeline } from './runner.js';
22
22
  export type { PipelinePhase, PipelineContext, PhaseResult } from './types.js';
23
23
  export { getPhaseOutput } from './types.js';
24
+ export { PhaseRegistry, type RegisterPhaseOptions } from './registry.js';
@@ -22,3 +22,4 @@ export { processesPhase } from './processes.js';
22
22
  // ── Infrastructure ─────────────────────────────────────────────────────────
23
23
  export { runPipeline } from './runner.js';
24
24
  export { getPhaseOutput } from './types.js';
25
+ export { PhaseRegistry } from './registry.js';
@@ -20,9 +20,9 @@ import { fileContentHash, computeChunkHash, loadParseCacheChunk, persistParseCac
20
20
  import { clearParsedFileStore, persistParsedFileChunk, getDurableParsedFileDir, loadDurableParsedFileIndex, restoreDurableParsedFileShard, } from '../../../storage/parsedfile-store.js';
21
21
  import { processRoutesFromExtracted, buildExportedTypeMapFromGraph, } from '../call-processor.js';
22
22
  import { createSemanticModel } from '../model/index.js';
23
- import { getLanguageFromFilename } from '../../../_shared/index.js';
23
+ import { getLanguageFromFilename, } from '../../../_shared/index.js';
24
24
  import { readFileContents } from '../filesystem-walker.js';
25
- import { isLanguageAvailable } from '../../tree-sitter/parser-loader.js';
25
+ import { isLanguageAvailable, isGrammarRuntimeSkipped } from '../../tree-sitter/parser-loader.js';
26
26
  import { createWorkerPool, workerPoolDisabledByEnv, resolveAutoPoolSize, WorkerPoolInitializationError, WorkerPoolDisabledError, } from '../workers/worker-pool.js';
27
27
  import fs from 'node:fs';
28
28
  import path from 'node:path';
@@ -167,7 +167,15 @@ export async function runChunkedParseAndResolve(graph, scannedFiles, allPaths, t
167
167
  }
168
168
  }
169
169
  for (const [lang, count] of skippedByLang) {
170
- logger.warn(`Skipping ${count} ${lang} file(s) ${lang} parser not available (native binding may not have built). Try: npm rebuild tree-sitter-${lang}`);
170
+ // Distinguish a deliberate runtime opt-out from a genuinely-missing binding
171
+ // so we don't tell a user who set GITNEXUS_SKIP_OPTIONAL_GRAMMARS to
172
+ // `npm rebuild` a grammar that built fine (#2091/#2093 review).
173
+ if (isGrammarRuntimeSkipped(lang)) {
174
+ logger.warn(`Skipping ${count} ${lang} file(s) — ${lang} parsing disabled via GITNEXUS_SKIP_OPTIONAL_GRAMMARS.`);
175
+ }
176
+ else {
177
+ logger.warn(`Skipping ${count} ${lang} file(s) — ${lang} parser not available (native binding may not have built). Try: npm rebuild tree-sitter-${lang}`);
178
+ }
171
179
  }
172
180
  // Sort parseableScanned alphabetically for stable chunk membership
173
181
  // across runs (Finding 4). Without this, filesystem-scan order can
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Phase registry seam (issue #2080, taint/PDG substrate M0).
3
+ *
4
+ * A small, behaviour-preserving abstraction over phase-list *assembly*. Today
5
+ * `buildPhaseList` is a hand-maintained array with a single ad-hoc
6
+ * `if (!skipGraphPhases)` guard; this registry generalises that guard into a
7
+ * per-phase `enabledWhen` predicate so later milestones can register opt-in
8
+ * phases (e.g. CFG → M1 #2081) without editing the array each time.
9
+ *
10
+ * M0 wires the seam with **no behaviour change**: `build(options)` must return
11
+ * a phase list identical in membership and order to the legacy array for every
12
+ * options combination. The registry covers only list assembly — the runner,
13
+ * topological sort, `PipelinePhase.execute`, and any result-extraction guards
14
+ * (e.g. the `skipGraphPhases` check in `runPipelineFromRepo`) are untouched.
15
+ *
16
+ * Generic over the options type so this module depends only on `PipelinePhase`
17
+ * (no import of `PipelineOptions`, which lives in `pipeline.ts` and would
18
+ * otherwise create an import cycle).
19
+ */
20
+ import type { PipelinePhase } from './types.js';
21
+ /** Options accepted when registering a phase. */
22
+ export interface RegisterPhaseOptions<TOptions> {
23
+ /**
24
+ * Predicate deciding whether this phase is included for a given options
25
+ * object. Absent ⇒ the phase is always enabled. This is the generalised
26
+ * form of the legacy `if (!skipGraphPhases)` guard.
27
+ *
28
+ * `options` is required, not optional: callers normalize an absent options
29
+ * object once at `build()` (e.g. `buildPhaseList` passes `options ?? {}`), so
30
+ * individual predicates read `(o) => !o.skipGraphPhases` without a defensive
31
+ * `?.` on every phase (#2080 review S1).
32
+ */
33
+ readonly enabledWhen?: (options: TOptions) => boolean;
34
+ }
35
+ /**
36
+ * Ordered registry of pipeline phases. Not a global singleton — callers
37
+ * construct a fresh registry (so registration order is deterministic and there
38
+ * is no import-order or test-isolation hazard) and `build()` it per run.
39
+ */
40
+ export declare class PhaseRegistry<TOptions = unknown> {
41
+ private readonly registrations;
42
+ /**
43
+ * Register a phase. This is the `registerPhase(phase, { enabledWhen })` seam
44
+ * named in issue #2080. Returns `this` for fluent chaining. Registration
45
+ * order is preserved by `build()`.
46
+ */
47
+ register(phase: PipelinePhase, options?: RegisterPhaseOptions<TOptions>): this;
48
+ /**
49
+ * Build the ordered phase list for the given options. A phase is included
50
+ * iff it has no `enabledWhen` predicate or its predicate returns `true`.
51
+ * Order matches registration order. `options` is required — callers that may
52
+ * have no options normalize once at the call site (`options ?? {}`) so the
53
+ * predicates never see `undefined`.
54
+ */
55
+ build(options: TOptions): PipelinePhase[];
56
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Phase registry seam (issue #2080, taint/PDG substrate M0).
3
+ *
4
+ * A small, behaviour-preserving abstraction over phase-list *assembly*. Today
5
+ * `buildPhaseList` is a hand-maintained array with a single ad-hoc
6
+ * `if (!skipGraphPhases)` guard; this registry generalises that guard into a
7
+ * per-phase `enabledWhen` predicate so later milestones can register opt-in
8
+ * phases (e.g. CFG → M1 #2081) without editing the array each time.
9
+ *
10
+ * M0 wires the seam with **no behaviour change**: `build(options)` must return
11
+ * a phase list identical in membership and order to the legacy array for every
12
+ * options combination. The registry covers only list assembly — the runner,
13
+ * topological sort, `PipelinePhase.execute`, and any result-extraction guards
14
+ * (e.g. the `skipGraphPhases` check in `runPipelineFromRepo`) are untouched.
15
+ *
16
+ * Generic over the options type so this module depends only on `PipelinePhase`
17
+ * (no import of `PipelineOptions`, which lives in `pipeline.ts` and would
18
+ * otherwise create an import cycle).
19
+ */
20
+ /**
21
+ * Ordered registry of pipeline phases. Not a global singleton — callers
22
+ * construct a fresh registry (so registration order is deterministic and there
23
+ * is no import-order or test-isolation hazard) and `build()` it per run.
24
+ */
25
+ export class PhaseRegistry {
26
+ registrations = [];
27
+ /**
28
+ * Register a phase. This is the `registerPhase(phase, { enabledWhen })` seam
29
+ * named in issue #2080. Returns `this` for fluent chaining. Registration
30
+ * order is preserved by `build()`.
31
+ */
32
+ register(phase, options) {
33
+ this.registrations.push({ phase, enabledWhen: options?.enabledWhen });
34
+ return this;
35
+ }
36
+ /**
37
+ * Build the ordered phase list for the given options. A phase is included
38
+ * iff it has no `enabledWhen` predicate or its predicate returns `true`.
39
+ * Order matches registration order. `options` is required — callers that may
40
+ * have no options normalize once at the call site (`options ?? {}`) so the
41
+ * predicates never see `undefined`.
42
+ */
43
+ build(options) {
44
+ return this.registrations
45
+ .filter((r) => r.enabledWhen === undefined || r.enabledWhen(options))
46
+ .map((r) => r.phase);
47
+ }
48
+ }
@@ -16,6 +16,7 @@
16
16
  */
17
17
  import { type PipelineProgress } from '../../_shared/index.js';
18
18
  import { PipelineResult } from '../../types/pipeline.js';
19
+ import { type PipelinePhase } from './pipeline-phases/index.js';
19
20
  export interface PipelineOptions {
20
21
  /**
21
22
  * Skip MRO, community detection, and process extraction for faster test runs.
@@ -104,4 +105,24 @@ export interface PipelineOptions {
104
105
  */
105
106
  keepLocalValueSymbols?: boolean;
106
107
  }
108
+ /**
109
+ * All pipeline phases with their dependency relationships.
110
+ *
111
+ * Phase dependency graph:
112
+ *
113
+ * scan → structure → [markdown, cobol] → parse → [routes, tools, orm]
114
+ * → crossFile → scopeResolution → pruneLocalSymbols
115
+ * → mro → communities → processes
116
+ *
117
+ * To add a new phase: create a file in pipeline-phases/, export the phase
118
+ * object, and `.register()` it at the appropriate position below. Opt-in
119
+ * phases pass an `enabledWhen` predicate (issue #2080 phase-registry seam) —
120
+ * the legacy `if (!skipGraphPhases)` guard is now expressed that way on the
121
+ * three graph phases, with no change in behaviour.
122
+ *
123
+ * Exported for the parity test (`pipeline-phase-registry.test.ts`), which
124
+ * asserts the produced list is byte-identical to the legacy array for every
125
+ * options combination.
126
+ */
127
+ export declare function buildPhaseList(options?: PipelineOptions): PipelinePhase[];
107
128
  export declare const runPipelineFromRepo: (repoPath: string, onProgress: (progress: PipelineProgress) => void, options?: PipelineOptions) => Promise<PipelineResult>;
@@ -15,7 +15,7 @@
15
15
  * See ARCHITECTURE.md for the full phase dependency diagram.
16
16
  */
17
17
  import { createKnowledgeGraph } from '../graph/graph.js';
18
- import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase, cobolPhase, parsePhase, routesPhase, toolsPhase, ormPhase, crossFilePhase, scopeResolutionPhase, pruneLocalSymbolsPhase, mroPhase, communitiesPhase, processesPhase, } from './pipeline-phases/index.js';
18
+ import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase, cobolPhase, parsePhase, routesPhase, toolsPhase, ormPhase, crossFilePhase, scopeResolutionPhase, pruneLocalSymbolsPhase, mroPhase, communitiesPhase, processesPhase, PhaseRegistry, } from './pipeline-phases/index.js';
19
19
  // ── Phase registry ─────────────────────────────────────────────────────────
20
20
  /**
21
21
  * All pipeline phases with their dependency relationships.
@@ -27,26 +27,34 @@ import { runPipeline, getPhaseOutput, scanPhase, structurePhase, markdownPhase,
27
27
  * → mro → communities → processes
28
28
  *
29
29
  * To add a new phase: create a file in pipeline-phases/, export the phase
30
- * object, and add it to the appropriate position in this array.
30
+ * object, and `.register()` it at the appropriate position below. Opt-in
31
+ * phases pass an `enabledWhen` predicate (issue #2080 phase-registry seam) —
32
+ * the legacy `if (!skipGraphPhases)` guard is now expressed that way on the
33
+ * three graph phases, with no change in behaviour.
34
+ *
35
+ * Exported for the parity test (`pipeline-phase-registry.test.ts`), which
36
+ * asserts the produced list is byte-identical to the legacy array for every
37
+ * options combination.
31
38
  */
32
- function buildPhaseList(options) {
33
- const phases = [
34
- scanPhase,
35
- structurePhase,
36
- markdownPhase,
37
- cobolPhase,
38
- parsePhase,
39
- routesPhase,
40
- toolsPhase,
41
- ormPhase,
42
- crossFilePhase,
43
- scopeResolutionPhase,
44
- pruneLocalSymbolsPhase,
45
- ];
46
- if (!options?.skipGraphPhases) {
47
- phases.push(mroPhase, communitiesPhase, processesPhase);
48
- }
49
- return phases;
39
+ export function buildPhaseList(options) {
40
+ return (new PhaseRegistry()
41
+ .register(scanPhase)
42
+ .register(structurePhase)
43
+ .register(markdownPhase)
44
+ .register(cobolPhase)
45
+ .register(parsePhase)
46
+ .register(routesPhase)
47
+ .register(toolsPhase)
48
+ .register(ormPhase)
49
+ .register(crossFilePhase)
50
+ .register(scopeResolutionPhase)
51
+ .register(pruneLocalSymbolsPhase)
52
+ .register(mroPhase, { enabledWhen: (o) => !o.skipGraphPhases })
53
+ .register(communitiesPhase, { enabledWhen: (o) => !o.skipGraphPhases })
54
+ .register(processesPhase, { enabledWhen: (o) => !o.skipGraphPhases })
55
+ // Normalize a missing options object once here so phase predicates above
56
+ // take a required PipelineOptions and need no `?.` guard (#2080 review S1).
57
+ .build(options ?? {}));
50
58
  }
51
59
  // ── Pipeline orchestrator ─────────────────────────────────────────────────
52
60
  export const runPipelineFromRepo = async (repoPath, onProgress, options) => {