@arii/boomtick-mcp 0.4.1 → 0.4.2

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 (111) hide show
  1. package/.mcp/schemas/agent.search_ddgs.json +28 -24
  2. package/.mcp/schemas/agent_search_ddgs.json +31 -0
  3. package/.mcp/schemas/boomtick.health.json +14 -10
  4. package/.mcp/schemas/boomtick_health.json +16 -0
  5. package/.mcp/schemas/github.checkout_branch.json +28 -24
  6. package/.mcp/schemas/github.comment_triage_summary.json +21 -17
  7. package/.mcp/schemas/github.create_issue.json +55 -50
  8. package/.mcp/schemas/github.create_pull_request.json +53 -48
  9. package/.mcp/schemas/github.get_merge_conflict_files.json +21 -17
  10. package/.mcp/schemas/github.get_pr.json +30 -12
  11. package/.mcp/schemas/github.get_pr_diff.json +30 -12
  12. package/.mcp/schemas/github.issue_comment.json +35 -17
  13. package/.mcp/schemas/github.issue_update.json +114 -96
  14. package/.mcp/schemas/github.issue_view.json +30 -12
  15. package/.mcp/schemas/github.open_replacement_pr.json +64 -60
  16. package/.mcp/schemas/github.search_open_prs.json +61 -43
  17. package/.mcp/schemas/github_checkout_branch.json +31 -0
  18. package/.mcp/schemas/github_comment_triage_summary.json +24 -0
  19. package/.mcp/schemas/github_create_issue.json +58 -0
  20. package/.mcp/schemas/github_create_pull_request.json +56 -0
  21. package/.mcp/schemas/github_get_merge_conflict_files.json +24 -0
  22. package/.mcp/schemas/github_get_pr.json +32 -0
  23. package/.mcp/schemas/github_get_pr_diff.json +32 -0
  24. package/.mcp/schemas/github_issue_comment.json +38 -0
  25. package/.mcp/schemas/github_issue_update.json +123 -0
  26. package/.mcp/schemas/github_issue_view.json +32 -0
  27. package/.mcp/schemas/github_open_replacement_pr.json +67 -0
  28. package/.mcp/schemas/github_search_open_prs.json +65 -0
  29. package/.mcp/schemas/jules.cancel_session.json +16 -12
  30. package/.mcp/schemas/jules.create_session.json +41 -37
  31. package/.mcp/schemas/jules.get_messages.json +16 -12
  32. package/.mcp/schemas/jules.get_pr.json +16 -12
  33. package/.mcp/schemas/jules.get_session.json +16 -12
  34. package/.mcp/schemas/jules.list_sessions.json +33 -29
  35. package/.mcp/schemas/jules.send_message.json +30 -26
  36. package/.mcp/schemas/jules.trigger_feedback.json +16 -12
  37. package/.mcp/schemas/jules_cancel_session.json +18 -0
  38. package/.mcp/schemas/jules_create_session.json +44 -0
  39. package/.mcp/schemas/jules_get_messages.json +18 -0
  40. package/.mcp/schemas/jules_get_pr.json +18 -0
  41. package/.mcp/schemas/jules_get_session.json +18 -0
  42. package/.mcp/schemas/jules_list_sessions.json +36 -0
  43. package/.mcp/schemas/jules_send_message.json +35 -0
  44. package/.mcp/schemas/jules_trigger_feedback.json +18 -0
  45. package/.mcp/schemas/repo.commit_patch.json +34 -30
  46. package/.mcp/schemas/repo.create_branch.json +21 -17
  47. package/.mcp/schemas/repo.create_repair_branch.json +34 -30
  48. package/.mcp/schemas/repo.get_changed_files.json +19 -15
  49. package/.mcp/schemas/repo.get_command_schema.json +16 -12
  50. package/.mcp/schemas/repo.get_package_scripts.json +21 -17
  51. package/.mcp/schemas/repo.get_route_map.json +21 -17
  52. package/.mcp/schemas/repo.logs.json +28 -24
  53. package/.mcp/schemas/repo.read_agent_context.json +7 -3
  54. package/.mcp/schemas/repo.read_ci_logs.json +21 -17
  55. package/.mcp/schemas/repo.run_lighthouse.json +26 -22
  56. package/.mcp/schemas/repo.run_playwright.json +33 -29
  57. package/.mcp/schemas/repo.run_tests.json +40 -36
  58. package/.mcp/schemas/repo_commit_patch.json +39 -0
  59. package/.mcp/schemas/repo_create_branch.json +24 -0
  60. package/.mcp/schemas/repo_create_repair_branch.json +37 -0
  61. package/.mcp/schemas/repo_get_changed_files.json +22 -0
  62. package/.mcp/schemas/repo_get_command_schema.json +18 -0
  63. package/.mcp/schemas/repo_get_package_scripts.json +23 -0
  64. package/.mcp/schemas/repo_get_route_map.json +23 -0
  65. package/.mcp/schemas/repo_logs.json +31 -0
  66. package/.mcp/schemas/repo_read_agent_context.json +9 -0
  67. package/.mcp/schemas/repo_read_ci_logs.json +24 -0
  68. package/.mcp/schemas/repo_run_lighthouse.json +29 -0
  69. package/.mcp/schemas/repo_run_playwright.json +36 -0
  70. package/.mcp/schemas/repo_run_tests.json +45 -0
  71. package/CHANGELOG.md +9 -0
  72. package/dist/lib/git.js +30 -0
  73. package/dist/lib/param_utils.js +35 -0
  74. package/dist/lib/param_utils.test.js +44 -0
  75. package/dist/mcp/definitions.js +11 -1
  76. package/dist/mcp/schemas.test.js +28 -0
  77. package/dist/mcp/server.js +72 -36
  78. package/dist/tools/contract.js +94 -8
  79. package/dist/tools/github.create_issue.js +3 -2
  80. package/dist/tools/github.create_issue.test.js +10 -0
  81. package/dist/tools/github.create_pull_request.js +4 -4
  82. package/dist/tools/github.get_pr.js +4 -1
  83. package/dist/tools/github.get_pr_diff.js +6 -2
  84. package/dist/tools/github.issue_comment.js +8 -1
  85. package/dist/tools/github.issue_update.js +3 -0
  86. package/dist/tools/github.issue_view.js +4 -1
  87. package/dist/tools/github.search_open_prs.js +4 -0
  88. package/dist/tools/repo.commit_patch.js +30 -10
  89. package/dist/tools/repo.run_playwright.js +10 -5
  90. package/dist/tools/repo.run_tests.js +26 -4
  91. package/package.json +2 -2
  92. package/scripts/sync-mcp-schemas.ts +6 -1
  93. package/src/lib/git.ts +34 -0
  94. package/src/lib/param_utils.test.ts +49 -0
  95. package/src/lib/param_utils.ts +42 -0
  96. package/src/mcp/definitions.ts +12 -1
  97. package/src/mcp/schemas.test.ts +34 -0
  98. package/src/mcp/server.ts +73 -38
  99. package/src/tools/contract.ts +94 -8
  100. package/src/tools/github.create_issue.test.ts +10 -0
  101. package/src/tools/github.create_issue.ts +3 -1
  102. package/src/tools/github.create_pull_request.ts +4 -5
  103. package/src/tools/github.get_pr.ts +4 -1
  104. package/src/tools/github.get_pr_diff.ts +7 -2
  105. package/src/tools/github.issue_comment.ts +8 -1
  106. package/src/tools/github.issue_update.ts +4 -1
  107. package/src/tools/github.issue_view.ts +4 -1
  108. package/src/tools/github.search_open_prs.ts +4 -0
  109. package/src/tools/repo.commit_patch.ts +35 -11
  110. package/src/tools/repo.run_playwright.ts +13 -6
  111. package/src/tools/repo.run_tests.ts +28 -5
