@weavetab/mcp 2.5.0-beta.5 → 2.5.1

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 (160) hide show
  1. package/AGENTS.md +49 -49
  2. package/ARCHITECTURE.md +590 -590
  3. package/README.md +216 -100
  4. package/SECURITY.md +207 -207
  5. package/TROUBLESHOOTING.md +373 -365
  6. package/dist/anticaptcha/detector.js +395 -395
  7. package/dist/anticaptcha/solver.js +130 -130
  8. package/dist/cdp/bridge.js +73 -73
  9. package/dist/cdp/connector.js +46 -22
  10. package/dist/cdp/extension.js +34 -34
  11. package/dist/cdp/helpers.js +174 -174
  12. package/dist/cdp/pruner.js +195 -195
  13. package/dist/cdp/ref_cache.js +66 -66
  14. package/dist/cdp/security.js +10 -10
  15. package/dist/cdp/verify.js +57 -57
  16. package/dist/cdp/walker.js +563 -525
  17. package/dist/cli/plugin.js +26 -3
  18. package/dist/config/loader.d.ts +0 -3
  19. package/dist/config/loader.js +0 -9
  20. package/dist/index.js +0 -4
  21. package/dist/intelligence/intent.js +81 -81
  22. package/dist/intelligence/sessionMemory.js +2 -2
  23. package/dist/overlay/ghost.js +22 -22
  24. package/dist/overlay/injector.js +89 -89
  25. package/dist/plugin/extension_bridge.js +54 -54
  26. package/dist/plugin/interface.d.ts +7 -0
  27. package/dist/plugin/loader.js +3 -4
  28. package/dist/plugin/schema.d.ts +11 -0
  29. package/dist/plugin/schema.js +59 -0
  30. package/dist/security/guard.js +18 -18
  31. package/dist/sensors/actionability.js +167 -167
  32. package/dist/sensors/guard.js +29 -29
  33. package/dist/sensors/network.js +15 -17
  34. package/dist/server.d.ts +1 -1
  35. package/dist/server.js +173 -144
  36. package/dist/state/delta.js +6 -7
  37. package/dist/tools/automation.js +85 -85
  38. package/dist/tools/canvas.js +48 -25
  39. package/dist/tools/checkpoint.js +94 -35
  40. package/dist/tools/click.js +52 -41
  41. package/dist/tools/clipboard.js +80 -74
  42. package/dist/tools/design_extract.js +441 -441
  43. package/dist/tools/dialog.js +13 -13
  44. package/dist/tools/emulation.d.ts +2 -0
  45. package/dist/tools/emulation.js +7 -0
  46. package/dist/tools/fill.js +344 -347
  47. package/dist/tools/find.js +78 -52
  48. package/dist/tools/highlight.js +67 -67
  49. package/dist/tools/inspect.js +54 -25
  50. package/dist/tools/key.js +42 -35
  51. package/dist/tools/navigate.d.ts +1 -1
  52. package/dist/tools/navigate.js +35 -35
  53. package/dist/tools/office/parse.js +62 -18
  54. package/dist/tools/pdf.d.ts +9 -0
  55. package/dist/tools/pdf.js +7 -4
  56. package/dist/tools/performance.d.ts +11 -4
  57. package/dist/tools/performance.js +94 -42
  58. package/dist/tools/performance_test.d.ts +2 -2
  59. package/dist/tools/performance_test.js +69 -69
  60. package/dist/tools/pointer.js +116 -116
  61. package/dist/tools/read.js +99 -67
  62. package/dist/tools/recording.js +9 -0
  63. package/dist/tools/scrape.js +146 -146
  64. package/dist/tools/screenshot.d.ts +2 -0
  65. package/dist/tools/screenshot.js +46 -4
  66. package/dist/tools/scroll.d.ts +3 -1
  67. package/dist/tools/scroll.js +13 -15
  68. package/dist/tools/select.d.ts +3 -0
  69. package/dist/tools/select.js +131 -124
  70. package/dist/tools/snapshot.js +8 -6
  71. package/dist/tools/storage.d.ts +5 -1
  72. package/dist/tools/storage.js +16 -0
  73. package/dist/tools/tabs.d.ts +7 -5
  74. package/dist/tools/tabs.js +79 -26
  75. package/dist/tools/thought.js +8 -8
  76. package/dist/tools/type.js +274 -274
  77. package/dist/tools/type_secret.js +23 -23
  78. package/dist/tools/upload.js +3 -3
  79. package/dist/tools/video_compiler.js +9 -0
  80. package/dist/tools/wait.js +35 -35
  81. package/dist/version.d.ts +1 -1
  82. package/dist/version.js +1 -1
  83. package/docs/DOCUMENTATION.md +583 -585
  84. package/docs/PLUGINS.md +139 -121
  85. package/docs/TOOLS.md +3 -4
  86. package/docs/architecture/blind-injection.md +83 -83
  87. package/docs/architecture/overview.md +49 -49
  88. package/docs/configuration/configuration.md +39 -27
  89. package/docs/configuration/folders.md +62 -55
  90. package/docs/desktop-automation/electron-apps.md +225 -214
  91. package/docs/get-started/installation.md +1 -1
  92. package/docs/get-started/introduction.md +60 -60
  93. package/docs/get-started/quickstart.md +2 -2
  94. package/docs/get-started/setup-wizard.md +1 -1
  95. package/docs/intelligence/site-profiles.md +151 -151
  96. package/docs/tools/tools.md +582 -631
  97. package/docs/troubleshooting/trouble-loop.md +31 -31
  98. package/ext-dist/background.js +415 -415
  99. package/ext-dist/content.js +2527 -2527
  100. package/ext-dist/dashboard.html +583 -583
  101. package/ext-dist/hud/hud.js +3 -3
  102. package/ext-dist/hud/index.html +20 -20
  103. package/ext-dist/manifest.json +73 -73
  104. package/ext-dist/styles.css +223 -223
  105. package/mcp.json +796 -805
  106. package/package.json +8 -8
  107. package/server.json +23 -23
  108. package/smithery.yaml +7 -11
  109. package/dist/cdp/walker.test.d.ts +0 -2
  110. package/dist/cdp/walker.test.js +0 -172
  111. package/dist/intelligence/sessionMemory.test.d.ts +0 -2
  112. package/dist/intelligence/sessionMemory.test.js +0 -62
  113. package/dist/intelligence/trail.test.d.ts +0 -2
  114. package/dist/intelligence/trail.test.js +0 -110
  115. package/dist/state/cache.test.d.ts +0 -2
  116. package/dist/state/cache.test.js +0 -76
  117. package/dist/state/delta.test.d.ts +0 -2
  118. package/dist/state/delta.test.js +0 -279
  119. package/dist/state/groups.d.ts +0 -15
  120. package/dist/state/groups.js +0 -80
  121. package/dist/tools/accessibility.d.ts +0 -14
  122. package/dist/tools/accessibility.js +0 -32
  123. package/dist/tools/ask.d.ts +0 -14
  124. package/dist/tools/ask.js +0 -49
  125. package/dist/tools/click_and_wait.d.ts +0 -33
  126. package/dist/tools/click_and_wait.js +0 -149
  127. package/dist/tools/drag.d.ts +0 -15
  128. package/dist/tools/drag.js +0 -29
  129. package/dist/tools/geo.d.ts +0 -19
  130. package/dist/tools/geo.js +0 -29
  131. package/dist/tools/github/analyze.d.ts +0 -4
  132. package/dist/tools/github/analyze.js +0 -113
  133. package/dist/tools/github/cache.d.ts +0 -21
  134. package/dist/tools/github/cache.js +0 -28
  135. package/dist/tools/github/index.d.ts +0 -19
  136. package/dist/tools/github/index.js +0 -40
  137. package/dist/tools/github/issues.d.ts +0 -9
  138. package/dist/tools/github/issues.js +0 -88
  139. package/dist/tools/github/pr.d.ts +0 -5
  140. package/dist/tools/github/pr.js +0 -88
  141. package/dist/tools/github/rateLimiter.d.ts +0 -4
  142. package/dist/tools/github/rateLimiter.js +0 -46
  143. package/dist/tools/github/read.d.ts +0 -34
  144. package/dist/tools/github/read.js +0 -74
  145. package/dist/tools/github/repoContext.d.ts +0 -20
  146. package/dist/tools/github/repoContext.js +0 -129
  147. package/dist/tools/hover.d.ts +0 -19
  148. package/dist/tools/hover.js +0 -57
  149. package/dist/tools/integration.test.d.ts +0 -2
  150. package/dist/tools/integration.test.js +0 -96
  151. package/dist/tools/macro_compiler.d.ts +0 -7
  152. package/dist/tools/macro_compiler.js +0 -82
  153. package/dist/tools/mouse.d.ts +0 -21
  154. package/dist/tools/mouse.js +0 -62
  155. package/dist/tools/response.d.ts +0 -129
  156. package/dist/tools/response.js +0 -5
  157. package/dist/tools/wait_for.d.ts +0 -23
  158. package/dist/tools/wait_for.js +0 -30
  159. package/dist/tools/windows.d.ts +0 -22
  160. package/dist/tools/windows.js +0 -57
