@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.
Files changed (116) hide show
  1. package/build/client/_app/immutable/assets/0.D2FnNtrO.css +1 -0
  2. package/build/client/_app/immutable/assets/0.D2FnNtrO.css.br +0 -0
  3. package/build/client/_app/immutable/assets/0.D2FnNtrO.css.gz +0 -0
  4. package/build/client/_app/immutable/chunks/BRMlZq2r.js +1 -0
  5. package/build/client/_app/immutable/chunks/BRMlZq2r.js.br +0 -0
  6. package/build/client/_app/immutable/chunks/BRMlZq2r.js.gz +0 -0
  7. package/build/client/_app/immutable/chunks/BUqdiQ8V.js +90 -0
  8. package/build/client/_app/immutable/chunks/BUqdiQ8V.js.br +0 -0
  9. package/build/client/_app/immutable/chunks/BUqdiQ8V.js.gz +0 -0
  10. package/build/client/_app/immutable/chunks/{D49tNEXH.js → wR6tcHqD.js} +1 -1
  11. package/build/client/_app/immutable/chunks/wR6tcHqD.js.br +0 -0
  12. package/build/client/_app/immutable/chunks/wR6tcHqD.js.gz +0 -0
  13. package/build/client/_app/immutable/entry/{app.Btq_bE7X.js → app.BIf927Xy.js} +2 -2
  14. package/build/client/_app/immutable/entry/app.BIf927Xy.js.br +0 -0
  15. package/build/client/_app/immutable/entry/app.BIf927Xy.js.gz +0 -0
  16. package/build/client/_app/immutable/entry/start.ChLZh9N7.js +1 -0
  17. package/build/client/_app/immutable/entry/start.ChLZh9N7.js.br +2 -0
  18. package/build/client/_app/immutable/entry/start.ChLZh9N7.js.gz +0 -0
  19. package/build/client/_app/immutable/nodes/{0.CjrUlXhs.js → 0.DKYfg-8s.js} +1 -1
  20. package/build/client/_app/immutable/nodes/0.DKYfg-8s.js.br +0 -0
  21. package/build/client/_app/immutable/nodes/0.DKYfg-8s.js.gz +0 -0
  22. package/build/client/_app/immutable/nodes/{1.C_mir9rr.js → 1.zZICpoUK.js} +1 -1
  23. package/build/client/_app/immutable/nodes/1.zZICpoUK.js.br +2 -0
  24. package/build/client/_app/immutable/nodes/1.zZICpoUK.js.gz +0 -0
  25. package/build/client/_app/immutable/nodes/2.5x79czX-.js +4 -0
  26. package/build/client/_app/immutable/nodes/2.5x79czX-.js.br +0 -0
  27. package/build/client/_app/immutable/nodes/2.5x79czX-.js.gz +0 -0
  28. package/build/client/_app/immutable/nodes/3.Drt04u7Q.js +4 -0
  29. package/build/client/_app/immutable/nodes/3.Drt04u7Q.js.br +0 -0
  30. package/build/client/_app/immutable/nodes/3.Drt04u7Q.js.gz +0 -0
  31. package/build/client/_app/version.json +1 -1
  32. package/build/client/_app/version.json.br +0 -0
  33. package/build/client/_app/version.json.gz +0 -0
  34. package/build/server/chunks/{0-_4Y5P6Pu.js → 0-Bpz08Uhs.js} +4 -4
  35. package/build/server/chunks/{0-_4Y5P6Pu.js.map → 0-Bpz08Uhs.js.map} +1 -1
  36. package/build/server/chunks/{1-BFEz-9-0.js → 1-BjgZlhLm.js} +2 -2
  37. package/build/server/chunks/{1-BFEz-9-0.js.map → 1-BjgZlhLm.js.map} +1 -1
  38. package/build/server/chunks/{2-BJBIDU_y.js → 2-Bvyspg6i.js} +3 -3
  39. package/build/server/chunks/{2-BJBIDU_y.js.map → 2-Bvyspg6i.js.map} +1 -1
  40. package/build/server/chunks/{3-fx1FyCiP.js → 3-BpYq9koE.js} +3 -3
  41. package/build/server/chunks/{3-fx1FyCiP.js.map → 3-BpYq9koE.js.map} +1 -1
  42. package/build/server/chunks/{Toast-Crka3UoV.js → Toast-Dr8M-5Wk.js} +2 -2
  43. package/build/server/chunks/{Toast-Crka3UoV.js.map → Toast-Dr8M-5Wk.js.map} +1 -1
  44. package/build/server/chunks/{_layout.svelte-IUZv8Y-p.js → _layout.svelte-CkIsNl4s.js} +3 -3
  45. package/build/server/chunks/{_layout.svelte-IUZv8Y-p.js.map → _layout.svelte-CkIsNl4s.js.map} +1 -1
  46. package/build/server/chunks/{_page.svelte-Hxh7dTyf.js → _page.svelte-BdKbLK1W.js} +3 -3
  47. package/build/server/chunks/{_page.svelte-Hxh7dTyf.js.map → _page.svelte-BdKbLK1W.js.map} +1 -1
  48. package/build/server/chunks/{_page.svelte-CVZlXeAH.js → _page.svelte-DWKQDFXZ.js} +83 -56
  49. package/build/server/chunks/_page.svelte-DWKQDFXZ.js.map +1 -0
  50. package/build/server/chunks/{_server.ts-kaRz-iNE.js → _server.ts-8OBR5eCA.js} +2 -2
  51. package/build/server/chunks/{_server.ts-kaRz-iNE.js.map → _server.ts-8OBR5eCA.js.map} +1 -1
  52. package/build/server/chunks/{_server.ts-BDo-cBep.js → _server.ts-B4SnxrOX.js} +2 -2
  53. package/build/server/chunks/{_server.ts-BDo-cBep.js.map → _server.ts-B4SnxrOX.js.map} +1 -1
  54. package/build/server/chunks/{_server.ts-B_tHvJuE.js → _server.ts-B9gP-Tri.js} +6 -3
  55. package/build/server/chunks/_server.ts-B9gP-Tri.js.map +1 -0
  56. package/build/server/chunks/{_server.ts-Cyd5L7R7.js → _server.ts-BQxGBeCg.js} +2 -2
  57. package/build/server/chunks/{_server.ts-Cyd5L7R7.js.map → _server.ts-BQxGBeCg.js.map} +1 -1
  58. package/build/server/chunks/{_server.ts-CYy3E-wy.js → _server.ts-Bcdjougg.js} +2 -2
  59. package/build/server/chunks/{_server.ts-CYy3E-wy.js.map → _server.ts-Bcdjougg.js.map} +1 -1
  60. package/build/server/chunks/{_server.ts-Dm4cFvT_.js → _server.ts-BeWDhgJ_.js} +2 -2
  61. package/build/server/chunks/{_server.ts-Dm4cFvT_.js.map → _server.ts-BeWDhgJ_.js.map} +1 -1
  62. package/build/server/chunks/{_server.ts-CwCozCTU.js → _server.ts-CEGd9zNn.js} +2 -2
  63. package/build/server/chunks/{_server.ts-CwCozCTU.js.map → _server.ts-CEGd9zNn.js.map} +1 -1
  64. package/build/server/chunks/{_server.ts-B1VENOjw.js → _server.ts-CMsFINkl.js} +2 -2
  65. package/build/server/chunks/{_server.ts-B1VENOjw.js.map → _server.ts-CMsFINkl.js.map} +1 -1
  66. package/build/server/chunks/{_server.ts-D_nsNW3s.js → _server.ts-CUginV8c.js} +2 -2
  67. package/build/server/chunks/{_server.ts-D_nsNW3s.js.map → _server.ts-CUginV8c.js.map} +1 -1
  68. package/build/server/chunks/{_server.ts-B7mAMmzV.js → _server.ts-Crip_Csr.js} +2 -2
  69. package/build/server/chunks/{_server.ts-B7mAMmzV.js.map → _server.ts-Crip_Csr.js.map} +1 -1
  70. package/build/server/chunks/{_server.ts-B3x7amtu.js → _server.ts-CuAlKvWH.js} +2 -2
  71. package/build/server/chunks/{_server.ts-B3x7amtu.js.map → _server.ts-CuAlKvWH.js.map} +1 -1
  72. package/build/server/chunks/{_server.ts-BEMET_M9.js → _server.ts-DfNIRtb5.js} +2 -2
  73. package/build/server/chunks/{_server.ts-BEMET_M9.js.map → _server.ts-DfNIRtb5.js.map} +1 -1
  74. package/build/server/chunks/{_server.ts-X0UsKGpZ.js → _server.ts-DnfpkUoI.js} +2 -2
  75. package/build/server/chunks/{_server.ts-X0UsKGpZ.js.map → _server.ts-DnfpkUoI.js.map} +1 -1
  76. package/build/server/chunks/{_server.ts-SM5kuocx.js → _server.ts-dXxEqPlK.js} +2 -2
  77. package/build/server/chunks/{_server.ts-SM5kuocx.js.map → _server.ts-dXxEqPlK.js.map} +1 -1
  78. package/build/server/chunks/{_server.ts-Cn3u85fU.js → _server.ts-sXXQUi2v.js} +3 -3
  79. package/build/server/chunks/_server.ts-sXXQUi2v.js.map +1 -0
  80. package/build/server/chunks/{index3-CcQtlmu9.js → index3-D8wHvUHX.js} +364 -327
  81. package/build/server/chunks/index3-D8wHvUHX.js.map +1 -0
  82. package/build/server/index.js +1 -1
  83. package/build/server/index.js.map +1 -1
  84. package/build/server/manifest.js +20 -20
  85. package/build/server/manifest.js.map +1 -1
  86. package/package.json +2 -2
  87. package/build/client/_app/immutable/assets/0.B02QGPuL.css +0 -1
  88. package/build/client/_app/immutable/assets/0.B02QGPuL.css.br +0 -0
  89. package/build/client/_app/immutable/assets/0.B02QGPuL.css.gz +0 -0
  90. package/build/client/_app/immutable/chunks/D49tNEXH.js.br +0 -0
  91. package/build/client/_app/immutable/chunks/D49tNEXH.js.gz +0 -0
  92. package/build/client/_app/immutable/chunks/DVh32r5c.js +0 -90
  93. package/build/client/_app/immutable/chunks/DVh32r5c.js.br +0 -0
  94. package/build/client/_app/immutable/chunks/DVh32r5c.js.gz +0 -0
  95. package/build/client/_app/immutable/chunks/Dzg_BFdu.js +0 -1
  96. package/build/client/_app/immutable/chunks/Dzg_BFdu.js.br +0 -0
  97. package/build/client/_app/immutable/chunks/Dzg_BFdu.js.gz +0 -0
  98. package/build/client/_app/immutable/entry/app.Btq_bE7X.js.br +0 -0
  99. package/build/client/_app/immutable/entry/app.Btq_bE7X.js.gz +0 -0
  100. package/build/client/_app/immutable/entry/start.DiKqSoAN.js +0 -1
  101. package/build/client/_app/immutable/entry/start.DiKqSoAN.js.br +0 -2
  102. package/build/client/_app/immutable/entry/start.DiKqSoAN.js.gz +0 -0
  103. package/build/client/_app/immutable/nodes/0.CjrUlXhs.js.br +0 -0
  104. package/build/client/_app/immutable/nodes/0.CjrUlXhs.js.gz +0 -0
  105. package/build/client/_app/immutable/nodes/1.C_mir9rr.js.br +0 -0
  106. package/build/client/_app/immutable/nodes/1.C_mir9rr.js.gz +0 -0
  107. package/build/client/_app/immutable/nodes/2.C1TvKf9x.js +0 -4
  108. package/build/client/_app/immutable/nodes/2.C1TvKf9x.js.br +0 -0
  109. package/build/client/_app/immutable/nodes/2.C1TvKf9x.js.gz +0 -0
  110. package/build/client/_app/immutable/nodes/3.C4KCGMhg.js +0 -4
  111. package/build/client/_app/immutable/nodes/3.C4KCGMhg.js.br +0 -0
  112. package/build/client/_app/immutable/nodes/3.C4KCGMhg.js.gz +0 -0
  113. package/build/server/chunks/_page.svelte-CVZlXeAH.js.map +0 -1
  114. package/build/server/chunks/_server.ts-B_tHvJuE.js.map +0 -1
  115. package/build/server/chunks/_server.ts-Cn3u85fU.js.map +0 -1
  116. package/build/server/chunks/index3-CcQtlmu9.js.map +0 -1
