@arii/boomtick-mcp 0.3.3

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 (187) hide show
  1. package/.env.example +6 -0
  2. package/.mcp/schemas/agent.search_ddgs.json +1 -0
  3. package/.mcp/schemas/boomtick.health.json +1 -0
  4. package/.mcp/schemas/github.checkout_branch.json +1 -0
  5. package/.mcp/schemas/github.comment_triage_summary.json +1 -0
  6. package/.mcp/schemas/github.create_issue.json +1 -0
  7. package/.mcp/schemas/github.create_pull_request.json +1 -0
  8. package/.mcp/schemas/github.get_merge_conflict_files.json +1 -0
  9. package/.mcp/schemas/github.get_pr.json +1 -0
  10. package/.mcp/schemas/github.get_pr_diff.json +1 -0
  11. package/.mcp/schemas/github.issue_comment.json +1 -0
  12. package/.mcp/schemas/github.issue_update.json +1 -0
  13. package/.mcp/schemas/github.issue_view.json +1 -0
  14. package/.mcp/schemas/github.open_replacement_pr.json +1 -0
  15. package/.mcp/schemas/github.search_open_prs.json +1 -0
  16. package/.mcp/schemas/jules.cancel_session.json +1 -0
  17. package/.mcp/schemas/jules.create_session.json +1 -0
  18. package/.mcp/schemas/jules.get_messages.json +1 -0
  19. package/.mcp/schemas/jules.get_pr.json +1 -0
  20. package/.mcp/schemas/jules.get_session.json +1 -0
  21. package/.mcp/schemas/jules.list_sessions.json +1 -0
  22. package/.mcp/schemas/jules.send_message.json +1 -0
  23. package/.mcp/schemas/jules.trigger_feedback.json +1 -0
  24. package/.mcp/schemas/repo.commit_patch.json +1 -0
  25. package/.mcp/schemas/repo.create_branch.json +1 -0
  26. package/.mcp/schemas/repo.create_repair_branch.json +1 -0
  27. package/.mcp/schemas/repo.get_changed_files.json +1 -0
  28. package/.mcp/schemas/repo.get_command_schema.json +1 -0
  29. package/.mcp/schemas/repo.get_package_scripts.json +1 -0
  30. package/.mcp/schemas/repo.get_route_map.json +1 -0
  31. package/.mcp/schemas/repo.logs.json +1 -0
  32. package/.mcp/schemas/repo.read_agent_context.json +1 -0
  33. package/.mcp/schemas/repo.read_ci_logs.json +1 -0
  34. package/.mcp/schemas/repo.run_lighthouse.json +1 -0
  35. package/.mcp/schemas/repo.run_playwright.json +1 -0
  36. package/.mcp/schemas/repo.run_tests.json +1 -0
  37. package/CHANGELOG.md +50 -0
  38. package/README.md +108 -0
  39. package/actions/ai-review/action.yml +15 -0
  40. package/actions/audit/action.yml +37 -0
  41. package/actions/ci-validate/action.yml +9 -0
  42. package/actions/impact-analysis/action.yml +385 -0
  43. package/actions/lint-typecheck/action.yml +19 -0
  44. package/actions/run-project-gate/action.yml +163 -0
  45. package/actions/setup/action.yml +15 -0
  46. package/actions/setup-workspace/action.yml +179 -0
  47. package/actions/test-build/action.yml +71 -0
  48. package/actions/update-pr-comment/action.yml +101 -0
  49. package/dist/config.js +110 -0
  50. package/dist/evals/run-evals.js +38 -0
  51. package/dist/index.js +10 -0
  52. package/dist/lib/error_utils.js +8 -0
  53. package/dist/lib/git.js +33 -0
  54. package/dist/lib/result.js +21 -0
  55. package/dist/lib/shell.js +91 -0
  56. package/dist/lib/shell.test.js +10 -0
  57. package/dist/lib/td-cli.js +27 -0
  58. package/dist/lib/test-utils.js +20 -0
  59. package/dist/mcp/definitions.js +242 -0
  60. package/dist/mcp/server.js +317 -0
  61. package/dist/mcp/tools.js +18 -0
  62. package/dist/tools/contract.js +2069 -0
  63. package/dist/tools/ddgs.search.js +50 -0
  64. package/dist/tools/ddgs.search.test.js +67 -0
  65. package/dist/tools/ddgs_search.py +23 -0
  66. package/dist/tools/github.checkout_branch.js +20 -0
  67. package/dist/tools/github.comment_triage_summary.js +25 -0
  68. package/dist/tools/github.create_issue.js +28 -0
  69. package/dist/tools/github.create_issue.test.js +54 -0
  70. package/dist/tools/github.create_pull_request.js +44 -0
  71. package/dist/tools/github.get_merge_conflict_files.js +26 -0
  72. package/dist/tools/github.get_pr.js +18 -0
  73. package/dist/tools/github.get_pr_diff.js +24 -0
  74. package/dist/tools/github.issue_comment.js +24 -0
  75. package/dist/tools/github.issue_update.js +29 -0
  76. package/dist/tools/github.issue_view.js +28 -0
  77. package/dist/tools/github.open_replacement_pr.js +41 -0
  78. package/dist/tools/github.search_open_prs.js +31 -0
  79. package/dist/tools/github.search_open_prs.test.js +51 -0
  80. package/dist/tools/jules/cancel-session.js +20 -0
  81. package/dist/tools/jules/create-session.js +20 -0
  82. package/dist/tools/jules/create-session.test.js +99 -0
  83. package/dist/tools/jules/get-messages.js +19 -0
  84. package/dist/tools/jules/get-messages.test.js +45 -0
  85. package/dist/tools/jules/get-pr.js +14 -0
  86. package/dist/tools/jules/get-pr.test.js +37 -0
  87. package/dist/tools/jules/get-session.js +10 -0
  88. package/dist/tools/jules/list-sessions.js +43 -0
  89. package/dist/tools/jules/send-message.js +22 -0
  90. package/dist/tools/jules/send-message.test.js +56 -0
  91. package/dist/tools/jules/shared.js +26 -0
  92. package/dist/tools/jules/trigger-feedback.js +16 -0
  93. package/dist/tools/jules/trigger-feedback.test.js +42 -0
  94. package/dist/tools/repo.commit_patch.js +33 -0
  95. package/dist/tools/repo.create_branch.js +21 -0
  96. package/dist/tools/repo.create_branch.test.js +42 -0
  97. package/dist/tools/repo.create_repair_branch.js +38 -0
  98. package/dist/tools/repo.get_changed_files.js +21 -0
  99. package/dist/tools/repo.get_command_schema.js +27 -0
  100. package/dist/tools/repo.get_package_scripts.js +35 -0
  101. package/dist/tools/repo.get_package_scripts.test.js +39 -0
  102. package/dist/tools/repo.get_route_map.js +37 -0
  103. package/dist/tools/repo.logs.js +16 -0
  104. package/dist/tools/repo.read_agent_context.js +20 -0
  105. package/dist/tools/repo.read_ci_logs.js +18 -0
  106. package/dist/tools/repo.run_lighthouse.js +37 -0
  107. package/dist/tools/repo.run_playwright.js +29 -0
  108. package/dist/tools/repo.run_tests.js +43 -0
  109. package/dist/tools/types.js +1 -0
  110. package/docs/testing.md +73 -0
  111. package/package.json +45 -0
  112. package/scripts/create_instructions.sh +42 -0
  113. package/scripts/export-mcp-schema.ts +7 -0
  114. package/scripts/sync-contracts.ts +74 -0
  115. package/scripts/sync-mcp-schemas.ts +97 -0
  116. package/src/agents/conflict-scout.prompt.md +20 -0
  117. package/src/agents/pr-consolidation.prompt.md +32 -0
  118. package/src/agents/pr-writer.prompt.md +13 -0
  119. package/src/agents/repair-agent.prompt.md +18 -0
  120. package/src/agents/repo-context.prompt.md +20 -0
  121. package/src/agents/verifier-agent.prompt.md +22 -0
  122. package/src/config.ts +113 -0
  123. package/src/evals/fixtures/merge-conflict-simple/README.md +0 -0
  124. package/src/evals/run-evals.ts +40 -0
  125. package/src/index.ts +12 -0
  126. package/src/lib/error_utils.ts +8 -0
  127. package/src/lib/git.ts +41 -0
  128. package/src/lib/result.ts +28 -0
  129. package/src/lib/shell.test.ts +11 -0
  130. package/src/lib/shell.ts +118 -0
  131. package/src/lib/td-cli.ts +38 -0
  132. package/src/lib/test-utils.ts +23 -0
  133. package/src/mcp/definitions.ts +278 -0
  134. package/src/mcp/server.ts +359 -0
  135. package/src/mcp/tools.ts +20 -0
  136. package/src/tools/contract.ts +2245 -0
  137. package/src/tools/ddgs.search.test.ts +92 -0
  138. package/src/tools/ddgs.search.ts +58 -0
  139. package/src/tools/ddgs_search.py +23 -0
  140. package/src/tools/github.checkout_branch.ts +25 -0
  141. package/src/tools/github.comment_triage_summary.ts +30 -0
  142. package/src/tools/github.create_issue.test.ts +63 -0
  143. package/src/tools/github.create_issue.ts +34 -0
  144. package/src/tools/github.create_pull_request.ts +50 -0
  145. package/src/tools/github.get_merge_conflict_files.ts +31 -0
  146. package/src/tools/github.get_pr.ts +24 -0
  147. package/src/tools/github.get_pr_diff.ts +29 -0
  148. package/src/tools/github.issue_comment.ts +31 -0
  149. package/src/tools/github.issue_update.ts +31 -0
  150. package/src/tools/github.issue_view.ts +35 -0
  151. package/src/tools/github.open_replacement_pr.ts +48 -0
  152. package/src/tools/github.search_open_prs.test.ts +60 -0
  153. package/src/tools/github.search_open_prs.ts +40 -0
  154. package/src/tools/jules/cancel-session.ts +26 -0
  155. package/src/tools/jules/create-session.test.ts +114 -0
  156. package/src/tools/jules/create-session.ts +24 -0
  157. package/src/tools/jules/get-messages.test.ts +52 -0
  158. package/src/tools/jules/get-messages.ts +24 -0
  159. package/src/tools/jules/get-pr.test.ts +43 -0
  160. package/src/tools/jules/get-pr.ts +17 -0
  161. package/src/tools/jules/get-session.ts +12 -0
  162. package/src/tools/jules/list-sessions.ts +50 -0
  163. package/src/tools/jules/send-message.test.ts +66 -0
  164. package/src/tools/jules/send-message.ts +27 -0
  165. package/src/tools/jules/shared.ts +28 -0
  166. package/src/tools/jules/trigger-feedback.test.ts +50 -0
  167. package/src/tools/jules/trigger-feedback.ts +21 -0
  168. package/src/tools/repo.commit_patch.ts +41 -0
  169. package/src/tools/repo.create_branch.test.ts +55 -0
  170. package/src/tools/repo.create_branch.ts +29 -0
  171. package/src/tools/repo.create_repair_branch.ts +47 -0
  172. package/src/tools/repo.get_changed_files.ts +26 -0
  173. package/src/tools/repo.get_command_schema.ts +30 -0
  174. package/src/tools/repo.get_package_scripts.test.ts +51 -0
  175. package/src/tools/repo.get_package_scripts.ts +36 -0
  176. package/src/tools/repo.get_route_map.ts +41 -0
  177. package/src/tools/repo.logs.ts +21 -0
  178. package/src/tools/repo.read_agent_context.ts +22 -0
  179. package/src/tools/repo.read_ci_logs.ts +21 -0
  180. package/src/tools/repo.run_lighthouse.ts +40 -0
  181. package/src/tools/repo.run_playwright.ts +35 -0
  182. package/src/tools/repo.run_tests.ts +47 -0
  183. package/src/tools/types.ts +8 -0
  184. package/start_browsermcp.sh +14 -0
  185. package/start_github_mcp.sh +6 -0
  186. package/tsconfig.json +15 -0
  187. package/vitest.config.ts +9 -0
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { config } from "../config.js";
5
+ export const GetPackageScriptsInputSchema = z.object({
6
+ filter: z.string().optional(),
7
+ });
8
+ export async function getPackageScriptsHandler(args) {
9
+ GetPackageScriptsInputSchema.parse(args);
10
+ const packageJsonPath = path.join(config.repoPath, "package.json");
11
+ try {
12
+ const content = await fs.readFile(packageJsonPath, "utf-8");
13
+ let pkg;
14
+ try {
15
+ pkg = JSON.parse(content);
16
+ }
17
+ catch (e) {
18
+ throw new Error(`Malformed package.json: ${e instanceof Error ? e.message : String(e)}`);
19
+ }
20
+ let scripts = pkg.scripts || {};
21
+ if (args.filter) {
22
+ const filtered = {};
23
+ for (const [name, cmd] of Object.entries(scripts)) {
24
+ if (name.includes(args.filter)) {
25
+ filtered[name] = cmd;
26
+ }
27
+ }
28
+ scripts = filtered;
29
+ }
30
+ return { scripts };
31
+ }
32
+ catch (error) {
33
+ throw new Error(`Failed to read package.json: ${error instanceof Error ? error.message : String(error)}`);
34
+ }
35
+ }
@@ -0,0 +1,39 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { getPackageScriptsHandler } from "./repo.get_package_scripts.js";
3
+ import fs from "fs/promises";
4
+ vi.mock("fs/promises");
5
+ describe("repo.get_package_scripts", () => {
6
+ it("should return scripts from package.json", async () => {
7
+ const mockPkg = {
8
+ scripts: { test: "vitest" }
9
+ };
10
+ vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockPkg));
11
+ const result = await getPackageScriptsHandler({});
12
+ expect(result.scripts.test).toBe("vitest");
13
+ });
14
+ it("should handle missing scripts", async () => {
15
+ vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify({}));
16
+ const result = await getPackageScriptsHandler({});
17
+ expect(result.scripts).toEqual({});
18
+ });
19
+ it("should throw error when file not found", async () => {
20
+ vi.mocked(fs.readFile).mockRejectedValue(new Error("File not found"));
21
+ await expect(getPackageScriptsHandler({})).rejects.toThrow("Failed to read package.json: File not found");
22
+ });
23
+ it("should filter scripts by pattern", async () => {
24
+ const mockPkg = {
25
+ scripts: {
26
+ test: "vitest",
27
+ build: "vite build",
28
+ "test:ui": "vitest --ui"
29
+ }
30
+ };
31
+ vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockPkg));
32
+ const result = await getPackageScriptsHandler({ filter: "test" });
33
+ expect(result.scripts).toEqual({
34
+ test: "vitest",
35
+ "test:ui": "vitest --ui"
36
+ });
37
+ expect(result.scripts.build).toBeUndefined();
38
+ });
39
+ });
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import { runCommand } from "../lib/shell.js";
3
+ import { config } from "../config.js";
4
+ import path from "path";
5
+ export const GetRouteMapInputSchema = z.object({
6
+ includeStatic: z.boolean().optional(),
7
+ });
8
+ export async function getRouteMapHandler(args) {
9
+ GetRouteMapInputSchema.parse(args);
10
+ // Logic based on tech-dancer repo structure: src/config/routes.ts and content/
11
+ const routesPath = path.join(config.repoPath, "src/config/routes.ts");
12
+ // For simplicity in MVP, we'll try to find routes by listing content files
13
+ // and reading the main routes file if it exists.
14
+ let routeMap = {};
15
+ try {
16
+ const gitFiles = await runCommand("git", ["ls-files", "content/"]);
17
+ const contentFiles = gitFiles.stdout.trim().split("\n");
18
+ for (const file of contentFiles) {
19
+ if (file.endsWith(".md")) {
20
+ const slug = path.basename(file, ".md");
21
+ if (file.includes("/posts/")) {
22
+ routeMap[`/blog/${slug}`] = file;
23
+ }
24
+ else if (file.includes("/resources/")) {
25
+ routeMap[`/resources/${slug}`] = file;
26
+ }
27
+ }
28
+ }
29
+ }
30
+ catch (error) {
31
+ // If no content files, that's fine
32
+ }
33
+ if (args.includeStatic) {
34
+ routeMap["/favicon.ico"] = "public/favicon.ico";
35
+ }
36
+ return { routeMap };
37
+ }
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ import { runTDCli } from "../lib/td-cli.js";
3
+ export const RepoLogsInputSchema = z.object({
4
+ prNumber: z.number(),
5
+ grep: z.string().optional(),
6
+ });
7
+ export async function repoLogsHandler(args) {
8
+ const params = ["repo", "logs", args.prNumber.toString()];
9
+ if (args.grep) {
10
+ params.push("--grep", args.grep);
11
+ }
12
+ const output = await runTDCli(params);
13
+ return {
14
+ logs: output.logs || (output.data ? output.data.logs : undefined)
15
+ };
16
+ }
@@ -0,0 +1,20 @@
1
+ import { z } from "zod";
2
+ import fs from "fs/promises";
3
+ import path from "path";
4
+ import { config } from "../config.js";
5
+ export const ReadAgentContextInputSchema = z.object({});
6
+ export async function readAgentContextHandler(_args) {
7
+ const contextPath = path.join(config.repoPath, ".agent-context.json");
8
+ try {
9
+ const content = await fs.readFile(contextPath, "utf-8");
10
+ const parsed = JSON.parse(content);
11
+ return {
12
+ status: "success",
13
+ ...parsed
14
+ };
15
+ }
16
+ catch (e) {
17
+ console.error("Failed to read agent context:", e.message);
18
+ throw new Error(`Failed to read agent context from ${contextPath}. Ensure it exists by running 'td-cli context-warm'.`);
19
+ }
20
+ }
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ import { runTDCli } from "../lib/td-cli.js";
3
+ export const ReadCiLogsInputSchema = z.object({
4
+ prNumber: z.number(),
5
+ all: z.boolean().optional(),
6
+ });
7
+ export async function readCiLogsHandler(args) {
8
+ const params = ["repo", "ci-logs", args.prNumber.toString()];
9
+ if (args.all) {
10
+ params.push("--all");
11
+ }
12
+ const output = await runTDCli(params);
13
+ return {
14
+ checks: output.checks,
15
+ failedChecks: output.failedChecks,
16
+ logs: output.logs
17
+ };
18
+ }
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import { runCommand } from "../lib/shell.js";
3
+ export const RunLighthouseInputSchema = z.object({
4
+ route: z.string().optional().default("/"),
5
+ worktreePath: z.string().optional(),
6
+ });
7
+ export async function runLighthouseHandler(args) {
8
+ const results = await runCommand("pnpm", ["lhci", "autorun", "--json"], { cwd: args.worktreePath });
9
+ let summary = {};
10
+ const failures = [];
11
+ try {
12
+ // Attempt to parse summary from LHCI output if available
13
+ // For MVP, we'll provide a structured placeholder if actual JSON isn't present
14
+ if (results.stdout.includes("{")) {
15
+ const possibleJson = results.stdout.substring(results.stdout.indexOf("{"));
16
+ summary = JSON.parse(possibleJson);
17
+ }
18
+ else {
19
+ summary = {
20
+ performance: 0,
21
+ accessibility: 0,
22
+ bestPractices: 0,
23
+ seo: 0
24
+ };
25
+ }
26
+ }
27
+ catch (e) {
28
+ failures.push("Failed to parse Lighthouse report");
29
+ }
30
+ return {
31
+ success: results.exitCode === 0,
32
+ route: args.route,
33
+ summary,
34
+ failures,
35
+ command: results.command
36
+ };
37
+ }
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import { runCommand } from "../lib/shell.js";
3
+ export const RunPlaywrightInputSchema = z.object({
4
+ grep: z.string().optional(),
5
+ worktreePath: z.string().optional(),
6
+ });
7
+ export async function runPlaywrightHandler(args) {
8
+ const tdArgs = ["repo", "run-playwright"];
9
+ if (args.grep) {
10
+ tdArgs.push("--grep", args.grep);
11
+ }
12
+ if (args.worktreePath) {
13
+ tdArgs.push("--worktree", args.worktreePath);
14
+ }
15
+ const result = await runCommand("td-cli", tdArgs);
16
+ if (result.exitCode !== 0) {
17
+ // Playwright might exit with non-zero if tests fail, but our td-cli should ideally handle it
18
+ // and return a JSON with success: false.
19
+ }
20
+ const output = JSON.parse(result.stdout);
21
+ if (output.status === "error") {
22
+ throw new Error(`Failed to run Playwright: ${output.message}`);
23
+ }
24
+ return {
25
+ success: output.success,
26
+ command: output.command,
27
+ failedTests: output.failedTests
28
+ };
29
+ }
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ import { runCommand } from "../lib/shell.js";
3
+ export const RunTestsInputSchema = z.object({
4
+ commands: z.array(z.string()).optional(),
5
+ timeoutSeconds: z.number().optional().default(300),
6
+ worktreePath: z.string().optional(),
7
+ });
8
+ export async function runTestsHandler(args) {
9
+ const commands = args.commands || [
10
+ "pnpm install --frozen-lockfile",
11
+ "pnpm lint",
12
+ "pnpm test",
13
+ "pnpm build"
14
+ ];
15
+ const results = [];
16
+ let success = true;
17
+ for (const fullCmd of commands) {
18
+ const [cmd, ...cmdArgs] = fullCmd.split(" ");
19
+ try {
20
+ const res = await runCommand(cmd, cmdArgs, {
21
+ cwd: args.worktreePath,
22
+ timeout: args.timeoutSeconds * 1000
23
+ });
24
+ results.push(res);
25
+ if (res.exitCode !== 0) {
26
+ success = false;
27
+ break;
28
+ }
29
+ }
30
+ catch (e) {
31
+ success = false;
32
+ results.push({
33
+ command: fullCmd,
34
+ stdout: "",
35
+ stderr: e instanceof Error ? e.message : String(e),
36
+ exitCode: 1,
37
+ durationMs: 0
38
+ });
39
+ break;
40
+ }
41
+ }
42
+ return { success, results };
43
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ # Boomtick MCP Testing Plan
2
+
3
+ This document outlines the steps to verify the Boomtick MCP server functionality locally.
4
+
5
+ ## 1. Automated Unit Tests
6
+ Run the unit test suite to verify core tool handlers and utilities.
7
+ ```bash
8
+ cd boomtick-mcp
9
+ pnpm test
10
+ ```
11
+ **Expected Result**: All tests in `src/lib/shell.test.ts`, `src/tools/github.search_open_prs.test.ts`, and `src/tools/repo.get_package_scripts.test.ts` should pass.
12
+
13
+ ## 2. Build Verification
14
+ Ensure the TypeScript source compiles correctly to ESM.
15
+ ```bash
16
+ cd boomtick-mcp
17
+ pnpm run build
18
+ ```
19
+ **Expected Result**: The `dist/` directory is populated with `.js` files and no compilation errors occur.
20
+
21
+ ## 3. Evaluation Suite
22
+ Run the internal evaluation runner which simulates tool calls in a real (or mocked) environment.
23
+ ```bash
24
+ cd boomtick-mcp
25
+ # Note: Ensure you have a valid .env or appropriate environment variables for repo paths
26
+ pnpm run run-evals
27
+ ```
28
+ **Expected Result**:
29
+ - Health check returns status "ok".
30
+ - Repository scripts are successfully extracted.
31
+ - GitHub PR search is attempted (may report auth error if token is missing, which is expected behavior).
32
+
33
+ ## 4. MCP Capability Discovery (JSON-RPC)
34
+ Verify that the server correctly registers and exposes its capabilities via the MCP protocol.
35
+
36
+ ### List Tools
37
+ ```bash
38
+ echo '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }' | node dist/index.js
39
+ ```
40
+ **Expected Result**: A JSON response containing the registered tools including `jules.create_session`, `jules.get_session`, etc.
41
+
42
+ ### List Resources
43
+ ```bash
44
+ echo '{ "jsonrpc": "2.0", "id": 1, "method": "resources/list", "params": {} }' | node dist/index.js
45
+ ```
46
+ **Expected Result**: A JSON response containing 8 resources.
47
+
48
+ ### List Prompts
49
+ ```bash
50
+ echo '{ "jsonrpc": "2.0", "id": 1, "method": "prompts/list", "params": {} }' | node dist/index.js
51
+ ```
52
+ **Expected Result**: A JSON response containing 5 prompts.
53
+
54
+ ## 5. Manual Resource Access
55
+ Verify that the server can read repository files via the Resource protocol.
56
+ ```bash
57
+ echo '{ "jsonrpc": "2.0", "id": 1, "method": "resources/read", "params": { "uri": "repo://package-json" } }' | node dist/index.js
58
+ ```
59
+ **Expected Result**: The content of the repository's `package.json` is returned in the `text` field.
60
+
61
+ ## 6. Manual Prompt Access
62
+ Verify that agent instructions are correctly retrieved.
63
+ ```bash
64
+ echo '{ "jsonrpc": "2.0", "id": 1, "method": "prompts/get", "params": { "name": "conflict-scout" } }' | node dist/index.js
65
+ ```
66
+ **Expected Result**: The markdown content of `src/agents/conflict-scout.prompt.md` is returned.
67
+
68
+ ## 7. Safety Verification (Write Guards)
69
+ Verify that mutating tools refuse to run without explicit flags.
70
+ ```bash
71
+ echo '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "repo.create_repair_branch", "arguments": { "prNumber": 1 } } }' | node dist/index.js
72
+ ```
73
+ **Expected Result**: An error message stating `writeMode must be true`.
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@arii/boomtick-mcp",
3
+ "version": "0.3.3",
4
+ "description": "Boomtick MCP Guide: PR Rescue + Merge Conflict Agent",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "main": "dist/index.js",
10
+ "bin": {
11
+ "boomtick-mcp": "dist/index.js"
12
+ },
13
+ "scripts": {
14
+ "build": "tsx scripts/sync-contracts.ts && tsc && shx cp src/tools/ddgs_search.py dist/tools/ && tsx scripts/sync-mcp-schemas.ts",
15
+ "watch": "tsc -w",
16
+ "start": "node dist/index.js",
17
+ "test": "tsx scripts/sync-contracts.ts && vitest run",
18
+ "run-evals": "node dist/evals/run-evals.js",
19
+ "sync:mcp-schemas": "tsx scripts/sync-mcp-schemas.ts",
20
+ "release:patch": "pnpm version patch",
21
+ "release:minor": "pnpm version minor",
22
+ "release:major": "pnpm version major",
23
+ "sync-contracts": "tsx scripts/sync-contracts.ts",
24
+ "type-check": "tsx scripts/sync-contracts.ts && tsc",
25
+ "lint": "tsx scripts/sync-contracts.ts && tsc --noEmit"
26
+ },
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.6.0",
29
+ "dotenv": "^17.4.2",
30
+ "zod": "^4.4.3"
31
+ },
32
+ "packageManager": "pnpm@10.28.2",
33
+ "engines": {
34
+ "node": "24.x",
35
+ "pnpm": "10.28.2"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.17.15",
39
+ "json-schema-to-zod": "^2.8.1",
40
+ "tsx": "^4.22.4",
41
+ "shx": "^0.4.0",
42
+ "typescript": "^5.7.3",
43
+ "vitest": "^4.1.9"
44
+ }
45
+ }
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ OUTPUT_FILE="${1:-src/agents/pr-consolidation.prompt.md}"
5
+ mkdir -p "$(dirname "$OUTPUT_FILE")"
6
+
7
+ cat << 'MARKDOWN' > "$OUTPUT_FILE"
8
+ # PR Consolidation Guidelines
9
+
10
+ ## Objective
11
+ Identify and propose consolidation of Pull Requests (PRs) that demonstrate high levels of functional or structural overlap to minimize code conflicts and streamline review cycles.
12
+
13
+ ## Analysis Criteria
14
+ When reviewing the output of the `pr_overlap.py` analysis, evaluate candidates based on the following:
15
+
16
+ ### 1. File Overlap Density
17
+ * **High Overlap:** PRs sharing identical files or logical components (e.g., core styles, shared UI components). These are primary candidates for consolidation.
18
+ * **Context:** Check if the overlapping files are `design-tokens.ts` or `ci.yml`. Broad overlaps in infrastructure files might indicate a need for coordination rather than full consolidation.
19
+
20
+ ### 2. Functional Alignment (PR Titles & Descriptions)
21
+ * Review the PR titles to determine if they share a common feature set (e.g., "Mobile UI" or "Home Page Performance").
22
+ * Look for duplicate effort; if two PRs address the same UI improvement, they should be merged into a single branch.
23
+
24
+ ### 3. Linked Issue Dependency
25
+ * Cross-reference the `(Fixes: #...)` metadata.
26
+ * If multiple PRs resolve related issues (e.g., #101 and #102 are both part of the same UX audit), suggest consolidating these to ensure the full feature set is verified as one unit.
27
+
28
+ ## Actionable Recommendations
29
+ For every identified cluster:
30
+ 1. **Draft a Proposal:** Write a summary identifying the involved PRs and the common files shared.
31
+ 2. **Assign Ownership:** Determine if one author should take lead on the consolidated PR, or if a pair-programming session is required.
32
+ 3. **Conflict Resolution:** Explicitly state the plan for handling conflicting logic in shared files identified in the report.
33
+
34
+ ## Submission
35
+ Present the findings in the following format:
36
+ - **Cluster ID:** [List of PR Numbers]
37
+ - **Primary Overlap:** [List of critical shared files]
38
+ - **Recommendation:** [Merge/Coordinate/Separate]
39
+ - **Rationale:** [Brief explanation referencing issues fixed]
40
+ MARKDOWN
41
+
42
+ echo "Successfully created instructions at $OUTPUT_FILE"
@@ -0,0 +1,7 @@
1
+ import { MCP_TOOLS, MCP_PROMPTS, MCP_RESOURCES } from "../src/mcp/definitions.js";
2
+
3
+ console.log(JSON.stringify({
4
+ tools: MCP_TOOLS,
5
+ prompts: MCP_PROMPTS,
6
+ resources: MCP_RESOURCES
7
+ }, null, 2));
@@ -0,0 +1,74 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ /**
5
+ * Synchronizes contracts from JSON schema to Zod.
6
+ */
7
+ async function syncContracts() {
8
+ let jsonSchemaToZod;
9
+ try {
10
+ const module = await import('json-schema-to-zod');
11
+ jsonSchemaToZod = module.jsonSchemaToZod;
12
+ } catch (err: unknown) {
13
+ const error = err as { code?: string; message?: string };
14
+ if (error.code === 'ERR_MODULE_NOT_FOUND' || error.message?.includes('Cannot find package')) {
15
+ console.error('❌ Error: json-schema-to-zod not found.');
16
+ console.error(' Please run `pnpm install` in the root directory.');
17
+ process.exit(1);
18
+ }
19
+ throw err;
20
+ }
21
+
22
+ let schemaPath = path.join(process.cwd(), 'cli/dev_tools/cli-schema.json');
23
+ let outputPath = path.join(process.cwd(), 'mcp/src/tools/contract.ts');
24
+
25
+ if (!fs.existsSync(schemaPath)) {
26
+ // Try relative to package root if in extracted mode (run from root)
27
+ schemaPath = path.join(process.cwd(), 'cli/dev_tools/cli-schema.json');
28
+ outputPath = path.join(process.cwd(), 'mcp/src/tools/contract.ts');
29
+ }
30
+
31
+ if (!fs.existsSync(schemaPath)) {
32
+ // Try if run from mcp directory
33
+ schemaPath = path.join(process.cwd(), '../cli/dev_tools/cli-schema.json');
34
+ outputPath = path.join(process.cwd(), 'src/tools/contract.ts');
35
+ }
36
+
37
+ if (!fs.existsSync(schemaPath)) {
38
+ console.error(`Schema not found at ${schemaPath}`);
39
+ process.exit(1);
40
+ }
41
+
42
+ const rawSchema = JSON.parse(fs.readFileSync(schemaPath, 'utf-8')) as { models?: Record<string, unknown> };
43
+ const models = rawSchema.models || {};
44
+
45
+ let tsContent = `// Automatically generated by sync-contracts.ts. Do not edit manually.\n`;
46
+ tsContent += `import { z } from "zod";\n\n`;
47
+
48
+ for (const [name, schema] of Object.entries(models)) {
49
+ // Get the raw Zod expression without any variable assignment or imports
50
+ const zodExpression = jsonSchemaToZod(schema as any, { module: 'none' });
51
+
52
+ tsContent += `export const ${name}Schema = ${zodExpression};\n\n`;
53
+ tsContent += `export type ${name} = z.infer<typeof ${name}Schema>;\n\n`;
54
+
55
+ // Also export the raw JSON schema for MCP definitions
56
+ tsContent += `export const ${name}JsonSchema = ${JSON.stringify(schema, null, 2)} as const;\n\n`;
57
+ }
58
+
59
+ // Normalize newlines to \n and ensure exactly one trailing newline at EOF
60
+ const finalContent = tsContent.replace(/\r\n/g, '\n').trimEnd() + '\n';
61
+
62
+ fs.writeFileSync(outputPath, finalContent);
63
+ console.log(`Generated ${outputPath}`);
64
+ }
65
+
66
+ // Ensure execution is awaited and errors are caught
67
+ (async () => {
68
+ try {
69
+ await syncContracts();
70
+ } catch (err) {
71
+ console.error('❌ Unexpected error during contract synchronization:', err);
72
+ process.exit(1);
73
+ }
74
+ })();
@@ -0,0 +1,97 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ const homeDir = process.env.HOME || process.env.USERPROFILE || '';
5
+ const globalTargetDir = homeDir ? path.join(homeDir, '.gemini', 'antigravity-cli', 'mcp', 'boomtick-mcp') : null;
6
+ const projectTargetDir = path.join(process.cwd(), '.mcp', 'schemas');
7
+
8
+ function isWritable(dir: string): boolean {
9
+ try {
10
+ const testFile = path.join(dir, '.write_test');
11
+ fs.writeFileSync(testFile, '');
12
+ fs.unlinkSync(testFile);
13
+ return true;
14
+ } catch {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ interface ToolDefinition {
20
+ name: string;
21
+ inputSchema: Record<string, unknown>;
22
+ }
23
+
24
+ /**
25
+ * Synchronizes MCP tool schemas to target locations.
26
+ */
27
+ async function syncSchemas() {
28
+ console.log('🔄 Synchronizing MCP tool schemas...');
29
+
30
+ let mcpToolsModule;
31
+ try {
32
+ mcpToolsModule = await import('../src/mcp/definitions.js');
33
+ } catch (err: unknown) {
34
+ const error = err as { code?: string; message?: string };
35
+ if (error.code === 'ERR_MODULE_NOT_FOUND' || error.message?.includes('Cannot find package')) {
36
+ console.error('❌ Error: MCP dependencies or source files not found.');
37
+ console.error(' Please run `pnpm install` in the root directory.');
38
+ process.exit(1);
39
+ }
40
+ throw err;
41
+ }
42
+
43
+ const mcpTools = mcpToolsModule.MCP_TOOLS as ToolDefinition[];
44
+
45
+ const targets = [projectTargetDir];
46
+ if (globalTargetDir) targets.push(globalTargetDir);
47
+
48
+ const validTargets: string[] = [];
49
+
50
+ targets.forEach(dir => {
51
+ try {
52
+ if (!fs.existsSync(dir)) {
53
+ fs.mkdirSync(dir, { recursive: true });
54
+ console.log(`📁 Created directory: ${dir}`);
55
+ }
56
+ if (isWritable(dir)) {
57
+ validTargets.push(dir);
58
+ } else {
59
+ console.warn(`⚠️ Directory is not writable, skipping: ${dir}`);
60
+ }
61
+ } catch (err) {
62
+ console.warn(`⚠️ Failed to prepare directory, skipping: ${dir}`, err);
63
+ }
64
+ });
65
+
66
+ if (validTargets.length === 0) {
67
+ console.warn('⚠️ No valid target directories available for schema synchronization.');
68
+ return;
69
+ }
70
+
71
+ mcpTools.forEach((tool) => {
72
+ const schemaContent = JSON.stringify(tool.inputSchema, null, 2);
73
+ const fileName = `${tool.name}.json`;
74
+
75
+ validTargets.forEach(targetDir => {
76
+ const filePath = path.join(targetDir, fileName);
77
+ try {
78
+ fs.writeFileSync(filePath, schemaContent);
79
+ } catch (err) {
80
+ console.error(`❌ Failed to write schema to ${filePath}:`, err);
81
+ }
82
+ });
83
+ });
84
+
85
+ console.log(`✅ Synchronized ${mcpTools.length} tool schemas to ${validTargets.length} locations.`);
86
+ validTargets.forEach(target => console.log(` - ${target}`));
87
+ }
88
+
89
+ // Ensure execution is awaited and errors are caught
90
+ (async () => {
91
+ try {
92
+ await syncSchemas();
93
+ } catch (error) {
94
+ console.error('❌ Unexpected error during MCP schema synchronization:', error);
95
+ process.exit(1);
96
+ }
97
+ })();
@@ -0,0 +1,20 @@
1
+ You are the Boomtick Conflict Scout Agent.
2
+
3
+ Your job is to find open PRs that may need rescue.
4
+
5
+ Rules:
6
+ - Use read-only tools only.
7
+ - Do not create branches.
8
+ - Do not comment.
9
+ - Do not edit files.
10
+ - Prefer PRs that are small, stale, conflicted, or failing checks.
11
+ - Ignore draft PRs unless explicitly configured.
12
+ - Produce a ranked rescue queue.
13
+
14
+ For each candidate, include:
15
+ - PR number
16
+ - title
17
+ - branch
18
+ - reason selected
19
+ - risk level
20
+ - recommended next action