gitnexus 1.6.12-rc.2 → 1.6.12-rc.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/dist/_shared/graph/types.d.ts +1 -1
  2. package/dist/_shared/graph/types.d.ts.map +1 -1
  3. package/dist/_shared/language-detection.d.ts.map +1 -1
  4. package/dist/_shared/language-detection.js +2 -0
  5. package/dist/_shared/language-detection.js.map +1 -1
  6. package/dist/_shared/languages.d.ts +1 -0
  7. package/dist/_shared/languages.d.ts.map +1 -1
  8. package/dist/_shared/languages.js +1 -0
  9. package/dist/_shared/languages.js.map +1 -1
  10. package/dist/_shared/lbug/schema-constants.d.ts +1 -1
  11. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  12. package/dist/_shared/lbug/schema-constants.js +2 -0
  13. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  14. package/dist/_shared/scope-resolution/language-classification.d.ts +2 -1
  15. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  16. package/dist/_shared/scope-resolution/language-classification.js +3 -1
  17. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  18. package/dist/_shared/scope-resolution/registries/class-registry.d.ts +3 -3
  19. package/dist/_shared/scope-resolution/registries/class-registry.js +3 -3
  20. package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
  21. package/dist/_shared/scope-resolution/registries/context.js +2 -0
  22. package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
  23. package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/resolve-type-ref.js +2 -0
  25. package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
  26. package/dist/cli/analyze-config.d.ts +2 -2
  27. package/dist/cli/analyze-config.js +10 -33
  28. package/dist/cli/doctor.js +6 -4
  29. package/dist/cli/eval-server.js +13 -1
  30. package/dist/cli/i18n/en.d.ts +4 -2
  31. package/dist/cli/i18n/en.js +4 -2
  32. package/dist/cli/i18n/resources.d.ts +6 -2
  33. package/dist/cli/i18n/zh-CN.d.ts +2 -0
  34. package/dist/cli/i18n/zh-CN.js +4 -2
  35. package/dist/core/analysis-feature-registry.d.ts +1 -1
  36. package/dist/core/analysis-feature-registry.js +2 -0
  37. package/dist/core/auto-sync/starter.js +2 -2
  38. package/dist/core/embeddings/ast-utils.js +8 -3
  39. package/dist/core/embeddings/chunker.js +67 -10
  40. package/dist/core/embeddings/embedding-pipeline.d.ts +1 -1
  41. package/dist/core/embeddings/embedding-pipeline.js +1 -1
  42. package/dist/core/embeddings/structural-extractor.js +2 -2
  43. package/dist/core/embeddings/types.d.ts +4 -2
  44. package/dist/core/embeddings/types.js +18 -0
  45. package/dist/core/git-ref.d.ts +22 -0
  46. package/dist/core/git-ref.js +114 -0
  47. package/dist/core/git-staleness.js +14 -0
  48. package/dist/core/group/extractors/graphql-extractor.d.ts +1 -1
  49. package/dist/core/group/extractors/graphql-extractor.js +149 -13
  50. package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
  51. package/dist/core/group/extractors/manifest-extractor.js +2 -2
  52. package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +5 -8
  53. package/dist/core/ingestion/content-language-classification.d.ts +10 -0
  54. package/dist/core/ingestion/content-language-classification.js +30 -0
  55. package/dist/core/ingestion/filesystem-walker.d.ts +1 -0
  56. package/dist/core/ingestion/filesystem-walker.js +1 -1
  57. package/dist/core/ingestion/import-resolvers/node-workspace-packages.js +3 -2
  58. package/dist/core/ingestion/language-config.d.ts +82 -13
  59. package/dist/core/ingestion/language-config.js +217 -13
  60. package/dist/core/ingestion/language-provider.d.ts +88 -1
  61. package/dist/core/ingestion/languages/index.d.ts +7 -0
  62. package/dist/core/ingestion/languages/index.js +30 -1
  63. package/dist/core/ingestion/languages/objective-c/analysis-features.d.ts +10 -0
  64. package/dist/core/ingestion/languages/objective-c/analysis-features.js +19 -0
  65. package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.d.ts +13 -0
  66. package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.js +124 -0
  67. package/dist/core/ingestion/languages/objective-c/facts.d.ts +148 -0
  68. package/dist/core/ingestion/languages/objective-c/facts.js +1150 -0
  69. package/dist/core/ingestion/languages/objective-c/import-target.d.ts +11 -0
  70. package/dist/core/ingestion/languages/objective-c/import-target.js +122 -0
  71. package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.d.ts +24 -0
  72. package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.js +261 -0
  73. package/dist/core/ingestion/languages/objective-c/resolution-config.d.ts +41 -0
  74. package/dist/core/ingestion/languages/objective-c/resolution-config.js +282 -0
  75. package/dist/core/ingestion/languages/objective-c/scope-resolver.d.ts +2 -0
  76. package/dist/core/ingestion/languages/objective-c/scope-resolver.js +503 -0
  77. package/dist/core/ingestion/languages/objective-c.d.ts +2 -0
  78. package/dist/core/ingestion/languages/objective-c.js +300 -0
  79. package/dist/core/ingestion/languages/typescript/query.d.ts +31 -0
  80. package/dist/core/ingestion/languages/typescript/query.js +7 -1
  81. package/dist/core/ingestion/languages/typescript/tsconfig.js +3 -2
  82. package/dist/core/ingestion/languages/typescript.js +1 -1
  83. package/dist/core/ingestion/languages/zig/query.d.ts +26 -0
  84. package/dist/core/ingestion/languages/zig/query.js +61 -1
  85. package/dist/core/ingestion/languages/zig/range-binding.d.ts +8 -0
  86. package/dist/core/ingestion/languages/zig/range-binding.js +24 -0
  87. package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +3 -2
  88. package/dist/core/ingestion/languages/zig/scope-resolver.js +18 -5
  89. package/dist/core/ingestion/languages/zig/this-alias-bindings.d.ts +58 -0
  90. package/dist/core/ingestion/languages/zig/this-alias-bindings.js +176 -0
  91. package/dist/core/ingestion/languages/zig/workspace-static-gating.d.ts +8 -0
  92. package/dist/core/ingestion/languages/zig/workspace-static-gating.js +82 -0
  93. package/dist/core/ingestion/model/registration-table.d.ts +3 -3
  94. package/dist/core/ingestion/model/registration-table.js +9 -5
  95. package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
  96. package/dist/core/ingestion/model/symbol-table.js +2 -0
  97. package/dist/core/ingestion/model/type-registry.d.ts +1 -1
  98. package/dist/core/ingestion/parsing-processor.d.ts +22 -6
  99. package/dist/core/ingestion/parsing-processor.js +39 -20
  100. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +9 -1
  101. package/dist/core/ingestion/pipeline-phases/parse-impl.js +307 -96
  102. package/dist/core/ingestion/pipeline-phases/parse-round-budget.d.ts +42 -0
  103. package/dist/core/ingestion/pipeline-phases/parse-round-budget.js +50 -0
  104. package/dist/core/ingestion/pipeline-phases/parse.d.ts +7 -1
  105. package/dist/core/ingestion/scope-extractor.js +4 -0
  106. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +13 -0
  107. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +2 -0
  108. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +2 -0
  109. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +78 -5
  110. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +262 -7
  111. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +5 -2
  112. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
  113. package/dist/core/ingestion/scope-resolution/pipeline/run.js +10 -1
  114. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +39 -3
  115. package/dist/core/ingestion/scope-resolution/scope/walkers.js +82 -3
  116. package/dist/core/ingestion/scope-resolution/value-ref-edges.d.ts +14 -0
  117. package/dist/core/ingestion/scope-resolution/value-ref-edges.js +14 -0
  118. package/dist/core/ingestion/tree-sitter-queries.js +2 -0
  119. package/dist/core/ingestion/utils/symbol-labels.js +2 -0
  120. package/dist/core/ingestion/workers/parse-worker.d.ts +1 -1
  121. package/dist/core/ingestion/workers/parse-worker.js +63 -3
  122. package/dist/core/ingestion/workers/worker-pool.d.ts +56 -2
  123. package/dist/core/ingestion/workers/worker-pool.js +117 -26
  124. package/dist/core/lbug/csv-generator.js +2 -0
  125. package/dist/core/lbug/schema.d.ts +3 -1
  126. package/dist/core/lbug/schema.js +27 -0
  127. package/dist/core/search/fts-indexes.js +13 -4
  128. package/dist/core/search/fts-schema.js +2 -0
  129. package/dist/core/tree-sitter/parser-loader.js +10 -0
  130. package/dist/core/tree-sitter/vendored-grammars.d.ts +1 -1
  131. package/dist/core/tree-sitter/vendored-grammars.js +2 -1
  132. package/dist/mcp/local/local-backend.d.ts +33 -0
  133. package/dist/mcp/local/local-backend.js +166 -5
  134. package/dist/mcp/tools.js +6 -4
  135. package/dist/server/analyze-job.d.ts +19 -1
  136. package/dist/server/analyze-job.js +14 -3
  137. package/dist/server/analyze-launch.d.ts +14 -0
  138. package/dist/server/analyze-launch.js +59 -14
  139. package/dist/server/analyze-worker-ipc.d.ts +6 -5
  140. package/dist/server/analyze-worker-ipc.js +4 -0
  141. package/dist/server/api.js +68 -21
  142. package/dist/server/git-clone.d.ts +38 -5
  143. package/dist/server/git-clone.js +216 -38
  144. package/dist/server/repo-projection.d.ts +88 -0
  145. package/dist/server/repo-projection.js +53 -0
  146. package/dist/storage/file-lock.js +5 -3
  147. package/dist/storage/parse-cache.js +32 -1
  148. package/dist/storage/parsedfile-store.js +53 -1
  149. package/dist/storage/v8-sidecar.d.ts +11 -0
  150. package/dist/storage/v8-sidecar.js +15 -7
  151. package/dist/utils/process-identity.d.ts +13 -0
  152. package/dist/utils/process-identity.js +18 -0
  153. package/package.json +1 -1
  154. package/scripts/build-tree-sitter-grammars.cjs +4 -3
  155. package/vendor/tree-sitter-objc/LICENSE +21 -0
  156. package/vendor/tree-sitter-objc/README.md +18 -0
  157. package/vendor/tree-sitter-objc/binding.gyp +35 -0
  158. package/vendor/tree-sitter-objc/bindings/node/binding.cc +19 -0
  159. package/vendor/tree-sitter-objc/bindings/node/binding_test.js +9 -0
  160. package/vendor/tree-sitter-objc/bindings/node/index.d.ts +27 -0
  161. package/vendor/tree-sitter-objc/bindings/node/index.js +11 -0
  162. package/vendor/tree-sitter-objc/grammar.js +1286 -0
  163. package/vendor/tree-sitter-objc/package.json +56 -0
  164. package/vendor/tree-sitter-objc/prebuilds/SHA256SUMS +6 -0
  165. package/vendor/tree-sitter-objc/prebuilds/darwin-arm64/tree-sitter-objc.node +0 -0
  166. package/vendor/tree-sitter-objc/prebuilds/darwin-x64/tree-sitter-objc.node +0 -0
  167. package/vendor/tree-sitter-objc/prebuilds/linux-arm64/tree-sitter-objc.node +0 -0
  168. package/vendor/tree-sitter-objc/prebuilds/linux-x64/tree-sitter-objc.node +0 -0
  169. package/vendor/tree-sitter-objc/prebuilds/win32-arm64/tree-sitter-objc.node +0 -0
  170. package/vendor/tree-sitter-objc/prebuilds/win32-x64/tree-sitter-objc.node +0 -0
  171. package/vendor/tree-sitter-objc/queries/folds.scm +20 -0
  172. package/vendor/tree-sitter-objc/queries/highlights.scm +216 -0
  173. package/vendor/tree-sitter-objc/queries/indents.scm +1 -0
  174. package/vendor/tree-sitter-objc/queries/injections.scm +10 -0
  175. package/vendor/tree-sitter-objc/queries/locals.scm +1 -0
  176. package/vendor/tree-sitter-objc/src/grammar.json +16292 -0
  177. package/vendor/tree-sitter-objc/src/node-types.json +7524 -0
  178. package/vendor/tree-sitter-objc/src/parser.c +684023 -0
  179. package/vendor/tree-sitter-objc/src/tree_sitter/alloc.h +54 -0
  180. package/vendor/tree-sitter-objc/src/tree_sitter/array.h +291 -0
  181. package/vendor/tree-sitter-objc/src/tree_sitter/parser.h +266 -0
  182. package/vendor/tree-sitter-objc/tree-sitter-objc.wasm +0 -0
  183. package/vendor/tree-sitter-objc/tree-sitter.json +38 -0
  184. package/web/assets/{agent-BMRqXorA.js → agent-C2n33ANd.js} +1 -1
  185. package/web/assets/{index-Dj3vQOHK.js → index-CHJoW_P1.js} +18 -18
  186. package/web/assets/src-jc8Ffy3T.js +1 -0
  187. package/web/index.html +2 -2
  188. package/web/assets/src-Df5C1Nz4.js +0 -1
