@joeytheman/gemini-mcp-tool 2.3.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.
- package/dist/__tests__/server.test.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -4
- package/dist/__tests__/utils/agyTranscriptRecovery.test.d.ts +0 -2
- package/dist/__tests__/utils/agyTranscriptRecovery.test.d.ts.map +0 -1
- package/dist/__tests__/utils/agyTranscriptRecovery.test.js +0 -127
- package/dist/__tests__/utils/agyTranscriptRecovery.test.js.map +0 -1
- package/dist/utils/agyTranscriptRecovery.d.ts +0 -16
- package/dist/utils/agyTranscriptRecovery.d.ts.map +0 -1
- package/dist/utils/agyTranscriptRecovery.js +0 -149
- package/dist/utils/agyTranscriptRecovery.js.map +0 -1
|
@@ -46,7 +46,7 @@ describe('Gemini MCP Server', () => {
|
|
|
46
46
|
expect(serverConstructorCalls.length).toBeGreaterThanOrEqual(1);
|
|
47
47
|
const [serverConfig] = serverConstructorCalls[0];
|
|
48
48
|
expect(serverConfig).toHaveProperty('name', 'gemini-mcp');
|
|
49
|
-
expect(packageVersion).toBe('2.3.
|
|
49
|
+
expect(packageVersion).toBe('2.3.1');
|
|
50
50
|
expect(serverConfig).toHaveProperty('version', packageVersion);
|
|
51
51
|
});
|
|
52
52
|
it('should register capabilities', () => {
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { startProgressUpdates } from "./utils/progressUpdates.js";
|
|
|
8
8
|
import { getToolDefinitions, getPromptDefinitions, executeTool, toolExists, getPromptMessage } from "./tools/index.js";
|
|
9
9
|
const server = new Server({
|
|
10
10
|
name: "gemini-mcp",
|
|
11
|
-
version: "2.3.
|
|
11
|
+
version: "2.3.1",
|
|
12
12
|
}, {
|
|
13
13
|
capabilities: {
|
|
14
14
|
tools: {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joeytheman/gemini-mcp-tool",
|
|
3
|
-
"version": "2.3.
|
|
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",
|
|
@@ -60,13 +60,13 @@
|
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@types/node": "^25.3.3",
|
|
62
62
|
"@vitest/coverage-v8": "^4.0.18",
|
|
63
|
-
"archiver": "^7.0.1",
|
|
64
63
|
"esbuild": "^0.25.12",
|
|
65
64
|
"mermaid": "^11.12.2",
|
|
66
65
|
"playwright-core": "1.64.1",
|
|
67
66
|
"prismjs": "^1.30.0",
|
|
68
|
-
"tsx": "^4.
|
|
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"
|
|
@@ -76,7 +76,10 @@
|
|
|
76
76
|
},
|
|
77
77
|
"overrides": {
|
|
78
78
|
"vitepress": {
|
|
79
|
-
"
|
|
79
|
+
"vite": "^6.4.4"
|
|
80
|
+
},
|
|
81
|
+
"mermaid": {
|
|
82
|
+
"katex": "^0.18.2"
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
85
|
}
|
|
@@ -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":"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"}
|
|
@@ -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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"}
|