thinkpool-pair 0.7.128 → 0.7.129
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 +19 -7
- package/package.json +1 -1
- package/session-store.mjs +11 -0
package/bridge.mjs
CHANGED
|
@@ -83,7 +83,7 @@ const flowRedispatch = new Map()
|
|
|
83
83
|
const flowBudgets = new Map()
|
|
84
84
|
import { formatPeek, PEEK, siblingsOf, resolveSibling, crossPostDecision, CROSSPOST, spawnDecision, CROSSROOM, formatPairRoster, crossRoomPostDecision } from './cross-terminal.mjs'
|
|
85
85
|
import { turnInFlight } from './update-gate.mjs'
|
|
86
|
-
import { saveSession, flushSession, deleteSession, loadAll, canResume, loadPtyId, savePtyId, loadNames, saveNames, appendDurableEvents, seedDurableEvents, readDurablePage, readDurableOldestSeq } from './session-store.mjs'
|
|
86
|
+
import { saveSession, flushSession, deleteSession, loadAll, canResume, loadPtyId, savePtyId, loadNames, saveNames, appendDurableEvents, seedDurableEvents, readDurablePage, readDurableOldestSeq, loadSummary, saveSummary } from './session-store.mjs'
|
|
87
87
|
import { stampEvent, makeSeqCounter, maxSeq, seqable, capReplayEvents, chunkReplayEvents, boundEventForBroadcast, inlineImageBlocks } from './event-id.mjs'
|
|
88
88
|
import { makeThrottledTrack } from './presence.mjs'
|
|
89
89
|
|
|
@@ -2213,6 +2213,13 @@ channel
|
|
|
2213
2213
|
// re-open within a page load).
|
|
2214
2214
|
.on('broadcast', { event: 'code-summarize' }, async ({ payload }) => {
|
|
2215
2215
|
const by = payload?.by || null
|
|
2216
|
+
// Peek — any device opening the panel fetches the cached recap (cross-device +
|
|
2217
|
+
// cross-restart persistence) WITHOUT spending a model call. No cache → silent.
|
|
2218
|
+
if (payload?.peek) {
|
|
2219
|
+
const cached = loadSummary(room)
|
|
2220
|
+
if (cached && cached.text) bcast('code-summary', { status: 'done', ...cached })
|
|
2221
|
+
return
|
|
2222
|
+
}
|
|
2216
2223
|
bcast('code-summary', { status: 'generating', by })
|
|
2217
2224
|
try {
|
|
2218
2225
|
// Pull assistant/user text out of a transcript-event array, keep the tail.
|
|
@@ -2253,18 +2260,23 @@ channel
|
|
|
2253
2260
|
? `\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)}`
|
|
2254
2261
|
: ''
|
|
2255
2262
|
|
|
2256
|
-
const prompt = `
|
|
2257
|
-
-
|
|
2258
|
-
-
|
|
2259
|
-
|
|
2263
|
+
const prompt = `Summarize this multi-terminal coding session as a STRUCTURED LIST. Output ONLY these lines, nothing else:
|
|
2264
|
+
- ONE line per LIVE terminal, EXACTLY: <terminal name> | <working or done> | <one clause, max 12 words, no trailing period>
|
|
2265
|
+
- If there are CLOSED terminals, ONE final line, EXACTLY: CLOSED | <count> | <one aggregate clause about what they handled — do NOT name them>
|
|
2266
|
+
Use the pipe "|" as the separator. No headers, no markdown, no bullets, no extra prose. Example:
|
|
2267
|
+
Bridge Whip | working | SDK 0.7.128, detection gates live
|
|
2268
|
+
Reddit | done | GTM strategy mapped
|
|
2269
|
+
CLOSED | 52 | flow-trigger churn and @pool integration
|
|
2260
2270
|
|
|
2261
2271
|
${liveBlock}${closedBlock}
|
|
2262
2272
|
|
|
2263
|
-
|
|
2273
|
+
Output:`
|
|
2264
2274
|
|
|
2265
2275
|
const res = await oneShotSummary({ prompt, env: env || process.env, cwd: cwd || process.cwd() })
|
|
2266
2276
|
if (!res || !res.text) { bcast('code-summary', { status: 'error', error: 'Summary model unavailable on this provider.', by }); return }
|
|
2267
|
-
|
|
2277
|
+
const summary = { text: res.text, model: res.model, generatedAt: Date.now() }
|
|
2278
|
+
try { saveSummary(room, summary) } catch { /* cache is best-effort */ }
|
|
2279
|
+
bcast('code-summary', { status: 'done', ...summary, by })
|
|
2268
2280
|
process.stderr.write(`\n ◆ session summary generated (${res.model}) for ${by || 'someone'}.\n`)
|
|
2269
2281
|
} catch (e) {
|
|
2270
2282
|
bcast('code-summary', { status: 'error', error: String(e?.message || e).slice(0, 140), by })
|
package/package.json
CHANGED
package/session-store.mjs
CHANGED
|
@@ -191,3 +191,14 @@ export function loadNames(room) {
|
|
|
191
191
|
export function saveNames(room, names) {
|
|
192
192
|
try { ensureDir(room); fs.writeFileSync(namesFile(room), JSON.stringify(names || {})) } catch { /* noop */ }
|
|
193
193
|
}
|
|
194
|
+
|
|
195
|
+
// Session recap cache (2026-07-02, Session Info panel). The last on-demand summary,
|
|
196
|
+
// stored as a dotfile (NOT *.json → never in loadAll) so it survives a bridge restart
|
|
197
|
+
// and any device that opens the panel can fetch it (persists across devices). One per room.
|
|
198
|
+
const summaryFile = (room) => path.join(dir(room), '.summary')
|
|
199
|
+
export function loadSummary(room) {
|
|
200
|
+
try { return JSON.parse(fs.readFileSync(summaryFile(room), 'utf8')) || null } catch { return null }
|
|
201
|
+
}
|
|
202
|
+
export function saveSummary(room, summary) {
|
|
203
|
+
try { ensureDir(room); fs.writeFileSync(summaryFile(room), JSON.stringify(summary || null)) } catch { /* noop */ }
|
|
204
|
+
}
|