instar 1.3.270 → 1.3.272

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 (57) hide show
  1. package/dashboard/index.html +73 -11
  2. package/dist/commands/server.d.ts.map +1 -1
  3. package/dist/commands/server.js +15 -2
  4. package/dist/commands/server.js.map +1 -1
  5. package/dist/coordination/ReviewExchange.d.ts +135 -0
  6. package/dist/coordination/ReviewExchange.d.ts.map +1 -0
  7. package/dist/coordination/ReviewExchange.js +192 -0
  8. package/dist/coordination/ReviewExchange.js.map +1 -0
  9. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  10. package/dist/core/PostUpdateMigrator.js +33 -1
  11. package/dist/core/PostUpdateMigrator.js.map +1 -1
  12. package/dist/core/SecretStore.d.ts.map +1 -1
  13. package/dist/core/SecretStore.js +10 -1
  14. package/dist/core/SecretStore.js.map +1 -1
  15. package/dist/core/TransferByNickname.d.ts +6 -0
  16. package/dist/core/TransferByNickname.d.ts.map +1 -1
  17. package/dist/core/TransferByNickname.js +18 -6
  18. package/dist/core/TransferByNickname.js.map +1 -1
  19. package/dist/core/seamlessnessConfig.d.ts.map +1 -1
  20. package/dist/core/seamlessnessConfig.js +12 -1
  21. package/dist/core/seamlessnessConfig.js.map +1 -1
  22. package/dist/core/types.d.ts +23 -0
  23. package/dist/core/types.d.ts.map +1 -1
  24. package/dist/core/types.js.map +1 -1
  25. package/dist/feedback-factory/cutoverReadiness.d.ts +103 -0
  26. package/dist/feedback-factory/cutoverReadiness.d.ts.map +1 -0
  27. package/dist/feedback-factory/cutoverReadiness.js +118 -0
  28. package/dist/feedback-factory/cutoverReadiness.js.map +1 -0
  29. package/dist/scaffold/templates.d.ts.map +1 -1
  30. package/dist/scaffold/templates.js +13 -1
  31. package/dist/scaffold/templates.js.map +1 -1
  32. package/dist/scheduler/MentorAutonomousGuardian.d.ts.map +1 -1
  33. package/dist/scheduler/MentorAutonomousGuardian.js +1 -0
  34. package/dist/scheduler/MentorAutonomousGuardian.js.map +1 -1
  35. package/dist/server/AgentServer.d.ts +6 -0
  36. package/dist/server/AgentServer.d.ts.map +1 -1
  37. package/dist/server/AgentServer.js +54 -6
  38. package/dist/server/AgentServer.js.map +1 -1
  39. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  40. package/dist/server/CapabilityIndex.js +28 -0
  41. package/dist/server/CapabilityIndex.js.map +1 -1
  42. package/dist/server/routes.d.ts +12 -0
  43. package/dist/server/routes.d.ts.map +1 -1
  44. package/dist/server/routes.js +255 -4
  45. package/dist/server/routes.js.map +1 -1
  46. package/package.json +1 -1
  47. package/src/data/builtin-manifest.json +64 -64
  48. package/src/scaffold/templates.ts +13 -1
  49. package/upgrades/1.3.271.md +154 -0
  50. package/upgrades/1.3.272.md +40 -0
  51. package/upgrades/autoloop-gate-compliance.eli16.md +11 -0
  52. package/upgrades/side-effects/autoloop-gate-compliance.md +43 -0
  53. package/upgrades/side-effects/cutover-readiness.md +63 -0
  54. package/upgrades/side-effects/dashboard-pool-sessions.md +103 -0
  55. package/upgrades/side-effects/review-exchange-protocol.md +60 -0
  56. package/upgrades/side-effects/secret-drop-store-first.md +117 -0
  57. package/upgrades/side-effects/transfer-idempotency-exactly-once.md +105 -0
