thinkpool-pair 0.7.21 → 0.7.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.
- package/bridge.mjs +28 -5
- package/package.json +1 -1
- package/session-store.mjs +14 -0
package/bridge.mjs
CHANGED
|
@@ -36,7 +36,7 @@ import { spawn } from 'node:child_process'
|
|
|
36
36
|
import { randomUUID } from 'node:crypto'
|
|
37
37
|
import { createClient } from '@supabase/supabase-js'
|
|
38
38
|
import { startClaudeSession } from './claude-session.mjs'
|
|
39
|
-
import { saveSession, flushSession, deleteSession, loadAll, canResume, loadPtyId, savePtyId } from './session-store.mjs'
|
|
39
|
+
import { saveSession, flushSession, deleteSession, loadAll, canResume, loadPtyId, savePtyId, loadNames, saveNames } from './session-store.mjs'
|
|
40
40
|
|
|
41
41
|
// Public client creds (the same anon values the web app ships — safe to embed).
|
|
42
42
|
// Override with TP_SUPABASE_URL / TP_SUPABASE_ANON if you ever need to.
|
|
@@ -331,6 +331,11 @@ const bcast = (event, payload) => {
|
|
|
331
331
|
} catch { /* noop */ }
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
// Per-room terminal display names (id -> label), set by the web's `term-rename`.
|
|
335
|
+
// Persisted on the host so a rename is cross-device + survives a bridge restart;
|
|
336
|
+
// every announce carries them so a late-joining or second device sees them too.
|
|
337
|
+
const termNames = loadNames(room)
|
|
338
|
+
|
|
334
339
|
const announce = () =>
|
|
335
340
|
bcast('bridge', {
|
|
336
341
|
v: 2, name, repo: repoLabel, branch,
|
|
@@ -352,10 +357,12 @@ const announce = () =>
|
|
|
352
357
|
// cols/rows: the PTY's one true size — web viewers render this grid and
|
|
353
358
|
// scale it to their own page instead of voting to reflow it.
|
|
354
359
|
terms: [
|
|
355
|
-
...[...terms.entries()].map(([id, t]) => ({ id, cmd: t.cmd, alive: true, cols: t.term.cols, rows: t.term.rows })),
|
|
360
|
+
...[...terms.entries()].map(([id, t]) => ({ id, cmd: t.cmd, alive: true, cols: t.term.cols, rows: t.term.rows, name: termNames[id] || undefined })),
|
|
356
361
|
// Structured sessions advertise kind:'structured' so the web renders the
|
|
357
|
-
// reader (not xterm) and drives them with code-turn / code-perm.
|
|
358
|
-
|
|
362
|
+
// reader (not xterm) and drives them with code-turn / code-perm. `mode` +
|
|
363
|
+
// `name` ride along so a second device shows the live permission mode and
|
|
364
|
+
// the chosen label instead of defaulting to Normal / unnamed.
|
|
365
|
+
...[...sessions.entries()].map(([id, s]) => ({ id, cmd: s.cmd, kind: 'structured', alive: true, commands: s.commands, mode: s.mode || undefined, name: termNames[id] || undefined })),
|
|
359
366
|
],
|
|
360
367
|
})
|
|
361
368
|
|
|
@@ -820,6 +827,16 @@ channel
|
|
|
820
827
|
.on('broadcast', { event: 'code-close' }, ({ payload }) => {
|
|
821
828
|
endStructured(payload?.id)
|
|
822
829
|
})
|
|
830
|
+
// Persist + re-announce terminal renames. The web also echoes term-rename to
|
|
831
|
+
// online peers directly; storing it here is what reaches a device that joins
|
|
832
|
+
// LATER (or a second machine) — those only ever see the announce.
|
|
833
|
+
.on('broadcast', { event: 'term-rename' }, ({ payload }) => {
|
|
834
|
+
if (!payload?.id) return
|
|
835
|
+
if (payload.name) termNames[payload.id] = String(payload.name).slice(0, 80)
|
|
836
|
+
else delete termNames[payload.id]
|
|
837
|
+
saveNames(room, termNames)
|
|
838
|
+
announce()
|
|
839
|
+
})
|
|
823
840
|
.on('broadcast', { event: 'who' }, announce)
|
|
824
841
|
.subscribe(status => {
|
|
825
842
|
if (status === 'SUBSCRIBED') {
|
|
@@ -837,7 +854,13 @@ channel
|
|
|
837
854
|
if (wantStructured(startCmd)) {
|
|
838
855
|
const all = loadAll(room).filter((r) => r.log?.length || r.sessionId)
|
|
839
856
|
if (all.length) for (const rec of all) openStructured({ id: rec.id, resume: canResume(rec) ? rec.sessionId : undefined, log: rec.log, commands: rec.commands, mode: rec.mode })
|
|
840
|
-
|
|
857
|
+
// Fresh open: ONLY for an explicit `-- <claude>` share. In account mode
|
|
858
|
+
// (autoAgent set, no attachedCmd) the web's `?new=1` flow opens the first
|
|
859
|
+
// terminal; opening one here too raced it into TWO terminals — each a
|
|
860
|
+
// fresh random id, so openStructured's id-dedup couldn't catch it. The
|
|
861
|
+
// saved-session restore above still runs unconditionally, so a bridge
|
|
862
|
+
// restart resumes backgrounded sessions regardless of this guard.
|
|
863
|
+
else if (attachedCmd) openStructured({ id: randomUUID() })
|
|
841
864
|
}
|
|
842
865
|
else {
|
|
843
866
|
// Reuse the prior auto-opened PTY id across restarts so a reconnecting
|
package/package.json
CHANGED
package/session-store.mjs
CHANGED
|
@@ -83,3 +83,17 @@ export function loadPtyId(room) {
|
|
|
83
83
|
export function savePtyId(room, id) {
|
|
84
84
|
try { ensureDir(room); fs.writeFileSync(ptyFile(room), String(id)) } catch { /* noop */ }
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
// Per-room terminal display names (terminal id -> label), set via the web's
|
|
88
|
+
// `term-rename` broadcast. This is what makes a rename CROSS-DEVICE + survive a
|
|
89
|
+
// bridge restart: names were previously web-localStorage only + a live broadcast,
|
|
90
|
+
// so a device that joined later (or a second machine) saw none of them. The bridge
|
|
91
|
+
// stores them here and includes them in every announce. Stored as a single dotfile
|
|
92
|
+
// (NOT *.json) so it never lands in listRecs/loadAll.
|
|
93
|
+
const namesFile = (room) => path.join(dir(room), '.names')
|
|
94
|
+
export function loadNames(room) {
|
|
95
|
+
try { return JSON.parse(fs.readFileSync(namesFile(room), 'utf8')) || {} } catch { return {} }
|
|
96
|
+
}
|
|
97
|
+
export function saveNames(room, names) {
|
|
98
|
+
try { ensureDir(room); fs.writeFileSync(namesFile(room), JSON.stringify(names || {})) } catch { /* noop */ }
|
|
99
|
+
}
|