@joeytheman/gemini-mcp-tool 1.3.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +127 -35
  2. package/dist/__tests__/agyModelSteps.test.d.ts +2 -0
  3. package/dist/__tests__/agyModelSteps.test.d.ts.map +1 -0
  4. package/dist/__tests__/agyModelSteps.test.js +58 -0
  5. package/dist/__tests__/agyModelSteps.test.js.map +1 -0
  6. package/dist/__tests__/ask-gemini.test.js +99 -37
  7. package/dist/__tests__/ask-gemini.test.js.map +1 -1
  8. package/dist/__tests__/capture-script.chromium.test.d.ts +2 -0
  9. package/dist/__tests__/capture-script.chromium.test.d.ts.map +1 -0
  10. package/dist/__tests__/capture-script.chromium.test.js +235 -0
  11. package/dist/__tests__/capture-script.chromium.test.js.map +1 -0
  12. package/dist/__tests__/layout-snippet.chromium.test.d.ts +2 -0
  13. package/dist/__tests__/layout-snippet.chromium.test.d.ts.map +1 -0
  14. package/dist/__tests__/layout-snippet.chromium.test.js +333 -0
  15. package/dist/__tests__/layout-snippet.chromium.test.js.map +1 -0
  16. package/dist/__tests__/layout-snippet.test.d.ts +2 -0
  17. package/dist/__tests__/layout-snippet.test.d.ts.map +1 -0
  18. package/dist/__tests__/layout-snippet.test.js +12 -0
  19. package/dist/__tests__/layout-snippet.test.js.map +1 -0
  20. package/dist/__tests__/live-pass.test.d.ts +2 -0
  21. package/dist/__tests__/live-pass.test.d.ts.map +1 -0
  22. package/dist/__tests__/live-pass.test.js +1249 -0
  23. package/dist/__tests__/live-pass.test.js.map +1 -0
  24. package/dist/__tests__/screen-review.test.d.ts +2 -0
  25. package/dist/__tests__/screen-review.test.d.ts.map +1 -0
  26. package/dist/__tests__/screen-review.test.js +553 -0
  27. package/dist/__tests__/screen-review.test.js.map +1 -0
  28. package/dist/__tests__/server-progress.test.d.ts +2 -0
  29. package/dist/__tests__/server-progress.test.d.ts.map +1 -0
  30. package/dist/__tests__/server-progress.test.js +63 -0
  31. package/dist/__tests__/server-progress.test.js.map +1 -0
  32. package/dist/__tests__/server.test.js +17 -19
  33. package/dist/__tests__/server.test.js.map +1 -1
  34. package/dist/__tests__/simple-tools.test.d.ts +2 -0
  35. package/dist/__tests__/simple-tools.test.d.ts.map +1 -0
  36. package/dist/__tests__/simple-tools.test.js +30 -0
  37. package/dist/__tests__/simple-tools.test.js.map +1 -0
  38. package/dist/__tests__/tools.test.js +91 -0
  39. package/dist/__tests__/tools.test.js.map +1 -1
  40. package/dist/__tests__/utils/agyExecutor.test.d.ts +2 -0
  41. package/dist/__tests__/utils/agyExecutor.test.d.ts.map +1 -0
  42. package/dist/__tests__/utils/agyExecutor.test.js +731 -0
  43. package/dist/__tests__/utils/agyExecutor.test.js.map +1 -0
  44. package/dist/__tests__/utils/agyTranscriptRecovery.test.d.ts +2 -0
  45. package/dist/__tests__/utils/agyTranscriptRecovery.test.d.ts.map +1 -0
  46. package/dist/__tests__/utils/agyTranscriptRecovery.test.js +127 -0
  47. package/dist/__tests__/utils/agyTranscriptRecovery.test.js.map +1 -0
  48. package/dist/__tests__/utils/chunkCache.test.js +26 -2
  49. package/dist/__tests__/utils/chunkCache.test.js.map +1 -1
  50. package/dist/__tests__/utils/commandExecutor.test.js +185 -7
  51. package/dist/__tests__/utils/commandExecutor.test.js.map +1 -1
  52. package/dist/__tests__/utils/fileReferences.test.d.ts +2 -0
  53. package/dist/__tests__/utils/fileReferences.test.d.ts.map +1 -0
  54. package/dist/__tests__/utils/fileReferences.test.js +87 -0
  55. package/dist/__tests__/utils/fileReferences.test.js.map +1 -0
  56. package/dist/__tests__/utils/gitStatusGuard.test.d.ts +2 -0
  57. package/dist/__tests__/utils/gitStatusGuard.test.d.ts.map +1 -0
  58. package/dist/__tests__/utils/gitStatusGuard.test.js +106 -0
  59. package/dist/__tests__/utils/gitStatusGuard.test.js.map +1 -0
  60. package/dist/__tests__/utils/progressUpdates.test.d.ts +2 -0
  61. package/dist/__tests__/utils/progressUpdates.test.d.ts.map +1 -0
  62. package/dist/__tests__/utils/progressUpdates.test.js +62 -0
  63. package/dist/__tests__/utils/progressUpdates.test.js.map +1 -0
  64. package/dist/__tests__/utils/responseCache.test.js +31 -11
  65. package/dist/__tests__/utils/responseCache.test.js.map +1 -1
  66. package/dist/__tests__/utils/test-helpers.d.ts +4 -0
  67. package/dist/__tests__/utils/test-helpers.d.ts.map +1 -1
  68. package/dist/__tests__/utils/test-helpers.js +16 -0
  69. package/dist/__tests__/utils/test-helpers.js.map +1 -1
  70. package/dist/constants.d.ts +91 -26
  71. package/dist/constants.d.ts.map +1 -1
  72. package/dist/constants.js +101 -28
  73. package/dist/constants.js.map +1 -1
  74. package/dist/index.js +20 -95
  75. package/dist/index.js.map +1 -1
  76. package/dist/layoutCheckSnippet.generated.d.ts +2 -0
  77. package/dist/layoutCheckSnippet.generated.d.ts.map +1 -0
  78. package/dist/layoutCheckSnippet.generated.js +3 -0
  79. package/dist/layoutCheckSnippet.generated.js.map +1 -0
  80. package/dist/tools/ask-gemini.tool.d.ts +34 -0
  81. package/dist/tools/ask-gemini.tool.d.ts.map +1 -1
  82. package/dist/tools/ask-gemini.tool.js +40 -23
  83. package/dist/tools/ask-gemini.tool.js.map +1 -1
  84. package/dist/tools/brainstorm.tool.d.ts.map +1 -1
  85. package/dist/tools/brainstorm.tool.js +7 -5
  86. package/dist/tools/brainstorm.tool.js.map +1 -1
  87. package/dist/tools/index.d.ts.map +1 -1
  88. package/dist/tools/index.js +3 -1
  89. package/dist/tools/index.js.map +1 -1
  90. package/dist/tools/live-pass.tool.d.ts +206 -0
  91. package/dist/tools/live-pass.tool.d.ts.map +1 -0
  92. package/dist/tools/live-pass.tool.js +670 -0
  93. package/dist/tools/live-pass.tool.js.map +1 -0
  94. package/dist/tools/registry.d.ts +6 -4
  95. package/dist/tools/registry.d.ts.map +1 -1
  96. package/dist/tools/registry.js +14 -11
  97. package/dist/tools/registry.js.map +1 -1
  98. package/dist/tools/screen-review.tool.d.ts +124 -0
  99. package/dist/tools/screen-review.tool.d.ts.map +1 -0
  100. package/dist/tools/screen-review.tool.js +449 -0
  101. package/dist/tools/screen-review.tool.js.map +1 -0
  102. package/dist/tools/simple-tools.d.ts.map +1 -1
  103. package/dist/tools/simple-tools.js +9 -3
  104. package/dist/tools/simple-tools.js.map +1 -1
  105. package/dist/utils/agyExecutor.d.ts +76 -0
  106. package/dist/utils/agyExecutor.d.ts.map +1 -0
  107. package/dist/utils/agyExecutor.js +449 -0
  108. package/dist/utils/agyExecutor.js.map +1 -0
  109. package/dist/utils/agyModelSteps.d.ts +5 -0
  110. package/dist/utils/agyModelSteps.d.ts.map +1 -0
  111. package/dist/utils/agyModelSteps.js +33 -0
  112. package/dist/utils/agyModelSteps.js.map +1 -0
  113. package/dist/utils/agyReport.d.ts +19 -0
  114. package/dist/utils/agyReport.d.ts.map +1 -0
  115. package/dist/utils/agyReport.js +62 -0
  116. package/dist/utils/agyReport.js.map +1 -0
  117. package/dist/utils/agyTranscriptRecovery.d.ts +16 -0
  118. package/dist/utils/agyTranscriptRecovery.d.ts.map +1 -0
  119. package/dist/utils/agyTranscriptRecovery.js +149 -0
  120. package/dist/utils/agyTranscriptRecovery.js.map +1 -0
  121. package/dist/utils/artifactFile.d.ts +6 -0
  122. package/dist/utils/artifactFile.d.ts.map +1 -0
  123. package/dist/utils/artifactFile.js +55 -0
  124. package/dist/utils/artifactFile.js.map +1 -0
  125. package/dist/utils/captureScript.d.ts +24 -0
  126. package/dist/utils/captureScript.d.ts.map +1 -0
  127. package/dist/utils/captureScript.js +83 -0
  128. package/dist/utils/captureScript.js.map +1 -0
  129. package/dist/utils/chunkCache.d.ts.map +1 -1
  130. package/dist/utils/chunkCache.js +19 -5
  131. package/dist/utils/chunkCache.js.map +1 -1
  132. package/dist/utils/commandExecutor.d.ts +7 -1
  133. package/dist/utils/commandExecutor.d.ts.map +1 -1
  134. package/dist/utils/commandExecutor.js +162 -22
  135. package/dist/utils/commandExecutor.js.map +1 -1
  136. package/dist/utils/fileReferences.d.ts +45 -0
  137. package/dist/utils/fileReferences.d.ts.map +1 -0
  138. package/dist/utils/fileReferences.js +169 -0
  139. package/dist/utils/fileReferences.js.map +1 -0
  140. package/dist/utils/gitCheckout.d.ts +14 -0
  141. package/dist/utils/gitCheckout.d.ts.map +1 -0
  142. package/dist/utils/gitCheckout.js +36 -0
  143. package/dist/utils/gitCheckout.js.map +1 -0
  144. package/dist/utils/gitStatusGuard.d.ts +35 -0
  145. package/dist/utils/gitStatusGuard.d.ts.map +1 -0
  146. package/dist/utils/gitStatusGuard.js +82 -0
  147. package/dist/utils/gitStatusGuard.js.map +1 -0
  148. package/dist/utils/layoutCheck.d.ts +58 -0
  149. package/dist/utils/layoutCheck.d.ts.map +1 -0
  150. package/dist/utils/layoutCheck.js +84 -0
  151. package/dist/utils/layoutCheck.js.map +1 -0
  152. package/dist/utils/logger.d.ts +0 -1
  153. package/dist/utils/logger.d.ts.map +1 -1
  154. package/dist/utils/logger.js +0 -6
  155. package/dist/utils/logger.js.map +1 -1
  156. package/dist/utils/progressUpdates.d.ts +14 -0
  157. package/dist/utils/progressUpdates.d.ts.map +1 -0
  158. package/dist/utils/progressUpdates.js +40 -0
  159. package/dist/utils/progressUpdates.js.map +1 -0
  160. package/dist/utils/responseCache.d.ts +3 -3
  161. package/dist/utils/responseCache.d.ts.map +1 -1
  162. package/dist/utils/responseCache.js +11 -6
  163. package/dist/utils/responseCache.js.map +1 -1
  164. package/package.json +19 -16
  165. package/dist/__tests__/utils/geminiExecutor.test.d.ts +0 -2
  166. package/dist/__tests__/utils/geminiExecutor.test.d.ts.map +0 -1
  167. package/dist/__tests__/utils/geminiExecutor.test.js +0 -337
  168. package/dist/__tests__/utils/geminiExecutor.test.js.map +0 -1
  169. package/dist/utils/geminiExecutor.d.ts +0 -17
  170. package/dist/utils/geminiExecutor.d.ts.map +0 -1
  171. package/dist/utils/geminiExecutor.js +0 -238
  172. package/dist/utils/geminiExecutor.js.map +0 -1
