instar 1.3.1238 → 1.3.1239

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.
@@ -79,6 +79,31 @@ export function effectiveAccountStatus(account) {
79
79
  return account && account.status;
80
80
  }
81
81
 
82
+ const KNOWN_REPAIR_STATES = new Set([
83
+ 'suggested', 'approved', 'cli-starting', 'artifact-ready', 'browser-driving',
84
+ 'cli-finishing', 'identity-verifying', 'auth-verifying', 'waiting-operator-only',
85
+ 'succeeded', 'refused', 'cancelled', 'failed',
86
+ ]);
87
+
88
+ /** A suggested/failed repair is actionable only while current pool truth still says
89
+ * the account cell needs authentication. Terminal repair rows remain durable audit
90
+ * history, but must never shadow a newer Active observation or offer a retry that
91
+ * the server's admission policy is required to refuse. In-flight states remain
92
+ * visible because pool activation can precede the controller's final ledger close. */
93
+ export function repairAppliesToCurrentState(repair, currentState) {
94
+ if (!repair || !KNOWN_REPAIR_STATES.has(repair.state)) return false;
95
+ if (repair.state === 'suggested' || repair.state === 'failed') {
96
+ return currentState === 'needs-reauth';
97
+ }
98
+ return true;
99
+ }
100
+
101
+ export function repairConflictMessage(error) {
102
+ return /^(?:retry|approval)-revalidation-refused:account-not-needs-reauth$/.test(
103
+ typeof error === 'string' ? error : '',
104
+ ) ? 'This account is already active. Refreshing its status…' : null;
105
+ }
106
+
82
107
  const PROVIDER_WORDS = { anthropic: 'Claude', openai: 'Codex', 'github-copilot': 'Copilot', google: 'Gemini' };