@@ -1,8 +1,8 @@
1
- import * as fs from 'fs';
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 fs5 from 'fs/promises';
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(() => fs5.readdir(projectPath));
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(() => fs5.readFile(filePath, "utf-8"));
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(() => fs5.readdir(projectPath));
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 fs5.readFile(filePath, "utf-8");
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(() => fs5.stat(entryPath).catch(() => null));
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
- () => fs5.stat(subagentsPath).then(() => true).catch(() => false)
333
+ () => fs6.stat(subagentsPath).then(() => true).catch(() => false)
312
334
  );
313
335
  if (subagentsExists) {
314
336
  const subagentFiles = yield* Effect.tryPromise(
315
- () => fs5.readdir(subagentsPath).catch(() => [])
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(() => fs5.unlink(orphan.filePath));
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(() => fs5.mkdir(backupDir2, { recursive: true }));
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(() => fs5.rename(orphan.filePath, agentBackupPath));
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 fs5.readdir(subagentsDir);
387
+ const files = await fs6.readdir(subagentsDir);
366
388
  return files.length === 0;
367
389
  });
368
390
  if (isEmpty) {
369
- yield* Effect.tryPromise(() => fs5.rmdir(subagentsDir));
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 fs5.readdir(sessionDir);
395
+ const files = await fs6.readdir(sessionDir);
374
396
  return files.length === 0;
375
397
  });
