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

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 (220) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +3 -3
  3. package/data/build/dist/client/bundle.js +1838 -223
  4. package/data/build/dist/client/bundle.js.map +1 -1
  5. package/data/build/dist/client/cli-session-config-cache.d.ts.map +1 -1
  6. package/data/build/dist/client/cli-session-config-cache.js +9 -3
  7. package/data/build/dist/client/cli-session-config-cache.js.map +1 -1
  8. package/data/build/dist/client/client.native-workspace-store.js +7 -1
  9. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  10. package/data/build/dist/client/client.transport.js +276 -60
  11. package/data/build/dist/client/client.transport.js.map +1 -1
  12. package/data/build/dist/client/desktop-assistant.js +274 -58
  13. package/data/build/dist/client/features/cli-adapters.d.ts.map +1 -1
  14. package/data/build/dist/client/features/cli-adapters.js +13 -1
  15. package/data/build/dist/client/features/cli-adapters.js.map +1 -1
  16. package/data/build/dist/client/features/index.d.ts.map +1 -1
  17. package/data/build/dist/client/features/index.js +2 -0
  18. package/data/build/dist/client/features/index.js.map +1 -1
  19. package/data/build/dist/client/features/magpie-management-controls.d.ts.map +1 -1
  20. package/data/build/dist/client/features/magpie-management-controls.js +45 -10
  21. package/data/build/dist/client/features/magpie-management-controls.js.map +1 -1
  22. package/data/build/dist/client/features/magpie-management-page.d.ts +6 -1
  23. package/data/build/dist/client/features/magpie-management-page.d.ts.map +1 -1
  24. package/data/build/dist/client/features/magpie-management-page.js +109 -37
  25. package/data/build/dist/client/features/magpie-management-page.js.map +1 -1
  26. package/data/build/dist/client/features/magpie-management.d.ts.map +1 -1
  27. package/data/build/dist/client/features/magpie-management.js +3 -2
  28. package/data/build/dist/client/features/magpie-management.js.map +1 -1
  29. package/data/build/dist/client/features/plugin-update.d.ts +3 -0
  30. package/data/build/dist/client/features/plugin-update.d.ts.map +1 -0
  31. package/data/build/dist/client/features/plugin-update.js +8 -0
  32. package/data/build/dist/client/features/plugin-update.js.map +1 -0
  33. package/data/build/dist/client/features/types.d.ts +3 -0
  34. package/data/build/dist/client/features/types.d.ts.map +1 -1
  35. package/data/build/dist/client/locale.d.ts.map +1 -1
  36. package/data/build/dist/client/locale.js +3 -0
  37. package/data/build/dist/client/locale.js.map +1 -1
  38. package/data/build/dist/client/locales/magpie.d.ts.map +1 -1
  39. package/data/build/dist/client/locales/magpie.js +92 -12
  40. package/data/build/dist/client/locales/magpie.js.map +1 -1
  41. package/data/build/dist/client/locales/pluginUpdate.d.ts +3 -0
  42. package/data/build/dist/client/locales/pluginUpdate.d.ts.map +1 -0
  43. package/data/build/dist/client/locales/pluginUpdate.js +131 -0
  44. package/data/build/dist/client/locales/pluginUpdate.js.map +1 -0
  45. package/data/build/dist/client/locales/usage.d.ts.map +1 -1
  46. package/data/build/dist/client/locales/usage.js +2 -0
  47. package/data/build/dist/client/locales/usage.js.map +1 -1
  48. package/data/build/dist/client/magpie-context-meter.d.ts +18 -0
  49. package/data/build/dist/client/magpie-context-meter.d.ts.map +1 -0
  50. package/data/build/dist/client/magpie-context-meter.js +274 -0
  51. package/data/build/dist/client/magpie-context-meter.js.map +1 -0
  52. package/data/build/dist/client/magpie-context-store.d.ts +32 -0
  53. package/data/build/dist/client/magpie-context-store.d.ts.map +1 -0
  54. package/data/build/dist/client/magpie-context-store.js +165 -0
  55. package/data/build/dist/client/magpie-context-store.js.map +1 -0
  56. package/data/build/dist/client/settings-promo-styles.d.ts +5 -0
  57. package/data/build/dist/client/settings-promo-styles.d.ts.map +1 -1
  58. package/data/build/dist/client/settings-promo-styles.js +15 -2
  59. package/data/build/dist/client/settings-promo-styles.js.map +1 -1
  60. package/data/build/dist/client/settings-promo.d.ts +4 -2
  61. package/data/build/dist/client/settings-promo.d.ts.map +1 -1
  62. package/data/build/dist/client/settings-promo.js +4 -4
  63. package/data/build/dist/client/settings-promo.js.map +1 -1
  64. package/data/build/dist/client/settings-section.d.ts +2 -3
  65. package/data/build/dist/client/settings-section.d.ts.map +1 -1
  66. package/data/build/dist/client/settings-section.js +7 -7
  67. package/data/build/dist/client/settings-section.js.map +1 -1
  68. package/data/build/dist/client/settings-update.d.ts +8 -0
  69. package/data/build/dist/client/settings-update.d.ts.map +1 -0
  70. package/data/build/dist/client/settings-update.js +57 -0
  71. package/data/build/dist/client/settings-update.js.map +1 -0
  72. package/data/build/dist/client/subscription-slot.d.ts +3 -2
  73. package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
  74. package/data/build/dist/client/subscription-slot.js +115 -43
  75. package/data/build/dist/client/subscription-slot.js.map +1 -1
  76. package/data/build/dist/client/update-panel-styles.d.ts +29 -0
  77. package/data/build/dist/client/update-panel-styles.d.ts.map +1 -0
  78. package/data/build/dist/client/update-panel-styles.js +69 -0
  79. package/data/build/dist/client/update-panel-styles.js.map +1 -0
  80. package/data/build/dist/client/update-panel.d.ts +7 -0
  81. package/data/build/dist/client/update-panel.d.ts.map +1 -0
  82. package/data/build/dist/client/update-panel.js +52 -0
  83. package/data/build/dist/client/update-panel.js.map +1 -0
  84. package/data/build/dist/client/update-store.d.ts +43 -0
  85. package/data/build/dist/client/update-store.d.ts.map +1 -0
  86. package/data/build/dist/client/update-store.js +207 -0
  87. package/data/build/dist/client/update-store.js.map +1 -0
  88. package/data/build/dist/dsh-capabilities/client/plugin-reload-adapter.d.ts +4 -0
  89. package/data/build/dist/dsh-capabilities/client/plugin-reload-adapter.d.ts.map +1 -0
  90. package/data/build/dist/dsh-capabilities/client/plugin-reload-adapter.js +6 -0
  91. package/data/build/dist/dsh-capabilities/client/plugin-reload-adapter.js.map +1 -0
  92. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.d.ts +15 -1
  93. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.d.ts.map +1 -1
  94. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.js +53 -21
  95. package/data/build/dist/dsh-capabilities/client/session-performance-adapter.js.map +1 -1
  96. package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.d.ts +22 -0
  97. package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.d.ts.map +1 -0
  98. package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.js +71 -0
  99. package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.js.map +1 -0
  100. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts +4 -0
  101. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts.map +1 -1
  102. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js +16 -1
  103. package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js.map +1 -1
  104. package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
  105. package/data/build/dist/dsh-capabilities/matrix.js +4 -0
  106. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  107. package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
  108. package/data/build/dist/dsh-capabilities/routes.js +10 -0
  109. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  110. package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
  111. package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
  112. package/data/build/dist/dsh-capabilities/types.js.map +1 -1
  113. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  114. package/data/build/dist/host/cli-adapters/feature.js +230 -34
  115. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  116. package/data/build/dist/host/cli-adapters/magpie-context.d.ts +9 -0
  117. package/data/build/dist/host/cli-adapters/magpie-context.d.ts.map +1 -0
  118. package/data/build/dist/host/cli-adapters/magpie-context.js +128 -0
  119. package/data/build/dist/host/cli-adapters/magpie-context.js.map +1 -0
  120. package/data/build/dist/host/cli-adapters/magpie-detection.d.ts +3 -3
  121. package/data/build/dist/host/cli-adapters/magpie-detection.d.ts.map +1 -1
  122. package/data/build/dist/host/cli-adapters/magpie-detection.js +18 -4
  123. package/data/build/dist/host/cli-adapters/magpie-detection.js.map +1 -1
  124. package/data/build/dist/host/cli-adapters/magpie-management.d.ts.map +1 -1
  125. package/data/build/dist/host/cli-adapters/magpie-management.js +95 -20
  126. package/data/build/dist/host/cli-adapters/magpie-management.js.map +1 -1
  127. package/data/build/dist/host/cli-adapters/magpie-update.d.ts.map +1 -1
  128. package/data/build/dist/host/cli-adapters/magpie-update.js +14 -4
  129. package/data/build/dist/host/cli-adapters/magpie-update.js.map +1 -1
  130. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts +17 -3
  131. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts.map +1 -1
  132. package/data/build/dist/host/cli-adapters/magpie-usage.js +382 -92
  133. package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
  134. package/data/build/dist/host/cli-adapters/magpie-web.d.ts +15 -0
  135. package/data/build/dist/host/cli-adapters/magpie-web.d.ts.map +1 -1
  136. package/data/build/dist/host/cli-adapters/magpie-web.js +100 -22
  137. package/data/build/dist/host/cli-adapters/magpie-web.js.map +1 -1
  138. package/data/build/dist/host/cli-adapters/process-utils.d.ts.map +1 -1
  139. package/data/build/dist/host/cli-adapters/process-utils.js +4 -0
  140. package/data/build/dist/host/cli-adapters/process-utils.js.map +1 -1
  141. package/data/build/dist/host/cli-adapters/registry.d.ts.map +1 -1
  142. package/data/build/dist/host/cli-adapters/registry.js +6 -5
  143. package/data/build/dist/host/cli-adapters/registry.js.map +1 -1
  144. package/data/build/dist/host/cli-adapters/session-performance-projection.d.ts +6 -0
  145. package/data/build/dist/host/cli-adapters/session-performance-projection.d.ts.map +1 -1
  146. package/data/build/dist/host/cli-adapters/session-performance-projection.js +25 -0
  147. package/data/build/dist/host/cli-adapters/session-performance-projection.js.map +1 -1
  148. package/data/build/dist/host/features/index.d.ts.map +1 -1
  149. package/data/build/dist/host/features/index.js +2 -0
  150. package/data/build/dist/host/features/index.js.map +1 -1
  151. package/data/build/dist/host/features/plugin-update.d.ts +6 -0
  152. package/data/build/dist/host/features/plugin-update.d.ts.map +1 -0
  153. package/data/build/dist/host/features/plugin-update.js +45 -0
  154. package/data/build/dist/host/features/plugin-update.js.map +1 -0
  155. package/data/build/dist/host/index.d.ts.map +1 -1
  156. package/data/build/dist/host/index.js +31 -1
  157. package/data/build/dist/host/index.js.map +1 -1
  158. package/data/build/dist/host/native-session-bridge.d.ts +8 -0
  159. package/data/build/dist/host/native-session-bridge.d.ts.map +1 -1
  160. package/data/build/dist/host/native-session-bridge.js +43 -0
  161. package/data/build/dist/host/native-session-bridge.js.map +1 -1
  162. package/data/build/dist/host/rpc.d.ts +4 -1
  163. package/data/build/dist/host/rpc.d.ts.map +1 -1
  164. package/data/build/dist/host/rpc.js +33 -7
  165. package/data/build/dist/host/rpc.js.map +1 -1
  166. package/data/build/dist/host/session-handle-eviction.d.ts +29 -0
  167. package/data/build/dist/host/session-handle-eviction.d.ts.map +1 -0
  168. package/data/build/dist/host/session-handle-eviction.js +413 -0
  169. package/data/build/dist/host/session-handle-eviction.js.map +1 -0
  170. package/data/build/dist/host/settings.d.ts.map +1 -1
  171. package/data/build/dist/host/settings.js +12 -1
  172. package/data/build/dist/host/settings.js.map +1 -1
  173. package/data/build/dist/host/update/application-result.d.ts +3 -0
  174. package/data/build/dist/host/update/application-result.d.ts.map +1 -0
  175. package/data/build/dist/host/update/application-result.js +13 -0
  176. package/data/build/dist/host/update/application-result.js.map +1 -0
  177. package/data/build/dist/host/update/http.d.ts +7 -0
  178. package/data/build/dist/host/update/http.d.ts.map +1 -0
  179. package/data/build/dist/host/update/http.js +55 -0
  180. package/data/build/dist/host/update/http.js.map +1 -0
  181. package/data/build/dist/host/update/metadata.d.ts +14 -0
  182. package/data/build/dist/host/update/metadata.d.ts.map +1 -0
  183. package/data/build/dist/host/update/metadata.js +75 -0
  184. package/data/build/dist/host/update/metadata.js.map +1 -0
  185. package/data/build/dist/host/update/release-notes.d.ts +6 -0
  186. package/data/build/dist/host/update/release-notes.d.ts.map +1 -0
  187. package/data/build/dist/host/update/release-notes.js +52 -0
  188. package/data/build/dist/host/update/release-notes.js.map +1 -0
  189. package/data/build/dist/host/update/service.d.ts +25 -0
  190. package/data/build/dist/host/update/service.d.ts.map +1 -0
  191. package/data/build/dist/host/update/service.js +209 -0
  192. package/data/build/dist/host/update/service.js.map +1 -0
  193. package/data/build/dist/shared/contracts/config.d.ts +17 -0
  194. package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
  195. package/data/build/dist/shared/contracts/config.js +8 -0
  196. package/data/build/dist/shared/contracts/config.js.map +1 -1
  197. package/data/build/dist/shared/contracts/magpie-management.d.ts +59 -0
  198. package/data/build/dist/shared/contracts/magpie-management.d.ts.map +1 -1
  199. package/data/build/dist/shared/contracts/plugin-update.d.ts +93 -0
  200. package/data/build/dist/shared/contracts/plugin-update.d.ts.map +1 -0
  201. package/data/build/dist/shared/contracts/plugin-update.js +128 -0
  202. package/data/build/dist/shared/contracts/plugin-update.js.map +1 -0
  203. package/data/build/dist/shared/contracts/subscription.d.ts +5 -0
  204. package/data/build/dist/shared/contracts/subscription.d.ts.map +1 -1
  205. package/data/build/dist/shared/contracts/subscription.js.map +1 -1
  206. package/data/build/dist/shared/contracts/version.d.ts +1 -1
  207. package/data/build/dist/shared/contracts/version.js +1 -1
  208. package/data/build/dist/shared/index.d.ts +2 -1
  209. package/data/build/dist/shared/index.d.ts.map +1 -1
  210. package/data/build/dist/shared/index.js +1 -0
  211. package/data/build/dist/shared/index.js.map +1 -1
  212. package/data/build/dist/shared/magpie-provider-id.d.ts +12 -0
  213. package/data/build/dist/shared/magpie-provider-id.d.ts.map +1 -0
  214. package/data/build/dist/shared/magpie-provider-id.js +16 -0
  215. package/data/build/dist/shared/magpie-provider-id.js.map +1 -0
  216. package/package.json +2 -1
  217. package/profile/README.md +2 -2
  218. package/profile/package.json +2 -2
  219. package/profile/version.json +1 -1
  220. package/version.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { startSerialPolling } from './serial-polling.js';
