gitnexus 1.6.7-rc.9 → 1.6.8-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/eval-server.d.ts +5 -1
  3. package/dist/cli/eval-server.js +16 -4
  4. package/dist/mcp/local/local-backend.d.ts +84 -17
  5. package/dist/mcp/local/local-backend.js +87 -1
  6. package/dist/mcp/server.js +1 -1
  7. package/dist/mcp/tools.d.ts +10 -0
  8. package/dist/mcp/tools.js +29 -3
  9. package/package.json +1 -1
  10. package/skills/gitnexus-guide.md +32 -1
  11. package/vendor/tree-sitter-c/prebuilds/SHA256SUMS +6 -0
  12. package/vendor/tree-sitter-c/prebuilds/darwin-arm64/tree-sitter-c.node +0 -0
  13. package/vendor/tree-sitter-c/prebuilds/darwin-x64/tree-sitter-c.node +0 -0
  14. package/vendor/tree-sitter-c/prebuilds/linux-arm64/tree-sitter-c.node +0 -0
  15. package/vendor/tree-sitter-c/prebuilds/linux-x64/tree-sitter-c.node +0 -0
  16. package/vendor/tree-sitter-c/prebuilds/win32-arm64/tree-sitter-c.node +0 -0
  17. package/vendor/tree-sitter-c/prebuilds/win32-x64/tree-sitter-c.node +0 -0
  18. package/vendor/tree-sitter-dart/prebuilds/SHA256SUMS +6 -0
  19. package/vendor/tree-sitter-dart/prebuilds/darwin-arm64/tree-sitter-dart.node +0 -0
  20. package/vendor/tree-sitter-dart/prebuilds/darwin-x64/tree-sitter-dart.node +0 -0
  21. package/vendor/tree-sitter-dart/prebuilds/linux-arm64/tree-sitter-dart.node +0 -0
  22. package/vendor/tree-sitter-dart/prebuilds/linux-x64/tree-sitter-dart.node +0 -0
  23. package/vendor/tree-sitter-dart/prebuilds/win32-arm64/tree-sitter-dart.node +0 -0
  24. package/vendor/tree-sitter-dart/prebuilds/win32-x64/tree-sitter-dart.node +0 -0
  25. package/vendor/tree-sitter-kotlin/prebuilds/SHA256SUMS +6 -0
  26. package/vendor/tree-sitter-kotlin/prebuilds/darwin-arm64/tree-sitter-kotlin.node +0 -0
  27. package/vendor/tree-sitter-kotlin/prebuilds/darwin-x64/tree-sitter-kotlin.node +0 -0
  28. package/vendor/tree-sitter-kotlin/prebuilds/linux-arm64/tree-sitter-kotlin.node +0 -0
  29. package/vendor/tree-sitter-kotlin/prebuilds/linux-x64/tree-sitter-kotlin.node +0 -0
  30. package/vendor/tree-sitter-kotlin/prebuilds/win32-arm64/tree-sitter-kotlin.node +0 -0
  31. package/vendor/tree-sitter-kotlin/prebuilds/win32-x64/tree-sitter-kotlin.node +0 -0
  32. package/vendor/tree-sitter-proto/prebuilds/SHA256SUMS +6 -0
  33. package/vendor/tree-sitter-proto/prebuilds/darwin-arm64/tree-sitter-proto.node +0 -0
  34. package/vendor/tree-sitter-proto/prebuilds/darwin-x64/tree-sitter-proto.node +0 -0
  35. package/vendor/tree-sitter-proto/prebuilds/linux-arm64/tree-sitter-proto.node +0 -0
  36. package/vendor/tree-sitter-proto/prebuilds/linux-x64/tree-sitter-proto.node +0 -0
  37. package/vendor/tree-sitter-proto/prebuilds/win32-arm64/tree-sitter-proto.node +0 -0
  38. package/vendor/tree-sitter-proto/prebuilds/win32-x64/tree-sitter-proto.node +0 -0
  39. package/vendor/tree-sitter-swift/prebuilds/SHA256SUMS +6 -0
  40. package/vendor/tree-sitter-swift/prebuilds/darwin-arm64/tree-sitter-swift.node +0 -0
  41. package/vendor/tree-sitter-swift/prebuilds/darwin-x64/tree-sitter-swift.node +0 -0
  42. package/vendor/tree-sitter-swift/prebuilds/linux-arm64/tree-sitter-swift.node +0 -0
  43. package/vendor/tree-sitter-swift/prebuilds/linux-x64/tree-sitter-swift.node +0 -0
  44. package/vendor/tree-sitter-swift/prebuilds/win32-arm64/tree-sitter-swift.node +0 -0
  45. package/vendor/tree-sitter-swift/prebuilds/win32-x64/tree-sitter-swift.node +0 -0
