@ccpocket/bridge 0.1.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/README.md +54 -0
- package/dist/claude-process.d.ts +108 -0
- package/dist/claude-process.js +471 -0
- package/dist/claude-process.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +42 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-process.d.ts +46 -0
- package/dist/codex-process.js +420 -0
- package/dist/codex-process.js.map +1 -0
- package/dist/debug-trace-store.d.ts +15 -0
- package/dist/debug-trace-store.js +78 -0
- package/dist/debug-trace-store.js.map +1 -0
- package/dist/firebase-auth.d.ts +35 -0
- package/dist/firebase-auth.js +132 -0
- package/dist/firebase-auth.js.map +1 -0
- package/dist/gallery-store.d.ts +66 -0
- package/dist/gallery-store.js +310 -0
- package/dist/gallery-store.js.map +1 -0
- package/dist/image-store.d.ts +22 -0
- package/dist/image-store.js +113 -0
- package/dist/image-store.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +153 -0
- package/dist/index.js.map +1 -0
- package/dist/mdns.d.ts +6 -0
- package/dist/mdns.js +42 -0
- package/dist/mdns.js.map +1 -0
- package/dist/parser.d.ts +381 -0
- package/dist/parser.js +218 -0
- package/dist/parser.js.map +1 -0
- package/dist/project-history.d.ts +10 -0
- package/dist/project-history.js +73 -0
- package/dist/project-history.js.map +1 -0
- package/dist/prompt-history-backup.d.ts +15 -0
- package/dist/prompt-history-backup.js +46 -0
- package/dist/prompt-history-backup.js.map +1 -0
- package/dist/push-relay.d.ts +27 -0
- package/dist/push-relay.js +69 -0
- package/dist/push-relay.js.map +1 -0
- package/dist/recording-store.d.ts +51 -0
- package/dist/recording-store.js +158 -0
- package/dist/recording-store.js.map +1 -0
- package/dist/screenshot.d.ts +28 -0
- package/dist/screenshot.js +98 -0
- package/dist/screenshot.js.map +1 -0
- package/dist/sdk-process.d.ts +151 -0
- package/dist/sdk-process.js +740 -0
- package/dist/sdk-process.js.map +1 -0
- package/dist/session.d.ts +126 -0
- package/dist/session.js +550 -0
- package/dist/session.js.map +1 -0
- package/dist/sessions-index.d.ts +86 -0
- package/dist/sessions-index.js +1027 -0
- package/dist/sessions-index.js.map +1 -0
- package/dist/setup-launchd.d.ts +8 -0
- package/dist/setup-launchd.js +109 -0
- package/dist/setup-launchd.js.map +1 -0
- package/dist/startup-info.d.ts +8 -0
- package/dist/startup-info.js +78 -0
- package/dist/startup-info.js.map +1 -0
- package/dist/usage.d.ts +17 -0
- package/dist/usage.js +236 -0
- package/dist/usage.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.js +39 -0
- package/dist/version.js.map +1 -0
- package/dist/websocket.d.ts +71 -0
- package/dist/websocket.js +1487 -0
- package/dist/websocket.js.map +1 -0
- package/dist/worktree-store.d.ts +25 -0
- package/dist/worktree-store.js +59 -0
- package/dist/worktree-store.js.map +1 -0
- package/dist/worktree.d.ts +43 -0
- package/dist/worktree.js +295 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +63 -0
package/dist/session.js
ADDED
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { pathToSlug } from "./sessions-index.js";
|
|
7
|
+
import { SdkProcess } from "./sdk-process.js";
|
|
8
|
+
import { CodexProcess } from "./codex-process.js";
|
|
9
|
+
import { createWorktree } from "./worktree.js";
|
|
10
|
+
const MAX_HISTORY_PER_SESSION = 100;
|
|
11
|
+
export class SessionManager {
|
|
12
|
+
sessions = new Map();
|
|
13
|
+
onMessage;
|
|
14
|
+
imageStore;
|
|
15
|
+
galleryStore;
|
|
16
|
+
onGalleryImage;
|
|
17
|
+
worktreeStore;
|
|
18
|
+
/** Cache slash commands per project path for early loading on subsequent sessions. */
|
|
19
|
+
commandCache = new Map();
|
|
20
|
+
constructor(onMessage, imageStore, galleryStore, onGalleryImage, worktreeStore) {
|
|
21
|
+
this.onMessage = onMessage;
|
|
22
|
+
this.imageStore = imageStore ?? null;
|
|
23
|
+
this.galleryStore = galleryStore ?? null;
|
|
24
|
+
this.onGalleryImage = onGalleryImage ?? null;
|
|
25
|
+
this.worktreeStore = worktreeStore ?? null;
|
|
26
|
+
}
|
|
27
|
+
create(projectPath, options, pastMessages, worktreeOpts, provider, codexOptions) {
|
|
28
|
+
const id = randomUUID().slice(0, 8);
|
|
29
|
+
const effectiveProvider = provider ?? "claude";
|
|
30
|
+
const proc = effectiveProvider === "codex" ? new CodexProcess() : new SdkProcess();
|
|
31
|
+
// Handle worktree: reuse existing or create new
|
|
32
|
+
let wtPath;
|
|
33
|
+
let wtBranch;
|
|
34
|
+
if (worktreeOpts?.existingWorktreePath) {
|
|
35
|
+
// Reuse an existing worktree (resume case)
|
|
36
|
+
wtPath = worktreeOpts.existingWorktreePath;
|
|
37
|
+
wtBranch = worktreeOpts.worktreeBranch;
|
|
38
|
+
console.log(`[session] Reusing existing worktree at ${wtPath}`);
|
|
39
|
+
}
|
|
40
|
+
else if (worktreeOpts?.useWorktree) {
|
|
41
|
+
// Create a new worktree
|
|
42
|
+
try {
|
|
43
|
+
const wt = createWorktree(projectPath, id, worktreeOpts.worktreeBranch);
|
|
44
|
+
wtPath = wt.worktreePath;
|
|
45
|
+
wtBranch = wt.branch;
|
|
46
|
+
console.log(`[session] Created worktree at ${wtPath} (branch: ${wtBranch})`);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`[session] Failed to create worktree:`, err);
|
|
50
|
+
// Fall through to use original projectPath
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Use worktree path as cwd if available
|
|
54
|
+
const effectiveCwd = wtPath ?? projectPath;
|
|
55
|
+
let gitBranch = "";
|
|
56
|
+
try {
|
|
57
|
+
gitBranch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
58
|
+
cwd: effectiveCwd, encoding: "utf-8",
|
|
59
|
+
}).trim();
|
|
60
|
+
}
|
|
61
|
+
catch { /* not a git repo */ }
|
|
62
|
+
const session = {
|
|
63
|
+
id,
|
|
64
|
+
process: proc,
|
|
65
|
+
provider: effectiveProvider,
|
|
66
|
+
history: [],
|
|
67
|
+
pastMessages: pastMessages && pastMessages.length > 0 ? pastMessages : undefined,
|
|
68
|
+
projectPath,
|
|
69
|
+
status: "starting",
|
|
70
|
+
createdAt: new Date(),
|
|
71
|
+
lastActivityAt: new Date(),
|
|
72
|
+
gitBranch,
|
|
73
|
+
worktreePath: wtPath,
|
|
74
|
+
worktreeBranch: wtBranch,
|
|
75
|
+
// Pre-populate claudeSessionId for resumed sessions so that get_history
|
|
76
|
+
// can return it immediately (before the SDK sends a system/result event).
|
|
77
|
+
claudeSessionId: options?.sessionId,
|
|
78
|
+
};
|
|
79
|
+
// Cache tool_use id → name for enriching tool_result messages
|
|
80
|
+
const toolUseNames = new Map();
|
|
81
|
+
proc.on("message", async (msg) => {
|
|
82
|
+
try {
|
|
83
|
+
session.lastActivityAt = new Date();
|
|
84
|
+
if (effectiveProvider === "claude") {
|
|
85
|
+
// Capture Claude session_id from result events
|
|
86
|
+
if (msg.type === "result" && "sessionId" in msg && msg.sessionId) {
|
|
87
|
+
session.claudeSessionId = msg.sessionId;
|
|
88
|
+
this.saveWorktreeMapping(session);
|
|
89
|
+
}
|
|
90
|
+
if (msg.type === "system" && "sessionId" in msg && msg.sessionId) {
|
|
91
|
+
session.claudeSessionId = msg.sessionId;
|
|
92
|
+
this.saveWorktreeMapping(session);
|
|
93
|
+
}
|
|
94
|
+
// Cache slash commands and skills from system messages.
|
|
95
|
+
if (msg.type === "system" &&
|
|
96
|
+
(msg.subtype === "init" || msg.subtype === "supported_commands") &&
|
|
97
|
+
msg.slashCommands) {
|
|
98
|
+
this.commandCache.set(projectPath, {
|
|
99
|
+
slashCommands: msg.slashCommands,
|
|
100
|
+
skills: msg.skills ?? this.commandCache.get(projectPath)?.skills ?? [],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// Cache tool_use names from assistant messages
|
|
104
|
+
if (msg.type === "assistant" && Array.isArray(msg.message.content)) {
|
|
105
|
+
for (const content of msg.message.content) {
|
|
106
|
+
if (content.type === "tool_use") {
|
|
107
|
+
const toolUse = content;
|
|
108
|
+
toolUseNames.set(toolUse.id, toolUse.name);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Enrich tool_result with toolName
|
|
113
|
+
if (msg.type === "tool_result") {
|
|
114
|
+
const cachedName = toolUseNames.get(msg.toolUseId);
|
|
115
|
+
if (cachedName) {
|
|
116
|
+
msg = { ...msg, toolName: cachedName };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Extract images from tool_result content
|
|
120
|
+
if (msg.type === "tool_result" && this.imageStore) {
|
|
121
|
+
const paths = this.imageStore.extractImagePaths(msg.content);
|
|
122
|
+
if (paths.length > 0) {
|
|
123
|
+
const images = await this.imageStore.registerImages(paths);
|
|
124
|
+
if (images.length > 0) {
|
|
125
|
+
msg = { ...msg, images };
|
|
126
|
+
}
|
|
127
|
+
// Also register in GalleryStore (disk-persistent)
|
|
128
|
+
if (this.galleryStore) {
|
|
129
|
+
for (const p of paths) {
|
|
130
|
+
const meta = await this.galleryStore.addImage(p, session.projectPath, session.id);
|
|
131
|
+
if (meta && this.onGalleryImage) {
|
|
132
|
+
this.onGalleryImage(meta);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Extract base64 images from content blocks (e.g., MCP screenshots)
|
|
138
|
+
if (msg.rawContentBlocks) {
|
|
139
|
+
const imageBlocks = msg.rawContentBlocks
|
|
140
|
+
.filter((c) => c.type === "image" && c.source?.type === "base64");
|
|
141
|
+
if (imageBlocks.length > 0) {
|
|
142
|
+
const existingImages = msg.images ?? [];
|
|
143
|
+
const newImages = [];
|
|
144
|
+
for (const block of imageBlocks) {
|
|
145
|
+
const source = block.source;
|
|
146
|
+
if (typeof source?.data !== "string" || typeof source?.media_type !== "string")
|
|
147
|
+
continue;
|
|
148
|
+
const b64Data = source.data;
|
|
149
|
+
const mimeType = source.media_type;
|
|
150
|
+
const ref = this.imageStore.registerFromBase64(b64Data, mimeType);
|
|
151
|
+
if (ref) {
|
|
152
|
+
newImages.push(ref);
|
|
153
|
+
// Also persist to GalleryStore
|
|
154
|
+
if (this.galleryStore) {
|
|
155
|
+
const meta = await this.galleryStore.addImageFromBase64(b64Data, mimeType, session.projectPath, session.id);
|
|
156
|
+
if (meta && this.onGalleryImage) {
|
|
157
|
+
this.onGalleryImage(meta);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (newImages.length > 0) {
|
|
163
|
+
msg = { ...msg, images: [...existingImages, ...newImages] };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Strip transient rawContentBlocks before sending to client
|
|
167
|
+
const { rawContentBlocks: _, ...cleanMsg } = msg;
|
|
168
|
+
msg = cleanMsg;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
// Codex: capture thread_id for session tracking and worktree restore.
|
|
174
|
+
if (msg.type === "system" && "sessionId" in msg && msg.sessionId) {
|
|
175
|
+
session.claudeSessionId = msg.sessionId;
|
|
176
|
+
this.saveWorktreeMapping(session);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Don't add streaming deltas to history
|
|
180
|
+
if (msg.type !== "stream_delta" && msg.type !== "thinking_delta") {
|
|
181
|
+
// When SDK echoes back a user_input with UUID, merge into the
|
|
182
|
+
// UUID-less placeholder that websocket.ts pushed earlier.
|
|
183
|
+
// This avoids duplicate entries while preserving the UUID needed
|
|
184
|
+
// for rewind candidate matching.
|
|
185
|
+
let merged = false;
|
|
186
|
+
if (msg.type === "user_input" &&
|
|
187
|
+
"userMessageUuid" in msg &&
|
|
188
|
+
msg.userMessageUuid) {
|
|
189
|
+
for (let i = session.history.length - 1; i >= 0; i--) {
|
|
190
|
+
const m = session.history[i];
|
|
191
|
+
if (m.type === "user_input" &&
|
|
192
|
+
!("userMessageUuid" in m && m.userMessageUuid)) {
|
|
193
|
+
session.history[i] = msg;
|
|
194
|
+
merged = true;
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
if (!merged) {
|
|
200
|
+
session.history.push(msg);
|
|
201
|
+
}
|
|
202
|
+
if (session.history.length > MAX_HISTORY_PER_SESSION) {
|
|
203
|
+
// Protect user_input messages from eviction so they remain
|
|
204
|
+
// visible when the client requests history after reconnecting.
|
|
205
|
+
const idx = session.history.findIndex(m => m.type !== "user_input");
|
|
206
|
+
if (idx >= 0) {
|
|
207
|
+
session.history.splice(idx, 1);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
session.history.shift();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
this.onMessage(id, msg);
|
|
215
|
+
// After a result (turn complete), backfill UUIDs from disk.
|
|
216
|
+
// The SDK does not echo user messages via the stream, so
|
|
217
|
+
// in-memory user_input entries lack UUIDs. The disk
|
|
218
|
+
// conversation file always has them.
|
|
219
|
+
if (msg.type === "result") {
|
|
220
|
+
this.backfillUserUuidsFromDisk(session);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
console.error(`[session] Error processing message for session ${id}:`, err);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
proc.on("status", (status) => {
|
|
228
|
+
session.status = status;
|
|
229
|
+
});
|
|
230
|
+
proc.on("exit", () => {
|
|
231
|
+
session.status = "idle";
|
|
232
|
+
// Add status message to history so it stays in sync with session.status
|
|
233
|
+
session.history.push({ type: "status", status: "idle" });
|
|
234
|
+
});
|
|
235
|
+
if (effectiveProvider === "codex" && codexOptions) {
|
|
236
|
+
session.codexSettings = {
|
|
237
|
+
approvalPolicy: codexOptions.approvalPolicy,
|
|
238
|
+
sandboxMode: codexOptions.sandboxMode,
|
|
239
|
+
model: codexOptions.model,
|
|
240
|
+
modelReasoningEffort: codexOptions.modelReasoningEffort,
|
|
241
|
+
networkAccessEnabled: codexOptions.networkAccessEnabled,
|
|
242
|
+
webSearchMode: codexOptions.webSearchMode,
|
|
243
|
+
};
|
|
244
|
+
// Resume starts know the thread id up front.
|
|
245
|
+
if (codexOptions.threadId) {
|
|
246
|
+
session.claudeSessionId = codexOptions.threadId;
|
|
247
|
+
this.saveWorktreeMapping(session);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
this.sessions.set(id, session);
|
|
251
|
+
if (effectiveProvider === "codex") {
|
|
252
|
+
proc.start(effectiveCwd, codexOptions);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
proc.start(effectiveCwd, options);
|
|
256
|
+
}
|
|
257
|
+
console.log(`[session] Created ${effectiveProvider} session ${id} for ${effectiveCwd}${wtPath ? ` (worktree of ${projectPath})` : ""}`);
|
|
258
|
+
return id;
|
|
259
|
+
}
|
|
260
|
+
get(id) {
|
|
261
|
+
return this.sessions.get(id);
|
|
262
|
+
}
|
|
263
|
+
list() {
|
|
264
|
+
return Array.from(this.sessions.values()).map((s) => {
|
|
265
|
+
const pendingPermission = s.status === "waiting_approval" && s.process instanceof SdkProcess
|
|
266
|
+
? s.process.getPendingPermission()
|
|
267
|
+
: undefined;
|
|
268
|
+
return {
|
|
269
|
+
id: s.id,
|
|
270
|
+
provider: s.provider,
|
|
271
|
+
projectPath: s.projectPath,
|
|
272
|
+
claudeSessionId: s.claudeSessionId,
|
|
273
|
+
status: s.status,
|
|
274
|
+
createdAt: s.createdAt.toISOString(),
|
|
275
|
+
lastActivityAt: s.lastActivityAt.toISOString(),
|
|
276
|
+
gitBranch: s.gitBranch,
|
|
277
|
+
lastMessage: this.extractLastMessage(s),
|
|
278
|
+
messageCount: (s.pastMessages?.length ?? 0) + s.history.length,
|
|
279
|
+
worktreePath: s.worktreePath,
|
|
280
|
+
worktreeBranch: s.worktreeBranch,
|
|
281
|
+
permissionMode: s.process instanceof SdkProcess
|
|
282
|
+
? s.process.permissionMode
|
|
283
|
+
: undefined,
|
|
284
|
+
codexSettings: s.codexSettings,
|
|
285
|
+
pendingPermission,
|
|
286
|
+
};
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
extractLastMessage(s) {
|
|
290
|
+
// Search in-memory history (newest first) for assistant text
|
|
291
|
+
for (let i = s.history.length - 1; i >= 0; i--) {
|
|
292
|
+
const msg = s.history[i];
|
|
293
|
+
if (msg.type === "assistant") {
|
|
294
|
+
const textBlock = msg.message.content.find((c) => c.type === "text");
|
|
295
|
+
if (textBlock && "text" in textBlock && textBlock.text) {
|
|
296
|
+
return textBlock.text.replace(/\s+/g, " ").trim().slice(0, 100);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// Fallback to pastMessages (raw Claude CLI format)
|
|
301
|
+
if (s.pastMessages) {
|
|
302
|
+
for (let i = s.pastMessages.length - 1; i >= 0; i--) {
|
|
303
|
+
const msg = s.pastMessages[i];
|
|
304
|
+
if (msg.role === "assistant") {
|
|
305
|
+
// Handle string content (defensive — normally array)
|
|
306
|
+
if (typeof msg.content === "string") {
|
|
307
|
+
return msg.content.replace(/\s+/g, " ").trim().slice(0, 100);
|
|
308
|
+
}
|
|
309
|
+
const content = msg.content;
|
|
310
|
+
const textBlock = content?.find((c) => c.type === "text");
|
|
311
|
+
if (textBlock?.text)
|
|
312
|
+
return textBlock.text.replace(/\s+/g, " ").trim().slice(0, 100);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return "";
|
|
317
|
+
}
|
|
318
|
+
getCachedCommands(projectPath) {
|
|
319
|
+
return this.commandCache.get(projectPath);
|
|
320
|
+
}
|
|
321
|
+
/** Get worktree store for external use (e.g., resume_session in websocket.ts). */
|
|
322
|
+
getWorktreeStore() {
|
|
323
|
+
return this.worktreeStore;
|
|
324
|
+
}
|
|
325
|
+
/** Save worktree mapping when a provider session ID is available. */
|
|
326
|
+
saveWorktreeMapping(session) {
|
|
327
|
+
if (this.worktreeStore && session.claudeSessionId && session.worktreePath && session.worktreeBranch) {
|
|
328
|
+
this.worktreeStore.set(session.claudeSessionId, {
|
|
329
|
+
worktreePath: session.worktreePath,
|
|
330
|
+
worktreeBranch: session.worktreeBranch,
|
|
331
|
+
projectPath: session.projectPath,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Rewind files to their state at the specified user message.
|
|
337
|
+
* Delegates to the session's SdkProcess.rewindFiles().
|
|
338
|
+
*/
|
|
339
|
+
async rewindFiles(id, targetUuid, dryRun) {
|
|
340
|
+
const session = this.sessions.get(id);
|
|
341
|
+
if (!session) {
|
|
342
|
+
return { canRewind: false, error: "Session not found" };
|
|
343
|
+
}
|
|
344
|
+
if (session.provider === "codex") {
|
|
345
|
+
return { canRewind: false, error: "Rewind is not supported for Codex sessions" };
|
|
346
|
+
}
|
|
347
|
+
return session.process.rewindFiles(targetUuid, dryRun);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Rewind the conversation to a specific point.
|
|
351
|
+
* Stops the current process and restarts with resumeSessionAt.
|
|
352
|
+
*
|
|
353
|
+
* `targetUuid` is a **user message UUID**. The SDK's `resumeSessionAt`
|
|
354
|
+
* expects an **assistant message UUID**, so we look up the assistant
|
|
355
|
+
* message that follows the target user message.
|
|
356
|
+
*/
|
|
357
|
+
rewindConversation(id, targetUuid, onReady) {
|
|
358
|
+
const session = this.sessions.get(id);
|
|
359
|
+
if (!session) {
|
|
360
|
+
throw new Error(`Session ${id} not found`);
|
|
361
|
+
}
|
|
362
|
+
if (session.provider === "codex") {
|
|
363
|
+
throw new Error("Rewind is not supported for Codex sessions");
|
|
364
|
+
}
|
|
365
|
+
const claudeSessionId = session.claudeSessionId;
|
|
366
|
+
if (!claudeSessionId) {
|
|
367
|
+
throw new Error("Session has no Claude session ID");
|
|
368
|
+
}
|
|
369
|
+
// resumeSessionAt expects assistant message UUID (per SDK docs).
|
|
370
|
+
// Convert user UUID → following assistant UUID.
|
|
371
|
+
const assistantUuid = this.findAssistantUuidAfterUser(session, targetUuid);
|
|
372
|
+
if (!assistantUuid) {
|
|
373
|
+
throw new Error("Cannot find assistant message after target user message");
|
|
374
|
+
}
|
|
375
|
+
const projectPath = session.projectPath;
|
|
376
|
+
const permissionMode = session.process.permissionMode;
|
|
377
|
+
const worktreePath = session.worktreePath;
|
|
378
|
+
const worktreeBranch = session.worktreeBranch;
|
|
379
|
+
// Stop and destroy the current session
|
|
380
|
+
this.destroy(id);
|
|
381
|
+
// Create a new session with resumeSessionAt (assistant UUID)
|
|
382
|
+
const newId = this.create(projectPath, {
|
|
383
|
+
sessionId: claudeSessionId,
|
|
384
|
+
permissionMode,
|
|
385
|
+
resumeSessionAt: assistantUuid,
|
|
386
|
+
}, undefined, worktreePath ? { existingWorktreePath: worktreePath, worktreeBranch } : undefined);
|
|
387
|
+
onReady(newId);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Find the assistant message UUID that follows a given user message UUID.
|
|
391
|
+
*
|
|
392
|
+
* Searches in-memory history first, then pastMessages (disk history).
|
|
393
|
+
*/
|
|
394
|
+
findAssistantUuidAfterUser(session, userUuid) {
|
|
395
|
+
// 1. Search in-memory history
|
|
396
|
+
let foundUser = false;
|
|
397
|
+
for (const msg of session.history) {
|
|
398
|
+
if (!foundUser) {
|
|
399
|
+
// user_input or tool_result with matching userMessageUuid
|
|
400
|
+
if ((msg.type === "user_input" || msg.type === "tool_result") &&
|
|
401
|
+
"userMessageUuid" in msg &&
|
|
402
|
+
msg.userMessageUuid === userUuid) {
|
|
403
|
+
foundUser = true;
|
|
404
|
+
}
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
// Found user message — look for next assistant
|
|
408
|
+
if (msg.type === "assistant" && "messageUuid" in msg && msg.messageUuid) {
|
|
409
|
+
return msg.messageUuid;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// 2. Search pastMessages (disk history with uuid field)
|
|
413
|
+
if (session.pastMessages) {
|
|
414
|
+
foundUser = false;
|
|
415
|
+
for (const raw of session.pastMessages) {
|
|
416
|
+
const pm = raw;
|
|
417
|
+
if (!foundUser) {
|
|
418
|
+
if (pm.role === "user" && pm.uuid === userUuid) {
|
|
419
|
+
foundUser = true;
|
|
420
|
+
}
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (pm.role === "assistant" && pm.uuid) {
|
|
424
|
+
return pm.uuid;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Read the Claude CLI conversation history file from disk and backfill
|
|
432
|
+
* `userMessageUuid` into in-memory history entries that are missing it.
|
|
433
|
+
*
|
|
434
|
+
* The SDK does not echo user messages via the stream, so in-memory
|
|
435
|
+
* `user_input` entries (pushed by websocket.ts) lack UUIDs. The disk
|
|
436
|
+
* file, however, always contains UUIDs. We match by text content.
|
|
437
|
+
*
|
|
438
|
+
* Also re-broadcasts the updated `user_input` message so the Flutter
|
|
439
|
+
* client can update its UserChatEntry.messageUuid values.
|
|
440
|
+
*/
|
|
441
|
+
backfillUserUuidsFromDisk(session) {
|
|
442
|
+
if (!session.claudeSessionId || !session.projectPath)
|
|
443
|
+
return;
|
|
444
|
+
const historyPath = this.findHistoryJsonlPath(session);
|
|
445
|
+
if (!historyPath)
|
|
446
|
+
return;
|
|
447
|
+
let lines;
|
|
448
|
+
try {
|
|
449
|
+
const raw = readFileSync(historyPath, "utf-8").trim();
|
|
450
|
+
if (!raw)
|
|
451
|
+
return;
|
|
452
|
+
lines = raw.split("\n");
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
// File may not exist yet (e.g., very new session)
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
// Collect user message text→uuid queue from disk.
|
|
459
|
+
// Use an array per text key so duplicate messages ("yes", "ok", etc.)
|
|
460
|
+
// are matched in order rather than collapsed to one UUID.
|
|
461
|
+
const diskUuids = new Map();
|
|
462
|
+
for (const line of lines) {
|
|
463
|
+
try {
|
|
464
|
+
const entry = JSON.parse(line);
|
|
465
|
+
if (entry.type !== "user" && entry.role !== "user")
|
|
466
|
+
continue;
|
|
467
|
+
if (!entry.uuid)
|
|
468
|
+
continue;
|
|
469
|
+
// Extract text from content array
|
|
470
|
+
const content = entry.message?.content;
|
|
471
|
+
if (!Array.isArray(content))
|
|
472
|
+
continue;
|
|
473
|
+
const texts = content
|
|
474
|
+
.filter((c) => c.type === "text")
|
|
475
|
+
.map((c) => c.text);
|
|
476
|
+
if (texts.length > 0) {
|
|
477
|
+
const key = texts.join("\n");
|
|
478
|
+
const arr = diskUuids.get(key) ?? [];
|
|
479
|
+
arr.push(entry.uuid);
|
|
480
|
+
diskUuids.set(key, arr);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
catch {
|
|
484
|
+
// skip malformed lines
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
// Backfill UUIDs into in-memory history
|
|
488
|
+
for (const msg of session.history) {
|
|
489
|
+
if (msg.type === "user_input" &&
|
|
490
|
+
!("userMessageUuid" in msg && msg.userMessageUuid)) {
|
|
491
|
+
const text = msg.text;
|
|
492
|
+
const queue = text ? diskUuids.get(text) : undefined;
|
|
493
|
+
if (queue && queue.length > 0) {
|
|
494
|
+
msg.userMessageUuid = queue.shift();
|
|
495
|
+
// Re-broadcast so Flutter can update UserChatEntry.messageUuid
|
|
496
|
+
this.onMessage(session.id, msg);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
findHistoryJsonlPath(session) {
|
|
502
|
+
if (!session.claudeSessionId)
|
|
503
|
+
return null;
|
|
504
|
+
const projectsDir = join(homedir(), ".claude", "projects");
|
|
505
|
+
const fileName = `${session.claudeSessionId}.jsonl`;
|
|
506
|
+
const slugCandidates = new Set([
|
|
507
|
+
pathToSlug(session.projectPath),
|
|
508
|
+
]);
|
|
509
|
+
// Worktree sessions are persisted under the worktree slug, not projectPath.
|
|
510
|
+
if (session.worktreePath) {
|
|
511
|
+
slugCandidates.add(pathToSlug(session.worktreePath));
|
|
512
|
+
}
|
|
513
|
+
for (const slug of slugCandidates) {
|
|
514
|
+
const candidate = join(projectsDir, slug, fileName);
|
|
515
|
+
if (existsSync(candidate))
|
|
516
|
+
return candidate;
|
|
517
|
+
}
|
|
518
|
+
// Fallback: scan all project dirs in case metadata paths drift.
|
|
519
|
+
try {
|
|
520
|
+
const entries = readdirSync(projectsDir, { withFileTypes: true });
|
|
521
|
+
for (const entry of entries) {
|
|
522
|
+
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
523
|
+
continue;
|
|
524
|
+
const candidate = join(projectsDir, entry.name, fileName);
|
|
525
|
+
if (existsSync(candidate))
|
|
526
|
+
return candidate;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
return null;
|
|
531
|
+
}
|
|
532
|
+
return null;
|
|
533
|
+
}
|
|
534
|
+
destroy(id) {
|
|
535
|
+
const session = this.sessions.get(id);
|
|
536
|
+
if (!session)
|
|
537
|
+
return false;
|
|
538
|
+
session.process.stop();
|
|
539
|
+
session.process.removeAllListeners();
|
|
540
|
+
this.sessions.delete(id);
|
|
541
|
+
console.log(`[session] Destroyed session ${id}`);
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
destroyAll() {
|
|
545
|
+
for (const [id] of this.sessions) {
|
|
546
|
+
this.destroy(id);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export interface SessionIndexEntry {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
provider: "claude" | "codex";
|
|
4
|
+
summary?: string;
|
|
5
|
+
firstPrompt: string;
|
|
6
|
+
lastPrompt?: string;
|
|
7
|
+
messageCount: number;
|
|
8
|
+
created: string;
|
|
9
|
+
modified: string;
|
|
10
|
+
gitBranch: string;
|
|
11
|
+
projectPath: string;
|
|
12
|
+
/** Raw cwd used to resume this session (worktree path for codex, if any). */
|
|
13
|
+
resumeCwd?: string;
|
|
14
|
+
isSidechain: boolean;
|
|
15
|
+
codexSettings?: {
|
|
16
|
+
approvalPolicy?: string;
|
|
17
|
+
sandboxMode?: string;
|
|
18
|
+
model?: string;
|
|
19
|
+
modelReasoningEffort?: string;
|
|
20
|
+
networkAccessEnabled?: boolean;
|
|
21
|
+
webSearchMode?: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface GetRecentSessionsOptions {
|
|
25
|
+
limit?: number;
|
|
26
|
+
offset?: number;
|
|
27
|
+
projectPath?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface GetRecentSessionsResult {
|
|
30
|
+
sessions: SessionIndexEntry[];
|
|
31
|
+
hasMore: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** Convert a filesystem path to Claude's project directory slug (e.g. /foo/bar → -foo-bar). */
|
|
34
|
+
export declare function pathToSlug(p: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Normalize a worktree cwd back to the main project path.
|
|
37
|
+
* e.g. /path/to/project-worktrees/branch → /path/to/project
|
|
38
|
+
*/
|
|
39
|
+
export declare function normalizeWorktreePath(p: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Check if a directory slug represents a worktree directory for a given project slug.
|
|
42
|
+
* e.g. "-Users-x-proj-worktrees-branch" is a worktree dir for "-Users-x-proj".
|
|
43
|
+
*/
|
|
44
|
+
export declare function isWorktreeSlug(dirSlug: string, projectSlug: string): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Scan a directory for JSONL session files and create SessionIndexEntry objects.
|
|
47
|
+
* Used as a fallback when sessions-index.json is missing (common for worktree sessions).
|
|
48
|
+
*/
|
|
49
|
+
export declare function scanJsonlDir(dirPath: string): Promise<SessionIndexEntry[]>;
|
|
50
|
+
export declare function getAllRecentSessions(options?: GetRecentSessionsOptions): Promise<GetRecentSessionsResult>;
|
|
51
|
+
export interface SessionHistoryMessage {
|
|
52
|
+
role: "user" | "assistant";
|
|
53
|
+
uuid?: string;
|
|
54
|
+
timestamp?: string;
|
|
55
|
+
/** Skill loading prompt or other meta message (rendered as a chip). */
|
|
56
|
+
isMeta?: boolean;
|
|
57
|
+
/** Number of images attached to this user message (for display indicator). */
|
|
58
|
+
imageCount?: number;
|
|
59
|
+
content: Array<{
|
|
60
|
+
type: string;
|
|
61
|
+
text?: string;
|
|
62
|
+
id?: string;
|
|
63
|
+
name?: string;
|
|
64
|
+
input?: Record<string, unknown>;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Read past conversation messages from a session's JSONL file.
|
|
69
|
+
* Returns user and assistant messages suitable for display.
|
|
70
|
+
*/
|
|
71
|
+
export declare function getSessionHistory(sessionId: string): Promise<SessionHistoryMessage[]>;
|
|
72
|
+
export interface ExtractedImage {
|
|
73
|
+
base64: string;
|
|
74
|
+
mimeType: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Extract image base64 data from a Claude Code session JSONL for a specific message UUID.
|
|
78
|
+
*/
|
|
79
|
+
export declare function extractMessageImages(sessionId: string, messageUuid: string): Promise<ExtractedImage[]>;
|
|
80
|
+
export declare function getCodexSessionHistory(threadId: string): Promise<SessionHistoryMessage[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Look up session metadata for a set of Claude CLI sessionIds.
|
|
83
|
+
* Returns a map from sessionId to a subset of session metadata.
|
|
84
|
+
* More efficient than getAllRecentSessions when you only need a few entries.
|
|
85
|
+
*/
|
|
86
|
+
export declare function findSessionsByClaudeIds(ids: Set<string>): Promise<Map<string, Pick<SessionIndexEntry, "summary" | "firstPrompt" | "lastPrompt" | "projectPath">>>;
|