thinkpool-pair 0.7.11 → 0.7.12

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 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, loadLatest, canResume } from './session-store.mjs'
39
+ import { saveSession, flushSession, loadLatest, canResume, loadPtyId, savePtyId } 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.
@@ -205,6 +205,15 @@ const askYesNo = (q, defaultYes = true) => new Promise((resolve) => {
205
205
  let attachedCmd = null, attachedArgs = [], continuing = false
206
206
  if (dashIdx >= 0) {
207
207
  ;[attachedCmd, ...attachedArgs] = argv.slice(dashIdx + 1)
208
+ // A token after `--` that's itself a flag (e.g. `-- --headless`) is a
209
+ // mis-placed own-flag, not a command to share — own-flags are already parsed
210
+ // from the full argv above, regardless of `--` position. Refuse to treat it
211
+ // as a command, else the subscribe handler auto-opens a junk PTY literally
212
+ // running `--headless` that immediately goes dormant (Maxbridge Main, 2026-06-17).
213
+ if (attachedCmd && attachedCmd.startsWith('-')) {
214
+ process.stderr.write(`\n ◇ ignoring "${attachedCmd}" after \`--\` — that's a flag, not a command to share.\n`)
215
+ attachedCmd = null; attachedArgs = []
216
+ }
208
217
  } else if (!headless) {
209
218
  if (installedAgents.length === 0) {
210
219
  console.error(`\n No known coding-agent CLI found on your PATH.\n Install one (claude / codex / gemini / aider / cursor-agent / opencode …)\n or share a specific command: npx thinkpool-pair ${room} -- <your-command>\n`)
@@ -774,7 +783,14 @@ channel
774
783
  if (prev && (prev.log?.length || prev.sessionId)) openStructured({ id: prev.id, resume: canResume(prev) ? prev.sessionId : undefined, log: prev.log, commands: prev.commands, mode: prev.mode })
775
784
  else openStructured({ id: randomUUID() })
776
785
  }
777
- else openTerm({ id: randomUUID(), cmd: startCmd, args: attachedArgs, attached: !autoAgent })
786
+ else {
787
+ // Reuse the prior auto-opened PTY id across restarts so a reconnecting
788
+ // bridge re-attaches to the SAME terminal tab instead of breeding a
789
+ // fresh dormant "Terminal N" on every reconnect.
790
+ const ptyId = loadPtyId(room) || randomUUID()
791
+ savePtyId(room, ptyId)
792
+ openTerm({ id: ptyId, cmd: startCmd, args: attachedArgs, attached: !autoAgent })
793
+ }
778
794
  }
779
795
  announce()
780
796
  process.stderr.write(headless
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.11",
3
+ "version": "0.7.12",
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": {
package/session-store.mjs CHANGED
@@ -55,3 +55,15 @@ export function loadLatest(room) {
55
55
  export function canResume(rec) {
56
56
  return !!(rec && rec.sessionId && rec.savedAt && (Date.now() - rec.savedAt) < RESUME_MAX_AGE_MS)
57
57
  }
58
+
59
+ // Last PTY terminal id auto-opened for an attached command. A reconnecting
60
+ // bridge reuses it so it re-attaches to the SAME terminal tab instead of
61
+ // minting a fresh UUID and breeding a new dormant "Terminal N" each restart.
62
+ // Stored as a dotfile (NOT *.json) so it never lands in listRecs/loadLatest.
63
+ const ptyFile = (room) => path.join(dir(room), '.pty-id')
64
+ export function loadPtyId(room) {
65
+ try { return fs.readFileSync(ptyFile(room), 'utf8').trim() || null } catch { return null }
66
+ }
67
+ export function savePtyId(room, id) {
68
+ try { ensureDir(room); fs.writeFileSync(ptyFile(room), String(id)) } catch { /* noop */ }
69
+ }