instar 1.3.1209 → 1.3.1211

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 (112) hide show
  1. package/dashboard/index.html +24 -1
  2. package/dashboard/subscriptions.js +164 -4
  3. package/dist/commands/server.d.ts.map +1 -1
  4. package/dist/commands/server.js +103 -0
  5. package/dist/commands/server.js.map +1 -1
  6. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  7. package/dist/config/ConfigDefaults.js +12 -0
  8. package/dist/config/ConfigDefaults.js.map +1 -1
  9. package/dist/core/AnthropicReloginBrowserDriver.d.ts +64 -0
  10. package/dist/core/AnthropicReloginBrowserDriver.d.ts.map +1 -0
  11. package/dist/core/AnthropicReloginBrowserDriver.js +178 -0
  12. package/dist/core/AnthropicReloginBrowserDriver.js.map +1 -0
  13. package/dist/core/BackupManager.d.ts.map +1 -1
  14. package/dist/core/BackupManager.js +5 -0
  15. package/dist/core/BackupManager.js.map +1 -1
  16. package/dist/core/ChromeCdpReloginBrowser.d.ts +42 -0
  17. package/dist/core/ChromeCdpReloginBrowser.d.ts.map +1 -0
  18. package/dist/core/ChromeCdpReloginBrowser.js +288 -0
  19. package/dist/core/ChromeCdpReloginBrowser.js.map +1 -0
  20. package/dist/core/ClaudePasteBackController.d.ts +24 -0
  21. package/dist/core/ClaudePasteBackController.d.ts.map +1 -0
  22. package/dist/core/ClaudePasteBackController.js +68 -0
  23. package/dist/core/ClaudePasteBackController.js.map +1 -0
  24. package/dist/core/EnrollmentWizard.d.ts +2 -0
  25. package/dist/core/EnrollmentWizard.d.ts.map +1 -1
  26. package/dist/core/EnrollmentWizard.js +1 -1
  27. package/dist/core/EnrollmentWizard.js.map +1 -1
  28. package/dist/core/PlaywrightProfileRegistry.d.ts +24 -0
  29. package/dist/core/PlaywrightProfileRegistry.d.ts.map +1 -1
  30. package/dist/core/PlaywrightProfileRegistry.js +44 -0
  31. package/dist/core/PlaywrightProfileRegistry.js.map +1 -1
  32. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  33. package/dist/core/PostUpdateMigrator.js +25 -0
  34. package/dist/core/PostUpdateMigrator.js.map +1 -1
  35. package/dist/core/SubscriptionReloginOrchestrator.d.ts +71 -0
  36. package/dist/core/SubscriptionReloginOrchestrator.d.ts.map +1 -0
  37. package/dist/core/SubscriptionReloginOrchestrator.js +257 -0
  38. package/dist/core/SubscriptionReloginOrchestrator.js.map +1 -0
  39. package/dist/core/SubscriptionReloginPolicy.d.ts +48 -0
  40. package/dist/core/SubscriptionReloginPolicy.d.ts.map +1 -0
  41. package/dist/core/SubscriptionReloginPolicy.js +87 -0
  42. package/dist/core/SubscriptionReloginPolicy.js.map +1 -0
  43. package/dist/core/SubscriptionReloginRuntime.d.ts +47 -0
  44. package/dist/core/SubscriptionReloginRuntime.d.ts.map +1 -0
  45. package/dist/core/SubscriptionReloginRuntime.js +187 -0
  46. package/dist/core/SubscriptionReloginRuntime.js.map +1 -0
  47. package/dist/core/SubscriptionReloginService.d.ts +50 -0
  48. package/dist/core/SubscriptionReloginService.d.ts.map +1 -0
  49. package/dist/core/SubscriptionReloginService.js +129 -0
  50. package/dist/core/SubscriptionReloginService.js.map +1 -0
  51. package/dist/core/SubscriptionReloginStore.d.ts +126 -0
  52. package/dist/core/SubscriptionReloginStore.d.ts.map +1 -0
  53. package/dist/core/SubscriptionReloginStore.js +336 -0
  54. package/dist/core/SubscriptionReloginStore.js.map +1 -0
  55. package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
  56. package/dist/core/WriteDomainRegistry.js +19 -0
  57. package/dist/core/WriteDomainRegistry.js.map +1 -1
  58. package/dist/core/componentCategories.d.ts.map +1 -1
  59. package/dist/core/componentCategories.js +1 -0
  60. package/dist/core/componentCategories.js.map +1 -1
  61. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  62. package/dist/core/devGatedFeatures.js +5 -0
  63. package/dist/core/devGatedFeatures.js.map +1 -1
  64. package/dist/core/types.d.ts +13 -0
  65. package/dist/core/types.d.ts.map +1 -1
  66. package/dist/core/types.js.map +1 -1
  67. package/dist/data/llmBenchCoverage.d.ts.map +1 -1
  68. package/dist/data/llmBenchCoverage.js +10 -0
  69. package/dist/data/llmBenchCoverage.js.map +1 -1
  70. package/dist/data/provenanceCoverage.d.ts +2 -0
  71. package/dist/data/provenanceCoverage.d.ts.map +1 -1
  72. package/dist/data/provenanceCoverage.js +12 -0
  73. package/dist/data/provenanceCoverage.js.map +1 -1
  74. package/dist/data/standards-guard-index.json +1 -1
  75. package/dist/data/standards-guard-index.meta.json +2 -2
  76. package/dist/data/standards-registry.meta.json +1 -1
  77. package/dist/scaffold/templates.d.ts.map +1 -1
  78. package/dist/scaffold/templates.js +3 -1
  79. package/dist/scaffold/templates.js.map +1 -1
  80. package/dist/server/AgentServer.d.ts +4 -0
  81. package/dist/server/AgentServer.d.ts.map +1 -1
  82. package/dist/server/AgentServer.js +27 -2
  83. package/dist/server/AgentServer.js.map +1 -1
  84. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  85. package/dist/server/CapabilityIndex.js +20 -0
  86. package/dist/server/CapabilityIndex.js.map +1 -1
  87. package/dist/server/DashboardOperatorSessionStore.d.ts +22 -0
  88. package/dist/server/DashboardOperatorSessionStore.d.ts.map +1 -0
  89. package/dist/server/DashboardOperatorSessionStore.js +57 -0
  90. package/dist/server/DashboardOperatorSessionStore.js.map +1 -0
  91. package/dist/server/fileRoutes.d.ts.map +1 -1
  92. package/dist/server/fileRoutes.js +2 -0
  93. package/dist/server/fileRoutes.js.map +1 -1
  94. package/dist/server/routes.d.ts +10 -0
  95. package/dist/server/routes.d.ts.map +1 -1
  96. package/dist/server/routes.js +235 -101
  97. package/dist/server/routes.js.map +1 -1
  98. package/dist/testing/selfActionRegistry.d.ts.map +1 -1
  99. package/dist/testing/selfActionRegistry.js +39 -0
  100. package/dist/testing/selfActionRegistry.js.map +1 -1
  101. package/package.json +1 -1
  102. package/src/data/builtin-manifest.json +65 -65
  103. package/src/data/llmBenchCoverage.ts +10 -0
  104. package/src/data/provenanceCoverage.ts +15 -0
  105. package/src/data/standards-guard-index.json +1 -1
  106. package/src/data/standards-guard-index.meta.json +2 -2
  107. package/src/data/standards-registry.meta.json +1 -1
  108. package/src/scaffold/templates.ts +3 -1
  109. package/upgrades/1.3.1210.md +31 -0
  110. package/upgrades/1.3.1211.md +23 -0
  111. package/upgrades/side-effects/assisted-subscription-relogin.md +112 -0
  112. package/upgrades/side-effects/chrome-cdp-profile-cleanup-race.md +86 -0
