thinkpool-pair 0.6.22 → 0.6.23

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/bridge.mjs +18 -3
  2. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -536,6 +536,16 @@ channel
536
536
  const t = terms.get(payload.term)
537
537
  if (t && !t.attached) { try { t.term.resize(Math.max(payload.cols, 80), Math.max(payload.rows, 20)); announce() } catch { /* noop */ } }
538
538
  })
539
+ .on('broadcast', { event: 'session-deleted' }, async () => {
540
+ // The room was deleted from the dashboard. Close the bridge — and if we're a
541
+ // background service, uninstall ourselves first so the supervisor doesn't
542
+ // restart us into a room that no longer exists.
543
+ process.stderr.write('\n ◆ this room was deleted — closing the bridge.\n')
544
+ if (process.env.THINKPOOL_PAIR_AUTOUPDATE === '1') {
545
+ try { const svc = await import('./service.mjs'); svc.uninstallService(room) } catch { /* noop */ }
546
+ }
547
+ shutdown()
548
+ })
539
549
  .on('broadcast', { event: 'term-open' }, ({ payload }) => {
540
550
  if (!payload?.id || !payload?.cmd) return
541
551
  // Multi-bridge rooms: a targeted open is for ONE machine. Untargeted
@@ -781,7 +791,7 @@ if (process.env.THINKPOOL_PAIR_AUTOUPDATE === '1' && VERSION) {
781
791
  }, 60000).unref()
782
792
  }
783
793
 
784
- function shutdown() {
794
+ async function shutdown() {
785
795
  if (shuttingDown) return
786
796
  shuttingDown = true
787
797
  clearInterval(flushTimer)
@@ -789,11 +799,16 @@ function shutdown() {
789
799
  const bye = Buffer.from('\r\n[ shared session ended ]\r\n', 'utf8').toString('base64')
790
800
  for (const id of terms.keys()) bcast('pty-out', { term: id, b64: bye })
791
801
  } catch { /* noop */ }
792
- try { supabase.removeChannel(channel) } catch { /* noop */ }
802
+ // Leave presence EXPLICITLY before exiting so the web room flips to dormant
803
+ // immediately. Previously we removeChannel()'d and process.exit()'d on the next
804
+ // line — the leave frame never flushed, so the web only noticed via the realtime
805
+ // heartbeat timeout (tens of seconds later) and looked stuck "live".
806
+ try { await channel.untrack() } catch { /* noop */ }
807
+ try { await supabase.removeChannel(channel) } catch { /* noop */ }
793
808
  for (const t of terms.values()) { try { t.term.kill() } catch { /* noop */ } }
794
809
  for (const s of sessions.values()) { try { s.session.end() } catch { /* noop */ } }
795
810
  detachLocal()
796
- process.exit(0)
811
+ setTimeout(() => process.exit(0), 250) // small grace for the leave/close frames to flush over the socket
797
812
  }
798
813
  process.on('SIGINT', shutdown)
799
814
  process.on('SIGTERM', shutdown)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.6.22",
3
+ "version": "0.6.23",
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": {