@joeytheman/gemini-mcp-tool 2.2.0 → 2.3.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 (115) hide show
  1. package/README.md +10 -7
  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__/capture-script.chromium.test.d.ts +2 -0
  7. package/dist/__tests__/capture-script.chromium.test.d.ts.map +1 -0
  8. package/dist/__tests__/capture-script.chromium.test.js +235 -0
  9. package/dist/__tests__/capture-script.chromium.test.js.map +1 -0
  10. package/dist/__tests__/layout-snippet.chromium.test.d.ts +2 -0
  11. package/dist/__tests__/layout-snippet.chromium.test.d.ts.map +1 -0
  12. package/dist/__tests__/layout-snippet.chromium.test.js +333 -0
  13. package/dist/__tests__/layout-snippet.chromium.test.js.map +1 -0
  14. package/dist/__tests__/layout-snippet.test.d.ts +2 -0
  15. package/dist/__tests__/layout-snippet.test.d.ts.map +1 -0
  16. package/dist/__tests__/layout-snippet.test.js +12 -0
  17. package/dist/__tests__/layout-snippet.test.js.map +1 -0
  18. package/dist/__tests__/live-pass.test.js +531 -7
  19. package/dist/__tests__/live-pass.test.js.map +1 -1
  20. package/dist/__tests__/screen-review.test.js +111 -2
  21. package/dist/__tests__/screen-review.test.js.map +1 -1
  22. package/dist/__tests__/server-progress.test.d.ts +2 -0
  23. package/dist/__tests__/server-progress.test.d.ts.map +1 -0
  24. package/dist/__tests__/server-progress.test.js +63 -0
  25. package/dist/__tests__/server-progress.test.js.map +1 -0
  26. package/dist/__tests__/server.test.js +1 -8
  27. package/dist/__tests__/server.test.js.map +1 -1
  28. package/dist/__tests__/simple-tools.test.js +8 -3
  29. package/dist/__tests__/simple-tools.test.js.map +1 -1
  30. package/dist/__tests__/tools.test.js +29 -1
  31. package/dist/__tests__/tools.test.js.map +1 -1
  32. package/dist/__tests__/utils/agyExecutor.test.js +176 -61
  33. package/dist/__tests__/utils/agyExecutor.test.js.map +1 -1
  34. package/dist/__tests__/utils/commandExecutor.test.js +155 -1
  35. package/dist/__tests__/utils/commandExecutor.test.js.map +1 -1
  36. package/dist/__tests__/utils/progressUpdates.test.d.ts +2 -0
  37. package/dist/__tests__/utils/progressUpdates.test.d.ts.map +1 -0
  38. package/dist/__tests__/utils/progressUpdates.test.js +62 -0
  39. package/dist/__tests__/utils/progressUpdates.test.js.map +1 -0
  40. package/dist/constants.d.ts +33 -10
  41. package/dist/constants.d.ts.map +1 -1
  42. package/dist/constants.js +42 -10
  43. package/dist/constants.js.map +1 -1
  44. package/dist/index.js +19 -94
  45. package/dist/index.js.map +1 -1
  46. package/dist/layoutCheckSnippet.generated.d.ts +2 -0
  47. package/dist/layoutCheckSnippet.generated.d.ts.map +1 -0
  48. package/dist/layoutCheckSnippet.generated.js +3 -0
  49. package/dist/layoutCheckSnippet.generated.js.map +1 -0
  50. package/dist/tools/ask-gemini.tool.d.ts.map +1 -1
  51. package/dist/tools/ask-gemini.tool.js +6 -5
  52. package/dist/tools/ask-gemini.tool.js.map +1 -1
  53. package/dist/tools/brainstorm.tool.d.ts.map +1 -1
  54. package/dist/tools/brainstorm.tool.js +2 -1
  55. package/dist/tools/brainstorm.tool.js.map +1 -1
  56. package/dist/tools/live-pass.tool.d.ts +24 -1
  57. package/dist/tools/live-pass.tool.d.ts.map +1 -1
  58. package/dist/tools/live-pass.tool.js +174 -52
  59. package/dist/tools/live-pass.tool.js.map +1 -1
  60. package/dist/tools/registry.d.ts +2 -2
  61. package/dist/tools/registry.d.ts.map +1 -1
  62. package/dist/tools/registry.js +2 -2
  63. package/dist/tools/registry.js.map +1 -1
  64. package/dist/tools/screen-review.tool.d.ts +3 -0
  65. package/dist/tools/screen-review.tool.d.ts.map +1 -1
  66. package/dist/tools/screen-review.tool.js +42 -8
  67. package/dist/tools/screen-review.tool.js.map +1 -1
  68. package/dist/tools/simple-tools.d.ts.map +1 -1
  69. package/dist/tools/simple-tools.js +6 -2
  70. package/dist/tools/simple-tools.js.map +1 -1
  71. package/dist/utils/agyExecutor.d.ts +9 -1
  72. package/dist/utils/agyExecutor.d.ts.map +1 -1
  73. package/dist/utils/agyExecutor.js +54 -48
  74. package/dist/utils/agyExecutor.js.map +1 -1
  75. package/dist/utils/agyModelSteps.d.ts +5 -0
  76. package/dist/utils/agyModelSteps.d.ts.map +1 -0
  77. package/dist/utils/agyModelSteps.js +33 -0
  78. package/dist/utils/agyModelSteps.js.map +1 -0
  79. package/dist/utils/artifactFile.d.ts +6 -0
  80. package/dist/utils/artifactFile.d.ts.map +1 -0
  81. package/dist/utils/artifactFile.js +55 -0
  82. package/dist/utils/artifactFile.js.map +1 -0
  83. package/dist/utils/captureScript.d.ts +24 -0
  84. package/dist/utils/captureScript.d.ts.map +1 -0
  85. package/dist/utils/captureScript.js +83 -0
  86. package/dist/utils/captureScript.js.map +1 -0
  87. package/dist/utils/commandExecutor.d.ts +7 -1
  88. package/dist/utils/commandExecutor.d.ts.map +1 -1
  89. package/dist/utils/commandExecutor.js +154 -22
  90. package/dist/utils/commandExecutor.js.map +1 -1
  91. package/dist/utils/gitCheckout.d.ts +14 -0
  92. package/dist/utils/gitCheckout.d.ts.map +1 -0
  93. package/dist/utils/gitCheckout.js +36 -0
  94. package/dist/utils/gitCheckout.js.map +1 -0
  95. package/dist/utils/layoutCheck.d.ts +58 -0
  96. package/dist/utils/layoutCheck.d.ts.map +1 -0
  97. package/dist/utils/layoutCheck.js +84 -0
  98. package/dist/utils/layoutCheck.js.map +1 -0
  99. package/dist/utils/logger.d.ts +0 -1
  100. package/dist/utils/logger.d.ts.map +1 -1
  101. package/dist/utils/logger.js +0 -6
  102. package/dist/utils/logger.js.map +1 -1
  103. package/dist/utils/progressUpdates.d.ts +14 -0
  104. package/dist/utils/progressUpdates.d.ts.map +1 -0
  105. package/dist/utils/progressUpdates.js +40 -0
  106. package/dist/utils/progressUpdates.js.map +1 -0
  107. package/package.json +18 -13
  108. package/dist/__tests__/utils/agyTranscriptRecovery.test.d.ts +0 -2
  109. package/dist/__tests__/utils/agyTranscriptRecovery.test.d.ts.map +0 -1
  110. package/dist/__tests__/utils/agyTranscriptRecovery.test.js +0 -127
  111. package/dist/__tests__/utils/agyTranscriptRecovery.test.js.map +0 -1
  112. package/dist/utils/agyTranscriptRecovery.d.ts +0 -16
  113. package/dist/utils/agyTranscriptRecovery.d.ts.map +0 -1
  114. package/dist/utils/agyTranscriptRecovery.js +0 -149
  115. package/dist/utils/agyTranscriptRecovery.js.map +0 -1
