thinkpool-pair 0.7.5 → 0.7.6

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 +14 -3
  2. package/package.json +1 -1
package/account.mjs CHANGED
@@ -109,7 +109,9 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
109
109
  // account without per-room probing. We TRACK this machine (name + served room
110
110
  // codes + version) on a per-account channel; the dashboard subscribes read-only.
111
111
  const machine = os.hostname().replace(/\.local$/, '')
112
- const acct = sb.channel(`tpacct:${session.user.id}`, { config: { presence: { key: machine } } })
112
+ const acct = sb.channel(`tpacct:${session.user.id}`, { config: { presence: { key: machine }, broadcast: { self: false } } })
113
+ // Dashboard "Disconnect" → broadcast shutdown → clean exit (presence leaves, bar flips live).
114
+ acct.on('broadcast', { event: 'shutdown' }, () => { process.stderr.write('\n ◇ disconnect requested from the dashboard — stopping bridge.\n'); process.kill(process.pid, 'SIGTERM') })
113
115
  const pushPresence = () => { try { acct.track({ name: machine, version: VERSION, rooms: [...children.keys()], ts: Date.now() }) } catch { /* noop */ } }
114
116
  await new Promise((res) => acct.subscribe((st) => { if (st === 'SUBSCRIBED') { pushPresence(); res() } }))
115
117
 
@@ -139,7 +141,16 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
139
141
 
140
142
  await tick()
141
143
  const iv = setInterval(tick, 15000)
142
- const stop = (sig) => { clearInterval(iv); try { acct.untrack(); sb.removeChannel(acct) } catch { /* noop */ } for (const c of children.values()) { try { c.kill(sig) } catch { /* noop */ } } setTimeout(() => process.exit(0), 400) }
143
- for (const sig of ['SIGINT', 'SIGTERM']) process.on(sig, () => stop(sig))
144
+ let stopping = false
145
+ const stop = (sig) => {
146
+ if (stopping) return; stopping = true
147
+ clearInterval(iv)
148
+ for (const c of children.values()) { try { c.kill(sig || 'SIGTERM') } catch { /* noop */ } }
149
+ // Flush the presence LEAVE before exiting so the dashboard flips to
150
+ // "not connected" in realtime (don't fire-and-forget the untrack).
151
+ ;(async () => { try { await acct.untrack() } catch { /* noop */ } try { await sb.removeChannel(acct) } catch { /* noop */ } process.exit(0) })()
152
+ setTimeout(() => process.exit(0), 1500) // hard backstop if the flush hangs
153
+ }
154
+ for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) process.on(sig, () => stop(sig))
144
155
  await new Promise(() => {})
145
156
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
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": {