instar 1.3.1286 → 1.3.1288

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 (88) hide show
  1. package/dashboard/index.html +14 -0
  2. package/dashboard/subscriptions.js +24 -5
  3. package/dist/commands/server.d.ts.map +1 -1
  4. package/dist/commands/server.js +55 -18
  5. package/dist/commands/server.js.map +1 -1
  6. package/dist/core/CliLoginStatus.d.ts +38 -0
  7. package/dist/core/CliLoginStatus.d.ts.map +1 -0
  8. package/dist/core/CliLoginStatus.js +116 -0
  9. package/dist/core/CliLoginStatus.js.map +1 -0
  10. package/dist/core/PostUpdateMigrator.d.ts +8 -0
  11. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  12. package/dist/core/PostUpdateMigrator.js +45 -0
  13. package/dist/core/PostUpdateMigrator.js.map +1 -1
  14. package/dist/core/QuotaPoller.d.ts +42 -0
  15. package/dist/core/QuotaPoller.d.ts.map +1 -1
  16. package/dist/core/QuotaPoller.js +110 -11
  17. package/dist/core/QuotaPoller.js.map +1 -1
  18. package/dist/core/SessionManager.d.ts +13 -0
  19. package/dist/core/SessionManager.d.ts.map +1 -1
  20. package/dist/core/SessionManager.js +22 -6
  21. package/dist/core/SessionManager.js.map +1 -1
  22. package/dist/core/SubscriptionLoginLedger.d.ts +1 -1
  23. package/dist/core/SubscriptionLoginLedger.d.ts.map +1 -1
  24. package/dist/core/SubscriptionLoginLedger.js +3 -0
  25. package/dist/core/SubscriptionLoginLedger.js.map +1 -1
  26. package/dist/core/SubscriptionReloginHelper.d.ts +119 -0
  27. package/dist/core/SubscriptionReloginHelper.d.ts.map +1 -0
  28. package/dist/core/SubscriptionReloginHelper.js +329 -0
  29. package/dist/core/SubscriptionReloginHelper.js.map +1 -0
  30. package/dist/core/SubscriptionReloginOrchestrator.d.ts +25 -2
  31. package/dist/core/SubscriptionReloginOrchestrator.d.ts.map +1 -1
  32. package/dist/core/SubscriptionReloginOrchestrator.js +58 -3
  33. package/dist/core/SubscriptionReloginOrchestrator.js.map +1 -1
  34. package/dist/core/SubscriptionReloginPolicy.d.ts +1 -1
  35. package/dist/core/SubscriptionReloginPolicy.d.ts.map +1 -1
  36. package/dist/core/SubscriptionReloginPolicy.js +1 -0
  37. package/dist/core/SubscriptionReloginPolicy.js.map +1 -1
  38. package/dist/core/SubscriptionReloginRuntime.d.ts +74 -4
  39. package/dist/core/SubscriptionReloginRuntime.d.ts.map +1 -1
  40. package/dist/core/SubscriptionReloginRuntime.js +163 -7
  41. package/dist/core/SubscriptionReloginRuntime.js.map +1 -1
  42. package/dist/core/SubscriptionReloginService.d.ts +17 -0
  43. package/dist/core/SubscriptionReloginService.d.ts.map +1 -1
  44. package/dist/core/SubscriptionReloginService.js +54 -4
  45. package/dist/core/SubscriptionReloginService.js.map +1 -1
  46. package/dist/core/SubscriptionReloginStore.d.ts +22 -2
  47. package/dist/core/SubscriptionReloginStore.d.ts.map +1 -1
  48. package/dist/core/SubscriptionReloginStore.js +82 -2
  49. package/dist/core/SubscriptionReloginStore.js.map +1 -1
  50. package/dist/core/types.d.ts +6 -3
  51. package/dist/core/types.d.ts.map +1 -1
  52. package/dist/core/types.js.map +1 -1
  53. package/dist/data/builtinSkillContent.d.ts +1 -1
  54. package/dist/data/builtinSkillContent.d.ts.map +1 -1
  55. package/dist/data/builtinSkillContent.js +11 -0
  56. package/dist/data/builtinSkillContent.js.map +1 -1
  57. package/dist/data/standards-guard-index.json +1 -1
  58. package/dist/data/standards-guard-index.meta.json +2 -2
  59. package/dist/data/standards-registry.meta.json +1 -1
  60. package/dist/providers/adapters/openai-codex/observability/codexLiveRateLimitReader.d.ts +29 -0
  61. package/dist/providers/adapters/openai-codex/observability/codexLiveRateLimitReader.d.ts.map +1 -1
  62. package/dist/providers/adapters/openai-codex/observability/codexLiveRateLimitReader.js +37 -9
  63. package/dist/providers/adapters/openai-codex/observability/codexLiveRateLimitReader.js.map +1 -1
  64. package/dist/scaffold/templates.d.ts.map +1 -1
  65. package/dist/scaffold/templates.js +1 -0
  66. package/dist/scaffold/templates.js.map +1 -1
  67. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  68. package/dist/server/CapabilityIndex.js +3 -1
  69. package/dist/server/CapabilityIndex.js.map +1 -1
  70. package/dist/server/middleware.d.ts +2 -0
  71. package/dist/server/middleware.d.ts.map +1 -1
  72. package/dist/server/middleware.js +18 -0
  73. package/dist/server/middleware.js.map +1 -1
  74. package/dist/server/routes.d.ts +5 -0
  75. package/dist/server/routes.d.ts.map +1 -1
  76. package/dist/server/routes.js +58 -1
  77. package/dist/server/routes.js.map +1 -1
  78. package/package.json +1 -1
  79. package/src/data/builtin-manifest.json +64 -64
  80. package/src/data/builtinSkillContent.ts +11 -0
  81. package/src/data/standards-guard-index.json +1 -1
  82. package/src/data/standards-guard-index.meta.json +2 -2
  83. package/src/data/standards-registry.meta.json +1 -1
  84. package/src/scaffold/templates.ts +1 -0
  85. package/upgrades/1.3.1288.md +58 -0
  86. package/upgrades/side-effects/skill-driven-signin-repair.md +197 -0
  87. package/upgrades/side-effects/subscriptions-provider-colors.md +44 -0
  88. package/upgrades/subscriptions-provider-colors.eli16.md +9 -0