83
108
  export function friendlyProvider(provider) {
84
109
  return PROVIDER_WORDS[typeof provider === 'string' ? provider : ''] || sanitizeForDisplay(provider, 'label');
@@ -294,9 +319,12 @@ export function renderAccounts(doc, target, accounts, now = Date.now(), inUseAcc
294
319
  if (refAge) {
295
320
  card.appendChild(el(doc, 'div', 'sub-account-refresh', `Token auto-refreshed ${refAge}`));
296
321
  }
297
- const repair = Array.isArray(reloginEpisodes)
322
+ const repairCandidate = Array.isArray(reloginEpisodes)
298
323
  ? reloginEpisodes.find((episode) => episode && a && episode.accountId === a.id)
299
324
  : null;
325
+ const repair = repairAppliesToCurrentState(repairCandidate, effectiveAccountStatus(a))
326
+ ? repairCandidate
327
+ : null;
300
328
  if (repair) {
301
329
  const repairBox = el(doc, 'div', 'sub-account-repair');
302
330
  const terminal = ['succeeded', 'refused', 'cancelled', 'failed'].includes(repair.state);
@@ -855,9 +883,12 @@ export function renderAccountMatrix(doc, target, poolScope, pendingScope, transi
855
883
  const tr = doc.createElement('tr');
856
884
  tr.appendChild(el(doc, 'th', 'sub-matrix-acct', sanitizeForDisplay(row.account.email, 'label')));
857
885
  for (const c of row.cells) {
858
- const repair = Array.isArray(reloginEpisodes)
886
+ const repairCandidate = Array.isArray(reloginEpisodes)
859
887
  ? reloginEpisodes.find((episode) => episode && episode.accountId === c.accountId && episode.machineId === c.machineId)
860
888
  : null;
889
+ const repair = repairAppliesToCurrentState(repairCandidate, c.state)
890
+ ? repairCandidate
891
+ : null;
861
892
  const repairUnavailable = Array.isArray(reloginFailures)
862
893
  && reloginFailures.some((failure) => failure && failure.machineId === c.machineId);
863
894
  // just-verified rides a transient highlight on an otherwise-active cell (D4 ceremony).
@@ -1360,8 +1391,12 @@ export function createController(opts) {
1360
1391
  });
1361
1392
  if (!response.ok) {
1362
1393
  if (response.status === 401) requestUnlock();
1363
- button.textContent = response.status === 401 ? 'Enter PIN, then try again' : 'Couldn’t start — try again';
1394
+ const body = await response.json().catch(() => ({}));
1395
+ const resolvedConflict = repairConflictMessage(body.error);
1396
+ button.textContent = response.status === 401 ? 'Enter PIN, then try again'
1397
+ : resolvedConflict || 'Couldn’t start — try again';
1364
1398
  button.removeAttribute('disabled');
1399
+ if (resolvedConflict) await tick();
1365
1400
  return;
1366
1401
  }
1367
1402
  await tick();
@@ -1564,10 +1599,12 @@ export function createController(opts) {
1564
1599
  const body = await response.json().catch(() => ({}));
1565
1600
  if (!response.ok) {
1566
1601
  if (response.status === 401) requestUnlock();
1602
+ const resolvedConflict = repairConflictMessage(body.error);
1567
1603
  setCellStatus(cell, response.status === 401
1568
1604
  ? 'Enter your dashboard PIN, then tap Repair sign-in once.'
1569
- : body.error || 'Couldn’t start the repair — try again.');
1605
+ : resolvedConflict || body.error || 'Couldn’t start the repair — try again.');
1570
1606
  btn.removeAttribute('disabled');
1607
+ if (resolvedConflict) await tick();
1571
1608
  return;
1572
1609
  }
1573
1610
  setCellStatus(cell, 'Repair started — Instar is handling the sign-in.');
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "generatedFrom": "source-tree",
4
4
  "registrySha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
5
- "packageVersion": "1.3.1238",
5
+ "packageVersion": "1.3.1239",
6
6
  "guards": [
7
7
  {
8
8
  "ref": "docs/audits/phase-b/f10-triage.md",
@@ -1,5 +1,5 @@
1
1
  {
2
- "sha256": "af9c9662b90d97f6fc09aa4a3228738e21756d3c8aa9fe686863ced09da5bb30",
2
+ "sha256": "ba4938bd77943c4fdd078bda04c5f6421eeddf240ea6ccc23b6e4030e1a08339",
3
3
  "registrySha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
4
- "packageVersion": "1.3.1238"
4
+ "packageVersion": "1.3.1239"
5
5
  }
@@ -2,5 +2,5 @@
2
2
  "sha256": "890eec3dcf80e4388c396f43001a0bd3fabc80c88f79aa9525885d6402a6dfdf",
3
3
  "articleCount": 91,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1238"
5
+ "packageVersion": "1.3.1239"
6
6
  }
@@ -29544,7 +29544,7 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
29544
29544
  catch (error) {
29545
29545
  const message = error instanceof Error ? error.message : 're-login approval failed';
29546
29546
  const status = message === 'relogin-episode-not-found' ? 404
29547
- : /mismatch|approvable|conflict|closed|expired/.test(message) ? 409 : 500;
29547
+ : /mismatch|approvable|conflict|closed|expired|revalidation-refused/.test(message) ? 409 : 500;
29548
29548
  res.status(status).json({ error: message });
29549
29549
  }
29550
29550
  });
@@ -29617,7 +29617,7 @@ document.getElementById('mcpForm').addEventListener('submit', async function (e)
29617
29617
  }
29618
29618
  catch (error) {
29619
29619
  const message = error instanceof Error ? error.message : 're-login approval failed';
29620
- res.status(/mismatch|approvable|conflict|closed|expired/.test(message) ? 409 : 500).json({ error: message });
29620
+ res.status(/mismatch|approvable|conflict|closed|expired|revalidation-refused/.test(message) ? 409 : 500).json({ error: message });
29621
29621
  }
29622
29622
  });
29623
29623
  // Fronting one-click route: recent dashboard unlock → exact account/machine