@opentabs-dev/opentabs-plugin-github 0.0.76 → 0.0.77

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.
Files changed (142) hide show
  1. package/README.md +75 -129
  2. package/dist/adapter.iife.js +1149 -663
  3. package/dist/adapter.iife.js.map +4 -4
  4. package/dist/github-api.d.ts +16 -10
  5. package/dist/github-api.d.ts.map +1 -1
  6. package/dist/github-api.js +314 -112
  7. package/dist/github-api.js.map +1 -1
  8. package/dist/tools/add-reaction.d.ts +5 -9
  9. package/dist/tools/add-reaction.d.ts.map +1 -1
  10. package/dist/tools/add-reaction.js +29 -31
  11. package/dist/tools/add-reaction.js.map +1 -1
  12. package/dist/tools/compare-commits.d.ts +2 -8
  13. package/dist/tools/compare-commits.d.ts.map +1 -1
  14. package/dist/tools/compare-commits.js +32 -34
  15. package/dist/tools/compare-commits.js.map +1 -1
  16. package/dist/tools/create-comment.d.ts +1 -8
  17. package/dist/tools/create-comment.d.ts.map +1 -1
  18. package/dist/tools/create-comment.js +21 -5
  19. package/dist/tools/create-comment.js.map +1 -1
  20. package/dist/tools/create-issue.d.ts +0 -2
  21. package/dist/tools/create-issue.d.ts.map +1 -1
  22. package/dist/tools/create-issue.js +32 -15
  23. package/dist/tools/create-issue.js.map +1 -1
  24. package/dist/tools/create-label.d.ts.map +1 -1
  25. package/dist/tools/create-label.js +20 -12
  26. package/dist/tools/create-label.js.map +1 -1
  27. package/dist/tools/create-or-update-file.d.ts +1 -4
  28. package/dist/tools/create-or-update-file.d.ts.map +1 -1
  29. package/dist/tools/create-or-update-file.js +23 -23
  30. package/dist/tools/create-or-update-file.js.map +1 -1
  31. package/dist/tools/create-pull-request.d.ts.map +1 -1
  32. package/dist/tools/create-pull-request.js +37 -16
  33. package/dist/tools/create-pull-request.js.map +1 -1
  34. package/dist/tools/create-release.d.ts.map +1 -1
  35. package/dist/tools/create-release.js +29 -19
  36. package/dist/tools/create-release.js.map +1 -1
  37. package/dist/tools/create-repo.d.ts.map +1 -1
  38. package/dist/tools/create-repo.js +33 -18
  39. package/dist/tools/create-repo.js.map +1 -1
  40. package/dist/tools/delete-file.d.ts +1 -6
  41. package/dist/tools/delete-file.d.ts.map +1 -1
  42. package/dist/tools/delete-file.js +8 -25
  43. package/dist/tools/delete-file.js.map +1 -1
  44. package/dist/tools/get-file-content.d.ts.map +1 -1
  45. package/dist/tools/get-file-content.js +5 -9
  46. package/dist/tools/get-file-content.js.map +1 -1
  47. package/dist/tools/get-issue.d.ts.map +1 -1
  48. package/dist/tools/get-issue.js +25 -4
  49. package/dist/tools/get-issue.js.map +1 -1
  50. package/dist/tools/get-pull-request-diff.d.ts.map +1 -1
  51. package/dist/tools/get-pull-request-diff.js +19 -5
  52. package/dist/tools/get-pull-request-diff.js.map +1 -1
  53. package/dist/tools/get-pull-request.d.ts.map +1 -1
  54. package/dist/tools/get-pull-request.js +32 -3
  55. package/dist/tools/get-pull-request.js.map +1 -1
  56. package/dist/tools/get-repo.d.ts.map +1 -1
  57. package/dist/tools/get-repo.js +21 -4
  58. package/dist/tools/get-repo.js.map +1 -1
  59. package/dist/tools/get-user-profile.d.ts.map +1 -1
  60. package/dist/tools/get-user-profile.js +15 -2
  61. package/dist/tools/get-user-profile.js.map +1 -1
  62. package/dist/tools/get-workflow-run.d.ts.map +1 -1
  63. package/dist/tools/get-workflow-run.js +28 -5
  64. package/dist/tools/get-workflow-run.js.map +1 -1
  65. package/dist/tools/list-branches.d.ts +0 -2
  66. package/dist/tools/list-branches.d.ts.map +1 -1
  67. package/dist/tools/list-branches.js +3 -9
  68. package/dist/tools/list-branches.js.map +1 -1
  69. package/dist/tools/list-comments.d.ts +0 -2
  70. package/dist/tools/list-comments.d.ts.map +1 -1
  71. package/dist/tools/list-comments.js +33 -10
  72. package/dist/tools/list-comments.js.map +1 -1
  73. package/dist/tools/list-commits.d.ts +0 -2
  74. package/dist/tools/list-commits.d.ts.map +1 -1
  75. package/dist/tools/list-commits.js +8 -13
  76. package/dist/tools/list-commits.js.map +1 -1
  77. package/dist/tools/list-issues.d.ts +2 -2
  78. package/dist/tools/list-issues.d.ts.map +1 -1
  79. package/dist/tools/list-issues.js +43 -16
  80. package/dist/tools/list-issues.js.map +1 -1
  81. package/dist/tools/list-labels.d.ts +0 -2
  82. package/dist/tools/list-labels.d.ts.map +1 -1
  83. package/dist/tools/list-labels.js +18 -10
  84. package/dist/tools/list-labels.js.map +1 -1
  85. package/dist/tools/list-notifications.d.ts +1 -6
  86. package/dist/tools/list-notifications.d.ts.map +1 -1
  87. package/dist/tools/list-notifications.js +30 -23
  88. package/dist/tools/list-notifications.js.map +1 -1
  89. package/dist/tools/list-org-members.d.ts +0 -3
  90. package/dist/tools/list-org-members.d.ts.map +1 -1
  91. package/dist/tools/list-org-members.js +24 -18
  92. package/dist/tools/list-org-members.js.map +1 -1
  93. package/dist/tools/list-pull-request-files.d.ts +0 -3
  94. package/dist/tools/list-pull-request-files.d.ts.map +1 -1
  95. package/dist/tools/list-pull-request-files.js +6 -28
  96. package/dist/tools/list-pull-request-files.js.map +1 -1
  97. package/dist/tools/list-pull-requests.d.ts +2 -4
  98. package/dist/tools/list-pull-requests.d.ts.map +1 -1
  99. package/dist/tools/list-pull-requests.js +34 -18
  100. package/dist/tools/list-pull-requests.js.map +1 -1
  101. package/dist/tools/list-releases.d.ts +0 -2
  102. package/dist/tools/list-releases.d.ts.map +1 -1
  103. package/dist/tools/list-releases.js +37 -10
  104. package/dist/tools/list-releases.js.map +1 -1
  105. package/dist/tools/list-repos.d.ts +0 -7
  106. package/dist/tools/list-repos.d.ts.map +1 -1
  107. package/dist/tools/list-repos.js +18 -23
  108. package/dist/tools/list-repos.js.map +1 -1
  109. package/dist/tools/list-workflow-runs.d.ts +0 -21
  110. package/dist/tools/list-workflow-runs.d.ts.map +1 -1
  111. package/dist/tools/list-workflow-runs.js +32 -43
  112. package/dist/tools/list-workflow-runs.js.map +1 -1
  113. package/dist/tools/merge-pull-request.d.ts +1 -3
  114. package/dist/tools/merge-pull-request.d.ts.map +1 -1
  115. package/dist/tools/merge-pull-request.js +11 -15
  116. package/dist/tools/merge-pull-request.js.map +1 -1
  117. package/dist/tools/request-pull-request-review.d.ts +1 -21
  118. package/dist/tools/request-pull-request-review.d.ts.map +1 -1
  119. package/dist/tools/request-pull-request-review.js +17 -10
  120. package/dist/tools/request-pull-request-review.js.map +1 -1
  121. package/dist/tools/schemas.d.ts +130 -38
  122. package/dist/tools/schemas.d.ts.map +1 -1
  123. package/dist/tools/schemas.js +140 -52
  124. package/dist/tools/schemas.js.map +1 -1
  125. package/dist/tools/search-issues.d.ts +0 -13
  126. package/dist/tools/search-issues.d.ts.map +1 -1
  127. package/dist/tools/search-issues.js +23 -17
  128. package/dist/tools/search-issues.js.map +1 -1
  129. package/dist/tools/search-repos.d.ts +0 -10
  130. package/dist/tools/search-repos.d.ts.map +1 -1
  131. package/dist/tools/search-repos.js +7 -12
  132. package/dist/tools/search-repos.js.map +1 -1
  133. package/dist/tools/update-issue.d.ts +2 -18
  134. package/dist/tools/update-issue.d.ts.map +1 -1
  135. package/dist/tools/update-issue.js +19 -16
  136. package/dist/tools/update-issue.js.map +1 -1
  137. package/dist/tools/update-pull-request.d.ts +2 -24
  138. package/dist/tools/update-pull-request.d.ts.map +1 -1
  139. package/dist/tools/update-pull-request.js +28 -20
  140. package/dist/tools/update-pull-request.js.map +1 -1
  141. package/dist/tools.json +70 -747
  142. package/package.json +10 -4
@@ -6,6 +6,9 @@
6
6
  __defProp(target, name, { get: all[name], enumerable: true });
7
7
  };
8
8
 
9
+ // node_modules/@opentabs-dev/shared/dist/error.js
10
+ var toErrorMessage = (err2) => err2 instanceof Error ? err2.message : String(err2);
11
+
9
12
  // node_modules/@opentabs-dev/plugin-sdk/dist/errors.js
10
13
  var ToolError = class _ToolError extends Error {
11
14
  code;
@@ -62,6 +65,36 @@
62
65
  };
63
66
 
64
67
  // node_modules/@opentabs-dev/plugin-sdk/dist/fetch.js
68
+ var MAX_ERROR_BODY_LENGTH = 512;
69
+ var httpStatusToToolError = (response, message) => {
70
+ const status = response.status;
71
+ if (status === 401 || status === 403) {
72
+ return ToolError.auth(message);
73
+ }
74
+ if (status === 404) {
75
+ return ToolError.notFound(message);
76
+ }
77
+ if (status === 429) {
78
+ const retryAfter = response.headers.get("Retry-After");
79
+ const retryAfterMs = retryAfter !== null ? parseRetryAfterMs(retryAfter) : void 0;
80
+ return ToolError.rateLimited(message, retryAfterMs);
81
+ }
82
+ if (status === 400 || status === 422) {
83
+ return ToolError.validation(message);
84
+ }
85
+ if (status === 408) {
86
+ return ToolError.timeout(message);
87
+ }
88
+ if (status >= 500) {
89
+ const retryAfter = status === 503 ? response.headers.get("Retry-After") : null;
90
+ const retryAfterMs = retryAfter !== null ? parseRetryAfterMs(retryAfter) : void 0;
91
+ return new ToolError(message, "http_error", { category: "internal", retryable: true, retryAfterMs });
92
+ }
93
+ if (status >= 400 && status < 500) {
94
+ return new ToolError(message, "http_error", { retryable: false });
95
+ }
96
+ return new ToolError(message, "http_error", { category: "internal" });
97
+ };
65
98
  var parseRetryAfterMs = (value) => {
66
99
  const seconds = Number(value);
67
100
  if (!Number.isNaN(seconds) && seconds >= 0) {
@@ -74,6 +107,59 @@
74
107
  }
75
108
  return void 0;
76
109
  };
110
+ var buildQueryString = (params) => {
111
+ const searchParams = new URLSearchParams();
112
+ for (const [key, value] of Object.entries(params)) {
113
+ if (value === void 0)
114
+ continue;
115
+ if (Array.isArray(value)) {
116
+ for (const item of value) {
117
+ searchParams.append(key, String(item));
118
+ }
119
+ } else {
120
+ searchParams.append(key, String(value));
121
+ }
122
+ }
123
+ return searchParams.toString();
124
+ };
125
+ var fetchFromPage = async (url2, init) => {
126
+ const { timeout = 3e4, signal, ...rest } = init ?? {};
127
+ const timeoutSignal = AbortSignal.timeout(timeout);
128
+ const combinedSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
129
+ let response;
130
+ try {
131
+ response = await fetch(url2, {
132
+ credentials: "include",
133
+ ...rest,
134
+ signal: combinedSignal
135
+ });
136
+ } catch (error48) {
137
+ if (error48 instanceof DOMException && error48.name === "TimeoutError") {
138
+ throw ToolError.timeout(`fetchFromPage: request timed out after ${timeout}ms for ${url2}`);
139
+ }
140
+ if (combinedSignal.aborted) {
141
+ throw new ToolError(`fetchFromPage: request aborted for ${url2}`, "aborted");
142
+ }
143
+ throw new ToolError(`fetchFromPage: network error for ${url2}: ${toErrorMessage(error48)}`, "network_error", {
144
+ category: "internal",
145
+ retryable: true
146
+ });
147
+ }
148
+ if (!response.ok) {
149
+ const rawText = await response.text().catch(() => response.statusText);
150
+ const errorText = rawText.length > MAX_ERROR_BODY_LENGTH ? `${rawText.slice(0, MAX_ERROR_BODY_LENGTH)}\u2026` : rawText;
151
+ const msg = `fetchFromPage: HTTP ${response.status} for ${url2}: ${errorText}`;
152
+ throw httpStatusToToolError(response, msg);
153
+ }
154
+ return response;
155
+ };
156
+ var fetchText = async (url2, init) => {
157
+ const response = await fetchFromPage(url2, init);
158
+ if (response.status === 204 || response.headers.get("content-length") === "0") {
159
+ return "";
160
+ }
161
+ return response.text();
162
+ };
77
163
 
78
164
  // node_modules/@opentabs-dev/plugin-sdk/dist/timing.js
79
165
  var waitUntil = (predicate, opts) => {
@@ -271,10 +357,11 @@
271
357
  * (e.g., 'https://github.com'), not a match pattern.
272
358
  */
273
359
  homepage;
360
+ /** Typed configuration schema — declares settings that users provide via config.json or the side panel. */
361
+ configSchema;
274
362
  };
275
363
 
276
364
  // src/github-api.ts
277
- var API_BASE = "https://api.github.com";
278
365
  var getAuth = () => {
279
366
  const login = getMetaContent("user-login");
280
367
  if (!login) return null;
@@ -290,105 +377,218 @@
290
377
  if (!auth) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
291
378
  return auth.login;
292
379
  };