@@ -0,0 +1,84 @@
1
+ import { z } from 'zod';
2
+ import * as fs from 'fs';
3
+ import { realpathOfExistingPrefix } from './fileReferences.js';
4
+ import { checkArtifactFile } from './artifactFile.js';
5
+ import { LIVE_PASS } from '../constants.js';
6
+ const rectSchema = z.object({
7
+ x: z.number(),
8
+ y: z.number(),
9
+ width: z.number(),
10
+ height: z.number(),
11
+ });
12
+ const entryFields = {
13
+ text: z.string().max(LIVE_PASS.LAYOUT_TEXT_CHARS),
14
+ testID: z.string().nullable(),
15
+ rect: rectSchema,
16
+ };
17
+ /** `dev-overlay` marks a frame a framework dev overlay (such as Expo's error overlay) covered; its other entries are suspect. */
18
+ export const LAYOUT_ENTRY_KINDS = [
19
+ 'dev-overlay',
20
+ 'page-scroll-x',
21
+ 'text-spill',
22
+ 'text-clipped',
23
+ 'control-covered',
24
+ 'control-offscreen',
25
+ ];
26
+ export const layoutReportSchema = z.object({
27
+ check: z.literal(LIVE_PASS.LAYOUT_CHECK_ID),
28
+ viewport: z.object({ width: z.number(), height: z.number() }),
29
+ found: z.number().int().nonnegative(),
30
+ entries: z.array(z.object({ kind: z.enum(LAYOUT_ENTRY_KINDS), ...entryFields })).max(LIVE_PASS.LAYOUT_MAX_ENTRIES),
31
+ clamped: z.array(z.object({ kind: z.literal('text-clamped'), ...entryFields })).max(LIVE_PASS.LAYOUT_MAX_ENTRIES),
32
+ });
33
+ export function layoutFileName(frameFileName) {
34
+ return frameFileName.replace(/\.png$/, LIVE_PASS.LAYOUT_FILE_SUFFIX);
35
+ }
36
+ const FILE_PROBLEMS = {
37
+ OUTSIDE: 'resolves outside the artifact directory',
38
+ MISSING: 'not written',
39
+ STALE: 'predates this run',
40
+ };
41
+ /**
42
+ * Read one frame's layout file. Never throws: a file that cannot be trusted is
43
+ * reported with its status and treated by the report as "not run". A file
44
+ * measured at another width than the frame's describes a different layout.
45
+ */
46
+ export function readLayoutCheck(file, artifactDir, runStartMs, expectedWidth) {
47
+ const absFile = realpathOfExistingPrefix(file);
48
+ const fileStatus = checkArtifactFile(absFile, artifactDir, runStartMs);
49
+ if (fileStatus === 'EMPTY')
50
+ return { file: absFile, status: 'MALFORMED', problem: 'empty' };
51
+ if (fileStatus !== 'OK')
52
+ return { file: absFile, status: fileStatus, problem: FILE_PROBLEMS[fileStatus] };
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(fs.readFileSync(absFile, 'utf-8'));
56
+ }
57
+ catch {
58
+ return { file: absFile, status: 'MALFORMED', problem: 'not valid JSON' };
59
+ }
60
+ const report = layoutReportSchema.safeParse(parsed);
61
+ if (!report.success) {
62
+ const issue = report.error.issues[0];
63
+ return {
64
+ file: absFile,
65
+ status: 'MALFORMED',
66
+ problem: `not a ${LIVE_PASS.LAYOUT_CHECK_ID} result (${issue.path.join('.') || 'root'}: ${issue.message})`,
67
+ };
68
+ }
69
+ const measuredWidth = report.data.viewport.width;
70
+ if (expectedWidth !== undefined && measuredWidth !== expectedWidth) {
71
+ return {
72
+ file: absFile,
73
+ status: 'MISMATCHED',
74
+ problem: `measured at width ${measuredWidth}, but the frame is ${expectedWidth} wide`,
75
+ };
76
+ }
77
+ return { file: absFile, status: 'OK', report: report.data };
78
+ }
79
+ export function formatLayoutEntry(entry) {
80
+ const { x, y, width, height } = entry.rect;
81
+ const testID = entry.testID ? ` testID=${entry.testID}` : '';
82
+ return `${entry.kind} "${entry.text}"${testID} at ${x},${y} ${width}x${height}`;
83
+ }
84
+ //# sourceMappingURL=layoutCheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layoutCheck.js","sourceRoot":"","sources":["../../src/utils/layoutCheck.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,6 @@ export declare class Logger {
7
7
  static toolInvocation(toolName: string, args: any): void;