2
2
  import { createElement, Fragment, useEffect, useLayoutEffect, useRef, useState } from 'react';
3
+ import { createPortal } from 'react-dom';
3
4
  import { isSubscriptionUsageFresh } from '../shared/contracts/subscription.js';
4
5
  import { DEFAULT_SUBSCRIPTION_USAGE_SETTINGS } from '../shared/contracts/config.js';
5
6
  import { callCliRpc } from './cli-catalog.js';
@@ -7,7 +8,7 @@ import { resolveCodingNsTranslator, useCodingNsTranslator } from './locale.js';
7
8
  import { providerIconUrl } from './provider-icons.js';
8
9
  import { MagpieProviderLogo } from './features/magpie-provider-logo.js';
9
10
  import { MAGPIE_REQUESTS_PAGE_SIZE, RequestsPage, installMagpiePageStyles } from './features/magpie-management-page.js';
10
- import { createQuotaAccountBlock, createQuotaGroupHeader, formatQuotaCredits, formatQuotaNumber, groupQuotasByProvider, readWindowCreditBalance, resolveQuotaBalanceLabel, resolveQuotaCreditBalance, } from './features/subscription-quota-groups.js';
11
+ import { createQuotaAccountBlock, createQuotaGroupHeader, formatQuotaCredits, formatQuotaNumber, groupQuotasByProvider, readWindowCreditBalance, quotaWindowRemaining, resolveQuotaBalanceLabel, resolveQuotaCreditBalance, } from './features/subscription-quota-groups.js';
11
12
  import { subscribeSessionAdapters } from './session-adapter-cache.js';
