thinkpool-pair 0.7.129 → 0.7.130
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 +13 -4
- package/package.json +1 -1
package/bridge.mjs
CHANGED
|
@@ -1222,12 +1222,16 @@ function restoredTurnOpen(log) {
|
|
|
1222
1222
|
// relay STRUCTURED events. onEvent → broadcast `code-event` + print locally +
|
|
1223
1223
|
// persist to the host file; tool calls round-trip through the perm card; the
|
|
1224
1224
|
// rolling log replays to joiners and survives bridge restarts (session-store).
|
|
1225
|
-
function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rolePrompt, flowSessionId, flowTaskKey, cwd, reviewSliceRoots }) {
|
|
1225
|
+
function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rolePrompt, flowSessionId, flowTaskKey, cwd, reviewSliceRoots, openedAt }) {
|
|
1226
1226
|
if (sessions.has(id)) return
|
|
1227
1227
|
// spawnedBy: set when this lane was Dispatched (spawn_terminal). Restored from the
|
|
1228
1228
|
// session store so the Ensemble flag survives a bridge restart (else a respin
|
|
1229
1229
|
// stripped it and the lane reverted to a plain tab — the t6 "no chip" bug).
|
|
1230
|
-
const entry = { cmd: 'claude', kind: 'structured', log: Array.isArray(log) ? log.slice(-STRUCTURED_LOG_MAX) : [], pending: new Map(), session: null, recovered: false, commands: Array.isArray(commands) ? commands : undefined, mode, model: model || null, spawnedBy: spawnedBy || undefined, flowSessionId: flowSessionId || null, flowTaskKey: flowTaskKey || null, cwd: cwd || null
|
|
1230
|
+
const entry = { cmd: 'claude', kind: 'structured', log: Array.isArray(log) ? log.slice(-STRUCTURED_LOG_MAX) : [], pending: new Map(), session: null, recovered: false, commands: Array.isArray(commands) ? commands : undefined, mode, model: model || null, spawnedBy: spawnedBy || undefined, flowSessionId: flowSessionId || null, flowTaskKey: flowTaskKey || null, cwd: cwd || null,
|
|
1231
|
+
// Stable creation order — persisted so a bridge restart restores tabs in the SAME
|
|
1232
|
+
// order (not readdir/filesystem order). Legacy recs (no openedAt) derive it from the
|
|
1233
|
+
// first transcript event ts, so even the first post-fix restart is ordered right.
|
|
1234
|
+
openedAt: openedAt || (Array.isArray(log) ? (log.find((e) => e?.ts)?.ts || 0) : 0) || Date.now() }
|
|
1231
1235
|
// C1 (RT-2): per-term contiguous seq counter. Seeded from the restored log's max
|
|
1232
1236
|
// so a bridge restart resumes ABOVE every persisted seq — fresh events never reuse
|
|
1233
1237
|
// an old seq, which is what keeps the between-turns restart dup-free (see
|
|
@@ -1340,7 +1344,7 @@ function openStructured({ id, model, resume, log, commands, mode, spawnedBy, rol
|
|
|
1340
1344
|
// subagent-block; without cwd it runs outside its worktree; without rolePrompt it loses its
|
|
1341
1345
|
// Flow role. blockSubagents / onLaneDone / onReviewVerdict / onSubmitPlan all derive from
|
|
1342
1346
|
// these, so restoring them restores the whole behavior.
|
|
1343
|
-
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 || [] })
|
|
1347
|
+
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 })
|
|
1344
1348
|
const persist = () => saveSession(room, id, sessionData())
|
|
1345
1349
|
// Synchronous flush of this session's record. Used on open (so a brand-new session
|
|
1346
1350
|
// has a file under its id BEFORE its first event — surviving a restart inside the
|
|
@@ -2302,11 +2306,16 @@ Output:`
|
|
|
2302
2306
|
// Closed sessions are unlinked by deleteSession, so a file existing on disk ==
|
|
2303
2307
|
// a session that was live at shutdown (never an explicitly closed one).
|
|
2304
2308
|
const all = loadAll(room)
|
|
2309
|
+
// Restore in stable creation order (openedAt) so the tab strip comes back in the
|
|
2310
|
+
// SAME order across a bridge restart — NOT readdir/filesystem order, which reshuffled
|
|
2311
|
+
// the tabs (Max, 2026-07-02). Legacy recs fall back to their first event ts / savedAt.
|
|
2312
|
+
const okey = (r) => r.openedAt || (Array.isArray(r.log) ? (r.log.find((e) => e?.ts)?.ts || 0) : 0) || r.savedAt || 0
|
|
2313
|
+
all.sort((a, b) => okey(a) - okey(b))
|
|
2305
2314
|
if (all.length) for (const rec of all) {
|
|
2306
2315
|
// FL-M6 — restore the flow context (id/role/cwd) so an in-flight flow survives a
|
|
2307
2316
|
// bridge restart: the conductor keeps its subagent-block + plan interception, and
|
|
2308
2317
|
// lanes keep their worktree cwd + the ability to mark done.
|
|
2309
|
-
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 })
|
|
2318
|
+
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 })
|
|
2310
2319
|
const re = sessions.get(rec.id)
|
|
2311
2320
|
if (re && rec.flowReviewTarget) re.flowReviewTarget = rec.flowReviewTarget
|
|
2312
2321
|
// S4 — a resumed re-dispatch lane keeps its surviving revert target across a bridge restart.
|