@paretools/github 0.8.5 → 0.10.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/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/formatters.d.ts +10 -2
- package/dist/lib/formatters.d.ts.map +1 -1
- package/dist/lib/formatters.js +144 -16
- package/dist/lib/formatters.js.map +1 -1
- package/dist/lib/gh-runner.d.ts.map +1 -1
- package/dist/lib/gh-runner.js +2 -1
- package/dist/lib/gh-runner.js.map +1 -1
- package/dist/lib/parsers.d.ts +54 -18
- package/dist/lib/parsers.d.ts.map +1 -1
- package/dist/lib/parsers.js +426 -38
- package/dist/lib/parsers.js.map +1 -1
- package/dist/lib/path-validation.d.ts +13 -0
- package/dist/lib/path-validation.d.ts.map +1 -0
- package/dist/lib/path-validation.js +54 -0
- package/dist/lib/path-validation.js.map +1 -0
- package/dist/schemas/index.d.ts +267 -4
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +195 -4
- package/dist/schemas/index.js.map +1 -1
- package/dist/tools/api.d.ts.map +1 -1
- package/dist/tools/api.js +134 -8
- package/dist/tools/api.js.map +1 -1
- package/dist/tools/gist-create.d.ts.map +1 -1
- package/dist/tools/gist-create.js +91 -21
- package/dist/tools/gist-create.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/issue-close.d.ts.map +1 -1
- package/dist/tools/issue-close.js +56 -9
- package/dist/tools/issue-close.js.map +1 -1
- package/dist/tools/issue-comment.d.ts.map +1 -1
- package/dist/tools/issue-comment.js +60 -9
- package/dist/tools/issue-comment.js.map +1 -1
- package/dist/tools/issue-create.d.ts.map +1 -1
- package/dist/tools/issue-create.js +95 -9
- package/dist/tools/issue-create.js.map +1 -1
- package/dist/tools/issue-list.d.ts.map +1 -1
- package/dist/tools/issue-list.js +139 -11
- package/dist/tools/issue-list.js.map +1 -1
- package/dist/tools/issue-update.d.ts.map +1 -1
- package/dist/tools/issue-update.js +142 -15
- package/dist/tools/issue-update.js.map +1 -1
- package/dist/tools/issue-view.d.ts.map +1 -1
- package/dist/tools/issue-view.js +26 -14
- package/dist/tools/issue-view.js.map +1 -1
- package/dist/tools/label-create.d.ts +4 -0
- package/dist/tools/label-create.d.ts.map +1 -0
- package/dist/tools/label-create.js +73 -0
- package/dist/tools/label-create.js.map +1 -0
- package/dist/tools/label-list.d.ts +4 -0
- package/dist/tools/label-list.d.ts.map +1 -0
- package/dist/tools/label-list.js +71 -0
- package/dist/tools/label-list.js.map +1 -0
- package/dist/tools/pr-checks.d.ts.map +1 -1
- package/dist/tools/pr-checks.js +57 -11
- package/dist/tools/pr-checks.js.map +1 -1
- package/dist/tools/pr-comment.d.ts.map +1 -1
- package/dist/tools/pr-comment.js +60 -9
- package/dist/tools/pr-comment.js.map +1 -1
- package/dist/tools/pr-create.d.ts.map +1 -1
- package/dist/tools/pr-create.js +154 -9
- package/dist/tools/pr-create.js.map +1 -1
- package/dist/tools/pr-diff.d.ts.map +1 -1
- package/dist/tools/pr-diff.js +63 -16
- package/dist/tools/pr-diff.js.map +1 -1
- package/dist/tools/pr-list.d.ts.map +1 -1
- package/dist/tools/pr-list.js +115 -11
- package/dist/tools/pr-list.js.map +1 -1
- package/dist/tools/pr-merge.d.ts.map +1 -1
- package/dist/tools/pr-merge.js +104 -15
- package/dist/tools/pr-merge.js.map +1 -1
- package/dist/tools/pr-review.d.ts.map +1 -1
- package/dist/tools/pr-review.js +41 -8
- package/dist/tools/pr-review.js.map +1 -1
- package/dist/tools/pr-update.d.ts.map +1 -1
- package/dist/tools/pr-update.js +157 -10
- package/dist/tools/pr-update.js.map +1 -1
- package/dist/tools/pr-view.d.ts.map +1 -1
- package/dist/tools/pr-view.js +27 -14
- package/dist/tools/pr-view.js.map +1 -1
- package/dist/tools/release-create.d.ts.map +1 -1
- package/dist/tools/release-create.js +106 -9
- package/dist/tools/release-create.js.map +1 -1
- package/dist/tools/release-list.d.ts.map +1 -1
- package/dist/tools/release-list.js +39 -13
- package/dist/tools/release-list.js.map +1 -1
- package/dist/tools/run-list.d.ts.map +1 -1
- package/dist/tools/run-list.js +111 -12
- package/dist/tools/run-list.js.map +1 -1
- package/dist/tools/run-rerun.d.ts.map +1 -1
- package/dist/tools/run-rerun.js +38 -8
- package/dist/tools/run-rerun.js.map +1 -1
- package/dist/tools/run-view.d.ts.map +1 -1
- package/dist/tools/run-view.js +64 -13
- package/dist/tools/run-view.js.map +1 -1
- package/package.json +2 -2
package/dist/tools/pr-diff.js
CHANGED
|
@@ -4,13 +4,18 @@ import { assertNoFlagInjection } from "@paretools/shared";
|
|
|
4
4
|
import { ghCmd } from "../lib/gh-runner.js";
|
|
5
5
|
import { formatPrDiff, compactPrDiffMap, formatPrDiffCompact } from "../lib/formatters.js";
|
|
6
6
|
import { PrDiffResultSchema } from "../schemas/index.js";
|
|
7
|
+
/** Maximum diff output size before marking as truncated (256 KB). */
|
|
8
|
+
const MAX_DIFF_SIZE = 256 * 1024;
|
|
7
9
|
/** Registers the `pr-diff` tool on the given MCP server. */
|
|
8
10
|
export function registerPrDiffTool(server) {
|
|
9
11
|
server.registerTool("pr-diff", {
|
|
10
12
|
title: "PR Diff",
|
|
11
|
-
description: "Returns file-level diff statistics for a pull request. Use full=true for patch content.
|
|
13
|
+
description: "Returns file-level diff statistics for a pull request. Use full=true for patch content.",
|
|
12
14
|
inputSchema: {
|
|
13
|
-
|
|
15
|
+
number: z
|
|
16
|
+
.string()
|
|
17
|
+
.max(INPUT_LIMITS.STRING_MAX)
|
|
18
|
+
.describe("Pull request number, URL, or branch name"),
|
|
14
19
|
repo: z
|
|
15
20
|
.string()
|
|
16
21
|
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
@@ -21,31 +26,40 @@ export function registerPrDiffTool(server) {
|
|
|
21
26
|
.optional()
|
|
22
27
|
.default(false)
|
|
23
28
|
.describe("Include full patch content in chunks"),
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
.optional()
|
|
27
|
-
.default(true)
|
|
28
|
-
.describe("Auto-compact when structured output exceeds raw CLI tokens. Set false to always get full schema."),
|
|
29
|
+
nameOnly: z.boolean().optional().describe("List only changed file names (--name-only)"),
|
|
30
|
+
compact: z.boolean().optional().default(true).describe("Prefer compact output"),
|
|
29
31
|
},
|
|
30
32
|
outputSchema: PrDiffResultSchema,
|
|
31
|
-
}, async ({
|
|
33
|
+
}, async ({ number, repo, full, nameOnly, compact }) => {
|
|
32
34
|
if (repo) {
|
|
33
35
|
assertNoFlagInjection(repo, "repo");
|
|
34
36
|
}
|
|
37
|
+
if (typeof number === "string") {
|
|
38
|
+
assertNoFlagInjection(number, "number");
|
|
39
|
+
}
|
|
40
|
+
const selector = String(number);
|
|
35
41
|
// Get numstat for structured file-level stats
|
|
36
|
-
const numstatArgs = ["pr", "diff",
|
|
42
|
+
const numstatArgs = ["pr", "diff", selector, "--patch=false"];
|
|
37
43
|
if (repo)
|
|
38
44
|
numstatArgs.push("--repo", repo);
|
|
39
45
|
// We use a two-pass approach: first get numstat, then optionally get full patch
|
|
40
|
-
const diffArgs = ["pr", "diff",
|
|
46
|
+
const diffArgs = ["pr", "diff", selector];
|
|
41
47
|
if (repo)
|
|
42
48
|
diffArgs.push("--repo", repo);
|
|
49
|
+
if (nameOnly)
|
|
50
|
+
diffArgs.push("--name-only");
|
|
43
51
|
const result = await ghCmd(diffArgs, { cwd: process.cwd() });
|
|
44
52
|
if (result.exitCode !== 0) {
|
|
45
53
|
throw new Error(`gh pr diff failed: ${result.stderr}`);
|
|
46
54
|
}
|
|
55
|
+
// S-gap: Detect truncation
|
|
56
|
+
const truncated = result.stdout.length >= MAX_DIFF_SIZE;
|
|
47
57
|
// Parse the unified diff output to extract numstat-like data
|
|
48
58
|
const diff = parsePrDiffFromPatch(result.stdout);
|
|
59
|
+
// S-gap: Set truncation flag
|
|
60
|
+
if (truncated) {
|
|
61
|
+
diff.truncated = true;
|
|
62
|
+
}
|
|
49
63
|
// If full patch requested, attach chunk data
|
|
50
64
|
if (full && diff.files.length > 0) {
|
|
51
65
|
const filePatches = result.stdout.split(/^diff --git /m).filter(Boolean);
|
|
@@ -54,6 +68,11 @@ export function registerPrDiffTool(server) {
|
|
|
54
68
|
if (fileMatch) {
|
|
55
69
|
const matchedFile = diff.files.find((f) => f.file === fileMatch[1]);
|
|
56
70
|
if (matchedFile) {
|
|
71
|
+
// S-gap: Extract file mode if present
|
|
72
|
+
const modeMatch = patch.match(/(?:new|old|index|diff) (?:file )?mode (\d+)/);
|
|
73
|
+
if (modeMatch) {
|
|
74
|
+
matchedFile.mode = modeMatch[1];
|
|
75
|
+
}
|
|
57
76
|
const chunks = patch.split(/^@@/m).slice(1);
|
|
58
77
|
matchedFile.chunks = chunks.map((chunk) => {
|
|
59
78
|
const headerEnd = chunk.indexOf("\n");
|
|
@@ -76,14 +95,40 @@ export function registerPrDiffTool(server) {
|
|
|
76
95
|
function parsePrDiffFromPatch(patchOutput) {
|
|
77
96
|
const filePatches = patchOutput.split(/^diff --git /m).filter(Boolean);
|
|
78
97
|
const files = filePatches.map((patch) => {
|
|
79
|
-
// Extract file
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
98
|
+
// Extract file paths from the diff header, handling quoted paths with spaces.
|
|
99
|
+
const headerLine = patch.split("\n", 1)[0] ?? "";
|
|
100
|
+
let oldFile = "";
|
|
101
|
+
let newFile = "";
|
|
102
|
+
const quotedHeader = headerLine.match(/^"a\/(.+)" "b\/(.+)"$/);
|
|
103
|
+
if (quotedHeader) {
|
|
104
|
+
oldFile = quotedHeader[1];
|
|
105
|
+
newFile = quotedHeader[2];
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const plainHeader = headerLine.match(/^a\/(.+?) b\/(.+)$/);
|
|
109
|
+
if (plainHeader) {
|
|
110
|
+
oldFile = plainHeader[1];
|
|
111
|
+
newFile = plainHeader[2];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Rename metadata is more reliable than the header for rename edge-cases.
|
|
115
|
+
const renameFromMatch = patch.match(/^rename from (.+)$/m);
|
|
116
|
+
const renameToMatch = patch.match(/^rename to (.+)$/m);
|
|
117
|
+
if (renameFromMatch)
|
|
118
|
+
oldFile = renameFromMatch[1];
|
|
119
|
+
if (renameToMatch)
|
|
120
|
+
newFile = renameToMatch[1];
|
|
83
121
|
// Detect status from diff headers
|
|
84
122
|
const isNew = /^new file mode/m.test(patch);
|
|
85
123
|
const isDeleted = /^deleted file mode/m.test(patch);
|
|
86
|
-
const isRenamed =
|
|
124
|
+
const isRenamed = !!renameFromMatch || !!renameToMatch || /^similarity index/m.test(patch);
|
|
125
|
+
// Detect binary files from diff markers
|
|
126
|
+
const isBinary = /^Binary files .* differ$/m.test(patch) ||
|
|
127
|
+
/^GIT binary patch$/m.test(patch) ||
|
|
128
|
+
/^Binary file .* has changed$/m.test(patch);
|
|
129
|
+
// S-gap: Extract file mode
|
|
130
|
+
const modeMatch = patch.match(/(?:new|old) file mode (\d+)/);
|
|
131
|
+
const mode = modeMatch ? modeMatch[1] : undefined;
|
|
87
132
|
// Count additions and deletions from diff lines
|
|
88
133
|
let additions = 0;
|
|
89
134
|
let deletions = 0;
|
|
@@ -114,11 +159,13 @@ function parsePrDiffFromPatch(patchOutput) {
|
|
|
114
159
|
? "renamed"
|
|
115
160
|
: "modified";
|
|
116
161
|
return {
|
|
117
|
-
file: newFile,
|
|
162
|
+
file: newFile || oldFile,
|
|
118
163
|
status,
|
|
119
164
|
additions,
|
|
120
165
|
deletions,
|
|
121
166
|
...(isRenamed && oldFile !== newFile ? { oldFile } : {}),
|
|
167
|
+
...(mode ? { mode } : {}),
|
|
168
|
+
...(isBinary ? { binary: true } : {}),
|
|
122
169
|
};
|
|
123
170
|
});
|
|
124
171
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-diff.js","sourceRoot":"","sources":["../../src/tools/pr-diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"pr-diff.js","sourceRoot":"","sources":["../../src/tools/pr-diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-list.d.ts","sourceRoot":"","sources":["../../src/tools/pr-list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"pr-list.d.ts","sourceRoot":"","sources":["../../src/tools/pr-list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWzE,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAgKnD"}
|
package/dist/tools/pr-list.js
CHANGED
|
@@ -4,12 +4,13 @@ import { ghCmd } from "../lib/gh-runner.js";
|
|
|
4
4
|
import { parsePrList } from "../lib/parsers.js";
|
|
5
5
|
import { formatPrList, compactPrListMap, formatPrListCompact } from "../lib/formatters.js";
|
|
6
6
|
import { PrListResultSchema } from "../schemas/index.js";
|
|
7
|
-
|
|
7
|
+
// S-gap: Add labels, isDraft, baseRefName, reviewDecision, mergeable to JSON fields
|
|
8
|
+
const PR_LIST_FIELDS = "number,state,title,url,headRefName,baseRefName,author,labels,isDraft,reviewDecision,mergeable";
|
|
8
9
|
/** Registers the `pr-list` tool on the given MCP server. */
|
|
9
10
|
export function registerPrListTool(server) {
|
|
10
11
|
server.registerTool("pr-list", {
|
|
11
12
|
title: "PR List",
|
|
12
|
-
description: "Lists pull requests with optional filters. Returns structured list with PR number, state, title, author,
|
|
13
|
+
description: "Lists pull requests with optional filters. Returns structured list with PR number, state, title, author, branch, labels, draft status, and merge readiness.",
|
|
13
14
|
inputSchema: {
|
|
14
15
|
state: z
|
|
15
16
|
.enum(["open", "closed", "merged", "all"])
|
|
@@ -27,24 +28,76 @@ export function registerPrListTool(server) {
|
|
|
27
28
|
.optional()
|
|
28
29
|
.describe("Filter by author username"),
|
|
29
30
|
label: z.string().max(INPUT_LIMITS.SHORT_STRING_MAX).optional().describe("Filter by label"),
|
|
30
|
-
|
|
31
|
+
// S-gap P1: Add label as array for multiple label filtering
|
|
32
|
+
labels: z
|
|
33
|
+
.array(z.string().max(INPUT_LIMITS.SHORT_STRING_MAX))
|
|
34
|
+
.max(INPUT_LIMITS.ARRAY_MAX)
|
|
35
|
+
.optional()
|
|
36
|
+
.describe("Filter by multiple labels (each maps to --label)"),
|
|
37
|
+
draft: z.boolean().optional().describe("Filter by draft status (-d/--draft)"),
|
|
38
|
+
// S-gap P0: Add base branch filter
|
|
39
|
+
base: z
|
|
40
|
+
.string()
|
|
41
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Filter by base branch (-B/--base)"),
|
|
44
|
+
// S-gap P0: Add head branch filter
|
|
45
|
+
head: z
|
|
46
|
+
.string()
|
|
47
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Filter by head branch (-H/--head)"),
|
|
50
|
+
// S-gap P1: Add assignee filter
|
|
51
|
+
assignee: z
|
|
52
|
+
.string()
|
|
53
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Filter by assignee username (-a/--assignee)"),
|
|
56
|
+
// S-gap P1: Add search
|
|
57
|
+
search: z
|
|
31
58
|
.string()
|
|
32
|
-
.max(INPUT_LIMITS.
|
|
59
|
+
.max(INPUT_LIMITS.STRING_MAX)
|
|
33
60
|
.optional()
|
|
34
|
-
.describe("
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
.describe("GitHub search syntax (-S/--search)"),
|
|
62
|
+
// S-gap P1: Add repo for cross-repo listing
|
|
63
|
+
repo: z
|
|
64
|
+
.string()
|
|
65
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
37
66
|
.optional()
|
|
38
|
-
.
|
|
39
|
-
|
|
67
|
+
.describe("Repository in OWNER/REPO format (--repo). Default: current repo."),
|
|
68
|
+
// S-gap P2: Add app filter
|
|
69
|
+
app: z
|
|
70
|
+
.string()
|
|
71
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
72
|
+
.optional()
|
|
73
|
+
.describe("Filter by GitHub App (--app)"),
|
|
74
|
+
path: z.string().max(INPUT_LIMITS.PATH_MAX).optional().describe("Repository path"),
|
|
75
|
+
compact: z.boolean().optional().default(true).describe("Prefer compact output"),
|
|
40
76
|
},
|
|
41
77
|
outputSchema: PrListResultSchema,
|
|
42
|
-
}, async ({ state, limit, author, label, path, compact }) => {
|
|
78
|
+
}, async ({ state, limit, author, label, labels, draft, base, head, assignee, search, repo, app, path, compact, }) => {
|
|
43
79
|
const cwd = path || process.cwd();
|
|
44
80
|
if (author)
|
|
45
81
|
assertNoFlagInjection(author, "author");
|
|
46
82
|
if (label)
|
|
47
83
|
assertNoFlagInjection(label, "label");
|
|
84
|
+
if (labels) {
|
|
85
|
+
for (const l of labels) {
|
|
86
|
+
assertNoFlagInjection(l, "labels");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (base)
|
|
90
|
+
assertNoFlagInjection(base, "base");
|
|
91
|
+
if (head)
|
|
92
|
+
assertNoFlagInjection(head, "head");
|
|
93
|
+
if (assignee)
|
|
94
|
+
assertNoFlagInjection(assignee, "assignee");
|
|
95
|
+
if (search)
|
|
96
|
+
assertNoFlagInjection(search, "search");
|
|
97
|
+
if (repo)
|
|
98
|
+
assertNoFlagInjection(repo, "repo");
|
|
99
|
+
if (app)
|
|
100
|
+
assertNoFlagInjection(app, "app");
|
|
48
101
|
const args = ["pr", "list", "--json", PR_LIST_FIELDS, "--limit", String(limit)];
|
|
49
102
|
if (state)
|
|
50
103
|
args.push("--state", state);
|
|
@@ -52,11 +105,62 @@ export function registerPrListTool(server) {
|
|
|
52
105
|
args.push("--author", author);
|
|
53
106
|
if (label)
|
|
54
107
|
args.push("--label", label);
|
|
108
|
+
if (labels && labels.length > 0) {
|
|
109
|
+
for (const l of labels) {
|
|
110
|
+
args.push("--label", l);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (draft)
|
|
114
|
+
args.push("--draft");
|
|
115
|
+
if (base)
|
|
116
|
+
args.push("--base", base);
|
|
117
|
+
if (head)
|
|
118
|
+
args.push("--head", head);
|
|
119
|
+
if (assignee)
|
|
120
|
+
args.push("--assignee", assignee);
|
|
121
|
+
if (search)
|
|
122
|
+
args.push("--search", search);
|
|
123
|
+
if (repo)
|
|
124
|
+
args.push("--repo", repo);
|
|
125
|
+
if (app)
|
|
126
|
+
args.push("--app", app);
|
|
55
127
|
const result = await ghCmd(args, cwd);
|
|
56
128
|
if (result.exitCode !== 0) {
|
|
57
129
|
throw new Error(`gh pr list failed: ${result.stderr}`);
|
|
58
130
|
}
|
|
59
|
-
|
|
131
|
+
let totalAvailable;
|
|
132
|
+
if (limit < 1000) {
|
|
133
|
+
const countArgs = ["pr", "list", "--json", PR_LIST_FIELDS, "--limit", "1000"];
|
|
134
|
+
if (state)
|
|
135
|
+
countArgs.push("--state", state);
|
|
136
|
+
if (author)
|
|
137
|
+
countArgs.push("--author", author);
|
|
138
|
+
if (label)
|
|
139
|
+
countArgs.push("--label", label);
|
|
140
|
+
if (labels && labels.length > 0) {
|
|
141
|
+
for (const l of labels)
|
|
142
|
+
countArgs.push("--label", l);
|
|
143
|
+
}
|
|
144
|
+
if (draft)
|
|
145
|
+
countArgs.push("--draft");
|
|
146
|
+
if (base)
|
|
147
|
+
countArgs.push("--base", base);
|
|
148
|
+
if (head)
|
|
149
|
+
countArgs.push("--head", head);
|
|
150
|
+
if (assignee)
|
|
151
|
+
countArgs.push("--assignee", assignee);
|
|
152
|
+
if (search)
|
|
153
|
+
countArgs.push("--search", search);
|
|
154
|
+
if (repo)
|
|
155
|
+
countArgs.push("--repo", repo);
|
|
156
|
+
if (app)
|
|
157
|
+
countArgs.push("--app", app);
|
|
158
|
+
const countResult = await ghCmd(countArgs, cwd);
|
|
159
|
+
if (countResult.exitCode === 0) {
|
|
160
|
+
totalAvailable = parsePrList(countResult.stdout).total;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const data = parsePrList(result.stdout, totalAvailable);
|
|
60
164
|
return compactDualOutput(data, result.stdout, formatPrList, compactPrListMap, formatPrListCompact, compact === false);
|
|
61
165
|
});
|
|
62
166
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-list.js","sourceRoot":"","sources":["../../src/tools/pr-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"pr-list.js","sourceRoot":"","sources":["../../src/tools/pr-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-merge.d.ts","sourceRoot":"","sources":["../../src/tools/pr-merge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"pr-merge.d.ts","sourceRoot":"","sources":["../../src/tools/pr-merge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkBzE,6DAA6D;AAC7D,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,QAiIpD"}
|
package/dist/tools/pr-merge.js
CHANGED
|
@@ -1,44 +1,133 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { dualOutput, INPUT_LIMITS } from "@paretools/shared";
|
|
2
|
+
import { dualOutput, assertNoFlagInjection, INPUT_LIMITS } from "@paretools/shared";
|
|
3
3
|
import { ghCmd } from "../lib/gh-runner.js";
|
|
4
4
|
import { parsePrMerge } from "../lib/parsers.js";
|
|
5
5
|
import { formatPrMerge } from "../lib/formatters.js";
|
|
6
6
|
import { PrMergeResultSchema } from "../schemas/index.js";
|
|
7
|
+
function classifyPrMergeError(text) {
|
|
8
|
+
const lower = text.toLowerCase();
|
|
9
|
+
if (/already merged|is already merged/.test(lower))
|
|
10
|
+
return "already-merged";
|
|
11
|
+
if (/merge conflict|conflicts/.test(lower))
|
|
12
|
+
return "merge-conflict";
|
|
13
|
+
if (/checks? (have )?not passed|required status check/.test(lower))
|
|
14
|
+
return "blocked-checks";
|
|
15
|
+
if (/forbidden|permission|403/.test(lower))
|
|
16
|
+
return "permission-denied";
|
|
17
|
+
return "unknown";
|
|
18
|
+
}
|
|
7
19
|
/** Registers the `pr-merge` tool on the given MCP server. */
|
|
8
20
|
export function registerPrMergeTool(server) {
|
|
9
21
|
server.registerTool("pr-merge", {
|
|
10
22
|
title: "PR Merge",
|
|
11
|
-
description: "Merges a pull request by number. Returns structured data with merge status, method,
|
|
23
|
+
description: "Merges a pull request by number, URL, or branch. Returns structured data with merge status, method, URL, and branch deletion status.",
|
|
12
24
|
inputSchema: {
|
|
13
|
-
number: z
|
|
25
|
+
number: z
|
|
26
|
+
.string()
|
|
27
|
+
.max(INPUT_LIMITS.STRING_MAX)
|
|
28
|
+
.describe("Pull request number, URL, or branch name"),
|
|
14
29
|
method: z
|
|
15
30
|
.enum(["squash", "merge", "rebase"])
|
|
16
31
|
.optional()
|
|
17
32
|
.default("squash")
|
|
18
33
|
.describe("Merge method (default: squash)"),
|
|
19
34
|
deleteBranch: z.boolean().optional().default(false).describe("Delete branch after merge"),
|
|
20
|
-
|
|
21
|
-
.
|
|
22
|
-
.max(INPUT_LIMITS.PATH_MAX)
|
|
35
|
+
admin: z
|
|
36
|
+
.boolean()
|
|
23
37
|
.optional()
|
|
24
|
-
.
|
|
25
|
-
|
|
38
|
+
.default(false)
|
|
39
|
+
.describe("Bypass branch protection rules (--admin)"),
|
|
40
|
+
auto: z
|
|
26
41
|
.boolean()
|
|
27
42
|
.optional()
|
|
28
|
-
.
|
|
29
|
-
|
|
43
|
+
.describe("Enable auto-merge when requirements are met (--auto)"),
|
|
44
|
+
disableAuto: z
|
|
45
|
+
.boolean()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Disable auto-merge for this PR (--disable-auto)"),
|
|
48
|
+
subject: z
|
|
49
|
+
.string()
|
|
50
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Commit subject for merge commit (--subject)"),
|
|
53
|
+
commitBody: z
|
|
54
|
+
.string()
|
|
55
|
+
.max(INPUT_LIMITS.STRING_MAX)
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("Commit body for merge commit (--body)"),
|
|
58
|
+
authorEmail: z
|
|
59
|
+
.string()
|
|
60
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
61
|
+
.optional()
|
|
62
|
+
.describe("Author email for merge commit (--author-email)"),
|
|
63
|
+
// S-gap P0: Add matchHeadCommit for safety check
|
|
64
|
+
matchHeadCommit: z
|
|
65
|
+
.string()
|
|
66
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Safety check: only merge if HEAD SHA matches this value (--match-head-commit)"),
|
|
69
|
+
// S-gap P1: Add repo for cross-repo merging
|
|
70
|
+
repo: z
|
|
71
|
+
.string()
|
|
72
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
73
|
+
.optional()
|
|
74
|
+
.describe("Repository in OWNER/REPO format (--repo). Default: current repo."),
|
|
75
|
+
path: z.string().max(INPUT_LIMITS.PATH_MAX).optional().describe("Repository path"),
|
|
76
|
+
compact: z.boolean().optional().default(true).describe("Prefer compact output"),
|
|
30
77
|
},
|
|
31
78
|
outputSchema: PrMergeResultSchema,
|
|
32
|
-
}, async ({ number, method, deleteBranch, path }) => {
|
|
79
|
+
}, async ({ number, method, deleteBranch, admin, auto, disableAuto, subject, commitBody, authorEmail, matchHeadCommit, repo, path, }) => {
|
|
33
80
|
const cwd = path || process.cwd();
|
|
34
|
-
|
|
81
|
+
if (subject)
|
|
82
|
+
assertNoFlagInjection(subject, "subject");
|
|
83
|
+
if (authorEmail)
|
|
84
|
+
assertNoFlagInjection(authorEmail, "authorEmail");
|
|
85
|
+
if (matchHeadCommit)
|
|
86
|
+
assertNoFlagInjection(matchHeadCommit, "matchHeadCommit");
|
|
87
|
+
if (repo)
|
|
88
|
+
assertNoFlagInjection(repo, "repo");
|
|
89
|
+
if (typeof number === "string")
|
|
90
|
+
assertNoFlagInjection(number, "number");
|
|
91
|
+
const selector = String(number);
|
|
92
|
+
const prNum = typeof number === "number" ? number : 0;
|
|
93
|
+
const args = ["pr", "merge", selector, `--${method}`];
|
|
35
94
|
if (deleteBranch)
|
|
36
95
|
args.push("--delete-branch");
|
|
37
|
-
|
|
96
|
+
if (admin)
|
|
97
|
+
args.push("--admin");
|
|
98
|
+
if (auto)
|
|
99
|
+
args.push("--auto");
|
|
100
|
+
if (disableAuto)
|
|
101
|
+
args.push("--disable-auto");
|
|
102
|
+
if (subject)
|
|
103
|
+
args.push("--subject", subject);
|
|
104
|
+
// Use --body-file - to pass commitBody via stdin, avoiding shell escaping issues
|
|
105
|
+
// for bodies with special characters (backticks, pipes, etc.) — especially on Windows
|
|
106
|
+
let stdin;
|
|
107
|
+
if (commitBody) {
|
|
108
|
+
args.push("--body-file", "-");
|
|
109
|
+
stdin = commitBody;
|
|
110
|
+
}
|
|
111
|
+
if (authorEmail)
|
|
112
|
+
args.push("--author-email", authorEmail);
|
|
113
|
+
if (matchHeadCommit)
|
|
114
|
+
args.push("--match-head-commit", matchHeadCommit);
|
|
115
|
+
if (repo)
|
|
116
|
+
args.push("--repo", repo);
|
|
117
|
+
const result = await ghCmd(args, { cwd, stdin });
|
|
38
118
|
if (result.exitCode !== 0) {
|
|
39
|
-
|
|
119
|
+
const combined = `${result.stdout}\n${result.stderr}`.trim();
|
|
120
|
+
return dualOutput({
|
|
121
|
+
number: prNum,
|
|
122
|
+
merged: false,
|
|
123
|
+
method: method,
|
|
124
|
+
url: "",
|
|
125
|
+
state: disableAuto ? "auto-merge-disabled" : auto ? "auto-merge-enabled" : undefined,
|
|
126
|
+
errorType: classifyPrMergeError(combined),
|
|
127
|
+
errorMessage: combined || "gh pr merge failed",
|
|
128
|
+
}, formatPrMerge);
|
|
40
129
|
}
|
|
41
|
-
const data = parsePrMerge(result.stdout,
|
|
130
|
+
const data = parsePrMerge(result.stdout, prNum, method, !!deleteBranch, auto, disableAuto);
|
|
42
131
|
return dualOutput(data, formatPrMerge);
|
|
43
132
|
});
|
|
44
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-merge.js","sourceRoot":"","sources":["../../src/tools/pr-merge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"pr-merge.js","sourceRoot":"","sources":["../../src/tools/pr-merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-review.d.ts","sourceRoot":"","sources":["../../src/tools/pr-review.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"pr-review.d.ts","sourceRoot":"","sources":["../../src/tools/pr-review.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,QAqFrD"}
|
package/dist/tools/pr-review.js
CHANGED
|
@@ -8,9 +8,12 @@ import { PrReviewResultSchema } from "../schemas/index.js";
|
|
|
8
8
|
export function registerPrReviewTool(server) {
|
|
9
9
|
server.registerTool("pr-review", {
|
|
10
10
|
title: "PR Review",
|
|
11
|
-
description: "Submits a review on a pull request (approve, request-changes, or comment). Returns structured data with the review event
|
|
11
|
+
description: "Submits a review on a pull request (approve, request-changes, or comment). Returns structured data with the review event, URL, and body echo.",
|
|
12
12
|
inputSchema: {
|
|
13
|
-
number: z
|
|
13
|
+
number: z
|
|
14
|
+
.string()
|
|
15
|
+
.max(INPUT_LIMITS.STRING_MAX)
|
|
16
|
+
.describe("Pull request number, URL, or branch name"),
|
|
14
17
|
event: z
|
|
15
18
|
.enum(["approve", "request-changes", "comment"])
|
|
16
19
|
.describe("Review type: approve, request-changes, or comment"),
|
|
@@ -19,34 +22,64 @@ export function registerPrReviewTool(server) {
|
|
|
19
22
|
.max(INPUT_LIMITS.STRING_MAX)
|
|
20
23
|
.optional()
|
|
21
24
|
.describe("Review body (required for request-changes and comment)"),
|
|
22
|
-
|
|
25
|
+
// S-gap P0: Add repo for cross-repo review
|
|
26
|
+
repo: z
|
|
27
|
+
.string()
|
|
28
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Repository in OWNER/REPO format (--repo). Default: current repo."),
|
|
31
|
+
// S-gap P2: Add bodyFile for reading review body from file
|
|
32
|
+
bodyFile: z
|
|
23
33
|
.string()
|
|
24
34
|
.max(INPUT_LIMITS.PATH_MAX)
|
|
25
35
|
.optional()
|
|
26
|
-
.describe("
|
|
36
|
+
.describe("Read review body from file (--body-file). Mutually exclusive with body."),
|
|
37
|
+
path: z.string().max(INPUT_LIMITS.PATH_MAX).optional().describe("Repository path"),
|
|
27
38
|
},
|
|
28
39
|
outputSchema: PrReviewResultSchema,
|
|
29
|
-
}, async ({ number, event, body, path }) => {
|
|
40
|
+
}, async ({ number, event, body, repo, bodyFile, path }) => {
|
|
30
41
|
const cwd = path || process.cwd();
|
|
31
42
|
if (body) {
|
|
32
43
|
assertNoFlagInjection(body, "body");
|
|
33
44
|
}
|
|
45
|
+
if (repo)
|
|
46
|
+
assertNoFlagInjection(repo, "repo");
|
|
47
|
+
if (bodyFile)
|
|
48
|
+
assertNoFlagInjection(bodyFile, "bodyFile");
|
|
49
|
+
if (typeof number === "string")
|
|
50
|
+
assertNoFlagInjection(number, "number");
|
|
34
51
|
// request-changes and comment require a body
|
|
35
|
-
if ((event === "request-changes" || event === "comment") && !body) {
|
|
52
|
+
if ((event === "request-changes" || event === "comment") && !body && !bodyFile) {
|
|
36
53
|
throw new Error(`Review body is required for "${event}" reviews.`);
|
|
37
54
|
}
|
|
38
|
-
const
|
|
55
|
+
const selector = String(number);
|
|
56
|
+
const prNum = typeof number === "number" ? number : 0;
|
|
57
|
+
const args = ["pr", "review", selector, `--${event}`];
|
|
58
|
+
if (repo)
|
|
59
|
+
args.push("--repo", repo);
|
|
39
60
|
// Pass body via stdin (--body-file -) to avoid shell escaping issues
|
|
40
61
|
let stdin;
|
|
41
62
|
if (body) {
|
|
42
63
|
args.push("--body-file", "-");
|
|
43
64
|
stdin = body;
|
|
44
65
|
}
|
|
66
|
+
else if (bodyFile) {
|
|
67
|
+
// S-gap P2: Read body from file
|
|
68
|
+
args.push("--body-file", bodyFile);
|
|
69
|
+
}
|
|
45
70
|
const result = await ghCmd(args, { cwd, stdin });
|
|
71
|
+
// P1-gap #146: Classify errors instead of always throwing
|
|
46
72
|
if (result.exitCode !== 0) {
|
|
73
|
+
// Return structured error output with classification
|
|
74
|
+
const data = parsePrReview(result.stdout, prNum, event, body, result.stderr);
|
|
75
|
+
if (data.errorType && data.errorType !== "unknown") {
|
|
76
|
+
// Return structured result with error classification
|
|
77
|
+
return dualOutput(data, formatPrReview);
|
|
78
|
+
}
|
|
47
79
|
throw new Error(`gh pr review failed: ${result.stderr}`);
|
|
48
80
|
}
|
|
49
|
-
|
|
81
|
+
// P1-gap #145: Pass body for echo in output (event mapped to GitHub type)
|
|
82
|
+
const data = parsePrReview(result.stdout, prNum, event, body);
|
|
50
83
|
return dualOutput(data, formatPrReview);
|
|
51
84
|
});
|
|
52
85
|
}
|