12
13
  import { loadCliSessionConfig } from './cli-session-config-cache.js';
13
14
  import { dshPopupSurfaceStyle, dshSettingsButtonStyle, dshSettingsPrimaryButtonStyle, dshThemeColor } from './theme.js';
@@ -123,6 +124,7 @@ function CommandCodeSubscriptionSlot(props) {
123
124
  const [clock, setClock] = useState(() => Date.now());
124
125
  const rootRef = useRef(null);
125
126
  const magpiePopoverRef = useRef(null);
127
+ const magpieRequestsDialogRef = useRef(null);
126
128
  const resetDialogRef = useRef(null);
127
129
  // 重置成功后的刷新不能重跑加载 effect,否则 usage 会被清空导致底部入口闪断。
128
130
  const refreshRef = useRef(null);
@@ -131,6 +133,8 @@ function CommandCodeSubscriptionSlot(props) {
131
133
  const [resetPending, setResetPending] = useState(false);
132
134
  const [resetResult, setResetResult] = useState(null);
133
135
  const [resetError, setResetError] = useState(null);
136
+ const sessionRef = useRef(undefined);
137
+ const routeKeyRef = useRef(null);
134
138
  // Agent-native session bindings are written by Host during a turn. Refresh
135
139
  // at turn state changes so a snapshot loaded before the binding is not kept.
136
140
  const modelSelectionRevision = props.useSession?.((value) => JSON.stringify([value.modelSelection, value.running]));
@@ -189,6 +193,8 @@ function CommandCodeSubscriptionSlot(props) {
189
193
  useEffect(() => {
190
194
  const sessionId = props.sessionId?.trim();
191
195
  if (!sessionId) {
196
+ sessionRef.current = undefined;
197
+ routeKeyRef.current = null;
192
198
  setEligible(false);
193
199
  setSnapshot(null);
194
200
  setAdapterId(null);
@@ -205,18 +211,23 @@ function CommandCodeSubscriptionSlot(props) {
205
211
  // 未解析的 Magpie 配额必须快速补读:官方余额一旦抢先显示,用户要等到下一次
206
212
  // 轮询(默认 5 分钟)或整页刷新才会切到 Magpie。
207
213
  let upstreamUnresolved = false;
208
- setEligible(false);
209
- setSnapshot(null);
210
- setAdapterId(null);
211
- setProviderId(null);
212
- setOpen(false);
213
- setResetOpen(false);
214
- setResetPending(false);
215
- setResetResult(null);
216
- setResetError(null);
217
- setMagpieTab('usage');
214
+ if (sessionRef.current !== sessionId) {
215
+ sessionRef.current = sessionId;
216
+ routeKeyRef.current = null;
217
+ setEligible(false);
218
+ setSnapshot(null);
219
+ setAdapterId(null);
220
+ setProviderId(null);
221
+ setOpen(false);
222
+ setResetOpen(false);
223
+ setResetPending(false);
224
+ setResetResult(null);
225
+ setResetError(null);
226
+ setMagpieTab('usage');
227
+ }
218
228
  const refresh = async (signal) => {
219
229
  let routeSignal;
230
+ let routeChanged = false;
220
231
  setLoading(true);
221
232
  try {
222
233
  // 订阅入口必须读取当前会话的真实 Provider;模型选择器切换后不能复用
@@ -234,6 +245,16 @@ function CommandCodeSubscriptionSlot(props) {
234
245
  }
235
246
  if (signal.aborted)
236
247
  return false;
248
+ const cacheKey = JSON.stringify([adapterId, selection.providerId ?? '', selection.modelId ?? '', sessionId, selection.providerSessionId ?? '']);
249
+ routeChanged = routeKeyRef.current !== cacheKey;
250
+ if (routeChanged) {
251
+ routeKeyRef.current = cacheKey;
252
+ if (active) {
253
+ setSnapshot(null);
254
+ setOpen(false);
255
+ setMagpieTab('usage');
256
+ }
257
+ }
237
258
  if (active) {
238
259
  setEligible(true);
239
260
  setAdapterId(adapterId);
@@ -243,8 +264,7 @@ function CommandCodeSubscriptionSlot(props) {
243
264
  // 模型也是读取键的一部分:Antigravity 的 Gemini 与 Claude/GPT 是两个独立配额组。
244
265
  // 会话 ID 同时承担 PeerHost 的路由身份;缓存也必须按会话隔离,
245
266
  // 否则本机与远端使用相同 Agent/Provider/模型时会互相复用上游结果。
246
- const cacheKey = JSON.stringify([adapterId, selection.providerId ?? '', selection.modelId ?? '', sessionId, selection.providerSessionId ?? '']);
247
- const magpieSnapshot = snapshotRef.current?.magpie;
267
+ const magpieSnapshot = routeChanged ? undefined : snapshotRef.current?.magpie;
248
268
  const includeRoute = magpieSnapshot !== null && magpieSnapshot !== undefined
249
269
  && (openRef.current || shouldResolveMagpieQuota(magpieSnapshot));
250
270
  const cached = subscriptionUsageCache.get(cacheKey);
@@ -278,8 +298,12 @@ function CommandCodeSubscriptionSlot(props) {
278
298
  if (signal.aborted || routeSignal?.aborted === true)
279
299
  return false;
280
300
  if (active) {
281
- setEligible(false);
282
- setSnapshot(null);
301
+ // A temporary Host/Web failure must not make the compact entry
302
+ // disappear. A later poll will replace the retained snapshot.
303
+ if (routeChanged || snapshotRef.current === null) {
304
+ setEligible(false);
305
+ setSnapshot(null);
306
+ }
283
307
  }
284
308
  return false;
285
309
  }
@@ -361,7 +385,7 @@ function CommandCodeSubscriptionSlot(props) {
361
385
  }
362
386
  })();
363
387
  };
364
- useDismissOnOutsidePointer(rootRef, open, () => setOpen(false));
388
+ useDismissOnOutsidePointer(rootRef, open, () => setOpen(false), { portal: magpieRequestsDialogRef });
365
389
  useDismissOnOutsidePointer(resetDialogRef, resetOpen && !resetPending, closeResetDialog);
366
390
  if (!eligible || snapshot === null)
367
391
  return null;
@@ -392,6 +416,7 @@ function CommandCodeSubscriptionSlot(props) {
392
416
  onToggleGroup: toggleQuotaGroup,
393
417
  placement: magpiePlacement,
394
418
  popoverRef: magpiePopoverRef,
419
+ requestsDialogRef: magpieRequestsDialogRef,
395
420
  }));
396
421
  }
397
422
  const usage = snapshot.providerUsage;
@@ -473,7 +498,7 @@ function CommandCodeSubscriptionSlot(props) {
473
498
  dialogRef: resetDialogRef,
474
499
  }));
475
500
  }
476
- function MagpieUsagePopover({ rpc, usage, t, tab = 'usage', onTabChange = () => { }, expandedGroups = [], onToggleGroup = () => { }, placement = { left: 0, width: 400 }, popoverRef }) {
501
+ function MagpieUsagePopover({ rpc, usage, t, tab = 'usage', onTabChange = () => { }, expandedGroups = [], onToggleGroup = () => { }, placement = { left: 0, width: 400 }, popoverRef, requestsDialogRef }) {
477
502
  const aggregateRows = usage.aggregate === null ? [] : [
478
503
  [t('usage.magpieRequests'), formatMagpieNumber(usage.aggregate.calls)],
479
504
  [t('usage.magpieErrors'), formatMagpieNumber(usage.aggregate.errors)],
@@ -523,12 +548,14 @@ function MagpieUsagePopover({ rpc, usage, t, tab = 'usage', onTabChange = () =>
523
548
  'aria-labelledby': `codingns4dsh-magpie-tab-${tab}`,
524
549
  style: magpieTabPanelStyle,
525
550
  }, tab === 'usage' ? MagpieUsagePanel({ usage, aggregateRows, sessionRows, t })
526
- : MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup })));
551
+ : MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup,
552
+ ...(requestsDialogRef === undefined ? {} : { requestsDialogRef }),
553
+ })));
527
554
  }
