sentinelayer-cli 0.30.12 → 0.30.13
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/package.json +1 -1
- package/src/session/listener.js +44 -2
package/package.json
CHANGED
package/src/session/listener.js
CHANGED
|
@@ -38,6 +38,10 @@ function normalizePositiveInteger(value, fallbackValue) {
|
|
|
38
38
|
return Math.floor(normalized);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
function isListenerStopDirective(event = {}) {
|
|
42
|
+
return normalizeString(event?.event) === "listener_stop";
|
|
43
|
+
}
|
|
44
|
+
|
|
41
45
|
function isPlainObject(value) {
|
|
42
46
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
43
47
|
}
|
|
@@ -255,6 +259,8 @@ export async function listenSessionEvents({
|
|
|
255
259
|
_readCursor = readSyncCursor,
|
|
256
260
|
_writeCursor = writeSyncCursor,
|
|
257
261
|
_sleep = defaultSleep,
|
|
262
|
+
_setInterval = setInterval,
|
|
263
|
+
_clearInterval = clearInterval,
|
|
258
264
|
_nowMs = Date.now,
|
|
259
265
|
} = {}) {
|
|
260
266
|
const normalizedSessionId = normalizeString(sessionId);
|
|
@@ -394,6 +400,7 @@ export async function listenSessionEvents({
|
|
|
394
400
|
const visibleEvents = [];
|
|
395
401
|
let preStartEventCount = 0;
|
|
396
402
|
for (const event of events) {
|
|
403
|
+
if (!isPlainObject(event)) continue;
|
|
397
404
|
const timestampMs = eventTimestampMs(event);
|
|
398
405
|
if (!timestampMs || timestampMs < startedAtMs) {
|
|
399
406
|
preStartEventCount += 1;
|
|
@@ -402,6 +409,7 @@ export async function listenSessionEvents({
|
|
|
402
409
|
if (isRecentActivity(activityMs, observedAtMs, activeWindowMs)) {
|
|
403
410
|
lastHumanActivityMs = Math.max(lastHumanActivityMs, activityMs);
|
|
404
411
|
}
|
|
412
|
+
if (timestampMs && timestampMs < startedAtMs && isListenerStopDirective(event)) continue;
|
|
405
413
|
if (isSessionListenerLifecycleEvent(event)) continue;
|
|
406
414
|
if (!eventMatchesAgent(event, normalizedAgentId)) continue;
|
|
407
415
|
visibleEvents.push(event);
|
|
@@ -441,9 +449,14 @@ export async function listenSessionEvents({
|
|
|
441
449
|
if (emittedKeys.has(key)) continue;
|
|
442
450
|
matched += 1;
|
|
443
451
|
if (!shouldEmitBatch && eventTimestampMs(event) < startedAtMs) continue;
|
|
444
|
-
await onEvent(event);
|
|
445
452
|
emittedKeys.add(key);
|
|
446
|
-
|
|
453
|
+
try {
|
|
454
|
+
await onEvent(event);
|
|
455
|
+
emitted += 1;
|
|
456
|
+
} catch (error) {
|
|
457
|
+
emittedKeys.delete(key);
|
|
458
|
+
throw error;
|
|
459
|
+
}
|
|
447
460
|
}
|
|
448
461
|
|
|
449
462
|
if (nextCursor && nextCursor !== cursor) {
|
|
@@ -473,6 +486,32 @@ export async function listenSessionEvents({
|
|
|
473
486
|
return humanActive;
|
|
474
487
|
}
|
|
475
488
|
|
|
489
|
+
let streamHeartbeatTimer = null;
|
|
490
|
+
let streamHeartbeatInFlight = false;
|
|
491
|
+
const streamHeartbeatMs = Math.max(1_000, Math.min(idleSleepMs, 60_000));
|
|
492
|
+
|
|
493
|
+
function stopStreamHeartbeatTimer() {
|
|
494
|
+
if (!streamHeartbeatTimer) return;
|
|
495
|
+
_clearInterval(streamHeartbeatTimer);
|
|
496
|
+
streamHeartbeatTimer = null;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function startStreamHeartbeatTimer() {
|
|
500
|
+
stopStreamHeartbeatTimer();
|
|
501
|
+
streamHeartbeatTimer = _setInterval(async () => {
|
|
502
|
+
if (signal?.aborted || streamHeartbeatInFlight) return;
|
|
503
|
+
streamHeartbeatInFlight = true;
|
|
504
|
+
try {
|
|
505
|
+
await notifyHeartbeat({ nextPollMs: null });
|
|
506
|
+
} finally {
|
|
507
|
+
streamHeartbeatInFlight = false;
|
|
508
|
+
}
|
|
509
|
+
}, streamHeartbeatMs);
|
|
510
|
+
if (streamHeartbeatTimer && typeof streamHeartbeatTimer.unref === "function") {
|
|
511
|
+
streamHeartbeatTimer.unref();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
476
515
|
await notifyLifecycle(
|
|
477
516
|
lifecycleSnapshot("started", {
|
|
478
517
|
startedAt: new Date(startedAtMs).toISOString(),
|
|
@@ -484,6 +523,7 @@ export async function listenSessionEvents({
|
|
|
484
523
|
if (normalizedTransport !== "poll") {
|
|
485
524
|
streamAttempted = true;
|
|
486
525
|
activeTransport = "stream";
|
|
526
|
+
startStreamHeartbeatTimer();
|
|
487
527
|
const streamResult = await _stream(normalizedSessionId, {
|
|
488
528
|
targetPath,
|
|
489
529
|
since: cursor,
|
|
@@ -502,6 +542,8 @@ export async function listenSessionEvents({
|
|
|
502
542
|
onHeartbeat: async () => {
|
|
503
543
|
await notifyHeartbeat({ nextPollMs: null });
|
|
504
544
|
},
|
|
545
|
+
}).finally(() => {
|
|
546
|
+
stopStreamHeartbeatTimer();
|
|
505
547
|
});
|
|
506
548
|
if (!streamResult?.ok) {
|
|
507
549
|
streamFallbackReason = normalizeString(streamResult?.reason) || lastReason || "stream_failed";
|