thinkpool-pair 0.7.140 → 0.7.141
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/claude-session.mjs +26 -1
- package/package.json +1 -1
package/claude-session.mjs
CHANGED
|
@@ -191,6 +191,7 @@ export function startClaudeSession({ cwd, model, resume, env, mode: initialMode
|
|
|
191
191
|
// that isn't persisted until a turn completes, so re-creating on it fails with
|
|
192
192
|
// "No conversation found" (Max 2026-07-02). This is always a resumable id.
|
|
193
193
|
let persistedSessionId = resume || null
|
|
194
|
+
let lastTurnText = null // the most recent turn text, so a bad-resume recovery can re-deliver it
|
|
194
195
|
let closed = false
|
|
195
196
|
// Lazy boot (2026-07-02): a RESTORED-IDLE terminal returns a full session object but
|
|
196
197
|
// defers the expensive query() cold-start (MCP + settingSources, ~50s each) until its
|
|
@@ -819,6 +820,30 @@ export function startClaudeSession({ cwd, model, resume, env, mode: initialMode
|
|
|
819
820
|
}
|
|
820
821
|
case 'result':
|
|
821
822
|
if (m.session_id) sessionId = m.session_id
|
|
823
|
+
// Bad resume target: the CLI can't find the session we tried to resume — a forked
|
|
824
|
+
// id that was never persisted, or a pruned transcript. It surfaces as an is_error
|
|
825
|
+
// RESULT (subtype error_during_execution), NOT a thrown error, so it bypasses the
|
|
826
|
+
// catch below and used to loop forever on the dead id (Max 2026-07-02, sid 6db6c1e3
|
|
827
|
+
// stuck across restarts + model switches). Drop the resume for good, re-run FRESH
|
|
828
|
+
// on the current model, and re-deliver the in-flight turn so nothing is lost.
|
|
829
|
+
if (m.is_error && Array.isArray(m.errors) && m.errors.some((x) => /no conversation found/i.test(String(x))) && (sessionId || persistedSessionId) && restartCount < RESTART_MAX) {
|
|
830
|
+
restartCount++
|
|
831
|
+
const wasActive = turnActive
|
|
832
|
+
turnActive = false
|
|
833
|
+
sessionId = null; persistedSessionId = null // never resume the dead id again
|
|
834
|
+
emit({ kind: 'note', text: 'previous session not found — continuing on a fresh one' })
|
|
835
|
+
const oldInput = input
|
|
836
|
+
input = makeInputStream()
|
|
837
|
+
try { oldInput.end() } catch { /* noop */ }
|
|
838
|
+
const replay = wasActive ? lastTurnText : null
|
|
839
|
+
restartTimer = setTimeout(() => {
|
|
840
|
+
restartTimer = null
|
|
841
|
+
if (closed) return
|
|
842
|
+
runQuery()
|
|
843
|
+
if (replay != null) { turnActive = true; lastEvtTs = Date.now(); stalledSent = false; input.push([{ type: 'text', text: replay }, { type: 'text', text: `<system-reminder>\n${TP_ROOM_REMINDER}\n</system-reminder>` }]) }
|
|
844
|
+
}, 300)
|
|
845
|
+
break
|
|
846
|
+
}
|
|
822
847
|
// Swallow the interrupt's redundant teardown results (see `interrupting` above):
|
|
823
848
|
// abort() already emitted the one canonical aborted boundary. `success` (and any
|
|
824
849
|
// non-teardown subtype) always emits; only the aborted/error_during_execution pair
|
|
@@ -956,7 +981,7 @@ export function startClaudeSession({ cwd, model, resume, env, mode: initialMode
|
|
|
956
981
|
return {
|
|
957
982
|
// A lazy (restored-idle) session cold-boots the query on its first turn. input.push
|
|
958
983
|
// is queue-backed, so the pushed turn buffers and runs once the query is ready.
|
|
959
|
-
sendTurn(text) { if (!closed) { if (!started) runQuery(); turnActive = true; sawSuggestion = false; if (sugTimer) { clearTimeout(sugTimer); sugTimer = null } lastEvtTs = Date.now(); stalledSent = false; input.push([{ type: 'text', text: String(text) }, { type: 'text', text: `<system-reminder>\n${TP_ROOM_REMINDER}\n</system-reminder>` }]) } },
|
|
984
|
+
sendTurn(text) { if (!closed) { if (!started) runQuery(); turnActive = true; sawSuggestion = false; lastTurnText = String(text); if (sugTimer) { clearTimeout(sugTimer); sugTimer = null } lastEvtTs = Date.now(); stalledSent = false; input.push([{ type: 'text', text: String(text) }, { type: 'text', text: `<system-reminder>\n${TP_ROOM_REMINDER}\n</system-reminder>` }]) } },
|
|
960
985
|
// Cold-boot the query WITHOUT sending a turn — the background warmer calls this on
|
|
961
986
|
// lazily-restored idle terminals so they're ready before the user clicks them.
|
|
962
987
|
warm() { if (!started && !closed) runQuery() },
|