thinkpool-pair 0.7.139 → 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/bridge.mjs +25 -14
- package/claude-session.mjs +26 -1
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -2262,12 +2262,13 @@ channel
|
|
|
2262
2262
|
saveNames(room, termNames)
|
|
2263
2263
|
announce()
|
|
2264
2264
|
})
|
|
2265
|
-
// Session Info panel (2026-07-02) — a cheap one-shot
|
|
2266
|
-
//
|
|
2267
|
-
//
|
|
2268
|
-
//
|
|
2269
|
-
//
|
|
2270
|
-
//
|
|
2265
|
+
// Session Info panel (2026-07-02, plain-English recap 2026-07-02) — a cheap one-shot
|
|
2266
|
+
// recap on demand. Writes a plain-English "Done so far" / "Working on now" bullet
|
|
2267
|
+
// summary (Markdown) of what the whole session accomplished + what's live — NOT a
|
|
2268
|
+
// per-terminal technical list (Max's ask: clean, readable, no jargon/terminal names).
|
|
2269
|
+
// Runs on the room's own subscription auth via oneShotSummary (cheap haiku →
|
|
2270
|
+
// provider-default fallback). Never auto — only on the panel button. The web caches
|
|
2271
|
+
// the result in React state (no re-charge on re-open within a page load).
|
|
2271
2272
|
.on('broadcast', { event: 'code-summarize' }, async ({ payload }) => {
|
|
2272
2273
|
const by = payload?.by || null
|
|
2273
2274
|
// Peek — any device opening the panel fetches the cached recap (cross-device +
|
|
@@ -2317,17 +2318,27 @@ channel
|
|
|
2317
2318
|
? `\n\nThere are also ${closedIds.length} CLOSED terminal(s). Recent excerpts (do NOT name them individually):\n${(closedDigests.join('\n---\n') || '(no retained detail)').slice(0, 1400)}`
|
|
2318
2319
|
: ''
|
|
2319
2320
|
|
|
2320
|
-
const prompt = `
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2321
|
+
const prompt = `Write a short, friendly recap of this coding session for someone non-technical who just wants to know what's going on. Plain English only — no jargon, no file names, no branch names, no terminal names or IDs, no code, no counts of terminals. Explain what the work MEANS and why it matters, not the mechanics.
|
|
2322
|
+
|
|
2323
|
+
Output ONLY this Markdown shape, nothing else:
|
|
2324
|
+
|
|
2325
|
+
**Done so far**
|
|
2326
|
+
- <one plain-English thing that got finished>
|
|
2327
|
+
- <another>
|
|
2328
|
+
|
|
2329
|
+
**Working on now**
|
|
2330
|
+
- <what's actively being worked on, in plain English>
|
|
2331
|
+
|
|
2332
|
+
Rules:
|
|
2333
|
+
- Merge ALL the finished work — live and closed terminals alike — into "Done so far". Combine similar items; do NOT organise by terminal or list them. Aim for 3–6 bullets.
|
|
2334
|
+
- Put only genuinely in-progress work under "Working on now". If nothing is active, write exactly: "- Nothing in progress right now — everything's wrapped up."
|
|
2335
|
+
- Each bullet is one clear sentence, ~16 words max, no trailing period, and no technical term a normal person wouldn't understand.
|
|
2336
|
+
|
|
2337
|
+
Here's the raw session activity to summarize:
|
|
2327
2338
|
|
|
2328
2339
|
${liveBlock}${closedBlock}
|
|
2329
2340
|
|
|
2330
|
-
|
|
2341
|
+
Recap:`
|
|
2331
2342
|
|
|
2332
2343
|
const res = await oneShotSummary({ prompt, env: env || process.env, cwd: cwd || process.cwd() })
|
|
2333
2344
|
if (!res || !res.text) { bcast('code-summary', { status: 'error', error: 'Summary model unavailable on this provider.', by }); return }
|
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() },
|