528
555
  function MagpieUsagePanel({ usage, aggregateRows, sessionRows, t }) {
529
556
  return createElement('div', undefined, createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieAggregateTitle')), usage.usageStatus === 'available'
530
557
  ? createMagpieRows(aggregateRows)
531
- : createElement('div', { style: magpieMutedTextStyle }, t('usage.magpieUsageUnavailable'))), createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieSessionTitle')), usage.sessionId !== null && createElement('div', { style: magpieSessionIdentityStyle }, createElement('span', undefined, t('usage.magpieAgent', { agent: usage.agent })), usage.sessionName !== undefined && createElement('strong', { style: magpieSessionNameStyle, title: usage.sessionName }, usage.sessionName), createElement('code', { style: magpieSessionIdStyle }, usage.sessionId)), usage.session === null
558
+ : createElement('div', { style: magpieMutedTextStyle }, t('usage.magpieUsageUnavailable'))), createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t(usage.sessionPeriod === 'today' ? 'usage.magpieSessionTodayTitle' : 'usage.magpieSessionTitle')), usage.sessionId !== null && createElement('div', { style: magpieSessionIdentityStyle }, createElement('div', { style: magpieSessionNameRowStyle }, createElement('span', { style: { flex: 'none' } }, t('usage.magpieAgent', { agent: usage.agent })), usage.sessionName !== undefined && createElement('strong', { style: magpieSessionNameStyle, title: usage.sessionName }, usage.sessionName)), createElement('code', { style: magpieSessionIdStyle }, usage.sessionId)), usage.session === null
532
559
  ? createElement('div', { style: magpieMutedTextStyle }, usage.sessionId === null ? t('usage.magpieSessionIdUnavailable') : t('usage.magpieSessionNoUsage'))