package/README.md CHANGED
@@ -126,7 +126,7 @@ Your AI agent gets these tools automatically:
126
126
 
127
127
  | Tool | What It Does | `repo` Param |
128
128
  | ---------------- | ---------------------------------------------------------------- | ------------ |
129
- | `list_repos` | Discover all indexed repositories | — |
129
+ | `list_repos` | Discover all indexed repositories (paginated — `limit`/`offset`) | — |
130
130
  | `query` | Process-grouped hybrid search (BM25 + semantic + RRF) | Optional |
131
131
  | `context` | 360-degree symbol view — categorized refs, process participation | Optional |
132
132
  | `impact` | Blast radius analysis with depth grouping and confidence | Optional |
@@ -28,6 +28,7 @@
28
28
  * GET /health — Health check. Returns {"status":"ok","repos":[...]}
29
29
  * POST /shutdown — Graceful shutdown.
30
30
  */
31
+ import { type RepoListing, type ListReposPagination } from '../mcp/local/local-backend.js';
31
32
  export { formatDetectChangesResult } from './detect-changes-format.js';
32
33
  export interface EvalServerOptions {
33
34
  port?: string;
@@ -45,6 +46,9 @@ export declare function formatQueryResult(result: any): string;
45
46
  export declare function formatContextResult(result: any): string;
46
47
  export declare function formatImpactResult(result: any): string;
47
48
  export declare function formatCypherResult(result: any): string;
48
- export declare function formatListReposResult(result: any): string;
49
+ export declare function formatListReposResult(result: {
50
+ repositories: RepoListing[];
51
+ pagination?: ListReposPagination;
52
+ }): string;
49
53
  export declare function evalServerCommand(options?: EvalServerOptions): Promise<void>;
50
54
  export declare const MAX_BODY_SIZE: number;
@@ -31,7 +31,7 @@
31
31
  import http from 'http';
32
32
  import { isIPv4, isIPv6 } from 'node:net';
33
33
  import { writeSync } from 'node:fs';
34
- import { LocalBackend } from '../mcp/local/local-backend.js';
34
+ import { LocalBackend, } from '../mcp/local/local-backend.js';
35
35
  import { logger } from '../core/logger.js';
36
36
  import { cliInfo, cliWarn, cliError } from './cli-message.js';
37
37
  import { formatDetectChangesResult } from './detect-changes-format.js';
@@ -228,16 +228,26 @@ export function formatCypherResult(result) {
228
228
  return typeof result === 'string' ? result : JSON.stringify(result, null, 2);
229
229
  }
230
230
  export function formatListReposResult(result) {
231
- if (!Array.isArray(result) || result.length === 0) {
232
- return 'No indexed repositories.';
231
+ // `list_repos` always returns the paginated { repositories, pagination } object (#2119).
232
+ const repos = result.repositories;
233
+ const pg = result.pagination;
234
+ if (repos.length === 0) {
235
+ return pg && pg.total > 0
236
+ ? `No repositories on this page (offset ${pg.offset} of ${pg.total} total).`
237
+ : 'No indexed repositories.';
233
238
  }
234
239
  const lines = ['Indexed repositories:\n'];
235
- for (const r of result) {
240
+ for (const r of repos) {
236
241
  const stats = r.stats || {};
237
242
  lines.push(` ${r.name} — ${stats.nodes || '?'} symbols, ${stats.edges || '?'} relationships, ${stats.processes || '?'} flows`);
238
243
  lines.push(` Path: ${r.path}`);
239
244
  lines.push(` Indexed: ${r.indexedAt}`);
240
245
  }
246
+ if (pg) {
247
+ lines.push('');
248
+ lines.push(` Showing ${repos.length} of ${pg.total} (offset ${pg.offset}).` +
249
+ (pg.hasMore ? ` More available — re-run with offset ${pg.nextOffset}.` : ''));
250
+ }
241
251
  return lines.join('\n');
242
252
  }
243
253
  /**
@@ -276,6 +286,8 @@ function getNextStepHint(toolName) {
276
286
  return '\n---\nNext: To explore a result symbol in depth, run gitnexus-context "<name>"';
277
287
  case 'detect_changes':
278
288
  return '\n---\nNext: Run gitnexus-context "<symbol>" on high-risk changed symbols to check their callers.';
289
+ case 'list_repos':
290
+ return '\n---\nNext: READ gitnexus://repo/{name}/context for a repo above. If pagination.hasMore is true, re-run list_repos with offset set to pagination.nextOffset to page through the rest.';
279
291
  default:
280
292
  return '';
281
293
  }
@@ -86,6 +86,67 @@ export declare function resolveWorktreeCwd(repoPath: string, launchCwd: string):
86
86
  * (#2054).
87
87
  */
88
88
  export declare const REPO_ID_HASH_LENGTH = 6;
89
+ /**
90
+ * One repository entry as returned by {@link LocalBackend.listRepos} and in each
91
+ * `list_repos` page. Named so the `listRepos`/`listReposPage` return types read
92
+ * clearly instead of an opaque `Awaited<ReturnType<…>>` expression.
93
+ */
94
+ export interface RepoListing {
95
+ name: string;
96
+ path: string;
97
+ indexedAt: string;
98
+ lastCommit: string;
99
+ remoteUrl?: string;
100
+ stats?: any;
101
+ staleness?: {
102
+ commitsBehind: number;
103
+ hint?: string;
104
+ };
105
+ siblings?: Array<{
106
+ name: string;
107
+ path: string;
108
+ lastCommit: string;
109
+ }>;
110
+ }
111
+ /** Continuation metadata for the paginated `list_repos` MCP tool (#2119). */
112
+ export interface ListReposPagination {
113
+ /** Total repositories across all pages. */
114
+ total: number;
115
+ /** Effective page size used (equals the requested limit; out-of-range is rejected, not clamped). */
116
+ limit: number;
117
+ /** Offset this page started at. */
118
+ offset: number;
119
+ /** Number of repositories actually returned in this page. */
120
+ returned: number;
121
+ /** True when more repositories remain past this page. */
122
+ hasMore: boolean;
123
+ /** Offset to request next; present only when `hasMore` is true. */
124
+ nextOffset?: number;
125
+ }
126
+ /**
127
+ * Validate and normalise `list_repos` pagination arguments.
128
+ *
129
+ * @internal Exported for unit testing; not part of the public API surface.
130
+ *
131
+ * There is NO MCP-SDK-level enforcement of a tool's advertised `inputSchema`
132
+ * (the SDK validates only the JSON-RPC envelope), and `callTool` is reachable
133
+ * directly, so the backend is the real validation boundary. Malformed values —
134
+ * non-number, `NaN`, non-integer, `limit < 1`, `limit > maxLimit`, or
135
+ * `offset < 0` — are REJECTED with a clear error. `limit` is bounded but NOT
136
+ * silently clamped: an over-max value throws (symmetric with the other bounds)
137
+ * so a client never receives a smaller page than it asked for without knowing.
138
+ * An omitted value (only `undefined`) falls back to the default.
139
+ */
140
+ export declare function parseListReposPagination(params: {
141
+ limit?: unknown;
142
+ offset?: unknown;
143
+ } | null | undefined, opts: {
144
+ defaultLimit: number;
145
+ maxLimit: number;
146
+ }): {
147
+ limit: number;
148
+ offset: number;
149
+ };
89
150
  export declare class LocalBackend {
90
151
  private repos;
91
152
  private contextCache;
@@ -198,23 +259,29 @@ export declare class LocalBackend {
198
259
  * that another clone of the same logical repo is registered).
199
260
  * - `remoteUrl`: the canonical origin URL recorded at index time.
200
261
  */
201
- listRepos(): Promise<Array<{
202
- name: string;
203
- path: string;
204
- indexedAt: string;
205
- lastCommit: string;
206
- remoteUrl?: string;
207
- stats?: any;
208
- staleness?: {
209
- commitsBehind: number;
210
- hint?: string;
211
- };
212
- siblings?: Array<{
213
- name: string;
214
- path: string;
215
- lastCommit: string;
216
- }>;
217
- }>>;
262
+ listRepos(): Promise<RepoListing[]>;
263
+ /**
264
+ * Paginated view over {@link listRepos} for the `list_repos` MCP tool (#2119).
265
+ *
266
+ * `listRepos()` itself still returns the FULL array — its resource and CLI
267
+ * consumers (`gitnexus://repos`, `gitnexus://setup`, startup logs) need every
268
+ * entry, so pagination lives ONLY here, on the tool surface, to keep the
269
+ * response under MCP/LLM token-truncation limits.
270
+ *
271
+ * Determinism: a single registry snapshot is taken per call, then sorted by
272
+ * lower-cased name with the repository path as a tie-breaker. Sibling clones
273
+ * share a name but never a path (#2054), so `(name, path)` is a total order —
274
+ * paging never skips or duplicates an entry while the registry is unchanged.
275
+ * Codepoint comparison (not `localeCompare`) keeps page boundaries stable
276
+ * across machines/locales, matching the existing `refreshRepos` ordering.
277
+ */
278
+ listReposPage(params?: {
279
+ limit?: unknown;
280
+ offset?: unknown;
281
+ } | null): Promise<{
282
+ repositories: RepoListing[];
283
+ pagination: ListReposPagination;
284
+ }>;
218
285
  /**
219
286
  * Best-effort sibling-clone drift warning.
220
287
  *
@@ -27,6 +27,7 @@ import { getExactScanLimit, isVectorExtensionSupportedByPlatform, } from '../../
27
27
  import { PhaseTimer } from '../../core/search/phase-timer.js';
28
28
  import { checkStalenessAsync, checkCwdMatch } from '../../core/git-staleness.js';
29
29
  import { logger } from '../../core/logger.js';
30
+ import { LIST_REPOS_DEFAULT_LIMIT, LIST_REPOS_MAX_LIMIT } from '../tools.js';
30
31
  // AI context generation is CLI-only (gitnexus analyze)
31
32
  // import { generateAIContextFiles } from '../../cli/ai-context.js';
32
33
  /**
@@ -272,6 +273,42 @@ export function resolveWorktreeCwd(repoPath, launchCwd) {
272
273
  * (#2054).
273
274
  */
274
275
  export const REPO_ID_HASH_LENGTH = 6;
276
+ /**
277
+ * Validate and normalise `list_repos` pagination arguments.
278
+ *
279
+ * @internal Exported for unit testing; not part of the public API surface.
280
+ *
281
+ * There is NO MCP-SDK-level enforcement of a tool's advertised `inputSchema`
282
+ * (the SDK validates only the JSON-RPC envelope), and `callTool` is reachable
283
+ * directly, so the backend is the real validation boundary. Malformed values —
284
+ * non-number, `NaN`, non-integer, `limit < 1`, `limit > maxLimit`, or
285
+ * `offset < 0` — are REJECTED with a clear error. `limit` is bounded but NOT
286
+ * silently clamped: an over-max value throws (symmetric with the other bounds)
287
+ * so a client never receives a smaller page than it asked for without knowing.
288
+ * An omitted value (only `undefined`) falls back to the default.
289
+ */
290
+ export function parseListReposPagination(params, opts) {
291
+ const requireInt = (value, field, min, max) => {
292
+ const valid = typeof value === 'number' &&
293
+ Number.isInteger(value) &&
294
+ value >= min &&
295
+ (max === undefined || value <= max);
296
+ if (!valid) {
297
+ const bound = max === undefined ? `>= ${min}` : `between ${min} and ${max}`;
298
+ throw new Error(`list_repos: "${field}" must be an integer ${bound} (received ${JSON.stringify(value)})`);
299
+ }
300
+ return value;
301
+ };
302
+ let limit = opts.defaultLimit;
303
+ if (params?.limit !== undefined) {
304
+ limit = requireInt(params.limit, 'limit', 1, opts.maxLimit);
305
+ }
306
+ let offset = 0;
307
+ if (params?.offset !== undefined) {
308
+ offset = requireInt(params.offset, 'offset', 0);
309
+ }
310
+ return { limit, offset };
311
+ }
275
312
  export class LocalBackend {
276
313
  repos = new Map();
277
314
  contextCache = new Map();
@@ -758,6 +795,52 @@ export class LocalBackend {
758
795
  };
759
796
  });
760
797
  }
798
+ /**
799
+ * Paginated view over {@link listRepos} for the `list_repos` MCP tool (#2119).
800
+ *
801
+ * `listRepos()` itself still returns the FULL array — its resource and CLI
802
+ * consumers (`gitnexus://repos`, `gitnexus://setup`, startup logs) need every
803
+ * entry, so pagination lives ONLY here, on the tool surface, to keep the
804
+ * response under MCP/LLM token-truncation limits.
805
+ *
806
+ * Determinism: a single registry snapshot is taken per call, then sorted by
807
+ * lower-cased name with the repository path as a tie-breaker. Sibling clones
808
+ * share a name but never a path (#2054), so `(name, path)` is a total order —
809
+ * paging never skips or duplicates an entry while the registry is unchanged.
810
+ * Codepoint comparison (not `localeCompare`) keeps page boundaries stable
811
+ * across machines/locales, matching the existing `refreshRepos` ordering.
812
+ */
813
+ async listReposPage(params) {
814
+ const { limit, offset } = parseListReposPagination(params, {
815
+ defaultLimit: LIST_REPOS_DEFAULT_LIMIT,
816
+ maxLimit: LIST_REPOS_MAX_LIMIT,
817
+ });
818
+ // One consistent snapshot per call (listRepos refreshes the registry once),
819
+ // sorted into a stable total order before slicing.
820
+ const all = await this.listRepos();
821
+ all.sort((a, b) => {
822
+ const an = a.name.toLowerCase();
823
+ const bn = b.name.toLowerCase();
824
+ if (an !== bn)
825
+ return an < bn ? -1 : 1;
826
+ return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
827
+ });
828
+ const total = all.length;
829
+ const repositories = all.slice(offset, offset + limit);
830
+ const returned = repositories.length;
831
+ const hasMore = offset + returned < total;
832
+ return {
833
+ repositories,
834
+ pagination: {
835
+ total,
836
+ limit,
837
+ offset,
838
+ returned,
839
+ hasMore,
840
+ ...(hasMore && { nextOffset: offset + returned }),
841
+ },
842
+ };
843
+ }
761
844
  /**
762
845
  * Best-effort sibling-clone drift warning.
763
846
  *
@@ -816,7 +899,10 @@ export class LocalBackend {
816
899
  // ─── Tool Dispatch ───────────────────────────────────────────────
817
900
  async callTool(method, params) {
818
901
  if (method === 'list_repos') {
819
- return this.listRepos();
902
+ // Paginated tool surface (#2119). `listRepos()` is unchanged for internal
903
+ // callers; the tool wraps it in { repositories, pagination } and forwards
904
+ // the limit/offset args that this dispatch previously discarded.
905
+ return this.listReposPage(params);
820
906
  }
821
907
  if (method.startsWith('group_')) {
822
908
  return this.handleGroupTool(method, params || {});
@@ -32,7 +32,7 @@ function getNextStepHint(toolName, args) {
32
32
  const repoPath = repo || '{name}';
33
33
  switch (toolName) {
34
34
  case 'list_repos':
35
- return `\n\n---\n**Next:** READ gitnexus://repo/{name}/context for any repo above to get its overview and check staleness.`;
35
+ return `\n\n---\n**Next:** READ gitnexus://repo/{name}/context for any repo above to get its overview and check staleness. If pagination.hasMore is true, call list_repos again with offset set to pagination.nextOffset to fetch the rest.`;
36
36
  case 'query':
37
37
  return `\n\n---\n**Next:** To understand a specific symbol in depth, use context({name: "<symbol_name>"${repoParam}}) to see categorized refs and process participation.`;
38
38
  case 'context':
@@ -26,4 +26,14 @@ export interface ToolDefinition {
26
26
  required: string[];
27
27
  };
28
28
  }
29
+ /**
30
+ * Pagination bounds for the `list_repos` tool. Exported so the backend
31
+ * validation (`local-backend.ts`) and the schema below stay a single source of
32
+ * truth. `list_repos` is paginated to keep its response under MCP/LLM token
33
+ * truncation limits when many repos are indexed (#2119); the default page is
34
+ * small enough to render safely, and `LIST_REPOS_MAX_LIMIT` caps how much a
35
+ * caller can pull in one request.
36
+ */
37
+ export declare const LIST_REPOS_DEFAULT_LIMIT = 50;
38
+ export declare const LIST_REPOS_MAX_LIMIT = 200;
29
39
  export declare const GITNEXUS_TOOLS: ToolDefinition[];
package/dist/mcp/tools.js CHANGED
@@ -22,12 +22,24 @@ const DESTRUCTIVE_TOOL_ANNOTATIONS = {
22
22
  idempotentHint: false,
23
23
  openWorldHint: false,
24
24
  };
25
+ /**
26
+ * Pagination bounds for the `list_repos` tool. Exported so the backend
27
+ * validation (`local-backend.ts`) and the schema below stay a single source of
28
+ * truth. `list_repos` is paginated to keep its response under MCP/LLM token
29
+ * truncation limits when many repos are indexed (#2119); the default page is
30
+ * small enough to render safely, and `LIST_REPOS_MAX_LIMIT` caps how much a
31
+ * caller can pull in one request.
32
+ */
33
+ export const LIST_REPOS_DEFAULT_LIMIT = 50;
34
+ export const LIST_REPOS_MAX_LIMIT = 200;
25
35
  export const GITNEXUS_TOOLS = [
26
36
  {
27
37
  name: 'list_repos',
28
- description: `List all indexed repositories available to GitNexus.
38
+ description: `List indexed repositories available to GitNexus (paginated).
29
39
 
30
- Returns each repo's name, path, indexed date, last commit, and stats.
40
+ Returns a page of repositories — each with name, path, indexed date, last commit, and stats — plus a "pagination" object: { total, limit, offset, returned, hasMore, nextOffset }.
41
+
42
+ PAGINATION: Results are paginated so a large registry is not truncated by MCP/LLM token limits. "limit" sets the page size (default ${LIST_REPOS_DEFAULT_LIMIT}, max ${LIST_REPOS_MAX_LIMIT}; values above the max are rejected, not capped). "offset" selects the start. To enumerate EVERY repository: when pagination.hasMore is true, call list_repos again with offset set to pagination.nextOffset, and repeat until hasMore is false. Repositories are returned in a stable order, so paging never skips or duplicates an entry while the registry is unchanged.
31
43
 
32
44
  WHEN TO USE: First step when multiple repos are indexed, or to discover available repos.
33
45
  AFTER THIS: READ gitnexus://repo/{name}/context for the repo you want to work with.
@@ -37,7 +49,21 @@ on other tools (query, context, impact, etc.) to target the correct one.`,
37
49
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
38
50
  inputSchema: {
39
51
  type: 'object',
40
- properties: {},
52
+ properties: {
53
+ limit: {
54
+ type: 'integer',
55
+ description: `Max repositories to return in this page (default: ${LIST_REPOS_DEFAULT_LIMIT}, min: 1, max: ${LIST_REPOS_MAX_LIMIT}). Values outside [1, ${LIST_REPOS_MAX_LIMIT}] are rejected.`,
56
+ default: LIST_REPOS_DEFAULT_LIMIT,
57
+ minimum: 1,
58
+ maximum: LIST_REPOS_MAX_LIMIT,
59
+ },
60
+ offset: {
61
+ type: 'integer',
62
+ description: 'Number of repositories to skip before this page (default: 0). Pass pagination.nextOffset from the previous response to fetch the next page.',
63
+ default: 0,
64
+ minimum: 0,
65
+ },
66
+ },
41
67
  required: [],
42
68
  },
43
69
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.7-rc.9",
3
+ "version": "1.6.8-rc.1",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",
@@ -38,7 +38,38 @@ For any task involving code understanding, debugging, impact analysis, or refact
38
38
  | `detect_changes` | Git-diff impact — what do your current changes affect |
39
39
  | `rename` | Multi-file coordinated rename with confidence-tagged edits |
40
40
  | `cypher` | Raw graph queries (read `gitnexus://repo/{name}/schema` first) |
41
- | `list_repos` | Discover indexed repos |
41
+ | `list_repos` | Discover indexed repos (paginated — `limit`/`offset`) |
42
+
43
+ ### Paginating `list_repos`
44
+
45
+ `list_repos` is paginated so a large registry is not truncated by MCP/LLM token limits. It takes optional `limit` (default **50**, max **200**) and `offset`, and returns:
46
+
47
+ ```jsonc
48
+ {
49
+ "repositories": [
50
+ { "name": "...", "path": "...", "indexedAt": "...", "lastCommit": "...", "stats": { } }
51
+ ],
52
+ "pagination": {
53
+ "total": 437,
54
+ "limit": 50,
55
+ "offset": 0,
56
+ "returned": 50,
57
+ "hasMore": true,
58
+ "nextOffset": 50
59
+ }
60
+ }
61
+ ```
62
+
63
+ To enumerate **every** repository, keep calling with `offset` set to `pagination.nextOffset` until `hasMore` is `false`:
64
+
65
+ ```text
66
+ list_repos {} → repos 1–50, nextOffset 50, hasMore true
67
+ list_repos { offset: 50 } → repos 51–100, nextOffset 100, hasMore true
68
+
69
+ list_repos { offset: 400 } → repos 401–437, hasMore false (done)
70
+ ```
71
+
72
+ Notes: `offset` ≥ `total` returns an empty page (with `total` still reported). Out-of-range or malformed `limit`/`offset` (non-integer, `limit` outside `[1, 200]`, `offset < 0`) are rejected with a clear error — `limit` above the max is rejected, not silently capped. The order is deterministic (lower-cased name, then path), so paging never skips or duplicates an entry while the registry is unchanged.
42
73
 
43
74
  ## Resources Reference
44
75
 
@@ -0,0 +1,6 @@
1
+ 0ef1ad3da01eacfbad1c83a4e6f39e5dfb563cb3ba663447ef563677e43f5802 ./darwin-arm64/tree-sitter-c.node
2
+ 5bea052ac3530f56c6c4849d7ad435469eb684a05fb641c4b1df5a0047a224b3 ./darwin-x64/tree-sitter-c.node
3
+ c0b20e0ddbbf7f15441bc09855892e0720623113dd24cbbb81f3f6fec800650e ./linux-arm64/tree-sitter-c.node
4
+ 85e912b183a49111b0f4c3a6c8908375732e70aca759ab0124501913cbbd942a ./linux-x64/tree-sitter-c.node
5
+ d15bd0478e24f6cedab5aea5b34a423b6918babb45fd81b6d05be740ac83f71e ./win32-arm64/tree-sitter-c.node
6
+ ce42c8f63ea0fbb21b36486c6aef8bd2208abb45cb478d1071bb44fda8d6558a ./win32-x64/tree-sitter-c.node
@@ -0,0 +1,6 @@
1
+ 423e36a7cc1e3186d5b5d34435916c9746883d3745de33be21ec0c9db19a0d0c ./darwin-arm64/tree-sitter-dart.node
2
+ da526be2e8c6caf0d6b5421c33a59ff0ffcba3609172bd0399bfe98abd1550f2 ./darwin-x64/tree-sitter-dart.node
3
+ 18ee4afbaaa883416ee671c551ba3c69b0dc7ff0bccc42463c9d8e32eea2e704 ./linux-arm64/tree-sitter-dart.node
4
+ 209d3949337ebc59b0f31b19333345e1a45c800f81808cf9f811a3b469166549 ./linux-x64/tree-sitter-dart.node
5
+ 535954d7ffe0b436551c9837be5cf5cf5d7b9cdb6a0d68dd9def2d154164cb51 ./win32-arm64/tree-sitter-dart.node
6
+ 0c3790d0d9e440c11ea90d9a48b308cef4fe0e1e1865243131e4c3e7dfe7e2ff ./win32-x64/tree-sitter-dart.node
@@ -0,0 +1,6 @@
1
+ 11e63706f960303259b842f98030bf7c5845f312ed9cfa1fcc44e6ff4c002841 ./darwin-arm64/tree-sitter-kotlin.node
2
+ e5cd10bf993a2d20f8187d39486e3cbcb0567ca192576fae745c70e8be43f223 ./darwin-x64/tree-sitter-kotlin.node
3
+ a73110ce49a421b4d09acfbbdbb05bc1d1a54b6c88017d2e59199144bb9c1853 ./linux-arm64/tree-sitter-kotlin.node
4
+ 7409baf83f363d15bdcbc09698acc9ca8e7e25ccb62eb6074e787166ff0bf9ef ./linux-x64/tree-sitter-kotlin.node
5
+ 1467a068fd28de07cd333e3e577ee2ccc34631780b7bd34b151c4c8118dddaf6 ./win32-arm64/tree-sitter-kotlin.node
6
+ c53bcf3c651e33d2778c83e9ef7cb7f18e547e1941132f6ade69d0717b9325eb ./win32-x64/tree-sitter-kotlin.node
@@ -0,0 +1,6 @@
1
+ dd9744a196fa560f1ec1c30110e3d023722c606dcb7cd4f4e07a2da68dc481e9 ./darwin-arm64/tree-sitter-proto.node
2
+ 82bf2b335e7f8197be98a126a0c982a71ffb4c25c6780cc41463d57986a4727e ./darwin-x64/tree-sitter-proto.node
3
+ ba65d25de1fd881def2cf85f473094d90a45612bfa763f4f97d2841b3d7d715e ./linux-arm64/tree-sitter-proto.node
4
+ dea80ed2fb48a6d19866468f652ec48eab5435306c6477b213eafe51cbbbf2ee ./linux-x64/tree-sitter-proto.node
5
+ f057563de539abd6ada73aa9097e5bd1849bd6c31d721e34c791bf0388bfa237 ./win32-arm64/tree-sitter-proto.node
6
+ 4269e6e073f22ed777400b6f4b553f51974c5d641c56374046bf5c0692f4c841 ./win32-x64/tree-sitter-proto.node
@@ -0,0 +1,6 @@
1
+ baffb118bb04eb3f2a3aea6e132a67f334323eec39fceb3420a04d4b31ac7544 ./darwin-arm64/tree-sitter-swift.node
2
+ b18b2b16c9ec26d4c43ad578fca3fdf1349dafbc5347fd897ff0b9e6c92927c0 ./darwin-x64/tree-sitter-swift.node
3
+ fed213320ee40a725f0b0728975ab9a472348f25b70ec1a0e9ff89e366849af5 ./linux-arm64/tree-sitter-swift.node
4
+ 9376099fff5847941bac216afa7142d7b3e98d8c2e5bc8c8c2de486693eeeaf6 ./linux-x64/tree-sitter-swift.node
5
+ 49300328ead166d005f5cf0065f21f6bfcacda570f2e026ce6886bad24f2004f ./win32-arm64/tree-sitter-swift.node
6
+ 16c146f30c74953832be37b7a65230d62ea1347a1be6e8ffa7e9bd120cf7f30f ./win32-x64/tree-sitter-swift.node