@arii/boomtick-mcp 0.4.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp/schemas/boomtick.health.json +5 -0
- package/.mcp/schemas/boomtick_health.json +5 -0
- package/.mcp/schemas/github.checkout_branch.json +5 -0
- package/.mcp/schemas/github.comment_triage_summary.json +5 -0
- package/.mcp/schemas/github.create_issue.json +5 -0
- package/.mcp/schemas/github.create_pull_request.json +5 -0
- package/.mcp/schemas/github.get_merge_conflict_files.json +5 -0
- package/.mcp/schemas/github.get_pr.json +5 -0
- package/.mcp/schemas/github.get_pr_commits.json +37 -0
- package/.mcp/schemas/github.get_pr_diff.json +5 -0
- package/.mcp/schemas/github.get_pr_reviews.json +37 -0
- package/.mcp/schemas/github.issue_comment.json +5 -0
- package/.mcp/schemas/github.issue_update.json +5 -0
- package/.mcp/schemas/github.issue_view.json +5 -0
- package/.mcp/schemas/github.open_replacement_pr.json +5 -0
- package/.mcp/schemas/github.search_open_prs.json +5 -0
- package/.mcp/schemas/github_checkout_branch.json +5 -0
- package/.mcp/schemas/github_comment_triage_summary.json +5 -0
- package/.mcp/schemas/github_create_issue.json +5 -0
- package/.mcp/schemas/github_create_pull_request.json +5 -0
- package/.mcp/schemas/github_get_merge_conflict_files.json +5 -0
- package/.mcp/schemas/github_get_pr.json +5 -0
- package/.mcp/schemas/github_get_pr_commits.json +37 -0
- package/.mcp/schemas/github_get_pr_diff.json +5 -0
- package/.mcp/schemas/github_get_pr_reviews.json +37 -0
- package/.mcp/schemas/github_issue_comment.json +5 -0
- package/.mcp/schemas/github_issue_update.json +5 -0
- package/.mcp/schemas/github_issue_view.json +5 -0
- package/.mcp/schemas/github_open_replacement_pr.json +5 -0
- package/.mcp/schemas/github_search_open_prs.json +5 -0
- package/.mcp/schemas/jules.cancel_session.json +5 -0
- package/.mcp/schemas/jules.create_session.json +5 -0
- package/.mcp/schemas/jules.get_messages.json +5 -0
- package/.mcp/schemas/jules.get_pr.json +5 -0
- package/.mcp/schemas/jules.get_session.json +5 -0
- package/.mcp/schemas/jules.list_sessions.json +5 -0
- package/.mcp/schemas/jules.send_message.json +5 -0
- package/.mcp/schemas/jules.trigger_feedback.json +5 -0
- package/.mcp/schemas/jules_cancel_session.json +5 -0
- package/.mcp/schemas/jules_create_session.json +5 -0
- package/.mcp/schemas/jules_get_messages.json +5 -0
- package/.mcp/schemas/jules_get_pr.json +5 -0
- package/.mcp/schemas/jules_get_session.json +5 -0
- package/.mcp/schemas/jules_list_sessions.json +5 -0
- package/.mcp/schemas/jules_send_message.json +5 -0
- package/.mcp/schemas/jules_trigger_feedback.json +5 -0
- package/.mcp/schemas/repo.commit_patch.json +5 -0
- package/.mcp/schemas/repo.create_branch.json +5 -0
- package/.mcp/schemas/repo.create_repair_branch.json +5 -0
- package/.mcp/schemas/repo.get_changed_files.json +5 -0
- package/.mcp/schemas/repo.get_command_schema.json +6 -1
- package/.mcp/schemas/repo.get_package_scripts.json +5 -0
- package/.mcp/schemas/repo.get_workflow_runs.json +55 -0
- package/.mcp/schemas/repo.logs.json +19 -0
- package/.mcp/schemas/repo.read_agent_context.json +5 -0
- package/.mcp/schemas/repo.read_ci_logs.json +19 -0
- package/.mcp/schemas/repo.run_tests.json +5 -0
- package/.mcp/schemas/repo_commit_patch.json +5 -0
- package/.mcp/schemas/repo_create_branch.json +5 -0
- package/.mcp/schemas/repo_create_repair_branch.json +5 -0
- package/.mcp/schemas/repo_get_changed_files.json +5 -0
- package/.mcp/schemas/repo_get_command_schema.json +6 -1
- package/.mcp/schemas/repo_get_package_scripts.json +5 -0
- package/.mcp/schemas/repo_get_workflow_runs.json +55 -0
- package/.mcp/schemas/repo_logs.json +19 -0
- package/.mcp/schemas/repo_read_agent_context.json +5 -0
- package/.mcp/schemas/repo_read_ci_logs.json +19 -0
- package/.mcp/schemas/repo_run_tests.json +5 -0
- package/CHANGELOG.md +14 -0
- package/README.md +0 -1
- package/actions/ai-review/action.yml +2 -2
- package/actions/audit/action.yml +1 -1
- package/actions/ci-validate/action.yml +2 -2
- package/actions/impact-analysis/action.yml +7 -19
- package/actions/run-project-gate/action.yml +7 -14
- package/actions/setup/action.yml +1 -1
- package/actions/test-build/action.yml +2 -20
- package/dist/config.js +1 -1
- package/dist/config.test.js +3 -3
- package/dist/lib/git.js +44 -0
- package/dist/lib/git.test.js +82 -0
- package/dist/lib/result.js +4 -0
- package/dist/lib/result.test.js +4 -2
- package/dist/lib/shell.js +6 -6
- package/dist/mcp/definitions.js +86 -38
- package/dist/mcp/http.js +91 -0
- package/dist/mcp/http.test.js +58 -0
- package/dist/mcp/server.js +51 -57
- package/dist/mcp/server.test.js +19 -32
- package/dist/tools/contract.js +244 -3
- package/dist/tools/github.checkout_branch.js +1 -1
- package/dist/tools/github.comment_triage_summary.js +1 -1
- package/dist/tools/github.create_issue.js +1 -1
- package/dist/tools/github.create_issue.test.js +6 -6
- package/dist/tools/github.create_pull_request.js +1 -1
- package/dist/tools/github.create_pull_request.test.js +4 -4
- package/dist/tools/github.get_merge_conflict_files.js +10 -18
- package/dist/tools/github.get_pr.js +1 -1
- package/dist/tools/github.get_pr_commits.js +21 -0
- package/dist/tools/github.get_pr_diff.js +1 -1
- package/dist/tools/github.get_pr_reviews.js +21 -0
- package/dist/tools/github.get_pr_reviews.test.js +99 -0
- package/dist/tools/github.issue_comment.js +1 -1
- package/dist/tools/github.issue_update.js +1 -1
- package/dist/tools/github.issue_view.js +1 -1
- package/dist/tools/github.search_open_prs.js +1 -1
- package/dist/tools/jules/cancel-session.js +1 -1
- package/dist/tools/jules/create-session.js +1 -2
- package/dist/tools/jules/create-session.test.js +11 -11
- package/dist/tools/jules/get-messages.js +1 -1
- package/dist/tools/jules/get-messages.test.js +3 -3
- package/dist/tools/jules/get-pr.js +1 -2
- package/dist/tools/jules/get-pr.test.js +3 -3
- package/dist/tools/jules/get-session.js +1 -2
- package/dist/tools/jules/list-sessions.js +1 -1
- package/dist/tools/jules/send-message.js +1 -1
- package/dist/tools/jules/send-message.test.js +5 -5
- package/dist/tools/jules/shared.js +24 -0
- package/dist/tools/jules/trigger-feedback.js +1 -1
- package/dist/tools/jules/trigger-feedback.test.js +5 -5
- package/dist/tools/repo.get_changed_files.js +2 -13
- package/dist/tools/repo.get_command_schema.js +2 -2
- package/dist/tools/repo.get_workflow_runs.js +29 -0
- package/dist/tools/repo.logs.js +5 -1
- package/dist/tools/repo.read_agent_context.js +27 -1
- package/dist/tools/repo.read_agent_context.test.js +1 -1
- package/dist/tools/repo.read_ci_logs.js +5 -1
- package/dist/tools/repo.run_tests.js +1 -1
- package/package.json +3 -6
- package/scripts/sync-mcp-schemas.ts +2 -0
- package/src/agents/verifier-agent.prompt.md +0 -4
- package/src/config.test.ts +3 -3
- package/src/config.ts +1 -1
- package/src/lib/git.test.ts +110 -0
- package/src/lib/git.ts +75 -0
- package/src/lib/result.test.ts +4 -2
- package/src/lib/result.ts +6 -0
- package/src/lib/shell.ts +6 -6
- package/src/mcp/definitions.ts +91 -42
- package/src/mcp/http.test.ts +72 -0
- package/src/mcp/http.ts +118 -0
- package/src/mcp/server.test.ts +20 -38
- package/src/mcp/server.ts +60 -54
- package/src/tools/contract.ts +256 -3
- package/src/tools/github.checkout_branch.ts +1 -1
- package/src/tools/github.comment_triage_summary.ts +1 -1
- package/src/tools/github.create_issue.test.ts +6 -6
- package/src/tools/github.create_issue.ts +1 -1
- package/src/tools/github.create_pull_request.test.ts +4 -4
- package/src/tools/github.create_pull_request.ts +1 -1
- package/src/tools/github.get_merge_conflict_files.ts +10 -20
- package/src/tools/github.get_pr.ts +1 -1
- package/src/tools/github.get_pr_commits.ts +27 -0
- package/src/tools/github.get_pr_diff.ts +1 -1
- package/src/tools/github.get_pr_reviews.test.ts +110 -0
- package/src/tools/github.get_pr_reviews.ts +27 -0
- package/src/tools/github.issue_comment.ts +1 -1
- package/src/tools/github.issue_update.ts +1 -1
- package/src/tools/github.issue_view.ts +1 -1
- package/src/tools/github.search_open_prs.ts +1 -1
- package/src/tools/jules/cancel-session.ts +1 -1
- package/src/tools/jules/create-session.test.ts +11 -11
- package/src/tools/jules/create-session.ts +1 -2
- package/src/tools/jules/get-messages.test.ts +3 -3
- package/src/tools/jules/get-messages.ts +1 -1
- package/src/tools/jules/get-pr.test.ts +3 -3
- package/src/tools/jules/get-pr.ts +1 -2
- package/src/tools/jules/get-session.ts +1 -2
- package/src/tools/jules/list-sessions.ts +1 -1
- package/src/tools/jules/send-message.test.ts +5 -5
- package/src/tools/jules/send-message.ts +1 -1
- package/src/tools/jules/shared.ts +35 -0
- package/src/tools/jules/trigger-feedback.test.ts +5 -5
- package/src/tools/jules/trigger-feedback.ts +1 -1
- package/src/tools/repo.get_changed_files.ts +2 -16
- package/src/tools/repo.get_command_schema.ts +2 -2
- package/src/tools/repo.get_workflow_runs.ts +36 -0
- package/src/tools/repo.logs.ts +5 -1
- package/src/tools/repo.read_agent_context.test.ts +1 -1
- package/src/tools/repo.read_agent_context.ts +35 -1
- package/src/tools/repo.read_ci_logs.ts +5 -1
- package/src/tools/repo.run_tests.ts +1 -1
- package/.mcp/schemas/agent.search_ddgs.json +0 -31
- package/.mcp/schemas/agent_search_ddgs.json +0 -31
- package/.mcp/schemas/repo.get_route_map.json +0 -23
- package/.mcp/schemas/repo.run_lighthouse.json +0 -29
- package/.mcp/schemas/repo.run_playwright.json +0 -36
- package/.mcp/schemas/repo_get_route_map.json +0 -23
- package/.mcp/schemas/repo_run_lighthouse.json +0 -29
- package/.mcp/schemas/repo_run_playwright.json +0 -36
- package/dist/lib/td-cli.js +0 -54
- package/dist/tools/ddgs.search.js +0 -50
- package/dist/tools/ddgs.search.test.js +0 -67
- package/dist/tools/ddgs_search.py +0 -23
- package/dist/tools/repo.get_route_map.js +0 -37
- package/dist/tools/repo.run_lighthouse.js +0 -37
- package/dist/tools/repo.run_playwright.js +0 -34
- package/scripts/export-mcp-schema.ts +0 -7
- package/src/lib/td-cli.ts +0 -73
- package/src/tools/ddgs.search.test.ts +0 -92
- package/src/tools/ddgs.search.ts +0 -58
- package/src/tools/ddgs_search.py +0 -23
- package/src/tools/repo.get_route_map.ts +0 -41
- package/src/tools/repo.run_lighthouse.ts +0 -40
- package/src/tools/repo.run_playwright.ts +0 -42
|
@@ -15,7 +15,7 @@ const IssueCommentOutputSchema = z.object({
|
|
|
15
15
|
export async function issueCommentHandler(args) {
|
|
16
16
|
const params = IssueCommentInputSchema.parse(args);
|
|
17
17
|
const targetRepo = resolveRepo(params.repo);
|
|
18
|
-
const result = await runCommand("td
|
|
18
|
+
const result = await runCommand("td", [
|
|
19
19
|
"gh", "issue-comment", params.issueNumber.toString(),
|
|
20
20
|
"--body", params.body,
|
|
21
21
|
"--repo", targetRepo
|
|
@@ -20,7 +20,7 @@ export async function issueUpdateHandler(args) {
|
|
|
20
20
|
if (params.state)
|
|
21
21
|
cmdArgs.push("--state", params.state);
|
|
22
22
|
cmdArgs.push("--repo", targetRepo);
|
|
23
|
-
const result = await runCommand("td
|
|
23
|
+
const result = await runCommand("td", cmdArgs);
|
|
24
24
|
if (result.exitCode !== 0) {
|
|
25
25
|
throw new Error(`Failed to update issue: ${sanitizeError(result.stderr)}`);
|
|
26
26
|
}
|
|
@@ -19,7 +19,7 @@ const IssueViewOutputSchema = z.object({
|
|
|
19
19
|
export async function issueViewHandler(args) {
|
|
20
20
|
const params = IssueViewInputSchema.parse(args);
|
|
21
21
|
const targetRepo = resolveRepo(params.repo);
|
|
22
|
-
const result = await runCommand("td
|
|
22
|
+
const result = await runCommand("td", ["gh", "issue-view", params.issueNumber.toString(), "--repo", targetRepo]);
|
|
23
23
|
if (result.exitCode !== 0) {
|
|
24
24
|
throw new Error(`Failed to view issue: ${sanitizeError(result.stderr)}`);
|
|
25
25
|
}
|
|
@@ -23,7 +23,7 @@ export async function searchOpenPrsHandler(args) {
|
|
|
23
23
|
if (params.labels && params.labels.length > 0) {
|
|
24
24
|
tdArgs.push("--labels", params.labels.join(","));
|
|
25
25
|
}
|
|
26
|
-
const result = await runCommand("td
|
|
26
|
+
const result = await runCommand("td", tdArgs);
|
|
27
27
|
if (result.exitCode !== 0) {
|
|
28
28
|
throw new Error(`Failed to list PRs: ${result.stderr}`);
|
|
29
29
|
}
|
|
@@ -4,7 +4,7 @@ export const CancelJulesSessionInputSchema = z.object({
|
|
|
4
4
|
sessionId: z.string(),
|
|
5
5
|
});
|
|
6
6
|
export async function cancelJulesSessionHandler(input) {
|
|
7
|
-
const result = await runCommand("td
|
|
7
|
+
const result = await runCommand("td", ["agent", "cancel", input.sessionId]);
|
|
8
8
|
if (result.exitCode !== 0) {
|
|
9
9
|
throw new Error(`Failed to cancel session: ${result.stderr}`);
|
|
10
10
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { runTDCli } from "
|
|
3
|
-
import { parseJulesSession } from "./shared.js";
|
|
2
|
+
import { runTDCli, parseJulesSession } from "./shared.js";
|
|
4
3
|
export const CreateJulesSessionInputSchema = z.object({
|
|
5
4
|
task: z.string(),
|
|
6
5
|
branch: z.string().optional(),
|
|
@@ -18,7 +18,7 @@ describe("createJulesSessionHandler", () => {
|
|
|
18
18
|
stderr: "",
|
|
19
19
|
exitCode: 0,
|
|
20
20
|
durationMs: 10,
|
|
21
|
-
command: "td
|
|
21
|
+
command: "td agent dispatch"
|
|
22
22
|
});
|
|
23
23
|
});
|
|
24
24
|
afterEach(() => {
|
|
@@ -30,14 +30,14 @@ describe("createJulesSessionHandler", () => {
|
|
|
30
30
|
expect(result.id).toBe("1234567890");
|
|
31
31
|
expect(result.status).toBe("IN_PROGRESS");
|
|
32
32
|
expect(result.createdAt).toBeInstanceOf(Date);
|
|
33
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
33
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
34
34
|
"agent", "dispatch", "main", "do work"
|
|
35
35
|
]);
|
|
36
36
|
});
|
|
37
37
|
it("should create a session with specific branch", async () => {
|
|
38
38
|
const result = await createJulesSessionHandler({ task: "do work", branch: "feature-x" });
|
|
39
39
|
expect(result.id).toBe("1234567890");
|
|
40
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
40
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
41
41
|
"agent", "dispatch", "feature-x", "do work"
|
|
42
42
|
]);
|
|
43
43
|
});
|
|
@@ -49,7 +49,7 @@ describe("createJulesSessionHandler", () => {
|
|
|
49
49
|
stderr: "",
|
|
50
50
|
exitCode: 0,
|
|
51
51
|
durationMs: 10,
|
|
52
|
-
command: "td
|
|
52
|
+
command: "td gh view"
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
return {
|
|
@@ -62,15 +62,15 @@ describe("createJulesSessionHandler", () => {
|
|
|
62
62
|
stderr: "",
|
|
63
63
|
exitCode: 0,
|
|
64
64
|
durationMs: 10,
|
|
65
|
-
command: "td
|
|
65
|
+
command: "td agent dispatch"
|
|
66
66
|
};
|
|
67
67
|
});
|
|
68
68
|
const result = await createJulesSessionHandler({ task: "do work", pr: 42 });
|
|
69
69
|
expect(result.id).toBe("1234567890");
|
|
70
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
70
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
71
71
|
"gh", "view", "42"
|
|
72
72
|
]);
|
|
73
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
73
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
74
74
|
"agent", "dispatch", "pr-branch", "do work"
|
|
75
75
|
]);
|
|
76
76
|
});
|
|
@@ -80,10 +80,10 @@ describe("createJulesSessionHandler", () => {
|
|
|
80
80
|
stderr: "Original error",
|
|
81
81
|
exitCode: 1,
|
|
82
82
|
durationMs: 10,
|
|
83
|
-
command: "td
|
|
83
|
+
command: "td gh view"
|
|
84
84
|
});
|
|
85
85
|
await expect(createJulesSessionHandler({ task: "do work", pr: 999 }))
|
|
86
|
-
.rejects.toThrow("td
|
|
86
|
+
.rejects.toThrow("td returned error: PR not found");
|
|
87
87
|
});
|
|
88
88
|
it("should throw descriptive error if PR JSON is invalid", async () => {
|
|
89
89
|
vi.mocked(shell.runCommand).mockResolvedValue({
|
|
@@ -91,9 +91,9 @@ describe("createJulesSessionHandler", () => {
|
|
|
91
91
|
stderr: "",
|
|
92
92
|
exitCode: 0,
|
|
93
93
|
durationMs: 10,
|
|
94
|
-
command: "td
|
|
94
|
+
command: "td gh view"
|
|
95
95
|
});
|
|
96
96
|
await expect(createJulesSessionHandler({ task: "do work", pr: 42 }))
|
|
97
|
-
.rejects.toThrow("td
|
|
97
|
+
.rejects.toThrow("td returned non-JSON output with exit code 0: invalid json");
|
|
98
98
|
});
|
|
99
99
|
});
|
|
@@ -4,7 +4,7 @@ export const GetJulesMessagesInputSchema = z.object({
|
|
|
4
4
|
sessionId: z.string(),
|
|
5
5
|
});
|
|
6
6
|
export async function getJulesMessagesHandler(input) {
|
|
7
|
-
const result = await runCommand("td
|
|
7
|
+
const result = await runCommand("td", ["agent", "messages", input.sessionId]);
|
|
8
8
|
if (result.exitCode !== 0) {
|
|
9
9
|
throw new Error(`Failed to get messages: ${result.stderr}`);
|
|
10
10
|
}
|
|
@@ -13,7 +13,7 @@ describe("getJulesMessagesHandler", () => {
|
|
|
13
13
|
teardownTestEnv();
|
|
14
14
|
vi.clearAllMocks();
|
|
15
15
|
});
|
|
16
|
-
it("should return messages from td
|
|
16
|
+
it("should return messages from td", async () => {
|
|
17
17
|
const mockMessages = [
|
|
18
18
|
{
|
|
19
19
|
role: "user",
|
|
@@ -31,14 +31,14 @@ describe("getJulesMessagesHandler", () => {
|
|
|
31
31
|
stderr: "",
|
|
32
32
|
exitCode: 0,
|
|
33
33
|
durationMs: 0,
|
|
34
|
-
command: "td
|
|
34
|
+
command: "td agent messages"
|
|
35
35
|
});
|
|
36
36
|
const result = await getJulesMessagesHandler({ sessionId: "123" });
|
|
37
37
|
expect(result.id).toBe("123");
|
|
38
38
|
expect(result.messages.length).toBe(2);
|
|
39
39
|
expect(result.messages[0].role).toBe("user");
|
|
40
40
|
expect(result.messages[0].content).toBe("Hello Jules");
|
|
41
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
41
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
42
42
|
"agent", "messages", "123"
|
|
43
43
|
]);
|
|
44
44
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { runTDCli } from "
|
|
3
|
-
import { parseJulesSession } from "./shared.js";
|
|
2
|
+
import { runTDCli, parseJulesSession } from "./shared.js";
|
|
4
3
|
export const GetJulesPullRequestInputSchema = z.object({
|
|
5
4
|
sessionId: z.string(),
|
|
6
5
|
});
|
|
@@ -13,7 +13,7 @@ describe("getJulesPullRequestHandler", () => {
|
|
|
13
13
|
teardownTestEnv();
|
|
14
14
|
vi.clearAllMocks();
|
|
15
15
|
});
|
|
16
|
-
it("should get PR from td
|
|
16
|
+
it("should get PR from td", async () => {
|
|
17
17
|
vi.mocked(shell.runCommand).mockResolvedValue({
|
|
18
18
|
stdout: JSON.stringify({
|
|
19
19
|
status: "success",
|
|
@@ -25,12 +25,12 @@ describe("getJulesPullRequestHandler", () => {
|
|
|
25
25
|
stderr: "",
|
|
26
26
|
exitCode: 0,
|
|
27
27
|
durationMs: 0,
|
|
28
|
-
command: "td
|
|
28
|
+
command: "td agent get-session"
|
|
29
29
|
});
|
|
30
30
|
const result = await getJulesPullRequestHandler({ sessionId: "123" });
|
|
31
31
|
expect(result.id).toBe("123");
|
|
32
32
|
expect(result.pullRequestUrl).toBe("https://github.com/pr/1");
|
|
33
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
33
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
34
34
|
"agent", "get-session", "123"
|
|
35
35
|
]);
|
|
36
36
|
});
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { runTDCli } from "
|
|
3
|
-
import { parseJulesSession } from "./shared.js";
|
|
2
|
+
import { runTDCli, parseJulesSession } from "./shared.js";
|
|
4
3
|
export const GetJulesSessionInputSchema = z.object({
|
|
5
4
|
sessionId: z.string(),
|
|
6
5
|
});
|
|
@@ -5,7 +5,7 @@ export const ListJulesSessionsInputSchema = z.object({
|
|
|
5
5
|
pageToken: z.string().optional(),
|
|
6
6
|
});
|
|
7
7
|
export async function listJulesSessionsHandler(input) {
|
|
8
|
-
const result = await runCommand("td
|
|
8
|
+
const result = await runCommand("td", ["agent", "sync"]);
|
|
9
9
|
if (result.exitCode !== 0) {
|
|
10
10
|
throw new Error(`Failed to list sessions: ${result.stderr}`);
|
|
11
11
|
}
|
|
@@ -6,7 +6,7 @@ export const SendJulesMessageInputSchema = z.object({
|
|
|
6
6
|
});
|
|
7
7
|
export async function sendJulesMessageHandler(input) {
|
|
8
8
|
const sessionIds = Array.isArray(input.sessionId) ? input.sessionId.join(",") : input.sessionId;
|
|
9
|
-
const result = await runCommand("td
|
|
9
|
+
const result = await runCommand("td", ["agent", "send", sessionIds, input.message]);
|
|
10
10
|
if (result.exitCode !== 0) {
|
|
11
11
|
throw new Error(`Failed to send message: ${result.stderr}`);
|
|
12
12
|
}
|
|
@@ -13,18 +13,18 @@ describe("sendJulesMessageHandler", () => {
|
|
|
13
13
|
teardownTestEnv();
|
|
14
14
|
vi.clearAllMocks();
|
|
15
15
|
});
|
|
16
|
-
it("should send a message via td
|
|
16
|
+
it("should send a message via td", async () => {
|
|
17
17
|
vi.mocked(shell.runCommand).mockResolvedValue({
|
|
18
18
|
stdout: JSON.stringify({ status: "success", message: "Message sent successfully" }),
|
|
19
19
|
stderr: "",
|
|
20
20
|
exitCode: 0,
|
|
21
21
|
durationMs: 0,
|
|
22
|
-
command: "td
|
|
22
|
+
command: "td agent send"
|
|
23
23
|
});
|
|
24
24
|
const result = await sendJulesMessageHandler({ sessionId: "123", message: "hi" });
|
|
25
25
|
expect(result.id).toBe("123");
|
|
26
26
|
expect(result.status).toBe("success");
|
|
27
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
27
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
28
28
|
"agent", "send", "123", "hi"
|
|
29
29
|
]);
|
|
30
30
|
});
|
|
@@ -41,7 +41,7 @@ describe("sendJulesMessageHandler", () => {
|
|
|
41
41
|
stderr: "",
|
|
42
42
|
exitCode: 0,
|
|
43
43
|
durationMs: 0,
|
|
44
|
-
command: "td
|
|
44
|
+
command: "td agent send"
|
|
45
45
|
});
|
|
46
46
|
const result = await sendJulesMessageHandler({
|
|
47
47
|
sessionId: ["sessions/s1", "sessions/s2"],
|
|
@@ -49,7 +49,7 @@ describe("sendJulesMessageHandler", () => {
|
|
|
49
49
|
});
|
|
50
50
|
expect(result.id).toEqual(["s1", "s2"]);
|
|
51
51
|
expect(result.status).toBe("success");
|
|
52
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
52
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
53
53
|
"agent", "send", "sessions/s1,sessions/s2", "hi batch"
|
|
54
54
|
]);
|
|
55
55
|
});
|
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
import { runCommand } from "../../lib/shell.js";
|
|
2
|
+
function tryParseJson(text) {
|
|
3
|
+
try {
|
|
4
|
+
return JSON.parse(text);
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function runTDCli(args) {
|
|
11
|
+
const result = await runCommand("td", args);
|
|
12
|
+
const stdout = result.stdout.trim();
|
|
13
|
+
const output = stdout.startsWith("{") ? tryParseJson(stdout) : null;
|
|
14
|
+
if (output?.status === "error") {
|
|
15
|
+
throw new Error(`td returned error: ${output.message ?? "Unknown error"}`);
|
|
16
|
+
}
|
|
17
|
+
if (result.exitCode !== 0) {
|
|
18
|
+
throw new Error(`td command failed (${args.join(" ")}): ${result.stderr || stdout}`);
|
|
19
|
+
}
|
|
20
|
+
if (!output) {
|
|
21
|
+
throw new Error(`td returned non-JSON output with exit code 0: ${stdout}`);
|
|
22
|
+
}
|
|
23
|
+
return output;
|
|
24
|
+
}
|
|
1
25
|
export function parseJulesSession(data) {
|
|
2
26
|
const name = data.name || "";
|
|
3
27
|
const id = name.startsWith("sessions/") ? name.substring(9) : name;
|
|
@@ -4,7 +4,7 @@ export const TriggerJulesFeedbackInputSchema = z.object({
|
|
|
4
4
|
sessionId: z.string(),
|
|
5
5
|
});
|
|
6
6
|
export async function triggerJulesFeedbackHandler(input) {
|
|
7
|
-
const result = await runCommand("td
|
|
7
|
+
const result = await runCommand("td", ["agent", "trigger-feedback", input.sessionId]);
|
|
8
8
|
if (result.exitCode !== 0) {
|
|
9
9
|
throw new Error(`Failed to trigger feedback: ${result.stderr}`);
|
|
10
10
|
}
|
|
@@ -13,28 +13,28 @@ describe("triggerJulesFeedbackHandler", () => {
|
|
|
13
13
|
teardownTestEnv();
|
|
14
14
|
vi.clearAllMocks();
|
|
15
15
|
});
|
|
16
|
-
it("should return success output from td
|
|
16
|
+
it("should return success output from td", async () => {
|
|
17
17
|
vi.mocked(shell.runCommand).mockResolvedValue({
|
|
18
18
|
stdout: JSON.stringify({ status: "success", feedback: "All checks passed successfully. You may proceed." }),
|
|
19
19
|
stderr: "",
|
|
20
20
|
exitCode: 0,
|
|
21
21
|
durationMs: 0,
|
|
22
|
-
command: "td
|
|
22
|
+
command: "td agent trigger-feedback"
|
|
23
23
|
});
|
|
24
24
|
const result = await triggerJulesFeedbackHandler({ sessionId: "123" });
|
|
25
25
|
expect(result.status).toBe("success");
|
|
26
26
|
expect(result.feedback).toBe("All checks passed successfully. You may proceed.");
|
|
27
|
-
expect(shell.runCommand).toHaveBeenCalledWith("td
|
|
27
|
+
expect(shell.runCommand).toHaveBeenCalledWith("td", [
|
|
28
28
|
"agent", "trigger-feedback", "123"
|
|
29
29
|
]);
|
|
30
30
|
});
|
|
31
|
-
it("should throw error if td
|
|
31
|
+
it("should throw error if td returns error", async () => {
|
|
32
32
|
vi.mocked(shell.runCommand).mockResolvedValue({
|
|
33
33
|
stdout: JSON.stringify({ status: "error", message: "Session not found" }),
|
|
34
34
|
stderr: "",
|
|
35
35
|
exitCode: 0,
|
|
36
36
|
durationMs: 0,
|
|
37
|
-
command: "td
|
|
37
|
+
command: "td agent trigger-feedback"
|
|
38
38
|
});
|
|
39
39
|
await expect(triggerJulesFeedbackHandler({ sessionId: "123" }))
|
|
40
40
|
.rejects.toThrow("Failed to trigger feedback: Session not found");
|
|
@@ -1,21 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { getChangedFiles } from "../lib/git.js";
|
|
3
3
|
export const GetChangedFilesInputSchema = z.object({
|
|
4
4
|
base: z.string().optional().default("main"),
|
|
5
5
|
head: z.string().optional().default("HEAD"),
|
|
6
6
|
});
|
|
7
7
|
export async function getChangedFilesHandler(args) {
|
|
8
|
-
const
|
|
9
|
-
"diff",
|
|
10
|
-
"--name-status",
|
|
11
|
-
`${args.base}...${args.head}`
|
|
12
|
-
]);
|
|
13
|
-
if (result.exitCode !== 0) {
|
|
14
|
-
throw new Error(`Failed to get changed files: ${result.stderr}`);
|
|
15
|
-
}
|
|
16
|
-
const files = result.stdout.trim().split("\n").filter(line => line.length > 0).map(line => {
|
|
17
|
-
const [status, path] = line.split(/\s+/);
|
|
18
|
-
return { status, path };
|
|
19
|
-
});
|
|
8
|
+
const files = await getChangedFiles(args.base || "main", args.head || "HEAD");
|
|
20
9
|
return { files };
|
|
21
10
|
}
|
|
@@ -6,11 +6,11 @@ export const GetCommandSchemaInputSchema = z.object({
|
|
|
6
6
|
export async function getCommandSchemaHandler(args) {
|
|
7
7
|
// Sanitize input to prevent command injection (allow only alphanumeric, spaces, hyphens, and underscores)
|
|
8
8
|
const sanitizedPath = args.commandPath.replace(/[^a-zA-Z0-9-_ ]/g, "");
|
|
9
|
-
const result = await runCommand("td
|
|
9
|
+
const result = await runCommand("td", ["schema", sanitizedPath]);
|
|
10
10
|
if (result.exitCode !== 0) {
|
|
11
11
|
// Log stderr for debugging but don't expose it to the user
|
|
12
12
|
// Using comma-separated arguments to satisfy semgrep unsafe-formatstring
|
|
13
|
-
console.error("td
|
|
13
|
+
console.error("td schema failed for", sanitizedPath, ":", result.stderr);
|
|
14
14
|
throw new Error(`Failed to get command schema for '${sanitizedPath}'`);
|
|
15
15
|
}
|
|
16
16
|
try {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { runCommand } from "../lib/shell.js";
|
|
3
|
+
import { resolveRepo } from "../lib/git.js";
|
|
4
|
+
import { sanitizeError } from "../lib/error_utils.js";
|
|
5
|
+
const GetWorkflowRunsInputSchema = z.object({
|
|
6
|
+
branch: z.string().optional().describe("Filter workflow runs by branch name."),
|
|
7
|
+
event: z.string().optional().describe("Filter workflow runs by event (e.g. push, pull_request)."),
|
|
8
|
+
repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
|
|
9
|
+
});
|
|
10
|
+
export async function getWorkflowRunsHandler(args) {
|
|
11
|
+
const params = GetWorkflowRunsInputSchema.parse(args);
|
|
12
|
+
const targetRepo = resolveRepo(params.repo);
|
|
13
|
+
const cliArgs = ["repo", "workflow-runs", "--repo", targetRepo];
|
|
14
|
+
if (params.branch) {
|
|
15
|
+
cliArgs.push("--branch", params.branch);
|
|
16
|
+
}
|
|
17
|
+
if (params.event) {
|
|
18
|
+
cliArgs.push("--event", params.event);
|
|
19
|
+
}
|
|
20
|
+
const result = await runCommand("td", cliArgs);
|
|
21
|
+
if (result.exitCode !== 0) {
|
|
22
|
+
throw new Error(`Failed to fetch workflow runs: ${sanitizeError(result.stderr)}`);
|
|
23
|
+
}
|
|
24
|
+
const output = JSON.parse(result.stdout);
|
|
25
|
+
if (output.status === "error") {
|
|
26
|
+
throw new Error(`Failed to fetch workflow runs: ${output.message}`);
|
|
27
|
+
}
|
|
28
|
+
return { workflowRuns: output.workflow_runs };
|
|
29
|
+
}
|
package/dist/tools/repo.logs.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { runTDCli } from "
|
|
2
|
+
import { runTDCli } from "./jules/shared.js";
|
|
3
3
|
export const RepoLogsInputSchema = z.object({
|
|
4
4
|
prNumber: z.number(),
|
|
5
5
|
grep: z.string().optional(),
|
|
6
|
+
repo: z.string().optional(),
|
|
6
7
|
});
|
|
7
8
|
export async function repoLogsHandler(args) {
|
|
8
9
|
const params = ["repo", "logs", args.prNumber.toString()];
|
|
9
10
|
if (args.grep) {
|
|
10
11
|
params.push("--grep", args.grep);
|
|
11
12
|
}
|
|
13
|
+
if (args.repo) {
|
|
14
|
+
params.push("--repo", args.repo);
|
|
15
|
+
}
|
|
12
16
|
const output = await runTDCli(params);
|
|
13
17
|
return {
|
|
14
18
|
logs: output.logs || (output.data ? output.data.logs : undefined)
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { config } from "../config.js";
|
|
3
|
-
import {
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
export const loadStandaloneAgentContext = (repoRoot = process.cwd()) => {
|
|
7
|
+
const configPath = path.join(repoRoot, "project_config.json");
|
|
8
|
+
let projectConfig = {};
|
|
9
|
+
if (fs.existsSync(configPath)) {
|
|
10
|
+
try {
|
|
11
|
+
projectConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
console.warn(`[MCP Warning] Failed to parse ${configPath}:`, e);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
let gitCommit = "unknown";
|
|
18
|
+
try {
|
|
19
|
+
gitCommit = execSync("git rev-parse HEAD", { cwd: repoRoot, encoding: "utf-8" }).trim();
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Fallback if git is unavailable
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
packageName: projectConfig.packageName ?? "boomtick",
|
|
26
|
+
gitCommit,
|
|
27
|
+
config: projectConfig,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
4
30
|
export const ReadAgentContextInputSchema = z.object({});
|
|
5
31
|
export async function readAgentContextHandler(_args) {
|
|
6
32
|
const context = loadStandaloneAgentContext(config.repoPath);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { loadStandaloneAgentContext } from "
|
|
2
|
+
import { loadStandaloneAgentContext } from "./repo.read_agent_context.js";
|
|
3
3
|
describe("Standalone Agent Context Loader", () => {
|
|
4
4
|
it("should load agent context without submodule references", () => {
|
|
5
5
|
const context = loadStandaloneAgentContext(process.cwd());
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { runTDCli } from "
|
|
2
|
+
import { runTDCli } from "./jules/shared.js";
|
|
3
3
|
export const ReadCiLogsInputSchema = z.object({
|
|
4
4
|
prNumber: z.number(),
|
|
5
5
|
all: z.boolean().optional(),
|
|
6
|
+
repo: z.string().optional(),
|
|
6
7
|
});
|
|
7
8
|
export async function readCiLogsHandler(args) {
|
|
8
9
|
const params = ["repo", "ci-logs", args.prNumber.toString()];
|
|
9
10
|
if (args.all) {
|
|
10
11
|
params.push("--all");
|
|
11
12
|
}
|
|
13
|
+
if (args.repo) {
|
|
14
|
+
params.push("--repo", args.repo);
|
|
15
|
+
}
|
|
12
16
|
const output = await runTDCli(params);
|
|
13
17
|
return {
|
|
14
18
|
checks: output.checks,
|
|
@@ -5,7 +5,7 @@ export const RunTestsInputSchema = z.object({
|
|
|
5
5
|
timeoutSeconds: z.number().optional().default(300),
|
|
6
6
|
worktreePath: z.string().optional(),
|
|
7
7
|
});
|
|
8
|
-
|
|
8
|
+
function parseCommandArguments(fullCmd) {
|
|
9
9
|
const tokens = [];
|
|
10
10
|
const regex = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|(\S+)/g;
|
|
11
11
|
let match;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arii/boomtick-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Boomtick MCP Guide: PR Rescue + Merge Conflict Agent",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@modelcontextprotocol/sdk": "^1.6.0",
|
|
20
|
-
"dotenv": "^17.4.2",
|
|
21
20
|
"zod": "^4.4.3"
|
|
22
21
|
},
|
|
23
22
|
"engines": {
|
|
@@ -27,14 +26,12 @@
|
|
|
27
26
|
"devDependencies": {
|
|
28
27
|
"@types/node": "^20.17.15",
|
|
29
28
|
"json-schema-to-zod": "^2.8.1",
|
|
30
|
-
"shx": "^0.4.0",
|
|
31
29
|
"tsx": "^4.22.4",
|
|
32
30
|
"typescript": "^5.7.3",
|
|
33
|
-
"vitest": "^4.1.9"
|
|
34
|
-
"yaml": "^2.9.0"
|
|
31
|
+
"vitest": "^4.1.9"
|
|
35
32
|
},
|
|
36
33
|
"scripts": {
|
|
37
|
-
"build": "tsx scripts/sync-contracts.ts && tsc &&
|
|
34
|
+
"build": "tsx scripts/sync-contracts.ts && tsc && tsx scripts/sync-mcp-schemas.ts",
|
|
38
35
|
"watch": "tsc -w",
|
|
39
36
|
"start": "node dist/index.js",
|
|
40
37
|
"test": "tsx scripts/sync-contracts.ts && tsx scripts/sync-mcp-schemas.ts && vitest run",
|
|
@@ -19,6 +19,7 @@ function isWritable(dir: string): boolean {
|
|
|
19
19
|
interface ToolDefinition {
|
|
20
20
|
name: string;
|
|
21
21
|
inputSchema: Record<string, unknown>;
|
|
22
|
+
outputSchema?: Record<string, unknown>;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
@@ -73,6 +74,7 @@ async function syncSchemas() {
|
|
|
73
74
|
name: tool.name,
|
|
74
75
|
description: tool.description,
|
|
75
76
|
parameters: tool.inputSchema,
|
|
77
|
+
outputSchema: tool.outputSchema,
|
|
76
78
|
};
|
|
77
79
|
const schemaContent = JSON.stringify(exportedSchema, null, 2);
|
|
78
80
|
const fileName = `${tool.name}.json`;
|
package/src/config.test.ts
CHANGED
|
@@ -20,14 +20,14 @@ describe("config", () => {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
describe("initializeConfig", () => {
|
|
23
|
-
it("should load dynamic config from td
|
|
23
|
+
it("should load dynamic config from td config view using active cwd", async () => {
|
|
24
24
|
const mockConfig = { github_repo: "owner/repo", base_branch: "origin/main", vite_base_path: "/app/" };
|
|
25
25
|
vi.mocked(execSync).mockReturnValue(JSON.stringify(mockConfig));
|
|
26
26
|
|
|
27
27
|
const { initializeConfig } = await import("./config.js");
|
|
28
28
|
const result = initializeConfig();
|
|
29
29
|
|
|
30
|
-
expect(execSync).toHaveBeenCalledWith("td
|
|
30
|
+
expect(execSync).toHaveBeenCalledWith("td config view", expect.objectContaining({
|
|
31
31
|
cwd: process.cwd()
|
|
32
32
|
}));
|
|
33
33
|
expect(result).toEqual(mockConfig);
|
|
@@ -119,7 +119,7 @@ describe("config", () => {
|
|
|
119
119
|
delete process.env.GITHUB_REPOSITORY;
|
|
120
120
|
delete process.env.GH_REPO;
|
|
121
121
|
vi.mocked(execSync).mockImplementation(() => {
|
|
122
|
-
throw new Error("td
|
|
122
|
+
throw new Error("td failed");
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
process.env.NODE_ENV = "production";
|
package/src/config.ts
CHANGED
|
@@ -41,7 +41,7 @@ export function initializeConfig() {
|
|
|
41
41
|
try {
|
|
42
42
|
// Attempt to load core properties from the Python CLI in the active workspace
|
|
43
43
|
const cwd = process.env.BOOMTICK_REPO_PATH || process.cwd();
|
|
44
|
-
const cmd = `td
|
|
44
|
+
const cmd = `td config view`;
|
|
45
45
|
const output = execSync(cmd, {
|
|
46
46
|
cwd,
|
|
47
47
|
encoding: "utf-8",
|