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.
Files changed (2) hide show
  1. package/claude-session.mjs +26 -1
  2. package/package.json +1 -1
@@ -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() },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.140",
3
+ "version": "0.7.141",
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": {