thinkpool-pair 0.7.174 → 0.7.175

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 (2) hide show
  1. package/account.mjs +18 -0
  2. package/package.json +1 -1
package/account.mjs CHANGED
@@ -594,6 +594,18 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
594
594
  provReply('providers-list-res', { nonce, ok: true, providers: listProviders() })
595
595
  })
596
596
 
597
+ // ENABLE presence delivery + the self-echo's ground truth. supabase-js only asks
598
+ // the server for presence state when a presence callback is bound at join time —
599
+ // with no listener, presenceState() stays {} FOREVER even while our own track()
600
+ // lands fine. That blind spot made the 0.7.174 self-echo watchdog false-positive
601
+ // respawn the supervisor every ~2.5 min ("the bridge disconnects and reconnects
602
+ // randomly", 2026-07-09 — nine respawns in an hour, track=ok on every one).
603
+ // Binding sync does two jobs: turns presence delivery ON (the echo becomes real)
604
+ // and stamps presenceSyncSeenAt — the watchdog's fail-safe (no proven delivery →
605
+ // no escalation, ever). Proof: /tmp echo-proof (no listener → {}, listener → key).
606
+ let presenceSyncSeenAt = 0
607
+ acct.on('presence', { event: 'sync' }, () => { presenceSyncSeenAt = Date.now() })
608
+
597
609
  // Re-track on EVERY (re)subscribe, not just the first: a realtime reconnect
598
610
  // (network blip, or a token swap mid-flight) rejoins the channel and must
599
611
  // re-announce, or the dashboard would read "no bridge" until the next restart.
@@ -1020,6 +1032,12 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
1020
1032
  const presenceWatch = setInterval(() => {
1021
1033
  if (stopping) return
1022
1034
  const now = Date.now()
1035
+ // FAIL-SAFE: escalation requires PROVEN presence delivery on this channel (≥1
1036
+ // sync ever received). An empty presenceState() without it means WE can't see —
1037
+ // not that the track failed; respawning on that is the 0.7.174 false-positive
1038
+ // loop. A real zombie (the bug this watchdog exists for) still escalates:
1039
+ // delivery was proven earlier, then our key vanished from the server's state.
1040
+ if (!presenceSyncSeenAt) { selfEchoMissingSince = 0; return }
1023
1041
  let present = false
1024
1042
  try { present = !!acct.presenceState?.()[machine] } catch { present = false }
1025
1043
  if (present) { selfEchoMissingSince = 0; presenceRecycledForMissing = 0; return }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.174",
3
+ "version": "0.7.175",
4
4
  "description": "Share a local coding-agent CLI (Claude Code, Codex, Gemini, Aider, …) into a ThinkPool Code room, live.",
5
5
  "type": "module",
6
6
  "bin": {