@claude-sessions/web 0.4.6 → 0.4.7-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/build/client/_app/immutable/chunks/CBiqUHp4.js +1 -0
  2. package/build/client/_app/immutable/chunks/CBiqUHp4.js.br +0 -0
  3. package/build/client/_app/immutable/chunks/CBiqUHp4.js.gz +0 -0
  4. package/build/client/_app/immutable/chunks/CYKpEMl5.js +1 -0
  5. package/build/client/_app/immutable/chunks/CYKpEMl5.js.br +0 -0
  6. package/build/client/_app/immutable/chunks/CYKpEMl5.js.gz +0 -0
  7. package/build/client/_app/immutable/chunks/DicbBas7.js +1 -0
  8. package/build/client/_app/immutable/chunks/DicbBas7.js.br +0 -0
  9. package/build/client/_app/immutable/chunks/DicbBas7.js.gz +0 -0
  10. package/build/client/_app/immutable/chunks/{aZi3OCpL.js → GmjPUgZ0.js} +30 -26
  11. package/build/client/_app/immutable/chunks/GmjPUgZ0.js.br +0 -0
  12. package/build/client/_app/immutable/chunks/GmjPUgZ0.js.gz +0 -0
  13. package/build/client/_app/immutable/entry/{app.CYY1PZCN.js → app.CMV94ayS.js} +2 -2
  14. package/build/client/_app/immutable/entry/app.CMV94ayS.js.br +0 -0
  15. package/build/client/_app/immutable/entry/app.CMV94ayS.js.gz +0 -0
  16. package/build/client/_app/immutable/entry/start.CgzpSnrE.js +1 -0
  17. package/build/client/_app/immutable/entry/start.CgzpSnrE.js.br +0 -0
  18. package/build/client/_app/immutable/entry/start.CgzpSnrE.js.gz +0 -0
  19. package/build/client/_app/immutable/nodes/{0.B2uv-WBM.js → 0.DVHVg7U5.js} +1 -1
  20. package/build/client/_app/immutable/nodes/0.DVHVg7U5.js.br +0 -0
  21. package/build/client/_app/immutable/nodes/0.DVHVg7U5.js.gz +0 -0
  22. package/build/client/_app/immutable/nodes/{1.BoxEAqK6.js → 1.D0PdYLPm.js} +1 -1
  23. package/build/client/_app/immutable/nodes/1.D0PdYLPm.js.br +0 -0
  24. package/build/client/_app/immutable/nodes/1.D0PdYLPm.js.gz +0 -0
  25. package/build/client/_app/immutable/nodes/2.Cs83Zp7C.js +4 -0
  26. package/build/client/_app/immutable/nodes/2.Cs83Zp7C.js.br +0 -0
  27. package/build/client/_app/immutable/nodes/2.Cs83Zp7C.js.gz +0 -0
  28. package/build/client/_app/immutable/nodes/{3.Dj8iwfME.js → 3.BMgB8JW6.js} +1 -1
  29. package/build/client/_app/immutable/nodes/3.BMgB8JW6.js.br +0 -0
  30. package/build/client/_app/immutable/nodes/3.BMgB8JW6.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-DChhR3gd.js → 0-CEq226Yu.js} +3 -3
  35. package/build/server/chunks/0-CEq226Yu.js.map +1 -0
  36. package/build/server/chunks/{1-BBSPd3nB.js → 1-CZKii7cF.js} +3 -3
  37. package/build/server/chunks/1-CZKii7cF.js.map +1 -0
  38. package/build/server/chunks/{2-C20RW_lJ.js → 2-1NHU8T7t.js} +3 -3
  39. package/build/server/chunks/2-1NHU8T7t.js.map +1 -0
  40. package/build/server/chunks/{3-D3wL2YSE.js → 3-DHru04k0.js} +3 -3
  41. package/build/server/chunks/3-DHru04k0.js.map +1 -0
  42. package/build/server/chunks/{InputModal-1qJGryUa.js → InputModal-B2QW71Rc.js} +2 -2
  43. package/build/server/chunks/InputModal-B2QW71Rc.js.map +1 -0
  44. package/build/server/chunks/{Toast-C9b_dWm4.js → Toast-BzqOqKOg.js} +3 -3
  45. package/build/server/chunks/Toast-BzqOqKOg.js.map +1 -0
  46. package/build/server/chunks/{_layout.svelte-CdDMC1RI.js → _layout.svelte-CkLZkYhs.js} +7 -7
  47. package/build/server/chunks/_layout.svelte-CkLZkYhs.js.map +1 -0
  48. package/build/server/chunks/{_page.svelte-Dx2ikKP_.js → _page.svelte-DSpIiljH.js} +13 -7
  49. package/build/server/chunks/_page.svelte-DSpIiljH.js.map +1 -0
  50. package/build/server/chunks/{_page.svelte-CVL9fjg-.js → _page.svelte-DuQWccy1.js} +7 -7
  51. package/build/server/chunks/_page.svelte-DuQWccy1.js.map +1 -0
  52. package/build/server/chunks/{_server.ts-DOSGEHuw.js → _server.ts-B-2v0wgR.js} +2 -2
  53. package/build/server/chunks/{_server.ts-DOSGEHuw.js.map → _server.ts-B-2v0wgR.js.map} +1 -1
  54. package/build/server/chunks/{_server.ts-BWxgSwZN.js → _server.ts-Ba6jXSm2.js} +2 -2
  55. package/build/server/chunks/{_server.ts-BWxgSwZN.js.map → _server.ts-Ba6jXSm2.js.map} +1 -1
  56. package/build/server/chunks/{_server.ts-rTWeIoSC.js → _server.ts-BhA9i-7j.js} +3 -3
  57. package/build/server/chunks/{_server.ts-rTWeIoSC.js.map → _server.ts-BhA9i-7j.js.map} +1 -1
  58. package/build/server/chunks/{_server.ts-CrKc6LEy.js → _server.ts-BjynU3C4.js} +2 -2
  59. package/build/server/chunks/{_server.ts-CrKc6LEy.js.map → _server.ts-BjynU3C4.js.map} +1 -1
  60. package/build/server/chunks/{_server.ts-F01KLghS.js → _server.ts-C-iKh37d.js} +2 -2
  61. package/build/server/chunks/{_server.ts-F01KLghS.js.map → _server.ts-C-iKh37d.js.map} +1 -1
  62. package/build/server/chunks/{_server.ts-COPvamIQ.js → _server.ts-CoLbb7aT.js} +2 -2
  63. package/build/server/chunks/{_server.ts-COPvamIQ.js.map → _server.ts-CoLbb7aT.js.map} +1 -1
  64. package/build/server/chunks/{_server.ts-B3M-jxF5.js → _server.ts-CozgvvoX.js} +2 -2
  65. package/build/server/chunks/{_server.ts-B3M-jxF5.js.map → _server.ts-CozgvvoX.js.map} +1 -1
  66. package/build/server/chunks/{_server.ts-BGA9W8aM.js → _server.ts-Cy5z0Rsk.js} +2 -2
  67. package/build/server/chunks/{_server.ts-BGA9W8aM.js.map → _server.ts-Cy5z0Rsk.js.map} +1 -1
  68. package/build/server/chunks/{_server.ts-QLTE_2dV.js → _server.ts-DCSJsfkA.js} +2 -2
  69. package/build/server/chunks/{_server.ts-QLTE_2dV.js.map → _server.ts-DCSJsfkA.js.map} +1 -1
  70. package/build/server/chunks/{_server.ts-DmWsoikX.js → _server.ts-DRrwjyQ0.js} +2 -2
  71. package/build/server/chunks/{_server.ts-DmWsoikX.js.map → _server.ts-DRrwjyQ0.js.map} +1 -1
  72. package/build/server/chunks/{_server.ts-C9GYaVf1.js → _server.ts-DcfIBmy4.js} +3 -3
  73. package/build/server/chunks/_server.ts-DcfIBmy4.js.map +1 -0
  74. package/build/server/chunks/{_server.ts-BCOHCAjW.js → _server.ts-Dq4A0ML7.js} +2 -2
  75. package/build/server/chunks/{_server.ts-BCOHCAjW.js.map → _server.ts-Dq4A0ML7.js.map} +1 -1
  76. package/build/server/chunks/{_server.ts-DP0i5Bdl.js → _server.ts-dEWE9PbU.js} +2 -2
  77. package/build/server/chunks/{_server.ts-DP0i5Bdl.js.map → _server.ts-dEWE9PbU.js.map} +1 -1
  78. package/build/server/chunks/{_server.ts-WZF_VFnZ.js → _server.ts-g1VNk1F2.js} +2 -2
  79. package/build/server/chunks/{_server.ts-WZF_VFnZ.js.map → _server.ts-g1VNk1F2.js.map} +1 -1
  80. package/build/server/chunks/{_server.ts-C0mKXnG1.js → _server.ts-klbpGqf9.js} +2 -2
  81. package/build/server/chunks/{_server.ts-C0mKXnG1.js.map → _server.ts-klbpGqf9.js.map} +1 -1
  82. package/build/server/chunks/{_server.ts-DmN9rdOH.js → _server.ts-xRJQMsoy.js} +3 -3
  83. package/build/server/chunks/{_server.ts-DmN9rdOH.js.map → _server.ts-xRJQMsoy.js.map} +1 -1
  84. package/build/server/chunks/{client-BtcIwznP.js → client-CJUAsTTN.js} +3 -3
  85. package/build/server/chunks/client-CJUAsTTN.js.map +1 -0
  86. package/build/server/chunks/{error.svelte-B02-pvoO.js → error.svelte-CYLEgCzL.js} +5 -5
  87. package/build/server/chunks/error.svelte-CYLEgCzL.js.map +1 -0
  88. package/build/server/chunks/exports-7ECo9oy7.js +102 -0
  89. package/build/server/chunks/exports-7ECo9oy7.js.map +1 -0
  90. package/build/server/chunks/{index2-B2Ld-FFX.js → index-CUeePJRv.js} +1145 -68
  91. package/build/server/chunks/index-CUeePJRv.js.map +1 -0
  92. package/build/server/chunks/{index3-DNyQGNm8.js → index2-BbHYMsUG.js} +265 -63
  93. package/build/server/chunks/index2-BbHYMsUG.js.map +1 -0
  94. package/build/server/chunks/{index4-CfOR2iO6.js → index3-BKokHvI9.js} +3 -3
  95. package/build/server/chunks/index3-BKokHvI9.js.map +1 -0
  96. package/build/server/chunks/server-Bf8x1V_n.js +16 -0
  97. package/build/server/chunks/server-Bf8x1V_n.js.map +1 -0
  98. package/build/server/chunks/{session-Dxp1vf6f.js → session-BEXBEvJ9.js} +2 -2
  99. package/build/server/chunks/{session-Dxp1vf6f.js.map → session-BEXBEvJ9.js.map} +1 -1
  100. package/build/server/index.js +4 -17
  101. package/build/server/index.js.map +1 -1
  102. package/build/server/manifest.js +21 -21
  103. package/build/server/manifest.js.map +1 -1
  104. package/package.json +3 -2
  105. package/build/client/_app/immutable/chunks/CiIZzKcO.js +0 -1
  106. package/build/client/_app/immutable/chunks/CiIZzKcO.js.br +0 -0
  107. package/build/client/_app/immutable/chunks/CiIZzKcO.js.gz +0 -0
  108. package/build/client/_app/immutable/chunks/DDmWtjsj.js +0 -1
  109. package/build/client/_app/immutable/chunks/DDmWtjsj.js.br +0 -0
  110. package/build/client/_app/immutable/chunks/DDmWtjsj.js.gz +0 -0
  111. package/build/client/_app/immutable/chunks/aZi3OCpL.js.br +0 -0
  112. package/build/client/_app/immutable/chunks/aZi3OCpL.js.gz +0 -0
  113. package/build/client/_app/immutable/entry/app.CYY1PZCN.js.br +0 -0
  114. package/build/client/_app/immutable/entry/app.CYY1PZCN.js.gz +0 -0
  115. package/build/client/_app/immutable/entry/start.D84fuMw9.js +0 -1
  116. package/build/client/_app/immutable/entry/start.D84fuMw9.js.br +0 -2
  117. package/build/client/_app/immutable/entry/start.D84fuMw9.js.gz +0 -0
  118. package/build/client/_app/immutable/nodes/0.B2uv-WBM.js.br +0 -0
  119. package/build/client/_app/immutable/nodes/0.B2uv-WBM.js.gz +0 -0
  120. package/build/client/_app/immutable/nodes/1.BoxEAqK6.js.br +0 -3
  121. package/build/client/_app/immutable/nodes/1.BoxEAqK6.js.gz +0 -0
  122. package/build/client/_app/immutable/nodes/2.mKAMmHlh.js +0 -4
  123. package/build/client/_app/immutable/nodes/2.mKAMmHlh.js.br +0 -0
  124. package/build/client/_app/immutable/nodes/2.mKAMmHlh.js.gz +0 -0
  125. package/build/client/_app/immutable/nodes/3.Dj8iwfME.js.br +0 -0
  126. package/build/client/_app/immutable/nodes/3.Dj8iwfME.js.gz +0 -0
  127. package/build/server/chunks/0-DChhR3gd.js.map +0 -1
  128. package/build/server/chunks/1-BBSPd3nB.js.map +0 -1
  129. package/build/server/chunks/2-C20RW_lJ.js.map +0 -1
  130. package/build/server/chunks/3-D3wL2YSE.js.map +0 -1
  131. package/build/server/chunks/InputModal-1qJGryUa.js.map +0 -1
  132. package/build/server/chunks/Toast-C9b_dWm4.js.map +0 -1
  133. package/build/server/chunks/_layout.svelte-CdDMC1RI.js.map +0 -1
  134. package/build/server/chunks/_page.svelte-CVL9fjg-.js.map +0 -1
  135. package/build/server/chunks/_page.svelte-Dx2ikKP_.js.map +0 -1
  136. package/build/server/chunks/_server.ts-C9GYaVf1.js.map +0 -1
  137. package/build/server/chunks/client-BtcIwznP.js.map +0 -1
  138. package/build/server/chunks/error.svelte-B02-pvoO.js.map +0 -1
  139. package/build/server/chunks/index2-B2Ld-FFX.js.map +0 -1
  140. package/build/server/chunks/index3-DNyQGNm8.js.map +0 -1
  141. package/build/server/chunks/index4-CfOR2iO6.js.map +0 -1
  142. package/build/server/chunks/root-B5iYE7yO.js +0 -1182
  143. package/build/server/chunks/root-B5iYE7yO.js.map +0 -1
