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

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 (202) hide show
  1. package/README.en.md +6 -4
  2. package/README.md +6 -6
  3. package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +1 -1
  4. package/data/build/dist/bootstrap/index.d.ts +1 -1
  5. package/data/build/dist/client/bundle.js +5306 -493
  6. package/data/build/dist/client/bundle.js.map +1 -1
  7. package/data/build/dist/client/client.magpie-model-tag.js +155 -5
  8. package/data/build/dist/client/client.magpie-model-tag.js.map +1 -1
  9. package/data/build/dist/client/client.native-workspace-store.js +30 -4
  10. package/data/build/dist/client/client.native-workspace-store.js.map +1 -1
  11. package/data/build/dist/client/client.transport.js +725 -48
  12. package/data/build/dist/client/client.transport.js.map +1 -1
  13. package/data/build/dist/client/desktop-assistant.js +931 -185
  14. package/data/build/dist/client/feature-requirement.d.ts +43 -0
  15. package/data/build/dist/client/feature-requirement.d.ts.map +1 -0
  16. package/data/build/dist/client/feature-requirement.js +105 -0
  17. package/data/build/dist/client/feature-requirement.js.map +1 -0
  18. package/data/build/dist/client/features/index.d.ts +1 -0
  19. package/data/build/dist/client/features/index.d.ts.map +1 -1
  20. package/data/build/dist/client/features/index.js +3 -0
  21. package/data/build/dist/client/features/index.js.map +1 -1
  22. package/data/build/dist/client/features/magpie-management-controls.d.ts +46 -0
  23. package/data/build/dist/client/features/magpie-management-controls.d.ts.map +1 -0
  24. package/data/build/dist/client/features/magpie-management-controls.js +759 -0
  25. package/data/build/dist/client/features/magpie-management-controls.js.map +1 -0
  26. package/data/build/dist/client/features/magpie-management-page.d.ts +124 -0
  27. package/data/build/dist/client/features/magpie-management-page.d.ts.map +1 -0
  28. package/data/build/dist/client/features/magpie-management-page.js +1256 -0
  29. package/data/build/dist/client/features/magpie-management-page.js.map +1 -0
  30. package/data/build/dist/client/features/magpie-management.d.ts +7 -0
  31. package/data/build/dist/client/features/magpie-management.d.ts.map +1 -0
  32. package/data/build/dist/client/features/magpie-management.js +154 -0
  33. package/data/build/dist/client/features/magpie-management.js.map +1 -0
  34. package/data/build/dist/client/features/magpie-mark.d.ts +10 -0
  35. package/data/build/dist/client/features/magpie-mark.d.ts.map +1 -0
  36. package/data/build/dist/client/features/magpie-mark.js +21 -0
  37. package/data/build/dist/client/features/magpie-mark.js.map +1 -0
  38. package/data/build/dist/client/features/magpie-provider-logo.d.ts +11 -0
  39. package/data/build/dist/client/features/magpie-provider-logo.d.ts.map +1 -0
  40. package/data/build/dist/client/features/magpie-provider-logo.js +35 -0
  41. package/data/build/dist/client/features/magpie-provider-logo.js.map +1 -0
  42. package/data/build/dist/client/features/subscription-quota-groups.d.ts +193 -0
  43. package/data/build/dist/client/features/subscription-quota-groups.d.ts.map +1 -0
  44. package/data/build/dist/client/features/subscription-quota-groups.js +548 -0
  45. package/data/build/dist/client/features/subscription-quota-groups.js.map +1 -0
  46. package/data/build/dist/client/git-management.d.ts.map +1 -1
  47. package/data/build/dist/client/git-management.js +11 -9
  48. package/data/build/dist/client/git-management.js.map +1 -1
  49. package/data/build/dist/client/git-panel-styles.js +1 -0
  50. package/data/build/dist/client/git-panel-styles.js.map +1 -1
  51. package/data/build/dist/client/index.d.ts +1 -1
  52. package/data/build/dist/client/index.d.ts.map +1 -1
  53. package/data/build/dist/client/index.js +1 -1
  54. package/data/build/dist/client/index.js.map +1 -1
  55. package/data/build/dist/client/locale.d.ts.map +1 -1
  56. package/data/build/dist/client/locale.js +7 -0
  57. package/data/build/dist/client/locale.js.map +1 -1
  58. package/data/build/dist/client/locales/magpie.d.ts +4 -0
  59. package/data/build/dist/client/locales/magpie.d.ts.map +1 -0
  60. package/data/build/dist/client/locales/magpie.js +622 -0
  61. package/data/build/dist/client/locales/magpie.js.map +1 -0
  62. package/data/build/dist/client/locales/usage.d.ts.map +1 -1
  63. package/data/build/dist/client/locales/usage.js +52 -0
  64. package/data/build/dist/client/locales/usage.js.map +1 -1
  65. package/data/build/dist/client/magpie-model-tag.d.ts +9 -1
  66. package/data/build/dist/client/magpie-model-tag.d.ts.map +1 -1
  67. package/data/build/dist/client/magpie-model-tag.js +15 -3
  68. package/data/build/dist/client/magpie-model-tag.js.map +1 -1
  69. package/data/build/dist/client/provider-icons.d.ts +8 -0
  70. package/data/build/dist/client/provider-icons.d.ts.map +1 -1
  71. package/data/build/dist/client/provider-icons.js +122 -2
  72. package/data/build/dist/client/provider-icons.js.map +1 -1
  73. package/data/build/dist/client/settings-bridge.d.ts +1 -0
  74. package/data/build/dist/client/settings-bridge.d.ts.map +1 -1
  75. package/data/build/dist/client/settings-bridge.js +29 -10
  76. package/data/build/dist/client/settings-bridge.js.map +1 -1
  77. package/data/build/dist/client/settings-section.d.ts.map +1 -1
  78. package/data/build/dist/client/settings-section.js +21 -3
  79. package/data/build/dist/client/settings-section.js.map +1 -1
  80. package/data/build/dist/client/style.css +224 -221
  81. package/data/build/dist/client/subscription-slot.d.ts +20 -0
  82. package/data/build/dist/client/subscription-slot.d.ts.map +1 -1
  83. package/data/build/dist/client/subscription-slot.js +321 -18
  84. package/data/build/dist/client/subscription-slot.js.map +1 -1
  85. package/data/build/dist/dsh-capabilities/client/global-panel-adapter.d.ts +27 -0
  86. package/data/build/dist/dsh-capabilities/client/global-panel-adapter.d.ts.map +1 -0
  87. package/data/build/dist/dsh-capabilities/client/global-panel-adapter.js +109 -0
  88. package/data/build/dist/dsh-capabilities/client/global-panel-adapter.js.map +1 -0
  89. package/data/build/dist/dsh-capabilities/host/session-title-adapter.d.ts +2 -1
  90. package/data/build/dist/dsh-capabilities/host/session-title-adapter.d.ts.map +1 -1
  91. package/data/build/dist/dsh-capabilities/host/session-title-adapter.js +32 -2
  92. package/data/build/dist/dsh-capabilities/host/session-title-adapter.js.map +1 -1
  93. package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
  94. package/data/build/dist/dsh-capabilities/matrix.js +12 -11
  95. package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
  96. package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
  97. package/data/build/dist/dsh-capabilities/routes.js +12 -9
  98. package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
  99. package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
  100. package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
  101. package/data/build/dist/dsh-capabilities/types.js.map +1 -1
  102. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts +27 -0
  103. package/data/build/dist/host/cli-adapters/acp-cli-driver.d.ts.map +1 -1
  104. package/data/build/dist/host/cli-adapters/acp-cli-driver.js +88 -13
  105. package/data/build/dist/host/cli-adapters/acp-cli-driver.js.map +1 -1
  106. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +10 -0
  107. package/data/build/dist/host/cli-adapters/codex-driver.d.ts.map +1 -1
  108. package/data/build/dist/host/cli-adapters/codex-driver.js +32 -1
  109. package/data/build/dist/host/cli-adapters/codex-driver.js.map +1 -1
  110. package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts +6 -5
  111. package/data/build/dist/host/cli-adapters/command-code-acp-loader.d.ts.map +1 -1
  112. package/data/build/dist/host/cli-adapters/command-code-acp-loader.js +72 -12
  113. package/data/build/dist/host/cli-adapters/command-code-acp-loader.js.map +1 -1
  114. package/data/build/dist/host/cli-adapters/command-code-driver.d.ts.map +1 -1
  115. package/data/build/dist/host/cli-adapters/command-code-driver.js +26 -1
  116. package/data/build/dist/host/cli-adapters/command-code-driver.js.map +1 -1
  117. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts.map +1 -1
  118. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +15 -2
  119. package/data/build/dist/host/cli-adapters/dsh-message-projector.js.map +1 -1
  120. package/data/build/dist/host/cli-adapters/feature.d.ts +13 -0
  121. package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
  122. package/data/build/dist/host/cli-adapters/feature.js +390 -6
  123. package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
  124. package/data/build/dist/host/cli-adapters/grok-driver.js +5 -0
  125. package/data/build/dist/host/cli-adapters/grok-driver.js.map +1 -1
  126. package/data/build/dist/host/cli-adapters/magpie-detection.d.ts +72 -0
  127. package/data/build/dist/host/cli-adapters/magpie-detection.d.ts.map +1 -0
  128. package/data/build/dist/host/cli-adapters/magpie-detection.js +298 -0
  129. package/data/build/dist/host/cli-adapters/magpie-detection.js.map +1 -0
  130. package/data/build/dist/host/cli-adapters/magpie-management.d.ts +50 -0
  131. package/data/build/dist/host/cli-adapters/magpie-management.d.ts.map +1 -0
  132. package/data/build/dist/host/cli-adapters/magpie-management.js +1268 -0
  133. package/data/build/dist/host/cli-adapters/magpie-management.js.map +1 -0
  134. package/data/build/dist/host/cli-adapters/magpie-update.d.ts +59 -0
  135. package/data/build/dist/host/cli-adapters/magpie-update.d.ts.map +1 -0
  136. package/data/build/dist/host/cli-adapters/magpie-update.js +249 -0
  137. package/data/build/dist/host/cli-adapters/magpie-update.js.map +1 -0
  138. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts +66 -8
  139. package/data/build/dist/host/cli-adapters/magpie-usage.d.ts.map +1 -1
  140. package/data/build/dist/host/cli-adapters/magpie-usage.js +846 -122
  141. package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
  142. package/data/build/dist/host/cli-adapters/magpie-web.d.ts +54 -0
  143. package/data/build/dist/host/cli-adapters/magpie-web.d.ts.map +1 -0
  144. package/data/build/dist/host/cli-adapters/magpie-web.js +407 -0
  145. package/data/build/dist/host/cli-adapters/magpie-web.js.map +1 -0
  146. package/data/build/dist/host/cli-adapters/process-utils.d.ts +2 -0
  147. package/data/build/dist/host/cli-adapters/process-utils.d.ts.map +1 -1
  148. package/data/build/dist/host/cli-adapters/process-utils.js +4 -0
  149. package/data/build/dist/host/cli-adapters/process-utils.js.map +1 -1
  150. package/data/build/dist/host/dsh-gateway-feature.d.ts.map +1 -1
  151. package/data/build/dist/host/dsh-gateway-feature.js +26 -3
  152. package/data/build/dist/host/dsh-gateway-feature.js.map +1 -1
  153. package/data/build/dist/host/features/host-status.d.ts +25 -0
  154. package/data/build/dist/host/features/host-status.d.ts.map +1 -1
  155. package/data/build/dist/host/features/host-status.js +60 -6
  156. package/data/build/dist/host/features/host-status.js.map +1 -1
  157. package/data/build/dist/host/features/lan-access-dsh.d.ts.map +1 -1
  158. package/data/build/dist/host/features/lan-access-dsh.js +61 -10
  159. package/data/build/dist/host/features/lan-access-dsh.js.map +1 -1
  160. package/data/build/dist/host/features/session-translation-protection.d.ts.map +1 -1
  161. package/data/build/dist/host/features/session-translation-protection.js +2 -1
  162. package/data/build/dist/host/features/session-translation-protection.js.map +1 -1
  163. package/data/build/dist/host/lan-access-dsh.d.ts.map +1 -1
  164. package/data/build/dist/host/lan-access-dsh.js +6 -2
  165. package/data/build/dist/host/lan-access-dsh.js.map +1 -1
  166. package/data/build/dist/host/modules/pwa/pwa-session-notifications.js +2 -1
  167. package/data/build/dist/host/modules/pwa/pwa-session-notifications.js.map +1 -1
  168. package/data/build/dist/host/rpc.d.ts +15 -2
  169. package/data/build/dist/host/rpc.d.ts.map +1 -1
  170. package/data/build/dist/host/rpc.js +47 -6
  171. package/data/build/dist/host/rpc.js.map +1 -1
  172. package/data/build/dist/host/settings.d.ts.map +1 -1
  173. package/data/build/dist/host/settings.js +5 -0
  174. package/data/build/dist/host/settings.js.map +1 -1
  175. package/data/build/dist/shared/contracts/config.d.ts +18 -0
  176. package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
  177. package/data/build/dist/shared/contracts/config.js +8 -0
  178. package/data/build/dist/shared/contracts/config.js.map +1 -1
  179. package/data/build/dist/shared/contracts/errors.d.ts +2 -2
  180. package/data/build/dist/shared/contracts/feature.d.ts +7 -0
  181. package/data/build/dist/shared/contracts/feature.d.ts.map +1 -1
  182. package/data/build/dist/shared/contracts/magpie-management.d.ts +395 -0
  183. package/data/build/dist/shared/contracts/magpie-management.d.ts.map +1 -0
  184. package/data/build/dist/shared/contracts/magpie-management.js +2 -0
  185. package/data/build/dist/shared/contracts/magpie-management.js.map +1 -0
  186. package/data/build/dist/shared/contracts/subscription.d.ts +75 -1
  187. package/data/build/dist/shared/contracts/subscription.d.ts.map +1 -1
  188. package/data/build/dist/shared/contracts/subscription.js.map +1 -1
  189. package/data/build/dist/shared/contracts/version.d.ts +4 -4
  190. package/data/build/dist/shared/contracts/version.js +3 -3
  191. package/data/build/dist/shared/index.d.ts +2 -1
  192. package/data/build/dist/shared/index.d.ts.map +1 -1
  193. package/data/build/dist/shared/index.js +1 -1
  194. package/data/build/dist/shared/index.js.map +1 -1
  195. package/data/build/dist/shared/session-title.d.ts.map +1 -1
  196. package/data/build/dist/shared/session-title.js +10 -4
  197. package/data/build/dist/shared/session-title.js.map +1 -1
  198. package/package.json +29 -29
  199. package/profile/README.md +2 -2
  200. package/profile/package.json +3 -3
  201. package/profile/version.json +3 -3
  202. package/version.json +3 -3
