@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
@@ -0,0 +1,149 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import { Logger } from './logger.js';
5
+ import { AGY_INTERNAL } from '../constants.js';
6
+ /**
7
+ * Best-effort recovery of an agy response from its on-disk transcript.
8
+ *
9
+ * `agy --print` sometimes exits 0 having printed nothing (empty stdout) or only
10
+ * `Error: timed out waiting for response`, even though the model DID produce an
11
+ * answer — that answer is written to the conversation transcript. This module
12
+ * recovers it, keyed deterministically by working directory.
13
+ *
14
+ * FRAGILE: depends entirely on undocumented agy 1.0.13 internals (see
15
+ * AGY_INTERNAL). Every access degrades to `null` on any mismatch — it must
16
+ * never throw, and it must never return another conversation's answer.
17
+ */
18
+ // Allow a small slack between the transcript record's second-precision
19
+ // timestamp and our millisecond run-start clock.
20
+ const FRESHNESS_TOLERANCE_MS = 2000;
21
+ // agy conversation IDs are UUID-shaped. Dots are excluded outright: `.` and
22
+ // `..` are valid path components and would traverse out of the brain directory.
23
+ const CONVERSATION_ID = /^[A-Za-z0-9_-]+$/;
24
+ /** Output that should trigger transcript recovery: empty or the timeout sentinel. */
25
+ export function isRecoverableEmptyOutput(stdout) {
26
+ const trimmed = stdout.trim();
27
+ return trimmed === '' || trimmed === AGY_INTERNAL.TIMEOUT_SENTINEL;
28
+ }
29
+ function recoveryDisabled() {
30
+ return process.env[AGY_INTERNAL.DISABLE_RECOVERY_ENV] === 'true';
31
+ }
32
+ function agyRoot() {
33
+ return path.join(os.homedir(), ...AGY_INTERNAL.ROOT_SEGMENTS);
34
+ }
35
+ /** Candidate forms of cwd to match against last_conversations.json keys. */
36
+ function cwdLookupKeys(cwd) {
37
+ const keys = new Set([cwd]);
38
+ try {
39
+ keys.add(path.resolve(cwd));
40
+ }
41
+ catch { }
42
+ try {
43
+ keys.add(fs.realpathSync(cwd));
44
+ }
45
+ catch { }
46
+ return [...keys];
47
+ }
48
+ function lookupConversationId(cwd) {
49
+ const mapPath = path.join(agyRoot(), ...AGY_INTERNAL.LAST_CONVERSATIONS_SEGMENTS);
50
+ const map = JSON.parse(fs.readFileSync(mapPath, 'utf-8'));
51
+ for (const key of cwdLookupKeys(cwd)) {
52
+ if (typeof map[key] === 'string')
53
+ return map[key];
54
+ }
55
+ return null;
56
+ }
57
+ /** Unwrap a record's `content`, falling back to the raw string if it is not the nested JSON form. */
58
+ function unwrapContent(content) {
59
+ if (typeof content !== 'string')
60
+ return null;
61
+ const trimmed = content.trim();
62
+ if (!trimmed)
63
+ return null;
64
+ try {
65
+ const parsed = JSON.parse(trimmed);
66
+ if (parsed && typeof parsed === 'object' && typeof parsed.content === 'string') {
67
+ const inner = parsed.content.trim();
68
+ return inner || null;
69
+ }
70
+ }
71
+ catch {
72
+ // Not the nested JSON form — use the raw string.
73
+ }
74
+ return trimmed;
75
+ }
76
+ function isFinalResponse(rec) {
77
+ const f = AGY_INTERNAL.TRANSCRIPT_FINAL;
78
+ return rec.type === f.type && rec.source === f.source && rec.status === f.status;
79
+ }
80
+ function readLastResponse(transcriptPath, runStartMs) {
81
+ // readFileSync throws (-> caller returns null) when the transcript is missing.
82
+ const lines = fs.readFileSync(transcriptPath, 'utf-8').split('\n');
83
+ let last = null;
84
+ for (const line of lines) {
85
+ if (!line.trim())
86
+ continue;
87
+ let rec;
88
+ try {
89
+ rec = JSON.parse(line);
90
+ }
91
+ catch {
92
+ continue;
93
+ }
94
+ if (isFinalResponse(rec))
95
+ last = rec;
96
+ }
97
+ if (!last)
98
+ return null;
99
+ // Freshness: prefer the record's own timestamp; fall back to the file mtime
100
+ // (only stat'd when the record has no usable timestamp).
101
+ const createdMs = last.created_at ? Date.parse(last.created_at) : NaN;
102
+ const effectiveMs = Number.isNaN(createdMs) ? fs.statSync(transcriptPath).mtimeMs : createdMs;
103
+ if (effectiveMs < runStartMs - FRESHNESS_TOLERANCE_MS) {
104
+ Logger.debug('[recovery] last transcript response predates this run; treating as stale');
105
+ return null;
106
+ }
107
+ return unwrapContent(last.content);
108
+ }
109
+ /**
110
+ * Recover the latest model response for `conversationId` (or, absent one, for
111
+ * `cwd`) if it was produced after
112
+ * `runStartMs`. Returns the recovered text, or `null` if recovery is disabled,
113
+ * the cwd has no known conversation, the transcript is stale/missing, or any
114
+ * access fails. There is intentionally NO global "newest transcript" fallback —
115
+ * that could return another project's or session's answer.
116
+ */
117
+ export function recoverFromTranscript(opts) {
118
+ if (recoveryDisabled())
119
+ return null;
120
+ const cwd = opts.cwd || process.cwd();
121
+ try {
122
+ // An explicitly resumed conversation is authoritative; the cwd map only
123
+ // knows the LAST conversation for a directory. The ID reaches us from tool
124
+ // arguments and is joined into a path, so only agy's own id shape is
125
+ // accepted — never a traversal out of the brain directory.
126
+ const id = opts.conversationId?.trim() || lookupConversationId(cwd);
127
+ if (!id) {
128
+ Logger.debug(`[recovery] no conversation mapped for cwd ${cwd}`);
129
+ return null;
130
+ }
131
+ // Whatever the source, the id becomes a path component: validate it before
132
+ // any join. The cwd map is on disk and is no more trusted than an argument.
133
+ if (!CONVERSATION_ID.test(id)) {
134
+ Logger.debug(`[recovery] refusing malformed conversation id ${id}`);
135
+ return null;
136
+ }
137
+ const transcriptPath = path.join(agyRoot(), AGY_INTERNAL.BRAIN_DIR, id, ...AGY_INTERNAL.TRANSCRIPT_SEGMENTS);
138
+ const recovered = readLastResponse(transcriptPath, opts.runStartMs);
139
+ if (recovered) {
140
+ Logger.debug(`[recovery] recovered ${recovered.length} chars from transcript for ${id}`);
141
+ }
142
+ return recovered;
143
+ }
144
+ catch (error) {
145
+ Logger.debug(`[recovery] failed: ${error}`);
146
+ return null;
147
+ }
148
+ }
149
+ //# sourceMappingURL=agyTranscriptRecovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agyTranscriptRecovery.js","sourceRoot":"","sources":["../../src/utils/agyTranscriptRecovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type ArtifactFileStatus = 'OK' | 'OUTSIDE' | 'MISSING' | 'EMPTY' | 'STALE';
2
+ export declare const IMAGE_FILE: RegExp;
3
+ export declare function hasImageSignature(file: string): boolean;
4
+ /** Whether a file a pass wrote is inside `artifactDir`, present, non-empty and written during this run. */
5
+ export declare function checkArtifactFile(absFile: string, artifactDir: string, runStartMs: number): ArtifactFileStatus;
6
+ //# sourceMappingURL=artifactFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifactFile.d.ts","sourceRoot":"","sources":["../../src/utils/artifactFile.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAElF,eAAO,MAAM,UAAU,QAAoB,CAAC;AAE5C,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CA4BvD;AAED,2GAA2G;AAC3G,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,kBAAkB,CAW9G"}
@@ -0,0 +1,55 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { isWithin } from './fileReferences.js';
4
+ import { LIVE_PASS } from '../constants.js';
5
+ export const IMAGE_FILE = /\.(png|jpe?g)$/i;
6
+ export function hasImageSignature(file) {
7
+ const extension = path.extname(file).toLowerCase();
8
+ if (extension !== '.png' && extension !== '.jpg' && extension !== '.jpeg')
9
+ return false;
10
+ let handle;
11
+ try {
12
+ handle = fs.openSync(file, 'r');
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ try {
18
+ const header = Buffer.alloc(24);
19
+ const size = fs.readSync(handle, header, 0, header.length, 0);
20
+ if (extension === '.png') {
21
+ return size === header.length
22
+ && header.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))
23
+ && header.readUInt32BE(8) === 13
24
+ && header.toString('ascii', 12, 16) === 'IHDR'
25
+ && header.readUInt32BE(16) > 0
26
+ && header.readUInt32BE(20) > 0;
27
+ }
28
+ return size >= 3 && header[0] === 0xff && header[1] === 0xd8 && header[2] === 0xff;
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ finally {
34
+ fs.closeSync(handle);
35
+ }
36
+ }
37
+ /** Whether a file a pass wrote is inside `artifactDir`, present, non-empty and written during this run. */
38
+ export function checkArtifactFile(absFile, artifactDir, runStartMs) {
39
+ if (!isWithin(artifactDir, absFile))
40
+ return 'OUTSIDE';
41
+ try {
42
+ const stat = fs.statSync(absFile);
43
+ if (!stat.isFile())
44
+ return 'MISSING';
45
+ if (stat.size === 0)
46
+ return 'EMPTY';
47
+ if (stat.mtimeMs < runStartMs - LIVE_PASS.FRESHNESS_TOLERANCE_MS)
48
+ return 'STALE';
49
+ return 'OK';
50
+ }
51
+ catch {
52
+ return 'MISSING';
53
+ }
54
+ }
55
+ //# sourceMappingURL=artifactFile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifactFile.js","sourceRoot":"","sources":["../../src/utils/artifactFile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,CAAC,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAE5C,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAExF,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9D,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,IAAI,KAAK,MAAM,CAAC,MAAM;mBACxB,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;mBAC5E,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE;mBAC7B,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,MAAM;mBAC3C,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC;mBAC3B,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,WAAmB,EAAE,UAAkB;IACxF,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACtD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,OAAO,SAAS,CAAC;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QACpC,IAAI,IAAI,CAAC,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC,sBAAsB;YAAE,OAAO,OAAO,CAAC;QACjF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ export interface Viewport {
2
+ width: number;
3
+ height: number;
4
+ }
5
+ /**
6
+ * With a shown aria-modal sheet open, only the scrollers inside it count, so a
7
+ * sheet over a long screen is still shot at the viewport. `shown` and the modal
8
+ * lookup match src/layout-check.snippet.js, so both agree on which sheet counts.
9
+ */
10
+ export declare const SCROLL_OVERFLOW_SNIPPET = "() => {\n const shown = (el) => {\n const r = el.getBoundingClientRect();\n return r.width > 0 && r.height > 0 && getComputedStyle(el).visibility !== 'hidden' && !el.closest('[aria-hidden=\"true\"],[inert]');\n };\n const scrolls = (el) => el.tagName !== 'TEXTAREA' && /^(auto|scroll)$/.test(getComputedStyle(el).overflowY) && shown(el);\n const modal = [...document.querySelectorAll('[aria-modal=\"true\"]')].find(shown);\n let overflow = modal ? 0 : (document.scrollingElement || document.documentElement).scrollHeight - innerHeight;\n for (const el of modal ? [modal, ...modal.querySelectorAll('*')] : document.querySelectorAll('*')) {\n const extra = el.scrollHeight - el.clientHeight;\n if (extra > overflow && scrolls(el)) overflow = extra;\n }\n return overflow;\n }";
11
+ export declare function parseViewport(viewport: string): Viewport | null;
12
+ export declare function saveLayoutFunction(key: string): string;
13
+ /**
14
+ * The text of one target's capture file, run by @playwright/mcp's
15
+ * browser_run_code_unsafe as `(<text>)(page)` in a vm context that holds only
16
+ * `page` and a few timer and web globals: it must stay one expression, with no
17
+ * `require`, `fs` or `process`, and no trailing `;` or line comment.
18
+ */
19
+ export declare function buildCaptureScript(config: {
20
+ viewport: Viewport;
21
+ frameFile: string;
22
+ key: string;
23
+ }): string;
24
+ //# sourceMappingURL=captureScript.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureScript.d.ts","sourceRoot":"","sources":["../../src/utils/captureScript.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,uzBAahC,CAAC;AAEL,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAG/D;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAgDzG"}
@@ -0,0 +1,83 @@
1
+ import { LAYOUT_CHECK_SNIPPET, LIVE_PASS } from '../constants.js';
2
+ /**
3
+ * With a shown aria-modal sheet open, only the scrollers inside it count, so a
4
+ * sheet over a long screen is still shot at the viewport. `shown` and the modal
5
+ * lookup match src/layout-check.snippet.js, so both agree on which sheet counts.
6
+ */
7
+ export const SCROLL_OVERFLOW_SNIPPET = `() => {
8
+ const shown = (el) => {
9
+ const r = el.getBoundingClientRect();
10
+ return r.width > 0 && r.height > 0 && getComputedStyle(el).visibility !== 'hidden' && !el.closest('[aria-hidden="true"],[inert]');
11
+ };
12
+ const scrolls = (el) => el.tagName !== 'TEXTAREA' && /^(auto|scroll)$/.test(getComputedStyle(el).overflowY) && shown(el);
13
+ const modal = [...document.querySelectorAll('[aria-modal="true"]')].find(shown);
14
+ let overflow = modal ? 0 : (document.scrollingElement || document.documentElement).scrollHeight - innerHeight;
15
+ for (const el of modal ? [modal, ...modal.querySelectorAll('*')] : document.querySelectorAll('*')) {
16
+ const extra = el.scrollHeight - el.clientHeight;
17
+ if (extra > overflow && scrolls(el)) overflow = extra;
18
+ }
19
+ return overflow;
20
+ }`;
21
+ export function parseViewport(viewport) {
22
+ const match = /^\s*([1-9]\d*)\s*x\s*([1-9]\d*)\s*$/i.exec(viewport);
23
+ return match ? { width: Number(match[1]), height: Number(match[2]) } : null;
24
+ }
25
+ export function saveLayoutFunction(key) {
26
+ return `() => window.__livePassLayout?.[${JSON.stringify(key)}]`;
27
+ }
28
+ /**
29
+ * The text of one target's capture file, run by @playwright/mcp's
30
+ * browser_run_code_unsafe as `(<text>)(page)` in a vm context that holds only
31
+ * `page` and a few timer and web globals: it must stay one expression, with no
32
+ * `require`, `fs` or `process`, and no trailing `;` or line comment.
33
+ */
34
+ export function buildCaptureScript(config) {
35
+ const capture = JSON.stringify({
36
+ ...config,
37
+ settleMs: LIVE_PASS.CAPTURE_SETTLE_MS,
38
+ maxHeight: Math.max(LIVE_PASS.CAPTURE_MAX_HEIGHT, config.viewport.height),
39
+ maxGrows: LIVE_PASS.CAPTURE_MAX_GROWS,
40
+ });
41
+ return `async (page) => {
42
+ const { viewport, frameFile, key, settleMs, maxHeight, maxGrows } = ${capture};
43
+ const settle = () => new Promise((resolve) => setTimeout(resolve, settleMs));
44
+ const firstLine = (error) => String((error && error.message) || error).split('\\n')[0];
45
+ const overflow = () => page.evaluate(${SCROLL_OVERFLOW_SNIPPET});
46
+ const shoot = async () => {
47
+ let height = viewport.height;
48
+ for (let grown = 0, last = Infinity; grown < maxGrows && height < maxHeight; grown++) {
49
+ const by = await overflow();
50
+ if (by <= 1 || by >= last) break;
51
+ height = Math.min(height + Math.ceil(by), maxHeight);
52
+ await page.setViewportSize({ width: viewport.width, height });
53
+ await settle();
54
+ last = by;
55
+ }
56
+ await page.screenshot({ path: frameFile, type: 'png', scale: 'css' });
57
+ const saved = 'saved ' + frameFile + ' at ' + viewport.width + 'x' + height;
58
+ try {
59
+ await page.evaluate((key) => {
60
+ const reports = (window.__livePassLayout = window.__livePassLayout || {});
61
+ delete reports[key];
62
+ reports[key] = (${LAYOUT_CHECK_SNIPPET})();
63
+ }, key);
64
+ return saved;
65
+ } catch (error) {
66
+ return saved + '; layout not measured: ' + firstLine(error);
67
+ }
68
+ };
69
+ const restore = () => page.setViewportSize(viewport).then(() => '', (error) => '; viewport not restored: ' + firstLine(error));
70
+ await page.setViewportSize(viewport);
71
+ await settle();
72
+ let result;
73
+ try {
74
+ result = await shoot();
75
+ } catch (error) {
76
+ await restore();
77
+ throw error;
78
+ }
79
+ return result + (await restore());
80
+ }
81
+ `;
82
+ }
83
+ //# sourceMappingURL=captureScript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captureScript.js","sourceRoot":"","sources":["../../src/utils/captureScript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAOlE;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;IAanC,CAAC;AAEL,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,KAAK,GAAG,sCAAsC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,mCAAmC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA8D;IAC/F,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,GAAG,MAAM;QACT,QAAQ,EAAE,SAAS,CAAC,iBAAiB;QACrC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzE,QAAQ,EAAE,SAAS,CAAC,iBAAiB;KACtC,CAAC,CAAC;IACH,OAAO;wEAC+D,OAAO;;;yCAGtC,uBAAuB;;;;;;;;;;;;;;;;;0BAiBtC,oBAAoB;;;;;;;;;;;;;;;;;;;CAmB7C,CAAC;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"chunkCache.d.ts","sourceRoot":"","sources":["../../src/utils/chunkCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAsBnD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAwBvE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,IAAI,CA0B9D;AA+DD,wBAAgB,aAAa,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAehG;AAED,wBAAgB,UAAU,IAAI,IAAI,CAejC"}
1
+ {"version":3,"file":"chunkCache.d.ts","sourceRoot":"","sources":["../../src/utils/chunkCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AA+BnD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAwBvE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,IAAI,CAkC9D;AA+DD,wBAAgB,aAAa,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAehG;AAED,wBAAgB,UAAU,IAAI,IAAI,CAejC"}
@@ -3,9 +3,17 @@ import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import * as os from 'os';
5
5
  import { Logger } from './logger.js';
6
- const CACHE_DIR = path.join(os.tmpdir(), 'gemini-mcp-chunks');
6
+ const CACHE_DIR = path.join(os.tmpdir(), 'agy-mcp-chunks');
7
7
  const CACHE_TTL = 10 * 60 * 1000;
8
8
  const MAX_CACHE_FILES = 50;
9
+ // Cache keys are the first 8 hex chars of a SHA256 digest (see cacheChunks).
10
+ // Validate any user/model-supplied key against this before it ever touches the
11
+ // filesystem — an unvalidated key would let a traversal path escape CACHE_DIR
12
+ // and (on parse error / expiry) get fs.unlinkSync'd.
13
+ const CACHE_KEY_PATTERN = /^[0-9a-f]{8}$/;
14
+ function isValidCacheKey(cacheKey) {
15
+ return typeof cacheKey === 'string' && CACHE_KEY_PATTERN.test(cacheKey);
16
+ }
9
17
  function ensureCacheDir() {
10
18
  if (!fs.existsSync(CACHE_DIR)) {
11
19
  fs.mkdirSync(CACHE_DIR, { recursive: true });
@@ -46,6 +54,13 @@ export function cacheChunks(prompt, chunks) {
46
54
  * @returns The cached chunks or null if expired/not found
47
55
  */
48
56
  export function getChunks(cacheKey) {
57
+ // Reject malformed keys before constructing any path. A non-hex/wrong-length
58
+ // key (e.g. a traversal sequence) returns a cache miss, which surfaces as the
59
+ // friendly "cache miss" text in fetch-chunk rather than an MCP error.
60
+ if (!isValidCacheKey(cacheKey)) {
61
+ Logger.debug(`Rejected invalid cache key: ${cacheKey}`);
62
+ return null;
63
+ }
49
64
  const filePath = path.join(CACHE_DIR, `${cacheKey}.json`);
50
65
  try {
51
66
  if (!fs.existsSync(filePath)) {
@@ -62,11 +77,10 @@ export function getChunks(cacheKey) {
62
77
  return data.chunks;
63
78
  }
64
79
  catch (error) {
80
+ // Treat any read/parse failure as a cache miss. Do NOT delete the file: a
81
+ // transient parse error (e.g. a concurrent writer mid-write) must not nuke a
82
+ // file that may still be valid. Stale files are reaped by mtime elsewhere.
65
83
  Logger.debug(`Cache read error for ${cacheKey}: ${error}`);
66
- try {
67
- fs.unlinkSync(filePath); // Clean up bad file
68
- }
69
- catch { }
70
84
  return null;
71
85
  }
72
86
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chunkCache.js","sourceRoot":"","sources":["../../src/utils/chunkCache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chunkCache.js","sourceRoot":"","sources":["../../src/utils/chunkCache.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,8 @@
1
- export declare function executeCommand(command: string, args: string[], onProgress?: (newOutput: string) => void, cwd?: string): Promise<string>;
1
+ export interface CommandLimits {
2
+ /** Stop the process this long after spawn (SIGTERM then SIGKILL on POSIX; taskkill on Windows). */
3
+ killAfterMs?: number;
4
+ /** Stop the process when the caller's request is cancelled. */
5
+ signal?: AbortSignal;
6
+ }
7
+ export declare function executeCommand(command: string, args: string[], onProgress?: (newOutput: string) => void, cwd?: string, limits?: CommandLimits): Promise<string>;
2
8
  //# sourceMappingURL=commandExecutor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commandExecutor.d.ts","sourceRoot":"","sources":["../../src/utils/commandExecutor.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EACxC,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CAmFjB"}
1
+ {"version":3,"file":"commandExecutor.d.ts","sourceRoot":"","sources":["../../src/utils/commandExecutor.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,mGAAmG;IACnG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EACxC,GAAG,CAAC,EAAE,MAAM,EACZ,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,CAmNjB"}