sentinelayer-cli 0.35.2 → 0.35.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentinelayer-cli",
3
- "version": "0.35.2",
3
+ "version": "0.35.3",
4
4
  "description": "Scaffold Sentinelayer spec/prompt/guide artifacts with secure browser auth and token bootstrap.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1851,6 +1851,23 @@ function listenerPresenceHeartbeatFingerprint(lifecycle = {}) {
1851
1851
  );
1852
1852
  }
1853
1853
 
1854
+ export function listenerLifecycleIdempotencyStep(lifecycle = {}) {
1855
+ const lifecycleType = normalizeString(lifecycle?.type) || "heartbeat";
1856
+ const heartbeatCount = Number(lifecycle?.heartbeatCount);
1857
+ if (
1858
+ lifecycleType === "heartbeat" &&
1859
+ Number.isInteger(heartbeatCount) &&
1860
+ heartbeatCount > 0
1861
+ ) {
1862
+ return heartbeatCount;
1863
+ }
1864
+ const pollCount = Number(lifecycle?.pollCount);
1865
+ if (Number.isInteger(pollCount) && pollCount >= 0) {
1866
+ return pollCount;
1867
+ }
1868
+ return 0;
1869
+ }
1870
+
1854
1871
  export function shouldPublishListenerPresenceHeartbeat({
1855
1872
  lifecycle = {},
1856
1873
  nowMs = Date.now(),
@@ -1900,6 +1917,10 @@ async function publishListenerPresenceEvent({
1900
1917
  } = {}) {
1901
1918
  const normalizedType = normalizeString(lifecycle.type) || "heartbeat";
1902
1919
  const eventName = listenerLifecycleEventName(normalizedType);
1920
+ const idempotencyStep = listenerLifecycleIdempotencyStep({
1921
+ ...lifecycle,
1922
+ type: normalizedType,
1923
+ });
1903
1924
  const identity = inferSessionAgentIdentity({
1904
1925
  agentId,
1905
1926
  model: agentModel,
@@ -1918,8 +1939,8 @@ async function publishListenerPresenceEvent({
1918
1939
  provider: normalizeString(identity.provider) || undefined,
1919
1940
  clientKind: normalizeString(identity.clientKind) || "cli",
1920
1941
  },
1921
- eventId: `session-listener-${listenerId}-${normalizedType}-${lifecycle.pollCount ?? 0}`,
1922
- idempotencyToken: `session-listener:${listenerId}:${normalizedType}:${lifecycle.pollCount ?? 0}`,
1942
+ eventId: `session-listener-${listenerId}-${normalizedType}-${idempotencyStep}`,
1943
+ idempotencyToken: `session-listener:${listenerId}:${normalizedType}:${idempotencyStep}`,
1923
1944
  payload: compactPayload({
1924
1945
  source: "session_listen",
1925
1946
  listenerId,
@@ -1930,6 +1951,7 @@ async function publishListenerPresenceEvent({
1930
1951
  cursorSuffix: lifecycle.cursorSuffix,
1931
1952
  cursorSource: lifecycle.cursorSource,
1932
1953
  pollCount: lifecycle.pollCount,
1954
+ heartbeatCount: lifecycle.heartbeatCount,
1933
1955
  matched: lifecycle.matched,
1934
1956
  emitted: lifecycle.emitted,
1935
1957
  persistedCursor: lifecycle.persistedCursor,
@@ -292,6 +292,7 @@ export async function listenSessionEvents({
292
292
  let activeTransport = normalizedTransport === "poll" ? "poll" : "stream";
293
293
  let streamAttempted = false;
294
294
  let streamFallbackReason = "";
295
+ let heartbeatCount = 0;
295
296
  let catchupNotified = false;
296
297
  let catchupEventCount = 0;
297
298
  let catchupMatchingEventCount = 0;
@@ -340,6 +341,7 @@ export async function listenSessionEvents({
340
341
  cursor: cursor || null,
341
342
  cursorSuffix,
342
343
  pollCount,
344
+ heartbeatCount,
343
345
  matched,
344
346
  emitted,
345
347
  persistedCursor,
@@ -474,6 +476,7 @@ export async function listenSessionEvents({
474
476
  }
475
477
 
476
478
  async function notifyHeartbeat({ stopping = false, nextPollMs = null } = {}) {
479
+ heartbeatCount += 1;
477
480
  const heartbeatAtMs = Number(_nowMs()) || Date.now();
478
481
  const humanActive = isRecentActivity(lastHumanActivityMs, heartbeatAtMs, activeWindowMs);
479
482
  await notifyLifecycle(