thinkpool-pair 0.7.111 → 0.7.112

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 +14 -1
  2. package/package.json +1 -1
package/bridge.mjs CHANGED
@@ -677,7 +677,11 @@ const announce = () =>
677
677
  // the chosen label instead of defaulting to Normal / unnamed. `spawned` (set
678
678
  // when an agent Dispatched this lane via spawn_terminal) lets the client keep
679
679
  // it OUT of the top tab strip and show it only in the Ensemble menu.
680
- ...[...sessions.entries()].map(([id, s]) => ({ id, cmd: s.cmd, kind: 'structured', alive: true, commands: s.commands, mode: s.mode || undefined, name: termNames[id] || undefined, ...(s.archiveOldestSeq != null ? { oldestSeq: s.archiveOldestSeq } : {}), ...(s.spawnedBy ? { spawned: true, spawnedBy: s.spawnedBy } : {}), ...(s.flowSessionId ? { flowId: s.flowSessionId, flowRole: s.flowTaskKey ? 'lane' : 'conductor' } : {}) })),
680
+ // busy: this structured session is mid-turn right now (the SDK's
681
+ // turnActive). Authoritative — the bridge owns the turn — so the /code
682
+ // dashboard reads "N agents working" off the roster instead of sniffing
683
+ // the live code-event stream (which a passive dashboard channel misses).
684
+ ...[...sessions.entries()].map(([id, s]) => ({ id, cmd: s.cmd, kind: 'structured', alive: true, busy: s.session?.turnActive ?? false, commands: s.commands, mode: s.mode || undefined, name: termNames[id] || undefined, ...(s.archiveOldestSeq != null ? { oldestSeq: s.archiveOldestSeq } : {}), ...(s.spawnedBy ? { spawned: true, spawnedBy: s.spawnedBy } : {}), ...(s.flowSessionId ? { flowId: s.flowSessionId, flowRole: s.flowTaskKey ? 'lane' : 'conductor' } : {}) })),
681
685
  ],
682
686
  })
683
687
 
@@ -1517,6 +1521,15 @@ function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rol
1517
1521
  // id, an event that arrives both live AND in a reconnect replay renders
1518
1522
  // twice (the 2026-06-19 duplicate-message bug). See event-id.mjs.
1519
1523
  stampEvent(evt)
1524
+ // Re-announce the roster on THIS session's busy EDGE — turn start (turnActive
1525
+ // flips true on the turn's first event) and turn end (false on result/error).
1526
+ // Edge-triggered: one announce per transition, not per token event. This is what
1527
+ // makes the /code dashboard's "N agents working" reliable — it reads busy off the
1528
+ // roster broadcast (delivered to every subscriber) instead of sniffing the live
1529
+ // code-event stream a passive dashboard channel misses. Covers every turn path
1530
+ // (normal, spawn, flow lane, cross-room) since they all flow through onEvent.
1531
+ { const busyNow = entry.session?.turnActive ?? false
1532
+ if (busyNow !== entry._busyAnn) { entry._busyAnn = busyNow; announce() } }
1520
1533
  // FL-B2 — fold this flow lane's completed-turn output tokens into its budget so the
1521
1534
  // autopilot cap can halt the next wave before overrun (output_tokens = the billed
1522
1535
  // reasoning+output spend the indicator already tracks; conservative enough for a guard).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.111",
3
+ "version": "0.7.112",
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": {