@@ -203,6 +203,19 @@
203
203
  .model-badge.sonnet { background: #1b2e4e; color: #60a5fa; }
204
204
  .model-badge.haiku { background: #1b3e3e; color: #5eead4; }
205
205
 
206
+ /* Which machine a session runs on (multi-machine pool). */
207
+ .machine-badge {
208
+ padding: 1px 6px;
209
+ border-radius: 4px;
210
+ font-size: 10px;
211
+ font-weight: 600;
212
+ background: #3a2a1b;
213
+ color: #fbbf24;
214
+ }
215
+ /* A session running on ANOTHER machine — visible, but its terminal can't
216
+ stream here (open that machine's dashboard to interact). */
217
+ .session-item.remote { opacity: 0.8; cursor: default; }
218
+
206
219
  .type-badge {
207
220
  padding: 1px 6px;
208
221
  border-radius: 4px;
@@ -3472,6 +3485,11 @@
3472
3485
  let ws = null;
3473
3486
  let token = '';
3474
3487
  let sessions = [];
3488
+ // Sessions running on OTHER machines in the pool (GET /sessions?scope=pool).
3489
+ // Kept separate from `sessions` because the WebSocket replaces that array
3490
+ // with LOCAL sessions on every broadcast — merging would be wiped each tick.
3491
+ let remoteSessions = [];
3492
+ let selfMachineNickname = null;
3475
3493
  let activeSession = null;
3476
3494
  let term = null;
3477
3495
  let fitAddon = null;
@@ -3518,6 +3536,7 @@
3518
3536
  connectWebSocket();
3519
3537
  startWaPolling();
3520
3538
  startVitalSigns();
3539
+ startPoolSessionsPolling();
3521
3540
  } else {
3522
3541
  showAuthError('Incorrect PIN');
3523
3542
  }
@@ -3543,6 +3562,7 @@
3543
3562
  connectWebSocket();
3544
3563
  startWaPolling();
3545
3564
  startVitalSigns();
3565
+ startPoolSessionsPolling();
3546
3566
  }
3547
3567
  })
3548
3568
  .catch(() => {});
@@ -3681,17 +3701,31 @@
3681
3701
  }
3682
3702
 
3683
3703
  // ── Session List ─────────────────────────────────────────