@@ -59,14 +59,13 @@ var extractTitle = (input) => {
59
59
  text = extractTextContent(input, { stripIdeTags: true });
60
60
  }
61
61
  if (!text) return "Untitled";
62
- const { name, args } = parseCommandMessage(text);
63
- if (name) return args ? `${name} ${args}` : name;
64
- let cleaned = text.trim();
65
- if (!cleaned) return "Untitled";
66
- if (cleaned.includes("\n\n")) {
67
- cleaned = cleaned.split("\n\n")[0];
62
+ let firstParagraph = text.trim();
63
+ if (firstParagraph.includes("\n\n")) {
64
+ firstParagraph = firstParagraph.split("\n\n")[0];
68
65
  }
69
- return cleaned || "Untitled";
66
+ const { name, args } = parseCommandMessage(firstParagraph);
67
+ if (name) return args ? `${name} ${args}` : name;
68
+ return firstParagraph || "Untitled";
70
69
  };
71
70
  var isInvalidApiKeyMessage = (msg) => {
72
71
  const text = extractTextContent(msg.message);
@@ -95,11 +94,12 @@ var getDisplayTitle = (customTitle, currentSummary, title, maxLength = 60, fallb
95
94
  return currentSummary.length > maxLength ? currentSummary.slice(0, maxLength - 3) + "..." : currentSummary;
96
95
  }
97
96
  if (title && title !== "Untitled") {
98
- if (title.includes("<command-name>")) {
99
- const { name, args } = parseCommandMessage(title);
97
+ const firstParagraph = title.includes("\n\n") ? title.split("\n\n")[0] : title;
98
+ if (firstParagraph.includes("<command-name>")) {
99
+ const { name, args } = parseCommandMessage(firstParagraph);
100
100
  if (name) return args ? `${name} ${args}` : name;
101
101
  }
102
- return title;
102
+ return firstParagraph;
103
103
  }
104
104
  return fallback;
105
105
  };
@@ -145,27 +145,32 @@ var tryParseJsonLine = (line, lineNumber, filePath) => {
145
145
  return JSON.parse(line);
146
146
  } catch {
147
147
  if (filePath) {
148
- console.warn(`Skipping invalid JSON at line ${lineNumber} in ${filePath}`);
148
+ logger.warn(`Skipping invalid JSON at line ${lineNumber} in ${filePath}`);
149
149
  }
150
150
  return null;
151
151
  }
152
152
  };
