mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-30 01:51:20 +00:00
fix: restore @group repo routing and prune obsolete migration-message tests
Restored callToolAtGroupRepo method + import + dispatch block in LocalBackend.callTool — the @-routing path is required by both production code (CLI/MCP @groupName syntax) and the group-repo-routing tests that came in via the rebase from origin/main. Removed two test cases from gitnexus/test/unit/resources.test.ts that exercised readGroupContractsResource / readGroupStatusResource — those backend methods do not exist in this PR's design (group resources are served via the @-routing path, not separate MCP resource readers). Removed three test cases from gitnexus/test/unit/mcp/group-repo-routing.test.ts that asserted group_contracts / group_status / unknown group_* tools throw a 'Removed tools' migration error. This PR explicitly reintroduces those tools as features, so the migration-removal assertions are obsolete.
This commit is contained in:
parent
fa115b8203
commit
e3784d519c
3 changed files with 96 additions and 35 deletions
|
|
@ -28,6 +28,7 @@ import {
|
|||
type RegistryEntry,
|
||||
} from '../../storage/repo-manager.js';
|
||||
import { GroupService, type GroupToolPort } from '../../core/group/service.js';
|
||||
import { resolveAtGroupMemberRepoPath } from '../../core/group/resolve-at-member.js';
|
||||
import { collectBestChunks } from '../../core/embeddings/types.js';
|
||||
import {
|
||||
rankExactEmbeddingRows,
|
||||
|
|
@ -639,6 +640,15 @@ export class LocalBackend {
|
|||
return this.handleGroupTool(method, params || {});
|
||||
}
|
||||
|
||||
const p = params && typeof params === 'object' ? (params as Record<string, unknown>) : {};
|
||||
if (
|
||||
(method === 'impact' || method === 'query' || method === 'context') &&
|
||||
typeof p.repo === 'string' &&
|
||||
p.repo.startsWith('@')
|
||||
) {
|
||||
return this.callToolAtGroupRepo(method, p);
|
||||
}
|
||||
|
||||
// Resolve repo from optional param (re-reads registry on miss)
|
||||
const repo = await this.resolveRepo((params as { repo?: string } | undefined)?.repo);
|
||||
|
||||
|
|
@ -3047,6 +3057,92 @@ export class LocalBackend {
|
|||
}
|
||||
}
|
||||
|
||||
private async callToolAtGroupRepo(
|
||||
method: string,
|
||||
params: Record<string, unknown>,
|
||||
): Promise<unknown> {
|
||||
await this.refreshRepos();
|
||||
|
||||
if (
|
||||
params.service !== undefined &&
|
||||
params.service !== null &&
|
||||
String(params.service).trim() === ''
|
||||
) {
|
||||
return { error: 'service must not be an empty string' };
|
||||
}
|
||||
|
||||
const raw = String(params.repo).slice(1);
|
||||
const slash = raw.indexOf('/');
|
||||
const groupName = (slash === -1 ? raw : raw.slice(0, slash)).trim();
|
||||
const memberRest = slash === -1 ? undefined : raw.slice(slash + 1).trim() || undefined;
|
||||
|
||||
const resolved = await resolveAtGroupMemberRepoPath(groupName, memberRest);
|
||||
if (resolved.ok === false) return { error: resolved.error };
|
||||
|
||||
const svc = this.getGroupService();
|
||||
if (method === 'impact') {
|
||||
const impactArgs: Record<string, unknown> = {
|
||||
name: groupName,
|
||||
repo: resolved.repoPath,
|
||||
target: params.target,
|
||||
direction: params.direction,
|
||||
};
|
||||
if (params.maxDepth !== undefined) impactArgs.maxDepth = params.maxDepth;
|
||||
if (params.crossDepth !== undefined) impactArgs.crossDepth = params.crossDepth;
|
||||
if (params.relationTypes !== undefined) impactArgs.relationTypes = params.relationTypes;
|
||||
if (params.includeTests !== undefined) impactArgs.includeTests = params.includeTests;
|
||||
if (params.minConfidence !== undefined) impactArgs.minConfidence = params.minConfidence;
|
||||
if (params.service !== undefined && params.service !== null)
|
||||
impactArgs.service = params.service;
|
||||
if (typeof params.subgroup === 'string') impactArgs.subgroup = params.subgroup;
|
||||
if (params.timeoutMs !== undefined) impactArgs.timeoutMs = params.timeoutMs;
|
||||
if (params.timeout !== undefined) impactArgs.timeout = params.timeout;
|
||||
return svc.groupImpact(impactArgs);
|
||||
}
|
||||
if (method === 'query') {
|
||||
const queryArgs: Record<string, unknown> = {
|
||||
name: groupName,
|
||||
query: params.query,
|
||||
};
|
||||
if (typeof params.task_context === 'string') queryArgs.task_context = params.task_context;
|
||||
if (typeof params.goal === 'string') queryArgs.goal = params.goal;
|
||||
if (typeof params.limit === 'number') queryArgs.limit = params.limit;
|
||||
if (typeof params.max_symbols === 'number') queryArgs.max_symbols = params.max_symbols;
|
||||
if (params.include_content !== undefined) queryArgs.include_content = params.include_content;
|
||||
if (params.service !== undefined && params.service !== null)
|
||||
queryArgs.service = params.service;
|
||||
if (memberRest !== undefined) {
|
||||
queryArgs.subgroup = memberRest;
|
||||
queryArgs.subgroupExact = true;
|
||||
}
|
||||
return svc.groupQuery(queryArgs);
|
||||
}
|
||||
if (method === 'context') {
|
||||
const targetSym =
|
||||
typeof params.target === 'string' && params.target.trim() !== ''
|
||||
? params.target.trim()
|
||||
: typeof params.name === 'string' && params.name.trim() !== ''
|
||||
? params.name.trim()
|
||||
: undefined;
|
||||
const contextArgs: Record<string, unknown> = {
|
||||
name: groupName,
|
||||
target: targetSym,
|
||||
};
|
||||
if (typeof params.uid === 'string') contextArgs.uid = params.uid;
|
||||
if (typeof params.file_path === 'string') contextArgs.file_path = params.file_path;
|
||||
if (params.include_content !== undefined)
|
||||
contextArgs.include_content = params.include_content;
|
||||
if (params.service !== undefined && params.service !== null)
|
||||
contextArgs.service = params.service;
|
||||
if (memberRest !== undefined) {
|
||||
contextArgs.subgroup = memberRest;
|
||||
contextArgs.subgroupExact = true;
|
||||
}
|
||||
return svc.groupContext(contextArgs);
|
||||
}
|
||||
throw new Error(`Internal: unsupported group-repo tool ${method}`);
|
||||
}
|
||||
|
||||
private async groupQuery(params: Record<string, unknown>): Promise<unknown> {
|
||||
await this.refreshRepos();
|
||||
return this.getGroupService().groupQuery(params);
|
||||
|
|
|
|||
|
|
@ -162,25 +162,6 @@ repos:
|
|||
expect(groupSpyQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('unknown group_* tools mention removal', async () => {
|
||||
const backend = new LocalBackend();
|
||||
await expect(backend.callTool('group_query', { name: 'g1', query: 'x' })).rejects.toThrow(
|
||||
/Removed tools/,
|
||||
);
|
||||
});
|
||||
|
||||
it('removed group_contracts mentions migration', async () => {
|
||||
const backend = new LocalBackend();
|
||||
await expect(backend.callTool('group_contracts', { name: 'g1' })).rejects.toThrow(
|
||||
/Removed tools/,
|
||||
);
|
||||
});
|
||||
|
||||
it('removed group_status mentions migration', async () => {
|
||||
const backend = new LocalBackend();
|
||||
await expect(backend.callTool('group_status', { name: 'g1' })).rejects.toThrow(/Removed tools/);
|
||||
});
|
||||
|
||||
describe('Issue #794 manual smoke checklist (automated)', () => {
|
||||
beforeEach(() => {
|
||||
const groupDir = path.join(tmpDir, 'groups', 'myproduct');
|
||||
|
|
|
|||
|
|
@ -213,22 +213,6 @@ describe('readResource', () => {
|
|||
expect(result).toContain('No repositories indexed');
|
||||
});
|
||||
|
||||
it('routes group contracts resource through backend', async () => {
|
||||
const backend = createMockBackend();
|
||||
const uri = 'gitnexus://group/g1/contracts?type=http&unmatchedOnly=true';
|
||||
await readResource(uri, backend);
|
||||
expect(backend.readGroupContractsResource).toHaveBeenCalledWith('g1', {
|
||||
type: 'http',
|
||||
unmatchedOnly: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('routes group status resource through backend', async () => {
|
||||
const backend = createMockBackend();
|
||||
await readResource('gitnexus://group/acme/status', backend);
|
||||
expect(backend.readGroupStatusResource).toHaveBeenCalledWith('acme');
|
||||
});
|
||||
|
||||
it('routes gitnexus://repo/{name}/context correctly', async () => {
|
||||
const backend = createMockBackend({
|
||||
context: {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue