@arii/boomtick-mcp 0.6.0 → 0.6.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 (75) hide show
  1. package/.mcp/schemas/github.create_issue.json +72 -3
  2. package/.mcp/schemas/github.get_merge_conflict_files.json +40 -3
  3. package/.mcp/schemas/github.get_pr_diff.json +30 -3
  4. package/.mcp/schemas/github.issue_update.json +72 -3
  5. package/.mcp/schemas/github.search_open_prs.json +130 -3
  6. package/.mcp/schemas/github_create_issue.json +72 -3
  7. package/.mcp/schemas/github_get_merge_conflict_files.json +40 -3
  8. package/.mcp/schemas/github_get_pr_diff.json +30 -3
  9. package/.mcp/schemas/github_issue_update.json +72 -3
  10. package/.mcp/schemas/github_search_open_prs.json +130 -3
  11. package/.mcp/schemas/repo.check_jules_status.json +38 -0
  12. package/.mcp/schemas/repo.run_tests.json +31 -3
  13. package/.mcp/schemas/repo_check_jules_status.json +38 -0
  14. package/.mcp/schemas/repo_run_tests.json +31 -3
  15. package/CHANGELOG.md +15 -0
  16. package/README.md +22 -1
  17. package/actions/run-project-gate/action.yml +1 -1
  18. package/dist/config/dynamic.js +33 -0
  19. package/dist/config/github.js +16 -0
  20. package/dist/config/repo.js +28 -0
  21. package/dist/config.js +16 -81
  22. package/dist/http.js +10 -0
  23. package/dist/mcp/definitions.js +29 -7
  24. package/dist/mcp/http.js +18 -10
  25. package/dist/mcp/http.test.js +54 -4
  26. package/dist/mcp/server.js +47 -10
  27. package/dist/mcp/server.test.js +52 -1
  28. package/dist/tools/contract.js +77 -0
  29. package/dist/tools/github.comment_triage_summary.js +3 -10
  30. package/dist/tools/github.get_merge_conflict_files.js +4 -2
  31. package/dist/tools/github.get_pr_commits.js +1 -1
  32. package/dist/tools/github.get_pr_diff.js +3 -11
  33. package/dist/tools/github.get_pr_reviews.js +1 -1
  34. package/dist/tools/jules/cancel-session.js +2 -9
  35. package/dist/tools/jules/cli.js +31 -0
  36. package/dist/tools/jules/get-messages.js +2 -9
  37. package/dist/tools/jules/list-sessions.js +4 -35
  38. package/dist/tools/jules/send-message.js +2 -9
  39. package/dist/tools/jules/session.js +26 -0
  40. package/dist/tools/jules/shared.js +2 -50
  41. package/dist/tools/jules/trigger-feedback.js +2 -10
  42. package/dist/tools/repo.check_jules_status.js +148 -0
  43. package/dist/tools/repo.check_jules_status.test.js +47 -0
  44. package/dist/tools/repo.get_workflow_runs.js +1 -1
  45. package/dist/tools/repo.run_tests.js +13 -1
  46. package/package.json +3 -2
  47. package/scripts/sync-contracts.ts +11 -2
  48. package/src/config/dynamic.ts +36 -0
  49. package/src/config/github.ts +16 -0
  50. package/src/config/repo.ts +36 -0
  51. package/src/config.ts +16 -89
  52. package/src/http.ts +13 -0
  53. package/src/mcp/definitions.ts +34 -6
  54. package/src/mcp/http.test.ts +65 -5
  55. package/src/mcp/http.ts +20 -14
  56. package/src/mcp/server.test.ts +62 -1
  57. package/src/mcp/server.ts +48 -11
  58. package/src/tools/contract.ts +85 -0
  59. package/src/tools/github.comment_triage_summary.ts +3 -12
  60. package/src/tools/github.get_merge_conflict_files.ts +5 -2
  61. package/src/tools/github.get_pr_commits.ts +1 -1
  62. package/src/tools/github.get_pr_diff.ts +3 -13
  63. package/src/tools/github.get_pr_reviews.ts +1 -1
  64. package/src/tools/jules/cancel-session.ts +2 -11
  65. package/src/tools/jules/cli.ts +42 -0
  66. package/src/tools/jules/get-messages.ts +2 -11
  67. package/src/tools/jules/list-sessions.ts +5 -39
  68. package/src/tools/jules/send-message.ts +2 -11
  69. package/src/tools/jules/session.ts +28 -0
  70. package/src/tools/jules/shared.ts +2 -63
  71. package/src/tools/jules/trigger-feedback.ts +2 -13
  72. package/src/tools/repo.check_jules_status.test.ts +55 -0
  73. package/src/tools/repo.check_jules_status.ts +176 -0
  74. package/src/tools/repo.get_workflow_runs.ts +1 -1
  75. package/src/tools/repo.run_tests.ts +14 -1
@@ -1645,6 +1645,53 @@ export const GetMergeConflictFilesInputJsonSchema = {
1645
1645
  "type": "object"
1646
1646
  } as const;
1647
1647
 
1648
+ export const GetMergeConflictFilesResponseSchema = z.object({ "hasConflicts": z.boolean(), "conflictedFiles": z.array(z.string()).optional(), "prNumber": z.union([z.number().int(), z.null()]).default(null), "baseBranch": z.string(), "headRef": z.string() });
1649
+
1650
+ export type GetMergeConflictFilesResponse = z.infer<typeof GetMergeConflictFilesResponseSchema>;
1651
+
1652
+ export const GetMergeConflictFilesResponseJsonSchema = {
1653
+ "properties": {
1654
+ "hasConflicts": {
1655
+ "title": "Hasconflicts",
1656
+ "type": "boolean"
1657
+ },
1658
+ "conflictedFiles": {
1659
+ "items": {
1660
+ "type": "string"
1661
+ },
1662
+ "title": "Conflictedfiles",
1663
+ "type": "array"
1664
+ },
1665
+ "prNumber": {
1666
+ "anyOf": [
1667
+ {
1668
+ "type": "integer"
1669
+ },
1670
+ {
1671
+ "type": "null"
1672
+ }
1673
+ ],
1674
+ "default": null,
1675
+ "title": "Prnumber"
1676
+ },
1677
+ "baseBranch": {
1678
+ "title": "Basebranch",
1679
+ "type": "string"
1680
+ },
1681
+ "headRef": {
1682
+ "title": "Headref",
1683
+ "type": "string"
1684
+ }
1685
+ },
1686
+ "required": [
1687
+ "hasConflicts",
1688
+ "baseBranch",
1689
+ "headRef"
1690
+ ],
1691
+ "title": "GetMergeConflictFilesResponse",
1692
+ "type": "object"
1693
+ } as const;
1694
+
1648
1695
  export const GetPackageScriptsInputSchema = z.object({ "filter": z.union([z.string(), z.null()]).describe("Optional glob pattern to filter script names.").default(null) });
1649
1696
 
1650
1697
  export type GetPackageScriptsInput = z.infer<typeof GetPackageScriptsInputSchema>;
@@ -3291,6 +3338,44 @@ export const RunTestsInputJsonSchema = {
3291
3338
  "type": "object"
3292
3339
  } as const;
3293
3340
 
3341
+ export const RunTestsResponseSchema = z.object({ "passed": z.boolean(), "exitCode": z.number().int(), "failedTests": z.array(z.string()).optional(), "results": z.array(z.record(z.string(), z.any())).optional() });
3342
+
3343
+ export type RunTestsResponse = z.infer<typeof RunTestsResponseSchema>;
3344
+
3345
+ export const RunTestsResponseJsonSchema = {
3346
+ "properties": {
3347
+ "passed": {
3348
+ "title": "Passed",
3349
+ "type": "boolean"
3350
+ },
3351
+ "exitCode": {
3352
+ "title": "Exitcode",
3353
+ "type": "integer"
3354
+ },
3355
+ "failedTests": {
3356
+ "items": {
3357
+ "type": "string"
3358
+ },
3359
+ "title": "Failedtests",
3360
+ "type": "array"
3361
+ },
3362
+ "results": {
3363
+ "items": {
3364
+ "additionalProperties": true,
3365
+ "type": "object"
3366
+ },
3367
+ "title": "Results",
3368
+ "type": "array"
3369
+ }
3370
+ },
3371
+ "required": [
3372
+ "passed",
3373
+ "exitCode"
3374
+ ],
3375
+ "title": "RunTestsResponse",
3376
+ "type": "object"
3377
+ } as const;
3378
+
3294
3379
  export const SearchDdgsInputSchema = z.object({ "query": z.string().describe("The search query."), "maxResults": z.union([z.number().int(), z.null()]).describe("Maximum number of results to return.").default(null) });
3295
3380
 
3296
3381
  export type SearchDdgsInput = z.infer<typeof SearchDdgsInputSchema>;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { runCommand } from "../lib/shell.js";
2
+ import { runTDCli } from "./jules/cli.js";
3
3
 
4
4
  export const CommentTriageSummaryInputSchema = z.object({
5
5
  prNumber: z.number(),
@@ -7,21 +7,12 @@ export const CommentTriageSummaryInputSchema = z.object({
7
7
  });
8
8
 
9
9
  export async function commentTriageSummaryHandler(args: z.infer<typeof CommentTriageSummaryInputSchema>) {
10
- const result = await runCommand("td", [
10
+ const output = await runTDCli([
11
11
  "gh",
12
12
  "post-comment",
13
13
  "--pr", args.prNumber.toString(),
14
14
  "--body", args.body
15
- ]);
16
-
17
- if (result.exitCode !== 0) {
18
- throw new Error(`Failed to comment on PR: ${result.stderr}`);
19
- }
20
-
21
- const output = JSON.parse(result.stdout);
22
- if (output.status === "error") {
23
- throw new Error(`Failed to comment on PR: ${output.message}`);
24
- }
15
+ ], "comment on PR");
25
16
 
26
17
  return {
27
18
  success: true,
@@ -12,10 +12,13 @@ export async function getMergeConflictFilesHandler(args: z.infer<typeof GetMerge
12
12
  const headRef = args.headRef || "HEAD";
13
13
  const conflictFiles = await getMergeConflictFiles(baseBranch, headRef);
14
14
 
15
+ const hasConflicts = conflictFiles.length > 0;
16
+
15
17
  return {
16
- prNumber: args.prNumber,
18
+ hasConflicts,
19
+ conflictedFiles: conflictFiles,
20
+ prNumber: args.prNumber ?? null,
17
21
  baseBranch,
18
22
  headRef,
19
- conflictFiles,
20
23
  };
21
24
  }
@@ -3,7 +3,7 @@ import { runCommand } from "../lib/shell.js";
3
3
  import { resolveRepo } from "../lib/git.js";
4
4
  import { sanitizeError } from "../lib/error_utils.js";
5
5
 
6
- const GetPrCommitsInputSchema = z.object({
6
+ export const GetPrCommitsInputSchema = z.object({
7
7
  prNumber: z.number().describe("The number of the PR to list commits for."),
8
8
  repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
9
9
  });
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
- import { runCommand } from "../lib/shell.js";
3
2
  import { resolveRepo } from "../lib/git.js";
3
+ import { runTDCli } from "./jules/cli.js";
4
4
 
5
5
  export const GetPrDiffInputSchema = z.object({
6
6
  prNumber: z.number().describe("The number of the pull request to get the diff for."),
@@ -11,20 +11,10 @@ export async function getPrDiffHandler(args: z.infer<typeof GetPrDiffInputSchema
11
11
  const params = GetPrDiffInputSchema.parse(args);
12
12
  const targetRepo = resolveRepo(params.repo);
13
13
 
14
- const result = await runCommand("td", [
14
+ const output = await runTDCli([
15
15
  "gh", "pr-diff", params.prNumber.toString(), "--repo", targetRepo
16
- ]);
16
+ ], "get PR diff");
17
17
 
18
- if (result.exitCode !== 0) {
19
- throw new Error(`Failed to get PR diff: ${result.stderr}`);
20
- }
21
-
22
- const output = JSON.parse(result.stdout);
23
- if (output.status === "error") {
24
- throw new Error(`Failed to get PR diff: ${output.message}`);
25
- }
26
-
27
- // Every TypeScript tool file must be a pure routing shim
28
18
  return {
29
19
  prNumber: output.prNumber,
30
20
  files: output.files,
@@ -3,7 +3,7 @@ import { runCommand } from "../lib/shell.js";
3
3
  import { resolveRepo } from "../lib/git.js";
4
4
  import { sanitizeError } from "../lib/error_utils.js";
5
5
 
6
- const GetPrReviewsInputSchema = z.object({
6
+ export const GetPrReviewsInputSchema = z.object({
7
7
  prNumber: z.number().describe("The number of the PR to view reviews for."),
8
8
  repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
9
9
  });
@@ -1,22 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { JulesSession } from "../types.js";
3
- import { runCommand } from "../../lib/shell.js";
3
+ import { runTDCli } from "./cli.js";
4
4
 
5
5
  export const CancelJulesSessionInputSchema = z.object({
6
6
  sessionId: z.string(),
7
7
  });
8
8
 
9
9
  export async function cancelJulesSessionHandler(input: z.infer<typeof CancelJulesSessionInputSchema>): Promise<JulesSession> {
10
- const result = await runCommand("td", ["agent", "cancel", input.sessionId]);
11
-
12
- if (result.exitCode !== 0) {
13
- throw new Error(`Failed to cancel session: ${result.stderr}`);
14
- }
15
-
16
- const output = JSON.parse(result.stdout);
17
- if (output.status === "error") {
18
- throw new Error(`Failed to cancel session: ${output.message}`);
19
- }
10
+ await runTDCli(["agent", "cancel", input.sessionId], "cancel session");
20
11
 
21
12
  return {
22
13
  id: input.sessionId.replace("sessions/", ""),
@@ -0,0 +1,42 @@
1
+ import { runCommand } from "../../lib/shell.js";
2
+
3
+ export interface TDCliResponse {
4
+ status?: string;
5
+ message?: string;
6
+ [key: string]: any;
7
+ }
8
+
9
+ function tryParseJson(text: string): TDCliResponse | null {
10
+ try {
11
+ return JSON.parse(text) as TDCliResponse;
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+
17
+ export async function runTDCli(args: string[], actionName?: string): Promise<TDCliResponse> {
18
+ const result = await runCommand("td", args);
19
+ const stdout = result.stdout.trim();
20
+ const output = stdout.startsWith("{") ? tryParseJson(stdout) : null;
21
+
22
+ if (output?.status === "error") {
23
+ const errorMsg = output.message ?? "Unknown error";
24
+ if (actionName) {
25
+ throw new Error(`Failed to ${actionName}: ${errorMsg}`);
26
+ }
27
+ throw new Error(`td returned error: ${errorMsg}`);
28
+ }
29
+
30
+ if (result.exitCode !== 0) {
31
+ if (actionName) {
32
+ throw new Error(`Failed to ${actionName}: ${result.stderr || stdout}`);
33
+ }
34
+ throw new Error(`td command failed (${args.join(" ")}): ${result.stderr || stdout}`);
35
+ }
36
+
37
+ if (!output) {
38
+ throw new Error(`td returned non-JSON output with exit code 0: ${stdout}`);
39
+ }
40
+
41
+ return output;
42
+ }
@@ -1,21 +1,12 @@
1
1
  import { z } from "zod";
2
- import { runCommand } from "../../lib/shell.js";
2
+ import { runTDCli } from "./cli.js";
3
3
 
4
4
  export const GetJulesMessagesInputSchema = z.object({
5
5
  sessionId: z.string(),
6
6
  });
7
7
 
8
8
  export async function getJulesMessagesHandler(input: z.infer<typeof GetJulesMessagesInputSchema>) {
9
- const result = await runCommand("td", ["agent", "messages", input.sessionId]);
10
-
11
- if (result.exitCode !== 0) {
12
- throw new Error(`Failed to get messages: ${result.stderr}`);
13
- }
14
-
15
- const output = JSON.parse(result.stdout);
16
- if (output.status === "error") {
17
- throw new Error(`Failed to get messages: ${output.message}`);
18
- }
9
+ const output = await runTDCli(["agent", "messages", input.sessionId], "get messages");
19
10
 
20
11
  return {
21
12
  id: input.sessionId.replace("sessions/", ""),
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
- import { JulesSession, JulesStatus } from "../types.js";
3
- import { runCommand } from "../../lib/shell.js";
2
+ import { JulesSession } from "../types.js";
3
+ import { runTDCli } from "./cli.js";
4
+ import { parseJulesSession } from "./session.js";
4
5
 
5
6
  export const ListJulesSessionsInputSchema = z.object({
6
7
  pageSize: z.number().optional(),
@@ -8,43 +9,8 @@ export const ListJulesSessionsInputSchema = z.object({
8
9
  });
9
10
 
10
11
  export async function listJulesSessionsHandler(input: z.infer<typeof ListJulesSessionsInputSchema>): Promise<JulesSession[]> {
11
- const result = await runCommand("td", ["agent", "sync"]);
12
-
13
- if (result.exitCode !== 0) {
14
- throw new Error(`Failed to list sessions: ${result.stderr}`);
15
- }
16
-
17
- const output = JSON.parse(result.stdout);
18
- if (output.status === "error") {
19
- throw new Error(`Failed to list sessions: ${output.message}`);
20
- }
21
-
12
+ const output = await runTDCli(["agent", "sync"], "list sessions");
22
13
  const sessions = output.sessions || [];
23
14
 
24
- return sessions.map((session: any) => {
25
- const name = session.name || "";
26
- const id = name.startsWith("sessions/") ? name.substring(9) : name;
27
-
28
- let status: JulesStatus = "PENDING";
29
- if (session.state === "SUCCEEDED" || session.state === "COMPLETED") status = "COMPLETED";
30
- else if (session.state === "FAILED" || session.state === "CANCELLED" || session.state === "TERMINATED") status = "FAILED";
31
- else if (session.state === "IN_PROGRESS") status = "IN_PROGRESS";
32
-
33
- let pullRequestUrl: string | undefined;
34
- if (session.outputs && Array.isArray(session.outputs)) {
35
- for (const out of session.outputs) {
36
- if (out.pullRequest && out.pullRequest.url) {
37
- pullRequestUrl = out.pullRequest.url;
38
- break;
39
- }
40
- }
41
- }
42
-
43
- return {
44
- id,
45
- status,
46
- createdAt: session.createTime ? new Date(session.createTime) : new Date(),
47
- pullRequestUrl,
48
- };
49
- });
15
+ return sessions.map((session: any) => parseJulesSession(session));
50
16
  }
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { runCommand } from "../../lib/shell.js";
2
+ import { runTDCli } from "./cli.js";
3
3
 
4
4
  export const SendJulesMessageInputSchema = z.object({
5
5
  sessionId: z.union([z.string(), z.array(z.string())]),
@@ -8,16 +8,7 @@ export const SendJulesMessageInputSchema = z.object({
8
8
 
9
9
  export async function sendJulesMessageHandler(input: z.infer<typeof SendJulesMessageInputSchema>) {
10
10
  const sessionIds = Array.isArray(input.sessionId) ? input.sessionId.join(",") : input.sessionId;
11
- const result = await runCommand("td", ["agent", "send", sessionIds, input.message]);
12
-
13
- if (result.exitCode !== 0) {
14
- throw new Error(`Failed to send message: ${result.stderr}`);
15
- }
16
-
17
- const output = JSON.parse(result.stdout);
18
- if (output.status === "error") {
19
- throw new Error(`Failed to send message: ${output.message}`);
20
- }
11
+ await runTDCli(["agent", "send", sessionIds, input.message], "send message");
21
12
 
22
13
  return {
23
14
  id: Array.isArray(input.sessionId) ? input.sessionId.map(id => id.replace("sessions/", "")) : input.sessionId.replace("sessions/", ""),
@@ -0,0 +1,28 @@
1
+ import { JulesSession, JulesStatus } from "../types.js";
2
+
3
+ export function parseJulesSession(data: any): JulesSession {
4
+ const name = data.name || "";
5
+ const id = name.startsWith("sessions/") ? name.substring(9) : name;
6
+
7
+ let status: JulesStatus = "PENDING";
8
+ if (data.state === "SUCCEEDED" || data.state === "COMPLETED") status = "COMPLETED";
9
+ else if (data.state === "FAILED" || data.state === "CANCELLED" || data.state === "TERMINATED") status = "FAILED";
10
+ else if (data.state === "IN_PROGRESS") status = "IN_PROGRESS";
11
+
12
+ let pullRequestUrl: string | undefined;
13
+ if (data.outputs && Array.isArray(data.outputs)) {
14
+ for (const out of data.outputs) {
15
+ if (out.pullRequest && out.pullRequest.url) {
16
+ pullRequestUrl = out.pullRequest.url;
17
+ break;
18
+ }
19
+ }
20
+ }
21
+
22
+ return {
23
+ id,
24
+ status,
25
+ createdAt: data.createTime ? new Date(data.createTime) : new Date(),
26
+ pullRequestUrl,
27
+ };
28
+ }
@@ -1,63 +1,2 @@
1
- import { JulesSession, JulesStatus } from "../types.js";
2
- import { runCommand } from "../../lib/shell.js";
3
-
4
- export interface TDCliResponse {
5
- status?: string;
6
- message?: string;
7
- [key: string]: any;
8
- }
9
-
10
- function tryParseJson(text: string): TDCliResponse | null {
11
- try {
12
- return JSON.parse(text) as TDCliResponse;
13
- } catch {
14
- return null;
15
- }
16
- }
17
-
18
- export async function runTDCli(args: string[]): Promise<TDCliResponse> {
19
- const result = await runCommand("td", args);
20
- const stdout = result.stdout.trim();
21
- const output = stdout.startsWith("{") ? tryParseJson(stdout) : null;
22
-
23
- if (output?.status === "error") {
24
- throw new Error(`td returned error: ${output.message ?? "Unknown error"}`);
25
- }
26
-
27
- if (result.exitCode !== 0) {
28
- throw new Error(`td command failed (${args.join(" ")}): ${result.stderr || stdout}`);
29
- }
30
-
31
- if (!output) {
32
- throw new Error(`td returned non-JSON output with exit code 0: ${stdout}`);
33
- }
34
-
35
- return output;
36
- }
37
-
38
- export function parseJulesSession(data: any): JulesSession {
39
- const name = data.name || "";
40
- const id = name.startsWith("sessions/") ? name.substring(9) : name;
41
-
42
- let status: JulesStatus = "PENDING";
43
- if (data.state === "SUCCEEDED" || data.state === "COMPLETED") status = "COMPLETED";
44
- else if (data.state === "FAILED" || data.state === "CANCELLED" || data.state === "TERMINATED") status = "FAILED";
45
- else if (data.state === "IN_PROGRESS") status = "IN_PROGRESS";
46
-
47
- let pullRequestUrl: string | undefined;
48
- if (data.outputs && Array.isArray(data.outputs)) {
49
- for (const out of data.outputs) {
50
- if (out.pullRequest && out.pullRequest.url) {
51
- pullRequestUrl = out.pullRequest.url;
52
- break;
53
- }
54
- }
55
- }
56
-
57
- return {
58
- id,
59
- status,
60
- createdAt: data.createTime ? new Date(data.createTime) : new Date(),
61
- pullRequestUrl,
62
- };
63
- }
1
+ export * from "./cli.js";
2
+ export * from "./session.js";
@@ -1,21 +1,10 @@
1
1
  import { z } from "zod";
2
- import { runCommand } from "../../lib/shell.js";
2
+ import { runTDCli } from "./cli.js";
3
3
 
4
4
  export const TriggerJulesFeedbackInputSchema = z.object({
5
5
  sessionId: z.string(),
6
6
  });
7
7
 
8
8
  export async function triggerJulesFeedbackHandler(input: z.infer<typeof TriggerJulesFeedbackInputSchema>) {
9
- const result = await runCommand("td", ["agent", "trigger-feedback", input.sessionId]);
10
-
11
- if (result.exitCode !== 0) {
12
- throw new Error(`Failed to trigger feedback: ${result.stderr}`);
13
- }
14
-
15
- const output = JSON.parse(result.stdout);
16
- if (output.status === "error") {
17
- throw new Error(`Failed to trigger feedback: ${output.message}`);
18
- }
19
-
20
- return output;
9
+ return await runTDCli(["agent", "trigger-feedback", input.sessionId], "trigger feedback");
21
10
  }
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import { checkJulesStatusHandler } from "./repo.check_jules_status.js";
3
+
4
+ describe("repo.check_jules_status MCP Tool Handler", () => {
5
+ const originalEnv = process.env;
6
+
7
+ beforeEach(() => {
8
+ vi.clearAllMocks();
9
+ process.env = { ...originalEnv };
10
+ delete process.env.TASK_ID;
11
+ delete process.env.JULES_API_KEY;
12
+ global.fetch = vi.fn();
13
+ });
14
+
15
+ afterEach(() => {
16
+ process.env = originalEnv;
17
+ vi.restoreAllMocks();
18
+ });
19
+
20
+ it("returns NOT_FOUND status if no session ID or JULES_API_KEY is available", async () => {
21
+ const result = await checkJulesStatusHandler({});
22
+ expect(result.status).toBe("NOT_FOUND");
23
+ expect(result.completed).toBe(false);
24
+ });
25
+
26
+ it("checks Jules session status and returns response object", async () => {
27
+ process.env.JULES_API_KEY = "test-api-key";
28
+
29
+ vi.mocked(global.fetch).mockResolvedValue({
30
+ ok: true,
31
+ json: vi.fn().mockResolvedValue({
32
+ name: "sessions/test-session-123",
33
+ state: "SUCCEEDED",
34
+ outputs: [
35
+ {
36
+ pullRequest: {
37
+ url: "https://github.com/org/repo/pull/100",
38
+ branch: "remediation-branch-123",
39
+ },
40
+ },
41
+ ],
42
+ }),
43
+ } as any);
44
+
45
+ const result = await checkJulesStatusHandler({
46
+ sessionId: "test-session-123",
47
+ });
48
+
49
+ expect(result.sessionId).toBe("sessions/test-session-123");
50
+ expect(result.status).toBe("COMPLETED");
51
+ expect(result.completed).toBe(true);
52
+ expect(result.remediationBranch).toBe("remediation-branch-123");
53
+ expect(result.pullRequestUrl).toBe("https://github.com/org/repo/pull/100");
54
+ });
55
+ });