@paretools/github 0.8.5 → 0.9.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/lib/formatters.d.ts.map +1 -1
- package/dist/lib/formatters.js +112 -16
- package/dist/lib/formatters.js.map +1 -1
- package/dist/lib/parsers.d.ts +33 -11
- package/dist/lib/parsers.d.ts.map +1 -1
- package/dist/lib/parsers.js +309 -24
- 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 +126 -3
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +116 -3
- package/dist/schemas/index.js.map +1 -1
- package/dist/tools/api.d.ts.map +1 -1
- package/dist/tools/api.js +135 -5
- package/dist/tools/api.js.map +1 -1
- package/dist/tools/gist-create.d.ts.map +1 -1
- package/dist/tools/gist-create.js +70 -16
- package/dist/tools/gist-create.js.map +1 -1
- package/dist/tools/issue-close.d.ts.map +1 -1
- package/dist/tools/issue-close.js +31 -5
- 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 +43 -6
- 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 +69 -5
- 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 +79 -3
- 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 +102 -11
- 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 -6
- package/dist/tools/issue-view.js.map +1 -1
- package/dist/tools/pr-checks.d.ts.map +1 -1
- package/dist/tools/pr-checks.js +27 -7
- 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 +43 -6
- 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 +125 -3
- 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 +36 -4
- 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 +83 -3
- 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 +77 -6
- 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 +43 -6
- 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 +110 -5
- 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 -6
- 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 +79 -3
- 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 +23 -5
- 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 +84 -3
- 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 +20 -4
- 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 +44 -4
- package/dist/tools/run-view.js.map +1 -1
- package/package.json +2 -2
package/dist/tools/api.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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 { parseApi } from "../lib/parsers.js";
|
|
5
5
|
import { formatApi } from "../lib/formatters.js";
|
|
@@ -27,6 +27,11 @@ export function registerApiTool(server) {
|
|
|
27
27
|
.record(z.string(), z.string())
|
|
28
28
|
.optional()
|
|
29
29
|
.describe("Key-value pairs sent as --raw-field parameters"),
|
|
30
|
+
// S-gap P1: Add typedFields for --field (typed field input)
|
|
31
|
+
typedFields: z
|
|
32
|
+
.record(z.string(), z.string())
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Key-value pairs sent as --field parameters (typed: booleans, numbers, null parsed by gh)"),
|
|
30
35
|
paginate: z
|
|
31
36
|
.boolean()
|
|
32
37
|
.optional()
|
|
@@ -37,6 +42,55 @@ export function registerApiTool(server) {
|
|
|
37
42
|
.max(INPUT_LIMITS.STRING_MAX)
|
|
38
43
|
.optional()
|
|
39
44
|
.describe("jq filter expression to apply to the response"),
|
|
45
|
+
slurp: z
|
|
46
|
+
.boolean()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe("Combine paginated JSON arrays into a single array (--slurp)"),
|
|
49
|
+
include: z
|
|
50
|
+
.boolean()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("Include response headers in output (-i/--include)"),
|
|
53
|
+
silent: z.boolean().optional().describe("Suppress response body output (--silent)"),
|
|
54
|
+
verbose: z.boolean().optional().describe("Show verbose debug output (--verbose)"),
|
|
55
|
+
// S-gap P0: Add headers param
|
|
56
|
+
headers: z
|
|
57
|
+
.record(z.string(), z.string())
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("Custom HTTP headers as key-value pairs (each maps to -H/--header)"),
|
|
60
|
+
// S-gap P1: Add hostname for GitHub Enterprise
|
|
61
|
+
hostname: z
|
|
62
|
+
.string()
|
|
63
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("GitHub Enterprise hostname (--hostname)"),
|
|
66
|
+
// S-gap P1: Add cache TTL
|
|
67
|
+
cache: z
|
|
68
|
+
.string()
|
|
69
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Cache TTL for responses, e.g. '5m', '1h' (--cache)"),
|
|
72
|
+
// S-gap P2: Add preview for API preview features
|
|
73
|
+
preview: z
|
|
74
|
+
.string()
|
|
75
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
76
|
+
.optional()
|
|
77
|
+
.describe("API preview feature name (--preview)"),
|
|
78
|
+
// S-gap P2: Add inputFile for reading body from file
|
|
79
|
+
inputFile: z
|
|
80
|
+
.string()
|
|
81
|
+
.max(INPUT_LIMITS.PATH_MAX)
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Read request body from file (--input). Mutually exclusive with body."),
|
|
84
|
+
// P1-gap #142: GraphQL support
|
|
85
|
+
query: z
|
|
86
|
+
.string()
|
|
87
|
+
.max(INPUT_LIMITS.STRING_MAX)
|
|
88
|
+
.optional()
|
|
89
|
+
.describe("GraphQL query string. When provided, makes a GraphQL request via `gh api graphql`."),
|
|
90
|
+
variables: z
|
|
91
|
+
.record(z.string(), z.unknown())
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("GraphQL variables as key-value pairs. Only used with `query` parameter."),
|
|
40
94
|
path: z
|
|
41
95
|
.string()
|
|
42
96
|
.max(INPUT_LIMITS.PATH_MAX)
|
|
@@ -44,8 +98,49 @@ export function registerApiTool(server) {
|
|
|
44
98
|
.describe("Repository path (default: cwd)"),
|
|
45
99
|
},
|
|
46
100
|
outputSchema: ApiResultSchema,
|
|
47
|
-
}, async ({ endpoint, method, body, fields, paginate, jq, path }) => {
|
|
101
|
+
}, async ({ endpoint, method, body, fields, typedFields, paginate, jq, slurp, include: _include, silent, verbose, headers, hostname, cache, preview, inputFile, query, variables, path, }) => {
|
|
48
102
|
const cwd = path || process.cwd();
|
|
103
|
+
assertNoFlagInjection(endpoint, "endpoint");
|
|
104
|
+
if (jq)
|
|
105
|
+
assertNoFlagInjection(jq, "jq");
|
|
106
|
+
if (hostname)
|
|
107
|
+
assertNoFlagInjection(hostname, "hostname");
|
|
108
|
+
if (cache)
|
|
109
|
+
assertNoFlagInjection(cache, "cache");
|
|
110
|
+
if (preview)
|
|
111
|
+
assertNoFlagInjection(preview, "preview");
|
|
112
|
+
if (inputFile)
|
|
113
|
+
assertNoFlagInjection(inputFile, "inputFile");
|
|
114
|
+
// P1-gap #142: Handle GraphQL queries
|
|
115
|
+
if (query) {
|
|
116
|
+
const gqlArgs = ["api", "graphql", "-f", `query=${query}`];
|
|
117
|
+
if (variables) {
|
|
118
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
119
|
+
gqlArgs.push("-f", `${key}=${typeof value === "string" ? value : JSON.stringify(value)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (hostname)
|
|
123
|
+
gqlArgs.push("--hostname", hostname);
|
|
124
|
+
if (headers) {
|
|
125
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
126
|
+
gqlArgs.push("-H", `${key}:${value}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (jq)
|
|
130
|
+
gqlArgs.push("--jq", jq);
|
|
131
|
+
if (paginate)
|
|
132
|
+
gqlArgs.push("--paginate");
|
|
133
|
+
if (slurp)
|
|
134
|
+
gqlArgs.push("--slurp");
|
|
135
|
+
gqlArgs.push("--include");
|
|
136
|
+
const gqlResult = await ghCmd(gqlArgs, { cwd });
|
|
137
|
+
if (gqlResult.exitCode !== 0 && !gqlResult.stdout && gqlResult.stderr) {
|
|
138
|
+
const data = parseApi("", gqlResult.exitCode, "graphql", "POST", gqlResult.stderr);
|
|
139
|
+
return dualOutput(data, formatApi);
|
|
140
|
+
}
|
|
141
|
+
const data = parseApi(gqlResult.stdout, gqlResult.exitCode, "graphql", "POST", gqlResult.stderr);
|
|
142
|
+
return dualOutput(data, formatApi);
|
|
143
|
+
}
|
|
49
144
|
const args = ["api", endpoint, "--method", method];
|
|
50
145
|
if (paginate) {
|
|
51
146
|
args.push("--paginate");
|
|
@@ -53,23 +148,58 @@ export function registerApiTool(server) {
|
|
|
53
148
|
if (jq) {
|
|
54
149
|
args.push("--jq", jq);
|
|
55
150
|
}
|
|
151
|
+
if (slurp)
|
|
152
|
+
args.push("--slurp");
|
|
153
|
+
// Always include response headers so we can parse the real HTTP status code.
|
|
154
|
+
// The --include flag is always set; the user's `include` param is redundant but harmless.
|
|
155
|
+
args.push("--include");
|
|
156
|
+
if (silent)
|
|
157
|
+
args.push("--silent");
|
|
158
|
+
if (verbose)
|
|
159
|
+
args.push("--verbose");
|
|
160
|
+
if (hostname)
|
|
161
|
+
args.push("--hostname", hostname);
|
|
162
|
+
if (cache)
|
|
163
|
+
args.push("--cache", cache);
|
|
164
|
+
if (preview)
|
|
165
|
+
args.push("--preview", preview);
|
|
166
|
+
// S-gap P0: Add custom headers
|
|
167
|
+
if (headers) {
|
|
168
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
169
|
+
args.push("-H", `${key}:${value}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
56
172
|
// Add --raw-field for each field entry
|
|
57
173
|
if (fields) {
|
|
58
174
|
for (const [key, value] of Object.entries(fields)) {
|
|
59
175
|
args.push("--raw-field", `${key}=${value}`);
|
|
60
176
|
}
|
|
61
177
|
}
|
|
178
|
+
// S-gap P1: Add --field for each typed field entry
|
|
179
|
+
if (typedFields) {
|
|
180
|
+
for (const [key, value] of Object.entries(typedFields)) {
|
|
181
|
+
args.push("--field", `${key}=${value}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
62
184
|
// Pass JSON body via stdin using --input -
|
|
63
185
|
let stdin;
|
|
64
186
|
if (body) {
|
|
65
187
|
args.push("--input", "-");
|
|
66
188
|
stdin = JSON.stringify(body);
|
|
67
189
|
}
|
|
190
|
+
else if (inputFile) {
|
|
191
|
+
// S-gap P2: Read body from file
|
|
192
|
+
args.push("--input", inputFile);
|
|
193
|
+
}
|
|
68
194
|
const result = await ghCmd(args, { cwd, stdin });
|
|
69
|
-
|
|
70
|
-
|
|
195
|
+
// P1-gap #141: Pass stderr to parser for error body preservation
|
|
196
|
+
// Only throw if there's no stdout at all (completely failed)
|
|
197
|
+
if (result.exitCode !== 0 && !result.stdout && result.stderr) {
|
|
198
|
+
// Still try to parse — pass stderr for error body
|
|
199
|
+
const data = parseApi("", result.exitCode, endpoint, method, result.stderr);
|
|
200
|
+
return dualOutput(data, formatApi);
|
|
71
201
|
}
|
|
72
|
-
const data = parseApi(result.stdout, result.exitCode, endpoint, method);
|
|
202
|
+
const data = parseApi(result.stdout, result.exitCode, endpoint, method, result.stderr);
|
|
73
203
|
return dualOutput(data, formatApi);
|
|
74
204
|
});
|
|
75
205
|
}
|
package/dist/tools/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/tools/api.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":"api.js","sourceRoot":"","sources":["../../src/tools/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gist-create.d.ts","sourceRoot":"","sources":["../../src/tools/gist-create.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"gist-create.d.ts","sourceRoot":"","sources":["../../src/tools/gist-create.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWzE,gEAAgE;AAChE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QA4GvD"}
|
|
@@ -1,20 +1,30 @@
|
|
|
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 { parseGistCreate } from "../lib/parsers.js";
|
|
5
5
|
import { formatGistCreate } from "../lib/formatters.js";
|
|
6
6
|
import { GistCreateResultSchema } from "../schemas/index.js";
|
|
7
|
+
import { assertSafeFilePath } from "../lib/path-validation.js";
|
|
8
|
+
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
7
11
|
/** Registers the `gist-create` tool on the given MCP server. */
|
|
8
12
|
export function registerGistCreateTool(server) {
|
|
9
13
|
server.registerTool("gist-create", {
|
|
10
14
|
title: "Gist Create",
|
|
11
|
-
description: "Creates a new GitHub gist from one or more files. Returns structured data with gist ID, URL, and
|
|
15
|
+
description: "Creates a new GitHub gist from one or more files. Returns structured data with gist ID, URL, visibility, file names, description, and file count. Use instead of running `gh gist create` in the terminal.",
|
|
12
16
|
inputSchema: {
|
|
13
17
|
files: z
|
|
14
18
|
.array(z.string().max(INPUT_LIMITS.PATH_MAX))
|
|
15
|
-
.min(1)
|
|
16
19
|
.max(INPUT_LIMITS.ARRAY_MAX)
|
|
17
|
-
.
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("File paths to include in the gist. Either files or content must be provided."),
|
|
22
|
+
// P1-gap #143: Add content-based gist creation from inline content
|
|
23
|
+
content: z
|
|
24
|
+
.record(z.string(), z.string())
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Inline content as filename-to-content map (e.g., {'script.py': 'print(1)'}). " +
|
|
27
|
+
"Creates gist from inline content instead of file paths. Either files or content must be provided."),
|
|
18
28
|
description: z
|
|
19
29
|
.string()
|
|
20
30
|
.max(INPUT_LIMITS.STRING_MAX)
|
|
@@ -32,22 +42,66 @@ export function registerGistCreateTool(server) {
|
|
|
32
42
|
.describe("Working directory (default: cwd)"),
|
|
33
43
|
},
|
|
34
44
|
outputSchema: GistCreateResultSchema,
|
|
35
|
-
}, async ({ files, description, public: isPublic, path }) => {
|
|
45
|
+
}, async ({ files, content: contentMap, description, public: isPublic, path }) => {
|
|
36
46
|
const cwd = path || process.cwd();
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
if (description)
|
|
48
|
+
assertNoFlagInjection(description, "description");
|
|
49
|
+
// P1-gap #143: Validate that at least one of files or content is provided
|
|
50
|
+
const hasFiles = files && files.length > 0;
|
|
51
|
+
const hasContent = contentMap && Object.keys(contentMap).length > 0;
|
|
52
|
+
if (!hasFiles && !hasContent) {
|
|
53
|
+
throw new Error("Either `files` or `content` must be provided.");
|
|
40
54
|
}
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
// Track temp dir for cleanup
|
|
56
|
+
let tempDir;
|
|
57
|
+
let resolvedFiles = [];
|
|
58
|
+
try {
|
|
59
|
+
if (hasFiles) {
|
|
60
|
+
// Validate all file paths are safe before passing to gh CLI
|
|
61
|
+
for (const file of files) {
|
|
62
|
+
assertNoFlagInjection(file, "files");
|
|
63
|
+
assertSafeFilePath(file, cwd);
|
|
64
|
+
}
|
|
65
|
+
resolvedFiles = files;
|
|
66
|
+
}
|
|
67
|
+
if (hasContent) {
|
|
68
|
+
// P1-gap #143: Write inline content to temp files
|
|
69
|
+
tempDir = mkdtempSync(join(tmpdir(), "pare-gist-"));
|
|
70
|
+
for (const [filename, fileContent] of Object.entries(contentMap)) {
|
|
71
|
+
assertNoFlagInjection(filename, "content filename");
|
|
72
|
+
const tempPath = join(tempDir, filename);
|
|
73
|
+
writeFileSync(tempPath, fileContent);
|
|
74
|
+
resolvedFiles.push(tempPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const args = ["gist", "create"];
|
|
78
|
+
if (description) {
|
|
79
|
+
args.push("--desc", description);
|
|
80
|
+
}
|
|
81
|
+
if (isPublic) {
|
|
82
|
+
args.push("--public");
|
|
83
|
+
}
|
|
84
|
+
args.push(...resolvedFiles);
|
|
85
|
+
const result = await ghCmd(args, cwd);
|
|
86
|
+
if (result.exitCode !== 0) {
|
|
87
|
+
throw new Error(`gh gist create failed: ${result.stderr}`);
|
|
88
|
+
}
|
|
89
|
+
// Build file list for output (use original filenames for content-based gists)
|
|
90
|
+
const outputFiles = hasContent ? Object.keys(contentMap) : (files ?? []);
|
|
91
|
+
const data = parseGistCreate(result.stdout, !!isPublic, outputFiles, description);
|
|
92
|
+
return dualOutput(data, formatGistCreate);
|
|
43
93
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
94
|
+
finally {
|
|
95
|
+
// P1-gap #143: Clean up temp files
|
|
96
|
+
if (tempDir) {
|
|
97
|
+
try {
|
|
98
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Best-effort cleanup
|
|
102
|
+
}
|
|
103
|
+
}
|
|
48
104
|
}
|
|
49
|
-
const data = parseGistCreate(result.stdout, !!isPublic);
|
|
50
|
-
return dualOutput(data, formatGistCreate);
|
|
51
105
|
});
|
|
52
106
|
}
|
|
53
107
|
//# sourceMappingURL=gist-create.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gist-create.js","sourceRoot":"","sources":["../../src/tools/gist-create.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":"gist-create.js","sourceRoot":"","sources":["../../src/tools/gist-create.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-close.d.ts","sourceRoot":"","sources":["../../src/tools/issue-close.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,gEAAgE;AAChE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"issue-close.d.ts","sourceRoot":"","sources":["../../src/tools/issue-close.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,gEAAgE;AAChE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QA0EvD"}
|
|
@@ -8,14 +8,20 @@ import { IssueCloseResultSchema } from "../schemas/index.js";
|
|
|
8
8
|
export function registerIssueCloseTool(server) {
|
|
9
9
|
server.registerTool("issue-close", {
|
|
10
10
|
title: "Issue Close",
|
|
11
|
-
description: "Closes an issue with an optional comment and reason. Returns structured data with issue number, state, and URL. Use instead of running `gh issue close` in the terminal.",
|
|
11
|
+
description: "Closes an issue with an optional comment and reason. Returns structured data with issue number, state, URL, reason, and comment URL. Use instead of running `gh issue close` in the terminal.",
|
|
12
12
|
inputSchema: {
|
|
13
|
-
number: z.
|
|
13
|
+
number: z.string().max(INPUT_LIMITS.STRING_MAX).describe("Issue number or URL"),
|
|
14
14
|
comment: z.string().max(INPUT_LIMITS.STRING_MAX).optional().describe("Closing comment"),
|
|
15
15
|
reason: z
|
|
16
16
|
.enum(["completed", "not planned"])
|
|
17
17
|
.optional()
|
|
18
18
|
.describe('Close reason: "completed" or "not planned"'),
|
|
19
|
+
// S-gap P1: Add repo for cross-repo close
|
|
20
|
+
repo: z
|
|
21
|
+
.string()
|
|
22
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Repository in OWNER/REPO format (default: current repo)"),
|
|
19
25
|
path: z
|
|
20
26
|
.string()
|
|
21
27
|
.max(INPUT_LIMITS.PATH_MAX)
|
|
@@ -23,23 +29,43 @@ export function registerIssueCloseTool(server) {
|
|
|
23
29
|
.describe("Repository path (default: cwd)"),
|
|
24
30
|
},
|
|
25
31
|
outputSchema: IssueCloseResultSchema,
|
|
26
|
-
}, async ({ number, comment, reason, path }) => {
|
|
32
|
+
}, async ({ number, comment, reason, repo, path }) => {
|
|
27
33
|
const cwd = path || process.cwd();
|
|
28
34
|
if (comment) {
|
|
29
35
|
assertNoFlagInjection(comment, "comment");
|
|
30
36
|
}
|
|
31
|
-
|
|
37
|
+
if (repo)
|
|
38
|
+
assertNoFlagInjection(repo, "repo");
|
|
39
|
+
if (typeof number === "string")
|
|
40
|
+
assertNoFlagInjection(number, "number");
|
|
41
|
+
const selector = String(number);
|
|
42
|
+
const issueNum = typeof number === "number" ? number : 0;
|
|
43
|
+
const args = ["issue", "close", selector];
|
|
32
44
|
if (comment) {
|
|
33
45
|
args.push("--comment", comment);
|
|
34
46
|
}
|
|
35
47
|
if (reason) {
|
|
36
48
|
args.push("--reason", reason);
|
|
37
49
|
}
|
|
50
|
+
if (repo) {
|
|
51
|
+
args.push("--repo", repo);
|
|
52
|
+
}
|
|
38
53
|
const result = await ghCmd(args, cwd);
|
|
54
|
+
// P1-gap #144: Detect already-closed issues instead of throwing
|
|
39
55
|
if (result.exitCode !== 0) {
|
|
56
|
+
const combined = `${result.stdout}\n${result.stderr}`;
|
|
57
|
+
const isAlreadyClosed = /already closed/i.test(combined) ||
|
|
58
|
+
/issue .* is already closed/i.test(combined) ||
|
|
59
|
+
/already been closed/i.test(combined);
|
|
60
|
+
if (isAlreadyClosed) {
|
|
61
|
+
// Return structured output with alreadyClosed flag
|
|
62
|
+
const data = parseIssueClose(result.stdout, issueNum, reason, comment, result.stderr);
|
|
63
|
+
return dualOutput(data, formatIssueClose);
|
|
64
|
+
}
|
|
40
65
|
throw new Error(`gh issue close failed: ${result.stderr}`);
|
|
41
66
|
}
|
|
42
|
-
|
|
67
|
+
// S-gap: Pass reason, comment, and stderr for echo in output
|
|
68
|
+
const data = parseIssueClose(result.stdout, issueNum, reason, comment, result.stderr);
|
|
43
69
|
return dualOutput(data, formatIssueClose);
|
|
44
70
|
});
|
|
45
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-close.js","sourceRoot":"","sources":["../../src/tools/issue-close.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,gEAAgE;AAChE,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,KAAK,EAAE,aAAa;QACpB,WAAW,EACT
|
|
1
|
+
{"version":3,"file":"issue-close.js","sourceRoot":"","sources":["../../src/tools/issue-close.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-comment.d.ts","sourceRoot":"","sources":["../../src/tools/issue-comment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,kEAAkE;AAClE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"issue-comment.d.ts","sourceRoot":"","sources":["../../src/tools/issue-comment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,kEAAkE;AAClE,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,QAqEzD"}
|
|
@@ -8,10 +8,28 @@ import { CommentResultSchema } from "../schemas/index.js";
|
|
|
8
8
|
export function registerIssueCommentTool(server) {
|
|
9
9
|
server.registerTool("issue-comment", {
|
|
10
10
|
title: "Issue Comment",
|
|
11
|
-
description: "Adds a comment
|
|
11
|
+
description: "Adds, edits, or deletes a comment on an issue. Returns structured data with the comment URL, operation type, comment ID, issue number, and body echo. Use instead of running `gh issue comment` in the terminal.",
|
|
12
12
|
inputSchema: {
|
|
13
|
-
number: z.
|
|
13
|
+
number: z.string().max(INPUT_LIMITS.STRING_MAX).describe("Issue number or URL"),
|
|
14
14
|
body: z.string().max(INPUT_LIMITS.STRING_MAX).describe("Comment text"),
|
|
15
|
+
editLast: z
|
|
16
|
+
.boolean()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Edit the last comment instead of creating a new one (--edit-last)"),
|
|
19
|
+
deleteLast: z
|
|
20
|
+
.boolean()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Delete the last comment (uses gh issue comment --delete-last)"),
|
|
23
|
+
createIfNone: z
|
|
24
|
+
.boolean()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("When used with editLast, create a new comment if no existing comment exists (--create-if-none)"),
|
|
27
|
+
// S-gap P1: Add repo for cross-repo commenting
|
|
28
|
+
repo: z
|
|
29
|
+
.string()
|
|
30
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
31
|
+
.optional()
|
|
32
|
+
.describe("Repository in OWNER/REPO format (default: current repo)"),
|
|
15
33
|
path: z
|
|
16
34
|
.string()
|
|
17
35
|
.max(INPUT_LIMITS.PATH_MAX)
|
|
@@ -19,15 +37,34 @@ export function registerIssueCommentTool(server) {
|
|
|
19
37
|
.describe("Repository path (default: cwd)"),
|
|
20
38
|
},
|
|
21
39
|
outputSchema: CommentResultSchema,
|
|
22
|
-
}, async ({ number, body, path }) => {
|
|
40
|
+
}, async ({ number, body, editLast, deleteLast, createIfNone, repo, path }) => {
|
|
23
41
|
const cwd = path || process.cwd();
|
|
24
|
-
|
|
25
|
-
|
|
42
|
+
if (repo)
|
|
43
|
+
assertNoFlagInjection(repo, "repo");
|
|
44
|
+
if (typeof number === "string")
|
|
45
|
+
assertNoFlagInjection(number, "number");
|
|
46
|
+
const selector = String(number);
|
|
47
|
+
const issueNum = typeof number === "number" ? number : 0;
|
|
48
|
+
const args = ["issue", "comment", selector, "--body-file", "-"];
|
|
49
|
+
if (editLast)
|
|
50
|
+
args.push("--edit-last");
|
|
51
|
+
if (deleteLast)
|
|
52
|
+
args.push("--delete-last");
|
|
53
|
+
if (createIfNone)
|
|
54
|
+
args.push("--create-if-none");
|
|
55
|
+
if (repo)
|
|
56
|
+
args.push("--repo", repo);
|
|
26
57
|
const result = await ghCmd(args, { cwd, stdin: body });
|
|
27
58
|
if (result.exitCode !== 0) {
|
|
28
59
|
throw new Error(`gh issue comment failed: ${result.stderr}`);
|
|
29
60
|
}
|
|
30
|
-
|
|
61
|
+
// S-gap: Determine operation type and pass context
|
|
62
|
+
const operation = deleteLast ? "delete" : editLast ? "edit" : "create";
|
|
63
|
+
const data = parseComment(result.stdout, {
|
|
64
|
+
operation: operation,
|
|
65
|
+
issueNumber: issueNum,
|
|
66
|
+
body,
|
|
67
|
+
});
|
|
31
68
|
return dualOutput(data, formatComment);
|
|
32
69
|
});
|
|
33
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-comment.js","sourceRoot":"","sources":["../../src/tools/issue-comment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,kEAAkE;AAClE,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"issue-comment.js","sourceRoot":"","sources":["../../src/tools/issue-comment.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-create.d.ts","sourceRoot":"","sources":["../../src/tools/issue-create.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,iEAAiE;AACjE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"issue-create.d.ts","sourceRoot":"","sources":["../../src/tools/issue-create.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,iEAAiE;AACjE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,QA0GxD"}
|
|
@@ -8,7 +8,7 @@ import { IssueCreateResultSchema } from "../schemas/index.js";
|
|
|
8
8
|
export function registerIssueCreateTool(server) {
|
|
9
9
|
server.registerTool("issue-create", {
|
|
10
10
|
title: "Issue Create",
|
|
11
|
-
description: "Creates a new issue. Returns structured data with issue number and
|
|
11
|
+
description: "Creates a new issue. Returns structured data with issue number, URL, and labels applied. Use instead of running `gh issue create` in the terminal.",
|
|
12
12
|
inputSchema: {
|
|
13
13
|
title: z.string().max(INPUT_LIMITS.SHORT_STRING_MAX).describe("Issue title"),
|
|
14
14
|
body: z.string().max(INPUT_LIMITS.STRING_MAX).describe("Issue body/description"),
|
|
@@ -17,6 +17,36 @@ export function registerIssueCreateTool(server) {
|
|
|
17
17
|
.max(INPUT_LIMITS.ARRAY_MAX)
|
|
18
18
|
.optional()
|
|
19
19
|
.describe("Labels to apply"),
|
|
20
|
+
// S-gap P0: Add assignees
|
|
21
|
+
assignees: z
|
|
22
|
+
.array(z.string().max(INPUT_LIMITS.SHORT_STRING_MAX))
|
|
23
|
+
.max(INPUT_LIMITS.ARRAY_MAX)
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Assignee usernames (-a/--assignee)"),
|
|
26
|
+
// S-gap P0: Add milestone
|
|
27
|
+
milestone: z
|
|
28
|
+
.string()
|
|
29
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
30
|
+
.optional()
|
|
31
|
+
.describe("Milestone name or number (-m/--milestone)"),
|
|
32
|
+
// S-gap P1: Add project
|
|
33
|
+
project: z
|
|
34
|
+
.string()
|
|
35
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Project board name (-p/--project)"),
|
|
38
|
+
// S-gap P1: Add template
|
|
39
|
+
template: z
|
|
40
|
+
.string()
|
|
41
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Issue template file name (--template)"),
|
|
44
|
+
// S-gap P1: Add repo for cross-repo creation
|
|
45
|
+
repo: z
|
|
46
|
+
.string()
|
|
47
|
+
.max(INPUT_LIMITS.SHORT_STRING_MAX)
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Repository in OWNER/REPO format (--repo). Default: current repo."),
|
|
20
50
|
path: z
|
|
21
51
|
.string()
|
|
22
52
|
.max(INPUT_LIMITS.PATH_MAX)
|
|
@@ -24,7 +54,7 @@ export function registerIssueCreateTool(server) {
|
|
|
24
54
|
.describe("Repository path (default: cwd)"),
|
|
25
55
|
},
|
|
26
56
|
outputSchema: IssueCreateResultSchema,
|
|
27
|
-
}, async ({ title, body, labels, path }) => {
|
|
57
|
+
}, async ({ title, body, labels, assignees, milestone, project, template, repo, path }) => {
|
|
28
58
|
const cwd = path || process.cwd();
|
|
29
59
|
assertNoFlagInjection(title, "title");
|
|
30
60
|
if (labels) {
|
|
@@ -32,17 +62,51 @@ export function registerIssueCreateTool(server) {
|
|
|
32
62
|
assertNoFlagInjection(label, "labels");
|
|
33
63
|
}
|
|
34
64
|
}
|
|
35
|
-
|
|
65
|
+
if (assignees) {
|
|
66
|
+
for (const assignee of assignees) {
|
|
67
|
+
assertNoFlagInjection(assignee, "assignees");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (milestone)
|
|
71
|
+
assertNoFlagInjection(milestone, "milestone");
|
|
72
|
+
if (project)
|
|
73
|
+
assertNoFlagInjection(project, "project");
|
|
74
|
+
if (template)
|
|
75
|
+
assertNoFlagInjection(template, "template");
|
|
76
|
+
if (repo)
|
|
77
|
+
assertNoFlagInjection(repo, "repo");
|
|
78
|
+
// Use --body-file - to pass body via stdin, avoiding shell escaping issues
|
|
79
|
+
// for long bodies with special characters
|
|
80
|
+
const args = ["issue", "create", "--title", title, "--body-file", "-"];
|
|
36
81
|
if (labels && labels.length > 0) {
|
|
37
82
|
for (const label of labels) {
|
|
38
83
|
args.push("--label", label);
|
|
39
84
|
}
|
|
40
85
|
}
|
|
41
|
-
|
|
86
|
+
// S-gap P0: Map assignees to --assignee flags
|
|
87
|
+
if (assignees && assignees.length > 0) {
|
|
88
|
+
for (const assignee of assignees) {
|
|
89
|
+
args.push("--assignee", assignee);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// S-gap P0: Map milestone to --milestone
|
|
93
|
+
if (milestone)
|
|
94
|
+
args.push("--milestone", milestone);
|
|
95
|
+
// S-gap P1: Map project to --project
|
|
96
|
+
if (project)
|
|
97
|
+
args.push("--project", project);
|
|
98
|
+
// S-gap P1: Map template to --template
|
|
99
|
+
if (template)
|
|
100
|
+
args.push("--template", template);
|
|
101
|
+
// S-gap P1: Map repo to --repo
|
|
102
|
+
if (repo)
|
|
103
|
+
args.push("--repo", repo);
|
|
104
|
+
const result = await ghCmd(args, { cwd, stdin: body });
|
|
42
105
|
if (result.exitCode !== 0) {
|
|
43
106
|
throw new Error(`gh issue create failed: ${result.stderr}`);
|
|
44
107
|
}
|
|
45
|
-
|
|
108
|
+
// S-gap: Pass labels for echo in output
|
|
109
|
+
const data = parseIssueCreate(result.stdout, labels);
|
|
46
110
|
return dualOutput(data, formatIssueCreate);
|
|
47
111
|
});
|
|
48
112
|
}
|