Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | 18x 18x 18x 18x 18x 20x 20x 19x 4x 4x 4x 4x 10x 10x 10x 10x 5x 5x 5x 5x 18x 1x 18x 4x 18x 3x 3x | import * as z from 'zod';
import { BrowseSearchSchema } from './schema-readonly';
import { ToolRegistry, EnhancedToolDefinition } from '../../types';
import { assertActionAllowed } from '../utils';
import { gitlab, paths, toQuery } from '../../utils/gitlab-api';
/**
* Search tools registry - 1 read-only CQRS tool
*
* browse_search (Query): global, project, group
*
* Search is read-only by design - no manage_search tool needed.
*/
export const searchToolRegistry: ToolRegistry = new Map<string, EnhancedToolDefinition>([
// ============================================================================
// browse_search - CQRS Query Tool (discriminated union schema)
// TypeScript automatically narrows types in each switch case
// ============================================================================
[
'browse_search',
{
name: 'browse_search',
description:
'Search across GitLab resources globally or within a scope. Actions: global (entire instance), project (within specific project), group (within specific group). Searchable: projects, issues, merge_requests, milestones, users, blobs (code), commits, wiki_blobs, notes.',
inputSchema: z.toJSONSchema(BrowseSearchSchema),
requirements: {
default: { tier: 'free', minVersion: '8.0' },
actions: {
group: { tier: 'free', minVersion: '10.5', notes: 'Group-scoped search' },
},
},
gate: { envVar: 'USE_SEARCH', defaultValue: true },
handler: async (args: unknown): Promise<unknown> => {
const input = BrowseSearchSchema.parse(args);
assertActionAllowed('browse_search', input.action);
switch (input.action) {
case 'global': {
// TypeScript knows: input has scope, search, and optional filters
const { scope, ...params } = input;
// Build query params excluding action (not an API parameter)
const query = toQuery(params, ['action']);
// Global search endpoint
const results = await gitlab.get<unknown[]>('search', {
query: { ...query, scope },
});
return {
scope,
count: results.length,
results,
};
}
case 'project': {
// TypeScript knows: input has project_id, scope, search, and optional filters
const { project_id, scope, ref, ...params } = input;
// Build query params excluding action (project_id, scope, ref are already destructured)
const query = toQuery(params, ['action']);
// Project-scoped search endpoint
const results = await gitlab.get<unknown[]>(`${paths.project(project_id)}/search`, {
query: { ...query, scope, ...(ref && { ref }) },
});
return {
project_id,
scope,
count: results.length,
results,
};
}
case 'group': {
// TypeScript knows: input has group_id, scope, search, and optional filters
const { group_id, scope, ...params } = input;
// Build query params excluding action (group_id, scope are already destructured)
const query = toQuery(params, ['action']);
// Group-scoped search endpoint
const results = await gitlab.get<unknown[]>(`${paths.group(group_id)}/search`, {
query: { ...query, scope },
});
return {
group_id,
scope,
count: results.length,
results,
};
}
/* istanbul ignore next -- unreachable with Zod discriminatedUnion */
default:
throw new Error(`Unknown action: ${(input as { action: string }).action}`);
}
},
},
],
]);
/**
* Get read-only tool names from the registry
* Search is entirely read-only, so all tools are read-only
*/
export function getSearchReadOnlyToolNames(): string[] {
return ['browse_search'];
}
/**
* Get all tool definitions from the registry
*/
export function getSearchToolDefinitions(): EnhancedToolDefinition[] {
return Array.from(searchToolRegistry.values());
}
/**
* Get filtered tools based on read-only mode
* Since search is read-only, this always returns all tools
*/
export function getFilteredSearchTools(readOnlyMode: boolean = false): EnhancedToolDefinition[] {
// Search is always read-only, so readOnlyMode doesn't affect filtering
void readOnlyMode;
return getSearchToolDefinitions();
}
|