@opencodehub/mcp 0.1.0

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 (210) hide show
  1. package/README.md +62 -0
  2. package/dist/analysis-bridge.d.ts +23 -0
  3. package/dist/analysis-bridge.d.ts.map +1 -0
  4. package/dist/analysis-bridge.js +83 -0
  5. package/dist/analysis-bridge.js.map +1 -0
  6. package/dist/connection-pool.d.ts +76 -0
  7. package/dist/connection-pool.d.ts.map +1 -0
  8. package/dist/connection-pool.js +179 -0
  9. package/dist/connection-pool.js.map +1 -0
  10. package/dist/error-envelope.d.ts +97 -0
  11. package/dist/error-envelope.d.ts.map +1 -0
  12. package/dist/error-envelope.js +75 -0
  13. package/dist/error-envelope.js.map +1 -0
  14. package/dist/group-resolver.d.ts +29 -0
  15. package/dist/group-resolver.d.ts.map +1 -0
  16. package/dist/group-resolver.js +100 -0
  17. package/dist/group-resolver.js.map +1 -0
  18. package/dist/index.d.ts +43 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +54 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/next-step-hints.d.ts +24 -0
  23. package/dist/next-step-hints.d.ts.map +1 -0
  24. package/dist/next-step-hints.js +41 -0
  25. package/dist/next-step-hints.js.map +1 -0
  26. package/dist/repo-resolver.d.ts +88 -0
  27. package/dist/repo-resolver.d.ts.map +1 -0
  28. package/dist/repo-resolver.js +211 -0
  29. package/dist/repo-resolver.js.map +1 -0
  30. package/dist/repo-uri-for-entry.d.ts +25 -0
  31. package/dist/repo-uri-for-entry.d.ts.map +1 -0
  32. package/dist/repo-uri-for-entry.js +64 -0
  33. package/dist/repo-uri-for-entry.js.map +1 -0
  34. package/dist/resources/repo-cluster.d.ts +19 -0
  35. package/dist/resources/repo-cluster.d.ts.map +1 -0
  36. package/dist/resources/repo-cluster.js +203 -0
  37. package/dist/resources/repo-cluster.js.map +1 -0
  38. package/dist/resources/repo-clusters.d.ts +14 -0
  39. package/dist/resources/repo-clusters.d.ts.map +1 -0
  40. package/dist/resources/repo-clusters.js +97 -0
  41. package/dist/resources/repo-clusters.js.map +1 -0
  42. package/dist/resources/repo-context.d.ts +12 -0
  43. package/dist/resources/repo-context.d.ts.map +1 -0
  44. package/dist/resources/repo-context.js +84 -0
  45. package/dist/resources/repo-context.js.map +1 -0
  46. package/dist/resources/repo-process.d.ts +19 -0
  47. package/dist/resources/repo-process.d.ts.map +1 -0
  48. package/dist/resources/repo-process.js +220 -0
  49. package/dist/resources/repo-process.js.map +1 -0
  50. package/dist/resources/repo-processes.d.ts +13 -0
  51. package/dist/resources/repo-processes.d.ts.map +1 -0
  52. package/dist/resources/repo-processes.js +99 -0
  53. package/dist/resources/repo-processes.js.map +1 -0
  54. package/dist/resources/repo-schema.d.ts +13 -0
  55. package/dist/resources/repo-schema.d.ts.map +1 -0
  56. package/dist/resources/repo-schema.js +99 -0
  57. package/dist/resources/repo-schema.js.map +1 -0
  58. package/dist/resources/repos.d.ts +20 -0
  59. package/dist/resources/repos.d.ts.map +1 -0
  60. package/dist/resources/repos.js +58 -0
  61. package/dist/resources/repos.js.map +1 -0
  62. package/dist/resources/store-helper.d.ts +28 -0
  63. package/dist/resources/store-helper.d.ts.map +1 -0
  64. package/dist/resources/store-helper.js +58 -0
  65. package/dist/resources/store-helper.js.map +1 -0
  66. package/dist/resources/yaml.d.ts +10 -0
  67. package/dist/resources/yaml.d.ts.map +1 -0
  68. package/dist/resources/yaml.js +16 -0
  69. package/dist/resources/yaml.js.map +1 -0
  70. package/dist/server.d.ts +46 -0
  71. package/dist/server.d.ts.map +1 -0
  72. package/dist/server.js +194 -0
  73. package/dist/server.js.map +1 -0
  74. package/dist/staleness.d.ts +19 -0
  75. package/dist/staleness.d.ts.map +1 -0
  76. package/dist/staleness.js +40 -0
  77. package/dist/staleness.js.map +1 -0
  78. package/dist/test-utils.d.ts +170 -0
  79. package/dist/test-utils.d.ts.map +1 -0
  80. package/dist/test-utils.js +473 -0
  81. package/dist/test-utils.js.map +1 -0
  82. package/dist/tools/api-impact.d.ts +47 -0
  83. package/dist/tools/api-impact.d.ts.map +1 -0
  84. package/dist/tools/api-impact.js +199 -0
  85. package/dist/tools/api-impact.js.map +1 -0
  86. package/dist/tools/confidence.d.ts +39 -0
  87. package/dist/tools/confidence.d.ts.map +1 -0
  88. package/dist/tools/confidence.js +58 -0
  89. package/dist/tools/confidence.js.map +1 -0
  90. package/dist/tools/context.d.ts +47 -0
  91. package/dist/tools/context.d.ts.map +1 -0
  92. package/dist/tools/context.js +577 -0
  93. package/dist/tools/context.js.map +1 -0
  94. package/dist/tools/dependencies.d.ts +29 -0
  95. package/dist/tools/dependencies.d.ts.map +1 -0
  96. package/dist/tools/dependencies.js +110 -0
  97. package/dist/tools/dependencies.js.map +1 -0
  98. package/dist/tools/detect-changes.d.ts +15 -0
  99. package/dist/tools/detect-changes.d.ts.map +1 -0
  100. package/dist/tools/detect-changes.js +78 -0
  101. package/dist/tools/detect-changes.js.map +1 -0
  102. package/dist/tools/group-contracts.d.ts +26 -0
  103. package/dist/tools/group-contracts.d.ts.map +1 -0
  104. package/dist/tools/group-contracts.js +251 -0
  105. package/dist/tools/group-contracts.js.map +1 -0
  106. package/dist/tools/group-cross-repo-links.d.ts +28 -0
  107. package/dist/tools/group-cross-repo-links.d.ts.map +1 -0
  108. package/dist/tools/group-cross-repo-links.js +128 -0
  109. package/dist/tools/group-cross-repo-links.js.map +1 -0
  110. package/dist/tools/group-list.d.ts +10 -0
  111. package/dist/tools/group-list.d.ts.map +1 -0
  112. package/dist/tools/group-list.js +74 -0
  113. package/dist/tools/group-list.js.map +1 -0
  114. package/dist/tools/group-query.d.ts +40 -0
  115. package/dist/tools/group-query.d.ts.map +1 -0
  116. package/dist/tools/group-query.js +209 -0
  117. package/dist/tools/group-query.js.map +1 -0
  118. package/dist/tools/group-status.d.ts +21 -0
  119. package/dist/tools/group-status.d.ts.map +1 -0
  120. package/dist/tools/group-status.js +121 -0
  121. package/dist/tools/group-status.js.map +1 -0
  122. package/dist/tools/group-sync.d.ts +23 -0
  123. package/dist/tools/group-sync.d.ts.map +1 -0
  124. package/dist/tools/group-sync.js +112 -0
  125. package/dist/tools/group-sync.js.map +1 -0
  126. package/dist/tools/impact.d.ts +36 -0
  127. package/dist/tools/impact.d.ts.map +1 -0
  128. package/dist/tools/impact.js +232 -0
  129. package/dist/tools/impact.js.map +1 -0
  130. package/dist/tools/license-audit.d.ts +34 -0
  131. package/dist/tools/license-audit.d.ts.map +1 -0
  132. package/dist/tools/license-audit.js +108 -0
  133. package/dist/tools/license-audit.js.map +1 -0
  134. package/dist/tools/list-dead-code.d.ts +26 -0
  135. package/dist/tools/list-dead-code.d.ts.map +1 -0
  136. package/dist/tools/list-dead-code.js +110 -0
  137. package/dist/tools/list-dead-code.js.map +1 -0
  138. package/dist/tools/list-findings-delta.d.ts +36 -0
  139. package/dist/tools/list-findings-delta.d.ts.map +1 -0
  140. package/dist/tools/list-findings-delta.js +274 -0
  141. package/dist/tools/list-findings-delta.js.map +1 -0
  142. package/dist/tools/list-findings.d.ts +30 -0
  143. package/dist/tools/list-findings.d.ts.map +1 -0
  144. package/dist/tools/list-findings.js +129 -0
  145. package/dist/tools/list-findings.js.map +1 -0
  146. package/dist/tools/list-repos.d.ts +17 -0
  147. package/dist/tools/list-repos.d.ts.map +1 -0
  148. package/dist/tools/list-repos.js +63 -0
  149. package/dist/tools/list-repos.js.map +1 -0
  150. package/dist/tools/owners.d.ts +23 -0
  151. package/dist/tools/owners.d.ts.map +1 -0
  152. package/dist/tools/owners.js +103 -0
  153. package/dist/tools/owners.js.map +1 -0
  154. package/dist/tools/pack-codebase.d.ts +76 -0
  155. package/dist/tools/pack-codebase.d.ts.map +1 -0
  156. package/dist/tools/pack-codebase.js +289 -0
  157. package/dist/tools/pack-codebase.js.map +1 -0
  158. package/dist/tools/project-profile.d.ts +28 -0
  159. package/dist/tools/project-profile.d.ts.map +1 -0
  160. package/dist/tools/project-profile.js +109 -0
  161. package/dist/tools/project-profile.js.map +1 -0
  162. package/dist/tools/query.d.ts +63 -0
  163. package/dist/tools/query.d.ts.map +1 -0
  164. package/dist/tools/query.js +662 -0
  165. package/dist/tools/query.js.map +1 -0
  166. package/dist/tools/remove-dead-code.d.ts +47 -0
  167. package/dist/tools/remove-dead-code.d.ts.map +1 -0
  168. package/dist/tools/remove-dead-code.js +258 -0
  169. package/dist/tools/remove-dead-code.js.map +1 -0
  170. package/dist/tools/rename.d.ts +21 -0
  171. package/dist/tools/rename.d.ts.map +1 -0
  172. package/dist/tools/rename.js +116 -0
  173. package/dist/tools/rename.js.map +1 -0
  174. package/dist/tools/risk-trends.d.ts +19 -0
  175. package/dist/tools/risk-trends.d.ts.map +1 -0
  176. package/dist/tools/risk-trends.js +73 -0
  177. package/dist/tools/risk-trends.js.map +1 -0
  178. package/dist/tools/route-map.d.ts +27 -0
  179. package/dist/tools/route-map.d.ts.map +1 -0
  180. package/dist/tools/route-map.js +119 -0
  181. package/dist/tools/route-map.js.map +1 -0
  182. package/dist/tools/scan.d.ts +27 -0
  183. package/dist/tools/scan.d.ts.map +1 -0
  184. package/dist/tools/scan.js +136 -0
  185. package/dist/tools/scan.js.map +1 -0
  186. package/dist/tools/shape-check.d.ts +53 -0
  187. package/dist/tools/shape-check.d.ts.map +1 -0
  188. package/dist/tools/shape-check.js +161 -0
  189. package/dist/tools/shape-check.js.map +1 -0
  190. package/dist/tools/shared.d.ts +101 -0
  191. package/dist/tools/shared.d.ts.map +1 -0
  192. package/dist/tools/shared.js +114 -0
  193. package/dist/tools/shared.js.map +1 -0
  194. package/dist/tools/signature.d.ts +38 -0
  195. package/dist/tools/signature.d.ts.map +1 -0
  196. package/dist/tools/signature.js +332 -0
  197. package/dist/tools/signature.js.map +1 -0
  198. package/dist/tools/sql.d.ts +34 -0
  199. package/dist/tools/sql.d.ts.map +1 -0
  200. package/dist/tools/sql.js +222 -0
  201. package/dist/tools/sql.js.map +1 -0
  202. package/dist/tools/tool-map.d.ts +24 -0
  203. package/dist/tools/tool-map.d.ts.map +1 -0
  204. package/dist/tools/tool-map.js +97 -0
  205. package/dist/tools/tool-map.js.map +1 -0
  206. package/dist/tools/verdict.d.ts +33 -0
  207. package/dist/tools/verdict.d.ts.map +1 -0
  208. package/dist/tools/verdict.js +102 -0
  209. package/dist/tools/verdict.js.map +1 -0
  210. package/package.json +76 -0