293
- var api = async (endpoint, options = {}) => {
294
- if (!getAuth()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
295
- let url2 = `${API_BASE}${endpoint}`;
296
- if (options.query) {
297
- const params = new URLSearchParams();
298
- for (const [key, value] of Object.entries(options.query)) {
299
- if (value !== void 0) params.append(key, String(value));
300
- }
301
- const qs = params.toString();
302
- if (qs) url2 += `?${qs}`;
303
- }
304
- const headers = {
305
- Accept: options.accept ?? "application/vnd.github+json",
306
- "X-GitHub-Api-Version": "2022-11-28"
307
- };
308
- let fetchBody;
309
- if (options.body) {
310
- headers["Content-Type"] = "application/json";
311
- fetchBody = JSON.stringify(options.body);
312
- }
313
- let response;
380
+ var getCsrfToken = () => {
381
+ const graphqlInput = document.querySelector(
382
+ 'form[action*="graphql"] input[name="authenticity_token"]'
383
+ );
384
+ if (graphqlInput?.value) return graphqlInput.value;
385
+ const anyInput = document.querySelector('input[name="authenticity_token"]');
386
+ return anyInput?.value ?? null;
387
+ };
388
+ var requireCsrf = () => {
389
+ const token = getCsrfToken();
390
+ if (!token) throw ToolError.auth("CSRF token not found \u2014 refresh the GitHub page.");
391
+ return token;
392
+ };
393
+ var classifyError = async (response, context) => {
394
+ const body = (await response.text().catch(() => "")).substring(0, 512);
395
+ const status = response.status;
396
+ if (status === 429) {
397
+ const retry2 = response.headers.get("Retry-After");
398
+ const ms = retry2 ? Number.parseInt(retry2, 10) * 1e3 || void 0 : void 0;
399
+ throw ToolError.rateLimited(`Rate limited: ${context} \u2014 ${body}`, ms);
400
+ }
401
+ if (status === 401 || status === 403) throw ToolError.auth(`Auth error (${status}): ${context} \u2014 ${body}`);
402
+ if (status === 404) throw ToolError.notFound(`Not found: ${context} \u2014 ${body}`);
403
+ if (status === 422) throw ToolError.validation(`Validation error: ${context} \u2014 ${body}`);
404
+ throw ToolError.internal(`API error (${status}): ${context} \u2014 ${body}`);
405
+ };
406
+ var doFetch = async (url2, init) => {
314
407
  try {
315
- response = await fetch(url2, {
316
- method: options.method ?? "GET",
317
- headers,
318
- body: fetchBody,
319
- signal: AbortSignal.timeout(3e4)
320
- });
408
+ return await fetchFromPage(url2, init);
321
409
  } catch (err2) {
410
+ if (err2 instanceof ToolError) throw err2;
322
411
  if (err2 instanceof DOMException && err2.name === "TimeoutError")
323
- throw ToolError.timeout(`API request timed out: ${endpoint}`);
324
- if (err2 instanceof DOMException && err2.name === "AbortError") throw new ToolError("Request was aborted", "aborted");
325
- throw new ToolError(`Network error: ${err2 instanceof Error ? err2.message : String(err2)}`, "network_error", {
326
- category: "internal",
327
- retryable: true
328
- });
412
+ throw ToolError.timeout(`Request timed out: ${url2}`);
413
+ throw ToolError.internal(`Network error: ${err2 instanceof Error ? err2.message : String(err2)}`);
329
414
  }
330
- if (!response.ok) {
331
- const errorBody = (await response.text().catch(() => "")).substring(0, 512);
332
- if (response.status === 429) {
333
- const retryAfter = response.headers.get("Retry-After");
334
- const retryMs = retryAfter !== null ? parseRetryAfterMs(retryAfter) : void 0;
335
- throw ToolError.rateLimited(`Rate limited: ${endpoint} \u2014 ${errorBody}`, retryMs);
336
- }
337
- if (response.status === 401 || response.status === 403)
338
- throw ToolError.auth(`Auth error (${response.status}): ${errorBody}`);
339
- if (response.status === 404) throw ToolError.notFound(`Not found: ${endpoint} \u2014 ${errorBody}`);
340
- if (response.status === 422) throw ToolError.validation(`Validation error: ${endpoint} \u2014 ${errorBody}`);
341
- throw ToolError.internal(`API error (${response.status}): ${endpoint} \u2014 ${errorBody}`);
342
- }
343
- if (response.status === 204) return {};
344
- return await response.json();
345
- };
346
- var apiRaw = async (endpoint, options = {}) => {
415
+ };
416
+ var pageJson = async (path, query) => {
417
+ if (!getAuth()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
418
+ const qs = query ? buildQueryString(query) : "";
419
+ const url2 = qs ? `${path}?${qs}` : path;
420
+ const response = await doFetch(url2, {
421
+ method: "GET",
422
+ headers: { Accept: "application/json" }
423
+ });
424
+ if (!response.ok) return classifyError(response, path);
425
+ const data = await response.json();
426
+ return data.payload ?? data;
427
+ };
428
+ var turboData = async (path, query) => {
347
429
  if (!getAuth()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
348
- let url2 = `${API_BASE}${endpoint}`;
349
- if (options.query) {
350
- const params = new URLSearchParams();
351
- for (const [key, value] of Object.entries(options.query)) {
352
- if (value !== void 0) params.append(key, String(value));
430
+ const qs = query ? buildQueryString(query) : "";
431
+ const url2 = qs ? `${path}?${qs}` : path;
432
+ const html = await fetchText(url2, {
433
+ headers: {
434
+ Accept: "text/html",
435
+ "Turbo-Frame": "repo-content-turbo-frame"
436
+ }
437
+ });
438
+ const match = html.match(/<script[^>]*data-target="react-app\.embeddedData"[^>]*>([\s\S]*?)<\/script>/);
439
+ if (!match?.[1]) throw ToolError.internal(`No embedded data found in ${path}`);
440
+ const embedded = JSON.parse(match[1]);
441
+ const preloaded = embedded.payload?.preloadedQueries;
442
+ if (preloaded) {
443
+ const first = Object.values(preloaded)[0];
444
+ if (first?.result?.data) {
445
+ return {
446
+ data: first.result.data,
447
+ queryId: first.queryId,
448
+ queryName: first.queryName
449
+ };
353
450
  }
354
- const qs = params.toString();
355
- if (qs) url2 += `?${qs}`;
356
451
  }
357
- const headers = {
358
- Accept: options.accept ?? "application/vnd.github.raw+json",
359
- "X-GitHub-Api-Version": "2022-11-28"
360
- };
361
- let response;
362
- try {
363
- response = await fetch(url2, {
364
- method: options.method ?? "GET",
365
- headers,
366
- signal: AbortSignal.timeout(3e4)
367
- });
368
- } catch (err2) {
369
- if (err2 instanceof DOMException && err2.name === "TimeoutError")
370
- throw ToolError.timeout(`API request timed out: ${endpoint}`);
371
- if (err2 instanceof DOMException && err2.name === "AbortError") throw new ToolError("Request was aborted", "aborted");
372
- throw new ToolError(`Network error: ${err2 instanceof Error ? err2.message : String(err2)}`, "network_error", {
373
- category: "internal",
374
- retryable: true
375
- });
452
+ return { data: embedded.payload ?? embedded };
453
+ };
454
+ var queryIdCache = /* @__PURE__ */ new Map();
455
+ var discoverMutationIds = async () => {
456
+ if (queryIdCache.has("__mutations_discovered__")) return;
457
+ const html = await fetchText(window.location.href, {
458
+ headers: { Accept: "text/html", "X-Requested-With": "XMLHttpRequest" }
459
+ });
460
+ const jsUrls = [];
461
+ for (const m of html.matchAll(/src="(https:\/\/github\.githubassets\.com\/assets\/[^"]+\.js)"/g)) {
462
+ if (m[1]) jsUrls.push(m[1]);
376
463
  }
377
- if (!response.ok) {
378
- const errorBody = (await response.text().catch(() => "")).substring(0, 512);
379
- if (response.status === 429) {
380
- const retryAfter = response.headers.get("Retry-After");
381
- const retryMs = retryAfter !== null ? parseRetryAfterMs(retryAfter) : void 0;
382
- throw ToolError.rateLimited(`Rate limited: ${endpoint} \u2014 ${errorBody}`, retryMs);
383
- }
384
- if (response.status === 401 || response.status === 403)
385
- throw ToolError.auth(`Auth error (${response.status}): ${errorBody}`);
386
- if (response.status === 404) throw ToolError.notFound(`Not found: ${endpoint} \u2014 ${errorBody}`);
387
- if (response.status === 422) throw ToolError.validation(`Validation error: ${endpoint} \u2014 ${errorBody}`);
388
- throw ToolError.internal(`API error (${response.status}): ${endpoint} \u2014 ${errorBody}`);
464
+ for (const url2 of jsUrls) {
465
+ try {
466
+ const response = await fetchFromPage(url2, { credentials: "omit" });
467
+ const code = await response.text();
468
+ if (!code.includes('operationKind:"mutation"')) continue;
469
+ const pattern = /name:"([^"]*)",operationKind:"mutation"/g;
470
+ for (const match of code.matchAll(pattern)) {
471
+ const name = match[1] ?? "";
472
+ const before = code.substring(Math.max(0, match.index - 300), match.index);
473
+ const idMatch = before.match(/id:"([a-f0-9]{32,64})"/);
474
+ if (idMatch?.[1]) {
475
+ queryIdCache.set(name, idMatch[1]);
476
+ }
477
+ }
478
+ } catch {
479
+ }
389
480
  }
390
- return response.text();
481
+ queryIdCache.set("__mutations_discovered__", "true");
482
+ };
483
+ var getMutationId = async (mutationName) => {
484
+ const cached2 = queryIdCache.get(mutationName);
485
+ if (cached2) return cached2;
486
+ await discoverMutationIds();
487
+ const id = queryIdCache.get(mutationName);
488
+ if (!id) throw ToolError.internal(`Mutation ${mutationName} not found in GitHub JS bundles`);
489
+ return id;
391
490
  };
491
+ var discoverQueryId = async (queryName, discoveryPath, discoveryQuery) => {
492
+ const cached2 = queryIdCache.get(queryName);
493
+ if (cached2) return cached2;
494
+ const result = await turboData(discoveryPath, discoveryQuery);
495
+ if (result.queryName && result.queryId) {
496
+ queryIdCache.set(result.queryName, result.queryId);
497
+ }
498
+ const id = queryIdCache.get(queryName);
499
+ if (!id) throw ToolError.internal(`Could not discover query ID for ${queryName}`);
500
+ return id;
501
+ };
502
+ var graphql = async (queryId, variables) => {
503
+ if (!getAuth()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
504
+ const csrf = requireCsrf();
505
+ const response = await doFetch("/_graphql", {
506
+ method: "POST",
507
+ headers: {
508
+ "Content-Type": "application/json",
509
+ Accept: "application/json",
510
+ "GitHub-Verified-Fetch": "true",
511
+ "X-CSRF-Token": csrf
512
+ },
513
+ body: JSON.stringify({ query: queryId, variables })
514
+ });
515
+ if (!response.ok) return classifyError(response, "/_graphql");
516
+ const result = await response.json();
517
+ if (result.errors?.length && !result.data) {
518
+ const err2 = result.errors[0];
519
+ if (err2?.type === "unknownQuery") {
520
+ queryIdCache.clear();
521
+ throw ToolError.internal(
522
+ "GraphQL persisted query expired \u2014 GitHub may have deployed a new version. Please retry."
523
+ );
524
+ }
525
+ throw ToolError.internal(`GraphQL error: ${err2?.message ?? JSON.stringify(result.errors)}`);
526
+ }
527
+ return result.data;
528
+ };
529
+ var pageEmbeddedData = async (path) => {
530
+ if (!getAuth()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
531
+ const html = await fetchText(path, {
532
+ headers: { Accept: "text/html", "X-Requested-With": "XMLHttpRequest" }
533
+ });
534
+ const match = html.match(/<script[^>]*data-target="react-app\.embeddedData"[^>]*>([\s\S]*?)<\/script>/);
535
+ if (!match?.[1]) throw ToolError.internal(`No embedded data found in ${path}`);
536
+ const embedded = JSON.parse(match[1]);
537
+ return embedded.payload ?? embedded;
538
+ };
539
+ var submitPageForm = async (pagePath, formSelector, fields) => {
540
+ if (!getAuth()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
541
+ const html = await fetchText(pagePath, {
542
+ headers: { Accept: "text/html", "X-Requested-With": "XMLHttpRequest" }
543
+ });
544
+ const doc = new DOMParser().parseFromString(html, "text/html");
545
+ const form = doc.querySelector(formSelector);
546
+ if (!form) throw ToolError.internal(`Form not found: ${formSelector} on ${pagePath}`);
547
+ const action = form.getAttribute("action");
548
+ if (!action) throw ToolError.internal(`Form has no action attribute on ${pagePath}`);
549
+ const formData = new FormData();
550
+ const inputs = form.querySelectorAll("input");
551
+ for (const input of inputs) {
552
+ const name = input.getAttribute("name");
553
+ if (name) {
554
+ formData.set(name, input.value ?? "");
555
+ }
556
+ }
557
+ for (const [key, value] of Object.entries(fields)) {
558
+ formData.set(key, value);
559
+ }
560
+ return xhrSubmit(action, formData);
561
+ };
562
+ var xhrSubmit = (action, formData) => new Promise((resolve, reject) => {
563
+ const xhr = new XMLHttpRequest();
564
+ xhr.open("POST", action, true);
565
+ xhr.setRequestHeader("Accept", "application/json");
566
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
567
+ xhr.withCredentials = true;
568
+ xhr.timeout = 3e4;
569
+ xhr.onload = () => {
570
+ if (xhr.status >= 200 && xhr.status < 300) {
571
+ try {
572
+ resolve(JSON.parse(xhr.responseText));
573
+ } catch {
574
+ resolve({});
575
+ }
576
+ } else if (xhr.status === 401 || xhr.status === 403) {
577
+ reject(ToolError.auth(`Auth error (${xhr.status}): ${action}`));
578
+ } else if (xhr.status === 404) {
579
+ reject(ToolError.notFound(`Not found: ${action}`));
580
+ } else if (xhr.status === 422) {
581
+ reject(
582
+ ToolError.validation(`Validation error (${xhr.status}): ${action} \u2014 ${xhr.responseText.substring(0, 200)}`)
583
+ );
584
+ } else {
585
+ reject(ToolError.internal(`Form submission error (${xhr.status}): ${action}`));
586
+ }
587
+ };
588
+ xhr.onerror = () => reject(ToolError.internal(`Network error submitting form: ${action}`));
589
+ xhr.ontimeout = () => reject(ToolError.timeout(`Form submission timed out: ${action}`));
590
+ xhr.send(formData);
591
+ });
392
592
 
393
593
  // node_modules/zod/v4/classic/external.js
394
594
  var external_exports = {};
@@ -14159,93 +14359,41 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14159
14359
  config(en_default());
14160
14360
 
14161
14361
  // src/tools/add-reaction.ts
14362
+ var REACTION_MAP = {
14363
+ "+1": "THUMBS_UP",
14364
+ "-1": "THUMBS_DOWN",
14365
+ laugh: "LAUGH",
14366
+ confused: "CONFUSED",
14367
+ heart: "HEART",
14368
+ hooray: "HOORAY",
14369
+ rocket: "ROCKET",
14370
+ eyes: "EYES"
14371
+ };
14162
14372
  var addReaction = defineTool({
14163
14373
  name: "add_reaction",
14164
14374
  displayName: "Add Reaction",
14165
- description: "Add a reaction to an issue, pull request, or comment.",
14375
+ description: "Add a reaction to an issue, pull request, or comment. Requires the node ID of the subject (e.g., from get_issue or get_pull_request).",
14166
14376
  summary: "Add a reaction to an issue or comment",
14167
14377
  icon: "smile-plus",
14168
14378
  group: "Reactions",
14169
14379
  input: external_exports.object({
14170
- owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14171
- repo: external_exports.string().min(1).describe("Repository name"),
14172
- content: external_exports.enum(["+1", "-1", "laugh", "confused", "heart", "hooray", "rocket", "eyes"]).describe("Reaction emoji name"),
14173
- issue_number: external_exports.number().int().min(1).optional().describe("Issue or PR number \u2014 provide this OR comment_id, not both"),
14174
- comment_id: external_exports.number().int().min(1).optional().describe("Comment ID \u2014 provide this OR issue_number, not both")
14380
+ subject_id: external_exports.string().min(1).describe('Node ID of the issue, PR, or comment to react to (e.g., "I_kwDOBPD3oc7y2-NQ", "IC_kwDOBPD3oc7xkPTu")'),
14381
+ content: external_exports.enum(["+1", "-1", "laugh", "confused", "heart", "hooray", "rocket", "eyes"]).describe("Reaction emoji name")
14175
14382
  }),
14176
14383
  output: external_exports.object({
14177
- id: external_exports.number().describe("Reaction ID"),
14178
- content: external_exports.string().describe("Reaction emoji name")
14384
+ success: external_exports.boolean().describe("Whether the reaction was added")
14179
14385
  }),
14180
14386
  handle: async (params) => {
14181
- let endpoint;
14182
- if (params.comment_id) {
14183
- endpoint = `/repos/${params.owner}/${params.repo}/issues/comments/${params.comment_id}/reactions`;
14184
- } else if (params.issue_number) {
14185
- endpoint = `/repos/${params.owner}/${params.repo}/issues/${params.issue_number}/reactions`;
14186
- } else {
14187
- throw ToolError.validation("Either issue_number or comment_id must be provided");
14188
- }
14189
- const data = await api(endpoint, {
14190
- method: "POST",
14191
- body: { content: params.content }
14387
+ const reactionContent = REACTION_MAP[params.content];
14388
+ if (!reactionContent) throw ToolError.validation(`Unknown reaction: ${params.content}`);
14389
+ const mutationId = await getMutationId("addReactionMutation");
14390
+ await graphql(mutationId, {
14391
+ input: {
14392
+ subjectId: params.subject_id,
14393
+ content: reactionContent
14394
+ }
14192
14395
  });
14193
- return {
14194
- id: data.id ?? 0,
14195
- content: data.content ?? ""
14196
- };
14197
- }
14198
- });
14199
-
14200
- // src/tools/compare-commits.ts
14201
- var compareFileSchema = external_exports.object({
14202
- filename: external_exports.string().describe("File path"),
14203
- status: external_exports.string().describe("File status: added, removed, modified, renamed, copied, changed, unchanged"),
14204
- additions: external_exports.number().describe("Number of lines added"),
14205
- deletions: external_exports.number().describe("Number of lines deleted")
14206
- });
14207
- var compareCommitSchema = external_exports.object({
14208
- sha: external_exports.string().describe("Full commit SHA"),
14209
- message: external_exports.string().describe("Commit message")
14210
- });
14211
- var compareCommits = defineTool({
14212
- name: "compare_commits",
14213
- displayName: "Compare Commits",
14214
- description: "Compare two commits, branches, or tags. Returns the diff status, commit count, and changed files between the base and head.",
14215
- summary: "Compare two commits or branches",
14216
- icon: "git-compare",
14217
- group: "Repositories",
14218
- input: external_exports.object({
14219
- owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14220
- repo: external_exports.string().min(1).describe("Repository name"),
14221
- basehead: external_exports.string().min(1).describe('Base and head to compare in "base...head" format (e.g., "main...feature-branch")')
14222
- }),
14223
- output: external_exports.object({
14224
- status: external_exports.string().describe("Comparison status: ahead, behind, diverged, or identical"),
14225
- ahead_by: external_exports.number().describe("Number of commits head is ahead of base"),
14226
- behind_by: external_exports.number().describe("Number of commits head is behind base"),
14227
- total_commits: external_exports.number().describe("Total number of commits in the comparison"),
14228
- files: external_exports.array(compareFileSchema).describe("List of changed files"),
14229
- commits: external_exports.array(compareCommitSchema).describe("List of commits")
14230
- }),
14231
- handle: async (params) => {
14232
- const data = await api(`/repos/${params.owner}/${params.repo}/compare/${params.basehead}`);
14233
- return {
14234
- status: data.status ?? "",
14235
- ahead_by: data.ahead_by ?? 0,
14236
- behind_by: data.behind_by ?? 0,
14237
- total_commits: data.total_commits ?? 0,
14238
- files: (data.files ?? []).map((f) => ({
14239
- filename: f.filename ?? "",
14240
- status: f.status ?? "",
14241
- additions: f.additions ?? 0,
14242
- deletions: f.deletions ?? 0
14243
- })),
14244
- commits: (data.commits ?? []).map((c) => ({
14245
- sha: c.sha ?? "",
14246
- message: c.commit?.message ?? ""
14247
- }))
14248
- };
14396
+ return { success: true };
14249
14397
  }
14250
14398
  });
14251
14399
 
@@ -14340,64 +14488,94 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14340
14488
  updated_at: external_exports.string().describe("Updated ISO 8601 timestamp")
14341
14489
  });
14342
14490
  var mapRepository = (r) => ({
14343
- id: r.id ?? 0,
14344
- name: r.name ?? "",
14345
- full_name: r.full_name ?? "",
14346
- description: r.description ?? "",
14347
- private: r.private ?? false,
14348
- html_url: r.html_url ?? "",
14491
+ id: r.id ?? r.repo?.repository?.id ?? 0,
14492
+ name: r.name ?? r.repo?.repository?.name ?? "",
14493
+ full_name: r.full_name ?? r.hl_name?.replace(/<\/?em>/g, "") ?? "",
14494
+ description: r.description ?? r.hl_trunc_description ?? "",
14495
+ private: r.private ?? r.public === false,
14496
+ html_url: r.html_url ?? (r.repo?.repository ? `https://github.com/${r.repo.repository.owner_login}/${r.repo.repository.name}` : ""),
14349
14497
  default_branch: r.default_branch ?? "",
14350
14498
  language: r.language ?? "",
14351
- stargazers_count: r.stargazers_count ?? 0,
14499
+ stargazers_count: r.stargazers_count ?? r.followers ?? 0,
14352
14500
  forks_count: r.forks_count ?? 0,
14353
14501
  open_issues_count: r.open_issues_count ?? 0,
14354
14502
  archived: r.archived ?? false,
14355
- updated_at: r.updated_at ?? ""
14356
- });
14357
- var mapIssue = (i) => ({
14358
- number: i.number ?? 0,
14359
- title: i.title ?? "",
14360
- state: i.state ?? "",
14361
- body: i.body ?? "",
14362
- html_url: i.html_url ?? "",
14363
- user_login: i.user?.login ?? "",
14364
- labels: (i.labels ?? []).map((l) => l.name ?? ""),
14365
- assignees: (i.assignees ?? []).map((a) => a.login ?? ""),
14366
- comments: i.comments ?? 0,
14367
- created_at: i.created_at ?? "",
14368
- updated_at: i.updated_at ?? "",
14369
- closed_at: i.closed_at ?? "",
14370
- is_pull_request: i.pull_request !== void 0 && i.pull_request !== null
14371
- });
14372
- var mapPullRequest = (pr) => ({
14373
- number: pr.number ?? 0,
14374
- title: pr.title ?? "",
14375
- state: pr.merged ? "merged" : pr.state ?? "",
14376
- body: pr.body ?? "",
14377
- html_url: pr.html_url ?? "",
14378
- user_login: pr.user?.login ?? "",
14379
- head_ref: pr.head?.ref ?? "",
14380
- base_ref: pr.base?.ref ?? "",
14381
- labels: (pr.labels ?? []).map((l) => l.name ?? ""),
14382
- draft: pr.draft ?? false,
14383
- merged: pr.merged ?? false,
14384
- mergeable: pr.mergeable ?? false,
14385
- comments: pr.comments ?? 0,
14386
- commits: pr.commits ?? 0,
14387
- additions: pr.additions ?? 0,
14388
- deletions: pr.deletions ?? 0,
14389
- changed_files: pr.changed_files ?? 0,
14390
- created_at: pr.created_at ?? "",
14391
- updated_at: pr.updated_at ?? ""
14392
- });
14393
- var mapComment = (c) => ({
14394
- id: c.id ?? 0,
14395
- body: c.body ?? "",
14396
- user_login: c.user?.login ?? "",
14397
- html_url: c.html_url ?? "",
14398
- created_at: c.created_at ?? "",
14399
- updated_at: c.updated_at ?? ""
14400
- });
14503
+ updated_at: r.updated_at ?? r.repo?.repository?.updated_at ?? ""
14504
+ });
14505
+ var mapIssue = (i, repoContext) => {
14506
+ const owner = repoContext?.owner ?? i.repository?.owner?.login ?? "";
14507
+ const repo = repoContext?.repo ?? i.repository?.name ?? "";
14508
+ const num = i.number ?? 0;
14509
+ const isRelay = !!i.__typename;
14510
+ const isClosed = isRelay ? i.closed ?? false : i.state === "closed";
14511
+ const state = isClosed ? "closed" : "open";
14512
+ const isPR = isRelay ? i.__typename === "PullRequest" : i.pull_request !== void 0 && i.pull_request !== null;
14513
+ const labels = i.relayLabels?.edges ? i.relayLabels.edges.map((e) => e.node?.name ?? "").filter(Boolean) : (i.labels ?? []).map((l) => l.name ?? "");
14514
+ return {
14515
+ number: num,
14516
+ title: i.title ?? "",
14517
+ state,
14518
+ body: i.body ?? "",
14519
+ html_url: i.html_url ?? (owner && repo && num ? `https://github.com/${owner}/${repo}/issues/${num}` : ""),
14520
+ user_login: i.user?.login ?? i.author?.login ?? "",
14521
+ labels,
14522
+ assignees: (i.assignees ?? []).map((a) => a.login ?? ""),
14523
+ comments: i.comments ?? 0,
14524
+ created_at: i.created_at ?? i.createdAt ?? "",
14525
+ updated_at: i.updated_at ?? i.updatedAt ?? "",
14526
+ closed_at: i.closed_at ?? i.closedAt ?? "",
14527
+ is_pull_request: isPR
14528
+ };
14529
+ };
14530
+ var mapPullRequest = (pr, repoContext) => {
14531
+ const owner = repoContext?.owner ?? pr.repository?.owner?.login ?? "";
14532
+ const repo = repoContext?.repo ?? pr.repository?.name ?? "";
14533
+ const num = pr.number ?? 0;
14534
+ const isRelay = !!pr.__typename;
14535
+ const relayState = pr.pullRequestState?.toLowerCase();
14536
+ const mergedByRelay = relayState === "merged";
14537
+ const mergedByRest = pr.merged ?? false;
14538
+ const mergedByPage = pr.mergedTime !== void 0 && pr.mergedTime !== null;
14539
+ const isMerged = mergedByRelay || mergedByRest || mergedByPage;
14540
+ let state;
14541
+ if (isMerged) {
14542
+ state = "merged";
14543
+ } else if (isRelay) {
14544
+ state = relayState ?? (pr.closed ? "closed" : "open");
14545
+ } else {
14546
+ state = pr.state ?? "open";
14547
+ }
14548
+ const labels = pr.relayLabels?.edges ? pr.relayLabels.edges.map((e) => e.node?.name ?? "").filter(Boolean) : (pr.labels ?? []).map((l) => l.name ?? "");
14549
+ let additions = pr.additions ?? 0;
14550
+ let deletions = pr.deletions ?? 0;
14551
+ let changedFiles = pr.changed_files ?? 0;
14552
+ if (pr.diffSummaries?.length) {
14553
+ additions = pr.diffSummaries.reduce((sum, d) => sum + (d.linesAdded ?? 0), 0);
14554
+ deletions = pr.diffSummaries.reduce((sum, d) => sum + (d.linesDeleted ?? 0), 0);
14555
+ changedFiles = pr.diffSummaries.length;
14556
+ }
14557
+ return {
14558
+ number: num,
14559
+ title: pr.title ?? "",
14560
+ state,
14561
+ body: pr.body ?? "",
14562
+ html_url: pr.html_url ?? (owner && repo && num ? `https://github.com/${owner}/${repo}/pull/${num}` : ""),
14563
+ user_login: pr.user?.login ?? pr.author?.login ?? "",
14564
+ head_ref: pr.head?.ref ?? pr.headBranch ?? "",
14565
+ base_ref: pr.base?.ref ?? pr.baseBranch ?? "",
14566
+ labels,
14567
+ draft: pr.draft ?? pr.isDraft ?? false,
14568
+ merged: isMerged,
14569
+ mergeable: pr.mergeable ?? false,
14570
+ comments: pr.comments ?? 0,
14571
+ commits: pr.commits ?? pr.commitsCount ?? 0,
14572
+ additions,
14573
+ deletions,
14574
+ changed_files: changedFiles,
14575
+ created_at: pr.created_at ?? pr.createdAt ?? "",
14576
+ updated_at: pr.updated_at ?? pr.updatedAt ?? ""
14577
+ };
14578
+ };
14401
14579
  var mapUser = (u) => ({
14402
14580
  login: u.login ?? "",
14403
14581
  id: u.id ?? 0,
@@ -14415,18 +14593,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14415
14593
  });
14416
14594
  var mapBranch = (b) => ({
14417
14595
  name: b.name ?? "",
14418
- protected: b.protected ?? false,
14419
- sha: b.commit?.sha ?? ""
14420
- });
14421
- var mapNotification = (n) => ({
14422
- id: n.id ?? "",
14423
- reason: n.reason ?? "",
14424
- unread: n.unread ?? false,
14425
- subject_title: n.subject?.title ?? "",
14426
- subject_type: n.subject?.type ?? "",
14427
- subject_url: n.subject?.url ?? "",
14428
- repository_full_name: n.repository?.full_name ?? "",
14429
- updated_at: n.updated_at ?? ""
14596
+ protected: b.protected ?? b.isProtected ?? false,
14597
+ sha: b.commit?.sha ?? b.oid ?? ""
14430
14598
  });
14431
14599
  var labelSchema = external_exports.object({
14432
14600
  id: external_exports.number().describe("Label ID"),
@@ -14434,12 +14602,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14434
14602
  color: external_exports.string().describe("Label hex color (without #)"),
14435
14603
  description: external_exports.string().describe("Label description")
14436
14604
  });
14437
- var mapLabel = (l) => ({
14438
- id: l.id ?? 0,
14439
- name: l.name ?? "",
14440
- color: l.color ?? "",
14441
- description: l.description ?? ""
14442
- });
14443
14605
  var workflowRunSchema = external_exports.object({
14444
14606
  id: external_exports.number().describe("Workflow run ID"),
14445
14607
  name: external_exports.string().describe("Workflow name"),
@@ -14451,17 +14613,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14451
14613
  created_at: external_exports.string().describe("Created ISO 8601 timestamp"),
14452
14614
  updated_at: external_exports.string().describe("Updated ISO 8601 timestamp")
14453
14615
  });
14454
- var mapWorkflowRun = (r) => ({
14455
- id: r.id ?? 0,
14456
- name: r.name ?? "",
14457
- status: r.status ?? "",
14458
- conclusion: r.conclusion ?? "",
14459
- head_branch: r.head_branch ?? "",
14460
- head_sha: r.head_sha ?? "",
14461
- html_url: r.html_url ?? "",
14462
- created_at: r.created_at ?? "",
14463
- updated_at: r.updated_at ?? ""
14464
- });
14465
14616
  var releaseSchema = external_exports.object({
14466
14617
  id: external_exports.number().describe("Release ID"),
14467
14618
  tag_name: external_exports.string().describe("Git tag name"),
@@ -14474,18 +14625,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14474
14625
  html_url: external_exports.string().describe("URL to the release on GitHub"),
14475
14626
  author_login: external_exports.string().describe("Login of the release author")
14476
14627
  });
14477
- var mapRelease = (r) => ({
14478
- id: r.id ?? 0,
14479
- tag_name: r.tag_name ?? "",
14480
- name: r.name ?? "",
14481
- body: r.body ?? "",
14482
- draft: r.draft ?? false,
14483
- prerelease: r.prerelease ?? false,
14484
- created_at: r.created_at ?? "",
14485
- published_at: r.published_at ?? "",
14486
- html_url: r.html_url ?? "",
14487
- author_login: r.author?.login ?? ""
14488
- });
14489
14628
  var commitSchema = external_exports.object({
14490
14629
  sha: external_exports.string().describe("Full commit SHA"),
14491
14630
  message: external_exports.string().describe("Commit message"),
@@ -14495,12 +14634,92 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14495
14634
  url: external_exports.string().describe("URL to the commit on GitHub")
14496
14635
  });
14497
14636
  var mapCommit = (c) => ({
14498
- sha: c.sha ?? "",
14499
- message: c.commit?.message ?? "",
14500
- author_name: c.commit?.author?.name ?? "",
14501
- author_email: c.commit?.author?.email ?? "",
14502
- date: c.commit?.author?.date ?? "",
14503
- url: c.html_url ?? ""
14637
+ sha: c.sha ?? c.oid ?? "",
14638
+ message: c.commit?.message ?? c.shortMessage ?? "",
14639
+ author_name: c.commit?.author?.name ?? c.authors?.[0]?.displayName ?? "",
14640
+ author_email: c.commit?.author?.email ?? c.authors?.[0]?.email ?? "",
14641
+ date: c.commit?.author?.date ?? c.authoredDate ?? c.committedDate ?? "",
14642
+ url: c.html_url ?? c.url ?? ""
14643
+ });
14644
+ var fileDiffSchema = external_exports.object({
14645
+ filename: external_exports.string().describe("File path"),
14646
+ status: external_exports.string().describe("Change type: added, removed, modified, renamed, etc."),
14647
+ additions: external_exports.number().describe("Lines added"),
14648
+ deletions: external_exports.number().describe("Lines deleted"),
14649
+ changes: external_exports.number().describe("Total lines changed")
14650
+ });
14651
+ var mapFileDiff = (f) => ({
14652
+ filename: f.filename ?? f.path ?? "",
14653
+ status: f.status ?? f.changeType?.toLowerCase() ?? "",
14654
+ additions: f.additions ?? f.linesAdded ?? 0,
14655
+ deletions: f.deletions ?? f.linesDeleted ?? 0,
14656
+ changes: f.changes ?? f.linesChanged ?? (f.linesAdded ?? 0) + (f.linesDeleted ?? 0)
14657
+ });
14658
+ var extractRelayLabels = (labels) => {
14659
+ if (!labels || typeof labels !== "object") return void 0;
14660
+ const l = labels;
14661
+ return l.edges ? { edges: l.edges } : void 0;
14662
+ };
14663
+ var relayNodeToRaw = (node) => ({
14664
+ __typename: node.__typename,
14665
+ number: node.number,
14666
+ title: node.title,
14667
+ author: node.author,
14668
+ createdAt: node.createdAt,
14669
+ updatedAt: node.updatedAt,
14670
+ closed: node.closed,
14671
+ closedAt: node.closedAt,
14672
+ isDraft: node.isDraft,
14673
+ pullRequestState: node.pullRequestState,
14674
+ milestone: node.milestone,
14675
+ relayLabels: extractRelayLabels(node.labels),
14676
+ repository: node.repository
14677
+ });
14678
+
14679
+ // src/tools/compare-commits.ts
14680
+ var compareCommits = defineTool({
14681
+ name: "compare_commits",
14682
+ displayName: "Compare Commits",
14683
+ description: "Compare two commits, branches, or tags. Returns the diff status, commit count, and changed files between the base and head.",
14684
+ summary: "Compare two commits or branches",
14685
+ icon: "git-compare",
14686
+ group: "Repositories",
14687
+ input: external_exports.object({
14688
+ owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14689
+ repo: external_exports.string().min(1).describe("Repository name"),
14690
+ basehead: external_exports.string().min(1).describe('Base and head to compare in "base...head" format (e.g., "main...feature-branch")')
14691
+ }),
14692
+ output: external_exports.object({
14693
+ files: external_exports.array(fileDiffSchema).describe("List of changed files"),
14694
+ total_files: external_exports.number().describe("Total number of files changed")
14695
+ }),
14696
+ handle: async (params) => {
14697
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
14698
+ try {
14699
+ const data = await pageEmbeddedData(
14700
+ `/${params.owner}/${params.repo}/compare/${params.basehead}`
14701
+ );
14702
+ const summaries = data.pullRequestsChangesRoute?.diffSummaries ?? [];
14703
+ return {
14704
+ files: summaries.map(mapFileDiff),
14705
+ total_files: summaries.length
14706
+ };
14707
+ } catch {
14708
+ const html = await fetchText(`/${params.owner}/${params.repo}/compare/${params.basehead}`, {
14709
+ headers: { "X-Requested-With": "XMLHttpRequest" }
14710
+ });
14711
+ const doc = new DOMParser().parseFromString(html, "text/html");
14712
+ const fileEls = doc.querySelectorAll(".file-info a, [data-path]");
14713
+ const files = [...fileEls].map((el) => ({
14714
+ filename: el.getAttribute("data-path") ?? el.textContent?.trim() ?? "",
14715
+ status: "modified",
14716
+ additions: 0,
14717
+ deletions: 0,
14718
+ changes: 0
14719
+ }));
14720
+ return { files, total_files: files.length };
14721
+ }
14722
+ }
14504
14723
  });
14505
14724
 
14506
14725
  // src/tools/create-comment.ts
@@ -14518,14 +14737,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14518
14737
  body: external_exports.string().min(1).describe("Comment body in Markdown")
14519
14738
  }),
14520
14739
  output: external_exports.object({
14521
- comment: commentSchema.describe("The created comment")
14740
+ success: external_exports.boolean().describe("Whether the comment was created successfully")
14522
14741
  }),
14523
14742
  handle: async (params) => {
14524
- const data = await api(
14525
- `/repos/${params.owner}/${params.repo}/issues/${params.issue_number}/comments`,
14526
- { method: "POST", body: { body: params.body } }
14527
- );
14528
- return { comment: mapComment(data) };
14743
+ const prPath = `/${params.owner}/${params.repo}/pull/${params.issue_number}`;
14744
+ const issuePath = `/${params.owner}/${params.repo}/issues/${params.issue_number}`;
14745
+ let pagePath;
14746
+ try {
14747
+ await submitPageForm(prPath, "form.js-new-comment-form", {
14748
+ "comment[body]": params.body
14749
+ });
14750
+ return { success: true };
14751
+ } catch {
14752
+ pagePath = issuePath;
14753
+ }
14754
+ await submitPageForm(pagePath, "form.js-new-comment-form", {
14755
+ "comment[body]": params.body
14756
+ });
14757
+ return { success: true };
14529
14758
  }
14530
14759
  });
14531
14760
 
@@ -14541,23 +14770,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14541
14770
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14542
14771
  repo: external_exports.string().min(1).describe("Repository name"),
14543
14772
  title: external_exports.string().min(1).describe("Issue title"),
14544
- body: external_exports.string().optional().describe("Issue body in Markdown"),
14545
- labels: external_exports.array(external_exports.string()).optional().describe("Label names to apply"),
14546
- assignees: external_exports.array(external_exports.string()).optional().describe("Logins of users to assign")
14773
+ body: external_exports.string().optional().describe("Issue body in Markdown")
14547
14774
  }),