@@ -1,20 +1,140 @@
1
1
  import { spawn } from "child_process";
2
2
  import { Logger } from "./logger.js";
3
- export async function executeCommand(command, args, onProgress, cwd) {
3
+ import { AGY_LIMITS, ERROR_MESSAGES } from "../constants.js";
4
+ // Node clamps longer delays to 1 ms, so long limits need more than one timer.
5
+ const MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
6
+ export async function executeCommand(command, args, onProgress, cwd, limits = {}) {
4
7
  return new Promise((resolve, reject) => {
8
+ if (limits.signal?.aborted) {
9
+ reject(new Error(ERROR_MESSAGES.AGY_CANCELLED));
10
+ return;
11
+ }
5
12
  const startTime = Date.now();
6
13
  Logger.commandExecution(command, args, startTime);
14
+ // Give limited POSIX commands their own process group. agy's MCP children
15
+ // inherit it, so a stop can reach them even if agy ignores SIGTERM.
16
+ const grouped = process.platform !== "win32" &&
17
+ (limits.killAfterMs !== undefined || limits.signal !== undefined);
7
18
  const childProcess = spawn(command, args, {
8
19
  env: process.env,
9
- shell: process.platform === "win32",
20
+ shell: false,
10
21
  stdio: ["ignore", "pipe", "pipe"],
11
22
  ...(cwd && { cwd }),
23
+ ...(grouped && { detached: true }),
12
24
  });
13
25
  // Use array buffers for O(n) performance instead of O(n²) string concatenation
14
26
  const stdoutChunks = [];
15
27
  const stderrChunks = [];
16
28
  let isResolved = false;
29
+ let stopError;
30
+ let resourceExhausted = false;
31
+ let ceilingTimer;
32
+ let graceTimer;
33
+ let closeTimer;
34
+ const settle = () => {
35
+ isResolved = true;
36
+ clearTimeout(ceilingTimer);
37
+ clearTimeout(graceTimer);
38
+ clearTimeout(closeTimer);
39
+ limits.signal?.removeEventListener("abort", onAbort);
40
+ };
41
+ const signalProcessGroup = (signal) => {
42
+ try {
43
+ if (grouped && childProcess.pid !== undefined) {
44
+ process.kill(-childProcess.pid, signal);
45
+ }
46
+ else {
47
+ childProcess.kill(signal);
48
+ }
49
+ }
50
+ catch {
51
+ // A process can exit between the timer and the signal. If the group
52
+ // signal failed for another reason, still try to stop agy itself.
53
+ if (grouped)
54
+ childProcess.kill(signal);
55
+ }
56
+ };
57
+ const signalWindowsTree = () => {
58
+ if (childProcess.pid === undefined) {
59
+ childProcess.kill("SIGKILL");
60
+ return;
61
+ }
62
+ // Windows has no negative-PID group signal. Kill the tree while the
63
+ // parent PID still exists, before its children can become orphaned.
64
+ const killer = spawn("taskkill", ["/PID", String(childProcess.pid), "/T", "/F"], {
65
+ shell: false,
66
+ stdio: "ignore",
67
+ windowsHide: true,
68
+ });
69
+ killer.on("error", (error) => {
70
+ Logger.error("Could not stop the Windows process tree:", error);
71
+ childProcess.kill("SIGKILL");
72
+ });
73
+ killer.on("close", (code) => {
74
+ if (code !== 0 && !isResolved) {
75
+ Logger.error(`taskkill could not stop the Windows process tree (exit ${code})`);
76
+ childProcess.kill("SIGKILL");
77
+ }
78
+ });
79
+ };
80
+ const finishStopped = (code) => {
81
+ if (isResolved)
82
+ return;
83
+ settle();
84
+ Logger.commandComplete(startTime, code);
85
+ reject(stopError);
86
+ };
87
+ const forceStop = () => {
88
+ if (isResolved)
89
+ return;
90
+ if (process.platform === "win32")
91
+ signalWindowsTree();
92
+ else
93
+ signalProcessGroup("SIGKILL");
94
+ // A detached descendant can keep inherited pipes open after agy dies,
95
+ // so bound the wait for close.
96
+ closeTimer = setTimeout(() => {
97
+ childProcess.stdout.destroy?.();
98
+ childProcess.stderr.destroy?.();
99
+ finishStopped(childProcess.exitCode ?? null);
100
+ }, AGY_LIMITS.KILL_CLOSE_WAIT_MS);
101
+ };
102
+ const stop = (error) => {
103
+ if (isResolved || stopError)
104
+ return;
105
+ stopError = error;
106
+ clearTimeout(ceilingTimer);
107
+ limits.signal?.removeEventListener("abort", onAbort);
108
+ Logger.error(error.message);
109
+ if (process.platform === "win32")
110
+ signalWindowsTree();
111
+ else
112
+ signalProcessGroup("SIGTERM");
113
+ graceTimer = setTimeout(forceStop, AGY_LIMITS.KILL_GRACE_MS);
114
+ };
115
+ function onAbort() {
116
+ stop(new Error(ERROR_MESSAGES.AGY_CANCELLED));
117
+ }
118
+ if (limits.killAfterMs !== undefined) {
119
+ const limitMs = limits.killAfterMs;
120
+ const deadline = Date.now() + limitMs;
121
+ const scheduleCeiling = () => {
122
+ const remaining = deadline - Date.now();
123
+ if (remaining <= 0) {
124
+ stop(new Error(`${ERROR_MESSAGES.AGY_HUNG}: limit ${Math.round(limitMs / 1000)}s`));
125
+ }
126
+ else {
127
+ ceilingTimer = setTimeout(scheduleCeiling, Math.min(remaining, MAX_TIMER_DELAY_MS));
128
+ }
129
+ };
130
+ scheduleCeiling();
131
+ }
132
+ limits.signal?.addEventListener("abort", onAbort, { once: true });
133
+ if (limits.signal?.aborted)
134
+ onAbort();
17
135
  childProcess.stdout.on("data", (data) => {
136
+ if (stopError)
137
+ return;
18
138
  const chunk = data.toString();
19
139
  stdoutChunks.push(chunk);
20
140
  // Report immediately if callback provided (no substring calculation needed)
@@ -24,10 +144,14 @@ export async function executeCommand(command, args, onProgress, cwd) {
24
144
  });
25
145
  // CLI level errors
26
146
  childProcess.stderr.on("data", (data) => {
147
+ if (stopError)
148
+ return;
27
149
  const chunk = data.toString();
28
150
  stderrChunks.push(chunk);
29
- // find RESOURCE_EXHAUSTED when Gemini Pro quota is exceeded
30
- if (chunk.includes("RESOURCE_EXHAUSTED")) {
151
+ // Surface resource/quota failures from the backend without attempting
152
+ // fallback. Build the structured error once, on the first marker.
153
+ if (!resourceExhausted && chunk.includes("RESOURCE_EXHAUSTED")) {
154
+ resourceExhausted = true;
31
155
  const stderrSoFar = stderrChunks.join('');
32
156
  const modelMatch = stderrSoFar.match(/Quota exceeded for quota metric '([^']+)'/);
33
157
  const statusMatch = stderrSoFar.match(/status["\s]*[:=]\s*(\d+)/);
@@ -42,36 +166,52 @@ export async function executeCommand(command, args, onProgress, cwd) {
42
166
  details: {
43
167
  model: model,
44
168
  reason: reason,
45
- statusText: "Too Many Requests -- > try using gemini-3-flash-preview by asking",
169
+ statusText: `Too Many Requests from Antigravity CLI backend`,
46
170
  }
47
171
  }
48
172
  };
49
- Logger.error(`Gemini Quota Error: ${JSON.stringify(errorJson, null, 2)}`);
173
+ Logger.error(`Antigravity resource error: ${JSON.stringify(errorJson, null, 2)}`);
50
174
  }
51
175
  });
52
176
  childProcess.on("error", (error) => {
53
177
  if (!isResolved) {
54
- isResolved = true;
178
+ if (stopError)
179
+ return;
180
+ settle();
55
181
  Logger.error(`Process error:`, error);
182
+ Logger.commandComplete(startTime, null);
56
183
  reject(new Error(`Failed to spawn command: ${error.message}`));
57
184
  }
58
185
  });
59
186
  childProcess.on("close", (code) => {
60
- if (!isResolved) {
61
- isResolved = true;
62
- // Join array buffers efficiently
63
- const stdout = stdoutChunks.join('');
64
- const stderr = stderrChunks.join('');
65
- if (code === 0) {
66
- Logger.commandComplete(startTime, code, stdout.length);
67
- resolve(stdout.trim());
68
- }
69
- else {
70
- Logger.commandComplete(startTime, code);
71
- Logger.error(`Failed with exit code ${code}`);
72
- const errorMessage = stderr.trim() || "Unknown error";
73
- reject(new Error(`Command failed with exit code ${code}: ${errorMessage}`));
74
- }
187
+ if (isResolved)
188
+ return;
189
+ if (stopError) {
190
+ // A parent can exit before its children. Clear any survivors from its
191
+ // process group before reporting that the request has stopped.
192
+ if (grouped && childProcess.pid !== undefined)
193
+ signalProcessGroup("SIGKILL");
194
+ finishStopped(code);
195
+ return;
196
+ }
197
+ settle();
198
+ // Join array buffers efficiently
199
+ const stdout = stdoutChunks.join('');
200
+ const stderr = stderrChunks.join('');
201
+ // Treat an exit-0 run as failed only when it reported quota exhaustion
202
+ // AND produced no usable stdout — so a quota error with empty output is
203
+ // surfaced (not silently "recovered"), while a run that still returned a
204
+ // real answer is kept.
205
+ const quotaFailure = resourceExhausted && stdout.trim() === "";
206
+ if (code === 0 && !quotaFailure) {
207
+ Logger.commandComplete(startTime, code, stdout.length);
208
+ resolve(stdout.trim());
209
+ }
210
+ else {
211
+ Logger.commandComplete(startTime, code);
212
+ Logger.error(`Failed with exit code ${code}`);
213
+ const errorMessage = stderr.trim() || (resourceExhausted ? "RESOURCE_EXHAUSTED" : "Unknown error");
214
+ reject(new Error(`Command failed with exit code ${code}: ${errorMessage}`));
75
215
  }
76
216
  });
77
217
  });
@@ -1 +1 @@
1
- {"version":3,"file":"commandExecutor.js","sourceRoot":"","sources":["../../src/utils/commandExecutor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"commandExecutor.js","sourceRoot":"","sources":["../../src/utils/commandExecutor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * File-reference handling for agy prompts.
3
+ *
4
+ * Why this exists: `agy --print` resolves an `@file` reference ONLY when the
5
+ * file's directory is part of the workspace (`--add-dir`). cwd is never
6
+ * auto-registered. An `@file` outside any added dir makes agy hang until
7
+ * `--print-timeout`. So for every reference in a prompt that actually resolves
8
+ * to a real file under a trusted root (the working directory or an explicitly
9
+ * supplied includeDirectories entry), we register that root with `--add-dir`.
10
+ *
11
+ * We never inline file contents: agy reads the file itself, keeping the
12
+ * `--print` argv small and preserving the large-file use case (inlining would
13
+ * risk E2BIG). References that don't resolve under a trusted root are left
14
+ * untouched — the prompt still runs.
15
+ */
16
+ /** Normalize a comma-separated string or array into a trimmed, non-empty list. */
17
+ export declare function normalizeList(value?: string | string[]): string[];
18
+ /** True when `p` resolves to a filesystem root (e.g. `/` or `C:\`). */
19
+ export declare function isFilesystemRoot(p: string): boolean;
20
+ /**
21
+ * Resolve a tool's `workingDirectory` argument: it must be an absolute path to
22
+ * an existing directory that is not a filesystem root, because it becomes both
23
+ * agy's cwd and its workspace root.
24
+ */
25
+ export declare function resolveWorkingDirectory(requested: string): string;
26
+ /**
27
+ * `target` with its deepest EXISTING ancestor realpath'd, so a path that does
28
+ * not exist yet can still be compared against a realpath'd root.
29
+ */
30
+ export declare function realpathOfExistingPrefix(target: string): string;
31
+ /** True when `candidate` is `root` itself or lives under it. */
32
+ export declare function isWithin(root: string, candidate: string): boolean;
33
+ /**
34
+ * Normalize file references in a prompt and collect the `--add-dir` roots agy
35
+ * needs to read them. Returns the (possibly rewritten) prompt and the deduped
36
+ * list of trust roots that contain a resolved reference. Never throws.
37
+ */
38
+ export declare function resolveFileReferences(prompt: string, opts: {
39
+ cwd?: string;
40
+ includeDirectories?: string | string[];
41
+ }): {
42
+ prompt: string;
43
+ addDirs: string[];
44
+ };
45
+ //# sourceMappingURL=fileReferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileReferences.d.ts","sourceRoot":"","sources":["../../src/utils/fileReferences.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,CAIjE;AAgBD,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAejE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAa/D;AAED,gEAAgE;AAChE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAGjE;AAyCD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,GAC7D;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA0BvC"}
@@ -0,0 +1,169 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { ERROR_MESSAGES } from '../constants.js';
4
+ /**
5
+ * File-reference handling for agy prompts.
6
+ *
7
+ * Why this exists: `agy --print` resolves an `@file` reference ONLY when the
8
+ * file's directory is part of the workspace (`--add-dir`). cwd is never
9
+ * auto-registered. An `@file` outside any added dir makes agy hang until
10
+ * `--print-timeout`. So for every reference in a prompt that actually resolves
11
+ * to a real file under a trusted root (the working directory or an explicitly
12
+ * supplied includeDirectories entry), we register that root with `--add-dir`.
13
+ *
14
+ * We never inline file contents: agy reads the file itself, keeping the
15
+ * `--print` argv small and preserving the large-file use case (inlining would
16
+ * risk E2BIG). References that don't resolve under a trusted root are left
17
+ * untouched — the prompt still runs.
18
+ */
19
+ /** Normalize a comma-separated string or array into a trimmed, non-empty list. */
20
+ export function normalizeList(value) {
21
+ if (!value)
22
+ return [];
23
+ const items = Array.isArray(value) ? value : value.split(',');
24
+ return items.map(item => item.trim()).filter(Boolean);
25
+ }
26
+ // `@` reference: an `@` that is NOT part of an email/scoped continuation
27
+ // (preceded by a word char, another `@`, `/`, or `.`), then a run of non-space,
28
+ // non-`@` characters. Existence under a trust root — not shape — gates whether
29
+ // it is treated as a file, so extensionless names (Makefile, LICENSE) work.
30
+ const AT_REF = /(?<![\w@/.])@([^\s@]+)/g;
31
+ // `file:` reference: `file:` at a word boundary, not a `file://` URL.
32
+ const FILE_REF = /(?<![\w])file:(?!\/\/)(\S+)/g;
33
+ const TRAILING_PUNCT = /[),.;:!?\]}'"`]+$/;
34
+ function stripTrailingPunct(token) {
35
+ return token.replace(TRAILING_PUNCT, '');
36
+ }
37
+ /** True when `p` resolves to a filesystem root (e.g. `/` or `C:\`). */
38
+ export function isFilesystemRoot(p) {
39
+ try {
40
+ const resolved = path.resolve(p);
41
+ return resolved === path.parse(resolved).root;
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ /**
48
+ * Resolve a tool's `workingDirectory` argument: it must be an absolute path to
49
+ * an existing directory that is not a filesystem root, because it becomes both
50
+ * agy's cwd and its workspace root.
51
+ */
52
+ export function resolveWorkingDirectory(requested) {
53
+ // Realpath'd, so that later containment checks compare like with like: on
54
+ // macOS /tmp/x and /private/tmp/x are the same directory but not the same
55
+ // string, and a frame reported under one would look OUTSIDE the other.
56
+ let real = null;
57
+ try {
58
+ const candidate = fs.realpathSync(path.resolve(requested));
59
+ if (fs.statSync(candidate).isDirectory())
60
+ real = candidate;
61
+ }
62
+ catch {
63
+ real = null;
64
+ }
65
+ if (!path.isAbsolute(requested) || !real || isFilesystemRoot(real)) {
66
+ throw new Error(`${ERROR_MESSAGES.INVALID_WORKING_DIRECTORY}. Received '${requested}'.`);
67
+ }
68
+ return real;
69
+ }
70
+ /**
71
+ * `target` with its deepest EXISTING ancestor realpath'd, so a path that does
72
+ * not exist yet can still be compared against a realpath'd root.
73
+ */
74
+ export function realpathOfExistingPrefix(target) {
75
+ let current = path.resolve(target);
76
+ const missing = [];
77
+ for (;;) {
78
+ try {
79
+ return path.join(fs.realpathSync(current), ...missing);
80
+ }
81
+ catch {
82
+ const parent = path.dirname(current);
83
+ if (parent === current)
84
+ return path.resolve(target);
85
+ missing.unshift(path.basename(current));
86
+ current = parent;
87
+ }
88
+ }
89
+ }
90
+ /** True when `candidate` is `root` itself or lives under it. */
91
+ export function isWithin(root, candidate) {
92
+ const rel = path.relative(root, candidate);
93
+ return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
94
+ }
95
+ /**
96
+ * Realpath'd, existing directories that references may resolve under: the
97
+ * working directory plus each includeDirectories entry.
98
+ */
99
+ function resolveTrustRoots(cwd, includeDirectories) {
100
+ const baseCwd = cwd || process.cwd();
101
+ const candidates = [baseCwd, ...normalizeList(includeDirectories).map(d => path.resolve(baseCwd, d))];
102
+ const roots = [];
103
+ for (const candidate of candidates) {
104
+ try {
105
+ const real = fs.realpathSync(candidate);
106
+ if (fs.statSync(real).isDirectory())
107
+ roots.push(real);
108
+ }
109
+ catch {
110
+ // Non-existent / unreadable root — skip.
111
+ }
112
+ }
113
+ return [...new Set(roots)];
114
+ }
115
+ /**
116
+ * Resolve a token to the trust root it lives under. agy joins the reference
117
+ * path to an added dir, so the root that resolves the token is exactly what
118
+ * must be added. Returns null for tokens that don't resolve to a real file, or
119
+ * that escape every root via absolute/`..`/symlink.
120
+ */
121
+ function rootForToken(rawToken, roots) {
122
+ const token = stripTrailingPunct(rawToken);
123
+ if (!token)
124
+ return null;
125
+ for (const root of roots) {
126
+ try {
127
+ const real = fs.realpathSync(path.resolve(root, token));
128
+ if (isWithin(root, real) && fs.statSync(real).isFile())
129
+ return root;
130
+ }
131
+ catch {
132
+ // Does not resolve under this root — try the next one.
133
+ }
134
+ }
135
+ return null;
136
+ }
137
+ /**
138
+ * Normalize file references in a prompt and collect the `--add-dir` roots agy
139
+ * needs to read them. Returns the (possibly rewritten) prompt and the deduped
140
+ * list of trust roots that contain a resolved reference. Never throws.
141
+ */
142
+ export function resolveFileReferences(prompt, opts) {
143
+ const roots = resolveTrustRoots(opts.cwd, opts.includeDirectories);
144
+ if (roots.length === 0)
145
+ return { prompt, addDirs: [] };
146
+ const addDirs = new Set();
147
+ // Rewrite a `file:` reference to `@` ONLY when it resolves to a real file
148
+ // under a trusted root — otherwise we'd hand agy a dangling @ref that hangs.
149
+ // The converted token drops trailing punctuation so agy sees the exact path.
150
+ const rewritten = prompt.replace(FILE_REF, (match, rawToken) => {
151
+ const root = rootForToken(rawToken, roots);
152
+ if (!root)
153
+ return match;
154
+ addDirs.add(root);
155
+ return `@${stripTrailingPunct(rawToken)}`;
156
+ });
157
+ // Collect the trust root for every `@` reference that resolves.
158
+ AT_REF.lastIndex = 0;
159
+ let m;
160
+ while ((m = AT_REF.exec(rewritten)) !== null) {
161
+ if (addDirs.size >= roots.length)
162
+ break; // every root already registered
163
+ const root = rootForToken(m[1], roots);
164
+ if (root)
165
+ addDirs.add(root);
166
+ }
167
+ return { prompt: rewritten, addDirs: [...addDirs] };
168
+ }
169
+ //# sourceMappingURL=fileReferences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileReferences.js","sourceRoot":"","sources":["../../src/utils/fileReferences.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface Checkout {
2
+ /** Null on a detached HEAD. */
3
+ branch: string | null;
4
+ head: string;
5
+ }
6
+ /** The branch and commit checked out in `directory`, or null when it is not a git checkout with a commit. */
7
+ export declare function readCheckout(directory: string): Promise<Checkout | null>;
8
+ /**
9
+ * The merge base of `ref` and HEAD in `directory`. Throws with git's own reason
10
+ * when the ref does not resolve; `--end-of-options` keeps a ref spelled like an
11
+ * option from being read as one.
12
+ */
13
+ export declare function resolveMergeBase(directory: string, ref: string): Promise<string>;
14
+ //# sourceMappingURL=gitCheckout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitCheckout.d.ts","sourceRoot":"","sources":["../../src/utils/gitCheckout.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAMD,6GAA6G;AAC7G,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAS9E;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQtF"}
@@ -0,0 +1,36 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ const execFileAsync = promisify(execFile);
4
+ const GIT_TIMEOUT_MS = 10_000;
5
+ function git(directory, args) {
6
+ return execFileAsync('git', args, { cwd: directory, timeout: GIT_TIMEOUT_MS });
7
+ }
8
+ /** The branch and commit checked out in `directory`, or null when it is not a git checkout with a commit. */
9
+ export async function readCheckout(directory) {
10
+ try {
11
+ const { stdout } = await git(directory, ['rev-parse', 'HEAD', '--abbrev-ref', 'HEAD']);
12
+ const [head, branch] = stdout.trim().split('\n');
13
+ if (!head || !branch)
14
+ return null;
15
+ return { head, branch: branch === 'HEAD' ? null : branch };
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ /**
22
+ * The merge base of `ref` and HEAD in `directory`. Throws with git's own reason
23
+ * when the ref does not resolve; `--end-of-options` keeps a ref spelled like an
24
+ * option from being read as one.
25
+ */
26
+ export async function resolveMergeBase(directory, ref) {
27
+ try {
28
+ const { stdout } = await git(directory, ['merge-base', '--end-of-options', ref, 'HEAD']);
29
+ return stdout.trim();
30
+ }
31
+ catch (error) {
32
+ const stderr = error.stderr?.trim();
33
+ throw new Error(stderr || error.message);
34
+ }
35
+ }
36
+ //# sourceMappingURL=gitCheckout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitCheckout.js","sourceRoot":"","sources":["../../src/utils/gitCheckout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAC1C,MAAM,cAAc,GAAG,MAAM,CAAC;AAQ9B,SAAS,GAAG,CAAC,SAAiB,EAAE,IAAc;IAC5C,OAAO,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,6GAA6G;AAC7G,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB;IAClD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC;QACvF,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,SAAiB,EAAE,GAAW;IACnE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC,YAAY,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACzF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,GAAI,KAA6B,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,MAAM,IAAK,KAAe,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Before/after snapshots of a working tree, so a tool that hands Gemini a shell
3
+ * can report uninvited edits. Never throws: a snapshot that cannot be taken is
4
+ * `null` and simply disables the comparison.
5
+ *
6
+ * Status lines alone are not enough. These tools run against a dirty PR
7
+ * worktree, where a file Gemini rewrites was already ` M` before the run and
8
+ * stays ` M` after — the very files under review. So each dirty path's content
9
+ * is hashed too, and the diff reports content changes as well as status changes.
10
+ *
11
+ * Async because `git status` on a cold repository takes seconds, and this runs
12
+ * inside an MCP call whose keepalive notifications need the event loop.
13
+ */
14
+ export interface WorkingTreeSnapshot {
15
+ /** Repository root: porcelain paths are relative to it, never to cwd. */
16
+ root: string;
17
+ lines: string[];
18
+ /** Absolute path -> sha256 of its content, for every dirty file we could hash. */
19
+ hashes: Map<string, string>;
20
+ /** True when MAX_HASHED_FILES cut the hashing short. */
21
+ truncated: boolean;
22
+ }
23
+ export interface WorkingTreeDiff {
24
+ added: string[];
25
+ removed: string[];
26
+ /** Paths whose content changed while keeping the same status. */
27
+ modified: string[];
28
+ /** True when either snapshot hashed only part of the dirty set. */
29
+ truncated: boolean;
30
+ }
31
+ export declare function snapshotWorkingTree(cwd: string): Promise<WorkingTreeSnapshot | null>;
32
+ export declare function diffWorkingTree(before: WorkingTreeSnapshot | null, after: WorkingTreeSnapshot | null, opts?: {
33
+ ignoreDirectory?: string;
34
+ }): WorkingTreeDiff;
35
+ //# sourceMappingURL=gitStatusGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitStatusGuard.d.ts","sourceRoot":"","sources":["../../src/utils/gitStatusGuard.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kFAAkF;IAClF,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,wDAAwD;IACxD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;CACpB;AAoBD,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA8B1F;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAClC,KAAK,EAAE,mBAAmB,GAAG,IAAI,EACjC,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC,eAAe,CAsBjB"}