@@ -3720,6 +3720,20 @@
3720
3720
  .sub-provider-heading { font-size:12px; font-weight:700; letter-spacing:.06em; text-transform:uppercase;
3721
3721
  opacity:.6; margin:14px 0 8px; padding-bottom:6px; border-bottom:1px solid var(--border,#2a2a2a); }
3722
3722
  .sub-provider-heading:first-child { margin-top:0; }
3723
+ /* Provider colors (operator request 2026-09-25): Claude and Codex are told apart
3724
+ at a glance — a colored band on each group heading and a colored edge on every
3725
+ account card and grid row. Claude = clay orange, Codex = blue. */
3726
+ .sub-prov-claude { --prov:#e07a4f; --prov-tint:rgba(224,122,79,.12); }
3727
+ .sub-prov-codex { --prov:#4f8ff0; --prov-tint:rgba(79,143,240,.12); }
3728
+ .sub-prov-other { --prov:#9ca3af; --prov-tint:rgba(156,163,175,.10); }
3729
+ .sub-provider-heading.sub-prov-claude, .sub-provider-heading.sub-prov-codex, .sub-provider-heading.sub-prov-other {
3730
+ opacity:1; color:var(--prov); font-size:15px; background:var(--prov-tint); border-bottom:none;
3731
+ border-left:6px solid var(--prov); border-radius:6px; padding:8px 12px; margin:20px 0 10px; }
3732
+ .sub-account.sub-prov-claude, .sub-account.sub-prov-codex, .sub-account.sub-prov-other { border-left:6px solid var(--prov); }
3733
+ .sub-matrix-group.sub-prov-claude, .sub-matrix-group.sub-prov-codex, .sub-matrix-group.sub-prov-other {
3734
+ color:var(--prov); background:var(--prov-tint); font-size:14px; opacity:1; border-left:6px solid var(--prov); padding:10px 12px; }
3735
+ .sub-matrix tr.sub-prov-claude > .sub-matrix-acct, .sub-matrix tr.sub-prov-codex > .sub-matrix-acct, .sub-matrix tr.sub-prov-other > .sub-matrix-acct {
3736
+ border-left:6px solid var(--prov); background:var(--prov-tint); }
3723
3737
  .sub-account { border:1px solid var(--border,#2a2a2a); border-radius:10px; padding:14px 16px; margin-bottom:12px; }
3724
3738
  .sub-account-inuse { border-color:#16a34a; box-shadow:0 0 0 1px #16a34a44; }
3725
3739
  .sub-account-inuse-badge { font-size:11px; font-weight:600; color:#22c55e; margin-right:auto; }
@@ -282,6 +282,15 @@ export function quotaBar(doc, label, pct, resetIso, now = Date.now()) {
282
282
  * pinned by a test, because "we grouped everything" would quietly add a redundant
283
283
  * heading to the common case.
284
284
  */
285
+ /** CSS class that colors a provider's group at a glance (operator request 2026-09-25:
286
+ * Claude and Codex must be distinguishable without reading). Closed mapping, so a
287
+ * provider string never reaches a class name raw. */
288
+ export function providerClass(provider) {
289
+ if (provider === 'anthropic') return 'sub-prov-claude';
290
+ if (provider === 'openai') return 'sub-prov-codex';
291
+ return 'sub-prov-other';
292
+ }
293
+
285
294
  export function groupAccountsByProvider(accounts) {
286
295
  if (!Array.isArray(accounts)) return [];
287
296
  const groups = new Map(); // provider key (raw) → accounts, in first-appearance order
@@ -298,7 +307,7 @@ export function groupAccountsByProvider(accounts) {
298
307
  // else, so an unrecognised or hostile provider string cannot reach the DOM raw.
299
308
  // An absent provider has no honest name, so say so rather than invent one.
300
309
  const label = friendlyProvider(key) || 'Other';
301
- out.push({ __providerHeading: label });
310
+ out.push({ __providerHeading: label, __providerKey: key });
302
311
  }
303
312
  for (const m of members) out.push(m);
304
313
  }
@@ -322,11 +331,11 @@ export function renderAccounts(doc, target, accounts, now = Date.now(), inUseAcc
322
331
  // accounts mixed together with only a small per-card meta line to tell them
323
332
  // apart. The heading is what makes the split scannable.)
324
333
  if (a && a.__providerHeading) {
325
- target.appendChild(el(doc, 'div', 'sub-provider-heading', a.__providerHeading));
334
+ target.appendChild(el(doc, 'div', `sub-provider-heading ${providerClass(a.__providerKey)}`, a.__providerHeading));
326
335
  continue;
327
336
  }
328
337
  const inUse = !!(inUseAccountId && a && a.id === inUseAccountId);
329
- const card = el(doc, 'div', inUse ? 'sub-account sub-account-inuse' : 'sub-account');
338
+ const card = el(doc, 'div', `${inUse ? 'sub-account sub-account-inuse' : 'sub-account'} ${providerClass(a && a.provider)}`);
330
339
  const head = el(doc, 'div', 'sub-account-head');
331
340
  head.appendChild(el(doc, 'span', 'sub-account-nick', sanitizeForDisplay(a && a.nickname, 'label')));
332
341
  if (inUse) head.appendChild(el(doc, 'span', 'sub-account-inuse-badge', '● In use now'));
@@ -924,7 +933,7 @@ export function renderAccountMatrix(doc, target, poolScope, pendingScope, transi
924
933
  for (const entry of groupMatrixRowsByProvider(model.rows)) {
925
934
  if (entry && entry.__providerHeading) {
926
935
  const gtr = doc.createElement('tr');
927
- const gth = el(doc, 'th', 'sub-matrix-group', entry.__providerHeading);
936
+ const gth = el(doc, 'th', `sub-matrix-group ${providerClass(entry.__providerKey)}`, entry.__providerHeading);
928
937
  // Span the account column + every machine column so the heading reads as a band
929
938
  // across the grid rather than a stray cell.
930
939
  gth.setAttribute('colspan', String(model.machines.length + 1));
@@ -934,7 +943,7 @@ export function renderAccountMatrix(doc, target, poolScope, pendingScope, transi
934
943
  continue;
935
944
  }
936
945
  const row = entry.__row;
937
- const tr = doc.createElement('tr');
946
+ const tr = el(doc, 'tr', providerClass(row && row.account && row.account.provider));
938
947
  tr.appendChild(el(doc, 'th', 'sub-matrix-acct', sanitizeForDisplay(row.account.email, 'label')));
939
948
  for (const c of row.cells) {
940
949
  const repairCandidate = Array.isArray(reloginEpisodes)
@@ -971,6 +980,16 @@ export function renderAccountMatrix(doc, target, poolScope, pendingScope, transi
971
980
  button.setAttribute('data-episode-id', sanitizeForDisplay(repair.id, 'label'));
972
981
  td.appendChild(button);
973
982
  }
983
+ // While a repair waits on the operator (a phone tap, a macOS Allow, no helper account), the
984
+ // operator can also finish the sign-in themselves from here — the same one-tap Sign in flow
985
+ // as a needs-reauth cell (spec skill-driven-signin-repair, operator contact).
986
+ if (repair.state === 'waiting-operator-only') {
987
+ const signIn = el(doc, 'button', 'sub-matrix-setup', 'Sign in');
988
+ signIn.setAttribute('data-matrix-setup', '1');
989
+ signIn.setAttribute('data-account-id', sanitizeForDisplay(c.accountId, 'label'));
990
+ signIn.setAttribute('data-machine-id', sanitizeForDisplay(c.machineId, 'label'));
991
+ td.appendChild(signIn);
992
+ }
974
993
  } else if (c.state === 'empty' || c.state === 'needs-reauth' || c.state === 'held' || c.state === 'cant-resolve' || c.state === 'email-missing' || c.state === 'expired' || c.state === 'broken') {
975
994
  // An actionable cell → a button that runs the SAME in-dashboard sign-in flow (PIN → link →
976
995
  // paste code). empty → "Set up"; needs-reauth (an existing account whose login expired) →
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAsGA,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;AAmI7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAkFtD;;;;;;;;;;;;;;;;;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;AAoDD,+EAA+E;AAC/E,wBAAgB,qCAAqC,CACnD,SAAS,EAAE,IAAI,CAAC,OAAO,2BAA2B,EAAE,cAAc,EAAE,QAAQ,CAAC,GAAG,IAAI,EACpF,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAsrDD;;;;;;;;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,CA8yBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAs9vBtE;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":"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"}
@@ -13442,12 +13442,21 @@ export async function startServer(options) {
13442
13442
  // pool is non-empty (started below); on-demand polling is always available
13443
13443
  // via POST /subscription-pool/poll.
13444
13444
  const { QuotaPoller } = await import('../core/QuotaPoller.js');
13445
- const { buildCodexLiveUsageReader } = await import('../providers/adapters/openai-codex/observability/codexLiveRateLimitReader.js');
13445
+ const { buildCodexLiveUsageReader, buildCodexLiveUsageReaderDetailed } = await import('../providers/adapters/openai-codex/observability/codexLiveRateLimitReader.js');
13446
+ // The Codex CLI's own login check (spec skill-driven-signin-repair), proven able to fail by
13447
+ // its canary before any "signed in" answer is trusted. Shared by the poller and the sign-in
13448
+ // repair's helper-seat pick.
13449
+ const { CodexLoginStatusChecker } = await import('../core/CliLoginStatus.js');
13450
+ const codexLoginStatusChecker = new CodexLoginStatusChecker();
13446
13451
  const quotaPoller = new QuotaPoller({
13447
13452
  pool: subscriptionPool,
13448
13453
  // Zero-spend live codex quota (app-server account/rateLimits/read). ON by
13449
13454
  // default; `subscriptionPool.codexLiveQuota: false` forces rollout-only.
13450
13455
  codexLiveUsageReader: buildCodexLiveUsageReader(config.subscriptionPool),
13456
+ // The same live read with its failure KIND kept: an app-server "authentication required"
13457
+ // refusal is told apart from a transport failure, and only a live read proves login.
13458
+ codexLiveUsageReaderDetailed: buildCodexLiveUsageReaderDetailed(config.subscriptionPool),
13459
+ codexLoginStatus: (codexHome) => codexLoginStatusChecker.check(codexHome),
13451
13460
  loginObservationSink: subscriptionLoginLedger
13452
13461
  ? (input) => subscriptionLoginLedger.recordObservation(input)
13453
13462
  : undefined,
@@ -13857,7 +13866,7 @@ export async function startServer(options) {
13857
13866
  const reloginCfg = config.subscriptionPool?.assistedRelogin;
13858
13867
  if (reloginCfg?.enabled === true && subscriptionLoginLedger && subscriptionPoolMachineId && sharedIntelligence) {
13859
13868
  try {
13860
- const [{ createSubscriptionReloginRuntime, resolveReloginNavigation, takeFirstBackupCode }, { PlaywrightProfileRegistry }, { SecretStore }, { secretKeyPaths }, { ClaudePasteBackController }, { createReloginBrowser }] = await Promise.all([
13869
+ const [{ createSubscriptionReloginRuntime, resolveReloginNavigation, takeFirstBackupCode, buildReloginHelperSessionPorts }, { PlaywrightProfileRegistry }, { SecretStore }, { secretKeyPaths }, { ClaudePasteBackController }, { createReloginBrowser }] = await Promise.all([
13861
13870
  import('../core/SubscriptionReloginRuntime.js'), import('../core/PlaywrightProfileRegistry.js'),
13862
13871
  import('../core/SecretStore.js'), import('../core/SecretSync.js'),
13863
13872
  import('../core/ClaudePasteBackController.js'), import('../core/PlainChromeReloginBrowser.js'),
@@ -13890,18 +13899,42 @@ export async function startServer(options) {
13890
13899
  });
13891
13900
  const notify = telegram ? async (episode, deliveryKey, kind) => {
13892
13901
  const doorway = episode.framework === 'codex-cli' ? 'Codex' : 'Claude Code';
13902
+ // The dashboard's Subscriptions tab, where the operator can finish from a phone.
13903
+ let subscriptionsLink = `http://localhost:${config.port}/dashboard?tab=subscriptions`;
13904
+ try {
13905
+ if (tunnel?.url)
13906
+ subscriptionsLink = `${tunnel.url}/dashboard?tab=subscriptions`;
13907
+ }
13908
+ catch { /* @silent-fallback-ok — tunnel URL is best-effort; the local link still names the tab */ }
13909
+ // A helper-reported macOS permission rides the reason token `agent-permission-<name>`.
13910
+ const permissionReason = episode.failureClass === 'automation-permission'
13911
+ ? (subscriptionReloginRuntime?.store.listEvents(episode.id, 5)
13912
+ .map((event) => event.reason ?? '').find((reason) => reason.startsWith('agent-permission-')) ?? null)
13913
+ : null;
13914
+ const permissionName = permissionReason === 'agent-permission-screen-recording' ? 'Screen Recording'
13915
+ : permissionReason === 'agent-permission-accessibility' ? 'Accessibility'
13916
+ : permissionReason === 'agent-permission-automation' ? 'Automation (control Google Chrome)' : null;
13893
13917
  const summary = kind === 'approval'
13894
- ? `A ${doorway} subscription sign-in needs repair. Open Subscriptions and tap Repair sign-in once.`
13895
- : kind === 'operator-only'
13896
- ? (episode.failureClass === 'automation-permission'
13897
- ? `${doorway} sign-in repair needs a one-time permission on this machine: allow the agent to control Google Chrome. On that machine, signed in as the Mac user the agent runs as, click Allow on the "control Google Chrome" prompt if one is showing, or turn it on in System Settings, Privacy & Security, Automation. Then open Subscriptions and tap Try repair again.`
13898
- : 'Automated sign-in paused at a provider security challenge. Open Subscriptions to continue.')
13899
- : episode.state === 'succeeded'
13900
- ? `${doorway} subscription sign-in was repaired and verified.`
13901
- : `${doorway} subscription repair ended in ${episode.state}. Open Subscriptions for the redacted audit.`;
13918
+ ? `A ${doorway} subscription sign-in needs repair. Open Subscriptions and tap Repair sign-in once: ${subscriptionsLink}`
13919
+ : kind === 'phone-tap'
13920
+ ? `${doorway} sign-in repair is waiting on your phone: tap "Yes, it's me" on the Google prompt now. The helper continues on its own after that.`
13921
+ : kind === 'operator-only'
13922
+ ? (episode.failureClass === 'no-healthy-seat'
13923
+ ? `${doorway} sign-in repair has no other healthy account on this machine to run its helper. Finish the sign-in from your phone: open ${subscriptionsLink} and tap Sign in on that account.`
13924
+ : episode.failureClass === 'automation-permission' && permissionName
13925
+ ? `${doorway} sign-in repair needs a one-time macOS permission on this machine: ${permissionName}. On that machine, click Allow if the prompt is showing, or turn it on in System Settings, Privacy & Security. Then open ${subscriptionsLink} and tap Try repair again, or tap Sign in to finish it yourself.`
13926
+ : episode.failureClass === 'automation-permission'
13927
+ ? `${doorway} sign-in repair needs a one-time permission on this machine: allow the agent to control Google Chrome. On that machine, signed in as the Mac user the agent runs as, click Allow on the "control Google Chrome" prompt if one is showing, or turn it on in System Settings, Privacy & Security, Automation. Then open Subscriptions and tap Try repair again: ${subscriptionsLink}`
13928
+ : `Automated sign-in paused and needs you. Open ${subscriptionsLink} to continue, or tap Sign in to finish it from your phone.`)
13929
+ : episode.failureClass === 'resolved-elsewhere'
13930
+ ? `${doorway} subscription is signed in again (verified), so its open sign-in repair was closed. Nothing to do.`
13931
+ : episode.state === 'succeeded'
13932
+ ? `${doorway} subscription sign-in was repaired and verified.`
13933
+ : `${doorway} subscription repair ended in ${episode.state}. Open ${subscriptionsLink} for the redacted audit, or tap Sign in to finish it from your phone.`;
13902
13934
  await telegram.createAttentionItem({ id: deliveryKey.replace(/:/g, '-'), title: `${doorway} sign-in repair`,
13903
13935
  summary, description: summary, category: 'subscription-relogin',
13904
- priority: kind === 'terminal' && episode.state === 'succeeded' ? 'NORMAL' : 'HIGH',
13936
+ priority: kind === 'phone-tap' ? 'URGENT'
13937
+ : kind === 'terminal' && (episode.state === 'succeeded' || episode.failureClass === 'resolved-elsewhere') ? 'NORMAL' : 'HIGH',
13905
13938
  sourceContext: 'assisted-subscription-relogin' });
13906
13939
  } : undefined;
13907
13940
  subscriptionReloginRuntime = createSubscriptionReloginRuntime({ stateDir: config.stateDir,
@@ -13940,7 +13973,13 @@ export async function startServer(options) {
13940
13973
  return action;
13941
13974
  },
13942
13975
  // Agent navigation (spec agent-driven-relogin): omitted ⇒ the development-agent gate.
13976
+ // `agent-session` (spec skill-driven-signin-repair) is macOS-only; omitted ⇒ agent-session
13977
+ // on a macOS development agent.
13943
13978
  navigation: resolveReloginNavigation(reloginCfg.navigation, config),
13979
+ // A Codex repair can only be proven by a LIVE app-server read (spec skill-driven-signin-repair).
13980
+ codexLiveReadAvailable: config.subscriptionPool?.codexLiveQuota !== false,
13981
+ helperSession: buildReloginHelperSessionPorts({ sessionManager, maxSessions: config.sessions.maxSessions,
13982
+ serverPort: config.port, codexLoginStatus: (codexHome) => codexLoginStatusChecker.check(codexHome) }),
13944
13983
  navigate: async (input) => {
13945
13984
  const prompt = [
13946
13985
  'You are signing an expired subscription account back in, in that account\'s own browser, the way a careful person would.',
@@ -13969,6 +14008,7 @@ export async function startServer(options) {
13969
14008
  onSuggested: notify ? (episode, key) => notify(episode, key, 'approval') : undefined,
13970
14009
  onOperatorOnly: notify ? (episode, key) => notify(episode, key, 'operator-only') : undefined,
13971
14010
  onTerminal: notify ? (episode, key) => notify(episode, key, 'terminal') : undefined,
14011
+ onPhoneTap: notify ? (episode, key) => notify(episode, key, 'phone-tap') : undefined,
13972
14012
  allowedScopes: reloginCfg.allowedScopes ?? [], tickMs: reloginCfg.tickMs,
13973
14013
  maxAttempts: reloginCfg.maxAttempts, retryBaseMs: reloginCfg.retryBaseMs,
13974
14014
  unattendedPolicy: reloginCfg.unattendedPolicy, });
@@ -26543,13 +26583,10 @@ export async function startServer(options) {
26543
26583
  });
26544
26584
  }
26545
26585
  server.setSubscriptionLoginLedger(subscriptionLoginLedger);
26546
- server.setSubscriptionRelogin(subscriptionReloginRuntime ? {
26547
- store: subscriptionReloginRuntime.store,
26548
- approve: (episodeId) => subscriptionReloginRuntime.service.approve(episodeId),
26549
- cancel: (episodeId) => subscriptionReloginRuntime.service.cancel(episodeId),
26550
- retry: (episodeId) => subscriptionReloginRuntime.service.retry(episodeId),
26551
- close: () => subscriptionReloginRuntime.close(),
26552
- } : null);
26586
+ {
26587
+ const { subscriptionReloginRouteContext } = await import('../core/SubscriptionReloginRuntime.js');
26588
+ server.setSubscriptionRelogin(subscriptionReloginRuntime ? subscriptionReloginRouteContext(subscriptionReloginRuntime) : null);
26589
+ }
26553
26590
  server.setWorkQueue(workQueue);
26554
26591
  if (_stateSyncStoresResolved?.classReview?.enabled && replicatedPeerStreamReader) {
26555
26592
  const { CLASS_REVIEW_STORE_KEY, classReviewFromOriginRecord } = await import('../core/ClassReviewReplicatedStore.js');