@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.
- package/.mcp/schemas/agent.search_ddgs.json +28 -24
- package/.mcp/schemas/agent_search_ddgs.json +31 -0
- package/.mcp/schemas/boomtick.health.json +14 -10
- package/.mcp/schemas/boomtick_health.json +16 -0
- package/.mcp/schemas/github.checkout_branch.json +28 -24
- package/.mcp/schemas/github.comment_triage_summary.json +21 -17
- package/.mcp/schemas/github.create_issue.json +55 -50
- package/.mcp/schemas/github.create_pull_request.json +53 -48
- package/.mcp/schemas/github.get_merge_conflict_files.json +21 -17
- package/.mcp/schemas/github.get_pr.json +30 -12
- package/.mcp/schemas/github.get_pr_diff.json +30 -12
- package/.mcp/schemas/github.issue_comment.json +35 -17
- package/.mcp/schemas/github.issue_update.json +114 -96
- package/.mcp/schemas/github.issue_view.json +30 -12
- package/.mcp/schemas/github.open_replacement_pr.json +64 -60
- package/.mcp/schemas/github.search_open_prs.json +61 -43
- package/.mcp/schemas/github_checkout_branch.json +31 -0
- package/.mcp/schemas/github_comment_triage_summary.json +24 -0
- package/.mcp/schemas/github_create_issue.json +58 -0
- package/.mcp/schemas/github_create_pull_request.json +56 -0
- package/.mcp/schemas/github_get_merge_conflict_files.json +24 -0
- package/.mcp/schemas/github_get_pr.json +32 -0
- package/.mcp/schemas/github_get_pr_diff.json +32 -0
- package/.mcp/schemas/github_issue_comment.json +38 -0
- package/.mcp/schemas/github_issue_update.json +123 -0
- package/.mcp/schemas/github_issue_view.json +32 -0
- package/.mcp/schemas/github_open_replacement_pr.json +67 -0
- package/.mcp/schemas/github_search_open_prs.json +65 -0
- package/.mcp/schemas/jules.cancel_session.json +16 -12
- package/.mcp/schemas/jules.create_session.json +41 -37
- package/.mcp/schemas/jules.get_messages.json +16 -12
- package/.mcp/schemas/jules.get_pr.json +16 -12
- package/.mcp/schemas/jules.get_session.json +16 -12
- package/.mcp/schemas/jules.list_sessions.json +33 -29
- package/.mcp/schemas/jules.send_message.json +30 -26
- package/.mcp/schemas/jules.trigger_feedback.json +16 -12
- package/.mcp/schemas/jules_cancel_session.json +18 -0
- package/.mcp/schemas/jules_create_session.json +44 -0
- package/.mcp/schemas/jules_get_messages.json +18 -0
- package/.mcp/schemas/jules_get_pr.json +18 -0
- package/.mcp/schemas/jules_get_session.json +18 -0
- package/.mcp/schemas/jules_list_sessions.json +36 -0
- package/.mcp/schemas/jules_send_message.json +35 -0
- package/.mcp/schemas/jules_trigger_feedback.json +18 -0
- package/.mcp/schemas/repo.commit_patch.json +34 -30
- package/.mcp/schemas/repo.create_branch.json +21 -17
- package/.mcp/schemas/repo.create_repair_branch.json +34 -30
- package/.mcp/schemas/repo.get_changed_files.json +19 -15
- package/.mcp/schemas/repo.get_command_schema.json +16 -12
- package/.mcp/schemas/repo.get_package_scripts.json +21 -17
- package/.mcp/schemas/repo.get_route_map.json +21 -17
- package/.mcp/schemas/repo.logs.json +28 -24
- package/.mcp/schemas/repo.read_agent_context.json +7 -3
- package/.mcp/schemas/repo.read_ci_logs.json +21 -17
- package/.mcp/schemas/repo.run_lighthouse.json +26 -22
- package/.mcp/schemas/repo.run_playwright.json +33 -29
- package/.mcp/schemas/repo.run_tests.json +40 -36
- package/.mcp/schemas/repo_commit_patch.json +39 -0
- package/.mcp/schemas/repo_create_branch.json +24 -0
- package/.mcp/schemas/repo_create_repair_branch.json +37 -0
- package/.mcp/schemas/repo_get_changed_files.json +22 -0
- package/.mcp/schemas/repo_get_command_schema.json +18 -0
- package/.mcp/schemas/repo_get_package_scripts.json +23 -0
- package/.mcp/schemas/repo_get_route_map.json +23 -0
- package/.mcp/schemas/repo_logs.json +31 -0
- package/.mcp/schemas/repo_read_agent_context.json +9 -0
- package/.mcp/schemas/repo_read_ci_logs.json +24 -0
- package/.mcp/schemas/repo_run_lighthouse.json +29 -0
- package/.mcp/schemas/repo_run_playwright.json +36 -0
- package/.mcp/schemas/repo_run_tests.json +45 -0
- package/CHANGELOG.md +9 -0
- package/dist/lib/git.js +30 -0
- package/dist/lib/param_utils.js +35 -0
- package/dist/lib/param_utils.test.js +44 -0
- package/dist/mcp/definitions.js +11 -1
- package/dist/mcp/schemas.test.js +28 -0
- package/dist/mcp/server.js +72 -36
- package/dist/tools/contract.js +94 -8
- package/dist/tools/github.create_issue.js +3 -2
- package/dist/tools/github.create_issue.test.js +10 -0
- package/dist/tools/github.create_pull_request.js +4 -4
- package/dist/tools/github.get_pr.js +4 -1
- package/dist/tools/github.get_pr_diff.js +6 -2
- package/dist/tools/github.issue_comment.js +8 -1
- package/dist/tools/github.issue_update.js +3 -0
- package/dist/tools/github.issue_view.js +4 -1
- package/dist/tools/github.search_open_prs.js +4 -0
- package/dist/tools/repo.commit_patch.js +30 -10
- package/dist/tools/repo.run_playwright.js +10 -5
- package/dist/tools/repo.run_tests.js +26 -4
- package/package.json +2 -2
- package/scripts/sync-mcp-schemas.ts +6 -1
- package/src/lib/git.ts +34 -0
- package/src/lib/param_utils.test.ts +49 -0
- package/src/lib/param_utils.ts +42 -0
- package/src/mcp/definitions.ts +12 -1
- package/src/mcp/schemas.test.ts +34 -0
- package/src/mcp/server.ts +73 -38
- package/src/tools/contract.ts +94 -8
- package/src/tools/github.create_issue.test.ts +10 -0
- package/src/tools/github.create_issue.ts +3 -1
- package/src/tools/github.create_pull_request.ts +4 -5
- package/src/tools/github.get_pr.ts +4 -1
- package/src/tools/github.get_pr_diff.ts +7 -2
- package/src/tools/github.issue_comment.ts +8 -1
- package/src/tools/github.issue_update.ts +4 -1
- package/src/tools/github.issue_view.ts +4 -1
- package/src/tools/github.search_open_prs.ts +4 -0
- package/src/tools/repo.commit_patch.ts +35 -11
- package/src/tools/repo.run_playwright.ts +13 -6
- package/src/tools/repo.run_tests.ts +28 -5
|
@@ -1,10 +1,12 @@
|
|
|
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 IssueCommentInputSchema = z.object({
|
|
6
7
|
issueNumber: z.number().describe("The number of the issue to comment on."),
|
|
7
8
|
body: z.string().min(1, "Comment body cannot be empty").describe("The content of the comment."),
|
|
9
|
+
repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
|
|
8
10
|
});
|
|
9
11
|
|
|
10
12
|
const IssueCommentOutputSchema = z.object({
|
|
@@ -15,8 +17,13 @@ const IssueCommentOutputSchema = z.object({
|
|
|
15
17
|
|
|
16
18
|
export async function issueCommentHandler(args: z.infer<typeof IssueCommentInputSchema>) {
|
|
17
19
|
const params = IssueCommentInputSchema.parse(args);
|
|
20
|
+
const targetRepo = resolveRepo(params.repo);
|
|
18
21
|
|
|
19
|
-
const result = await runCommand("td-cli", [
|
|
22
|
+
const result = await runCommand("td-cli", [
|
|
23
|
+
"gh", "issue-comment", params.issueNumber.toString(),
|
|
24
|
+
"--body", params.body,
|
|
25
|
+
"--repo", targetRepo
|
|
26
|
+
]);
|
|
20
27
|
|
|
21
28
|
if (result.exitCode !== 0) {
|
|
22
29
|
throw new Error(`Failed to post comment: ${sanitizeError(result.stderr)}`);
|
|
@@ -1,12 +1,14 @@
|
|
|
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 { IssueUpdateInputSchema, IssueUpdateResponseSchema } from "./contract.js";
|
|
5
6
|
|
|
6
7
|
export { IssueUpdateInputSchema };
|
|
7
8
|
|
|
8
|
-
export async function issueUpdateHandler(args:
|
|
9
|
+
export async function issueUpdateHandler(args: z.infer<typeof IssueUpdateInputSchema>) {
|
|
9
10
|
const params = IssueUpdateInputSchema.parse(args);
|
|
11
|
+
const targetRepo = resolveRepo(params.repo);
|
|
10
12
|
|
|
11
13
|
const cmdArgs = ["gh", "issue-update", params.issueNumber.toString()];
|
|
12
14
|
if (params.body) cmdArgs.push("--body", params.body);
|
|
@@ -15,6 +17,7 @@ export async function issueUpdateHandler(args: any) {
|
|
|
15
17
|
if (params.addLabels && params.addLabels.length > 0) cmdArgs.push("--add-labels", params.addLabels.join(","));
|
|
16
18
|
if (params.removeLabels && params.removeLabels.length > 0) cmdArgs.push("--remove-labels", params.removeLabels.join(","));
|
|
17
19
|
if (params.state) cmdArgs.push("--state", params.state);
|
|
20
|
+
cmdArgs.push("--repo", targetRepo);
|
|
18
21
|
|
|
19
22
|
const result = await runCommand("td-cli", cmdArgs);
|
|
20
23
|
|
|
@@ -1,9 +1,11 @@
|
|
|
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 IssueViewInputSchema = z.object({
|
|
6
7
|
issueNumber: z.number().describe("The number of the issue to view."),
|
|
8
|
+
repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
|
|
7
9
|
});
|
|
8
10
|
|
|
9
11
|
const IssueViewOutputSchema = z.object({
|
|
@@ -19,8 +21,9 @@ const IssueViewOutputSchema = z.object({
|
|
|
19
21
|
|
|
20
22
|
export async function issueViewHandler(args: z.infer<typeof IssueViewInputSchema>) {
|
|
21
23
|
const params = IssueViewInputSchema.parse(args);
|
|
24
|
+
const targetRepo = resolveRepo(params.repo);
|
|
22
25
|
|
|
23
|
-
const result = await runCommand("td-cli", ["gh", "issue-view", params.issueNumber.toString()]);
|
|
26
|
+
const result = await runCommand("td-cli", ["gh", "issue-view", params.issueNumber.toString(), "--repo", targetRepo]);
|
|
24
27
|
|
|
25
28
|
if (result.exitCode !== 0) {
|
|
26
29
|
throw new Error(`Failed to view issue: ${sanitizeError(result.stderr)}`);
|
|
@@ -1,20 +1,24 @@
|
|
|
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 SearchOpenPrsInputSchema = z.object({
|
|
5
6
|
state: z.enum(["open", "closed", "all"]).optional().default("open"),
|
|
6
7
|
includeDrafts: z.boolean().optional().default(true),
|
|
7
8
|
limit: z.number().min(1).max(100).optional().default(100),
|
|
8
9
|
labels: z.array(z.string()).optional(),
|
|
10
|
+
repo: z.string().optional().describe("The target repository override (e.g. org/repo)."),
|
|
9
11
|
});
|
|
10
12
|
|
|
11
13
|
export async function searchOpenPrsHandler(args: z.infer<typeof SearchOpenPrsInputSchema>) {
|
|
12
14
|
const params = SearchOpenPrsInputSchema.parse(args);
|
|
15
|
+
const targetRepo = resolveRepo(params.repo);
|
|
13
16
|
|
|
14
17
|
const tdArgs = [
|
|
15
18
|
"gh", "search-prs",
|
|
16
19
|
"--state", params.state,
|
|
17
20
|
"--limit", params.limit.toString(),
|
|
21
|
+
"--repo", targetRepo,
|
|
18
22
|
];
|
|
19
23
|
|
|
20
24
|
if (!params.includeDrafts) {
|
|
@@ -1,21 +1,45 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { runCommand } from "../lib/shell.js";
|
|
3
|
+
import { config } from "../config.js";
|
|
3
4
|
|
|
4
5
|
export const CommitPatchInputSchema = z.object({
|
|
5
|
-
worktreePath: z.string(),
|
|
6
|
+
worktreePath: z.string().optional(),
|
|
6
7
|
message: z.string(),
|
|
7
8
|
allowedFiles: z.array(z.string()),
|
|
8
|
-
writeMode: z.boolean().optional().default(
|
|
9
|
+
writeMode: z.boolean().optional().default(true),
|
|
9
10
|
});
|
|
10
11
|
|
|
11
|
-
export
|
|
12
|
-
|
|
12
|
+
export type CommitPatchInput = z.input<typeof CommitPatchInputSchema>;
|
|
13
|
+
|
|
14
|
+
export async function commitPatchHandler(args: CommitPatchInput) {
|
|
15
|
+
const parsed = CommitPatchInputSchema.parse(args || {});
|
|
16
|
+
const worktreePath = parsed.worktreePath || config.repoPath;
|
|
17
|
+
|
|
18
|
+
if (parsed.writeMode === false) {
|
|
13
19
|
throw new Error("writeMode must be true to commit changes.");
|
|
14
20
|
}
|
|
15
|
-
const statusResult = await runCommand("git", ["status", "--porcelain"], { cwd: args.worktreePath });
|
|
16
|
-
const changedFiles = statusResult.stdout.trim().split("\n").filter(l => l.length > 0).map(l => l.substring(3));
|
|
17
21
|
|
|
18
|
-
const
|
|
22
|
+
const statusResult = await runCommand("git", ["status", "--porcelain"], { cwd: worktreePath });
|
|
23
|
+
|
|
24
|
+
const changedFiles = statusResult.stdout
|
|
25
|
+
.split("\n")
|
|
26
|
+
.map((l) => (l.endsWith("\r") ? l.slice(0, -1) : l))
|
|
27
|
+
.filter((l) => l.trim().length > 0)
|
|
28
|
+
.map((l) => {
|
|
29
|
+
const match = l.match(/^..\s+(.*)$/);
|
|
30
|
+
if (!match) return l.slice(3).trim();
|
|
31
|
+
let file = match[1].trim();
|
|
32
|
+
if (file.includes(" -> ")) {
|
|
33
|
+
file = file.split(" -> ").pop()!.trim();
|
|
34
|
+
}
|
|
35
|
+
if (file.startsWith('"') && file.endsWith('"')) {
|
|
36
|
+
file = file.slice(1, -1);
|
|
37
|
+
}
|
|
38
|
+
return file;
|
|
39
|
+
})
|
|
40
|
+
.filter(Boolean);
|
|
41
|
+
|
|
42
|
+
const forbiddenFiles = changedFiles.filter((f) => !parsed.allowedFiles.includes(f));
|
|
19
43
|
if (forbiddenFiles.length > 0) {
|
|
20
44
|
throw new Error(`The following files are not in the allowed list: ${forbiddenFiles.join(", ")}`);
|
|
21
45
|
}
|
|
@@ -24,18 +48,18 @@ export async function commitPatchHandler(args: z.infer<typeof CommitPatchInputSc
|
|
|
24
48
|
throw new Error("No changes to commit.");
|
|
25
49
|
}
|
|
26
50
|
|
|
27
|
-
await runCommand("git", ["add", "
|
|
28
|
-
const commitResult = await runCommand("git", ["commit", "-m",
|
|
51
|
+
await runCommand("git", ["add", "--", ...changedFiles], { cwd: worktreePath });
|
|
52
|
+
const commitResult = await runCommand("git", ["commit", "-m", parsed.message], { cwd: worktreePath });
|
|
29
53
|
|
|
30
54
|
if (commitResult.exitCode !== 0) {
|
|
31
55
|
throw new Error(`Failed to commit: ${commitResult.stderr}`);
|
|
32
56
|
}
|
|
33
57
|
|
|
34
|
-
const shaResult = await runCommand("git", ["rev-parse", "HEAD"], { cwd:
|
|
58
|
+
const shaResult = await runCommand("git", ["rev-parse", "HEAD"], { cwd: worktreePath });
|
|
35
59
|
|
|
36
60
|
return {
|
|
37
61
|
success: true,
|
|
38
62
|
commitSha: shaResult.stdout.trim(),
|
|
39
|
-
changedFiles
|
|
63
|
+
changedFiles,
|
|
40
64
|
};
|
|
41
65
|
}
|
|
@@ -4,18 +4,25 @@ import { runCommand } from "../lib/shell.js";
|
|
|
4
4
|
export const RunPlaywrightInputSchema = z.object({
|
|
5
5
|
grep: z.string().optional(),
|
|
6
6
|
worktreePath: z.string().optional(),
|
|
7
|
+
timeoutSeconds: z.number().optional().default(180),
|
|
7
8
|
});
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
+
export type RunPlaywrightInput = z.input<typeof RunPlaywrightInputSchema>;
|
|
11
|
+
|
|
12
|
+
export async function runPlaywrightHandler(args: RunPlaywrightInput) {
|
|
13
|
+
const parsed = RunPlaywrightInputSchema.parse(args || {});
|
|
10
14
|
const tdArgs = ["repo", "run-playwright"];
|
|
11
|
-
if (
|
|
12
|
-
tdArgs.push("--grep",
|
|
15
|
+
if (parsed.grep) {
|
|
16
|
+
tdArgs.push("--grep", parsed.grep);
|
|
13
17
|
}
|
|
14
|
-
if (
|
|
15
|
-
tdArgs.push("--worktree",
|
|
18
|
+
if (parsed.worktreePath) {
|
|
19
|
+
tdArgs.push("--worktree", parsed.worktreePath);
|
|
16
20
|
}
|
|
17
21
|
|
|
18
|
-
const result = await runCommand("td-cli", tdArgs
|
|
22
|
+
const result = await runCommand("td-cli", tdArgs, {
|
|
23
|
+
cwd: parsed.worktreePath,
|
|
24
|
+
timeout: parsed.timeoutSeconds * 1000,
|
|
25
|
+
});
|
|
19
26
|
|
|
20
27
|
if (result.exitCode !== 0) {
|
|
21
28
|
// Playwright might exit with non-zero if tests fail, but our td-cli should ideally handle it
|
|
@@ -7,8 +7,31 @@ export const RunTestsInputSchema = z.object({
|
|
|
7
7
|
worktreePath: z.string().optional(),
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
10
|
+
export type RunTestsInput = z.input<typeof RunTestsInputSchema>;
|
|
11
|
+
|
|
12
|
+
export function parseCommandArguments(fullCmd: string): [string, string[]] {
|
|
13
|
+
const tokens: string[] = [];
|
|
14
|
+
const regex = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|(\S+)/g;
|
|
15
|
+
let match: RegExpExecArray | null;
|
|
16
|
+
while ((match = regex.exec(fullCmd)) !== null) {
|
|
17
|
+
if (match[1] !== undefined) {
|
|
18
|
+
tokens.push(match[1].replace(/\\"/g, '"'));
|
|
19
|
+
} else if (match[2] !== undefined) {
|
|
20
|
+
tokens.push(match[2].replace(/\\'/g, "'"));
|
|
21
|
+
} else {
|
|
22
|
+
tokens.push(match[3]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (tokens.length === 0) {
|
|
26
|
+
return ["", []];
|
|
27
|
+
}
|
|
28
|
+
const [cmd, ...args] = tokens;
|
|
29
|
+
return [cmd, args];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function runTestsHandler(args: RunTestsInput) {
|
|
33
|
+
const parsed = RunTestsInputSchema.parse(args || {});
|
|
34
|
+
const commands = parsed.commands || [
|
|
12
35
|
"pnpm install --frozen-lockfile",
|
|
13
36
|
"pnpm lint",
|
|
14
37
|
"pnpm test",
|
|
@@ -19,11 +42,11 @@ export async function runTestsHandler(args: z.infer<typeof RunTestsInputSchema>)
|
|
|
19
42
|
let success = true;
|
|
20
43
|
|
|
21
44
|
for (const fullCmd of commands) {
|
|
22
|
-
const [cmd,
|
|
45
|
+
const [cmd, cmdArgs] = parseCommandArguments(fullCmd);
|
|
23
46
|
try {
|
|
24
47
|
const res = await runCommand(cmd, cmdArgs, {
|
|
25
|
-
cwd:
|
|
26
|
-
timeout:
|
|
48
|
+
cwd: parsed.worktreePath,
|
|
49
|
+
timeout: parsed.timeoutSeconds * 1000
|
|
27
50
|
});
|
|
28
51
|
results.push(res);
|
|
29
52
|
if (res.exitCode !== 0) {
|