14548
14775
  output: external_exports.object({
14549
14776
  issue: issueSchema.describe("The created issue")
14550
14777
  }),
14551
14778
  handle: async (params) => {
14552
- const body = { title: params.title };
14553
- if (params.body !== void 0) body.body = params.body;
14554
- if (params.labels !== void 0) body.labels = params.labels;
14555
- if (params.assignees !== void 0) body.assignees = params.assignees;
14556
- const data = await api(`/repos/${params.owner}/${params.repo}/issues`, {
14557
- method: "POST",
14558
- body
14779
+ const { data: repoData } = await turboData(
14780
+ `/${params.owner}/${params.repo}/issues`,
14781
+ { q: "is:issue is:open" }
14782
+ );
14783
+ const repoId = repoData?.repository?.id;
14784
+ if (!repoId) throw new Error("Could not determine repository ID");
14785
+ const mutationId = await getMutationId("createIssueMutation");
14786
+ const result = await graphql(mutationId, {
14787
+ input: {
14788
+ repositoryId: repoId,
14789
+ title: params.title,
14790
+ body: params.body ?? ""
14791
+ }
14559
14792
  });
14560
- return { issue: mapIssue(data) };
14793
+ const issue2 = result.createIssue?.issue;
14794
+ return {
14795
+ issue: {
14796
+ number: issue2?.number ?? 0,
14797
+ title: issue2?.title ?? params.title,
14798
+ state: "open",
14799
+ body: params.body ?? "",
14800
+ html_url: issue2?.url ?? `https://github.com/${params.owner}/${params.repo}/issues/${issue2?.number ?? 0}`,
14801
+ user_login: "",
14802
+ labels: [],
14803
+ assignees: [],
14804
+ comments: 0,
14805
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
14806
+ updated_at: (/* @__PURE__ */ new Date()).toISOString(),
14807
+ closed_at: "",
14808
+ is_pull_request: false
14809
+ }
14810
+ };
14561
14811
  }
14562
14812
  });
