litmus-cli 1.4.72 → 1.4.74
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 +13 -0
- package/dist/commands/connect.d.ts +17 -1
- package/dist/commands/connect.d.ts.map +1 -1
- package/dist/commands/connect.js +51 -4
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/forward.d.ts +3 -0
- package/dist/commands/forward.d.ts.map +1 -1
- package/dist/commands/forward.js +81 -8
- package/dist/commands/forward.js.map +1 -1
- package/dist/lib/api.d.ts +7 -1
- package/dist/lib/api.d.ts.map +1 -1
- package/dist/lib/api.js +38 -8
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auto-forward.d.ts +3 -1
- package/dist/lib/auto-forward.d.ts.map +1 -1
- package/dist/lib/auto-forward.js +32 -3
- package/dist/lib/auto-forward.js.map +1 -1
- package/dist/lib/backfill-tools.d.ts +3 -0
- package/dist/lib/backfill-tools.d.ts.map +1 -1
- package/dist/lib/backfill-tools.js +9 -2
- package/dist/lib/backfill-tools.js.map +1 -1
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/connection-attempt.d.ts +13 -2
- package/dist/lib/connection-attempt.d.ts.map +1 -1
- package/dist/lib/connection-attempt.js +16 -3
- package/dist/lib/connection-attempt.js.map +1 -1
- package/dist/lib/hook-logger.cjs +99 -6
- package/dist/lib/hosted-capture.d.ts +21 -0
- package/dist/lib/hosted-capture.d.ts.map +1 -0
- package/dist/lib/hosted-capture.js +231 -0
- package/dist/lib/hosted-capture.js.map +1 -0
- package/dist/lib/hosted-transcripts.d.ts +31 -0
- package/dist/lib/hosted-transcripts.d.ts.map +1 -0
- package/dist/lib/hosted-transcripts.js +364 -0
- package/dist/lib/hosted-transcripts.js.map +1 -0
- package/dist/lib/hosted-watcher.d.ts +2 -0
- package/dist/lib/hosted-watcher.d.ts.map +1 -0
- package/dist/lib/hosted-watcher.js +200 -0
- package/dist/lib/hosted-watcher.js.map +1 -0
- package/dist/lib/session-state.d.ts +61 -0
- package/dist/lib/session-state.d.ts.map +1 -0
- package/dist/lib/session-state.js +92 -0
- package/dist/lib/session-state.js.map +1 -0
- package/dist/lib/ssh-client.d.ts +5 -1
- package/dist/lib/ssh-client.d.ts.map +1 -1
- package/dist/lib/ssh-client.js +22 -3
- package/dist/lib/ssh-client.js.map +1 -1
- package/dist/lib/tracker.d.ts.map +1 -1
- package/dist/lib/tracker.js +7 -2
- package/dist/lib/tracker.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/** Observe turns appended to sessions that existed before hosted capture setup.
|
|
2
|
+
* Hooks remain the writer for new sessions. Existing sessions have exactly one
|
|
3
|
+
* writer (this observer), even if their hooks subsequently reload.
|
|
4
|
+
* Transcript formats are internal to the tools; accept only measured shapes.
|
|
5
|
+
*/
|
|
6
|
+
import { appendFileSync, closeSync, constants, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, writeFileSync, renameSync, fstatSync } from "fs";
|
|
7
|
+
import { createHash, randomUUID } from "crypto";
|
|
8
|
+
import os from "os";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { codexTypedPrompt, isCodexContextualText, parseCodexRollout } from "./backfill-tools.js";
|
|
11
|
+
const UUID = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
|
|
12
|
+
const STATE_FILE = "transcript-observer.json";
|
|
13
|
+
const MAX_READ = 1024 * 1024;
|
|
14
|
+
const MAX_LINE = 8 * 1024 * 1024;
|
|
15
|
+
const identity = (s) => `${s.dev}:${s.ino}`;
|
|
16
|
+
const digest = (...parts) => createHash("sha256").update(JSON.stringify(parts)).digest("hex");
|
|
17
|
+
function validState(value) {
|
|
18
|
+
return value?.version === 1 && Number.isFinite(value.startedAt) && Array.isArray(value.cursors)
|
|
19
|
+
&& (value.captureSince === undefined || (Number.isFinite(value.captureSince) && value.captureSince >= value.startedAt))
|
|
20
|
+
&& (value.suspended === undefined || typeof value.suspended === "boolean")
|
|
21
|
+
&& (value.lastExpiresAt === undefined || Number.isFinite(value.lastExpiresAt))
|
|
22
|
+
&& value.cursors.every((c) => typeof c.file === "string" && ["codex", "claude"].includes(c.tool)
|
|
23
|
+
&& typeof c.sessionId === "string" && Number.isSafeInteger(c.offset) && c.offset >= 0 && typeof c.identity === "string");
|
|
24
|
+
}
|
|
25
|
+
function codexSession(file) {
|
|
26
|
+
let fd;
|
|
27
|
+
try {
|
|
28
|
+
fd = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
29
|
+
const buffer = Buffer.alloc(MAX_READ), count = readSync(fd, buffer, 0, buffer.length, 0);
|
|
30
|
+
const end = buffer.subarray(0, count).indexOf(10);
|
|
31
|
+
if (end < 0)
|
|
32
|
+
return null;
|
|
33
|
+
// Only the file's FIRST metadata is authoritative. Do not read a later
|
|
34
|
+
// copied parent's source or import any historical conversation bodies.
|
|
35
|
+
const parsed = parseCodexRollout(buffer.subarray(0, end).toString("utf8"), new Date().toISOString());
|
|
36
|
+
return parsed.interactive ? parsed.sessionId : null;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
if (fd !== undefined)
|
|
43
|
+
closeSync(fd);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function save(file, state) {
|
|
47
|
+
mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
48
|
+
const temp = `${file}.${randomUUID()}.tmp`;
|
|
49
|
+
writeFileSync(temp, JSON.stringify(state), { mode: 0o600 });
|
|
50
|
+
renameSync(temp, file);
|
|
51
|
+
}
|
|
52
|
+
/** No symlinks, subagent logs, or arbitrary user-supplied paths. */
|
|
53
|
+
function discover(root, tool) {
|
|
54
|
+
const found = [];
|
|
55
|
+
function visit(dir, depth) {
|
|
56
|
+
if (depth > 4 || found.length >= 10000)
|
|
57
|
+
return;
|
|
58
|
+
let entries;
|
|
59
|
+
try {
|
|
60
|
+
if (lstatSync(dir).isSymbolicLink())
|
|
61
|
+
return;
|
|
62
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
if (found.length >= 10000)
|
|
69
|
+
break;
|
|
70
|
+
if (entry.isSymbolicLink() || entry.name === "subagents")
|
|
71
|
+
continue;
|
|
72
|
+
const file = path.join(dir, entry.name);
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
visit(file, depth + 1);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
let id = entry.name.match(UUID)?.[0];
|
|
78
|
+
if (!entry.isFile() || !id || !entry.name.endsWith(".jsonl"))
|
|
79
|
+
continue;
|
|
80
|
+
if (tool === "codex" && !entry.name.startsWith("rollout-"))
|
|
81
|
+
continue;
|
|
82
|
+
if (tool === "codex") {
|
|
83
|
+
const canonical = codexSession(file);
|
|
84
|
+
if (!canonical || canonical !== id)
|
|
85
|
+
continue;
|
|
86
|
+
id = canonical;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const stat = lstatSync(file);
|
|
90
|
+
found.push({ file, tool, sessionId: id, offset: stat.size, identity: identity(stat) });
|
|
91
|
+
}
|
|
92
|
+
catch { /* vanished during enumeration */ }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
visit(root, 0);
|
|
96
|
+
return found;
|
|
97
|
+
}
|
|
98
|
+
export function prepareHostedTranscripts(projectDir, startedAt) {
|
|
99
|
+
const file = path.join(projectDir, ".litmus", STATE_FILE);
|
|
100
|
+
if (existsSync(file)) {
|
|
101
|
+
try {
|
|
102
|
+
const prior = JSON.parse(readFileSync(file, "utf8"));
|
|
103
|
+
if (validState(prior) && prior.startedAt === startedAt)
|
|
104
|
+
return; // watcher revival, same window
|
|
105
|
+
}
|
|
106
|
+
catch { /* damaged prior state: recover with a fresh EOF boundary */ }
|
|
107
|
+
}
|
|
108
|
+
const home = os.homedir();
|
|
109
|
+
const cursors = [
|
|
110
|
+
...discover(path.join(process.env.CODEX_HOME?.trim() || path.join(home, ".codex"), "sessions"), "codex"),
|
|
111
|
+
...discover(path.join(process.env.CLAUDE_CONFIG_DIR?.trim() || path.join(home, ".claude"), "projects"), "claude"),
|
|
112
|
+
];
|
|
113
|
+
save(file, { version: 1, startedAt, captureSince: startedAt, cursors });
|
|
114
|
+
}
|
|
115
|
+
function text(content) {
|
|
116
|
+
if (typeof content === "string")
|
|
117
|
+
return content;
|
|
118
|
+
if (!Array.isArray(content))
|
|
119
|
+
return "";
|
|
120
|
+
return content.filter(b => b && ["text", "input_text", "output_text"].includes(b.type) && typeof b.text === "string").map(b => b.text).join("\n");
|
|
121
|
+
}
|
|
122
|
+
export class HostedTranscriptObserver {
|
|
123
|
+
constructor(projectDir, activityLog) {
|
|
124
|
+
this.projectDir = projectDir;
|
|
125
|
+
this.activityLog = activityLog;
|
|
126
|
+
this.pending = new Map();
|
|
127
|
+
this.claudeReplies = new Map();
|
|
128
|
+
this.previousExpiry = 0;
|
|
129
|
+
this.stateFile = path.join(projectDir, ".litmus", STATE_FILE);
|
|
130
|
+
this.state = JSON.parse(readFileSync(this.stateFile, "utf8"));
|
|
131
|
+
if (!validState(this.state))
|
|
132
|
+
throw new Error("Unsupported transcript cursor state");
|
|
133
|
+
this.previousExpiry = this.state.lastExpiresAt ?? 0;
|
|
134
|
+
}
|
|
135
|
+
/** Offsets advance even while unauthorized: a later lease cannot backfill
|
|
136
|
+
* messages sent during a disconnect. No content is checkpointed in state.
|
|
137
|
+
*/
|
|
138
|
+
poll(lease, now = Date.now()) {
|
|
139
|
+
// A laptop can sleep past expiry without running an interval. Do not
|
|
140
|
+
// backfill the sleep gap merely because renewal completed before this poll.
|
|
141
|
+
const authorized = lease && now >= lease.startedAt && now < lease.expiresAt && typeof lease.receipt === "string";
|
|
142
|
+
const resumed = authorized && (this.state.suspended || (this.previousExpiry > 0 && lease.leaseResponseReceivedAt >= this.previousExpiry));
|
|
143
|
+
if (resumed) {
|
|
144
|
+
this.state.captureSince = Math.max(this.state.captureSince ?? this.state.startedAt, lease.leaseResponseReceivedAt);
|
|
145
|
+
// A delayed paused prompt may never have reached disk. Invalidate the
|
|
146
|
+
// prior turn too, so its post-resume replies cannot inherit that prompt.
|
|
147
|
+
for (const cursor of this.state.cursors) {
|
|
148
|
+
delete cursor.turnId;
|
|
149
|
+
delete cursor.nativeTurnId;
|
|
150
|
+
}
|
|
151
|
+
this.claudeReplies.clear();
|
|
152
|
+
}
|
|
153
|
+
this.previousExpiry = lease?.expiresAt ?? 0;
|
|
154
|
+
let changed = this.state.lastExpiresAt !== this.previousExpiry || !!resumed || this.state.suspended === !!authorized;
|
|
155
|
+
this.state.suspended = !authorized;
|
|
156
|
+
this.state.lastExpiresAt = this.previousExpiry;
|
|
157
|
+
let budget = 8 * MAX_READ;
|
|
158
|
+
for (const cursor of this.state.cursors) {
|
|
159
|
+
if (authorized && budget <= 0)
|
|
160
|
+
break;
|
|
161
|
+
let fd;
|
|
162
|
+
const before = { ...cursor };
|
|
163
|
+
const pendingBefore = this.pending.get(cursor.file);
|
|
164
|
+
const replyBefore = this.claudeReplies.get(cursor.file);
|
|
165
|
+
try {
|
|
166
|
+
const current = lstatSync(cursor.file);
|
|
167
|
+
if (current.isSymbolicLink())
|
|
168
|
+
continue;
|
|
169
|
+
if (authorized && identity(current) === cursor.identity && current.size === cursor.offset) {
|
|
170
|
+
if (this.finishClaude(cursor, lease, now))
|
|
171
|
+
changed = true;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
fd = openSync(cursor.file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
175
|
+
const stat = fstatSync(fd);
|
|
176
|
+
if (!stat.isFile())
|
|
177
|
+
continue;
|
|
178
|
+
// Replacement/truncation may replay history with new timestamps. Start
|
|
179
|
+
// at EOF again rather than guessing whether it contains new messages.
|
|
180
|
+
if (!authorized || cursor.identity !== identity(stat) || stat.size < cursor.offset) {
|
|
181
|
+
changed || (changed = cursor.offset !== stat.size || cursor.identity !== identity(stat) || !!cursor.turnId || !!cursor.nativeTurnId || !!cursor.discarding);
|
|
182
|
+
cursor.offset = stat.size;
|
|
183
|
+
cursor.identity = identity(stat);
|
|
184
|
+
delete cursor.turnId;
|
|
185
|
+
delete cursor.nativeTurnId;
|
|
186
|
+
delete cursor.discarding;
|
|
187
|
+
this.pending.delete(cursor.file);
|
|
188
|
+
this.claudeReplies.delete(cursor.file);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const buffer = Buffer.alloc(Math.min(MAX_READ, stat.size - cursor.offset));
|
|
192
|
+
if (!buffer.length)
|
|
193
|
+
continue;
|
|
194
|
+
const count = readSync(fd, buffer, 0, buffer.length, cursor.offset);
|
|
195
|
+
budget -= count;
|
|
196
|
+
const bytes = Buffer.concat([this.pending.get(cursor.file) ?? Buffer.alloc(0), buffer.subarray(0, count)]);
|
|
197
|
+
const baseOffset = cursor.offset - (this.pending.get(cursor.file)?.length ?? 0);
|
|
198
|
+
cursor.offset += count;
|
|
199
|
+
let start = 0;
|
|
200
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
201
|
+
if (bytes[i] !== 10)
|
|
202
|
+
continue;
|
|
203
|
+
if (!cursor.discarding && i - start <= MAX_LINE) {
|
|
204
|
+
let row;
|
|
205
|
+
try {
|
|
206
|
+
row = JSON.parse(bytes.subarray(start, i).toString("utf8"));
|
|
207
|
+
}
|
|
208
|
+
catch { /* malformed record */ }
|
|
209
|
+
if (row && typeof row === "object")
|
|
210
|
+
this.record(cursor, row, lease, now, baseOffset + start);
|
|
211
|
+
}
|
|
212
|
+
cursor.discarding = false;
|
|
213
|
+
start = i + 1;
|
|
214
|
+
}
|
|
215
|
+
const tail = bytes.subarray(start);
|
|
216
|
+
if (tail.length > MAX_LINE)
|
|
217
|
+
cursor.discarding = true;
|
|
218
|
+
this.pending.set(cursor.file, !cursor.discarding ? Buffer.from(tail) : Buffer.alloc(0));
|
|
219
|
+
if (!tail.length)
|
|
220
|
+
this.finishClaude(cursor, lease, now);
|
|
221
|
+
changed = true;
|
|
222
|
+
// Checkpoint only complete lines; a restarted watcher re-reads the
|
|
223
|
+
// unfinished tail, and stable event ids collapse append-before-save.
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// An outbox append failure must not consume the transcript. Any earlier
|
|
227
|
+
// successful appends are replay-safe via their stable native event ids.
|
|
228
|
+
Object.assign(cursor, before);
|
|
229
|
+
for (const key of ["turnId", "nativeTurnId", "discarding"])
|
|
230
|
+
if (!(key in before))
|
|
231
|
+
delete cursor[key];
|
|
232
|
+
if (pendingBefore)
|
|
233
|
+
this.pending.set(cursor.file, pendingBefore);
|
|
234
|
+
else
|
|
235
|
+
this.pending.delete(cursor.file);
|
|
236
|
+
if (replyBefore)
|
|
237
|
+
this.claudeReplies.set(cursor.file, replyBefore);
|
|
238
|
+
else
|
|
239
|
+
this.claudeReplies.delete(cursor.file);
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
if (fd !== undefined)
|
|
243
|
+
closeSync(fd);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (changed)
|
|
247
|
+
save(this.stateFile, { ...this.state, cursors: this.state.cursors.map(c => ({ ...c, offset: Math.min(c.offset - (this.pending.get(c.file)?.length ?? 0), this.claudeReplies.get(c.file)?.startOffset ?? Infinity) })) });
|
|
248
|
+
}
|
|
249
|
+
record(cursor, row, lease, now, recordOffset) {
|
|
250
|
+
const timestamp = Date.parse(row.timestamp);
|
|
251
|
+
// EOF boundary + occurrence time excludes old turns and delayed pre-window
|
|
252
|
+
// flushes. The lease's receipt dates delivery, not the tool's local clock.
|
|
253
|
+
if (!Number.isFinite(timestamp) || timestamp < Math.max(this.state.captureSince ?? this.state.startedAt, lease.startedAt) || timestamp > now + 1000)
|
|
254
|
+
return;
|
|
255
|
+
if (cursor.tool === "codex") {
|
|
256
|
+
if (row.type === "event_msg" && row.payload?.type === "task_started") {
|
|
257
|
+
cursor.nativeTurnId = typeof row.payload.turn_id === "string" ? row.payload.turn_id : undefined;
|
|
258
|
+
delete cursor.turnId;
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (row.type === "turn_context") {
|
|
262
|
+
if (typeof row.payload?.turn_id === "string")
|
|
263
|
+
cursor.nativeTurnId = row.payload.turn_id;
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (row.type === "event_msg" && ["task_complete", "turn_aborted"].includes(row.payload?.type)) {
|
|
267
|
+
delete cursor.turnId;
|
|
268
|
+
delete cursor.nativeTurnId;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// event_msg.user_message is another copy of response_item.message.
|
|
272
|
+
if (row.type !== "response_item" || row.payload?.type !== "message")
|
|
273
|
+
return;
|
|
274
|
+
const message = row.payload;
|
|
275
|
+
if (message.role === "user") {
|
|
276
|
+
const fragments = Array.isArray(message.content) ? message.content.filter((b) => b?.type === "input_text" && typeof b.text === "string").map((b) => b.text) : [];
|
|
277
|
+
if (fragments.some(isCodexContextualText))
|
|
278
|
+
return;
|
|
279
|
+
const prompt = codexTypedPrompt(fragments.join("\n\n"));
|
|
280
|
+
if (prompt)
|
|
281
|
+
this.emit(cursor, "ai_prompt", prompt, message.id, timestamp, lease, now);
|
|
282
|
+
}
|
|
283
|
+
if (message.role === "assistant" && (!message.phase || message.phase === "final"))
|
|
284
|
+
this.emit(cursor, "ai_response", text(message.content), message.id, timestamp, lease, now);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
if (row.isMeta || row.isSidechain || !["user", "assistant"].includes(row.type))
|
|
288
|
+
return;
|
|
289
|
+
if (row.type === "user" && Array.isArray(row.message?.content) && row.message.content.some((b) => b.type === "tool_result"))
|
|
290
|
+
return;
|
|
291
|
+
if (row.type === "user") {
|
|
292
|
+
this.claudeReplies.delete(cursor.file);
|
|
293
|
+
this.emit(cursor, "ai_prompt", text(row.message?.content), row.uuid, timestamp, lease, now);
|
|
294
|
+
}
|
|
295
|
+
else if (cursor.turnId) {
|
|
296
|
+
const reply = this.claudeReplies.get(cursor.file) ?? { startOffset: recordOffset, chunks: new Map() };
|
|
297
|
+
reply.lastEntry = typeof row.uuid === "string" ? row.uuid : undefined;
|
|
298
|
+
reply.timestamp = timestamp;
|
|
299
|
+
const chunk = text(row.message?.content);
|
|
300
|
+
if (chunk)
|
|
301
|
+
reply.chunks.set(typeof row.uuid === "string" ? row.uuid : digest(String(timestamp), chunk), chunk.slice(-60000));
|
|
302
|
+
// Bound long tool loops while preserving their completed answer.
|
|
303
|
+
while ([...reply.chunks.values()].reduce((n, part) => n + part.length, 0) > 240000) {
|
|
304
|
+
reply.chunks.delete(reply.chunks.keys().next().value);
|
|
305
|
+
}
|
|
306
|
+
this.claudeReplies.set(cursor.file, reply);
|
|
307
|
+
const reason = row.message?.stop_reason;
|
|
308
|
+
if (reason && reason !== "tool_use") {
|
|
309
|
+
this.emit(cursor, "ai_response", [...reply.chunks.values()].join("\n\n"), row.uuid, timestamp, lease, now);
|
|
310
|
+
this.claudeReplies.delete(cursor.file);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/** Some Claude versions persist the final assistant row with stop_reason:
|
|
316
|
+
* null. Their Stop hook records only the final native entry id, never text.
|
|
317
|
+
* Wait until that exact entry has been read before publishing one reply.
|
|
318
|
+
* A terminal stop_reason remains sufficient when hooks have not reloaded.
|
|
319
|
+
*/
|
|
320
|
+
finishClaude(cursor, lease, now) {
|
|
321
|
+
const reply = this.claudeReplies.get(cursor.file);
|
|
322
|
+
if (!reply?.lastEntry || !cursor.turnId)
|
|
323
|
+
return false;
|
|
324
|
+
let marker;
|
|
325
|
+
try {
|
|
326
|
+
marker = JSON.parse(readFileSync(path.join(this.projectDir, ".litmus/transcript-completions", `${digest(cursor.sessionId)}.json`), "utf8"));
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return false;
|
|
330
|
+
}
|
|
331
|
+
if (marker.startedAt !== this.state.startedAt || marker.entryId !== reply.lastEntry
|
|
332
|
+
|| !Number.isFinite(marker.completedAt) || marker.completedAt < (this.state.captureSince ?? this.state.startedAt)
|
|
333
|
+
|| marker.completedAt > now)
|
|
334
|
+
return false;
|
|
335
|
+
this.emit(cursor, "ai_response", [...reply.chunks.values()].join("\n\n"), reply.lastEntry, reply.timestamp, lease, now);
|
|
336
|
+
this.claudeReplies.delete(cursor.file);
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
emit(cursor, type, body, nativeId, timestamp, lease, now) {
|
|
340
|
+
if (!body || /^(?:<system-reminder>|<local-command|<command-name>|<task-notification>)/.test(body.trimStart()))
|
|
341
|
+
return;
|
|
342
|
+
const key = typeof nativeId === "string" ? nativeId : digest(String(timestamp), body);
|
|
343
|
+
const id = `transcript-${digest(cursor.tool, cursor.sessionId, type, key)}`;
|
|
344
|
+
const turnId = type === "ai_prompt" ? cursor.nativeTurnId || id : cursor.turnId;
|
|
345
|
+
if (!turnId)
|
|
346
|
+
return; // a reply to a prompt from before capture
|
|
347
|
+
const event = {
|
|
348
|
+
id, type, tool: cursor.tool, sessionId: cursor.sessionId, turnId,
|
|
349
|
+
ts: new Date(lease.serverTime + now - lease.leaseResponseReceivedAt).toISOString(),
|
|
350
|
+
capture_location: "local", capture_receipt: lease.receipt,
|
|
351
|
+
capture_method: "transcript", ...(type === "ai_prompt" ? { prompt: body } : { text: body }),
|
|
352
|
+
};
|
|
353
|
+
const field = type === "ai_prompt" ? "prompt" : "text";
|
|
354
|
+
while (Buffer.byteLength(JSON.stringify(event)) > 60000) {
|
|
355
|
+
const value = event[field];
|
|
356
|
+
if (value.length < 2)
|
|
357
|
+
return;
|
|
358
|
+
event[field] = type === "ai_response" ? value.slice(-Math.floor(value.length / 2)) : value.slice(0, Math.floor(value.length / 2));
|
|
359
|
+
}
|
|
360
|
+
appendFileSync(this.activityLog, JSON.stringify(event) + "\n", { mode: 0o600 });
|
|
361
|
+
cursor.turnId = turnId;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=hosted-transcripts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-transcripts.js","sourceRoot":"","sources":["../../src/lib/hosted-transcripts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-watcher.d.ts","sourceRoot":"","sources":["../../src/lib/hosted-watcher.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/** Laptop-side capture supervisor. No file snapshots or auto-submission. */
|
|
2
|
+
import { CLI_VERSION } from "./version.js";
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync, rmSync, openSync, readSync, closeSync, fstatSync } from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { atomicPrivateJson, captureLease, HOSTED_CAPTURE_FILE, acquireCaptureSetupLock } from "./hosted-capture.js";
|
|
6
|
+
import { retireAiCaptureForEndedSession, sessionOverMarked, writeSessionOverMarker } from "./session-over.js";
|
|
7
|
+
import { HostedTranscriptObserver, prepareHostedTranscripts } from "./hosted-transcripts.js";
|
|
8
|
+
const projectDir = process.argv[2];
|
|
9
|
+
const activityLog = process.argv[3];
|
|
10
|
+
const nonce = process.argv[5];
|
|
11
|
+
const stateDir = path.join(projectDir, ".litmus");
|
|
12
|
+
const config = JSON.parse(readFileSync(path.join(stateDir, "config.json"), "utf8"));
|
|
13
|
+
const ready = path.join(stateDir, "tracker.ready");
|
|
14
|
+
const pidFile = path.join(stateDir, "tracker.pid");
|
|
15
|
+
let stopped = false;
|
|
16
|
+
let lastFlushAttempt = 0;
|
|
17
|
+
let offset = 0;
|
|
18
|
+
let observer;
|
|
19
|
+
let observerTimer;
|
|
20
|
+
try {
|
|
21
|
+
offset = Number(readFileSync(path.join(stateDir, "upload-offset"), "utf8")) || 0;
|
|
22
|
+
}
|
|
23
|
+
catch { /* first boot */ }
|
|
24
|
+
function ownsRegistration() {
|
|
25
|
+
try {
|
|
26
|
+
return JSON.parse(readFileSync(HOSTED_CAPTURE_FILE, "utf8")).projectDir === projectDir;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function stop(retire) {
|
|
33
|
+
if (stopped)
|
|
34
|
+
return await new Promise(() => { });
|
|
35
|
+
stopped = true;
|
|
36
|
+
if (observerTimer)
|
|
37
|
+
clearInterval(observerTimer);
|
|
38
|
+
let ownsPid = false;
|
|
39
|
+
try {
|
|
40
|
+
ownsPid = readFileSync(pidFile, "utf8").trim() === String(process.pid);
|
|
41
|
+
}
|
|
42
|
+
catch { /* absent */ }
|
|
43
|
+
if (ownsRegistration() && ownsPid) {
|
|
44
|
+
// Silence the hooks BEFORE slow cleanup; do not touch a successor window.
|
|
45
|
+
const registration = JSON.parse(readFileSync(HOSTED_CAPTURE_FILE, "utf8"));
|
|
46
|
+
atomicPrivateJson(HOSTED_CAPTURE_FILE, { ...registration, expiresAt: 0 });
|
|
47
|
+
if (retire) {
|
|
48
|
+
// Disable collection first. Bounded draining cannot start new capture.
|
|
49
|
+
const deadline = Date.now() + 10000;
|
|
50
|
+
try {
|
|
51
|
+
while (Date.now() < deadline && await flush()) { /* next bounded batch */ }
|
|
52
|
+
}
|
|
53
|
+
catch { /* preserve local outbox on failure */ }
|
|
54
|
+
writeSessionOverMarker(projectDir, config.token, "coding session ended");
|
|
55
|
+
const cleanupDeadline = Date.now() + 10000;
|
|
56
|
+
let cleaned = false;
|
|
57
|
+
while (!cleaned && Date.now() < cleanupDeadline) {
|
|
58
|
+
let releaseSetup;
|
|
59
|
+
try {
|
|
60
|
+
// Setup or an unrelated port owner may briefly hold the guard. Keep
|
|
61
|
+
// capture disabled while retrying; never uninstall a successor's hooks.
|
|
62
|
+
releaseSetup = await acquireCaptureSetupLock(`${HOSTED_CAPTURE_FILE}.lock`);
|
|
63
|
+
retireAiCaptureForEndedSession(projectDir, config.token);
|
|
64
|
+
if (ownsRegistration())
|
|
65
|
+
rmSync(HOSTED_CAPTURE_FILE, { force: true });
|
|
66
|
+
cleaned = true;
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
await new Promise(resolve => setTimeout(resolve, 250));
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
if (releaseSetup)
|
|
73
|
+
await releaseSetup();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// On persistent contention, the expired routing record, ended marker and
|
|
77
|
+
// registry entry preserve pending cleanup for the next connect attempt.
|
|
78
|
+
// Credentials are no longer needed to release that retired installation.
|
|
79
|
+
rmSync(path.join(stateDir, "config.json"), { force: true });
|
|
80
|
+
if (!cleaned)
|
|
81
|
+
process.stderr.write("[hosted capture] capture stopped; hook cleanup pending until the local setup guard is available on reconnect\n");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
if (readFileSync(ready, "utf8").trim() === String(process.pid))
|
|
86
|
+
rmSync(ready, { force: true });
|
|
87
|
+
}
|
|
88
|
+
catch { /* absent */ }
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
91
|
+
process.on("SIGTERM", () => { void stop(false); });
|
|
92
|
+
process.on("SIGINT", () => { void stop(false); });
|
|
93
|
+
async function flush() {
|
|
94
|
+
if (!existsSync(activityLog))
|
|
95
|
+
return false;
|
|
96
|
+
const fd = openSync(activityLog, "r");
|
|
97
|
+
let bytes;
|
|
98
|
+
try {
|
|
99
|
+
if (offset > fstatSync(fd).size)
|
|
100
|
+
offset = 0;
|
|
101
|
+
const buffer = Buffer.alloc(8 * 1024 * 1024);
|
|
102
|
+
bytes = buffer.subarray(0, readSync(fd, buffer, 0, buffer.length, offset));
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
closeSync(fd);
|
|
106
|
+
}
|
|
107
|
+
// A bounded batch; only complete lines, no prompt bodies in diagnostics.
|
|
108
|
+
let end = -1;
|
|
109
|
+
let count = 0;
|
|
110
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
111
|
+
if (bytes[i] === 10) {
|
|
112
|
+
end = i;
|
|
113
|
+
if (++count === 512)
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (end < 0)
|
|
118
|
+
return false;
|
|
119
|
+
const lines = bytes.subarray(0, end).toString("utf8").split("\n").filter(Boolean);
|
|
120
|
+
const events = lines.map(line => JSON.parse(line));
|
|
121
|
+
const result = await fetch(`${config.backendUrl}/cli/activity`, {
|
|
122
|
+
method: "POST", redirect: "error", headers: { Authorization: `Bearer ${config.token}`, "Content-Type": "application/json", "X-Litmus-CLI-Version": CLI_VERSION, "X-Litmus-Hosted-Capture": "v1" },
|
|
123
|
+
body: JSON.stringify({ events }), signal: AbortSignal.timeout(4000),
|
|
124
|
+
});
|
|
125
|
+
// Never discard a refused or unknown-outcome batch. Hook uploads share event IDs.
|
|
126
|
+
const acknowledgement = result.ok ? await result.json() : null;
|
|
127
|
+
const acknowledged = acknowledgement?.success === true;
|
|
128
|
+
if (acknowledged && typeof acknowledgement?.discarded === "number" && acknowledgement.discarded > 0) {
|
|
129
|
+
process.stderr.write(`[hosted capture] ${acknowledgement.discarded} events permanently rejected outside their capture authorization window; original outbox retained\n`);
|
|
130
|
+
}
|
|
131
|
+
if (acknowledged) {
|
|
132
|
+
offset += end + 1;
|
|
133
|
+
writeFileSync(path.join(stateDir, "upload-offset"), String(offset), { mode: 0o600 });
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
async function run() {
|
|
139
|
+
// Parent stamps tracker.pid during spawn. Yield once before asserting ownership.
|
|
140
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
141
|
+
if (!ownsRegistration() || sessionOverMarked(projectDir))
|
|
142
|
+
await stop(true);
|
|
143
|
+
const initial = JSON.parse(readFileSync(HOSTED_CAPTURE_FILE, "utf8"));
|
|
144
|
+
prepareHostedTranscripts(projectDir, initial.startedAt);
|
|
145
|
+
observer = new HostedTranscriptObserver(projectDir, activityLog);
|
|
146
|
+
observerTimer = setInterval(() => {
|
|
147
|
+
if (stopped)
|
|
148
|
+
return;
|
|
149
|
+
try {
|
|
150
|
+
const registration = JSON.parse(readFileSync(HOSTED_CAPTURE_FILE, "utf8"));
|
|
151
|
+
const ownsPid = readFileSync(pidFile, "utf8").trim() === String(process.pid);
|
|
152
|
+
const active = ownsPid && registration.projectDir === projectDir && !sessionOverMarked(projectDir) && !existsSync(path.join(stateDir, "shutdown"));
|
|
153
|
+
observer.poll(active ? registration : null);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
try {
|
|
157
|
+
observer.poll(null);
|
|
158
|
+
}
|
|
159
|
+
catch { /* unreadable cursor state; next tick retries */ }
|
|
160
|
+
}
|
|
161
|
+
}, 1000);
|
|
162
|
+
while (!stopped) {
|
|
163
|
+
if (!ownsRegistration())
|
|
164
|
+
await stop(false);
|
|
165
|
+
try {
|
|
166
|
+
if (readFileSync(pidFile, "utf8").trim() !== String(process.pid))
|
|
167
|
+
await stop(false);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
await stop(false);
|
|
171
|
+
}
|
|
172
|
+
if (sessionOverMarked(projectDir))
|
|
173
|
+
await stop(true);
|
|
174
|
+
if (existsSync(path.join(stateDir, "shutdown")))
|
|
175
|
+
await stop(true);
|
|
176
|
+
try {
|
|
177
|
+
// Anchor expiry at request START: delayed responses cannot lengthen the lease.
|
|
178
|
+
const started = Date.now();
|
|
179
|
+
const lease = await captureLease(config.backendUrl, config.token);
|
|
180
|
+
if (!lease.active)
|
|
181
|
+
return await stop(true);
|
|
182
|
+
const registration = JSON.parse(readFileSync(HOSTED_CAPTURE_FILE, "utf8"));
|
|
183
|
+
if (registration.projectDir !== projectDir)
|
|
184
|
+
await stop(false);
|
|
185
|
+
atomicPrivateJson(HOSTED_CAPTURE_FILE, { ...registration, expiresAt: started + lease.leaseSeconds * 1000, receipt: lease.receipt, serverTime: lease.serverTime, leaseRequestStarted: started, leaseResponseReceivedAt: lease.receivedAt });
|
|
186
|
+
writeFileSync(nonce, String(Date.now()), { mode: 0o600 });
|
|
187
|
+
writeFileSync(ready, String(process.pid), { mode: 0o600 });
|
|
188
|
+
if (Date.now() - lastFlushAttempt >= 5000) {
|
|
189
|
+
lastFlushAttempt = Date.now();
|
|
190
|
+
await flush();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
process.stderr.write(`[hosted capture] authorization/upload unavailable; capture lease will expire\n`);
|
|
195
|
+
}
|
|
196
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
run().catch(() => stop(false));
|
|
200
|
+
//# sourceMappingURL=hosted-watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosted-watcher.js","sourceRoot":"","sources":["../../src/lib/hosted-watcher.ts"],"names":[],"mappings":"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"}
|