noterai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +368 -0
  2. package/bin/noter.js +218 -0
  3. package/bin/noter.js.map +1 -0
  4. package/package.json +73 -0
  5. package/packages/client/dist/assets/geist-mono-latin-400-normal-CoULgQGM.woff +0 -0
  6. package/packages/client/dist/assets/geist-mono-latin-400-normal-LC9RFr9I.woff2 +0 -0
  7. package/packages/client/dist/assets/index-CBiNAMaA.js +264 -0
  8. package/packages/client/dist/assets/index-u7i5Fle2.css +1 -0
  9. package/packages/client/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  10. package/packages/client/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  11. package/packages/client/dist/assets/space-grotesk-latin-600-normal-BflQw4A9.woff +0 -0
  12. package/packages/client/dist/assets/space-grotesk-latin-600-normal-DjKNqYRj.woff2 +0 -0
  13. package/packages/client/dist/assets/vendor-react-DHeZC_T5.js +17 -0
  14. package/packages/client/dist/index.html +14 -0
  15. package/packages/server/dist/adapters/claudeAdapter.d.ts +34 -0
  16. package/packages/server/dist/adapters/claudeAdapter.d.ts.map +1 -0
  17. package/packages/server/dist/adapters/claudeAdapter.js +281 -0
  18. package/packages/server/dist/adapters/claudeAdapter.js.map +1 -0
  19. package/packages/server/dist/adapters/codexAdapter.d.ts +39 -0
  20. package/packages/server/dist/adapters/codexAdapter.d.ts.map +1 -0
  21. package/packages/server/dist/adapters/codexAdapter.js +347 -0
  22. package/packages/server/dist/adapters/codexAdapter.js.map +1 -0
  23. package/packages/server/dist/adapters/droidAdapter.d.ts +34 -0
  24. package/packages/server/dist/adapters/droidAdapter.d.ts.map +1 -0
  25. package/packages/server/dist/adapters/droidAdapter.js +109 -0
  26. package/packages/server/dist/adapters/droidAdapter.js.map +1 -0
  27. package/packages/server/dist/adapters/genericAdapter.d.ts +50 -0
  28. package/packages/server/dist/adapters/genericAdapter.d.ts.map +1 -0
  29. package/packages/server/dist/adapters/genericAdapter.js +203 -0
  30. package/packages/server/dist/adapters/genericAdapter.js.map +1 -0
  31. package/packages/server/dist/adapters/index.d.ts +7 -0
  32. package/packages/server/dist/adapters/index.d.ts.map +1 -0
  33. package/packages/server/dist/adapters/index.js +7 -0
  34. package/packages/server/dist/adapters/index.js.map +1 -0
  35. package/packages/server/dist/adapters/opencodeAdapter.d.ts +28 -0
  36. package/packages/server/dist/adapters/opencodeAdapter.d.ts.map +1 -0
  37. package/packages/server/dist/adapters/opencodeAdapter.js +265 -0
  38. package/packages/server/dist/adapters/opencodeAdapter.js.map +1 -0
  39. package/packages/server/dist/adapters/opencodeSessionManager.d.ts +13 -0
  40. package/packages/server/dist/adapters/opencodeSessionManager.d.ts.map +1 -0
  41. package/packages/server/dist/adapters/opencodeSessionManager.js +230 -0
  42. package/packages/server/dist/adapters/opencodeSessionManager.js.map +1 -0
  43. package/packages/server/dist/adapters/pathUtils.d.ts +54 -0
  44. package/packages/server/dist/adapters/pathUtils.d.ts.map +1 -0
  45. package/packages/server/dist/adapters/pathUtils.js +86 -0
  46. package/packages/server/dist/adapters/pathUtils.js.map +1 -0
  47. package/packages/server/dist/adapters/piAdapter.d.ts +34 -0
  48. package/packages/server/dist/adapters/piAdapter.d.ts.map +1 -0
  49. package/packages/server/dist/adapters/piAdapter.js +307 -0
  50. package/packages/server/dist/adapters/piAdapter.js.map +1 -0
  51. package/packages/server/dist/autoDetect.d.ts +15 -0
  52. package/packages/server/dist/autoDetect.d.ts.map +1 -0
  53. package/packages/server/dist/autoDetect.js +102 -0
  54. package/packages/server/dist/autoDetect.js.map +1 -0
  55. package/packages/server/dist/config.d.ts +29 -0
  56. package/packages/server/dist/config.d.ts.map +1 -0
  57. package/packages/server/dist/config.js +96 -0
  58. package/packages/server/dist/config.js.map +1 -0
  59. package/packages/server/dist/eventStore.d.ts +14 -0
  60. package/packages/server/dist/eventStore.d.ts.map +1 -0
  61. package/packages/server/dist/eventStore.js +35 -0
  62. package/packages/server/dist/eventStore.js.map +1 -0
  63. package/packages/server/dist/hookWatcher.d.ts +24 -0
  64. package/packages/server/dist/hookWatcher.d.ts.map +1 -0
  65. package/packages/server/dist/hookWatcher.js +152 -0
  66. package/packages/server/dist/hookWatcher.js.map +1 -0
  67. package/packages/server/dist/index.d.ts +58 -0
  68. package/packages/server/dist/index.d.ts.map +1 -0
  69. package/packages/server/dist/index.js +527 -0
  70. package/packages/server/dist/index.js.map +1 -0
  71. package/packages/server/dist/llm/jsonExtractor.d.ts +39 -0
  72. package/packages/server/dist/llm/jsonExtractor.d.ts.map +1 -0
  73. package/packages/server/dist/llm/jsonExtractor.js +83 -0
  74. package/packages/server/dist/llm/jsonExtractor.js.map +1 -0
  75. package/packages/server/dist/llm/ollamaCache.d.ts +19 -0
  76. package/packages/server/dist/llm/ollamaCache.d.ts.map +1 -0
  77. package/packages/server/dist/llm/ollamaCache.js +31 -0
  78. package/packages/server/dist/llm/ollamaCache.js.map +1 -0
  79. package/packages/server/dist/llm/ollamaClient.d.ts +29 -0
  80. package/packages/server/dist/llm/ollamaClient.d.ts.map +1 -0
  81. package/packages/server/dist/llm/ollamaClient.js +117 -0
  82. package/packages/server/dist/llm/ollamaClient.js.map +1 -0
  83. package/packages/server/dist/llm/ollamaQueue.d.ts +7 -0
  84. package/packages/server/dist/llm/ollamaQueue.d.ts.map +1 -0
  85. package/packages/server/dist/llm/ollamaQueue.js +28 -0
  86. package/packages/server/dist/llm/ollamaQueue.js.map +1 -0
  87. package/packages/server/dist/llm/promptBuilder.d.ts +8 -0
  88. package/packages/server/dist/llm/promptBuilder.d.ts.map +1 -0
  89. package/packages/server/dist/llm/promptBuilder.js +85 -0
  90. package/packages/server/dist/llm/promptBuilder.js.map +1 -0
  91. package/packages/server/dist/llm/promptSections.d.ts +64 -0
  92. package/packages/server/dist/llm/promptSections.d.ts.map +1 -0
  93. package/packages/server/dist/llm/promptSections.js +128 -0
  94. package/packages/server/dist/llm/promptSections.js.map +1 -0
  95. package/packages/server/dist/llm/providerModels.d.ts +14 -0
  96. package/packages/server/dist/llm/providerModels.d.ts.map +1 -0
  97. package/packages/server/dist/llm/providerModels.js +67 -0
  98. package/packages/server/dist/llm/providerModels.js.map +1 -0
  99. package/packages/server/dist/llm/suggester.d.ts +12 -0
  100. package/packages/server/dist/llm/suggester.d.ts.map +1 -0
  101. package/packages/server/dist/llm/suggester.js +263 -0
  102. package/packages/server/dist/llm/suggester.js.map +1 -0
  103. package/packages/server/dist/llm/summarizer.d.ts +53 -0
  104. package/packages/server/dist/llm/summarizer.d.ts.map +1 -0
  105. package/packages/server/dist/llm/summarizer.js +174 -0
  106. package/packages/server/dist/llm/summarizer.js.map +1 -0
  107. package/packages/server/dist/persistence.d.ts +42 -0
  108. package/packages/server/dist/persistence.d.ts.map +1 -0
  109. package/packages/server/dist/persistence.js +103 -0
  110. package/packages/server/dist/persistence.js.map +1 -0
  111. package/packages/server/dist/repoContext.d.ts +60 -0
  112. package/packages/server/dist/repoContext.d.ts.map +1 -0
  113. package/packages/server/dist/repoContext.js +197 -0
  114. package/packages/server/dist/repoContext.js.map +1 -0
  115. package/packages/server/dist/routes/blueprint.d.ts +7 -0
  116. package/packages/server/dist/routes/blueprint.d.ts.map +1 -0
  117. package/packages/server/dist/routes/blueprint.js +529 -0
  118. package/packages/server/dist/routes/blueprint.js.map +1 -0
  119. package/packages/server/dist/routes/config.d.ts +17 -0
  120. package/packages/server/dist/routes/config.d.ts.map +1 -0
  121. package/packages/server/dist/routes/config.js +282 -0
  122. package/packages/server/dist/routes/config.js.map +1 -0
  123. package/packages/server/dist/routes/lmstudio.d.ts +4 -0
  124. package/packages/server/dist/routes/lmstudio.d.ts.map +1 -0
  125. package/packages/server/dist/routes/lmstudio.js +67 -0
  126. package/packages/server/dist/routes/lmstudio.js.map +1 -0
  127. package/packages/server/dist/routes/notes.d.ts +5 -0
  128. package/packages/server/dist/routes/notes.d.ts.map +1 -0
  129. package/packages/server/dist/routes/notes.js +60 -0
  130. package/packages/server/dist/routes/notes.js.map +1 -0
  131. package/packages/server/dist/routes/ollama.d.ts +4 -0
  132. package/packages/server/dist/routes/ollama.d.ts.map +1 -0
  133. package/packages/server/dist/routes/ollama.js +207 -0
  134. package/packages/server/dist/routes/ollama.js.map +1 -0
  135. package/packages/server/dist/routes/prompt.d.ts +4 -0
  136. package/packages/server/dist/routes/prompt.d.ts.map +1 -0
  137. package/packages/server/dist/routes/prompt.js +75 -0
  138. package/packages/server/dist/routes/prompt.js.map +1 -0
  139. package/packages/server/dist/routes/refineNotes.d.ts +4 -0
  140. package/packages/server/dist/routes/refineNotes.d.ts.map +1 -0
  141. package/packages/server/dist/routes/refineNotes.js +87 -0
  142. package/packages/server/dist/routes/refineNotes.js.map +1 -0
  143. package/packages/server/dist/routes/repoContext.d.ts +3 -0
  144. package/packages/server/dist/routes/repoContext.d.ts.map +1 -0
  145. package/packages/server/dist/routes/repoContext.js +15 -0
  146. package/packages/server/dist/routes/repoContext.js.map +1 -0
  147. package/packages/server/dist/routes/sessions.d.ts +15 -0
  148. package/packages/server/dist/routes/sessions.d.ts.map +1 -0
  149. package/packages/server/dist/routes/sessions.js +420 -0
  150. package/packages/server/dist/routes/sessions.js.map +1 -0
  151. package/packages/server/dist/routes/summarize.d.ts +6 -0
  152. package/packages/server/dist/routes/summarize.d.ts.map +1 -0
  153. package/packages/server/dist/routes/summarize.js +85 -0
  154. package/packages/server/dist/routes/summarize.js.map +1 -0
  155. package/packages/server/dist/server.d.ts +2 -0
  156. package/packages/server/dist/server.d.ts.map +1 -0
  157. package/packages/server/dist/server.js +6 -0
  158. package/packages/server/dist/server.js.map +1 -0
  159. package/packages/server/dist/sessionManager.d.ts +41 -0
  160. package/packages/server/dist/sessionManager.d.ts.map +1 -0
  161. package/packages/server/dist/sessionManager.js +493 -0
  162. package/packages/server/dist/sessionManager.js.map +1 -0
  163. package/packages/server/dist/sessionScanner.d.ts +22 -0
  164. package/packages/server/dist/sessionScanner.d.ts.map +1 -0
  165. package/packages/server/dist/sessionScanner.js +165 -0
  166. package/packages/server/dist/sessionScanner.js.map +1 -0
  167. package/packages/server/dist/sessionTitle.d.ts +17 -0
  168. package/packages/server/dist/sessionTitle.d.ts.map +1 -0
  169. package/packages/server/dist/sessionTitle.js +321 -0
  170. package/packages/server/dist/sessionTitle.js.map +1 -0
  171. package/packages/server/dist/stateManager.d.ts +38 -0
  172. package/packages/server/dist/stateManager.d.ts.map +1 -0
  173. package/packages/server/dist/stateManager.js +83 -0
  174. package/packages/server/dist/stateManager.js.map +1 -0
  175. package/packages/server/dist/wsServer.d.ts +27 -0
  176. package/packages/server/dist/wsServer.d.ts.map +1 -0
  177. package/packages/server/dist/wsServer.js +144 -0
  178. package/packages/server/dist/wsServer.js.map +1 -0
  179. package/packages/shared/dist/index.d.ts +3 -0
  180. package/packages/shared/dist/index.d.ts.map +1 -0
  181. package/packages/shared/dist/index.js +3 -0
  182. package/packages/shared/dist/index.js.map +1 -0
  183. package/packages/shared/dist/llm/mambaDetect.d.ts +84 -0
  184. package/packages/shared/dist/llm/mambaDetect.d.ts.map +1 -0
  185. package/packages/shared/dist/llm/mambaDetect.js +205 -0
  186. package/packages/shared/dist/llm/mambaDetect.js.map +1 -0
  187. package/packages/shared/dist/types.d.ts +184 -0
  188. package/packages/shared/dist/types.d.ts.map +1 -0
  189. package/packages/shared/dist/types.js +2 -0
  190. package/packages/shared/dist/types.js.map +1 -0
  191. package/scripts/postbuild.js +70 -0
