codesift-mcp 0.8.11 → 0.8.15

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 (32) hide show
  1. package/dist/cli/hooks.d.ts.map +1 -1
  2. package/dist/cli/hooks.js +31 -2
  3. package/dist/cli/hooks.js.map +1 -1
  4. package/dist/cli/setup.d.ts.map +1 -1
  5. package/dist/cli/setup.js +77 -9
  6. package/dist/cli/setup.js.map +1 -1
  7. package/dist/register-tools.d.ts.map +1 -1
  8. package/dist/register-tools.js +90 -3
  9. package/dist/register-tools.js.map +1 -1
  10. package/dist/search/static-embedding-provider.d.ts.map +1 -1
  11. package/dist/search/static-embedding-provider.js +9 -1
  12. package/dist/search/static-embedding-provider.js.map +1 -1
  13. package/dist/storage/group-registry.d.ts +51 -0
  14. package/dist/storage/group-registry.d.ts.map +1 -0
  15. package/dist/storage/group-registry.js +263 -0
  16. package/dist/storage/group-registry.js.map +1 -0
  17. package/dist/tools/cross-repo-contract-tools.d.ts +137 -0
  18. package/dist/tools/cross-repo-contract-tools.d.ts.map +1 -0
  19. package/dist/tools/cross-repo-contract-tools.js +593 -0
  20. package/dist/tools/cross-repo-contract-tools.js.map +1 -0
  21. package/dist/tools/cross-repo-outbound-lexer.d.ts +35 -0
  22. package/dist/tools/cross-repo-outbound-lexer.d.ts.map +1 -0
  23. package/dist/tools/cross-repo-outbound-lexer.js +594 -0
  24. package/dist/tools/cross-repo-outbound-lexer.js.map +1 -0
  25. package/dist/tools/index-tools.d.ts.map +1 -1
  26. package/dist/tools/index-tools.js +4 -1
  27. package/dist/tools/index-tools.js.map +1 -1
  28. package/dist/tools/wiki-tools.d.ts +7 -0
  29. package/dist/tools/wiki-tools.d.ts.map +1 -1
  30. package/dist/tools/wiki-tools.js +33 -1
  31. package/dist/tools/wiki-tools.js.map +1 -1
  32. package/package.json +1 -1