376
398
  if (sessionDirEmpty) {
377
- yield* Effect.tryPromise(() => fs5.rmdir(sessionDir));
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(() => fs5.readFile(agentFilePath, "utf-8"));
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 (const line of lines) {
400
- try {
401
- const parsed = JSON.parse(line);
402
- if ("sessionId" in parsed && !("type" in parsed)) {
403
- continue;
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
- () => fs5.access(todosDir).then(() => true).catch(() => false)
434
+ () => fs6.access(todosDir).then(() => true).catch(() => false)
415
435
  );
416
436
  if (!exists) {
417
- return void 0;
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
- () => fs5.access(sessionTodoPath).then(() => true).catch(() => false)
447
+ () => fs6.access(sessionTodoPath).then(() => true).catch(() => false)
423
448
  );
424
449
  if (sessionTodoExists) {
425
- const content = yield* Effect.tryPromise(() => fs5.readFile(sessionTodoPath, "utf-8"));
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(() => fs5.readdir(todosDir));
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
- () => fs5.access(agentTodoPath).then(() => true).catch(() => false)
470
+ () => fs6.access(agentTodoPath).then(() => true).catch(() => false)
446
471
  );
447
472
  if (agentTodoExists) {
448
- const content = yield* Effect.tryPromise(() => fs5.readFile(agentTodoPath, "utf-8"));
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
- () => fs5.access(todosDir).then(() => true).catch(() => false)
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
- () => fs5.access(sessionTodoPath).then(() => true).catch(() => false)
499
+ () => fs6.access(sessionTodoPath).then(() => true).catch(() => false)
475
500
  );
476
501
  if (sessionTodoExists) {
477
- const content = yield* Effect.tryPromise(() => fs5.readFile(sessionTodoPath, "utf-8"));
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(() => fs5.readdir(todosDir));
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
- () => fs5.access(agentTodoPath).then(() => true).catch(() => false)
522
+ () => fs6.access(agentTodoPath).then(() => true).catch(() => false)
498
523
  );
499
524
  if (agentTodoExists) {
500
- const content = yield* Effect.tryPromise(() => fs5.readFile(agentTodoPath, "utf-8"));
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
- () => fs5.access(todosDir).then(() => true).catch(() => false)
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(() => fs5.mkdir(backupDir, { recursive: true }));
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
- () => fs5.access(sessionTodoPath).then(() => true).catch(() => false)
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(() => fs5.rename(sessionTodoPath, backupPath));
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
- () => fs5.access(agentTodoPath).then(() => true).catch(() => false)
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(() => fs5.rename(agentTodoPath, backupPath));
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
- () => fs5.access(todosDir).then(() => true).catch(() => false)
572
+ () => fs6.access(todosDir).then(() => true).catch(() => false)
548
573
  ),
549
574
  Effect.tryPromise(
550
- () => fs5.access(sessionsDir).then(() => true).catch(() => false)
575
+ () => fs6.access(sessionsDir).then(() => true).catch(() => false)
551
576
  )
552
577
  ]);
553
578
  if (!todosExists || !sessionsExists) return [];
554
- const todoFiles = yield* Effect.tryPromise(() => fs5.readdir(todosDir));
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
- () => fs5.readdir(sessionsDir, { withFileTypes: true })
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(() => fs5.readdir(projectPath));
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(() => fs5.mkdir(backupDir, { recursive: true }));
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(() => fs5.rename(filePath, backupPath));
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
- () => fs5.access(sessionsDir).then(() => true).catch(() => false)
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(() => fs5.readdir(sessionsDir, { withFileTypes: true }));
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(() => fs5.readdir(projectPath));
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(() => fs5.readdir(projectPath));
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 content = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
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
- const content = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
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 content = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
761
- const lines = content.trim().split("\n").filter(Boolean);
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(() => fs5.writeFile(filePath, newContent, "utf-8"));
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 content = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
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(() => fs5.writeFile(filePath, newContent, "utf-8"));
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(() => fs5.stat(filePath));
823
+ const stat4 = yield* Effect.tryPromise(() => fs6.stat(filePath));
799
824
  if (stat4.size === 0) {
800
- yield* Effect.tryPromise(() => fs5.unlink(filePath));
825
+ yield* Effect.tryPromise(() => fs6.unlink(filePath));
801
826
  const agentBackupDir2 = path5.join(projectPath, ".bak");
802
- yield* Effect.tryPromise(() => fs5.mkdir(agentBackupDir2, { recursive: true }));
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(() => fs5.rename(agentPath, agentBackupPath).catch(() => {
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(() => fs5.mkdir(backupDir, { recursive: true }));
838
+ yield* Effect.tryPromise(() => fs6.mkdir(backupDir, { recursive: true }));
814
839
  const agentBackupDir = path5.join(projectPath, ".bak");
815
- yield* Effect.tryPromise(() => fs5.mkdir(agentBackupDir, { recursive: true }));
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(() => fs5.rename(agentPath, agentBackupPath).catch(() => {
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(() => fs5.rename(filePath, backupPath));
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(() => fs5.readFile(filePath, "utf-8"));
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.map((line) => JSON.parse(line));
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(() => fs5.writeFile(filePath, newContent, "utf-8"));
860
- const projectFiles = yield* Effect.tryPromise(() => fs5.readdir(projectPath));
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 otherContent = yield* Effect.tryPromise(() => fs5.readFile(otherFilePath, "utf-8"));
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 summaryContent = yield* Effect.tryPromise(() => fs5.readFile(summaryFilePath, "utf-8"));
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(() => fs5.writeFile(summaryFilePath, newSummaryContent, "utf-8"));
916
+ yield* Effect.tryPromise(() => fs6.writeFile(summaryFilePath, newSummaryContent, "utf-8"));
896
917
  } else {
897
- const currentContent = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
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(() => fs5.writeFile(filePath, updatedContent, "utf-8"));
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
- () => fs5.access(sourceFile).then(() => true).catch(() => false)
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
- () => fs5.access(targetFile).then(() => true).catch(() => false)
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(() => fs5.mkdir(targetPath, { recursive: true }));
960
+ yield* Effect.tryPromise(() => fs6.mkdir(targetPath, { recursive: true }));
942
961
  const linkedAgents = yield* findLinkedAgents(sourceProject, sessionId);
943
- yield* Effect.tryPromise(() => fs5.rename(sourceFile, targetFile));
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
- () => fs5.access(sourceAgentFile).then(() => true).catch(() => false)
967
+ () => fs6.access(sourceAgentFile).then(() => true).catch(() => false)
949
968
  );
950
969
  if (agentExists) {
951
- yield* Effect.tryPromise(() => fs5.rename(sourceAgentFile, targetAgentFile));
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 content = yield* Effect.tryPromise(() => fs5.readFile(filePath, "utf-8"));
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(() => fs5.writeFile(filePath, keptContent, "utf-8"));
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(() => fs5.writeFile(newFilePath, newContent, "utf-8"));
1011
- const agentFiles = yield* Effect.tryPromise(() => fs5.readdir(projectPath));
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(() => fs5.readFile(agentPath, "utf-8"));
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 firstAgentMsg = JSON.parse(agentLines[0]);
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 = agentLines.map((line) => {
1026
- const msg = JSON.parse(line);
1027
- return JSON.stringify({ ...msg, sessionId: newSessionId });
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(() => fs5.writeFile(agentPath, updatedAgentContent, "utf-8"));
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(() => fs5.readFile(filePath, "utf-8"));
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.map((line) => JSON.parse(line));
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(() => fs5.readdir(projectPath));
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(() => fs5.readFile(otherFilePath, "utf-8"));
1123
+ const otherContent = yield* Effect.tryPromise(() => fs6.readFile(otherFilePath, "utf-8"));
1107
1124
  const otherLines = otherContent.trim().split("\n").filter(Boolean);
1108
- for (const line of otherLines) {
1109
- try {
1110
- const msg = JSON.parse(line);
1111
- if (msg.type === "summary" && typeof msg.summary === "string" && typeof msg.leafUuid === "string" && sessionUuids.has(msg.leafUuid)) {
1112
- const targetMsg = messages.find((m) => m.uuid === msg.leafUuid);
1113
- summaries.push({
1114
- summary: msg.summary,
1115
- leafUuid: msg.leafUuid,
1116
- timestamp: targetMsg?.timestamp ?? msg.timestamp,
1117
- sourceFile: file
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(() => fs5.readFile(agentPath, "utf-8"));
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(() => fs5.readdir(projectPath));
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(() => fs5.stat(filePath));
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(() => fs5.readFile(filePath, "utf-8"));
1249
+ const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
1235
1250
  const lines = content.trim().split("\n").filter(Boolean);
1236
- for (const line of lines) {
1237
- try {
1238
- const msg = JSON.parse(line);
1239
- if (msg.uuid && typeof msg.uuid === "string") {
1240
- globalUuidMap.set(msg.uuid, {
1241
- sessionId: fileSessionId,
1242
- timestamp: msg.timestamp
1243
- });
1244
- }
1245
- if (msg.messageId && typeof msg.messageId === "string") {
1246
- globalUuidMap.set(msg.messageId, {
1247
- sessionId: fileSessionId,
1248
- timestamp: msg.snapshot?.timestamp
1249
- });
1250
- }
1251
- if (msg.type === "summary" && typeof msg.summary === "string") {
1252
- allSummaries.push({
1253
- summary: msg.summary,
1254
- leafUuid: msg.leafUuid,
1255
- timestamp: msg.timestamp,
1256
- sourceFile: file
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(() => fs5.readFile(filePath, "utf-8"));
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.map((line) => JSON.parse(line));
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(() => fs5.writeFile(filePath, newContent, "utf-8"));
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(() => fs5.readdir(projectPath));
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
- for (const project of targetProjects) {
1472
- const sessions = yield* listSessions(project.name);
1473
- for (const session of sessions) {
1474
- const titleLower = (session.title ?? "").toLowerCase();
1475
- if (titleLower.includes(queryLower)) {
1476
- results.push({
1477
- sessionId: session.id,
1478
- projectName: project.name,
1479
- title: session.title ?? "Untitled",
1480
- matchType: "title",
1481
- timestamp: session.updatedAt
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
- for (const project of targetProjects) {
1488
- const projectPath = path5.join(getSessionsDir(), project.name);
1489
- const files = yield* Effect.tryPromise(() => fs5.readdir(projectPath));
1490
- const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
1491
- for (const file of sessionFiles) {
1492
- const sessionId = file.replace(".jsonl", "");
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
- return results.sort((a, b) => {
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, maskHomePath as w };
1587
- //# sourceMappingURL=index3-CcQtlmu9.js.map
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