533
560
  : createMagpieRows(sessionRows)));
534
561
  }
@@ -549,7 +576,7 @@ function createMagpieQuotaCard(quota, t, index) {
549
576
  return createElement('div', { key: `${quota.provider}-${quota.user ?? 'account'}-${index}`, style: magpieQuotaCardStyle }, createElement('div', { style: magpieQuotaCardHeadingStyle }, createElement('span', { style: magpieQuotaNameWithLogoStyle }, createElement(MagpieProviderLogo, { identities: [quota.provider, quota.name], logoDataUrl: quota.logoDataUrl, size: 20, className: 'codingns4dsh-magpie-quota-logo', fallback: 'none' }), createElement('span', { style: magpieQuotaNameStyle }, quota.alias ?? quota.name)), createElement('span', { style: magpieQuotaHeadingMetaStyle }, quota.plan ?? quota.provider)), (quota.user !== null || quota.balance !== null) && createElement('div', { style: magpieQuotaIdentityStyle }, quota.user !== null && createElement('span', { title: quota.user }, t('usage.magpieQuotaAccount', { account: quota.user })), quota.balance !== null && createElement('span', undefined, t('usage.magpieQuotaBalance', { balance: quota.balance }))), quota.windows.length === 0
550
577
  ? createElement('div', { style: magpieQuotaMetaStyle }, t('usage.magpieQuotaNoWindows'))
551
578
  : quota.windows.map((window, windowIndex) => {
552
- const remaining = window.remainingPercent;
579
+ const remaining = quotaWindowRemaining(window);
553
580
  // 积分窗口(WorkBuddy 的 `0 / 350`)按数量读更准确:百分比在这里没有意义。
554
581
  const credits = formatQuotaWindowCredits(window);
555
582
  const amount = window.display ?? (window.amount !== null && window.limit !== null ? `${window.amount} / ${window.limit}${window.unit === null ? '' : ` ${window.unit}`}` : null);
@@ -569,10 +596,11 @@ function formatQuotaWindowCredits(window) {
569
596
  const credits = readWindowCreditBalance(window);
570
597
  return credits === null ? null : formatQuotaCredits(credits);
571
598
  }
572
- function MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup }) {
599
+ function MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup, requestsDialogRef }) {
573
600
  const route = usage.route;
574
601
  const groups = groupQuotasByProvider(quotas);
575
602
  const sessionAccount = route?.providerAccount ?? null;
603
+ const requestSessionId = usage.requestSessionId ?? usage.session?.id ?? usage.sessionId;
576
604
  const quotaMessage = magpieQuotaUnavailableMessage(usage, quotas, t);
577
605
  const routeStatus = usage.routeStatus === 'no-route'
578
606
  ? t('usage.magpieRouteNoRequests')
@@ -615,10 +643,11 @@ function MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup
615
643
  // “查看请求”入口与状态徽标同高、同排:入口在左,状态在右。
616
644
  createElement(MagpieRouteRequests, {
617
645
  rpc,
618
- sessionId: usage.sessionId,
646
+ sessionId: requestSessionId,
619
647
  sessionName: usage.sessionName ?? null,
620
648
  agent: usage.agent,
621
649
  t,
650
+ ...(requestsDialogRef === undefined ? {} : { requestsDialogRef }),
622
651
  }), createElement('span', { className: active ? 'codingns4dsh-magpie-route-node-active' : undefined, style: magpieRouteStatusStyle }, createElement('span', { style: magpieRouteStatusDotStyle }), createElement('strong', undefined, route.done === true ? t('usage.magpieRouteComplete') : route.done === false ? t('usage.magpieRouteRunning').replace(/\s*·\s*$/u, '') : route.status ?? '--')))), route === null