@@ -33,9 +33,29 @@ export declare function calculateMagpiePopoverPlacement(rootLeft: number, viewpo
33
33
  readonly left: number;
34
34
  readonly width: number;
35
35
  };
36
+ /**
37
+ * 移动端订阅入口只保留图标,完整数据仍可在点击后的弹层中查看。
38
+ * 弹层高度上限固定为浏览器可视高度的 75%:先写 `vh` 兜底,再由 `dvh` 覆盖,
39
+ * 使移动端工具栏收展后仍按真实可视区计算;超出部分在弹层内部纵向滚动。
40
+ */
41
+ export declare const SUBSCRIPTION_RESPONSIVE_CSS = "@media (max-width: 768px){.codingns4dsh-subscription-trigger{gap:0!important;padding-left:4px!important;padding-right:4px!important}.codingns4dsh-subscription-label,.codingns4dsh-subscription-value{display:none!important}.codingns4dsh-subscription-popover{position:fixed!important;left:12px!important;right:12px!important;bottom:48px!important;width:auto!important;min-width:0!important;max-width:none!important;max-height:75vh!important;max-height:75dvh!important;overflow-x:hidden!important;overflow-y:auto!important;overscroll-behavior:contain!important;box-sizing:border-box!important}}";
36
42
  /** 在 DSH 原生步骤统计左侧显示当前 Agent 的订阅余量。 */
