instar 1.3.402 → 1.3.404

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.
@@ -2692,6 +2692,7 @@
2692
2692
  <button class="tab" data-tab="threadline" onclick="switchTab('threadline')">Threadline</button>
2693
2693
  <button class="tab" data-tab="evidence" onclick="switchTab('evidence')">Evidence</button>
2694
2694
  <button class="tab" data-tab="process-health" onclick="switchTab('process-health')">Process Health</button>
2695
+ <button class="tab" data-tab="subscriptions" onclick="switchTab('subscriptions')">Subscriptions</button>
2695
2696
  <button class="tab" data-tab="preferences-learning" onclick="switchTab('preferences-learning')">Preferences</button>
2696
2697
  <button class="tab" data-tab="machines" onclick="switchTab('machines')">Machines</button>
2697
2698
  <button class="tab" data-tab="mandates" onclick="switchTab('mandates')">Mandates</button>
@@ -3243,6 +3244,44 @@
3243
3244
  </details>
3244
3245
  </div>
3245
3246
 
3247
+ <!-- subscriptions tab (Subscription & Auth Standard P2.2 — live quota + pending logins) -->
3248
+ <style>
3249
+ .sub-account { border:1px solid var(--border,#2a2a2a); border-radius:10px; padding:14px 16px; margin-bottom:12px; }
3250
+ .sub-account-head { display:flex; justify-content:space-between; align-items:baseline; gap:12px; }
3251
+ .sub-account-nick { font-weight:600; font-size:15px; }
3252
+ .sub-account-status { font-size:12px; opacity:.75; }
3253
+ .sub-account-meta { font-size:12px; opacity:.6; margin:2px 0 10px; }
3254
+ .sub-account-noquota { font-size:12px; opacity:.6; }
3255
+ .sub-quota { margin:8px 0; }
3256
+ .sub-quota-head { display:flex; justify-content:space-between; font-size:12px; margin-bottom:4px; }
3257
+ .sub-quota-label { opacity:.8; }
3258
+ .sub-quota-pct { opacity:.65; }
3259
+ .sub-quota-track { height:8px; border-radius:4px; background:var(--border,#2a2a2a); overflow:hidden; }
3260
+ .sub-quota-fill { height:100%; background:linear-gradient(90deg,#4caf80,#3a9); }
3261
+ .sub-pending { border:1px solid var(--border,#2a2a2a); border-radius:10px; padding:12px 16px; margin-bottom:10px; }
3262
+ .sub-pending-head { display:flex; justify-content:space-between; align-items:baseline; gap:12px; }
3263
+ .sub-pending-label { font-weight:600; }
3264
+ .sub-pending-ttl { font-size:12px; opacity:.7; }
3265
+ .sub-pending-code { font-family:monospace; font-size:14px; margin-top:6px; }
3266
+ .sub-pending-url { font-size:12px; opacity:.7; word-break:break-all; margin-top:4px; }
3267
+ .sub-pending-reissue { font-size:11px; opacity:.55; margin-top:4px; }
3268
+ .sub-empty, .sub-disabled { font-size:13px; opacity:.7; padding:8px 0; }
3269
+ </style>
3270
+ <div id="subscriptionsPanel" class="ph-root" style="display:none;flex-direction:column;padding:28px;gap:24px;overflow-y:auto">
3271
+ <h2 class="ph-title">Subscriptions</h2>
3272
+ <p class="ph-intro">Your subscription accounts and how much of each is left before it resets — plus any logins waiting for you to approve on your phone.</p>
3273
+ <section class="ph-section">
3274
+ <h3 class="ph-h">Accounts</h3>
3275
+ <p class="ph-h-sub">Each account’s live usage (5-hour and weekly) and when it resets.</p>
3276
+ <div id="subAccounts"></div>
3277
+ </section>
3278
+ <section class="ph-section">
3279
+ <h3 class="ph-h">Pending logins</h3>
3280
+ <p class="ph-h-sub">Logins waiting for approval — open the link on your phone and confirm. An expired code is re-issued automatically.</p>
3281
+ <div id="subPending"></div>
3282
+ </section>
3283
+ </div>
3284
+
3246
3285
  <!-- mandates tab (coordination-mandate spec, decision 2A — the operator's PIN-gated surface) -->
3247
3286
  <div id="mandatesPanel" class="ph-root" style="display:none;flex-direction:column;padding:28px;gap:24px;overflow-y:auto">
3248
3287
  <div style="display:flex;justify-content:space-between;align-items:baseline">
@@ -4650,6 +4689,13 @@
4650
4689
  onActivate: () => { if (typeof startProcessHealth === 'function') startProcessHealth(); },
4651
4690
  onDeactivate: () => { if (typeof stopProcessHealth === 'function') stopProcessHealth(); },
4652
4691
  },
4692
+ {
4693
+ id: 'subscriptions',
4694
+ panels: ['subscriptionsPanel'],
4695
+ display: ['flex'],
4696
+ onActivate: () => { if (typeof startSubscriptions === 'function') startSubscriptions(); },
4697
+ onDeactivate: () => { if (typeof stopSubscriptions === 'function') stopSubscriptions(); },
4698
+ },
4653
4699
  {
4654
4700
  id: 'preferences-learning',
4655
4701
  panels: ['preferencesLearningPanel'],
@@ -8602,6 +8648,34 @@
8602
8648
  if (__phController) __phController.stop();
8603
8649
  }
8604
8650
 
8651
+ // ── Subscriptions tab (Subscription & Auth Standard P2.2) ──
8652
+ // Same lazy dynamic-import pattern as Process Health: the controller lives in
8653
+ // this (classic) scope so it can read `token`; the module ships the pure
8654
+ // renderers + the polling controller.
8655
+ let __subController = null;
8656
+ let __subModule = null;
8657
+ async function startSubscriptions() {
8658
+ if (!__subModule) {
8659
+ try { __subModule = await import('/dashboard/subscriptions.js'); }
8660
+ catch (e) { console.error('[subscriptions] module load failed', e); return; }
8661
+ }
8662
+ if (!__subController) {
8663
+ const els = {
8664
+ accounts: document.getElementById('subAccounts'),
8665
+ pending: document.getElementById('subPending'),
8666
+ };
8667
+ const fetchImpl = (url, opts = {}) => fetch(url, {
8668
+ headers: { 'Authorization': `Bearer ${token}`, ...(opts.headers || {}) },
8669
+ signal: opts.signal,
8670
+ });
8671
+ __subController = __subModule.createController({ doc: document, els, fetchImpl });
8672
+ }
8673
+ __subController.start();
8674
+ }
8675
+ function stopSubscriptions() {
8676
+ if (__subController) __subController.stop();
8677
+ }
8678
+
8605
8679
  // ── Mandates tab (coordination-mandate spec, decision 2A) ──
8606
8680
  // Same lazy dynamic-import pattern as Process Health. The PIN typed in this
8607
8681
  // tab is sent once per action and never stored anywhere.
@@ -0,0 +1,264 @@
1
+ // Subscriptions tab — a read surface for the multi-account Subscription & Auth
2
+ // pool: per-account live quota bars (5h / weekly + reset countdown), status, and
3
+ // the Pending Logins panel (device codes / verification URLs awaiting approval,
4
+ // with TTL). Spec: docs/specs/_drafts/subscription-auth-standard-master-spec.md.
5
+ //
6
+ // Browser-native ESM (no build step; served at /dashboard/subscriptions.js and
7
+ // loaded by index.html via <script type="module">). The pure functions are
8
+ // exported so the 3-tier jsdom tests exercise the SHIPPED code, not a copy; the
9
+ // controller is attached to window.Subscriptions so index.html drives start/stop
10
+ // on tab activation.
11
+ //
12
+ // Load-bearing safety contract (mirrors the Process Health tab §4.6): every
13
+ // dynamic value flows through sanitizeForDisplay before the DOM; all DOM writes
14
+ // are textContent only (never innerHTML); the only dynamic ATTRIBUTE written is a
15
+ // quota-bar width, set from a clamped NUMBER (0–100) — never a string from data.
16
+ // No verification URL is ever rendered as a live href (defense-in-depth): it is
17
+ // shown as sanitized TEXT for the operator to copy.
18
+
19
+ const CAPS = { label: 64, code: 48, url: 320, summary: 240 };
20
+
21
+ // Structural presentation-glyph class (NFKC-fold THEN strip), identical to the
22
+ // Process Health tab: \p{So} + arrows + geometric + box-drawing + dingbats +
23
+ // variation-selectors + bullet/middot — so a confusable can't impersonate chrome.
24
+ const CHROME_GLYPH_RE = new RegExp(
25
+ '[\\p{So}\\u2190-\\u21FF\\u25A0-\\u25FF\\u2500-\\u257F\\u2700-\\u27BF\\uFE00-\\uFE0F\\u2022\\u00B7\\u2027\\u2043]',
26
+ 'gu',
27
+ );
28
+ const CONTROL_RE = new RegExp('[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u009F]', 'g');
29
+ const BIDI_RE = new RegExp('[\\u202A-\\u202E\\u2066-\\u2069]', 'g');
30
+
31
+ /** Sanitize a dynamic value before it touches the DOM (see contract above). */
32
+ export function sanitizeForDisplay(value, fieldKind = 'summary') {
33
+ let s = value == null ? '' : String(value);
34
+ s = s.normalize('NFKC');
35
+ s = s.replace(CONTROL_RE, '');
36
+ s = s.replace(BIDI_RE, '');
37
+ s = s.replace(/\n{2,}/g, '\n').replace(/[ \t]{5,}/g, ' ');
38
+ s = s.replace(CHROME_GLYPH_RE, '');
39
+ s = capGraphemes(s, CAPS[fieldKind] ?? CAPS.summary);
40
+ return s;
41
+ }
42
+
43
+ function capGraphemes(s, max) {
44
+ if (s.length <= max) return s;
45
+ if (typeof Intl !== 'undefined' && Intl.Segmenter) {
46
+ const arr = Array.from(new Intl.Segmenter(undefined, { granularity: 'grapheme' }).segment(s), (x) => x.segment);
47
+ if (arr.length <= max) return s;
48
+ return arr.slice(0, max - 1).join('') + '…';
49
+ }
50
+ let cut = max - 1;
51
+ const c = s.charCodeAt(cut - 1);
52
+ if (c >= 0xd800 && c <= 0xdbff) cut -= 1;
53
+ return s.slice(0, cut) + '…';
54
+ }
55
+
56
+ /** Clamp a utilization value to an integer 0–100 (the only dynamic attribute). */
57
+ export function clampPct(value) {
58
+ const n = Number(value);
59
+ if (!Number.isFinite(n)) return 0;
60
+ return Math.max(0, Math.min(100, Math.round(n)));
61
+ }
62
+
63
+ const STATUS_WORDS = {
64
+ active: 'Active',
65
+ warming: 'Warming up',
66
+ 'rate-limited': 'At its limit',
67
+ 'needs-reauth': 'Needs sign-in',
68
+ disabled: 'Disabled',
69
+ };
70
+ export function friendlyStatus(status) {
71
+ return STATUS_WORDS[typeof status === 'string' ? status : ''] || 'Unknown';
72
+ }
73
+
74
+ const PROVIDER_WORDS = { anthropic: 'Claude', openai: 'Codex', 'github-copilot': 'Copilot', google: 'Gemini' };
75
+ export function friendlyProvider(provider) {
76
+ return PROVIDER_WORDS[typeof provider === 'string' ? provider : ''] || sanitizeForDisplay(provider, 'label');
77
+ }
78
+
79
+ /** Human countdown to a reset/expiry instant: "resets in 2h 15m" / "expired". */
80
+ export function countdown(iso, now = Date.now(), { expiredWord = 'expired' } = {}) {
81
+ const t = typeof iso === 'string' ? Date.parse(iso) : NaN;
82
+ if (Number.isNaN(t)) return '';
83
+ const sec = Math.floor((t - now) / 1000);
84
+ if (sec <= 0) return expiredWord;
85
+ const hr = Math.floor(sec / 3600);
86
+ const min = Math.floor((sec % 3600) / 60);
87
+ if (hr >= 24) { const d = Math.floor(hr / 24); return `${d}d ${hr % 24}h`; }
88
+ if (hr >= 1) return `${hr}h ${min}m`;
89
+ if (min >= 1) return `${min}m`;
90
+ return `${sec}s`;
91
+ }
92
+
93
+ // ── DOM helpers (textContent ONLY — never innerHTML) ────────────────────────
94
+ function el(doc, tag, cls, text) {
95
+ const node = doc.createElement(tag);
96
+ if (cls) node.setAttribute('class', cls); // static literal
97
+ if (text != null) node.textContent = text; // dynamic text → textContent ONLY
98
+ return node;
99
+ }
100
+
101
+ /** A labelled quota bar. `pct` is clamped to a 0–100 NUMBER before it reaches the
102
+ * only dynamic attribute (style width); the percent text is also from that number. */
103
+ export function quotaBar(doc, label, pct, resetIso, now = Date.now()) {
104
+ const wrap = el(doc, 'div', 'sub-quota');
105
+ const used = clampPct(pct);
106
+ const head = el(doc, 'div', 'sub-quota-head');
107
+ head.appendChild(el(doc, 'span', 'sub-quota-label', sanitizeForDisplay(label, 'label')));
108
+ const resetTxt = resetIso ? countdown(resetIso, now, { expiredWord: 'resetting' }) : '';
109
+ head.appendChild(el(doc, 'span', 'sub-quota-pct', `${used}% used${resetTxt ? ` · resets in ${resetTxt}` : ''}`));
110
+ wrap.appendChild(head);
111
+ const track = el(doc, 'div', 'sub-quota-track');
112
+ const fill = el(doc, 'div', 'sub-quota-fill');
113
+ fill.style.width = `${used}%`; // safe: `used` is a clamped integer
114
+ track.appendChild(fill);
115
+ wrap.appendChild(track);
116
+ return wrap;
117
+ }
118
+
119
+ /** Per-account rows: nickname, status, provider·framework, 5h + weekly quota bars. */
120
+ export function renderAccounts(doc, target, accounts, now = Date.now()) {
121
+ if (!target) return;
122
+ target.replaceChildren();
123
+ if (!Array.isArray(accounts) || accounts.length === 0) {
124
+ target.appendChild(el(doc, 'div', 'sub-empty', 'No subscription accounts enrolled yet.'));
125
+ return;
126
+ }
127
+ for (const a of accounts) {
128
+ const card = el(doc, 'div', 'sub-account');
129
+ const head = el(doc, 'div', 'sub-account-head');
130
+ head.appendChild(el(doc, 'span', 'sub-account-nick', sanitizeForDisplay(a && a.nickname, 'label')));
131
+ head.appendChild(el(doc, 'span', 'sub-account-status', friendlyStatus(a && a.status)));
132
+ card.appendChild(head);
133
+ card.appendChild(el(doc, 'div', 'sub-account-meta',
134
+ `${friendlyProvider(a && a.provider)} · ${sanitizeForDisplay(a && a.framework, 'label')}`));
135
+ const q = (a && a.lastQuota) || null;
136
+ if (q && (q.fiveHour || q.sevenDay)) {
137
+ if (q.fiveHour) card.appendChild(quotaBar(doc, '5-hour', q.fiveHour.utilizationPct, q.fiveHour.resetsAt, now));
138
+ if (q.sevenDay) card.appendChild(quotaBar(doc, 'Weekly', q.sevenDay.utilizationPct, q.sevenDay.resetsAt, now));
139
+ } else {
140
+ card.appendChild(el(doc, 'div', 'sub-account-noquota', 'No quota reading yet.'));
141
+ }
142
+ target.appendChild(card);
143
+ }
144
+ }
145
+
146
+ /** Pending Logins panel: device code / verification URL (as TEXT) + TTL + reissues. */
147
+ export function renderPendingLogins(doc, target, logins, now = Date.now()) {
148
+ if (!target) return;
149
+ target.replaceChildren();
150
+ if (!Array.isArray(logins) || logins.length === 0) {
151
+ target.appendChild(el(doc, 'div', 'sub-empty', 'No logins waiting for approval.'));
152
+ return;
153
+ }
154
+ for (const l of logins) {
155
+ const row = el(doc, 'div', 'sub-pending');
156
+ const head = el(doc, 'div', 'sub-pending-head');
157
+ head.appendChild(el(doc, 'span', 'sub-pending-label', sanitizeForDisplay(l && l.label, 'label')));
158
+ const ttl = l && l.ttlExpiresAt ? countdown(l.ttlExpiresAt, now) : '';
159
+ head.appendChild(el(doc, 'span', 'sub-pending-ttl', ttl ? `expires in ${ttl}` : 'expired'));
160
+ row.appendChild(head);
161
+ if (l && l.userCode) {
162
+ row.appendChild(el(doc, 'div', 'sub-pending-code', `Code: ${sanitizeForDisplay(l.userCode, 'code')}`));
163
+ }
164
+ // Verification URL shown as TEXT for the operator to copy — never a live href.
165
+ row.appendChild(el(doc, 'div', 'sub-pending-url', sanitizeForDisplay(l && l.verificationUrl, 'url')));
166
+ const rc = l && Number(l.reissueCount);
167
+ if (Number.isFinite(rc) && rc > 0) {
168
+ row.appendChild(el(doc, 'div', 'sub-pending-reissue', `Re-issued ${rc} time${rc === 1 ? '' : 's'}`));
169
+ }
170
+ target.appendChild(row);
171
+ }
172
+ }
173
+
174
+ export function renderDisabled(doc, els) {
175
+ if (els && els.accounts) {
176
+ els.accounts.replaceChildren(
177
+ el(doc, 'div', 'sub-disabled', 'The subscription pool isn’t set up yet. Enroll an account to get started.'),
178
+ );
179
+ }
180
+ if (els && els.pending) els.pending.replaceChildren();
181
+ }
182
+
183
+ // ── Controller (fetch /subscription-pool + /pending-logins, render) ─────────
184
+ const URLS = {
185
+ accounts: '/subscription-pool',
186
+ pending: '/subscription-pool/pending-logins',
187
+ };
188
+
189
+ export function createController(opts) {
190
+ const {
191
+ doc,
192
+ els = {},
193
+ fetchImpl,
194
+ now = () => Date.now(),
195
+ cadenceMs = 30_000,
196
+ schedule = (fn, ms) => setTimeout(fn, ms),
197
+ cancel = (id) => clearTimeout(id),
198
+ } = opts;
199
+
200
+ const state = { timerId: null, active: false, inFlight: null };
201
+
202
+ async function fetchJson(url, controller) {
203
+ const resp = await fetchImpl(url, { signal: controller.signal });
204
+ if (!resp.ok) throw new Error(`${url} ${resp.status}`);
205
+ return resp.json();
206
+ }
207
+
208
+ async function tick() {
209
+ if (!state.active) return;
210
+ if (state.inFlight) { try { state.inFlight.abort(); } catch { /* superseded */ } }
211
+ const controller = typeof AbortController !== 'undefined' ? new AbortController() : { signal: undefined, abort() {} };
212
+ state.inFlight = controller;
213
+ let accountsBody, pendingBody;
214
+ try {
215
+ [accountsBody, pendingBody] = await Promise.all([
216
+ fetchJson(URLS.accounts, controller),
217
+ fetchJson(URLS.pending, controller),
218
+ ]);
219
+ } catch {
220
+ if (controller.signal && controller.signal.aborted) return;
221
+ state.inFlight = null;
222
+ reschedule();
223
+ return;
224
+ }
225
+ if (controller.signal && controller.signal.aborted) return;
226
+ state.inFlight = null;
227
+ // Feature dark → both routes answer { enabled:false }. Show the friendly copy.
228
+ if (accountsBody && accountsBody.enabled === false && pendingBody && pendingBody.enabled === false) {
229
+ renderDisabled(doc, els);
230
+ reschedule();
231
+ return;
232
+ }
233
+ render(accountsBody, pendingBody);
234
+ reschedule();
235
+ }
236
+
237
+ function render(accountsBody, pendingBody) {
238
+ const accounts = accountsBody && Array.isArray(accountsBody.accounts) ? accountsBody.accounts : [];
239
+ const logins = pendingBody && Array.isArray(pendingBody.logins) ? pendingBody.logins : [];
240
+ renderAccounts(doc, els.accounts, accounts, now());
241
+ renderPendingLogins(doc, els.pending, logins, now());
242
+ }
243
+
244
+ function reschedule() {
245
+ if (!state.active) return;
246
+ if (state.timerId != null) cancel(state.timerId);
247
+ state.timerId = schedule(() => { void tick(); }, cadenceMs);
248
+ }
249
+
250
+ function start() { if (state.active) return; state.active = true; void tick(); }
251
+ function stop() {
252
+ state.active = false;
253
+ if (state.timerId != null) { cancel(state.timerId); state.timerId = null; }
254
+ if (state.inFlight) { try { state.inFlight.abort(); } catch { /* ignore */ } state.inFlight = null; }
255
+ }
256
+ function onVisible() { if (!state.active) start(); }
257
+ function onHidden() { stop(); }
258
+
259
+ return { start, stop, onVisible, onHidden, tick, render, _state: state };
260
+ }
261
+
262
+ if (typeof window !== 'undefined') {
263
+ window.Subscriptions = { createController, sanitizeForDisplay, renderAccounts, renderPendingLogins };
264
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
@@ -2801,6 +2801,24 @@ Rule: I do not state that work landed inside another agent's state unless I have
2801
2801
  patched = true;
2802
2802
  result.upgraded.push('CLAUDE.md: added MTP Protocol (EXO 3.0 test-action) section');
2803
2803
  }
2804
+ // Subscription Pool (Subscription & Auth Standard) — graduated from
2805
+ // INTERNAL_PREFIXES to a surfaced capability once P1.3 (scheduler) + P2.1
2806
+ // (enrollment) + P2.2 (dashboard) made it user-usable. Existing agents need
2807
+ // the awareness blurb (multi-account quota + continuity-guaranteed auto-swap +
2808
+ // mobile enrollment). Content-sniffed on a distinctive marker.
2809
+ if (!content.includes('Subscription Pool (multi-account quota')) {
2810
+ const subscriptionPoolSection = `
2811
+ **Subscription Pool (multi-account quota + auto-swap + enrollment)** — Hold ALL of your subscriptions for a provider (e.g. several Claude logins) and use them as one pool: I read each account's live quota, drain each before its reset, and when a session hits an account's limit I resume it on another account instead of letting it die. The registry stores each account's login LOCATION (its config home), NEVER a token.
2812
+ - See the pool + each account's live quota: \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/subscription-pool\` · one account's quota + burn: \`GET /subscription-pool/:id/quota\` · poll all now: \`POST /subscription-pool/poll\`.
2813
+ - **Continuity guarantee** — a long session that hits its account's quota resumes on another eligible account (conversation preserved via \`--resume\`), never dies. Manual lever: \`POST /subscription-pool/swap\` \`{"sessionName":"...","exhaustedAccountId":"..."}\`. Auto-swap on rate-limit ships OFF (opt-in via \`subscriptionPool.autoSwapOnRateLimit\` — it moves a live session, real authority).
2814
+ - **Enroll a new account from your phone** — \`POST /subscription-pool/enroll\` \`{"id","label","provider","framework","configHome"}\` starts a login and returns a public code/URL (never a token); \`GET /subscription-pool/pending-logins\` is the surface; expired codes are auto-reissued. Mark done with \`POST /subscription-pool/enroll/:id/complete\`.
2815
+ - **Dashboard**: the **Subscriptions tab** shows live quota bars (5h + weekly + reset countdown), status, and the Pending Logins panel — share the dashboard URL + PIN.
2816
+ - **When to use** (PROACTIVE): "how much quota is left across my accounts?" / "am I about to hit a limit?" → \`GET /subscription-pool\`; the user wants to add another subscription → drive the enrollment wizard (never ask them to paste a token); a long job is at risk of a quota wall → the continuity guarantee + \`/swap\` keep it alive. Single-account pools are a no-op.
2817
+ `;
2818
+ content += '\n' + subscriptionPoolSection;
2819
+ patched = true;
2820
+ result.upgraded.push('CLAUDE.md: added Subscription Pool (multi-account quota + enrollment) section');
2821
+ }
2804
2822
  // Session Boot Self-Knowledge (spec: session-boot-self-knowledge.md).
2805
2823
  // Existing agents need the rule ("a secret named in your boot block is in
2806
2824
  // the vault — retrieve, don't re-ask") + the facts writer + the retrieval
@@ -4660,6 +4678,12 @@ Create worktrees for collaborator repos with \`instar worktree create <branch>\`
4660
4678
  '**Coordination Mandate**',
4661
4679
  '**ReviewExchange (autonomous code review)**',
4662
4680
  '**Cutover Readiness**',
4681
+ // Subscription Pool (Subscription & Auth Standard): a framework-agnostic
4682
+ // capability — a Codex/Gemini agent should also know it can manage a
4683
+ // multi-account subscription pool, swap to keep a session alive, and drive
4684
+ // the enrollment wizard (never ask the user to paste a token). Mirrored to
4685
+ // the shadows like every agent-facing capability.
4686
+ '**Subscription Pool (multi-account quota + auto-swap + enrollment)**',
4663
4687
  // Working-Set Handoff (WORKING-SET-HANDOFF-SPEC §3.7): the fetch reflex
4664
4688
  // (POST /coherence/fetch-working-set). A Codex/Gemini agent that never
4665
4689
  // learns it will tell the user the files "aren't on this machine"