8
8
  static toolParsedArgs(prompt: string, model?: string, sandbox?: boolean, changeMode?: boolean): void;
9
9
  static commandExecution(command: string, args: string[], startTime: number): void;
10
- private static _commandStartTimes;
11
10
  static commandComplete(startTime: number, exitCode: number | null, outputLength?: number): void;
12
11
  }
13
12
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAGA,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAIjD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAIlD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAInD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAInD,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAIxD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI;IAIpG,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAQjF,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAA6E;IAE9G,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;CAUhG"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAGA,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,aAAa;IAI5B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAIjD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAIlD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAInD,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI;IAInD,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAIxD,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI;IAIpG,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAIjF,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;CAOhG"}
@@ -24,19 +24,13 @@ export class Logger {
24
24
  }
25
25
  static commandExecution(command, args, startTime) {
26
26
  this.warn(`[${startTime}] Starting: ${command} ${args.map((arg) => `"${arg}"`).join(" ")}`);
27
- // Store command execution start for timing analysis
28
- this._commandStartTimes.set(startTime, { command, args, startTime });
29
27
  }
30
- // Track command start times for duration calculation
31
- static _commandStartTimes = new Map();
32
28
  static commandComplete(startTime, exitCode, outputLength) {
33
29
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
34
30
  this.warn(`[${elapsed}s] Process finished with exit code: ${exitCode}`);
35
31
  if (outputLength !== undefined) {
36
32
  this.warn(`Response: ${outputLength} chars`);
37
33
  }
38
- // Clean up command tracking
39
- this._commandStartTimes.delete(startTime);
40
34
  }