@@ -0,0 +1,49 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { normalizeArguments } from "./param_utils.js";
3
+
4
+ describe("param_utils.normalizeArguments", () => {
5
+ it("should convert snake_case keys to camelCase", () => {
6
+ const input = {
7
+ pr_number: 123,
8
+ issue_number: 456,
9
+ worktree_path: "/tmp/worktree",
10
+ base_branch: "main",
11
+ };
12
+ const output = normalizeArguments(input);
13
+ expect(output).toEqual({
14
+ prNumber: 123,
15
+ issueNumber: 456,
16
+ worktreePath: "/tmp/worktree",
17
+ baseBranch: "main",
18
+ });
19
+ });
20
+
21
+ it("should coerce numeric strings for prNumber and issueNumber", () => {
22
+ const input = {
23
+ pr_number: "789",
24
+ issue_number: "101",
25
+ };
26
+ const output = normalizeArguments(input);
27
+ expect(output).toEqual({
28
+ prNumber: 789,
29
+ issueNumber: 101,
30
+ });
31
+ });
32
+
33
+ it("should synchronize branch and branchName", () => {
34
+ expect(normalizeArguments({ branch: "feat-x" })).toEqual({
35
+ branch: "feat-x",
36
+ branchName: "feat-x",
37
+ });
38
+
39
+ expect(normalizeArguments({ branch_name: "feat-y" })).toEqual({
40
+ branchName: "feat-y",
41
+ branch: "feat-y",
42
+ });
43
+ });
44
+
45
+ it("should handle null or empty arguments safely", () => {
46
+ expect(normalizeArguments(null)).toEqual({});
47
+ expect(normalizeArguments(undefined)).toEqual({});
48
+ });
49
+ });
@@ -0,0 +1,42 @@
1
+ export function normalizeArguments(args: Record<string, unknown> | null | undefined): Record<string, unknown> {
2
+ if (!args || typeof args !== "object") {
3
+ return {};
4
+ }
5
+
6
+ const result: Record<string, unknown> = {};
7
+
8
+ for (const [key, value] of Object.entries(args)) {
9
+ // Convert snake_case to camelCase
10
+ const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
11
+
12
+ // Normalize value recursively if it's an object/array
13
+ let normalizedValue = value;
14
+ if (Array.isArray(value)) {
15
+ normalizedValue = value.map((item) =>
16
+ item && typeof item === "object" ? normalizeArguments(item as Record<string, unknown>) : item
17
+ );
18
+ } else if (value && typeof value === "object" && !(value instanceof RegExp)) {
19
+ normalizedValue = normalizeArguments(value as Record<string, unknown>);
20
+ }
21
+
22
+ // Coerce numeric string to integer for prNumber / issueNumber if applicable
23
+ if ((camelKey === "prNumber" || camelKey === "issueNumber") && typeof normalizedValue === "string") {
24
+ const parsedNum = parseInt(normalizedValue, 10);
25
+ if (!isNaN(parsedNum)) {
26
+ normalizedValue = parsedNum;
27
+ }
28
+ }
29
+
30
+ result[camelKey] = normalizedValue;
31
+ }
32
+
33
+ // Parameter aliases harmonization
34
+ // branch vs branchName harmonization
35
+ if (result.branch !== undefined && result.branchName === undefined) {
36
+ result.branchName = result.branch;
37
+ } else if (result.branchName !== undefined && result.branch === undefined) {
38
+ result.branch = result.branchName;
39
+ }
40
+
41
+ return result;
42
+ }
@@ -99,7 +99,7 @@ export const MCP_RESOURCES: Resource[] = [
99
99
  },
