@kenkaiiii/ggcoder 5.26.2 → 5.27.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.
- package/dist/app-sidecar.js +81 -47
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/agent-session-marker-anchors.test.js +181 -2
- package/dist/core/agent-session-marker-anchors.test.js.map +1 -1
- package/dist/core/agent-session-process-gate.test.d.ts +2 -0
- package/dist/core/agent-session-process-gate.test.d.ts.map +1 -0
- package/dist/core/agent-session-process-gate.test.js +88 -0
- package/dist/core/agent-session-process-gate.test.js.map +1 -0
- package/dist/core/agent-session-slash-restore.test.d.ts +2 -0
- package/dist/core/agent-session-slash-restore.test.d.ts.map +1 -0
- package/dist/core/agent-session-slash-restore.test.js +121 -0
- package/dist/core/agent-session-slash-restore.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +66 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +304 -35
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts +21 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +16 -0
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +91 -0
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/foreign-session-import.d.ts +120 -0
- package/dist/core/foreign-session-import.d.ts.map +1 -0
- package/dist/core/foreign-session-import.js +594 -0
- package/dist/core/foreign-session-import.js.map +1 -0
- package/dist/core/foreign-session-import.test.d.ts +2 -0
- package/dist/core/foreign-session-import.test.d.ts.map +1 -0
- package/dist/core/foreign-session-import.test.js +220 -0
- package/dist/core/foreign-session-import.test.js.map +1 -0
- package/dist/core/foreign-transcript-blocks.d.ts +51 -0
- package/dist/core/foreign-transcript-blocks.d.ts.map +1 -0
- package/dist/core/foreign-transcript-blocks.js +151 -0
- package/dist/core/foreign-transcript-blocks.js.map +1 -0
- package/dist/core/mcp/catalog-cache.d.ts +63 -0
- package/dist/core/mcp/catalog-cache.d.ts.map +1 -0
- package/dist/core/mcp/catalog-cache.js +163 -0
- package/dist/core/mcp/catalog-cache.js.map +1 -0
- package/dist/core/mcp/catalog-cache.test.d.ts +2 -0
- package/dist/core/mcp/catalog-cache.test.d.ts.map +1 -0
- package/dist/core/mcp/catalog-cache.test.js +99 -0
- package/dist/core/mcp/catalog-cache.test.js.map +1 -0
- package/dist/core/mcp/client.d.ts +61 -0
- package/dist/core/mcp/client.d.ts.map +1 -1
- package/dist/core/mcp/client.js +216 -31
- package/dist/core/mcp/client.js.map +1 -1
- package/dist/core/mcp/legacy-negotiation.test.d.ts +2 -0
- package/dist/core/mcp/legacy-negotiation.test.d.ts.map +1 -0
- package/dist/core/mcp/legacy-negotiation.test.js +80 -0
- package/dist/core/mcp/legacy-negotiation.test.js.map +1 -0
- package/dist/core/mcp/oauth-provider.d.ts +1 -2
- package/dist/core/mcp/oauth-provider.d.ts.map +1 -1
- package/dist/core/mcp/oauth-provider.js +5 -1
- package/dist/core/mcp/oauth-provider.js.map +1 -1
- package/dist/core/mcp/oauth-store.d.ts +1 -1
- package/dist/core/mcp/oauth-store.d.ts.map +1 -1
- package/dist/core/mcp/oauth-store.js.map +1 -1
- package/dist/core/mcp/when-connected.test.d.ts +2 -0
- package/dist/core/mcp/when-connected.test.d.ts.map +1 -0
- package/dist/core/mcp/when-connected.test.js +46 -0
- package/dist/core/mcp/when-connected.test.js.map +1 -0
- package/dist/core/process-gate.d.ts +45 -0
- package/dist/core/process-gate.d.ts.map +1 -0
- package/dist/core/process-gate.js +71 -0
- package/dist/core/process-gate.js.map +1 -0
- package/dist/core/process-gate.test.d.ts +2 -0
- package/dist/core/process-gate.test.d.ts.map +1 -0
- package/dist/core/process-gate.test.js +87 -0
- package/dist/core/process-gate.test.js.map +1 -0
- package/dist/core/process-manager.d.ts +9 -0
- package/dist/core/process-manager.d.ts.map +1 -1
- package/dist/core/process-manager.js +17 -15
- package/dist/core/process-manager.js.map +1 -1
- package/dist/core/session-history.d.ts +61 -4
- package/dist/core/session-history.d.ts.map +1 -1
- package/dist/core/session-history.js +144 -15
- package/dist/core/session-history.js.map +1 -1
- package/dist/core/session-history.test.js +50 -1
- package/dist/core/session-history.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +35 -6
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +39 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +14 -2
- package/dist/core/session-manager.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +6 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts +2 -0
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +17 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/slash-commands.test.js +1 -0
- package/dist/core/slash-commands.test.js.map +1 -1
- package/dist/tools/tool-search.d.ts +12 -1
- package/dist/tools/tool-search.d.ts.map +1 -1
- package/dist/tools/tool-search.js +22 -3
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-search.test.d.ts +2 -0
- package/dist/tools/tool-search.test.d.ts.map +1 -0
- package/dist/tools/tool-search.test.js +69 -0
- package/dist/tools/tool-search.test.js.map +1 -0
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +27 -1
- package/dist/ui/App.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { detectForeignFormat, importForeignSession, parseForeignTranscript, } from "./foreign-session-import.js";
|
|
7
|
+
import { extractCursorUserQuery } from "./foreign-transcript-blocks.js";
|
|
8
|
+
import { APP_MARKER_CUSTOM_KIND, SessionManager } from "./session-manager.js";
|
|
9
|
+
const FIXTURES = path.join(path.dirname(fileURLToPath(import.meta.url)), "__fixtures__");
|
|
10
|
+
const FIXTURE_FILE = {
|
|
11
|
+
claude: path.join(FIXTURES, "claude-transcript.jsonl"),
|
|
12
|
+
codex: path.join(FIXTURES, "codex-transcript.jsonl"),
|
|
13
|
+
cursor: path.join(FIXTURES, "cursor-transcript.jsonl"),
|
|
14
|
+
};
|
|
15
|
+
async function parseFixture(format) {
|
|
16
|
+
return parseForeignTranscript(await fs.readFile(FIXTURE_FILE[format], "utf-8"));
|
|
17
|
+
}
|
|
18
|
+
function assistantParts(message) {
|
|
19
|
+
if (!message || message.role !== "assistant")
|
|
20
|
+
throw new Error("expected an assistant message");
|
|
21
|
+
return message.content;
|
|
22
|
+
}
|
|
23
|
+
function allText(messages) {
|
|
24
|
+
return JSON.stringify(messages);
|
|
25
|
+
}
|
|
26
|
+
describe("detectForeignFormat", () => {
|
|
27
|
+
it("identifies each format from its record shapes", async () => {
|
|
28
|
+
for (const format of ["claude", "codex", "cursor"]) {
|
|
29
|
+
const text = await fs.readFile(FIXTURE_FILE[format], "utf-8");
|
|
30
|
+
expect(detectForeignFormat(text)).toBe(format);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
it("returns undefined for an unrelated JSONL file", () => {
|
|
34
|
+
expect(detectForeignFormat('{"hello":"world"}\n{"a":1}')).toBeUndefined();
|
|
35
|
+
});
|
|
36
|
+
it("throws a clear error when asked to parse an unknown format", () => {
|
|
37
|
+
expect(() => parseForeignTranscript('{"hello":"world"}')).toThrow(/Unrecognized transcript/);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("Claude Code import", () => {
|
|
41
|
+
it("maps prompts, thinking, tool calls and tool results", async () => {
|
|
42
|
+
const result = await parseFixture("claude");
|
|
43
|
+
expect(result.cwd).toBe("/Users/dev/widgets");
|
|
44
|
+
expect(result.preview).toBe("Add a retry to the fetch helper.");
|
|
45
|
+
expect(result.messages.map((m) => m.role)).toEqual(["user", "assistant", "tool", "assistant"]);
|
|
46
|
+
const parts = assistantParts(result.messages[1]);
|
|
47
|
+
expect(Array.isArray(parts)).toBe(true);
|
|
48
|
+
expect(parts.map((p) => p.type)).toEqual([
|
|
49
|
+
"thinking",
|
|
50
|
+
"text",
|
|
51
|
+
"tool_call",
|
|
52
|
+
]);
|
|
53
|
+
const toolMessage = result.messages[2];
|
|
54
|
+
expect(toolMessage?.role).toBe("tool");
|
|
55
|
+
if (toolMessage?.role === "tool") {
|
|
56
|
+
expect(toolMessage.content[0]?.toolCallId).toBe("toolu_1");
|
|
57
|
+
expect(toolMessage.content[0]?.content).toContain("export async function get");
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
it("skips sidechain (subagent) records", async () => {
|
|
61
|
+
const result = await parseFixture("claude");
|
|
62
|
+
expect(allText(result.messages)).not.toContain("subagent chatter");
|
|
63
|
+
});
|
|
64
|
+
it("drops an orphan tool result rather than inventing a pairing", async () => {
|
|
65
|
+
const result = await parseFixture("claude");
|
|
66
|
+
expect(allText(result.messages)).not.toContain("no matching call");
|
|
67
|
+
expect(result.dropped.toolResults).toBe(1);
|
|
68
|
+
});
|
|
69
|
+
it("counts unparseable lines instead of failing the import", async () => {
|
|
70
|
+
const result = await parseFixture("claude");
|
|
71
|
+
expect(result.dropped.records).toBe(1);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe("Codex import", () => {
|
|
75
|
+
it("maps the conversation without duplicating event_msg mirrors", async () => {
|
|
76
|
+
const result = await parseFixture("codex");
|
|
77
|
+
expect(result.cwd).toBe("/Users/dev/widgets");
|
|
78
|
+
expect(result.preview).toBe("Why is the build slow?");
|
|
79
|
+
expect(result.messages.map((m) => m.role)).toEqual(["user", "assistant", "tool", "assistant"]);
|
|
80
|
+
// "Why is the build slow?" appears in both an event_msg and a response_item.
|
|
81
|
+
const userMessages = result.messages.filter((m) => m.role === "user");
|
|
82
|
+
expect(userMessages).toHaveLength(1);
|
|
83
|
+
});
|
|
84
|
+
it("skips Codex's own harness context turns", async () => {
|
|
85
|
+
const result = await parseFixture("codex");
|
|
86
|
+
expect(allText(result.messages)).not.toContain("permissions instructions");
|
|
87
|
+
});
|
|
88
|
+
it("parses a JSON-string function_call into structured args", async () => {
|
|
89
|
+
const result = await parseFixture("codex");
|
|
90
|
+
const parts = assistantParts(result.messages[1]);
|
|
91
|
+
const call = parts.find((part) => part.type === "tool_call");
|
|
92
|
+
expect(call?.args).toEqual({ command: ["bash", "-lc", "cat tsup.config.ts"] });
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
describe("Cursor import", () => {
|
|
96
|
+
it("strips recognized context wrappers from the user query", async () => {
|
|
97
|
+
const result = await parseFixture("cursor");
|
|
98
|
+
expect(result.preview).toBe("Rename the Button component to IconButton.");
|
|
99
|
+
expect(result.preview).not.toContain("cursor_commands");
|
|
100
|
+
expect(result.preview).not.toContain("<timestamp>");
|
|
101
|
+
});
|
|
102
|
+
it("carries no wrapper text anywhere in the imported messages", async () => {
|
|
103
|
+
const result = await parseFixture("cursor");
|
|
104
|
+
const serialized = allText(result.messages);
|
|
105
|
+
expect(serialized).not.toContain("<cursor_commands>");
|
|
106
|
+
expect(serialized).not.toContain("<timestamp>");
|
|
107
|
+
expect(serialized).not.toContain("user opened src/index.ts");
|
|
108
|
+
});
|
|
109
|
+
it("keeps a message with unrecognized leading context intact", async () => {
|
|
110
|
+
const result = await parseFixture("cursor");
|
|
111
|
+
const users = result.messages.filter((m) => m.role === "user");
|
|
112
|
+
expect(users[1]?.content).toContain("<mystery_context>");
|
|
113
|
+
expect(users[1]?.content).toContain("Now add a size prop.");
|
|
114
|
+
});
|
|
115
|
+
it("pairs tool calls with their results", async () => {
|
|
116
|
+
const result = await parseFixture("cursor");
|
|
117
|
+
const toolMessage = result.messages.find((m) => m.role === "tool");
|
|
118
|
+
expect(toolMessage?.role).toBe("tool");
|
|
119
|
+
if (toolMessage?.role === "tool") {
|
|
120
|
+
expect(toolMessage.content[0]?.toolCallId).toBe("tc_1");
|
|
121
|
+
expect(toolMessage.content[0]?.content).toBe("1 file changed");
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
it("normalizes second-precision timestamps to millis", async () => {
|
|
125
|
+
const result = await parseFixture("cursor");
|
|
126
|
+
expect(result.startedAt).toBe(1784544000 * 1000);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe("extractCursorUserQuery", () => {
|
|
130
|
+
it("returns plain text unchanged", () => {
|
|
131
|
+
expect(extractCursorUserQuery("just a prompt")).toBe("just a prompt");
|
|
132
|
+
});
|
|
133
|
+
it("unwraps a bare user_query", () => {
|
|
134
|
+
expect(extractCursorUserQuery("<user_query>hello</user_query>")).toBe("hello");
|
|
135
|
+
});
|
|
136
|
+
it("refuses to truncate unknown leading context", () => {
|
|
137
|
+
const raw = "<unknown>ctx</unknown>\n<user_query>hi</user_query>";
|
|
138
|
+
expect(extractCursorUserQuery(raw)).toBe(raw);
|
|
139
|
+
});
|
|
140
|
+
it("leaves an unterminated wrapper alone", () => {
|
|
141
|
+
const raw = "<cursor_commands>oops\n<user_query>hi</user_query>";
|
|
142
|
+
expect(extractCursorUserQuery(raw)).toBe(raw);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe("importForeignSession", () => {
|
|
146
|
+
let root;
|
|
147
|
+
let sessionManager;
|
|
148
|
+
beforeEach(async () => {
|
|
149
|
+
root = await fs.mkdtemp(path.join(os.tmpdir(), "gg-import-"));
|
|
150
|
+
sessionManager = new SessionManager(path.join(root, "sessions"));
|
|
151
|
+
});
|
|
152
|
+
afterEach(async () => {
|
|
153
|
+
await fs.rm(root, { recursive: true, force: true });
|
|
154
|
+
});
|
|
155
|
+
it("writes a resumable session that round-trips through the normal loader", async () => {
|
|
156
|
+
const imported = await importForeignSession({
|
|
157
|
+
filePath: FIXTURE_FILE.claude,
|
|
158
|
+
sessionManager,
|
|
159
|
+
provider: "anthropic",
|
|
160
|
+
model: "claude-sonnet-5",
|
|
161
|
+
});
|
|
162
|
+
expect(imported.cwd).toBe("/Users/dev/widgets");
|
|
163
|
+
expect(imported.messageCount).toBe(4);
|
|
164
|
+
const loaded = await sessionManager.load(imported.sessionPath);
|
|
165
|
+
expect(loaded).not.toBeNull();
|
|
166
|
+
expect(loaded.header.cwd).toBe("/Users/dev/widgets");
|
|
167
|
+
expect(loaded.header.preview).toBe("Add a retry to the fetch helper.");
|
|
168
|
+
const messages = sessionManager.getMessages(loaded.entries, loaded.header.leafId);
|
|
169
|
+
expect(messages.map((m) => m.role)).toEqual(["user", "assistant", "tool", "assistant"]);
|
|
170
|
+
});
|
|
171
|
+
it("records an import marker naming the source and what was dropped", async () => {
|
|
172
|
+
const imported = await importForeignSession({
|
|
173
|
+
filePath: FIXTURE_FILE.claude,
|
|
174
|
+
sessionManager,
|
|
175
|
+
provider: "anthropic",
|
|
176
|
+
model: "claude-sonnet-5",
|
|
177
|
+
});
|
|
178
|
+
const loaded = await sessionManager.load(imported.sessionPath);
|
|
179
|
+
const markers = sessionManager.getAppMarkers(loaded.entries, loaded.header.leafId);
|
|
180
|
+
const importMarker = markers.find((marker) => marker.kind === "import");
|
|
181
|
+
expect(importMarker).toBeDefined();
|
|
182
|
+
expect(importMarker?.data.source).toBe("claude");
|
|
183
|
+
expect(String(importMarker?.data.dropped)).toContain("tool result");
|
|
184
|
+
// The marker must stay OFF the message DAG so the model never sees it.
|
|
185
|
+
const custom = loaded.entries.filter((entry) => entry.type === "custom" && entry.kind === APP_MARKER_CUSTOM_KIND);
|
|
186
|
+
expect(custom).toHaveLength(1);
|
|
187
|
+
expect(custom[0]?.parentId).toBeNull();
|
|
188
|
+
});
|
|
189
|
+
it("imports a Cursor thread with no wrapper text in its preview", async () => {
|
|
190
|
+
const imported = await importForeignSession({
|
|
191
|
+
filePath: FIXTURE_FILE.cursor,
|
|
192
|
+
sessionManager,
|
|
193
|
+
provider: "anthropic",
|
|
194
|
+
model: "claude-sonnet-5",
|
|
195
|
+
});
|
|
196
|
+
expect(imported.preview).toBe("Rename the Button component to IconButton.");
|
|
197
|
+
const loaded = await sessionManager.load(imported.sessionPath);
|
|
198
|
+
expect(loaded.header.preview).not.toContain("cursor_commands");
|
|
199
|
+
expect(loaded.header.preview).not.toContain("<timestamp>");
|
|
200
|
+
});
|
|
201
|
+
it("prefers an explicit cwd over the one recorded by the source agent", async () => {
|
|
202
|
+
const imported = await importForeignSession({
|
|
203
|
+
filePath: FIXTURE_FILE.codex,
|
|
204
|
+
sessionManager,
|
|
205
|
+
provider: "anthropic",
|
|
206
|
+
model: "claude-sonnet-5",
|
|
207
|
+
cwd: "/Users/dev/elsewhere",
|
|
208
|
+
});
|
|
209
|
+
expect(imported.cwd).toBe("/Users/dev/elsewhere");
|
|
210
|
+
});
|
|
211
|
+
it("fails clearly on a missing file", async () => {
|
|
212
|
+
await expect(importForeignSession({
|
|
213
|
+
filePath: path.join(root, "nope.jsonl"),
|
|
214
|
+
sessionManager,
|
|
215
|
+
provider: "anthropic",
|
|
216
|
+
model: "claude-sonnet-5",
|
|
217
|
+
})).rejects.toThrow(/Could not read transcript/);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
//# sourceMappingURL=foreign-session-import.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreign-session-import.test.js","sourceRoot":"","sources":["../../src/core/foreign-session-import.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ContentPart, TextContent, ToolCall } from "@kenkaiiii/gg-ai";
|
|
2
|
+
/**
|
|
3
|
+
* Primitives shared by every foreign-transcript parser (Claude Code, Codex,
|
|
4
|
+
* Cursor): content-block normalization, tool-call extraction and timestamps.
|
|
5
|
+
*
|
|
6
|
+
* The formats differ in their envelopes but agree on the substance — text,
|
|
7
|
+
* thinking, tool calls and tool results — so the per-format parsers stay thin
|
|
8
|
+
* and the risky normalization lives in exactly one place.
|
|
9
|
+
*/
|
|
10
|
+
/** Loose JSON object guard; foreign records are untrusted input. */
|
|
11
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
12
|
+
export declare function asString(value: unknown): string | undefined;
|
|
13
|
+
/** Parse one JSONL line, returning undefined for blank or malformed lines. */
|
|
14
|
+
export declare function parseJsonLine(line: string): Record<string, unknown> | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Normalize a record's timestamp to epoch millis. Foreign formats use ISO
|
|
17
|
+
* strings (Claude, Codex) or numeric epochs in seconds or millis (Cursor).
|
|
18
|
+
* Returns undefined rather than guessing when the value is unusable.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeTimestamp(value: unknown): number | undefined;
|
|
21
|
+
/** Collapse a text block list into one string, dropping empties. */
|
|
22
|
+
export declare function joinText(parts: readonly string[]): string;
|
|
23
|
+
export declare function textPart(text: string): TextContent;
|
|
24
|
+
/**
|
|
25
|
+
* Build a tool-call part from a foreign record. `args` may arrive as an object
|
|
26
|
+
* (Claude `input`) or a JSON string (Codex `arguments`); an unparseable string
|
|
27
|
+
* is preserved verbatim under `raw` rather than dropped, so a resumed thread
|
|
28
|
+
* still shows what was attempted.
|
|
29
|
+
*/
|
|
30
|
+
export declare function toolCallPart(id: string, name: string, args: unknown): ToolCall;
|
|
31
|
+
export declare function normalizeToolArgs(args: unknown): Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Flatten a foreign tool result into plain text. Import is lossy by design: we
|
|
34
|
+
* never fabricate structure we did not read, so anything that is not text
|
|
35
|
+
* becomes a short placeholder instead of an invented block.
|
|
36
|
+
*/
|
|
37
|
+
export declare function toolResultText(content: unknown): string;
|
|
38
|
+
/** Drop empty text parts so an import never produces a blank message. */
|
|
39
|
+
export declare function compactParts(parts: ContentPart[]): ContentPart[];
|
|
40
|
+
/**
|
|
41
|
+
* Extract the real prompt from a Cursor user message.
|
|
42
|
+
*
|
|
43
|
+
* Cursor wraps the typed prompt in `<user_query>` and prepends context blocks
|
|
44
|
+
* (`<cursor_commands>`, `<timestamp>`, …). Importing the raw string leaks that
|
|
45
|
+
* scaffolding into the session preview and title. We take the trailing
|
|
46
|
+
* `<user_query>` only when everything before it is recognized context;
|
|
47
|
+
* otherwise the message is returned unchanged, because unknown leading context
|
|
48
|
+
* may be part of what the user actually said.
|
|
49
|
+
*/
|
|
50
|
+
export declare function extractCursorUserQuery(raw: string): string;
|
|
51
|
+
//# sourceMappingURL=foreign-transcript-blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreign-transcript-blocks.d.ts","sourceRoot":"","sources":["../../src/core/foreign-transcript-blocks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE3E;;;;;;;GAOG;AAEH,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE3D;AAED,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAS/E;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CASrE;AAED,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAKzD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,CAE9E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUxE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAkBvD;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAIhE;AAYD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM1D"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Primitives shared by every foreign-transcript parser (Claude Code, Codex,
|
|
3
|
+
* Cursor): content-block normalization, tool-call extraction and timestamps.
|
|
4
|
+
*
|
|
5
|
+
* The formats differ in their envelopes but agree on the substance — text,
|
|
6
|
+
* thinking, tool calls and tool results — so the per-format parsers stay thin
|
|
7
|
+
* and the risky normalization lives in exactly one place.
|
|
8
|
+
*/
|
|
9
|
+
/** Loose JSON object guard; foreign records are untrusted input. */
|
|
10
|
+
export function isRecord(value) {
|
|
11
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
export function asString(value) {
|
|
14
|
+
return typeof value === "string" ? value : undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Parse one JSONL line, returning undefined for blank or malformed lines. */
|
|
17
|
+
export function parseJsonLine(line) {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
if (!trimmed)
|
|
20
|
+
return undefined;
|
|
21
|
+
try {
|
|
22
|
+
const parsed = JSON.parse(trimmed);
|
|
23
|
+
return isRecord(parsed) ? parsed : undefined;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Normalize a record's timestamp to epoch millis. Foreign formats use ISO
|
|
31
|
+
* strings (Claude, Codex) or numeric epochs in seconds or millis (Cursor).
|
|
32
|
+
* Returns undefined rather than guessing when the value is unusable.
|
|
33
|
+
*/
|
|
34
|
+
export function normalizeTimestamp(value) {
|
|
35
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
36
|
+
// Anything below ~1e12 is seconds, not millis (1e12 ms ≈ 2001-09-09).
|
|
37
|
+
return value < 1e12 ? Math.round(value * 1000) : Math.round(value);
|
|
38
|
+
}
|
|
39
|
+
const text = asString(value);
|
|
40
|
+
if (!text)
|
|
41
|
+
return undefined;
|
|
42
|
+
const parsed = Date.parse(text);
|
|
43
|
+
return Number.isNaN(parsed) ? undefined : parsed;
|
|
44
|
+
}
|
|
45
|
+
/** Collapse a text block list into one string, dropping empties. */
|
|
46
|
+
export function joinText(parts) {
|
|
47
|
+
return parts
|
|
48
|
+
.map((part) => part.trim())
|
|
49
|
+
.filter(Boolean)
|
|
50
|
+
.join("\n\n");
|
|
51
|
+
}
|
|
52
|
+
export function textPart(text) {
|
|
53
|
+
return { type: "text", text };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build a tool-call part from a foreign record. `args` may arrive as an object
|
|
57
|
+
* (Claude `input`) or a JSON string (Codex `arguments`); an unparseable string
|
|
58
|
+
* is preserved verbatim under `raw` rather than dropped, so a resumed thread
|
|
59
|
+
* still shows what was attempted.
|
|
60
|
+
*/
|
|
61
|
+
export function toolCallPart(id, name, args) {
|
|
62
|
+
return { type: "tool_call", id, name, args: normalizeToolArgs(args) };
|
|
63
|
+
}
|
|
64
|
+
export function normalizeToolArgs(args) {
|
|
65
|
+
if (isRecord(args))
|
|
66
|
+
return args;
|
|
67
|
+
const text = asString(args);
|
|
68
|
+
if (text === undefined)
|
|
69
|
+
return {};
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(text);
|
|
72
|
+
return isRecord(parsed) ? parsed : { raw: text };
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return { raw: text };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Flatten a foreign tool result into plain text. Import is lossy by design: we
|
|
80
|
+
* never fabricate structure we did not read, so anything that is not text
|
|
81
|
+
* becomes a short placeholder instead of an invented block.
|
|
82
|
+
*/
|
|
83
|
+
export function toolResultText(content) {
|
|
84
|
+
const direct = asString(content);
|
|
85
|
+
if (direct !== undefined)
|
|
86
|
+
return direct;
|
|
87
|
+
if (Array.isArray(content)) {
|
|
88
|
+
const parts = [];
|
|
89
|
+
for (const item of content) {
|
|
90
|
+
if (!isRecord(item))
|
|
91
|
+
continue;
|
|
92
|
+
const text = asString(item.text);
|
|
93
|
+
if (text !== undefined)
|
|
94
|
+
parts.push(text);
|
|
95
|
+
else if (item.type === "image")
|
|
96
|
+
parts.push("[image omitted on import]");
|
|
97
|
+
}
|
|
98
|
+
return joinText(parts);
|
|
99
|
+
}
|
|
100
|
+
if (isRecord(content)) {
|
|
101
|
+
const text = asString(content.text) ?? asString(content.output);
|
|
102
|
+
if (text !== undefined)
|
|
103
|
+
return text;
|
|
104
|
+
}
|
|
105
|
+
return "";
|
|
106
|
+
}
|
|
107
|
+
/** Drop empty text parts so an import never produces a blank message. */
|
|
108
|
+
export function compactParts(parts) {
|
|
109
|
+
return parts.filter((part) => !((part.type === "text" || part.type === "thinking") && !part.text.trim()));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Context wrappers Cursor prepends to a user turn before the real prompt.
|
|
113
|
+
* Each is stripped only when it sits before a trailing `<user_query>`; a
|
|
114
|
+
* message carrying context we do NOT recognize is left completely intact
|
|
115
|
+
* rather than silently truncated.
|
|
116
|
+
*/
|
|
117
|
+
const RECOGNIZED_CURSOR_WRAPPERS = ["cursor_commands", "timestamp", "additional_data"];
|
|
118
|
+
const USER_QUERY_RE = /<user_query>([\s\S]*)<\/user_query>\s*$/;
|
|
119
|
+
/**
|
|
120
|
+
* Extract the real prompt from a Cursor user message.
|
|
121
|
+
*
|
|
122
|
+
* Cursor wraps the typed prompt in `<user_query>` and prepends context blocks
|
|
123
|
+
* (`<cursor_commands>`, `<timestamp>`, …). Importing the raw string leaks that
|
|
124
|
+
* scaffolding into the session preview and title. We take the trailing
|
|
125
|
+
* `<user_query>` only when everything before it is recognized context;
|
|
126
|
+
* otherwise the message is returned unchanged, because unknown leading context
|
|
127
|
+
* may be part of what the user actually said.
|
|
128
|
+
*/
|
|
129
|
+
export function extractCursorUserQuery(raw) {
|
|
130
|
+
const match = USER_QUERY_RE.exec(raw);
|
|
131
|
+
if (!match)
|
|
132
|
+
return raw;
|
|
133
|
+
const lead = raw.slice(0, match.index).trim();
|
|
134
|
+
if (lead && !isRecognizedCursorContext(lead))
|
|
135
|
+
return raw;
|
|
136
|
+
return match[1].trim();
|
|
137
|
+
}
|
|
138
|
+
function isRecognizedCursorContext(lead) {
|
|
139
|
+
let rest = lead;
|
|
140
|
+
while (rest) {
|
|
141
|
+
const tag = RECOGNIZED_CURSOR_WRAPPERS.find((name) => rest.startsWith(`<${name}>`));
|
|
142
|
+
if (!tag)
|
|
143
|
+
return false;
|
|
144
|
+
const close = rest.indexOf(`</${tag}>`);
|
|
145
|
+
if (close === -1)
|
|
146
|
+
return false;
|
|
147
|
+
rest = rest.slice(close + tag.length + 3).trim();
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=foreign-transcript-blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreign-transcript-blocks.js","sourceRoot":"","sources":["../../src/core/foreign-transcript-blocks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { MCPServerConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* On-disk cache of MCP tool definitions, so a cold start can answer
|
|
4
|
+
* `tool_search` honestly before any server has finished connecting.
|
|
5
|
+
*
|
|
6
|
+
* With `backgroundMcpConnect` on (the desktop default) the first turns run
|
|
7
|
+
* against an empty `DeferredToolCatalog`, and `tool_search` reports "the
|
|
8
|
+
* catalog is empty — every catalog tool is already available" for capabilities
|
|
9
|
+
* that genuinely exist. That is a wrong answer, not a slow one.
|
|
10
|
+
*
|
|
11
|
+
* Entries are keyed by server name plus a hash of the resolved server config,
|
|
12
|
+
* so editing a server's command, URL, headers or env invalidates its cache
|
|
13
|
+
* instead of serving tools that server no longer exposes.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Negotiated MCP protocol era for a server, using the SDK's own vocabulary:
|
|
17
|
+
* `legacy` = the 2025 `initialize` handshake, `modern` = 2026-07-28+. Feeds the
|
|
18
|
+
* connect-time `prior` hint that lets a later connect skip the discovery probe.
|
|
19
|
+
*/
|
|
20
|
+
export type ProtocolEra = "legacy" | "modern";
|
|
21
|
+
export interface CachedTool {
|
|
22
|
+
name: string;
|
|
23
|
+
description: string;
|
|
24
|
+
rawInputSchema?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface CachedServerEntry {
|
|
27
|
+
configHash: string;
|
|
28
|
+
savedAt: number;
|
|
29
|
+
protocolEra?: ProtocolEra;
|
|
30
|
+
tools: CachedTool[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Stable hash of everything that can change which tools a server exposes.
|
|
34
|
+
* Key order is normalized so a reordered config file is not a cache miss.
|
|
35
|
+
*/
|
|
36
|
+
export declare function hashServerConfig(config: MCPServerConfig): string;
|
|
37
|
+
/**
|
|
38
|
+
* File-backed MCP tool catalog cache at `~/.gg/mcp-catalog.json`. Every read
|
|
39
|
+
* re-reads the file so concurrent sidecars/windows see each other's writes;
|
|
40
|
+
* writes are read-modify-write so two servers don't clobber one another.
|
|
41
|
+
* Malformed files are treated as empty — a broken cache must never break a run.
|
|
42
|
+
*/
|
|
43
|
+
export declare class McpCatalogCache {
|
|
44
|
+
private readonly filePath;
|
|
45
|
+
/** Serializes read-modify-write cycles within one process. */
|
|
46
|
+
private writeQueue;
|
|
47
|
+
constructor(filePath?: string);
|
|
48
|
+
private readAll;
|
|
49
|
+
private writeAll;
|
|
50
|
+
/**
|
|
51
|
+
* Cached tools for the given configs, skipping any server whose config hash
|
|
52
|
+
* changed or whose entry has aged out. Servers with no usable entry are
|
|
53
|
+
* simply absent from the result.
|
|
54
|
+
*/
|
|
55
|
+
entriesFor(configs: readonly MCPServerConfig[]): Promise<Map<string, CachedServerEntry>>;
|
|
56
|
+
/** Negotiated protocol era recorded for a server, if its config still matches. */
|
|
57
|
+
protocolEraFor(config: MCPServerConfig): Promise<ProtocolEra | undefined>;
|
|
58
|
+
/** Record a server's live tool list. Serialized against concurrent saves. */
|
|
59
|
+
save(config: MCPServerConfig, tools: readonly CachedTool[], protocolEra?: ProtocolEra): Promise<void>;
|
|
60
|
+
/** Drop a server's cached tools (removal, or a connect that found none). */
|
|
61
|
+
clear(name: string): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=catalog-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-cache.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/catalog-cache.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAUD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAUhE;AAoCD;;;;;GAKG;AACH,qBAAa,eAAe;IAId,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAHrC,8DAA8D;IAC9D,OAAO,CAAC,UAAU,CAAoC;gBAEzB,QAAQ,GAAE,MAAqC;YAE9D,OAAO;YAiBP,QAAQ;IAatB;;;;OAIG;IACG,UAAU,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAc9F,kFAAkF;IAC5E,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;IAK/E,6EAA6E;IACvE,IAAI,CACR,MAAM,EAAE,eAAe,EACvB,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,IAAI,CAAC;IAmBhB,4EAA4E;IACtE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUzC"}
|