14563
14813
 
@@ -14580,16 +14830,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14580
14830
  label: labelSchema.describe("The created label")
14581
14831
  }),
14582
14832
  handle: async (params) => {
14583
- const body = {
14584
- name: params.name
14585
- };
14586
- if (params.color !== void 0) body.color = params.color;
14587
- if (params.description !== void 0) body.description = params.description;
14588
- const data = await api(`/repos/${params.owner}/${params.repo}/labels`, {
14589
- method: "POST",
14590
- body
14833
+ const { data: repoData } = await turboData(
14834
+ `/${params.owner}/${params.repo}/issues`,
14835
+ { q: "is:issue is:open" }
14836
+ );
14837
+ const repoId = repoData?.repository?.id;
14838
+ if (!repoId) throw new Error("Could not determine repository ID");
14839
+ const mutationId = await getMutationId("createRepositoryLabelMutation");
14840
+ await graphql(mutationId, {
14841
+ repositoryId: repoId,
14842
+ name: params.name,
14843
+ color: params.color ?? "ededed",
14844
+ description: params.description ?? ""
14591
14845
  });
14592
- return { label: mapLabel(data) };
14846
+ return {
14847
+ label: {
14848
+ id: 0,
14849
+ name: params.name,
14850
+ color: params.color ?? "ededed",
14851
+ description: params.description ?? ""
14852
+ }
14853
+ };
14593
14854
  }
14594
14855
  });
14595
14856
 
@@ -14597,7 +14858,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14597
14858
  var createOrUpdateFile = defineTool({
14598
14859
  name: "create_or_update_file",
14599
14860
  displayName: "Create or Update File",
14600
- description: "Create or update a file in a repository. To update an existing file, provide the current file SHA (obtainable from the contents API). Commits directly to the specified branch.",
14861
+ description: "Create or update a file in a repository. Commits directly to the specified branch.",
14601
14862
  summary: "Create or update a file in a repository",
14602
14863
  icon: "file-edit",
14603
14864
  group: "Repositories",
@@ -14605,33 +14866,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14605
14866
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14606
14867
  repo: external_exports.string().min(1).describe("Repository name"),
14607
14868
  path: external_exports.string().min(1).describe("File path relative to repository root"),
14608
- content: external_exports.string().min(1).describe("File content as a UTF-8 string (will be base64-encoded automatically)"),
14869
+ content: external_exports.string().min(1).describe("File content as a UTF-8 string"),
14609
14870
  message: external_exports.string().min(1).describe("Commit message"),
14610
- branch: external_exports.string().optional().describe("Branch to commit to (defaults to the default branch)"),
14611
- sha: external_exports.string().optional().describe("SHA of the file being replaced \u2014 required when updating an existing file")
14871
+ branch: external_exports.string().optional().describe("Branch to commit to (defaults to the default branch)")
14612
14872
  }),
14613
14873
  output: external_exports.object({
14614
- sha: external_exports.string().describe("SHA of the created/updated file blob"),
14615
- commit_sha: external_exports.string().describe("SHA of the commit"),
14616
- html_url: external_exports.string().describe("URL to the file on GitHub")
14874
+ success: external_exports.boolean().describe("Whether the file was created/updated")
14617
14875
  }),
14618
14876
  handle: async (params) => {
14619
- const body = {
14877
+ const branch = params.branch ?? "main";
14878
+ const fields = {
14879
+ value: params.content,
14620
14880
  message: params.message,
14621
- content: btoa(unescape(encodeURIComponent(params.content)))
14622
- };
14623
- if (params.branch) body.branch = params.branch;
14624
- if (params.sha) body.sha = params.sha;
14625
- const encodedPath = params.path.split("/").map(encodeURIComponent).join("/");
14626
- const data = await api(`/repos/${params.owner}/${params.repo}/contents/${encodedPath}`, {
14627
- method: "PUT",
14628
- body
14629
- });
14630
- return {
14631
- sha: data.content?.sha ?? "",
14632
- commit_sha: data.commit?.sha ?? "",
14633
- html_url: data.content?.html_url ?? ""
14881
+ placeholder_message: params.message,
14882
+ "commit-choice": "direct",
14883
+ target_branch: branch,
14884
+ quick_pull: "",
14885
+ filename: params.path.split("/").pop() ?? ""
14634
14886
  };
14887
+ try {
14888
+ await submitPageForm(
14889
+ `/${params.owner}/${params.repo}/edit/${branch}/${params.path}`,
14890
+ "form.js-blob-form",
14891
+ fields
14892
+ );
14893
+ } catch {
14894
+ await submitPageForm(`/${params.owner}/${params.repo}/new/${branch}`, "form.js-blob-form", fields);
14895
+ }
14896
+ return { success: true };
14635
14897
  }
14636
14898
  });
14637
14899
 
@@ -14647,7 +14909,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14647
14909
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14648
14910
  repo: external_exports.string().min(1).describe("Repository name"),
14649
14911
  title: external_exports.string().min(1).describe("Pull request title"),
14650
- head: external_exports.string().min(1).describe('Source branch name (or "user:branch" for cross-repo)'),
14912
+ head: external_exports.string().min(1).describe("Source branch name"),
14651
14913
  base: external_exports.string().min(1).describe("Target branch name to merge into"),
14652
14914
  body: external_exports.string().optional().describe("Pull request description in Markdown"),
14653
14915
  draft: external_exports.boolean().optional().describe("Create as a draft PR (default: false)")
@@ -14656,18 +14918,41 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14656
14918
  pull_request: pullRequestSchema.describe("The created pull request")
14657
14919
  }),
14658
14920
  handle: async (params) => {
14659
- const body = {
14660
- title: params.title,
14661
- head: params.head,
14662
- base: params.base
14921
+ const fields = {
14922
+ "pull_request[title]": params.title,
14923
+ "pull_request[head]": params.head,
14924
+ "pull_request[base]": params.base
14925
+ };
14926
+ if (params.body) fields["pull_request[body]"] = params.body;
14927
+ if (params.draft) fields["pull_request[draft]"] = "1";
14928
+ await submitPageForm(
14929
+ `/${params.owner}/${params.repo}/compare/${params.base}...${params.head}`,
14930
+ 'form#new_pull_request, form[action*="pull"]',
14931
+ fields
14932
+ );
14933
+ return {
14934
+ pull_request: {
14935
+ number: 0,
14936
+ title: params.title,
14937
+ state: "open",
14938
+ body: params.body ?? "",
14939
+ html_url: `https://github.com/${params.owner}/${params.repo}/pulls`,
14940
+ user_login: "",
14941
+ head_ref: params.head,
14942
+ base_ref: params.base,
14943
+ labels: [],
14944
+ draft: params.draft ?? false,
14945
+ merged: false,
14946
+ mergeable: false,
14947
+ comments: 0,
14948
+ commits: 0,
14949
+ additions: 0,
14950
+ deletions: 0,
14951
+ changed_files: 0,
14952
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
14953
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
14954
+ }
14663
14955
  };
14664
- if (params.body !== void 0) body.body = params.body;
14665
- if (params.draft !== void 0) body.draft = params.draft;
14666
- const data = await api(`/repos/${params.owner}/${params.repo}/pulls`, {
14667
- method: "POST",
14668
- body
14669
- });
14670
- return { pull_request: mapPullRequest(data) };
14671
14956
  }
14672
14957
  });