@@ -3706,6 +3706,15 @@
3706
3706
  .sub-account-meta { font-size:12px; opacity:.6; margin:2px 0 2px; }
3707
3707
  .sub-account-email { font-size:12px; opacity:.5; margin:0 0 10px; }
3708
3708
  .sub-account-noquota { font-size:12px; opacity:.6; }
3709
+ .sub-profile-provision { border:1px solid var(--border,#2a2a2a); border-left:4px solid #16a34a;
3710
+ border-radius:10px; padding:14px 16px; display:flex; flex-direction:column; gap:10px; }
3711
+ .sub-profile-title { font-size:16px; font-weight:650; }
3712
+ .sub-profile-copy { margin:0; font-size:13px; line-height:1.5; opacity:.78; }
3713
+ .sub-profile-input { width:100%; box-sizing:border-box; min-height:44px; padding:10px 12px;
3714
+ font-size:16px; border:1px solid var(--border,#2a2a2a); border-radius:8px; background:transparent; color:inherit; }
3715
+ .sub-profile-create { min-height:44px; padding:10px 14px; font-size:14px; font-weight:600;
3716
+ border-radius:8px; border:1px solid #16a34a; background:rgba(22,163,74,.12); color:inherit; cursor:pointer; }
3717
+ .sub-profile-status { min-height:18px; font-size:12px; line-height:1.45; opacity:.8; }
3709
3718
  .sub-quota { margin:8px 0; }
3710
3719
  .sub-quota-head { display:flex; justify-content:space-between; font-size:12px; margin-bottom:4px; }
3711
3720
  .sub-quota-label { opacity:.8; }
@@ -3773,6 +3782,11 @@
3773
3782
  your subscriptions (ws52-operator-tap-not-text Part A). Leads the panel as the primary
3774
3783
  action when present; silent otherwise. -->
3775
3784
  <div id="subFollowMe"></div>
3785
+ <section class="ph-section">
3786
+ <h3 class="ph-h">Dedicated browser profiles</h3>
3787
+ <p class="ph-h-sub">Prepare a private Chrome profile for one Google account. The agent handles the machine; you only respond to a secure password, verification, or approval link when the provider truly requires it.</p>
3788
+ <div id="subProfileProvision"></div>
3789
+ </section>
3776
3790
  <!-- Account × Machine matrix (account-machine-matrix) — at-a-glance "which account is set up
3777
3791
  on which machine," with a one-tap "Set up" per empty cell that runs the whole sign-in in
3778
3792
  the dashboard (PIN → sign-in link → paste the code). Hidden when there's nothing to show. -->
@@ -4146,6 +4160,9 @@
4146
4160
  // ── State ────────────────────────────────────────────────
4147
4161
  let ws = null;
4148
4162
  let token = '';
4163
+ // Short-lived proof of a recent PIN unlock. Kept in memory only: the durable
4164
+ // API token is intentionally insufficient for operator-only actions.
4165
+ let operatorSessionToken = '';
4149
4166
  let sessions = [];
4150
4167
  // Sessions running on OTHER machines in the pool (GET /sessions?scope=pool).
4151
4168
  // Kept separate from `sessions` because the WebSocket replaces that array
@@ -4193,6 +4210,8 @@
4193
4210
  .then(data => {
4194
4211
  if (data && data.token) {
4195
4212
  token = data.token;
4213
+ operatorSessionToken = typeof data.operatorSessionToken === 'string'
4214
+ ? data.operatorSessionToken : '';
4196
4215
  } else {
4197
4216
  // Fall back: treat input as raw Bearer token
4198
4217
  token = pin;
@@ -9670,6 +9689,7 @@
9670
9689
  accounts: document.getElementById('subAccounts'),
9671
9690
  followMe: document.getElementById('subFollowMe'),
9672
9691
  matrix: document.getElementById('subMatrix'),
9692
+ profileProvision: document.getElementById('subProfileProvision'),
9673
9693
  };
9674
9694
  // Pass opts through (method/body/signal) so the controller can POST the follow-me
9675
9695
  // scan + the PIN-gated issue-for-machine, not just GET.
@@ -9677,7 +9697,10 @@
9677
9697
  ...opts,
9678
9698
  headers: { 'Authorization': `Bearer ${token}`, ...(opts.headers || {}) },
9679
9699
  });
9680
- __subController = __subModule.createController({ doc: document, els, fetchImpl });
9700
+ __subController = __subModule.createController({
9701
+ doc: document, els, fetchImpl,
9702
+ getOperatorSessionToken: () => operatorSessionToken,
9703
+ });
9681
9704
  }
9682
9705
  __subController.start();
9683
9706
  }
@@ -240,7 +240,7 @@ export function groupAccountsByProvider(accounts) {
240
240
  * `inUseAccountId` (optional) is the account the agent is CURRENTLY running on —
241
241
  * that card gets an "In use" marker so "active" (healthy) reads distinct from
242
242
  * "actually running right now". */
243
- export function renderAccounts(doc, target, accounts, now = Date.now(), inUseAccountId = null) {
243
+ export function renderAccounts(doc, target, accounts, now = Date.now(), inUseAccountId = null, reloginEpisodes = []) {
244
244
  if (!target) return;
245
245
  target.replaceChildren();
246
246
  if (!Array.isArray(accounts) || accounts.length === 0) {
@@ -294,6 +294,31 @@ export function renderAccounts(doc, target, accounts, now = Date.now(), inUseAcc
294
294
  if (refAge) {
295
295
  card.appendChild(el(doc, 'div', 'sub-account-refresh', `Token auto-refreshed ${refAge}`));
296
296
  }
297
+ const repair = Array.isArray(reloginEpisodes)
298
+ ? reloginEpisodes.find((episode) => episode && a && episode.accountId === a.id)
299
+ : null;
300
+ if (repair) {
301
+ const repairBox = el(doc, 'div', 'sub-account-repair');
302
+ const terminal = ['succeeded', 'refused', 'cancelled', 'failed'].includes(repair.state);
303
+ const label = repair.state === 'suggested' ? 'Sign-in repair is ready.'
304
+ : repair.state === 'succeeded' ? 'Sign-in repaired.'
305
+ : repair.state === 'waiting-operator-only' ? 'Sign-in needs your help.'
306
+ : repair.state === 'failed' ? 'Sign-in repair stopped safely.'
307
+ : repair.state === 'refused' ? 'Sign-in repair was refused for safety.'
308
+ : repair.state === 'cancelled' ? 'Sign-in repair cancelled.'
309
+ : 'Repairing sign-in…';
310
+ repairBox.appendChild(el(doc, 'div', 'sub-account-repair-status', label));
311
+ const action = repair.state === 'suggested' ? ['approve', 'Repair sign-in']
312
+ : repair.state === 'failed' ? ['retry', 'Try repair again']
313
+ : (!terminal ? ['cancel', 'Cancel repair'] : null);
314
+ if (action) {
315
+ const button = el(doc, 'button', `sub-account-repair-${action[0]}`, action[1]);
316
+ button.setAttribute('data-relogin-action', action[0]);
317
+ button.setAttribute('data-relogin-id', sanitizeForDisplay(repair.id, 'label'));
318
+ repairBox.appendChild(button);
319
+ }
320
+ card.appendChild(repairBox);
321
+ }
297
322
  target.appendChild(card);
298
323
  }
299
324
  }
@@ -934,8 +959,54 @@ const URLS = {
934
959
  accountsPool: '/subscription-pool?scope=pool',
935
960
  startCell: '/subscription-pool/matrix/start-cell', // POST (PIN-gated) — start a cell's sign-in
936
961
  cancel: '/subscription-pool/follow-me/cancel', // POST (Bearer, no PIN) — cancel an in-flight cell (relay → self/peer)
962
+ relogin: '/subscription-relogin',
963
+ provisionProfile: '/playwright-profiles/provision',
937
964
  };
938
965
 
966
+ export function renderProfileProvisioner(doc, target) {
967
+ if (!target) return;
968
+ const card = el(doc, 'div', 'sub-profile-provision');
969
+ card.setAttribute('data-interaction-open', '1');
970
+ card.appendChild(el(doc, 'div', 'sub-profile-title', 'Create a dedicated sign-in profile'));
971
+ card.appendChild(el(doc, 'p', 'sub-profile-copy',
972
+ 'Instar prepares the private Chrome profile on this machine. If a password or verification step is needed, your agent will send a secure link — you never need to access this machine.'));
973
+
974
+ const identity = el(doc, 'input', 'sub-profile-input');
975
+ identity.setAttribute('type', 'email');
976
+ identity.setAttribute('inputmode', 'email');
977
+ identity.setAttribute('autocomplete', 'email');
978
+ identity.setAttribute('placeholder', 'Google account email');
979
+ identity.setAttribute('aria-label', 'Google account email');
980
+ card.appendChild(identity);
981
+
982
+ const profileId = el(doc, 'input', 'sub-profile-input');
983
+ profileId.setAttribute('type', 'text');
984
+ profileId.setAttribute('placeholder', 'Profile name, for example work-google');
985
+ profileId.setAttribute('aria-label', 'Profile name');
986
+ card.appendChild(profileId);
987
+
988
+ const method = el(doc, 'select', 'sub-profile-input');
989
+ method.setAttribute('aria-label', 'Sign-in method');
990
+ for (const [value, label] of [
991
+ ['session-cookie', 'Already signed in / provider approval'],
992
+ ['password', 'Password'],
993
+ ['password+totp', 'Password + authenticator'],
994
+ ]) {
995
+ const option = el(doc, 'option', '', label);
996
+ option.setAttribute('value', value);
997
+ method.appendChild(option);
998
+ }
999
+ card.appendChild(method);
1000
+
1001
+ const button = el(doc, 'button', 'sub-profile-create', 'Create dedicated profile');
1002
+ button.setAttribute('type', 'button');
1003
+ card.appendChild(button);
1004
+ const status = el(doc, 'div', 'sub-profile-status', '');
1005
+ status.setAttribute('aria-live', 'polite');
1006
+ card.appendChild(status);
1007
+ target.replaceChildren(card);
1008
+ }
1009
+
939
1010
  export function createController(opts) {
940
1011
  const {
941
1012
  doc,
@@ -945,6 +1016,7 @@ export function createController(opts) {
945
1016
  cadenceMs = 30_000,
946
1017
  schedule = (fn, ms) => setTimeout(fn, ms),
947
1018
  cancel = (id) => clearTimeout(id),
1019
+ getOperatorSessionToken = () => '',
948
1020
  } = opts;
949
1021
 
950
1022
  // matrixTransient: client-side last-attempt state per `${accountId}::${machineId}` cell (FD6 —
@@ -955,6 +1027,7 @@ export function createController(opts) {
955
1027
  // add the D4 ceremony when the episode lands. recentOutcomes: client-observed terminal
956
1028
  // outcomes rendered as explicit cards in the pending panel (D4 — never a vanishing line).
957
1029
  const state = { timerId: null, active: false, inFlight: null, offers: [], approveWired: false,
1030
+ reloginWired: false, reloginEpisodes: [], profileProvisionWired: false,
958
1031
  matrixWired: false, matrixTransient: {}, lastPoolBody: null, lastPendingBody: null,
959
1032
  matrixEpisodes: {}, recentOutcomes: [] };
960
1033
 
@@ -988,17 +1061,18 @@ export function createController(opts) {
988
1061
  if (state.inFlight) { try { state.inFlight.abort(); } catch { /* superseded */ } }
989
1062
  const controller = typeof AbortController !== 'undefined' ? new AbortController() : { signal: undefined, abort() {} };
990
1063
  state.inFlight = controller;
991
- let accountsBody, pendingBody, inUseBody, scanBody, poolBody;
1064
+ let accountsBody, pendingBody, inUseBody, scanBody, poolBody, reloginBody;
992
1065
  try {
993
1066
  // in-use AND the follow-me scan are best-effort — their failure must not blank the
994
1067
  // accounts list, so each is caught independently (in-use → "unknown"; scan → no card).
995
1068
  // poolBody (scope=pool) feeds the account×machine matrix; best-effort (matrix is hidden if absent).
996
- [accountsBody, pendingBody, inUseBody, scanBody, poolBody] = await Promise.all([
1069
+ [accountsBody, pendingBody, inUseBody, scanBody, poolBody, reloginBody] = await Promise.all([
997
1070
  fetchJson(URLS.accounts, controller),
998
1071
  fetchJson(URLS.pending, controller),
999
1072
  fetchJson(URLS.inUse, controller).catch(() => null),
1000
1073
  postJson(URLS.scan, {}, controller).then((r) => (r.ok ? r.json : null)).catch(() => null),
1001
1074
  fetchJson(URLS.accountsPool, controller).catch(() => null),
1075
+ fetchJson(URLS.relogin, controller).catch(() => null),
1002
1076
  ]);
1003
1077
  } catch {
1004
1078
  if (controller.signal && controller.signal.aborted) return;
@@ -1015,10 +1089,57 @@ export function createController(opts) {
1015
1089
  return;
1016
1090
  }
1017
1091
  state.offers = scanBody && Array.isArray(scanBody.offered) ? scanBody.offered : [];
1092
+ state.reloginEpisodes = reloginBody && Array.isArray(reloginBody.episodes) ? reloginBody.episodes : [];
1093
+ if (els.profileProvision && !state.profileProvisionWired) {
1094
+ renderProfileProvisioner(doc, els.profileProvision);
1095
+ wireProfileProvisioner();
1096
+ }
1018
1097
  render(accountsBody, pendingBody, inUseBody, poolBody);
1019
1098
  reschedule();
1020
1099
  }
1021
1100
 
1101
+ function wireProfileProvisioner() {
1102
+ if (!els.profileProvision || state.profileProvisionWired) return;
1103
+ state.profileProvisionWired = true;
1104
+ els.profileProvision.addEventListener('click', (event) => {
1105
+ const button = event.target && event.target.closest ? event.target.closest('.sub-profile-create') : null;
1106
+ if (!button) return;
1107
+ const proof = getOperatorSessionToken();
1108
+ const identity = els.profileProvision.querySelector('[aria-label="Google account email"]')?.value?.trim() || '';
1109
+ const profileId = els.profileProvision.querySelector('[aria-label="Profile name"]')?.value?.trim() || '';
1110
+ const loginMethod = els.profileProvision.querySelector('[aria-label="Sign-in method"]')?.value || 'session-cookie';
1111
+ const status = els.profileProvision.querySelector('.sub-profile-status');
1112
+ if (!proof) { status.textContent = 'Unlock the dashboard again, then retry.'; return; }
1113
+ if (!identity || !profileId) { status.textContent = 'Enter the Google account and a profile name.'; return; }
1114
+ button.setAttribute('disabled', 'disabled');
1115
+ status.textContent = 'Preparing the private profile…';
1116
+ void (async () => {
1117
+ try {
1118
+ const response = await fetchImpl(URLS.provisionProfile, {
1119
+ method: 'POST',
1120
+ headers: { 'Content-Type': 'application/json', 'X-Instar-Operator-Session': proof },
1121
+ body: JSON.stringify({ profileId, identity, loginMethod }),
1122
+ });
1123
+ const body = await response.json().catch(() => ({}));
1124
+ if (!response.ok) {
1125
+ status.textContent = response.status === 401
1126
+ ? 'Unlock the dashboard again, then retry.'
1127
+ : `Couldn’t create the profile: ${body.error || 'try again'}`;
1128
+ button.removeAttribute('disabled');
1129
+ return;
1130
+ }
1131
+ status.textContent = loginMethod === 'session-cookie'
1132
+ ? 'Profile ready. Your agent can now open the provider sign-in and send you any required approval link.'
1133
+ : 'Profile ready. Your agent will send a secure credential link before the first sign-in.';
1134
+ button.textContent = 'Profile created';
1135
+ } catch {
1136
+ status.textContent = 'Couldn’t reach the server — try again.';
1137
+ button.removeAttribute('disabled');
1138
+ }
1139
+ })();
1140
+ });
1141
+ }
1142
+
1022
1143
  // ── Episode + outcome bookkeeping (D1/D4/D5) ───────────────────────────────
1023
1144
  function purgeTransients() {
1024
1145
  const t = now();
@@ -1128,7 +1249,8 @@ export function createController(opts) {
1128
1249
  const accounts = accountsBody && Array.isArray(accountsBody.accounts) ? accountsBody.accounts : [];
1129
1250
  const logins = pendingBody && Array.isArray(pendingBody.logins) ? pendingBody.logins : [];
1130
1251
  const inUseAccountId = inUseBody && inUseBody.activeAccountId ? inUseBody.activeAccountId : null;
1131
- renderAccounts(doc, els.accounts, accounts, now(), inUseAccountId);
1252
+ renderAccounts(doc, els.accounts, accounts, now(), inUseAccountId, state.reloginEpisodes);
1253
+ wireReloginActions();
1132
1254
  purgeTransients();
1133
1255
  // Episode reconciliation runs FIRST so a terminal transition it derives (expired /
1134
1256
  // landed) is visible to BOTH surfaces on this same tick (the panel card + the cell).
@@ -1169,6 +1291,44 @@ export function createController(opts) {
1169
1291
  }
1170
1292
  }
1171
1293
 
1294
+ function wireReloginActions() {
1295
+ if (!els.accounts || state.reloginWired) return;
1296
+ state.reloginWired = true;
1297
+ els.accounts.addEventListener('click', (event) => {
1298
+ const button = event.target && event.target.closest ? event.target.closest('[data-relogin-action]') : null;
1299
+ if (!button) return;
1300
+ const action = button.getAttribute('data-relogin-action');
1301
+ const episodeId = button.getAttribute('data-relogin-id');
1302
+ if (!['approve', 'cancel', 'retry'].includes(action) || !episodeId) return;
1303
+ const proof = getOperatorSessionToken();
1304
+ if (!proof) {
1305
+ button.textContent = 'Unlock the dashboard again';
1306
+ return;
1307
+ }
1308
+ button.setAttribute('disabled', 'disabled');
1309
+ void postReloginAction(episodeId, action, proof, button);
1310
+ });
1311
+ }
1312
+
1313
+ async function postReloginAction(episodeId, action, proof, button) {
1314
+ try {
1315
+ const response = await fetchImpl(`${URLS.relogin}/${encodeURIComponent(episodeId)}/${action}`, {
1316
+ method: 'POST',
1317
+ headers: { 'Content-Type': 'application/json', 'X-Instar-Operator-Session': proof },
1318
+ body: '{}',
1319
+ });
1320
+ if (!response.ok) {
1321
+ button.textContent = response.status === 401 ? 'Unlock the dashboard again' : 'Couldn’t start — try again';
1322
+ button.removeAttribute('disabled');
1323
+ return;
1324
+ }
1325
+ await tick();
1326
+ } catch {
1327
+ button.textContent = 'Couldn’t reach the server — try again';
1328
+ button.removeAttribute('disabled');
1329
+ }
1330
+ }
1331
+
1172
1332
  // Delegated, wired ONCE: an Approve tap reads the card's PIN, builds the issue-for-machine
1173
1333
  // payload from the held offers (FD2 agents resolved server-side — never typed), and POSTs the
1174
1334
  // PIN-gated mandate. The card carries only non-sensitive ids; the PIN is sent once, never stored.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAoFH,OAAO,EAAE,cAAc,EAAwD,MAAM,2BAA2B,CAAC;AAUjH,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA4BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiI7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AA0ID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAouDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAivBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA42sBtE;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;AAqFH,OAAO,EAAE,cAAc,EAAwD,MAAM,2BAA2B,CAAC;AAUjH,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA4BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiI7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AA0ID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAouDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAivBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA48sBtE;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"}
@@ -74,6 +74,7 @@ import { gapBEligibleForTopic, recentUserMessageFromHistory, recentUserMessageAt
74
74
  import { TopicProfileTransferCarrier, createTopicProfilePullHandler } from '../core/TopicProfileTransferCarrier.js';
75
75
  import { resolveFrameworkBinaryPath, computeGrokInteractiveOptIn } from '../core/frameworkSessionLaunch.js';
76
76
  import { closeAllSqlite } from '../core/SqliteRegistry.js';
77
+ import { DP_SUBSCRIPTION_RELOGIN_ACTION } from '../data/provenanceCoverage.js';
77
78
  import { SessionManager, IDLE_PROMPT_PATTERNS } from '../core/SessionManager.js';
78
79
  import { configureSyncOpMarker, defaultInflightMarkerReader } from '../core/InFlightSyncOpMarker.js';
79
80
  import { StateManager } from '../core/StateManager.js';
@@ -13506,6 +13507,101 @@ export async function startServer(options) {
13506
13507
  interactiveReservePct: 0.4,
13507
13508
  maxDailyCents: promiseBeaconCfg.maxDailyLlmSpendCents ?? 100,
13508
13509
  });
13510
+ // Assisted subscription re-login — explicit opt-in, dry-run/observe by default.
13511
+ // Constructed from the existing authority owners; no credential/token is copied.
13512
+ let subscriptionReloginRuntime = null;
13513
+ const reloginCfg = config.subscriptionPool?.assistedRelogin;
13514
+ if (reloginCfg?.enabled === true && subscriptionLoginLedger && subscriptionPoolMachineId && sharedIntelligence) {
13515
+ try {
13516
+ const [{ createSubscriptionReloginRuntime }, { PlaywrightProfileRegistry }, { SecretStore }, { secretKeyPaths }, { ClaudePasteBackController }, { ChromeCdpReloginBrowser }] = await Promise.all([
13517
+ import('../core/SubscriptionReloginRuntime.js'), import('../core/PlaywrightProfileRegistry.js'),
13518
+ import('../core/SecretStore.js'), import('../core/SecretSync.js'),
13519
+ import('../core/ClaudePasteBackController.js'), import('../core/ChromeCdpReloginBrowser.js'),
13520
+ ]);
13521
+ const vault = new SecretStore({ stateDir: config.stateDir, forceFileKey: config.secrets?.forceFileKey });
13522
+ const profiles = new PlaywrightProfileRegistry({ stateDir: config.stateDir, projectDir: config.projectDir,
13523
+ listVaultNames: () => {
13524
+ try {
13525
+ return secretKeyPaths(vault.read());
13526
+ }
13527
+ catch {
13528
+ return null;
13529
+ }
13530
+ } });
13531
+ const pasteBack = new ClaudePasteBackController({
13532
+ captureOutput: (session, lines) => sessionManager.captureOutput(session, lines),
13533
+ sendInput: (session, input) => sessionManager.sendInput(session, input),
13534
+ clearHistory: (session) => {
13535
+ const tmux = detectTmuxPath();
13536
+ if (!tmux)
13537
+ throw new Error('tmux-unavailable');
13538
+ execFileSync(tmux, ['clear-history', '-t', `=${session}:`], { stdio: 'ignore' });
13539
+ },
13540
+ credentialReady: async (login) => {
13541
+ if (!login.configHome)
13542
+ return false;
13543
+ const result = await subscriptionIdentityOracle.resolveSlotTenant(login.configHome);
13544
+ return !('unavailable' in result) && typeof result.email === 'string' && result.email.length > 0;
13545
+ },
13546
+ });
13547
+ const notify = telegram ? async (episode, deliveryKey, kind) => {
13548
+ const summary = kind === 'approval'
13549
+ ? 'A Claude Code subscription sign-in needs repair. Open Subscriptions and tap Repair sign-in once.'
13550
+ : kind === 'operator-only'
13551
+ ? 'Automated sign-in paused at a provider security challenge. Open Subscriptions to continue.'
13552
+ : episode.state === 'succeeded'
13553
+ ? 'Claude Code subscription sign-in was repaired and verified.'
13554
+ : `Claude Code subscription repair ended in ${episode.state}. Open Subscriptions for the redacted audit.`;
13555
+ await telegram.createAttentionItem({ id: deliveryKey.replace(/:/g, '-'), title: 'Claude Code sign-in repair',
13556
+ summary, description: summary, category: 'subscription-relogin',
13557
+ priority: kind === 'terminal' && episode.state === 'succeeded' ? 'NORMAL' : 'HIGH',
13558
+ sourceContext: 'assisted-subscription-relogin' });
13559
+ } : undefined;
13560
+ subscriptionReloginRuntime = createSubscriptionReloginRuntime({ stateDir: config.stateDir,
13561
+ projectDir: config.projectDir, machineId: subscriptionPoolMachineId,
13562
+ mode: reloginCfg.dryRun !== false ? 'observe' : (reloginCfg.mode ?? 'approval'),
13563
+ pool: subscriptionPool, ledger: subscriptionLoginLedger, enrollment: enrollmentWizard,
13564
+ profiles, quotaPoller, identityOracle: subscriptionIdentityOracle, pasteBack,
13565
+ createBrowser: (userDataDir) => new ChromeCdpReloginBrowser({ userDataDir }),
13566
+ resolveSecret: async (name) => { const value = vault.get(name); return typeof value === 'string' ? value : null; },
13567
+ supervise: async ({ snapshot, allowedActions }) => {
13568
+ const prompt = [
13569
+ 'You are a Tier-1 validator for a bounded Claude sign-in browser worker.',
13570
+ 'Choose exactly one action from allowedActions. Output only that action token.',
13571
+ 'You cannot authorize an account, broaden scopes/origins, retrieve secrets, or declare success.',
13572
+ `closedSnapshot=${JSON.stringify(snapshot)}`,
13573
+ `allowedActions=${JSON.stringify(allowedActions)}`,
13574
+ ].join('\n');
13575
+ const raw = await sharedLlmQueue.enqueue('background', (signal) => sharedIntelligence.evaluate(prompt, {
13576
+ model: 'fast', maxTokens: 20, temperature: 0, signal,
13577
+ attribution: { component: 'subscription-relogin-supervisor' },
13578
+ provenance: {
13579
+ decisionPoint: DP_SUBSCRIPTION_RELOGIN_ACTION,
13580
+ context: { ...snapshot },
13581
+ optionsPresented: [...allowedActions],
13582
+ promptId: 'subscription-relogin-action-v1',
13583
+ },
13584
+ }), 1);
13585
+ const action = raw.trim();
13586
+ if (!allowedActions.includes(action))
13587
+ throw new Error('relogin-supervisor-invalid-action');
13588
+ return action;
13589
+ },
13590
+ onSuggested: notify ? (episode, key) => notify(episode, key, 'approval') : undefined,
13591
+ onOperatorOnly: notify ? (episode, key) => notify(episode, key, 'operator-only') : undefined,
13592
+ onTerminal: notify ? (episode, key) => notify(episode, key, 'terminal') : undefined,
13593
+ allowedScopes: reloginCfg.allowedScopes ?? [], tickMs: reloginCfg.tickMs,
13594
+ maxAttempts: reloginCfg.maxAttempts, retryBaseMs: reloginCfg.retryBaseMs, });
13595
+ subscriptionReloginRuntime.start();
13596
+ console.log(pc.green(` Assisted subscription re-login: ${reloginCfg.dryRun !== false ? 'observe' : (reloginCfg.mode ?? 'approval')}`));
13597
+ }
13598
+ catch (error) {
13599
+ // @silent-fallback-ok — bootstrap refusal is logged and the runtime is explicitly darkened; routes return typed 503.
13600
+ console.warn(`[subscription-relogin] bootstrap refused: ${error instanceof Error ? error.message : String(error)}`);
13601
+ subscriptionReloginRuntime?.close();
13602
+ subscriptionReloginRuntime = null;
13603
+ }
13604
+ }
13509
13605
  // sharedLlmQueue is wired into both PromiseBeacon (background lane) and
13510
13606
  // PresenceProxy (interactive lane) below.
13511
13607
  // ── WS3 one-voice speaker election (MULTI-MACHINE-SEAMLESSNESS-SPEC) ──
@@ -24774,6 +24870,13 @@ export async function startServer(options) {
24774
24870
  } if (peers.length === 0)
24775
24871
  return []; const { fetchPeerSubscriptionViews } = await import('../core/fetchPeerSubscriptionViews.js'); return fetchPeerSubscriptionViews({ peers: () => peers, fetchImpl: fetch, authToken: config.authToken ?? '' }); }, quotaPoller, quotaAwareScheduler: _quotaAwareScheduler ?? undefined, proactiveSwapMonitor: _proactiveSwapMonitor ?? undefined, inUseAccountResolver, enrollmentWizard, accountFollowMeRevocation, credentialRepointing, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, greenPrAutoMerger: greenPrAutoMerger ?? undefined, guardLatchStore: guardLatchStore ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, topicProfile: _topicProfileCtx ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, meshBindActive: coordinator.managers.identityManager.hasIdentity() && config.multiMachine?.meshTransport?.enabled !== false, localSigningKeyPem, leaseTransport, peerEndpointRecorder, getSelfMeshEndpoints, 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, conversationRegistry, conversationBindAuth, conversationFollowThrough, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, threadLog, threadMessageRecorder, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, getLastRelayEvent: threadlineGetLastRelayEvent, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, a2aDeliveryTracker: a2aDeliveryTracker ?? undefined, responseReviewGate, reviewCanaryBattery, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, machinePoolRegistry, ropeHealthMonitor, writeAdmission: writeAdmission ?? undefined, getInboundQueue: () => _inboundQueue, getMachineCoherence: () => _machineCoherenceSentinel, getSingleMachineFailoverGap: () => _singleMachineFailoverGap, getMissingLoginSession: () => _missingLoginSession, getSessionPoolFailoverRunner: () => _sessionPoolFailoverRunnerDriver?.status() ?? null, sessionPoolPromotionActivation: _sessionPoolPromotionActivation, meshRpcDispatcher, deliverA2aToMachine: _deliverA2aToMachine ?? undefined, workingSetPullCoordinator, workingSetArtifactManager, orchestratorPoller, commitmentReplicaStore, preferenceReplicaStore, replicatedRecordEmitter, conflictStore, rollbackUnmerge, droppedOriginRegistry, preferencesUnionReader, forwardCommitmentMutate, sessionOwnershipRegistry, sendDrain: _sendDrain ?? undefined, topicPinStore: _topicPinStore ?? undefined, topicPinSkewQuarantine: _topicPinSkewQuarantine ?? undefined, topicPinFoldView: _topicPinFoldView ?? undefined, ownershipReconciler: _ownershipReconciler ?? undefined, staleOwnerEngine: _staleOwnerEngine ?? undefined, duplicateReconciler: _duplicateReconciler ?? undefined, ownerDarkLadder: _ownerDarkLadder ?? undefined, spawnAdmission: _spawnAdmission ?? undefined, judgmentProvenance: _judgmentProvenance ?? undefined, leaseHandback: _leaseHandbackCtx ?? undefined, streamTicketStore: _streamTicketStore ?? undefined, poolStreamAllowRemoteInput: config.dashboard?.poolStream?.allowRemoteInput ?? false, poolStreamConnector: _poolStreamConnector ?? undefined, secretSync: _secretSyncHandle ?? undefined, meshSelfId: _meshSelfId ?? undefined, resolveRouterUrl: _resolveRouterUrl ?? undefined, resolvePeerUrls: _resolvePeerUrls ?? undefined, guardRegistry, listPoolMachines: _listPoolMachines ?? undefined, deliverMandateToMachine: _deliverMandateToMachine ?? undefined, poolLink: _poolLink ?? undefined, poolPollCache: _poolPollCache ?? undefined, sessionPoolE2EResultStore, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, agentWorktreeReaper, externalHogSentinel, orphanedWorkSentinel, mcpProcessReaper, geminiLoopRunner, sleepController, agentActivityState, reapLog, resumeQueue, resumeDrainer, autonomousLivenessReconciler, enforcedTerminationStatus: () => enforcedTerminationWatchdog?.guardStatus() ?? null, prHandLease: prHandLease ?? undefined, standDownRegistry: _standDownRegistry ?? undefined, standDownAudit: _standDownAudit ?? undefined, operatorStopRecorder: recordOperatorStop, sleepWakeDetector, unjustifiedStopGate, stopGateDb, stopNotifier, liveTestGate, liveTestGateMode, liveTestRunnerCtx }); // Resolve the late-bound topic-operator getter (increment 2e): routing was
24776
24872
  server.setSubscriptionLoginLedger(subscriptionLoginLedger);
24873
+ server.setSubscriptionRelogin(subscriptionReloginRuntime ? {
24874
+ store: subscriptionReloginRuntime.store,
24875
+ approve: (episodeId) => subscriptionReloginRuntime.service.approve(episodeId),
24876
+ cancel: (episodeId) => subscriptionReloginRuntime.service.cancel(episodeId),
24877
+ retry: (episodeId) => subscriptionReloginRuntime.service.retry(episodeId),
24878
+ close: () => subscriptionReloginRuntime.close(),
24879
+ } : null);
24777
24880
  server.setWorkQueue(workQueue);
24778
24881
  if (_stateSyncStoresResolved?.classReview?.enabled && replicatedPeerStreamReader) {
24779
24882
  const { CLASS_REVIEW_STORE_KEY, classReviewFromOriginRecord } = await import('../core/ClassReviewReplicatedStore.js');