@@ -0,0 +1,110 @@
1
+ /**
2
+ * `dependencies` — enumerate Dependency nodes for an indexed repo.
3
+ *
4
+ * A Dependency node is produced by the `dependencies` pipeline phase
5
+ * from per-ecosystem manifest parsers. Every node carries
6
+ * `ecosystem`, `name`, `version`, and a `lockfileSource` relpath.
7
+ *
8
+ * Filters:
9
+ * - `ecosystem` — restrict to one ecosystem (npm, pypi, go, cargo,
10
+ * maven, nuget). Server does no validation beyond
11
+ * string compare — an unknown value returns an
12
+ * empty list.
13
+ * - `filePath` — substring match against `file_path` (alias of the
14
+ * lockfile source). Useful when a repo has multiple
15
+ * workspaces with their own manifests.
16
+ */
17
+ // biome-ignore-all lint/complexity/useLiteralKeys: dot-access disallowed on Record index signatures
18
+ import { z } from "zod";
19
+ import { toolErrorFromUnknown } from "../error-envelope.js";
20
+ import { withNextSteps } from "../next-step-hints.js";
21
+ import { stalenessFromMeta } from "../staleness.js";
22
+ import { fromToolResult, repoArgShape, toToolResult, withStore, } from "./shared.js";
23
+ const DependenciesInput = {
24
+ ...repoArgShape,
25
+ filePath: z
26
+ .string()
27
+ .optional()
28
+ .describe("Optional substring filter on the manifest path (e.g. 'apps/web/package.json')."),
29
+ ecosystem: z
30
+ .enum(["npm", "pypi", "go", "cargo", "maven", "nuget"])
31
+ .optional()
32
+ .describe("Restrict to a single ecosystem."),
33
+ limit: z
34
+ .number()
35
+ .int()
36
+ .positive()
37
+ .max(10_000)
38
+ .optional()
39
+ .describe("Maximum number of dependencies to return (default 500, max 10000)."),
40
+ };
41
+ export async function runDependencies(ctx, args) {
42
+ const limit = args.limit ?? 500;
43
+ const call = await withStore(ctx, args, async (store, resolved) => {
44
+ try {
45
+ // Typed `listDependencies` finder reads the Dependency rows directly,
46
+ // already rehydrated into the typed shape. The `filePath` substring
47
+ // filter is applied in TS because the finder doesn't expose a LIKE
48
+ // option — dependencies are bounded per repo so a TS filter is fine.
49
+ const opts = { limit };
50
+ if (args.ecosystem !== undefined)
51
+ opts.ecosystem = args.ecosystem;
52
+ const all = await store.graph.listDependencies(opts);
53
+ const filtered = args.filePath === undefined
54
+ ? all
55
+ : all.filter((d) => {
56
+ const lf = d.lockfileSource ?? d.filePath;
57
+ return lf.includes(args.filePath);
58
+ });
59
+ const rows = filtered.map((d) => ({
60
+ id: d.id,
61
+ name: d.name,
62
+ version: stringOr(d.version, "UNKNOWN"),
63
+ ecosystem: stringOr(d.ecosystem, "unknown"),
64
+ license: stringOr(d.license, "UNKNOWN"),
65
+ lockfileSource: stringOr(d.lockfileSource, d.filePath),
66
+ }));
67
+ const header = `Dependencies (${rows.length}) for ${resolved.name}${args.ecosystem ? ` · ecosystem=${args.ecosystem}` : ""}${args.filePath ? ` · filePath~${args.filePath}` : ""}:`;
68
+ const body = rows.length === 0
69
+ ? "(no dependencies found — index the repo with `codehub analyze` and verify the pipeline ran the `dependencies` phase)"
70
+ : rows
71
+ .map((d) => `- [${d.ecosystem}] ${d.name}@${d.version} (${d.lockfileSource}, license=${d.license})`)
72
+ .join("\n");
73
+ const next = rows.length === 0
74
+ ? [
75
+ "call `list_repos` to confirm the repo is indexed",
76
+ "re-index with `codehub analyze` to populate Dependency nodes",
77
+ ]
78
+ : [
79
+ "call `query` with one of the names above to find import sites",
80
+ "call `sql` with 'SELECT * FROM relations WHERE type = ''DEPENDS_ON''' for the raw edges",
81
+ ];
82
+ return withNextSteps(`${header}\n${body}`, { dependencies: rows, total: rows.length }, next, stalenessFromMeta(resolved.meta));
83
+ }
84
+ catch (err) {
85
+ return toolErrorFromUnknown(err);
86
+ }
87
+ });
88
+ return toToolResult(call);
89
+ }
90
+ export function registerDependenciesTool(server, ctx) {
91
+ server.registerTool("dependencies", {
92
+ title: "List external dependencies",
93
+ description: "Enumerate external package dependencies of the indexed repo, sourced from lockfiles and manifests (package-lock.json, pnpm-lock.yaml, pyproject.toml, requirements.txt, uv.lock, go.mod, go.sum, Cargo.lock, Cargo.toml, pom.xml, *.csproj, packages.lock.json). Optionally filter by ecosystem or lockfile path substring. License field is 'UNKNOWN' at v1.0; real license detection lands in a later release.",
94
+ inputSchema: DependenciesInput,
95
+ annotations: {
96
+ readOnlyHint: true,
97
+ destructiveHint: false,
98
+ openWorldHint: false,
99
+ idempotentHint: true,
100
+ },
101
+ }, async (args) => fromToolResult(await runDependencies(ctx, args)));
102
+ }
103
+ function stringOr(v, fallback) {
104
+ if (typeof v === "string")
105
+ return v;
106
+ if (typeof v === "number" || typeof v === "boolean")
107
+ return String(v);
108
+ return fallback;
109
+ }
110
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../src/tools/dependencies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `detect_changes` — map a git diff to affected graph symbols & processes.
3
+ */
4
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { type ToolContext, type ToolResult } from "./shared.js";
6
+ interface DetectChangesArgs {
7
+ readonly scope: "unstaged" | "staged" | "all" | "compare";
8
+ readonly compareRef?: string | undefined;
9
+ readonly repo?: string | undefined;
10
+ readonly repo_uri?: string | undefined;
11
+ }
12
+ export declare function runDetectChanges(ctx: ToolContext, args: DetectChangesArgs): Promise<ToolResult>;
13
+ export declare function registerDetectChangesTool(server: McpServer, ctx: ToolContext): void;
14
+ export {};
15
+ //# sourceMappingURL=detect-changes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-changes.d.ts","sourceRoot":"","sources":["../../src/tools/detect-changes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,UAAU,EAGhB,MAAM,aAAa,CAAC;AAerB,UAAU,iBAAiB;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,UAAU,CAAC,CAwDrB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAiBnF"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * `detect_changes` — map a git diff to affected graph symbols & processes.
3
+ */
4
+ import { z } from "zod";
5
+ import { callRunDetectChanges } from "../analysis-bridge.js";
6
+ import { toolErrorFromUnknown } from "../error-envelope.js";
7
+ import { withNextSteps } from "../next-step-hints.js";
8
+ import { stalenessFromMeta } from "../staleness.js";
9
+ import { fromToolResult, repoArgShape, toToolResult, withStore, } from "./shared.js";
10
+ const DetectChangesInput = {
11
+ scope: z
12
+ .enum(["unstaged", "staged", "all", "compare"])
13
+ .describe("unstaged = working-tree diff, staged = index diff, all = union, compare = diff vs compareRef."),
14
+ compareRef: z
15
+ .string()
16
+ .optional()
17
+ .describe("Git ref to compare against (only used when scope='compare')."),
18
+ ...repoArgShape,
19
+ };
20
+ export async function runDetectChanges(ctx, args) {
21
+ const call = await withStore(ctx, args, async (store, resolved) => {
22
+ try {
23
+ const q = { scope: args.scope, repoPath: resolved.repoPath };
24
+ if (args.compareRef !== undefined)
25
+ q.compareRef = args.compareRef;
26
+ const result = await callRunDetectChanges(store.graph, q);
27
+ const lines = [];
28
+ lines.push(`${result.summary.fileCount} file(s), ${result.summary.symbolCount} symbol(s), ${result.summary.processCount} process(es) affected. Risk: ${result.summary.risk}.`);
29
+ if (result.changedFiles.length > 0) {
30
+ lines.push(`Changed files:`);
31
+ for (const f of result.changedFiles.slice(0, 30))
32
+ lines.push(` • ${f}`);
33
+ }
34
+ if (result.affectedSymbols.length > 0) {
35
+ lines.push(`Affected symbols (${result.affectedSymbols.length}):`);
36
+ for (const s of result.affectedSymbols.slice(0, 50)) {
37
+ lines.push(` • ${s.name} [${s.kind}] — ${s.filePath}`);
38
+ }
39
+ }
40
+ if (result.affectedProcesses.length > 0) {
41
+ lines.push(`Affected processes (${result.affectedProcesses.length}):`);
42
+ for (const p of result.affectedProcesses) {
43
+ lines.push(` ⊿ ${p.name}`);
44
+ }
45
+ }
46
+ const next = result.affectedSymbols.length > 0
47
+ ? [
48
+ "call `impact` on each affected symbol for per-change risk",
49
+ "call `query` with the feature name to confirm test coverage",
50
+ ]
51
+ : ["no indexed symbols touched — change may be to docs or tests only"];
52
+ return withNextSteps(lines.join("\n"), {
53
+ summary: result.summary,
54
+ changed_files: result.changedFiles,
55
+ affected_symbols: result.affectedSymbols,
56
+ affected_processes: result.affectedProcesses,
57
+ }, next, stalenessFromMeta(resolved.meta));
58
+ }
59
+ catch (err) {
60
+ return toolErrorFromUnknown(err);
61
+ }
62
+ });
63
+ return toToolResult(call);
64
+ }
65
+ export function registerDetectChangesTool(server, ctx) {
66
+ server.registerTool("detect_changes", {
67
+ title: "Map git diff to indexed symbols",
68
+ description: "Parse the repo's git diff for the requested scope (unstaged, staged, all, or compared to a ref) and map every changed line back to indexed symbols. Lists the affected processes so agents can spot flows impacted by a commit before pushing.",
69
+ inputSchema: DetectChangesInput,
70
+ annotations: {
71
+ readOnlyHint: true,
72
+ destructiveHint: false,
73
+ idempotentHint: true,
74
+ openWorldHint: false,
75
+ },
76
+ }, async (args) => fromToolResult(await runDetectChanges(ctx, args)));
77
+ }
78
+ //# sourceMappingURL=detect-changes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-changes.js","sourceRoot":"","sources":["../../src/tools/detect-changes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `group_contracts` — cross-repo HTTP-contract discovery.
3
+ *
4
+ * For every repo in a named group, read the unresolved FETCHES edges
5
+ * stored by the `fetches` ingestion phase (target id prefixed with
6
+ * `fetches:unresolved:METHOD:URL`). Each unresolved edge is then matched
7
+ * against the `Route` nodes in every OTHER repo in the group. A match
8
+ * surfaces as a `contract` row mapping consumer → producer.
9
+ *
10
+ * Determinism:
11
+ * - Repos iterate in alphabetical order.
12
+ * - Contracts are sorted by (consumerRepo, consumerSymbol, method,
13
+ * path, producerRepo) so repeated calls yield stable output.
14
+ *
15
+ * Annotations: readOnlyHint, idempotentHint, openWorldHint:false — the
16
+ * tool never reaches past the named group.
17
+ */
18
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
19
+ import { type ToolContext, type ToolResult } from "./shared.js";
20
+ interface GroupContractsArgs {
21
+ readonly groupName: string;
22
+ }
23
+ export declare function runGroupContracts(ctx: ToolContext, args: GroupContractsArgs): Promise<ToolResult>;
24
+ export declare function registerGroupContractsTool(server: McpServer, ctx: ToolContext): void;
25
+ export {};
26
+ //# sourceMappingURL=group-contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-contracts.d.ts","sourceRoot":"","sources":["../../src/tools/group-contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWzE,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAgB,MAAM,aAAa,CAAC;AAmF9F,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,UAAU,CAAC,CA6JrB;AAsBD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAiBpF"}
@@ -0,0 +1,251 @@
1
+ /**
2
+ * `group_contracts` — cross-repo HTTP-contract discovery.
3
+ *
4
+ * For every repo in a named group, read the unresolved FETCHES edges
5
+ * stored by the `fetches` ingestion phase (target id prefixed with
6
+ * `fetches:unresolved:METHOD:URL`). Each unresolved edge is then matched
7
+ * against the `Route` nodes in every OTHER repo in the group. A match
8
+ * surfaces as a `contract` row mapping consumer → producer.
9
+ *
10
+ * Determinism:
11
+ * - Repos iterate in alphabetical order.
12
+ * - Contracts are sorted by (consumerRepo, consumerSymbol, method,
13
+ * path, producerRepo) so repeated calls yield stable output.
14
+ *
15
+ * Annotations: readOnlyHint, idempotentHint, openWorldHint:false — the
16
+ * tool never reaches past the named group.
17
+ */
18
+ // biome-ignore-all lint/complexity/useLiteralKeys: dot-access disallowed on Record index signatures
19
+ import { readFile } from "node:fs/promises";
20
+ import { resolve } from "node:path";
21
+ import { resolveDbPath } from "@opencodehub/storage";
22
+ import { z } from "zod";
23
+ import { toolError, toolErrorFromUnknown } from "../error-envelope.js";
24
+ import { readGroup } from "../group-resolver.js";
25
+ import { withNextSteps } from "../next-step-hints.js";
26
+ import { readRegistry } from "../repo-resolver.js";
27
+ import { repoUriForEntry } from "../repo-uri-for-entry.js";
28
+ import { resolveGroupContractsPath } from "./group-sync.js";
29
+ import { fromToolResult, toToolResult } from "./shared.js";
30
+ const UNRESOLVED_PREFIX = "fetches:unresolved:";
31
+ const GroupContractsInput = {
32
+ groupName: z.string().min(1).describe("Name of the group to inspect."),
33
+ };
34
+ /** Canonicalize a URL template so `:id`, `{id}`, trailing-slash variants
35
+ * collapse into a single key. */
36
+ function normalizePath(raw) {
37
+ return raw
38
+ .replace(/:([A-Za-z_][A-Za-z0-9_]*)/g, "{$1}")
39
+ .replace(/\?.*$/, "")
40
+ .replace(/\/+$/, "");
41
+ }
42
+ function parseUnresolvedTarget(target) {
43
+ if (!target.startsWith(UNRESOLVED_PREFIX))
44
+ return undefined;
45
+ const rest = target.slice(UNRESOLVED_PREFIX.length);
46
+ const colon = rest.indexOf(":");
47
+ if (colon < 0)
48
+ return undefined;
49
+ const method = rest.slice(0, colon).toUpperCase();
50
+ const path = rest.slice(colon + 1);
51
+ return { method, path };
52
+ }
53
+ async function readConsumerEdges(graph) {
54
+ const fetches = await graph.listEdgesByType("FETCHES");
55
+ const sorted = [...fetches].sort((a, b) => {
56
+ if (a.from !== b.from)
57
+ return a.from < b.from ? -1 : 1;
58
+ return a.to < b.to ? -1 : a.to > b.to ? 1 : 0;
59
+ });
60
+ const out = [];
61
+ for (const e of sorted) {
62
+ const parsed = parseUnresolvedTarget(e.to);
63
+ if (parsed === undefined)
64
+ continue;
65
+ out.push({
66
+ consumerSymbol: e.from,
67
+ method: parsed.method,
68
+ path: normalizePath(parsed.path),
69
+ });
70
+ }
71
+ return out;
72
+ }
73
+ async function readProducerRoutes(graph) {
74
+ const routes = await graph.listRoutes();
75
+ const sorted = [...routes].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
76
+ const out = [];
77
+ for (const r of sorted) {
78
+ if (typeof r.url !== "string" || r.url.length === 0)
79
+ continue;
80
+ const method = (r.method ?? "GET").toUpperCase();
81
+ out.push({ nodeId: r.id, method, url: r.url });
82
+ }
83
+ return out;
84
+ }
85
+ export async function runGroupContracts(ctx, args) {
86
+ try {
87
+ const opts = ctx.home !== undefined ? { home: ctx.home } : {};
88
+ const group = await readGroup(args.groupName, opts);
89
+ if (!group) {
90
+ return toToolResult(toolError("NOT_FOUND", `Group ${args.groupName} is not defined.`, "Run `codehub group list` to see defined groups."));
91
+ }
92
+ const registry = await readRegistry(opts);
93
+ const sortedRepos = [...group.repos].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
94
+ const missing = [];
95
+ const consumersByRepo = new Map();
96
+ const producersByRepo = new Map();
97
+ // Resolve `repo_uri` for every registered member so every
98
+ // ContractRow carries `consumerRepoUri` / `producerRepoUri`.
99
+ const repoUriByName = new Map();
100
+ for (const repo of sortedRepos) {
101
+ const hit = registry[repo.name];
102
+ if (!hit) {
103
+ missing.push(repo.name);
104
+ continue;
105
+ }
106
+ repoUriByName.set(repo.name, await repoUriForEntry(hit, ctx.pool));
107
+ const repoPath = resolve(hit.path);
108
+ const dbPath = resolveDbPath(repoPath);
109
+ const store = await ctx.pool.acquire(repoPath, dbPath).catch((err) => {
110
+ const msg = err instanceof Error ? err.message : String(err);
111
+ throw new Error(`Failed to open DuckDB for ${repo.name}: ${msg}`);
112
+ });
113
+ try {
114
+ const [consumers, producers] = await Promise.all([
115
+ readConsumerEdges(store.graph),
116
+ readProducerRoutes(store.graph),
117
+ ]);
118
+ consumersByRepo.set(repo.name, consumers);
119
+ producersByRepo.set(repo.name, producers);
120
+ }
121
+ finally {
122
+ await ctx.pool.release(repoPath);
123
+ }
124
+ }
125
+ const contracts = [];
126
+ for (const [consumerRepo, consumers] of consumersByRepo) {
127
+ for (const consumer of consumers) {
128
+ // Search every OTHER repo in the group for a Route matching
129
+ // method + normalized path.
130
+ for (const [producerRepo, producers] of producersByRepo) {
131
+ if (producerRepo === consumerRepo)
132
+ continue;
133
+ for (const route of producers) {
134
+ if (route.method !== consumer.method)
135
+ continue;
136
+ if (normalizePath(route.url) !== consumer.path)
137
+ continue;
138
+ // Both sides must be registered members (consumers/producers
139
+ // were only populated for registered repos), so the uri map
140
+ // has a hit — but guard with an empty-string fallback to
141
+ // keep the type `string` not `string | undefined`.
142
+ const consumerRepoUri = repoUriByName.get(consumerRepo) ?? "";
143
+ const producerRepoUri = repoUriByName.get(producerRepo) ?? "";
144
+ contracts.push({
145
+ consumerRepo,
146
+ consumerRepoUri,
147
+ consumerSymbol: consumer.consumerSymbol,
148
+ producerRepo,
149
+ producerRepoUri,
150
+ producerRoute: route.nodeId,
151
+ method: consumer.method,
152
+ path: consumer.path,
153
+ });
154
+ }
155
+ }
156
+ }
157
+ }
158
+ contracts.sort((a, b) => {
159
+ if (a.consumerRepo !== b.consumerRepo)
160
+ return a.consumerRepo < b.consumerRepo ? -1 : 1;
161
+ if (a.consumerSymbol !== b.consumerSymbol)
162
+ return a.consumerSymbol < b.consumerSymbol ? -1 : 1;
163
+ if (a.method !== b.method)
164
+ return a.method < b.method ? -1 : 1;
165
+ if (a.path !== b.path)
166
+ return a.path < b.path ? -1 : 1;
167
+ if (a.producerRepo !== b.producerRepo)
168
+ return a.producerRepo < b.producerRepo ? -1 : 1;
169
+ return a.producerRoute < b.producerRoute ? -1 : 1;
170
+ });
171
+ // Secondary surface: the ContractRegistry persisted by `group_sync`.
172
+ // When the file exists we expose its cross-links + contract hashes so
173
+ // agents can browse HTTP, gRPC, and topic pairings without re-running
174
+ // the extractors themselves.
175
+ const persisted = await loadPersistedRegistry(group.name, ctx.home);
176
+ const crossLinks = persisted?.crossLinks ?? [];
177
+ const header = `Cross-repo contracts for group ${group.name}: ${contracts.length} DuckDB-backed HTTP edge(s), ${crossLinks.length} registry cross-link(s).`;
178
+ const body = contracts.length === 0
179
+ ? "(no FETCH-derived contracts — verify consumer repos ran the `fetches` phase and producer repos registered Route nodes)"
180
+ : contracts
181
+ .map((c) => `- [${c.consumerRepo}] ${c.consumerSymbol} → [${c.producerRepo}] ${c.method} ${c.path}`)
182
+ .join("\n");
183
+ const crossLinkBody = crossLinks.length === 0
184
+ ? ""
185
+ : `\n\nCross-links (from group_sync registry):\n${crossLinks
186
+ .slice(0, 50)
187
+ .map((l) => `- [${l.producer.repo}] ${l.producer.type} "${l.producer.signature}" (${l.producer.file}:${l.producer.line}) ↔ [${l.consumer.repo}] ${l.consumer.type} (${l.consumer.file}:${l.consumer.line}) [${l.matchReason}]`)
188
+ .join("\n")}${crossLinks.length > 50 ? `\n… and ${crossLinks.length - 50} more` : ""}`;
189
+ const warnLines = missing.length > 0
190
+ ? `\n\nWarning: ${missing.length} repo reference(s) missing from registry: ${missing.join(", ")}. Run \`codehub analyze\` for each.`
191
+ : "";
192
+ const registryHint = persisted
193
+ ? ""
194
+ : `\n\nHint: call \`group_sync\` with groupName="${group.name}" to materialize HTTP / gRPC / topic cross-links under ~/.codehub/groups/${group.name}/contracts.json`;
195
+ const next = contracts.length === 0 && crossLinks.length === 0
196
+ ? [
197
+ `call \`group_sync\` with groupName="${group.name}" to materialize cross-repo contracts`,
198
+ `call \`group_status\` with groupName="${group.name}" to confirm all repos are fresh`,
199
+ ]
200
+ : contracts.length > 0
201
+ ? [
202
+ `call \`context\` with symbol="${contracts[0]?.consumerSymbol ?? ""}" and repo="${contracts[0]?.consumerRepo ?? ""}" to inspect the first contract`,
203
+ `call \`group_sync\` with groupName="${group.name}" to refresh the cross-link registry`,
204
+ ]
205
+ : [
206
+ `call \`group_sync\` with groupName="${group.name}" to refresh the cross-link registry`,
207
+ `call \`group_query\` with groupName="${group.name}" to locate related code paths`,
208
+ ];
209
+ return toToolResult(withNextSteps(`${header}\n${body}${crossLinkBody}${warnLines}${registryHint}`, {
210
+ groupName: group.name,
211
+ contracts,
212
+ crossLinks,
213
+ registryComputedAt: persisted?.computedAt ?? null,
214
+ registryPath: persisted ? resolveGroupContractsPath(group.name, ctx.home) : null,
215
+ }, next));
216
+ }
217
+ catch (err) {
218
+ return toToolResult(toolErrorFromUnknown(err));
219
+ }
220
+ }
221
+ /**
222
+ * Load `<home>/.codehub/groups/<name>/contracts.json`. Returns `null`
223
+ * when the file does not exist or fails to parse — the tool still
224
+ * succeeds on the DuckDB-backed surface when the persisted file is
225
+ * missing.
226
+ */
227
+ async function loadPersistedRegistry(groupName, home) {
228
+ const path = resolveGroupContractsPath(groupName, home);
229
+ try {
230
+ const raw = await readFile(path, "utf8");
231
+ const parsed = JSON.parse(raw);
232
+ return parsed;
233
+ }
234
+ catch {
235
+ return null;
236
+ }
237
+ }
238
+ export function registerGroupContractsTool(server, ctx) {
239
+ server.registerTool("group_contracts", {
240
+ title: "Cross-repo HTTP contracts + cross-links",
241
+ description: "Two-part surface for cross-repo contract discovery. (1) Match unresolved FETCHES edges (consumer) against Route nodes (producer) across every repo in the group — this is the DuckDB-backed HTTP surface. (2) When `group_sync` has written a contracts.json under `<home>/.codehub/groups/<name>/`, surface its cross-links with signature + file + line for HTTP, gRPC, and topic pairings. Use this to audit cross-repo coupling after a schema change in a shared API or proto.",
242
+ inputSchema: GroupContractsInput,
243
+ annotations: {
244
+ readOnlyHint: true,
245
+ destructiveHint: false,
246
+ idempotentHint: true,
247
+ openWorldHint: false,
248
+ },
249
+ }, async (args) => fromToolResult(await runGroupContracts(ctx, args)));
250
+ }
251
+ //# sourceMappingURL=group-contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-contracts.js","sourceRoot":"","sources":["../../src/tools/group-contracts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `group_cross_repo_links` — sourced cross-repo link graph for Phase E.
3
+ *
4
+ * The `codehub-document` skill calls this during its Phase E assembler
5
+ * (group mode) and embeds the returned `links[]` verbatim into the
6
+ * `.docmeta.json` v2 `cross_repo_links[]` field. The skill does the
7
+ * Markdown rendering; this tool only emits data.
8
+ *
9
+ * Data path: loads the persisted ContractRegistry written by `group_sync`
10
+ * (at `<home>/.codehub/groups/<name>/contracts.json`), maps each
11
+ * repo name to its stable `repo_uri` via `deriveRepoUri`, and hands off
12
+ * to the pure analysis helper `computeCrossRepoLinks`. The helper does
13
+ * the sort + dedup + relation inference; the tool only wires I/O.
14
+ *
15
+ * Annotations: readOnlyHint, idempotentHint, openWorldHint:false — the
16
+ * tool reads two files (group descriptor + persisted registry) and
17
+ * computes from them. Never writes.
18
+ */
19
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
20
+ import { type ToolContext, type ToolResult } from "./shared.js";
21
+ interface GroupCrossRepoLinksArgs {
22
+ readonly groupName: string;
23
+ readonly docPathScheme?: "default" | "per-repo-landing-only" | undefined;
24
+ }
25
+ export declare function runGroupCrossRepoLinks(ctx: ToolContext, args: GroupCrossRepoLinksArgs): Promise<ToolResult>;
26
+ export declare function registerGroupCrossRepoLinksTool(server: McpServer, ctx: ToolContext): void;
27
+ export {};
28
+ //# sourceMappingURL=group-cross-repo-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-cross-repo-links.d.ts","sourceRoot":"","sources":["../../src/tools/group-cross-repo-links.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAgB,MAAM,aAAa,CAAC;AAY9F,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,GAAG,uBAAuB,GAAG,SAAS,CAAC;CAC1E;AAoBD,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,UAAU,CAAC,CA2FrB;AAED,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAiBzF"}