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.
- package/bridge.mjs +25 -0
- 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.
|