@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,121 @@
1
+ /**
2
+ * `group_status` — per-repo index freshness within a named group.
3
+ *
4
+ * For each repo referenced by the group we emit:
5
+ * - name, path
6
+ * - nodeCount / edgeCount from the registry at group-create time
7
+ * - indexedAt from the registry (ISO8601)
8
+ * - staleness envelope via @opencodehub/analysis.computeStaleness when
9
+ * the on-disk meta.json is readable
10
+ * - `inRegistry: false` for orphan references (repo was removed but the
11
+ * group still points at it)
12
+ */
13
+ // biome-ignore-all lint/complexity/useLiteralKeys: dot-access disallowed on Record index signatures
14
+ import { readStoreMeta } from "@opencodehub/storage";
15
+ import { z } from "zod";
16
+ import { toolError, toolErrorFromUnknown } from "../error-envelope.js";
17
+ import { readGroup } from "../group-resolver.js";
18
+ import { withNextSteps } from "../next-step-hints.js";
19
+ import { deriveRepoUri, readRegistry } from "../repo-resolver.js";
20
+ import { repoUriForEntry } from "../repo-uri-for-entry.js";
21
+ import { stalenessFor } from "../staleness.js";
22
+ import { fromToolResult, toToolResult } from "./shared.js";
23
+ const GroupStatusInput = {
24
+ groupName: z.string().min(1).describe("Name of the group to inspect."),
25
+ };
26
+ export async function runGroupStatus(ctx, args) {
27
+ try {
28
+ const opts = ctx.home !== undefined ? { home: ctx.home } : {};
29
+ const group = await readGroup(args.groupName, opts);
30
+ if (!group) {
31
+ return toToolResult(toolError("NOT_FOUND", `Group ${args.groupName} is not defined.`, "Run `codehub group list` to see defined groups."));
32
+ }
33
+ const registry = await readRegistry(opts);
34
+ const rows = [];
35
+ // Alphabetical iteration keeps output deterministic.
36
+ const sorted = [...group.repos].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
37
+ for (const repo of sorted) {
38
+ const hit = registry[repo.name];
39
+ if (!hit) {
40
+ // Orphan reference — still emit a deterministic repo_uri so
41
+ // consumers always receive the additive `repo_uri` field.
42
+ const orphanUri = deriveRepoUri({
43
+ name: repo.name,
44
+ path: repo.path,
45
+ indexedAt: "",
46
+ nodeCount: 0,
47
+ edgeCount: 0,
48
+ });
49
+ rows.push({
50
+ name: repo.name,
51
+ repo_uri: orphanUri,
52
+ path: repo.path,
53
+ inRegistry: false,
54
+ indexedAt: null,
55
+ nodeCount: null,
56
+ edgeCount: null,
57
+ lastCommit: null,
58
+ });
59
+ continue;
60
+ }
61
+ const meta = await readStoreMeta(hit.path).catch(() => undefined);
62
+ const staleness = meta
63
+ ? await stalenessFor(hit.path, meta).catch(() => undefined)
64
+ : undefined;
65
+ const repoUri = await repoUriForEntry(hit, ctx.pool);
66
+ rows.push({
67
+ name: hit.name,
68
+ repo_uri: repoUri,
69
+ path: hit.path,
70
+ inRegistry: true,
71
+ indexedAt: hit.indexedAt,
72
+ nodeCount: hit.nodeCount,
73
+ edgeCount: hit.edgeCount,
74
+ lastCommit: hit.lastCommit ?? null,
75
+ ...(staleness ? { staleness } : {}),
76
+ });
77
+ }
78
+ const header = `Group ${group.name} (${rows.length} repo${rows.length === 1 ? "" : "s"}):`;
79
+ const body = rows
80
+ .map((r) => {
81
+ if (!r.inRegistry)
82
+ return `- ${r.name} [orphan — run \`codehub analyze ${r.path}\`]`;
83
+ const staleBadge = r.staleness?.isStale ? " [stale]" : "";
84
+ return (`- ${r.name}${staleBadge}\n` +
85
+ ` path: ${r.path}\n` +
86
+ ` nodes: ${r.nodeCount ?? "?"}, edges: ${r.edgeCount ?? "?"}\n` +
87
+ ` indexedAt: ${r.indexedAt ?? "?"}, lastCommit: ${r.lastCommit ?? "-"}`);
88
+ })
89
+ .join("\n");
90
+ const staleRepos = rows.filter((r) => r.staleness?.isStale).map((r) => r.name);
91
+ const orphans = rows.filter((r) => !r.inRegistry).map((r) => r.name);
92
+ const next = [];
93
+ if (orphans.length > 0) {
94
+ next.push(`re-run \`codehub analyze\` for orphaned repo(s): ${orphans.join(", ")}`);
95
+ }
96
+ if (staleRepos.length > 0) {
97
+ next.push(`re-run \`codehub analyze\` to refresh: ${staleRepos.join(", ")}`);
98
+ }
99
+ if (next.length === 0) {
100
+ next.push(`call \`group_query\` with groupName="${group.name}" and a search phrase to explore`);
101
+ }
102
+ return toToolResult(withNextSteps(`${header}\n${body}`, { groupName: group.name, repos: rows }, next));
103
+ }
104
+ catch (err) {
105
+ return toToolResult(toolErrorFromUnknown(err));
106
+ }
107
+ }
108
+ export function registerGroupStatusTool(server, ctx) {
109
+ server.registerTool("group_status", {
110
+ title: "Cross-repo group status",
111
+ description: "Report per-repo index freshness for every repo in a named group. Returns node/edge counts, last-indexed timestamp, last commit, and a best-effort staleness envelope so the agent can decide whether to re-analyze before querying.",
112
+ inputSchema: GroupStatusInput,
113
+ annotations: {
114
+ readOnlyHint: true,
115
+ destructiveHint: false,
116
+ idempotentHint: true,
117
+ openWorldHint: false,
118
+ },
119
+ }, async (args) => fromToolResult(await runGroupStatus(ctx, args)));
120
+ }
121
+ //# sourceMappingURL=group-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-status.js","sourceRoot":"","sources":["../../src/tools/group-status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `group_sync` — rebuild the cross-repo contract registry for a named
3
+ * group. Walks each registered repo, runs the HTTP / gRPC / topic
4
+ * extractors, and writes the result to
5
+ * `<home>/.codehub/groups/<name>/contracts.json`. The tool returns a
6
+ * compact summary so agents can reason about pairing density before
7
+ * jumping into the richer `group_contracts` tool.
8
+ *
9
+ * Annotations: writes a single file under the home directory — not
10
+ * `readOnlyHint`. `openWorldHint: false` because the scan stays within
11
+ * the registry.
12
+ */
13
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
+ import { type ToolContext, type ToolResult } from "./shared.js";
15
+ interface GroupSyncArgs {
16
+ readonly groupName: string;
17
+ }
18
+ /** Absolute path of `<home>/.codehub/groups/<name>/contracts.json`. */
19
+ export declare function resolveGroupContractsPath(groupName: string, home?: string): string;
20
+ export declare function runGroupSyncTool(ctx: ToolContext, args: GroupSyncArgs): Promise<ToolResult>;
21
+ export declare function registerGroupSyncTool(server: McpServer, ctx: ToolContext): void;
22
+ export {};
23
+ //# sourceMappingURL=group-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-sync.d.ts","sourceRoot":"","sources":["../../src/tools/group-sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,UAAU,EAAgB,MAAM,aAAa,CAAC;AAM9F,UAAU,aAAa;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAID,uEAAuE;AACvE,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAGlF;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAiFjG;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAiB/E"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * `group_sync` — rebuild the cross-repo contract registry for a named
3
+ * group. Walks each registered repo, runs the HTTP / gRPC / topic
4
+ * extractors, and writes the result to
5
+ * `<home>/.codehub/groups/<name>/contracts.json`. The tool returns a
6
+ * compact summary so agents can reason about pairing density before
7
+ * jumping into the richer `group_contracts` tool.
8
+ *
9
+ * Annotations: writes a single file under the home directory — not
10
+ * `readOnlyHint`. `openWorldHint: false` because the scan stays within
11
+ * the registry.
12
+ */
13
+ // biome-ignore-all lint/complexity/useLiteralKeys: dot-access disallowed on Record index signatures
14
+ import { mkdir, rename, writeFile } from "node:fs/promises";
15
+ import { homedir } from "node:os";
16
+ import { dirname, resolve } from "node:path";
17
+ import { runGroupSync } from "@opencodehub/analysis";
18
+ import { z } from "zod";
19
+ import { toolError, toolErrorFromUnknown } from "../error-envelope.js";
20
+ import { readGroup } from "../group-resolver.js";
21
+ import { withNextSteps } from "../next-step-hints.js";
22
+ import { readRegistry } from "../repo-resolver.js";
23
+ import { repoUriForEntry } from "../repo-uri-for-entry.js";
24
+ import { fromToolResult, toToolResult } from "./shared.js";
25
+ const GroupSyncInput = {
26
+ groupName: z.string().min(1).describe("Name of the group to sync."),
27
+ };
28
+ const CODEHUB_HOME_DIR = ".codehub";
29
+ /** Absolute path of `<home>/.codehub/groups/<name>/contracts.json`. */
30
+ export function resolveGroupContractsPath(groupName, home) {
31
+ const root = home ?? homedir();
32
+ return resolve(root, CODEHUB_HOME_DIR, "groups", groupName, "contracts.json");
33
+ }
34
+ export async function runGroupSyncTool(ctx, args) {
35
+ try {
36
+ const opts = ctx.home !== undefined ? { home: ctx.home } : {};
37
+ const group = await readGroup(args.groupName, opts);
38
+ if (!group) {
39
+ return toToolResult(toolError("NOT_FOUND", `Group ${args.groupName} is not defined.`, "Run `codehub group list` to see defined groups."));
40
+ }
41
+ const registry = await readRegistry(opts);
42
+ const sortedRepos = [...group.repos].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
43
+ const inputs = [];
44
+ const missing = [];
45
+ // Additive per-repo `{name, repo_uri}` rows surfaced in the
46
+ // structured response so agents that consume `group_sync` can key
47
+ // on the new handle without re-running `group_list`. Legacy top-
48
+ // level `repos: string[]` (from `ContractRegistry`) stays intact.
49
+ const reposWithUri = [];
50
+ for (const repo of sortedRepos) {
51
+ const hit = registry[repo.name];
52
+ if (!hit) {
53
+ missing.push(repo.name);
54
+ continue;
55
+ }
56
+ inputs.push({ name: repo.name, path: resolve(hit.path) });
57
+ reposWithUri.push({
58
+ name: repo.name,
59
+ repo_uri: await repoUriForEntry(hit, ctx.pool),
60
+ });
61
+ }
62
+ const registryResult = await runGroupSync({ repos: inputs });
63
+ const outPath = resolveGroupContractsPath(group.name, ctx.home);
64
+ await mkdir(dirname(outPath), { recursive: true });
65
+ const payload = `${JSON.stringify(registryResult, null, 2)}\n`;
66
+ // Atomic write: stage at `.tmp` sibling, rename into place. Keeps
67
+ // concurrent readers from seeing a torn write mid-flight.
68
+ const tmp = `${outPath}.tmp`;
69
+ await writeFile(tmp, payload, "utf8");
70
+ await rename(tmp, outPath);
71
+ const header = `group_sync: wrote ${registryResult.contracts.length} contract(s) and ${registryResult.crossLinks.length} cross-link(s) for ${group.name}.`;
72
+ const body = [`Registry → ${outPath}`];
73
+ if (missing.length > 0) {
74
+ body.push(`Skipped ${missing.length} unregistered repo(s): ${missing.join(", ")}`);
75
+ }
76
+ const next = registryResult.crossLinks.length === 0
77
+ ? [
78
+ `call \`group_contracts\` with groupName="${group.name}" to inspect extracted contracts`,
79
+ `confirm repos are freshly analyzed with \`group_status\` for ${group.name}`,
80
+ ]
81
+ : [
82
+ `call \`group_contracts\` with groupName="${group.name}" to browse producer↔consumer pairs`,
83
+ ];
84
+ return toToolResult(withNextSteps([header, ...body].join("\n"), {
85
+ groupName: group.name,
86
+ registryPath: outPath,
87
+ contractCount: registryResult.contracts.length,
88
+ crossLinkCount: registryResult.crossLinks.length,
89
+ missingRepos: missing,
90
+ repos: registryResult.repos,
91
+ // Additive field — per-repo `{name, repo_uri}` rows.
92
+ reposWithUri,
93
+ }, next));
94
+ }
95
+ catch (err) {
96
+ return toToolResult(toolErrorFromUnknown(err));
97
+ }
98
+ }
99
+ export function registerGroupSyncTool(server, ctx) {
100
+ server.registerTool("group_sync", {
101
+ title: "Rebuild cross-repo contract registry",
102
+ description: "Walk every repo in a named group, run HTTP / gRPC / topic contract extractors, and write `<home>/.codehub/groups/<name>/contracts.json`. Returns a summary of extracted contracts + cross-links. Use this before calling `group_contracts` when you want the registry to reflect the current working tree.",
103
+ inputSchema: GroupSyncInput,
104
+ annotations: {
105
+ readOnlyHint: false,
106
+ destructiveHint: false,
107
+ idempotentHint: true,
108
+ openWorldHint: false,
109
+ },
110
+ }, async (args) => fromToolResult(await runGroupSyncTool(ctx, args)));
111
+ }
112
+ //# sourceMappingURL=group-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-sync.js","sourceRoot":"","sources":["../../src/tools/group-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * `impact` — blast-radius analysis for a symbol.
3
+ *
4
+ * Delegates to `@opencodehub/analysis.runImpact`. Surfaces:
5
+ * - `target_uid` for zero-ambiguity lookup by node id,
6
+ * - `file_path` + `kind` filters to disambiguate same-named symbols,
7
+ * - `relationTypes` to widen/narrow the traversal edge set
8
+ * (default: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, METHOD_OVERRIDES,
9
+ * METHOD_IMPLEMENTS, HAS_METHOD, HAS_PROPERTY),
10
+ * - `includeTests` to opt into test-file dependents (default: false),
11
+ * - `minConfidence` to filter heuristic edges (default: 0.7).
12
+ *
13
+ * When the analysis layer reports `ambiguous: true` we surface the candidate
14
+ * list as an INVALID_INPUT error envelope with a ranked list so the caller
15
+ * can re-invoke with `target_uid`, `file_path`, or `kind` — mirroring the
16
+ * same EC-04 disambiguation pattern used by `context`.
17
+ */
18
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
19
+ import { type ToolContext, type ToolResult } from "./shared.js";
20
+ interface ImpactArgs {
21
+ readonly target: string;
22
+ readonly target_uid?: string | undefined;
23
+ readonly file_path?: string | undefined;
24
+ readonly kind?: string | undefined;
25
+ readonly direction?: "upstream" | "downstream" | "both" | undefined;
26
+ readonly maxDepth?: number | undefined;
27
+ readonly minConfidence?: number | undefined;
28
+ readonly relationTypes?: readonly string[] | undefined;
29
+ readonly includeTests?: boolean | undefined;
30
+ readonly repo?: string | undefined;
31
+ readonly repo_uri?: string | undefined;
32
+ }
33
+ export declare function runImpact(ctx: ToolContext, args: ImpactArgs): Promise<ToolResult>;
34
+ export declare function registerImpactTool(server: McpServer, ctx: ToolContext): void;
35
+ export {};
36
+ //# sourceMappingURL=impact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.d.ts","sourceRoot":"","sources":["../../src/tools/impact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,UAAU,EAGhB,MAAM,aAAa,CAAC;AAwDrB,UAAU,UAAU;IAClB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,CAAC;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAoJvF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAiB5E"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * `impact` — blast-radius analysis for a symbol.
3
+ *
4
+ * Delegates to `@opencodehub/analysis.runImpact`. Surfaces:
5
+ * - `target_uid` for zero-ambiguity lookup by node id,
6
+ * - `file_path` + `kind` filters to disambiguate same-named symbols,
7
+ * - `relationTypes` to widen/narrow the traversal edge set
8
+ * (default: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, METHOD_OVERRIDES,
9
+ * METHOD_IMPLEMENTS, HAS_METHOD, HAS_PROPERTY),
10
+ * - `includeTests` to opt into test-file dependents (default: false),
11
+ * - `minConfidence` to filter heuristic edges (default: 0.7).
12
+ *
13
+ * When the analysis layer reports `ambiguous: true` we surface the candidate
14
+ * list as an INVALID_INPUT error envelope with a ranked list so the caller
15
+ * can re-invoke with `target_uid`, `file_path`, or `kind` — mirroring the
16
+ * same EC-04 disambiguation pattern used by `context`.
17
+ */
18
+ import { z } from "zod";
19
+ import { callRunImpact } from "../analysis-bridge.js";
20
+ import { toolError, toolErrorFromUnknown } from "../error-envelope.js";
21
+ import { withNextSteps } from "../next-step-hints.js";
22
+ import { stalenessFromMeta } from "../staleness.js";
23
+ import { computeConfidenceBreakdown } from "./confidence.js";
24
+ import { fromToolResult, repoArgShape, toToolResult, withStore, } from "./shared.js";
25
+ const ImpactInput = {
26
+ target: z
27
+ .string()
28
+ .min(1)
29
+ .describe("Symbol name OR node id of the change target. Node id gives an exact match."),
30
+ target_uid: z
31
+ .string()
32
+ .optional()
33
+ .describe("Exact node id (UID) from a prior tool result. Skips name disambiguation entirely."),
34
+ file_path: z
35
+ .string()
36
+ .optional()
37
+ .describe("File path (or suffix) to disambiguate when multiple symbols share a name."),
38
+ kind: z
39
+ .string()
40
+ .optional()
41
+ .describe("Kind filter to disambiguate same-named symbols (e.g. Function, Method, Class, Interface)."),
42
+ direction: z
43
+ .enum(["upstream", "downstream", "both"])
44
+ .optional()
45
+ .describe("upstream = dependents (who breaks if this changes), downstream = dependencies, both = transitive both ways. Default: upstream."),
46
+ maxDepth: z.number().int().min(1).max(6).optional().describe("Traversal depth cap. Default 3."),
47
+ minConfidence: z
48
+ .number()
49
+ .min(0)
50
+ .max(1)
51
+ .optional()
52
+ .describe("Drop edges below this confidence. Default 0.7."),
53
+ relationTypes: z
54
+ .array(z.string())
55
+ .optional()
56
+ .describe("Filter: CALLS, IMPORTS, EXTENDS, IMPLEMENTS, METHOD_OVERRIDES, METHOD_IMPLEMENTS, HAS_METHOD, HAS_PROPERTY, ACCESSES. Default: the first 8."),
57
+ includeTests: z
58
+ .boolean()
59
+ .optional()
60
+ .describe("When true, test-file dependents are counted. Default false — test nodes are filtered out."),
61
+ ...repoArgShape,
62
+ };
63
+ export async function runImpact(ctx, args) {
64
+ const call = await withStore(ctx, args, async (store, resolved) => {
65
+ try {
66
+ const direction = args.direction ?? "upstream";
67
+ const q = {
68
+ target: args.target,
69
+ direction,
70
+ };
71
+ if (args.maxDepth !== undefined)
72
+ q.maxDepth = args.maxDepth;
73
+ if (args.minConfidence !== undefined)
74
+ q.minConfidence = args.minConfidence;
75
+ if (args.relationTypes && args.relationTypes.length > 0) {
76
+ q.relationTypes = args.relationTypes;
77
+ }
78
+ if (args.target_uid !== undefined && args.target_uid.length > 0) {
79
+ q.targetUid = args.target_uid;
80
+ }
81
+ if (args.file_path !== undefined && args.file_path.length > 0) {
82
+ q.filePath = args.file_path;
83
+ }
84
+ if (args.kind !== undefined && args.kind.length > 0)
85
+ q.kind = args.kind;
86
+ if (args.includeTests !== undefined)
87
+ q.includeTests = args.includeTests;
88
+ const result = await callRunImpact(store.graph, q);
89
+ if (result.ambiguous) {
90
+ const candidates = result.targetCandidates.slice(0, 10).map((c) => ({
91
+ uid: c.id,
92
+ name: c.name,
93
+ filePath: c.filePath,
94
+ kind: c.kind,
95
+ }));
96
+ const list = candidates
97
+ .map((c, i) => `${i + 1}. [${c.kind}] ${c.name} — ${c.filePath} (${c.uid})`)
98
+ .join("\n");
99
+ return toolError("INVALID_INPUT", `Target "${args.target}" matched ${result.targetCandidates.length} symbols. Re-call with target_uid, file_path, or kind.\n${list}`, "pass target_uid from one of the listed candidates, or narrow with file_path/kind");
100
+ }
101
+ const chosen = result.chosenTarget;
102
+ const chosenLabel = chosen ? `${chosen.name} [${chosen.kind}]` : args.target;
103
+ const confidenceBreakdown = computeConfidenceBreakdown(result.traversedEdges);
104
+ const cochanges = chosen ? await fetchCochangesForFile(store.temporal, chosen.filePath) : [];
105
+ const byDepthMap = buildByDepthMap(result.byDepth);
106
+ const affectedProcesses = mapProcesses(result.affectedProcesses);
107
+ const affectedModules = mapModules(result.affectedModules);
108
+ const impactedCount = result.totalAffected;
109
+ const lines = [];
110
+ lines.push(`Impact for ${chosenLabel} (${direction}, depth≤${q.maxDepth ?? 3})`);
111
+ lines.push(`Risk: ${result.risk} (${impactedCount} impacted)`);
112
+ lines.push(`Summary: ${byDepthMap[1]?.length ?? 0} direct, ${affectedProcesses.length} process(es), ${affectedModules.length} module(s)`);
113
+ lines.push(`Confidence: ${confidenceBreakdown.confirmed} confirmed, ` +
114
+ `${confidenceBreakdown.heuristic} heuristic, ` +
115
+ `${confidenceBreakdown.unknown} unknown`);
116
+ for (const bucket of result.byDepth) {
117
+ lines.push(`d=${bucket.depth} (${bucket.nodes.length}):`);
118
+ for (const n of bucket.nodes.slice(0, 20)) {
119
+ lines.push(` • ${n.name} [${n.kind}] via ${n.viaRelation} — ${n.filePath || "(no file)"}`);
120
+ }
121
+ if (bucket.nodes.length > 20) {
122
+ lines.push(` … ${bucket.nodes.length - 20} more`);
123
+ }
124
+ }
125
+ if (affectedProcesses.length > 0) {
126
+ lines.push(`Affected processes (${affectedProcesses.length}):`);
127
+ for (const p of affectedProcesses) {
128
+ lines.push(` ⊿ ${p.label} — ${p.entryPointFile}`);
129
+ }
130
+ }
131
+ if (affectedModules.length > 0) {
132
+ lines.push(`Affected modules (${affectedModules.length}):`);
133
+ for (const m of affectedModules) {
134
+ lines.push(` ⊡ ${m.name} [${m.impact}] — ${m.hits} hit(s)`);
135
+ }
136
+ }
137
+ if (cochanges.length > 0) {
138
+ lines.push(`Files often edited together with this one (by lift) — git history, NOT call dependencies (${cochanges.length}):`);
139
+ for (const p of cochanges) {
140
+ lines.push(` ⇌ ${p.file} [lift=${p.lift.toFixed(2)}, co-commits=${p.cocommitCount}, last=${p.lastCocommitAt}]`);
141
+ }
142
+ }
143
+ if (result.hint)
144
+ lines.push(`Hint: ${result.hint}`);
145
+ const next = [];
146
+ const d1 = byDepthMap[1]?.length ?? 0;
147
+ if (d1 > 0) {
148
+ next.push("review d=1 nodes first — they will definitely break");
149
+ next.push("call `context` on each d=1 node to craft targeted tests");
150
+ }
151
+ else {
152
+ next.push("no direct dependents — this change looks safe");
153
+ }
154
+ if (confidenceBreakdown.heuristic + confidenceBreakdown.unknown >
155
+ confidenceBreakdown.confirmed) {
156
+ next.push("blast radius rests mostly on unconfirmed edges — treat the risk band as a lower bound and probe heuristic callers manually");
157
+ }
158
+ return withNextSteps(lines.join("\n"), {
159
+ target: chosen
160
+ ? { id: chosen.id, name: chosen.name, kind: chosen.kind, filePath: chosen.filePath }
161
+ : null,
162
+ direction,
163
+ risk: result.risk,
164
+ impactedCount,
165
+ byDepth: byDepthMap,
166
+ affected_processes: affectedProcesses,
167
+ affected_modules: affectedModules,
168
+ confidenceBreakdown,
169
+ traversedEdges: result.traversedEdges,
170
+ cochanges,
171
+ ambiguous: false,
172
+ }, next, stalenessFromMeta(resolved.meta));
173
+ }
174
+ catch (err) {
175
+ return toolErrorFromUnknown(err);
176
+ }
177
+ });
178
+ return toToolResult(call);
179
+ }
180
+ export function registerImpactTool(server, ctx) {
181
+ server.registerTool("impact", {
182
+ title: "Change-impact blast radius",
183
+ description: "Walk the graph from a target symbol and group dependents by traversal depth. Depth-1 nodes will definitely break if the target's contract changes; depth-2 very likely; depth-3+ transitive. Returns a risk band (LOW/MEDIUM/HIGH/CRITICAL) derived from impactedCount + process count, plus `byDepth` groups, `affected_processes`, `affected_modules`, and a `confidenceBreakdown` (confirmed / heuristic / unknown) tallying the provenance tier of every edge traversed — low-risk verdicts are only trustworthy when `heuristic` and `unknown` are small relative to `confirmed`. Ambiguous names return an INVALID_INPUT error with a candidate list so the caller can re-invoke with `target_uid`, `file_path`, or `kind`. A side-section `cochanges` field lists files historically co-edited with the target's enclosing file, ranked by lift. These come from git history, not the call graph, and MUST NOT be mixed into the impactedNodes list.",
184
+ inputSchema: ImpactInput,
185
+ annotations: {
186
+ readOnlyHint: true,
187
+ destructiveHint: false,
188
+ idempotentHint: true,
189
+ openWorldHint: false,
190
+ },
191
+ }, async (args) => fromToolResult(await runImpact(ctx, args)));
192
+ }
193
+ /**
194
+ * Re-shape the analysis-layer `byDepth` array into the `{1: [...], 2: [...]}`
195
+ * map the MCP contract exposes. The array form is kept for text rendering;
196
+ * the map form is what agents consume programmatically.
197
+ */
198
+ function buildByDepthMap(buckets) {
199
+ const out = {};
200
+ for (const b of buckets) {
201
+ out[b.depth] = [...b.nodes];
202
+ }
203
+ return out;
204
+ }
205
+ function mapProcesses(procs) {
206
+ return procs.map((p) => ({ id: p.id, label: p.name, entryPointFile: p.entryPointFile }));
207
+ }
208
+ function mapModules(mods) {
209
+ return mods.map((m) => ({ name: m.name, hits: m.hits, impact: m.impact }));
210
+ }
211
+ /**
212
+ * Side-channel lookup for the `cochanges` section of the impact response.
213
+ * Cochange is a git-history signal and must not be mixed into the call-graph
214
+ * blast radius — we fetch it independently and surface it as its own field.
215
+ */
216
+ async function fetchCochangesForFile(temporal, file) {
217
+ if (file.length === 0)
218
+ return [];
219
+ const rows = await temporal.lookupCochangesForFile(file, { limit: 10 });
220
+ const out = [];
221
+ for (const r of rows) {
222
+ const partner = r.sourceFile === file ? r.targetFile : r.sourceFile;
223
+ out.push({
224
+ file: partner,
225
+ cocommitCount: r.cocommitCount,
226
+ lift: r.lift,
227
+ lastCocommitAt: r.lastCocommitAt,
228
+ });
229
+ }
230
+ return out;
231
+ }
232
+ //# sourceMappingURL=impact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impact.js","sourceRoot":"","sources":["../../src/tools/impact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `license_audit` — classify Dependency nodes by license risk tier.
3
+ *
4
+ * Walks every Dependency node the ingestion pipeline produced and sorts
5
+ * each one into three buckets:
6
+ *
7
+ * - copyleft — names matching GPL/AGPL/SSPL/EUPL/CPAL/OSL/RPL. These
8
+ * are redistribution-contagious licenses that the host
9
+ * project (Apache-2.0) cannot safely link against.
10
+ * - proprietary — explicit "PROPRIETARY" declarations.
11
+ * - unknown — missing licenses or the `"UNKNOWN"` sentinel emitted
12
+ * by the dependency phase when a manifest parser could
13
+ * not recover a declared license. A later release will
14
+ * populate real licenses from ecosystem metadata;
15
+ * until then most audits WILL return tier=WARN.
16
+ *
17
+ * Tier assignment:
18
+ * BLOCK — any copyleft OR any proprietary dep.
19
+ * WARN — no copyleft/proprietary, at least one unknown.
20
+ * OK — nothing flagged.
21
+ *
22
+ * Annotations are {readOnly, closedWorld, idempotent} — the tool only
23
+ * queries the graph.
24
+ */
25
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
26
+ import { type ToolContext, type ToolResult } from "./shared.js";
27
+ interface LicenseAuditArgs {
28
+ readonly repo?: string | undefined;
29
+ readonly repo_uri?: string | undefined;
30
+ }
31
+ export declare function runLicenseAudit(ctx: ToolContext, args: LicenseAuditArgs): Promise<ToolResult>;
32
+ export declare function registerLicenseAuditTool(server: McpServer, ctx: ToolContext): void;
33
+ export {};
34
+ //# sourceMappingURL=license-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license-audit.d.ts","sourceRoot":"","sources":["../../src/tools/license-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,UAAU,EAGhB,MAAM,aAAa,CAAC;AAMrB,UAAU,gBAAgB;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,UAAU,CAAC,CAkFrB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAiBlF"}