thinkpool-pair 0.7.50 → 0.7.51

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 +25 -0
  2. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -653,6 +653,22 @@ function pushLog(entry, evt) {
653
653
  return evt
654
654
  }
655
655
 
656
+ // Resume-idle guard (2026-06-22 cooked-terminal bug): a turn force-killed mid-flight
657
+ // leaves the restored log ending on in-flight events (assistant/you/tool_result) with
658
+ // NO terminal `result`, so the web reads it as "thinking" forever AND Stop is a no-op
659
+ // (the freshly-resumed SDK session has no live turn to interrupt — q.interrupt() on an
660
+ // idle query does nothing). Mirror of the client working-scan in
661
+ // src/pages/code/structured.jsx: walking back from the end, a result/error/propose/pool
662
+ // closes the turn; an assistant/you/tool_result reached first means it's still open.
663
+ function restoredTurnOpen(log) {
664
+ for (let i = log.length - 1; i >= 0; i--) {
665
+ const k = log[i]?.kind
666
+ if (k === 'result' || k === 'error' || k === 'propose' || k === 'pool') return false
667
+ if (k === 'assistant' || k === 'you' || k === 'tool_result') return true
668
+ }
669
+ return false
670
+ }
671
+
656
672
  // The Phase-2 path: instead of a PTY, run Claude Code through the Agent SDK and
657
673
  // relay STRUCTURED events. onEvent → broadcast `code-event` + print locally +
658
674
  // persist to the host file; tool calls round-trip through the perm card; the
@@ -666,6 +682,15 @@ function openStructured({ id, model, resume, log, commands, mode }) {
666
682
  // event-id.mjs + src/pages/code/seqDedup.js). pushLog() is the single stamp point.
667
683
  entry.seq = makeSeqCounter(maxSeq(entry.log))
668
684
  sessions.set(id, entry)
685
+ // Close an interrupted turn so a restored terminal comes back IDLE-with-history
686
+ // instead of stuck "thinking" (see restoredTurnOpen). Idempotent: the closer is
687
+ // persisted, so a later resume sees a closed turn and no-ops.
688
+ if (entry.log.length && restoredTurnOpen(entry.log)) {
689
+ const closer = { kind: 'result', subtype: 'aborted', recovered: true }
690
+ stampEvent(closer)
691
+ pushLog(entry, closer)
692
+ process.stderr.write(`\n ◆ closed an interrupted turn on resume (${id.slice(0, 8)}) — restored idle.\n`)
693
+ }
669
694
  // This session's private mockup outbox — render.sh writes manifests here (via
670
695
  // TP_MOCKUP_OUTBOX below) and the watcher attributes every card to THIS id, so
671
696
  // they land on this session even after other terminals open/close.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.50",
3
+ "version": "0.7.51",
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": {