@@ -0,0 +1,493 @@
1
+ /**
2
+ * SessionManager — manages multiple concurrent session files for file-watching adapters.
3
+ *
4
+ * Each session is isolated in its own event slice. Only the active session's
5
+ * events flow into the shared global EventStore. Switching sessions clears
6
+ * the shared store and replays the selected session's events.
7
+ */
8
+ import { watch } from "fs";
9
+ import { createReadStream, existsSync, statSync } from "fs";
10
+ import { createInterface } from "readline";
11
+ import { join, basename } from "path";
12
+ import { collectFiles } from "./adapters/pathUtils.js";
13
+ const POLL_INTERVAL_MS = 1000;
14
+ import { extractTitleFromFile } from "./sessionTitle.js";
15
+ export function extractTitle(filePath) {
16
+ return extractTitleFromFile(filePath);
17
+ }
18
+ function extractMessageText(msg) {
19
+ if (!msg)
20
+ return undefined;
21
+ if (typeof msg.content === "string")
22
+ return msg.content;
23
+ if (Array.isArray(msg.content)) {
24
+ return msg.content
25
+ .filter((c) => c &&
26
+ typeof c === "object" &&
27
+ "text" in c)
28
+ .map((c) => c.text)
29
+ .filter((t) => typeof t === "string")
30
+ .join("");
31
+ }
32
+ if (typeof msg.text === "string")
33
+ return msg.text;
34
+ return undefined;
35
+ }
36
+ export function createSessionManager(deps) {
37
+ const { sessionDir, filePattern, recursive, eventStore, ws, summarizer, normalizeEvent, source, } = deps;
38
+ let started = false;
39
+ let dirWatcher = null;
40
+ let pollTimer = null;
41
+ const tailers = new Map();
42
+ let activeSessionId;
43
+ let handleSignal = null;
44
+ // Track non-active session event counts to detect changes for WS notification
45
+ let lastNonActiveEventCounts = new Map();
46
+ function pushToGlobal(event) {
47
+ eventStore.push(event);
48
+ ws.broadcast({ type: "event", payload: event });
49
+ summarizer.handleEvent(event);
50
+ }
51
+ // Push event to store only — no broadcast, no summarizer.
52
+ // Used during replay where we must not trigger premature summarization
53
+ // before the full event set is loaded. The caller triggers summarization
54
+ // after replay completes if needed.
55
+ function pushToStoreOnly(event) {
56
+ eventStore.push(event);
57
+ }
58
+ function processFile(filePath) {
59
+ const tailer = tailers.get(filePath);
60
+ if (!tailer || tailer.isProcessing || !existsSync(filePath)) {
61
+ return;
62
+ }
63
+ tailer.isProcessing = true;
64
+ try {
65
+ const stats = statSync(filePath);
66
+ const currentSize = stats.size;
67
+ if (currentSize <= tailer.lastSize) {
68
+ tailer.isProcessing = false;
69
+ return;
70
+ }
71
+ const stream = createReadStream(filePath, {
72
+ start: tailer.lastSize,
73
+ end: currentSize - 1, // Fix: prevent reading past currentSize and corrupting incremental state
74
+ encoding: "utf-8",
75
+ });
76
+ stream.on("error", (err) => {
77
+ console.error(`[SessionManager] Stream error for ${filePath}:`, err);
78
+ tailer.isProcessing = false;
79
+ tailer.lineBuffer = "";
80
+ // Stream error may have delivered partial events; check for changes
81
+ setImmediate(() => notifySessionChanges());
82
+ });
83
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
84
+ const now = Date.now();
85
+ const fileMtime = stats.mtimeMs;
86
+ // If file is significantly older than now, timestamps that are very recent
87
+ // are likely bogus (e.g. normalizer fell back to Date.now() for events
88
+ // without an explicit timestamp like session_start). Use file mtime instead.
89
+ const isHistoricalFile = now - fileMtime > 60_000;
90
+ rl.on("line", (line) => {
91
+ tailer.lineBuffer += line;
92
+ const trimmed = tailer.lineBuffer.trim();
93
+ if (!trimmed) {
94
+ tailer.lineBuffer = "";
95
+ return;
96
+ }
97
+ try {
98
+ const parsed = JSON.parse(trimmed);
99
+ tailer.lineBuffer = "";
100
+ const event = normalizeEvent(parsed);
101
+ if (event) {
102
+ // Enforce source
103
+ event.source = source;
104
+ // Fix bogus timestamps: if event timestamp is very recent but file is old,
105
+ // the normalizer likely used Date.now() fallback. Use file mtime instead.
106
+ if (isHistoricalFile && now - event.timestamp < 60_000) {
107
+ event.timestamp = fileMtime;
108
+ }
109
+ tailer.events.push(event);
110
+ // Prevent lastEventAt from jumping backward when processing older events
111
+ tailer.lastEventAt = Math.max(tailer.lastEventAt, event.timestamp);
112
+ // Only push to global if this session is active
113
+ if (activeSessionId === getSessionId(filePath)) {
114
+ pushToGlobal(event);
115
+ }
116
+ }
117
+ }
118
+ catch {
119
+ // Incomplete JSON — keep buffering
120
+ }
121
+ });
122
+ rl.on("close", () => {
123
+ tailer.lastSize = currentSize;
124
+ tailer.isProcessing = false;
125
+ // Schedule change detection after async read completes so
126
+ // notifySessionChanges sees updated tailer.events.
127
+ setImmediate(() => notifySessionChanges());
128
+ });
129
+ rl.on("error", (err) => {
130
+ console.error(`[SessionManager] Readline error for ${filePath}:`, err);
131
+ tailer.isProcessing = false;
132
+ tailer.lineBuffer = "";
133
+ // Readline error may have delivered partial events; check for changes
134
+ setImmediate(() => notifySessionChanges());
135
+ });
136
+ }
137
+ catch (err) {
138
+ console.error(`[SessionManager] Process error for ${filePath}:`, err);
139
+ tailer.isProcessing = false;
140
+ tailer.lineBuffer = "";
141
+ }
142
+ }
143
+ function getSessionId(filePath) {
144
+ return basename(filePath, ".jsonl");
145
+ }
146
+ function registerFile(filePath) {
147
+ if (tailers.has(filePath))
148
+ return;
149
+ const title = extractTitle(filePath);
150
+ let startedAt = 0;
151
+ let lastEventAt = 0;
152
+ try {
153
+ if (existsSync(filePath)) {
154
+ const stats = statSync(filePath);
155
+ // Use file birth time as startedAt, modification time as lastEventAt
156
+ startedAt = stats.birthtimeMs || stats.ctimeMs;
157
+ lastEventAt = stats.mtimeMs;
158
+ }
159
+ }
160
+ catch {
161
+ // ignore permission errors
162
+ }
163
+ tailers.set(filePath, {
164
+ lastSize: 0,
165
+ isProcessing: false,
166
+ lineBuffer: "",
167
+ events: [],
168
+ lastEventAt,
169
+ startedAt,
170
+ title,
171
+ });
172
+ console.error(`[SessionManager] Registered session file: ${filePath}`);
173
+ // Notify clients that a new session is available so UI can refresh
174
+ ws.broadcast({ type: "sessions-update", payload: { total: tailers.size } });
175
+ }
176
+ function scanFiles() {
177
+ const files = [];
178
+ collectFiles(sessionDir, filePattern, recursive, files);
179
+ for (const filePath of files) {
180
+ registerFile(filePath);
181
+ }
182
+ }
183
+ function pollAllFiles() {
184
+ for (const filePath of tailers.keys()) {
185
+ processFile(filePath);
186
+ }
187
+ }
188
+ function notifySessionChanges() {
189
+ // Check if any non-active session's event count changed since last check.
190
+ // This ensures the client refreshes session list even when no WS 'event'
191
+ // messages are flowing (which only happens for the active session).
192
+ let changed = false;
193
+ const currentIds = new Set();
194
+ for (const [filePath, tailer] of tailers) {
195
+ const id = getSessionId(filePath);
196
+ currentIds.add(id);
197
+ if (id === activeSessionId)
198
+ continue;
199
+ const prev = lastNonActiveEventCounts.get(id) ?? 0;
200
+ if (tailer.events.length !== prev) {
201
+ // Re-extract title now that the file has more content —
202
+ // a session with only session_start would have had a short/UUID title
203
+ // at registration time, but after more events the title can be resolved.
204
+ const newTitle = extractTitle(filePath);
205
+ if (newTitle && newTitle !== tailer.title) {
206
+ tailer.title = newTitle;
207
+ }
208
+ lastNonActiveEventCounts.set(id, tailer.events.length);
209
+ changed = true;
210
+ }
211
+ }
212
+ // Remove entries for sessions that no longer exist
213
+ for (const id of lastNonActiveEventCounts.keys()) {
214
+ if (!currentIds.has(id)) {
215
+ lastNonActiveEventCounts.delete(id);
216
+ }
217
+ }
218
+ if (changed) {
219
+ ws.broadcast({
220
+ type: "sessions-update",
221
+ payload: { total: tailers.size },
222
+ });
223
+ }
224
+ }
225
+ async function replaySession(filePath) {
226
+ const tailer = tailers.get(filePath);
227
+ if (!tailer)
228
+ return;
229
+ // ALways fetch latest events before replaying as a fallback
230
+ // to ensure we don't miss anything that background polling hasn't caught yet.
231
+ if (existsSync(filePath)) {
232
+ try {
233
+ await processFileAsync(filePath);
234
+ }
235
+ catch {
236
+ /* ignore */
237
+ }
238
+ }
239
+ // Clear global store and replay all cached events for this session.
240
+ // Use pushToStoreOnly to avoid per-event WS broadcasts during replay;
241
+ // the caller (selectSession) will broadcast a single sync message.
242
+ eventStore.clear();
243
+ for (const event of tailer.events) {
244
+ pushToStoreOnly(event);
245
+ }
246
+ }
247
+ /** Process file synchronously and return a Promise that resolves when readline finishes. */
248
+ function processFileAsync(filePath) {
249
+ return new Promise((resolve) => {
250
+ const tailer = tailers.get(filePath);
251
+ if (!tailer || !existsSync(filePath)) {
252
+ resolve();
253
+ return;
254
+ }
255
+ // If already processing, wait until it finishes
256
+ if (tailer.isProcessing) {
257
+ const checkInterval = setInterval(() => {
258
+ if (!tailer.isProcessing) {
259
+ clearInterval(checkInterval);
260
+ // After it finishes, check if we need to read more
261
+ const stats = statSync(filePath);
262
+ if (stats.size > tailer.lastSize) {
263
+ processFileAsync(filePath).then(resolve);
264
+ }
265
+ else {
266
+ resolve();
267
+ }
268
+ }
269
+ }, 50);
270
+ return;
271
+ }
272
+ tailer.isProcessing = true;
273
+ try {
274
+ const stats = statSync(filePath);
275
+ const currentSize = stats.size;
276
+ if (currentSize <= tailer.lastSize) {
277
+ tailer.isProcessing = false;
278
+ resolve();
279
+ return;
280
+ }
281
+ const stream = createReadStream(filePath, {
282
+ start: tailer.lastSize,
283
+ end: currentSize - 1, // Fix: prevent reading past currentSize and corrupting incremental state
284
+ encoding: "utf-8",
285
+ });
286
+ stream.on("error", (err) => {
287
+ console.error(`[SessionManager] Stream error for ${filePath}:`, err);
288
+ tailer.isProcessing = false;
289
+ tailer.lineBuffer = "";
290
+ resolve();
291
+ });
292
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
293
+ const now = Date.now();
294
+ const fileMtime = stats.mtimeMs;
295
+ const isHistoricalFile = now - fileMtime > 60_000;
296
+ rl.on("line", (line) => {
297
+ tailer.lineBuffer += line;
298
+ const trimmed = tailer.lineBuffer.trim();
299
+ if (!trimmed) {
300
+ tailer.lineBuffer = "";
301
+ return;
302
+ }
303
+ try {
304
+ const parsed = JSON.parse(trimmed);
305
+ tailer.lineBuffer = "";
306
+ const event = normalizeEvent(parsed);
307
+ if (event) {
308
+ // Enforce source
309
+ event.source = source;
310
+ // Fix bogus timestamps: if event timestamp is very recent but file is old,
311
+ // the normalizer likely used Date.now() fallback. Use file mtime instead.
312
+ if (isHistoricalFile && now - event.timestamp < 60_000) {
313
+ event.timestamp = fileMtime;
314
+ }
315
+ tailer.events.push(event);
316
+ // Prevent lastEventAt from jumping backward when processing older events
317
+ tailer.lastEventAt = Math.max(tailer.lastEventAt, event.timestamp);
318
+ // Only push to global if this session is active
319
+ if (activeSessionId === getSessionId(filePath)) {
320
+ pushToGlobal(event);
321
+ }
322
+ }
323
+ }
324
+ catch {
325
+ // Incomplete JSON — keep buffering
326
+ }
327
+ });
328
+ rl.on("close", () => {
329
+ tailer.lastSize = currentSize;
330
+ tailer.isProcessing = false;
331
+ // Schedule change detection after async read completes so
332
+ // notifySessionChanges sees updated tailer.events.
333
+ setImmediate(() => notifySessionChanges());
334
+ resolve();
335
+ });
336
+ rl.on("error", (err) => {
337
+ console.error(`[SessionManager] Readline error for ${filePath}:`, err);
338
+ tailer.isProcessing = false;
339
+ tailer.lineBuffer = "";
340
+ resolve();
341
+ });
342
+ }
343
+ catch (err) {
344
+ console.error(`[SessionManager] Process error for ${filePath}:`, err);
345
+ tailer.isProcessing = false;
346
+ tailer.lineBuffer = "";
347
+ resolve();
348
+ }
349
+ });
350
+ }
351
+ const stopFn = async () => {
352
+ started = false;
353
+ if (handleSignal) {
354
+ process.off("SIGINT", handleSignal);
355
+ process.off("SIGTERM", handleSignal);
356
+ handleSignal = null;
357
+ }
358
+ if (dirWatcher) {
359
+ dirWatcher.close();
360
+ dirWatcher = null;
361
+ }
362
+ if (pollTimer) {
363
+ clearInterval(pollTimer);
364
+ pollTimer = null;
365
+ }
366
+ tailers.clear();
367
+ console.error("[SessionManager] Stopped");
368
+ };
369
+ return {
370
+ start: async () => {
371
+ started = true;
372
+ if (!existsSync(sessionDir)) {
373
+ console.error(`[SessionManager] Session directory not found: ${sessionDir}`);
374
+ }
375
+ else {
376
+ scanFiles();
377
+ }
378
+ if (existsSync(sessionDir)) {
379
+ try {
380
+ dirWatcher = watch(sessionDir, { recursive }, (eventType, filename) => {
381
+ if (filename && filePattern(filename)) {
382
+ const filePath = recursive
383
+ ? join(sessionDir, filename)
384
+ : join(sessionDir, filename);
385
+ registerFile(filePath);
386
+ }
387
+ });
388
+ dirWatcher.on("error", (err) => {
389
+ console.error(`[SessionManager] Watcher error: ${err.message}`);
390
+ // On EMFILE, close watcher and fall back to polling only
391
+ if (err.code === "EMFILE") {
392
+ dirWatcher?.close();
393
+ dirWatcher = null;
394
+ console.error("[SessionManager] Switched to polling-only mode (EMFILE)");
395
+ }
396
+ });
397
+ }
398
+ catch (err) {
399
+ console.error(`[SessionManager] Failed to start watcher: ${err.message}`);
400
+ }
401
+ }
402
+ pollTimer = setInterval(() => {
403
+ scanFiles();
404
+ pollAllFiles();
405
+ notifySessionChanges();
406
+ }, POLL_INTERVAL_MS);
407
+ handleSignal = () => {
408
+ void stopFn();
409
+ };
410
+ process.on("SIGINT", handleSignal);
411
+ process.on("SIGTERM", handleSignal);
412
+ console.error(`[SessionManager] Watching ${sessionDir} for sessions`);
413
+ },
414
+ stop: stopFn,
415
+ getSessions: () => {
416
+ const sessions = [];
417
+ for (const [filePath, tailer] of tailers) {
418
+ // Use event timestamps when available, otherwise fall back to file stats from registration
419
+ const startedAt = tailer.events.length > 0
420
+ ? tailer.events[0].timestamp
421
+ : (tailer.startedAt ?? 0);
422
+ // Ensure lastEventAt is always valid — fall back to file mtime or startedAt
423
+ const lastEventAt = tailer.lastEventAt || tailer.startedAt || startedAt || Date.now();
424
+ sessions.push({
425
+ id: getSessionId(filePath),
426
+ path: filePath,
427
+ title: tailer.title,
428
+ startedAt,
429
+ lastEventAt,
430
+ eventCount: tailer.events.length,
431
+ active: activeSessionId === getSessionId(filePath),
432
+ });
433
+ }
434
+ sessions.sort((a, b) => b.lastEventAt - a.lastEventAt);
435
+ return sessions;
436
+ },
437
+ getActiveSession: () => {
438
+ if (!activeSessionId)
439
+ return undefined;
440
+ for (const [filePath, tailer] of tailers) {
441
+ if (activeSessionId === getSessionId(filePath)) {
442
+ const startedAt = tailer.events.length > 0
443
+ ? tailer.events[0].timestamp
444
+ : (tailer.startedAt ?? 0);
445
+ const lastEventAt = tailer.lastEventAt || tailer.startedAt || startedAt || Date.now();
446
+ return {
447
+ id: activeSessionId,
448
+ path: filePath,
449
+ title: tailer.title,
450
+ startedAt,
451
+ lastEventAt,
452
+ eventCount: tailer.events.length,
453
+ active: true,
454
+ };
455
+ }
456
+ }
457
+ return undefined;
458
+ },
459
+ selectSession: async (id) => {
460
+ const filePath = Array.from(tailers.keys()).find((p) => getSessionId(p) === id);
461
+ if (!filePath)
462
+ return false;
463
+ activeSessionId = id;
464
+ // Reset summarizer state so counters and first-summary flag from
465
+ // the previous session do not leak into this one.
466
+ summarizer.resetForSessionSwitch();
467
+ await replaySession(filePath);
468
+ // Clear session-scoped state so stale suggestions/summary don't leak across sessions
469
+ const { stateManager } = await import("./stateManager.js");
470
+ stateManager.setSuggestions([]);
471
+ stateManager.setSummary(null);
472
+ // Broadcast sync so all panels refresh
473
+ ws.broadcast({
474
+ type: "sync",
475
+ payload: { ...stateManager.getState(), events: eventStore.getAll() },
476
+ });
477
+ // Trigger summarization directly — the EventStore is already fully
478
+ // populated by replaySession, and triggerSummarization reads from it.
479
+ // No need for a handleEvent loop which would cause mid-replay
480
+ // auto-summarizations and counter pollution.
481
+ const sessionEvents = tailers.get(filePath)?.events ?? [];
482
+ const storeCount = eventStore.getAll().length;
483
+ console.error(`[replaySession] session=${id} tailer.events=${sessionEvents.length} eventStore=${storeCount}`);
484
+ if (sessionEvents.length > 0) {
485
+ void summarizer.triggerSummarization();
486
+ }
487
+ console.error(`[SessionManager] Switched to session: ${id}`);
488
+ return true;
489
+ },
490
+ isRunning: () => started,
491
+ };
492
+ }
493
+ //# sourceMappingURL=sessionManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionManager.js","sourceRoot":"","sources":["../src/sessionManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Session scanner — discovers session files for file-watching adapters.
3
+ *
4
+ * Each harness stores sessions differently:
5
+ * - claude-code: ~/.claude/transcripts/*.jsonl
6
+ * - pi: ~/.pi/agent/sessions/<workspace-dir>/*.jsonl
7
+ * - codex: ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl
8
+ * - factory-droid: ~/.factory/sessions/<escaped-cwd>/*.jsonl (recursive)
9
+ * - generic: single file (no sessions) or GENERIC_SESSION_DIR if set
10
+ * - opencode: SSE stream (no sessions)
11
+ */
12
+ import type { SessionInfo } from '../../shared/dist/index.js';
13
+ /**
14
+ * Estimate event count from file size instead of reading the entire file.
15
+ * JSONL lines are typically 200-800 bytes each. Using 300 as a reasonable
16
+ * average avoids reading potentially 100MB+ files line-by-line just to
17
+ * count entries for display purposes.
18
+ */
19
+ export declare function estimateEventCount(filePath: string): number;
20
+ export declare function hasSessionSupport(harness: string): boolean;
21
+ export declare function scanSessions(harness: string, activeFile?: string): SessionInfo[];
22
+ //# sourceMappingURL=sessionScanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionScanner.d.ts","sourceRoot":"","sources":["../src/sessionScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA6CjD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ3D;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG1D;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAqFhF"}