thinkpool-pair 0.7.316 → 0.7.317

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
@@ -982,6 +982,8 @@ function syncStructuredTurn(entry, now = Date.now()) {
982
982
  if (busy) {
983
983
  entry._turnRev = (Number(entry._turnRev) || 0) + 1
984
984
  entry._turnStart = now
985
+ entry._settledTurnRev = null
986
+ entry._turnSettledAt = null
985
987
  }
986
988
  entry._busyAnn = busy
987
989
  return true
@@ -992,6 +994,8 @@ function beginStructuredTurn(entry, now = Date.now()) {
992
994
  entry._turnRev = (Number(entry._turnRev) || 0) + 1
993
995
  entry._turnStart = now
994
996
  entry._busyAnn = true
997
+ entry._settledTurnRev = null
998
+ entry._turnSettledAt = null
995
999
  return true
996
1000
  }
997
1001
 
@@ -999,6 +1003,8 @@ function advanceStructuredTurn(entry, now = Date.now()) {
999
1003
  entry._turnRev = (Number(entry._turnRev) || 0) + 1
1000
1004
  entry._turnStart = now
1001
1005
  entry._busyAnn = true
1006
+ entry._settledTurnRev = null
1007
+ entry._turnSettledAt = null
1002
1008
  return true
1003
1009
  }
1004
1010
 
@@ -1281,7 +1287,7 @@ const announce = () => {
1281
1287
  // laneStatusOf: authoritative busy/idle + last-action timestamp/age +
1282
1288
  // STUCK/BLOCKED alert. The bridge owns the turn and permission state, so
1283
1289
  // every roster consumer reads one status instead of reconstructing it.
1284
- ...[...sessions.entries()].map(([id, s]) => ({ id, cmd: s.cmd, kind: 'structured', runtime: s.runtime || 'claude', alive: true, ...laneStatusOf(s), turnRev: Number(s._turnRev) || 0, ...(laneBusyOf(s) && s._turnStart ? { turnStartedAt: s._turnStart } : {}), hasTranscript: s.log.length > 0, commands: s.commands, mode: s.mode || undefined, effort: s.effort || undefined, name: termNames[id] || undefined, model: s.model || undefined, capabilities: { ...structuredRuntimeMetadata(s.runtime || 'claude'), modes: structuredModesForLane(s.runtime || 'claude', s) }, ...(s.runtime === 'codex' ? { approvalPolicy: codexConfigForMode(s.mode).approvalPolicy, models: s.models || [], canSteer: s.session?.canSteer ?? false } : s.runtime === 'hermes' ? { models: s.models || [], canSteer: s.session?.canSteer ?? false } : {}), ...(s.archiveOldestSeq != null ? { oldestSeq: s.archiveOldestSeq } : {}), ...(s.spawnedBy ? { spawned: true, spawnedBy: s.spawnedBy } : {}), ...(s.sideParent ? { sideParent: s.sideParent, sideTask: s.sideTask || undefined, sideHandback: !!s.sideHandback } : {}), ...(s.flowSessionId ? { flowId: s.flowSessionId, flowRole: s.flowTaskKey ? 'lane' : 'conductor' } : {}),
1290
+ ...[...sessions.entries()].map(([id, s]) => ({ id, cmd: s.cmd, kind: 'structured', runtime: s.runtime || 'claude', alive: true, ...laneStatusOf(s), turnRev: Number(s._turnRev) || 0, ...(laneBusyOf(s) && s._turnStart ? { turnStartedAt: s._turnStart } : {}), ...(!laneBusyOf(s) && Number(s._settledTurnRev) > 0 && Number(s._settledTurnRev) === Number(s._turnRev) ? { settledTurnRev: Number(s._settledTurnRev), turnSettledAt: Number(s._turnSettledAt) || undefined } : {}), hasTranscript: s.log.length > 0, commands: s.commands, mode: s.mode || undefined, effort: s.effort || undefined, name: termNames[id] || undefined, model: s.model || undefined, capabilities: { ...structuredRuntimeMetadata(s.runtime || 'claude'), modes: structuredModesForLane(s.runtime || 'claude', s) }, ...(s.runtime === 'codex' ? { approvalPolicy: codexConfigForMode(s.mode).approvalPolicy, models: s.models || [], canSteer: s.session?.canSteer ?? false } : s.runtime === 'hermes' ? { models: s.models || [], canSteer: s.session?.canSteer ?? false } : {}), ...(s.archiveOldestSeq != null ? { oldestSeq: s.archiveOldestSeq } : {}), ...(s.spawnedBy ? { spawned: true, spawnedBy: s.spawnedBy } : {}), ...(s.sideParent ? { sideParent: s.sideParent, sideTask: s.sideTask || undefined, sideHandback: !!s.sideHandback } : {}), ...(s.flowSessionId ? { flowId: s.flowSessionId, flowRole: s.flowTaskKey ? 'lane' : 'conductor' } : {}),
1285
1291
  // provider: the registered LLM-provider this lane runs on, NAME-ONLY {id,name}
1286
1292
  // (NEVER the key or baseUrl). Additive; older clients ignore it. Omitted for the
1287
1293
  // built-in/default Claude path (no badge). Makes the lane's provider badge +
@@ -2167,6 +2173,9 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
2167
2173
  // first transcript event ts, so even the first post-fix restart is ordered right.
2168
2174
  openedAt: openedAt || (Array.isArray(log) ? (log.find((e) => e?.ts)?.ts || 0) : 0) || Date.now() }
2169
2175
  entry._turnRev = entry.log.reduce((max, event) => Math.max(max, Number(event?.turnRev) || 0), 0)
2176
+ const restoredBoundary = [...entry.log].reverse().find((event) => event?.kind === 'result' && Number(event?.turnRev) > 0)
2177
+ entry._settledTurnRev = Number(restoredBoundary?.turnRev) || null
2178
+ entry._turnSettledAt = Number(restoredBoundary?.ts) || null
2170
2179
  entry.interruptedRecap = restoredTurnOpen(entry.log) ? buildRecapFromLog(entry.log, RECAP_CAP) : null
2171
2180
  // Slice 3 — a permission card left unanswered past the grace window pushes
2172
2181
  // "<lane> — needs you: <what>"; answering it anywhere retracts the banner
@@ -3244,6 +3253,10 @@ function openStructured({ id, runtime = 'claude', model, models, effort, resume,
3244
3253
  const mockupDeliveryBoundary = isMockupDeliveryBoundary(evt, { turnActive: entry.session?.turnActive === true })
3245
3254
  stampStructuredTurn(entry, evt)
3246
3255
  stampEvent(evt)
3256
+ if (terminalBoundary) {
3257
+ entry._settledTurnRev = Number(evt.turnRev) || Number(entry._turnRev) || null
3258
+ entry._turnSettledAt = Number(evt.ts) || Date.now()
3259
+ }
3247
3260
  const stalledChanged = evt.kind === 'stalled' ? !entry.stalled : !!entry.stalled
3248
3261
  entry.stalled = evt.kind === 'stalled'
3249
3262
  entry.lastEvent = evt
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thinkpool-pair",
3
- "version": "0.7.316",
3
+ "version": "0.7.317",
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": {