@@ -160,6 +160,8 @@ export function namesAtScope(scopeId, scopes) {
160
160
  */
161
161
  export function isClassLike(t) {
162
162
  return (t === 'Class' ||
163
+ t === 'Protocol' ||
164
+ t === 'Category' ||
163
165
  t === 'Interface' ||
164
166
  t === 'Struct' ||
165
167
  t === 'Record' ||
@@ -323,6 +325,82 @@ export function isNamespaceNameShadowed(namespaceName, inScope, scopes) {
323
325
  }
324
326
  return true;
325
327
  }
328
+ /**
329
+ * Does something between `inScope` and its module scope bind `name` to
330
+ * ANYTHING other than `def`?
331
+ *
332
+ * `isNamespaceNameShadowed` asks the same question for a namespace handle,
333
+ * where any local binding of the name is by definition not the import. A
334
+ * CONTAINER receiver needs the extra clause: the container may itself be the
335
+ * local declaration (`fn make() { const Local = struct {…}; … Local.go … }`),
336
+ * and reading that as its own shadow would suppress exactly the resolutions it
337
+ * is meant to permit — the #2723 mistake, one channel over.
338
+ *
339
+ * So a scope that binds the name answers immediately, and the answer is "not
340
+ * shadowed" only when one of that scope's bindings IS `def`. A name bound in a
341
+ * nearer scope to something else — a parameter, a local, a type binding — wins
342
+ * the lexical race, which is the whole point: `findClassBindingInScope` filters
343
+ * the chain by `isClassLike` and therefore cannot see that it lost it.
344
+ *
345
+ * The MODULE scope is inspected too, unlike `isNamespaceNameShadowed`, and the
346
+ * exemption is what makes that safe. That guard stops one rung short because a
347
+ * namespace import writes its own name into the module scope and would read as
348
+ * its own shadow (#2723); here the owner is compared by identity, so the binding
349
+ * that IS the owner exempts itself and only a binding to something ELSE answers
350
+ * `true`. Stopping short would leave the exact hole this walk exists to close:
351
+ * `findClassBindingInScope` steps over a module-scope binding that is not
352
+ * class-like and then answers from a WORKSPACE-wide qualified-name index, so
353
+ * `const Gauge = @import("other.zig").SOME_CONST;` in a file that never imports
354
+ * `Gauge.zig` would still resolve `Gauge.read` to that file's container.
355
+ * `lookupBindingsAt` is used at that scope and only there, because an imported
356
+ * alias lives in the finalized channel rather than in `scope.bindings`.
357
+ *
358
+ * Fail-closed like its sibling: a missing scope or a parent cycle answers
359
+ * `true`, because suppressing a resolution costs a missing edge while trusting a
360
+ * corrupt chain costs a wrong one.
361
+ */
362
+ export function isOwnerNameShadowedBySomethingElse(name, def, inScope, scopes) {
363
+ let currentId = inScope;
364
+ const visited = new Set();
365
+ while (currentId !== null) {
366
+ if (visited.has(currentId))
367
+ return true;
368
+ visited.add(currentId);
369
+ const scope = scopes.scopeTree.getScope(currentId);
370
+ if (scope === undefined)
371
+ return true;
372
+ if (scope.kind !== 'Object') {
373
+ const isModule = scope.kind === 'Module';
374
+ const imported = isModule ? lookupBindingsAt(currentId, name, scopes) : [];
375
+ const bindsHere = scope.bindings.has(name) ||
376
+ scope.typeBindings.has(name) ||
377
+ scope.lexicalNames?.has(name) === true ||
378
+ imported.length > 0 ||
379
+ scope.ownedDefs.some((d) => {
380
+ const qualifiedName = d.qualifiedName;
381
+ if (qualifiedName === undefined)
382
+ return false;
383
+ const dot = qualifiedName.lastIndexOf('.');
384
+ return (dot === -1 ? qualifiedName : qualifiedName.slice(dot + 1)) === name;
385
+ });
386
+ if (bindsHere) {
387
+ if ((scope.bindings.get(name) ?? []).some((b) => b.def.nodeId === def.nodeId))
388
+ return false;
389
+ if (scope.ownedDefs.some((d) => d.nodeId === def.nodeId))
390
+ return false;
391
+ if (imported.some((b) => b.def.nodeId === def.nodeId))
392
+ return false;
393
+ return true;
394
+ }
395
+ }
396
+ // The module scope is the last rung, not a rung to skip: nothing above it
397
+ // can shadow a name for this file.
398
+ if (scope.kind === 'Module')
399
+ return false;
400
+ currentId = scope.parent;
401
+ }
402
+ return true;
403
+ }
326
404
  export function findReceiverTypeBinding(startScope, receiverName, scopes) {
327
405
  let currentId = startScope;
328
406
  const visited = new Set();
@@ -401,9 +479,10 @@ export function moduleScopeIdOf(startScope, scopes) {
401
479
  /**
402
480
  * Look up a class-like binding by name in the given scope's chain.
403
481
  *
404
- * "Class-like" covers `Class | Interface | Struct | Record | Enum |
405
- * Trait` via the shared `isClassLike` predicate — every kind that
406
- * collapses to `@scope.class` in the scope-extractor query contract.
482
+ * "Class-like" covers `Class | Interface | Struct | Record | Enum | Trait |
483
+ * Protocol | Category` via the shared `isClassLike` predicate. Objective-C
484
+ * protocol and category definitions are graph-side containers rather than
485
+ * `@scope.class` captures.
407
486
  *
408
487
  * Walks the scope chain upward and consults TWO sources at each step:
409
488
  * 1. `scope.bindings` — populated during scope-extraction Pass 2 with
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The `reason` text stamped on the USES edge a `value-ref` site emits.
3
+ *
4
+ * A leaf module on purpose. Two modules need this string and they sit on
5
+ * opposite sides of the product: `passes/property-dispatch.ts` writes it at
6
+ * analysis time, and `mcp/local/local-backend.ts` reads it back at query time
7
+ * to decide whether an answer is `exact`. Re-typing the literal in the reader
8
+ * would make the epistemic signal fail SILENTLY the day the writer's text is
9
+ * reworded — the query would simply match nothing and every answer would go
10
+ * back to claiming certainty, which is the exact defect (#3399) this constant
11
+ * exists to close. Importing `property-dispatch.ts` for it instead would drag
12
+ * the whole scope-resolution emit graph into the MCP backend for one string.
13
+ */
14
+ export declare const VALUE_REF_EDGE_REASON = "scope-resolution: value-ref";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The `reason` text stamped on the USES edge a `value-ref` site emits.
3
+ *
4
+ * A leaf module on purpose. Two modules need this string and they sit on
5
+ * opposite sides of the product: `passes/property-dispatch.ts` writes it at
6
+ * analysis time, and `mcp/local/local-backend.ts` reads it back at query time
7
+ * to decide whether an answer is `exact`. Re-typing the literal in the reader
8
+ * would make the epistemic signal fail SILENTLY the day the writer's text is
9
+ * reworded — the query would simply match nothing and every answer would go
10
+ * back to claiming certainty, which is the exact defect (#3399) this constant
11
+ * exists to close. Importing `property-dispatch.ts` for it instead would drag
12
+ * the whole scope-resolution emit graph into the MCP backend for one string.
13
+ */
14
+ export const VALUE_REF_EDGE_REASON = 'scope-resolution: value-ref';
@@ -2592,12 +2592,14 @@ export const ZIG_QUERIES = `
2592
2592
  member: (identifier) @call.name)) @call
2593
2593
  `;
2594
2594
  import { SupportedLanguages } from '../../_shared/index.js';
2595
+ const OBJECTIVE_C_QUERIES = `((translation_unit) @objc.root)`;
2595
2596
  export const LANGUAGE_QUERIES = {
2596
2597
  [SupportedLanguages.TypeScript]: TYPESCRIPT_QUERIES,
2597
2598
  [SupportedLanguages.JavaScript]: JAVASCRIPT_QUERIES,
2598
2599
  [SupportedLanguages.Python]: PYTHON_QUERIES,
2599
2600
  [SupportedLanguages.Java]: JAVA_QUERIES,
2600
2601
  [SupportedLanguages.C]: C_QUERIES,
2602
+ [SupportedLanguages.ObjectiveC]: OBJECTIVE_C_QUERIES,
2601
2603
  [SupportedLanguages.Go]: GO_QUERIES,
2602
2604
  [SupportedLanguages.CPlusPlus]: CPP_QUERIES,
2603
2605
  [SupportedLanguages.CSharp]: CSHARP_QUERIES,
@@ -21,6 +21,8 @@ export const SYMBOL_NODE_LABELS = new Set([
21
21
  'Function',
22
22
  'Method',
23
23
  'Class',
24
+ 'Protocol',
25
+ 'Category',
24
26
  'Interface',
25
27
  'CodeElement',
26
28
  'Struct',
@@ -29,7 +29,7 @@ interface ParsedRelationship {
29
29
  id: string;
30
30
  sourceId: string;
31
31
  targetId: string;
32
- type: 'DEFINES' | 'HAS_METHOD' | 'HAS_PROPERTY';
32
+ type: 'DEFINES' | 'DECLARES' | 'HAS_METHOD' | 'HAS_PROPERTY';
33
33
  confidence: number;
34
34
  reason: string;
35
35
  }
@@ -14,7 +14,7 @@ import PHP from 'tree-sitter-php';
14
14
  import Ruby from 'tree-sitter-ruby';
15
15
  import { requireVendoredGrammar } from '../../tree-sitter/vendored-grammars.js';
16
16
  import { SupportedLanguages } from '../../../_shared/index.js';
17
- import { getProvider } from '../languages/index.js';
17
+ import { getLanguageForFileContent, getProvider } from '../languages/index.js';
18
18
  import { getTreeSitterBufferSize, getTreeSitterContentByteLength, TREE_SITTER_MAX_BUFFER, } from '../constants.js';
19
19
  import { ARRAY_METHOD_HOC_BLOCKLIST_SET, DEFAULT_EXPORT_IDENTIFIER_BLOCKLIST_SET, deriveDefaultExportHocName, } from '../ts-js-hoc-utils.js';
20
20
  import { parseSourceSafe } from '../../tree-sitter/safe-parse.js';
@@ -63,6 +63,11 @@ try {
63
63
  Zig = requireVendoredGrammar('tree-sitter-zig');
64
64
  }
65
65
  catch { }
66
+ let ObjectiveC = null;
67
+ try {
68
+ ObjectiveC = requireVendoredGrammar('tree-sitter-objc');
69
+ }
70
+ catch { }
66
71
  import { getLanguageFromFilename } from '../../../_shared/index.js';
67
72
  import { buildDefinitionPreScan, FUNCTION_NODE_TYPES, findAncestorBeforeBoundary, findSplitBodyCallableAncestor, SPLIT_SIGNATURE_NODE_TYPES, getDefinitionNodeFromCaptures, findEnclosingClassInfo, findObjectLiteralBindingInfo, isArrayContainedObjectLiteralMember, findReturnShapeOwnerInfo, isReturnShapeProperty, findMemberAssignmentOwnerInfo, isCjsDefaultExportAssignment, getLabelFromCaptures, genericFuncName, inferFunctionLabel, isSuppressedConcreteTypedefDuplicate, isValueDefinitionLabel, isQualifiableScopeLabel, MEMBER_OWNER_NODE_TYPES, qualifyByEnclosingModScope, qualifyRustImplTargetByModScope, CLASS_CONTAINER_TYPES, PARAMETER_LIST_NODE_TYPES, LOCAL_SCOPE_BODY_NODE_TYPES, } from '../utils/ast-helpers.js';
68
73
  import { isPositionQualifiedLocalLabel } from '../utils/callable-labels.js';
@@ -140,6 +145,7 @@ const languageMap = {
140
145
  [SupportedLanguages.Java]: Java,
141
146
  ...(C ? { [SupportedLanguages.C]: C } : {}),
142
147
  [SupportedLanguages.CPlusPlus]: CPP,
148
+ ...(ObjectiveC ? { [SupportedLanguages.ObjectiveC]: ObjectiveC } : {}),
143
149
  [SupportedLanguages.CSharp]: CSharp,
144
150
  [SupportedLanguages.Go]: Go,
145
151
  [SupportedLanguages.Rust]: Rust,
@@ -741,7 +747,7 @@ const processBatch = (files, onProgress) => {
741
747
  // Group by language to minimize setLanguage calls
742
748
  const byLanguage = new Map();
743
749
  for (const file of files) {
744
- const lang = getLanguageFromFilename(file.path);
750
+ const lang = getLanguageForFileContent(file.path, file.content);
745
751
  if (!lang)
746
752
  continue;
747
753
  let list = byLanguage.get(lang);
@@ -993,11 +999,22 @@ function reportWarning(message) {
993
999
  logger.warn(message);
994
1000
  }
995
1001
  }
1002
+ // Keep compiled queries across jobs in this worker. A language can select
1003
+ // multiple native grammars, so both grammar identity and query text matter.
1004
+ const compiledQueries = new WeakMap();
996
1005
  const processFileGroup = (files, language, queryString, result, onFileProcessed) => {
997
1006
  let query;
998
1007
  try {
999
1008
  const lang = parser.getLanguage();
1000
- query = new Parser.Query(lang, queryString);
1009
+ let queries = compiledQueries.get(lang);
1010
+ if (!queries) {
1011
+ queries = new Map();
1012
+ compiledQueries.set(lang, queries);
1013
+ }
1014
+ const cached = queries.get(queryString);
1015
+ query = cached ?? new Parser.Query(lang, queryString);
1016
+ if (!cached)
1017
+ queries.set(queryString, query);
1001
1018
  }
1002
1019
  catch (err) {
1003
1020
  reportWarning(`Query compilation failed for ${language}: ${err instanceof Error ? err.message : String(err)}`);
@@ -1139,6 +1156,49 @@ const processFileGroup = (files, language, queryString, result, onFileProcessed)
1139
1156
  }
1140
1157
  result.parsedFiles.push(withChannels);
1141
1158
  }
1159
+ const semanticGraph = provider.extractSemanticGraph?.(tree, file.path, parseContent);
1160
+ if (semanticGraph !== undefined) {
1161
+ for (const node of semanticGraph.nodes) {
1162
+ result.nodes.push({
1163
+ id: node.id,
1164
+ label: node.label,
1165
+ properties: { ...node.properties },
1166
+ });
1167
+ }
1168
+ for (const relationship of semanticGraph.relationships) {
1169
+ if (relationship.type === 'DECLARES' ||
1170
+ relationship.type === 'DEFINES' ||
1171
+ relationship.type === 'HAS_METHOD' ||
1172
+ relationship.type === 'HAS_PROPERTY') {
1173
+ result.relationships.push({ ...relationship, type: relationship.type });
1174
+ }
1175
+ }
1176
+ for (const symbol of semanticGraph.symbols) {
1177
+ result.symbols.push({
1178
+ filePath: symbol.filePath,
1179
+ name: symbol.name,
1180
+ nodeId: symbol.nodeId,
1181
+ type: symbol.type,
1182
+ ...(symbol.qualifiedName !== undefined ? { qualifiedName: symbol.qualifiedName } : {}),
1183
+ ...(symbol.parameterCount !== undefined ? { parameterCount: symbol.parameterCount } : {}),
1184
+ ...(symbol.requiredParameterCount !== undefined
1185
+ ? { requiredParameterCount: symbol.requiredParameterCount }
1186
+ : {}),
1187
+ ...(symbol.parameterTypes !== undefined
1188
+ ? { parameterTypes: [...symbol.parameterTypes] }
1189
+ : {}),
1190
+ ...(symbol.parameterTypeClasses !== undefined
1191
+ ? { parameterTypeClasses: [...symbol.parameterTypeClasses] }
1192
+ : {}),
1193
+ ...(symbol.returnType !== undefined ? { returnType: symbol.returnType } : {}),
1194
+ ...(symbol.declaredType !== undefined ? { declaredType: symbol.declaredType } : {}),
1195
+ ...(symbol.ownerId !== undefined ? { ownerId: symbol.ownerId } : {}),
1196
+ ...(symbol.visibility !== undefined ? { visibility: symbol.visibility } : {}),
1197
+ ...(symbol.isStatic !== undefined ? { isStatic: symbol.isStatic } : {}),
1198
+ ...(symbol.isReadonly !== undefined ? { isReadonly: symbol.isReadonly } : {}),
1199
+ });
1200
+ }
1201
+ }
1142
1202
  // Build per-file type environment + constructor bindings in a single AST walk.
1143
1203
  // The legacy heritage pre-pass that seeded a file-local parentMap for
1144
1204
  // buildTypeEnv was removed in RING4-1 (#942) along with the rest of the
@@ -1,8 +1,44 @@
1
1
  import { Worker } from 'node:worker_threads';
2
+ /**
3
+ * One content-addressed parse-cache chunk's worth of work inside a pool round.
4
+ * See {@link WorkerPool.dispatchGroups}.
5
+ */
6
+ export interface DispatchGroup<TInput> {
7
+ readonly items: readonly TInput[];
8
+ /**
9
+ * Chunk hash tagged onto every job derived from `items`, exactly as the
10
+ * `chunkHash` argument of {@link WorkerPool.dispatch} does for a lone chunk.
11
+ */
12
+ readonly chunkHash?: string;
13
+ }
2
14
  export interface WorkerPool {
3
15
  /**
4
- * Dispatch items across workers. Items are split into bounded jobs, each job
5
- * is committed independently, and stalled jobs are split/retried locally.
16
+ * Dispatch several content-addressed chunks in ONE pool round.
17
+ *
18
+ * `dispatch` is a barrier: it resolves only once every job it created has
19
+ * committed, so dispatching one small parse-cache pack at a time leaves most
20
+ * slots idle for the whole round-trip. Stable packs are keyed by
21
+ * `(language, hash(path) % 128)`, which routinely yields packs far below the
22
+ * byte budget — on this repo, 1285 packs where the budget alone needs 16, and
23
+ * 549 of them hold a single file. Batching packs into one round removes those
24
+ * barriers without touching pack identity: jobs are still cut at group
25
+ * boundaries, so each job carries exactly one `chunkHash` and every result
26
+ * stays attributable to the pack that owns its cache key.
27
+ *
28
+ * Returns one result array per input group, in input order. A group whose
29
+ * items were all quarantined yields an empty array.
30
+ *
31
+ * Required, not optional. `getQuarantinedPaths?` and `getStats?` below are
32
+ * marked optional as a compatibility accommodation for `WorkerPool` shapes
33
+ * that predate them — not as a convention for new members. Making this one
34
+ * optional would force a `?.` plus a fallback branch at its only production
35
+ * call site, and that branch could never run.
36
+ */
37
+ dispatchGroups<TInput, TResult>(groups: readonly DispatchGroup<TInput>[], onProgress?: (filesProcessed: number) => void): Promise<TResult[][]>;
38
+ /**
39
+ * Dispatch ONE chunk across workers — {@link WorkerPool.dispatchGroups} with
40
+ * a single group. Items are split into bounded jobs, each job is committed
41
+ * independently, and stalled jobs are split/retried locally.
6
42
  *
7
43
  * Files in {@link WorkerPool.getQuarantinedPaths} are filtered out before
8
44
  * dispatch — they have already caused a worker death this pool lifetime and
@@ -230,6 +266,17 @@ interface ResolvedWorkerPoolOptions {
230
266
  workerReadyTimeoutMs: number;
231
267
  }
232
268
  export declare function resolveWorkerPoolOptions(options?: WorkerPoolOptions, poolSize?: number): ResolvedWorkerPoolOptions;
269
+ /**
270
+ * The pool size requested via the `GITNEXUS_WORKER_POOL_SIZE` env var, or
271
+ * `undefined` when unset, empty/whitespace, or invalid. Module-internal sizing
272
+ * reader consumed by {@link resolveAutoPoolSize} (the env override) and
273
+ * {@link workerPoolDisabledByEnv} (the disabled-channel check). Reads only —
274
+ * never mutates `process.env`. Empty/whitespace is treated as *unset* (falls
275
+ * through to the auto formula), not as 0 — an empty assignment (`export
276
+ * GITNEXUS_WORKER_POOL_SIZE=`) is an accident, not a request for zero workers;
277
+ * only a literal `0` disables the pool.
278
+ */
279
+ export declare function envWorkerPoolSize(): number | undefined;
233
280
  /**
234
281
  * True when the operator set `GITNEXUS_WORKER_POOL_SIZE=0` — the env-channel
235
282
  * equivalent of `--workers 0`. The parse phase consults this (only when no
@@ -255,6 +302,13 @@ export declare function workerPoolDisabledByEnv(): boolean;
255
302
  * on the env / default.
256
303
  */
257
304
  export declare function resolveAutoPoolSize(): number;
305
+ /**
306
+ * Usable parallelism for this process. Prefers `os.availableParallelism` so
307
+ * cgroup CPU limits are honored, falling back to `os.cpus().length` on older
308
+ * Node. Exported so callers that size work against the host (rather than
309
+ * against the pool default) do not re-derive the fallback.
310
+ */
311
+ export declare function resolveHostParallelism(): number;
258
312
  export declare function startHeartbeatStallTracker(): {
259
313
  read: () => number;
260
314
  stop: () => void;
@@ -124,7 +124,9 @@ const DEFAULT_WORKER_READY_TIMEOUT_MS = 5_000;
124
124
  * extraction / structured-clone overhead, and the marginal worker adds
125
125
  * memory pressure (tree-sitter state + sub-batch buffer) without much
126
126
  * throughput gain. Operators on bigger machines override via
127
- * `GITNEXUS_WORKER_POOL_SIZE` or `--workers <N>`.
127
+ * `GITNEXUS_WORKER_POOL_SIZE` or `--workers <N>`; both are deliberate
128
+ * operator input and bypass the work-proportional sizing in `parse-impl`,
129
+ * which only bounds the AUTO default.
128
130
  */
129
131
  const DEFAULT_POOL_SIZE_CAP = 16;
130
132
  // ── Self-healing startup restart policy (#1741) ──────────────────────────────
@@ -263,7 +265,7 @@ export function resolveWorkerPoolOptions(options = {}, poolSize) {
263
265
  * GITNEXUS_WORKER_POOL_SIZE=`) is an accident, not a request for zero workers;
264
266
  * only a literal `0` disables the pool.
265
267
  */
266
- function envWorkerPoolSize() {
268
+ export function envWorkerPoolSize() {
267
269
  const raw = process.env.GITNEXUS_WORKER_POOL_SIZE;
268
270
  if (raw === undefined || raw.trim() === '')
269
271
  return undefined;
@@ -307,8 +309,18 @@ export function resolveAutoPoolSize() {
307
309
  // pool cap exists to prevent. Falls back to os.cpus().length on
308
310
  // older Node versions. Mirrors `capabilities.ts:85`
309
311
  // (`defaultEmbeddingThreads`).
310
- const cores = typeof os.availableParallelism === 'function' ? os.availableParallelism() : os.cpus().length;
311
- return Math.min(DEFAULT_POOL_SIZE_CAP, Math.max(1, cores - 1));
312
+ return Math.min(DEFAULT_POOL_SIZE_CAP, Math.max(1, resolveHostParallelism() - 1));
313
+ }
314
+ /**
315
+ * Usable parallelism for this process. Prefers `os.availableParallelism` so
316
+ * cgroup CPU limits are honored, falling back to `os.cpus().length` on older
317
+ * Node. Exported so callers that size work against the host (rather than
318
+ * against the pool default) do not re-derive the fallback.
319
+ */
320
+ export function resolveHostParallelism() {
321
+ return typeof os.availableParallelism === 'function'
322
+ ? os.availableParallelism()
323
+ : os.cpus().length;
312
324
  }
313
325
  /**
314
326
  * Max characters of a worker's stderr retained for crash diagnostics. A
@@ -488,9 +500,14 @@ function inFlightExcludePath(job, lastProgress) {
488
500
  const path = itemPath(job.items[lastProgress]);
489
501
  return path ? [path] : [];
490
502
  }
491
- function createJobs(items, maxItems, maxBytes, timeoutMs, chunkHash) {
503
+ /**
504
+ * Cut `items` into bounded jobs. `startIndexOffset` places those jobs on a
505
+ * shared index space so several groups can be laid out end to end in one
506
+ * dispatch round and every result still sorts back into global input order.
507
+ */
508
+ function createJobs(items, maxItems, maxBytes, timeoutMs, chunkHash, startIndexOffset = 0) {
492
509
  const jobs = [];
493
- let startIndex = 0;
510
+ let startIndex = startIndexOffset;
494
511
  let batch = [];
495
512
  let batchBytes = 0;
496
513
  const flush = () => {
@@ -827,7 +844,31 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
827
844
  // First dispatch awaits this; it settles every slot's bounded retry loop in
828
845
  // parallel and drops the unrecoverable ones before any dispatch can fire.
829
846
  const initialReadyGate = Promise.allSettled(workers.map((_, i) => bringSlotReady(i))).then(() => undefined);
830
- const dispatch = async (items, onProgress, chunkHash) => {
847
+ /**
848
+ * Guards the one-dispatch-at-a-time contract. The dispatch machinery keeps
849
+ * its jobs/busy-slot/in-flight state per call, so two concurrent dispatches
850
+ * hand the same slots out twice: both stall, and the failure surfaces only
851
+ * when every worker hits its idle timeout (10s+ of a wedged pool with no
852
+ * indication of the cause). Fail loudly at the call instead.
853
+ */
854
+ let dispatchInFlight = false;
855
+ /**
856
+ * Claim the pool synchronously, then run the dispatch. The claim CANNOT be
857
+ * taken inside `dispatchGroupsInner`: its first statement awaits the
858
+ * readiness gate, so two calls made in the same tick would both get past the
859
+ * check before either set the flag.
860
+ */
861
+ const dispatchGroups = (groups, onProgress) => {
862
+ if (dispatchInFlight) {
863
+ return Promise.reject(new WorkerPoolDispatchError('Worker pool dispatch is already in flight. `dispatch`/`dispatchGroups` is not ' +
864
+ 'reentrant — await the previous call before starting another on the same pool.', []));
865
+ }
866
+ dispatchInFlight = true;
867
+ return dispatchGroupsInner(groups, onProgress).finally(() => {
868
+ dispatchInFlight = false;
869
+ });
870
+ };
871
+ const dispatchGroupsInner = async (groups, onProgress) => {
831
872
  // Await the initial-spawn readiness gate (F13). On first dispatch
832
873
  // this blocks for up to poolOptions.workerReadyTimeoutMs while every initial
833
874
  // worker's `{type:'ready'}` handshake is checked; on subsequent
@@ -842,8 +883,9 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
842
883
  throw new WorkerPoolDispatchError(`Worker pool circuit breaker tripped${reason}. ` +
843
884
  `Subsequent dispatches require a fresh pool instance.`, []);
844
885
  }
845
- if (items.length === 0)
846
- return [];
886
+ const emptyPerGroup = () => groups.map(() => []);
887
+ if (groups.every((group) => group.items.length === 0))
888
+ return emptyPerGroup();
847
889
  if (activeSlots.size === 0) {
848
890
  const detail = initialReadinessFailures.length > 0
849
891
  ? ` after initial ready handshake: ${initialReadinessFailures.join('; ')}`
@@ -859,17 +901,42 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
859
901
  // Layer 3: filter out quarantined paths so a known-bad file never reaches
860
902
  // a worker again this pool lifetime. The caller queries
861
903
  // `getQuarantinedPaths` after dispatch to route filtered items.
862
- const dispatchableItems = [];
863
- for (const item of items) {
864
- const path = itemPath(item);
865
- if (path !== undefined && quarantine.has(path))
866
- continue;
867
- dispatchableItems.push(item);
904
+ // Quarantine is empty on every run that has not had a worker die, so the
905
+ // filter below would be an identity copy of every group's items. Skip it.
906
+ const dispatchableGroups = quarantine.size === 0
907
+ ? groups
908
+ : groups.map((group) => {
909
+ const items = [];
910
+ for (const item of group.items) {
911
+ const path = itemPath(item);
912
+ if (path !== undefined && quarantine.has(path))
913
+ continue;
914
+ items.push(item);
915
+ }
916
+ return { items, chunkHash: group.chunkHash };
917
+ });
918
+ const dispatchableCount = dispatchableGroups.reduce((sum, group) => sum + group.items.length, 0);
919
+ if (dispatchableCount === 0)
920
+ return emptyPerGroup();
921
+ // Stable cache packs can be much smaller than either job ceiling. Split
922
+ // those packs across the live slots too, otherwise each serial dispatch
923
+ // feeds only one worker. Keep both configured ceilings as upper bounds.
924
+ const maxItemsPerJob = Math.min(poolOptions.subBatchSize, Math.max(1, Math.floor(dispatchableCount / activeSlots.size)));
925
+ // Lay the groups end to end on one index space and cut jobs at every group
926
+ // boundary. A job therefore belongs to exactly one group, which is what
927
+ // lets a result be attributed back to the parse-cache chunk that owns it
928
+ // (and what keeps `chunkHash` a per-job constant through splits/requeues).
929
+ const jobs = [];
930
+ const groupEnds = [];
931
+ let groupStart = 0;
932
+ for (const group of dispatchableGroups) {
933
+ for (const job of createJobs(group.items, maxItemsPerJob, poolOptions.subBatchMaxBytes, poolOptions.subBatchIdleTimeoutMs, group.chunkHash, groupStart)) {
934
+ jobs.push(job);
935
+ }
936
+ groupStart += group.items.length;
937
+ groupEnds.push(groupStart);
868
938
  }
869
- if (dispatchableItems.length === 0)
870
- return [];
871
- const jobs = createJobs(dispatchableItems, poolOptions.subBatchSize, poolOptions.subBatchMaxBytes, poolOptions.subBatchIdleTimeoutMs, chunkHash);
872
- return new Promise((resolve, reject) => {
939
+ return await new Promise((resolve, reject) => {
873
940
  const results = [];
874
941
  const inFlightProgress = new Array(size).fill(0);
875
942
  // Tracks which slots are currently mid-job so the "wake idle slots"
@@ -899,7 +966,7 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
899
966
  if (!onProgress)
900
967
  return;
901
968
  const inFlight = inFlightProgress.reduce((sum, value) => sum + value, 0);
902
- const next = Math.min(dispatchableItems.length, Math.max(maxReported, completedFiles + inFlight));
969
+ const next = Math.min(dispatchableCount, Math.max(maxReported, completedFiles + inFlight));
903
970
  if (next === maxReported)
904
971
  return;
905
972
  maxReported = next;
@@ -984,7 +1051,13 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
984
1051
  retireWorkerAfterTimeout(existing, workerIndex, reason);
985
1052
  return;
986
1053
  }
987
- await existing.terminate().catch(() => undefined);
1054
+ // Recovery must settle before dispatch returns, but a failed thread
1055
+ // may never acknowledge termination. Bound that wait as in shutdown.
1056
+ const termination = existing.terminate().then(() => undefined, () => undefined);
1057
+ if (!(await settledWithin(termination, poolOptions.shutdownDrainMs))) {
1058
+ existing.unref?.();
1059
+ logger.warn({ workerIndex, drainMs: poolOptions.shutdownDrainMs, reason }, `Worker ${workerIndex} did not finish terminating within the shutdown drain; continuing recovery.`);
1060
+ }
988
1061
  };
989
1062
  const replaceWorker = async (workerIndex, mode = 'terminate', reason = 'replacing worker') => {
990
1063
  await removeWorkerFromSlot(workerIndex, mode, reason);
@@ -1057,9 +1130,20 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
1057
1130
  if (jobs.length === 0 && activeWorkers === 0) {
1058
1131
  stopped = true;
1059
1132
  results.sort((a, b) => a.startIndex - b.startIndex);
1060
- if (onProgress && maxReported < dispatchableItems.length)
1061
- onProgress(dispatchableItems.length);
1062
- resolve(results.map((result) => result.data));
1133
+ if (onProgress && maxReported < dispatchableCount)
1134
+ onProgress(dispatchableCount);
1135
+ // Partition back per group. Job (and split sub-job) start indices
1136
+ // stay inside their group's span, so a single forward walk over the
1137
+ // sorted results assigns every result to exactly one group.
1138
+ const perGroup = groupEnds.map(() => []);
1139
+ let groupIdx = 0;
1140
+ for (const result of results) {
1141
+ while (groupIdx < groupEnds.length - 1 && result.startIndex >= groupEnds[groupIdx]) {
1142
+ groupIdx++;
1143
+ }
1144
+ perGroup[groupIdx].push(result.data);
1145
+ }
1146
+ resolve(perGroup);
1063
1147
  }
1064
1148
  };
1065
1149
  // Re-queue the non-quarantined remainder of a dead worker's job so a
@@ -1357,11 +1441,13 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
1357
1441
  // (`error`, `exit`, msg-channel error). Bridges the per-job teardown
1358
1442
  // into the pool-level handleWorkerDeath recovery + breaker logic.
1359
1443
  const recoverAndResume = async (reason, excludePaths) => {
1360
- activeWorkers--;
1361
1444
  busySlots.delete(workerIndex);
1362
1445
  inFlightProgress[workerIndex] = 0;
1363
1446
  requeueRemainder(job, excludePaths);
1447
+ // Keep recovery in flight so another slot finishing cannot settle
1448
+ // this dispatch before the replacement is ready for the next one.
1364
1449
  await handleWorkerDeath(workerIndex, reason, excludePaths);
1450
+ activeWorkers--;
1365
1451
  if (stopped)
1366
1452
  return;
1367
1453
  // Slot may have been dropped or respawned. Kick the current slot
@@ -1406,10 +1492,10 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
1406
1492
  // is respawned (or dropped) and can dispatch the next
1407
1493
  // job deterministically.
1408
1494
  void (async () => {
1409
- activeWorkers--;
1410
1495
  busySlots.delete(workerIndex);
1411
1496
  requeueRemainder(job, decision.excludePaths);
1412
1497
  await handleWorkerDeath(workerIndex, decision.reason, decision.excludePaths, 'retire');
1498
+ activeWorkers--;
1413
1499
  if (stopped)
1414
1500
  return;
1415
1501
  if (activeSlots.has(workerIndex))
@@ -1689,8 +1775,13 @@ export const createWorkerPool = (workerUrl, poolSize, options) => {
1689
1775
  workers.length = 0;
1690
1776
  activeSlots.clear();
1691
1777
  };
1778
+ const dispatch = async (items, onProgress, chunkHash) => {
1779
+ const [result] = await dispatchGroups([{ items, chunkHash }], onProgress);
1780
+ return result ?? [];
1781
+ };
1692
1782
  return {
1693
1783
  dispatch,
1784
+ dispatchGroups,
1694
1785
  terminate,
1695
1786
  size,
1696
1787
  getQuarantinedPaths: () => quarantine.snapshot(),
@@ -455,6 +455,8 @@ export const streamAllCSVsToDisk = async (graph, repoPath, csvDir, onNodePhaseCo
455
455
  const multiLangHeader = 'id,name,filePath,startLine,endLine,content,description';
456
456
  const constHeader = `${multiLangHeader},convexEndpointFactory`;
457
457
  const MULTI_LANG_TYPES = [
458
+ 'Protocol',
459
+ 'Category',
458
460
  'Struct',
459
461
  'Enum',
460
462
  'Macro',
@@ -15,6 +15,8 @@ export declare const FILE_SCHEMA = "\nCREATE NODE TABLE File (\n id STRING,\n
15
15
  export declare const FOLDER_SCHEMA = "\nCREATE NODE TABLE Folder (\n id STRING,\n name STRING,\n filePath STRING,\n PRIMARY KEY (id)\n)";
16
16
  export declare const FUNCTION_SCHEMA = "\nCREATE NODE TABLE Function (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n convexEndpointFactory STRING,\n PRIMARY KEY (id)\n)";
17
17
  export declare const CLASS_SCHEMA = "\nCREATE NODE TABLE Class (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n frameworkAnnotations STRING[],\n PRIMARY KEY (id)\n)";
18
+ export declare const PROTOCOL_SCHEMA = "\nCREATE NODE TABLE Protocol (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
19
+ export declare const CATEGORY_SCHEMA = "\nCREATE NODE TABLE Category (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
18
20
  export declare const INTERFACE_SCHEMA = "\nCREATE NODE TABLE Interface (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
19
21
  export declare const METHOD_SCHEMA = "\nCREATE NODE TABLE Method (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n parameterCount INT32,\n returnType STRING,\n PRIMARY KEY (id)\n)";
20
22
  export declare const CODE_ELEMENT_SCHEMA = "\nCREATE NODE TABLE CodeElement (\n id STRING,\n name STRING,\n filePath STRING,\n startLine INT64,\n endLine INT64,\n isExported BOOLEAN,\n content STRING,\n description STRING,\n PRIMARY KEY (id)\n)";
@@ -94,7 +96,7 @@ export declare const BASICBLOCK_SCHEMA = "\nCREATE NODE TABLE BasicBlock (\n id
94
96
  * `test/integration/structural-pair-coverage.test.ts` guards this half from a
95
97
  * corpus — that is the guard, not this comment.
96
98
  */
97
- export declare const STRUCTURAL_PAIR_DDL = " FROM File TO Folder,\n FROM File TO CodeElement,\n FROM File TO `Typedef`,\n FROM File TO `Namespace`,\n FROM File TO `Impl`,\n FROM File TO `Static`,\n FROM File TO `Template`,\n FROM File TO Section,\n FROM Folder TO Folder,\n FROM Folder TO File,\n FROM Function TO `Template`,\n FROM Function TO `Namespace`,\n FROM Function TO `Impl`,\n FROM Function TO `Typedef`,\n FROM Function TO CodeElement,\n FROM Class TO `Template`,\n FROM Class TO `Impl`,\n FROM Class TO `Namespace`,\n FROM Class TO `Typedef`,\n FROM Class TO CodeElement,\n FROM Method TO `Template`,\n FROM Method TO `Namespace`,\n FROM Method TO `Impl`,\n FROM Method TO CodeElement,\n FROM `Template` TO `Template`,\n FROM `Template` TO Function,\n FROM `Template` TO Method,\n FROM `Template` TO Class,\n FROM `Template` TO `Struct`,\n FROM `Template` TO `TypeAlias`,\n FROM `Template` TO `Enum`,\n FROM `Template` TO `Macro`,\n FROM `Template` TO Interface,\n FROM `Template` TO `Constructor`,\n FROM `Module` TO CodeElement,\n FROM `Module` TO `Namespace`,\n FROM `Namespace` TO Function,\n FROM CodeElement TO CodeElement,\n FROM CodeElement TO `Module`,\n FROM CodeElement TO `Property`,\n FROM Section TO Section,\n FROM Interface TO CodeElement,\n FROM `Namespace` TO `Struct`,\n FROM `Impl` TO Method,\n FROM `Impl` TO Function,\n FROM `Impl` TO `Constructor`,\n FROM `Impl` TO `Property`,\n FROM `Impl` TO `Trait`,\n FROM `Impl` TO `Struct`,\n FROM `Impl` TO `Impl`,\n FROM `Constructor` TO `Template`,\n FROM `Constructor` TO `Impl`,\n FROM `Constructor` TO `Namespace`,\n FROM `Constructor` TO `Typedef`,\n FROM Route TO Process,\n FROM Tool TO Process,\n FROM Destination TO `Property`,\n FROM BasicBlock TO BasicBlock";
99
+ export declare const STRUCTURAL_PAIR_DDL = " FROM File TO Folder,\n FROM File TO CodeElement,\n FROM File TO `Typedef`,\n FROM File TO `Namespace`,\n FROM File TO `Impl`,\n FROM File TO `Static`,\n FROM File TO `Template`,\n FROM File TO Section,\n FROM Folder TO Folder,\n FROM Folder TO File,\n FROM Function TO `Template`,\n FROM Function TO `Namespace`,\n FROM Function TO `Impl`,\n FROM Function TO `Typedef`,\n FROM Function TO CodeElement,\n FROM Class TO `Template`,\n FROM Class TO `Impl`,\n FROM Class TO `Namespace`,\n FROM Class TO `Typedef`,\n FROM Class TO CodeElement,\n FROM Method TO `Template`,\n FROM Method TO `Namespace`,\n FROM Method TO `Impl`,\n FROM Method TO CodeElement,\n FROM `Template` TO `Template`,\n FROM `Template` TO Function,\n FROM `Template` TO Method,\n FROM `Template` TO Class,\n FROM `Template` TO `Struct`,\n FROM `Template` TO `TypeAlias`,\n FROM `Template` TO `Enum`,\n FROM `Template` TO `Macro`,\n FROM `Template` TO Interface,\n FROM `Template` TO `Constructor`,\n FROM `Module` TO CodeElement,\n FROM `Module` TO `Namespace`,\n FROM `Namespace` TO Function,\n FROM CodeElement TO CodeElement,\n FROM CodeElement TO Class,\n FROM CodeElement TO Category,\n FROM CodeElement TO Method,\n FROM CodeElement TO `Module`,\n FROM CodeElement TO `Property`,\n FROM Section TO Section,\n FROM Interface TO CodeElement,\n FROM `Namespace` TO `Struct`,\n FROM `Impl` TO Method,\n FROM `Impl` TO Function,\n FROM `Impl` TO `Constructor`,\n FROM `Impl` TO `Property`,\n FROM `Impl` TO `Trait`,\n FROM `Impl` TO `Struct`,\n FROM `Impl` TO `Impl`,\n FROM `Constructor` TO `Template`,\n FROM `Constructor` TO `Impl`,\n FROM `Constructor` TO `Namespace`,\n FROM `Constructor` TO `Typedef`,\n FROM Route TO Process,\n FROM Tool TO Process,\n FROM Destination TO `Property`,\n FROM BasicBlock TO BasicBlock";
98
100
  export declare const RELATION_SCHEMA: string;
99
101
  export declare const EMBEDDING_DIMS: number;
100
102
  /** HNSW vector index name for the CodeEmbedding table. */