37
43
  export declare function registerSubscriptionSlot(slots: SlotRegistry, rpc: CodingNsRpcClient, getRefreshIntervalMins?: () => number, locale?: CodingNsLocale): () => void;
38
44
  declare function CommandCodeSubscriptionSlot(props: SubscriptionSlotProps): ReactElement | null;
45
+ /**
46
+ * 路由标题栏的“查看请求”入口:按钮、模态框与读取状态放在同一个子组件里。
47
+ *
48
+ * 弹层内容本身不持有 Hook(无浏览器测试会直接展开内容树),因此这里只由
49
+ * `MagpieRoutePanel` 渲染元素,真正的状态留在本组件内部。模态框内的请求明细
50
+ * 直接复用管理页的 `RequestsPage`,只把会话筛选固定为当前会话。
51
+ */
52
+ export declare function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t }: {
53
+ readonly rpc: CodingNsRpcClient;
54
+ readonly sessionId: string | null;
55
+ readonly sessionName: string | null;
56
+ readonly agent: string;
57
+ readonly t: CodingNsTranslator;
58
+ }): ReactElement;
39
59
  export declare function ProviderBalancePopover({ usage, providerName, t, nowMs }: {
40
60
  readonly usage: ProviderBalanceUsage;
41
61
  readonly providerName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"subscription-slot.d.ts","sourceRoot":"","sources":["../../../../src/client/subscription-slot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,OAAO,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAG9E,OAAO,KAAK,EAA6G,uBAAuB,EAAgG,oBAAoB,EAAsD,MAAM,qCAAqC,CAAA;AAErW,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,EAAoD,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAM5H,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,oBAAoB;QAC5B,SAAS,EAAE,MAAM,CAAA;KAClB;CACF;AAED,KAAK,eAAe,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,QAAQ,KAAK,QAAQ,CAAA;AAE7F,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAA;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAA;IACrC,oCAAoC;IACpC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,MAAM,CAAA;IAC9C,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAA;CACjC;AAeD;;;GAGG;AACH,KAAK,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AASvG,sCAAsC;AACtC,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAG/I;AAkBD,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMtK;AAYD,sCAAsC;AACtC,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,EAAE,MAAM,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,IAAI,CAehK;AAED,iBAAS,2BAA2B,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,GAAG,IAAI,CAoXtF;AAimBD,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CA+CvN;AAicD,OAAO,EAAE,2BAA2B,EAAE,CAAA;AACtC,eAAO,MAAM,mCAAmC,iCAA2B,CAAA"}
1
+ {"version":3,"file":"subscription-slot.d.ts","sourceRoot":"","sources":["../../../../src/client/subscription-slot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAa,MAAM,OAAO,CAAA;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAA;AAG9E,OAAO,KAAK,EAA6G,uBAAuB,EAAmH,oBAAoB,EAAsD,MAAM,qCAAqC,CAAA;AAGxX,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,EAAoD,KAAK,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAmB5H,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,oBAAoB;QAC5B,SAAS,EAAE,MAAM,CAAA;KAClB;CACF;AAED,KAAK,eAAe,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,QAAQ,KAAK,QAAQ,CAAA;AAE7F,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAA;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAA;IACrC,oCAAoC;IACpC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,MAAM,CAAA;IAC9C,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAA;CACjC;AAeD;;;GAGG;AACH,KAAK,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AASvG,sCAAsC;AACtC,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAG/I;AAoBD,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMtK;AAED;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,mlBAAmlB,CAAA;AAW3nB,sCAAsC;AACtC,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,EAAE,MAAM,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,IAAI,CAehK;AAED,iBAAS,2BAA2B,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,GAAG,IAAI,CA4YtF;AA4RD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;IAC7E,QAAQ,CAAC,GAAG,EAAE,iBAAiB,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,CAAC,EAAE,kBAAkB,CAAA;CAC/B,GAAG,YAAY,CAoFf;AAyeD,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CA+CvN;AA4gBD,OAAO,EAAE,2BAA2B,EAAE,CAAA;AACtC,eAAO,MAAM,mCAAmC,iCAA2B,CAAA"}
@@ -1,14 +1,18 @@
1
1
  import { startSerialPolling } from './serial-polling.js';
2
- import { createElement, useEffect, useLayoutEffect, useRef, useState } from 'react';
2
+ import { createElement, Fragment, useEffect, useLayoutEffect, useRef, useState } from 'react';
3
3
  import { isSubscriptionUsageFresh } from '../shared/contracts/subscription.js';
4
4
  import { DEFAULT_SUBSCRIPTION_USAGE_SETTINGS } from '../shared/contracts/config.js';
5
5
  import { callCliRpc } from './cli-catalog.js';
6
6
  import { resolveCodingNsTranslator, useCodingNsTranslator } from './locale.js';
7
7
  import { providerIconUrl } from './provider-icons.js';
8
+ import { MagpieProviderLogo } from './features/magpie-provider-logo.js';
9
+ 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';
8
11
  import { subscribeSessionAdapters } from './session-adapter-cache.js';
9
12
  import { loadCliSessionConfig } from './cli-session-config-cache.js';
10
13
  import { dshPopupSurfaceStyle, dshSettingsButtonStyle, dshSettingsPrimaryButtonStyle, dshThemeColor } from './theme.js';
11
- import { useDismissOnOutsidePointer } from './popup-dismiss.js';
14
+ import { backdropPointerDownHandler, useDismissOnOutsidePointer } from './popup-dismiss.js';
15
+ import { callCodingNsRpcResult } from './rpc-call.js';
12
16
  import { uiFontSize } from './font-scale.js';
13
17
  const SUBSCRIPTION_STYLE_ID = 'codingns4dsh-subscription-responsive-style';
14
18
  /**
@@ -57,6 +61,7 @@ function loadUsage(rpc, key, payload) {
57
61
  /** 图标重置按钮的悬停/按下/聚焦/禁用只能由注入样式表表达,内联样式无法命中伪类。 */
58
62
  const RESET_BUTTON_CSS = '.codingns4dsh-subscription-reset{display:inline-flex;align-items:center;justify-content:center;flex:none;width:26px;height:26px;padding:0;border:1px solid var(--dsw-alias-border-l2,#d9d9d9);border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary,GrayText);cursor:pointer;transition:background .15s ease,color .15s ease}.codingns4dsh-subscription-reset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}.codingns4dsh-subscription-reset:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active,rgba(127,127,127,.14))}.codingns4dsh-subscription-reset:focus-visible{outline:none;box-shadow:0 0 0 var(--dsw-focus-ring-width,2px) var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#1677ff))}.codingns4dsh-subscription-reset:disabled{opacity:.4;cursor:not-allowed}@media (prefers-reduced-motion: reduce){.codingns4dsh-subscription-reset{transition:none}}';
59
63
  const MAGPIE_ROUTE_CSS = '@keyframes codingns4dsh-magpie-route-pulse{0%{transform:translateY(-120%);opacity:0}20%{opacity:1}80%{opacity:1}100%{transform:translateY(320%);opacity:0}}@keyframes codingns4dsh-magpie-route-breathe{0%,100%{box-shadow:0 0 0 0 rgba(22,119,255,0)}50%{box-shadow:0 0 0 4px rgba(22,119,255,.16)}}@keyframes codingns4dsh-magpie-route-step{from{opacity:0;transform:translateY(4px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.codingns4dsh-magpie-route-pulse{animation:codingns4dsh-magpie-route-pulse 1.8s ease-in-out infinite}.codingns4dsh-magpie-route-node-active{animation:codingns4dsh-magpie-route-breathe 2s ease-in-out infinite}.codingns4dsh-magpie-route-step{animation:codingns4dsh-magpie-route-step .38s cubic-bezier(.2,.75,.25,1) both;transition:background .16s ease}.codingns4dsh-magpie-route-step:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.07))}.codingns4dsh-magpie-route-step:hover .codingns4dsh-magpie-route-node{box-shadow:0 0 0 1px var(--dsw-alias-state-business-primary,#1677ff),0 0 0 4px rgba(22,119,255,.1)}.codingns4dsh-magpie-route-node{transition:box-shadow .16s ease}.codingns4dsh-magpie-tab:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#1677ff)) inset}@media (prefers-reduced-motion:reduce){.codingns4dsh-magpie-route-pulse,.codingns4dsh-magpie-route-node-active,.codingns4dsh-magpie-route-step,.codingns4dsh-magpie-route-node{animation:none;transition:none}}';
64
+ const MAGPIE_REQUESTS_CSS = '.codingns4dsh-magpie-route-requests:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}.codingns4dsh-magpie-route-requests:focus-visible,.codingns4dsh-magpie-requests-close:focus-visible,.codingns4dsh-magpie-requests-retry:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary,#1677ff))}.codingns4dsh-magpie-requests-close:hover,.codingns4dsh-magpie-requests-retry:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(127,127,127,.08));color:var(--dsw-alias-label-primary,CanvasText)}.codingns4dsh-magpie-requests-dialog:focus,.codingns4dsh-magpie-requests-dialog:focus-visible{outline:none}.codingns4dsh-magpie-requests-body{flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.codingns4dsh-magpie-requests-view{display:block!important;width:100%;height:auto!important;min-height:0;padding-left:0!important;background:transparent}.codingns4dsh-magpie-requests-view .codingns-magpie-view{max-width:none;padding:0}@media (max-width:768px){.codingns4dsh-magpie-requests-overlay{align-items:flex-end!important;padding:12px!important}.codingns4dsh-magpie-requests-dialog{width:100%!important;max-height:78vh!important;max-height:78dvh!important}}@media (prefers-reduced-motion:reduce){.codingns4dsh-magpie-route-requests{transition:none}}';
60
65
  export function calculateMagpiePopoverPlacement(rootLeft, viewportWidth, sidebarLeft) {
61
66
  const margin = 12;
62
67
  const boundary = Math.min(viewportWidth - margin, sidebarLeft === null ? viewportWidth - margin : sidebarLeft - margin);
@@ -64,14 +69,19 @@ export function calculateMagpiePopoverPlacement(rootLeft, viewportWidth, sidebar
64
69
  const left = Math.max(margin, Math.min(rootLeft, boundary - width));
65
70
  return { left: left - rootLeft, width };
66
71
  }
67
- /** 移动端订阅入口只保留图标,完整数据仍可在点击后的弹层中查看。 */
72
+ /**
73
+ * 移动端订阅入口只保留图标,完整数据仍可在点击后的弹层中查看。
74
+ * 弹层高度上限固定为浏览器可视高度的 75%:先写 `vh` 兜底,再由 `dvh` 覆盖,
75
+ * 使移动端工具栏收展后仍按真实可视区计算;超出部分在弹层内部纵向滚动。
76
+ */
77
+ export const SUBSCRIPTION_RESPONSIVE_CSS = '@media (max-width: 768px){.codingns4dsh-subscription-trigger{gap:0!important;padding-left:4px!important;padding-right:4px!important}.codingns4dsh-subscription-label,.codingns4dsh-subscription-value{display:none!important}.codingns4dsh-subscription-popover{position:fixed!important;left:12px!important;right:12px!important;bottom:48px!important;width:auto!important;min-width:0!important;max-width:none!important;max-height:75vh!important;max-height:75dvh!important;overflow-x:hidden!important;overflow-y:auto!important;overscroll-behavior:contain!important;box-sizing:border-box!important}}';
68
78
  function installSubscriptionStyles() {
69
79
  if (typeof document === 'undefined' || document.querySelector(`style[data-plugin-css="${SUBSCRIPTION_STYLE_ID}"]`) !== null)
70
80
  return;
71
81
  const style = document.createElement('style');
72
82
  style.dataset.plugin = 'codingns4dsh';
73
83
  style.dataset.pluginCss = SUBSCRIPTION_STYLE_ID;
74
- style.textContent = '@media (max-width: 768px){.codingns4dsh-subscription-trigger{gap:0!important;padding-left:4px!important;padding-right:4px!important}.codingns4dsh-subscription-label,.codingns4dsh-subscription-value{display:none!important}.codingns4dsh-subscription-popover{position:fixed!important;left:12px!important;right:12px!important;bottom:48px!important;width:auto!important;min-width:0!important;max-width:none!important;max-height:calc(100vh - 72px)!important;overflow:auto!important}}' + RESET_BUTTON_CSS + MAGPIE_ROUTE_CSS;
84
+ style.textContent = SUBSCRIPTION_RESPONSIVE_CSS + RESET_BUTTON_CSS + MAGPIE_ROUTE_CSS + MAGPIE_REQUESTS_CSS;
75
85
  document.head.appendChild(style);
76
86
  }
77
87
  /** 在 DSH 原生步骤统计左侧显示当前 Agent 的订阅余量。 */
@@ -101,6 +111,14 @@ function CommandCodeSubscriptionSlot(props) {
101
111
  const [open, setOpen] = useState(false);
102
112
  const [loading, setLoading] = useState(false);
103
113
  const [magpieTab, setMagpieTab] = useState('usage');
114
+ // 多账号厂商默认只展开会话实际使用的账号;展开状态挂在根组件上,
115
+ // 弹层内容本身不持有 Hook,便于无浏览器的组件测试直接展开内容树。
116
+ const [expandedQuotaGroups, setExpandedQuotaGroups] = useState([]);
117
+ const toggleQuotaGroup = (provider) => {
118
+ setExpandedQuotaGroups((current) => current.includes(provider)
119
+ ? current.filter((item) => item !== provider)
120
+ : [...current, provider]);
121
+ };
104
122
  const [magpiePlacement, setMagpiePlacement] = useState({ left: 0, width: 400 });
105
123
  const [clock, setClock] = useState(() => Date.now());
106
124
  const rootRef = useRef(null);
@@ -184,6 +202,9 @@ function CommandCodeSubscriptionSlot(props) {
184
202
  return;
185
203
  }
186
204
  let active = true;
205
+ // 未解析的 Magpie 配额必须快速补读:官方余额一旦抢先显示,用户要等到下一次
206
+ // 轮询(默认 5 分钟)或整页刷新才会切到 Magpie。
207
+ let upstreamUnresolved = false;
187
208
  setEligible(false);
188
209
  setSnapshot(null);
189
210
  setAdapterId(null);
@@ -249,6 +270,7 @@ function CommandCodeSubscriptionSlot(props) {
249
270
  : await loadUsage(props.rpc, cacheKey, payload);
250
271
  if (next !== null)
251
272
  subscriptionUsageCache.set(cacheKey, { usage: next, capturedAt: Date.now() });
273
+ upstreamUnresolved = shouldResolveMagpieQuota(next?.magpie);
252
274
  if (active)
253
275
  setSnapshot(next);
254
276
  }
@@ -267,7 +289,11 @@ function CommandCodeSubscriptionSlot(props) {
267
289
  }
268
290
  };
269
291
  const intervalMins = props.getRefreshIntervalMins?.() ?? DEFAULT_SUBSCRIPTION_USAGE_SETTINGS.refreshIntervalMins;
270
- const poll = startSerialPolling(refresh, Math.max(0, intervalMins) * 60_000, { timeoutMs: 30_000 });
292
+ const pollIntervalMs = Math.max(0, intervalMins) * 60_000;
293
+ const poll = startSerialPolling(refresh, pollIntervalMs, {
294
+ timeoutMs: 30_000,
295
+ getIntervalMs: () => upstreamUnresolved ? Math.min(pollIntervalMs, MAGPIE_QUOTA_RETRY_MS) : pollIntervalMs,
296
+ });
271
297
  refreshRef.current = poll.refresh;
272
298
  return () => {
273
299
  active = false;
@@ -341,7 +367,7 @@ function CommandCodeSubscriptionSlot(props) {
341
367
  return null;
342
368
  if (snapshot.magpie !== null) {
343
369
  const magpie = snapshot.magpie;
344
- const magpieRemaining = resolveMagpieQuotaRemaining(magpie);
370
+ const readout = resolveMagpieTriggerReadout(magpie);
345
371
  const label = t('usage.magpieUsageLabel');
346
372
  return createElement('div', { ref: rootRef, style: subscriptionRootStyle }, createElement('button', {
347
373
  type: 'button',
@@ -356,9 +382,17 @@ function CommandCodeSubscriptionSlot(props) {
356
382
  width: 20,
357
383
  height: 20,
358
384
  style: magpieTriggerImageStyle,
359
- })), magpieRemaining === null
360
- ? createElement('span', { className: 'codingns4dsh-subscription-label', style: subscriptionLabelStyle }, t('usage.magpieShortLabel'))
361
- : createRemainingRing(magpieRemaining)), open && createElement(MagpieUsagePopover, { usage: magpie, t, tab: magpieTab, onTabChange: setMagpieTab, placement: magpiePlacement, popoverRef: magpiePopoverRef }));
385
+ })), createMagpieTriggerReadout(readout, t)), open && createElement(MagpieUsagePopover, {
386
+ rpc: props.rpc,
387
+ usage: magpie,
388
+ t,
389
+ tab: magpieTab,
390
+ onTabChange: setMagpieTab,
391
+ expandedGroups: expandedQuotaGroups,
392
+ onToggleGroup: toggleQuotaGroup,
393
+ placement: magpiePlacement,
394
+ popoverRef: magpiePopoverRef,
395
+ }));
362
396
  }
