2g 0.3.1 → 0.4.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/CHANGELOG.md +12 -0
- package/dist/2g-api.js +5 -120
- package/dist/2g-api.js.map +1 -1
- package/dist/2g-api.mjs +1 -120
- package/dist/2g-api.mjs.map +1 -1
- package/dist/2g.js +42 -42
- package/dist/2g.js.map +1 -1
- package/dist/2g.mjs +115 -115
- package/dist/2g.mjs.map +1 -1
- package/dist/chunks/api-chunk.js +430 -0
- package/dist/chunks/api-chunk.js.map +1 -0
- package/dist/chunks/api-chunk.mjs +430 -0
- package/dist/chunks/api-chunk.mjs.map +1 -0
- package/dist/chunks/cli-chunk.js +160 -46
- package/dist/chunks/cli-chunk.js.map +1 -1
- package/dist/chunks/cli-chunk.mjs +214 -100
- package/dist/chunks/cli-chunk.mjs.map +1 -1
- package/dist/chunks/sessionSockets-chunk.js +4 -0
- package/dist/chunks/sessionSockets-chunk.js.map +1 -1
- package/dist/chunks/sessionSockets-chunk.mjs +9 -5
- package/dist/chunks/sessionSockets-chunk.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/tap-chunk.js +0 -287
- package/dist/chunks/tap-chunk.js.map +0 -1
- package/dist/chunks/tap-chunk.mjs +0 -287
- package/dist/chunks/tap-chunk.mjs.map +0 -1
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import t from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
import e from "node:path";
|
|
4
|
+
|
|
5
|
+
import n from "node:net";
|
|
6
|
+
|
|
7
|
+
import { createInterface as o } from "node:readline";
|
|
8
|
+
|
|
9
|
+
import { p as i, b as s, s as r, e as a, a as c, t as l, u, h as f, v as d, S as h, o as m, q as p } from "./sessionSockets-chunk.mjs";
|
|
10
|
+
|
|
11
|
+
async function listSessions(n = {}) {
|
|
12
|
+
c();
|
|
13
|
+
const o = m();
|
|
14
|
+
const i = await t.readdir(o, {
|
|
15
|
+
withFileTypes: !0
|
|
16
|
+
}).catch(() => []);
|
|
17
|
+
const s = [];
|
|
18
|
+
for (const t of i) {
|
|
19
|
+
if (!t.isDirectory()) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const n = e.join(o, t.name);
|
|
23
|
+
const i = r(n);
|
|
24
|
+
if (!i) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
s.push({
|
|
28
|
+
id: t.name,
|
|
29
|
+
pid: i.pid,
|
|
30
|
+
formatVersion: i.formatVersion,
|
|
31
|
+
alive: !1,
|
|
32
|
+
startedAt: i.startedAt,
|
|
33
|
+
command: i.command,
|
|
34
|
+
cwd: i.cwd,
|
|
35
|
+
version: i.version,
|
|
36
|
+
origin: i.origin,
|
|
37
|
+
sessionDir: n
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const a = l(s);
|
|
41
|
+
for (const t of s) {
|
|
42
|
+
t.alive = u(t.pid) && a.has(t.id);
|
|
43
|
+
}
|
|
44
|
+
return function filterSessions(t, e) {
|
|
45
|
+
const n = e?.trim();
|
|
46
|
+
if (!n) {
|
|
47
|
+
return t;
|
|
48
|
+
}
|
|
49
|
+
const o = t.filter(t => function matchesSessionExactly(t, e) {
|
|
50
|
+
return sessionSearchValues(t).some(t => t === e);
|
|
51
|
+
}(t, n));
|
|
52
|
+
if (o.length) {
|
|
53
|
+
return o;
|
|
54
|
+
}
|
|
55
|
+
const i = n.toLowerCase();
|
|
56
|
+
return t.filter(t => sessionSearchValues(t).some(t => t.toLowerCase().includes(i)));
|
|
57
|
+
}(s, n.selector).sort((t, e) => e.startedAt - t.startedAt);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function resolveSession(t) {
|
|
61
|
+
const e = await listSessions({
|
|
62
|
+
selector: t
|
|
63
|
+
});
|
|
64
|
+
const n = e.filter(t => t.alive);
|
|
65
|
+
const o = 1 === e.length ? e[0] : 1 === n.length ? n[0] : null;
|
|
66
|
+
if (!o) {
|
|
67
|
+
throw new Error(null != t ? e.length ? `Ambiguous 2g session "${t}"; specify one of: ${e.map(formatSessionSelector).join(", ")}` : `No 2g session matching "${t}"` : e.length ? `Ambiguous 2g session; specify one of: ${e.map(formatSessionSelector).join(", ")}` : "No 2g sessions found");
|
|
68
|
+
}
|
|
69
|
+
return o;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function* tap(n, c = {}) {
|
|
73
|
+
const l = !0 === c.follow;
|
|
74
|
+
const u = i(c.since);
|
|
75
|
+
const m = s(c.filter);
|
|
76
|
+
const p = function createTapAbortController(t, e) {
|
|
77
|
+
if (!e || null == t.timeout && null == t.idleTimeout) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const n = new AbortController;
|
|
81
|
+
t.signal?.addEventListener("abort", () => n.abort(), {
|
|
82
|
+
once: !0
|
|
83
|
+
});
|
|
84
|
+
if (null != t.timeout) {
|
|
85
|
+
setAbortTimer(n, t.timeout);
|
|
86
|
+
}
|
|
87
|
+
return n;
|
|
88
|
+
}(c, l);
|
|
89
|
+
const w = p?.signal ?? c.signal;
|
|
90
|
+
const v = r(n);
|
|
91
|
+
const y = l ? await async function connectLive(t, e, n) {
|
|
92
|
+
const i = d(t, e?.socket ?? h.liveSocket);
|
|
93
|
+
const s = await async function connectWithRetry(t, e) {
|
|
94
|
+
for (let n = 0; n < 20 && !e?.aborted; n++) {
|
|
95
|
+
const n = await tryConnect(t, e);
|
|
96
|
+
if (n) {
|
|
97
|
+
return n;
|
|
98
|
+
}
|
|
99
|
+
await new Promise(t => setTimeout(t, 50));
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}(i, n);
|
|
103
|
+
if (!s) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const r = o({
|
|
107
|
+
input: s
|
|
108
|
+
});
|
|
109
|
+
const a = [];
|
|
110
|
+
const c = [];
|
|
111
|
+
let l = !1;
|
|
112
|
+
const push = t => {
|
|
113
|
+
const e = c.shift();
|
|
114
|
+
if (e) {
|
|
115
|
+
e(t);
|
|
116
|
+
} else if (null != t) {
|
|
117
|
+
a.push(t);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
r.on("line", t => push(t));
|
|
121
|
+
r.on("close", () => {
|
|
122
|
+
l = !0;
|
|
123
|
+
push(null);
|
|
124
|
+
});
|
|
125
|
+
s.on("error", () => {
|
|
126
|
+
l = !0;
|
|
127
|
+
push(null);
|
|
128
|
+
});
|
|
129
|
+
n?.addEventListener("abort", () => s.destroy(), {
|
|
130
|
+
once: !0
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
buffer: a,
|
|
134
|
+
next() {
|
|
135
|
+
if (a.length) {
|
|
136
|
+
return Promise.resolve(a.shift());
|
|
137
|
+
}
|
|
138
|
+
if (l) {
|
|
139
|
+
return Promise.resolve(null);
|
|
140
|
+
}
|
|
141
|
+
return new Promise(t => c.push(t));
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}(n, v, w) : void 0;
|
|
145
|
+
const g = await async function openHistoryFiles(n, o) {
|
|
146
|
+
const i = o?.maxSegments ?? f;
|
|
147
|
+
const s = await Promise.all(Array.from({
|
|
148
|
+
length: i
|
|
149
|
+
}, (o, i) => t.open(e.join(n, `${i}.jsonl`), "r").catch(() => null)));
|
|
150
|
+
return s.filter(t => null != t).reverse();
|
|
151
|
+
}(n, v);
|
|
152
|
+
let b;
|
|
153
|
+
try {
|
|
154
|
+
for (const t of g) {
|
|
155
|
+
for await (const e of readLines(t)) {
|
|
156
|
+
const t = a(e, c, m, u);
|
|
157
|
+
if (t) {
|
|
158
|
+
yield t;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
} finally {
|
|
163
|
+
await Promise.all(g.map(t => t.close().catch(() => {})));
|
|
164
|
+
}
|
|
165
|
+
if (!y) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (null != c.idleTimeout && p) {
|
|
169
|
+
b = setAbortTimer(p, c.idleTimeout);
|
|
170
|
+
}
|
|
171
|
+
for (const t of y.buffer.splice(0)) {
|
|
172
|
+
const e = a(t, c, m, u);
|
|
173
|
+
if (e) {
|
|
174
|
+
if (b) {
|
|
175
|
+
b = resetAbortTimer(b, p, c.idleTimeout);
|
|
176
|
+
}
|
|
177
|
+
yield e;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
while (!w?.aborted) {
|
|
181
|
+
const t = await readLiveLine(y, w);
|
|
182
|
+
if (null == t) {
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
if (b) {
|
|
186
|
+
b = resetAbortTimer(b, p, c.idleTimeout);
|
|
187
|
+
}
|
|
188
|
+
const e = a(t, c, m, u);
|
|
189
|
+
if (e) {
|
|
190
|
+
yield e;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (b) {
|
|
194
|
+
clearTimeout(b);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function detectRotationLoss(n) {
|
|
199
|
+
const o = r(n);
|
|
200
|
+
for (let i = (o?.maxSegments ?? f) - 1; i >= 0; i--) {
|
|
201
|
+
const o = await t.open(e.join(n, `${i}.jsonl`), "r").catch(() => null);
|
|
202
|
+
if (!o) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const t = await readFirstLine(o);
|
|
207
|
+
return null != t && !isSessionStartLine(t);
|
|
208
|
+
} finally {
|
|
209
|
+
await o.close().catch(() => {});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return !1;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async function readFirstLine(t) {
|
|
216
|
+
for await (const e of readLines(t)) {
|
|
217
|
+
return e;
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function isSessionStartLine(t) {
|
|
223
|
+
return t.startsWith('{"_e":"root:init"');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function* readLines(t) {
|
|
227
|
+
let e = "";
|
|
228
|
+
for await (const n of t.createReadStream({
|
|
229
|
+
encoding: "utf8"
|
|
230
|
+
})) {
|
|
231
|
+
e += n;
|
|
232
|
+
let t = -1;
|
|
233
|
+
while ((t = e.indexOf("\n")) >= 0) {
|
|
234
|
+
const n = e.slice(0, t);
|
|
235
|
+
e = e.slice(t + 1);
|
|
236
|
+
if (n) {
|
|
237
|
+
yield n;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (e) {
|
|
242
|
+
yield e;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function formatSessionSelector(t) {
|
|
247
|
+
return `${t.pid} (${t.command})`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function readLiveLine(t, e) {
|
|
251
|
+
if (!e) {
|
|
252
|
+
return t.next();
|
|
253
|
+
}
|
|
254
|
+
if (e.aborted) {
|
|
255
|
+
return Promise.resolve(null);
|
|
256
|
+
}
|
|
257
|
+
return new Promise(n => {
|
|
258
|
+
const onAbort = () => n(null);
|
|
259
|
+
e.addEventListener("abort", onAbort, {
|
|
260
|
+
once: !0
|
|
261
|
+
});
|
|
262
|
+
t.next().then(t => {
|
|
263
|
+
e.removeEventListener("abort", onAbort);
|
|
264
|
+
n(e.aborted ? null : t);
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function resetAbortTimer(t, e, n) {
|
|
270
|
+
clearTimeout(t);
|
|
271
|
+
return setAbortTimer(e, n);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function setAbortTimer(t, e) {
|
|
275
|
+
const n = setTimeout(() => t.abort(), e);
|
|
276
|
+
n.unref?.();
|
|
277
|
+
return n;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function sessionSearchValues(t) {
|
|
281
|
+
return [ t.id, String(t.pid), t.sessionDir, t.cwd, t.command, t.origin?.cwd, t.origin?.argv.join(" "), t.origin?.execPath, t.origin?.env?.npmLifecycleEvent, t.origin?.env?.npmPackageName ].filter(t => !!t);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function tryConnect(t, e) {
|
|
285
|
+
return new Promise(o => {
|
|
286
|
+
const i = n.connect(t);
|
|
287
|
+
const cleanup = () => {
|
|
288
|
+
i.off("connect", onConnect);
|
|
289
|
+
i.off("error", onError);
|
|
290
|
+
e?.removeEventListener("abort", onAbort);
|
|
291
|
+
};
|
|
292
|
+
const onConnect = () => {
|
|
293
|
+
cleanup();
|
|
294
|
+
o(i);
|
|
295
|
+
};
|
|
296
|
+
const onError = () => {
|
|
297
|
+
cleanup();
|
|
298
|
+
i.destroy();
|
|
299
|
+
o(null);
|
|
300
|
+
};
|
|
301
|
+
const onAbort = () => {
|
|
302
|
+
cleanup();
|
|
303
|
+
i.destroy();
|
|
304
|
+
o(null);
|
|
305
|
+
};
|
|
306
|
+
i.once("connect", onConnect);
|
|
307
|
+
i.once("error", onError);
|
|
308
|
+
e?.addEventListener("abort", onAbort, {
|
|
309
|
+
once: !0
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
class EventCapture {
|
|
315
|
+
#t;
|
|
316
|
+
#e;
|
|
317
|
+
#n;
|
|
318
|
+
#o=!1;
|
|
319
|
+
#i=!1;
|
|
320
|
+
#s=[];
|
|
321
|
+
#r=[];
|
|
322
|
+
constructor(t = {}) {
|
|
323
|
+
this.#t = t;
|
|
324
|
+
this.#e = s(t.filter);
|
|
325
|
+
}
|
|
326
|
+
spawnOptions(t) {
|
|
327
|
+
const e = Array.isArray(t?.stdio) ? [ ...t.stdio ] : null != t?.stdio ? [ t.stdio, t.stdio, t.stdio ] : [];
|
|
328
|
+
while (e.length < 3) {
|
|
329
|
+
e.push("inherit");
|
|
330
|
+
}
|
|
331
|
+
this.#n = e.length;
|
|
332
|
+
e.push("pipe");
|
|
333
|
+
return {
|
|
334
|
+
...t,
|
|
335
|
+
stdio: e,
|
|
336
|
+
env: {
|
|
337
|
+
...t?.env ?? process.env,
|
|
338
|
+
[p]: `${this.#n}`
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
attach(t) {
|
|
343
|
+
if (null == this.#n) {
|
|
344
|
+
throw new Error("captureEvents: spawnOptions() must create the pipe before attach()");
|
|
345
|
+
}
|
|
346
|
+
if (this.#o) {
|
|
347
|
+
throw new Error("captureEvents: a child is already attached");
|
|
348
|
+
}
|
|
349
|
+
const e = t.stdio[this.#n];
|
|
350
|
+
if (!e || "function" != typeof e.setEncoding) {
|
|
351
|
+
throw new Error(`captureEvents: child stdio[${this.#n}] is not a readable pipe`);
|
|
352
|
+
}
|
|
353
|
+
this.#o = !0;
|
|
354
|
+
let n = "";
|
|
355
|
+
e.setEncoding("utf8");
|
|
356
|
+
e.on("data", t => {
|
|
357
|
+
const e = n ? n + t : t;
|
|
358
|
+
let o = 0;
|
|
359
|
+
let i;
|
|
360
|
+
while (-1 !== (i = e.indexOf("\n", o))) {
|
|
361
|
+
const t = e.slice(o, i);
|
|
362
|
+
o = i + 1;
|
|
363
|
+
if (t) {
|
|
364
|
+
this.#a(t);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
n = o ? e.slice(o) : e;
|
|
368
|
+
});
|
|
369
|
+
const finish = () => {
|
|
370
|
+
if (this.#i) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
this.#i = !0;
|
|
374
|
+
if (n) {
|
|
375
|
+
this.#a(n);
|
|
376
|
+
}
|
|
377
|
+
this.#c(null);
|
|
378
|
+
};
|
|
379
|
+
e.on("end", finish);
|
|
380
|
+
e.on("close", finish);
|
|
381
|
+
e.on("error", finish);
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
async collect() {
|
|
385
|
+
const t = [];
|
|
386
|
+
for await (const e of this) {
|
|
387
|
+
t.push(e);
|
|
388
|
+
}
|
|
389
|
+
return t;
|
|
390
|
+
}
|
|
391
|
+
async* [Symbol.asyncIterator]() {
|
|
392
|
+
let t;
|
|
393
|
+
while (t = await this.#l()) {
|
|
394
|
+
yield t;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
#a(t) {
|
|
398
|
+
const e = a(t, this.#t, this.#e);
|
|
399
|
+
if (e) {
|
|
400
|
+
this.#c(e);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
#c(t) {
|
|
404
|
+
const e = this.#r.shift();
|
|
405
|
+
if (e) {
|
|
406
|
+
e(t);
|
|
407
|
+
} else if (t) {
|
|
408
|
+
this.#s.push(t);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
#l() {
|
|
412
|
+
if (this.#s.length) {
|
|
413
|
+
return Promise.resolve(this.#s.shift());
|
|
414
|
+
}
|
|
415
|
+
if (this.#i) {
|
|
416
|
+
return Promise.resolve(null);
|
|
417
|
+
}
|
|
418
|
+
if (!this.#o) {
|
|
419
|
+
throw new Error("captureEvents: attach() a child before iterating");
|
|
420
|
+
}
|
|
421
|
+
return new Promise(t => this.#r.push(t));
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function captureEvents(t) {
|
|
426
|
+
return new EventCapture(t);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export { captureEvents as c, detectRotationLoss as d, listSessions as l, resolveSession as r, tap as t };
|
|
430
|
+
//# sourceMappingURL=api-chunk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-chunk.mjs","sources":["../../src/tap.ts","../../src/capture.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport net from 'node:net';\nimport { createInterface } from 'node:readline';\n\nimport { DEFAULT_SEGMENTS, SESSION_FILES } from './constants';\nimport {\n cleanStaleSessionsSync,\n getSessionBaseDir,\n isPidAlive,\n newestSessionIds,\n readMetaSync,\n} from './clean';\nimport { type SessionMeta } from './session';\nimport type { ParsedEvent } from './types';\nimport {\n compileEventFilter,\n parseEventLine,\n parseSince,\n type EventFilterOptions,\n} from './utils/eventFilter';\nimport { resolveSocketPath } from './utils/sessionSockets';\n\nexport interface ListedSession {\n id: string;\n pid: number;\n formatVersion: number;\n alive: boolean;\n startedAt: number;\n command: string;\n cwd: string;\n version?: string;\n origin?: SessionMeta['origin'];\n sessionDir: string;\n}\n\nexport interface ListSessionsOptions {\n selector?: string;\n}\n\nexport interface TapOptions extends EventFilterOptions {\n follow?: boolean;\n signal?: AbortSignal;\n timeout?: number;\n idleTimeout?: number;\n}\n\nexport async function listSessions(\n options: ListSessionsOptions = {}\n): Promise<ListedSession[]> {\n cleanStaleSessionsSync();\n const baseDir = getSessionBaseDir();\n const entries = await fs\n .readdir(baseDir, { withFileTypes: true })\n .catch(() => []);\n const sessions: ListedSession[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const sessionDir = path.join(baseDir, entry.name);\n const meta = readMetaSync(sessionDir);\n if (!meta) continue;\n sessions.push({\n id: entry.name,\n pid: meta.pid,\n formatVersion: meta.formatVersion,\n alive: false,\n startedAt: meta.startedAt,\n command: meta.command,\n cwd: meta.cwd,\n version: meta.version,\n origin: meta.origin,\n sessionDir,\n });\n }\n\n const newest = newestSessionIds(sessions);\n for (const session of sessions) {\n session.alive = isPidAlive(session.pid) && newest.has(session.id);\n }\n\n return filterSessions(sessions, options.selector).sort(\n (a, b) => b.startedAt - a.startedAt\n );\n}\n\nexport async function resolveSession(selector?: string) {\n const sessions = await listSessions({ selector });\n const activeSessions = sessions.filter(session => session.alive);\n const session =\n sessions.length === 1\n ? sessions[0]\n : activeSessions.length === 1\n ? activeSessions[0]\n : null;\n if (!session)\n throw new Error(\n selector != null\n ? sessions.length\n ? `Ambiguous 2g session \"${selector}\"; specify one of: ${sessions\n .map(formatSessionSelector)\n .join(', ')}`\n : `No 2g session matching \"${selector}\"`\n : sessions.length\n ? `Ambiguous 2g session; specify one of: ${sessions\n .map(formatSessionSelector)\n .join(', ')}`\n : 'No 2g sessions found'\n );\n return session;\n}\n\nexport async function* tap(\n sessionDir: string,\n options: TapOptions = {}\n): AsyncIterable<ParsedEvent> {\n const follow = options.follow === true;\n const since = parseSince(options.since);\n const eventFilter = compileEventFilter(options.filter);\n const abort = createTapAbortController(options, follow);\n const signal = abort?.signal ?? options.signal;\n const meta = readMetaSync(sessionDir);\n const live = follow ? await connectLive(sessionDir, meta, signal) : undefined;\n const history = await openHistoryFiles(sessionDir, meta);\n let idleTimer: NodeJS.Timeout | undefined;\n\n try {\n for (const handle of history) {\n for await (const line of readLines(handle)) {\n const event = parseEventLine(line, options, eventFilter, since);\n if (event) yield event;\n }\n }\n } finally {\n await Promise.all(history.map(handle => handle.close().catch(() => {})));\n }\n\n if (!live) return;\n if (options.idleTimeout != null && abort) {\n idleTimer = setAbortTimer(abort, options.idleTimeout);\n }\n\n for (const line of live.buffer.splice(0)) {\n const event = parseEventLine(line, options, eventFilter, since);\n if (event) {\n if (idleTimer)\n idleTimer = resetAbortTimer(idleTimer, abort!, options.idleTimeout!);\n yield event;\n }\n }\n\n while (!signal?.aborted) {\n const line = await readLiveLine(live, signal);\n if (line == null) break;\n if (idleTimer)\n idleTimer = resetAbortTimer(idleTimer, abort!, options.idleTimeout!);\n const event = parseEventLine(line, options, eventFilter, since);\n if (event) yield event;\n }\n\n if (idleTimer) clearTimeout(idleTimer);\n}\n\n// Rotation discards the oldest segment once the ring fills, so a retained\n// window whose oldest event is not the session's start has lost earlier events.\nexport async function detectRotationLoss(sessionDir: string): Promise<boolean> {\n const meta = readMetaSync(sessionDir);\n const maxSegments = meta?.maxSegments ?? DEFAULT_SEGMENTS;\n // The oldest retained segment is the highest-numbered file still present\n for (let index = maxSegments - 1; index >= 0; index--) {\n const handle = await fs\n .open(path.join(sessionDir, `${index}.jsonl`), 'r')\n .catch(() => null);\n if (!handle) continue;\n try {\n const first = await readFirstLine(handle);\n // An empty window has lost nothing; otherwise loss iff it skips the start\n return first != null && !isSessionStartLine(first);\n } finally {\n await handle.close().catch(() => {});\n }\n }\n return false;\n}\n\nasync function readFirstLine(handle: fs.FileHandle) {\n for await (const line of readLines(handle)) return line;\n return null;\n}\n\nfunction isSessionStartLine(line: string) {\n // Every session opens with a root:init event (see installEventLogger)\n return line.startsWith('{\"_e\":\"root:init\"');\n}\n\nasync function openHistoryFiles(sessionDir: string, meta: SessionMeta | null) {\n const maxSegments = meta?.maxSegments ?? DEFAULT_SEGMENTS;\n const handles = await Promise.all(\n Array.from({ length: maxSegments }, (_, index) =>\n fs.open(path.join(sessionDir, `${index}.jsonl`), 'r').catch(() => null)\n )\n );\n return handles.filter(handle => handle != null).reverse();\n}\n\nasync function* readLines(handle: fs.FileHandle) {\n let pending = '';\n for await (const chunk of handle.createReadStream({ encoding: 'utf8' })) {\n pending += chunk;\n let index = -1;\n while ((index = pending.indexOf('\\n')) >= 0) {\n const line = pending.slice(0, index);\n pending = pending.slice(index + 1);\n if (line) yield line;\n }\n }\n if (pending) yield pending;\n}\n\nfunction filterSessions(\n sessions: ListedSession[],\n selector: string | undefined\n) {\n const input = selector?.trim();\n if (!input) return sessions;\n\n const exact = sessions.filter(session =>\n matchesSessionExactly(session, input)\n );\n if (exact.length) return exact;\n\n const normalized = input.toLowerCase();\n return sessions.filter(session =>\n sessionSearchValues(session).some(value =>\n value.toLowerCase().includes(normalized)\n )\n );\n}\n\nfunction formatSessionSelector(session: ListedSession) {\n return `${session.pid} (${session.command})`;\n}\n\nasync function connectLive(\n sessionDir: string,\n meta: SessionMeta | null,\n signal?: AbortSignal\n) {\n const socketPath = resolveSocketPath(\n sessionDir,\n meta?.socket ?? SESSION_FILES.liveSocket\n );\n const socket = await connectWithRetry(socketPath, signal);\n if (!socket) return undefined;\n const rl = createInterface({ input: socket });\n const buffer: string[] = [];\n const waiters: Array<(line: string | null) => void> = [];\n let closed = false;\n\n const push = (line: string | null) => {\n const waiter = waiters.shift();\n if (waiter) waiter(line);\n else if (line != null) buffer.push(line);\n };\n\n rl.on('line', line => push(line));\n rl.on('close', () => {\n closed = true;\n push(null);\n });\n socket.on('error', () => {\n closed = true;\n push(null);\n });\n signal?.addEventListener('abort', () => socket.destroy(), { once: true });\n\n return {\n buffer,\n next() {\n if (buffer.length) return Promise.resolve(buffer.shift()!);\n if (closed) return Promise.resolve(null);\n return new Promise<string | null>(resolve => waiters.push(resolve));\n },\n };\n}\n\nfunction readLiveLine(\n live: { next(): Promise<string | null> },\n signal?: AbortSignal\n) {\n if (!signal) return live.next();\n if (signal.aborted) return Promise.resolve(null);\n\n return new Promise<string | null>(resolve => {\n const onAbort = () => resolve(null);\n signal.addEventListener('abort', onAbort, { once: true });\n live.next().then(line => {\n signal.removeEventListener('abort', onAbort);\n resolve(signal.aborted ? null : line);\n });\n });\n}\n\nfunction createTapAbortController(options: TapOptions, follow: boolean) {\n if (!follow || (options.timeout == null && options.idleTimeout == null))\n return undefined;\n\n const abort = new AbortController();\n options.signal?.addEventListener('abort', () => abort.abort(), {\n once: true,\n });\n if (options.timeout != null) setAbortTimer(abort, options.timeout);\n return abort;\n}\n\nfunction resetAbortTimer(\n timer: NodeJS.Timeout,\n abort: AbortController,\n timeout: number\n) {\n clearTimeout(timer);\n return setAbortTimer(abort, timeout);\n}\n\nfunction setAbortTimer(abort: AbortController, timeout: number) {\n const timer = setTimeout(() => abort.abort(), timeout);\n timer.unref?.();\n return timer;\n}\n\nfunction matchesSessionExactly(session: ListedSession, selector: string) {\n return sessionSearchValues(session).some(value => value === selector);\n}\n\nfunction sessionSearchValues(session: ListedSession) {\n return [\n session.id,\n String(session.pid),\n session.sessionDir,\n session.cwd,\n session.command,\n session.origin?.cwd,\n session.origin?.argv.join(' '),\n session.origin?.execPath,\n session.origin?.env?.npmLifecycleEvent,\n session.origin?.env?.npmPackageName,\n ].filter((value): value is string => !!value);\n}\n\nasync function connectWithRetry(socketPath: string, signal?: AbortSignal) {\n for (let attempt = 0; attempt < 20 && !signal?.aborted; attempt++) {\n const socket = await tryConnect(socketPath, signal);\n if (socket) return socket;\n await new Promise(resolve => setTimeout(resolve, 50));\n }\n return null;\n}\n\nfunction tryConnect(socketPath: string, signal?: AbortSignal) {\n return new Promise<net.Socket | null>(resolve => {\n const socket = net.connect(socketPath);\n const cleanup = () => {\n socket.off('connect', onConnect);\n socket.off('error', onError);\n signal?.removeEventListener('abort', onAbort);\n };\n const onConnect = () => {\n cleanup();\n resolve(socket);\n };\n const onError = () => {\n cleanup();\n socket.destroy();\n resolve(null);\n };\n const onAbort = () => {\n cleanup();\n socket.destroy();\n resolve(null);\n };\n socket.once('connect', onConnect);\n socket.once('error', onError);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","import type { ChildProcess, StdioOptions } from 'node:child_process';\nimport type { Readable } from 'node:stream';\n\nimport { LOG_EVENTS_ENV } from './constants';\nimport type { TapOptions } from './tap';\nimport type { ParsedEvent } from './types';\nimport { compileEventFilter, parseEventLine } from './utils/eventFilter';\n\nexport type CaptureOptions = Pick<TapOptions, 'debug' | 'filter'>;\n\nexport interface CaptureSpawnOptions {\n env?: NodeJS.ProcessEnv;\n stdio?: StdioOptions;\n}\n\nexport class EventCapture implements AsyncIterable<ParsedEvent> {\n #options: CaptureOptions;\n #eventFilter: RegExp | null;\n #index: number | undefined;\n #attached = false;\n #done = false;\n #events: ParsedEvent[] = [];\n #waiters: Array<(event: ParsedEvent | null) => void> = [];\n\n constructor(options: CaptureOptions = {}) {\n this.#options = options;\n this.#eventFilter = compileEventFilter(options.filter);\n }\n\n spawnOptions<T extends CaptureSpawnOptions>(\n options?: T\n ): T & Required<CaptureSpawnOptions> {\n const stdio: Extract<StdioOptions, readonly unknown[]> = Array.isArray(\n options?.stdio\n )\n ? [...options.stdio]\n : options?.stdio != null\n ? [options.stdio, options.stdio, options.stdio]\n : [];\n while (stdio.length < 3) stdio.push('inherit');\n this.#index = stdio.length;\n stdio.push('pipe');\n return {\n ...(options as T),\n stdio,\n env: {\n ...(options?.env ?? process.env),\n [LOG_EVENTS_ENV]: `${this.#index}`,\n },\n };\n }\n\n attach(child: ChildProcess): this {\n if (this.#index == null)\n throw new Error(\n 'captureEvents: spawnOptions() must create the pipe before attach()'\n );\n if (this.#attached)\n throw new Error('captureEvents: a child is already attached');\n const stream = child.stdio[this.#index] as Readable | null | undefined;\n if (!stream || typeof stream.setEncoding !== 'function')\n throw new Error(\n `captureEvents: child stdio[${this.#index}] is not a readable pipe`\n );\n this.#attached = true;\n\n let pending = '';\n stream.setEncoding('utf8');\n stream.on('data', (chunk: string) => {\n const data = pending ? pending + chunk : chunk;\n let start = 0;\n let end: number;\n while ((end = data.indexOf('\\n', start)) !== -1) {\n const line = data.slice(start, end);\n start = end + 1;\n if (line) this.#ingest(line);\n }\n pending = start ? data.slice(start) : data;\n });\n\n const finish = () => {\n if (this.#done) return;\n this.#done = true;\n if (pending) this.#ingest(pending);\n this.#notify(null);\n };\n stream.on('end', finish);\n stream.on('close', finish);\n stream.on('error', finish);\n return this;\n }\n\n async collect(): Promise<ParsedEvent[]> {\n const events: ParsedEvent[] = [];\n for await (const event of this) events.push(event);\n return events;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<ParsedEvent> {\n let event: ParsedEvent | null;\n while ((event = await this.#next())) yield event;\n }\n\n #ingest(line: string) {\n const event = parseEventLine(line, this.#options, this.#eventFilter);\n if (event) this.#notify(event);\n }\n\n #notify(event: ParsedEvent | null) {\n const waiter = this.#waiters.shift();\n if (waiter) waiter(event);\n else if (event) this.#events.push(event);\n }\n\n #next(): Promise<ParsedEvent | null> {\n if (this.#events.length) return Promise.resolve(this.#events.shift()!);\n if (this.#done) return Promise.resolve(null);\n if (!this.#attached)\n throw new Error('captureEvents: attach() a child before iterating');\n return new Promise(resolve => this.#waiters.push(resolve));\n }\n}\n\nexport function captureEvents(options?: CaptureOptions): EventCapture {\n return new EventCapture(options);\n}\n"],"names":["async","listSessions","options","cleanStaleSessionsSync","baseDir","getSessionBaseDir","entries","fs","readdir","withFileTypes","catch","sessions","entry","isDirectory","sessionDir","path","join","name","meta","readMetaSync","push","id","pid","formatVersion","alive","startedAt","command","cwd","version","origin","newest","newestSessionIds","session","isPidAlive","has","filterSessions","selector","input","trim","exact","filter","matchesSessionExactly","sessionSearchValues","some","value","length","normalized","toLowerCase","includes","sort","a","b","resolveSession","activeSessions","Error","map","formatSessionSelector","tap","follow","since","parseSince","eventFilter","compileEventFilter","abort","createTapAbortController","timeout","idleTimeout","AbortController","signal","addEventListener","once","setAbortTimer","live","connectLive","socketPath","resolveSocketPath","socket","SESSION_FILES","liveSocket","connectWithRetry","attempt","aborted","tryConnect","Promise","resolve","setTimeout","rl","createInterface","buffer","waiters","closed","line","waiter","shift","on","destroy","next","undefined","history","openHistoryFiles","maxSegments","DEFAULT_SEGMENTS","handles","all","Array","from","_","index","open","handle","reverse","idleTimer","readLines","event","parseEventLine","close","splice","resetAbortTimer","readLiveLine","clearTimeout","detectRotationLoss","first","readFirstLine","isSessionStartLine","startsWith","pending","chunk","createReadStream","encoding","indexOf","slice","onAbort","then","removeEventListener","timer","unref","String","argv","execPath","env","npmLifecycleEvent","npmPackageName","net","connect","cleanup","off","onConnect","onError","EventCapture","attached","done","events","constructor","this","spawnOptions","stdio","isArray","process","LOG_EVENTS_ENV","attach","child","stream","setEncoding","data","start","end","ingest","finish","notify","collect","Symbol","asyncIterator","captureEvents"],"mappings":"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"}
|