14673
14958
 
@@ -14693,19 +14978,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14693
14978
  release: releaseSchema.describe("The created release")
14694
14979
  }),
14695
14980
  handle: async (params) => {
14696
- const body = {
14697
- tag_name: params.tag_name
14981
+ const fields = {
14982
+ "release[tag_name]": params.tag_name
14983
+ };
14984
+ if (params.name) fields["release[name]"] = params.name;
14985
+ if (params.body) fields["release[body]"] = params.body;
14986
+ if (params.draft) fields["release[draft]"] = "1";
14987
+ if (params.prerelease) fields["release[prerelease]"] = "1";
14988
+ if (params.target_commitish) fields["release[target_commitish]"] = params.target_commitish;
14989
+ await submitPageForm(`/${params.owner}/${params.repo}/releases/new`, 'form[action*="releases"]', fields);
14990
+ return {
14991
+ release: {
14992
+ id: 0,
14993
+ tag_name: params.tag_name,
14994
+ name: params.name ?? params.tag_name,
14995
+ body: params.body ?? "",
14996
+ draft: params.draft ?? false,
14997
+ prerelease: params.prerelease ?? false,
14998
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
14999
+ published_at: params.draft ? "" : (/* @__PURE__ */ new Date()).toISOString(),
15000
+ html_url: `https://github.com/${params.owner}/${params.repo}/releases/tag/${params.tag_name}`,
15001
+ author_login: ""
15002
+ }
14698
15003
  };
14699
- if (params.name !== void 0) body.name = params.name;
14700
- if (params.body !== void 0) body.body = params.body;
14701
- if (params.draft !== void 0) body.draft = params.draft;
14702
- if (params.prerelease !== void 0) body.prerelease = params.prerelease;
14703
- if (params.target_commitish !== void 0) body.target_commitish = params.target_commitish;
14704
- const data = await api(`/repos/${params.owner}/${params.repo}/releases`, {
14705
- method: "POST",
14706
- body
14707
- });
14708
- return { release: mapRelease(data) };
14709
15004
  }
14710
15005
  });
14711
15006
 
@@ -14729,30 +15024,40 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14729
15024
  repository: repositorySchema.describe("The created repository")
14730
15025
  }),
14731
15026
  handle: async (params) => {
14732
- const body = { name: params.name };
14733
- if (params.description !== void 0) body.description = params.description;
14734
- if (params.private !== void 0) body.private = params.private;
14735
- if (params.auto_init !== void 0) body.auto_init = params.auto_init;
14736
- if (params.gitignore_template !== void 0) body.gitignore_template = params.gitignore_template;
14737
- if (params.license_template !== void 0) body.license_template = params.license_template;
14738
- const data = await api("/user/repos", {
14739
- method: "POST",
14740
- body
14741
- });
14742
- return { repository: mapRepository(data) };
15027
+ const fields = {
15028
+ "repository[name]": params.name
15029
+ };
15030
+ if (params.description) fields["repository[description]"] = params.description;
15031
+ if (params.private) fields["repository[visibility]"] = "private";
15032
+ if (params.auto_init) fields["repository[auto_init]"] = "1";
15033
+ if (params.gitignore_template) fields["repository[gitignore_template]"] = params.gitignore_template;
15034
+ if (params.license_template) fields["repository[license_template]"] = params.license_template;
15035
+ await submitPageForm("/new", 'form[action="/repositories"]', fields);
15036
+ return {
15037
+ repository: {
15038
+ id: 0,
15039
+ name: params.name,
15040
+ full_name: params.name,
15041
+ description: params.description ?? "",
15042
+ private: params.private ?? false,
15043
+ html_url: `https://github.com/${params.name}`,
15044
+ default_branch: "main",
15045
+ language: "",
15046
+ stargazers_count: 0,
15047
+ forks_count: 0,
15048
+ open_issues_count: 0,
15049
+ archived: false,
15050
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
15051
+ }
15052
+ };
14743
15053
  }
14744
15054
  });
14745
15055
 
14746
15056
  // src/tools/delete-file.ts
14747
- var deleteCommitSchema = external_exports.object({
14748
- sha: external_exports.string().describe("Commit SHA"),
14749
- message: external_exports.string().describe("Commit message"),
14750
- url: external_exports.string().describe("URL to the commit on GitHub")
14751
- });
14752
15057
  var deleteFile = defineTool({
14753
15058
  name: "delete_file",
14754
15059
  displayName: "Delete File",
14755
- description: "Delete a file from a repository. Requires the current file SHA (obtainable from the contents API). Commits directly to the specified branch.",
15060
+ description: "Delete a file from a repository. Commits directly to the specified branch.",
14756
15061
  summary: "Delete a file from a repository",
14757
15062
  icon: "file-x",
14758
15063
  group: "Repositories",
@@ -14761,30 +15066,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14761
15066
  repo: external_exports.string().min(1).describe("Repository name"),
14762
15067
  path: external_exports.string().min(1).describe("File path relative to repository root"),
14763
15068
  message: external_exports.string().min(1).describe("Commit message for the deletion"),
14764
- sha: external_exports.string().min(1).describe("SHA of the file being deleted \u2014 required to prevent accidental overwrites"),
14765
15069
  branch: external_exports.string().optional().describe("Branch to commit to (defaults to the default branch)")
14766
15070
  }),
14767
15071
  output: external_exports.object({
14768
- commit: deleteCommitSchema.describe("The commit created by the deletion")
15072
+ success: external_exports.boolean().describe("Whether the file was deleted")
14769
15073
  }),
14770
15074
  handle: async (params) => {
14771
- const body = {
15075
+ const branch = params.branch ?? "main";
15076
+ await submitPageForm(`/${params.owner}/${params.repo}/delete/${branch}/${params.path}`, 'form[action*="delete"]', {
14772
15077
  message: params.message,
14773
- sha: params.sha
14774
- };
14775
- if (params.branch !== void 0) body.branch = params.branch;
14776
- const encodedPath = params.path.split("/").map(encodeURIComponent).join("/");
14777
- const data = await api(`/repos/${params.owner}/${params.repo}/contents/${encodedPath}`, {
14778
- method: "DELETE",
14779
- body
15078
+ commit_choice: "direct",
15079
+ target_branch: branch
14780
15080
  });
14781
- return {
14782
- commit: {
14783
- sha: data.commit?.sha ?? "",
14784
- message: data.commit?.message ?? "",
14785
- url: data.commit?.html_url ?? ""
14786
- }
14787
- };
15081
+ return { success: true };
14788
15082
  }
14789
15083
  });
14790
15084
 
@@ -14807,13 +15101,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14807
15101
  path: external_exports.string().describe("File path")
14808
15102
  }),
14809
15103
  handle: async (params) => {
14810
- const query = {};
14811
- if (params.ref) query.ref = params.ref;
14812
- const encodedPath = params.path.split("/").map(encodeURIComponent).join("/");
14813
- const content = await apiRaw(`/repos/${params.owner}/${params.repo}/contents/${encodedPath}`, {
14814
- query,
14815
- accept: "application/vnd.github.raw+json"
14816
- });
15104
+ const ref = params.ref ?? "HEAD";
15105
+ const data = await pageEmbeddedData(`/${params.owner}/${params.repo}/blob/${ref}/${params.path}`);
15106
+ const rawLines = data["codeViewBlobLayoutRoute.StyledBlob"]?.rawLines;
15107
+ const content = rawLines ? rawLines.join("\n") : "";
14817
15108
  return { content, path: params.path };
14818
15109
  }
14819
15110
  });
@@ -14835,10 +15126,30 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14835
15126
  issue: issueSchema.describe("Issue details")
14836
15127
  }),
14837
15128
  handle: async (params) => {
14838
- const data = await api(
14839
- `/repos/${params.owner}/${params.repo}/issues/${params.issue_number}`
14840
- );
14841
- return { issue: mapIssue(data) };
15129
+ const result = await turboData(`/${params.owner}/${params.repo}/issues/${params.issue_number}`);
15130
+ const issue2 = result.data?.repository?.issue;
15131
+ const labels = (issue2?.labels?.edges ?? []).map((e) => e.node?.name ?? "").filter(Boolean);
15132
+ const assignees = (issue2?.assignedActors?.nodes ?? []).map((a) => a.login ?? "").filter(Boolean);
15133
+ const state = issue2?.state?.toLowerCase() ?? "";
15134
+ const isPR = false;
15135
+ return {
15136
+ issue: {
15137
+ number: issue2?.number ?? params.issue_number,
15138
+ title: issue2?.title ?? "",
15139
+ state,
15140
+ body: issue2?.body ?? "",
15141
+ html_url: `https://github.com/${params.owner}/${params.repo}/issues/${params.issue_number}`,
15142
+ user_login: issue2?.author?.login ?? "",
15143
+ labels,
15144
+ assignees,
15145
+ comments: 0,
15146
+ // Not available in this query
15147
+ created_at: issue2?.createdAt ?? "",
15148
+ updated_at: issue2?.updatedAt ?? "",
15149
+ closed_at: issue2?.closedAt ?? "",
15150
+ is_pull_request: isPR
15151
+ }
15152
+ };
14842
15153
  }
14843
15154
  });
14844
15155
 
@@ -14859,10 +15170,36 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14859
15170
  pull_request: pullRequestSchema.describe("Pull request details")
14860
15171
  }),
14861
15172
  handle: async (params) => {
14862
- const data = await api(
14863
- `/repos/${params.owner}/${params.repo}/pulls/${params.pull_number}`
14864
- );
14865
- return { pull_request: mapPullRequest(data) };
15173
+ const pageData = await pageEmbeddedData(`/${params.owner}/${params.repo}/pull/${params.pull_number}`);
15174
+ const prLayout = pageData.pullRequestsLayoutRoute?.pullRequest;
15175
+ let diffSummaries;
15176
+ try {
15177
+ const filesData = await pageEmbeddedData(
15178
+ `/${params.owner}/${params.repo}/pull/${params.pull_number}/files`
15179
+ );
15180
+ diffSummaries = filesData.pullRequestsChangesRoute;
15181
+ } catch {
15182
+ }
15183
+ const raw = {
15184
+ number: prLayout?.number ?? params.pull_number,
15185
+ title: prLayout?.title,
15186
+ author: prLayout?.author,
15187
+ baseBranch: prLayout?.baseBranch,
15188
+ headBranch: prLayout?.headBranch,
15189
+ commitsCount: prLayout?.commitsCount,
15190
+ mergedBy: prLayout?.mergedBy,
15191
+ mergedTime: prLayout?.mergedTime,
15192
+ // Map state from page format (OPEN, CLOSED, MERGED) to lowercase
15193
+ pullRequestState: prLayout?.state,
15194
+ closed: prLayout?.state === "CLOSED" || prLayout?.state === "MERGED",
15195
+ isDraft: false,
15196
+ // not available in layout route
15197
+ __typename: "PullRequest",
15198
+ diffSummaries: diffSummaries?.diffSummaries
15199
+ };
15200
+ return {
15201
+ pull_request: mapPullRequest(raw, { owner: params.owner, repo: params.repo })
15202
+ };
14866
15203
  }
14867
15204
  });
14868
15205
 
@@ -14883,10 +15220,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14883
15220
  diff: external_exports.string().describe("Raw unified diff text")
14884
15221
  }),
14885
15222
  handle: async (params) => {
14886
- const diff = await apiRaw(`/repos/${params.owner}/${params.repo}/pulls/${params.pull_number}`, {
14887
- accept: "application/vnd.github.diff"
14888
- });
14889
- return { diff };
15223
+ const data = await pageEmbeddedData(
15224
+ `/${params.owner}/${params.repo}/pull/${params.pull_number}/files`
15225
+ );
15226
+ const route = data.pullRequestsChangesRoute;
15227
+ const summaries = route?.diffSummaries ?? [];
15228
+ const contents = route?.diffContents ?? {};
15229
+ const diffParts = [];
15230
+ for (let i = 0; i < summaries.length; i++) {
15231
+ const path = summaries[i]?.path ?? "";
15232
+ const content = contents[String(i)];
15233
+ if (!content?.diffLines) continue;
15234
+ diffParts.push(`diff --git a/${path} b/${path}`);
15235
+ for (const line of content.diffLines) {
15236
+ diffParts.push(line.text ?? "");
15237
+ }
15238
+ }
15239
+ return { diff: diffParts.join("\n") };
14890
15240
  }
14891
15241
  });
14892
15242
 
@@ -14906,8 +15256,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14906
15256
  repository: repositorySchema.describe("Repository details")
14907
15257
  }),
14908
15258
  handle: async (params) => {
14909
- const data = await api(`/repos/${params.owner}/${params.repo}`);
14910
- return { repository: mapRepository(data) };
15259
+ const data = await pageJson(`/${params.owner}/${params.repo}`);
15260
+ const route = data.codeViewRepoRoute;
15261
+ return {
15262
+ repository: {
15263
+ id: data.repo?.id ?? 0,
15264
+ name: params.repo,
15265
+ full_name: `${params.owner}/${params.repo}`,
15266
+ description: data.repo?.description ?? "",
15267
+ private: data.repo?.isPrivate ?? false,
15268
+ html_url: `https://github.com/${params.owner}/${params.repo}`,
15269
+ default_branch: route?.refInfo?.name ?? data.repo?.defaultBranch ?? "",
15270
+ language: data.repo?.language ?? "",
15271
+ stargazers_count: data.repo?.stargazerCount ?? 0,
15272
+ forks_count: data.repo?.forkCount ?? 0,
15273
+ open_issues_count: data.repo?.openIssueCount ?? 0,
15274
+ archived: data.repo?.isArchived ?? false,
15275
+ updated_at: data.repo?.updatedAt ?? ""
15276
+ }
15277
+ };
14911
15278
  }
14912
15279
  });
14913
15280
 
@@ -14926,8 +15293,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14926
15293
  user: userSchema.describe("User profile")
14927
15294
  }),
14928
15295
  handle: async (params) => {
15296
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
14929
15297
  const username = params.username ?? getLogin();
14930
- const data = await api(`/users/${username}`);
15298
+ const response = await fetchFromPage(`https://api.github.com/users/${username}`, {
15299
+ headers: { Accept: "application/vnd.github+json" },
15300
+ credentials: "omit"
15301
+ });
15302
+ if (!response.ok) {
15303
+ if (response.status === 404) throw ToolError.notFound(`User not found: ${username}`);
15304
+ throw ToolError.internal(`API error (${response.status}): /users/${username}`);
15305
+ }
15306
+ const data = await response.json();
14931
15307
  return { user: mapUser(data) };
14932
15308
  }
14933
15309
  });
@@ -14936,7 +15312,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14936
15312
  var getWorkflowRun = defineTool({
14937
15313
  name: "get_workflow_run",
14938
15314
  displayName: "Get Workflow Run",
14939
- description: "Get detailed information about a specific GitHub Actions workflow run by its run ID.",
15315
+ description: "Get information about a specific GitHub Actions workflow run by its run ID.",
14940
15316
  summary: "Get a workflow run by ID",
14941
15317
  icon: "play",
14942
15318
  group: "Actions",
@@ -14949,8 +15325,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14949
15325
  workflow_run: workflowRunSchema.describe("The workflow run")
14950
15326
  }),
