mcp-fs-shell-windows 0.2.20 → 0.2.29

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.
@@ -0,0 +1,97 @@
1
+ // compat/schema.ts — argument schemas for the 9 Beledarian-compatible alias tools.
2
+ // (MCP filesystem fork v0.2.28 — Beledarian-parity project, Stage 5 / task 3.)
3
+ //
4
+ // Purpose: same-named drop-ins for the Beledarian plugin tools so the fork can
5
+ // shadow/replace Beledarian with zero behavior change for existing prompts.
6
+ // Parameter names are kept EXACTLY as Beledarian's (reference:
7
+ // .beledarians-llm-toolbox/dev-src/beledarians-lm-studio-tools/src/toolsProvider.ts),
8
+ // plus the fork's own optional `cwd` where noted.
9
+ import { z } from "zod";
10
+ // ---------------------------------------------------------------------------
11
+ // Timeout caps.
12
+ //
13
+ // The fork's native shell tools cap at 28 s (SHELL_MAX_TIMEOUT_SEC) to stay under
14
+ // the MCP client's request-kill window. Beledarian's execute_command / run_python
15
+ // / run_javascript all cap at 60 s (verified: the client window is >63 s).
16
+ // To be a zero-behavior-change drop-in, the compat tools keep Beledarian's 60 s cap.
17
+ // ---------------------------------------------------------------------------
18
+ export const COMPAT_SYNC_TIMEOUT_SEC = 60; // execute_command, run_python, run_javascript
19
+ // ---------------------------------------------------------------------------
20
+ // execute_command — compat alias of shell_run (bounded synchronous execution),
21
+ // with Beledarian's 60 s cap. Params match Beledarian exactly:
22
+ // command, input?, timeout_seconds? (reference toolsProvider.ts L1155-1176).
23
+ // ---------------------------------------------------------------------------
24
+ export const ExecuteCommandArgsSchema = z.object({
25
+ command: z.string().describe("The shell command to execute (Windows cmd.exe syntax)."),
26
+ input: z.string().optional().describe("Input text to pipe to the command's stdin."),
27
+ timeout_seconds: z.number().min(0.1).max(COMPAT_SYNC_TIMEOUT_SEC).optional().describe("Timeout in seconds (default: 5, max: 60)."),
28
+ });
29
+ // ---------------------------------------------------------------------------
30
+ // run_in_terminal — compat alias of shell_terminal (visible console window).
31
+ // Params match Beledarian exactly: command (reference L1317-1332).
32
+ // ---------------------------------------------------------------------------
33
+ export const RunInTerminalArgsSchema = z.object({
34
+ command: z.string().describe("Command to run in the new terminal window."),
35
+ });
36
+ // ---------------------------------------------------------------------------
37
+ // run_test_command — compat alias of shell_test (test wrapper, CI=true, never
38
+ // errors on a failing test). Params match Beledarian exactly: command
39
+ // (reference L2303-2345).
40
+ // ---------------------------------------------------------------------------
41
+ export const RunTestCommandArgsSchema = z.object({
42
+ command: z.string().describe("The test command to run (e.g. 'npm test', 'pytest')."),
43
+ });
44
+ // ---------------------------------------------------------------------------
45
+ // run_background_command — compat alias of shell_start (background job).
46
+ // Beledarian: command, timeout_hours (MANDATORY, max 10), name (MANDATORY)
47
+ // (reference L930-1010). Fork variant: name stays REQUIRED (as in Beledarian),
48
+ // timeout_hours gets the fork's default of 10 (max 10), and the fork's cwd
49
+ // override is available.
50
+ // ---------------------------------------------------------------------------
51
+ export const RunBackgroundCommandArgsSchema = z.object({
52
+ command: z.string().describe("The command to run as a background job (Windows cmd.exe syntax)."),
53
+ name: z.string().describe("MANDATORY: A short, descriptive name for the background task (e.g. 'Vite Dev Server')."),
54
+ timeout_hours: z.number().max(10).optional().default(10).describe("Auto-kill the job after this many hours (default 10, max 10)."),
55
+ cwd: z.string().optional().describe("Working directory override (default: the shell_cwd default)."),
56
+ });
57
+ // ---------------------------------------------------------------------------
58
+ // check_background_command — compat alias of shell_check.
59
+ // Params match Beledarian exactly: id (reference L1013-1033).
60
+ // ---------------------------------------------------------------------------
61
+ export const CheckBackgroundCommandArgsSchema = z.object({
62
+ id: z.string().describe("Job ID returned by run_background_command or run_in_terminal."),
63
+ });
64
+ // ---------------------------------------------------------------------------
65
+ // cancel_background_command — compat alias of shell_cancel.
66
+ // Params match Beledarian exactly: id (reference L1036-1054).
67
+ // ---------------------------------------------------------------------------
68
+ export const CancelBackgroundCommandArgsSchema = z.object({
69
+ id: z.string().describe("Job ID returned by run_background_command or run_in_terminal."),
70
+ });
71
+ // ---------------------------------------------------------------------------
72
+ // run_python — compat alias of shell_python (temp .py + system python),
73
+ // with Beledarian's 60 s cap. Beledarian params: python, timeout_seconds?
74
+ // (reference L692-712); the fork's cwd override is available.
75
+ // ---------------------------------------------------------------------------
76
+ export const RunPythonArgsSchema = z.object({
77
+ python: z.string().describe("Python code to execute (requires system Python on PATH)."),
78
+ timeout_seconds: z.number().min(0.1).max(COMPAT_SYNC_TIMEOUT_SEC).optional().describe("Timeout in seconds (default: 5, max: 60)."),
79
+ cwd: z.string().optional().describe("Working directory override (default: the shell_cwd default)."),
80
+ });
81
+ // ---------------------------------------------------------------------------
82
+ // run_javascript — the CONFINED variant (NOT an alias of run_javascript_free).
83
+ // Beledarian params: javascript, timeout_seconds? (reference L612-633, impl
84
+ // L544-610). No cwd param (the reference confines to its working directory,
85
+ // which is the fork's shell_cwd default here).
86
+ // ---------------------------------------------------------------------------
87
+ export const RunJavascriptArgsSchema = z.object({
88
+ javascript: z.string().describe("JavaScript (or TypeScript) code to execute. Runs as a Deno script confined to the working directory: Deno.* APIs and console.log work; network, env, sys, run, and ffi are denied."),
89
+ timeout_seconds: z.number().min(0.1).max(COMPAT_SYNC_TIMEOUT_SEC).optional().describe("Timeout in seconds (default: 5, max: 60)."),
90
+ });
91
+ // ---------------------------------------------------------------------------
92
+ // save_memory — STANDALONE (no fork equivalent; not an alias).
93
+ // Beledarian param: fact (reference L509-542).
94
+ // ---------------------------------------------------------------------------
95
+ export const SaveMemoryArgsSchema = z.object({
96
+ fact: z.string().describe("The specific fact or piece of information to remember."),
97
+ });
@@ -0,0 +1,406 @@
1
+ // gh/handler.ts — gh CLI wrappers for the 8 gh_* tools (MCP filesystem fork).
2
+ //
3
+ // Design: spawn the `gh` binary directly (no new dependency; `git push` for
4
+ // gh_push spawns the git CLI). Every tool operates against the repo at the
5
+ // server process's current working directory (process.cwd()) — the same
6
+ // "current working directory context" the git/shell tools use — and takes NO
7
+ // working-directory parameter (matching the reference Beledarian tools: the
8
+ // reference's gh spawns inherit the plugin process cwd, and gh itself resolves
9
+ // the repo from that cwd's git remote). All argument values (titles, bodies,
10
+ // labels, branch names, issue/PR numbers) are passed as individual argv
11
+ // elements (no shell), so quotes / Unicode / special characters pass through
12
+ // verbatim. Long issue/PR bodies are written to a temp file in the working
13
+ // directory and passed via --body-file (mirroring the reference); the temp
14
+ // file is always removed afterwards.
15
+ //
16
+ // gh binary resolution (port of the reference's checkGhInstalled, with a
17
+ // documented fallback): PATH lookup via `where gh` (win32) / `which gh` first;
18
+ // if gh is not on the server process's PATH, fall back to the known portable
19
+ // install <home>/tools/gh/bin/gh.exe (this machine's layout — gh 2.99.0,
20
+ // authenticated to github.com). If neither is found, the reference's
21
+ // "not installed" error string is returned.
22
+ //
23
+ // gh_auth: runs `gh auth status`; on failure it opens a detached terminal
24
+ // window (cmd /k) for interactive `gh auth login --git-protocol=https` exactly
25
+ // as the reference does — spawned with {detached: true, stdio: "ignore"} so it
26
+ // survives the MCP call returning, using the RESOLVED gh path so the window
27
+ // works even when gh is not on the inherited PATH. The window persists for the
28
+ // user (cmd /k) and can be closed manually.
29
+ //
30
+ // Return shape mirrors the reference implementation: each handler returns a JSON
31
+ // text string carrying the reference's fields ({success, ...} / {error} /
32
+ // {issues} / {pull_requests} / {comments} / {diff} / raw_output) instead of
33
+ // throwing, so a missing gh, a bad remote, or a bad branch yields a clear
34
+ // structured error string rather than a crash or hang.
35
+ import { spawn } from "child_process";
36
+ import fs from "fs";
37
+ import nodeOs from "os";
38
+ import nodePath from "path";
39
+ /** Run `<bin> <args>` with the given cwd. Never rejects; spawn failures resolve with code -1. */
40
+ function runCmd(bin, args, cwd) {
41
+ return new Promise((resolve) => {
42
+ let child;
43
+ try {
44
+ child = spawn(bin, args, { cwd });
45
+ }
46
+ catch (e) {
47
+ resolve({ code: -1, stdout: "", stderr: e instanceof Error ? e.message : String(e) });
48
+ return;
49
+ }
50
+ let stdout = "";
51
+ let stderr = "";
52
+ let settled = false;
53
+ const finish = (code) => {
54
+ if (settled)
55
+ return;
56
+ settled = true;
57
+ resolve({ code, stdout, stderr });
58
+ };
59
+ if (child.stdout) {
60
+ child.stdout.on("data", (d) => {
61
+ stdout += d.toString("utf8");
62
+ });
63
+ }
64
+ if (child.stderr) {
65
+ child.stderr.on("data", (d) => {
66
+ stderr += d.toString("utf8");
67
+ });
68
+ }
69
+ child.on("error", (e) => {
70
+ // e.g. ENOENT when the binary cannot be found
71
+ stderr += (stderr ? "\n" : "") + (e.message || String(e));
72
+ finish(-1);
73
+ });
74
+ child.on("close", (code) => finish(code === null ? -1 : code));
75
+ });
76
+ }
77
+ /** Run a shell one-liner (e.g. `where gh`). Never rejects. */
78
+ function runShellLine(cmd) {
79
+ return new Promise((resolve) => {
80
+ let child;
81
+ try {
82
+ child = spawn(cmd, [], { shell: true });
83
+ }
84
+ catch (e) {
85
+ resolve({ code: -1, stdout: "", stderr: e instanceof Error ? e.message : String(e) });
86
+ return;
87
+ }
88
+ let stdout = "";
89
+ let stderr = "";
90
+ let settled = false;
91
+ const finish = (code) => {
92
+ if (settled)
93
+ return;
94
+ settled = true;
95
+ resolve({ code, stdout, stderr });
96
+ };
97
+ if (child.stdout) {
98
+ child.stdout.on("data", (d) => {
99
+ stdout += d.toString("utf8");
100
+ });
101
+ }
102
+ if (child.stderr) {
103
+ child.stderr.on("data", (d) => {
104
+ stderr += d.toString("utf8");
105
+ });
106
+ }
107
+ child.on("error", (e) => {
108
+ stderr += (stderr ? "\n" : "") + (e.message || String(e));
109
+ finish(-1);
110
+ });
111
+ child.on("close", (code) => finish(code === null ? -1 : code));
112
+ });
113
+ }
114
+ const GH_NOT_INSTALLED = "GitHub CLI ('gh') is not installed. Please ask the user to install it from https://cli.github.com/";
115
+ /** Absolute path of gh on the PATH (first hit of `where gh` / `which gh`), or null. */
116
+ async function findGhOnPath() {
117
+ const r = await runShellLine(process.platform === "win32" ? "where gh" : "which gh");
118
+ if (!r.stdout.trim())
119
+ return null;
120
+ const first = r.stdout
121
+ .split(/\r?\n/)
122
+ .map((s) => s.trim())
123
+ .find((s) => s.length > 0);
124
+ if (!first)
125
+ return null;
126
+ try {
127
+ if (fs.existsSync(first))
128
+ return first;
129
+ }
130
+ catch {
131
+ // fall through
132
+ }
133
+ return null;
134
+ }
135
+ /** Known portable-install locations, checked in order (documented fallback). */
136
+ function findGhKnownPaths() {
137
+ const home = nodeOs.homedir();
138
+ const candidates = [nodePath.join(home, "tools", "gh", "bin", "gh.exe")];
139
+ for (const c of candidates) {
140
+ try {
141
+ if (fs.existsSync(c))
142
+ return c;
143
+ }
144
+ catch {
145
+ // ignore
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+ /** Resolve the gh executable (absolute path): PATH first, then known portable install; null if absent. */
151
+ async function resolveGh() {
152
+ const onPath = await findGhOnPath();
153
+ if (onPath)
154
+ return onPath;
155
+ return findGhKnownPaths();
156
+ }
157
+ /** The repo context for all gh_* tools: the server process's current working directory. */
158
+ function ghCwd() {
159
+ return process.cwd();
160
+ }
161
+ /** Detail text for a non-zero exit: stderr first, then stdout, then the exit code. */
162
+ function detail(out) {
163
+ return out.stderr.trim() || out.stdout.trim() || `gh exited with code ${out.code}`;
164
+ }
165
+ // ---------------------------------------------------------------- gh_auth
166
+ export async function handleGhAuth() {
167
+ const dir = ghCwd();
168
+ const ghBin = await resolveGh();
169
+ if (!ghBin)
170
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
171
+ try {
172
+ const st = await runCmd(ghBin, ["auth", "status"], dir);
173
+ if (st.code === 0) {
174
+ return JSON.stringify({ success: true, message: "Already authenticated with GitHub." });
175
+ }
176
+ // Not authenticated: open a detached terminal window for interactive login,
177
+ // exactly as the reference does. The window is spawned detached with ignored
178
+ // stdio so it outlives this call; cmd /k keeps it open for the user.
179
+ // The resolved absolute gh path is used so the window works even when gh is
180
+ // not on the server process's PATH.
181
+ const escapedDir = dir.replace(/"/g, '""');
182
+ const shellCommand = `start "" /D "${escapedDir}" cmd.exe /k "${ghBin} auth login --git-protocol=https & exit"`;
183
+ try {
184
+ spawn("cmd.exe", ["/c", shellCommand], { detached: true, stdio: "ignore", cwd: dir });
185
+ }
186
+ catch (e) {
187
+ return JSON.stringify({
188
+ error: `Auth check failed: ${e instanceof Error ? e.message : String(e)}`,
189
+ });
190
+ }
191
+ return JSON.stringify({
192
+ success: true,
193
+ message: "Opened a terminal window for GitHub authentication. Please sign in there.",
194
+ });
195
+ }
196
+ catch (e) {
197
+ return JSON.stringify({ error: `Auth check failed: ${e instanceof Error ? e.message : String(e)}` });
198
+ }
199
+ }
200
+ // ----------------------------------------------------------- gh_create_issue
201
+ export async function handleGhCreateIssue(title, body, labels) {
202
+ const dir = ghCwd();
203
+ const ghBin = await resolveGh();
204
+ if (!ghBin)
205
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
206
+ try {
207
+ let tempFilePath = "";
208
+ const ghArgs = ["issue", "create", "--title", title];
209
+ if (body) {
210
+ tempFilePath = nodePath.join(dir, `gh_issue_body_${Date.now()}.md`);
211
+ fs.writeFileSync(tempFilePath, body, "utf-8");
212
+ ghArgs.push("--body-file", tempFilePath);
213
+ }
214
+ if (labels) {
215
+ for (const label of labels) {
216
+ ghArgs.push("-l", label);
217
+ }
218
+ }
219
+ const out = await runCmd(ghBin, ghArgs, dir);
220
+ if (tempFilePath) {
221
+ try {
222
+ fs.rmSync(tempFilePath, { force: true });
223
+ }
224
+ catch {
225
+ // best-effort cleanup
226
+ }
227
+ }
228
+ if (out.code === 0)
229
+ return JSON.stringify({ success: true, url: out.stdout.trim() });
230
+ return JSON.stringify({ error: `Failed to create issue: ${detail(out)}` });
231
+ }
232
+ catch (e) {
233
+ return JSON.stringify({ error: `Create issue failed: ${e instanceof Error ? e.message : String(e)}` });
234
+ }
235
+ }
236
+ // ------------------------------------------------------------ gh_list_issues
237
+ export async function handleGhListIssues(state, labels, limit) {
238
+ const dir = ghCwd();
239
+ const ghBin = await resolveGh();
240
+ if (!ghBin)
241
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
242
+ const st = state ?? "open";
243
+ const lim = typeof limit === "number" && Number.isFinite(limit) && limit >= 1
244
+ ? Math.min(50, Math.floor(limit))
245
+ : 10;
246
+ try {
247
+ const ghArgs = [
248
+ "issue",
249
+ "list",
250
+ "--state",
251
+ st,
252
+ "--limit",
253
+ String(lim),
254
+ "--json",
255
+ "number,title,state,url,labels",
256
+ ];
257
+ if (labels) {
258
+ for (const label of labels) {
259
+ ghArgs.push("-l", label);
260
+ }
261
+ }
262
+ const out = await runCmd(ghBin, ghArgs, dir);
263
+ if (out.code === 0) {
264
+ try {
265
+ return JSON.stringify({ issues: JSON.parse(out.stdout) });
266
+ }
267
+ catch {
268
+ return JSON.stringify({ error: "Failed to parse issue list output" });
269
+ }
270
+ }
271
+ return JSON.stringify({ error: `List issues failed: ${detail(out)}` });
272
+ }
273
+ catch (e) {
274
+ return JSON.stringify({ error: `List issues failed: ${e instanceof Error ? e.message : String(e)}` });
275
+ }
276
+ }
277
+ // ---------------------------------------------------------- gh_view_comments
278
+ export async function handleGhViewComments(number, type) {
279
+ const dir = ghCwd();
280
+ const ghBin = await resolveGh();
281
+ if (!ghBin)
282
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
283
+ try {
284
+ // Fallback to standard gh command for reliable JSON parsing of comments
285
+ const ghArgs = type === "pr"
286
+ ? ["pr", "view", String(number), "--json", "comments"]
287
+ : ["issue", "view", String(number), "--json", "comments"];
288
+ const out = await runCmd(ghBin, ghArgs, dir);
289
+ if (out.code === 0) {
290
+ try {
291
+ const data = JSON.parse(out.stdout);
292
+ return JSON.stringify({ comments: data.comments || [] });
293
+ }
294
+ catch {
295
+ return JSON.stringify({ raw_output: out.stdout });
296
+ }
297
+ }
298
+ return JSON.stringify({ error: `View comments failed: ${detail(out)}` });
299
+ }
300
+ catch (e) {
301
+ return JSON.stringify({ error: `View comments failed: ${e instanceof Error ? e.message : String(e)}` });
302
+ }
303
+ }
304
+ // ------------------------------------------------------------- gh_create_pr
305
+ export async function handleGhCreatePr(title, body, head_branch, base_branch) {
306
+ const dir = ghCwd();
307
+ const ghBin = await resolveGh();
308
+ if (!ghBin)
309
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
310
+ const base = base_branch || "main";
311
+ try {
312
+ let tempFilePath = "";
313
+ const ghArgs = ["pr", "create", "--title", title, "--head", head_branch, "--base", base];
314
+ if (body) {
315
+ tempFilePath = nodePath.join(dir, `gh_pr_body_${Date.now()}.md`);
316
+ fs.writeFileSync(tempFilePath, body, "utf-8");
317
+ ghArgs.push("--body-file", tempFilePath);
318
+ }
319
+ const out = await runCmd(ghBin, ghArgs, dir);
320
+ if (tempFilePath) {
321
+ try {
322
+ fs.rmSync(tempFilePath, { force: true });
323
+ }
324
+ catch {
325
+ // best-effort cleanup
326
+ }
327
+ }
328
+ if (out.code === 0)
329
+ return JSON.stringify({ success: true, url: out.stdout.trim() });
330
+ return JSON.stringify({ error: `Failed to create PR: ${detail(out)}` });
331
+ }
332
+ catch (e) {
333
+ return JSON.stringify({ error: `Create PR failed: ${e instanceof Error ? e.message : String(e)}` });
334
+ }
335
+ }
336
+ // -------------------------------------------------------------- gh_list_prs
337
+ export async function handleGhListPrs(state, limit) {
338
+ const dir = ghCwd();
339
+ const ghBin = await resolveGh();
340
+ if (!ghBin)
341
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
342
+ const st = state ?? "open";
343
+ const lim = typeof limit === "number" && Number.isFinite(limit) && limit >= 1
344
+ ? Math.min(50, Math.floor(limit))
345
+ : 10;
346
+ try {
347
+ const ghArgs = [
348
+ "pr",
349
+ "list",
350
+ "--state",
351
+ st,
352
+ "--limit",
353
+ String(lim),
354
+ "--json",
355
+ "number,title,state,url,headRefName,baseRefName",
356
+ ];
357
+ const out = await runCmd(ghBin, ghArgs, dir);
358
+ if (out.code === 0) {
359
+ try {
360
+ return JSON.stringify({ pull_requests: JSON.parse(out.stdout) });
361
+ }
362
+ catch {
363
+ return JSON.stringify({ error: "Failed to parse PR list output" });
364
+ }
365
+ }
366
+ return JSON.stringify({ error: `List PRs failed: ${detail(out)}` });
367
+ }
368
+ catch (e) {
369
+ return JSON.stringify({ error: `List PRs failed: ${e instanceof Error ? e.message : String(e)}` });
370
+ }
371
+ }
372
+ // ---------------------------------------------------------- gh_view_pr_diff
373
+ export async function handleGhViewPrDiff(number) {
374
+ const dir = ghCwd();
375
+ const ghBin = await resolveGh();
376
+ if (!ghBin)
377
+ return JSON.stringify({ error: GH_NOT_INSTALLED });
378
+ try {
379
+ const out = await runCmd(ghBin, ["pr", "diff", String(number)], dir);
380
+ if (out.code === 0) {
381
+ return JSON.stringify({
382
+ diff: out.stdout.substring(0, 50000) + (out.stdout.length > 50000 ? "\n... (truncated)" : ""),
383
+ });
384
+ }
385
+ return JSON.stringify({ error: `Fetch PR diff failed: ${detail(out)}` });
386
+ }
387
+ catch (e) {
388
+ return JSON.stringify({ error: `Fetch PR diff failed: ${e instanceof Error ? e.message : String(e)}` });
389
+ }
390
+ }
391
+ // ----------------------------------------------------------------- gh_push
392
+ export async function handleGhPush(branch) {
393
+ const dir = ghCwd();
394
+ try {
395
+ const gitArgs = ["push", "origin"];
396
+ if (branch)
397
+ gitArgs.push(branch);
398
+ const out = await runCmd("git", gitArgs, dir);
399
+ if (out.code === 0)
400
+ return JSON.stringify({ success: true, message: "Pushed successfully." });
401
+ return JSON.stringify({ error: `Git push failed: ${detail(out)}` });
402
+ }
403
+ catch (e) {
404
+ return JSON.stringify({ error: `Git push failed: ${e instanceof Error ? e.message : String(e)}` });
405
+ }
406
+ }
@@ -0,0 +1,36 @@
1
+ // gh/schema.ts — argument schemas for the 8 gh_* tools.
2
+ // (MCP filesystem fork; thin gh CLI wrappers that operate against the repo at the
3
+ // server process's current working directory — no working-directory parameter, same
4
+ // "current working directory context" as the git/shell tools.)
5
+ import { z } from "zod";
6
+ export const GhAuthArgsSchema = z.object({});
7
+ export const GhCreateIssueArgsSchema = z.object({
8
+ title: z.string(),
9
+ body: z.string().optional(),
10
+ labels: z.array(z.string()).optional(),
11
+ });
12
+ export const GhListIssuesArgsSchema = z.object({
13
+ state: z.enum(["open", "closed"]).optional().default("open"),
14
+ labels: z.array(z.string()).optional(),
15
+ limit: z.number().min(1).max(50).optional().default(10),
16
+ });
17
+ export const GhViewCommentsArgsSchema = z.object({
18
+ number: z.number().describe("The issue or PR number"),
19
+ type: z.enum(["issue", "pr"]).default("issue").describe("Whether it's an issue or a pull request"),
20
+ });
21
+ export const GhCreatePrArgsSchema = z.object({
22
+ title: z.string(),
23
+ body: z.string().optional(),
24
+ head_branch: z.string().describe("The branch containing your changes"),
25
+ base_branch: z.string().default("main").describe("The branch you want to merge into (e.g., main, master)"),
26
+ });
27
+ export const GhListPrsArgsSchema = z.object({
28
+ state: z.enum(["open", "closed"]).optional().default("open"),
29
+ limit: z.number().min(1).max(50).optional().default(10),
30
+ });
31
+ export const GhViewPrDiffArgsSchema = z.object({
32
+ number: z.number().describe("The PR number"),
33
+ });
34
+ export const GhPushArgsSchema = z.object({
35
+ branch: z.string().optional().describe("Optional: The branch to push. Defaults to current branch."),
36
+ });