153
- var parseJsonlLines = (lines, filePath) => {
154
- return lines.map((line, idx) => {
153
+ var parseJsonlLines = (lines, filePath, { strict = false } = {}) => {
154
+ const results = [];
155
+ for (let idx = 0; idx < lines.length; idx++) {
155
156
  try {
156
- return JSON.parse(line);
157
+ results.push(JSON.parse(lines[idx]));
157
158
  } catch (e) {
158
159
  const err = e;
159
- throw new Error(`Failed to parse line ${idx + 1} in ${filePath}: ${err.message}`, {
160
- cause: e
161
- });
160
+ if (strict) {
161
+ throw new Error(`Failed to parse line ${idx + 1} in ${filePath}: ${err.message}`, {
162
+ cause: e
163
+ });
164
+ }
165
+ logger.warn(`Skipping malformed line ${idx + 1} in ${filePath}: ${err.message}`);
162
166
  }
163
- });
167
+ }
168
+ return results;
164
169
  };
165
- var readJsonlFile = (filePath) => Effect.gen(function* () {
170
+ var readJsonlFile = (filePath, options) => Effect.gen(function* () {
166
171
  const content = yield* Effect.tryPromise(() => fs6.readFile(filePath, "utf-8"));
167
172
  const lines = content.trim().split("\n").filter(Boolean);
168
- return parseJsonlLines(lines, filePath);
173
+ return parseJsonlLines(lines, filePath, options);
169
174
  });
170
175
  var getTotalTodoCount = (todos) => {
171
176
  return todos.sessionTodos.length + todos.agentTodos.reduce((sum, a) => sum + a.todos.length, 0);
@@ -308,14 +313,14 @@ var resolvePathFromClaudeConfig = async (folderName, fileSystem = fs6) => {
308
313
  };
309
314
  var folderNameToPath = async (folderName) => {
310
315
  const homeDir = os.homedir();
311
- const realPath = getRealPathFromSession(folderName);
312
- if (realPath) {
313
- return toRelativePath(realPath, homeDir);
314
- }
315
316
  const configPath = await resolvePathFromClaudeConfig(folderName);
316
317
  if (configPath) {
317
318
  return toRelativePath(configPath, homeDir);
318
319
  }
320
+ const realPath = getRealPathFromSession(folderName);
321
+ if (realPath) {
322
+ return toRelativePath(realPath, homeDir);
323
+ }
319
324
  const absolutePath = folderNameToDisplayPath(folderName);
320
325
  return toRelativePath(absolutePath, homeDir);
321
326
  };
@@ -990,7 +995,7 @@ var readSession = (projectName, sessionId) => Effect.gen(function* () {
990
995
  });
991
996
  var deleteMessage = (projectName, sessionId, messageUuid, targetType) => Effect.gen(function* () {
992
997
  const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
993
- const messages = yield* readJsonlFile(filePath);
998
+ const messages = yield* readJsonlFile(filePath, { strict: true });
994
999
  const result = deleteMessageWithChainRepair(messages, messageUuid, targetType);
995
1000
  if (!result.deleted) {
996
1001
  return { success: false, error: "Message not found" };
@@ -1001,7 +1006,7 @@ var deleteMessage = (projectName, sessionId, messageUuid, targetType) => Effect.
1001
1006
  });
1002
1007
  var restoreMessage = (projectName, sessionId, message, index) => Effect.gen(function* () {
1003
1008
  const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
1004
- const messages = yield* readJsonlFile(filePath);
1009
+ const messages = yield* readJsonlFile(filePath, { strict: true });
1005
1010
  const msgUuid = message.uuid ?? message.messageId;
1006
1011
  if (!msgUuid) {
1007
1012
  return { success: false, error: "Message has no uuid or messageId" };
@@ -1066,7 +1071,7 @@ var renameSession = (projectName, sessionId, newTitle) => Effect.gen(function* (
1066
1071
  if (lines.length === 0) {
1067
1072
  return { success: false, error: "Empty session" };
1068
1073
  }
1069
- const messages = parseJsonlLines(lines, filePath);
1074
+ const messages = parseJsonlLines(lines, filePath, { strict: true });
1070
1075
  const customTitleIdx = messages.findIndex((m) => m.type === "custom-title");
1071
1076
  if (customTitleIdx >= 0) {
1072
1077
  messages.splice(customTitleIdx, 1);
@@ -1116,7 +1121,7 @@ var moveSession = (sourceProject, sessionId, targetProject) => Effect.gen(functi
1116
1121
  var splitSession = (projectName, sessionId, splitAtMessageUuid) => Effect.gen(function* () {
1117
1122
  const projectPath = path5.join(getSessionsDir(), projectName);
1118
1123
  const filePath = path5.join(projectPath, `${sessionId}.jsonl`);
1119
- const allMessages = yield* readJsonlFile(filePath);
1124
+ const allMessages = yield* readJsonlFile(filePath, { strict: true });
1120
1125
  const splitIndex = allMessages.findIndex((m) => m.uuid === splitAtMessageUuid);
1121
1126
  if (splitIndex === -1) {
1122
1127
  return { success: false, error: "Message not found" };
@@ -1163,7 +1168,9 @@ var splitSession = (projectName, sessionId, splitAtMessageUuid) => Effect.gen(fu
1163
1168
  const agentContent = yield* Effect.tryPromise(() => fs6.readFile(agentPath, "utf-8"));
1164
1169
  const agentLines = agentContent.trim().split("\n").filter(Boolean);
1165
1170
  if (agentLines.length === 0) continue;
1166
- const agentMessages = parseJsonlLines(agentLines, agentPath);
1171
+ const agentMessages = parseJsonlLines(agentLines, agentPath, {
1172
+ strict: true
1173
+ });
1167
1174
  const firstAgentMsg = agentMessages[0];
1168
1175
  if (firstAgentMsg.sessionId === sessionId) {
1169
1176
  const agentId = agentFile.replace("agent-", "").replace(".jsonl", "");
@@ -1187,6 +1194,67 @@ var splitSession = (projectName, sessionId, splitAtMessageUuid) => Effect.gen(fu
1187
1194
  duplicatedSummary: shouldDuplicate
1188
1195
  };
1189
1196
  });
1197
+ var log2 = createLogger("cache");
1198
+ var CACHE_VERSION = 1;
1199
+ var CACHE_FILENAME = ".tree-cache.json";
1200
+ var getCachePath = (projectName) => path5.join(getSessionsDir(), projectName, CACHE_FILENAME);
1201
+ var loadTreeCache = async (projectName) => {
1202
+ const cachePath = getCachePath(projectName);
1203
+ try {
1204
+ const raw = await fs6.readFile(cachePath, "utf-8");
1205
+ const parsed = JSON.parse(raw);
1206
+ if (parsed.version !== CACHE_VERSION) {
1207
+ log2.debug(`cache version mismatch (${parsed.version} !== ${CACHE_VERSION}), ignoring`);
1208
+ return null;
1209
+ }
1210
+ return parsed;
1211
+ } catch {
1212
+ return null;
1213
+ }
1214
+ };
1215
+ var writeTreeCache = async (projectName, cache) => {
1216
+ const cachePath = getCachePath(projectName);
1217
+ const tmpPath = cachePath + ".tmp";
1218
+ try {
1219
+ await fs6.writeFile(tmpPath, JSON.stringify(cache), "utf-8");
1220
+ await fs6.rename(tmpPath, cachePath);
1221
+ } catch (e) {
1222
+ log2.debug(`failed to write cache: ${e}`);
1223
+ try {
1224
+ await fs6.unlink(tmpPath);
1225
+ } catch {
1226
+ }
1227
+ }
1228
+ };
1229
+ var validateCache = (cache, sessionFileIds, currentMtimes) => {
1230
+ const cachedIds = new Set(Object.keys(cache.sessions));
1231
+ const currentIds = new Set(sessionFileIds);
1232
+ const changedSessionIds = [];
1233
+ const unchangedSessionIds = [];
1234
+ const newSessionIds = [];
1235
+ const deletedSessionIds = [];
1236
+ for (const id of currentIds) {
1237
+ if (!cachedIds.has(id)) {
1238
+ newSessionIds.push(id);
1239
+ } else {
1240
+ const cachedMtime = cache.sessions[id].fileMtime;
1241
+ const currentMtime = currentMtimes.get(id) ?? 0;
1242
+ if (Math.abs(cachedMtime - currentMtime) <= 1) {
1243
+ unchangedSessionIds.push(id);
1244
+ } else {
1245
+ changedSessionIds.push(id);
1246
+ }
1247
+ }
1248
+ }
1249
+ for (const id of cachedIds) {
1250
+ if (!currentIds.has(id)) {
1251
+ deletedSessionIds.push(id);
1252
+ }
1253
+ }
1254
+ const isFullHit = changedSessionIds.length === 0 && newSessionIds.length === 0 && deletedSessionIds.length === 0;
1255
+ return { isFullHit, changedSessionIds, unchangedSessionIds, deletedSessionIds, newSessionIds };
1256
+ };
1257
+ var log3 = createLogger("tree");
1190
1258
  var sortSessions = (sessions, sort) => {
1191
1259
  return sessions.sort((a, b) => {
1192
1260
  let comparison = 0;
@@ -1345,32 +1413,9 @@ var loadSessionTreeDataInternal = (projectName, sessionId, summariesByTargetSess
1345
1413
  });
1346
1414
  var loadSessionTreeData = (projectName, sessionId) => loadSessionTreeDataInternal(projectName, sessionId, void 0);
1347
1415
  var DEFAULT_SORT = { field: "summary", order: "desc" };
1348
- var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* () {
1349
- const project = (yield* listProjects).find((p) => p.name === projectName);
1350
- if (!project) {
1351
- return null;
1352
- }
1353
- const sort = sortOptions ?? DEFAULT_SORT;
1354
- const projectPath = path5.join(getSessionsDir(), projectName);
1355
- const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
1356
- const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
1357
- const fileMtimes = /* @__PURE__ */ new Map();
1358
- yield* Effect.all(
1359
- sessionFiles.map(
1360
- (file) => Effect.gen(function* () {
1361
- const filePath = path5.join(projectPath, file);
1362
- try {
1363
- const stat4 = yield* Effect.tryPromise(() => fs6.stat(filePath));
1364
- fileMtimes.set(file.replace(".jsonl", ""), stat4.mtimeMs);
1365
- } catch {
1366
- }
1367
- })
1368
- ),
1369
- { concurrency: 20 }
1370
- );
1416
+ var buildPhase1 = (projectPath, allJsonlFiles) => Effect.gen(function* () {
1371
1417
  const globalUuidMap = /* @__PURE__ */ new Map();
1372
1418
  const allSummaries = [];
1373
- const allJsonlFiles = files.filter((f) => f.endsWith(".jsonl"));
1374
1419
  yield* Effect.all(
1375
1420
  allJsonlFiles.map(
1376
1421
  (file) => Effect.gen(function* () {
@@ -1409,6 +1454,9 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
1409
1454
  ),
1410
1455
  { concurrency: 20 }
1411
1456
  );
1457
+ return { globalUuidMap, allSummaries };
1458
+ });
1459
+ var buildSummariesByTargetSession = (globalUuidMap, allSummaries) => {
1412
1460
  const summariesByTargetSession = /* @__PURE__ */ new Map();
1413
1461
  for (const summaryData of allSummaries) {
1414
1462
  if (summaryData.leafUuid) {
@@ -1421,21 +1469,22 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
1421
1469
  summariesByTargetSession.get(targetSessionId).push({
1422
1470
  summary: summaryData.summary,
1423
1471
  leafUuid: summaryData.leafUuid,
1424
- // Use summary's own timestamp for sorting, not the target message's timestamp
1425
1472
  timestamp: summaryData.timestamp ?? targetInfo.timestamp,
1426
1473
  sourceFile: summaryData.sourceFile
1427
1474
  });
1428
1475
  }
1429
1476
  }
1430
1477
  }
1431
- const sessions = yield* Effect.all(
1432
- sessionFiles.map((file) => {
1433
- const sessionId = file.replace(".jsonl", "");
1434
- const mtime = fileMtimes.get(sessionId);
1435
- return loadSessionTreeDataInternal(projectName, sessionId, summariesByTargetSession, mtime);
1436
- }),
1437
- { concurrency: 10 }
1438
- );
1478
+ return summariesByTargetSession;
1479
+ };
1480
+ var sortSummaries = (summaries) => {
1481
+ return [...summaries].sort((a, b) => {
1482
+ const timestampCmp = (a.timestamp ?? "").localeCompare(b.timestamp ?? "");
1483
+ if (timestampCmp !== 0) return timestampCmp;
1484
+ return (b.sourceFile ?? "").localeCompare(a.sourceFile ?? "");
1485
+ });
1486
+ };
1487
+ var buildProjectTreeResult = (project, sessions, sort) => {
1439
1488
  const sortedSessions = sortSessions(sessions, sort);
1440
1489
  const filteredSessions = sortedSessions.filter((s) => {
1441
1490
  if (isErrorSessionTitle(s.title)) return false;
@@ -1450,6 +1499,159 @@ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* ()
1450
1499
  sessionCount: filteredSessions.length,
1451
1500
  sessions: filteredSessions
1452
1501
  };
1502
+ };
1503
+ var buildTreeCache = (globalUuidMap, allSummaries, sessions, fileMtimes) => {
1504
+ const uuidMapRecord = {};
1505
+ for (const [key, val] of globalUuidMap) {
1506
+ uuidMapRecord[key] = val;
1507
+ }
1508
+ const sessionsRecord = {};
1509
+ for (const s of sessions) {
1510
+ sessionsRecord[s.id] = {
1511
+ fileMtime: fileMtimes.get(s.id) ?? 0,
1512
+ data: s
1513
+ };
1514
+ }
1515
+ return {
1516
+ version: 1,
1517
+ globalUuidMap: uuidMapRecord,
1518
+ allSummaries,
1519
+ sessions: sessionsRecord
1520
+ };
1521
+ };
1522
+ var updateSessionSummaries = (cached, summariesByTargetSession) => {
1523
+ const newSummaries = sortSummaries(summariesByTargetSession.get(cached.id) ?? []);
1524
+ const oldJson = JSON.stringify(cached.summaries);
1525
+ const newJson = JSON.stringify(newSummaries);
1526
+ if (oldJson === newJson) return cached;
1527
+ const newSortTimestamp = getSessionSortTimestamp({
1528
+ summaries: newSummaries,
1529
+ createdAt: cached.createdAt
1530
+ });
1531
+ return {
1532
+ ...cached,
1533
+ summaries: newSummaries,
1534
+ currentSummary: newSummaries[0]?.summary,
1535
+ sortTimestamp: newSortTimestamp
1536
+ };
1537
+ };
1538
+ var loadProjectTreeData = (projectName, sortOptions) => Effect.gen(function* () {
1539
+ const projectPath = path5.join(getSessionsDir(), projectName);
1540
+ const exists = yield* Effect.tryPromise(
1541
+ () => fs6.access(projectPath).then(() => true).catch(() => false)
1542
+ );
1543
+ if (!exists) return null;
1544
+ const displayName = yield* Effect.tryPromise(() => folderNameToPath(projectName));
1545
+ const project = { name: projectName, displayName, path: projectPath };
1546
+ const sort = sortOptions ?? DEFAULT_SORT;
1547
+ const files = yield* Effect.tryPromise(() => fs6.readdir(projectPath));
1548
+ const sessionFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
1549
+ const sessionFileIds = sessionFiles.map((f) => f.replace(".jsonl", ""));
1550
+ const fileMtimes = /* @__PURE__ */ new Map();
1551
+ yield* Effect.all(
1552
+ sessionFiles.map(
1553
+ (file) => Effect.gen(function* () {
1554
+ const filePath = path5.join(projectPath, file);
1555
+ try {
1556
+ const stat4 = yield* Effect.tryPromise(() => fs6.stat(filePath));
1557
+ fileMtimes.set(file.replace(".jsonl", ""), stat4.mtimeMs);
1558
+ } catch {
1559
+ }
1560
+ })
1561
+ ),
1562
+ { concurrency: 20 }
1563
+ );
1564
+ const cache = yield* Effect.tryPromise(() => loadTreeCache(projectName));
1565
+ if (cache) {
1566
+ const validation = validateCache(cache, sessionFileIds, fileMtimes);
1567
+ if (validation.isFullHit) {
1568
+ log3.debug(`cache hit for ${projectName} (${sessionFileIds.length} sessions)`);
1569
+ const sessions = sessionFileIds.map((id) => cache.sessions[id]?.data).filter((s) => s != null);
1570
+ return buildProjectTreeResult(project, sessions, sort);
1571
+ }
1572
+ const changedCount = validation.changedSessionIds.length + validation.newSessionIds.length + validation.deletedSessionIds.length;
1573
+ log3.debug(
1574
+ `cache partial miss for ${projectName}: ${validation.changedSessionIds.length} changed, ${validation.newSessionIds.length} new, ${validation.deletedSessionIds.length} deleted, ${validation.unchangedSessionIds.length} unchanged`
1575
+ );
1576
+ if (changedCount <= sessionFileIds.length / 2) {
1577
+ const result = yield* loadProjectTreeDataIncremental(
1578
+ projectName,
1579
+ projectPath,
1580
+ files,
1581
+ sessionFiles,
1582
+ fileMtimes,
1583
+ cache,
1584
+ validation,
1585
+ project,
1586
+ sort
1587
+ );
1588
+ return result;
1589
+ }
1590
+ }
1591
+ log3.debug(`full load for ${projectName} (${sessionFileIds.length} sessions)`);
1592
+ return yield* loadProjectTreeDataFull(
1593
+ projectName,
1594
+ projectPath,
1595
+ files,
1596
+ sessionFiles,
1597
+ fileMtimes,
1598
+ project,
1599
+ sort
1600
+ );
1601
+ });
1602
+ var loadProjectTreeDataFull = (projectName, projectPath, files, sessionFiles, fileMtimes, project, sort) => Effect.gen(function* () {
1603
+ const allJsonlFiles = files.filter((f) => f.endsWith(".jsonl"));
1604
+ const { globalUuidMap, allSummaries } = yield* buildPhase1(projectPath, allJsonlFiles);
1605
+ const summariesByTargetSession = buildSummariesByTargetSession(globalUuidMap, allSummaries);
1606
+ const sessions = yield* Effect.all(
1607
+ sessionFiles.map((file) => {
1608
+ const sessionId = file.replace(".jsonl", "");
1609
+ const mtime = fileMtimes.get(sessionId);
1610
+ return loadSessionTreeDataInternal(projectName, sessionId, summariesByTargetSession, mtime);
1611
+ }),
1612
+ { concurrency: 10 }
1613
+ );
1614
+ const cacheData = buildTreeCache(globalUuidMap, allSummaries, sessions, fileMtimes);
1615
+ writeTreeCache(projectName, cacheData).catch((err) => {
1616
+ log3.debug(`cache write failed for ${projectName}: ${err}`);
1617
+ });
1618
+ return buildProjectTreeResult(project, sessions, sort);
1619
+ });
1620
+ var loadProjectTreeDataIncremental = (projectName, projectPath, files, sessionFiles, fileMtimes, cache, validation, project, sort) => Effect.gen(function* () {
1621
+ const allJsonlFiles = files.filter((f) => f.endsWith(".jsonl"));
1622
+ const { globalUuidMap, allSummaries } = yield* buildPhase1(projectPath, allJsonlFiles);
1623
+ const summariesByTargetSession = buildSummariesByTargetSession(globalUuidMap, allSummaries);
1624
+ const sessionsToLoad = [...validation.changedSessionIds, ...validation.newSessionIds];
1625
+ const loadedSessions = yield* Effect.all(
1626
+ sessionsToLoad.map((sessionId) => {
1627
+ const mtime = fileMtimes.get(sessionId);
1628
+ return loadSessionTreeDataInternal(projectName, sessionId, summariesByTargetSession, mtime);
1629
+ }),
1630
+ { concurrency: 10 }
1631
+ );
1632
+ const loadedMap = /* @__PURE__ */ new Map();
1633
+ for (const s of loadedSessions) {
1634
+ loadedMap.set(s.id, s);
1635
+ }
1636
+ const allSessions = [];
1637
+ for (const file of sessionFiles) {
1638
+ const sessionId = file.replace(".jsonl", "");
1639
+ const loaded = loadedMap.get(sessionId);
1640
+ if (loaded) {
1641
+ allSessions.push(loaded);
1642
+ } else if (cache.sessions[sessionId]) {
1643
+ const updated = updateSessionSummaries(
1644
+ cache.sessions[sessionId].data,
1645
+ summariesByTargetSession
1646
+ );
1647
+ allSessions.push({ ...updated, fileMtime: fileMtimes.get(sessionId) });
1648
+ }
1649
+ }
1650
+ const cacheData = buildTreeCache(globalUuidMap, allSummaries, allSessions, fileMtimes);
1651
+ writeTreeCache(projectName, cacheData).catch((err) => {
1652
+ log3.debug(`cache write failed for ${projectName}: ${err}`);
1653
+ });
1654
+ return buildProjectTreeResult(project, allSessions, sort);
1453
1655
  });
1454
1656
  var cleanInvalidMessages = (projectName, sessionId) => Effect.gen(function* () {
1455
1657
  const filePath = path5.join(getSessionsDir(), projectName, `${sessionId}.jsonl`);
@@ -1752,4 +1954,4 @@ var getSessionFiles = (projectName, sessionId) => Effect.gen(function* () {
1752
1954
  });
1753
1955
 
1754
1956
  export { sessionHasSubItems as A, getSessionTooltip as B, validateProgressMessages as C, parseCommandMessage as D, deleteMessageWithChainRepair as E, maskHomePath as F, TREE_ICONS as T, listProjects as a, loadProjectTreeData as b, clearSessions as c, deleteMessage as d, listSessions as e, deleteSession as f, readSession as g, getLogger as h, getSessionFiles as i, renameSession as j, getSessionsDir as k, loadAgentMessages as l, moveSession as m, autoRepairChain as n, folderNameToPath as o, previewCleanup as p, expandHomePath as q, restoreMessage as r, searchSessions as s, splitSession as t, loadSessionTreeData as u, validateChain as v, pathToFolderName as w, sortProjects as x, getTotalTodoCount as y, getDisplayTitle as z };
1755
- //# sourceMappingURL=index3-DNyQGNm8.js.map
1957
+ //# sourceMappingURL=index2-BbHYMsUG.js.map