100
100
  ];
101
101
 
102
- export const MCP_TOOLS: Tool[] = [
102
+ const BASE_MCP_TOOLS: Tool[] = [
103
103
  {
104
104
  name: "boomtick.health",
105
105
  description: "Check the health and configuration of the MCP server.",
@@ -276,3 +276,14 @@ export const MCP_TOOLS: Tool[] = [
276
276
  inputSchema: SearchDdgsInputJsonSchema as any,
277
277
  },
278
278
  ];
279
+
280
+ export const MCP_TOOLS: Tool[] = BASE_MCP_TOOLS.flatMap((tool) => {
281
+ const underscoreName = tool.name.replace(/\./g, "_");
282
+ if (underscoreName !== tool.name) {
283
+ return [
284
+ { ...tool, name: underscoreName },
285
+ tool,
286
+ ];
287
+ }
288
+ return [tool];
289
+ });
@@ -0,0 +1,34 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import { execSync } from "child_process";
5
+
6
+ describe("MCP tool schemas export", () => {
7
+ it("should generate valid schema files with non-null parameters object", () => {
8
+ const schemasDir = path.resolve(process.cwd(), ".mcp/schemas");
9
+ if (!fs.existsSync(schemasDir)) {
10
+ execSync("npx tsx scripts/sync-mcp-schemas.ts", { cwd: process.cwd() });
11
+ }
12
+ expect(fs.existsSync(schemasDir)).toBe(true);
13
+
14
+ const files = fs.readdirSync(schemasDir).filter((f) => f.endsWith(".json"));
15
+ expect(files.length).toBeGreaterThan(0);
16
+
17
+ for (const file of files) {
18
+ const filePath = path.join(schemasDir, file);
19
+ const content = JSON.parse(fs.readFileSync(filePath, "utf-8"));
20
+
21
+ expect(content).toHaveProperty("name");
22
+ expect(typeof content.name).toBe("string");
23
+
24
+ expect(content).toHaveProperty("description");
25
+ expect(typeof content.description).toBe("string");
26
+
27
+ expect(content).toHaveProperty("parameters");
28
+ expect(content.parameters).not.toBeNull();
29
+ expect(typeof content.parameters).toBe("object");
30
+ expect(content.parameters.type).toBe("object");
31
+ expect(content.parameters.properties).toBeDefined();
32
+ }
33
+ });
34
+ });
package/src/mcp/server.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  import { config } from "../config.js";
12
12
  import { createSuccessResult, createErrorResult } from "../lib/result.js";
13
13
  import { MCP_TOOLS, MCP_PROMPTS, MCP_RESOURCES } from "./definitions.js";
14
+ import { normalizeArguments } from "../lib/param_utils.js";
14
15
  import { healthHandler, HealthCheckInputSchema } from "./tools.js";
15
16
  import { searchOpenPrsHandler, SearchOpenPrsInputSchema } from "../tools/github.search_open_prs.js";
16
17
  import { getPrDiffHandler, GetPrDiffInputSchema } from "../tools/github.get_pr_diff.js";
@@ -182,80 +183,114 @@ export class BoomtickMCPServer {
182
183
 
183
184
  this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
184
185
  try {
185
- switch (request.params.name) {
186
+ const normalizedToolName = request.params.name.replace(/_/g, ".");
187
+ const normArgs = normalizeArguments(request.params.arguments as Record<string, unknown>);
188
+
189
+ switch (normalizedToolName) {
186
190
  case "boomtick.health":
187
- return createSuccessResult(await healthHandler(HealthCheckInputSchema.parse(request.params.arguments || {})));
191
+ return createSuccessResult(await healthHandler(HealthCheckInputSchema.parse(normArgs)));
192
+ case "github.search.open.prs":
188
193
  case "github.search_open_prs":
189
- return createSuccessResult(await searchOpenPrsHandler(SearchOpenPrsInputSchema.parse(request.params.arguments || {})));
194
+ return createSuccessResult(await searchOpenPrsHandler(SearchOpenPrsInputSchema.parse(normArgs)));
195
+ case "repo.read.agent.context":
190
196
  case "repo.read_agent_context":
191
- return createSuccessResult(await readAgentContextHandler(ReadAgentContextInputSchema.parse(request.params.arguments || {})));
197
+ return createSuccessResult(await readAgentContextHandler(ReadAgentContextInputSchema.parse(normArgs)));
198
+ case "github.get.pr.diff":
192
199
  case "github.get_pr_diff":
193
- return createSuccessResult(await getPrDiffHandler(GetPrDiffInputSchema.parse(request.params.arguments)));
200
+ return createSuccessResult(await getPrDiffHandler(GetPrDiffInputSchema.parse(normArgs)));
201
+ case "github.get.merge.conflict.files":
194
202
  case "github.get_merge_conflict_files":
195
- return createSuccessResult(await getMergeConflictFilesHandler(GetMergeConflictFilesInputSchema.parse(request.params.arguments)));
203
+ return createSuccessResult(await getMergeConflictFilesHandler(GetMergeConflictFilesInputSchema.parse(normArgs)));
204
+ case "github.checkout.branch":
196
205
  case "github.checkout_branch":
197
- return createSuccessResult(await checkoutBranchHandler(CheckoutBranchInputSchema.parse(request.params.arguments)));
206
+ return createSuccessResult(await checkoutBranchHandler(CheckoutBranchInputSchema.parse(normArgs)));
207
+ case "repo.get.changed.files":
198
208
  case "repo.get_changed_files":
199
- return createSuccessResult(await getChangedFilesHandler(GetChangedFilesInputSchema.parse(request.params.arguments || {})));
209
+ return createSuccessResult(await getChangedFilesHandler(GetChangedFilesInputSchema.parse(normArgs)));
210
+ case "repo.get.command.schema":
200
211
  case "repo.get_command_schema":
201
- return createSuccessResult(await getCommandSchemaHandler(GetCommandSchemaInputSchema.parse(request.params.arguments)));
212
+ return createSuccessResult(await getCommandSchemaHandler(GetCommandSchemaInputSchema.parse(normArgs)));
213
+ case "repo.get.package.scripts":
202
214
  case "repo.get_package_scripts":
203
- return createSuccessResult(await getPackageScriptsHandler(GetPackageScriptsInputSchema.parse(request.params.arguments || {})));
215
+ return createSuccessResult(await getPackageScriptsHandler(GetPackageScriptsInputSchema.parse(normArgs)));
216
+ case "repo.get.route.map":
204
217
  case "repo.get_route_map":
205
- return createSuccessResult(await getRouteMapHandler(GetRouteMapInputSchema.parse(request.params.arguments || {})));
218
+ return createSuccessResult(await getRouteMapHandler(GetRouteMapInputSchema.parse(normArgs)));
219
+ case "repo.read.ci.logs":
206
220
  case "repo.read_ci_logs":
207
- return createSuccessResult(await readCiLogsHandler(ReadCiLogsInputSchema.parse(request.params.arguments)));
221
+ return createSuccessResult(await readCiLogsHandler(ReadCiLogsInputSchema.parse(normArgs)));
208
222
  case "repo.logs":
209
- return createSuccessResult(await repoLogsHandler(RepoLogsInputSchema.parse(request.params.arguments)));
223
+ return createSuccessResult(await repoLogsHandler(RepoLogsInputSchema.parse(normArgs)));
224
+ case "repo.create.branch":
210
225
  case "repo.create_branch":
211
- return createSuccessResult(await createBranchHandler(CreateBranchInputSchema.parse(request.params.arguments)));
226
+ return createSuccessResult(await createBranchHandler(CreateBranchInputSchema.parse(normArgs)));
227
+ case "repo.create.repair.branch":
212
228
  case "repo.create_repair_branch":
213
- return createSuccessResult(await createRepairBranchHandler(CreateRepairBranchInputSchema.parse(request.params.arguments)));
229
+ return createSuccessResult(await createRepairBranchHandler(CreateRepairBranchInputSchema.parse(normArgs)));
230
+ case "repo.run.tests":
214
231
  case "repo.run_tests":
215
- return createSuccessResult(await runTestsHandler(RunTestsInputSchema.parse(request.params.arguments || {})));
232
+ return createSuccessResult(await runTestsHandler(RunTestsInputSchema.parse(normArgs)));
233
+ case "repo.run.lighthouse":
216
234
  case "repo.run_lighthouse":
217
- return createSuccessResult(await runLighthouseHandler(RunLighthouseInputSchema.parse(request.params.arguments || {})));
235
+ return createSuccessResult(await runLighthouseHandler(RunLighthouseInputSchema.parse(normArgs)));
236
+ case "repo.run.playwright":
218
237
  case "repo.run_playwright":
219
- return createSuccessResult(await runPlaywrightHandler(RunPlaywrightInputSchema.parse(request.params.arguments || {})));
238
+ return createSuccessResult(await runPlaywrightHandler(RunPlaywrightInputSchema.parse(normArgs)));
239
+ case "repo.commit.patch":
220
240
  case "repo.commit_patch":
221
- return createSuccessResult(await commitPatchHandler(CommitPatchInputSchema.parse(request.params.arguments)));
241
+ return createSuccessResult(await commitPatchHandler(CommitPatchInputSchema.parse(normArgs)));
242
+ case "github.open.replacement.pr":
222
243
  case "github.open_replacement_pr":
223
- return createSuccessResult(await openReplacementPrHandler(OpenReplacementPrInputSchema.parse(request.params.arguments)));
244
+ return createSuccessResult(await openReplacementPrHandler(OpenReplacementPrInputSchema.parse(normArgs)));
245
+ case "github.comment.triage.summary":
224
246
  case "github.comment_triage_summary":
225
- return createSuccessResult(await commentTriageSummaryHandler(CommentTriageSummaryInputSchema.parse(request.params.arguments)));
247
+ return createSuccessResult(await commentTriageSummaryHandler(CommentTriageSummaryInputSchema.parse(normArgs)));
248
+ case "github.create.pull.request":
226
249
  case "github.create_pull_request":
227
- return createSuccessResult(await createPullRequestHandler(CreatePullRequestInputSchema.parse(request.params.arguments)));
250
+ return createSuccessResult(await createPullRequestHandler(CreatePullRequestInputSchema.parse(normArgs)));
251
+ case "github.get.pr":
228
252
  case "github.get_pr":
229
- return createSuccessResult(await getPrHandler(GetPrInputSchema.parse(request.params.arguments)));
253
+ return createSuccessResult(await getPrHandler(GetPrInputSchema.parse(normArgs)));
254
+ case "github.issue.view":
230
255
  case "github.issue_view":
231
- return createSuccessResult(await issueViewHandler(IssueViewInputSchema.parse(request.params.arguments)));
256
+ return createSuccessResult(await issueViewHandler(IssueViewInputSchema.parse(normArgs)));
257
+ case "github.issue.update":
232
258
  case "github.issue_update":
233
- return createSuccessResult(await issueUpdateHandler(IssueUpdateInputSchema.parse(request.params.arguments)));
259
+ return createSuccessResult(await issueUpdateHandler(IssueUpdateInputSchema.parse(normArgs)));
260
+ case "github.issue.comment":
234
261
  case "github.issue_comment":
235
- return createSuccessResult(await issueCommentHandler(IssueCommentInputSchema.parse(request.params.arguments)));
262
+ return createSuccessResult(await issueCommentHandler(IssueCommentInputSchema.parse(normArgs)));
263
+ case "github.create.issue":
236
264
  case "github.create_issue":
237
- return createSuccessResult(await createIssueHandler(CreateIssueInputSchema.parse(request.params.arguments)));
238
-
239
-
265
+ return createSuccessResult(await createIssueHandler(CreateIssueInputSchema.parse(normArgs)));
240
266
 
267
+ case "jules.create.session":
241
268
  case "jules.create_session":
242
- return createSuccessResult(await createJulesSessionHandler(CreateJulesSessionInputSchema.parse(request.params.arguments)));
269
+ return createSuccessResult(await createJulesSessionHandler(CreateJulesSessionInputSchema.parse(normArgs)));
270
+ case "jules.get.session":
243
271
  case "jules.get_session":
244
- return createSuccessResult(await getJulesSessionHandler(GetJulesSessionInputSchema.parse(request.params.arguments)));
272
+ return createSuccessResult(await getJulesSessionHandler(GetJulesSessionInputSchema.parse(normArgs)));
273
+ case "jules.send.message":
245
274
  case "jules.send_message":
246
- return createSuccessResult(await sendJulesMessageHandler(SendJulesMessageInputSchema.parse(request.params.arguments)));
275
+ return createSuccessResult(await sendJulesMessageHandler(SendJulesMessageInputSchema.parse(normArgs)));
276
+ case "jules.get.messages":
247
277
  case "jules.get_messages":
248
- return createSuccessResult(await getJulesMessagesHandler(GetJulesMessagesInputSchema.parse(request.params.arguments)));
278
+ return createSuccessResult(await getJulesMessagesHandler(GetJulesMessagesInputSchema.parse(normArgs)));
279
+ case "jules.list.sessions":
249
280
  case "jules.list_sessions":
250
- return createSuccessResult(await listJulesSessionsHandler(ListJulesSessionsInputSchema.parse(request.params.arguments || {})));
281
+ return createSuccessResult(await listJulesSessionsHandler(ListJulesSessionsInputSchema.parse(normArgs)));
282
+ case "jules.cancel.session":
251
283
  case "jules.cancel_session":
252
- return createSuccessResult(await cancelJulesSessionHandler(CancelJulesSessionInputSchema.parse(request.params.arguments)));
284
+ return createSuccessResult(await cancelJulesSessionHandler(CancelJulesSessionInputSchema.parse(normArgs)));
285
+ case "jules.get.pr":
253
286
  case "jules.get_pr":
254
- return createSuccessResult(await getJulesPullRequestHandler(GetJulesPullRequestInputSchema.parse(request.params.arguments)));
287
+ return createSuccessResult(await getJulesPullRequestHandler(GetJulesPullRequestInputSchema.parse(normArgs)));
288
+ case "jules.trigger.feedback":
255
289
  case "jules.trigger_feedback":
256
- return createSuccessResult(await triggerJulesFeedbackHandler(TriggerJulesFeedbackInputSchema.parse(request.params.arguments)));
290
+ return createSuccessResult(await triggerJulesFeedbackHandler(TriggerJulesFeedbackInputSchema.parse(normArgs)));
291
+ case "agent.search.ddgs":
257
292
  case "agent.search_ddgs":
258
- return createSuccessResult(await ddgsSearchHandler(DdgsSearchInputSchema.parse(request.params.arguments)));
293
+ return createSuccessResult(await ddgsSearchHandler(DdgsSearchInputSchema.parse(normArgs)));
259
294
  default:
260
295
  return createErrorResult(`Tool not found: ${request.params.name}`);
261
296
  }
@@ -1228,7 +1228,7 @@ export const CreateBranchInputJsonSchema = {
1228
1228
  "type": "object"
1229
1229
  } as const;
1230
1230
 
1231
- export const CreateIssueInputSchema = z.object({ "title": z.string().min(1), "body": z.union([z.string().min(1), z.null()]).default(null), "file": z.union([z.string().min(1), z.null()]).default(null), "repo": z.union([z.string(), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1231
+ export const CreateIssueInputSchema = z.object({ "title": z.string().min(1), "body": z.union([z.string().min(1), z.null()]).default(null), "file": z.union([z.string().min(1), z.null()]).default(null), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1232
1232
 
1233
1233
  export type CreateIssueInput = z.infer<typeof CreateIssueInputSchema>;
1234
1234
 
@@ -1268,6 +1268,7 @@ export const CreateIssueInputJsonSchema = {
1268
1268
  "repo": {
1269
1269
  "anyOf": [
1270
1270
  {
1271
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1271
1272
  "type": "string"
1272
1273
  },
1273
1274
  {
@@ -1410,7 +1411,7 @@ export const CreateJulesSessionInputJsonSchema = {
1410
1411
  "type": "object"
1411
1412
  } as const;
1412
1413
 
1413
- export const CreatePullRequestInputSchema = z.object({ "title": z.string().describe("PR Title."), "body": z.string().describe("Description of changes."), "head": z.string().describe("The branch containing changes to merge."), "base": z.string().describe("The target branch to merge into.").default("main"), "draft": z.boolean().describe("Whether to create the PR as a draft.").default(false), "repo": z.union([z.string(), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1414
+ export const CreatePullRequestInputSchema = z.object({ "title": z.string().describe("PR Title."), "body": z.string().describe("Description of changes."), "head": z.string().describe("The branch containing changes to merge."), "base": z.string().describe("The target branch to merge into.").default("main"), "draft": z.boolean().describe("Whether to create the PR as a draft.").default(false), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1414
1415
 
1415
1416
  export type CreatePullRequestInput = z.infer<typeof CreatePullRequestInputSchema>;
1416
1417
 
@@ -1446,6 +1447,7 @@ export const CreatePullRequestInputJsonSchema = {
1446
1447
  "repo": {
1447
1448
  "anyOf": [
1448
1449
  {
1450
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1449
1451
  "type": "string"
1450
1452
  },
1451
1453
  {
@@ -1595,7 +1597,7 @@ export const GetPackageScriptsInputJsonSchema = {
1595
1597
  "type": "object"
1596
1598
  } as const;
1597
1599
 
1598
- export const GetPrDiffInputSchema = z.object({ "prNumber": z.number().int().describe("The number of the pull request to get the diff for.") });
1600
+ export const GetPrDiffInputSchema = z.object({ "prNumber": z.number().int().describe("The number of the pull request to get the diff for."), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1599
1601
 
1600
1602
  export type GetPrDiffInput = z.infer<typeof GetPrDiffInputSchema>;
1601
1603
 
@@ -1605,6 +1607,20 @@ export const GetPrDiffInputJsonSchema = {
1605
1607
  "description": "The number of the pull request to get the diff for.",
1606
1608
  "title": "Prnumber",
1607
1609
  "type": "integer"
1610
+ },
1611
+ "repo": {
1612
+ "anyOf": [
1613
+ {
1614
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1615
+ "type": "string"
1616
+ },
1617
+ {
1618
+ "type": "null"
1619
+ }
1620
+ ],
1621
+ "default": null,
1622
+ "description": "The target repository override (e.g. org/repo).",
1623
+ "title": "Repo"
1608
1624
  }
1609
1625
  },
1610
1626
  "required": [
@@ -1614,7 +1630,7 @@ export const GetPrDiffInputJsonSchema = {
1614
1630
  "type": "object"
1615
1631
  } as const;
1616
1632
 
1617
- export const GetPrInputSchema = z.object({ "prNumber": z.number().int().describe("The number of the PR to view.") });
1633
+ export const GetPrInputSchema = z.object({ "prNumber": z.number().int().describe("The number of the PR to view."), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1618
1634
 
1619
1635
  export type GetPrInput = z.infer<typeof GetPrInputSchema>;
1620
1636
 
@@ -1624,6 +1640,20 @@ export const GetPrInputJsonSchema = {
1624
1640
  "description": "The number of the PR to view.",
1625
1641
  "title": "Prnumber",
1626
1642
  "type": "integer"
1643
+ },
1644
+ "repo": {
1645
+ "anyOf": [
1646
+ {
1647
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1648
+ "type": "string"
1649
+ },
1650
+ {
1651
+ "type": "null"
1652
+ }
1653
+ ],
1654
+ "default": null,
1655
+ "description": "The target repository override (e.g. org/repo).",
1656
+ "title": "Repo"
1627
1657
  }
1628
1658
  },
1629
1659
  "required": [
@@ -1674,7 +1704,7 @@ export const HealthCheckInputJsonSchema = {
1674
1704
  "type": "object"
1675
1705
  } as const;
1676
1706
 
1677
- export const IssueCommentInputSchema = z.object({ "issueNumber": z.number().int().describe("The number of the issue to comment on."), "body": z.string().describe("The content of the comment.") });
1707
+ export const IssueCommentInputSchema = z.object({ "issueNumber": z.number().int().describe("The number of the issue to comment on."), "body": z.string().describe("The content of the comment."), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1678
1708
 
1679
1709
  export type IssueCommentInput = z.infer<typeof IssueCommentInputSchema>;
1680
1710
 
@@ -1689,6 +1719,20 @@ export const IssueCommentInputJsonSchema = {
1689
1719
  "description": "The content of the comment.",
1690
1720
  "title": "Body",
1691
1721
  "type": "string"
1722
+ },
1723
+ "repo": {
1724
+ "anyOf": [
1725
+ {
1726
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1727
+ "type": "string"
1728
+ },
1729
+ {
1730
+ "type": "null"
1731
+ }
1732
+ ],
1733
+ "default": null,
1734
+ "description": "The target repository override (e.g. org/repo).",
1735
+ "title": "Repo"
1692
1736
  }
1693
1737
  },
1694
1738
  "required": [
@@ -1732,7 +1776,7 @@ export const IssueSummaryJsonSchema = {
1732
1776
  "type": "object"
1733
1777
  } as const;
1734
1778
 
1735
- export const IssueUpdateInputSchema = z.object({ "issueNumber": z.number().int().describe("The number of the issue to update."), "body": z.union([z.string(), z.null()]).describe("The new body content for the issue.").default(null), "file": z.union([z.string(), z.null()]).describe("Path to file containing new issue body.").default(null), "labels": z.union([z.array(z.string()), z.null()]).describe("Comma-separated list of labels to set.").default(null), "addLabels": z.union([z.array(z.string()), z.null()]).describe("Comma-separated list of labels to add.").default(null), "removeLabels": z.union([z.array(z.string()), z.null()]).describe("Comma-separated list of labels to remove.").default(null), "state": z.union([z.enum(["open","closed"]), z.null()]).describe("The state to set the issue to.").default(null) });
1779
+ export const IssueUpdateInputSchema = z.object({ "issueNumber": z.number().int().describe("The number of the issue to update."), "body": z.union([z.string(), z.null()]).describe("The new body content for the issue.").default(null), "file": z.union([z.string(), z.null()]).describe("Path to file containing new issue body.").default(null), "labels": z.union([z.array(z.string()), z.null()]).describe("Comma-separated list of labels to set.").default(null), "addLabels": z.union([z.array(z.string()), z.null()]).describe("Comma-separated list of labels to add.").default(null), "removeLabels": z.union([z.array(z.string()), z.null()]).describe("Comma-separated list of labels to remove.").default(null), "state": z.union([z.enum(["open","closed"]), z.null()]).describe("The state to set the issue to.").default(null), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1736
1780
 
1737
1781
  export type IssueUpdateInput = z.infer<typeof IssueUpdateInputSchema>;
1738
1782
 
@@ -1833,6 +1877,20 @@ export const IssueUpdateInputJsonSchema = {
1833
1877
  "default": null,
1834
1878
  "description": "The state to set the issue to.",
1835
1879
  "title": "State"
1880
+ },
1881
+ "repo": {
1882
+ "anyOf": [
1883
+ {
1884
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1885
+ "type": "string"
1886
+ },
1887
+ {
1888
+ "type": "null"
1889
+ }
1890
+ ],
1891
+ "default": null,
1892
+ "description": "The target repository override (e.g. org/repo).",
1893
+ "title": "Repo"
1836
1894
  }
1837
1895
  },
1838
1896
  "required": [
@@ -1921,7 +1979,7 @@ export const IssueUpdateResponseJsonSchema = {
1921
1979
  "type": "object"
1922
1980
  } as const;
1923
1981
 
1924
- export const IssueViewInputSchema = z.object({ "issueNumber": z.number().int().describe("The number of the issue to view.") });
1982
+ export const IssueViewInputSchema = z.object({ "issueNumber": z.number().int().describe("The number of the issue to view."), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
1925
1983
 
1926
1984
  export type IssueViewInput = z.infer<typeof IssueViewInputSchema>;
1927
1985
 
@@ -1931,6 +1989,20 @@ export const IssueViewInputJsonSchema = {
1931
1989
  "description": "The number of the issue to view.",
1932
1990
  "title": "Issuenumber",
1933
1991
  "type": "integer"
1992
+ },
1993
+ "repo": {
1994
+ "anyOf": [
1995
+ {
1996
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
1997
+ "type": "string"
1998
+ },
1999
+ {
2000
+ "type": "null"
2001
+ }
2002
+ ],
2003
+ "default": null,
2004
+ "description": "The target repository override (e.g. org/repo).",
2005
+ "title": "Repo"
1934
2006
  }
1935
2007
  },
1936
2008
  "required": [
@@ -2998,7 +3070,7 @@ export const SearchDdgsInputJsonSchema = {
2998
3070
  "type": "object"
2999
3071
  } as const;
3000
3072
 
3001
- export const SearchPRsInputSchema = z.object({ "state": z.enum(["open","closed","all"]).describe("The state of the PRs to search for.").default("open"), "limit": z.number().int().gte(1).lte(100).describe("The maximum number of PRs to return (default: 100, range: 1-100).").default(100), "includeDrafts": z.boolean().describe("Whether to include draft PRs in the results.").default(true), "labels": z.union([z.array(z.string()), z.null()]).describe("Filter PRs by labels.").default(null) });
3073
+ export const SearchPRsInputSchema = z.object({ "state": z.enum(["open","closed","all"]).describe("The state of the PRs to search for.").default("open"), "limit": z.number().int().gte(1).lte(100).describe("The maximum number of PRs to return (default: 100, range: 1-100).").default(100), "includeDrafts": z.boolean().describe("Whether to include draft PRs in the results.").default(true), "labels": z.union([z.array(z.string()), z.null()]).describe("Filter PRs by labels.").default(null), "repo": z.union([z.string().regex(new RegExp("^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$")), z.null()]).describe("The target repository override (e.g. org/repo).").default(null) });
3002
3074
 
3003
3075
  export type SearchPRsInput = z.infer<typeof SearchPRsInputSchema>;
3004
3076
 
@@ -3044,6 +3116,20 @@ export const SearchPRsInputJsonSchema = {
3044
3116
  "default": null,
3045
3117
  "description": "Filter PRs by labels.",
3046
3118
  "title": "Labels"
3119
+ },
3120
+ "repo": {
3121
+ "anyOf": [
3122
+ {
3123
+ "pattern": "^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$",
3124
+ "type": "string"
3125
+ },
3126
+ {
3127
+ "type": "null"
3128
+ }
3129
+ ],
3130
+ "default": null,
3131
+ "description": "The target repository override (e.g. org/repo).",
3132
+ "title": "Repo"
3047
3133
  }
3048
3134
  },
3049
3135
  "title": "SearchPRsInput",
@@ -27,6 +27,16 @@ describe("github.create_issue", () => {
27
27
  });
28
28
 
29
29
  const result = await createIssueHandler({ title: "Test Issue", body: "Test Body", file: null, repo: null });
30
+ expect(shell.runCommand).toHaveBeenCalledWith("td-cli", [
31
+ "gh",
32
+ "create-issue",
33
+ "--title",
34
+ "Test Issue",
35
+ "--body",
36
+ "Test Body",
37
+ "--repo",
38
+ expect.any(String)
39
+ ]);
30
40
  expect(result.status).toBe("success");
31
41
  expect(result.issue?.number).toBe(123);
32
42
  expect(result.issue?.title).toBe("Test Issue");
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { runCommand } from "../lib/shell.js";
3
+ import { resolveRepo } from "../lib/git.js";
3
4
  import { sanitizeError } from "../lib/error_utils.js";
4
5
  import { CreateIssueInputSchema, CreateIssueResponseSchema } from "./contract.js";
5
6
 
@@ -7,11 +8,12 @@ export { CreateIssueInputSchema };
7
8
 
8
9
  export async function createIssueHandler(args: z.input<typeof CreateIssueInputSchema>) {
9
10
  const params = CreateIssueInputSchema.parse(args);
11
+ const targetRepo = resolveRepo(params.repo);
10
12
 
11
13
  const cmdArgs = ["gh", "create-issue", "--title", params.title];
12
14
  if (params.body) cmdArgs.push("--body", params.body);
13
15
  if (params.file) cmdArgs.push("--file", params.file);
14
- if (params.repo) cmdArgs.push("--repo", params.repo);
16
+ cmdArgs.push("--repo", targetRepo);
15
17
 
16
18
  const result = await runCommand("td-cli", cmdArgs);
17
19
 
@@ -1,11 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { runCommand } from "../lib/shell.js";
3
+ import { resolveRepo } from "../lib/git.js";
3
4
  import { CreatePullRequestInputSchema } from "./contract.js";
4
5
 
5
6
  export { CreatePullRequestInputSchema };
6
7
 
7
8
  export async function createPullRequestHandler(args: z.input<typeof CreatePullRequestInputSchema>) {
8
9
  const params = CreatePullRequestInputSchema.parse(args);
10
+ const targetRepo = resolveRepo(params.repo);
9
11
 
10
12
  const tdArgs = [
11
13
  "gh",
@@ -13,17 +15,14 @@ export async function createPullRequestHandler(args: z.input<typeof CreatePullRe
13
15
  "--title", params.title,
14
16
  "--body", params.body,
15
17
  "--head", params.head,
16
- "--base", params.base
18
+ "--base", params.base,
19
+ "--repo", targetRepo
17
20
  ];
18
21
 
19
22
  if (params.draft) {
20
23
  tdArgs.push("--draft");
21
24
  }
22
25
 
23
- if (params.repo) {
24
- tdArgs.push("--repo", params.repo);
25
- }
26
-
27
26
  const result = await runCommand("td-cli", tdArgs);
28
27
 
29
28
  if (result.exitCode !== 0) {
@@ -1,15 +1,18 @@
1
1
  import { z } from "zod";
2
2
  import { runCommand } from "../lib/shell.js";
3
+ import { resolveRepo } from "../lib/git.js";
3
4
  import { sanitizeError } from "../lib/error_utils.js";
4
5
 
5
6
  export const GetPrInputSchema = z.object({
6
7
  prNumber: z.number().describe("The number of the PR to view."),
8
+ repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
7
9
  });
8
10
 
9
11
  export async function getPrHandler(args: z.infer<typeof GetPrInputSchema>) {
10
12
  const params = GetPrInputSchema.parse(args);
13
+ const targetRepo = resolveRepo(params.repo);
11
14
 
12
- const result = await runCommand("td-cli", ["gh", "view", params.prNumber.toString()]);
15
+ const result = await runCommand("td-cli", ["gh", "view", params.prNumber.toString(), "--repo", targetRepo]);
13
16
 
14
17
  if (result.exitCode !== 0) {
15
18
  throw new Error(`Failed to get PR details: ${sanitizeError(result.stderr)}`);
@@ -1,13 +1,18 @@
1
1
  import { z } from "zod";
2
2
  import { runCommand } from "../lib/shell.js";
3
+ import { resolveRepo } from "../lib/git.js";
3
4
 
4
5
  export const GetPrDiffInputSchema = z.object({
5
- prNumber: z.number(),
6
+ prNumber: z.number().describe("The number of the pull request to get the diff for."),
7
+ repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
6
8
  });
7
9
 
8
10
  export async function getPrDiffHandler(args: z.infer<typeof GetPrDiffInputSchema>) {
11
+ const params = GetPrDiffInputSchema.parse(args);
12
+ const targetRepo = resolveRepo(params.repo);
13
+
9
14
  const result = await runCommand("td-cli", [
10
- "gh", "pr-diff", args.prNumber.toString()
15
+ "gh", "pr-diff", params.prNumber.toString(), "--repo", targetRepo
11
16
  ]);
12
17
 
13
18
  if (result.exitCode !== 0) {