363
397
  const usage = snapshot.providerUsage;
364
398
  // 未拿到真实订阅数据时不占用底部栏空间;加载状态不能伪装成订阅存在。
@@ -439,7 +473,7 @@ function CommandCodeSubscriptionSlot(props) {
439
473
  dialogRef: resetDialogRef,
440
474
  }));
441
475
  }
442
- function MagpieUsagePopover({ usage, t, tab = 'usage', onTabChange = () => { }, placement = { left: 0, width: 400 }, popoverRef }) {
476
+ function MagpieUsagePopover({ rpc, usage, t, tab = 'usage', onTabChange = () => { }, expandedGroups = [], onToggleGroup = () => { }, placement = { left: 0, width: 400 }, popoverRef }) {
443
477
  const aggregateRows = usage.aggregate === null ? [] : [
444
478
  [t('usage.magpieRequests'), formatMagpieNumber(usage.aggregate.calls)],
445
479
  [t('usage.magpieErrors'), formatMagpieNumber(usage.aggregate.errors)],
@@ -489,12 +523,12 @@ function MagpieUsagePopover({ usage, t, tab = 'usage', onTabChange = () => { },
489
523
  'aria-labelledby': `codingns4dsh-magpie-tab-${tab}`,
490
524
  style: magpieTabPanelStyle,
491
525
  }, tab === 'usage' ? MagpieUsagePanel({ usage, aggregateRows, sessionRows, t })
492
- : MagpieRoutePanel({ usage, quotas, t })));
526
+ : MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup })));
493
527
  }