@@ -0,0 +1,593 @@
1
+ /**
2
+ * Cross-repo contract adapters (Task 12) and outbound HTTP call extractor (Task 13).
3
+ *
4
+ * Normalises endpoint shapes from Hono, NestJS, and Next.js into the shared
5
+ * RepoEndpoint type so that the outbound extractor (T13) and matcher (T14)
6
+ * can work against a single canonical form.
7
+ *
8
+ * extractOutboundCalls: lexer-based consumer-side outbound HTTP call extractor.
9
+ * Supports fetch, axios.{get|post|put|patch|delete}, got.{get|post|put|patch|delete}.
10
+ * Uses a single-pass state-machine lexer (cross-repo-outbound-lexer.ts) so calls
11
+ * inside comments, string literals, template literals, and regex literals are never
12
+ * falsely reported.
13
+ */
14
+ import { findOutboundCalls } from "./cross-repo-outbound-lexer.js";
15
+ // ---------------------------------------------------------------------------
16
+ // Path normalisation
17
+ // ---------------------------------------------------------------------------
18
+ /**
19
+ * Replace all path-parameter segments with the canonical `{param}` placeholder.
20
+ *
21
+ * Recognised styles:
22
+ * - Express / Hono `:name`
23
+ * - OpenAPI / NestJS `{name}`
24
+ * - Next.js `[name]`
25
+ * - Next.js catch-all `[...name]`
26
+ *
27
+ * Trailing slashes are stripped (except for a bare "/").
28
+ * Method strings are UPPERCASED by callers; this function only handles paths.
29
+ */
30
+ export function normalizePathParams(path) {
31
+ // Replace :name segments
32
+ let result = path.replace(/:([^/]+)/g, "{param}");
33
+ // Replace {name} segments (already-braced OpenAPI style)
34
+ result = result.replace(/\{([^}]+)\}/g, "{param}");
35
+ // Replace [...name] and [name] Next.js segments
36
+ result = result.replace(/\[\.\.\.([^\]]+)\]/g, "{param}");
37
+ result = result.replace(/\[([^\]]+)\]/g, "{param}");
38
+ // Strip trailing slash (but keep bare "/")
39
+ if (result.length > 1 && result.endsWith("/")) {
40
+ result = result.slice(0, -1);
41
+ }
42
+ return result;
43
+ }
44
+ // ---------------------------------------------------------------------------
45
+ // Hono adapter
46
+ // ---------------------------------------------------------------------------
47
+ /**
48
+ * Adapt an `extractApiContract` result (Hono) into `RepoEndpoint[]`.
49
+ *
50
+ * Only the `summary` format carries the per-route list; `openapi` format and
51
+ * missing/undefined summary both return [].
52
+ */
53
+ export function adaptHonoContract(repo, r) {
54
+ if (!r.summary)
55
+ return [];
56
+ return r.summary.map((entry) => {
57
+ const method = entry.method.toUpperCase();
58
+ const normalized_path = normalizePathParams(entry.path);
59
+ return { repo, method, path: entry.path, normalized_path, file: entry.file };
60
+ });
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // NestJS adapter
64
+ // ---------------------------------------------------------------------------
65
+ /**
66
+ * Adapt a `nestRouteInventory` result into `RepoEndpoint[]`.
67
+ *
68
+ * `NestRouteEntry.file` is a required string field — the value is used as-is
69
+ * (may be "" for entries where the controller file couldn't be resolved).
70
+ */
71
+ export function adaptNestInventory(repo, r) {
72
+ const routes = r.routes ?? [];
73
+ return routes.map((entry) => {
74
+ const method = entry.method.toUpperCase();
75
+ const normalized_path = normalizePathParams(entry.path);
76
+ return { repo, method, path: entry.path, normalized_path, file: entry.file };
77
+ });
78
+ }
79
+ // ---------------------------------------------------------------------------
80
+ // Next.js adapter
81
+ // ---------------------------------------------------------------------------
82
+ /**
83
+ * Adapt a Next.js `ApiContractResult` into `RepoEndpoint[]`.
84
+ *
85
+ * `HandlerShape.method` is a single `HttpMethod` string per entry (Next.js
86
+ * emits one handler per HTTP verb), so each handler maps to one RepoEndpoint.
87
+ */
88
+ export function adaptNextjsContract(repo, r) {
89
+ const handlers = r.handlers ?? [];
90
+ return handlers.map((handler) => {
91
+ const method = handler.method.toUpperCase();
92
+ const normalized_path = normalizePathParams(handler.path);
93
+ return { repo, method, path: handler.path, normalized_path, file: handler.file };
94
+ });
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Helpers
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Strip the origin (scheme + host + port) from a URL string, returning the
101
+ * path+query portion. If there is no origin (e.g. "/api/users"), returns as-is.
102
+ * Examples:
103
+ * "https://api.example.com/v1/users" → "/v1/users"
104
+ * "/api/users" → "/api/users"
105
+ */
106
+ function stripOrigin(url) {
107
+ // Match http(s)://host(:port) prefix
108
+ const m = url.match(/^https?:\/\/[^/]+(\/.*)?$/);
109
+ if (m) {
110
+ return m[1] ?? "/";
111
+ }
112
+ return url;
113
+ }
114
+ /**
115
+ * Handle the "leading variable" case: `${BASE}/path/to/resource`.
116
+ *
117
+ * rawUrlContent is the raw content of the URL literal (between quotes/backticks),
118
+ * escape sequences intact, interpolation markers `${...}` preserved verbatim.
119
+ *
120
+ * C1: Strip query string (from first `?`) and fragment (from first `#`) from
121
+ * plain string URLs before returning.
122
+ * C2: Track brace depth properly so `${ {a:1}.a }` (inner object literal) does
123
+ * not prematurely close the interpolation.
124
+ */
125
+ function extractUrlPrefix(rawUrlContent) {
126
+ // Trim leading/trailing whitespace (can appear in multi-line template literals — C4)
127
+ const trimmed = rawUrlContent.trim();
128
+ // Does the content contain any ${ ... } interpolations?
129
+ const hasInterp = trimmed.includes("${");
130
+ if (!hasInterp) {
131
+ // Plain string / no interpolation — strip origin, then strip query/fragment (C1)
132
+ let prefix = stripOrigin(trimmed);
133
+ // Strip query string and fragment
134
+ const qIdx = prefix.indexOf("?");
135
+ const hIdx = prefix.indexOf("#");
136
+ const cutIdx = qIdx === -1 ? hIdx : hIdx === -1 ? qIdx : Math.min(qIdx, hIdx);
137
+ if (cutIdx !== -1)
138
+ prefix = prefix.slice(0, cutIdx);
139
+ return { url_prefix: prefix, partial: false };
140
+ }
141
+ // Template literal with interpolations.
142
+ // Find first "/" that is NOT inside a ${...} block.
143
+ // Track brace DEPTH inside ${} so inner objects `{ key: val }` don't
144
+ // prematurely close the expression (C2 fix).
145
+ let depth = 0;
146
+ let firstSlashIdx = -1;
147
+ for (let i = 0; i < trimmed.length; i++) {
148
+ const c = trimmed[i];
149
+ if (c === "$" && trimmed[i + 1] === "{") {
150
+ depth++;
151
+ i++; // skip '{'
152
+ continue;
153
+ }
154
+ if (c === "{" && depth > 0) {
155
+ // Inner brace — increase depth (C2 fix)
156
+ depth++;
157
+ continue;
158
+ }
159
+ if (c === "}" && depth > 0) {
160
+ depth--;
161
+ continue;
162
+ }
163
+ if (depth === 0 && c === "/" && firstSlashIdx === -1) {
164
+ firstSlashIdx = i;
165
+ break;
166
+ }
167
+ }
168
+ if (firstSlashIdx === -1) {
169
+ // No static path segment at all
170
+ return { url_prefix: "", partial: true };
171
+ }
172
+ // From firstSlashIdx, collect static prefix until the next interpolation.
173
+ // Also stop at `?` or `#` (C1) since query/fragment is not a path prefix.
174
+ let prefix = "";
175
+ let d = 0;
176
+ let hitInterp = false;
177
+ for (let i = firstSlashIdx; i < trimmed.length; i++) {
178
+ const c = trimmed[i];
179
+ if (c === "$" && trimmed[i + 1] === "{") {
180
+ // Hit an interpolation — stop here, prefix is partial
181
+ hitInterp = true;
182
+ break;
183
+ }
184
+ // C1: stop at query/fragment
185
+ if (c === "?" || c === "#") {
186
+ break;
187
+ }
188
+ if (c === "{" && d > 0) {
189
+ d++;
190
+ continue;
191
+ }
192
+ if (c === "}" && d > 0) {
193
+ d--;
194
+ continue;
195
+ }
196
+ if (d === 0) {
197
+ prefix += c;
198
+ }
199
+ }
200
+ // The result is partial when:
201
+ // - there was a leading interpolation (firstSlashIdx > 0 means content before the slash)
202
+ // - or the prefix ends at an interpolation (hitInterp)
203
+ const leadingInterp = firstSlashIdx > 0;
204
+ return { url_prefix: prefix, partial: leadingInterp || hitInterp };
205
+ }
206
+ /**
207
+ * Scan a window of source text (starting just after the fetch URL argument)
208
+ * for a `method:` option to determine the HTTP verb.
209
+ * Returns "GET" if not found.
210
+ */
211
+ function sniffFetchMethodFromWindow(window) {
212
+ const methodMatch = window.match(/\bmethod\s*:\s*['"]([A-Za-z]+)['"]/);
213
+ if (methodMatch) {
214
+ return methodMatch[1].toUpperCase();
215
+ }
216
+ return "GET";
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // matchContracts — Task 14
220
+ // ---------------------------------------------------------------------------
221
+ // (matchContracts implementation follows below; ContractMatch imported at top)
222
+ /**
223
+ * Split a path into non-empty segments (splitting on "/").
224
+ * "/users/{param}" → ["users", "{param}"]
225
+ */
226
+ function pathSegments(path) {
227
+ return path.split("/").filter((s) => s.length > 0);
228
+ }
229
+ /**
230
+ * Compute the longest literal prefix of a normalised template path.
231
+ * Returns the prefix string that ends just before the first `{param}` segment.
232
+ * Examples:
233
+ * "/users/{param}" → "/users/"
234
+ * "/users/{param}/settings" → "/users/"
235
+ * "/health" → "/health"
236
+ * "/{param}" → "/"
237
+ */
238
+ function templateLiteralHead(normalizedPath) {
239
+ const segs = pathSegments(normalizedPath);
240
+ const literalSegs = [];
241
+ for (const seg of segs) {
242
+ if (seg === "{param}")
243
+ break;
244
+ literalSegs.push(seg);
245
+ }
246
+ if (literalSegs.length === 0)
247
+ return "/";
248
+ return "/" + literalSegs.join("/") + "/";
249
+ }
250
+ /**
251
+ * Test whether a concrete path (no param placeholders) INSTANTIATES a normalised
252
+ * template path. Rules:
253
+ * - Same number of segments
254
+ * - Each literal template segment equals the corresponding concrete segment
255
+ * - Each `{param}` template segment matches any single non-empty concrete segment
256
+ */
257
+ function instantiatesTemplate(concretePath, normalizedTemplate) {
258
+ const concSegs = pathSegments(concretePath);
259
+ const tmplSegs = pathSegments(normalizedTemplate);
260
+ if (concSegs.length !== tmplSegs.length)
261
+ return false;
262
+ for (let i = 0; i < tmplSegs.length; i++) {
263
+ const t = tmplSegs[i];
264
+ const c = concSegs[i];
265
+ if (t === "{param}") {
266
+ if (c.length === 0)
267
+ return false; // must match exactly one non-empty segment
268
+ }
269
+ else {
270
+ if (t !== c)
271
+ return false;
272
+ }
273
+ }
274
+ return true;
275
+ }
276
+ /**
277
+ * Test whether a partial consumer `url_prefix` (which may end with "/")
278
+ * is a prefix of the template's literal head.
279
+ *
280
+ * We normalise both sides: strip trailing slash from each (except bare "/")
281
+ * for the literal-head match, OR require the prefix to be a path-prefix of
282
+ * the literal head.
283
+ *
284
+ * A prefix "/users/" matches template literal head "/users/" exactly.
285
+ * A prefix "/users/" also matches "/users/{param}/settings" (literal head "/users/").
286
+ */
287
+ function matchesPartialPrefix(urlPrefix, normalizedTemplate) {
288
+ if (!urlPrefix)
289
+ return false;
290
+ const head = templateLiteralHead(normalizedTemplate);
291
+ // Normalise: ensure both end with "/" for prefix comparison
292
+ const normPrefix = urlPrefix.endsWith("/") ? urlPrefix : urlPrefix + "/";
293
+ const normHead = head.endsWith("/") ? head : head + "/";
294
+ // The consumer prefix must equal or be a path-prefix of the template literal head
295
+ return normHead.startsWith(normPrefix) || normPrefix === normHead;
296
+ }
297
+ /**
298
+ * Match producer `RepoEndpoint[]` against consumer outbound calls (annotated with repo).
299
+ *
300
+ * Matching rules:
301
+ * - Same HTTP method (case-insensitive, already uppercased by adapters)
302
+ * - Cross-repo only (producer.repo !== consumer.repo)
303
+ * - Non-partial consumer: concrete path INSTANTIATES the normalised template → "exact"
304
+ * - Partial consumer: url_prefix is a path-prefix of the template's literal head → "partial"
305
+ *
306
+ * One consumer can match multiple producers (all reported).
307
+ * Multiple consumers can match one producer (all reported).
308
+ * Deduplication: identical (producer_repo, consumer_file, line, path, method) → single entry.
309
+ */
310
+ export function matchContracts(producers, consumers) {
311
+ const results = [];
312
+ const seen = new Set();
313
+ for (const p of producers) {
314
+ for (const c of consumers) {
315
+ // Cross-repo only
316
+ if (p.repo === c.repo)
317
+ continue;
318
+ // Method must match
319
+ if (p.method !== c.method)
320
+ continue;
321
+ let confidence = null;
322
+ if (!c.partial) {
323
+ // Exact: concrete path must instantiate the normalised template
324
+ if (instantiatesTemplate(c.url_prefix, p.normalized_path)) {
325
+ confidence = "exact";
326
+ }
327
+ }
328
+ else {
329
+ // Partial: prefix must match template's literal head
330
+ if (matchesPartialPrefix(c.url_prefix, p.normalized_path)) {
331
+ confidence = "partial";
332
+ }
333
+ }
334
+ if (confidence === null)
335
+ continue;
336
+ // Deduplication key
337
+ const key = `${p.repo}|${c.file}|${c.line}|${p.normalized_path}|${c.method}`;
338
+ if (seen.has(key))
339
+ continue;
340
+ seen.add(key);
341
+ results.push({
342
+ producer_repo: p.repo,
343
+ consumer_repo: c.repo,
344
+ method: c.method,
345
+ path: p.normalized_path,
346
+ consumer_file: c.file,
347
+ consumer_line: c.line,
348
+ confidence,
349
+ });
350
+ }
351
+ }
352
+ return results;
353
+ }
354
+ // ---------------------------------------------------------------------------
355
+ /**
356
+ * Extract all outbound HTTP calls from `source` (TypeScript/JavaScript).
357
+ * Supports fetch, axios.METHOD, and got.METHOD patterns.
358
+ *
359
+ * Uses a single-pass state-machine lexer so calls inside comments, string
360
+ * literals, template literals, and regex literals are never falsely reported
361
+ * (fixes C3/C6). Multi-line templates are handled naturally (C4). Wide-
362
+ * spaced string concatenation is detected via the lexer's nextCodeToken (C5).
363
+ * Query-string and fragment stripping is done in extractUrlPrefix (C1).
364
+ *
365
+ * @param source - Raw source code.
366
+ * @param file - File path to embed in results (returned as-is).
367
+ */
368
+ export function extractOutboundCalls(source, file) {
369
+ const lexerCalls = findOutboundCalls(source);
370
+ const results = [];
371
+ for (const lc of lexerCalls) {
372
+ const rawUrl = lc.urlLiteral.raw;
373
+ const { url_prefix, partial } = extractUrlPrefix(rawUrl);
374
+ // C5: string concat detection — check the token immediately after the
375
+ // closing quote/backtick. nextCodeToken already captures any amount of
376
+ // whitespace before the next token, so wide spacing is handled correctly.
377
+ const isConcat = lc.nextCodeToken.startsWith("+");
378
+ let method;
379
+ if (lc.callee === "fetch") {
380
+ // For fetch, scan the source ahead of the call site for method: "VERB"
381
+ // We need a substring of source starting after the URL literal.
382
+ // Use line as rough anchor — search a window after the call.
383
+ // We approximate by scanning from a position we can derive from source.
384
+ // Since the lexer already consumed the URL, scan next ~200 chars of source
385
+ // from just after the URL literal.
386
+ // Simplest: search the source from lc.line onwards for `method:`.
387
+ // More accurately: findOutboundCalls gives us the line, so we scan a
388
+ // window of the raw source from the end of the call's URL literal.
389
+ // We don't have the exact offset, but we can search a window around the
390
+ // line. Use source.indexOf approach: locate the URL in source and scan.
391
+ // For robustness, scan the 300-char window of source starting from the
392
+ // first character of the matching line.
393
+ const lineStart = findLineStart(source, lc.line);
394
+ const window = source.slice(lineStart, lineStart + 300);
395
+ method = sniffFetchMethodFromWindow(window);
396
+ }
397
+ else {
398
+ // axios / got: method comes from the callee (axios.get → GET)
399
+ method = lc.method ?? "GET";
400
+ }
401
+ results.push({
402
+ url_prefix,
403
+ method,
404
+ partial: partial || isConcat,
405
+ file,
406
+ line: lc.line,
407
+ });
408
+ }
409
+ return results;
410
+ }
411
+ /**
412
+ * Find the character index of the start of line `lineNumber` (1-based) in `source`.
413
+ */
414
+ function findLineStart(source, lineNumber) {
415
+ if (lineNumber <= 1)
416
+ return 0;
417
+ let line = 1;
418
+ for (let i = 0; i < source.length; i++) {
419
+ if (source[i] === "\n") {
420
+ line++;
421
+ if (line === lineNumber)
422
+ return i + 1;
423
+ }
424
+ }
425
+ return source.length;
426
+ }
427
+ // ---------------------------------------------------------------------------
428
+ // Group orchestration + MCP-facing helpers — Task 15
429
+ // ---------------------------------------------------------------------------
430
+ /** Hard cap on repos processed per group (CQ6 — bounds cross-repo fan-out). */
431
+ export const MAX_GROUP_REPOS = 20;
432
+ /** Source extensions scanned for outbound consumer calls. */
433
+ const CONSUMER_SOURCE_EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cts", ".mts"]);
434
+ /**
435
+ * Default repo resolver: real getCodeIndex → framework-detected producer
436
+ * extraction (hono/nest/nextjs adapters) + indexed-source outbound scan.
437
+ * Dynamic imports avoid a register-tools ↔ index-tools cycle at module load.
438
+ */
439
+ async function defaultRepoResolver(repo) {
440
+ const { getCodeIndex } = await import("./index-tools.js");
441
+ const index = await getCodeIndex(repo);
442
+ if (!index)
443
+ return { producers: [], consumers: [], indexed: false };
444
+ const { detectFrameworks } = await import("../utils/framework-detect.js");
445
+ const frameworks = detectFrameworks(index);
446
+ // --- producers: run EVERY detected framework's extractor (a monorepo can
447
+ // serve Hono + NestJS + Next.js side by side — an else-if chain would drop
448
+ // all but the first). Each runs in its own try so one failure neither aborts
449
+ // the others nor hides itself (it surfaces a per-framework warning).
450
+ const producers = [];
451
+ const repoWarnings = [];
452
+ const producerJobs = [];
453
+ if (frameworks.has("hono")) {
454
+ producerJobs.push(["hono", async () => {
455
+ const { extractApiContract } = await import("./hono-api-contract.js");
456
+ return adaptHonoContract(repo, await extractApiContract(repo, undefined, "summary"));
457
+ }]);
458
+ }
459
+ if (frameworks.has("nestjs")) {
460
+ producerJobs.push(["nestjs", async () => {
461
+ const { nestRouteInventory } = await import("./nest-tools.js");
462
+ return adaptNestInventory(repo, await nestRouteInventory(repo));
463
+ }]);
464
+ }
465
+ if (frameworks.has("nextjs")) {
466
+ producerJobs.push(["nextjs", async () => {
467
+ const { nextjsApiContract } = await import("./nextjs-api-contract-tools.js");
468
+ return adaptNextjsContract(repo, await nextjsApiContract(repo));
469
+ }]);
470
+ }
471
+ for (const [fw, job] of producerJobs) {
472
+ try {
473
+ producers.push(...(await job()));
474
+ }
475
+ catch (err) {
476
+ // Surface so a genuine extraction failure is distinguishable from "no endpoints".
477
+ repoWarnings.push(`repo "${repo}" ${fw} producer extraction failed: ${err instanceof Error ? err.message : String(err)}`);
478
+ }
479
+ }
480
+ // --- consumers: scan indexed source files for outbound fetch/axios/got calls,
481
+ // in bounded-concurrency batches so a large repo does not serialize thousands
482
+ // of awaited readFile calls (CQ17 — avoids per-call latency stacking).
483
+ const { readFile } = await import("node:fs/promises");
484
+ const { join, extname } = await import("node:path");
485
+ const scanFiles = index.files.filter((fe) => CONSUMER_SOURCE_EXT.has(extname(fe.path)));
486
+ const consumers = [];
487
+ const CONSUMER_SCAN_CONCURRENCY = 16;
488
+ for (let b = 0; b < scanFiles.length; b += CONSUMER_SCAN_CONCURRENCY) {
489
+ const batch = scanFiles.slice(b, b + CONSUMER_SCAN_CONCURRENCY);
490
+ const calls = await Promise.all(batch.map(async (fe) => {
491
+ let src;
492
+ try {
493
+ src = await readFile(join(index.root, fe.path), "utf-8");
494
+ }
495
+ catch {
496
+ return []; // file vanished / unreadable — skip
497
+ }
498
+ return extractOutboundCalls(src, fe.path);
499
+ }));
500
+ for (const fileCalls of calls) {
501
+ for (const call of fileCalls)
502
+ consumers.push({ ...call, repo });
503
+ }
504
+ }
505
+ return repoWarnings.length > 0
506
+ ? { producers, consumers, indexed: true, warnings: repoWarnings }
507
+ : { producers, consumers, indexed: true };
508
+ }
509
+ /**
510
+ * Answer "who calls what" across a registered repo group: extract producer
511
+ * endpoints and consumer outbound calls for every indexed repo in the group,
512
+ * then match them. Unindexed repos collect a warning and are skipped; a group
513
+ * over MAX_GROUP_REPOS is capped with a truncation warning.
514
+ */
515
+ async function collectGroupData(groupName, opts) {
516
+ const { getGroup, getGroupRegistryPath } = await import("../storage/group-registry.js");
517
+ let registryPath = opts?.registryPath;
518
+ if (!registryPath) {
519
+ const { loadConfig } = await import("../config.js");
520
+ registryPath = getGroupRegistryPath(loadConfig().dataDir);
521
+ }
522
+ const group = await getGroup(registryPath, groupName);
523
+ if (!group) {
524
+ return { producers: [], consumers: [], warnings: [], repos_processed: 0, error: `repo group "${groupName}" not found` };
525
+ }
526
+ const resolver = opts?.resolver ?? defaultRepoResolver;
527
+ const warnings = [];
528
+ let repos = group.repos;
529
+ if (repos.length > MAX_GROUP_REPOS) {
530
+ warnings.push(`group "${groupName}" has ${repos.length} repos; capped at ${MAX_GROUP_REPOS}`);
531
+ repos = repos.slice(0, MAX_GROUP_REPOS);
532
+ }
533
+ const producers = [];
534
+ const consumers = [];
535
+ let processed = 0;
536
+ for (const repo of repos) {
537
+ let data;
538
+ try {
539
+ data = await resolver(repo);
540
+ }
541
+ catch (err) {
542
+ warnings.push(`repo "${repo}" failed to resolve: ${err instanceof Error ? err.message : String(err)}`);
543
+ continue;
544
+ }
545
+ if (data.warnings)
546
+ warnings.push(...data.warnings);
547
+ if (!data.indexed) {
548
+ warnings.push(`repo "${repo}" is not indexed — skipped`);
549
+ continue;
550
+ }
551
+ producers.push(...data.producers);
552
+ consumers.push(...data.consumers);
553
+ processed++;
554
+ }
555
+ return { producers, consumers, warnings, repos_processed: processed };
556
+ }
557
+ export async function matchGroupContracts(groupName, opts) {
558
+ const d = await collectGroupData(groupName, opts);
559
+ if (d.error)
560
+ return { matches: [], warnings: d.warnings, repos_processed: d.repos_processed, error: d.error };
561
+ return { matches: matchContracts(d.producers, d.consumers), warnings: d.warnings, repos_processed: d.repos_processed };
562
+ }
563
+ /**
564
+ * Answer "who calls METHOD path" within a group. Returns producer↔consumer
565
+ * `matches` for the endpoint AND `consumers_of_path` — every raw consumer call
566
+ * hitting that path, INCLUDING calls to endpoints with no producer in the group
567
+ * (an external/un-indexed service). Method is uppercased; the path is normalised
568
+ * (`:id`/`{id}`/`[id]` → `{param}`) so any param style works.
569
+ */
570
+ export async function findEndpointConsumers(groupName, method, path, opts) {
571
+ const d = await collectGroupData(groupName, opts);
572
+ if (d.error)
573
+ return { matches: [], warnings: d.warnings, repos_processed: d.repos_processed, error: d.error };
574
+ const wantMethod = method.toUpperCase();
575
+ const wantPath = normalizePathParams(path);
576
+ const matches = matchContracts(d.producers, d.consumers).filter((m) => m.method === wantMethod && m.path === wantPath);
577
+ // Raw consumers of the queried path — independent of whether a group producer
578
+ // serves it (covers external endpoints the group does not produce).
579
+ const consumersOfPath = d.consumers.filter((c) => {
580
+ if (c.method !== wantMethod)
581
+ return false;
582
+ return c.partial
583
+ ? matchesPartialPrefix(c.url_prefix, wantPath)
584
+ : instantiatesTemplate(c.url_prefix, wantPath);
585
+ });
586
+ return {
587
+ matches,
588
+ warnings: d.warnings,
589
+ repos_processed: d.repos_processed,
590
+ consumers_of_path: consumersOfPath,
591
+ };
592
+ }
593
+ //# sourceMappingURL=cross-repo-contract-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-repo-contract-tools.js","sourceRoot":"","sources":["../../src/tools/cross-repo-contract-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Lightweight state-machine lexer for outbound HTTP call detection.
3
+ *
4
+ * Performs a single forward scan over JS/TS source, classifying each position as:
5
+ * code | string | template | regex | lineComment | blockComment
6
+ *
7
+ * At code positions only, detects `fetch(`, `axios.METHOD(`, `got.METHOD(` calls,
8
+ * then reads the immediately following string/template literal as the URL argument.
9
+ *
10
+ * This approach fixes C2 (inner braces in interpolation), C3 (regex literals
11
+ * not confused with comments), C4 (multi-line templates), C5 (wide-spaced concat),
12
+ * and C6 (no false positives from string-embedded call text).
13
+ */
14
+ export type OutboundCallee = "fetch" | "axios" | "got";
15
+ export interface UrlLiteral {
16
+ kind: "string" | "template";
17
+ /** Raw content between quotes/backticks, escape sequences intact. */
18
+ raw: string;
19
+ }
20
+ export interface LexerOutboundCall {
21
+ callee: OutboundCallee;
22
+ /** HTTP method from callee name (axios.get → "GET"). fetch/got default undefined. */
23
+ method?: string;
24
+ urlLiteral: UrlLiteral;
25
+ /** The first non-whitespace token after the closing quote/backtick. */
26
+ nextCodeToken: string;
27
+ /** 1-based line number of the call keyword. */
28
+ line: number;
29
+ }
30
+ /**
31
+ * Lex `source` and return all detected outbound HTTP calls with their URL
32
+ * literal and metadata. Calls inside strings/templates/comments are skipped.
33
+ */
34
+ export declare function findOutboundCalls(source: string): LexerOutboundCall[];
35
+ //# sourceMappingURL=cross-repo-outbound-lexer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cross-repo-outbound-lexer.d.ts","sourceRoot":"","sources":["../../src/tools/cross-repo-outbound-lexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,cAAc,CAAC;IACvB,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;CACd;AA0CD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CA2crE"}