thinkpool-pair 0.7.132 → 0.7.134

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/bridge.mjs +23 -10
  2. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -1370,7 +1370,11 @@ function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rol
1370
1370
  // subagent-block; without cwd it runs outside its worktree; without rolePrompt it loses its
1371
1371
  // Flow role. blockSubagents / onLaneDone / onReviewVerdict / onSubmitPlan all derive from
1372
1372
  // these, so restoring them restores the whole behavior.
1373
- const sessionData = () => ({ sessionId: entry.session?.sessionId || resume || null, log: entry.log, commands: entry.commands, mode: entry.mode, spawnedBy: entry.spawnedBy, flowSessionId: entry.flowSessionId, flowTaskKey: entry.flowTaskKey, cwd: entry.cwd, rolePrompt: entry.rolePrompt, flowReviewTarget: entry.flowReviewTarget || null, revertTarget: entry.revertTarget || null, reviewSliceRoots: entry.reviewSliceRoots || [], openedAt: entry.openedAt || null })
1373
+ // model: persist the terminal's active model so a /model switch SURVIVES a bridge
1374
+ // restart. Without this, sessionData omitted it → on restart the resumed session
1375
+ // re-launched on the host default (Opus) regardless of the last switch, and the
1376
+ // switch looked like it "never changed the model" (Max 2026-07-02). Restored below.
1377
+ const sessionData = () => ({ sessionId: entry.session?.sessionId || resume || null, log: entry.log, commands: entry.commands, mode: entry.mode, model: entry.model || null, spawnedBy: entry.spawnedBy, flowSessionId: entry.flowSessionId, flowTaskKey: entry.flowTaskKey, cwd: entry.cwd, rolePrompt: entry.rolePrompt, flowReviewTarget: entry.flowReviewTarget || null, revertTarget: entry.revertTarget || null, reviewSliceRoots: entry.reviewSliceRoots || [], openedAt: entry.openedAt || null })
1374
1378
  const persist = () => saveSession(room, id, sessionData())
1375
1379
  // Synchronous flush of this session's record. Used on open (so a brand-new session
1376
1380
  // has a file under its id BEFORE its first event — surviving a restart inside the
@@ -1758,6 +1762,17 @@ function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rol
1758
1762
  // A background-warmed terminal is now live — free its warmer slot so the next queued
1759
1763
  // idle terminal starts booting.
1760
1764
  if (evt.kind === 'system' && entry.warming) warmComplete(entry)
1765
+ // Compaction milestone → the persistent recap card (CompactionCard). Attribute a
1766
+ // MANUAL compaction to whoever ran /compact; for an AUTO compaction (SDK-initiated
1767
+ // mid-turn) flash a brief "Compacting…" beat so it isn't silent — we only learn of it
1768
+ // post-hoc, so there's no real duration to animate (Max, 2026-07-02).
1769
+ if (evt.kind === 'compaction') {
1770
+ if (entry.compacting) evt.by = entry.compactBy || null
1771
+ else if (evt.trigger === 'auto') {
1772
+ bcast('code-event', { term: id, evt: { kind: 'compact', status: 'start', ts: Date.now() } })
1773
+ setTimeout(() => { bcast('code-event', { term: id, evt: { kind: 'compact', status: 'done', ts: Date.now() } }) }, 2500)
1774
+ }
1775
+ }
1761
1776
  // Chrome events (mode / usage / clear / compact) are transient state, not
1762
1777
  // transcript — broadcast + print them but keep out of the persisted/replayed log.
1763
1778
  // 'stalled' is transient turn-liveness state (would replay as a stale frozen
@@ -1773,12 +1788,10 @@ function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rol
1773
1788
  // text is the signal, so no line. Same control-event shape as ctlLine (kind:'control').
1774
1789
  if ((evt.kind === 'result' || evt.kind === 'error') && entry.compacting) {
1775
1790
  entry.compacting = false
1791
+ // Clear the ephemeral "Compacting…" indicator. The persistent record is the
1792
+ // CompactionCard (kind:'compaction', now attributed) — no redundant control line
1793
+ // that lingers in scrollback reading as "compacted recently" (Max, 2026-07-02).
1776
1794
  bcast('code-event', { term: id, evt: { kind: 'compact', status: 'done', ts: Date.now() } })
1777
- if (evt.kind === 'result') {
1778
- const doneEvt = { kind: 'control', text: '◈ context compacted', by: entry.compactBy || null }
1779
- pushLog(entry, doneEvt)
1780
- bcast('code-event', { term: id, evt: doneEvt })
1781
- }
1782
1795
  entry.compactBy = null
1783
1796
  }
1784
1797
  // Single tail: stamp into the log (transcript kinds only), broadcast live,
@@ -2179,10 +2192,10 @@ channel
2179
2192
  ctlLine('context cleared. You can continue with these answers in mind.')
2180
2193
  return
2181
2194
  }
2182
- // /compact → announce immediately, track so onEvent can emit a done signal when
2183
- // the SDK turn finishes. No echoYou — the ctl line IS the announcement.
2195
+ // /compact → show the ephemeral "Compacting…" indicator (the compact-start event),
2196
+ // track so onEvent clears it + attributes the recap card when the SDK turn finishes.
2197
+ // No persisted ctl line — the live indicator + the CompactionCard are the record.
2184
2198
  if (/^\/compact\b/.test(text)) {
2185
- ctlLine('◈ compacting context…')
2186
2199
  s.compacting = true
2187
2200
  s.compactBy = payload.by
2188
2201
  bcast('code-event', { term: payload.term, evt: { kind: 'compact', status: 'start', ts: Date.now() } })
@@ -2348,7 +2361,7 @@ Output:`
2348
2361
  // FL-M6 — restore the flow context (id/role/cwd) so an in-flight flow survives a
2349
2362
  // bridge restart: the conductor keeps its subagent-block + plan interception, and
2350
2363
  // lanes keep their worktree cwd + the ability to mark done.
2351
- openStructured({ id: rec.id, resume: canResume(rec) ? rec.sessionId : undefined, log: rec.log, commands: rec.commands, mode: rec.mode, spawnedBy: rec.spawnedBy, flowSessionId: rec.flowSessionId, flowTaskKey: rec.flowTaskKey, cwd: rec.cwd, rolePrompt: rec.rolePrompt, reviewSliceRoots: rec.reviewSliceRoots, openedAt: rec.openedAt,
2364
+ openStructured({ id: rec.id, model: rec.model || undefined, resume: canResume(rec) ? rec.sessionId : undefined, log: rec.log, commands: rec.commands, mode: rec.mode, spawnedBy: rec.spawnedBy, flowSessionId: rec.flowSessionId, flowTaskKey: rec.flowTaskKey, cwd: rec.cwd, rolePrompt: rec.rolePrompt, reviewSliceRoots: rec.reviewSliceRoots, openedAt: rec.openedAt,
2352
2365
  // Lazy-boot restored terminals that were IDLE + not part of a flow: their transcript
2353
2366
  // shows immediately; the query boots on first turn. Mid-turn + flow terminals boot now
2354
2367
  // (mid-turn needs auto-resume; flow needs its lane live).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.132",
3
+ "version": "0.7.134",
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": {