41
35
  }
42
36
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM;AACN,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,OAAO,MAAM;IACT,MAAM,CAAC,aAAa,CAAC,OAAe;QAC1C,OAAO,GAAG,UAAU,IAAI,OAAO,EAAE,GAAG,IAAI,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,OAAe,EAAE,GAAG,IAAW;QACxC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QACzC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QAC1C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QAC1C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,QAAgB,EAAE,IAAS;QAC/C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,MAAc,EAAE,KAAc,EAAE,OAAiB,EAAE,UAAoB;QAC3F,IAAI,CAAC,IAAI,CAAC,mBAAmB,MAAM,kBAAkB,UAAU,IAAI,KAAK,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,OAAe,EAAE,IAAc,EAAE,SAAiB;QACxE,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,eAAe,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAE5F,oDAAoD;QACpD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,qDAAqD;IAC7C,MAAM,CAAC,kBAAkB,GAAG,IAAI,GAAG,EAAkE,CAAC;IAE9G,MAAM,CAAC,eAAe,CAAC,SAAiB,EAAE,QAAuB,EAAE,YAAqB;QACtF,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,uCAAuC,QAAQ,EAAE,CAAC,CAAC;QACxE,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,aAAa,YAAY,QAAQ,CAAC,CAAC;QAC/C,CAAC;QAED,4BAA4B;QAC5B,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM;AACN,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,OAAO,MAAM;IACT,MAAM,CAAC,aAAa,CAAC,OAAe;QAC1C,OAAO,GAAG,UAAU,IAAI,OAAO,EAAE,GAAG,IAAI,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,OAAe,EAAE,GAAG,IAAW;QACxC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,OAAe,EAAE,GAAG,IAAW;QACzC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QAC1C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,OAAe,EAAE,GAAG,IAAW;QAC1C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,QAAgB,EAAE,IAAS;QAC/C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,CAAC,cAAc,CAAC,MAAc,EAAE,KAAc,EAAE,OAAiB,EAAE,UAAoB;QAC3F,IAAI,CAAC,IAAI,CAAC,mBAAmB,MAAM,kBAAkB,UAAU,IAAI,KAAK,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,CAAC,gBAAgB,CAAC,OAAe,EAAE,IAAc,EAAE,SAAiB;QACxE,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,eAAe,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,CAAC,eAAe,CAAC,SAAiB,EAAE,QAAuB,EAAE,YAAqB;QACtF,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,uCAAuC,QAAQ,EAAE,CAAC,CAAC;QACxE,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,aAAa,YAAY,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ export type ProgressToken = string | number;
2
+ export type SendProgress = (progressToken: ProgressToken, progress: number, total: number | undefined, message: string) => Promise<void> | void;
3
+ export type ProgressOutcome = 'success' | 'failure';
4
+ export interface ProgressUpdates {
5
+ recordOutput(output: string): void;
6
+ finish(outcome: ProgressOutcome): void;
7
+ }
8
+ /**
9
+ * Keep-alive progress for ONE tool call. Each call owns its timer and output
10
+ * preview, so a call that finishes never silences another call still running
11
+ * in the same server; a silenced call is aborted by the client.
12
+ */
13
+ export declare function startProgressUpdates(operationName: string, progressToken: ProgressToken | undefined, send: SendProgress): ProgressUpdates;
14
+ //# sourceMappingURL=progressUpdates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressUpdates.d.ts","sourceRoot":"","sources":["../../src/utils/progressUpdates.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,MAAM,YAAY,GAAG,CACzB,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,MAAM,KACZ,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE1B,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,CAAC;AAEpD,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAC;CACxC;AAeD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,aAAa,GAAG,SAAS,EACxC,IAAI,EAAE,YAAY,GACjB,eAAe,CA6BjB"}
@@ -0,0 +1,40 @@
1
+ import { PROTOCOL } from '../constants.js';
2
+ const OUTPUT_PREVIEW_CHARS = 150;
3
+ function keepAliveMessage(operationName, index) {
4
+ const messages = [
5
+ `🧠 ${operationName} - Gemini is analyzing your request...`,
6
+ `📊 ${operationName} - Processing files and generating insights...`,
7
+ `✨ ${operationName} - Creating structured response for your review...`,
8
+ `⏱️ ${operationName} - Large analysis in progress (this is normal for big requests)...`,
9
+ `🔍 ${operationName} - Still working... Gemini takes time for quality results...`,
10
+ ];
11
+ return messages[index % messages.length];
12
+ }
13
+ /**
14
+ * Keep-alive progress for ONE tool call. Each call owns its timer and output
15
+ * preview, so a call that finishes never silences another call still running
16
+ * in the same server; a silenced call is aborted by the client.
17
+ */
18
+ export function startProgressUpdates(operationName, progressToken, send) {
19
+ if (!progressToken) {
20
+ return { recordOutput: () => { }, finish: () => { } };
21
+ }
22
+ let latestOutput = '';
23
+ let ticks = 0;
24
+ void send(progressToken, 0, undefined, `🔍 Starting ${operationName}`);
25
+ const interval = setInterval(() => {
26
+ const base = keepAliveMessage(operationName, ticks);
27
+ ticks += 1;
28
+ const preview = latestOutput.slice(-OUTPUT_PREVIEW_CHARS).trim();
29
+ void send(progressToken, ticks, undefined, preview ? `${base}\n📝 Output: ...${preview}` : base);
30
+ }, PROTOCOL.KEEPALIVE_INTERVAL);
31
+ return {
32
+ recordOutput: (output) => { latestOutput = output; },
33
+ finish: (outcome) => {
34
+ clearInterval(interval);
35
+ const finalProgress = ticks + 1;
36
+ void send(progressToken, finalProgress, finalProgress, outcome === 'success' ? `✅ ${operationName} completed successfully` : `❌ ${operationName} failed`);
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=progressUpdates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progressUpdates.js","sourceRoot":"","sources":["../../src/utils/progressUpdates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAkB3C,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,SAAS,gBAAgB,CAAC,aAAqB,EAAE,KAAa;IAC5D,MAAM,QAAQ,GAAG;QACf,MAAM,aAAa,wCAAwC;QAC3D,MAAM,aAAa,gDAAgD;QACnE,KAAK,aAAa,oDAAoD;QACtE,MAAM,aAAa,oEAAoE;QACvF,MAAM,aAAa,8DAA8D;KAClF,CAAC;IACF,OAAO,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,aAAqB,EACrB,aAAwC,EACxC,IAAkB;IAElB,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IACtD,CAAC;IAED,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,SAAS,EAAE,eAAe,aAAa,EAAE,CAAC,CAAC;IAEvE,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,MAAM,IAAI,GAAG,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QACpD,KAAK,IAAI,CAAC,CAAC;QACX,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,CAAC,IAAI,EAAE,CAAC;QACjE,KAAK,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,mBAAmB,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACnG,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAEhC,OAAO;QACL,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC;QACpD,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE;YAClB,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,MAAM,aAAa,GAAG,KAAK,GAAG,CAAC,CAAC;YAChC,KAAK,IAAI,CACP,aAAa,EACb,aAAa,EACb,aAAa,EACb,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,aAAa,yBAAyB,CAAC,CAAC,CAAC,KAAK,aAAa,SAAS,CAClG,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joeytheman/gemini-mcp-tool",
3
- "version": "2.2.0",
3
+ "version": "2.3.1",
4
4
  "description": "MCP server for asking Gemini through Antigravity CLI (agy)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,6 +14,8 @@
14
14
  "test": "vitest run",
15
15
  "test:watch": "vitest watch",
16
16
  "test:coverage": "vitest run --coverage",
17
+ "snippet:build": "node scripts/minify-layout-snippet.mjs",
18
+ "test:chromium": "playwright-core install chromium-headless-shell && vitest run --config vitest.chromium.config.ts",
17
19
  "lint": "tsc --noEmit",
18
20
  "contribute": "tsx src/contribute.ts",
19
21
  "prepare": "npm run build",
@@ -43,7 +45,7 @@
43
45
  },
44
46
  "homepage": "https://github.com/joeytheman/gemini-mcp-tool#readme",
45
47
  "engines": {
46
- "node": ">=18.0.0"
48
+ "node": ">=20.12.0"
47
49
  },
48
50
  "files": [
49
51
  "dist/",
@@ -51,22 +53,20 @@
51
53
  "LICENSE"
52
54
  ],
53
55
  "dependencies": {
54
- "@modelcontextprotocol/sdk": "^1.25.3",
55
- "chalk": "^5.0.0",
56
- "d3-shape": "^3.2.0",
57
- "inquirer": "^13.3.0",
58
- "lru-cache": "^11.2.4",
59
- "prismjs": "^1.30.0",
60
- "zod": "^4.3.6"
56
+ "@modelcontextprotocol/sdk": "^1.32.2",
57
+ "lru-cache": "^11.5.3",
58
+ "zod": "^4.6.7"
61
59
  },
62
60
  "devDependencies": {
63
- "@types/inquirer": "^9.0.9",
64
61
  "@types/node": "^25.3.3",
65
62
  "@vitest/coverage-v8": "^4.0.18",
66
- "archiver": "^7.0.1",
63
+ "esbuild": "^0.25.12",
67
64
  "mermaid": "^11.12.2",
68
- "tsx": "^4.0.0",
65
+ "playwright-core": "1.64.1",
66
+ "prismjs": "^1.30.0",
67
+ "tsx": "^4.23.15",
69
68
  "typescript": "^5.0.0",
69
+ "vite": "^6.4.4",
70
70
  "vitepress": "^1.6.4",
71
71
  "vitepress-plugin-mermaid": "^2.0.17",
72
72
  "vitest": "^4.0.18"
@@ -75,6 +75,11 @@
75
75
  "access": "public"
76
76
  },
77
77
  "overrides": {
78
- "esbuild": ">=0.25.0"
78
+ "vitepress": {
79
+ "vite": "^6.4.4"
80
+ },
81
+ "mermaid": {
82
+ "katex": "^0.18.2"
83
+ }
79
84
  }
80
85
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=agyTranscriptRecovery.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agyTranscriptRecovery.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/utils/agyTranscriptRecovery.test.ts"],"names":[],"mappings":""}
@@ -1,127 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- const store = new Map();
3
- const stats = new Map();
4
- vi.mock('os', () => ({
5
- homedir: () => '/home/test',
6
- }));
7
- vi.mock('fs', () => ({
8
- readFileSync: vi.fn((p) => {
9
- if (!store.has(p))
10
- throw new Error(`ENOENT: ${p}`);
11
- return store.get(p);
12
- }),
13
- statSync: vi.fn((p) => {
14
- if (!stats.has(p))
15
- throw new Error(`ENOENT: ${p}`);
16
- return stats.get(p);
17
- }),
18
- realpathSync: vi.fn((p) => p),
19
- }));
20
- vi.mock('../../utils/logger.js', () => ({
21
- Logger: { debug: vi.fn(), warn: vi.fn(), error: vi.fn(), log: vi.fn() },
22
- }));
23
- import { recoverFromTranscript, isRecoverableEmptyOutput } from '../../utils/agyTranscriptRecovery.js';
24
- import { AGY_INTERNAL } from '../../constants.js';
25
- const ROOT = '/home/test/.gemini/antigravity-cli';
26
- const MAP_PATH = `${ROOT}/cache/last_conversations.json`;
27
- const RUN_START = 1_700_000_000_000;
28
- const FRESH = new Date(RUN_START + 3000).toISOString();
29
- const STALE = new Date(RUN_START - 600_000).toISOString();
30
- function transcriptPath(id) {
31
- return `${ROOT}/brain/${id}/.system_generated/logs/transcript.jsonl`;
32
- }
33
- function setMap(map) {
34
- store.set(MAP_PATH, JSON.stringify(map));
35
- stats.set(MAP_PATH, { mtimeMs: RUN_START });
36
- }
37
- function setTranscript(id, lines) {
38
- const p = transcriptPath(id);
39
- store.set(p, lines.map((l) => JSON.stringify(l)).join('\n'));
40
- stats.set(p, { mtimeMs: RUN_START + 3000 });
41
- }
42
- function finalResponse(content, created_at = FRESH) {
43
- return { step_index: 1, source: 'MODEL', type: 'PLANNER_RESPONSE', status: 'DONE', created_at, content };
44
- }
45
- describe('isRecoverableEmptyOutput', () => {
46
- it('is true for empty / whitespace / the timeout sentinel only', () => {
47
- expect(isRecoverableEmptyOutput('')).toBe(true);
48
- expect(isRecoverableEmptyOutput(' \n ')).toBe(true);
49
- expect(isRecoverableEmptyOutput(AGY_INTERNAL.TIMEOUT_SENTINEL)).toBe(true);
50
- expect(isRecoverableEmptyOutput('a real answer')).toBe(false);
51
- });
52
- });
53
- describe('recoverFromTranscript', () => {
54
- beforeEach(() => {
55
- store.clear();
56
- stats.clear();
57
- delete process.env[AGY_INTERNAL.DISABLE_RECOVERY_ENV];
58
- });
59
- it('returns the last final response content keyed by cwd', () => {
60
- setMap({ '/proj': 'conv1' });
61
- setTranscript('conv1', [
62
- { source: 'MODEL', type: 'VIEW_FILE', status: 'DONE', content: 'noise' },
63
- finalResponse('ANSWER'),
64
- ]);
65
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBe('ANSWER');
66
- });
67
- it('unwraps a nested {content} JSON payload', () => {
68
- setMap({ '/proj': 'conv1' });
69
- setTranscript('conv1', [finalResponse(JSON.stringify({ type: 'message', content: 'INNER' }))]);
70
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBe('INNER');
71
- });
72
- it('falls back to the raw string when nested JSON is malformed', () => {
73
- setMap({ '/proj': 'conv1' });
74
- setTranscript('conv1', [finalResponse('{"content": brokenjson')]);
75
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBe('{"content": brokenjson');
76
- });
77
- it('returns the LAST final response when several exist', () => {
78
- setMap({ '/proj': 'conv1' });
79
- setTranscript('conv1', [finalResponse('FIRST'), finalResponse('LAST')]);
80
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBe('LAST');
81
- });
82
- it('returns null when cwd is not in the map (no cross-conversation leakage)', () => {
83
- setMap({ '/other': 'conv1' });
84
- setTranscript('conv1', [finalResponse('NOT YOURS')]);
85
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBeNull();
86
- });
87
- it('treats a response that predates the run as stale', () => {
88
- setMap({ '/proj': 'conv1' });
89
- setTranscript('conv1', [finalResponse('OLD', STALE)]);
90
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBeNull();
91
- });
92
- it('returns null when recovery is disabled via env', () => {
93
- process.env[AGY_INTERNAL.DISABLE_RECOVERY_ENV] = 'true';
94
- setMap({ '/proj': 'conv1' });
95
- setTranscript('conv1', [finalResponse('ANSWER')]);
96
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBeNull();
97
- });
98
- it('never throws when the map or transcript is missing', () => {
99
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBeNull(); // no map
100
- setMap({ '/proj': 'conv1' }); // map present, transcript absent
101
- expect(recoverFromTranscript({ cwd: '/proj', runStartMs: RUN_START })).toBeNull();
102
- });
103
- it('reads only the explicitly requested conversation, ignoring the cwd map', () => {
104
- setMap({ '/proj': 'conv1' });
105
- setTranscript('conv1', [finalResponse('LATEST FOR CWD')]);
106
- setTranscript('conv2', [finalResponse('RESUMED')]);
107
- expect(recoverFromTranscript({ cwd: '/proj', conversationId: 'conv2', runStartMs: RUN_START }))
108
- .toBe('RESUMED');
109
- });
110
- it('refuses a conversation id that would escape the brain directory', () => {
111
- setMap({ '/proj': 'conv1' });
112
- setTranscript('conv1', [finalResponse('ANSWER')]);
113
- setTranscript('../../../etc/passwd', [finalResponse('SECRET')]);
114
- expect(recoverFromTranscript({
115
- cwd: '/proj',
116
- conversationId: '../../../etc/passwd',
117
- runStartMs: RUN_START,
118
- })).toBeNull();
119
- });
120
- it('falls back to the cwd lookup when no conversation id is given', () => {
121
- setMap({ '/proj': 'conv1' });
122
- setTranscript('conv1', [finalResponse('LATEST FOR CWD')]);
123
- expect(recoverFromTranscript({ cwd: '/proj', conversationId: ' ', runStartMs: RUN_START }))
124
- .toBe('LATEST FOR CWD');
125
- });
126
- });
127
- //# sourceMappingURL=agyTranscriptRecovery.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agyTranscriptRecovery.test.js","sourceRoot":"","sources":["../../../src/__tests__/utils/agyTranscriptRecovery.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;AACxC,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;AAErD,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY;CAC5B,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnB,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE;QAChC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACnD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC,CAAC;IACF,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE;QAC5B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACnD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC,CAAC;IACF,YAAY,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC;CACtC,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,CAAC;IACtC,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;CACxE,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AACvG,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,IAAI,GAAG,oCAAoC,CAAC;AAClD,MAAM,QAAQ,GAAG,GAAG,IAAI,gCAAgC,CAAC;AACzD,MAAM,SAAS,GAAG,iBAAiB,CAAC;AACpC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AACvD,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;AAE1D,SAAS,cAAc,CAAC,EAAU;IAChC,OAAO,GAAG,IAAI,UAAU,EAAE,0CAA0C,CAAC;AACvE,CAAC;AAED,SAAS,MAAM,CAAC,GAA2B;IACzC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,aAAa,CAAC,EAAU,EAAE,KAAe;IAChD,MAAM,CAAC,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;IAC7B,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,aAAa,CAAC,OAAgB,EAAE,UAAU,GAAG,KAAK;IACzD,OAAO,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AAC3G,CAAC;AAED,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,wBAAwB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,wBAAwB,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3E,MAAM,CAAC,wBAAwB,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,UAAU,CAAC,GAAG,EAAE;QACd,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE;YACrB,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE;YACxE,aAAa,CAAC,QAAQ,CAAC;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/F,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACxG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACxE,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,oBAAoB,CAAC,GAAG,MAAM,CAAC;QACxD,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,SAAS;QAC5F,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,iCAAiC;QAC/D,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;QAChF,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAC1D,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAEnD,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;aAC5F,IAAI,CAAC,SAAS,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAClD,aAAa,CAAC,qBAAqB,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAEhE,MAAM,CAAC,qBAAqB,CAAC;YAC3B,GAAG,EAAE,OAAO;YACZ,cAAc,EAAE,qBAAqB;YACrC,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7B,aAAa,CAAC,OAAO,EAAE,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QAE1D,MAAM,CAAC,qBAAqB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;aACzF,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,16 +0,0 @@
1
- /** Output that should trigger transcript recovery: empty or the timeout sentinel. */
2
- export declare function isRecoverableEmptyOutput(stdout: string): boolean;
3
- /**
4
- * Recover the latest model response for `conversationId` (or, absent one, for
5
- * `cwd`) if it was produced after
6
- * `runStartMs`. Returns the recovered text, or `null` if recovery is disabled,
7
- * the cwd has no known conversation, the transcript is stale/missing, or any
8
- * access fails. There is intentionally NO global "newest transcript" fallback —
9
- * that could return another project's or session's answer.
10
- */
11
- export declare function recoverFromTranscript(opts: {
12
- cwd?: string;
13
- conversationId?: string;
14
- runStartMs: number;
15
- }): string | null;
16
- //# sourceMappingURL=agyTranscriptRecovery.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agyTranscriptRecovery.d.ts","sourceRoot":"","sources":["../../src/utils/agyTranscriptRecovery.ts"],"names":[],"mappings":"AAmCA,qFAAqF;AACrF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGhE;AA8ED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAClE,MAAM,GAAG,IAAI,CA8Bf"}
@@ -1,149 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"agyTranscriptRecovery.js","sourceRoot":"","sources":["../../src/utils/agyTranscriptRecovery.ts"],"names":[],"mappings":"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"}