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.
- package/README.md +368 -0
- package/bin/noter.js +218 -0
- package/bin/noter.js.map +1 -0
- package/package.json +73 -0
- package/packages/client/dist/assets/geist-mono-latin-400-normal-CoULgQGM.woff +0 -0
- package/packages/client/dist/assets/geist-mono-latin-400-normal-LC9RFr9I.woff2 +0 -0
- package/packages/client/dist/assets/index-CBiNAMaA.js +264 -0
- package/packages/client/dist/assets/index-u7i5Fle2.css +1 -0
- package/packages/client/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
- package/packages/client/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
- package/packages/client/dist/assets/space-grotesk-latin-600-normal-BflQw4A9.woff +0 -0
- package/packages/client/dist/assets/space-grotesk-latin-600-normal-DjKNqYRj.woff2 +0 -0
- package/packages/client/dist/assets/vendor-react-DHeZC_T5.js +17 -0
- package/packages/client/dist/index.html +14 -0
- package/packages/server/dist/adapters/claudeAdapter.d.ts +34 -0
- package/packages/server/dist/adapters/claudeAdapter.d.ts.map +1 -0
- package/packages/server/dist/adapters/claudeAdapter.js +281 -0
- package/packages/server/dist/adapters/claudeAdapter.js.map +1 -0
- package/packages/server/dist/adapters/codexAdapter.d.ts +39 -0
- package/packages/server/dist/adapters/codexAdapter.d.ts.map +1 -0
- package/packages/server/dist/adapters/codexAdapter.js +347 -0
- package/packages/server/dist/adapters/codexAdapter.js.map +1 -0
- package/packages/server/dist/adapters/droidAdapter.d.ts +34 -0
- package/packages/server/dist/adapters/droidAdapter.d.ts.map +1 -0
- package/packages/server/dist/adapters/droidAdapter.js +109 -0
- package/packages/server/dist/adapters/droidAdapter.js.map +1 -0
- package/packages/server/dist/adapters/genericAdapter.d.ts +50 -0
- package/packages/server/dist/adapters/genericAdapter.d.ts.map +1 -0
- package/packages/server/dist/adapters/genericAdapter.js +203 -0
- package/packages/server/dist/adapters/genericAdapter.js.map +1 -0
- package/packages/server/dist/adapters/index.d.ts +7 -0
- package/packages/server/dist/adapters/index.d.ts.map +1 -0
- package/packages/server/dist/adapters/index.js +7 -0
- package/packages/server/dist/adapters/index.js.map +1 -0
- package/packages/server/dist/adapters/opencodeAdapter.d.ts +28 -0
- package/packages/server/dist/adapters/opencodeAdapter.d.ts.map +1 -0
- package/packages/server/dist/adapters/opencodeAdapter.js +265 -0
- package/packages/server/dist/adapters/opencodeAdapter.js.map +1 -0
- package/packages/server/dist/adapters/opencodeSessionManager.d.ts +13 -0
- package/packages/server/dist/adapters/opencodeSessionManager.d.ts.map +1 -0
- package/packages/server/dist/adapters/opencodeSessionManager.js +230 -0
- package/packages/server/dist/adapters/opencodeSessionManager.js.map +1 -0
- package/packages/server/dist/adapters/pathUtils.d.ts +54 -0
- package/packages/server/dist/adapters/pathUtils.d.ts.map +1 -0
- package/packages/server/dist/adapters/pathUtils.js +86 -0
- package/packages/server/dist/adapters/pathUtils.js.map +1 -0
- package/packages/server/dist/adapters/piAdapter.d.ts +34 -0
- package/packages/server/dist/adapters/piAdapter.d.ts.map +1 -0
- package/packages/server/dist/adapters/piAdapter.js +307 -0
- package/packages/server/dist/adapters/piAdapter.js.map +1 -0
- package/packages/server/dist/autoDetect.d.ts +15 -0
- package/packages/server/dist/autoDetect.d.ts.map +1 -0
- package/packages/server/dist/autoDetect.js +102 -0
- package/packages/server/dist/autoDetect.js.map +1 -0
- package/packages/server/dist/config.d.ts +29 -0
- package/packages/server/dist/config.d.ts.map +1 -0
- package/packages/server/dist/config.js +96 -0
- package/packages/server/dist/config.js.map +1 -0
- package/packages/server/dist/eventStore.d.ts +14 -0
- package/packages/server/dist/eventStore.d.ts.map +1 -0
- package/packages/server/dist/eventStore.js +35 -0
- package/packages/server/dist/eventStore.js.map +1 -0
- package/packages/server/dist/hookWatcher.d.ts +24 -0
- package/packages/server/dist/hookWatcher.d.ts.map +1 -0
- package/packages/server/dist/hookWatcher.js +152 -0
- package/packages/server/dist/hookWatcher.js.map +1 -0
- package/packages/server/dist/index.d.ts +58 -0
- package/packages/server/dist/index.d.ts.map +1 -0
- package/packages/server/dist/index.js +527 -0
- package/packages/server/dist/index.js.map +1 -0
- package/packages/server/dist/llm/jsonExtractor.d.ts +39 -0
- package/packages/server/dist/llm/jsonExtractor.d.ts.map +1 -0
- package/packages/server/dist/llm/jsonExtractor.js +83 -0
- package/packages/server/dist/llm/jsonExtractor.js.map +1 -0
- package/packages/server/dist/llm/ollamaCache.d.ts +19 -0
- package/packages/server/dist/llm/ollamaCache.d.ts.map +1 -0
- package/packages/server/dist/llm/ollamaCache.js +31 -0
- package/packages/server/dist/llm/ollamaCache.js.map +1 -0
- package/packages/server/dist/llm/ollamaClient.d.ts +29 -0
- package/packages/server/dist/llm/ollamaClient.d.ts.map +1 -0
- package/packages/server/dist/llm/ollamaClient.js +117 -0
- package/packages/server/dist/llm/ollamaClient.js.map +1 -0
- package/packages/server/dist/llm/ollamaQueue.d.ts +7 -0
- package/packages/server/dist/llm/ollamaQueue.d.ts.map +1 -0
- package/packages/server/dist/llm/ollamaQueue.js +28 -0
- package/packages/server/dist/llm/ollamaQueue.js.map +1 -0
- package/packages/server/dist/llm/promptBuilder.d.ts +8 -0
- package/packages/server/dist/llm/promptBuilder.d.ts.map +1 -0
- package/packages/server/dist/llm/promptBuilder.js +85 -0
- package/packages/server/dist/llm/promptBuilder.js.map +1 -0
- package/packages/server/dist/llm/promptSections.d.ts +64 -0
- package/packages/server/dist/llm/promptSections.d.ts.map +1 -0
- package/packages/server/dist/llm/promptSections.js +128 -0
- package/packages/server/dist/llm/promptSections.js.map +1 -0
- package/packages/server/dist/llm/providerModels.d.ts +14 -0
- package/packages/server/dist/llm/providerModels.d.ts.map +1 -0
- package/packages/server/dist/llm/providerModels.js +67 -0
- package/packages/server/dist/llm/providerModels.js.map +1 -0
- package/packages/server/dist/llm/suggester.d.ts +12 -0
- package/packages/server/dist/llm/suggester.d.ts.map +1 -0
- package/packages/server/dist/llm/suggester.js +263 -0
- package/packages/server/dist/llm/suggester.js.map +1 -0
- package/packages/server/dist/llm/summarizer.d.ts +53 -0
- package/packages/server/dist/llm/summarizer.d.ts.map +1 -0
- package/packages/server/dist/llm/summarizer.js +174 -0
- package/packages/server/dist/llm/summarizer.js.map +1 -0
- package/packages/server/dist/persistence.d.ts +42 -0
- package/packages/server/dist/persistence.d.ts.map +1 -0
- package/packages/server/dist/persistence.js +103 -0
- package/packages/server/dist/persistence.js.map +1 -0
- package/packages/server/dist/repoContext.d.ts +60 -0
- package/packages/server/dist/repoContext.d.ts.map +1 -0
- package/packages/server/dist/repoContext.js +197 -0
- package/packages/server/dist/repoContext.js.map +1 -0
- package/packages/server/dist/routes/blueprint.d.ts +7 -0
- package/packages/server/dist/routes/blueprint.d.ts.map +1 -0
- package/packages/server/dist/routes/blueprint.js +529 -0
- package/packages/server/dist/routes/blueprint.js.map +1 -0
- package/packages/server/dist/routes/config.d.ts +17 -0
- package/packages/server/dist/routes/config.d.ts.map +1 -0
- package/packages/server/dist/routes/config.js +282 -0
- package/packages/server/dist/routes/config.js.map +1 -0
- package/packages/server/dist/routes/lmstudio.d.ts +4 -0
- package/packages/server/dist/routes/lmstudio.d.ts.map +1 -0
- package/packages/server/dist/routes/lmstudio.js +67 -0
- package/packages/server/dist/routes/lmstudio.js.map +1 -0
- package/packages/server/dist/routes/notes.d.ts +5 -0
- package/packages/server/dist/routes/notes.d.ts.map +1 -0
- package/packages/server/dist/routes/notes.js +60 -0
- package/packages/server/dist/routes/notes.js.map +1 -0
- package/packages/server/dist/routes/ollama.d.ts +4 -0
- package/packages/server/dist/routes/ollama.d.ts.map +1 -0
- package/packages/server/dist/routes/ollama.js +207 -0
- package/packages/server/dist/routes/ollama.js.map +1 -0
- package/packages/server/dist/routes/prompt.d.ts +4 -0
- package/packages/server/dist/routes/prompt.d.ts.map +1 -0
- package/packages/server/dist/routes/prompt.js +75 -0
- package/packages/server/dist/routes/prompt.js.map +1 -0
- package/packages/server/dist/routes/refineNotes.d.ts +4 -0
- package/packages/server/dist/routes/refineNotes.d.ts.map +1 -0
- package/packages/server/dist/routes/refineNotes.js +87 -0
- package/packages/server/dist/routes/refineNotes.js.map +1 -0
- package/packages/server/dist/routes/repoContext.d.ts +3 -0
- package/packages/server/dist/routes/repoContext.d.ts.map +1 -0
- package/packages/server/dist/routes/repoContext.js +15 -0
- package/packages/server/dist/routes/repoContext.js.map +1 -0
- package/packages/server/dist/routes/sessions.d.ts +15 -0
- package/packages/server/dist/routes/sessions.d.ts.map +1 -0
- package/packages/server/dist/routes/sessions.js +420 -0
- package/packages/server/dist/routes/sessions.js.map +1 -0
- package/packages/server/dist/routes/summarize.d.ts +6 -0
- package/packages/server/dist/routes/summarize.d.ts.map +1 -0
- package/packages/server/dist/routes/summarize.js +85 -0
- package/packages/server/dist/routes/summarize.js.map +1 -0
- package/packages/server/dist/server.d.ts +2 -0
- package/packages/server/dist/server.d.ts.map +1 -0
- package/packages/server/dist/server.js +6 -0
- package/packages/server/dist/server.js.map +1 -0
- package/packages/server/dist/sessionManager.d.ts +41 -0
- package/packages/server/dist/sessionManager.d.ts.map +1 -0
- package/packages/server/dist/sessionManager.js +493 -0
- package/packages/server/dist/sessionManager.js.map +1 -0
- package/packages/server/dist/sessionScanner.d.ts +22 -0
- package/packages/server/dist/sessionScanner.d.ts.map +1 -0
- package/packages/server/dist/sessionScanner.js +165 -0
- package/packages/server/dist/sessionScanner.js.map +1 -0
- package/packages/server/dist/sessionTitle.d.ts +17 -0
- package/packages/server/dist/sessionTitle.d.ts.map +1 -0
- package/packages/server/dist/sessionTitle.js +321 -0
- package/packages/server/dist/sessionTitle.js.map +1 -0
- package/packages/server/dist/stateManager.d.ts +38 -0
- package/packages/server/dist/stateManager.d.ts.map +1 -0
- package/packages/server/dist/stateManager.js +83 -0
- package/packages/server/dist/stateManager.js.map +1 -0
- package/packages/server/dist/wsServer.d.ts +27 -0
- package/packages/server/dist/wsServer.d.ts.map +1 -0
- package/packages/server/dist/wsServer.js +144 -0
- package/packages/server/dist/wsServer.js.map +1 -0
- package/packages/shared/dist/index.d.ts +3 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +3 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/shared/dist/llm/mambaDetect.d.ts +84 -0
- package/packages/shared/dist/llm/mambaDetect.d.ts.map +1 -0
- package/packages/shared/dist/llm/mambaDetect.js +205 -0
- package/packages/shared/dist/llm/mambaDetect.js.map +1 -0
- package/packages/shared/dist/types.d.ts +184 -0
- package/packages/shared/dist/types.d.ts.map +1 -0
- package/packages/shared/dist/types.js +2 -0
- package/packages/shared/dist/types.js.map +1 -0
- 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"}
|