gitnexus 1.6.3-rc.8 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -5
- package/dist/_shared/graph/types.d.ts +16 -0
- package/dist/_shared/graph/types.d.ts.map +1 -1
- package/dist/_shared/index.d.ts +20 -2
- package/dist/_shared/index.d.ts.map +1 -1
- package/dist/_shared/index.js +11 -0
- package/dist/_shared/index.js.map +1 -1
- package/dist/_shared/scope-resolution/def-index.js +2 -2
- package/dist/_shared/scope-resolution/def-index.js.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts +8 -0
- package/dist/_shared/scope-resolution/method-dispatch-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/method-dispatch-index.js +2 -2
- package/dist/_shared/scope-resolution/method-dispatch-index.js.map +1 -1
- package/dist/_shared/scope-resolution/module-scope-index.d.ts +8 -0
- package/dist/_shared/scope-resolution/module-scope-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/module-scope-index.js +10 -2
- package/dist/_shared/scope-resolution/module-scope-index.js.map +1 -1
- package/dist/_shared/scope-resolution/parsed-file.d.ts +76 -0
- package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/parsed-file.js +54 -0
- package/dist/_shared/scope-resolution/parsed-file.js.map +1 -0
- package/dist/_shared/scope-resolution/position-index.d.ts +12 -0
- package/dist/_shared/scope-resolution/position-index.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/position-index.js +2 -2
- package/dist/_shared/scope-resolution/position-index.js.map +1 -1
- package/dist/_shared/scope-resolution/qualified-name-index.js +2 -2
- package/dist/_shared/scope-resolution/qualified-name-index.js.map +1 -1
- package/dist/_shared/scope-resolution/reference-site.d.ts +75 -0
- package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/reference-site.js +24 -0
- package/dist/_shared/scope-resolution/reference-site.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts +27 -0
- package/dist/_shared/scope-resolution/registries/class-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js +30 -0
- package/dist/_shared/scope-resolution/registries/class-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts +69 -0
- package/dist/_shared/scope-resolution/registries/context.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/context.js +44 -0
- package/dist/_shared/scope-resolution/registries/context.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts +56 -0
- package/dist/_shared/scope-resolution/registries/evidence.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/evidence.js +150 -0
- package/dist/_shared/scope-resolution/registries/evidence.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts +26 -0
- package/dist/_shared/scope-resolution/registries/field-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js +31 -0
- package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts +81 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js +332 -0
- package/dist/_shared/scope-resolution/registries/lookup-core.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts +33 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js +56 -0
- package/dist/_shared/scope-resolution/registries/lookup-qualified.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts +36 -0
- package/dist/_shared/scope-resolution/registries/method-registry.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js +32 -0
- package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts +43 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.d.ts.map +1 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js +60 -0
- package/dist/_shared/scope-resolution/registries/tie-breaks.js.map +1 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts +1 -10
- package/dist/_shared/scope-resolution/resolve-type-ref.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/resolve-type-ref.js +6 -0
- package/dist/_shared/scope-resolution/resolve-type-ref.js.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.d.ts +4 -4
- package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/scope-tree.js +3 -2
- package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts +6 -2
- package/dist/_shared/scope-resolution/shadow/aggregate.d.ts.map +1 -1
- package/dist/_shared/scope-resolution/shadow/aggregate.js +5 -0
- package/dist/_shared/scope-resolution/shadow/aggregate.js.map +1 -1
- package/dist/_shared/scope-resolution/types.d.ts +11 -0
- package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
- package/dist/cli/ai-context.js +35 -4
- package/dist/cli/analyze.d.ts +27 -0
- package/dist/cli/analyze.js +31 -1
- package/dist/cli/clean.js +19 -1
- package/dist/cli/group.js +73 -0
- package/dist/cli/index-repo.js +8 -1
- package/dist/cli/index.js +26 -1
- package/dist/cli/list.js +11 -1
- package/dist/cli/remove.d.ts +30 -0
- package/dist/cli/remove.js +99 -0
- package/dist/cli/setup.js +185 -57
- package/dist/cli/tool.d.ts +5 -0
- package/dist/cli/tool.js +42 -0
- package/dist/config/ignore-service.d.ts +9 -0
- package/dist/config/ignore-service.js +80 -13
- package/dist/core/embedding-mode.d.ts +30 -0
- package/dist/core/embedding-mode.js +30 -0
- package/dist/core/embeddings/ast-utils.js +22 -22
- package/dist/core/embeddings/chunker.js +30 -25
- package/dist/core/embeddings/embedding-pipeline.d.ts +6 -0
- package/dist/core/embeddings/embedding-pipeline.js +15 -6
- package/dist/core/embeddings/text-generator.d.ts +1 -1
- package/dist/core/embeddings/text-generator.js +33 -24
- package/dist/core/embeddings/types.d.ts +43 -1
- package/dist/core/embeddings/types.js +101 -29
- package/dist/core/git-staleness.d.ts +18 -0
- package/dist/core/git-staleness.js +108 -0
- package/dist/core/graph/graph.js +115 -20
- package/dist/core/graph/types.d.ts +12 -1
- package/dist/core/group/config-parser.d.ts +4 -0
- package/dist/core/group/config-parser.js +18 -1
- package/dist/core/group/cross-impact.d.ts +41 -0
- package/dist/core/group/cross-impact.js +441 -0
- package/dist/core/group/extractors/http-patterns/php.js +126 -18
- package/dist/core/group/group-path-utils.d.ts +17 -0
- package/dist/core/group/group-path-utils.js +40 -0
- package/dist/core/group/resolve-at-member.d.ts +10 -0
- package/dist/core/group/resolve-at-member.js +31 -0
- package/dist/core/group/service.d.ts +9 -0
- package/dist/core/group/service.js +259 -25
- package/dist/core/group/types.d.ts +30 -0
- package/dist/core/ingestion/ast-cache.d.ts +16 -1
- package/dist/core/ingestion/ast-cache.js +14 -2
- package/dist/core/ingestion/call-processor.js +9 -0
- package/dist/core/ingestion/emit-references.d.ts +88 -0
- package/dist/core/ingestion/emit-references.js +229 -0
- package/dist/core/ingestion/filesystem-walker.js +6 -4
- package/dist/core/ingestion/finalize-orchestrator.d.ts +63 -0
- package/dist/core/ingestion/finalize-orchestrator.js +139 -0
- package/dist/core/ingestion/framework-detection.js +6 -2
- package/dist/core/ingestion/import-processor.js +4 -0
- package/dist/core/ingestion/import-resolvers/python.js +9 -6
- package/dist/core/ingestion/import-target-adapter.d.ts +73 -0
- package/dist/core/ingestion/import-target-adapter.js +95 -0
- package/dist/core/ingestion/language-provider.d.ts +36 -33
- package/dist/core/ingestion/languages/csharp/accessor-unwrap.d.ts +21 -0
- package/dist/core/ingestion/languages/csharp/accessor-unwrap.js +56 -0
- package/dist/core/ingestion/languages/csharp/arity-metadata.d.ts +26 -0
- package/dist/core/ingestion/languages/csharp/arity-metadata.js +46 -0
- package/dist/core/ingestion/languages/csharp/arity.d.ts +23 -0
- package/dist/core/ingestion/languages/csharp/arity.js +37 -0
- package/dist/core/ingestion/languages/csharp/cache-stats.d.ts +15 -0
- package/dist/core/ingestion/languages/csharp/cache-stats.js +26 -0
- package/dist/core/ingestion/languages/csharp/captures.d.ts +19 -0
- package/dist/core/ingestion/languages/csharp/captures.js +249 -0
- package/dist/core/ingestion/languages/csharp/import-decomposer.d.ts +19 -0
- package/dist/core/ingestion/languages/csharp/import-decomposer.js +93 -0
- package/dist/core/ingestion/languages/csharp/import-target.d.ts +25 -0
- package/dist/core/ingestion/languages/csharp/import-target.js +123 -0
- package/dist/core/ingestion/languages/csharp/index.d.ts +82 -0
- package/dist/core/ingestion/languages/csharp/index.js +82 -0
- package/dist/core/ingestion/languages/csharp/interpret.d.ts +15 -0
- package/dist/core/ingestion/languages/csharp/interpret.js +132 -0
- package/dist/core/ingestion/languages/csharp/merge-bindings.d.ts +27 -0
- package/dist/core/ingestion/languages/csharp/merge-bindings.js +55 -0
- package/dist/core/ingestion/languages/csharp/namespace-siblings.d.ts +50 -0
- package/dist/core/ingestion/languages/csharp/namespace-siblings.js +374 -0
- package/dist/core/ingestion/languages/csharp/query.d.ts +35 -0
- package/dist/core/ingestion/languages/csharp/query.js +515 -0
- package/dist/core/ingestion/languages/csharp/receiver-binding.d.ts +31 -0
- package/dist/core/ingestion/languages/csharp/receiver-binding.js +135 -0
- package/dist/core/ingestion/languages/csharp/scope-resolver.d.ts +10 -0
- package/dist/core/ingestion/languages/csharp/scope-resolver.js +63 -0
- package/dist/core/ingestion/languages/csharp/simple-hooks.d.ts +53 -0
- package/dist/core/ingestion/languages/csharp/simple-hooks.js +76 -0
- package/dist/core/ingestion/languages/csharp.js +14 -0
- package/dist/core/ingestion/languages/python/arity-metadata.d.ts +24 -0
- package/dist/core/ingestion/languages/python/arity-metadata.js +45 -0
- package/dist/core/ingestion/languages/python/arity.d.ts +22 -0
- package/dist/core/ingestion/languages/python/arity.js +38 -0
- package/dist/core/ingestion/languages/python/cache-stats.d.ts +17 -0
- package/dist/core/ingestion/languages/python/cache-stats.js +28 -0
- package/dist/core/ingestion/languages/python/captures.d.ts +19 -0
- package/dist/core/ingestion/languages/python/captures.js +106 -0
- package/dist/core/ingestion/languages/python/import-decomposer.d.ts +15 -0
- package/dist/core/ingestion/languages/python/import-decomposer.js +112 -0
- package/dist/core/ingestion/languages/python/import-target.d.ts +21 -0
- package/dist/core/ingestion/languages/python/import-target.js +99 -0
- package/dist/core/ingestion/languages/python/index.d.ts +80 -0
- package/dist/core/ingestion/languages/python/index.js +80 -0
- package/dist/core/ingestion/languages/python/interpret.d.ts +15 -0
- package/dist/core/ingestion/languages/python/interpret.js +191 -0
- package/dist/core/ingestion/languages/python/merge-bindings.d.ts +16 -0
- package/dist/core/ingestion/languages/python/merge-bindings.js +44 -0
- package/dist/core/ingestion/languages/python/query.d.ts +9 -0
- package/dist/core/ingestion/languages/python/query.js +267 -0
- package/dist/core/ingestion/languages/python/receiver-binding.d.ts +21 -0
- package/dist/core/ingestion/languages/python/receiver-binding.js +116 -0
- package/dist/core/ingestion/languages/python/scope-resolver.d.ts +16 -0
- package/dist/core/ingestion/languages/python/scope-resolver.js +53 -0
- package/dist/core/ingestion/languages/python/simple-hooks.d.ts +23 -0
- package/dist/core/ingestion/languages/python/simple-hooks.js +35 -0
- package/dist/core/ingestion/languages/python.js +14 -0
- package/dist/core/ingestion/model/method-registry.d.ts +9 -0
- package/dist/core/ingestion/model/method-registry.js +4 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.d.ts +59 -0
- package/dist/core/ingestion/model/scope-resolution-indexes.js +42 -0
- package/dist/core/ingestion/model/semantic-model.d.ts +64 -0
- package/dist/core/ingestion/model/semantic-model.js +55 -0
- package/dist/core/ingestion/mro-processor.js +38 -22
- package/dist/core/ingestion/parsing-processor.d.ts +18 -1
- package/dist/core/ingestion/parsing-processor.js +45 -11
- package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
- package/dist/core/ingestion/pipeline-phases/index.js +1 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +10 -0
- package/dist/core/ingestion/pipeline-phases/parse-impl.js +17 -2
- package/dist/core/ingestion/pipeline-phases/parse.d.ts +18 -0
- package/dist/core/ingestion/pipeline.js +2 -1
- package/dist/core/ingestion/registry-primary-flag.d.ts +86 -0
- package/dist/core/ingestion/registry-primary-flag.js +111 -0
- package/dist/core/ingestion/resolve-references.d.ts +63 -0
- package/dist/core/ingestion/resolve-references.js +175 -0
- package/dist/core/ingestion/scope-extractor-bridge.d.ts +32 -0
- package/dist/core/ingestion/scope-extractor-bridge.js +44 -0
- package/dist/core/ingestion/scope-extractor.d.ts +86 -0
- package/dist/core/ingestion/scope-extractor.js +758 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +372 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.js +212 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +43 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +79 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.d.ts +57 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +112 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/imports-to-edges.js +46 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.d.ts +19 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/method-dispatch.js +30 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.d.ts +37 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +113 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +38 -0
- package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +73 -0
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +42 -0
- package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +198 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +27 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +131 -0
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.d.ts +48 -0
- package/dist/core/ingestion/scope-resolution/passes/imported-return-types.js +130 -0
- package/dist/core/ingestion/scope-resolution/passes/mro.d.ts +42 -0
- package/dist/core/ingestion/scope-resolution/passes/mro.js +99 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.d.ts +26 -0
- package/dist/core/ingestion/scope-resolution/passes/overload-narrowing.js +61 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +46 -0
- package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +327 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +47 -0
- package/dist/core/ingestion/scope-resolution/pipeline/phase.js +130 -0
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.d.ts +68 -0
- package/dist/core/ingestion/scope-resolution/pipeline/reconcile-ownership.js +125 -0
- package/dist/core/ingestion/scope-resolution/pipeline/registry.d.ts +17 -0
- package/dist/core/ingestion/scope-resolution/pipeline/registry.js +21 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +66 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +157 -0
- package/dist/core/ingestion/scope-resolution/scope/namespace-targets.d.ts +36 -0
- package/dist/core/ingestion/scope-resolution/scope/namespace-targets.js +52 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +127 -0
- package/dist/core/ingestion/scope-resolution/scope/walkers.js +349 -0
- package/dist/core/ingestion/scope-resolution/workspace-index.d.ts +52 -0
- package/dist/core/ingestion/scope-resolution/workspace-index.js +61 -0
- package/dist/core/ingestion/shadow-harness.d.ts +113 -0
- package/dist/core/ingestion/shadow-harness.js +148 -0
- package/dist/core/ingestion/utils/ast-helpers.d.ts +19 -1
- package/dist/core/ingestion/utils/ast-helpers.js +70 -0
- package/dist/core/ingestion/utils/max-file-size.d.ts +20 -0
- package/dist/core/ingestion/utils/max-file-size.js +52 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +9 -0
- package/dist/core/ingestion/workers/parse-worker.js +57 -21
- package/dist/core/lbug/lbug-adapter.d.ts +22 -2
- package/dist/core/lbug/lbug-adapter.js +58 -14
- package/dist/core/lbug/pool-adapter.d.ts +17 -0
- package/dist/core/lbug/pool-adapter.js +24 -14
- package/dist/core/run-analyze.d.ts +32 -0
- package/dist/core/run-analyze.js +74 -19
- package/dist/core/search/bm25-index.d.ts +18 -0
- package/dist/core/search/bm25-index.js +125 -12
- package/dist/core/tree-sitter/parser-loader.js +6 -1
- package/dist/mcp/local/local-backend.d.ts +67 -3
- package/dist/mcp/local/local-backend.js +296 -34
- package/dist/mcp/resources.d.ts +31 -0
- package/dist/mcp/resources.js +100 -17
- package/dist/mcp/tools.d.ts +4 -1
- package/dist/mcp/tools.js +75 -54
- package/dist/server/api.js +6 -2
- package/dist/storage/git.d.ts +49 -0
- package/dist/storage/git.js +111 -0
- package/dist/storage/repo-manager.d.ts +246 -1
- package/dist/storage/repo-manager.js +391 -9
- package/package.json +7 -6
- package/scripts/bench-scope-resolution.ts +134 -0
- package/scripts/ci-list-migrated-languages.ts +24 -0
- package/skills/gitnexus-cli.md +1 -0
|
@@ -56,6 +56,7 @@ interface RepoHandle {
|
|
|
56
56
|
lbugPath: string;
|
|
57
57
|
indexedAt: string;
|
|
58
58
|
lastCommit: string;
|
|
59
|
+
remoteUrl?: string;
|
|
59
60
|
stats?: RegistryEntry['stats'];
|
|
60
61
|
}
|
|
61
62
|
export declare class LocalBackend {
|
|
@@ -65,6 +66,13 @@ export declare class LocalBackend {
|
|
|
65
66
|
private reinitPromises;
|
|
66
67
|
private lastStalenessCheck;
|
|
67
68
|
private groupToolSvc;
|
|
69
|
+
/**
|
|
70
|
+
* One-shot stderr warnings for sibling-clone drift, keyed by
|
|
71
|
+
* `${repoId}|${cwdGitRoot}`. Without this guard every tool call
|
|
72
|
+
* from inside a sibling clone would print the same warning,
|
|
73
|
+
* making MCP stderr unreadable.
|
|
74
|
+
*/
|
|
75
|
+
private warnedSiblingDrift;
|
|
68
76
|
/**
|
|
69
77
|
* Cross-repo group tools (CLI). Shares logic with MCP `group_*` handlers.
|
|
70
78
|
*/
|
|
@@ -110,14 +118,55 @@ export declare class LocalBackend {
|
|
|
110
118
|
* List all registered repos with their metadata.
|
|
111
119
|
* Re-reads the global registry so newly indexed repos are discovered
|
|
112
120
|
* without restarting the MCP server.
|
|
121
|
+
*
|
|
122
|
+
* Each entry includes:
|
|
123
|
+
* - `staleness`: if the indexed clone's own HEAD has moved past
|
|
124
|
+
* the recorded `lastCommit` (option D in the issue's fix list).
|
|
125
|
+
* - `siblings`: other registered entries sharing the same
|
|
126
|
+
* `remoteUrl` (option B's payoff: callers can see at a glance
|
|
127
|
+
* that another clone of the same logical repo is registered).
|
|
128
|
+
* - `remoteUrl`: the canonical origin URL recorded at index time.
|
|
113
129
|
*/
|
|
114
130
|
listRepos(): Promise<Array<{
|
|
115
131
|
name: string;
|
|
116
132
|
path: string;
|
|
117
133
|
indexedAt: string;
|
|
118
134
|
lastCommit: string;
|
|
135
|
+
remoteUrl?: string;
|
|
119
136
|
stats?: any;
|
|
137
|
+
staleness?: {
|
|
138
|
+
commitsBehind: number;
|
|
139
|
+
hint?: string;
|
|
140
|
+
};
|
|
141
|
+
siblings?: Array<{
|
|
142
|
+
name: string;
|
|
143
|
+
path: string;
|
|
144
|
+
lastCommit: string;
|
|
145
|
+
}>;
|
|
120
146
|
}>>;
|
|
147
|
+
/**
|
|
148
|
+
* Best-effort sibling-clone drift warning.
|
|
149
|
+
*
|
|
150
|
+
* When the resolved index has a `remoteUrl` recorded and the caller's
|
|
151
|
+
* `process.cwd()` is inside a *different* clone of the same repo, emit
|
|
152
|
+
* one stderr line per (repo, cwd) pair so the operator knows the
|
|
153
|
+
* graph may be stale relative to what's actually on disk under their
|
|
154
|
+
* cwd. Silent on path matches and on repos without a remote URL.
|
|
155
|
+
*
|
|
156
|
+
* Limitation: in MCP stdio server mode `process.cwd()` is the
|
|
157
|
+
* server's CWD at start time, *not* the agent client's CWD. The
|
|
158
|
+
* warning therefore only fires when the MCP server itself was
|
|
159
|
+
* launched from inside a sibling clone (typical for `npx gitnexus
|
|
160
|
+
* serve` from a polecat workspace). Surfacing the client's CWD
|
|
161
|
+
* would require a per-tool-call `cwd` parameter — out of scope for
|
|
162
|
+
* the current MCP contract.
|
|
163
|
+
*
|
|
164
|
+
* Pure side-effect (stderr); never affects the returned handle.
|
|
165
|
+
* After the first computation for a given (repo, cwd) pair the
|
|
166
|
+
* result is cached so subsequent `resolveRepo()` calls don't
|
|
167
|
+
* re-shell-out to git.
|
|
168
|
+
*/
|
|
169
|
+
private maybeWarnSiblingDrift;
|
|
121
170
|
callTool(method: string, params: any): Promise<any>;
|
|
122
171
|
/**
|
|
123
172
|
* Query tool — process-grouped search.
|
|
@@ -236,11 +285,26 @@ export declare class LocalBackend {
|
|
|
236
285
|
includeTests: boolean;
|
|
237
286
|
}): Promise<any | null>;
|
|
238
287
|
private handleGroupTool;
|
|
288
|
+
/**
|
|
289
|
+
* Dispatch impact/query/context when `repo` is `@groupName` or `@groupName/memberPath`
|
|
290
|
+
* (group mode — not the global indexed-repo `repo` parameter).
|
|
291
|
+
*/
|
|
292
|
+
private callToolAtGroupRepo;
|
|
239
293
|
private groupList;
|
|
240
294
|
private groupSync;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
295
|
+
/**
|
|
296
|
+
* MCP resource body for `gitnexus://group/{name}/contracts` (Issue #794).
|
|
297
|
+
*/
|
|
298
|
+
readGroupContractsResource(groupName: string, filter: {
|
|
299
|
+
type?: string;
|
|
300
|
+
repo?: string;
|
|
301
|
+
unmatchedOnly?: boolean;
|
|
302
|
+
}): Promise<string>;
|
|
303
|
+
/**
|
|
304
|
+
* MCP resource body for `gitnexus://group/{name}/status` (Issue #794).
|
|
305
|
+
*/
|
|
306
|
+
readGroupStatusResource(groupName: string): Promise<string>;
|
|
307
|
+
private static formatGroupResourcePayload;
|
|
244
308
|
/**
|
|
245
309
|
* Fetch Route nodes with their consumers in a single query.
|
|
246
310
|
* Shared by routeMap and shapeCheck to avoid N+1 query patterns.
|
|
@@ -16,9 +16,11 @@ export { isWriteQuery };
|
|
|
16
16
|
import { parseDiffHunks } from '../../storage/git.js';
|
|
17
17
|
import { listRegisteredRepos, cleanupOldKuzuFiles, } from '../../storage/repo-manager.js';
|
|
18
18
|
import { GroupService } from '../../core/group/service.js';
|
|
19
|
+
import { resolveAtGroupMemberRepoPath } from '../../core/group/resolve-at-member.js';
|
|
19
20
|
import { collectBestChunks } from '../../core/embeddings/types.js';
|
|
20
21
|
import { EMBEDDING_TABLE_NAME, EMBEDDING_INDEX_NAME } from '../../core/lbug/schema.js';
|
|
21
22
|
import { PhaseTimer } from '../../core/search/phase-timer.js';
|
|
23
|
+
import { checkStaleness, checkCwdMatch } from '../../core/git-staleness.js';
|
|
22
24
|
// AI context generation is CLI-only (gitnexus analyze)
|
|
23
25
|
// import { generateAIContextFiles } from '../../cli/ai-context.js';
|
|
24
26
|
/**
|
|
@@ -161,6 +163,13 @@ export class LocalBackend {
|
|
|
161
163
|
reinitPromises = new Map();
|
|
162
164
|
lastStalenessCheck = new Map();
|
|
163
165
|
groupToolSvc = null;
|
|
166
|
+
/**
|
|
167
|
+
* One-shot stderr warnings for sibling-clone drift, keyed by
|
|
168
|
+
* `${repoId}|${cwdGitRoot}`. Without this guard every tool call
|
|
169
|
+
* from inside a sibling clone would print the same warning,
|
|
170
|
+
* making MCP stderr unreadable.
|
|
171
|
+
*/
|
|
172
|
+
warnedSiblingDrift = new Set();
|
|
164
173
|
/**
|
|
165
174
|
* Cross-repo group tools (CLI). Shares logic with MCP `group_*` handlers.
|
|
166
175
|
*/
|
|
@@ -171,6 +180,7 @@ export class LocalBackend {
|
|
|
171
180
|
impact: (r, p) => this.impact(r, p),
|
|
172
181
|
query: (r, p) => this.query(r, p),
|
|
173
182
|
impactByUid: (id, uid, d, o) => this.impactByUid(id, uid, d, o),
|
|
183
|
+
context: (r, p) => this.context(r, p),
|
|
174
184
|
};
|
|
175
185
|
this.groupToolSvc = new GroupService(port);
|
|
176
186
|
}
|
|
@@ -216,6 +226,7 @@ export class LocalBackend {
|
|
|
216
226
|
lbugPath,
|
|
217
227
|
indexedAt: entry.indexedAt,
|
|
218
228
|
lastCommit: entry.lastCommit,
|
|
229
|
+
remoteUrl: entry.remoteUrl,
|
|
219
230
|
stats: entry.stats,
|
|
220
231
|
};
|
|
221
232
|
this.repos.set(id, handle);
|
|
@@ -268,23 +279,43 @@ export class LocalBackend {
|
|
|
268
279
|
*/
|
|
269
280
|
async resolveRepo(repoParam) {
|
|
270
281
|
const result = this.resolveRepoFromCache(repoParam);
|
|
271
|
-
if (result)
|
|
282
|
+
if (result) {
|
|
283
|
+
// Issue: silent graph drift across sibling clones.
|
|
284
|
+
// If the caller's cwd lives in a *different* on-disk clone of
|
|
285
|
+
// the same repo (matched by `remoteUrl`), warn once per
|
|
286
|
+
// (repo, cwd) pair on stderr. We do not fail or refuse to
|
|
287
|
+
// serve — the index is still the best answer we have — but
|
|
288
|
+
// the operator/agent has to know the answer may be stale.
|
|
289
|
+
this.maybeWarnSiblingDrift(result).catch(() => {
|
|
290
|
+
/* best-effort; never throw from resolveRepo */
|
|
291
|
+
});
|
|
272
292
|
return result;
|
|
293
|
+
}
|
|
273
294
|
// Miss — refresh registry and try once more
|
|
274
295
|
await this.refreshRepos();
|
|
275
296
|
const retried = this.resolveRepoFromCache(repoParam);
|
|
276
|
-
if (retried)
|
|
297
|
+
if (retried) {
|
|
298
|
+
this.maybeWarnSiblingDrift(retried).catch(() => { });
|
|
277
299
|
return retried;
|
|
300
|
+
}
|
|
278
301
|
// Still no match — throw with helpful message
|
|
279
302
|
if (this.repos.size === 0) {
|
|
280
303
|
throw new Error('No indexed repositories. Run: gitnexus analyze');
|
|
281
304
|
}
|
|
305
|
+
// Build a disambiguated "Available: …" list (#829). When two handles
|
|
306
|
+
// share a name, annotate each colliding label with its path so the
|
|
307
|
+
// caller can actually pick the right one. Single-name entries render
|
|
308
|
+
// identically to pre-#829 output.
|
|
309
|
+
const nameCounts = new Map();
|
|
310
|
+
for (const h of this.repos.values()) {
|
|
311
|
+
const key = h.name.toLowerCase();
|
|
312
|
+
nameCounts.set(key, (nameCounts.get(key) ?? 0) + 1);
|
|
313
|
+
}
|
|
314
|
+
const labels = [...this.repos.values()].map((h) => (nameCounts.get(h.name.toLowerCase()) ?? 0) > 1 ? `${h.name} (${h.repoPath})` : h.name);
|
|
282
315
|
if (repoParam) {
|
|
283
|
-
|
|
284
|
-
throw new Error(`Repository "${repoParam}" not found. Available: ${names.join(', ')}`);
|
|
316
|
+
throw new Error(`Repository "${repoParam}" not found. Available: ${labels.join(', ')}`);
|
|
285
317
|
}
|
|
286
|
-
|
|
287
|
-
throw new Error(`Multiple repositories indexed. Specify which one with the "repo" parameter. Available: ${names.join(', ')}`);
|
|
318
|
+
throw new Error(`Multiple repositories indexed. Specify which one with the "repo" parameter. Available: ${labels.join(', ')}`);
|
|
288
319
|
}
|
|
289
320
|
/**
|
|
290
321
|
* Try to resolve a repo from the in-memory cache. Returns null on miss.
|
|
@@ -396,16 +427,113 @@ export class LocalBackend {
|
|
|
396
427
|
* List all registered repos with their metadata.
|
|
397
428
|
* Re-reads the global registry so newly indexed repos are discovered
|
|
398
429
|
* without restarting the MCP server.
|
|
430
|
+
*
|
|
431
|
+
* Each entry includes:
|
|
432
|
+
* - `staleness`: if the indexed clone's own HEAD has moved past
|
|
433
|
+
* the recorded `lastCommit` (option D in the issue's fix list).
|
|
434
|
+
* - `siblings`: other registered entries sharing the same
|
|
435
|
+
* `remoteUrl` (option B's payoff: callers can see at a glance
|
|
436
|
+
* that another clone of the same logical repo is registered).
|
|
437
|
+
* - `remoteUrl`: the canonical origin URL recorded at index time.
|
|
399
438
|
*/
|
|
400
439
|
async listRepos() {
|
|
401
440
|
await this.refreshRepos();
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
441
|
+
const handles = [...this.repos.values()];
|
|
442
|
+
// Pre-group registered handles by `remoteUrl` so the sibling
|
|
443
|
+
// lookup is O(1) per handle. We reuse the in-memory `this.repos`
|
|
444
|
+
// (already populated by `refreshRepos`) instead of doing a fresh
|
|
445
|
+
// `readRegistry()` per entry — that would be N file reads for N
|
|
446
|
+
// registered repos.
|
|
447
|
+
const isWin = process.platform === 'win32';
|
|
448
|
+
const norm = (p) => (isWin ? path.resolve(p).toLowerCase() : path.resolve(p));
|
|
449
|
+
const byRemote = new Map();
|
|
450
|
+
for (const h of handles) {
|
|
451
|
+
if (!h.remoteUrl)
|
|
452
|
+
continue;
|
|
453
|
+
const list = byRemote.get(h.remoteUrl) ?? [];
|
|
454
|
+
list.push(h);
|
|
455
|
+
byRemote.set(h.remoteUrl, list);
|
|
456
|
+
}
|
|
457
|
+
return handles.map((h) => {
|
|
458
|
+
const stale = checkStaleness(h.repoPath, h.lastCommit);
|
|
459
|
+
const selfNorm = norm(h.repoPath);
|
|
460
|
+
const siblings = h.remoteUrl
|
|
461
|
+
? (byRemote.get(h.remoteUrl) ?? []).filter((e) => norm(e.repoPath) !== selfNorm)
|
|
462
|
+
: [];
|
|
463
|
+
return {
|
|
464
|
+
name: h.name,
|
|
465
|
+
path: h.repoPath,
|
|
466
|
+
indexedAt: h.indexedAt,
|
|
467
|
+
lastCommit: h.lastCommit,
|
|
468
|
+
remoteUrl: h.remoteUrl,
|
|
469
|
+
stats: h.stats,
|
|
470
|
+
staleness: stale.isStale
|
|
471
|
+
? { commitsBehind: stale.commitsBehind, hint: stale.hint }
|
|
472
|
+
: undefined,
|
|
473
|
+
siblings: siblings.length > 0
|
|
474
|
+
? siblings.map((s) => ({
|
|
475
|
+
name: s.name,
|
|
476
|
+
path: s.repoPath,
|
|
477
|
+
lastCommit: s.lastCommit,
|
|
478
|
+
}))
|
|
479
|
+
: undefined,
|
|
480
|
+
};
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Best-effort sibling-clone drift warning.
|
|
485
|
+
*
|
|
486
|
+
* When the resolved index has a `remoteUrl` recorded and the caller's
|
|
487
|
+
* `process.cwd()` is inside a *different* clone of the same repo, emit
|
|
488
|
+
* one stderr line per (repo, cwd) pair so the operator knows the
|
|
489
|
+
* graph may be stale relative to what's actually on disk under their
|
|
490
|
+
* cwd. Silent on path matches and on repos without a remote URL.
|
|
491
|
+
*
|
|
492
|
+
* Limitation: in MCP stdio server mode `process.cwd()` is the
|
|
493
|
+
* server's CWD at start time, *not* the agent client's CWD. The
|
|
494
|
+
* warning therefore only fires when the MCP server itself was
|
|
495
|
+
* launched from inside a sibling clone (typical for `npx gitnexus
|
|
496
|
+
* serve` from a polecat workspace). Surfacing the client's CWD
|
|
497
|
+
* would require a per-tool-call `cwd` parameter — out of scope for
|
|
498
|
+
* the current MCP contract.
|
|
499
|
+
*
|
|
500
|
+
* Pure side-effect (stderr); never affects the returned handle.
|
|
501
|
+
* After the first computation for a given (repo, cwd) pair the
|
|
502
|
+
* result is cached so subsequent `resolveRepo()` calls don't
|
|
503
|
+
* re-shell-out to git.
|
|
504
|
+
*/
|
|
505
|
+
async maybeWarnSiblingDrift(handle) {
|
|
506
|
+
if (!handle.remoteUrl)
|
|
507
|
+
return;
|
|
508
|
+
let cwd;
|
|
509
|
+
try {
|
|
510
|
+
cwd = process.cwd();
|
|
511
|
+
}
|
|
512
|
+
catch {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
// Early-exit cache: keyed on (repo, cwd) BEFORE any git shellout.
|
|
516
|
+
// After the first call for a given cwd, this short-circuits the
|
|
517
|
+
// up-to-four `execSync`/`execFileSync` calls inside `checkCwdMatch`
|
|
518
|
+
// — important for MCP-server mode where `process.cwd()` is constant
|
|
519
|
+
// and `resolveRepo` runs on every tool call.
|
|
520
|
+
const cacheKey = `${handle.id}|${cwd}`;
|
|
521
|
+
if (this.warnedSiblingDrift.has(cacheKey))
|
|
522
|
+
return;
|
|
523
|
+
const match = await checkCwdMatch(cwd);
|
|
524
|
+
if (match.match !== 'sibling-by-remote' ||
|
|
525
|
+
!match.entry ||
|
|
526
|
+
!match.cwdGitRoot ||
|
|
527
|
+
match.entry.path !== handle.repoPath ||
|
|
528
|
+
!match.hint) {
|
|
529
|
+
// Cache "nothing to warn about" outcomes too — `checkCwdMatch`
|
|
530
|
+
// is deterministic for a fixed (registry, cwd) pair, so re-running
|
|
531
|
+
// it yields nothing new.
|
|
532
|
+
this.warnedSiblingDrift.add(cacheKey);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
this.warnedSiblingDrift.add(cacheKey);
|
|
536
|
+
console.error(`GitNexus: ${match.hint}`);
|
|
409
537
|
}
|
|
410
538
|
// ─── Tool Dispatch ───────────────────────────────────────────────
|
|
411
539
|
async callTool(method, params) {
|
|
@@ -415,6 +543,12 @@ export class LocalBackend {
|
|
|
415
543
|
if (method.startsWith('group_')) {
|
|
416
544
|
return this.handleGroupTool(method, params || {});
|
|
417
545
|
}
|
|
546
|
+
const p = params && typeof params === 'object' ? params : {};
|
|
547
|
+
if ((method === 'impact' || method === 'query' || method === 'context') &&
|
|
548
|
+
typeof p.repo === 'string' &&
|
|
549
|
+
p.repo.startsWith('@')) {
|
|
550
|
+
return this.callToolAtGroupRepo(method, p);
|
|
551
|
+
}
|
|
418
552
|
// Resolve repo from optional param (re-reads registry on miss)
|
|
419
553
|
const repo = await this.resolveRepo(params?.repo);
|
|
420
554
|
switch (method) {
|
|
@@ -691,12 +825,22 @@ export class LocalBackend {
|
|
|
691
825
|
for (const bm25Result of bm25Results) {
|
|
692
826
|
const fullPath = bm25Result.filePath;
|
|
693
827
|
try {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
828
|
+
// Prefer direct nodeId lookup (exact FTS-matched nodes) over filePath fallback.
|
|
829
|
+
// Without this, LIMIT 3 on filePath returns arbitrary symbols rather than
|
|
830
|
+
// the nodes that actually scored highest in the BM25 index.
|
|
831
|
+
const nodeIds = bm25Result.nodeIds?.length ? bm25Result.nodeIds : null;
|
|
832
|
+
const symbols = nodeIds
|
|
833
|
+
? await executeParameterized(repo.id, `
|
|
834
|
+
MATCH (n)
|
|
835
|
+
WHERE n.id IN $nodeIds
|
|
836
|
+
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
|
|
837
|
+
`, { nodeIds })
|
|
838
|
+
: await executeParameterized(repo.id, `
|
|
839
|
+
MATCH (n)
|
|
840
|
+
WHERE n.filePath = $filePath
|
|
841
|
+
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath, n.startLine AS startLine, n.endLine AS endLine
|
|
842
|
+
LIMIT 3
|
|
843
|
+
`, { filePath: fullPath });
|
|
700
844
|
if (symbols.length > 0) {
|
|
701
845
|
for (const sym of symbols) {
|
|
702
846
|
results.push({
|
|
@@ -2293,32 +2437,150 @@ export class LocalBackend {
|
|
|
2293
2437
|
return this.groupList(params);
|
|
2294
2438
|
case 'group_sync':
|
|
2295
2439
|
return this.groupSync(params);
|
|
2296
|
-
case 'group_contracts':
|
|
2297
|
-
return this.groupContracts(params);
|
|
2298
|
-
case 'group_query':
|
|
2299
|
-
return this.groupQuery(params);
|
|
2300
|
-
case 'group_status':
|
|
2301
|
-
return this.groupStatus(params);
|
|
2302
2440
|
default:
|
|
2303
|
-
throw new Error(`Unknown group tool: ${method}
|
|
2441
|
+
throw new Error(`Unknown group tool: ${method}. Removed tools: use repo "@<groupName>" on impact, query, or context (optional "/<memberPath>"), or MCP resources.`);
|
|
2304
2442
|
}
|
|
2305
2443
|
}
|
|
2444
|
+
/**
|
|
2445
|
+
* Dispatch impact/query/context when `repo` is `@groupName` or `@groupName/memberPath`
|
|
2446
|
+
* (group mode — not the global indexed-repo `repo` parameter).
|
|
2447
|
+
*/
|
|
2448
|
+
async callToolAtGroupRepo(method, params) {
|
|
2449
|
+
await this.refreshRepos();
|
|
2450
|
+
if (params.service !== undefined &&
|
|
2451
|
+
params.service !== null &&
|
|
2452
|
+
String(params.service).trim() === '') {
|
|
2453
|
+
return { error: 'service must not be an empty string' };
|
|
2454
|
+
}
|
|
2455
|
+
const raw = String(params.repo).slice(1);
|
|
2456
|
+
const slash = raw.indexOf('/');
|
|
2457
|
+
const groupName = (slash === -1 ? raw : raw.slice(0, slash)).trim();
|
|
2458
|
+
const memberRest = slash === -1 ? undefined : raw.slice(slash + 1).trim() || undefined;
|
|
2459
|
+
const resolved = await resolveAtGroupMemberRepoPath(groupName, memberRest);
|
|
2460
|
+
if (resolved.ok === false)
|
|
2461
|
+
return { error: resolved.error };
|
|
2462
|
+
const svc = this.getGroupService();
|
|
2463
|
+
if (method === 'impact') {
|
|
2464
|
+
const impactArgs = {
|
|
2465
|
+
name: groupName,
|
|
2466
|
+
repo: resolved.repoPath,
|
|
2467
|
+
target: params.target,
|
|
2468
|
+
direction: params.direction,
|
|
2469
|
+
};
|
|
2470
|
+
if (params.maxDepth !== undefined)
|
|
2471
|
+
impactArgs.maxDepth = params.maxDepth;
|
|
2472
|
+
if (params.crossDepth !== undefined)
|
|
2473
|
+
impactArgs.crossDepth = params.crossDepth;
|
|
2474
|
+
if (params.relationTypes !== undefined)
|
|
2475
|
+
impactArgs.relationTypes = params.relationTypes;
|
|
2476
|
+
if (params.includeTests !== undefined)
|
|
2477
|
+
impactArgs.includeTests = params.includeTests;
|
|
2478
|
+
if (params.minConfidence !== undefined)
|
|
2479
|
+
impactArgs.minConfidence = params.minConfidence;
|
|
2480
|
+
if (params.service !== undefined && params.service !== null)
|
|
2481
|
+
impactArgs.service = params.service;
|
|
2482
|
+
if (typeof params.subgroup === 'string')
|
|
2483
|
+
impactArgs.subgroup = params.subgroup;
|
|
2484
|
+
if (params.timeoutMs !== undefined)
|
|
2485
|
+
impactArgs.timeoutMs = params.timeoutMs;
|
|
2486
|
+
if (params.timeout !== undefined)
|
|
2487
|
+
impactArgs.timeout = params.timeout;
|
|
2488
|
+
return svc.groupImpact(impactArgs);
|
|
2489
|
+
}
|
|
2490
|
+
if (method === 'query') {
|
|
2491
|
+
const queryArgs = {
|
|
2492
|
+
name: groupName,
|
|
2493
|
+
query: params.query,
|
|
2494
|
+
};
|
|
2495
|
+
if (typeof params.task_context === 'string')
|
|
2496
|
+
queryArgs.task_context = params.task_context;
|
|
2497
|
+
if (typeof params.goal === 'string')
|
|
2498
|
+
queryArgs.goal = params.goal;
|
|
2499
|
+
if (typeof params.limit === 'number')
|
|
2500
|
+
queryArgs.limit = params.limit;
|
|
2501
|
+
if (typeof params.max_symbols === 'number')
|
|
2502
|
+
queryArgs.max_symbols = params.max_symbols;
|
|
2503
|
+
if (params.include_content !== undefined)
|
|
2504
|
+
queryArgs.include_content = params.include_content;
|
|
2505
|
+
if (params.service !== undefined && params.service !== null)
|
|
2506
|
+
queryArgs.service = params.service;
|
|
2507
|
+
if (memberRest !== undefined) {
|
|
2508
|
+
queryArgs.subgroup = memberRest;
|
|
2509
|
+
queryArgs.subgroupExact = true;
|
|
2510
|
+
}
|
|
2511
|
+
return svc.groupQuery(queryArgs);
|
|
2512
|
+
}
|
|
2513
|
+
if (method === 'context') {
|
|
2514
|
+
const targetSym = typeof params.target === 'string' && params.target.trim() !== ''
|
|
2515
|
+
? params.target.trim()
|
|
2516
|
+
: typeof params.name === 'string' && params.name.trim() !== ''
|
|
2517
|
+
? params.name.trim()
|
|
2518
|
+
: undefined;
|
|
2519
|
+
const contextArgs = {
|
|
2520
|
+
name: groupName,
|
|
2521
|
+
target: targetSym,
|
|
2522
|
+
};
|
|
2523
|
+
if (typeof params.uid === 'string')
|
|
2524
|
+
contextArgs.uid = params.uid;
|
|
2525
|
+
if (typeof params.file_path === 'string')
|
|
2526
|
+
contextArgs.file_path = params.file_path;
|
|
2527
|
+
if (params.include_content !== undefined)
|
|
2528
|
+
contextArgs.include_content = params.include_content;
|
|
2529
|
+
if (params.service !== undefined && params.service !== null)
|
|
2530
|
+
contextArgs.service = params.service;
|
|
2531
|
+
if (memberRest !== undefined) {
|
|
2532
|
+
contextArgs.subgroup = memberRest;
|
|
2533
|
+
contextArgs.subgroupExact = true;
|
|
2534
|
+
}
|
|
2535
|
+
return svc.groupContext(contextArgs);
|
|
2536
|
+
}
|
|
2537
|
+
throw new Error(`Internal: unsupported group-repo tool ${method}`);
|
|
2538
|
+
}
|
|
2306
2539
|
async groupList(params) {
|
|
2307
2540
|
return this.getGroupService().groupList(params);
|
|
2308
2541
|
}
|
|
2309
2542
|
async groupSync(params) {
|
|
2310
2543
|
return this.getGroupService().groupSync(params);
|
|
2311
2544
|
}
|
|
2312
|
-
|
|
2313
|
-
|
|
2545
|
+
/**
|
|
2546
|
+
* MCP resource body for `gitnexus://group/{name}/contracts` (Issue #794).
|
|
2547
|
+
*/
|
|
2548
|
+
async readGroupContractsResource(groupName, filter) {
|
|
2549
|
+
try {
|
|
2550
|
+
const params = { name: groupName };
|
|
2551
|
+
if (filter.type !== undefined)
|
|
2552
|
+
params.type = filter.type;
|
|
2553
|
+
if (filter.repo !== undefined)
|
|
2554
|
+
params.repo = filter.repo;
|
|
2555
|
+
if (filter.unmatchedOnly === true)
|
|
2556
|
+
params.unmatchedOnly = true;
|
|
2557
|
+
const raw = await this.getGroupService().groupContracts(params);
|
|
2558
|
+
return LocalBackend.formatGroupResourcePayload(raw);
|
|
2559
|
+
}
|
|
2560
|
+
catch (e) {
|
|
2561
|
+
return `error: ${e instanceof Error ? e.message : String(e)}`;
|
|
2562
|
+
}
|
|
2314
2563
|
}
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2564
|
+
/**
|
|
2565
|
+
* MCP resource body for `gitnexus://group/{name}/status` (Issue #794).
|
|
2566
|
+
*/
|
|
2567
|
+
async readGroupStatusResource(groupName) {
|
|
2568
|
+
try {
|
|
2569
|
+
const raw = await this.getGroupService().groupStatus({ name: groupName });
|
|
2570
|
+
return LocalBackend.formatGroupResourcePayload(raw);
|
|
2571
|
+
}
|
|
2572
|
+
catch (e) {
|
|
2573
|
+
return `error: ${e instanceof Error ? e.message : String(e)}`;
|
|
2574
|
+
}
|
|
2318
2575
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2576
|
+
static formatGroupResourcePayload(raw) {
|
|
2577
|
+
if (raw && typeof raw === 'object' && 'error' in raw) {
|
|
2578
|
+
const err = raw.error;
|
|
2579
|
+
if (typeof err === 'string' && err.length > 0) {
|
|
2580
|
+
return `error: ${err}`;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
return JSON.stringify(raw, null, 2);
|
|
2322
2584
|
}
|
|
2323
2585
|
/**
|
|
2324
2586
|
* Fetch Route nodes with their consumers in a single query.
|
package/dist/mcp/resources.d.ts
CHANGED
|
@@ -25,6 +25,37 @@ export declare function getResourceDefinitions(): ResourceDefinition[];
|
|
|
25
25
|
* Dynamic resource templates
|
|
26
26
|
*/
|
|
27
27
|
export declare function getResourceTemplates(): ResourceTemplate[];
|
|
28
|
+
/** Query parameters for `gitnexus://group/{name}/contracts` */
|
|
29
|
+
export type GroupContractsResourceFilter = {
|
|
30
|
+
type?: string;
|
|
31
|
+
repo?: string;
|
|
32
|
+
unmatchedOnly?: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** Normalized parse result for GitNexus MCP resource URIs */
|
|
35
|
+
export type ParsedGitnexusResource = {
|
|
36
|
+
kind: 'repos';
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'setup';
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'repo';
|
|
41
|
+
repoName: string;
|
|
42
|
+
resourceType: string;
|
|
43
|
+
param?: string;
|
|
44
|
+
} | {
|
|
45
|
+
kind: 'group';
|
|
46
|
+
groupName: string;
|
|
47
|
+
resourceType: 'contracts';
|
|
48
|
+
contractsFilter: GroupContractsResourceFilter;
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'group';
|
|
51
|
+
groupName: string;
|
|
52
|
+
resourceType: 'status';
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Parse a GitNexus resource URI (repos, setup, per-repo, or per-group templates).
|
|
56
|
+
* Used by `readResource` and tests (round-trip / dispatch coverage).
|
|
57
|
+
*/
|
|
58
|
+
export declare function parseResourceUri(uri: string): ParsedGitnexusResource;
|
|
28
59
|
/**
|
|
29
60
|
* Read a resource and return its content
|
|
30
61
|
*/
|