@jingyi0605/codingns4dsh 0.2.1-rc.5 → 0.2.1-rc.7

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 (174) hide show
  1. package/README.en.md +4 -4
  2. package/README.md +5 -5
  3. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.d.ts +1 -1
  4. package/data/build/dist/bootstrap/dsh-peer-host-preboot-shim.js +1 -1
  5. package/data/build/dist/client/bundle.js +1550 -148
  6. package/data/build/dist/client/bundle.js.map +1 -1
  7. package/data/build/dist/client/cli-slots.js +2 -2
  8. package/data/build/dist/client/cli-slots.js.map +1 -1
  9. package/data/build/dist/client/client.delegate-command.js +3 -2
  10. package/data/build/dist/client/client.delegate-command.js.map +1 -1
  11. package/data/build/dist/client/client.magpie-model-tag.js +24 -8
  12. package/data/build/dist/client/client.magpie-model-tag.js.map +1 -1
  13. package/data/build/dist/client/client.native-workspace-store.js +26 -15
  14. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  15. package/data/build/dist/client/client.session-translation.js +25 -0
  16. package/data/build/dist/client/client.session-translation.js.map +1 -1
  17. package/data/build/dist/client/client.transport.js +224 -0
  18. package/data/build/dist/client/client.transport.js.map +1 -1
  19. package/data/build/dist/client/delegate-command.js +2 -1
  20. package/data/build/dist/client/delegate-command.js.map +1 -1
  21. package/data/build/dist/client/desktop-assistant.js +224 -0
  22. package/data/build/dist/client/features/index.d.ts +2 -1
  23. package/data/build/dist/client/features/index.d.ts.map +1 -1
  24. package/data/build/dist/client/features/index.js +3 -1
  25. package/data/build/dist/client/features/index.js.map +1 -1
  26. package/data/build/dist/client/features/magpie-management-page.d.ts +7 -3
  27. package/data/build/dist/client/features/magpie-management-page.d.ts.map +1 -1
  28. package/data/build/dist/client/features/magpie-management-page.js +142 -8
  29. package/data/build/dist/client/features/magpie-management-page.js.map +1 -1
  30. package/data/build/dist/client/features/workspace-mcp.d.ts +3 -0
  31. package/data/build/dist/client/features/workspace-mcp.d.ts.map +1 -0
  32. package/data/build/dist/client/features/workspace-mcp.js +320 -0
  33. package/data/build/dist/client/features/workspace-mcp.js.map +1 -0
  34. package/data/build/dist/client/locale.d.ts.map +1 -1
  35. package/data/build/dist/client/locale.js +180 -0
  36. package/data/build/dist/client/locale.js.map +1 -1
  37. package/data/build/dist/client/locales/magpie.d.ts.map +1 -1
  38. package/data/build/dist/client/locales/magpie.js +12 -0
  39. package/data/build/dist/client/locales/magpie.js.map +1 -1
  40. package/data/build/dist/client/locales/panels.d.ts.map +1 -1
  41. package/data/build/dist/client/locales/panels.js +18 -0
  42. package/data/build/dist/client/locales/panels.js.map +1 -1
  43. package/data/build/dist/client/locales/usage.d.ts.map +1 -1
  44. package/data/build/dist/client/locales/usage.js +14 -0
  45. package/data/build/dist/client/locales/usage.js.map +1 -1
  46. package/data/build/dist/client/magpie-model-tag.d.ts +4 -2
  47. package/data/build/dist/client/magpie-model-tag.d.ts.map +1 -1
  48. package/data/build/dist/client/magpie-model-tag.js +25 -8
  49. package/data/build/dist/client/magpie-model-tag.js.map +1 -1
  50. package/data/build/dist/client/native-model-translation-menu.d.ts +1 -0
  51. package/data/build/dist/client/native-model-translation-menu.d.ts.map +1 -1
  52. package/data/build/dist/client/native-model-translation-menu.js +2 -2
  53. package/data/build/dist/client/native-model-translation-menu.js.map +1 -1
  54. package/data/build/dist/client/session-translation-chat.d.ts.map +1 -1
  55. package/data/build/dist/client/session-translation-chat.js +6 -2
  56. package/data/build/dist/client/session-translation-chat.js.map +1 -1
  57. package/data/build/dist/client/settings-section.d.ts.map +1 -1
  58. package/data/build/dist/client/settings-section.js +6 -3
  59. package/data/build/dist/client/settings-section.js.map +1 -1
  60. package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
  61. package/data/build/dist/client/subscription-slot.js +104 -11
  62. package/data/build/dist/client/subscription-slot.js.map +1 -1
  63. package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.d.ts +18 -0
  64. package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.d.ts.map +1 -0
  65. package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.js +172 -0
  66. package/data/build/dist/dsh-capabilities/host/workspace-approval-adapter.js.map +1 -0
  67. package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.d.ts +28 -0
  68. package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.d.ts.map +1 -0
  69. package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.js +103 -0
  70. package/data/build/dist/dsh-capabilities/host/workspace-pending-questions-adapter.js.map +1 -0
  71. package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.d.ts +26 -0
  72. package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.d.ts.map +1 -0
  73. package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.js +86 -0
  74. package/data/build/dist/dsh-capabilities/host/workspace-session-control-adapter.js.map +1 -0
  75. package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
  76. package/data/build/dist/dsh-capabilities/matrix.js +17 -14
  77. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  78. package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
  79. package/data/build/dist/dsh-capabilities/routes.js +19 -10
  80. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  81. package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
  82. package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
  83. package/data/build/dist/dsh-capabilities/types.js.map +1 -1
  84. package/data/build/dist/host/cli-adapters/claude-model-options.d.ts.map +1 -1
  85. package/data/build/dist/host/cli-adapters/claude-model-options.js +13 -2
  86. package/data/build/dist/host/cli-adapters/claude-model-options.js.map +1 -1
  87. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  88. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +6 -2
  89. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  90. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  91. package/data/build/dist/host/cli-adapters/feature.js +12 -4
  92. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  93. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts +13 -2
  94. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts.map +1 -1
  95. package/data/build/dist/host/cli-adapters/magpie-usage.js +186 -14
  96. package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
  97. package/data/build/dist/host/dsh-runtime-version.d.ts.map +1 -1
  98. package/data/build/dist/host/dsh-runtime-version.js +4 -1
  99. package/data/build/dist/host/dsh-runtime-version.js.map +1 -1
  100. package/data/build/dist/host/features/index.d.ts +1 -0
  101. package/data/build/dist/host/features/index.d.ts.map +1 -1
  102. package/data/build/dist/host/features/index.js +3 -0
  103. package/data/build/dist/host/features/index.js.map +1 -1
  104. package/data/build/dist/host/features/workspace-mcp.d.ts +9 -0
  105. package/data/build/dist/host/features/workspace-mcp.d.ts.map +1 -0
  106. package/data/build/dist/host/features/workspace-mcp.js +197 -0
  107. package/data/build/dist/host/features/workspace-mcp.js.map +1 -0
  108. package/data/build/dist/host/index.d.ts.map +1 -1
  109. package/data/build/dist/host/index.js +6 -2
  110. package/data/build/dist/host/index.js.map +1 -1
  111. package/data/build/dist/host/native-session-bridge.d.ts +2 -0
  112. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  113. package/data/build/dist/host/native-session-bridge.js +30 -0
  114. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  115. package/data/build/dist/host/rpc.d.ts +4 -1
  116. package/data/build/dist/host/rpc.d.ts.map +1 -1
  117. package/data/build/dist/host/rpc.js +57 -9
  118. package/data/build/dist/host/rpc.js.map +1 -1
  119. package/data/build/dist/host/session-handle-eviction.d.ts +4 -2
  120. package/data/build/dist/host/session-handle-eviction.d.ts.map +1 -1
  121. package/data/build/dist/host/session-handle-eviction.js +10 -9
  122. package/data/build/dist/host/session-handle-eviction.js.map +1 -1
  123. package/data/build/dist/host/terminal/terminal-process-service.d.ts +22 -0
  124. package/data/build/dist/host/terminal/terminal-process-service.d.ts.map +1 -1
  125. package/data/build/dist/host/terminal/terminal-process-service.js +102 -0
  126. package/data/build/dist/host/terminal/terminal-process-service.js.map +1 -1
  127. package/data/build/dist/host/terminal/terminal-service.d.ts +5 -1
  128. package/data/build/dist/host/terminal/terminal-service.d.ts.map +1 -1
  129. package/data/build/dist/host/terminal/terminal-service.js +32 -0
  130. package/data/build/dist/host/terminal/terminal-service.js.map +1 -1
  131. package/data/build/dist/host/workspace-mcp/api-key-store.d.ts +16 -0
  132. package/data/build/dist/host/workspace-mcp/api-key-store.d.ts.map +1 -0
  133. package/data/build/dist/host/workspace-mcp/api-key-store.js +65 -0
  134. package/data/build/dist/host/workspace-mcp/api-key-store.js.map +1 -0
  135. package/data/build/dist/host/workspace-mcp/tools.d.ts +54 -0
  136. package/data/build/dist/host/workspace-mcp/tools.d.ts.map +1 -0
  137. package/data/build/dist/host/workspace-mcp/tools.js +800 -0
  138. package/data/build/dist/host/workspace-mcp/tools.js.map +1 -0
  139. package/data/build/dist/host/workspace-mcp/transport.d.ts +35 -0
  140. package/data/build/dist/host/workspace-mcp/transport.d.ts.map +1 -0
  141. package/data/build/dist/host/workspace-mcp/transport.js +575 -0
  142. package/data/build/dist/host/workspace-mcp/transport.js.map +1 -0
  143. package/data/build/dist/shared/contracts/cli-adapter.d.ts +2 -0
  144. package/data/build/dist/shared/contracts/cli-adapter.d.ts.map +1 -1
  145. package/data/build/dist/shared/contracts/errors.d.ts +2 -2
  146. package/data/build/dist/shared/contracts/errors.d.ts.map +1 -1
  147. package/data/build/dist/shared/contracts/errors.js +1 -1
  148. package/data/build/dist/shared/contracts/errors.js.map +1 -1
  149. package/data/build/dist/shared/contracts/magpie-management.d.ts +15 -1
  150. package/data/build/dist/shared/contracts/magpie-management.d.ts.map +1 -1
  151. package/data/build/dist/shared/contracts/session-translation.d.ts +4 -0
  152. package/data/build/dist/shared/contracts/session-translation.d.ts.map +1 -1
  153. package/data/build/dist/shared/contracts/session-translation.js +21 -0
  154. package/data/build/dist/shared/contracts/session-translation.js.map +1 -1
  155. package/data/build/dist/shared/contracts/subscription.d.ts +7 -0
  156. package/data/build/dist/shared/contracts/subscription.d.ts.map +1 -1
  157. package/data/build/dist/shared/contracts/subscription.js.map +1 -1
  158. package/data/build/dist/shared/contracts/terminal.d.ts +2 -0
  159. package/data/build/dist/shared/contracts/terminal.d.ts.map +1 -1
  160. package/data/build/dist/shared/contracts/version.d.ts +7 -7
  161. package/data/build/dist/shared/contracts/version.d.ts.map +1 -1
  162. package/data/build/dist/shared/contracts/version.js +11 -17
  163. package/data/build/dist/shared/contracts/version.js.map +1 -1
  164. package/data/build/dist/shared/index.d.ts +1 -1
  165. package/data/build/dist/shared/index.d.ts.map +1 -1
  166. package/data/build/dist/shared/index.js +1 -1
  167. package/data/build/dist/shared/index.js.map +1 -1
  168. package/package.json +3 -3
  169. package/profile/README.md +6 -6
  170. package/profile/package.json +3 -3
  171. package/profile/scripts/check-dsh-install.mjs +14 -1
  172. package/profile/version.json +2 -2
  173. package/scripts/check-dsh-install.mjs +14 -1
  174. package/version.json +2 -2