14951
15327
  handle: async (params) => {
14952
- const data = await api(`/repos/${params.owner}/${params.repo}/actions/runs/${params.run_id}`);
14953
- return { workflow_run: mapWorkflowRun(data) };
15328
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
15329
+ const html = await fetchText(`/${params.owner}/${params.repo}/actions/runs/${params.run_id}`, {
15330
+ headers: { "X-Requested-With": "XMLHttpRequest" }
15331
+ });
15332
+ const doc = new DOMParser().parseFromString(html, "text/html");
15333
+ const titleEl = doc.querySelector("h1, .workflow-run-title");
15334
+ const statusEl = doc.querySelector('[data-testid="conclusion-icon"], .octicon-check, .octicon-x');
15335
+ const branchEl = doc.querySelector('a[href*="tree/"]');
15336
+ const timeEl = doc.querySelector("relative-time, time");
15337
+ const shaEl = doc.querySelector('a[href*="commit/"]');
15338
+ return {
15339
+ workflow_run: {
15340
+ id: params.run_id,
15341
+ name: titleEl?.textContent?.trim() ?? "",
15342
+ status: statusEl?.getAttribute("aria-label") ?? "",
15343
+ conclusion: "",
15344
+ head_branch: branchEl?.textContent?.trim() ?? "",
15345
+ head_sha: shaEl?.textContent?.trim() ?? "",
15346
+ html_url: `https://github.com/${params.owner}/${params.repo}/actions/runs/${params.run_id}`,
15347
+ created_at: timeEl?.getAttribute("datetime") ?? "",
15348
+ updated_at: timeEl?.getAttribute("datetime") ?? ""
15349
+ }
15350
+ };
14954
15351
  }
14955
15352
  });
14956
15353
 
@@ -14964,20 +15361,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14964
15361
  group: "Repositories",
14965
15362
  input: external_exports.object({
14966
15363
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14967
- repo: external_exports.string().min(1).describe("Repository name"),
14968
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
14969
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15364
+ repo: external_exports.string().min(1).describe("Repository name")
14970
15365
  }),
14971
15366
  output: external_exports.object({
14972
15367
  branches: external_exports.array(branchSchema).describe("List of branches")
14973
15368
  }),
14974
15369
  handle: async (params) => {
14975
- const query = {
14976
- per_page: params.per_page ?? 30,
14977
- page: params.page
14978
- };
14979
- const data = await api(`/repos/${params.owner}/${params.repo}/branches`, { query });
14980
- return { branches: (data ?? []).map(mapBranch) };
15370
+ const data = await pageJson(`/${params.owner}/${params.repo}/branches`);
15371
+ return { branches: (data.branches ?? []).map(mapBranch) };
14981
15372
  }
14982
15373
  });
14983
15374
 
@@ -14992,23 +15383,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
14992
15383
  input: external_exports.object({
14993
15384
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
14994
15385
  repo: external_exports.string().min(1).describe("Repository name"),
14995
- issue_number: external_exports.number().int().min(1).describe("Issue or pull request number"),
14996
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
14997
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15386
+ issue_number: external_exports.number().int().min(1).describe("Issue or pull request number")
14998
15387
  }),
14999
15388
  output: external_exports.object({
15000
15389
  comments: external_exports.array(commentSchema).describe("List of comments")
15001
15390
  }),
15002
15391
  handle: async (params) => {
15003
- const query = {
15004
- per_page: params.per_page ?? 30,
15005
- page: params.page
15006
- };
15007
- const data = await api(
15008
- `/repos/${params.owner}/${params.repo}/issues/${params.issue_number}/comments`,
15009
- { query }
15010
- );
15011
- return { comments: (data ?? []).map(mapComment) };
15392
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
15393
+ const html = await fetchText(`/${params.owner}/${params.repo}/issues/${params.issue_number}`, {
15394
+ headers: { "X-Requested-With": "XMLHttpRequest" }
15395
+ });
15396
+ const doc = new DOMParser().parseFromString(html, "text/html");
15397
+ const commentElements = doc.querySelectorAll(".js-comment-container, .timeline-comment");
15398
+ const comments = [];
15399
+ for (const el of commentElements) {
15400
+ const bodyEl = el.querySelector(".comment-body, .js-comment-body");
15401
+ const authorEl = el.querySelector(".author, a.timeline-comment-header-text");
15402
+ const timeEl = el.querySelector("relative-time, time");
15403
+ const linkEl = el.querySelector('a[id^="issuecomment-"]');
15404
+ const id = linkEl?.getAttribute("id")?.replace("issuecomment-", "") ?? "0";
15405
+ if (bodyEl) {
15406
+ comments.push({
15407
+ id: Number.parseInt(id, 10) || 0,
15408
+ body: bodyEl.textContent?.trim() ?? "",
15409
+ user_login: authorEl?.textContent?.trim() ?? "",
15410
+ html_url: linkEl ? `https://github.com/${params.owner}/${params.repo}/issues/${params.issue_number}#${linkEl.getAttribute("id")}` : "",
15411
+ created_at: timeEl?.getAttribute("datetime") ?? "",
15412
+ updated_at: timeEl?.getAttribute("datetime") ?? ""
15413
+ });
15414
+ }
15415
+ }
15416
+ return { comments };
15012
15417
  }
15013
15418
  });
15014
15419
 
@@ -15016,32 +15421,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15016
15421
  var listCommits = defineTool({
15017
15422
  name: "list_commits",
15018
15423
  displayName: "List Commits",
15019
- description: "List commits for a repository. Optionally filter by branch, tag, or SHA. Returns commits sorted by date descending.",
15424
+ description: "List commits for a repository. Optionally filter by branch or tag. Returns commits sorted by date descending.",
15020
15425
  summary: "List commits for a repository",
15021
15426
  icon: "git-commit",
15022
15427
  group: "Repositories",
15023
15428
  input: external_exports.object({
15024
15429
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
15025
15430
  repo: external_exports.string().min(1).describe("Repository name"),
15026
- sha: external_exports.string().optional().describe("Branch name, tag, or commit SHA to list commits from"),
15027
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15028
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15431
+ sha: external_exports.string().optional().describe("Branch name or tag to list commits from (defaults to the default branch)")
15029
15432
  }),
15030
15433
  output: external_exports.object({
15031
15434
  commits: external_exports.array(commitSchema).describe("List of commits")
15032
15435
  }),
15033
15436
  handle: async (params) => {
15034
- const query = {
15035
- per_page: params.per_page ?? 30,
15036
- page: params.page
15037
- };
15038
- if (params.sha) query.sha = params.sha;
15039
- const data = await api(`/repos/${params.owner}/${params.repo}/commits`, { query });
15040
- return { commits: (data ?? []).map(mapCommit) };
15437
+ const ref = params.sha ?? "HEAD";
15438
+ const data = await pageJson(`/${params.owner}/${params.repo}/commits/${ref}`);
15439
+ const commits = (data.commitGroups ?? []).flatMap((g) => (g.commits ?? []).map(mapCommit));
15440
+ return { commits };
15041
15441
  }
15042
15442
  });
15043
15443
 
15044
15444
  // src/tools/list-issues.ts
15445
+ var ISSUE_INDEX_QUERY_NAME = "IssueIndexPageQuery";
15045
15446
  var listIssues = defineTool({
15046
15447
  name: "list_issues",
15047
15448
  displayName: "List Issues",
@@ -15057,28 +15458,50 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15057
15458
  assignee: external_exports.string().optional().describe('Filter by assignee login, or "none" for unassigned, "*" for any'),
15058
15459
  sort: external_exports.enum(["created", "updated", "comments"]).optional().describe("Sort field (default: created)"),
15059
15460
  direction: external_exports.enum(["asc", "desc"]).optional().describe("Sort direction (default: desc)"),
15060
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15461
+ per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 25)"),
15061
15462
  page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15062
15463
  }),
15063
15464
  output: external_exports.object({
15064
15465
  issues: external_exports.array(issueSchema).describe("List of issues")
15065
15466
  }),
15066
15467
  handle: async (params) => {
15067
- const query = {
15068
- state: params.state ?? "open",
15069
- per_page: params.per_page ?? 30,
15070
- page: params.page,
15071
- sort: params.sort,
15072
- direction: params.direction
15073
- };
15074
- if (params.labels) query.labels = params.labels;
15075
- if (params.assignee) query.assignee = params.assignee;
15076
- const data = await api(`/repos/${params.owner}/${params.repo}/issues`, { query });
15077
- return { issues: (data ?? []).map(mapIssue) };
15468
+ const state = params.state ?? "open";
15469
+ const sort = params.sort ?? "created";
15470
+ const dir = params.direction ?? "desc";
15471
+ const perPage = params.per_page ?? 25;
15472
+ const page = params.page ?? 1;
15473
+ const parts = [`is:issue`, `repo:${params.owner}/${params.repo}`];
15474
+ if (state !== "all") parts.push(`is:${state}`);
15475
+ if (params.labels) {
15476
+ for (const label of params.labels.split(",")) {
15477
+ parts.push(`label:"${label.trim()}"`);
15478
+ }
15479
+ }
15480
+ if (params.assignee) {
15481
+ if (params.assignee === "none") parts.push("no:assignee");
15482
+ else if (params.assignee !== "*") parts.push(`assignee:${params.assignee}`);
15483
+ }
15484
+ parts.push(`sort:${sort}-${dir}`);
15485
+ const query = parts.join(" ");
15486
+ const queryId = await discoverQueryId(ISSUE_INDEX_QUERY_NAME, `/${params.owner}/${params.repo}/issues`, {
15487
+ q: "is:issue is:open"
15488
+ });
15489
+ const skip = (page - 1) * perPage;
15490
+ const data = await graphql(queryId, {
15491
+ owner: params.owner,
15492
+ name: params.repo,
15493
+ query,
15494
+ skip,
15495
+ includeReactions: false
15496
+ });
15497
+ const edges = data?.repository?.search?.edges ?? [];
15498
+ const issues = edges.map((e) => relayNodeToRaw(e.node)).filter((n) => n.__typename === "Issue").map((n) => mapIssue(n, { owner: params.owner, repo: params.repo }));
15499
+ return { issues };
15078
15500
  }
15079
15501
  });
15080
15502
 
15081
15503
  // src/tools/list-labels.ts
15504
+ var LABEL_QUERY_NAME = "RepositoryLabelIndexPageQuery";
15082
15505
  var listLabels = defineTool({
15083
15506
  name: "list_labels",
15084
15507
  displayName: "List Labels",
@@ -15088,20 +15511,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15088
15511
  group: "Issues",
15089
15512
  input: external_exports.object({
15090
15513
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
15091
- repo: external_exports.string().min(1).describe("Repository name"),
15092
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15093
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15514
+ repo: external_exports.string().min(1).describe("Repository name")
15094
15515
  }),
15095
15516
  output: external_exports.object({
15096
15517
  labels: external_exports.array(labelSchema).describe("List of labels")
15097
15518
  }),
15098
15519
  handle: async (params) => {
15099
- const query = {
15100
- per_page: params.per_page ?? 30,
15101
- page: params.page
15102
- };
15103
- const data = await api(`/repos/${params.owner}/${params.repo}/labels`, { query });
15104
- return { labels: (data ?? []).map(mapLabel) };
15520
+ const queryId = await discoverQueryId(LABEL_QUERY_NAME, `/${params.owner}/${params.repo}/labels`);
15521
+ const data = await graphql(queryId, {
15522
+ owner: params.owner,
15523
+ name: params.repo,
15524
+ first: 100,
15525
+ skip: 0
15526
+ });
15527
+ const edges = data?.repository?.labels?.edges ?? [];
15528
+ const labels = edges.map((e) => ({
15529
+ id: 0,
15530
+ // GraphQL returns string IDs, not numeric
15531
+ name: e.node?.name ?? "",
15532
+ color: e.node?.color ?? "",
15533
+ description: e.node?.description ?? ""
15534
+ }));
15535
+ return { labels };
15105
15536
  }
15106
15537
  });
15107
15538
 
@@ -15113,26 +15544,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15113
15544
  summary: "List notifications for the authenticated user",
15114
15545
  icon: "bell",
15115
15546
  group: "Users",
15116
- input: external_exports.object({
15117
- all: external_exports.boolean().optional().describe("Show all notifications including read ones (default: false)"),
15118
- participating: external_exports.boolean().optional().describe("Only show notifications where the user is directly participating (default: false)"),
15119
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15120
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15121
- }),
15547
+ input: external_exports.object({}),
15122
15548
  output: external_exports.object({
15123
15549
  notifications: external_exports.array(notificationSchema).describe("List of notifications")
15124
15550
  }),