623
652
  ? createElement('div', { style: magpieEmptyStateStyle }, routeStatus)
624
653
  : createElement('div', { style: magpieRouteHeroStyle }, createElement('div', { style: magpieRouteTrackStyle, 'aria-label': t('usage.magpieRouteFlowTitle'), role: 'list' }, ...routeStages.map(([label, model], index) => createElement('div', {
@@ -635,35 +664,42 @@ function MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup
635
664
  * `MagpieRoutePanel` 渲染元素,真正的状态留在本组件内部。模态框内的请求明细
636
665
  * 直接复用管理页的 `RequestsPage`,只把会话筛选固定为当前会话。
637
666
  */
638
- export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t }) {
667
+ export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t, requestsDialogRef }) {
639
668
  const enabled = canReadMagpieSessionRequests(sessionId, agent);
640
669
  const [open, setOpen] = useState(false);
670
+ // 弹层固定筛选一个会话:这里持有从头累计的所有已加载请求,而不是只留当前一页。
641
671
  const [page, setPage] = useState(null);
642
672
  const [offset, setOffset] = useState(0);
643
673
  const [loading, setLoading] = useState(false);
644
674
  const [error, setError] = useState(false);
645
675
  const [reloadKey, setReloadKey] = useState(0);
646
676
  const controllerRef = useRef(null);
677
+ const sequenceRef = useRef(0);
647
678
  useEffect(() => {
648
679
  if (!open || !enabled)
649
680
  return;
650
681
  const controller = new AbortController();
651
682
  controllerRef.current = controller;
683
+ // 只有一次请求在飞:更晚的请求序号作废更早的回包。
684
+ const sequence = sequenceRef.current + 1;
685
+ sequenceRef.current = sequence;
652
686
  setLoading(true);
653
687
  setError(false);
654
688
  void readMagpieSessionRequestPage(rpc, sessionId, agent, offset, controller.signal).then((next) => {
655
- if (controller.signal.aborted)
689
+ if (controller.signal.aborted || sequence !== sequenceRef.current)
656
690
  return;
657
691
  if (next === null) {
658
692
  setError(true);
659
693
  return;
660
694
  }
661
- setPage(next);
695
+ setPage((current) => current === null || offset === 0
696
+ ? next
697
+ : { ...next, items: [...current.items, ...next.items] });
662
698
  }).catch(() => {
663
- if (!controller.signal.aborted)
699
+ if (!controller.signal.aborted && sequence === sequenceRef.current)
664
700
  setError(true);
665
701
  }).finally(() => {
666
- if (!controller.signal.aborted)
702
+ if (!controller.signal.aborted && sequence === sequenceRef.current)
667
703
  setLoading(false);
668
704
  });
669
705
  return () => {
@@ -672,6 +708,24 @@ export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t }) {
672
708
  controllerRef.current = null;
673
709
  };
674
710
  }, [open, enabled, offset, reloadKey, rpc, sessionId, agent]);
711
+ // 滚到列表底部就自动追加下一页:149 条请求也能一口气看完,不必数着点“加载更多”。
712
+ // 用捕获阶段监听滚动,真实滚动容器(弹层主体、表格横向容器)都在子树里。
713
+ useEffect(() => {
714
+ if (!open || typeof document === 'undefined' || !enabled)
715
+ return;
716
+ const onScroll = (event) => {
717
+ const target = event.target;
718
+ if (!(target instanceof Element) || !target.closest('.codingns4dsh-magpie-requests-body'))
719
+ return;
720
+ if (target.scrollHeight - target.scrollTop - target.clientHeight > 160)
721
+ return;
722
+ if (loading || error || page === null || !page.hasMore)
723
+ return;
724
+ setOffset(page.items.length);
725
+ };
726
+ document.addEventListener('scroll', onScroll, true);
727
+ return () => document.removeEventListener('scroll', onScroll, true);
728
+ }, [open, enabled, loading, error, page]);
675
729
  // 模态框覆盖整个视口,Esc 是移动端之外唯一的键盘关闭方式。
676
730
  useEffect(() => {
677
731
  if (!open || typeof document === 'undefined')
@@ -718,7 +772,13 @@ export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t }) {
718
772
  error,
719
773
  t,
720
774
  onClose: close,
721
- onOffsetChange: setOffset,
775
+ ...(requestsDialogRef === undefined ? {} : { dialogRef: requestsDialogRef }),
776
+ onOffsetChange: (value) => {
777
+ // 追加下一页;重试则从头重读,避免把同一页拼两遍。
778
+ if (value === 0)
779
+ setPage(null);
780
+ setOffset(value);
781
+ },
722
782
  onRetry: () => { setLoading(true); setError(false); setReloadKey((value) => value + 1); },
723
783
  }));
