claude-sessions-mcp 0.1.5 → 0.2.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 +4 -4
- package/dist/mcp/index.js +173 -10
- package/dist/mcp/index.js.map +1 -1
- package/dist/web/client/_app/immutable/assets/0.bo32IKJI.css +1 -0
- package/dist/web/client/_app/immutable/assets/0.bo32IKJI.css.br +0 -0
- package/dist/web/client/_app/immutable/assets/0.bo32IKJI.css.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/{ChDMIF_r.js → BOlr2Mx0.js} +1 -1
- package/dist/web/client/_app/immutable/chunks/BOlr2Mx0.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/BOlr2Mx0.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/BpzfNVdV.js +1 -0
- package/dist/web/client/_app/immutable/chunks/BpzfNVdV.js.br +1 -0
- package/dist/web/client/_app/immutable/chunks/BpzfNVdV.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/{DXY2Rq4J.js → CkYrZ5uP.js} +1 -1
- package/dist/web/client/_app/immutable/chunks/CkYrZ5uP.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/CkYrZ5uP.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/DhpCfsq_.js +2 -0
- package/dist/web/client/_app/immutable/chunks/DhpCfsq_.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/DhpCfsq_.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/JuVRPOYA.js +1 -0
- package/dist/web/client/_app/immutable/chunks/JuVRPOYA.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/JuVRPOYA.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/qEz027d4.js +1 -0
- package/dist/web/client/_app/immutable/chunks/qEz027d4.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/qEz027d4.js.gz +0 -0
- package/dist/web/client/_app/immutable/entry/app.BF3469YR.js +2 -0
- package/dist/web/client/_app/immutable/entry/app.BF3469YR.js.br +0 -0
- package/dist/web/client/_app/immutable/entry/app.BF3469YR.js.gz +0 -0
- package/dist/web/client/_app/immutable/entry/start.1QHkE8aN.js +1 -0
- package/dist/web/client/_app/immutable/entry/start.1QHkE8aN.js.br +2 -0
- package/dist/web/client/_app/immutable/entry/start.1QHkE8aN.js.gz +0 -0
- package/dist/web/client/_app/immutable/nodes/0.0G4u1RwN.js +1 -0
- package/dist/web/client/_app/immutable/nodes/0.0G4u1RwN.js.br +0 -0
- package/dist/web/client/_app/immutable/nodes/0.0G4u1RwN.js.gz +0 -0
- package/dist/web/client/_app/immutable/nodes/1.C1QnsN4y.js +1 -0
- package/dist/web/client/_app/immutable/nodes/1.C1QnsN4y.js.br +0 -0
- package/dist/web/client/_app/immutable/nodes/1.C1QnsN4y.js.gz +0 -0
- package/dist/web/client/_app/immutable/nodes/2.rvNN8qKE.js +69 -0
- package/dist/web/client/_app/immutable/nodes/2.rvNN8qKE.js.br +0 -0
- package/dist/web/client/_app/immutable/nodes/2.rvNN8qKE.js.gz +0 -0
- package/dist/web/client/_app/version.json +1 -1
- package/dist/web/client/_app/version.json.br +0 -0
- package/dist/web/client/_app/version.json.gz +0 -0
- package/dist/web/server/chunks/{0-PRvIjum0.js → 0-CpLgwGZT.js} +3 -3
- package/dist/web/server/chunks/{0-PRvIjum0.js.map → 0-CpLgwGZT.js.map} +1 -1
- package/dist/web/server/chunks/{1-CnJ2Thhc.js → 1-BmrRQM7e.js} +2 -2
- package/dist/web/server/chunks/{1-CnJ2Thhc.js.map → 1-BmrRQM7e.js.map} +1 -1
- package/dist/web/server/chunks/2-CXKmp7vO.js +9 -0
- package/dist/web/server/chunks/2-CXKmp7vO.js.map +1 -0
- package/dist/web/server/chunks/{_page.svelte-BzYm1sb_.js → _page.svelte-Bu5w4fE4.js} +54 -14
- package/dist/web/server/chunks/_page.svelte-Bu5w4fE4.js.map +1 -0
- package/dist/web/server/chunks/{_server.ts-CpyT5bqO.js → _server.ts-9dSpOSZD.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-CpyT5bqO.js.map → _server.ts-9dSpOSZD.js.map} +1 -1
- package/dist/web/server/chunks/{_server.ts-BaSoV9WJ.js → _server.ts-Ba06VInL.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-BaSoV9WJ.js.map → _server.ts-Ba06VInL.js.map} +1 -1
- package/dist/web/server/chunks/_server.ts-BoS0ijI9.js +19 -0
- package/dist/web/server/chunks/_server.ts-BoS0ijI9.js.map +1 -0
- package/dist/web/server/chunks/{_server.ts-BUo23tM8.js → _server.ts-CHX8x48n.js} +9 -5
- package/dist/web/server/chunks/_server.ts-CHX8x48n.js.map +1 -0
- package/dist/web/server/chunks/{_server.ts-DWAZmBHh.js → _server.ts-DCZgqkA_.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-DWAZmBHh.js.map → _server.ts-DCZgqkA_.js.map} +1 -1
- package/dist/web/server/chunks/{_server.ts-D1Ih9YID.js → _server.ts-DNSYjrWg.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-D1Ih9YID.js.map → _server.ts-DNSYjrWg.js.map} +1 -1
- package/dist/web/server/chunks/_server.ts-DmMLJ93T.js +18 -0
- package/dist/web/server/chunks/_server.ts-DmMLJ93T.js.map +1 -0
- package/dist/web/server/chunks/{_server.ts-Bn_98d_y.js → _server.ts-Dq5i1Bg9.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-Bn_98d_y.js.map → _server.ts-Dq5i1Bg9.js.map} +1 -1
- package/dist/web/server/chunks/{_server.ts-CR3BXGRo.js → _server.ts-XEsSs7Il.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-CR3BXGRo.js.map → _server.ts-XEsSs7Il.js.map} +1 -1
- package/dist/web/server/chunks/{_server.ts-CmmN7FJP.js → _server.ts-uDQ4gQW0.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-CmmN7FJP.js.map → _server.ts-uDQ4gQW0.js.map} +1 -1
- package/dist/web/server/chunks/{_server.ts-BzsEPkcX.js → _server.ts-zkRNh3d2.js} +2 -2
- package/dist/web/server/chunks/{_server.ts-BzsEPkcX.js.map → _server.ts-zkRNh3d2.js.map} +1 -1
- package/dist/web/server/chunks/{session--a-xLYU7.js → session-BAE596_s.js} +63 -3
- package/dist/web/server/chunks/session-BAE596_s.js.map +1 -0
- package/dist/web/server/index.js +1 -1
- package/dist/web/server/index.js.map +1 -1
- package/dist/web/server/manifest.js +27 -13
- package/dist/web/server/manifest.js.map +1 -1
- package/package.json +6 -2
- package/dist/web/client/_app/immutable/assets/0.C8nBXjrd.css +0 -1
- package/dist/web/client/_app/immutable/assets/0.C8nBXjrd.css.br +0 -0
- package/dist/web/client/_app/immutable/assets/0.C8nBXjrd.css.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/Bnj9_x4l.js +0 -1
- package/dist/web/client/_app/immutable/chunks/Bnj9_x4l.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/Bnj9_x4l.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/ChDMIF_r.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/ChDMIF_r.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/DUVCQSoz.js +0 -2
- package/dist/web/client/_app/immutable/chunks/DUVCQSoz.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/DUVCQSoz.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/DXY2Rq4J.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/DXY2Rq4J.js.gz +0 -0
- package/dist/web/client/_app/immutable/chunks/sCxbWNg5.js +0 -1
- package/dist/web/client/_app/immutable/chunks/sCxbWNg5.js.br +0 -0
- package/dist/web/client/_app/immutable/chunks/sCxbWNg5.js.gz +0 -0
- package/dist/web/client/_app/immutable/entry/app.PVSbiNUe.js +0 -2
- package/dist/web/client/_app/immutable/entry/app.PVSbiNUe.js.br +0 -0
- package/dist/web/client/_app/immutable/entry/app.PVSbiNUe.js.gz +0 -0
- package/dist/web/client/_app/immutable/entry/start.tEaZ4KCg.js +0 -1
- package/dist/web/client/_app/immutable/entry/start.tEaZ4KCg.js.br +0 -2
- package/dist/web/client/_app/immutable/entry/start.tEaZ4KCg.js.gz +0 -0
- package/dist/web/client/_app/immutable/nodes/0.BkssNmeP.js +0 -1
- package/dist/web/client/_app/immutable/nodes/0.BkssNmeP.js.br +0 -0
- package/dist/web/client/_app/immutable/nodes/0.BkssNmeP.js.gz +0 -0
- package/dist/web/client/_app/immutable/nodes/1.QcVHNSXD.js +0 -1
- package/dist/web/client/_app/immutable/nodes/1.QcVHNSXD.js.br +0 -0
- package/dist/web/client/_app/immutable/nodes/1.QcVHNSXD.js.gz +0 -0
- package/dist/web/client/_app/immutable/nodes/2.JRQSNUQJ.js +0 -1
- package/dist/web/client/_app/immutable/nodes/2.JRQSNUQJ.js.br +0 -0
- package/dist/web/client/_app/immutable/nodes/2.JRQSNUQJ.js.gz +0 -0
- package/dist/web/server/chunks/2-CAJqQrr8.js +0 -9
- package/dist/web/server/chunks/2-CAJqQrr8.js.map +0 -1
- package/dist/web/server/chunks/_page.svelte-BzYm1sb_.js.map +0 -1
- package/dist/web/server/chunks/_server.ts-BUo23tM8.js.map +0 -1
- package/dist/web/server/chunks/session--a-xLYU7.js.map +0 -1
package/README.md
CHANGED
|
@@ -14,10 +14,10 @@ MCP (Model Context Protocol) server and Web UI for managing Claude Code sessions
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
# Using npx (recommended)
|
|
17
|
-
npx
|
|
17
|
+
npx claude-sessions-mcp
|
|
18
18
|
|
|
19
19
|
# Or install globally
|
|
20
|
-
npm install -g
|
|
20
|
+
npm install -g claude-sessions-mcp
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Usage
|
|
@@ -27,7 +27,7 @@ npm install -g @es6kr/claude-sessions-mcp
|
|
|
27
27
|
Add to Claude Code:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
claude mcp add claude-sessions -- npx
|
|
30
|
+
claude mcp add claude-sessions -- npx claude-sessions-mcp
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
Or manually edit `~/.claude.json`:
|
|
@@ -37,7 +37,7 @@ Or manually edit `~/.claude.json`:
|
|
|
37
37
|
"mcpServers": {
|
|
38
38
|
"claude-sessions": {
|
|
39
39
|
"command": "npx",
|
|
40
|
-
"args": ["
|
|
40
|
+
"args": ["claude-sessions-mcp"]
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
}
|
package/dist/mcp/index.js
CHANGED
|
@@ -86,14 +86,44 @@ var readSession = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
86
86
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
87
87
|
return lines.map((line) => JSON.parse(line));
|
|
88
88
|
});
|
|
89
|
+
var findLinkedAgents = (projectName, sessionId) => Effect.gen(function* () {
|
|
90
|
+
const projectPath = path.join(getSessionsDir(), projectName);
|
|
91
|
+
const files = yield* Effect.tryPromise(() => fs.readdir(projectPath));
|
|
92
|
+
const agentFiles = files.filter((f) => f.startsWith("agent-") && f.endsWith(".jsonl"));
|
|
93
|
+
const linkedAgents = [];
|
|
94
|
+
for (const agentFile of agentFiles) {
|
|
95
|
+
const filePath = path.join(projectPath, agentFile);
|
|
96
|
+
const content = yield* Effect.tryPromise(() => fs.readFile(filePath, "utf-8"));
|
|
97
|
+
const firstLine = content.split("\n")[0];
|
|
98
|
+
if (firstLine) {
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse(firstLine);
|
|
101
|
+
if (parsed.sessionId === sessionId) {
|
|
102
|
+
linkedAgents.push(agentFile.replace(".jsonl", ""));
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return linkedAgents;
|
|
109
|
+
});
|
|
89
110
|
var deleteSession = (projectName, sessionId) => Effect.gen(function* () {
|
|
90
111
|
const sessionsDir = getSessionsDir();
|
|
91
|
-
const
|
|
92
|
-
const
|
|
112
|
+
const projectPath = path.join(sessionsDir, projectName);
|
|
113
|
+
const filePath = path.join(projectPath, `${sessionId}.jsonl`);
|
|
114
|
+
const backupDir = path.join(projectPath, ".bak");
|
|
93
115
|
yield* Effect.tryPromise(() => fs.mkdir(backupDir, { recursive: true }));
|
|
116
|
+
const linkedAgents = yield* findLinkedAgents(projectName, sessionId);
|
|
117
|
+
const deletedAgents = [];
|
|
118
|
+
for (const agentId of linkedAgents) {
|
|
119
|
+
const agentPath = path.join(projectPath, `${agentId}.jsonl`);
|
|
120
|
+
const agentBackupPath = path.join(backupDir, `${agentId}.jsonl`);
|
|
121
|
+
yield* Effect.tryPromise(() => fs.rename(agentPath, agentBackupPath));
|
|
122
|
+
deletedAgents.push(agentId);
|
|
123
|
+
}
|
|
94
124
|
const backupPath = path.join(backupDir, `${sessionId}.jsonl`);
|
|
95
125
|
yield* Effect.tryPromise(() => fs.rename(filePath, backupPath));
|
|
96
|
-
return { success: true, backupPath };
|
|
126
|
+
return { success: true, backupPath, deletedAgents };
|
|
97
127
|
});
|
|
98
128
|
var renameSession = (projectName, sessionId, newTitle) => Effect.gen(function* () {
|
|
99
129
|
const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
|
|
@@ -120,7 +150,9 @@ var deleteMessage = (projectName, sessionId, messageUuid) => Effect.gen(function
|
|
|
120
150
|
const content = yield* Effect.tryPromise(() => fs.readFile(filePath, "utf-8"));
|
|
121
151
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
122
152
|
const messages = lines.map((line) => JSON.parse(line));
|
|
123
|
-
const targetIndex = messages.findIndex(
|
|
153
|
+
const targetIndex = messages.findIndex(
|
|
154
|
+
(m) => m.uuid === messageUuid || m.messageId === messageUuid
|
|
155
|
+
);
|
|
124
156
|
if (targetIndex === -1) {
|
|
125
157
|
return { success: false, error: "Message not found" };
|
|
126
158
|
}
|
|
@@ -157,21 +189,73 @@ var previewCleanup = (projectName) => Effect.gen(function* () {
|
|
|
157
189
|
);
|
|
158
190
|
return results;
|
|
159
191
|
});
|
|
192
|
+
var findOrphanAgents = (projectName) => Effect.gen(function* () {
|
|
193
|
+
const projectPath = path.join(getSessionsDir(), projectName);
|
|
194
|
+
const files = yield* Effect.tryPromise(() => fs.readdir(projectPath));
|
|
195
|
+
const sessionIds = new Set(
|
|
196
|
+
files.filter((f) => !f.startsWith("agent-") && f.endsWith(".jsonl")).map((f) => f.replace(".jsonl", ""))
|
|
197
|
+
);
|
|
198
|
+
const agentFiles = files.filter((f) => f.startsWith("agent-") && f.endsWith(".jsonl"));
|
|
199
|
+
const orphanAgents = [];
|
|
200
|
+
for (const agentFile of agentFiles) {
|
|
201
|
+
const filePath = path.join(projectPath, agentFile);
|
|
202
|
+
const content = yield* Effect.tryPromise(() => fs.readFile(filePath, "utf-8"));
|
|
203
|
+
const firstLine = content.split("\n")[0];
|
|
204
|
+
if (firstLine) {
|
|
205
|
+
try {
|
|
206
|
+
const parsed = JSON.parse(firstLine);
|
|
207
|
+
if (parsed.sessionId && !sessionIds.has(parsed.sessionId)) {
|
|
208
|
+
orphanAgents.push({
|
|
209
|
+
agentId: agentFile.replace(".jsonl", ""),
|
|
210
|
+
sessionId: parsed.sessionId
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
} catch {
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return orphanAgents;
|
|
218
|
+
});
|
|
219
|
+
var deleteOrphanAgents = (projectName) => Effect.gen(function* () {
|
|
220
|
+
const projectPath = path.join(getSessionsDir(), projectName);
|
|
221
|
+
const orphans = yield* findOrphanAgents(projectName);
|
|
222
|
+
const backupDir = path.join(projectPath, ".bak");
|
|
223
|
+
yield* Effect.tryPromise(() => fs.mkdir(backupDir, { recursive: true }));
|
|
224
|
+
const deletedAgents = [];
|
|
225
|
+
for (const orphan of orphans) {
|
|
226
|
+
const agentPath = path.join(projectPath, `${orphan.agentId}.jsonl`);
|
|
227
|
+
const agentBackupPath = path.join(backupDir, `${orphan.agentId}.jsonl`);
|
|
228
|
+
yield* Effect.tryPromise(() => fs.rename(agentPath, agentBackupPath));
|
|
229
|
+
deletedAgents.push(orphan.agentId);
|
|
230
|
+
}
|
|
231
|
+
return { success: true, deletedAgents, count: deletedAgents.length };
|
|
232
|
+
});
|
|
160
233
|
var clearSessions = (options) => Effect.gen(function* () {
|
|
161
|
-
const {
|
|
234
|
+
const {
|
|
235
|
+
projectName,
|
|
236
|
+
clearEmpty = true,
|
|
237
|
+
clearInvalid = true,
|
|
238
|
+
clearOrphanAgents = true
|
|
239
|
+
} = options;
|
|
162
240
|
const cleanupPreview = yield* previewCleanup(projectName);
|
|
163
241
|
let deletedCount = 0;
|
|
242
|
+
let deletedAgentCount = 0;
|
|
164
243
|
for (const result of cleanupPreview) {
|
|
165
244
|
const toDelete = [
|
|
166
245
|
...clearEmpty ? result.emptySessions : [],
|
|
167
246
|
...clearInvalid ? result.invalidSessions : []
|
|
168
247
|
];
|
|
169
248
|
for (const session of toDelete) {
|
|
170
|
-
yield* deleteSession(result.project, session.id);
|
|
249
|
+
const deleteResult = yield* deleteSession(result.project, session.id);
|
|
171
250
|
deletedCount++;
|
|
251
|
+
deletedAgentCount += deleteResult.deletedAgents.length;
|
|
252
|
+
}
|
|
253
|
+
if (clearOrphanAgents) {
|
|
254
|
+
const orphanResult = yield* deleteOrphanAgents(result.project);
|
|
255
|
+
deletedAgentCount += orphanResult.count;
|
|
172
256
|
}
|
|
173
257
|
}
|
|
174
|
-
return { success: true, deletedCount };
|
|
258
|
+
return { success: true, deletedCount, deletedAgentCount };
|
|
175
259
|
});
|
|
176
260
|
var getSessionFiles = (projectName, sessionId) => Effect.gen(function* () {
|
|
177
261
|
const messages = yield* readSession(projectName, sessionId);
|
|
@@ -223,6 +307,64 @@ var getSessionFiles = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
223
307
|
totalChanges: fileChanges.length
|
|
224
308
|
};
|
|
225
309
|
});
|
|
310
|
+
var splitSession = (projectName, sessionId, splitAtMessageUuid) => Effect.gen(function* () {
|
|
311
|
+
const projectPath = path.join(getSessionsDir(), projectName);
|
|
312
|
+
const filePath = path.join(projectPath, `${sessionId}.jsonl`);
|
|
313
|
+
const content = yield* Effect.tryPromise(() => fs.readFile(filePath, "utf-8"));
|
|
314
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
315
|
+
const allMessages = lines.map((line) => JSON.parse(line));
|
|
316
|
+
const splitIndex = allMessages.findIndex((m) => m.uuid === splitAtMessageUuid);
|
|
317
|
+
if (splitIndex === -1) {
|
|
318
|
+
return { success: false, error: "Message not found" };
|
|
319
|
+
}
|
|
320
|
+
if (splitIndex === 0) {
|
|
321
|
+
return { success: false, error: "Cannot split at first message" };
|
|
322
|
+
}
|
|
323
|
+
const newSessionId = crypto.randomUUID();
|
|
324
|
+
const remainingMessages = allMessages.slice(0, splitIndex);
|
|
325
|
+
const movedMessages = allMessages.slice(splitIndex);
|
|
326
|
+
const updatedMovedMessages = movedMessages.map((msg, index) => {
|
|
327
|
+
const updated = { ...msg, sessionId: newSessionId };
|
|
328
|
+
if (index === 0) {
|
|
329
|
+
updated.parentUuid = null;
|
|
330
|
+
}
|
|
331
|
+
return updated;
|
|
332
|
+
});
|
|
333
|
+
const remainingContent = remainingMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
334
|
+
yield* Effect.tryPromise(() => fs.writeFile(filePath, remainingContent, "utf-8"));
|
|
335
|
+
const newFilePath = path.join(projectPath, `${newSessionId}.jsonl`);
|
|
336
|
+
const newContent = updatedMovedMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
337
|
+
yield* Effect.tryPromise(() => fs.writeFile(newFilePath, newContent, "utf-8"));
|
|
338
|
+
const agentFiles = yield* Effect.tryPromise(() => fs.readdir(projectPath));
|
|
339
|
+
const agentJsonlFiles = agentFiles.filter((f) => f.startsWith("agent-") && f.endsWith(".jsonl"));
|
|
340
|
+
for (const agentFile of agentJsonlFiles) {
|
|
341
|
+
const agentPath = path.join(projectPath, agentFile);
|
|
342
|
+
const agentContent = yield* Effect.tryPromise(() => fs.readFile(agentPath, "utf-8"));
|
|
343
|
+
const agentLines = agentContent.trim().split("\n").filter(Boolean);
|
|
344
|
+
if (agentLines.length === 0) continue;
|
|
345
|
+
const firstAgentMsg = JSON.parse(agentLines[0]);
|
|
346
|
+
if (firstAgentMsg.sessionId === sessionId) {
|
|
347
|
+
const agentId = agentFile.replace("agent-", "").replace(".jsonl", "");
|
|
348
|
+
const isRelatedToMoved = movedMessages.some(
|
|
349
|
+
(msg) => msg.agentId === agentId
|
|
350
|
+
);
|
|
351
|
+
if (isRelatedToMoved) {
|
|
352
|
+
const updatedAgentMessages = agentLines.map((line) => {
|
|
353
|
+
const msg = JSON.parse(line);
|
|
354
|
+
return JSON.stringify({ ...msg, sessionId: newSessionId });
|
|
355
|
+
});
|
|
356
|
+
const updatedAgentContent = updatedAgentMessages.join("\n") + "\n";
|
|
357
|
+
yield* Effect.tryPromise(() => fs.writeFile(agentPath, updatedAgentContent, "utf-8"));
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
success: true,
|
|
363
|
+
newSessionId,
|
|
364
|
+
newSessionPath: newFilePath,
|
|
365
|
+
movedMessageCount: movedMessages.length
|
|
366
|
+
};
|
|
367
|
+
});
|
|
226
368
|
var getSessionDiffSummary = (projectName, sessionId) => Effect.gen(function* () {
|
|
227
369
|
const messages = yield* readSession(projectName, sessionId);
|
|
228
370
|
const title = pipe(
|
|
@@ -361,14 +503,16 @@ server.tool(
|
|
|
361
503
|
{
|
|
362
504
|
project_name: z.string().optional().describe("Optional: filter by project name"),
|
|
363
505
|
clear_empty: z.boolean().default(true).describe("Clear empty sessions (default: true)"),
|
|
364
|
-
clear_invalid: z.boolean().default(true).describe("Clear invalid API key sessions (default: true)")
|
|
506
|
+
clear_invalid: z.boolean().default(true).describe("Clear invalid API key sessions (default: true)"),
|
|
507
|
+
clear_orphan_agents: z.boolean().default(true).describe("Clear orphan agent files whose session no longer exists (default: true)")
|
|
365
508
|
},
|
|
366
|
-
async ({ project_name, clear_empty, clear_invalid }) => {
|
|
509
|
+
async ({ project_name, clear_empty, clear_invalid, clear_orphan_agents }) => {
|
|
367
510
|
const result = await Effect2.runPromise(
|
|
368
511
|
clearSessions({
|
|
369
512
|
projectName: project_name,
|
|
370
513
|
clearEmpty: clear_empty,
|
|
371
|
-
clearInvalid: clear_invalid
|
|
514
|
+
clearInvalid: clear_invalid,
|
|
515
|
+
clearOrphanAgents: clear_orphan_agents
|
|
372
516
|
})
|
|
373
517
|
);
|
|
374
518
|
return {
|
|
@@ -404,6 +548,25 @@ server.tool(
|
|
|
404
548
|
};
|
|
405
549
|
}
|
|
406
550
|
);
|
|
551
|
+
server.tool(
|
|
552
|
+
"split_session",
|
|
553
|
+
"Split a session at a specific message, creating a new session with messages from that point onwards",
|
|
554
|
+
{
|
|
555
|
+
project_name: z.string().describe("Project folder name"),
|
|
556
|
+
session_id: z.string().describe("Session ID to split"),
|
|
557
|
+
message_uuid: z.string().describe(
|
|
558
|
+
"UUID of the message where the split starts (this message becomes the first message of the new session)"
|
|
559
|
+
)
|
|
560
|
+
},
|
|
561
|
+
async ({ project_name, session_id, message_uuid }) => {
|
|
562
|
+
const result = await Effect2.runPromise(
|
|
563
|
+
splitSession(project_name, session_id, message_uuid)
|
|
564
|
+
);
|
|
565
|
+
return {
|
|
566
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
);
|
|
407
570
|
var webServerInstance = null;
|
|
408
571
|
server.tool(
|
|
409
572
|
"start_gui",
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/index.ts","../../src/lib/session.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { Effect } from 'effect'\nimport { z } from 'zod'\nimport * as session from '../lib/session.js'\nimport { startWebServer, stopWebServer } from '../server.js'\n\nconst server = new McpServer({\n name: 'claude-sessions-mcp',\n version: '0.1.0',\n})\n\n// List all projects\nserver.tool('list_projects', 'List all Claude Code projects with session counts', {}, async () => {\n const result = await Effect.runPromise(session.listProjects)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n})\n\n// List sessions in a project\nserver.tool(\n 'list_sessions',\n 'List all sessions in a project',\n {\n project_name: z.string().describe(\"Project folder name (e.g., '-Users-young-works-myproject')\"),\n },\n async ({ project_name }) => {\n const result = await Effect.runPromise(session.listSessions(project_name))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Rename session\nserver.tool(\n 'rename_session',\n 'Rename a session by adding a title prefix to the first message',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID (filename without .jsonl)'),\n new_title: z.string().describe('New title to add as prefix'),\n },\n async ({ project_name, session_id, new_title }) => {\n const result = await Effect.runPromise(\n session.renameSession(project_name, session_id, new_title)\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Delete session\nserver.tool(\n 'delete_session',\n 'Delete a session (moves to .bak folder for recovery)',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID to delete'),\n },\n async ({ project_name, session_id }) => {\n const result = await Effect.runPromise(session.deleteSession(project_name, session_id))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Delete message\nserver.tool(\n 'delete_message',\n 'Delete a message from a session and repair the parentUuid chain',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID'),\n message_uuid: z.string().describe('UUID of the message to delete'),\n },\n async ({ project_name, session_id, message_uuid }) => {\n const result = await Effect.runPromise(\n session.deleteMessage(project_name, session_id, message_uuid)\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Preview cleanup\nserver.tool(\n 'preview_cleanup',\n 'Preview sessions that would be cleaned (empty and invalid API key sessions)',\n {\n project_name: z.string().optional().describe('Optional: filter by project name'),\n },\n async ({ project_name }) => {\n const result = await Effect.runPromise(session.previewCleanup(project_name))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Clear sessions\nserver.tool(\n 'clear_sessions',\n 'Delete all empty sessions and invalid API key sessions',\n {\n project_name: z.string().optional().describe('Optional: filter by project name'),\n clear_empty: z.boolean().default(true).describe('Clear empty sessions (default: true)'),\n clear_invalid: z\n .boolean()\n .default(true)\n .describe('Clear invalid API key sessions (default: true)'),\n },\n async ({ project_name, clear_empty, clear_invalid }) => {\n const result = await Effect.runPromise(\n session.clearSessions({\n projectName: project_name,\n clearEmpty: clear_empty,\n clearInvalid: clear_invalid,\n })\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Get changed files from a session\nserver.tool(\n 'get_session_files',\n 'Get list of all files changed in a session (from file-history-snapshot and tool_use)',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID'),\n },\n async ({ project_name, session_id }) => {\n const result = await Effect.runPromise(session.getSessionFiles(project_name, session_id))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Get session diff summary\nserver.tool(\n 'get_session_diff',\n 'Get diff summary for a session including file changes and snapshot info',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID'),\n },\n async ({ project_name, session_id }) => {\n const result = await Effect.runPromise(session.getSessionDiffSummary(project_name, session_id))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Start GUI\nlet webServerInstance: Awaited<ReturnType<typeof startWebServer>> | null = null\n\nserver.tool(\n 'start_gui',\n 'Start the web GUI for session management and open it in browser',\n {\n port: z.number().default(5173).describe('Port to run the web server on (default: 5173)'),\n open_browser: z\n .boolean()\n .default(true)\n .describe('Whether to open browser automatically (default: true)'),\n restart: z\n .boolean()\n .default(false)\n .describe('Restart the server if already running (default: false)'),\n },\n async ({ port, open_browser, restart }) => {\n try {\n if (webServerInstance) {\n if (restart) {\n await stopWebServer(webServerInstance)\n webServerInstance = null\n } else {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Web GUI is already running',\n url: `http://localhost:${port}`,\n },\n null,\n 2\n ),\n },\n ],\n }\n }\n }\n\n webServerInstance = await startWebServer(port, open_browser)\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Web GUI started successfully',\n url: `http://localhost:${port}`,\n pid: process.pid,\n },\n null,\n 2\n ),\n },\n ],\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: false,\n error: String(error),\n },\n null,\n 2\n ),\n },\n ],\n }\n }\n }\n)\n\n// Stop GUI\nserver.tool('stop_gui', 'Stop the web GUI server', {}, async () => {\n if (webServerInstance) {\n const port = webServerInstance.port\n // Call shutdown API first for graceful shutdown\n try {\n await fetch(`http://localhost:${port}/api/shutdown`, { method: 'POST' })\n } catch {\n // Server might already be stopping\n }\n // Then kill the process if still running\n await stopWebServer(webServerInstance)\n webServerInstance = null\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ success: true, message: 'Web GUI stopped successfully' }, null, 2),\n },\n ],\n }\n }\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ success: true, message: 'Web GUI was not running' }, null, 2),\n },\n ],\n }\n})\n\n// Main entry\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\nmain().catch(console.error)\n","import { Effect, pipe, Array as A, Option as O } from 'effect'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport type { Message, SessionMeta, Project } from './schema.js'\n\n// Get Claude sessions directory\nexport const getSessionsDir = (): string => path.join(os.homedir(), '.claude', 'projects')\n\n// List all project directories\nexport const listProjects = Effect.gen(function* () {\n const sessionsDir = getSessionsDir()\n\n const exists = yield* Effect.tryPromise(() =>\n fs\n .access(sessionsDir)\n .then(() => true)\n .catch(() => false)\n )\n\n if (!exists) {\n return [] as Project[]\n }\n\n const entries = yield* Effect.tryPromise(() => fs.readdir(sessionsDir, { withFileTypes: true }))\n\n const projects = yield* Effect.all(\n entries\n .filter((e) => e.isDirectory())\n .map((entry) =>\n Effect.gen(function* () {\n const projectPath = path.join(sessionsDir, entry.name)\n const files = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n const sessionFiles = files.filter((f) => f.endsWith('.jsonl'))\n\n return {\n name: entry.name,\n path: projectPath,\n sessionCount: sessionFiles.length,\n } satisfies Project\n })\n ),\n { concurrency: 10 }\n )\n\n return projects\n})\n\n// List sessions in a project\nexport const listSessions = (projectName: string) =>\n Effect.gen(function* () {\n const projectPath = path.join(getSessionsDir(), projectName)\n const files = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n const sessionFiles = files.filter((f) => f.endsWith('.jsonl'))\n\n const sessions = yield* Effect.all(\n sessionFiles.map((file) =>\n Effect.gen(function* () {\n const filePath = path.join(projectPath, file)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n const messages = lines.map((line) => JSON.parse(line) as Message)\n\n const sessionId = file.replace('.jsonl', '')\n const firstMessage = messages[0]\n const lastMessage = messages[messages.length - 1]\n\n // Extract title from first user message\n const title = pipe(\n messages,\n A.findFirst((m) => m.type === 'human'),\n O.map((m) => {\n const msg = m.message as { content?: string } | undefined\n const content = msg?.content ?? ''\n return content.slice(0, 50) + (content.length > 50 ? '...' : '')\n }),\n O.getOrElse(() => 'Untitled')\n )\n\n return {\n id: sessionId,\n projectName,\n title,\n messageCount: messages.length,\n createdAt: firstMessage?.timestamp,\n updatedAt: lastMessage?.timestamp,\n } satisfies SessionMeta\n })\n ),\n { concurrency: 10 }\n )\n\n return sessions\n })\n\n// Read session messages\nexport const readSession = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n return lines.map((line) => JSON.parse(line) as Message)\n })\n\n// Delete a session\nexport const deleteSession = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const sessionsDir = getSessionsDir()\n const filePath = path.join(sessionsDir, projectName, `${sessionId}.jsonl`)\n\n // Create backup directory\n const backupDir = path.join(sessionsDir, projectName, '.bak')\n yield* Effect.tryPromise(() => fs.mkdir(backupDir, { recursive: true }))\n\n // Move to backup\n const backupPath = path.join(backupDir, `${sessionId}.jsonl`)\n yield* Effect.tryPromise(() => fs.rename(filePath, backupPath))\n\n return { success: true, backupPath }\n })\n\n// Rename session by adding title prefix\nexport const renameSession = (projectName: string, sessionId: string, newTitle: string) =>\n Effect.gen(function* () {\n const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n\n if (lines.length === 0) {\n return { success: false, error: 'Empty session' }\n }\n\n const messages = lines.map((line) => JSON.parse(line) as Message)\n const firstMsg = messages[0]\n\n // Add title prefix to first message\n if (firstMsg && typeof firstMsg.message === 'object' && firstMsg.message !== null) {\n const msg = firstMsg.message as { content?: string }\n if (msg.content) {\n // Remove existing title prefix if any\n const cleanContent = msg.content.replace(/^\\[.*?\\]\\s*/, '')\n msg.content = `[${newTitle}] ${cleanContent}`\n }\n }\n\n const newContent = messages.map((m) => JSON.stringify(m)).join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(filePath, newContent, 'utf-8'))\n\n return { success: true }\n })\n\n// Delete a message from session\nexport const deleteMessage = (projectName: string, sessionId: string, messageUuid: string) =>\n Effect.gen(function* () {\n const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n const messages = lines.map((line) => JSON.parse(line) as Message)\n\n const targetIndex = messages.findIndex((m) => m.uuid === messageUuid)\n if (targetIndex === -1) {\n return { success: false, error: 'Message not found' }\n }\n\n // Get the parent UUID of deleted message\n const deletedMsg = messages[targetIndex]\n const parentUuid = deletedMsg?.parentUuid\n\n // Update child message to point to deleted message's parent\n const nextMsg = messages[targetIndex + 1]\n if (nextMsg) {\n nextMsg.parentUuid = parentUuid\n }\n\n // Remove the message\n messages.splice(targetIndex, 1)\n\n const newContent = messages.map((m) => JSON.stringify(m)).join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(filePath, newContent, 'utf-8'))\n\n return { success: true }\n })\n\n// Preview cleanup - find empty and invalid sessions\nexport const previewCleanup = (projectName?: string) =>\n Effect.gen(function* () {\n const projects = yield* listProjects\n const targetProjects = projectName ? projects.filter((p) => p.name === projectName) : projects\n\n const results = yield* Effect.all(\n targetProjects.map((project) =>\n Effect.gen(function* () {\n const sessions = yield* listSessions(project.name)\n const emptySessions = sessions.filter((s) => s.messageCount === 0)\n const invalidSessions = sessions.filter(\n (s) => s.title?.includes('Invalid API key') || s.title?.includes('API key')\n )\n\n return {\n project: project.name,\n emptySessions,\n invalidSessions,\n }\n })\n ),\n { concurrency: 5 }\n )\n\n return results\n })\n\n// Clear sessions (empty and invalid)\nexport const clearSessions = (options: {\n projectName?: string\n clearEmpty?: boolean\n clearInvalid?: boolean\n}) =>\n Effect.gen(function* () {\n const { projectName, clearEmpty = true, clearInvalid = true } = options\n const cleanupPreview = yield* previewCleanup(projectName)\n\n let deletedCount = 0\n\n for (const result of cleanupPreview) {\n const toDelete = [\n ...(clearEmpty ? result.emptySessions : []),\n ...(clearInvalid ? result.invalidSessions : []),\n ]\n\n for (const session of toDelete) {\n yield* deleteSession(result.project, session.id)\n deletedCount++\n }\n }\n\n return { success: true, deletedCount }\n })\n\n// File change info extracted from session\nexport interface FileChange {\n path: string\n action: 'created' | 'modified' | 'deleted'\n timestamp?: string\n messageUuid?: string\n}\n\n// Session file changes summary\nexport interface SessionFilesSummary {\n sessionId: string\n projectName: string\n files: FileChange[]\n totalChanges: number\n}\n\n// Get changed files from a session\nexport const getSessionFiles = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const messages = yield* readSession(projectName, sessionId)\n const fileChanges: FileChange[] = []\n const seenFiles = new Set<string>()\n\n for (const msg of messages) {\n // Check for file-history-snapshot type\n if (msg.type === 'file-history-snapshot') {\n const snapshot = msg as unknown as {\n type: string\n messageId?: string\n snapshot?: {\n trackedFileBackups?: Record<string, unknown>\n timestamp?: string\n }\n }\n\n const backups = snapshot.snapshot?.trackedFileBackups\n if (backups && typeof backups === 'object') {\n for (const filePath of Object.keys(backups)) {\n if (!seenFiles.has(filePath)) {\n seenFiles.add(filePath)\n fileChanges.push({\n path: filePath,\n action: 'modified',\n timestamp: snapshot.snapshot?.timestamp,\n messageUuid: snapshot.messageId ?? msg.uuid,\n })\n }\n }\n }\n }\n\n // Also check tool_use for Write/Edit operations\n if (msg.type === 'assistant' && msg.message) {\n const assistantMsg = msg.message as {\n content?: Array<{ type: string; name?: string; input?: { file_path?: string } }>\n }\n const content = assistantMsg.content\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'tool_use' && (block.name === 'Write' || block.name === 'Edit')) {\n const filePath = block.input?.file_path\n if (filePath && !seenFiles.has(filePath)) {\n seenFiles.add(filePath)\n fileChanges.push({\n path: filePath,\n action: block.name === 'Write' ? 'created' : 'modified',\n timestamp: msg.timestamp,\n messageUuid: msg.uuid,\n })\n }\n }\n }\n }\n }\n }\n\n return {\n sessionId,\n projectName,\n files: fileChanges,\n totalChanges: fileChanges.length,\n } satisfies SessionFilesSummary\n })\n\n// Get file changes diff summary for a session\nexport interface FileDiffSummary {\n sessionId: string\n projectName: string\n title: string\n changes: Array<{\n path: string\n action: 'created' | 'modified' | 'deleted'\n hasBackup: boolean\n backupPreview?: string\n }>\n totalFiles: number\n snapshotCount: number\n}\n\nexport const getSessionDiffSummary = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const messages = yield* readSession(projectName, sessionId)\n\n // Extract title\n const title = pipe(\n messages,\n A.findFirst((m) => m.type === 'human'),\n O.map((m) => {\n const msg = m.message as { content?: string } | undefined\n const content = msg?.content ?? ''\n return content.slice(0, 50) + (content.length > 50 ? '...' : '')\n }),\n O.getOrElse(() => 'Untitled')\n )\n\n const changes: FileDiffSummary['changes'] = []\n const seenFiles = new Set<string>()\n let snapshotCount = 0\n\n for (const msg of messages) {\n if (msg.type === 'file-history-snapshot') {\n snapshotCount++\n const snapshot = msg as {\n type: string\n snapshot?: {\n trackedFileBackups?: Record<string, { content?: string }>\n }\n }\n\n const backups = snapshot.snapshot?.trackedFileBackups\n if (backups && typeof backups === 'object') {\n for (const [filePath, backup] of Object.entries(backups)) {\n if (!seenFiles.has(filePath)) {\n seenFiles.add(filePath)\n const backupData = backup as { content?: string } | undefined\n const content = backupData?.content ?? ''\n changes.push({\n path: filePath,\n action: 'modified',\n hasBackup: content.length > 0,\n backupPreview: content.slice(0, 100) + (content.length > 100 ? '...' : ''),\n })\n }\n }\n }\n }\n }\n\n return {\n sessionId,\n projectName,\n title,\n changes,\n totalFiles: changes.length,\n snapshotCount,\n } satisfies FileDiffSummary\n })\n"],"mappings":"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","names":["Effect","content","Effect"]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/index.ts","../../src/lib/session.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { Effect } from 'effect'\nimport { z } from 'zod'\nimport * as session from '../lib/session.js'\nimport { startWebServer, stopWebServer } from '../server.js'\n\nconst server = new McpServer({\n name: 'claude-sessions-mcp',\n version: '0.1.0',\n})\n\n// List all projects\nserver.tool('list_projects', 'List all Claude Code projects with session counts', {}, async () => {\n const result = await Effect.runPromise(session.listProjects)\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n})\n\n// List sessions in a project\nserver.tool(\n 'list_sessions',\n 'List all sessions in a project',\n {\n project_name: z.string().describe(\"Project folder name (e.g., '-Users-young-works-myproject')\"),\n },\n async ({ project_name }) => {\n const result = await Effect.runPromise(session.listSessions(project_name))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Rename session\nserver.tool(\n 'rename_session',\n 'Rename a session by adding a title prefix to the first message',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID (filename without .jsonl)'),\n new_title: z.string().describe('New title to add as prefix'),\n },\n async ({ project_name, session_id, new_title }) => {\n const result = await Effect.runPromise(\n session.renameSession(project_name, session_id, new_title)\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Delete session\nserver.tool(\n 'delete_session',\n 'Delete a session (moves to .bak folder for recovery)',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID to delete'),\n },\n async ({ project_name, session_id }) => {\n const result = await Effect.runPromise(session.deleteSession(project_name, session_id))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Delete message\nserver.tool(\n 'delete_message',\n 'Delete a message from a session and repair the parentUuid chain',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID'),\n message_uuid: z.string().describe('UUID of the message to delete'),\n },\n async ({ project_name, session_id, message_uuid }) => {\n const result = await Effect.runPromise(\n session.deleteMessage(project_name, session_id, message_uuid)\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Preview cleanup\nserver.tool(\n 'preview_cleanup',\n 'Preview sessions that would be cleaned (empty and invalid API key sessions)',\n {\n project_name: z.string().optional().describe('Optional: filter by project name'),\n },\n async ({ project_name }) => {\n const result = await Effect.runPromise(session.previewCleanup(project_name))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Clear sessions\nserver.tool(\n 'clear_sessions',\n 'Delete all empty sessions and invalid API key sessions',\n {\n project_name: z.string().optional().describe('Optional: filter by project name'),\n clear_empty: z.boolean().default(true).describe('Clear empty sessions (default: true)'),\n clear_invalid: z\n .boolean()\n .default(true)\n .describe('Clear invalid API key sessions (default: true)'),\n clear_orphan_agents: z\n .boolean()\n .default(true)\n .describe('Clear orphan agent files whose session no longer exists (default: true)'),\n },\n async ({ project_name, clear_empty, clear_invalid, clear_orphan_agents }) => {\n const result = await Effect.runPromise(\n session.clearSessions({\n projectName: project_name,\n clearEmpty: clear_empty,\n clearInvalid: clear_invalid,\n clearOrphanAgents: clear_orphan_agents,\n })\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Get changed files from a session\nserver.tool(\n 'get_session_files',\n 'Get list of all files changed in a session (from file-history-snapshot and tool_use)',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID'),\n },\n async ({ project_name, session_id }) => {\n const result = await Effect.runPromise(session.getSessionFiles(project_name, session_id))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Get session diff summary\nserver.tool(\n 'get_session_diff',\n 'Get diff summary for a session including file changes and snapshot info',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID'),\n },\n async ({ project_name, session_id }) => {\n const result = await Effect.runPromise(session.getSessionDiffSummary(project_name, session_id))\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Split session\nserver.tool(\n 'split_session',\n 'Split a session at a specific message, creating a new session with messages from that point onwards',\n {\n project_name: z.string().describe('Project folder name'),\n session_id: z.string().describe('Session ID to split'),\n message_uuid: z\n .string()\n .describe(\n 'UUID of the message where the split starts (this message becomes the first message of the new session)'\n ),\n },\n async ({ project_name, session_id, message_uuid }) => {\n const result = await Effect.runPromise(\n session.splitSession(project_name, session_id, message_uuid)\n )\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n }\n }\n)\n\n// Start GUI\nlet webServerInstance: Awaited<ReturnType<typeof startWebServer>> | null = null\n\nserver.tool(\n 'start_gui',\n 'Start the web GUI for session management and open it in browser',\n {\n port: z.number().default(5173).describe('Port to run the web server on (default: 5173)'),\n open_browser: z\n .boolean()\n .default(true)\n .describe('Whether to open browser automatically (default: true)'),\n restart: z\n .boolean()\n .default(false)\n .describe('Restart the server if already running (default: false)'),\n },\n async ({ port, open_browser, restart }) => {\n try {\n if (webServerInstance) {\n if (restart) {\n await stopWebServer(webServerInstance)\n webServerInstance = null\n } else {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Web GUI is already running',\n url: `http://localhost:${port}`,\n },\n null,\n 2\n ),\n },\n ],\n }\n }\n }\n\n webServerInstance = await startWebServer(port, open_browser)\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: true,\n message: 'Web GUI started successfully',\n url: `http://localhost:${port}`,\n pid: process.pid,\n },\n null,\n 2\n ),\n },\n ],\n }\n } catch (error) {\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(\n {\n success: false,\n error: String(error),\n },\n null,\n 2\n ),\n },\n ],\n }\n }\n }\n)\n\n// Stop GUI\nserver.tool('stop_gui', 'Stop the web GUI server', {}, async () => {\n if (webServerInstance) {\n const port = webServerInstance.port\n // Call shutdown API first for graceful shutdown\n try {\n await fetch(`http://localhost:${port}/api/shutdown`, { method: 'POST' })\n } catch {\n // Server might already be stopping\n }\n // Then kill the process if still running\n await stopWebServer(webServerInstance)\n webServerInstance = null\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ success: true, message: 'Web GUI stopped successfully' }, null, 2),\n },\n ],\n }\n }\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({ success: true, message: 'Web GUI was not running' }, null, 2),\n },\n ],\n }\n})\n\n// Main entry\nasync function main() {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n}\n\nmain().catch(console.error)\n","import { Effect, pipe, Array as A, Option as O } from 'effect'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport * as os from 'node:os'\nimport type { Message, SessionMeta, Project } from './schema.js'\n\n// Get Claude sessions directory\nexport const getSessionsDir = (): string => path.join(os.homedir(), '.claude', 'projects')\n\n// List all project directories\nexport const listProjects = Effect.gen(function* () {\n const sessionsDir = getSessionsDir()\n\n const exists = yield* Effect.tryPromise(() =>\n fs\n .access(sessionsDir)\n .then(() => true)\n .catch(() => false)\n )\n\n if (!exists) {\n return [] as Project[]\n }\n\n const entries = yield* Effect.tryPromise(() => fs.readdir(sessionsDir, { withFileTypes: true }))\n\n const projects = yield* Effect.all(\n entries\n .filter((e) => e.isDirectory())\n .map((entry) =>\n Effect.gen(function* () {\n const projectPath = path.join(sessionsDir, entry.name)\n const files = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n const sessionFiles = files.filter((f) => f.endsWith('.jsonl'))\n\n return {\n name: entry.name,\n path: projectPath,\n sessionCount: sessionFiles.length,\n } satisfies Project\n })\n ),\n { concurrency: 10 }\n )\n\n return projects\n})\n\n// List sessions in a project\nexport const listSessions = (projectName: string) =>\n Effect.gen(function* () {\n const projectPath = path.join(getSessionsDir(), projectName)\n const files = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n const sessionFiles = files.filter((f) => f.endsWith('.jsonl'))\n\n const sessions = yield* Effect.all(\n sessionFiles.map((file) =>\n Effect.gen(function* () {\n const filePath = path.join(projectPath, file)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n const messages = lines.map((line) => JSON.parse(line) as Message)\n\n const sessionId = file.replace('.jsonl', '')\n const firstMessage = messages[0]\n const lastMessage = messages[messages.length - 1]\n\n // Extract title from first user message\n const title = pipe(\n messages,\n A.findFirst((m) => m.type === 'human'),\n O.map((m) => {\n const msg = m.message as { content?: string } | undefined\n const content = msg?.content ?? ''\n return content.slice(0, 50) + (content.length > 50 ? '...' : '')\n }),\n O.getOrElse(() => 'Untitled')\n )\n\n return {\n id: sessionId,\n projectName,\n title,\n messageCount: messages.length,\n createdAt: firstMessage?.timestamp,\n updatedAt: lastMessage?.timestamp,\n } satisfies SessionMeta\n })\n ),\n { concurrency: 10 }\n )\n\n return sessions\n })\n\n// Read session messages\nexport const readSession = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n return lines.map((line) => JSON.parse(line) as Message)\n })\n\n// Find agent files linked to a session\nexport const findLinkedAgents = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const projectPath = path.join(getSessionsDir(), projectName)\n const files = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n const agentFiles = files.filter((f) => f.startsWith('agent-') && f.endsWith('.jsonl'))\n\n const linkedAgents: string[] = []\n\n for (const agentFile of agentFiles) {\n const filePath = path.join(projectPath, agentFile)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const firstLine = content.split('\\n')[0]\n\n if (firstLine) {\n try {\n const parsed = JSON.parse(firstLine) as { sessionId?: string }\n if (parsed.sessionId === sessionId) {\n linkedAgents.push(agentFile.replace('.jsonl', ''))\n }\n } catch {\n // Skip invalid JSON\n }\n }\n }\n\n return linkedAgents\n })\n\n// Delete a session and its linked agent files\nexport const deleteSession = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const sessionsDir = getSessionsDir()\n const projectPath = path.join(sessionsDir, projectName)\n const filePath = path.join(projectPath, `${sessionId}.jsonl`)\n\n // Create backup directory\n const backupDir = path.join(projectPath, '.bak')\n yield* Effect.tryPromise(() => fs.mkdir(backupDir, { recursive: true }))\n\n // Find and delete linked agent files\n const linkedAgents = yield* findLinkedAgents(projectName, sessionId)\n const deletedAgents: string[] = []\n\n for (const agentId of linkedAgents) {\n const agentPath = path.join(projectPath, `${agentId}.jsonl`)\n const agentBackupPath = path.join(backupDir, `${agentId}.jsonl`)\n yield* Effect.tryPromise(() => fs.rename(agentPath, agentBackupPath))\n deletedAgents.push(agentId)\n }\n\n // Move session file to backup\n const backupPath = path.join(backupDir, `${sessionId}.jsonl`)\n yield* Effect.tryPromise(() => fs.rename(filePath, backupPath))\n\n return { success: true, backupPath, deletedAgents }\n })\n\n// Rename session by adding title prefix\nexport const renameSession = (projectName: string, sessionId: string, newTitle: string) =>\n Effect.gen(function* () {\n const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n\n if (lines.length === 0) {\n return { success: false, error: 'Empty session' }\n }\n\n const messages = lines.map((line) => JSON.parse(line) as Message)\n const firstMsg = messages[0]\n\n // Add title prefix to first message\n if (firstMsg && typeof firstMsg.message === 'object' && firstMsg.message !== null) {\n const msg = firstMsg.message as { content?: string }\n if (msg.content) {\n // Remove existing title prefix if any\n const cleanContent = msg.content.replace(/^\\[.*?\\]\\s*/, '')\n msg.content = `[${newTitle}] ${cleanContent}`\n }\n }\n\n const newContent = messages.map((m) => JSON.stringify(m)).join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(filePath, newContent, 'utf-8'))\n\n return { success: true }\n })\n\n// Delete a message from session\nexport const deleteMessage = (projectName: string, sessionId: string, messageUuid: string) =>\n Effect.gen(function* () {\n const filePath = path.join(getSessionsDir(), projectName, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n const messages = lines.map((line) => JSON.parse(line) as Record<string, unknown>)\n\n // Find by uuid or messageId (for file-history-snapshot type)\n const targetIndex = messages.findIndex(\n (m) => m.uuid === messageUuid || m.messageId === messageUuid\n )\n if (targetIndex === -1) {\n return { success: false, error: 'Message not found' }\n }\n\n // Get the parent UUID of deleted message\n const deletedMsg = messages[targetIndex]\n const parentUuid = deletedMsg?.parentUuid\n\n // Update child message to point to deleted message's parent\n const nextMsg = messages[targetIndex + 1]\n if (nextMsg) {\n nextMsg.parentUuid = parentUuid\n }\n\n // Remove the message\n messages.splice(targetIndex, 1)\n\n const newContent = messages.map((m) => JSON.stringify(m)).join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(filePath, newContent, 'utf-8'))\n\n return { success: true }\n })\n\n// Preview cleanup - find empty and invalid sessions\nexport const previewCleanup = (projectName?: string) =>\n Effect.gen(function* () {\n const projects = yield* listProjects\n const targetProjects = projectName ? projects.filter((p) => p.name === projectName) : projects\n\n const results = yield* Effect.all(\n targetProjects.map((project) =>\n Effect.gen(function* () {\n const sessions = yield* listSessions(project.name)\n const emptySessions = sessions.filter((s) => s.messageCount === 0)\n const invalidSessions = sessions.filter(\n (s) => s.title?.includes('Invalid API key') || s.title?.includes('API key')\n )\n\n return {\n project: project.name,\n emptySessions,\n invalidSessions,\n }\n })\n ),\n { concurrency: 5 }\n )\n\n return results\n })\n\n// Find orphan agent files (agents whose parent session no longer exists)\nexport const findOrphanAgents = (projectName: string) =>\n Effect.gen(function* () {\n const projectPath = path.join(getSessionsDir(), projectName)\n const files = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n\n const sessionIds = new Set(\n files\n .filter((f) => !f.startsWith('agent-') && f.endsWith('.jsonl'))\n .map((f) => f.replace('.jsonl', ''))\n )\n\n const agentFiles = files.filter((f) => f.startsWith('agent-') && f.endsWith('.jsonl'))\n const orphanAgents: Array<{ agentId: string; sessionId: string }> = []\n\n for (const agentFile of agentFiles) {\n const filePath = path.join(projectPath, agentFile)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const firstLine = content.split('\\n')[0]\n\n if (firstLine) {\n try {\n const parsed = JSON.parse(firstLine) as { sessionId?: string }\n if (parsed.sessionId && !sessionIds.has(parsed.sessionId)) {\n orphanAgents.push({\n agentId: agentFile.replace('.jsonl', ''),\n sessionId: parsed.sessionId,\n })\n }\n } catch {\n // Skip invalid JSON\n }\n }\n }\n\n return orphanAgents\n })\n\n// Delete orphan agent files\nexport const deleteOrphanAgents = (projectName: string) =>\n Effect.gen(function* () {\n const projectPath = path.join(getSessionsDir(), projectName)\n const orphans = yield* findOrphanAgents(projectName)\n\n // Create backup directory\n const backupDir = path.join(projectPath, '.bak')\n yield* Effect.tryPromise(() => fs.mkdir(backupDir, { recursive: true }))\n\n const deletedAgents: string[] = []\n\n for (const orphan of orphans) {\n const agentPath = path.join(projectPath, `${orphan.agentId}.jsonl`)\n const agentBackupPath = path.join(backupDir, `${orphan.agentId}.jsonl`)\n yield* Effect.tryPromise(() => fs.rename(agentPath, agentBackupPath))\n deletedAgents.push(orphan.agentId)\n }\n\n return { success: true, deletedAgents, count: deletedAgents.length }\n })\n\n// Clear sessions (empty and invalid)\nexport const clearSessions = (options: {\n projectName?: string\n clearEmpty?: boolean\n clearInvalid?: boolean\n clearOrphanAgents?: boolean\n}) =>\n Effect.gen(function* () {\n const {\n projectName,\n clearEmpty = true,\n clearInvalid = true,\n clearOrphanAgents = true,\n } = options\n const cleanupPreview = yield* previewCleanup(projectName)\n\n let deletedCount = 0\n let deletedAgentCount = 0\n\n for (const result of cleanupPreview) {\n const toDelete = [\n ...(clearEmpty ? result.emptySessions : []),\n ...(clearInvalid ? result.invalidSessions : []),\n ]\n\n for (const session of toDelete) {\n const deleteResult = yield* deleteSession(result.project, session.id)\n deletedCount++\n deletedAgentCount += deleteResult.deletedAgents.length\n }\n\n // Clean up orphan agents after deleting sessions\n if (clearOrphanAgents) {\n const orphanResult = yield* deleteOrphanAgents(result.project)\n deletedAgentCount += orphanResult.count\n }\n }\n\n return { success: true, deletedCount, deletedAgentCount }\n })\n\n// File change info extracted from session\nexport interface FileChange {\n path: string\n action: 'created' | 'modified' | 'deleted'\n timestamp?: string\n messageUuid?: string\n}\n\n// Session file changes summary\nexport interface SessionFilesSummary {\n sessionId: string\n projectName: string\n files: FileChange[]\n totalChanges: number\n}\n\n// Get changed files from a session\nexport const getSessionFiles = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const messages = yield* readSession(projectName, sessionId)\n const fileChanges: FileChange[] = []\n const seenFiles = new Set<string>()\n\n for (const msg of messages) {\n // Check for file-history-snapshot type\n if (msg.type === 'file-history-snapshot') {\n const snapshot = msg as unknown as {\n type: string\n messageId?: string\n snapshot?: {\n trackedFileBackups?: Record<string, unknown>\n timestamp?: string\n }\n }\n\n const backups = snapshot.snapshot?.trackedFileBackups\n if (backups && typeof backups === 'object') {\n for (const filePath of Object.keys(backups)) {\n if (!seenFiles.has(filePath)) {\n seenFiles.add(filePath)\n fileChanges.push({\n path: filePath,\n action: 'modified',\n timestamp: snapshot.snapshot?.timestamp,\n messageUuid: snapshot.messageId ?? msg.uuid,\n })\n }\n }\n }\n }\n\n // Also check tool_use for Write/Edit operations\n if (msg.type === 'assistant' && msg.message) {\n const assistantMsg = msg.message as {\n content?: Array<{ type: string; name?: string; input?: { file_path?: string } }>\n }\n const content = assistantMsg.content\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'tool_use' && (block.name === 'Write' || block.name === 'Edit')) {\n const filePath = block.input?.file_path\n if (filePath && !seenFiles.has(filePath)) {\n seenFiles.add(filePath)\n fileChanges.push({\n path: filePath,\n action: block.name === 'Write' ? 'created' : 'modified',\n timestamp: msg.timestamp,\n messageUuid: msg.uuid,\n })\n }\n }\n }\n }\n }\n }\n\n return {\n sessionId,\n projectName,\n files: fileChanges,\n totalChanges: fileChanges.length,\n } satisfies SessionFilesSummary\n })\n\n// Split session at a specific message\nexport interface SplitSessionResult {\n success: boolean\n newSessionId?: string\n newSessionPath?: string\n movedMessageCount?: number\n error?: string\n}\n\nexport const splitSession = (projectName: string, sessionId: string, splitAtMessageUuid: string) =>\n Effect.gen(function* () {\n const projectPath = path.join(getSessionsDir(), projectName)\n const filePath = path.join(projectPath, `${sessionId}.jsonl`)\n const content = yield* Effect.tryPromise(() => fs.readFile(filePath, 'utf-8'))\n const lines = content.trim().split('\\n').filter(Boolean)\n\n // Parse all messages preserving their full structure\n const allMessages = lines.map((line) => JSON.parse(line) as Record<string, unknown>)\n\n // Find the split point\n const splitIndex = allMessages.findIndex((m) => m.uuid === splitAtMessageUuid)\n if (splitIndex === -1) {\n return { success: false, error: 'Message not found' } satisfies SplitSessionResult\n }\n\n if (splitIndex === 0) {\n return { success: false, error: 'Cannot split at first message' } satisfies SplitSessionResult\n }\n\n // Generate new session ID\n const newSessionId = crypto.randomUUID()\n\n // Split messages\n const remainingMessages = allMessages.slice(0, splitIndex)\n const movedMessages = allMessages.slice(splitIndex)\n\n // Update moved messages with new sessionId and fix first message's parentUuid\n const updatedMovedMessages = movedMessages.map((msg, index) => {\n const updated: Record<string, unknown> = { ...msg, sessionId: newSessionId }\n if (index === 0) {\n // First message of new session should have no parent\n updated.parentUuid = null\n }\n return updated\n })\n\n // Write remaining messages to original file\n const remainingContent = remainingMessages.map((m) => JSON.stringify(m)).join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(filePath, remainingContent, 'utf-8'))\n\n // Write moved messages to new session file\n const newFilePath = path.join(projectPath, `${newSessionId}.jsonl`)\n const newContent = updatedMovedMessages.map((m) => JSON.stringify(m)).join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(newFilePath, newContent, 'utf-8'))\n\n // Update linked agent files that reference the old sessionId\n const agentFiles = yield* Effect.tryPromise(() => fs.readdir(projectPath))\n const agentJsonlFiles = agentFiles.filter((f) => f.startsWith('agent-') && f.endsWith('.jsonl'))\n\n for (const agentFile of agentJsonlFiles) {\n const agentPath = path.join(projectPath, agentFile)\n const agentContent = yield* Effect.tryPromise(() => fs.readFile(agentPath, 'utf-8'))\n const agentLines = agentContent.trim().split('\\n').filter(Boolean)\n\n if (agentLines.length === 0) continue\n\n const firstAgentMsg = JSON.parse(agentLines[0]) as { sessionId?: string }\n\n // If this agent belongs to the original session, check if it should be moved\n if (firstAgentMsg.sessionId === sessionId) {\n // Check if any message in moved messages is related to this agent\n const agentId = agentFile.replace('agent-', '').replace('.jsonl', '')\n const isRelatedToMoved = movedMessages.some(\n (msg) => (msg as { agentId?: string }).agentId === agentId\n )\n\n if (isRelatedToMoved) {\n // Update all messages in this agent file to reference new sessionId\n const updatedAgentMessages = agentLines.map((line) => {\n const msg = JSON.parse(line) as Record<string, unknown>\n return JSON.stringify({ ...msg, sessionId: newSessionId })\n })\n const updatedAgentContent = updatedAgentMessages.join('\\n') + '\\n'\n yield* Effect.tryPromise(() => fs.writeFile(agentPath, updatedAgentContent, 'utf-8'))\n }\n }\n }\n\n return {\n success: true,\n newSessionId,\n newSessionPath: newFilePath,\n movedMessageCount: movedMessages.length,\n } satisfies SplitSessionResult\n })\n\n// Get file changes diff summary for a session\nexport interface FileDiffSummary {\n sessionId: string\n projectName: string\n title: string\n changes: Array<{\n path: string\n action: 'created' | 'modified' | 'deleted'\n hasBackup: boolean\n backupPreview?: string\n }>\n totalFiles: number\n snapshotCount: number\n}\n\nexport const getSessionDiffSummary = (projectName: string, sessionId: string) =>\n Effect.gen(function* () {\n const messages = yield* readSession(projectName, sessionId)\n\n // Extract title\n const title = pipe(\n messages,\n A.findFirst((m) => m.type === 'human'),\n O.map((m) => {\n const msg = m.message as { content?: string } | undefined\n const content = msg?.content ?? ''\n return content.slice(0, 50) + (content.length > 50 ? '...' : '')\n }),\n O.getOrElse(() => 'Untitled')\n )\n\n const changes: FileDiffSummary['changes'] = []\n const seenFiles = new Set<string>()\n let snapshotCount = 0\n\n for (const msg of messages) {\n if (msg.type === 'file-history-snapshot') {\n snapshotCount++\n const snapshot = msg as {\n type: string\n snapshot?: {\n trackedFileBackups?: Record<string, { content?: string }>\n }\n }\n\n const backups = snapshot.snapshot?.trackedFileBackups\n if (backups && typeof backups === 'object') {\n for (const [filePath, backup] of Object.entries(backups)) {\n if (!seenFiles.has(filePath)) {\n seenFiles.add(filePath)\n const backupData = backup as { content?: string } | undefined\n const content = backupData?.content ?? ''\n changes.push({\n path: filePath,\n action: 'modified',\n hasBackup: content.length > 0,\n backupPreview: content.slice(0, 100) + (content.length > 100 ? '...' : ''),\n })\n }\n }\n }\n }\n }\n\n return {\n sessionId,\n projectName,\n title,\n changes,\n totalFiles: changes.length,\n snapshotCount,\n } satisfies FileDiffSummary\n })\n"],"mappings":"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","names":["Effect","content","Effect"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-700:oklch(50.5% .213 27.518);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-cyan-400:oklch(78.9% .154 211.53);--color-cyan-500:oklch(71.5% .143 215.221);--color-violet-400:oklch(70.2% .183 293.541);--color-violet-500:oklch(60.6% .25 292.717);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-500:oklch(62.7% .265 303.9);--color-white:#fff;--spacing:.25rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-gh-bg:#0d1117;--color-gh-bg-secondary:#161b22;--color-gh-border:#30363d;--color-gh-border-subtle:#21262d;--color-gh-text:#c9d1d9;--color-gh-text-secondary:#8b949e;--color-gh-accent:#1f6feb;--color-gh-green:#238636;--color-gh-red:#f85149}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.right-0{right:calc(var(--spacing)*0)}.right-4{right:calc(var(--spacing)*4)}.bottom-0{bottom:calc(var(--spacing)*0)}.bottom-1{bottom:calc(var(--spacing)*1)}.bottom-4{bottom:calc(var(--spacing)*4)}.left-0{left:calc(var(--spacing)*0)}.left-1\/2{left:50%}.z-50{z-index:50}.mx-auto{margin-inline:auto}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-2{margin-top:calc(var(--spacing)*2)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-8{height:calc(var(--spacing)*8)}.h-\[calc\(100vh-120px\)\]{height:calc(100vh - 120px)}.min-h-screen{min-height:100vh}.w-3{width:calc(var(--spacing)*3)}.w-full{width:100%}.max-w-7xl{max-width:var(--container-7xl)}.max-w-full{max-width:100%}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.grid-cols-\[350px_1fr\]{grid-template-columns:350px 1fr}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:calc(var(--spacing)*.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-3{border-left-style:var(--tw-border-style);border-left-width:3px}.border-none{--tw-border-style:none;border-style:none}.border-gh-border{border-color:var(--color-gh-border)}.border-gh-border-subtle{border-color:var(--color-gh-border-subtle)}.border-gh-red{border-color:var(--color-gh-red)}.border-l-amber-500{border-left-color:var(--color-amber-500)}.border-l-cyan-500{border-left-color:var(--color-cyan-500)}.border-l-gh-accent{border-left-color:var(--color-gh-accent)}.border-l-gh-green{border-left-color:var(--color-gh-green)}.border-l-purple-500{border-left-color:var(--color-purple-500)}.border-l-violet-500{border-left-color:var(--color-violet-500)}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/10{background-color:color-mix(in oklab,var(--color-amber-500)10%,transparent)}}.bg-cyan-500\/10{background-color:#00b7d71a}@supports (color:color-mix(in lab,red,red)){.bg-cyan-500\/10{background-color:color-mix(in oklab,var(--color-cyan-500)10%,transparent)}}.bg-gh-accent{background-color:var(--color-gh-accent)}.bg-gh-accent\/10{background-color:#1f6feb1a}@supports (color:color-mix(in lab,red,red)){.bg-gh-accent\/10{background-color:color-mix(in oklab,var(--color-gh-accent)10%,transparent)}}.bg-gh-accent\/15{background-color:#1f6feb26}@supports (color:color-mix(in lab,red,red)){.bg-gh-accent\/15{background-color:color-mix(in oklab,var(--color-gh-accent)15%,transparent)}}.bg-gh-accent\/20{background-color:#1f6feb33}@supports (color:color-mix(in lab,red,red)){.bg-gh-accent\/20{background-color:color-mix(in oklab,var(--color-gh-accent)20%,transparent)}}.bg-gh-bg{background-color:var(--color-gh-bg)}.bg-gh-bg-secondary{background-color:var(--color-gh-bg-secondary)}.bg-gh-border{background-color:var(--color-gh-border)}.bg-gh-border-subtle{background-color:var(--color-gh-border-subtle)}.bg-gh-green{background-color:var(--color-gh-green)}.bg-gh-green\/15{background-color:#23863626}@supports (color:color-mix(in lab,red,red)){.bg-gh-green\/15{background-color:color-mix(in oklab,var(--color-gh-green)15%,transparent)}}.bg-gh-red{background-color:var(--color-gh-red)}.bg-purple-500\/15{background-color:#ac4bff26}@supports (color:color-mix(in lab,red,red)){.bg-purple-500\/15{background-color:color-mix(in oklab,var(--color-purple-500)15%,transparent)}}.bg-transparent{background-color:#0000}.bg-violet-500\/10{background-color:#8d54ff1a}@supports (color:color-mix(in lab,red,red)){.bg-violet-500\/10{background-color:color-mix(in oklab,var(--color-violet-500)10%,transparent)}}.bg-gradient-to-t{--tw-gradient-position:to top in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.p-0{padding:calc(var(--spacing)*0)}.p-1{padding:calc(var(--spacing)*1)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-8{padding:calc(var(--spacing)*8)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-px{padding-block:1px}.pr-2{padding-right:calc(var(--spacing)*2)}.pl-8{padding-left:calc(var(--spacing)*8)}.pl-\[calc\(2rem-3px\)\]{padding-left:calc(2rem - 3px)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-400{color:var(--color-amber-400)}.text-cyan-400{color:var(--color-cyan-400)}.text-gh-accent{color:var(--color-gh-accent)}.text-gh-text{color:var(--color-gh-text)}.text-gh-text-secondary{color:var(--color-gh-text-secondary)}.text-gh-text-secondary\/70{color:#8b949eb3}@supports (color:color-mix(in lab,red,red)){.text-gh-text-secondary\/70{color:color-mix(in oklab,var(--color-gh-text-secondary)70%,transparent)}}.text-purple-400{color:var(--color-purple-400)}.text-violet-400{color:var(--color-violet-400)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.opacity-0{opacity:0}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:hidden:is(:where(.group):hover *){display:none}.group-hover\:inline:is(:where(.group):hover *){display:inline}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:border-gh-text-secondary:hover{border-color:var(--color-gh-text-secondary)}.hover\:bg-gh-accent\/20:hover{background-color:#1f6feb33}@supports (color:color-mix(in lab,red,red)){.hover\:bg-gh-accent\/20:hover{background-color:color-mix(in oklab,var(--color-gh-accent)20%,transparent)}}.hover\:bg-gh-border:hover{background-color:var(--color-gh-border)}.hover\:bg-gh-border-subtle:hover{background-color:var(--color-gh-border-subtle)}.hover\:bg-gh-red\/20:hover{background-color:#f8514933}@supports (color:color-mix(in lab,red,red)){.hover\:bg-gh-red\/20:hover{background-color:color-mix(in oklab,var(--color-gh-red)20%,transparent)}}.hover\:bg-red-700:hover{background-color:var(--color-red-700)}.hover\:underline:hover{text-decoration-line:underline}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}}.message-content{word-break:break-word}.message-content p{margin:.5em 0}.message-content p:first-child{margin-top:0}.message-content p:last-child{margin-bottom:0}.message-content code{background:var(--color-gh-border-subtle);border-radius:4px;padding:.15em .4em;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.9em}.message-content pre{background:var(--color-gh-bg);border:1px solid var(--color-gh-border);border-radius:6px;margin:.75em 0;padding:1em;overflow-x:auto}.message-content pre code{background:0 0;border-radius:0;padding:0}.message-content ul,.message-content ol{margin:.5em 0;padding-left:1.5em}.message-content li{margin:.25em 0}.message-content blockquote{border-left:3px solid var(--color-gh-border);color:var(--color-gh-text-secondary);margin:.5em 0;padding-left:1em}.message-content a{color:var(--color-gh-accent);text-decoration:none}.message-content a:hover{text-decoration:underline}.message-content strong{font-weight:600}.message-content h1,.message-content h2,.message-content h3,.message-content h4,.message-content h5,.message-content h6{margin:.75em 0 .5em;font-weight:600}.message-content h1:first-child,.message-content h2:first-child,.message-content h3:first-child{margin-top:0}.message-content hr{border:none;border-top:1px solid var(--color-gh-border);margin:1em 0}.message-content table{border-collapse:collapse;width:100%;margin:.5em 0}.message-content th,.message-content td{border:1px solid var(--color-gh-border);padding:.5em}.message-content th{background:var(--color-gh-bg-secondary);font-weight:600}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}
|
|
Binary file
|
|
Binary file
|