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.
- package/dist/_shared/graph/types.d.ts +1 -1
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/language-detection.d.ts.map +1 -1
- package/dist/_shared/language-detection.js +2 -0
- package/dist/_shared/language-detection.js.map +1 -1
- package/dist/_shared/languages.d.ts +1 -0
- package/dist/_shared/languages.d.ts.map +1 -1
- package/dist/_shared/languages.js +1 -0
- package/dist/_shared/languages.js.map +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts +1 -1
- package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
- package/dist/_shared/lbug/schema-constants.js +2 -0
- package/dist/_shared/lbug/schema-constants.js.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.d.ts +2 -1
- package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/language-classification.js +3 -1
- package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts +3 -3
- package/dist/_shared/scope-resolution/registries/class-registry.js +3 -3
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/registries/context.js +2 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.js +2 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
- package/dist/cli/analyze-config.d.ts +2 -2
- package/dist/cli/analyze-config.js +10 -33
- package/dist/cli/doctor.js +6 -4
- package/dist/cli/eval-server.js +13 -1
- package/dist/cli/i18n/en.d.ts +4 -2
- package/dist/cli/i18n/en.js +4 -2
- package/dist/cli/i18n/resources.d.ts +6 -2
- package/dist/cli/i18n/zh-CN.d.ts +2 -0
- package/dist/cli/i18n/zh-CN.js +4 -2
- package/dist/core/analysis-feature-registry.d.ts +1 -1
- package/dist/core/analysis-feature-registry.js +2 -0
- package/dist/core/auto-sync/starter.js +2 -2
- package/dist/core/embeddings/ast-utils.js +8 -3
- package/dist/core/embeddings/chunker.js +67 -10
- package/dist/core/embeddings/embedding-pipeline.d.ts +1 -1
- package/dist/core/embeddings/embedding-pipeline.js +1 -1
- package/dist/core/embeddings/structural-extractor.js +2 -2
- package/dist/core/embeddings/types.d.ts +4 -2
- package/dist/core/embeddings/types.js +18 -0
- package/dist/core/git-ref.d.ts +22 -0
- package/dist/core/git-ref.js +114 -0
- package/dist/core/git-staleness.js +14 -0
- package/dist/core/group/extractors/graphql-extractor.d.ts +1 -1
- package/dist/core/group/extractors/graphql-extractor.js +149 -13
- package/dist/core/group/extractors/manifest-extractor.d.ts +1 -1
- package/dist/core/group/extractors/manifest-extractor.js +2 -2
- package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +5 -8
- package/dist/core/ingestion/content-language-classification.d.ts +10 -0
- package/dist/core/ingestion/content-language-classification.js +30 -0
- package/dist/core/ingestion/filesystem-walker.d.ts +1 -0
- package/dist/core/ingestion/filesystem-walker.js +1 -1
- package/dist/core/ingestion/import-resolvers/node-workspace-packages.js +3 -2
- package/dist/core/ingestion/language-config.d.ts +82 -13
- package/dist/core/ingestion/language-config.js +217 -13
- package/dist/core/ingestion/language-provider.d.ts +88 -1
- package/dist/core/ingestion/languages/index.d.ts +7 -0
- package/dist/core/ingestion/languages/index.js +30 -1
- package/dist/core/ingestion/languages/objective-c/analysis-features.d.ts +10 -0
- package/dist/core/ingestion/languages/objective-c/analysis-features.js +19 -0
- package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.d.ts +13 -0
- package/dist/core/ingestion/languages/objective-c/compilation-unit-siblings.js +124 -0
- package/dist/core/ingestion/languages/objective-c/facts.d.ts +148 -0
- package/dist/core/ingestion/languages/objective-c/facts.js +1150 -0
- package/dist/core/ingestion/languages/objective-c/import-target.d.ts +11 -0
- package/dist/core/ingestion/languages/objective-c/import-target.js +122 -0
- package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.d.ts +24 -0
- package/dist/core/ingestion/languages/objective-c/macro-marker-preprocess.js +261 -0
- package/dist/core/ingestion/languages/objective-c/resolution-config.d.ts +41 -0
- package/dist/core/ingestion/languages/objective-c/resolution-config.js +282 -0
- package/dist/core/ingestion/languages/objective-c/scope-resolver.d.ts +2 -0
- package/dist/core/ingestion/languages/objective-c/scope-resolver.js +503 -0
- package/dist/core/ingestion/languages/objective-c.d.ts +2 -0
- package/dist/core/ingestion/languages/objective-c.js +300 -0
- package/dist/core/ingestion/languages/typescript/query.d.ts +31 -0
- package/dist/core/ingestion/languages/typescript/query.js +7 -1
- package/dist/core/ingestion/languages/typescript/tsconfig.js +3 -2
- package/dist/core/ingestion/languages/typescript.js +1 -1
- package/dist/core/ingestion/languages/zig/query.d.ts +26 -0
- package/dist/core/ingestion/languages/zig/query.js +61 -1
- package/dist/core/ingestion/languages/zig/range-binding.d.ts +8 -0
- package/dist/core/ingestion/languages/zig/range-binding.js +24 -0
- package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +3 -2
- package/dist/core/ingestion/languages/zig/scope-resolver.js +18 -5
- package/dist/core/ingestion/languages/zig/this-alias-bindings.d.ts +58 -0
- package/dist/core/ingestion/languages/zig/this-alias-bindings.js +176 -0
- package/dist/core/ingestion/languages/zig/workspace-static-gating.d.ts +8 -0
- package/dist/core/ingestion/languages/zig/workspace-static-gating.js +82 -0
- package/dist/core/ingestion/model/registration-table.d.ts +3 -3
- package/dist/core/ingestion/model/registration-table.js +9 -5
- package/dist/core/ingestion/model/symbol-table.d.ts +1 -1
- package/dist/core/ingestion/model/symbol-table.js +2 -0
- package/dist/core/ingestion/model/type-registry.d.ts +1 -1
- package/dist/core/ingestion/parsing-processor.d.ts +22 -6
- package/dist/core/ingestion/parsing-processor.js +39 -20
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +9 -1
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +307 -96
- package/dist/core/ingestion/pipeline-phases/parse-round-budget.d.ts +42 -0
- package/dist/core/ingestion/pipeline-phases/parse-round-budget.js +50 -0
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +7 -1
- package/dist/core/ingestion/scope-extractor.js +4 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +13 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +2 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +2 -0
- package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +78 -5
- package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +262 -7
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +5 -2
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +10 -1
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +39 -3
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +82 -3
- package/dist/core/ingestion/scope-resolution/value-ref-edges.d.ts +14 -0
- package/dist/core/ingestion/scope-resolution/value-ref-edges.js +14 -0
- package/dist/core/ingestion/tree-sitter-queries.js +2 -0
- package/dist/core/ingestion/utils/symbol-labels.js +2 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +1 -1
- package/dist/core/ingestion/workers/parse-worker.js +63 -3
- package/dist/core/ingestion/workers/worker-pool.d.ts +56 -2
- package/dist/core/ingestion/workers/worker-pool.js +117 -26
- package/dist/core/lbug/csv-generator.js +2 -0
- package/dist/core/lbug/schema.d.ts +3 -1
- package/dist/core/lbug/schema.js +27 -0
- package/dist/core/search/fts-indexes.js +13 -4
- package/dist/core/search/fts-schema.js +2 -0
- package/dist/core/tree-sitter/parser-loader.js +10 -0
- package/dist/core/tree-sitter/vendored-grammars.d.ts +1 -1
- package/dist/core/tree-sitter/vendored-grammars.js +2 -1
- package/dist/mcp/local/local-backend.d.ts +33 -0
- package/dist/mcp/local/local-backend.js +166 -5
- package/dist/mcp/tools.js +6 -4
- package/dist/server/analyze-job.d.ts +19 -1
- package/dist/server/analyze-job.js +14 -3
- package/dist/server/analyze-launch.d.ts +14 -0
- package/dist/server/analyze-launch.js +59 -14
- package/dist/server/analyze-worker-ipc.d.ts +6 -5
- package/dist/server/analyze-worker-ipc.js +4 -0
- package/dist/server/api.js +68 -21
- package/dist/server/git-clone.d.ts +38 -5
- package/dist/server/git-clone.js +216 -38
- package/dist/server/repo-projection.d.ts +88 -0
- package/dist/server/repo-projection.js +53 -0
- package/dist/storage/file-lock.js +5 -3
- package/dist/storage/parse-cache.js +32 -1
- package/dist/storage/parsedfile-store.js +53 -1
- package/dist/storage/v8-sidecar.d.ts +11 -0
- package/dist/storage/v8-sidecar.js +15 -7
- package/dist/utils/process-identity.d.ts +13 -0
- package/dist/utils/process-identity.js +18 -0
- package/package.json +1 -1
- package/scripts/build-tree-sitter-grammars.cjs +4 -3
- package/vendor/tree-sitter-objc/LICENSE +21 -0
- package/vendor/tree-sitter-objc/README.md +18 -0
- package/vendor/tree-sitter-objc/binding.gyp +35 -0
- package/vendor/tree-sitter-objc/bindings/node/binding.cc +19 -0
- package/vendor/tree-sitter-objc/bindings/node/binding_test.js +9 -0
- package/vendor/tree-sitter-objc/bindings/node/index.d.ts +27 -0
- package/vendor/tree-sitter-objc/bindings/node/index.js +11 -0
- package/vendor/tree-sitter-objc/grammar.js +1286 -0
- package/vendor/tree-sitter-objc/package.json +56 -0
- package/vendor/tree-sitter-objc/prebuilds/SHA256SUMS +6 -0
- package/vendor/tree-sitter-objc/prebuilds/darwin-arm64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/darwin-x64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/linux-arm64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/linux-x64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/win32-arm64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/prebuilds/win32-x64/tree-sitter-objc.node +0 -0
- package/vendor/tree-sitter-objc/queries/folds.scm +20 -0
- package/vendor/tree-sitter-objc/queries/highlights.scm +216 -0
- package/vendor/tree-sitter-objc/queries/indents.scm +1 -0
- package/vendor/tree-sitter-objc/queries/injections.scm +10 -0
- package/vendor/tree-sitter-objc/queries/locals.scm +1 -0
- package/vendor/tree-sitter-objc/src/grammar.json +16292 -0
- package/vendor/tree-sitter-objc/src/node-types.json +7524 -0
- package/vendor/tree-sitter-objc/src/parser.c +684023 -0
- package/vendor/tree-sitter-objc/src/tree_sitter/alloc.h +54 -0
- package/vendor/tree-sitter-objc/src/tree_sitter/array.h +291 -0
- package/vendor/tree-sitter-objc/src/tree_sitter/parser.h +266 -0
- package/vendor/tree-sitter-objc/tree-sitter-objc.wasm +0 -0
- package/vendor/tree-sitter-objc/tree-sitter.json +38 -0
- package/web/assets/{agent-BMRqXorA.js → agent-C2n33ANd.js} +1 -1
- package/web/assets/{index-Dj3vQOHK.js → index-CHJoW_P1.js} +18 -18
- package/web/assets/src-jc8Ffy3T.js +1 -0
- package/web/index.html +2 -2
- 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
|
-
*
|
|
406
|
-
*
|
|
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,
|
|
@@ -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 =
|
|
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
|
-
|
|
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
|
|
5
|
-
*
|
|
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
|
-
|
|
311
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
846
|
-
|
|
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
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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 <
|
|
1061
|
-
onProgress(
|
|
1062
|
-
|
|
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. */
|