15125
- handle: async (params) => {
15126
- const query = {
15127
- per_page: params.per_page ?? 30,
15128
- page: params.page
15129
- };
15130
- if (params.all !== void 0) query.all = params.all;
15131
- if (params.participating !== void 0) query.participating = params.participating;
15132
- const data = await api("/notifications", {
15133
- query
15551
+ handle: async () => {
15552
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
15553
+ const html = await fetchText("/notifications", {
15554
+ headers: { "X-Requested-With": "XMLHttpRequest" }
15134
15555
  });
15135
- return { notifications: (data ?? []).map(mapNotification) };
15556
+ const doc = new DOMParser().parseFromString(html, "text/html");
15557
+ const items = doc.querySelectorAll(".notifications-list-item, .notification-list-item-link");
15558
+ const notifications = [];
15559
+ for (const item of items) {
15560
+ const titleEl = item.querySelector(".markdown-title, .notification-list-item-link");
15561
+ const repoEl = item.querySelector(".notification-list-item-repo, .text-small");
15562
+ const timeEl = item.querySelector("relative-time, time");
15563
+ const typeEl = item.querySelector(".type-icon");
15564
+ notifications.push({
15565
+ id: item.getAttribute("data-notification-id") ?? "",
15566
+ reason: "",
15567
+ unread: item.classList.contains("notification-unread"),
15568
+ subject_title: titleEl?.textContent?.trim() ?? "",
15569
+ subject_type: typeEl?.getAttribute("aria-label") ?? "",
15570
+ subject_url: "",
15571
+ repository_full_name: repoEl?.textContent?.trim() ?? "",
15572
+ updated_at: timeEl?.getAttribute("datetime") ?? ""
15573
+ });
15574
+ }
15575
+ return { notifications };
15136
15576
  }
15137
15577
  });
15138
15578
 
@@ -15140,62 +15580,46 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15140
15580
  var listOrgMembers = defineTool({
15141
15581
  name: "list_org_members",
15142
15582
  displayName: "List Organization Members",
15143
- description: "List public members of a GitHub organization.",
15583
+ description: "List members of a GitHub organization.",
15144
15584
  summary: "List members of an organization",
15145
15585
  icon: "users",
15146
15586
  group: "Users",
15147
15587
  input: external_exports.object({
15148
- org: external_exports.string().min(1).describe("Organization name"),
15149
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15150
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15588
+ org: external_exports.string().min(1).describe("Organization name")
15151
15589
  }),
15152
15590
  output: external_exports.object({
15153
15591
  members: external_exports.array(
15154
15592
  external_exports.object({
15155
15593
  login: external_exports.string().describe("Username"),
15156
- id: external_exports.number().describe("User ID"),
15157
15594
  avatar_url: external_exports.string().describe("Avatar URL"),
15158
15595
  html_url: external_exports.string().describe("Profile URL")
15159
15596
  })
15160
15597
  ).describe("List of organization members")
15161
15598
  }),
15162
15599
  handle: async (params) => {
15163
- const query = {
15164
- per_page: params.per_page ?? 30,
15165
- page: params.page
15166
- };
15167
- const data = await api(
15168
- `/orgs/${params.org}/members`,
15169
- { query }
15170
- );
15171
- return {
15172
- members: (data ?? []).map((m) => ({
15173
- login: m.login ?? "",
15174
- id: m.id ?? 0,
15175
- avatar_url: m.avatar_url ?? "",
15176
- html_url: m.html_url ?? ""
15177
- }))
15178
- };
15600
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
15601
+ const html = await fetchText(`/orgs/${params.org}/people`, {
15602
+ headers: { "X-Requested-With": "XMLHttpRequest" }
15603
+ });
15604
+ const doc = new DOMParser().parseFromString(html, "text/html");
15605
+ const memberEls = doc.querySelectorAll(".member-list-item, [data-bulk-actions-id]");
15606
+ const members = [];
15607
+ for (const el of memberEls) {
15608
+ const linkEl = el.querySelector('a[data-hovercard-type="user"]');
15609
+ const imgEl = el.querySelector("img.avatar");
15610
+ const login = linkEl?.textContent?.trim() ?? "";
15611
+ if (!login) continue;
15612
+ members.push({
15613
+ login,
15614
+ avatar_url: imgEl?.getAttribute("src") ?? "",
15615
+ html_url: `https://github.com/${login}`
15616
+ });
15617
+ }
15618
+ return { members };
15179
15619
  }
15180
15620
  });
15181
15621
 
15182
15622
  // src/tools/list-pull-request-files.ts
15183
- var prFileSchema = external_exports.object({
15184
- filename: external_exports.string().describe("File path"),
15185
- status: external_exports.string().describe("File status: added, removed, modified, renamed, copied, changed, unchanged"),
15186
- additions: external_exports.number().describe("Number of lines added"),
15187
- deletions: external_exports.number().describe("Number of lines deleted"),
15188
- changes: external_exports.number().describe("Total number of line changes"),
15189
- patch: external_exports.string().describe("Unified diff patch text (may be empty for binary files)")
15190
- });
15191
- var mapPrFile = (f) => ({
15192
- filename: f.filename ?? "",
15193
- status: f.status ?? "",
15194
- additions: f.additions ?? 0,
15195
- deletions: f.deletions ?? 0,
15196
- changes: f.changes ?? 0,
15197
- patch: f.patch ?? ""
15198
- });
15199
15623
  var listPullRequestFiles = defineTool({
15200
15624
  name: "list_pull_request_files",
15201
15625
  displayName: "List Pull Request Files",
@@ -15206,26 +15630,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15206
15630
  input: external_exports.object({
15207
15631
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
15208
15632
  repo: external_exports.string().min(1).describe("Repository name"),
15209
- pull_number: external_exports.number().int().min(1).describe("Pull request number"),
15210
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15211
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15633
+ pull_number: external_exports.number().int().min(1).describe("Pull request number")
15212
15634
  }),
15213
15635
  output: external_exports.object({
15214
- files: external_exports.array(prFileSchema).describe("List of changed files")
15636
+ files: external_exports.array(fileDiffSchema).describe("List of changed files")
15215
15637
  }),
15216
15638
  handle: async (params) => {
15217
- const query = {
15218
- per_page: params.per_page ?? 30,
15219
- page: params.page
15220
- };
15221
- const data = await api(`/repos/${params.owner}/${params.repo}/pulls/${params.pull_number}/files`, {
15222
- query
15223
- });
15224
- return { files: (data ?? []).map(mapPrFile) };
15639
+ const data = await pageEmbeddedData(
15640
+ `/${params.owner}/${params.repo}/pull/${params.pull_number}/files`
15641
+ );
15642
+ const summaries = data.pullRequestsChangesRoute?.diffSummaries ?? [];
15643
+ return { files: summaries.map(mapFileDiff) };
15225
15644
  }
15226
15645
  });
15227
15646
 
15228
15647
  // src/tools/list-pull-requests.ts
15648
+ var ISSUE_INDEX_QUERY_NAME2 = "IssueIndexPageQuery";
15229
15649
  var listPullRequests = defineTool({
15230
15650
  name: "list_pull_requests",
15231
15651
  displayName: "List Pull Requests",
@@ -15239,26 +15659,36 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15239
15659
  state: external_exports.enum(["open", "closed", "all"]).optional().describe("PR state filter (default: open)"),
15240
15660
  sort: external_exports.enum(["created", "updated", "popularity", "long-running"]).optional().describe("Sort field (default: created)"),
15241
15661
  direction: external_exports.enum(["asc", "desc"]).optional().describe("Sort direction (default: desc)"),
15242
- head: external_exports.string().optional().describe('Filter by head branch \u2014 format: "user:ref-name" or "ref-name"'),
15243
- base: external_exports.string().optional().describe("Filter by base branch name"),
15244
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15662
+ per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 25)"),
15245
15663
  page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15246
15664
  }),
15247
15665
  output: external_exports.object({
15248
15666
  pull_requests: external_exports.array(pullRequestSchema).describe("List of pull requests")
15249
15667
  }),
15250
15668
  handle: async (params) => {
15251
- const query = {
15252
- state: params.state ?? "open",
15253
- per_page: params.per_page ?? 30,
15254
- page: params.page,
15255
- sort: params.sort,
15256
- direction: params.direction
15257
- };
15258
- if (params.head) query.head = params.head;
15259
- if (params.base) query.base = params.base;
15260
- const data = await api(`/repos/${params.owner}/${params.repo}/pulls`, { query });
15261
- return { pull_requests: (data ?? []).map(mapPullRequest) };
15669
+ const state = params.state ?? "open";
15670
+ const sort = params.sort === "popularity" ? "reactions" : params.sort ?? "created";
15671
+ const dir = params.direction ?? "desc";
15672
+ const perPage = params.per_page ?? 25;
15673
+ const page = params.page ?? 1;
15674
+ const stateFilter = state === "all" ? "" : `is:${state}`;
15675
+ const sortFilter = `sort:${sort}-${dir}`;
15676
+ const query = `is:pr ${stateFilter} repo:${params.owner}/${params.repo} ${sortFilter}`.trim();
15677
+ const queryId = await discoverQueryId(ISSUE_INDEX_QUERY_NAME2, `/${params.owner}/${params.repo}/issues`, {
15678
+ type: "pr",
15679
+ q: "is:pr is:open"
15680
+ });
15681
+ const skip = (page - 1) * perPage;
15682
+ const data = await graphql(queryId, {
15683
+ owner: params.owner,
15684
+ name: params.repo,
15685
+ query,
15686
+ skip,
15687
+ includeReactions: false
15688
+ });
15689
+ const edges = data?.repository?.search?.edges ?? [];
15690
+ const pullRequests = edges.map((e) => relayNodeToRaw(e.node)).filter((n) => n.__typename === "PullRequest").map((n) => mapPullRequest(n, { owner: params.owner, repo: params.repo }));
15691
+ return { pull_requests: pullRequests };
15262
15692
  }
15263
15693
  });
15264
15694
 
@@ -15272,20 +15702,43 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15272
15702
  group: "Repositories",
15273
15703
  input: external_exports.object({
15274
15704
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
15275
- repo: external_exports.string().min(1).describe("Repository name"),
15276
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15277
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15705
+ repo: external_exports.string().min(1).describe("Repository name")
15278
15706
  }),
15279
15707
  output: external_exports.object({
15280
15708
  releases: external_exports.array(releaseSchema).describe("List of releases")
15281
15709
  }),
15282
15710
  handle: async (params) => {
15283
- const query = {
15284
- per_page: params.per_page ?? 30,
15285
- page: params.page
15286
- };
15287
- const data = await api(`/repos/${params.owner}/${params.repo}/releases`, { query });
15288
- return { releases: (data ?? []).map(mapRelease) };
15711
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
15712
+ const html = await fetchText(`/${params.owner}/${params.repo}/releases`, {
15713
+ headers: { "X-Requested-With": "XMLHttpRequest" }
15714
+ });
15715
+ const doc = new DOMParser().parseFromString(html, "text/html");
15716
+ const releaseCards = doc.querySelectorAll('[data-testid="release-card"], .release, section');
15717
+ const releases = [];
15718
+ for (const card of releaseCards) {
15719
+ const tagEl = card.querySelector('[data-testid="release-card-tag"], .release-tag, a[href*="tag"]');
15720
+ const titleEl = card.querySelector('[data-testid="release-card-title"], .release-title, h2 a');
15721
+ const bodyEl = card.querySelector(".markdown-body");
15722
+ const timeEl = card.querySelector("relative-time, time");
15723
+ const authorEl = card.querySelector('a[data-hovercard-type="user"]');
15724
+ const isDraft = card.textContent?.includes("Draft") ?? false;
15725
+ const isPrerelease = card.textContent?.includes("Pre-release") ?? false;
15726
+ const tagName = tagEl?.textContent?.trim() ?? "";
15727
+ if (!tagName) continue;
15728
+ releases.push({
15729
+ id: 0,
15730
+ tag_name: tagName,
15731
+ name: titleEl?.textContent?.trim() ?? tagName,
15732
+ body: bodyEl?.textContent?.trim() ?? "",
15733
+ draft: isDraft,
15734
+ prerelease: isPrerelease,
15735
+ created_at: timeEl?.getAttribute("datetime") ?? "",
15736
+ published_at: timeEl?.getAttribute("datetime") ?? "",
15737
+ html_url: `https://github.com/${params.owner}/${params.repo}/releases/tag/${tagName}`,
15738
+ author_login: authorEl?.textContent?.trim() ?? ""
15739
+ });
15740
+ }
15741
+ return { releases };
15289
15742
  }
15290
15743
  });
15291
15744
 
@@ -15299,7 +15752,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15299
15752
  group: "Repositories",
15300
15753
  input: external_exports.object({
15301
15754
  owner: external_exports.string().optional().describe("Username or org name \u2014 defaults to the authenticated user"),
15302
- type: external_exports.enum(["all", "owner", "public", "private", "member"]).optional().describe("Type filter for user repos (default: all)"),
15303
15755
  sort: external_exports.enum(["created", "updated", "pushed", "full_name"]).optional().describe("Sort field (default: updated)"),
15304
15756
  per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15305
15757
  page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
@@ -15309,22 +15761,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15309
15761
  }),
15310
15762
  handle: async (params) => {
15311
15763
  const owner = params.owner ?? getLogin();
15312
- const isOrg = params.owner !== void 0;
15313
- const query = {
15314
- per_page: params.per_page ?? 30,
15315
- page: params.page,
15316
- sort: params.sort ?? "updated"
15764
+ const sort = params.sort ?? "updated";
15765
+ const sortMap = {
15766
+ updated: "updated",
15767
+ created: "created",
15768
+ pushed: "updated",
15769
+ full_name: "repositories"
15770
+ };
15771
+ const data = await pageJson("/search", {
15772
+ type: "repositories",
15773
+ q: `user:${owner}`,
15774
+ s: sortMap[sort] ?? "updated",
15775
+ o: "desc",
15776
+ p: params.page ?? 1
15777
+ });
15778
+ return {
15779
+ repositories: (data.results ?? []).map((r) => mapRepository(r))
15317
15780
  };
15318
- let endpoint;
15319
- if (isOrg) {
15320
- endpoint = `/users/${owner}/repos`;
15321
- if (params.type) query.type = params.type;
15322
- } else {
15323
- endpoint = "/user/repos";
15324
- if (params.type) query.type = params.type;
15325
- }
15326
- const data = await api(endpoint, { query });
15327
- return { repositories: (data ?? []).map(mapRepository) };
15328
15781
  }
15329
15782
  });
15330
15783
 
@@ -15332,51 +15785,45 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15332
15785
  var listWorkflowRuns = defineTool({
15333
15786
  name: "list_workflow_runs",
15334
15787
  displayName: "List Workflow Runs",
15335
- description: "List workflow runs for a repository. Optionally filter by workflow ID, branch, or status. Returns runs sorted by creation date.",
15788
+ description: "List workflow runs for a repository. Returns recent workflow runs from the Actions page.",
15336
15789
  summary: "List GitHub Actions workflow runs",
15337
15790
  icon: "play",
15338
15791
  group: "Actions",
15339
15792
  input: external_exports.object({
15340
15793
  owner: external_exports.string().min(1).describe("Repository owner (user or org)"),
15341
- repo: external_exports.string().min(1).describe("Repository name"),
15342
- workflow_id: external_exports.string().optional().describe('Workflow ID or filename to filter by (e.g., "ci.yml")'),
15343
- branch: external_exports.string().optional().describe("Filter by branch name"),
15344
- status: external_exports.enum([
15345
- "completed",
15346
- "action_required",
15347
- "cancelled",
15348
- "failure",
15349
- "neutral",
15350
- "skipped",
15351
- "stale",
15352
- "success",
15353
- "timed_out",
15354
- "in_progress",
15355
- "queued",
15356
- "requested",
15357
- "waiting",
15358
- "pending"
15359
- ]).optional().describe("Filter by run status"),
15360
- per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15361
- page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15794
+ repo: external_exports.string().min(1).describe("Repository name")
15362
15795
  }),
15363
15796
  output: external_exports.object({
15364
- total_count: external_exports.number().describe("Total number of matching workflow runs"),
15365
15797
  workflow_runs: external_exports.array(workflowRunSchema).describe("List of workflow runs")
15366
15798
  }),
15367
15799
  handle: async (params) => {
15368
- const query = {
15369
- per_page: params.per_page ?? 30,
15370
- page: params.page
15371
- };
15372
- if (params.branch) query.branch = params.branch;
15373
- if (params.status) query.status = params.status;
15374
- const endpoint = params.workflow_id ? `/repos/${params.owner}/${params.repo}/actions/workflows/${params.workflow_id}/runs` : `/repos/${params.owner}/${params.repo}/actions/runs`;
15375
- const data = await api(endpoint, { query });
15376
- return {
15377
- total_count: data.total_count ?? 0,
15378
- workflow_runs: (data.workflow_runs ?? []).map(mapWorkflowRun)
15379
- };
15800
+ if (!isAuthenticated()) throw ToolError.auth("Not authenticated \u2014 please log in to GitHub.");
15801
+ const html = await fetchText(`/${params.owner}/${params.repo}/actions`, {
15802
+ headers: { "X-Requested-With": "XMLHttpRequest" }
15803
+ });
15804
+ const doc = new DOMParser().parseFromString(html, "text/html");
15805
+ const rows = doc.querySelectorAll('.ActionListItem, [data-testid="workflow-run-row"]');
15806
+ const runs = [];
15807
+ for (const row of rows) {
15808
+ const titleEl = row.querySelector("a.Link--primary, .workflow-run-title");
15809
+ const statusEl = row.querySelector('[data-testid="workflow-run-status"], .octicon-check, .octicon-x');
15810
+ const branchEl = row.querySelector('a[href*="tree/"]');
15811
+ const timeEl = row.querySelector("relative-time, time");
15812
+ const href = titleEl?.getAttribute("href") ?? "";
15813
+ const idMatch = href.match(/\/runs\/(\d+)/);
15814
+ runs.push({
15815
+ id: idMatch?.[1] ? Number.parseInt(idMatch[1], 10) : 0,
15816
+ name: titleEl?.textContent?.trim() ?? "",
15817
+ status: statusEl?.getAttribute("aria-label") ?? "",
15818
+ conclusion: "",
15819
+ head_branch: branchEl?.textContent?.trim() ?? "",
15820
+ head_sha: "",
15821
+ html_url: href ? `https://github.com${href}` : "",
15822
+ created_at: timeEl?.getAttribute("datetime") ?? "",
15823
+ updated_at: timeEl?.getAttribute("datetime") ?? ""
15824
+ });
15825
+ }
15826
+ return { workflow_runs: runs };
15380
15827
  }
15381
15828
  });