724
784
  }
@@ -726,10 +786,10 @@ export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t }) {
726
786
  function canReadMagpieSessionRequests(sessionId, agent) {
727
787
  return sessionId !== null && sessionId.trim() !== '' && sessionId.length <= 512 && /^[a-z0-9][a-z0-9-]*$/u.test(agent);
728
788
  }
729
- /** 只读取今天的会话请求,与路由卡片和“当前 Agent 会话”用量保持同一时间口径。 */
789
+ /** Include every date in the selected session's paginated request history. */
730
790
  async function readMagpieSessionRequestPage(rpc, sessionId, agent, offset, signal) {
731
791
  const result = await callCodingNsRpcResult(rpc, 'magpie/usage/requests', {
732
- period: 'today',
792
+ period: 'all',
733
793
  offset,
734
794
  limit: MAGPIE_REQUESTS_PAGE_SIZE,
735
795
  sessionId,
@@ -748,9 +808,11 @@ async function readMagpieSessionRequestPage(rpc, sessionId, agent, offset, signa
748
808
  * 管理页视图自带统计条、桌面表格 / 移动卡片、分页和空状态,这里只负责把会话固定住,
749
809
  * 不再维护一套重复的请求卡片渲染。
750
810
  */
751
- function MagpieSessionRequestsDialog({ sessionId, sessionName, agent, page, offset, loading, error, t, onClose, onOffsetChange, onRetry }) {
752
- return createElement('div', {
811
+ function MagpieSessionRequestsDialog({ sessionId, sessionName, agent, page, offset, loading, error, t, onClose, dialogRef, onOffsetChange, onRetry }) {
812
+ const displaySessionName = sessionName ?? page?.sessionName ?? null;
813
+ const dialog = createElement('div', {
753
814
  className: 'codingns4dsh-magpie-requests-overlay',
815
+ ref: dialogRef,
754
816
  role: 'presentation',
755
817
  style: magpieRequestsOverlayStyle,
756
818
  // 只有按在遮罩自身时才关闭;从内容内部按下再拖到遮罩上不会误关。
@@ -780,12 +842,18 @@ function MagpieSessionRequestsDialog({ sessionId, sessionName, agent, page, offs
780
842
  page,
781
843
  loading,
782
844
  error,
783
- selectedSession: { id: sessionId, agent, ...(sessionName === null ? {} : { dshSessionName: sessionName }) },
845
+ selectedSession: { id: sessionId, agent, ...(displaySessionName === null ? {} : { dshSessionName: displaySessionName }) },
784
846
  offset,
785
847
  onOffsetChange,
786
848
  onClearSession: null,
787
849
  t,
850
+ // 弹层筛选的是单一会话,列表从头累计,直到整条会话的请求都加载完。
851
+ append: true,
788
852
  })))));
853
+ // The usage popover has its own lower stacking context. Portaling the modal
854
+ // to body lets it actually cover the host sidebar instead of being clipped
855
+ // by the popover's parent context.
856
+ return typeof document === 'undefined' ? dialog : createPortal(dialog, document.body);
789
857
  }
790
858
  function createMagpieRows(rows) {
791
859
  if (rows.length === 0)
@@ -1206,17 +1274,20 @@ const MAGPIE_QUOTA_RETRY_MS = 3_000;
1206
1274
  function shouldResolveMagpieQuota(usage) {
1207
1275
  if (usage === null || usage === undefined)
1208
1276
  return false;
1277
+ if (usage.session === null)
1278
+ return true;
1209
1279
  if (usage.quotaStatus !== 'available')
1210
1280
  return usage.upstreamProvider === null;
1211
- return usage.sessionId !== null && usage.session !== null && usage.quotas.length === 0;
1281
+ return usage.sessionId !== null && usage.session !== null && (usage.quotas?.length ?? 0) === 0;
1212
1282
  }
1213
1283
  function resolveMagpieQuotaRemaining(usage) {
1214
- if (usage.quotaStatus !== 'available')
1215
- return null;
1216
- for (const quota of usage.quotas) {
1284
+ for (const quota of usage.quotas ?? []) {
1217
1285
  for (const window of quota.windows) {
1218
- if (window.remainingPercent !== null)
1219
- return window.remainingPercent;
1286
+ // A few Magpie responses report only `used`; the quota card derives the same
1287
+ // remaining share, so the compact trigger must use that normalized value too.
1288
+ const remaining = quotaWindowRemaining(window);
1289
+ if (remaining !== null)
1290
+ return remaining;
1220
1291
  }
1221
1292
  }
1222
1293
  return null;
@@ -1411,9 +1482,10 @@ const magpieStatsGridStyle = { display: 'grid', gridTemplateColumns: 'repeat(3,
1411
1482
  const magpieStatStyle = { display: 'grid', alignContent: 'space-between', gap: 1, minWidth: 0, minHeight: 40, boxSizing: 'border-box', padding: '5px 7px', borderRadius: 8, background: dshThemeColor.surfaceSubtle };
1412
1483
  const magpieStatLabelStyle = { minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '13px', overflowWrap: 'anywhere' };
1413
1484
  const magpieRowValueStyle = { color: dshThemeColor.labelPrimary, fontSize: uiFontSize(14), fontWeight: 650, lineHeight: '18px', textAlign: 'right', overflowWrap: 'anywhere' };
1414
- const magpieSessionIdentityStyle = { display: 'flex', flexWrap: 'wrap', alignItems: 'baseline', gap: '2px 10px', minWidth: 0, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(12), lineHeight: '16px' };
1415
- const magpieSessionNameStyle = { maxWidth: '100%', overflow: 'hidden', color: dshThemeColor.labelPrimary, fontSize: uiFontSize(12), fontWeight: 650, textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
1416
- const magpieSessionIdStyle = { flex: '1 1 120px', minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '14px', whiteSpace: 'normal', overflowWrap: 'anywhere' };
1485
+ const magpieSessionIdentityStyle = { display: 'grid', gap: 2, minWidth: 0, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(12), lineHeight: '16px' };
1486
+ const magpieSessionNameRowStyle = { display: 'flex', alignItems: 'baseline', gap: 10, minWidth: 0 };
1487
+ const magpieSessionNameStyle = { minWidth: 0, maxWidth: '100%', overflow: 'hidden', color: dshThemeColor.labelPrimary, fontSize: uiFontSize(12), fontWeight: 650, textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
1488
+ const magpieSessionIdStyle = { minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '14px', whiteSpace: 'normal', overflowWrap: 'anywhere' };
1417
1489
  const magpieAttemptsStyle = { display: 'grid', gap: 5, paddingTop: 6 };
1418
1490
  const magpieAttemptRowStyle = { display: 'flex', justifyContent: 'space-between', gap: 14, fontSize: uiFontSize(12) };
1419
1491
  const magpieAttemptModelStyle = { color: dshThemeColor.labelSecondary, overflowWrap: 'anywhere' };
@@ -1452,7 +1524,7 @@ const magpieRouteMetaValueStyle = { color: dshThemeColor.labelSecondary, fontSiz
1452
1524
  // 请求入口与请求模态框:入口与状态徽标同高并排在标题栏,模态框覆盖视口并在内部滚动。
1453
1525
  const magpieRouteHeadingActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 8, minWidth: 0 };
1454
1526
  const magpieRouteRequestsButtonStyle = { flex: 'none', display: 'inline-flex', alignItems: 'center', gap: 4, boxSizing: 'border-box', padding: '2px 8px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 999, background: dshThemeColor.menuBackground, color: dshThemeColor.labelSecondary, fontFamily: 'inherit', fontSize: uiFontSize(11), lineHeight: '15px', cursor: 'pointer', whiteSpace: 'nowrap', transition: 'background .15s ease,color .15s ease' };
1455
- const magpieRequestsOverlayStyle = { position: 'fixed', inset: 0, zIndex: 1500, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16, boxSizing: 'border-box', background: dshThemeColor.overlay };
1527
+ const magpieRequestsOverlayStyle = { position: 'fixed', inset: 0, zIndex: 2147483000, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16, boxSizing: 'border-box', background: dshThemeColor.overlay };
1456
1528
  const magpieRequestsDialogStyle = { ...dshPopupSurfaceStyle, display: 'flex', flexDirection: 'column', gap: 10, width: 'min(96vw, 1320px)', maxHeight: 'min(88vh, 820px)', boxSizing: 'border-box', padding: 14, borderRadius: 14 };
1457
1529
  const magpieRequestsHeadingStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, paddingBottom: 10, borderBottom: `1px solid ${dshThemeColor.border}` };
1458
1530
  const magpieRequestsHeadingActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 8, flex: 'none' };