3704
+ // Stable per-row key. Remote sessions are namespaced by machine so a tmux
3705
+ // name reused on two machines never collides with a local row.
3706
+ function sessionRowKey(s) {
3707
+ return s.remote ? `remote:${s.machineId || '?'}:${s.tmuxSession}` : s.tmuxSession;
3708
+ }
3709
+
3684
3710
  function renderSessionList() {
3685
3711
  const list = document.getElementById('sessionList');
3686
3712
  const empty = document.getElementById('emptyState');
3687
3713
  const count = document.getElementById('sessionCount');
3688
3714
 
3689
- count.textContent = sessions.length;
3715
+ // Local sessions (live via WebSocket) + every other machine's sessions
3716
+ // (via the /sessions?scope=pool poll). Local rows inherit this machine's
3717
+ // nickname so EVERY row states where it runs once the pool is live.
3718
+ const all = [
3719
+ ...sessions.map(s => (s.machineNickname || !selfMachineNickname) ? s : { ...s, machineNickname: selfMachineNickname }),
3720
+ ...remoteSessions,
3721
+ ];
3722
+
3723
+ count.textContent = all.length;
3690
3724
  // Keep tab bar count in sync
3691
3725
  const tabCount = document.getElementById('tabSessionCount');
3692
- if (tabCount) tabCount.textContent = sessions.length;
3726
+ if (tabCount) tabCount.textContent = all.length;
3693
3727
 
3694
- if (sessions.length === 0) {
3728
+ if (all.length === 0) {
3695
3729
  empty.style.display = 'flex';
3696
3730
  // Clear any existing session items
3697
3731
  list.querySelectorAll('.session-item').forEach(el => el.remove());
@@ -3708,29 +3742,35 @@
3708
3742
 
3709
3743
  // Remove sessions no longer running
3710
3744
  for (const [name, el] of existing) {
3711
- if (!sessions.find(s => s.tmuxSession === name)) {
3745
+ if (!all.find(s => sessionRowKey(s) === name)) {
3712
3746
  el.remove();
3713
3747
  }
3714
3748
  }
3715
3749
 
3716
3750
  // Add/update sessions
3717
- for (const session of sessions) {
3718
- let el = existing.get(session.tmuxSession);
3751
+ for (const session of all) {
3752
+ let el = existing.get(sessionRowKey(session));
3719
3753
  if (!el) {
3720
3754
  el = document.createElement('div');
3721
3755
  el.className = 'session-item';
3722
- el.dataset.session = session.tmuxSession;
3723
- el.onclick = () => selectSession(session.tmuxSession, session);
3756
+ el.dataset.session = sessionRowKey(session);
3757
+ if (session.remote) {
3758
+ // A remote session's terminal streams on ITS machine's dashboard —
3759
+ // clicking here can't subscribe to it, so the row is informational.
3760
+ el.title = `Running on ${session.machineNickname || session.machineId || 'another machine'} — open that machine's dashboard to interact.`;
3761
+ } else {
3762
+ el.onclick = () => selectSession(session.tmuxSession, session);
3763
+ }
3724
3764
  list.appendChild(el);
3725
3765
  }
3726
3766
 
3727
3767
  const elapsed = formatElapsed(session.startedAt);
3728
3768
  const model = session.model || 'opus';
3729
- const isActive = session.tmuxSession === activeSession;
3769
+ const isActive = !session.remote && session.tmuxSession === activeSession;
3730
3770
  const sType = session.type || (session.jobSlug ? 'job' : 'interactive');
3731
3771
  const tele = session.telemetry;
3732
3772
 
3733
- el.className = `session-item${isActive ? ' active' : ''}`;
3773
+ el.className = `session-item${isActive ? ' active' : ''}${session.remote ? ' remote' : ''}`;
3734
3774
 
3735
3775
  let telemetryHtml = '';
3736
3776
  if (tele) {
@@ -3765,12 +3805,13 @@
3765
3805
  el.innerHTML = `
3766
3806
  <div class="session-name-row">
3767
3807
  <div class="session-name">${escapeHtml(session.platformName || session.name)}</div>
3768
- <button class="session-close-btn" data-tmux="${escapeHtml(session.tmuxSession)}" data-name="${escapeHtml(session.name)}" onclick="event.stopPropagation();closeSession(this.dataset.tmux,this.dataset.name)" title="Close session">&times;</button>
3808
+ ${session.remote ? '' : `<button class="session-close-btn" data-tmux="${escapeHtml(session.tmuxSession)}" data-name="${escapeHtml(session.name)}" onclick="event.stopPropagation();closeSession(this.dataset.tmux,this.dataset.name)" title="Close session">&times;</button>`}
3769
3809
  </div>
3770
3810
  <div class="session-meta">
3771
3811
  <span class="type-badge ${sType}">${sType}</span>
3772
3812
  <span class="model-badge ${model}">${model}</span>
3773
3813
  <span class="platform-badge ${platform}" title="${platformLabel}">${platformIcon}</span>
3814
+ ${session.machineNickname ? `<span class="machine-badge" title="Machine this session runs on">${escapeHtml(session.machineNickname)}</span>` : ''}
3774
3815
  <span>${elapsed}</span>
3775
3816
  </div>
3776
3817
  ${telemetryHtml}
@@ -4210,6 +4251,27 @@
4210
4251
  const WA_QR_TIMEOUT_MS = 30000; // 30s timeout for QR appearance
4211
4252
  let waLastError = ''; // last error message for display
4212
4253
 
4254
+ // ── Pool-wide sessions (multi-machine) ───────────────────
4255
+ // The WebSocket only carries THIS machine's sessions. When the agent runs a
4256
+ // multi-machine pool, poll the aggregated view so every session — on every
4257
+ // machine — shows in the list, each tagged with the machine it runs on.
4258
+ let poolPollTimer = null;
4259
+ function startPoolSessionsPolling() {
4260
+ if (poolPollTimer) return;
4261
+ const poll = async () => {
4262
+ try {
4263
+ const r = await fetch('/sessions?scope=pool', { headers: { 'Authorization': `Bearer ${token}` } });
4264
+ if (!r.ok) return;
4265
+ const j = await r.json();
4266
+ selfMachineNickname = (j.pool && j.pool.selfMachineNickname) || null;
4267
+ remoteSessions = (j.sessions || []).filter(s => s.remote === true);
4268
+ renderSessionList();
4269
+ } catch { /* best-effort — peers may be offline; next tick retries */ }
4270
+ };
4271
+ poll();
4272
+ poolPollTimer = setInterval(poll, 15000);
4273
+ }
4274
+
4213
4275
  function startWaPolling() {
4214
4276
  if (waQrInterval) return;
4215
4277
  waQrPollingStarted = Date.now();
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4SH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAkxDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAs+QtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4SH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAqxDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAi/QtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
@@ -326,6 +326,9 @@ let _meshSelfId = null;
326
326
  * a moved topic's prior history from the router (bug #2). Set in the mesh block where
327
327
  * the peer-URL resolver + coordinator are in scope. */
328
328
  let _resolveRouterUrl = null;
329
+ /** Every OTHER active machine with a known URL — backs GET /sessions?scope=pool
330
+ * (pool-wide session aggregation for the dashboard). Set in the same mesh block. */
331
+ let _resolvePeerUrls = null;
329
332
  /** Multi-Machine Session Pool §L4: per-topic placement pin store ("move this to <nickname>"). */
330
333
  let _topicPinStore = null;
331
334
  /** Cross-machine secret-sync (spec Phase 4): route-facing handle (push lever + read-only status). */
@@ -9295,6 +9298,10 @@ export async function startServer(options) {
9295
9298
  const h = coordinator.getSyncStatus().leaseHolder;
9296
9299
  return h && h !== meshSelfId ? peerUrl(h) : null;
9297
9300
  };
9301
+ _resolvePeerUrls = () => meshIdMgr
9302
+ .getActiveMachines()
9303
+ .filter((m) => m.machineId !== meshSelfId && !!m.entry.lastKnownUrl)
9304
+ .map((m) => ({ machineId: m.machineId, url: m.entry.lastKnownUrl }));
9298
9305
  // ── Self-nickname convergence (§L4, 2026-06-04 live-caught fix) ──
9299
9306
  // `updateNickname` (PATCH /pool/machines) is local-only, so a rename applied on a
9300
9307
  // PEER's registry never reaches the owning machine — leaving that machine unable to
@@ -9602,6 +9609,10 @@ export async function startServer(options) {
9602
9609
  isOnline: (m) => machinePoolRegistry?.getCapacity(m)?.online ?? false,
9603
9610
  currentOwnerOf: (sk) => ownReg.ownerOf(sk),
9604
9611
  isMidReply: () => false, // best-effort; the pin takes effect on the next routed message
9612
+ // Pin-aware idempotency: a duplicate "move to X" while already pinned
9613
+ // to X (e.g. a lifeline retry / post-restart replay of the same
9614
+ // message) no-ops as "already there" instead of burning the rate limit.
9615
+ currentPinOf: (sk) => _topicPinStore?.get(sk)?.preferredMachine ?? null,
9605
9616
  lastPlacementUpdateAt: (sk) => _topicPinStore?.lastUpdatedAtMs(sk) ?? null,
9606
9617
  now: () => Date.now(),
9607
9618
  }, sessionKey);
@@ -9616,7 +9627,9 @@ export async function startServer(options) {
9616
9627
  }
9617
9628
  catch { /* best-effort; route() re-places regardless once the owner is cleared */ }
9618
9629
  await telegram?.sendToTopic(topicId, plan.action === 'noop'
9619
- ? `This conversation is already pinned to ${cmd.nickname} — it'll keep running there.`
9630
+ ? (plan.detail === 'already-on-target'
9631
+ ? `This conversation is already running on ${cmd.nickname} — nothing to move.`
9632
+ : `This conversation is already pinned to ${cmd.nickname} — it'll keep running there.`)
9620
9633
  : `Moving this conversation to ${cmd.nickname} — it'll pick up there on your next message.`).catch(() => { });
9621
9634
  console.log(pc.green(` [session-pool] topic ${topicId} pinned to ${target} (${plan.action}) via "${cmd.matchedVerb}"`));
9622
9635
  return { handled: true };
@@ -9708,7 +9721,7 @@ export async function startServer(options) {
9708
9721
  catch (err) {
9709
9722
  console.log(pc.dim(` [session-pool] rollout gate not wired: ${err instanceof Error ? err.message : String(err)}`));
9710
9723
  }
9711
- const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, leaseTransport, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, meshRpcDispatcher, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier });
9724
+ const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, leaseTransport, onLeasePullRequest: () => leaseCoordinatorRef?.currentLease() ?? null, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, meshRpcDispatcher, sessionOwnershipRegistry, topicPinStore: _topicPinStore ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier });
9712
9725
  // Boot-recovery (tunnel-failure-resilience spec Part 6): if the agent
9713
9726
  // died mid-relay-episode, the persisted tunnel.json carries
9714
9727
  // rotationPending=true. Rotate the dashboard PIN + authToken BEFORE