494
528
  function MagpieUsagePanel({ usage, aggregateRows, sessionRows, t }) {
495
529
  return createElement('div', undefined, createElement('section', { style: magpieUsageSectionStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieAggregateTitle')), usage.usageStatus === 'available'
496
530
  ? createMagpieRows(aggregateRows)
497
- : 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 })), createElement('code', { style: magpieSessionIdStyle }, usage.sessionId)), usage.session === null
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
498
532
  ? createElement('div', { style: magpieMutedTextStyle }, usage.sessionId === null ? t('usage.magpieSessionIdUnavailable') : t('usage.magpieSessionNoUsage'))
499
533
  : createMagpieRows(sessionRows)));
500
534
  }
@@ -512,16 +546,33 @@ function createMagpieProviderBadges(usage, style) {
512
546
  return createElement('span', { style }, ...providers.map((provider) => createElement('span', { key: provider, style: magpieProviderBadgeStyle }, provider)));
513
547
  }
514
548
  function createMagpieQuotaCard(quota, t, index) {
515
- return createElement('div', { key: `${quota.provider}-${quota.user ?? 'account'}-${index}`, style: magpieQuotaCardStyle }, createElement('div', { style: magpieQuotaCardHeadingStyle }, 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
549
+ 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
516
550
  ? createElement('div', { style: magpieQuotaMetaStyle }, t('usage.magpieQuotaNoWindows'))
517
551
  : quota.windows.map((window, windowIndex) => {
518
552
  const remaining = window.remainingPercent;
553
+ // 积分窗口(WorkBuddy 的 `0 / 350`)按数量读更准确:百分比在这里没有意义。
554
+ const credits = formatQuotaWindowCredits(window);
519
555
  const amount = window.display ?? (window.amount !== null && window.limit !== null ? `${window.amount} / ${window.limit}${window.unit === null ? '' : ` ${window.unit}`}` : null);
520
- return createElement('div', { key: `${window.name}-${windowIndex}`, style: magpieQuotaWindowStyle }, createElement('div', { style: windowHeadingStyle }, createElement('span', undefined, window.name), remaining === null ? amount : createElement('strong', undefined, `${formatPercent(remaining)}%`)), remaining !== null && createElement('div', { role: 'progressbar', 'aria-label': t('usage.magpieQuotaRemaining', { name: window.name, percent: formatPercent(remaining) }), 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-valuenow': remaining, style: barStyle }, createElement('span', { style: { ...barFillStyle, width: `${remaining}%` } })), (amount !== null || window.resetsAt !== null) && createElement('div', { style: magpieQuotaFooterStyle }, amount !== null && createElement('span', undefined, amount), window.resetsAt !== null && createElement('span', undefined, t('usage.magpieQuotaResets', { time: formatMagpieTimestamp(window.resetsAt) }))));
556
+ return createElement('div', { key: `${window.name}-${windowIndex}`, style: magpieQuotaWindowStyle }, createElement('div', { style: windowHeadingStyle }, createElement('span', undefined, window.name), credits !== null
557
+ ? createElement('strong', undefined, credits)
558
+ : remaining === null ? amount : createElement('strong', undefined, `${formatPercent(remaining)}%`)),
559
+ // 积分窗口用满格数量条展示已用比例,避免"0% 还能用"的误读。
560
+ remaining !== null && createElement('div', { role: 'progressbar', 'aria-label': t('usage.magpieQuotaRemaining', { name: window.name, percent: formatPercent(remaining) }), 'aria-valuemin': 0, 'aria-valuemax': 100, 'aria-valuenow': remaining, style: barStyle }, createElement('span', { style: { ...barFillStyle, width: `${remaining}%` } })), (amount !== null || window.resetsAt !== null) && createElement('div', { style: magpieQuotaFooterStyle }, amount !== null && createElement('span', undefined, amount), window.resetsAt !== null && createElement('span', undefined, t('usage.magpieQuotaResets', { time: formatMagpieTimestamp(window.resetsAt) }))));
521
561
  }));
522
562
  }
523
- function MagpieRoutePanel({ usage, quotas, t }) {
563
+ /**
564
+ * 单个窗口若是按积分计量,返回"剩余 / 上限"文本;普通百分比窗口返回 null。
565
+ *
566
+ * 卡片会为每个窗口单独调用一次,所以这里按窗口自治判断,不依赖账号整体状态。
567
+ */
568
+ function formatQuotaWindowCredits(window) {
569
+ const credits = readWindowCreditBalance(window);
570
+ return credits === null ? null : formatQuotaCredits(credits);
571
+ }
572
+ function MagpieRoutePanel({ rpc, usage, quotas, t, expandedGroups, onToggleGroup }) {
524
573
  const route = usage.route;
574
+ const groups = groupQuotasByProvider(quotas);
575
+ const sessionAccount = route?.providerAccount ?? null;
525
576
  const quotaMessage = magpieQuotaUnavailableMessage(usage, quotas, t);
526
577
  const routeStatus = usage.routeStatus === 'no-route'
527
578
  ? t('usage.magpieRouteNoRequests')
@@ -543,7 +594,32 @@ function MagpieRoutePanel({ usage, quotas, t }) {
543
594
  ];
544
595
  return createElement('div', undefined, createElement('section', { style: magpieSectionStyle }, createElement('div', { style: magpieQuotaHeadingStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieQuotaTitle')), createMagpieProviderBadges(usage, magpieProviderBadgesStyle)), quotaMessage !== null
545
596
  ? createElement('div', { style: magpieEmptyStateStyle }, quotaMessage)
546
- : quotas.map((quota, index) => createMagpieQuotaCard(quota, t, index))), createElement('section', { style: magpieSectionStyle }, createElement('div', { style: magpieRouteHeadingStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieRouteTitle')), route !== null && 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
597
+ : groups.map((group) => {
598
+ const expanded = expandedGroups.includes(group.provider);
599
+ const multiple = group.accounts.length > 1;
600
+ return createElement('div', { key: group.provider, style: magpieQuotaCardStyle }, createQuotaGroupHeader({
601
+ group,
602
+ t,
603
+ expanded,
604
+ onToggle: multiple ? () => onToggleGroup(group.provider) : null,
605
+ }), group.accounts.map((quota, index) => createElement('div', { key: `${group.provider}-${quota.user ?? 'account'}-${index}` }, createQuotaAccountBlock(quota, {
606
+ t,
607
+ nowMs: Date.now(),
608
+ // 单账号厂商由组头承担名称,账号块不再重复。
609
+ showAccountName: multiple,
610
+ // 组未展开时只留会话账号的明细,其余账号折叠成余量行。
611
+ compact: multiple && !expanded && quota.active !== true && (sessionAccount === null || quota.user !== sessionAccount),
612
+ fallbackName: group.name === '' ? group.provider : group.name,
613
+ }))));
614
+ })), createElement('section', { style: magpieSectionStyle }, createElement('div', { style: magpieRouteHeadingStyle }, createElement('strong', { style: magpieSectionTitleStyle }, t('usage.magpieRouteTitle')), route !== null && createElement('div', { style: magpieRouteHeadingActionsStyle },
615
+ // “查看请求”入口与状态徽标同高、同排:入口在左,状态在右。
616
+ createElement(MagpieRouteRequests, {
617
+ rpc,
618
+ sessionId: usage.sessionId,
619
+ sessionName: usage.sessionName ?? null,
620
+ agent: usage.agent,
621
+ t,
622
+ }), 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
547
623
  ? createElement('div', { style: magpieEmptyStateStyle }, routeStatus)
548
624
  : createElement('div', { style: magpieRouteHeroStyle }, createElement('div', { style: magpieRouteTrackStyle, 'aria-label': t('usage.magpieRouteFlowTitle'), role: 'list' }, ...routeStages.map(([label, model], index) => createElement('div', {
549
625
  key: `step-${index}`,
@@ -552,6 +628,165 @@ function MagpieRoutePanel({ usage, quotas, t }) {
552
628
  style: { ...magpieRouteTrackItemStyle, animationDelay: `${index * 90}ms` },
553
629
  }, createElement('div', { style: magpieRouteMarkerColumnStyle, 'aria-hidden': true }, createElement('div', { className: 'codingns4dsh-magpie-route-node', style: magpieRouteNodeStyle }, createElement('span', { style: magpieRouteNodeDotStyle })), index < routeStages.length - 1 && createElement('div', { style: magpieRouteConnectorStyle }, active && createElement('span', { className: 'codingns4dsh-magpie-route-pulse', style: magpieRoutePulseStyle }))), createElement('div', { style: magpieRouteStageCopyStyle }, createElement('span', { style: magpieRouteStageLabelStyle }, label), createElement('strong', { style: magpieRouteStageValueStyle, title: model }, model))))), routeRows.length > 0 && createElement('div', { style: magpieRouteMetaStyle }, ...routeRows.filter((row) => row[1] !== null).map(([label, value]) => createElement('div', { key: label, style: magpieRouteMetaItemStyle }, createElement('span', { style: magpieRouteMetaLabelStyle }, label), createElement('strong', { style: magpieRouteMetaValueStyle, title: value }, value)))), route.tries.length > 0 && createElement('div', { style: magpieAttemptsStyle }, ...route.tries.map((attempt, index) => createElement('div', { key: `${attempt.model ?? 'model'}-${index}`, style: magpieAttemptRowStyle }, createElement('span', { style: magpieAttemptModelStyle }, attempt.model ?? t('usage.magpieUnknownModel')), attempt.failed && createElement('span', { style: magpieFailedStyle }, t('usage.magpieFallback'))))))));
554
630
  }
631
+ /**
632
+ * 路由标题栏的“查看请求”入口:按钮、模态框与读取状态放在同一个子组件里。
633
+ *
634
+ * 弹层内容本身不持有 Hook(无浏览器测试会直接展开内容树),因此这里只由
635
+ * `MagpieRoutePanel` 渲染元素,真正的状态留在本组件内部。模态框内的请求明细
636
+ * 直接复用管理页的 `RequestsPage`,只把会话筛选固定为当前会话。
637
+ */
638
+ export function MagpieRouteRequests({ rpc, sessionId, sessionName, agent, t }) {
639
+ const enabled = canReadMagpieSessionRequests(sessionId, agent);
640
+ const [open, setOpen] = useState(false);
641
+ const [page, setPage] = useState(null);
642
+ const [offset, setOffset] = useState(0);
643
+ const [loading, setLoading] = useState(false);
644
+ const [error, setError] = useState(false);
645
+ const [reloadKey, setReloadKey] = useState(0);
646
+ const controllerRef = useRef(null);
647
+ useEffect(() => {
648
+ if (!open || !enabled)
649
+ return;
650
+ const controller = new AbortController();
651
+ controllerRef.current = controller;
652
+ setLoading(true);
653
+ setError(false);
654
+ void readMagpieSessionRequestPage(rpc, sessionId, agent, offset, controller.signal).then((next) => {
655
+ if (controller.signal.aborted)
656
+ return;
657
+ if (next === null) {
658
+ setError(true);
659
+ return;
660
+ }
661
+ setPage(next);
662
+ }).catch(() => {
663
+ if (!controller.signal.aborted)
664
+ setError(true);
665
+ }).finally(() => {
666
+ if (!controller.signal.aborted)
667
+ setLoading(false);
668
+ });
669
+ return () => {
670
+ controller.abort();
671
+ if (controllerRef.current === controller)
672
+ controllerRef.current = null;
673
+ };
674
+ }, [open, enabled, offset, reloadKey, rpc, sessionId, agent]);
675
+ // 模态框覆盖整个视口,Esc 是移动端之外唯一的键盘关闭方式。
676
+ useEffect(() => {
677
+ if (!open || typeof document === 'undefined')
678
+ return;
679
+ // 捕获阶段拦截 Esc:只关闭模态框,不再让底部弹层的关闭监听把整个弹层一起收起。
680
+ const onKeyDown = (event) => {
681
+ if (event.key !== 'Escape')
682
+ return;
683
+ event.stopPropagation();
684
+ setOpen(false);
685
+ };
686
+ document.addEventListener('keydown', onKeyDown, true);
687
+ return () => document.removeEventListener('keydown', onKeyDown, true);
688
+ }, [open]);
689
+ const close = () => {
690
+ controllerRef.current?.abort();
691
+ controllerRef.current = null;
692
+ setOpen(false);
693
+ };
694
+ const openRequests = () => {
695
+ controllerRef.current?.abort();
696
+ setPage(null);
697
+ setOffset(0);
698
+ setError(false);
699
+ setLoading(true);
700
+ // 请求明细复用管理页组件,需要先装上管理页自己的样式表。
701
+ installMagpiePageStyles();
702
+ setOpen(true);
703
+ };
704
+ return createElement(Fragment, undefined, enabled && createElement('button', {
705
+ type: 'button',
706
+ className: 'codingns4dsh-magpie-route-requests',
707
+ onClick: openRequests,
708
+ 'aria-haspopup': 'dialog',
709
+ title: t('usage.magpieViewRequests'),
710
+ style: magpieRouteRequestsButtonStyle,
711
+ }, t('usage.magpieViewRequests')), enabled && open && createElement(MagpieSessionRequestsDialog, {
712
+ sessionId,
713
+ sessionName,
714
+ agent,
715
+ page,
716
+ offset,
717
+ loading,
718
+ error,
719
+ t,
720
+ onClose: close,
721
+ onOffsetChange: setOffset,
722
+ onRetry: () => { setLoading(true); setError(false); setReloadKey((value) => value + 1); },
723
+ }));
724
+ }
725
+ /** Host 只接受小写 Agent ID;会话与 Agent 必须成对出现,缺一不可。 */
726
+ function canReadMagpieSessionRequests(sessionId, agent) {
727
+ return sessionId !== null && sessionId.trim() !== '' && sessionId.length <= 512 && /^[a-z0-9][a-z0-9-]*$/u.test(agent);
728
+ }
729
+ /** 只读取今天的会话请求,与路由卡片和“当前 Agent 会话”用量保持同一时间口径。 */
730
+ async function readMagpieSessionRequestPage(rpc, sessionId, agent, offset, signal) {
731
+ const result = await callCodingNsRpcResult(rpc, 'magpie/usage/requests', {
732
+ period: 'today',
733
+ offset,
734
+ limit: MAGPIE_REQUESTS_PAGE_SIZE,
735
+ sessionId,
736
+ sessionAgent: agent,
737
+ }, signal);
738
+ if (!result.ok)
739
+ throw new Error(result.error.message);
740
+ const value = result.value;
741
+ return isRecord(value) && Array.isArray(value.items)
742
+ ? value
743
+ : null;
744
+ }
745
+ /**
746
+ * 请求模态框:外壳(遮罩、标题、关闭)由弹层提供,明细直接复用管理页的请求用量视图。
747
+ *
748
+ * 管理页视图自带统计条、桌面表格 / 移动卡片、分页和空状态,这里只负责把会话固定住,
749
+ * 不再维护一套重复的请求卡片渲染。
750
+ */
751
+ function MagpieSessionRequestsDialog({ sessionId, sessionName, agent, page, offset, loading, error, t, onClose, onOffsetChange, onRetry }) {
752
+ return createElement('div', {
753
+ className: 'codingns4dsh-magpie-requests-overlay',
754
+ role: 'presentation',
755
+ style: magpieRequestsOverlayStyle,
756
+ // 只有按在遮罩自身时才关闭;从内容内部按下再拖到遮罩上不会误关。
757
+ onPointerDown: backdropPointerDownHandler(onClose),
758
+ }, createElement('div', {
759
+ role: 'dialog',
760
+ 'aria-modal': true,
761
+ 'aria-label': t('usage.magpieRequestsTitle'),
762
+ className: 'codingns4dsh-magpie-requests-dialog',
763
+ tabIndex: -1,
764
+ autoFocus: true,
765
+ style: magpieRequestsDialogStyle,
766
+ }, createElement('div', { style: magpieRequestsHeadingStyle }, createElement('strong', { style: magpieRequestsTitleStyle }, t('usage.magpieRequestsTitle')), createElement('div', { style: magpieRequestsHeadingActionsStyle }, error && createElement('button', {
767
+ type: 'button',
768
+ className: 'codingns4dsh-magpie-requests-retry',
769
+ onClick: onRetry,
770
+ style: magpieRequestsRetryStyle,
771
+ }, t('magpie.refresh')), createElement('button', {
772
+ type: 'button',
773
+ className: 'codingns4dsh-magpie-requests-close',
774
+ onClick: onClose,
775
+ 'aria-label': t('usage.magpieRequestsClose'),
776
+ style: magpieRequestsCloseStyle,
777
+ }, '×'))), createElement('div', { className: 'codingns4dsh-magpie-requests-body', style: magpieRequestsBodyStyle },
778
+ // `.codingns-magpie-page` 提供管理页的 `--mp-*` 主题变量;外层样式再把它压进弹层尺寸。
779
+ createElement('div', { className: 'codingns-magpie-page codingns4dsh-magpie-requests-view' }, createElement(RequestsPage, {
780
+ page,
781
+ loading,
782
+ error,
783
+ selectedSession: { id: sessionId, agent, ...(sessionName === null ? {} : { dshSessionName: sessionName }) },
784
+ offset,
785
+ onOffsetChange,
786
+ onClearSession: null,
787
+ t,
788
+ })))));
789
+ }
555
790
  function createMagpieRows(rows) {
556
791
  if (rows.length === 0)
557
792
  return createElement('div', { style: magpieMutedTextStyle }, '--');
@@ -954,8 +1189,26 @@ function createModelRow(model, unit) {
954
1189
  function resolveDisplayWindow(usage) {
955
1190
  return usage.primary ?? usage.secondary ?? usage.monthly;
956
1191
  }
1192
+ /** 配额解析完成前的补读间隔;与弹层打开时的路由读取共用串行轮询。 */
1193
+ const MAGPIE_QUOTA_RETRY_MS = 3_000;
1194
+ /**
1195
+ * Magpie 用量入口是否还需要带路由补读。
1196
+ *
1197
+ * Host 会为「已确认属于 Magpie、但会话身份还没写进账本」的模型下发带会话数据的
1198
+ * `provider-unavailable` 占位快照;还在启动中的网关则是 `unavailable`。
1199
+ * 两种状态都表示上游未知,必须按 `MAGPIE_QUOTA_RETRY_MS` 快速重新解析,否则首屏
1200
+ * 会一直停在官方余额或 Magpie 标签上,直到整页刷新。
1201
+ *
1202
+ * 上游已解析(`provider-unavailable` 但 `upstreamProvider` 有值,例如该厂商本来
1203
+ * 就不上报任何配额窗口)不再补读——再读也只是重复确认同一个结论。没有上游信息的
1204
+ * 占位快照才有资格要求补读,Host 也只在这种情况下才下发它。
1205
+ */
957
1206
  function shouldResolveMagpieQuota(usage) {
958
- return usage?.quotaStatus === 'provider-unavailable' && usage.sessionId !== null && usage.session !== null;
1207
+ if (usage === null || usage === undefined)
1208
+ return false;
1209
+ if (usage.quotaStatus !== 'available')
1210
+ return usage.upstreamProvider === null;
1211
+ return usage.sessionId !== null && usage.session !== null && usage.quotas.length === 0;
959
1212
  }
960
1213
  function resolveMagpieQuotaRemaining(usage) {
961
1214
  if (usage.quotaStatus !== 'available')
@@ -968,6 +1221,41 @@ function resolveMagpieQuotaRemaining(usage) {
968
1221
  }
969
1222
  return null;
970
1223
  }
1224
+ function resolveMagpieTriggerReadout(usage) {
1225
+ const remaining = resolveMagpieQuotaRemaining(usage);
1226
+ if (remaining !== null)
1227
+ return { kind: 'ring', percent: remaining };
1228
+ const quotas = usage.quotas ?? [];
1229
+ const balance = resolveQuotaBalanceLabel(quotas);
1230
+ if (balance !== null)
1231
+ return { kind: 'money', text: balance };
1232
+ const credits = resolveQuotaCreditsLabel(quotas);
1233
+ if (credits !== null)
1234
+ return { kind: 'credits', text: credits };
1235
+ return { kind: 'label' };
1236
+ }
1237
+ /** 积分余额的展示文本:只给数量,单位放在 title 里,不占用底部栏宽度。 */
1238
+ function resolveQuotaCreditsLabel(quotas) {
1239
+ for (const quota of quotas) {
1240
+ const credits = resolveQuotaCreditBalance(quota);
1241
+ if (credits === null || !(credits.remaining > 0))
1242
+ continue;
1243
+ return formatQuotaNumber(credits.remaining);
1244
+ }
1245
+ return null;
1246
+ }
1247
+ function createMagpieTriggerReadout(readout, t) {
1248
+ switch (readout.kind) {
1249
+ case 'ring':
1250
+ return createRemainingRing(readout.percent);
1251
+ case 'money':
1252
+ return createElement('span', { className: 'codingns4dsh-subscription-value', style: magpieBalanceStyle, title: t('usage.accountBalance') }, readout.text);
1253
+ case 'credits':
1254
+ return createElement('span', { className: 'codingns4dsh-subscription-value', style: magpieBalanceStyle, title: t('usage.creditBalanceLabel') }, readout.text);
1255
+ default:
1256
+ return createElement('span', { className: 'codingns4dsh-subscription-label', style: subscriptionLabelStyle }, t('usage.magpieShortLabel'));
1257
+ }
1258
+ }
971
1259
  function selectDeepseekBalance(usage) {
972
1260
  return usage.balances.find((balance) => balance.currency.toUpperCase() === 'USD') ?? usage.balances[0] ?? null;
973
1261
  }
@@ -1103,6 +1391,8 @@ function formatCreditBalance(value) {
1103
1391
  const subscriptionRootStyle = { position: 'relative', minWidth: 0, display: 'inline-flex', alignItems: 'center' };
1104
1392
  const subscriptionTriggerStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, height: 28, border: 0, borderRadius: 14, padding: '0 8px 0 4px', color: dshThemeColor.labelSecondary, background: 'transparent', cursor: 'pointer', fontSize: uiFontSize(13), lineHeight: '20px' };
1105
1393
  const subscriptionLabelStyle = { whiteSpace: 'nowrap' };
1394
+ // 余额金额与积分和百分比环并排/替换显示:数字用等宽字形,避免刷新时抖动。
1395
+ const magpieBalanceStyle = { display: 'inline-flex', alignItems: 'center', whiteSpace: 'nowrap', color: dshThemeColor.labelSecondary, fontSize: uiFontSize(12), fontWeight: 600, fontVariantNumeric: 'tabular-nums' };
1106
1396
  const magpieTriggerIconStyle = { display: 'inline-flex', width: 20, height: 20, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', borderRadius: 6, background: dshThemeColor.surfaceSubtle };
1107
1397
  const magpieTriggerImageStyle = { display: 'block', width: '100%', height: '100%', objectFit: 'cover' };
1108
1398
  const magpieMutedTextStyle = { color: dshThemeColor.labelTertiary, fontSize: uiFontSize(12), lineHeight: '17px', overflowWrap: 'anywhere' };
@@ -1122,6 +1412,7 @@ const magpieStatStyle = { display: 'grid', alignContent: 'space-between', gap: 1
1122
1412
  const magpieStatLabelStyle = { minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '13px', overflowWrap: 'anywhere' };
1123
1413
  const magpieRowValueStyle = { color: dshThemeColor.labelPrimary, fontSize: uiFontSize(14), fontWeight: 650, lineHeight: '18px', textAlign: 'right', overflowWrap: 'anywhere' };
1124
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' };
1125
1416
  const magpieSessionIdStyle = { flex: '1 1 120px', minWidth: 0, color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '14px', whiteSpace: 'normal', overflowWrap: 'anywhere' };
1126
1417
  const magpieAttemptsStyle = { display: 'grid', gap: 5, paddingTop: 6 };
1127
1418
  const magpieAttemptRowStyle = { display: 'flex', justifyContent: 'space-between', gap: 14, fontSize: uiFontSize(12) };
@@ -1133,6 +1424,7 @@ const magpieProviderBadgeStyle = { flex: 'none', maxWidth: 220, overflow: 'hidde
1133
1424
  const magpieEmptyStateStyle = { display: 'grid', placeItems: 'center', minHeight: 36, padding: '8px 10px', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(12), lineHeight: '17px', textAlign: 'center' };
1134
1425
  const magpieQuotaCardStyle = { display: 'grid', gap: 5, marginTop: 7, padding: '9px 10px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 9, background: dshThemeColor.surfaceSubtle };
1135
1426
  const magpieQuotaCardHeadingStyle = { display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 10 };
1427
+ const magpieQuotaNameWithLogoStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, minWidth: 0, overflow: 'hidden' };
1136
1428
  const magpieQuotaNameStyle = { minWidth: 0, overflow: 'hidden', color: dshThemeColor.labelPrimary, fontSize: uiFontSize(13), fontWeight: 650, textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
1137
1429
  const magpieQuotaHeadingMetaStyle = { flex: 'none', maxWidth: 160, overflow: 'hidden', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(11), textOverflow: 'ellipsis', whiteSpace: 'nowrap' };
1138
1430
  const magpieQuotaIdentityStyle = { display: 'flex', flexWrap: 'wrap', gap: '3px 12px', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(11), lineHeight: '15px', overflowWrap: 'anywhere' };
@@ -1141,7 +1433,7 @@ const magpieQuotaWindowStyle = { display: 'grid', gap: 4, paddingTop: 3 };
1141
1433
  const magpieQuotaFooterStyle = { display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: '3px 10px', color: dshThemeColor.labelTertiary, fontSize: uiFontSize(11), lineHeight: '15px' };
1142
1434
  const magpieRouteHeadingStyle = { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 10 };
1143
1435
  const magpieRouteHeroStyle = { display: 'grid', gap: 11, padding: '12px 13px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 12, background: `linear-gradient(145deg, ${dshThemeColor.surfaceSubtle}, transparent)` };
1144
- const magpieRouteStatusStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, width: 'fit-content', padding: '3px 8px', borderRadius: 999, background: dshThemeColor.surfaceSubtle, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(11), whiteSpace: 'nowrap' };
1436
+ const magpieRouteStatusStyle = { display: 'inline-flex', alignItems: 'center', gap: 6, width: 'fit-content', boxSizing: 'border-box', padding: '3px 8px', borderRadius: 999, background: dshThemeColor.surfaceSubtle, color: dshThemeColor.labelSecondary, fontSize: uiFontSize(11), lineHeight: '15px', whiteSpace: 'nowrap' };
1145
1437
  const magpieRouteStatusDotStyle = { width: 8, height: 8, borderRadius: '50%', background: dshThemeColor.accent };
1146
1438
  const magpieRouteTrackStyle = { display: 'grid', gap: 0, minWidth: 0, padding: '3px 0' };
1147
1439
  const magpieRouteTrackItemStyle = { display: 'grid', gridTemplateColumns: '18px minmax(0, 1fr)', alignItems: 'start', gap: 12, minWidth: 0, padding: '5px 8px', margin: '0 -8px', borderRadius: 8 };
@@ -1157,6 +1449,17 @@ const magpieRouteMetaStyle = { display: 'grid', gridTemplateColumns: 'repeat(2,
1157
1449
  const magpieRouteMetaItemStyle = { display: 'grid', alignContent: 'start', gap: 3, minWidth: 0, padding: '6px 8px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 8, background: dshThemeColor.menuBackground };
1158
1450
  const magpieRouteMetaLabelStyle = { color: dshThemeColor.labelTertiary, fontSize: uiFontSize(10), lineHeight: '13px' };
1159
1451
  const magpieRouteMetaValueStyle = { color: dshThemeColor.labelSecondary, fontSize: uiFontSize(11), fontWeight: 550, lineHeight: '15px', overflowWrap: 'anywhere' };
1452
+ // 请求入口与请求模态框:入口与状态徽标同高并排在标题栏,模态框覆盖视口并在内部滚动。
1453
+ const magpieRouteHeadingActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 8, minWidth: 0 };
1454
+ 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 };
1456
+ 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
+ const magpieRequestsHeadingStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, paddingBottom: 10, borderBottom: `1px solid ${dshThemeColor.border}` };
1458
+ const magpieRequestsHeadingActionsStyle = { display: 'inline-flex', alignItems: 'center', gap: 8, flex: 'none' };
1459
+ const magpieRequestsTitleStyle = { fontSize: uiFontSize(15), lineHeight: '20px' };
1460
+ const magpieRequestsCloseStyle = { flex: 'none', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 28, height: 28, padding: 0, border: 0, borderRadius: '50%', background: 'transparent', color: dshThemeColor.labelSecondary, fontSize: uiFontSize(18), lineHeight: 1, cursor: 'pointer' };
1461
+ const magpieRequestsBodyStyle = { flex: '1 1 auto', minHeight: 0, overflowY: 'auto', overscrollBehavior: 'contain' };
1462
+ const magpieRequestsRetryStyle = { padding: '5px 12px', border: `1px solid ${dshThemeColor.border}`, borderRadius: 999, background: dshThemeColor.menuBackground, color: dshThemeColor.labelSecondary, fontFamily: 'inherit', fontSize: uiFontSize(11), lineHeight: '15px', cursor: 'pointer' };
1160
1463
  const sub2apiIdentityStyle = { display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' };
1161
1464
  const sub2apiLogoStyle = { display: 'block', borderRadius: 4, objectFit: 'contain' };
1162
1465
  const deepseekBalanceIdentityStyle = { display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' };