@@ -135,9 +135,12 @@ export class MagpieUsageService {
135
135
  if (id === null)
136
136
  return model;
137
137
  const record = metadata?.get(id);
138
- const enriched = record === undefined
138
+ const metadataModel = record === undefined
139
139
  ? model.source === 'magpie' ? model : { ...model, source: 'magpie' }
140
140
  : mergeMagpieModelMetadata(model, record);
141
+ const providerId = providerFromModel(id);
142
+ const enriched = providerId === null || metadataModel.magpieProviderId === providerId
143
+ ? metadataModel : { ...metadataModel, magpieProviderId: providerId };
141
144
  if (enriched === model)
142
145
  return model;
143
146
  groupChanged = true;
@@ -154,11 +157,13 @@ export class MagpieUsageService {
154
157
  .filter((id) => !existingModelIds.has(id))
155
158
  .map((id) => {
156
159
  const record = metadata?.get(id);
160
+ const providerId = providerFromModel(id);
157
161
  const model = {
158
162
  id,
159
163
  name: record?.name ?? agentCatalog.displayNames.get(id) ?? id,
160
164
  efforts: record?.efforts ?? [],
161
165
  source: 'magpie',
166
+ ...(providerId === null ? {} : { magpieProviderId: providerId }),
162
167
  };
163
168
  return record === undefined ? model : mergeMagpieModelMetadata(model, record);
164
169
  });
@@ -178,6 +183,31 @@ export class MagpieUsageService {
178
183
  }
179
184
  return changed ? { ...resolvedCatalog, groups } : resolvedCatalog;
180
185
  }
186
+ async updateAccountPolicy(input, signal) {
187
+ const update = readMagpieAccountPolicyUpdate(input);
188
+ const path = update.policy === 'credits' ? '/api/settings/codex-credits' : '/api/settings/codex-auto-reset';
189
+ const body = update.policy === 'credits'
190
+ ? { user: update.user, on: update.enabled }
191
+ : { user: update.user, on: update.enabled, when: update.policy };
192
+ const result = await this.requestWebJson(path, { method: 'POST', body }, signal);
193
+ if (!result.ok)
194
+ throw new Error('Magpie account policy update failed');
195
+ const settings = parseMagpieAccountPolicies(result.value);
196
+ if (settings === null || !magpieAccountPolicyMatches(settings, update)) {
197
+ throw new Error('Magpie account policy update could not be verified');
198
+ }
199
+ return update;
200
+ }
201
+ async resetCodexAccount(input, signal) {
202
+ const user = readMagpieAccountUser(input);
203
+ const result = await this.requestWebJson('/api/usage/codex-reset', {
204
+ method: 'POST',
205
+ body: { user },
206
+ }, signal);
207
+ if (!result.ok)
208
+ throw new Error('Magpie Codex reset failed');
209
+ return { outcome: normalizeMagpieResetOutcome(result.value) };
210
+ }
181
211
  /** Return an exact, CLI-confirmed Magpie model record for trusted Host use. */
182
212
  async readModelMetadata(adapterId, modelId, signal) {
183
213
  signal?.throwIfAborted();
@@ -204,16 +234,16 @@ export class MagpieUsageService {
204
234
  return parseMagpieContextResponse(response.value, options);
205
235
  }
206
236
  /** Read bounded, graph-ready usage and quota data through authenticated Magpie Web. */
207
- async readDashboard(period, signal) {
237
+ async readDashboard(period, signal, force = false) {
208
238
  signal?.throwIfAborted();
209
239
  const cached = this.dashboardCache.get(period);
210
- if (cached !== undefined) {
240
+ if (!force && cached !== undefined) {
211
241
  if (this.now() - cached.loadedAt >= MAGPIE_DASHBOARD_CACHE_TTL_MS) {
212
242
  void this.refreshDashboard(period).catch(() => undefined);
213
243
  }
214
244
  return cached.dashboard;
215
245
  }
216
- return this.refreshDashboard(period, signal);
246
+ return this.refreshDashboard(period, signal, force);
217
247
  }
218
248
  /** Stream cumulative dashboard snapshots as each independent Web API part is ready. */
219
249
  async *readDashboardStream(period, signal, force = false) {
@@ -233,22 +263,25 @@ export class MagpieUsageService {
233
263
  if (latest !== undefined)
234
264
  this.dashboardCache.set(period, { dashboard: latest, loadedAt: this.now() });
235
265
  }
236
- async refreshDashboard(period, signal) {
266
+ async refreshDashboard(period, signal, force = false) {
237
267
  const pending = this.dashboardRefreshes.get(period);
238
- if (pending !== undefined)
268
+ if (!force && pending !== undefined)
239
269
  return awaitWithSignal(pending, signal);
240
- const request = (async () => {
270
+ let request = null;
271
+ const task = (async () => {
241
272
  let latest;
242
273
  for await (const chunk of this.readDashboardNetwork(period, signal))
243
274
  latest = chunk.dashboard;
244
275
  if (latest === undefined)
245
276
  throw new Error('Magpie dashboard returned no snapshot');
246
- this.dashboardCache.set(period, { dashboard: latest, loadedAt: this.now() });
277
+ if (request !== null && this.dashboardRefreshes.get(period) === request)
278
+ this.dashboardCache.set(period, { dashboard: latest, loadedAt: this.now() });
247
279
  return latest;
248
280
  })().finally(() => {
249
- if (this.dashboardRefreshes.get(period) === request)
281
+ if (request !== null && this.dashboardRefreshes.get(period) === request)
250
282
  this.dashboardRefreshes.delete(period);
251
283
  });
284
+ request = task;
252
285
  this.dashboardRefreshes.set(period, request);
253
286
  return awaitWithSignal(request, signal);
254
287
  }
@@ -257,19 +290,23 @@ export class MagpieUsageService {
257
290
  let dashboard = emptyMagpieDashboard(period, capturedAt);
258
291
  let quotas = null;
259
292
  let logoLoad;
293
+ let settingsRead = false;
260
294
  const results = new Map([
261
295
  ['usage', this.timedDashboardRead('usage', () => this.readWebJson(`/api/usage?period=${magpieWebPeriod(period)}`, signal))],
262
296
  ['quotas', this.timedDashboardRead('quotas', () => this.readWebJson('/api/usage/quotas', signal))],
297
+ ['settings', this.timedDashboardRead('settings', () => this.readWebJson('/api/settings', signal))],
263
298
  ['history', this.timedDashboardRead('history', () => this.readWebJson('/api/usage/quotas/history?days=30', signal))],
264
299
  ]);
265
300
  const completed = new Map();
301
+ let policies = null;
266
302
  while (results.size > 0) {
267
303
  const result = await Promise.race(results.values());
268
304
  results.delete(result.part);
269
305
  const response = asRecord(result.value);
270
306
  const partOk = result.ok && response?.ok === true;
271
307
  const partValue = partOk ? response.value : undefined;
272
- completed.set(result.part, partOk);
308
+ if (result.part !== 'settings')
309
+ completed.set(result.part, partOk);
273
310
  if (result.part === 'usage') {
274
311
  const parsed = partOk ? parseMagpieDashboardUsage(partValue) : null;
275
312
  dashboard = {
@@ -286,10 +323,21 @@ export class MagpieUsageService {
286
323
  };
287
324
  }
288
325
  else if (result.part === 'quotas') {
289
- quotas = partOk ? parseMagpieQuotaCards(partValue) : null;
326
+ const parsedQuotas = partOk ? parseMagpieQuotaCards(partValue) : null;
327
+ quotas = parsedQuotas === null ? null : applyMagpieDashboardAccountPolicies(parsedQuotas, policies);
290
328
  dashboard = { ...dashboard, quotaStatus: quotas === null ? 'unavailable' : 'available', quotas: quotas ?? [] };
329
+ if (quotas !== null && settingsRead)
330
+ logoLoad = this.timedDashboardRead('quota-logos', () => this.attachQuotaLogos(quotas, signal)).then((logoResult) => logoResult.value);
331
+ }
332
+ else if (result.part === 'settings') {
333
+ settingsRead = true;
334
+ policies = partOk ? parseMagpieAccountPolicies(partValue) : null;
335
+ if (quotas !== null && policies !== null) {
336
+ quotas = applyMagpieDashboardAccountPolicies(quotas, policies);
337
+ dashboard = { ...dashboard, quotas };
338
+ }
291
339
  if (quotas !== null)
292
- logoLoad = this.timedDashboardRead('quota-logos', () => this.attachQuotaLogos(quotas, signal)).then((result) => result.value);
340
+ logoLoad = this.timedDashboardRead('quota-logos', () => this.attachQuotaLogos(quotas, signal)).then((logoResult) => logoResult.value);
293
341
  }
294
342
  else {
295
343
  const parsed = partOk ? parseMagpieQuotaHistory(partValue) : null;
@@ -469,10 +517,11 @@ export class MagpieUsageService {
469
517
  }
470
518
  async readFromWeb(agent, modelId, sessionId, magpieSessionId, fallbackSessionId, signal, includeRoute, allowPendingSession) {
471
519
  const capturedAt = new Date(this.now()).toISOString();
472
- const [usageResult, sessionResult, quotaResult] = await Promise.all([
520
+ const [usageResult, sessionResult, quotaResult, settingsResult] = await Promise.all([
473
521
  this.readWebJson('/api/usage?period=today', signal),
474
522
  this.readWebJson('/api/usage?period=all', signal),
475
523
  this.readWebJson('/api/usage/quotas', signal),
524
+ agent === 'codex' ? this.readWebJson('/api/settings', signal) : Promise.resolve({ ok: false }),
476
525
  ]);
477
526
  const aggregate = usageResult.ok ? readTotals(usageResult.value) : null;
478
527
  const primarySession = sessionResult.ok && magpieSessionId !== null
@@ -514,7 +563,9 @@ export class MagpieUsageService {
514
563
  : !canReadRoute || !routeHistoryValid
515
564
  ? 'unavailable'
516
565
  : 'no-route';
517
- const allQuotas = quotaResult.ok ? parseMagpieQuotas(quotaResult.value) : null;
566
+ const allQuotas = quotaResult.ok
567
+ ? applyMagpieAccountPolicies(parseMagpieQuotas(quotaResult.value), settingsResult.ok ? settingsResult.value : null)
568
+ : null;
518
569
  const routeProviders = [...new Set([
519
570
  providerFromRoute(route),
520
571
  ...routeHistory.map((record) => record.provider),
@@ -725,6 +776,20 @@ export class MagpieUsageService {
725
776
  return { ok: false };
726
777
  }
727
778
  }
779
+ async requestWebJson(path, options, signal) {
780
+ if (this.webApi === undefined)
781
+ return { ok: false };
782
+ try {
783
+ return {
784
+ ok: true,
785
+ value: await this.webApi.requestJson(path, signal === undefined ? options : { ...options, signal }),
786
+ };
787
+ }
788
+ catch {
789
+ signal?.throwIfAborted();
790
+ return { ok: false };
791
+ }
792
+ }
728
793
  /** Provider management data is the canonical source when a usage row mislabels its upstream. */
729
794
  async readProviderCatalog(signal) {
730
795
  const cached = this.providerCatalog;
@@ -1390,6 +1455,113 @@ export function parseMagpieQuotas(value) {
1390
1455
  }
1391
1456
  return quotas;
1392
1457
  }
1458
+ function parseMagpieAccountPolicies(value) {
1459
+ const root = asRecord(value);
1460
+ if (root === null)
1461
+ return null;
1462
+ const autoResetUsers = readLowercaseSet(root.codexAutoReset, 500);
1463
+ const noCreditsUsers = readLowercaseSet(root.codexNoCredits, 500);
1464
+ const autoResetOnly = new Map();
1465
+ const only = asRecord(root.codexAutoResetOnly);
1466
+ if (only !== null) {
1467
+ for (const [user, value] of Object.entries(only).slice(0, 500)) {
1468
+ if (value === 'week' || value === 'expiring')
1469
+ autoResetOnly.set(user.toLocaleLowerCase(), value);
1470
+ }
1471
+ }
1472
+ if (autoResetUsers === null || noCreditsUsers === null)
1473
+ return null;
1474
+ return { autoResetUsers, autoResetOnly, noCreditsUsers };
1475
+ }
1476
+ function applyMagpieAccountPolicies(quotas, settingsValue) {
1477
+ if (quotas === null)
1478
+ return null;
1479
+ const settings = parseMagpieAccountPolicies(settingsValue);
1480
+ if (settings === null)
1481
+ return quotas;
1482
+ return quotas.map((quota) => {
1483
+ if (quota.provider.toLocaleLowerCase() !== 'codex' || quota.user === null)
1484
+ return quota;
1485
+ const user = quota.user.toLocaleLowerCase();
1486
+ const enabled = settings.autoResetUsers.has(user);
1487
+ const only = settings.autoResetOnly.get(user);
1488
+ return {
1489
+ ...quota,
1490
+ autoReset: {
1491
+ week: enabled && only !== 'expiring',
1492
+ expiring: enabled && only !== 'week',
1493
+ },
1494
+ useCredits: !settings.noCreditsUsers.has(user),
1495
+ };
1496
+ });
1497
+ }
1498
+ function applyMagpieDashboardAccountPolicies(quotas, settings) {
1499
+ return quotas.map((quota) => {
1500
+ if (quota.provider.toLocaleLowerCase() !== 'codex' || quota.user === null)
1501
+ return quota;
1502
+ if (settings === null)
1503
+ return { ...quota, policyStatus: 'unavailable' };
1504
+ const user = quota.user.toLocaleLowerCase();
1505
+ const enabled = settings.autoResetUsers.has(user);
1506
+ const only = settings.autoResetOnly.get(user);
1507
+ return {
1508
+ ...quota,
1509
+ autoReset: {
1510
+ week: enabled && only !== 'expiring',
1511
+ expiring: enabled && only !== 'week',
1512
+ },
1513
+ useCredits: !settings.noCreditsUsers.has(user),
1514
+ policyStatus: 'available',
1515
+ };
1516
+ });
1517
+ }
1518
+ function readLowercaseSet(value, maxItems) {
1519
+ if (value === undefined)
1520
+ return new Set();
1521
+ if (!Array.isArray(value) || value.length > maxItems)
1522
+ return null;
1523
+ const values = value.filter((item) => typeof item === 'string' && item.trim() !== '');
1524
+ return values.length === value.length
1525
+ ? new Set(values.map((item) => item.trim().toLocaleLowerCase()))
1526
+ : null;
1527
+ }
1528
+ function readMagpieAccountUser(value) {
1529
+ const record = asRecord(value);
1530
+ const user = typeof record?.user === 'string' ? record.user.trim() : '';
1531
+ if (user === '' || user.length > 180)
1532
+ throw new TypeError('Magpie account user is invalid');
1533
+ return user;
1534
+ }
1535
+ function readMagpieAccountPolicyUpdate(value) {
1536
+ const record = asRecord(value);
1537
+ const user = readMagpieAccountUser(value);
1538
+ const policy = record?.policy;
1539
+ if (policy !== 'week' && policy !== 'expiring' && policy !== 'credits') {
1540
+ throw new TypeError('Magpie account policy is invalid');
1541
+ }
1542
+ if (typeof record?.enabled !== 'boolean')
1543
+ throw new TypeError('Magpie account policy state is invalid');
1544
+ return { user, policy, enabled: record.enabled };
1545
+ }
1546
+ function magpieAccountPolicyMatches(settings, update) {
1547
+ const user = update.user.toLocaleLowerCase();
1548
+ if (update.policy === 'credits')
1549
+ return settings.noCreditsUsers.has(user) !== update.enabled;
1550
+ const enabled = settings.autoResetUsers.has(user);
1551
+ const only = settings.autoResetOnly.get(user);
1552
+ const current = update.policy === 'week'
1553
+ ? enabled && only !== 'expiring'
1554
+ : enabled && only !== 'week';
1555
+ return current === update.enabled;
1556
+ }
1557
+ function normalizeMagpieResetOutcome(value) {
1558
+ const record = asRecord(value);
1559
+ const outcome = record?.code ?? record?.outcome;
1560
+ if (outcome === 'reset' || outcome === 'alreadyRedeemed' || outcome === 'nothingToReset' || outcome === 'noCredit') {
1561
+ return outcome;
1562
+ }
1563
+ throw new Error('Magpie returned an unknown reset result');
1564
+ }
1393
1565
  /** Normalize the live aggregate and per-dimension usage response. */
1394
1566
  export function parseMagpieDashboardUsage(value) {
1395
1567
  const root = asRecord(value);