@claude-sessions/web 0.4.1 → 0.4.2-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/client/_app/immutable/assets/0.D2FnNtrO.css +1 -0
- package/build/client/_app/immutable/assets/0.D2FnNtrO.css.br +0 -0
- package/build/client/_app/immutable/assets/0.D2FnNtrO.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BRMlZq2r.js +1 -0
- package/build/client/_app/immutable/chunks/BRMlZq2r.js.br +0 -0
- package/build/client/_app/immutable/chunks/BRMlZq2r.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BUqdiQ8V.js +90 -0
- package/build/client/_app/immutable/chunks/BUqdiQ8V.js.br +0 -0
- package/build/client/_app/immutable/chunks/BUqdiQ8V.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{D49tNEXH.js → wR6tcHqD.js} +1 -1
- package/build/client/_app/immutable/chunks/wR6tcHqD.js.br +0 -0
- package/build/client/_app/immutable/chunks/wR6tcHqD.js.gz +0 -0
- package/build/client/_app/immutable/entry/{app.Btq_bE7X.js → app.BIf927Xy.js} +2 -2
- package/build/client/_app/immutable/entry/app.BIf927Xy.js.br +0 -0
- package/build/client/_app/immutable/entry/app.BIf927Xy.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.ChLZh9N7.js +1 -0
- package/build/client/_app/immutable/entry/start.ChLZh9N7.js.br +2 -0
- package/build/client/_app/immutable/entry/start.ChLZh9N7.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{0.CjrUlXhs.js → 0.DKYfg-8s.js} +1 -1
- package/build/client/_app/immutable/nodes/0.DKYfg-8s.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.DKYfg-8s.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.C_mir9rr.js → 1.zZICpoUK.js} +1 -1
- package/build/client/_app/immutable/nodes/1.zZICpoUK.js.br +2 -0
- package/build/client/_app/immutable/nodes/1.zZICpoUK.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.5x79czX-.js +4 -0
- package/build/client/_app/immutable/nodes/2.5x79czX-.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.5x79czX-.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.Drt04u7Q.js +4 -0
- package/build/client/_app/immutable/nodes/3.Drt04u7Q.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.Drt04u7Q.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/{0-_4Y5P6Pu.js → 0-Bpz08Uhs.js} +4 -4
- package/build/server/chunks/{0-_4Y5P6Pu.js.map → 0-Bpz08Uhs.js.map} +1 -1
- package/build/server/chunks/{1-BFEz-9-0.js → 1-BjgZlhLm.js} +2 -2
- package/build/server/chunks/{1-BFEz-9-0.js.map → 1-BjgZlhLm.js.map} +1 -1
- package/build/server/chunks/{2-BJBIDU_y.js → 2-Bvyspg6i.js} +3 -3
- package/build/server/chunks/{2-BJBIDU_y.js.map → 2-Bvyspg6i.js.map} +1 -1
- package/build/server/chunks/{3-fx1FyCiP.js → 3-BpYq9koE.js} +3 -3
- package/build/server/chunks/{3-fx1FyCiP.js.map → 3-BpYq9koE.js.map} +1 -1
- package/build/server/chunks/{Toast-Crka3UoV.js → Toast-Dr8M-5Wk.js} +2 -2
- package/build/server/chunks/{Toast-Crka3UoV.js.map → Toast-Dr8M-5Wk.js.map} +1 -1
- package/build/server/chunks/{_layout.svelte-IUZv8Y-p.js → _layout.svelte-CkIsNl4s.js} +3 -3
- package/build/server/chunks/{_layout.svelte-IUZv8Y-p.js.map → _layout.svelte-CkIsNl4s.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-Hxh7dTyf.js → _page.svelte-BdKbLK1W.js} +3 -3
- package/build/server/chunks/{_page.svelte-Hxh7dTyf.js.map → _page.svelte-BdKbLK1W.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-CVZlXeAH.js → _page.svelte-DWKQDFXZ.js} +83 -56
- package/build/server/chunks/_page.svelte-DWKQDFXZ.js.map +1 -0
- package/build/server/chunks/{_server.ts-kaRz-iNE.js → _server.ts-8OBR5eCA.js} +2 -2
- package/build/server/chunks/{_server.ts-kaRz-iNE.js.map → _server.ts-8OBR5eCA.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BDo-cBep.js → _server.ts-B4SnxrOX.js} +2 -2
- package/build/server/chunks/{_server.ts-BDo-cBep.js.map → _server.ts-B4SnxrOX.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B_tHvJuE.js → _server.ts-B9gP-Tri.js} +6 -3
- package/build/server/chunks/_server.ts-B9gP-Tri.js.map +1 -0
- package/build/server/chunks/{_server.ts-Cyd5L7R7.js → _server.ts-BQxGBeCg.js} +2 -2
- package/build/server/chunks/{_server.ts-Cyd5L7R7.js.map → _server.ts-BQxGBeCg.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CYy3E-wy.js → _server.ts-Bcdjougg.js} +2 -2
- package/build/server/chunks/{_server.ts-CYy3E-wy.js.map → _server.ts-Bcdjougg.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Dm4cFvT_.js → _server.ts-BeWDhgJ_.js} +2 -2
- package/build/server/chunks/{_server.ts-Dm4cFvT_.js.map → _server.ts-BeWDhgJ_.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CwCozCTU.js → _server.ts-CEGd9zNn.js} +2 -2
- package/build/server/chunks/{_server.ts-CwCozCTU.js.map → _server.ts-CEGd9zNn.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B1VENOjw.js → _server.ts-CMsFINkl.js} +2 -2
- package/build/server/chunks/{_server.ts-B1VENOjw.js.map → _server.ts-CMsFINkl.js.map} +1 -1
- package/build/server/chunks/{_server.ts-D_nsNW3s.js → _server.ts-CUginV8c.js} +2 -2
- package/build/server/chunks/{_server.ts-D_nsNW3s.js.map → _server.ts-CUginV8c.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B7mAMmzV.js → _server.ts-Crip_Csr.js} +2 -2
- package/build/server/chunks/{_server.ts-B7mAMmzV.js.map → _server.ts-Crip_Csr.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B3x7amtu.js → _server.ts-CuAlKvWH.js} +2 -2
- package/build/server/chunks/{_server.ts-B3x7amtu.js.map → _server.ts-CuAlKvWH.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BEMET_M9.js → _server.ts-DfNIRtb5.js} +2 -2
- package/build/server/chunks/{_server.ts-BEMET_M9.js.map → _server.ts-DfNIRtb5.js.map} +1 -1
- package/build/server/chunks/{_server.ts-X0UsKGpZ.js → _server.ts-DnfpkUoI.js} +2 -2
- package/build/server/chunks/{_server.ts-X0UsKGpZ.js.map → _server.ts-DnfpkUoI.js.map} +1 -1
- package/build/server/chunks/{_server.ts-SM5kuocx.js → _server.ts-dXxEqPlK.js} +2 -2
- package/build/server/chunks/{_server.ts-SM5kuocx.js.map → _server.ts-dXxEqPlK.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Cn3u85fU.js → _server.ts-sXXQUi2v.js} +3 -3
- package/build/server/chunks/_server.ts-sXXQUi2v.js.map +1 -0
- package/build/server/chunks/{index3-CcQtlmu9.js → index3-D8wHvUHX.js} +364 -327
- package/build/server/chunks/index3-D8wHvUHX.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +20 -20
- package/build/server/manifest.js.map +1 -1
- package/package.json +2 -2
- package/build/client/_app/immutable/assets/0.B02QGPuL.css +0 -1
- package/build/client/_app/immutable/assets/0.B02QGPuL.css.br +0 -0
- package/build/client/_app/immutable/assets/0.B02QGPuL.css.gz +0 -0
- package/build/client/_app/immutable/chunks/D49tNEXH.js.br +0 -0
- package/build/client/_app/immutable/chunks/D49tNEXH.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DVh32r5c.js +0 -90
- package/build/client/_app/immutable/chunks/DVh32r5c.js.br +0 -0
- package/build/client/_app/immutable/chunks/DVh32r5c.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dzg_BFdu.js +0 -1
- package/build/client/_app/immutable/chunks/Dzg_BFdu.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dzg_BFdu.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.Btq_bE7X.js.br +0 -0
- package/build/client/_app/immutable/entry/app.Btq_bE7X.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.DiKqSoAN.js +0 -1
- package/build/client/_app/immutable/entry/start.DiKqSoAN.js.br +0 -2
- package/build/client/_app/immutable/entry/start.DiKqSoAN.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.CjrUlXhs.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.CjrUlXhs.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.C_mir9rr.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.C_mir9rr.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.C1TvKf9x.js +0 -4
- package/build/client/_app/immutable/nodes/2.C1TvKf9x.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.C1TvKf9x.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.C4KCGMhg.js +0 -4
- package/build/client/_app/immutable/nodes/3.C4KCGMhg.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.C4KCGMhg.js.gz +0 -0
- package/build/server/chunks/_page.svelte-CVZlXeAH.js.map +0 -1
- package/build/server/chunks/_server.ts-B_tHvJuE.js.map +0 -1
- package/build/server/chunks/_server.ts-Cn3u85fU.js.map +0 -1
- package/build/server/chunks/index3-CcQtlmu9.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as fs2 from 'fs';
|
|
2
2
|
import * as os from 'os';
|
|
3
3
|
import * as path5 from 'path';
|
|
4
4
|
import { Effect, pipe, Array as Array$1, Option } from 'effect';
|
|
5
|
-
import * as
|
|
5
|
+
import * as fs6 from 'fs/promises';
|
|
6
6
|
import * as crypto from 'crypto';
|
|
7
7
|
|
|
8
8
|
var consoleLogger = {
|
|
@@ -18,109 +18,6 @@ var createLogger = (namespace) => ({
|
|
|
18
18
|
warn: (msg, ...args) => currentLogger.warn(`[${namespace}] ${msg}`, ...args),
|
|
19
19
|
error: (msg, ...args) => currentLogger.error(`[${namespace}] ${msg}`, ...args)
|
|
20
20
|
});
|
|
21
|
-
var log = createLogger("paths");
|
|
22
|
-
var getSessionsDir = () => process.env.CLAUDE_SESSIONS_DIR || path5.join(os.homedir(), ".claude", "projects");
|
|
23
|
-
var getTodosDir = () => path5.join(os.homedir(), ".claude", "todos");
|
|
24
|
-
var extractCwdFromContent = (content) => {
|
|
25
|
-
const lines = content.split("\n").filter((l) => l.trim());
|
|
26
|
-
for (const line of lines) {
|
|
27
|
-
try {
|
|
28
|
-
const parsed = JSON.parse(line);
|
|
29
|
-
if (parsed?.cwd) {
|
|
30
|
-
return parsed.cwd;
|
|
31
|
-
}
|
|
32
|
-
} catch {
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return null;
|
|
36
|
-
};
|
|
37
|
-
var isSessionFile = (filename) => filename.endsWith(".jsonl") && !filename.startsWith("agent-");
|
|
38
|
-
var toRelativePath = (absolutePath, homeDir) => {
|
|
39
|
-
const normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
40
|
-
const normalizedHome = homeDir.replace(/\\/g, "/");
|
|
41
|
-
if (normalizedPath === normalizedHome) {
|
|
42
|
-
return "~";
|
|
43
|
-
}
|
|
44
|
-
if (normalizedPath.startsWith(normalizedHome + "/")) {
|
|
45
|
-
return "~" + normalizedPath.slice(normalizedHome.length);
|
|
46
|
-
}
|
|
47
|
-
return absolutePath;
|
|
48
|
-
};
|
|
49
|
-
var folderNameToDisplayPath = (folderName) => {
|
|
50
|
-
const windowsDriveMatch = folderName.match(/^([A-Za-z])--/);
|
|
51
|
-
if (windowsDriveMatch) {
|
|
52
|
-
const driveLetter = windowsDriveMatch[1];
|
|
53
|
-
const rest = folderName.slice(3);
|
|
54
|
-
return driveLetter + ":\\" + rest.replace(/--/g, "\\.").replace(/-/g, "\\");
|
|
55
|
-
}
|
|
56
|
-
return folderName.replace(/^-/, "/").replace(/--/g, "/.").replace(/-/g, "/");
|
|
57
|
-
};
|
|
58
|
-
var pathToFolderName = (absolutePath) => {
|
|
59
|
-
const convertNonAscii = (str) => [...str].map((char) => char.charCodeAt(0) <= 127 ? char : "-").join("");
|
|
60
|
-
const windowsDriveMatch = absolutePath.match(/^([A-Za-z]):[/\\]/);
|
|
61
|
-
if (windowsDriveMatch) {
|
|
62
|
-
const driveLetter = windowsDriveMatch[1].toLowerCase();
|
|
63
|
-
const rest = absolutePath.slice(3);
|
|
64
|
-
return driveLetter + "--" + convertNonAscii(rest).replace(/[/\\]\./g, "--").replace(/[/\\]/g, "-").replace(/\./g, "-");
|
|
65
|
-
}
|
|
66
|
-
return convertNonAscii(absolutePath).replace(/^\//g, "-").replace(/\/\./g, "--").replace(/\//g, "-").replace(/\./g, "-");
|
|
67
|
-
};
|
|
68
|
-
var tryGetCwdFromFile = (filePath, fileSystem = fs, logger2 = log) => {
|
|
69
|
-
const basename3 = path5.basename(filePath);
|
|
70
|
-
try {
|
|
71
|
-
const content = fileSystem.readFileSync(filePath, "utf-8");
|
|
72
|
-
const cwd = extractCwdFromContent(content);
|
|
73
|
-
if (cwd === null) {
|
|
74
|
-
const lines = content.split("\n").filter((l) => l.trim());
|
|
75
|
-
if (lines.length === 0) {
|
|
76
|
-
logger2.debug(`tryGetCwdFromFile: ${basename3} -> empty file`);
|
|
77
|
-
} else {
|
|
78
|
-
logger2.debug(`tryGetCwdFromFile: ${basename3} -> no cwd found in ${lines.length} lines`);
|
|
79
|
-
}
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
return cwd;
|
|
83
|
-
} catch (e) {
|
|
84
|
-
logger2.warn(`tryGetCwdFromFile: ${basename3} -> read error: ${e}`);
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
var getRealPathFromSession = (folderName, sessionsDir = getSessionsDir(), fileSystem = fs, logger2 = log) => {
|
|
89
|
-
const projectDir = path5.join(sessionsDir, folderName);
|
|
90
|
-
try {
|
|
91
|
-
const files = fileSystem.readdirSync(projectDir).filter(isSessionFile);
|
|
92
|
-
const cwdList = [];
|
|
93
|
-
for (const f of files) {
|
|
94
|
-
const cwd = tryGetCwdFromFile(path5.join(projectDir, f), fileSystem, logger2);
|
|
95
|
-
if (cwd !== null) {
|
|
96
|
-
cwdList.push(cwd);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
const matched = cwdList.find((cwd) => pathToFolderName(cwd) === folderName);
|
|
100
|
-
if (matched) {
|
|
101
|
-
return matched;
|
|
102
|
-
}
|
|
103
|
-
if (cwdList.length > 0) {
|
|
104
|
-
logger2.warn(
|
|
105
|
-
`getRealPathFromSession: ${folderName} -> no match, cwds found: ${cwdList.join(", ")}`
|
|
106
|
-
);
|
|
107
|
-
} else {
|
|
108
|
-
logger2.warn(`getRealPathFromSession: ${folderName} -> no valid cwd in any session`);
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
} catch {
|
|
112
|
-
return null;
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
var folderNameToPath = (folderName) => {
|
|
116
|
-
const homeDir = os.homedir();
|
|
117
|
-
const realPath = getRealPathFromSession(folderName);
|
|
118
|
-
if (realPath) {
|
|
119
|
-
return toRelativePath(realPath, homeDir);
|
|
120
|
-
}
|
|
121
|
-
const absolutePath = folderNameToDisplayPath(folderName);
|
|
122
|
-
return toRelativePath(absolutePath, homeDir);
|
|
123
|
-
};
|
|
124
21
|
var logger = createLogger("utils");
|
|
125
22
|
var extractTextContent = (message) => {
|
|
126
23
|
if (!message) return "";
|
|
@@ -225,6 +122,135 @@ var maskHomePath = (text, homeDir) => {
|
|
|
225
122
|
const regex = new RegExp(`${escapedHome}(?=[/\\\\]|$)`, "g");
|
|
226
123
|
return text.replace(regex, "~");
|
|
227
124
|
};
|
|
125
|
+
var getSessionSortTimestamp = (session) => {
|
|
126
|
+
const timestampStr = session.summaries?.[0]?.timestamp ?? session.createdAt;
|
|
127
|
+
return timestampStr ? new Date(timestampStr).getTime() : 0;
|
|
128
|
+
};
|
|
129
|
+
var tryParseJsonLine = (line, lineNumber, filePath) => {
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(line);
|
|
132
|
+
} catch {
|
|
133
|
+
if (filePath) {
|
|
134
|
+
console.warn(`Skipping invalid JSON at line ${lineNumber} in ${filePath}`);
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var parseJsonlLines = (lines, filePath) => {
|
|
140
|
+
return lines.map((line, idx) => {
|
|
141
|
+
try {
|
|
142
|
+
return JSON.parse(line);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
const err = e;
|
|
145
|
+
throw new Error(`Failed to parse line ${idx + 1} in ${filePath}: ${err.message}`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
var readJsonlFile = (filePath) => Effect.gen(function* () {
|
|
150
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
|
|
151
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
152
|
+
return parseJsonlLines(lines, filePath);
|
|
153
|
+
});
|
|
154
|
+
var log = createLogger("paths");
|
|
155
|
+
var getSessionsDir = () => process.env.CLAUDE_SESSIONS_DIR || path5.join(os.homedir(), ".claude", "projects");
|
|
156
|
+
var getTodosDir = () => path5.join(os.homedir(), ".claude", "todos");
|
|
157
|
+
var extractCwdFromContent = (content, filePath) => {
|
|
158
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
159
|
+
for (let i = 0; i < lines.length; i++) {
|
|
160
|
+
const parsed = tryParseJsonLine(lines[i], i + 1, filePath);
|
|
161
|
+
if (parsed?.cwd) {
|
|
162
|
+
return parsed.cwd;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
};
|
|
167
|
+
var isSessionFile = (filename) => filename.endsWith(".jsonl") && !filename.startsWith("agent-");
|
|
168
|
+
var toRelativePath = (absolutePath, homeDir) => {
|
|
169
|
+
const normalizedPath = absolutePath.replace(/\\/g, "/");
|
|
170
|
+
const normalizedHome = homeDir.replace(/\\/g, "/");
|
|
171
|
+
if (normalizedPath === normalizedHome) {
|
|
172
|
+
return "~";
|
|
173
|
+
}
|
|
174
|
+
if (normalizedPath.startsWith(normalizedHome + "/")) {
|
|
175
|
+
return "~" + normalizedPath.slice(normalizedHome.length);
|
|
176
|
+
}
|
|
177
|
+
return absolutePath;
|
|
178
|
+
};
|
|
179
|
+
var folderNameToDisplayPath = (folderName) => {
|
|
180
|
+
const windowsDriveMatch = folderName.match(/^([A-Za-z])--/);
|
|
181
|
+
if (windowsDriveMatch) {
|
|
182
|
+
const driveLetter = windowsDriveMatch[1];
|
|
183
|
+
const rest = folderName.slice(3);
|
|
184
|
+
return driveLetter + ":\\" + rest.replace(/--/g, "\\.").replace(/-/g, "\\");
|
|
185
|
+
}
|
|
186
|
+
return folderName.replace(/^-/, "/").replace(/--/g, "/.").replace(/-/g, "/");
|
|
187
|
+
};
|
|
188
|
+
var pathToFolderName = (absolutePath) => {
|
|
189
|
+
const convertNonAscii = (str) => [...str].map((char) => char.charCodeAt(0) <= 127 ? char : "-").join("");
|
|
190
|
+
const windowsDriveMatch = absolutePath.match(/^([A-Za-z]):[/\\]/);
|
|
191
|
+
if (windowsDriveMatch) {
|
|
192
|
+
const driveLetter = windowsDriveMatch[1].toLowerCase();
|
|
193
|
+
const rest = absolutePath.slice(3);
|
|
194
|
+
return driveLetter + "--" + convertNonAscii(rest).replace(/[/\\]\./g, "--").replace(/[/\\]/g, "-").replace(/\./g, "-");
|
|
195
|
+
}
|
|
196
|
+
return convertNonAscii(absolutePath).replace(/^\//g, "-").replace(/\/\./g, "--").replace(/\//g, "-").replace(/\./g, "-");
|
|
197
|
+
};
|
|
198
|
+
var tryGetCwdFromFile = (filePath, fileSystem = fs2, logger2 = log) => {
|
|
199
|
+
const basename3 = path5.basename(filePath);
|
|
200
|
+
try {
|
|
201
|
+
const content = fileSystem.readFileSync(filePath, "utf-8");
|
|
202
|
+
const cwd = extractCwdFromContent(content);
|
|
203
|
+
if (cwd === null) {
|
|
204
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
205
|
+
if (lines.length === 0) {
|
|
206
|
+
logger2.debug(`tryGetCwdFromFile: ${basename3} -> empty file`);
|
|
207
|
+
} else {
|
|
208
|
+
logger2.debug(`tryGetCwdFromFile: ${basename3} -> no cwd found in ${lines.length} lines`);
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
return cwd;
|
|
213
|
+
} catch (e) {
|
|
214
|
+
logger2.warn(`tryGetCwdFromFile: ${basename3} -> read error: ${e}`);
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
var getRealPathFromSession = (folderName, sessionsDir = getSessionsDir(), fileSystem = fs2, logger2 = log) => {
|
|
219
|
+
const projectDir = path5.join(sessionsDir, folderName);
|
|
220
|
+
try {
|
|
221
|
+
const files = fileSystem.readdirSync(projectDir).filter(isSessionFile);
|
|
222
|
+
const cwdList = [];
|
|
223
|
+
for (const f of files) {
|
|
224
|
+
const cwd = tryGetCwdFromFile(path5.join(projectDir, f), fileSystem, logger2);
|
|
225
|
+
if (cwd !== null) {
|
|
226
|
+
cwdList.push(cwd);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const matched = cwdList.find((cwd) => pathToFolderName(cwd) === folderName);
|
|
230
|
+
if (matched) {
|
|
231
|
+
return matched;
|
|
232
|
+
}
|
|
233
|
+
if (cwdList.length > 0) {
|
|
234
|
+
logger2.warn(
|
|
235
|
+
`getRealPathFromSession: ${folderName} -> no match, cwds found: ${cwdList.join(", ")}`
|
|
236
|
+
);
|
|
237
|
+
} else {
|
|
238
|
+
logger2.warn(`getRealPathFromSession: ${folderName} -> no valid cwd in any session`);
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
} catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
var folderNameToPath = (folderName) => {
|
|
246
|
+
const homeDir = os.homedir();
|
|
247
|
+
const realPath = getRealPathFromSession(folderName);
|
|
248
|
+
if (realPath) {
|
|
249
|
+
return toRelativePath(realPath, homeDir);
|
|
250
|
+
}
|
|
251
|
+
const absolutePath = folderNameToDisplayPath(folderName);
|
|
252
|
+
return toRelativePath(absolutePath, homeDir);
|
|
253
|
+
};
|
|
228
254
|
var sortProjects = (projects, options = {}) => {
|
|
229
255
|
const { currentProjectName, homeDir, filterEmpty = true } = options;
|
|
230
256
|
const filtered = filterEmpty ? projects.filter((p) => p.sessionCount > 0) : projects;
|
|
@@ -243,18 +269,14 @@ var sortProjects = (projects, options = {}) => {
|
|
|
243
269
|
return a.displayName.localeCompare(b.displayName);
|
|
244
270
|
});
|
|
245
271
|
};
|
|
246
|
-
var getSessionSortTimestamp = (session) => {
|
|
247
|
-
const timestampStr = session.summaries?.[0]?.timestamp ?? session.createdAt;
|
|
248
|
-
return timestampStr ? new Date(timestampStr).getTime() : 0;
|
|
249
|
-
};
|
|
250
272
|
var findLinkedAgents = (projectName, sessionId) => Effect.gen(function* () {
|
|
251
273
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
252
|
-
const files = yield* Effect.tryPromise(() =>
|
|
274
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
253
275
|
const agentFiles = files.filter((f) => f.startsWith("agent-") && f.endsWith(".jsonl"));
|
|
254
276
|
const linkedAgents = [];
|
|
255
277
|
for (const agentFile of agentFiles) {
|
|
256
278
|
const filePath = path5.join(projectPath, agentFile);
|
|
257
|
-
const content = yield* Effect.tryPromise(() =>
|
|
279
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
|
|
258
280
|
const firstLine = content.split("\n")[0];
|
|
259
281
|
if (firstLine) {
|
|
260
282
|
try {
|
|
@@ -270,14 +292,14 @@ var findLinkedAgents = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
270
292
|
});
|
|
271
293
|
var findOrphanAgentsWithPaths = (projectName) => Effect.gen(function* () {
|
|
272
294
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
273
|
-
const files = yield* Effect.tryPromise(() =>
|
|
295
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
274
296
|
const sessionIds = new Set(
|
|
275
297
|
files.filter((f) => !f.startsWith("agent-") && f.endsWith(".jsonl")).map((f) => f.replace(".jsonl", ""))
|
|
276
298
|
);
|
|
277
299
|
const orphanAgents = [];
|
|
278
300
|
const checkAgentFile = async (filePath) => {
|
|
279
301
|
try {
|
|
280
|
-
const content = await
|
|
302
|
+
const content = await fs6.readFile(filePath, "utf-8");
|
|
281
303
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
282
304
|
const firstLine = lines[0];
|
|
283
305
|
if (!firstLine) return null;
|
|
@@ -304,15 +326,15 @@ var findOrphanAgentsWithPaths = (projectName) => Effect.gen(function* () {
|
|
|
304
326
|
}
|
|
305
327
|
for (const entry of files) {
|
|
306
328
|
const entryPath = path5.join(projectPath, entry);
|
|
307
|
-
const stat4 = yield* Effect.tryPromise(() =>
|
|
329
|
+
const stat4 = yield* Effect.tryPromise(() => fs6.stat(entryPath).catch(() => null));
|
|
308
330
|
if (stat4?.isDirectory() && !entry.startsWith(".")) {
|
|
309
331
|
const subagentsPath = path5.join(entryPath, "subagents");
|
|
310
332
|
const subagentsExists = yield* Effect.tryPromise(
|
|
311
|
-
() =>
|
|
333
|
+
() => fs6.stat(subagentsPath).then(() => true).catch(() => false)
|
|
312
334
|
);
|
|
313
335
|
if (subagentsExists) {
|
|
314
336
|
const subagentFiles = yield* Effect.tryPromise(
|
|
315
|
-
() =>
|
|
337
|
+
() => fs6.readdir(subagentsPath).catch(() => [])
|
|
316
338
|
);
|
|
317
339
|
for (const subagentFile of subagentFiles) {
|
|
318
340
|
if (subagentFile.startsWith("agent-") && subagentFile.endsWith(".jsonl")) {
|
|
@@ -346,35 +368,35 @@ var deleteOrphanAgents = (projectName) => Effect.gen(function* () {
|
|
|
346
368
|
foldersToCheck.add(parentDir);
|
|
347
369
|
}
|
|
348
370
|
if (orphan.lineCount <= 2) {
|
|
349
|
-
yield* Effect.tryPromise(() =>
|
|
371
|
+
yield* Effect.tryPromise(() => fs6.unlink(orphan.filePath));
|
|
350
372
|
deletedAgents.push(orphan.agentId);
|
|
351
373
|
} else {
|
|
352
374
|
if (!backupDirCreated) {
|
|
353
375
|
const backupDir2 = path5.join(projectPath, ".bak");
|
|
354
|
-
yield* Effect.tryPromise(() =>
|
|
376
|
+
yield* Effect.tryPromise(() => fs6.mkdir(backupDir2, { recursive: true }));
|
|
355
377
|
backupDirCreated = true;
|
|
356
378
|
}
|
|
357
379
|
const backupDir = path5.join(projectPath, ".bak");
|
|
358
380
|
const agentBackupPath = path5.join(backupDir, `${orphan.agentId}.jsonl`);
|
|
359
|
-
yield* Effect.tryPromise(() =>
|
|
381
|
+
yield* Effect.tryPromise(() => fs6.rename(orphan.filePath, agentBackupPath));
|
|
360
382
|
backedUpAgents.push(orphan.agentId);
|
|
361
383
|
}
|
|
362
384
|
}
|
|
363
385
|
for (const subagentsDir of foldersToCheck) {
|
|
364
386
|
const isEmpty = yield* Effect.tryPromise(async () => {
|
|
365
|
-
const files = await
|
|
387
|
+
const files = await fs6.readdir(subagentsDir);
|
|
366
388
|
return files.length === 0;
|
|
367
389
|
});
|
|
368
390
|
if (isEmpty) {
|
|
369
|
-
yield* Effect.tryPromise(() =>
|
|
391
|
+
yield* Effect.tryPromise(() => fs6.rmdir(subagentsDir));
|
|
370
392
|
cleanedFolders.push(subagentsDir);
|
|
371
393
|
const sessionDir = path5.dirname(subagentsDir);
|
|
372
394
|
const sessionDirEmpty = yield* Effect.tryPromise(async () => {
|
|
373
|
-
const files = await
|
|
395
|
+
const files = await fs6.readdir(sessionDir);
|
|
374
396
|
return files.length === 0;
|
|
375
397
|
});
|
|
376
398
|
if (sessionDirEmpty) {
|
|
377
|
-
yield* Effect.tryPromise(() =>
|
|
399
|
+
yield* Effect.tryPromise(() => fs6.rmdir(sessionDir));
|
|
378
400
|
cleanedFolders.push(sessionDir);
|
|
379
401
|
}
|
|
380
402
|
}
|
|
@@ -393,42 +415,45 @@ var deleteOrphanAgents = (projectName) => Effect.gen(function* () {
|
|
|
393
415
|
var loadAgentMessages = (projectName, _sessionId, agentId) => Effect.gen(function* () {
|
|
394
416
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
395
417
|
const agentFilePath = path5.join(projectPath, `${agentId}.jsonl`);
|
|
396
|
-
const content = yield* Effect.tryPromise(() =>
|
|
418
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(agentFilePath, "utf-8"));
|
|
397
419
|
const lines = content.split("\n").filter((line) => line.trim());
|
|
398
420
|
const messages = [];
|
|
399
|
-
for (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
messages.push(parsed);
|
|
406
|
-
} catch {
|
|
421
|
+
for (let i = 0; i < lines.length; i++) {
|
|
422
|
+
const parsed = tryParseJsonLine(lines[i], i + 1, agentFilePath);
|
|
423
|
+
if (!parsed) continue;
|
|
424
|
+
if ("sessionId" in parsed && !("type" in parsed)) {
|
|
425
|
+
continue;
|
|
407
426
|
}
|
|
427
|
+
messages.push(parsed);
|
|
408
428
|
}
|
|
409
429
|
return messages;
|
|
410
430
|
});
|
|
411
431
|
var findLinkedTodos = (sessionId, agentIds = []) => Effect.gen(function* () {
|
|
412
432
|
const todosDir = getTodosDir();
|
|
413
433
|
const exists = yield* Effect.tryPromise(
|
|
414
|
-
() =>
|
|
434
|
+
() => fs6.access(todosDir).then(() => true).catch(() => false)
|
|
415
435
|
);
|
|
416
436
|
if (!exists) {
|
|
417
|
-
return
|
|
437
|
+
return {
|
|
438
|
+
sessionId,
|
|
439
|
+
sessionTodos: [],
|
|
440
|
+
agentTodos: [],
|
|
441
|
+
hasTodos: false
|
|
442
|
+
};
|
|
418
443
|
}
|
|
419
444
|
const sessionTodoPath = path5.join(todosDir, `${sessionId}.json`);
|
|
420
445
|
let sessionTodos = [];
|
|
421
446
|
const sessionTodoExists = yield* Effect.tryPromise(
|
|
422
|
-
() =>
|
|
447
|
+
() => fs6.access(sessionTodoPath).then(() => true).catch(() => false)
|
|
423
448
|
);
|
|
424
449
|
if (sessionTodoExists) {
|
|
425
|
-
const content = yield* Effect.tryPromise(() =>
|
|
450
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(sessionTodoPath, "utf-8"));
|
|
426
451
|
try {
|
|
427
452
|
sessionTodos = JSON.parse(content);
|
|
428
453
|
} catch {
|
|
429
454
|
}
|
|
430
455
|
}
|
|
431
|
-
const allFiles = yield* Effect.tryPromise(() =>
|
|
456
|
+
const allFiles = yield* Effect.tryPromise(() => fs6.readdir(todosDir));
|
|
432
457
|
const agentTodoPattern = new RegExp(`^${sessionId}-agent-([a-f0-9-]+)\\.json$`);
|
|
433
458
|
const discoveredAgentIds = new Set(agentIds);
|
|
434
459
|
for (const file of allFiles) {
|
|
@@ -442,10 +467,10 @@ var findLinkedTodos = (sessionId, agentIds = []) => Effect.gen(function* () {
|
|
|
442
467
|
const shortAgentId = agentId.replace("agent-", "");
|
|
443
468
|
const agentTodoPath = path5.join(todosDir, `${sessionId}-agent-${shortAgentId}.json`);
|
|
444
469
|
const agentTodoExists = yield* Effect.tryPromise(
|
|
445
|
-
() =>
|
|
470
|
+
() => fs6.access(agentTodoPath).then(() => true).catch(() => false)
|
|
446
471
|
);
|
|
447
472
|
if (agentTodoExists) {
|
|
448
|
-
const content = yield* Effect.tryPromise(() =>
|
|
473
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(agentTodoPath, "utf-8"));
|
|
449
474
|
try {
|
|
450
475
|
const todos = JSON.parse(content);
|
|
451
476
|
if (todos.length > 0) {
|
|
@@ -466,22 +491,22 @@ var findLinkedTodos = (sessionId, agentIds = []) => Effect.gen(function* () {
|
|
|
466
491
|
var sessionHasTodos = (sessionId, agentIds = []) => Effect.gen(function* () {
|
|
467
492
|
const todosDir = getTodosDir();
|
|
468
493
|
const exists = yield* Effect.tryPromise(
|
|
469
|
-
() =>
|
|
494
|
+
() => fs6.access(todosDir).then(() => true).catch(() => false)
|
|
470
495
|
);
|
|
471
496
|
if (!exists) return false;
|
|
472
497
|
const sessionTodoPath = path5.join(todosDir, `${sessionId}.json`);
|
|
473
498
|
const sessionTodoExists = yield* Effect.tryPromise(
|
|
474
|
-
() =>
|
|
499
|
+
() => fs6.access(sessionTodoPath).then(() => true).catch(() => false)
|
|
475
500
|
);
|
|
476
501
|
if (sessionTodoExists) {
|
|
477
|
-
const content = yield* Effect.tryPromise(() =>
|
|
502
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(sessionTodoPath, "utf-8"));
|
|
478
503
|
try {
|
|
479
504
|
const todos = JSON.parse(content);
|
|
480
505
|
if (todos.length > 0) return true;
|
|
481
506
|
} catch {
|
|
482
507
|
}
|
|
483
508
|
}
|
|
484
|
-
const allFiles = yield* Effect.tryPromise(() =>
|
|
509
|
+
const allFiles = yield* Effect.tryPromise(() => fs6.readdir(todosDir));
|
|
485
510
|
const agentTodoPattern = new RegExp(`^${sessionId}-agent-([a-f0-9-]+)\\.json$`);
|
|
486
511
|
const discoveredAgentIds = new Set(agentIds);
|
|
487
512
|
for (const file of allFiles) {
|
|
@@ -494,10 +519,10 @@ var sessionHasTodos = (sessionId, agentIds = []) => Effect.gen(function* () {
|
|
|
494
519
|
const shortAgentId = agentId.replace("agent-", "");
|
|
495
520
|
const agentTodoPath = path5.join(todosDir, `${sessionId}-agent-${shortAgentId}.json`);
|
|
496
521
|
const agentTodoExists = yield* Effect.tryPromise(
|
|
497
|
-
() =>
|
|
522
|
+
() => fs6.access(agentTodoPath).then(() => true).catch(() => false)
|
|
498
523
|
);
|
|
499
524
|
if (agentTodoExists) {
|
|
500
|
-
const content = yield* Effect.tryPromise(() =>
|
|
525
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(agentTodoPath, "utf-8"));
|
|
501
526
|
try {
|
|
502
527
|
const todos = JSON.parse(content);
|
|
503
528
|
if (todos.length > 0) return true;
|
|
@@ -510,30 +535,30 @@ var sessionHasTodos = (sessionId, agentIds = []) => Effect.gen(function* () {
|
|
|
510
535
|
var deleteLinkedTodos = (sessionId, agentIds) => Effect.gen(function* () {
|
|
511
536
|
const todosDir = getTodosDir();
|
|
512
537
|
const exists = yield* Effect.tryPromise(
|
|
513
|
-
() =>
|
|
538
|
+
() => fs6.access(todosDir).then(() => true).catch(() => false)
|
|
514
539
|
);
|
|
515
540
|
if (!exists) return { deletedCount: 0 };
|
|
516
541
|
const backupDir = path5.join(todosDir, ".bak");
|
|
517
|
-
yield* Effect.tryPromise(() =>
|
|
542
|
+
yield* Effect.tryPromise(() => fs6.mkdir(backupDir, { recursive: true }));
|
|
518
543
|
let deletedCount = 0;
|
|
519
544
|
const sessionTodoPath = path5.join(todosDir, `${sessionId}.json`);
|
|
520
545
|
const sessionTodoExists = yield* Effect.tryPromise(
|
|
521
|
-
() =>
|
|
546
|
+
() => fs6.access(sessionTodoPath).then(() => true).catch(() => false)
|
|
522
547
|
);
|
|
523
548
|
if (sessionTodoExists) {
|
|
524
549
|
const backupPath = path5.join(backupDir, `${sessionId}.json`);
|
|
525
|
-
yield* Effect.tryPromise(() =>
|
|
550
|
+
yield* Effect.tryPromise(() => fs6.rename(sessionTodoPath, backupPath));
|
|
526
551
|
deletedCount++;
|
|
527
552
|
}
|
|
528
553
|
for (const agentId of agentIds) {
|
|
529
554
|
const shortAgentId = agentId.replace("agent-", "");
|
|
530
555
|
const agentTodoPath = path5.join(todosDir, `${sessionId}-agent-${shortAgentId}.json`);
|
|
531
556
|
const agentTodoExists = yield* Effect.tryPromise(
|
|
532
|
-
() =>
|
|
557
|
+
() => fs6.access(agentTodoPath).then(() => true).catch(() => false)
|
|
533
558
|
);
|
|
534
559
|
if (agentTodoExists) {
|
|
535
560
|
const backupPath = path5.join(backupDir, `${sessionId}-agent-${shortAgentId}.json`);
|
|
536
|
-
yield* Effect.tryPromise(() =>
|
|
561
|
+
yield* Effect.tryPromise(() => fs6.rename(agentTodoPath, backupPath));
|
|
537
562
|
deletedCount++;
|
|
538
563
|
}
|
|
539
564
|
}
|
|
@@ -544,23 +569,23 @@ var findOrphanTodos = () => Effect.gen(function* () {
|
|
|
544
569
|
const sessionsDir = getSessionsDir();
|
|
545
570
|
const [todosExists, sessionsExists] = yield* Effect.all([
|
|
546
571
|
Effect.tryPromise(
|
|
547
|
-
() =>
|
|
572
|
+
() => fs6.access(todosDir).then(() => true).catch(() => false)
|
|
548
573
|
),
|
|
549
574
|
Effect.tryPromise(
|
|
550
|
-
() =>
|
|
575
|
+
() => fs6.access(sessionsDir).then(() => true).catch(() => false)
|
|
551
576
|
)
|
|
552
577
|
]);
|
|
553
578
|
if (!todosExists || !sessionsExists) return [];
|
|
554
|
-
const todoFiles = yield* Effect.tryPromise(() =>
|
|
579
|
+
const todoFiles = yield* Effect.tryPromise(() => fs6.readdir(todosDir));
|
|
555
580
|
const jsonFiles = todoFiles.filter((f) => f.endsWith(".json"));
|
|
556
581
|
const validSessionIds = /* @__PURE__ */ new Set();
|
|
557
582
|
const projectEntries = yield* Effect.tryPromise(
|
|
558
|
-
() =>
|
|
583
|
+
() => fs6.readdir(sessionsDir, { withFileTypes: true })
|
|
559
584
|
);
|
|
560
585
|
for (const entry of projectEntries) {
|
|
561
586
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
562
587
|
const projectPath = path5.join(sessionsDir, entry.name);
|
|
563
|
-
const files = yield* Effect.tryPromise(() =>
|
|
588
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
564
589
|
for (const f of files) {
|
|
565
590
|
if (f.endsWith(".jsonl") && !f.startsWith("agent-")) {
|
|
566
591
|
validSessionIds.add(f.replace(".jsonl", ""));
|
|
@@ -584,12 +609,12 @@ var deleteOrphanTodos = () => Effect.gen(function* () {
|
|
|
584
609
|
const orphans = yield* findOrphanTodos();
|
|
585
610
|
if (orphans.length === 0) return { success: true, deletedCount: 0 };
|
|
586
611
|
const backupDir = path5.join(todosDir, ".bak");
|
|
587
|
-
yield* Effect.tryPromise(() =>
|
|
612
|
+
yield* Effect.tryPromise(() => fs6.mkdir(backupDir, { recursive: true }));
|
|
588
613
|
let deletedCount = 0;
|
|
589
614
|
for (const orphan of orphans) {
|
|
590
615
|
const filePath = path5.join(todosDir, orphan);
|
|
591
616
|
const backupPath = path5.join(backupDir, orphan);
|
|
592
|
-
yield* Effect.tryPromise(() =>
|
|
617
|
+
yield* Effect.tryPromise(() => fs6.rename(filePath, backupPath));
|
|
593
618
|
deletedCount++;
|
|
594
619
|
}
|
|
595
620
|
return { success: true, deletedCount };
|
|
@@ -597,17 +622,17 @@ var deleteOrphanTodos = () => Effect.gen(function* () {
|
|
|
597
622
|
var listProjects = Effect.gen(function* () {
|
|
598
623
|
const sessionsDir = getSessionsDir();
|
|
599
624
|
const exists = yield* Effect.tryPromise(
|
|
600
|
-
() =>
|
|
625
|
+
() => fs6.access(sessionsDir).then(() => true).catch(() => false)
|
|
601
626
|
);
|
|
602
627
|
if (!exists) {
|
|
603
628
|
return [];
|
|
604
629
|
}
|
|
605
|
-
const entries = yield* Effect.tryPromise(() =>
|
|
630
|
+
const entries = yield* Effect.tryPromise(() => fs6.readdir(sessionsDir, { withFileTypes: true }));
|
|
606
631
|
const projects = yield* Effect.all(
|
|
607
632
|
entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map(
|
|
608
633
|
(entry) => Effect.gen(function* () {
|
|
609
634
|
const projectPath = path5.join(sessionsDir, entry.name);
|
|
610
|
-
const files = yield* Effect.tryPromise(() =>
|
|
635
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
611
636
|
const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
612
637
|
return {
|
|
613
638
|
name: entry.name,
|
|
@@ -623,7 +648,15 @@ var listProjects = Effect.gen(function* () {
|
|
|
623
648
|
});
|
|
624
649
|
function deleteMessageWithChainRepair(messages, targetId, targetType) {
|
|
625
650
|
let targetIndex = -1;
|
|
626
|
-
{
|
|
651
|
+
if (targetType === "file-history-snapshot") {
|
|
652
|
+
targetIndex = messages.findIndex(
|
|
653
|
+
(m) => m.type === "file-history-snapshot" && m.messageId === targetId
|
|
654
|
+
);
|
|
655
|
+
} else if (targetType === "summary") {
|
|
656
|
+
targetIndex = messages.findIndex(
|
|
657
|
+
(m) => m.leafUuid === targetId
|
|
658
|
+
);
|
|
659
|
+
} else {
|
|
627
660
|
targetIndex = messages.findIndex((m) => m.uuid === targetId);
|
|
628
661
|
if (targetIndex === -1) {
|
|
629
662
|
targetIndex = messages.findIndex(
|
|
@@ -690,15 +723,13 @@ function deleteMessageWithChainRepair(messages, targetId, targetType) {
|
|
|
690
723
|
}
|
|
691
724
|
var listSessions = (projectName) => Effect.gen(function* () {
|
|
692
725
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
693
|
-
const files = yield* Effect.tryPromise(() =>
|
|
726
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
694
727
|
const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
695
728
|
const sessions = yield* Effect.all(
|
|
696
729
|
sessionFiles.map(
|
|
697
730
|
(file) => Effect.gen(function* () {
|
|
698
731
|
const filePath = path5.join(projectPath, file);
|
|
699
|
-
const
|
|
700
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
701
|
-
const messages = lines.map((line) => JSON.parse(line));
|
|
732
|
+
const messages = yield* readJsonlFile(filePath);
|
|
702
733
|
const sessionId = file.replace(".jsonl", "");
|
|
703
734
|
const userAssistantMessages = messages.filter(
|
|
704
735
|
(m) => m.type === "user" || m.type === "assistant"
|
|
@@ -751,28 +782,22 @@ var listSessions = (projectName) => Effect.gen(function* () {
|
|
|
751
782
|
});
|
|
752
783
|
var readSession = (projectName, sessionId) => Effect.gen(function* () {
|
|
753
784
|
const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
|
|
754
|
-
|
|
755
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
756
|
-
return lines.map((line) => JSON.parse(line));
|
|
785
|
+
return yield* readJsonlFile(filePath);
|
|
757
786
|
});
|
|
758
787
|
var deleteMessage = (projectName, sessionId, messageUuid, targetType) => Effect.gen(function* () {
|
|
759
788
|
const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
|
|
760
|
-
const
|
|
761
|
-
const
|
|
762
|
-
const messages = lines.map((line) => JSON.parse(line));
|
|
763
|
-
const result = deleteMessageWithChainRepair(messages, messageUuid);
|
|
789
|
+
const messages = yield* readJsonlFile(filePath);
|
|
790
|
+
const result = deleteMessageWithChainRepair(messages, messageUuid, targetType);
|
|
764
791
|
if (!result.deleted) {
|
|
765
792
|
return { success: false, error: "Message not found" };
|
|
766
793
|
}
|
|
767
794
|
const newContent = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
768
|
-
yield* Effect.tryPromise(() =>
|
|
795
|
+
yield* Effect.tryPromise(() => fs6.writeFile(filePath, newContent, "utf-8"));
|
|
769
796
|
return { success: true, deletedMessage: result.deleted };
|
|
770
797
|
});
|
|
771
798
|
var restoreMessage = (projectName, sessionId, message, index) => Effect.gen(function* () {
|
|
772
799
|
const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
|
|
773
|
-
const
|
|
774
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
775
|
-
const messages = lines.map((line) => JSON.parse(line));
|
|
800
|
+
const messages = yield* readJsonlFile(filePath);
|
|
776
801
|
const msgUuid = message.uuid ?? message.messageId;
|
|
777
802
|
if (!msgUuid) {
|
|
778
803
|
return { success: false, error: "Message has no uuid or messageId" };
|
|
@@ -787,7 +812,7 @@ var restoreMessage = (projectName, sessionId, message, index) => Effect.gen(func
|
|
|
787
812
|
const insertIndex = Math.min(index, messages.length);
|
|
788
813
|
messages.splice(insertIndex, 0, message);
|
|
789
814
|
const newContent = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
790
|
-
yield* Effect.tryPromise(() =>
|
|
815
|
+
yield* Effect.tryPromise(() => fs6.writeFile(filePath, newContent, "utf-8"));
|
|
791
816
|
return { success: true };
|
|
792
817
|
});
|
|
793
818
|
var deleteSession = (projectName, sessionId) => Effect.gen(function* () {
|
|
@@ -795,33 +820,33 @@ var deleteSession = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
795
820
|
const projectPath = path5.join(sessionsDir, projectName);
|
|
796
821
|
const filePath = path5.join(projectPath, `${sessionId}.jsonl`);
|
|
797
822
|
const linkedAgents = yield* findLinkedAgents(projectName, sessionId);
|
|
798
|
-
const stat4 = yield* Effect.tryPromise(() =>
|
|
823
|
+
const stat4 = yield* Effect.tryPromise(() => fs6.stat(filePath));
|
|
799
824
|
if (stat4.size === 0) {
|
|
800
|
-
yield* Effect.tryPromise(() =>
|
|
825
|
+
yield* Effect.tryPromise(() => fs6.unlink(filePath));
|
|
801
826
|
const agentBackupDir2 = path5.join(projectPath, ".bak");
|
|
802
|
-
yield* Effect.tryPromise(() =>
|
|
827
|
+
yield* Effect.tryPromise(() => fs6.mkdir(agentBackupDir2, { recursive: true }));
|
|
803
828
|
for (const agentId of linkedAgents) {
|
|
804
829
|
const agentPath = path5.join(projectPath, `${agentId}.jsonl`);
|
|
805
830
|
const agentBackupPath = path5.join(agentBackupDir2, `${agentId}.jsonl`);
|
|
806
|
-
yield* Effect.tryPromise(() =>
|
|
831
|
+
yield* Effect.tryPromise(() => fs6.rename(agentPath, agentBackupPath).catch(() => {
|
|
807
832
|
}));
|
|
808
833
|
}
|
|
809
834
|
yield* deleteLinkedTodos(sessionId, linkedAgents);
|
|
810
835
|
return { success: true, deletedAgents: linkedAgents.length };
|
|
811
836
|
}
|
|
812
837
|
const backupDir = path5.join(sessionsDir, ".bak");
|
|
813
|
-
yield* Effect.tryPromise(() =>
|
|
838
|
+
yield* Effect.tryPromise(() => fs6.mkdir(backupDir, { recursive: true }));
|
|
814
839
|
const agentBackupDir = path5.join(projectPath, ".bak");
|
|
815
|
-
yield* Effect.tryPromise(() =>
|
|
840
|
+
yield* Effect.tryPromise(() => fs6.mkdir(agentBackupDir, { recursive: true }));
|
|
816
841
|
for (const agentId of linkedAgents) {
|
|
817
842
|
const agentPath = path5.join(projectPath, `${agentId}.jsonl`);
|
|
818
843
|
const agentBackupPath = path5.join(agentBackupDir, `${agentId}.jsonl`);
|
|
819
|
-
yield* Effect.tryPromise(() =>
|
|
844
|
+
yield* Effect.tryPromise(() => fs6.rename(agentPath, agentBackupPath).catch(() => {
|
|
820
845
|
}));
|
|
821
846
|
}
|
|
822
847
|
const todosResult = yield* deleteLinkedTodos(sessionId, linkedAgents);
|
|
823
848
|
const backupPath = path5.join(backupDir, `${projectName}_${sessionId}.jsonl`);
|
|
824
|
-
yield* Effect.tryPromise(() =>
|
|
849
|
+
yield* Effect.tryPromise(() => fs6.rename(filePath, backupPath));
|
|
825
850
|
return {
|
|
826
851
|
success: true,
|
|
827
852
|
backupPath,
|
|
@@ -832,12 +857,12 @@ var deleteSession = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
832
857
|
var renameSession = (projectName, sessionId, newTitle) => Effect.gen(function* () {
|
|
833
858
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
834
859
|
const filePath = path5.join(projectPath, `${sessionId}.jsonl`);
|
|
835
|
-
const content = yield* Effect.tryPromise(() =>
|
|
860
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
|
|
836
861
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
837
862
|
if (lines.length === 0) {
|
|
838
863
|
return { success: false, error: "Empty session" };
|
|
839
864
|
}
|
|
840
|
-
const messages = lines
|
|
865
|
+
const messages = parseJsonlLines(lines, filePath);
|
|
841
866
|
const sessionUuids = /* @__PURE__ */ new Set();
|
|
842
867
|
for (const msg of messages) {
|
|
843
868
|
if (msg.uuid && typeof msg.uuid === "string") {
|
|
@@ -856,16 +881,14 @@ var renameSession = (projectName, sessionId, newTitle) => Effect.gen(function* (
|
|
|
856
881
|
messages.unshift(customTitleRecord);
|
|
857
882
|
}
|
|
858
883
|
const newContent = messages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
859
|
-
yield* Effect.tryPromise(() =>
|
|
860
|
-
const projectFiles = yield* Effect.tryPromise(() =>
|
|
884
|
+
yield* Effect.tryPromise(() => fs6.writeFile(filePath, newContent, "utf-8"));
|
|
885
|
+
const projectFiles = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
861
886
|
const allJsonlFiles = projectFiles.filter((f) => f.endsWith(".jsonl"));
|
|
862
887
|
const summariesTargetingThis = [];
|
|
863
888
|
for (const file of allJsonlFiles) {
|
|
864
889
|
const otherFilePath = path5.join(projectPath, file);
|
|
865
890
|
try {
|
|
866
|
-
const
|
|
867
|
-
const otherLines = otherContent.trim().split("\n").filter(Boolean);
|
|
868
|
-
const otherMessages = otherLines.map((l) => JSON.parse(l));
|
|
891
|
+
const otherMessages = yield* readJsonlFile(otherFilePath);
|
|
869
892
|
for (let i = 0; i < otherMessages.length; i++) {
|
|
870
893
|
const msg = otherMessages[i];
|
|
871
894
|
if (msg.type === "summary" && typeof msg.leafUuid === "string" && sessionUuids.has(msg.leafUuid)) {
|
|
@@ -884,19 +907,15 @@ var renameSession = (projectName, sessionId, newTitle) => Effect.gen(function* (
|
|
|
884
907
|
summariesTargetingThis.sort((a, b) => (a.timestamp ?? "").localeCompare(b.timestamp ?? ""));
|
|
885
908
|
const firstSummary = summariesTargetingThis[0];
|
|
886
909
|
const summaryFilePath = path5.join(projectPath, firstSummary.file);
|
|
887
|
-
const
|
|
888
|
-
const summaryLines = summaryContent.trim().split("\n").filter(Boolean);
|
|
889
|
-
const summaryMessages = summaryLines.map((l) => JSON.parse(l));
|
|
910
|
+
const summaryMessages = yield* readJsonlFile(summaryFilePath);
|
|
890
911
|
summaryMessages[firstSummary.idx] = {
|
|
891
912
|
...summaryMessages[firstSummary.idx],
|
|
892
913
|
summary: newTitle
|
|
893
914
|
};
|
|
894
915
|
const newSummaryContent = summaryMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
895
|
-
yield* Effect.tryPromise(() =>
|
|
916
|
+
yield* Effect.tryPromise(() => fs6.writeFile(summaryFilePath, newSummaryContent, "utf-8"));
|
|
896
917
|
} else {
|
|
897
|
-
const
|
|
898
|
-
const currentLines = currentContent.trim().split("\n").filter(Boolean);
|
|
899
|
-
const currentMessages = currentLines.map((l) => JSON.parse(l));
|
|
918
|
+
const currentMessages = yield* readJsonlFile(filePath);
|
|
900
919
|
const firstUserIdx = currentMessages.findIndex((m) => m.type === "user");
|
|
901
920
|
if (firstUserIdx >= 0) {
|
|
902
921
|
const firstMsg = currentMessages[firstUserIdx];
|
|
@@ -913,7 +932,7 @@ var renameSession = (projectName, sessionId, newTitle) => Effect.gen(function* (
|
|
|
913
932
|
|
|
914
933
|
${cleanedText}`;
|
|
915
934
|
const updatedContent = currentMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
916
|
-
yield* Effect.tryPromise(() =>
|
|
935
|
+
yield* Effect.tryPromise(() => fs6.writeFile(filePath, updatedContent, "utf-8"));
|
|
917
936
|
}
|
|
918
937
|
}
|
|
919
938
|
}
|
|
@@ -927,28 +946,28 @@ var moveSession = (sourceProject, sessionId, targetProject) => Effect.gen(functi
|
|
|
927
946
|
const sourceFile = path5.join(sourcePath, `${sessionId}.jsonl`);
|
|
928
947
|
const targetFile = path5.join(targetPath, `${sessionId}.jsonl`);
|
|
929
948
|
const sourceExists = yield* Effect.tryPromise(
|
|
930
|
-
() =>
|
|
949
|
+
() => fs6.access(sourceFile).then(() => true).catch(() => false)
|
|
931
950
|
);
|
|
932
951
|
if (!sourceExists) {
|
|
933
952
|
return { success: false, error: "Source session not found" };
|
|
934
953
|
}
|
|
935
954
|
const targetExists = yield* Effect.tryPromise(
|
|
936
|
-
() =>
|
|
955
|
+
() => fs6.access(targetFile).then(() => true).catch(() => false)
|
|
937
956
|
);
|
|
938
957
|
if (targetExists) {
|
|
939
958
|
return { success: false, error: "Session already exists in target project" };
|
|
940
959
|
}
|
|
941
|
-
yield* Effect.tryPromise(() =>
|
|
960
|
+
yield* Effect.tryPromise(() => fs6.mkdir(targetPath, { recursive: true }));
|
|
942
961
|
const linkedAgents = yield* findLinkedAgents(sourceProject, sessionId);
|
|
943
|
-
yield* Effect.tryPromise(() =>
|
|
962
|
+
yield* Effect.tryPromise(() => fs6.rename(sourceFile, targetFile));
|
|
944
963
|
for (const agentId of linkedAgents) {
|
|
945
964
|
const sourceAgentFile = path5.join(sourcePath, `${agentId}.jsonl`);
|
|
946
965
|
const targetAgentFile = path5.join(targetPath, `${agentId}.jsonl`);
|
|
947
966
|
const agentExists = yield* Effect.tryPromise(
|
|
948
|
-
() =>
|
|
967
|
+
() => fs6.access(sourceAgentFile).then(() => true).catch(() => false)
|
|
949
968
|
);
|
|
950
969
|
if (agentExists) {
|
|
951
|
-
yield* Effect.tryPromise(() =>
|
|
970
|
+
yield* Effect.tryPromise(() => fs6.rename(sourceAgentFile, targetAgentFile));
|
|
952
971
|
}
|
|
953
972
|
}
|
|
954
973
|
return { success: true };
|
|
@@ -956,9 +975,7 @@ var moveSession = (sourceProject, sessionId, targetProject) => Effect.gen(functi
|
|
|
956
975
|
var splitSession = (projectName, sessionId, splitAtMessageUuid) => Effect.gen(function* () {
|
|
957
976
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
958
977
|
const filePath = path5.join(projectPath, `${sessionId}.jsonl`);
|
|
959
|
-
const
|
|
960
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
961
|
-
const allMessages = lines.map((line) => JSON.parse(line));
|
|
978
|
+
const allMessages = yield* readJsonlFile(filePath);
|
|
962
979
|
const splitIndex = allMessages.findIndex((m) => m.uuid === splitAtMessageUuid);
|
|
963
980
|
if (splitIndex === -1) {
|
|
964
981
|
return { success: false, error: "Message not found" };
|
|
@@ -1004,30 +1021,30 @@ var splitSession = (projectName, sessionId, splitAtMessageUuid) => Effect.gen(fu
|
|
|
1004
1021
|
updatedMovedMessages.unshift(clonedSummary);
|
|
1005
1022
|
}
|
|
1006
1023
|
const keptContent = keptMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
1007
|
-
yield* Effect.tryPromise(() =>
|
|
1024
|
+
yield* Effect.tryPromise(() => fs6.writeFile(filePath, keptContent, "utf-8"));
|
|
1008
1025
|
const newFilePath = path5.join(projectPath, `${newSessionId}.jsonl`);
|
|
1009
1026
|
const newContent = updatedMovedMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
1010
|
-
yield* Effect.tryPromise(() =>
|
|
1011
|
-
const agentFiles = yield* Effect.tryPromise(() =>
|
|
1027
|
+
yield* Effect.tryPromise(() => fs6.writeFile(newFilePath, newContent, "utf-8"));
|
|
1028
|
+
const agentFiles = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
1012
1029
|
const agentJsonlFiles = agentFiles.filter((f) => f.startsWith("agent-") && f.endsWith(".jsonl"));
|
|
1013
1030
|
for (const agentFile of agentJsonlFiles) {
|
|
1014
1031
|
const agentPath = path5.join(projectPath, agentFile);
|
|
1015
|
-
const agentContent = yield* Effect.tryPromise(() =>
|
|
1032
|
+
const agentContent = yield* Effect.tryPromise(() => fs6.readFile(agentPath, "utf-8"));
|
|
1016
1033
|
const agentLines = agentContent.trim().split("\n").filter(Boolean);
|
|
1017
1034
|
if (agentLines.length === 0) continue;
|
|
1018
|
-
const
|
|
1035
|
+
const agentMessages = parseJsonlLines(agentLines, agentPath);
|
|
1036
|
+
const firstAgentMsg = agentMessages[0];
|
|
1019
1037
|
if (firstAgentMsg.sessionId === sessionId) {
|
|
1020
1038
|
const agentId = agentFile.replace("agent-", "").replace(".jsonl", "");
|
|
1021
1039
|
const isRelatedToMoved = movedMessages.some(
|
|
1022
1040
|
(msg) => msg.agentId === agentId
|
|
1023
1041
|
);
|
|
1024
1042
|
if (isRelatedToMoved) {
|
|
1025
|
-
const updatedAgentMessages =
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
});
|
|
1043
|
+
const updatedAgentMessages = agentMessages.map(
|
|
1044
|
+
(msg) => JSON.stringify({ ...msg, sessionId: newSessionId })
|
|
1045
|
+
);
|
|
1029
1046
|
const updatedAgentContent = updatedAgentMessages.join("\n") + "\n";
|
|
1030
|
-
yield* Effect.tryPromise(() =>
|
|
1047
|
+
yield* Effect.tryPromise(() => fs6.writeFile(agentPath, updatedAgentContent, "utf-8"));
|
|
1031
1048
|
}
|
|
1032
1049
|
}
|
|
1033
1050
|
}
|
|
@@ -1080,9 +1097,9 @@ var sortSessions = (sessions, sort) => {
|
|
|
1080
1097
|
var loadSessionTreeDataInternal = (projectName, sessionId, summariesByTargetSession, fileMtime) => Effect.gen(function* () {
|
|
1081
1098
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
1082
1099
|
const filePath = path5.join(projectPath, `${sessionId}.jsonl`);
|
|
1083
|
-
const content = yield* Effect.tryPromise(() =>
|
|
1100
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
|
|
1084
1101
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
1085
|
-
const messages = lines
|
|
1102
|
+
const messages = parseJsonlLines(lines, filePath);
|
|
1086
1103
|
let summaries;
|
|
1087
1104
|
if (summariesByTargetSession) {
|
|
1088
1105
|
summaries = [...summariesByTargetSession.get(sessionId) ?? []].sort((a, b) => {
|
|
@@ -1098,26 +1115,24 @@ var loadSessionTreeDataInternal = (projectName, sessionId, summariesByTargetSess
|
|
|
1098
1115
|
sessionUuids.add(msg.uuid);
|
|
1099
1116
|
}
|
|
1100
1117
|
}
|
|
1101
|
-
const projectFiles = yield* Effect.tryPromise(() =>
|
|
1118
|
+
const projectFiles = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
1102
1119
|
const allJsonlFiles = projectFiles.filter((f) => f.endsWith(".jsonl"));
|
|
1103
1120
|
for (const file of allJsonlFiles) {
|
|
1104
1121
|
try {
|
|
1105
1122
|
const otherFilePath = path5.join(projectPath, file);
|
|
1106
|
-
const otherContent = yield* Effect.tryPromise(() =>
|
|
1123
|
+
const otherContent = yield* Effect.tryPromise(() => fs6.readFile(otherFilePath, "utf-8"));
|
|
1107
1124
|
const otherLines = otherContent.trim().split("\n").filter(Boolean);
|
|
1108
|
-
for (
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
}
|
|
1120
|
-
} catch {
|
|
1125
|
+
for (let i = 0; i < otherLines.length; i++) {
|
|
1126
|
+
const msg = tryParseJsonLine(otherLines[i], i + 1, otherFilePath);
|
|
1127
|
+
if (!msg) continue;
|
|
1128
|
+
if (msg.type === "summary" && typeof msg.summary === "string" && typeof msg.leafUuid === "string" && sessionUuids.has(msg.leafUuid)) {
|
|
1129
|
+
const targetMsg = messages.find((m) => m.uuid === msg.leafUuid);
|
|
1130
|
+
summaries.push({
|
|
1131
|
+
summary: msg.summary,
|
|
1132
|
+
leafUuid: msg.leafUuid,
|
|
1133
|
+
timestamp: targetMsg?.timestamp ?? msg.timestamp,
|
|
1134
|
+
sourceFile: file
|
|
1135
|
+
});
|
|
1121
1136
|
}
|
|
1122
1137
|
}
|
|
1123
1138
|
} catch {
|
|
@@ -1151,7 +1166,7 @@ var loadSessionTreeDataInternal = (projectName, sessionId, summariesByTargetSess
|
|
|
1151
1166
|
for (const agentId of linkedAgentIds) {
|
|
1152
1167
|
const agentPath = path5.join(projectPath, `${agentId}.jsonl`);
|
|
1153
1168
|
try {
|
|
1154
|
-
const agentContent = yield* Effect.tryPromise(() =>
|
|
1169
|
+
const agentContent = yield* Effect.tryPromise(() => fs6.readFile(agentPath, "utf-8"));
|
|
1155
1170
|
const agentLines = agentContent.trim().split("\n").filter(Boolean);
|
|
1156
1171
|
const agentMsgs = agentLines.map((l) => JSON.parse(l));
|
|
1157
1172
|
const agentUserAssistant = agentMsgs.filter(
|
|
@@ -1206,7 +1221,7 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
|
|
|
1206
1221
|
}
|
|
1207
1222
|
const sort = sortOptions ?? DEFAULT_SORT;
|
|
1208
1223
|
const projectPath = path5.join(getSessionsDir(), projectName);
|
|
1209
|
-
const files = yield* Effect.tryPromise(() =>
|
|
1224
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
1210
1225
|
const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
1211
1226
|
const fileMtimes = /* @__PURE__ */ new Map();
|
|
1212
1227
|
yield* Effect.all(
|
|
@@ -1214,7 +1229,7 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
|
|
|
1214
1229
|
(file) => Effect.gen(function* () {
|
|
1215
1230
|
const filePath = path5.join(projectPath, file);
|
|
1216
1231
|
try {
|
|
1217
|
-
const stat4 = yield* Effect.tryPromise(() =>
|
|
1232
|
+
const stat4 = yield* Effect.tryPromise(() => fs6.stat(filePath));
|
|
1218
1233
|
fileMtimes.set(file.replace(".jsonl", ""), stat4.mtimeMs);
|
|
1219
1234
|
} catch {
|
|
1220
1235
|
}
|
|
@@ -1231,32 +1246,30 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
|
|
|
1231
1246
|
const filePath = path5.join(projectPath, file);
|
|
1232
1247
|
const fileSessionId = file.replace(".jsonl", "");
|
|
1233
1248
|
try {
|
|
1234
|
-
const content = yield* Effect.tryPromise(() =>
|
|
1249
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
|
|
1235
1250
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
1236
|
-
for (
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
}
|
|
1259
|
-
} catch {
|
|
1251
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1252
|
+
const msg = tryParseJsonLine(lines[i], i + 1, filePath);
|
|
1253
|
+
if (!msg) continue;
|
|
1254
|
+
if (msg.uuid && typeof msg.uuid === "string") {
|
|
1255
|
+
globalUuidMap.set(msg.uuid, {
|
|
1256
|
+
sessionId: fileSessionId,
|
|
1257
|
+
timestamp: msg.timestamp
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
if (msg.messageId && typeof msg.messageId === "string") {
|
|
1261
|
+
globalUuidMap.set(msg.messageId, {
|
|
1262
|
+
sessionId: fileSessionId,
|
|
1263
|
+
timestamp: msg.snapshot?.timestamp
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
if (msg.type === "summary" && typeof msg.summary === "string") {
|
|
1267
|
+
allSummaries.push({
|
|
1268
|
+
summary: msg.summary,
|
|
1269
|
+
leafUuid: msg.leafUuid,
|
|
1270
|
+
timestamp: msg.timestamp,
|
|
1271
|
+
sourceFile: file
|
|
1272
|
+
});
|
|
1260
1273
|
}
|
|
1261
1274
|
}
|
|
1262
1275
|
} catch {
|
|
@@ -1309,10 +1322,10 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
|
|
|
1309
1322
|
});
|
|
1310
1323
|
var cleanInvalidMessages = (projectName, sessionId) => Effect.gen(function* () {
|
|
1311
1324
|
const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
|
|
1312
|
-
const content = yield* Effect.tryPromise(() =>
|
|
1325
|
+
const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
|
|
1313
1326
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
1314
1327
|
if (lines.length === 0) return { removedCount: 0, remainingCount: 0 };
|
|
1315
|
-
const messages = lines
|
|
1328
|
+
const messages = parseJsonlLines(lines, filePath);
|
|
1316
1329
|
const invalidIndices = [];
|
|
1317
1330
|
messages.forEach((msg, idx) => {
|
|
1318
1331
|
if (isInvalidApiKeyMessage(msg)) {
|
|
@@ -1341,7 +1354,7 @@ var cleanInvalidMessages = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
1341
1354
|
lastValidUuid = msg.uuid;
|
|
1342
1355
|
}
|
|
1343
1356
|
const newContent = filtered.length > 0 ? filtered.map((m) => JSON.stringify(m)).join("\n") + "\n" : "";
|
|
1344
|
-
yield* Effect.tryPromise(() =>
|
|
1357
|
+
yield* Effect.tryPromise(() => fs6.writeFile(filePath, newContent, "utf-8"));
|
|
1345
1358
|
const remainingUserAssistant = filtered.filter(
|
|
1346
1359
|
(m) => m.type === "user" || m.type === "assistant"
|
|
1347
1360
|
).length;
|
|
@@ -1408,7 +1421,7 @@ var clearSessions = (options) => Effect.gen(function* () {
|
|
|
1408
1421
|
if (clearInvalid) {
|
|
1409
1422
|
for (const project of targetProjects) {
|
|
1410
1423
|
const projectPath = path5.join(getSessionsDir(), project.name);
|
|
1411
|
-
const files = yield* Effect.tryPromise(() =>
|
|
1424
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
1412
1425
|
const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
1413
1426
|
for (const file of sessionFiles) {
|
|
1414
1427
|
const sessionId = file.replace(".jsonl", "");
|
|
@@ -1462,69 +1475,93 @@ var clearSessions = (options) => Effect.gen(function* () {
|
|
|
1462
1475
|
deletedOrphanTodoCount
|
|
1463
1476
|
};
|
|
1464
1477
|
});
|
|
1478
|
+
var extractSnippet = (text, matchIndex, queryLength) => {
|
|
1479
|
+
const start = Math.max(0, matchIndex - 50);
|
|
1480
|
+
const end = Math.min(text.length, matchIndex + queryLength + 50);
|
|
1481
|
+
return (start > 0 ? "..." : "") + text.slice(start, end).trim() + (end < text.length ? "..." : "");
|
|
1482
|
+
};
|
|
1483
|
+
var findContentMatch = (lines, queryLower, filePath) => {
|
|
1484
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1485
|
+
const msg = tryParseJsonLine(lines[i], i + 1, filePath);
|
|
1486
|
+
if (!msg) continue;
|
|
1487
|
+
if (msg.type !== "user" && msg.type !== "assistant") continue;
|
|
1488
|
+
const text = extractTextContent(msg.message);
|
|
1489
|
+
const textLower = text.toLowerCase();
|
|
1490
|
+
const matchIndex = textLower.indexOf(queryLower);
|
|
1491
|
+
if (matchIndex !== -1) {
|
|
1492
|
+
return {
|
|
1493
|
+
msg,
|
|
1494
|
+
snippet: extractSnippet(text, matchIndex, queryLower.length)
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
return null;
|
|
1499
|
+
};
|
|
1500
|
+
var searchSessionContent = (projectName, sessionId, filePath, queryLower) => pipe(
|
|
1501
|
+
Effect.tryPromise(() => fs6.readFile(filePath, "utf-8")),
|
|
1502
|
+
Effect.map((content) => {
|
|
1503
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
1504
|
+
const match = findContentMatch(lines, queryLower, filePath);
|
|
1505
|
+
if (!match) return null;
|
|
1506
|
+
return {
|
|
1507
|
+
sessionId,
|
|
1508
|
+
projectName,
|
|
1509
|
+
title: extractTitle(extractTextContent(match.msg.message)) || `Session ${sessionId.slice(0, 8)}`,
|
|
1510
|
+
matchType: "content",
|
|
1511
|
+
snippet: match.snippet,
|
|
1512
|
+
messageUuid: match.msg.uuid,
|
|
1513
|
+
timestamp: match.msg.timestamp
|
|
1514
|
+
};
|
|
1515
|
+
}),
|
|
1516
|
+
Effect.catchAll(() => Effect.succeed(null))
|
|
1517
|
+
);
|
|
1518
|
+
var searchProjectContent = (project, queryLower, alreadyFoundIds) => Effect.gen(function* () {
|
|
1519
|
+
const projectPath = path5.join(getSessionsDir(), project.name);
|
|
1520
|
+
const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
|
|
1521
|
+
const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
|
1522
|
+
const searchEffects = sessionFiles.map((file) => ({
|
|
1523
|
+
sessionId: file.replace(".jsonl", ""),
|
|
1524
|
+
filePath: path5.join(projectPath, file)
|
|
1525
|
+
})).filter(({ sessionId }) => !alreadyFoundIds.has(`${project.name}:${sessionId}`)).map(
|
|
1526
|
+
({ sessionId, filePath }) => searchSessionContent(project.name, sessionId, filePath, queryLower)
|
|
1527
|
+
);
|
|
1528
|
+
const results = yield* Effect.all(searchEffects, { concurrency: 10 });
|
|
1529
|
+
return results.filter((r) => r !== null);
|
|
1530
|
+
});
|
|
1465
1531
|
var searchSessions = (query, options = {}) => Effect.gen(function* () {
|
|
1466
1532
|
const { projectName, searchContent = false } = options;
|
|
1467
|
-
const results = [];
|
|
1468
1533
|
const queryLower = query.toLowerCase();
|
|
1469
1534
|
const projects = yield* listProjects;
|
|
1470
1535
|
const targetProjects = projectName ? projects.filter((p) => p.name === projectName) : projects;
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1536
|
+
const titleSearchEffects = targetProjects.map(
|
|
1537
|
+
(project) => pipe(
|
|
1538
|
+
listSessions(project.name),
|
|
1539
|
+
Effect.map(
|
|
1540
|
+
(sessions) => sessions.filter((session) => (session.title ?? "").toLowerCase().includes(queryLower)).map(
|
|
1541
|
+
(session) => ({
|
|
1542
|
+
sessionId: session.id,
|
|
1543
|
+
projectName: project.name,
|
|
1544
|
+
title: session.title ?? "Untitled",
|
|
1545
|
+
matchType: "title",
|
|
1546
|
+
timestamp: session.updatedAt
|
|
1547
|
+
})
|
|
1548
|
+
)
|
|
1549
|
+
)
|
|
1550
|
+
)
|
|
1551
|
+
);
|
|
1552
|
+
const titleResultsNested = yield* Effect.all(titleSearchEffects, { concurrency: 10 });
|
|
1553
|
+
const titleResults = titleResultsNested.flat();
|
|
1554
|
+
let contentResults = [];
|
|
1486
1555
|
if (searchContent) {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
if (results.some((r) => r.sessionId === sessionId && r.projectName === project.name)) {
|
|
1494
|
-
continue;
|
|
1495
|
-
}
|
|
1496
|
-
const filePath = path5.join(projectPath, file);
|
|
1497
|
-
const content = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
|
|
1498
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
1499
|
-
for (const line of lines) {
|
|
1500
|
-
try {
|
|
1501
|
-
const msg = JSON.parse(line);
|
|
1502
|
-
if (msg.type !== "user" && msg.type !== "assistant") continue;
|
|
1503
|
-
const text = extractTextContent(msg.message);
|
|
1504
|
-
const textLower = text.toLowerCase();
|
|
1505
|
-
if (textLower.includes(queryLower)) {
|
|
1506
|
-
const matchIndex = textLower.indexOf(queryLower);
|
|
1507
|
-
const start = Math.max(0, matchIndex - 50);
|
|
1508
|
-
const end = Math.min(text.length, matchIndex + query.length + 50);
|
|
1509
|
-
const snippet = (start > 0 ? "..." : "") + text.slice(start, end).trim() + (end < text.length ? "..." : "");
|
|
1510
|
-
results.push({
|
|
1511
|
-
sessionId,
|
|
1512
|
-
projectName: project.name,
|
|
1513
|
-
title: extractTitle(extractTextContent(msg.message)) || `Session ${sessionId.slice(0, 8)}`,
|
|
1514
|
-
matchType: "content",
|
|
1515
|
-
snippet,
|
|
1516
|
-
messageUuid: msg.uuid,
|
|
1517
|
-
timestamp: msg.timestamp
|
|
1518
|
-
});
|
|
1519
|
-
break;
|
|
1520
|
-
}
|
|
1521
|
-
} catch {
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1556
|
+
const alreadyFoundIds = new Set(titleResults.map((r) => `${r.projectName}:${r.sessionId}`));
|
|
1557
|
+
const contentSearchEffects = targetProjects.map(
|
|
1558
|
+
(project) => searchProjectContent(project, queryLower, alreadyFoundIds)
|
|
1559
|
+
);
|
|
1560
|
+
const contentResultsNested = yield* Effect.all(contentSearchEffects, { concurrency: 5 });
|
|
1561
|
+
contentResults = contentResultsNested.flat();
|
|
1526
1562
|
}
|
|
1527
|
-
|
|
1563
|
+
const allResults = [...titleResults, ...contentResults];
|
|
1564
|
+
return allResults.sort((a, b) => {
|
|
1528
1565
|
const dateA = a.timestamp ? new Date(a.timestamp).getTime() : 0;
|
|
1529
1566
|
const dateB = b.timestamp ? new Date(b.timestamp).getTime() : 0;
|
|
1530
1567
|
return dateB - dateA;
|
|
@@ -1583,5 +1620,5 @@ var getSessionFiles = (projectName, sessionId) => Effect.gen(function* () {
|
|
|
1583
1620
|
};
|
|
1584
1621
|
});
|
|
1585
1622
|
|
|
1586
|
-
export { listProjects as a, loadProjectTreeData as b, clearSessions as c, deleteMessage as d, listSessions as e, deleteSession as f, getSessionsDir as g, readSession as h, getSessionFiles as i, renameSession as j, folderNameToPath as k, loadAgentMessages as l, moveSession as m, splitSession as n, loadSessionTreeData as o, previewCleanup as p, pathToFolderName as q, restoreMessage as r, searchSessions as s, sortProjects as t, getDisplayTitle as u, parseCommandMessage as v,
|
|
1587
|
-
//# sourceMappingURL=index3-
|
|
1623
|
+
export { listProjects as a, loadProjectTreeData as b, clearSessions as c, deleteMessage as d, listSessions as e, deleteSession as f, getSessionsDir as g, readSession as h, getSessionFiles as i, renameSession as j, folderNameToPath as k, loadAgentMessages as l, moveSession as m, splitSession as n, loadSessionTreeData as o, previewCleanup as p, pathToFolderName as q, restoreMessage as r, searchSessions as s, sortProjects as t, getDisplayTitle as u, parseCommandMessage as v, deleteMessageWithChainRepair as w, maskHomePath as x };
|
|
1624
|
+
//# sourceMappingURL=index3-D8wHvUHX.js.map
|