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.
Files changed (53) hide show
  1. package/README.md +13 -0
  2. package/dist/commands/connect.d.ts +17 -1
  3. package/dist/commands/connect.d.ts.map +1 -1
  4. package/dist/commands/connect.js +51 -4
  5. package/dist/commands/connect.js.map +1 -1
  6. package/dist/commands/forward.d.ts +3 -0
  7. package/dist/commands/forward.d.ts.map +1 -1
  8. package/dist/commands/forward.js +81 -8
  9. package/dist/commands/forward.js.map +1 -1
  10. package/dist/lib/api.d.ts +7 -1
  11. package/dist/lib/api.d.ts.map +1 -1
  12. package/dist/lib/api.js +38 -8
  13. package/dist/lib/api.js.map +1 -1
  14. package/dist/lib/auto-forward.d.ts +3 -1
  15. package/dist/lib/auto-forward.d.ts.map +1 -1
  16. package/dist/lib/auto-forward.js +32 -3
  17. package/dist/lib/auto-forward.js.map +1 -1
  18. package/dist/lib/backfill-tools.d.ts +3 -0
  19. package/dist/lib/backfill-tools.d.ts.map +1 -1
  20. package/dist/lib/backfill-tools.js +9 -2
  21. package/dist/lib/backfill-tools.js.map +1 -1
  22. package/dist/lib/config.d.ts +1 -0
  23. package/dist/lib/config.d.ts.map +1 -1
  24. package/dist/lib/config.js.map +1 -1
  25. package/dist/lib/connection-attempt.d.ts +13 -2
  26. package/dist/lib/connection-attempt.d.ts.map +1 -1
  27. package/dist/lib/connection-attempt.js +16 -3
  28. package/dist/lib/connection-attempt.js.map +1 -1
  29. package/dist/lib/hook-logger.cjs +99 -6
  30. package/dist/lib/hosted-capture.d.ts +21 -0
  31. package/dist/lib/hosted-capture.d.ts.map +1 -0
  32. package/dist/lib/hosted-capture.js +231 -0
  33. package/dist/lib/hosted-capture.js.map +1 -0
  34. package/dist/lib/hosted-transcripts.d.ts +31 -0
  35. package/dist/lib/hosted-transcripts.d.ts.map +1 -0
  36. package/dist/lib/hosted-transcripts.js +364 -0
  37. package/dist/lib/hosted-transcripts.js.map +1 -0
  38. package/dist/lib/hosted-watcher.d.ts +2 -0
  39. package/dist/lib/hosted-watcher.d.ts.map +1 -0
  40. package/dist/lib/hosted-watcher.js +200 -0
  41. package/dist/lib/hosted-watcher.js.map +1 -0
  42. package/dist/lib/session-state.d.ts +61 -0
  43. package/dist/lib/session-state.d.ts.map +1 -0
  44. package/dist/lib/session-state.js +92 -0
  45. package/dist/lib/session-state.js.map +1 -0
  46. package/dist/lib/ssh-client.d.ts +5 -1
  47. package/dist/lib/ssh-client.d.ts.map +1 -1
  48. package/dist/lib/ssh-client.js +22 -3
  49. package/dist/lib/ssh-client.js.map +1 -1
  50. package/dist/lib/tracker.d.ts.map +1 -1
  51. package/dist/lib/tracker.js +7 -2
  52. package/dist/lib/tracker.js.map +1 -1
  53. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hosted-watcher.d.ts.map
@@ -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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"}