@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
@@ -92,6 +92,12 @@ export function MagpieManagementPage({ rpc, locale, initialPageTab = 'overview',
92
92
  const [dashboardLoading, setDashboardLoading] = useState(true);
93
93
  const [dashboardError, setDashboardError] = useState(false);
94
94
  const [dashboardIssue, setDashboardIssue] = useState(null);
95
+ const [quotaPolicyPending, setQuotaPolicyPending] = useState(null);
96
+ const [quotaPolicyFailed, setQuotaPolicyFailed] = useState(false);
97
+ const [quotaResetTarget, setQuotaResetTarget] = useState(null);
98
+ const [quotaResetPending, setQuotaResetPending] = useState(false);
99
+ const [quotaResetResult, setQuotaResetResult] = useState(null);
100
+ const [quotaResetFailed, setQuotaResetFailed] = useState(false);
95
101
  const [chartMetric, setChartMetric] = useState('calls');
96
102
  const [sessionSearch, setSessionSearch] = useState('');
97
103
  const [selectedSession, setSelectedSession] = useState(null);
@@ -114,14 +120,14 @@ export function MagpieManagementPage({ rpc, locale, initialPageTab = 'overview',
114
120
  const dashboardSequence = useRef(0);
115
121
  const requestSequence = useRef(0);
116
122
  const managementSequence = useRef(0);
117
- const loadDashboard = useCallback(async (signal) => {
123
+ const loadDashboard = useCallback(async (signal, force = false) => {
118
124
  const sequence = dashboardSequence.current + 1;
119
125
  dashboardSequence.current = sequence;
120
126
  setDashboardLoading(true);
121
127
  setDashboardError(false);
122
128
  setDashboardIssue(null);
123
129
  try {
124
- const next = await callMagpieRpc(rpc, 'usage/dashboard', { period }, signal);
130
+ const next = await callMagpieRpc(rpc, 'usage/dashboard', { period, ...(force ? { force: true } : {}) }, signal);
125
131
  if (signal.aborted || sequence !== dashboardSequence.current)
126
132
  return;
127
133
  setDashboard(next);
@@ -141,6 +147,47 @@ export function MagpieManagementPage({ rpc, locale, initialPageTab = 'overview',
141
147
  setDashboardLoading(false);
142
148
  }
143
149
  }, [period, rpc]);
150
+ const updateQuotaPolicy = useCallback(async (user, policy, enabled) => {
151
+ if (quotaPolicyPending !== null)
152
+ return;
153
+ setQuotaPolicyPending(`${user}:${policy}`);
154
+ setQuotaPolicyFailed(false);
155
+ try {
156
+ await callMagpieRpc(rpc, 'usage/account/update', { user, policy, enabled });
157
+ await loadDashboard(new AbortController().signal, true);
158
+ }
159
+ catch {
160
+ setQuotaPolicyFailed(true);
161
+ }
162
+ finally {
163
+ setQuotaPolicyPending(null);
164
+ }
165
+ }, [loadDashboard, quotaPolicyPending, rpc]);
166
+ const closeQuotaReset = () => {
167
+ if (quotaResetPending)
168
+ return;
169
+ setQuotaResetTarget(null);
170
+ setQuotaResetResult(null);
171
+ setQuotaResetFailed(false);
172
+ };
173
+ const confirmQuotaReset = async () => {
174
+ const target = quotaResetTarget;
175
+ if (target === null || quotaResetPending)
176
+ return;
177
+ setQuotaResetPending(true);
178
+ setQuotaResetFailed(false);
179
+ try {
180
+ const result = await callMagpieRpc(rpc, 'usage/reset', { user: target.user });
181
+ setQuotaResetResult(result.outcome);
182
+ await loadDashboard(new AbortController().signal, true);
183
+ }
184
+ catch {
185
+ setQuotaResetFailed(true);
186
+ }
187
+ finally {
188
+ setQuotaResetPending(false);
189
+ }
190
+ };
144
191
  useEffect(() => {
145
192
  const controller = new AbortController();
146
193
  void loadDashboard(controller.signal);
@@ -456,7 +503,28 @@ export function MagpieManagementPage({ rpc, locale, initialPageTab = 'overview',
456
503
  ? createElement(SessionsPage, { dashboard, sessions: filteredSessions, search: sessionSearch, onSearch: setSessionSearch, onOpenSession: openSession, t })
457
504
  : section === 'requests'
458
505
  ? createElement(RequestsPage, { page: requestPage, loading: requestLoading, error: requestError, selectedSession, offset: requestOffset, onOffsetChange: setRequestOffset, onClearSession: clearSession, t })
459
- : createElement(QuotasPage, { dashboard, loading: dashboardLoading, quotaView, t })));
506
+ : createElement(QuotasPage, {
507
+ dashboard, loading: dashboardLoading, quotaView, t,
508
+ policyPending: quotaPolicyPending,
509
+ policyFailed: quotaPolicyFailed,
510
+ onPolicyChange: updateQuotaPolicy,
511
+ onResetRequest: (quota) => {
512
+ if (quota.user === null || quota.resets?.count === null || quota.resets?.count === undefined || quota.resets.count <= 0)
513
+ return;
514
+ setQuotaResetTarget({ user: quota.user, account: quota.alias ?? quota.name, count: quota.resets.count });
515
+ setQuotaResetResult(null);
516
+ setQuotaResetFailed(false);
517
+ },
518
+ })), quotaResetTarget !== null && createElement(MagpieQuotaResetDialog, {
519
+ target: quotaResetTarget,
520
+ pending: quotaResetPending,
521
+ result: quotaResetResult,
522
+ failed: quotaResetFailed,
523
+ t,
524
+ onCancel: closeQuotaReset,
525
+ onConfirm: confirmQuotaReset,
526
+ onClose: closeQuotaReset,
527
+ }));
460
528
  }
461
529
  export function OverviewPage({ dashboard, loading, error, chartMetric, onChartMetricChange, t, onOpenSession }) {
462
530
  const [modelBreakdownMode, setModelBreakdownMode] = useState('aggregate');
@@ -761,7 +829,7 @@ function QuotaViewIcon() {
761
829
  className: 'codingns-magpie-quota-view-icon-svg',
762
830
  }, createElement('circle', { cx: 8, cy: 8, r: 6.25, stroke: 'currentColor', strokeWidth: 1.5, opacity: 0.45 }), createElement('path', { d: 'M8 1.75a6.25 6.25 0 0 1 0 12.5z', fill: 'currentColor' }));
763
831
  }
764
- export function QuotasPage({ dashboard, loading, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTINGS.quotaView, t }) {
832
+ export function QuotasPage({ dashboard, loading, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTINGS.quotaView, t, policyPending = null, policyFailed = false, onPolicyChange = () => undefined, onResetRequest = () => undefined }) {
765
833
  const quotaUnavailable = dashboard?.quotaStatus !== 'available';
766
834
  const quotas = dashboard?.quotas ?? [];
767
835
  const quotaHistory = dashboard?.quotaHistory ?? [];
@@ -769,7 +837,9 @@ export function QuotasPage({ dashboard, loading, quotaView = DEFAULT_SUBSCRIPTIO
769
837
  ? createElement(EmptyState, { message: t(dashboard === null && loading ? 'magpie.loading' : 'magpie.quotaUnavailable'), loading: dashboard === null && loading })
770
838
  : quotas.length === 0
771
839
  ? createElement(EmptyState, { message: t('magpie.noQuotas') })
772
- : createElement('div', { className: 'codingns-magpie-quota-grid' }, ...groupQuotaRowsByProvider(quotas).map((group) => createElement(QuotaGroupCard, { key: group.provider, group, quotaView, t }))), createElement('section', { className: 'codingns-magpie-panel codingns-magpie-history-panel' }, createElement('div', { className: 'codingns-magpie-panel-head' }, createElement('div', undefined, createElement('h2', undefined, t('magpie.quotaHistory')), createElement('p', undefined, t('magpie.quotaHistoryNote')))), quotaHistory.length === 0
840
+ : createElement('div', { className: 'codingns-magpie-quota-grid' }, ...groupQuotaRowsByProvider(quotas).map((group) => createElement(QuotaGroupCard, {
841
+ key: group.provider, group, quotaView, t, policyPending, policyFailed, onPolicyChange, onResetRequest,
842
+ }))), createElement('section', { className: 'codingns-magpie-panel codingns-magpie-history-panel' }, createElement('div', { className: 'codingns-magpie-panel-head' }, createElement('div', undefined, createElement('h2', undefined, t('magpie.quotaHistory')), createElement('p', undefined, t('magpie.quotaHistoryNote')))), quotaHistory.length === 0
773
843
  ? createElement('div', { className: 'codingns-magpie-inline-empty' }, t(dashboard === null && loading ? 'magpie.loading' : dashboard?.quotaHistoryStatus === 'available' ? 'magpie.noHistory' : 'magpie.historyUnavailable'))
774
844
  : createElement('div', { className: 'codingns-magpie-history-grid' }, ...quotaHistory.map((history) => createElement(QuotaHistoryCard, { key: `${history.provider}:${history.user ?? ''}`, history })))));
775
845
  }
@@ -815,7 +885,7 @@ function ProgressSection({ title, rows, t, onOpen, header, limit = 8 }) {
815
885
  * 同一厂商的多个账号(如 WorkBuddy 的 4 个)共用一张卡,避免每个账号各占一张卡导致
816
886
  * 同类账号被拆散在网格各处;单账号厂商的读法与改造前一致。
817
887
  */
818
- function QuotaGroupCard({ group, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTINGS.quotaView, t }) {
888
+ function QuotaGroupCard({ group, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTINGS.quotaView, t, policyPending, policyFailed, onPolicyChange, onResetRequest }) {
819
889
  const first = group.accounts[0];
820
890
  // 默认展开:只有用户主动收起后才是折叠态。
821
891
  const [collapsed, setCollapsed] = useState(false);
@@ -835,6 +905,10 @@ function QuotaGroupCard({ group, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTING
835
905
  quota,
836
906
  quotaView,
837
907
  t,
908
+ policyPending,
909
+ policyFailed,
910
+ onPolicyChange,
911
+ onResetRequest,
838
912
  // 单账号时不重复显示账号段头,保持与改造前一致的读法。
839
913
  showHeading: multi,
840
914
  })));
@@ -846,13 +920,15 @@ function QuotaGroupCard({ group, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTING
846
920
  * Sub2api 的钱包余额、按积分计量的 WorkBuddy)单独显示余额行,与 Magpie 原生卡片
847
921
  * 一致——过去这些账号只剩一条空进度条,余额被完全藏起来。
848
922
  */
849
- function QuotaAccountSection({ quota, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTINGS.quotaView, t, showHeading }) {
923
+ function QuotaAccountSection({ quota, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SETTINGS.quotaView, t, showHeading, policyPending, policyFailed, onPolicyChange, onResetRequest }) {
850
924
  // `daily` 现在带 `since`,按日点位于 `days` 里。
851
925
  const dailyValues = quota.daily.days.map((point) => point.used).filter((value) => value !== null);
852
926
  const balance = resolveQuotaAccountBalance(quota);
853
927
  // 只有真正带百分比的窗口才画进度条;纯金额窗口在余额行里已经有完整读法。
854
928
  const percentWindows = quota.windows.filter((window) => window.usedPercent !== null || window.remainingPercent !== null);
855
- return createElement('div', { className: 'codingns-magpie-quota-account-block' }, showHeading && createElement('div', { className: 'codingns-magpie-quota-account-head' }, createElement('strong', undefined, quota.alias ?? quota.name), quota.user !== null && createElement('span', undefined, t('magpie.account', { account: quota.user })), quota.plan !== null && createElement('small', undefined, quota.plan)), !showHeading && quota.user !== null && createElement('div', { className: 'codingns-magpie-quota-account' }, t('magpie.account', { account: quota.user })), balance !== null && createElement('div', { className: 'codingns-magpie-quota-balance' }, createElement('span', { className: 'codingns-magpie-quota-balance-label' }, t('magpie.balance')), createElement('strong', { className: balance.money ? 'codingns-magpie-quota-balance-value is-money' : 'codingns-magpie-quota-balance-value', title: balance.raw }, balance.text)), quota.windows.length === 0
929
+ return createElement('div', { className: 'codingns-magpie-quota-account-block' }, showHeading && createElement('div', { className: 'codingns-magpie-quota-account-head' }, createElement('strong', undefined, quota.alias ?? quota.name), quota.user !== null && createElement('span', undefined, t('magpie.account', { account: quota.user })), quota.plan !== null && createElement('small', undefined, quota.plan)), !showHeading && quota.user !== null && createElement('div', { className: 'codingns-magpie-quota-account' }, t('magpie.account', { account: quota.user })), quota.provider.toLocaleLowerCase() === 'codex' && createElement(MagpieQuotaControls, {
930
+ quota, t, policyPending, policyFailed, onPolicyChange, onResetRequest,
931
+ }), balance !== null && createElement('div', { className: 'codingns-magpie-quota-balance' }, createElement('span', { className: 'codingns-magpie-quota-balance-label' }, t('magpie.balance')), createElement('strong', { className: balance.money ? 'codingns-magpie-quota-balance-value is-money' : 'codingns-magpie-quota-balance-value', title: balance.raw }, balance.text)), quota.windows.length === 0
856
932
  ? balance === null && createElement('div', { className: 'codingns-magpie-inline-empty' }, t('magpie.noLimit'))
857
933
  : percentWindows.length > 0 && percentWindows.map((window) => {
858
934
  const used = window.usedPercent ?? (window.remainingPercent === null ? null : 100 - window.remainingPercent);
@@ -870,6 +946,57 @@ function QuotaAccountSection({ quota, quotaView = DEFAULT_SUBSCRIPTION_REPORT_SE
870
946
  // 有余额但没有百分比的账号,把重置时间单独留在余额下面。
871
947
  balance !== null && percentWindows.length === 0 && quota.windows.some((window) => window.resetsAt !== null) && createElement('div', { className: 'codingns-magpie-quota-foot' }, ...quota.windows.filter((window) => window.resetsAt !== null).map((window) => createElement('span', { key: window.name }, t('magpie.resets', { time: formatTimestamp(window.resetsAt) })))), quota.daily.days.length > 1 && createElement('div', { className: 'codingns-magpie-daily-chart' }, createElement(Sparkline, { values: dailyValues }), createElement('small', undefined, t('magpie.dailyUsage'))));
872
948
  }
949
+ function MagpieQuotaControls({ quota, t, policyPending, policyFailed, onPolicyChange, onResetRequest }) {
950
+ const user = quota.user;
951
+ const resetCount = quota.resets?.count;
952
+ const policyUnavailable = user === null || quota.policyStatus === 'unavailable'
953
+ || quota.autoReset === undefined || quota.useCredits === undefined;
954
+ return createElement('div', { className: 'codingns-magpie-codex-controls' }, createElement('div', { className: 'codingns-magpie-codex-reset-count' }, createElement('span', undefined, t('usage.magpieResetCountLabel')), createElement('strong', undefined, resetCount === null || resetCount === undefined ? '—' : t('usage.magpieResetCount', { count: resetCount }))), policyUnavailable
955
+ ? createElement('div', { className: 'codingns-magpie-codex-unavailable', role: 'status' }, t('magpie.codexPolicyUnavailable'))
956
+ : quota.autoReset !== undefined && createElement(MagpieQuotaPolicySwitch, {
957
+ label: t('usage.magpieResetWhenWeek'), checked: quota.autoReset.week,
958
+ pending: policyPending === `${user}:week`, disabled: policyPending !== null,
959
+ onChange: (enabled) => onPolicyChange(user, 'week', enabled),
960
+ }), !policyUnavailable && quota.autoReset !== undefined && createElement(MagpieQuotaPolicySwitch, {
961
+ label: t('usage.magpieResetBeforeExpiry'), checked: quota.autoReset.expiring,
962
+ pending: policyPending === `${user}:expiring`, disabled: policyPending !== null,
963
+ onChange: (enabled) => onPolicyChange(user, 'expiring', enabled),
964
+ }), !policyUnavailable && quota.useCredits !== undefined && createElement(MagpieQuotaPolicySwitch, {
965
+ label: t('usage.magpieUseCredits'), checked: quota.useCredits,
966
+ pending: policyPending === `${user}:credits`, disabled: policyPending !== null,
967
+ onChange: (enabled) => onPolicyChange(user, 'credits', enabled),
968
+ }), policyFailed && createElement('div', { className: 'codingns-magpie-codex-error', role: 'alert' }, t('magpie.codexPolicyFailed')), user !== null && resetCount !== null && resetCount !== undefined && createElement('button', {
969
+ type: 'button',
970
+ className: 'codingns-magpie-codex-reset-button',
971
+ disabled: resetCount <= 0,
972
+ onClick: () => onResetRequest(quota),
973
+ }, t('usage.magpieUseReset')));
974
+ }
975
+ function MagpieQuotaPolicySwitch({ label, checked, pending, disabled, onChange }) {
976
+ return createElement('button', {
977
+ type: 'button', role: 'switch', 'aria-checked': checked, disabled,
978
+ 'aria-busy': pending,
979
+ className: 'codingns-magpie-codex-policy',
980
+ onClick: () => onChange(!checked),
981
+ }, createElement('span', undefined, label), createElement('span', { className: `codingns-magpie-codex-switch${checked ? ' is-on' : ''}` }, createElement('span')));
982
+ }
983
+ function MagpieQuotaResetDialog({ target, pending, result, failed, t, onCancel, onConfirm, onClose }) {
984
+ const finished = result !== null || failed;
985
+ const outcomeKeys = {
986
+ reset: 'usage.resetOutcomeReset',
987
+ alreadyRedeemed: 'usage.resetOutcomeAlreadyRedeemed',
988
+ nothingToReset: 'usage.resetOutcomeNothingToReset',
989
+ noCredit: 'usage.resetOutcomeNoCredit',
990
+ };
991
+ const outcomeMessage = result === null ? null : t(outcomeKeys[result]);
992
+ return createElement('div', {
993
+ className: 'codingns-magpie-codex-reset-overlay', role: 'presentation',
994
+ onMouseDown: (event) => { if (event.target === event.currentTarget && !pending)
995
+ onCancel(); },
996
+ }, createElement('div', { className: 'codingns-magpie-codex-reset-dialog', role: 'dialog', 'aria-modal': true, 'aria-label': t('usage.resetDialogTitle') }, createElement('strong', undefined, t('usage.resetDialogTitle')), createElement('span', undefined, t('magpie.resetDialogAccount', { account: target.account })), createElement('span', { className: failed ? 'is-error' : result === 'reset' || result === 'alreadyRedeemed' ? 'is-success' : '' }, pending ? t('usage.resetDialogPending') : failed ? t('magpie.codexResetFailed') : outcomeMessage ?? t('magpie.resetDialogBody', { count: target.count })), createElement('div', { className: 'codingns-magpie-codex-reset-actions' }, finished
997
+ ? createElement('button', { type: 'button', onClick: onClose }, t('usage.resetDialogClose'))
998
+ : createElement('button', { type: 'button', disabled: pending, onClick: onCancel }, t('usage.resetDialogCancel')), !finished && createElement('button', { type: 'button', disabled: pending, onClick: onConfirm }, t('usage.resetDialogConfirm')))));
999
+ }
873
1000
  function QuotaHistoryCard({ history }) {
874
1001
  return createElement('div', { className: 'codingns-magpie-history-card' }, createElement('div', { className: 'codingns-magpie-provider-inline' }, createElement(MagpieProviderLogo, { identities: [history.provider], size: 22, className: 'codingns-magpie-provider-logo codingns-magpie-provider-logo-compact', fallback: 'none' }), createElement('strong', undefined, history.provider)), history.user !== null && createElement('small', undefined, history.user), ...history.lines.map((line) => createElement('div', { key: line.name, className: 'codingns-magpie-history-line' }, createElement('div', { className: 'codingns-magpie-history-line-head' }, createElement('span', undefined, line.name), createElement('span', undefined, line.points.at(-1)?.left === null || line.points.at(-1)?.left === undefined ? '—' : formatValue(line.points.at(-1).left))), createElement(Sparkline, { values: line.points.map((point) => point.left).filter((value) => value !== null) }))));
875
1002
  }
@@ -1137,6 +1264,13 @@ const MAGPIE_PAGE_CSS = `
1137
1264
  .codingns-magpie-quota-balance-label{flex:0 0 auto;color:var(--mp-muted);font-size:${uiFontSize(13)}}
1138
1265
  .codingns-magpie-quota-balance-value{min-width:0;overflow:hidden;color:var(--mp-ink);font-size:${uiFontSize(15)};font-weight:600;font-variant-numeric:tabular-nums;text-overflow:ellipsis;white-space:nowrap}
1139
1266
  .codingns-magpie-quota-balance-value.is-money{font-size:${uiFontSize(17)};letter-spacing:-.01em}
1267
+ .codingns-magpie-codex-controls{display:grid;gap:2px;margin:9px 0 10px;padding:8px 10px;border-top:.5px solid var(--mp-line);border-bottom:.5px solid var(--mp-line);background:color-mix(in srgb,var(--mp-layer) 45%,transparent)}
1268
+ .codingns-magpie-codex-reset-count{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0;padding:2px 0 5px;color:var(--mp-muted);font-size:${uiFontSize(12)}}.codingns-magpie-codex-reset-count strong{color:var(--mp-ink);font-size:${uiFontSize(13)};font-variant-numeric:tabular-nums}
1269
+ .codingns-magpie-codex-policy{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-width:0;min-height:32px;padding:4px 0;border:0;background:transparent;color:var(--mp-muted);font:inherit;font-size:${uiFontSize(12)};text-align:left;cursor:pointer}.codingns-magpie-codex-policy>span:first-child{min-width:0;line-height:1.4;overflow-wrap:anywhere}.codingns-magpie-codex-policy:disabled{opacity:.58;cursor:wait}.codingns-magpie-codex-policy:focus-visible,.codingns-magpie-codex-reset-button:focus-visible{outline:2px solid color-mix(in srgb,var(--mp-accent) 60%,transparent);outline-offset:2px}
1270
+ .codingns-magpie-codex-switch{display:grid;place-items:center;flex:0 0 34px;width:34px;height:20px;padding:2px;border-radius:999px;background:var(--mp-line-strong);transition:background .15s}.codingns-magpie-codex-switch>span{justify-self:start;width:16px;height:16px;border-radius:50%;background:var(--mp-surface);box-shadow:0 1px 2px rgba(0,0,0,.18);transition:transform .15s}.codingns-magpie-codex-switch.is-on{background:var(--mp-accent)}.codingns-magpie-codex-switch.is-on>span{transform:translateX(14px)}
1271
+ .codingns-magpie-codex-unavailable,.codingns-magpie-codex-error{padding:5px 0;color:var(--mp-caption);font-size:${uiFontSize(12)}}.codingns-magpie-codex-error{color:var(--dsw-alias-state-error-primary,#c54b4b)}
1272
+ .codingns-magpie-codex-reset-button{justify-self:start;min-height:27px;margin-top:4px;padding:0 9px;border:.5px solid var(--mp-line-strong);border-radius:var(--dsw-radius-sm,6px);background:transparent;color:var(--mp-ink);font:inherit;font-size:${uiFontSize(12)};cursor:pointer}.codingns-magpie-codex-reset-button:hover:not(:disabled){border-color:var(--mp-accent);color:var(--mp-accent)}.codingns-magpie-codex-reset-button:disabled{opacity:.45;cursor:not-allowed}
1273
+ .codingns-magpie-codex-reset-overlay{position:absolute;inset:0;z-index:30;display:flex;align-items:center;justify-content:center;overflow:auto;padding:20px;background:color-mix(in srgb,var(--mp-surface) 70%,rgba(0,0,0,.3));backdrop-filter:blur(2px)}.codingns-magpie-codex-reset-dialog{display:grid;gap:10px;width:min(420px,100%);padding:16px;border:.5px solid var(--mp-line-strong);border-radius:var(--mp-radius);background:var(--mp-surface);box-shadow:var(--dsw-elevation-prominent,0 16px 44px rgba(0,0,0,.2));font-size:${uiFontSize(13)};line-height:1.5}.codingns-magpie-codex-reset-dialog>strong{font-size:${uiFontSize(14)}}.codingns-magpie-codex-reset-dialog>span{color:var(--mp-muted);overflow-wrap:anywhere}.codingns-magpie-codex-reset-dialog>span.is-error{color:var(--dsw-alias-state-error-primary,#c54b4b)}.codingns-magpie-codex-reset-dialog>span.is-success{color:var(--dsw-alias-state-success-primary,#3f9d6b)}.codingns-magpie-codex-reset-actions{display:flex;justify-content:flex-end;gap:8px;padding-top:3px}.codingns-magpie-codex-reset-actions button{min-height:30px;padding:0 11px;border:.5px solid var(--mp-line-strong);border-radius:var(--dsw-radius-sm,6px);background:transparent;color:var(--mp-ink);font:inherit;font-size:${uiFontSize(12)};cursor:pointer}.codingns-magpie-codex-reset-actions button:last-child{border-color:var(--mp-accent);background:var(--mp-accent);color:var(--dsw-alias-label-primary-foreground,#fff)}.codingns-magpie-codex-reset-actions button:disabled{opacity:.5;cursor:wait}
1140
1274
  .codingns-magpie-quota-window{padding:11px 0;border-top:.5px solid var(--mp-line)}.codingns-magpie-quota-window-head,.codingns-magpie-quota-foot,.codingns-magpie-history-line-head{display:flex;align-items:center;justify-content:space-between;gap:9px}.codingns-magpie-quota-window-head{font-size:${uiFontSize(13)};font-weight:500}.codingns-magpie-quota-window-head span{color:var(--mp-muted);font-variant-numeric:tabular-nums}.quota-track{height:6px}.quota-track span{background:linear-gradient(90deg,var(--mp-accent),color-mix(in srgb,var(--mp-accent) 55%,transparent))}.codingns-magpie-quota-foot{color:var(--mp-caption);font-size:${uiFontSize(12)}}
1141
1275
  .codingns-magpie-daily-chart{display:grid;grid-template-columns:1fr auto;align-items:center;gap:9px;margin-top:4px;padding-top:10px;border-top:.5px solid var(--mp-line);color:var(--mp-muted);font-size:${uiFontSize(12)}}.codingns-magpie-sparkline{width:100%;height:30px;overflow:visible}.codingns-magpie-sparkline polyline{stroke:var(--mp-accent);stroke-width:2;vector-effect:non-scaling-stroke}
1142
1276
  .codingns-magpie-history-panel{padding:17px;margin-top:14px}.codingns-magpie-history-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.codingns-magpie-history-card{padding:12px;border:1px solid var(--mp-line);border-radius:9px;background:var(--mp-card)}.codingns-magpie-history-card>strong,.codingns-magpie-history-card>small{display:block}.codingns-magpie-history-card>strong{font-size:${uiFontSize(13)};font-weight:600}.codingns-magpie-history-card>small{margin-top:3px;color:var(--mp-caption);font-size:${uiFontSize(12)}}.codingns-magpie-history-line{margin-top:10px}.codingns-magpie-history-line-head{font-size:${uiFontSize(12)}}.codingns-magpie-history-line-head span:last-child{font-variant-numeric:tabular-nums;font-weight:650}