15382
15829
 
@@ -15394,24 +15841,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15394
15841
  pull_number: external_exports.number().int().min(1).describe("Pull request number"),
15395
15842
  commit_title: external_exports.string().optional().describe("Title for the merge commit"),
15396
15843
  commit_message: external_exports.string().optional().describe("Extra detail for the merge commit"),
15397
- merge_method: external_exports.enum(["merge", "squash", "rebase"]).optional().describe("Merge strategy (default: merge)")
15844
+ merge_method: external_exports.enum(["merge", "squash", "rebase"]).optional().describe("Merge strategy (default: squash)")
15398
15845
  }),
15399
15846
  output: external_exports.object({
15400
- sha: external_exports.string().describe("SHA of the merge commit"),
15401
- message: external_exports.string().describe("Merge result message"),
15402
- merged: external_exports.boolean().describe("Whether the merge succeeded")
15847
+ success: external_exports.boolean().describe("Whether the merge was initiated")
15403
15848
  }),
15404
15849
  handle: async (params) => {
15405
- const body = {};
15406
- if (params.commit_title) body.commit_title = params.commit_title;
15407
- if (params.commit_message) body.commit_message = params.commit_message;
15408
- if (params.merge_method) body.merge_method = params.merge_method;
15409
- const data = await api(`/repos/${params.owner}/${params.repo}/pulls/${params.pull_number}/merge`, { method: "PUT", body });
15410
- return {
15411
- sha: data.sha ?? "",
15412
- message: data.message ?? "",
15413
- merged: data.merged ?? false
15850
+ const fields = {
15851
+ _method: "put"
15414
15852
  };
15853
+ if (params.commit_title) fields.commit_title = params.commit_title;
15854
+ if (params.commit_message) fields.commit_message = params.commit_message;
15855
+ if (params.merge_method) fields.merge_method = params.merge_method;
15856
+ await submitPageForm(
15857
+ `/${params.owner}/${params.repo}/pull/${params.pull_number}`,
15858
+ `form[action$="/pull/${params.pull_number}/merge"]`,
15859
+ fields
15860
+ );
15861
+ return { success: true };
15415
15862
  }
15416
15863
  });
15417
15864
 
@@ -15431,17 +15878,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15431
15878
  team_reviewers: external_exports.array(external_exports.string()).optional().describe("Array of team slugs to request review from")
15432
15879
  }),
15433
15880
  output: external_exports.object({
15434
- pull_request: pullRequestSchema.describe("The pull request with updated reviewers")
15881
+ success: external_exports.boolean().describe("Whether the review request was submitted")
15435
15882
  }),
15436
15883
  handle: async (params) => {
15437
- const body = {};
15438
- if (params.reviewers !== void 0) body.reviewers = params.reviewers;
15439
- if (params.team_reviewers !== void 0) body.team_reviewers = params.team_reviewers;
15440
- const data = await api(
15441
- `/repos/${params.owner}/${params.repo}/pulls/${params.pull_number}/requested_reviewers`,
15442
- { method: "POST", body }
15884
+ const fields = {
15885
+ "dummy-field-just-to-avoid-empty-submit": "foo"
15886
+ };
15887
+ if (params.reviewers) {
15888
+ for (const reviewer of params.reviewers) {
15889
+ fields["reviewer_user_logins[]"] = reviewer;
15890
+ }
15891
+ }
15892
+ if (params.team_reviewers) {
15893
+ for (const team of params.team_reviewers) {
15894
+ fields["reviewer_team_slugs[]"] = team;
15895
+ }
15896
+ }
15897
+ await submitPageForm(
15898
+ `/${params.owner}/${params.repo}/pull/${params.pull_number}`,
15899
+ 'form[action*="review-requests"]',
15900
+ fields
15443
15901
  );
15444
- return { pull_request: mapPullRequest(data) };
15902
+ return { success: true };
15445
15903
  }
15446
15904
  });
15447
15905
 
@@ -15457,8 +15915,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15457
15915
  query: external_exports.string().min(1).describe(
15458
15916
  'Search query using GitHub search syntax (e.g., "repo:owner/name is:open label:bug", "org:myorg is:pr is:merged")'
15459
15917
  ),
15460
- sort: external_exports.enum(["comments", "reactions", "reactions-+1", "reactions--1", "interactions", "created", "updated"]).optional().describe("Sort field"),
15461
- order: external_exports.enum(["asc", "desc"]).optional().describe("Sort order (default: desc)"),
15462
15918
  per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15463
15919
  page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15464
15920
  }),
@@ -15467,17 +15923,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15467
15923
  issues: external_exports.array(issueSchema).describe("List of matching issues/PRs")
15468
15924
  }),
15469
15925
  handle: async (params) => {
15470
- const query = {
15926
+ const data = await pageJson("/search", {
15927
+ type: "issues",
15471
15928
  q: params.query,
15472
- per_page: params.per_page ?? 30,
15473
- page: params.page
15474
- };
15475
- if (params.sort) query.sort = params.sort;
15476
- if (params.order) query.order = params.order;
15477
- const data = await api("/search/issues", { query });
15929
+ p: params.page ?? 1
15930
+ });
15931
+ const issues = (data.results ?? []).map((r) => {
15932
+ const owner = r.repo?.repository?.owner_login ?? "";
15933
+ const repo = r.repo?.repository?.name ?? "";
15934
+ const isPR = r.issue?.issue?.pull_request_id !== null && r.issue?.issue?.pull_request_id !== void 0;
15935
+ return mapIssue(
15936
+ {
15937
+ number: r.number,
15938
+ title: r.hl_title?.replace(/<\/?em>/g, ""),
15939
+ state: r.state,
15940
+ created_at: r.created,
15941
+ updated_at: r.updated,
15942
+ closed_at: r.closed_at,
15943
+ labels: r.labels,
15944
+ pull_request: isPR ? {} : void 0,
15945
+ user: { login: r.author_name }
15946
+ },
15947
+ { owner, repo }
15948
+ );
15949
+ });
15478
15950
  return {
15479
- total_count: data.total_count ?? 0,
15480
- issues: (data.items ?? []).map(mapIssue)
15951
+ total_count: data.result_count ?? 0,
15952
+ issues
15481
15953
  };
15482
15954
  }
15483
15955
  });
@@ -15492,8 +15964,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15492
15964
  group: "Search",
15493
15965
  input: external_exports.object({
15494
15966
  query: external_exports.string().min(1).describe('Search query using GitHub search syntax (e.g., "language:typescript stars:>1000")'),
15495
- sort: external_exports.enum(["stars", "forks", "help-wanted-issues", "updated"]).optional().describe("Sort field"),
15496
- order: external_exports.enum(["asc", "desc"]).optional().describe("Sort order (default: desc)"),
15497
15967
  per_page: external_exports.number().int().min(1).max(100).optional().describe("Results per page (default 30, max 100)"),
15498
15968
  page: external_exports.number().int().min(1).optional().describe("Page number (default 1)")
15499
15969
  }),
@@ -15502,17 +15972,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15502
15972
  repositories: external_exports.array(repositorySchema).describe("List of matching repositories")
15503
15973
  }),
15504
15974
  handle: async (params) => {
15505
- const query = {
15975
+ const data = await pageJson("/search", {
15976
+ type: "repositories",
15506
15977
  q: params.query,
15507
- per_page: params.per_page ?? 30,
15508
- page: params.page,
15509
- sort: params.sort,
15510
- order: params.order
15511
- };
15512
- const data = await api("/search/repositories", { query });
15978
+ p: params.page ?? 1
15979
+ });
15513
15980
  return {
15514
- total_count: data.total_count ?? 0,
15515
- repositories: (data.items ?? []).map(mapRepository)
15981
+ total_count: data.result_count ?? 0,
15982
+ repositories: (data.results ?? []).map((r) => mapRepository(r))
15516
15983
  };
15517
15984
  }
15518
15985
  });
@@ -15531,25 +15998,38 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15531
15998
  issue_number: external_exports.number().int().min(1).describe("Issue number"),
15532
15999
  title: external_exports.string().optional().describe("New issue title"),
15533
16000
  body: external_exports.string().optional().describe("New issue body in Markdown"),
15534
- state: external_exports.enum(["open", "closed"]).optional().describe("Set issue state"),
15535
- labels: external_exports.array(external_exports.string()).optional().describe("Replace all labels with these names"),
15536
- assignees: external_exports.array(external_exports.string()).optional().describe("Replace all assignees with these logins")
16001
+ state: external_exports.enum(["open", "closed"]).optional().describe("Set issue state")
15537
16002
  }),
15538
16003
  output: external_exports.object({
15539
- issue: issueSchema.describe("The updated issue")
16004
+ success: external_exports.boolean().describe("Whether the update succeeded")
15540
16005
  }),
15541
16006
  handle: async (params) => {
15542
- const body = {};
15543
- if (params.title !== void 0) body.title = params.title;
15544
- if (params.body !== void 0) body.body = params.body;
15545
- if (params.state !== void 0) body.state = params.state;
15546
- if (params.labels !== void 0) body.labels = params.labels;
15547
- if (params.assignees !== void 0) body.assignees = params.assignees;
15548
- const data = await api(
15549
- `/repos/${params.owner}/${params.repo}/issues/${params.issue_number}`,
15550
- { method: "PATCH", body }
15551
- );
15552
- return { issue: mapIssue(data) };
16007
+ const fields = {
16008
+ _method: "put"
16009
+ };
16010
+ if (params.title !== void 0) fields["issue[title]"] = params.title;
16011
+ if (params.body !== void 0) fields["issue[body]"] = params.body;
16012
+ if (params.state === "closed") {
16013
+ await submitPageForm(
16014
+ `/${params.owner}/${params.repo}/issues/${params.issue_number}`,
16015
+ "form.js-new-comment-form",
16016
+ { comment_and_close: "1", "comment[body]": "" }
16017
+ );
16018
+ } else if (params.state === "open") {
16019
+ await submitPageForm(
16020
+ `/${params.owner}/${params.repo}/issues/${params.issue_number}`,
16021
+ "form.js-new-comment-form",
16022
+ { comment_and_reopen: "1", "comment[body]": "" }
16023
+ );
16024
+ }
16025
+ if (params.title !== void 0 || params.body !== void 0) {
16026
+ await submitPageForm(
16027
+ `/${params.owner}/${params.repo}/issues/${params.issue_number}`,
16028
+ `form.js-comment-update[action$="/issues/${params.issue_number}"]`,
16029
+ fields
16030
+ );
16031
+ }
16032
+ return { success: true };
15553
16033
  }
15554
16034
  });
15555
16035
 
@@ -15557,7 +16037,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15557
16037
  var updatePullRequest = defineTool({
15558
16038
  name: "update_pull_request",
15559
16039
  displayName: "Update Pull Request",
15560
- description: "Update an existing pull request. Only specified fields are changed; omitted fields remain unchanged.",
16040
+ description: "Update an existing pull request title or body, or close/reopen it.",
15561
16041
  summary: "Update a pull request",
15562
16042
  icon: "git-pull-request",
15563
16043
  group: "Pull Requests",
@@ -15567,25 +16047,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15567
16047
  pull_number: external_exports.number().int().min(1).describe("Pull request number"),
15568
16048
  title: external_exports.string().optional().describe("New pull request title"),
15569
16049
  body: external_exports.string().optional().describe("New pull request body in Markdown"),
15570
- state: external_exports.enum(["open", "closed"]).optional().describe("Set PR state"),
15571
- base: external_exports.string().optional().describe("New target branch name to merge into"),
15572
- draft: external_exports.boolean().optional().describe("Convert to draft or ready for review")
16050
+ state: external_exports.enum(["open", "closed"]).optional().describe("Set PR state (close or reopen)")
15573
16051
  }),
15574
16052
  output: external_exports.object({
15575
- pull_request: pullRequestSchema.describe("The updated pull request")
16053
+ success: external_exports.boolean().describe("Whether the update succeeded")
15576
16054
  }),
15577
16055
  handle: async (params) => {
15578
- const body = {};
15579
- if (params.title !== void 0) body.title = params.title;
15580
- if (params.body !== void 0) body.body = params.body;
15581
- if (params.state !== void 0) body.state = params.state;
15582
- if (params.base !== void 0) body.base = params.base;
15583
- if (params.draft !== void 0) body.draft = params.draft;
15584
- const data = await api(
15585
- `/repos/${params.owner}/${params.repo}/pulls/${params.pull_number}`,
15586
- { method: "PATCH", body }
15587
- );
15588
- return { pull_request: mapPullRequest(data) };
16056
+ const pagePath = `/${params.owner}/${params.repo}/pull/${params.pull_number}`;
16057
+ if (params.state === "closed") {
16058
+ await submitPageForm(pagePath, "form.js-new-comment-form", {
16059
+ comment_and_close: "1",
16060
+ "comment[body]": ""
16061
+ });
16062
+ } else if (params.state === "open") {
16063
+ await submitPageForm(pagePath, "form.js-new-comment-form", {
16064
+ comment_and_reopen: "1",
16065
+ "comment[body]": ""
16066
+ });
16067
+ }
16068
+ if (params.title !== void 0 || params.body !== void 0) {
16069
+ const fields = { _method: "put" };
16070
+ if (params.title !== void 0) fields["issue[title]"] = params.title;
16071
+ if (params.body !== void 0) fields["issue[body]"] = params.body;
16072
+ await submitPageForm(pagePath, `form.js-comment-update[action$="/issues/${params.pull_number}"]`, fields);
16073
+ }
16074
+ return { success: true };
15589
16075
  }
15590
16076
  });
15591
16077
 
@@ -15650,7 +16136,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15650
16136
  };
15651
16137
  var src_default = new GitHubPlugin();
15652
16138
 
15653
- // dist/_adapter_entry_81bc4434-49a3-4175-89c4-824103523f96.ts
16139
+ // dist/_adapter_entry_ebe57b7d-b113-4bee-ac8c-48712d79acfe.ts
15654
16140
  if (!globalThis.__openTabs) {
15655
16141
  globalThis.__openTabs = {};
15656
16142
  } else {
@@ -15866,5 +16352,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15866
16352
  };
15867
16353
  delete src_default.onDeactivate;
15868
16354
  }
15869
- })();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["github"]){var a=o.adapters["github"];a.__adapterHash="eaeffc6a59ae91d862c2fbf0f20fa03c45a069a6d97f797b7b3827ddb5454cfb";if(a.tools&&Array.isArray(a.tools)){for(var i=0;i<a.tools.length;i++){Object.freeze(a.tools[i]);}Object.freeze(a.tools);}Object.freeze(a);Object.defineProperty(o.adapters,"github",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
16355
+ })();(function(){var o=(globalThis).__openTabs;if(o&&o.adapters&&o.adapters["github"]){var a=o.adapters["github"];a.__adapterHash="f078e1e5083ccb3605e75a51f355120cb8ffb21fbb250e4eee39ccc19ba35616";if(a.tools&&Array.isArray(a.tools)){for(var i=0;i<a.tools.length;i++){Object.freeze(a.tools[i]);}Object.freeze(a.tools);}Object.freeze(a);Object.defineProperty(o.adapters,"github",{value:a,writable:false,configurable:false,enumerable:true});Object.defineProperty(o,"adapters",{value:o.adapters,writable:false,configurable:false});}})();
15870
16356
  //# sourceMappingURL=adapter.iife.js.map