@@ -1,15 +0,0 @@
1
- /**
2
- * Weavetab — tools/drag.ts
3
- * browser_drag: mousedown on sourceNodeId, mousemove to targetNodeId, mouseup.
4
- * Weavetab by fy2ne
5
- */
6
- import CDP from "chrome-remote-interface";
7
- import type { Config } from "../config/loader.js";
8
- export interface DragOptions {
9
- sourceNodeId: number;
10
- targetNodeId: number;
11
- }
12
- export declare function browserDrag(session: CDP.Client, options: DragOptions, _config: Config): Promise<{
13
- success: boolean;
14
- }>;
15
- //# sourceMappingURL=drag.d.ts.map
@@ -1,29 +0,0 @@
1
- export async function browserDrag(session, options, _config) {
2
- const { sourceNodeId, targetNodeId } = options;
3
- if (!sourceNodeId || !targetNodeId) {
4
- throw new Error("browser_drag requires sourceNodeId and targetNodeId");
5
- }
6
- const getCoords = async (nodeId) => {
7
- const { model } = await session.DOM.getBoxModel({ backendNodeId: nodeId });
8
- return {
9
- x: (model.content[0] + model.content[2]) / 2,
10
- y: (model.content[1] + model.content[5]) / 2
11
- };
12
- };
13
- const src = await getCoords(sourceNodeId);
14
- const tgt = await getCoords(targetNodeId);
15
- // 1. Move to source
16
- await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: src.x, y: src.y });
17
- // 2. Mouse down
18
- await session.Input.dispatchMouseEvent({ type: "mousePressed", x: src.x, y: src.y, button: "left", clickCount: 1 });
19
- // Small delay to let UI react (e.g. drag start handlers)
20
- await new Promise(r => setTimeout(r, 100));
21
- // 3. Move to target with button held
22
- // In a real smooth drag, we'd interpolate this, but a direct move often works.
23
- await session.Input.dispatchMouseEvent({ type: "mouseMoved", x: tgt.x, y: tgt.y, button: "left" });
24
- await new Promise(r => setTimeout(r, 100));
25
- // 4. Mouse up
26
- await session.Input.dispatchMouseEvent({ type: "mouseReleased", x: tgt.x, y: tgt.y, button: "left", clickCount: 1 });
27
- return { success: true };
28
- }
29
- //# sourceMappingURL=drag.js.map
@@ -1,19 +0,0 @@
1
- /**
2
- * Weavetab — tools/geo.ts
3
- * browser_geo: Override geolocation and timezone.
4
- * Weavetab by fy2ne
5
- */
6
- import CDP from "chrome-remote-interface";
7
- import type { Config } from "../config/loader.js";
8
- export interface GeoOptions {
9
- action: "set" | "clear";
10
- latitude?: number;
11
- longitude?: number;
12
- accuracy?: number;
13
- timezoneId?: string;
14
- }
15
- export declare function browserGeo(session: CDP.Client, options: GeoOptions, _config: Config): Promise<{
16
- success: boolean;
17
- message: string;
18
- }>;
19
- //# sourceMappingURL=geo.d.ts.map
package/dist/tools/geo.js DELETED
@@ -1,29 +0,0 @@
1
- export async function browserGeo(session, options, _config) {
2
- const { action, latitude, longitude, accuracy = 100, timezoneId } = options;
3
- if (action === "clear") {
4
- await session.Emulation.clearGeolocationOverride();
5
- await session.Emulation.setTimezoneOverride({ timezoneId: "" });
6
- return { success: true, message: "Cleared geolocation and timezone overrides" };
7
- }
8
- if (action === "set") {
9
- let msg = "";
10
- if (latitude !== undefined && longitude !== undefined) {
11
- await session.Emulation.setGeolocationOverride({
12
- latitude,
13
- longitude,
14
- accuracy
15
- });
16
- msg += `Geolocation set to ${latitude}, ${longitude}. `;
17
- }
18
- if (timezoneId) {
19
- await session.Emulation.setTimezoneOverride({ timezoneId });
20
- msg += `Timezone set to ${timezoneId}.`;
21
- }
22
- if (!msg) {
23
- throw new Error("Must provide latitude/longitude or timezoneId to set");
24
- }
25
- return { success: true, message: msg.trim() };
26
- }
27
- throw new Error("Unknown action");
28
- }
29
- //# sourceMappingURL=geo.js.map
@@ -1,4 +0,0 @@
1
- import CDP from "chrome-remote-interface";
2
- import type { Config } from "../../config/loader.js";
3
- import { GithubRepoCache } from "./cache.js";
4
- export declare function githubAnalyze(session: CDP.Client, config: Config, repoSlug?: string): Promise<import("./repoContext.js").GithubToolError | GithubRepoCache>;
@@ -1,113 +0,0 @@
1
- import { getRepoContext, isGithubError } from "./repoContext.js";
2
- import { loadRepoCache, saveRepoCache } from "./cache.js";
3
- import { canMakeApiCall, handleApiResponse } from "./rateLimiter.js";
4
- export async function githubAnalyze(session, config, repoSlug) {
5
- const context = await getRepoContext(session, repoSlug);
6
- if (isGithubError(context))
7
- return context;
8
- const { owner, repo } = context;
9
- // Check cache
10
- const cached = await loadRepoCache(owner, repo, config);
11
- if (cached) {
12
- return cached;
13
- }
14
- // Check rate limit before proceeding
15
- const rateLimitCheck = canMakeApiCall();
16
- if (isGithubError(rateLimitCheck))
17
- return rateLimitCheck;
18
- // 1. Fetch repo metadata
19
- const repoUrl = `https://api.github.com/repos/${owner}/${repo}`;
20
- const repoRes = await fetch(repoUrl, {
21
- headers: {
22
- "Accept": "application/vnd.github.v3+json",
23
- "User-Agent": "Weavetab-MCP"
24
- }
25
- });
26
- const handledRepoRes = handleApiResponse(repoRes);
27
- if (isGithubError(handledRepoRes))
28
- return handledRepoRes;
29
- if (repoRes.status === 404) {
30
- return {
31
- error: "REPO_NOT_FOUND",
32
- message: "Repository not found or not accessible. Note: Only public repositories are supported."
33
- };
34
- }
35
- if (!repoRes.ok) {
36
- return {
37
- error: "API_ERROR",
38
- message: `GitHub API error: ${repoRes.statusText}`
39
- };
40
- }
41
- const repoData = await repoRes.json();
42
- const default_branch = repoData.default_branch || "main";
43
- const description = repoData.description || null;
44
- const language = repoData.language || null;
45
- // Check rate limit again just in case
46
- const rateLimitCheck2 = canMakeApiCall();
47
- if (isGithubError(rateLimitCheck2))
48
- return rateLimitCheck2;
49
- // 2. Fetch file tree
50
- const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${default_branch}?recursive=1`;
51
- const treeRes = await fetch(treeUrl, {
52
- headers: {
53
- "Accept": "application/vnd.github.v3+json",
54
- "User-Agent": "Weavetab-MCP"
55
- }
56
- });
57
- const handledTreeRes = handleApiResponse(treeRes);
58
- if (isGithubError(handledTreeRes))
59
- return handledTreeRes;
60
- let file_tree = [];
61
- if (treeRes.ok) {
62
- const treeData = await treeRes.json();
63
- if (treeData.tree && Array.isArray(treeData.tree)) {
64
- // Pick flat structure - it's more compact and easy to grep
65
- file_tree = treeData.tree.map((t) => ({
66
- path: t.path,
67
- mode: t.mode,
68
- type: t.type,
69
- sha: t.sha,
70
- size: t.size,
71
- url: t.url
72
- }));
73
- }
74
- }
75
- // 3. Fetch README (raw)
76
- let readme_snippet = "";
77
- // Check common README paths
78
- const possibleReadmes = ["README.md", "README", "readme.md", "Readme.md", "README.txt"];
79
- const readmeEntry = file_tree.find(f => possibleReadmes.includes(f.path));
80
- if (readmeEntry) {
81
- const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${default_branch}/${readmeEntry.path}`;
82
- try {
83
- const controller = new AbortController();
84
- const timeout = setTimeout(() => controller.abort(), 10000);
85
- const rawRes = await fetch(rawUrl, { signal: controller.signal });
86
- clearTimeout(timeout);
87
- if (rawRes.ok) {
88
- const fullReadme = await rawRes.text();
89
- // Truncate snippet to first 100 lines
90
- const lines = fullReadme.split('\n');
91
- readme_snippet = lines.slice(0, 100).join('\n');
92
- if (lines.length > 100) {
93
- readme_snippet += "\n\n... (truncated)";
94
- }
95
- }
96
- }
97
- catch {
98
- // ignore
99
- }
100
- }
101
- const cacheData = {
102
- owner,
103
- repo,
104
- default_branch,
105
- description,
106
- language,
107
- file_tree,
108
- readme_snippet,
109
- analyzed_at: Date.now()
110
- };
111
- await saveRepoCache(cacheData);
112
- return cacheData;
113
- }
@@ -1,21 +0,0 @@
1
- import type { Config } from "../../config/loader.js";
2
- export interface TreeEntry {
3
- path: string;
4
- mode: string;
5
- type: string;
6
- sha: string;
7
- size?: number;
8
- url: string;
9
- }
10
- export interface GithubRepoCache {
11
- owner: string;
12
- repo: string;
13
- default_branch: string;
14
- description: string | null;
15
- language: string | null;
16
- file_tree: TreeEntry[];
17
- readme_snippet: string;
18
- analyzed_at: number;
19
- }
20
- export declare function loadRepoCache(owner: string, repo: string, config: Config): Promise<GithubRepoCache | null>;
21
- export declare function saveRepoCache(data: GithubRepoCache): Promise<void>;
@@ -1,28 +0,0 @@
1
- import { readFile, writeFile, mkdir } from "fs/promises";
2
- import { join } from "path";
3
- import { homedir } from "os";
4
- import { getConfigGithubCacheTtlMs } from "../../config/loader.js";
5
- const CACHE_DIR = join(homedir(), ".weavetab-system", "github_cache");
6
- function getCacheFile(owner, repo) {
7
- const safeOwner = owner.replace(/[^a-zA-Z0-9.-]/g, "_");
8
- const safeRepo = repo.replace(/[^a-zA-Z0-9.-]/g, "_");
9
- return join(CACHE_DIR, `${safeOwner}_${safeRepo}.json`);
10
- }
11
- export async function loadRepoCache(owner, repo, config) {
12
- try {
13
- const content = await readFile(getCacheFile(owner, repo), "utf-8");
14
- const data = JSON.parse(content);
15
- const ttl = getConfigGithubCacheTtlMs(config) ?? (30 * 60 * 1000);
16
- if (Date.now() - data.analyzed_at > ttl) {
17
- return null; // Stale cache
18
- }
19
- return data;
20
- }
21
- catch {
22
- return null;
23
- }
24
- }
25
- export async function saveRepoCache(data) {
26
- await mkdir(CACHE_DIR, { recursive: true });
27
- await writeFile(getCacheFile(data.owner, data.repo), JSON.stringify(data), "utf-8");
28
- }
@@ -1,19 +0,0 @@
1
- import CDP from "chrome-remote-interface";
2
- import type { Config } from "../../config/loader.js";
3
- import { githubAnalyze } from "./analyze.js";
4
- import { githubRead } from "./read.js";
5
- import { githubIssues } from "./issues.js";
6
- import { githubGetPr } from "./pr.js";
7
- export { githubAnalyze, githubRead, githubIssues, githubGetPr };
8
- export interface BrowserGithubArgs {
9
- action: "analyze" | "read" | "issues" | "pr";
10
- repo?: string;
11
- paths?: string[];
12
- line_range?: [number, number];
13
- number?: number;
14
- search?: string;
15
- labels?: string[];
16
- state?: "open" | "closed" | "all";
17
- limit?: number;
18
- }
19
- export declare function browserGithub(session: CDP.Client, args: BrowserGithubArgs, cfg: Config): Promise<any>;
@@ -1,40 +0,0 @@
1
- import { githubAnalyze } from "./analyze.js";
2
- import { githubRead } from "./read.js";
3
- import { githubIssues } from "./issues.js";
4
- import { githubGetPr } from "./pr.js";
5
- export { githubAnalyze, githubRead, githubIssues, githubGetPr };
6
- export async function browserGithub(session, args, cfg) {
7
- switch (args.action) {
8
- case "analyze":
9
- return await githubAnalyze(session, cfg, args.repo);
10
- case "read": {
11
- const paths = args.paths || [];
12
- if (!paths.length) {
13
- return {
14
- error: "MISSING_PATHS",
15
- message: "action 'read' requires 'paths' parameter with at least one file path."
16
- };
17
- }
18
- return await githubRead(session, { repo: args.repo, paths, line_range: args.line_range }, cfg);
19
- }
20
- case "issues":
21
- return await githubIssues(session, {
22
- repo: args.repo,
23
- search: args.search,
24
- number: args.number,
25
- labels: args.labels,
26
- state: args.state,
27
- limit: args.limit
28
- });
29
- case "pr":
30
- return await githubGetPr(session, {
31
- repo: args.repo,
32
- number: args.number
33
- });
34
- default:
35
- return {
36
- error: "INVALID_ACTION",
37
- message: `Unknown action: ${args.action}. Must be 'analyze', 'read', 'issues', or 'pr'.`
38
- };
39
- }
40
- }
@@ -1,9 +0,0 @@
1
- import CDP from "chrome-remote-interface";
2
- export declare function githubIssues(session: CDP.Client, args: {
3
- repo?: string;
4
- search?: string;
5
- number?: number;
6
- labels?: string[];
7
- state?: 'open' | 'closed' | 'all';
8
- limit?: number;
9
- }): Promise<any>;
@@ -1,88 +0,0 @@
1
- import { getRepoContext, isGithubError } from "./repoContext.js";
2
- import { canMakeApiCall, handleApiResponse } from "./rateLimiter.js";
3
- export async function githubIssues(session, args) {
4
- const context = await getRepoContext(session, args.repo);
5
- if (isGithubError(context))
6
- return context;
7
- const { owner, repo } = context;
8
- const rateLimitCheck = canMakeApiCall();
9
- if (isGithubError(rateLimitCheck))
10
- return rateLimitCheck;
11
- const headers = {
12
- "Accept": "application/vnd.github.v3+json",
13
- "User-Agent": "Weavetab-MCP"
14
- };
15
- // If number is provided, fetch specific issue + comments
16
- if (args.number) {
17
- const issueUrl = `https://api.github.com/repos/${owner}/${repo}/issues/${args.number}`;
18
- const issueRes = await fetch(issueUrl, { headers });
19
- const handledIssueRes = handleApiResponse(issueRes);
20
- if (isGithubError(handledIssueRes))
21
- return handledIssueRes;
22
- if (!issueRes.ok) {
23
- return { error: "FETCH_FAILED", status: issueRes.status, message: `Failed to fetch issue #${args.number}` };
24
- }
25
- const issueData = await issueRes.json();
26
- let comments = [];
27
- if (issueData.comments > 0) {
28
- const rateLimitCheck2 = canMakeApiCall();
29
- if (!isGithubError(rateLimitCheck2)) {
30
- const commentsUrl = `https://api.github.com/repos/${owner}/${repo}/issues/${args.number}/comments`;
31
- const commentsRes = await fetch(commentsUrl, { headers });
32
- const handledCommentsRes = handleApiResponse(commentsRes);
33
- if (!isGithubError(handledCommentsRes) && commentsRes.ok) {
34
- const commentsData = await commentsRes.json();
35
- comments = commentsData.map((c) => ({
36
- id: c.id,
37
- user: c.user?.login,
38
- body: c.body,
39
- created_at: c.created_at
40
- }));
41
- }
42
- }
43
- }
44
- return {
45
- number: issueData.number,
46
- title: issueData.title,
47
- state: issueData.state,
48
- user: issueData.user?.login,
49
- body: issueData.body,
50
- created_at: issueData.created_at,
51
- labels: issueData.labels?.map((l) => l.name),
52
- comments
53
- };
54
- }
55
- // Else list issues
56
- let urlStr = `https://api.github.com/repos/${owner}/${repo}/issues?per_page=${args.limit || 5}`;
57
- if (args.state)
58
- urlStr += `&state=${args.state}`;
59
- if (args.labels && args.labels.length > 0)
60
- urlStr += `&labels=${args.labels.join(',')}`;
61
- // GitHub Search API is different from Issues API. If search is provided, we should use search API.
62
- if (args.search) {
63
- let q = `repo:${owner}/${repo} is:issue ${args.search}`;
64
- if (args.state && args.state !== 'all')
65
- q += ` is:${args.state}`;
66
- if (args.labels)
67
- args.labels.forEach(l => q += ` label:"${l}"`);
68
- urlStr = `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&per_page=${args.limit || 5}`;
69
- }
70
- const listRes = await fetch(urlStr, { headers });
71
- const handledListRes = handleApiResponse(listRes);
72
- if (isGithubError(handledListRes))
73
- return handledListRes;
74
- if (!listRes.ok) {
75
- return { error: "FETCH_FAILED", status: listRes.status, message: "Failed to list/search issues" };
76
- }
77
- const listData = await listRes.json();
78
- const items = args.search ? listData.items : listData;
79
- return items.map((i) => ({
80
- number: i.number,
81
- title: i.title,
82
- state: i.state,
83
- user: i.user?.login,
84
- labels: i.labels?.map((l) => l.name),
85
- created_at: i.created_at,
86
- comments_count: i.comments
87
- }));
88
- }
@@ -1,5 +0,0 @@
1
- import CDP from "chrome-remote-interface";
2
- export declare function githubGetPr(session: CDP.Client, args: {
3
- repo?: string;
4
- number?: number;
5
- }): Promise<any>;
@@ -1,88 +0,0 @@
1
- import { getRepoContext, isGithubError } from "./repoContext.js";
2
- import { canMakeApiCall, handleApiResponse } from "./rateLimiter.js";
3
- export async function githubGetPr(session, args) {
4
- const context = await getRepoContext(session, args.repo);
5
- if (isGithubError(context))
6
- return context;
7
- const { owner, repo } = context;
8
- const rateLimitCheck = canMakeApiCall();
9
- if (isGithubError(rateLimitCheck))
10
- return rateLimitCheck;
11
- const headers = {
12
- "Accept": "application/vnd.github.v3+json",
13
- "User-Agent": "Weavetab-MCP"
14
- };
15
- if (args.number) {
16
- const prUrl = `https://api.github.com/repos/${owner}/${repo}/pulls/${args.number}`;
17
- const prRes = await fetch(prUrl, { headers });
18
- const handledPrRes = handleApiResponse(prRes);
19
- if (isGithubError(handledPrRes))
20
- return handledPrRes;
21
- if (!prRes.ok) {
22
- return { error: "FETCH_FAILED", status: prRes.status, message: `Failed to fetch PR #${args.number}` };
23
- }
24
- const prData = await prRes.json();
25
- let files_changed = [];
26
- const rateLimitCheck2 = canMakeApiCall();
27
- if (!isGithubError(rateLimitCheck2)) {
28
- const filesUrl = `https://api.github.com/repos/${owner}/${repo}/pulls/${args.number}/files`;
29
- const filesRes = await fetch(filesUrl, { headers });
30
- const handledFilesRes = handleApiResponse(filesRes);
31
- if (!isGithubError(handledFilesRes) && filesRes.ok) {
32
- const filesData = await filesRes.json();
33
- files_changed = filesData.map((f) => f.filename);
34
- }
35
- }
36
- let comments = [];
37
- if (prData.comments > 0) {
38
- const rateLimitCheck3 = canMakeApiCall();
39
- if (!isGithubError(rateLimitCheck3)) {
40
- const commentsUrl = `https://api.github.com/repos/${owner}/${repo}/issues/${args.number}/comments`;
41
- const commentsRes = await fetch(commentsUrl, { headers });
42
- const handledCommentsRes = handleApiResponse(commentsRes);
43
- if (!isGithubError(handledCommentsRes) && commentsRes.ok) {
44
- const commentsData = await commentsRes.json();
45
- comments = commentsData.map((c) => ({
46
- id: c.id,
47
- user: c.user?.login,
48
- body: c.body,
49
- created_at: c.created_at
50
- }));
51
- }
52
- }
53
- }
54
- return {
55
- number: prData.number,
56
- title: prData.title,
57
- state: prData.state,
58
- user: prData.user?.login,
59
- body: prData.body,
60
- created_at: prData.created_at,
61
- merged: prData.merged,
62
- mergeable: prData.mergeable,
63
- additions: prData.additions,
64
- deletions: prData.deletions,
65
- changed_files: prData.changed_files,
66
- files: files_changed,
67
- comments
68
- };
69
- }
70
- // Else list recent PRs
71
- const listUrl = `https://api.github.com/repos/${owner}/${repo}/pulls?state=all&per_page=10`;
72
- const listRes = await fetch(listUrl, { headers });
73
- const handledListRes = handleApiResponse(listRes);
74
- if (isGithubError(handledListRes))
75
- return handledListRes;
76
- if (!listRes.ok) {
77
- return { error: "FETCH_FAILED", status: listRes.status, message: "Failed to list PRs" };
78
- }
79
- const listData = await listRes.json();
80
- return listData.map((pr) => ({
81
- number: pr.number,
82
- title: pr.title,
83
- state: pr.state,
84
- user: pr.user?.login,
85
- created_at: pr.created_at,
86
- updated_at: pr.updated_at
87
- }));
88
- }
@@ -1,4 +0,0 @@
1
- import type { GithubToolError } from "./repoContext.js";
2
- export declare function canMakeApiCall(): true | GithubToolError;
3
- export declare function recordApiCall(headers: Headers): void;
4
- export declare function handleApiResponse(response: Response): Response | GithubToolError;
@@ -1,46 +0,0 @@
1
- let state = {
2
- remaining: 60,
3
- resetAt: null,
4
- };
5
- const SAFETY_THRESHOLD = 5;
6
- export function canMakeApiCall() {
7
- const nowSec = Math.floor(Date.now() / 1000);
8
- if (state.resetAt && nowSec >= state.resetAt) {
9
- // We've passed the reset window, assume we have quota again
10
- state.remaining = 60;
11
- state.resetAt = null;
12
- }
13
- if (state.remaining < SAFETY_THRESHOLD) {
14
- const resetTime = state.resetAt ? new Date(state.resetAt * 1000).toISOString() : "unknown";
15
- return {
16
- error: "RATE_LIMIT_LOW",
17
- message: `GitHub API hourly rate limit is too low (remaining: ${state.remaining}). Please wait until ${resetTime} before making more API calls. Note: github_read does NOT consume API calls.`,
18
- remaining: state.remaining,
19
- reset_at: state.resetAt
20
- };
21
- }
22
- return true;
23
- }
24
- export function recordApiCall(headers) {
25
- const remainingStr = headers.get("x-ratelimit-remaining");
26
- const resetStr = headers.get("x-ratelimit-reset");
27
- if (remainingStr) {
28
- state.remaining = parseInt(remainingStr, 10) || state.remaining;
29
- }
30
- if (resetStr) {
31
- state.resetAt = parseInt(resetStr, 10) || state.resetAt;
32
- }
33
- }
34
- export function handleApiResponse(response) {
35
- recordApiCall(response.headers);
36
- if (response.status === 403 || response.status === 429) {
37
- const resetTime = state.resetAt ? new Date(state.resetAt * 1000).toISOString() : "unknown";
38
- return {
39
- error: "RATE_LIMIT_EXCEEDED",
40
- message: `GitHub API rate limit exceeded. Please wait until ${resetTime}.`,
41
- remaining: state.remaining,
42
- reset_at: state.resetAt
43
- };
44
- }
45
- return response;
46
- }
@@ -1,34 +0,0 @@
1
- import CDP from "chrome-remote-interface";
2
- import type { Config } from "../../config/loader.js";
3
- export declare function githubRead(session: CDP.Client, args: {
4
- repo?: string;
5
- paths: string[];
6
- line_range?: [number, number];
7
- }, config: Config): Promise<import("./repoContext.js").GithubToolError | {
8
- warnings: string[] | undefined;
9
- files: ({
10
- path: string;
11
- error: string;
12
- status: number;
13
- message: string;
14
- total_lines?: undefined;
15
- truncated?: undefined;
16
- content?: undefined;
17
- } | {
18
- path: string;
19
- total_lines: number;
20
- truncated: boolean;
21
- content: string;
22
- error?: undefined;
23
- status?: undefined;
24
- message?: undefined;
25
- } | {
26
- path: string;
27
- error: string;
28
- message: any;
29
- status?: undefined;
30
- total_lines?: undefined;
31
- truncated?: undefined;
32
- content?: undefined;
33
- })[];
34
- }>;