@jingyi0605/codingns4dsh 0.1.0 → 0.1.1

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 (216) hide show
  1. package/README.en.md +306 -0
  2. package/README.md +190 -993
  3. package/data/build/dist/client/account-bar.d.ts +2 -2
  4. package/data/build/dist/client/account-bar.js +96 -39
  5. package/data/build/dist/client/bundle.js +13722 -3611
  6. package/data/build/dist/client/cli-catalog.js +20 -3
  7. package/data/build/dist/client/cli-slots.d.ts +5 -0
  8. package/data/build/dist/client/cli-slots.js +57 -7
  9. package/data/build/dist/client/debug/ui.d.ts +1 -1
  10. package/data/build/dist/client/debug/ui.js +62 -32
  11. package/data/build/dist/client/dsh-runtime-version.d.ts +9 -2
  12. package/data/build/dist/client/dsh-runtime-version.js +24 -2
  13. package/data/build/dist/client/features/cli-adapters.d.ts +1 -1
  14. package/data/build/dist/client/features/cli-adapters.js +19 -16
  15. package/data/build/dist/client/features/debug.js +2 -2
  16. package/data/build/dist/client/features/index.d.ts +2 -1
  17. package/data/build/dist/client/features/index.js +3 -1
  18. package/data/build/dist/client/features/lan-access-panel.d.ts +1 -1
  19. package/data/build/dist/client/features/lan-access-panel.js +8 -10
  20. package/data/build/dist/client/features/lan-access.js +1 -1
  21. package/data/build/dist/client/features/login-protection-panel.d.ts +1 -1
  22. package/data/build/dist/client/features/login-protection-panel.js +7 -9
  23. package/data/build/dist/client/features/reverse-proxy-panel.d.ts +1 -1
  24. package/data/build/dist/client/features/reverse-proxy-panel.js +99 -11
  25. package/data/build/dist/client/features/reverse-proxy.d.ts +1 -1
  26. package/data/build/dist/client/features/reverse-proxy.js +19 -18
  27. package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +1 -1
  28. package/data/build/dist/client/features/terminal-enhancement-panel.js +62 -55
  29. package/data/build/dist/client/features/terminal-enhancement.d.ts +1 -1
  30. package/data/build/dist/client/features/terminal-enhancement.js +3 -3
  31. package/data/build/dist/client/features/types.d.ts +14 -3
  32. package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +1 -1
  33. package/data/build/dist/client/features/workspace-session-enhancement-panel.js +31 -9
  34. package/data/build/dist/client/features/workspace-session-enhancement.js +72 -11
  35. package/data/build/dist/client/git-management.d.ts +16 -0
  36. package/data/build/dist/client/git-management.js +757 -0
  37. package/data/build/dist/client/index.d.ts +3 -2
  38. package/data/build/dist/client/index.js +152 -27
  39. package/data/build/dist/client/locale.js +91 -29
  40. package/data/build/dist/client/quick-phrase-layout.d.ts +49 -0
  41. package/data/build/dist/client/quick-phrase-layout.js +95 -0
  42. package/data/build/dist/client/quick-phrase-slot.d.ts +7 -0
  43. package/data/build/dist/client/quick-phrase-slot.js +370 -0
  44. package/data/build/dist/client/remote-web-context.js +1 -1
  45. package/data/build/dist/client/settings-bridge.d.ts +9 -6
  46. package/data/build/dist/client/settings-bridge.js +51 -27
  47. package/data/build/dist/client/settings-section.d.ts +3 -2
  48. package/data/build/dist/client/settings-section.js +33 -19
  49. package/data/build/dist/client/subscription-slot.d.ts +3 -0
  50. package/data/build/dist/client/subscription-slot.js +108 -16
  51. package/data/build/dist/client/terminal/model.d.ts +14 -2
  52. package/data/build/dist/client/terminal/model.js +109 -21
  53. package/data/build/dist/client/terminal/recovery.d.ts +50 -0
  54. package/data/build/dist/client/terminal/recovery.js +101 -0
  55. package/data/build/dist/client/terminal/ui.d.ts +2 -2
  56. package/data/build/dist/client/terminal/ui.js +49 -11
  57. package/data/build/dist/client/terminal/xterm-view.d.ts +2 -2
  58. package/data/build/dist/client/terminal/xterm-view.js +2 -1
  59. package/data/build/dist/client/theme.d.ts +6 -1
  60. package/data/build/dist/client/theme.js +32 -1
  61. package/data/build/dist/client/workspace-session-archive-dom.d.ts +12 -0
  62. package/data/build/dist/client/workspace-session-archive-dom.js +27 -5
  63. package/data/build/dist/client/workspace-session-visibility-dom.d.ts +30 -0
  64. package/data/build/dist/client/workspace-session-visibility-dom.js +604 -0
  65. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +50 -0
  66. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +139 -0
  67. package/data/build/dist/dsh-capabilities/client/conversation-adapter.d.ts +7 -0
  68. package/data/build/dist/dsh-capabilities/client/conversation-adapter.js +6 -0
  69. package/data/build/dist/dsh-capabilities/client/locale-adapter.d.ts +9 -0
  70. package/data/build/dist/dsh-capabilities/client/locale-adapter.js +4 -0
  71. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +10 -0
  72. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +14 -0
  73. package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +8 -0
  74. package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.js +16 -0
  75. package/data/build/dist/dsh-capabilities/client/sidebar-adapter.d.ts +7 -0
  76. package/data/build/dist/dsh-capabilities/client/sidebar-adapter.js +5 -0
  77. package/data/build/dist/dsh-capabilities/client/theme-adapter.d.ts +6 -0
  78. package/data/build/dist/dsh-capabilities/client/theme-adapter.js +4 -0
  79. package/data/build/dist/dsh-capabilities/client/typert-adapter.d.ts +5 -0
  80. package/data/build/dist/dsh-capabilities/client/typert-adapter.js +4 -0
  81. package/data/build/dist/dsh-capabilities/host/config-forms-adapter.d.ts +19 -0
  82. package/data/build/dist/dsh-capabilities/host/config-forms-adapter.js +45 -0
  83. package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.d.ts +19 -0
  84. package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.js +13 -0
  85. package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.d.ts +8 -0
  86. package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.js +47 -0
  87. package/data/build/dist/dsh-capabilities/host/typert-adapter.d.ts +6 -0
  88. package/data/build/dist/dsh-capabilities/host/typert-adapter.js +4 -0
  89. package/data/build/dist/dsh-capabilities/index.d.ts +6 -0
  90. package/data/build/dist/dsh-capabilities/index.js +6 -0
  91. package/data/build/dist/dsh-capabilities/matrix.d.ts +15 -0
  92. package/data/build/dist/dsh-capabilities/matrix.js +32 -0
  93. package/data/build/dist/dsh-capabilities/registry.d.ts +22 -0
  94. package/data/build/dist/dsh-capabilities/registry.js +196 -0
  95. package/data/build/dist/dsh-capabilities/routes.d.ts +10 -0
  96. package/data/build/dist/dsh-capabilities/routes.js +34 -0
  97. package/data/build/dist/dsh-capabilities/settings-store.d.ts +29 -0
  98. package/data/build/dist/dsh-capabilities/settings-store.js +5 -0
  99. package/data/build/dist/dsh-capabilities/types.d.ts +50 -0
  100. package/data/build/dist/dsh-capabilities/types.js +23 -0
  101. package/data/build/dist/features/registry.d.ts +8 -2
  102. package/data/build/dist/features/registry.js +104 -1
  103. package/data/build/dist/host/auth-session.d.ts +8 -1
  104. package/data/build/dist/host/auth-session.js +28 -6
  105. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +2 -0
  106. package/data/build/dist/host/cli-adapters/claude-driver.js +19 -4
  107. package/data/build/dist/host/cli-adapters/claude-model-options.d.ts +14 -0
  108. package/data/build/dist/host/cli-adapters/claude-model-options.js +157 -0
  109. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +11 -0
  110. package/data/build/dist/host/cli-adapters/codex-driver.js +166 -14
  111. package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
  112. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +15 -0
  113. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +120 -29
  114. package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +4 -1
  115. package/data/build/dist/host/cli-adapters/dsh-tool-history.js +25 -7
  116. package/data/build/dist/host/cli-adapters/feature.js +74 -8
  117. package/data/build/dist/host/cli-adapters/gemini-driver.js +2 -2
  118. package/data/build/dist/host/cli-adapters/grok-driver.js +2 -2
  119. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +4 -2
  120. package/data/build/dist/host/cli-adapters/json-rpc-process.js +8 -9
  121. package/data/build/dist/host/cli-adapters/kimi-driver.js +1 -1
  122. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +17 -0
  123. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +88 -0
  124. package/data/build/dist/host/cli-adapters/legacy-session-settings.d.ts +24 -0
  125. package/data/build/dist/host/cli-adapters/legacy-session-settings.js +162 -0
  126. package/data/build/dist/host/cli-adapters/official-provider-subscription.d.ts +29 -0
  127. package/data/build/dist/host/cli-adapters/official-provider-subscription.js +361 -0
  128. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +2 -0
  129. package/data/build/dist/host/cli-adapters/opencode-driver.js +97 -12
  130. package/data/build/dist/host/cli-adapters/pi-driver.js +69 -23
  131. package/data/build/dist/host/cli-adapters/provider-registry.d.ts +33 -0
  132. package/data/build/dist/host/cli-adapters/provider-registry.js +83 -0
  133. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +25 -3
  134. package/data/build/dist/host/cli-adapters/provider-subscription.js +346 -30
  135. package/data/build/dist/host/cli-adapters/registry.d.ts +6 -0
  136. package/data/build/dist/host/cli-adapters/registry.js +170 -13
  137. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +10 -0
  138. package/data/build/dist/host/cli-adapters/session-store.d.ts +7 -0
  139. package/data/build/dist/host/cli-adapters/session-store.js +39 -1
  140. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +3 -0
  141. package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +3 -0
  142. package/data/build/dist/host/cli-adapters/stream-normalizer.js +22 -2
  143. package/data/build/dist/host/control-api-client.d.ts +3 -3
  144. package/data/build/dist/host/control-api-client.js +2 -1
  145. package/data/build/dist/host/credential-store.js +11 -1
  146. package/data/build/dist/host/dsh-device-runtime.d.ts +4 -0
  147. package/data/build/dist/host/dsh-device-runtime.js +20 -9
  148. package/data/build/dist/host/dsh-runtime-version.d.ts +3 -2
  149. package/data/build/dist/host/dsh-runtime-version.js +71 -2
  150. package/data/build/dist/host/features/auth.js +8 -5
  151. package/data/build/dist/host/features/debug.js +1 -1
  152. package/data/build/dist/host/features/git-management.d.ts +5 -0
  153. package/data/build/dist/host/features/git-management.js +290 -0
  154. package/data/build/dist/host/features/host-status.js +1 -1
  155. package/data/build/dist/host/features/index.d.ts +1 -0
  156. package/data/build/dist/host/features/index.js +3 -0
  157. package/data/build/dist/host/features/terminal-process.js +1 -1
  158. package/data/build/dist/host/features/terminal-status.d.ts +3 -1
  159. package/data/build/dist/host/features/terminal-status.js +3 -1
  160. package/data/build/dist/host/index.d.ts +7 -3
  161. package/data/build/dist/host/index.js +79 -15
  162. package/data/build/dist/host/lan-access-dsh.js +18 -5
  163. package/data/build/dist/host/native-session-bridge.d.ts +23 -1
  164. package/data/build/dist/host/native-session-bridge.js +157 -10
  165. package/data/build/dist/host/rpc-table.d.ts +1 -1
  166. package/data/build/dist/host/rpc.js +60 -10
  167. package/data/build/dist/host/session-migration-repair.d.ts +19 -0
  168. package/data/build/dist/host/session-migration-repair.js +395 -0
  169. package/data/build/dist/host/settings.d.ts +8 -1
  170. package/data/build/dist/host/settings.js +94 -3
  171. package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +1 -0
  172. package/data/build/dist/host/terminal/backends/tmux-backend.js +4 -2
  173. package/data/build/dist/host/terminal/controller-factory.d.ts +4 -0
  174. package/data/build/dist/host/terminal/controller-factory.js +26 -7
  175. package/data/build/dist/host/terminal/runtime-manager.d.ts +2 -1
  176. package/data/build/dist/host/terminal/runtime-manager.js +3 -0
  177. package/data/build/dist/host/terminal/startup.d.ts +2 -0
  178. package/data/build/dist/host/terminal/startup.js +2 -1
  179. package/data/build/dist/host/terminal/terminal-controller.d.ts +10 -3
  180. package/data/build/dist/host/terminal/terminal-controller.js +101 -15
  181. package/data/build/dist/host/terminal/terminal-process-service.js +3 -1
  182. package/data/build/dist/host/terminal/terminal-service.d.ts +2 -0
  183. package/data/build/dist/host/terminal/terminal-service.js +10 -0
  184. package/data/build/dist/index.d.ts +6 -2
  185. package/data/build/dist/index.js +8 -2
  186. package/data/build/dist/shared/contracts/cli-adapter.d.ts +14 -0
  187. package/data/build/dist/shared/contracts/config.d.ts +31 -1
  188. package/data/build/dist/shared/contracts/config.js +25 -0
  189. package/data/build/dist/shared/contracts/dsh-device.d.ts +13 -1
  190. package/data/build/dist/shared/contracts/errors.d.ts +1 -1
  191. package/data/build/dist/shared/contracts/feature.d.ts +6 -0
  192. package/data/build/dist/shared/contracts/git.d.ts +82 -0
  193. package/data/build/dist/shared/contracts/git.js +3 -0
  194. package/data/build/dist/shared/contracts/subscription.d.ts +46 -0
  195. package/data/build/dist/shared/contracts/terminal.d.ts +4 -1
  196. package/data/build/dist/shared/contracts/version.d.ts +2 -2
  197. package/data/build/dist/shared/contracts/version.js +4 -6
  198. package/data/build/dist/shared/debug.d.ts +14 -0
  199. package/data/build/dist/shared/debug.js +53 -0
  200. package/data/build/dist/shared/index.d.ts +7 -4
  201. package/data/build/dist/shared/index.js +2 -1
  202. package/data/build/dist/transport/debug.d.ts +1 -1
  203. package/data/build/dist/transport/debug.js +3 -30
  204. package/data/build/dist/transport/dsh-session.js +3 -3
  205. package/data/build/dist/typert.host.d.ts +1 -1
  206. package/data/build/dist/typert.host.js +6 -3
  207. package/data/build/dist/typert.remote-client.d.ts +11 -0
  208. package/data/build/dist/typert.remote-client.js +7 -0
  209. package/dsh.bundle.patch +1 -1
  210. package/package.json +13 -5
  211. package/profile/README.md +4 -4
  212. package/profile/package.json +6 -4
  213. package/profile/scripts/check-dsh-install.mjs +2 -2
  214. package/profile/version.json +2 -2
  215. package/scripts/check-dsh-install.mjs +2 -2
  216. package/version.json +2 -2
@@ -24,6 +24,7 @@ export class OpenCodeDriver {
24
24
  /** Provider 会话的实际工作目录;目录变化时禁止复用旧会话。 */
25
25
  sessionCwds = new Map();
26
26
  interactionTargets = new Map();
27
+ modelContextWindows = new Map();
27
28
  constructor(options = {}) {
28
29
  this.binaries = options.binaries ?? DEFAULT_BINARIES;
29
30
  this.serverUrls = options.serverUrls ?? (process.env.OPENCODE_SERVER_URL ? [process.env.OPENCODE_SERVER_URL] : DEFAULT_URLS);
@@ -51,6 +52,7 @@ export class OpenCodeDriver {
51
52
  const response = await this.http.json(`${server}${path}`);
52
53
  if (!response.data || response.status < 200 || response.status >= 300)
53
54
  continue;
55
+ rememberModelContextWindows(this.modelContextWindows, response.data);
54
56
  const catalog = parseModelCatalog(response.data);
55
57
  if (catalog.groups.length > 0)
56
58
  return catalog;
@@ -106,6 +108,7 @@ export class OpenCodeDriver {
106
108
  sessionId = await this.createSession(server, input);
107
109
  this.sessions.set(input.sessionId, sessionId);
108
110
  }
111
+ const contextWindow = await this.resolveModelContextWindow(server, input.modelId);
109
112
  if (input.cwd?.trim())
110
113
  this.sessionCwds.set(sessionId, input.cwd.trim());
111
114
  this.interactionTargets.set(input.sessionId, server);
@@ -164,7 +167,7 @@ export class OpenCodeDriver {
164
167
  const pending = pendingMessageParts.get(messageRole.id) ?? [];
165
168
  pendingMessageParts.delete(messageRole.id);
166
169
  for (const pendingPart of pending) {
167
- const chunk = eventToChunk(pendingPart, cumulative, assistantMessageIds, partTypes);
170
+ const chunk = eventToChunk(pendingPart, cumulative, assistantMessageIds, partTypes, contextWindow);
168
171
  if (chunk !== null) {
169
172
  emitted = true;
170
173
  yield chunk;
@@ -174,6 +177,15 @@ export class OpenCodeDriver {
174
177
  else {
175
178
  pendingMessageParts.delete(messageRole.id);
176
179
  }
180
+ // message.updated 同时承载 assistant 的最终 tokens。角色识别后
181
+ // 不能直接跳过,否则 OpenCode 的 token/context 统计会被吞掉。
182
+ if (messageRole.role === 'assistant') {
183
+ const chunk = eventToChunk(parsed, cumulative, assistantMessageIds, partTypes, contextWindow);
184
+ if (chunk !== null) {
185
+ emitted = true;
186
+ yield chunk;
187
+ }
188
+ }
177
189
  continue;
178
190
  }
179
191
  const messageId = eventMessageId(parsed);
@@ -183,7 +195,7 @@ export class OpenCodeDriver {
183
195
  // assistant 消息结算后才投影,否则原生工具节点会被追加到正文底部。
184
196
  // 用户消息没有 tool 字段,因此仍然暂存并等待 role 校验。
185
197
  if (isOpenCodeToolEvent(parsed)) {
186
- const chunk = eventToChunk(parsed, cumulative, undefined, partTypes);
198
+ const chunk = eventToChunk(parsed, cumulative, undefined, partTypes, contextWindow);
187
199
  if (chunk !== null) {
188
200
  emitted = true;
189
201
  yield chunk;
@@ -197,7 +209,7 @@ export class OpenCodeDriver {
197
209
  }
198
210
  if (messageId !== undefined && !assistantMessageIds.has(messageId))
199
211
  continue;
200
- const chunk = eventToChunk(parsed, cumulative, assistantMessageIds, partTypes);
212
+ const chunk = eventToChunk(parsed, cumulative, assistantMessageIds, partTypes, contextWindow);
201
213
  if (chunk !== null) {
202
214
  emitted = true;
203
215
  yield chunk;
@@ -218,7 +230,7 @@ export class OpenCodeDriver {
218
230
  const response = await send;
219
231
  if (sendError !== null && !aborted)
220
232
  throw sendError;
221
- for (const chunk of responseChunks(response, cumulative, partTypes)) {
233
+ for (const chunk of responseChunks(response, cumulative, partTypes, contextWindow)) {
222
234
  emitted = true;
223
235
  yield chunk;
224
236
  }
@@ -264,6 +276,7 @@ export class OpenCodeDriver {
264
276
  dispose() {
265
277
  this.sessions.clear();
266
278
  this.sessionCwds.clear();
279
+ this.modelContextWindows.clear();
267
280
  for (const managed of this.managedServers.values())
268
281
  terminateChildProcess(managed.child);
269
282
  this.managedServers.clear();
@@ -324,6 +337,23 @@ export class OpenCodeDriver {
324
337
  }
325
338
  catch { /* 取消请求尽力而为 */ }
326
339
  }
340
+ async resolveModelContextWindow(server, modelId) {
341
+ if (modelId === undefined)
342
+ return undefined;
343
+ const known = this.modelContextWindows.get(modelId);
344
+ if (known !== undefined)
345
+ return known;
346
+ try {
347
+ const response = await this.http.json(`${server}/config/providers`);
348
+ if (response.status < 200 || response.status >= 300)
349
+ return undefined;
350
+ rememberModelContextWindows(this.modelContextWindows, response.data);
351
+ return this.modelContextWindows.get(modelId);
352
+ }
353
+ catch {
354
+ return undefined;
355
+ }
356
+ }
327
357
  async ensureServer(probeOnly, cwd) {
328
358
  const workspace = cwd ?? process.cwd();
329
359
  const managed = this.managedServers.get(workspace);
@@ -423,6 +453,43 @@ function parseOpenCodeModel(modelId) {
423
453
  return null;
424
454
  return { providerID: modelId.slice(0, separator), modelID: modelId.slice(separator + 1) };
425
455
  }
456
+ /** 从 OpenCode provider 配置缓存每个模型的上下文窗口。 */
457
+ function rememberModelContextWindows(target, value) {
458
+ const root = asRecord(value);
459
+ const rawProviders = root?.providers;
460
+ const providers = [];
461
+ if (Array.isArray(rawProviders)) {
462
+ for (const raw of rawProviders) {
463
+ const provider = asRecord(raw);
464
+ if (provider !== null && typeof provider.id === 'string')
465
+ providers.push([provider.id, provider]);
466
+ }
467
+ }
468
+ else {
469
+ const providerMap = asRecord(rawProviders) ?? root;
470
+ if (providerMap !== null) {
471
+ for (const [id, raw] of Object.entries(providerMap)) {
472
+ const provider = asRecord(raw);
473
+ if (provider !== null)
474
+ providers.push([id, provider]);
475
+ }
476
+ }
477
+ }
478
+ for (const [providerId, provider] of providers) {
479
+ const models = asRecord(provider.models);
480
+ if (models === null)
481
+ continue;
482
+ for (const [modelId, rawModel] of Object.entries(models)) {
483
+ const model = asRecord(rawModel);
484
+ const limit = asRecord(model?.limit);
485
+ const context = limit?.context ?? model?.contextWindow ?? model?.context_window;
486
+ if (typeof context !== 'number' || !Number.isFinite(context) || context <= 0)
487
+ continue;
488
+ target.set(`${providerId}/${modelId}`, context);
489
+ target.set(modelId, context);
490
+ }
491
+ }
492
+ }
426
493
  function readProviderDirectory(record) {
427
494
  const value = record?.directory ?? record?.cwd;
428
495
  return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;
@@ -454,7 +521,7 @@ function parseEvent(event) {
454
521
  return null;
455
522
  }
456
523
  }
457
- function eventToChunk(event, cumulative, assistantMessageIds, partTypes) {
524
+ function eventToChunk(event, cumulative, assistantMessageIds, partTypes, contextWindow) {
458
525
  const type = typeof event.type === 'string' ? event.type : '';
459
526
  const properties = asRecord(event.properties);
460
527
  const part = asRecord(event.part) ?? asRecord(properties?.part) ?? properties ?? event;
@@ -536,24 +603,42 @@ function eventToChunk(event, cumulative, assistantMessageIds, partTypes) {
536
603
  ...(detail !== undefined ? { detail } : {}),
537
604
  };
538
605
  }
539
- const usage = asRecord(event.usage) ?? asRecord(part.usage) ?? readOpenCodeTokenUsage(properties);
606
+ const usage = asRecord(event.usage) ?? asRecord(part.usage) ?? readOpenCodeTokenUsage(properties, contextWindow);
540
607
  if (usage !== null)
541
608
  return usageChunk(usage);
542
609
  return null;
543
610
  }
544
611
  /** OpenCode 将最终用量放在 message.updated.properties.info.tokens。 */
545
- function readOpenCodeTokenUsage(properties) {
612
+ function readOpenCodeTokenUsage(properties, contextWindow) {
546
613
  const info = asRecord(properties?.info);
547
614
  const tokens = asRecord(info?.tokens);
548
615
  if (tokens === null)
549
616
  return null;
550
617
  const cache = asRecord(tokens.cache);
618
+ const model = asRecord(info?.model);
619
+ const modelLimit = asRecord(model?.limit);
620
+ const input = tokens.input ?? tokens.input_tokens;
621
+ const cacheRead = cache?.read ?? tokens.cache_read_tokens ?? tokens.cacheReadTokens;
622
+ const cacheWrite = cache?.write ?? tokens.cache_write_tokens ?? tokens.cacheWriteTokens;
623
+ const embeddedContextWindow = modelLimit?.context
624
+ ?? model?.contextWindow
625
+ ?? info?.contextWindow
626
+ ?? tokens.contextWindow
627
+ ?? tokens.context_window;
628
+ const contextTokens = tokens.contextTokens
629
+ ?? tokens.context_tokens
630
+ ?? (typeof input === 'number'
631
+ ? input + (typeof cacheRead === 'number' ? cacheRead : 0) + (typeof cacheWrite === 'number' ? cacheWrite : 0)
632
+ : undefined);
551
633
  return {
552
- input_tokens: tokens.input ?? tokens.input_tokens,
634
+ input_tokens: input,
553
635
  output_tokens: tokens.output ?? tokens.output_tokens,
554
- cache_read_tokens: cache?.read ?? tokens.cache_read_tokens ?? tokens.cacheReadTokens,
555
- cache_creation_tokens: cache?.write ?? tokens.cache_write_tokens ?? tokens.cacheWriteTokens,
636
+ cache_read_tokens: cacheRead,
637
+ cache_creation_tokens: cacheWrite,
556
638
  total_tokens: tokens.total ?? tokens.total_tokens ?? tokens.totalTokens,
639
+ ...(embeddedContextWindow === undefined && contextWindow === undefined ? {} : { context_window: embeddedContextWindow ?? contextWindow }),
640
+ ...(contextTokens === undefined ? {} : { context_tokens: contextTokens }),
641
+ ...(typeof tokens.contextUsageRatio === 'number' ? { context_usage_ratio: tokens.contextUsageRatio } : {}),
557
642
  };
558
643
  }
559
644
  function isFinishedEvent(event, emitted) {
@@ -566,11 +651,11 @@ function isFinishedEvent(event, emitted) {
566
651
  const status = typeof rawStatus === 'string' ? rawStatus.toLowerCase() : typeof statusRecord?.type === 'string' ? statusRecord.type.toLowerCase() : '';
567
652
  return status === 'idle' || status === 'completed' || status === 'success';
568
653
  }
569
- function responseChunks(value, cumulative, partTypes) {
654
+ function responseChunks(value, cumulative, partTypes, contextWindow) {
570
655
  const record = asRecord(value);
571
656
  if (record === null)
572
657
  return [];
573
- const chunk = eventToChunk(record, cumulative, undefined, partTypes);
658
+ const chunk = eventToChunk(record, cumulative, undefined, partTypes, contextWindow);
574
659
  return chunk === null ? [] : [chunk];
575
660
  }
576
661
  function readMessageRole(event) {
@@ -40,7 +40,7 @@ export class PiAgentDriver {
40
40
  const controller = new AbortController();
41
41
  const timer = setTimeout(() => controller.abort(), 12_000);
42
42
  try {
43
- const response = await rpc.request('get_available_models', {}, { signal: controller.signal });
43
+ const response = await rpc.request('get_available_models', {}, { signal: controller.signal, wireFormat: 'pi' });
44
44
  const catalog = parsePiCatalog(response);
45
45
  if (catalog.groups.length > 0)
46
46
  return catalog;
@@ -73,23 +73,34 @@ export class PiAgentDriver {
73
73
  const command = this.cachedBinary ?? (await this.detect()).command;
74
74
  if (command === null)
75
75
  throw new Error('Pi Agent 未安装');
76
- const session = this.getSession(input.sessionId, command, input.cwd, input.providerSessionId);
76
+ const session = this.getSession(input.sessionId, command, input.cwd, input.providerSessionId, input.rawStoreRef);
77
77
  const rpc = session.rpc;
78
78
  try {
79
- // 新版 Pi 接受可选模型设置;旧版会以错误响应结束,随后仍可使用默认模型。
80
- if (session.needsResume && input.providerSessionId) {
79
+ // Pi 的 sessionId 由进程创建;先读状态,避免把 DSH sessionId 错当成 Provider 会话标识。
80
+ if (!session.stateLoaded) {
81
81
  try {
82
- await rpc.request('resume', { sessionId: input.providerSessionId }, { signal: input.signal, killOnAbort: false });
83
- session.providerSessionId = input.providerSessionId;
82
+ const state = await rpc.request('get_state', {}, { signal: input.signal, killOnAbort: false, wireFormat: 'pi' });
83
+ const discoveredId = readPiStateSessionId(state);
84
+ if (discoveredId)
85
+ session.providerSessionId = discoveredId;
84
86
  }
85
- catch { /* 旧版 Pi 没有显式 resume,继续复用当前进程 */ }
86
- session.needsResume = false;
87
+ catch { /* 旧版 Pi 不提供 get_state 时保留 Host 侧回退标识。 */ }
88
+ session.stateLoaded = true;
87
89
  }
88
90
  if (!isProviderDefaultModel(input.modelId)) {
91
+ const model = parsePiModelId(input.modelId);
92
+ if (model !== null) {
93
+ try {
94
+ await rpc.request('set_model', model, { signal: input.signal, killOnAbort: false, wireFormat: 'pi' });
95
+ }
96
+ catch { /* 模型目录或旧版 Pi 不支持切换时继续使用当前模型。 */ }
97
+ }
98
+ }
99
+ if (input.effortId && input.effortId !== 'default') {
89
100
  try {
90
- await rpc.request('set_model', { model: input.modelId }, { signal: input.signal, killOnAbort: false });
101
+ await rpc.request('set_thinking_level', { level: input.effortId }, { signal: input.signal, killOnAbort: false, wireFormat: 'pi' });
91
102
  }
92
- catch { /* 兼容旧版 */ }
103
+ catch { /* 旧版 Pi 不支持单独设置思考等级时使用当前等级。 */ }
93
104
  }
94
105
  yield { type: 'session-binding', providerSessionId: session.providerSessionId };
95
106
  const stream = streamPiPrompt(rpc, input.prompt, input.signal);
@@ -121,14 +132,14 @@ export class PiAgentDriver {
121
132
  const session = this.sessions.get(sessionId);
122
133
  if (session === undefined)
123
134
  throw new Error('Pi 会话不存在');
124
- await session.rpc.request('steer', { message: prompt }, { killOnAbort: false });
135
+ await session.rpc.request('steer', { message: prompt }, { killOnAbort: false, wireFormat: 'pi' });
125
136
  }
126
137
  /** 向运行中的 Pi 会话追加 follow-up。 */
127
138
  async followUp(sessionId, prompt) {
128
139
  const session = this.sessions.get(sessionId);
129
140
  if (session === undefined)
130
141
  throw new Error('Pi 会话不存在');
131
- await session.rpc.request('follow_up', { message: prompt }, { killOnAbort: false });
142
+ await session.rpc.request('follow_up', { message: prompt }, { killOnAbort: false, wireFormat: 'pi' });
132
143
  }
133
144
  /** 中断当前 turn,但保留 Pi 进程供同一会话继续使用。 */
134
145
  async interrupt(sessionId) {
@@ -136,11 +147,11 @@ export class PiAgentDriver {
136
147
  if (session === undefined)
137
148
  return;
138
149
  try {
139
- await session.rpc.request('interrupt', {}, { killOnAbort: false });
150
+ await session.rpc.request('abort', {}, { killOnAbort: false, wireFormat: 'pi' });
140
151
  }
141
152
  catch {
142
153
  try {
143
- session.rpc.notify('abort', {});
154
+ session.rpc.notify('abort', {}, 'pi');
144
155
  }
145
156
  catch { /* 进程可能已退出 */ }
146
157
  }
@@ -152,18 +163,27 @@ export class PiAgentDriver {
152
163
  this.processes.clear();
153
164
  this.cachedBinary = null;
154
165
  }
155
- getSession(sessionId, command, cwd, providerSessionId) {
166
+ getSession(sessionId, command, cwd, providerSessionId, rawStoreRef) {
156
167
  const previous = this.sessions.get(sessionId);
157
- if (previous !== undefined && previous.cwd === cwd)
168
+ if (previous !== undefined
169
+ && previous.cwd === cwd
170
+ && (providerSessionId === undefined || providerSessionId === previous.providerSessionId)
171
+ && (rawStoreRef === undefined || rawStoreRef === previous.rawStoreRef))
158
172
  return previous;
159
173
  previous?.rpc.dispose();
160
- const rpc = new JsonRpcProcess({ command, args: ['--mode', 'rpc'], cwd, spawn: this.runSpawn });
174
+ const args = ['--mode', 'rpc'];
175
+ if (rawStoreRef?.trim())
176
+ args.push('--session', rawStoreRef.trim());
177
+ else if (providerSessionId?.trim())
178
+ args.push('--session-id', providerSessionId.trim());
179
+ const rpc = new JsonRpcProcess({ command, args, cwd, spawn: this.runSpawn });
161
180
  this.processes.add(rpc);
162
181
  const session = {
163
182
  rpc,
164
183
  cwd,
184
+ rawStoreRef,
165
185
  providerSessionId: providerSessionId ?? sessionId,
166
- needsResume: providerSessionId !== undefined,
186
+ stateLoaded: false,
167
187
  };
168
188
  this.sessions.set(sessionId, session);
169
189
  return session;
@@ -182,10 +202,10 @@ async function* streamPiPrompt(rpc, prompt, signal) {
182
202
  const listener = (message) => {
183
203
  queue.push(message);
184
204
  const type = piEventType(message);
185
- if (type === 'agent_settled')
186
- terminalReason = 'stop';
187
- else if (type === 'error' || type === 'agent_error' || type === 'agent_failed')
205
+ if (type === 'error' || type === 'agent_error' || type === 'agent_failed' || piEventHasError(message))
188
206
  terminalReason = 'error';
207
+ else if (type === 'agent_settled' && terminalReason === null)
208
+ terminalReason = 'stop';
189
209
  notify();
190
210
  };
191
211
  const removeListener = rpc.addNotificationListener(listener);
@@ -194,7 +214,7 @@ async function* streamPiPrompt(rpc, prompt, signal) {
194
214
  onAbort();
195
215
  else
196
216
  signal?.addEventListener('abort', onAbort, { once: true });
197
- void rpc.request('prompt', { message: prompt }, { signal, killOnAbort: false }).then(() => { promptSettled = true; notify(); }, () => {
217
+ void rpc.request('prompt', { message: prompt }, { signal, killOnAbort: false, wireFormat: 'pi' }).then(() => { promptSettled = true; notify(); }, () => {
198
218
  promptSettled = true;
199
219
  terminalReason = signal?.aborted ? 'cancel' : 'error';
200
220
  notify();
@@ -218,6 +238,12 @@ function piEventType(message) {
218
238
  const params = isRecord(message.params) ? message.params : message;
219
239
  return typeof params.type === 'string' ? params.type.toLowerCase() : '';
220
240
  }
241
+ function piEventHasError(message) {
242
+ const params = isRecord(message.params) ? message.params : message;
243
+ const event = isRecord(params.message) ? params.message : params;
244
+ const stopReason = textValue(event.stopReason ?? params.stopReason);
245
+ return stopReason === 'error' || stopReason === 'failed' || typeof event.errorMessage === 'string' && event.errorMessage.trim() !== '';
246
+ }
221
247
  function parsePiCliCatalog(output) {
222
248
  const models = [];
223
249
  const levels = ['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
@@ -266,7 +292,13 @@ function piMessageToChunk(message) {
266
292
  const assistantEvent = isRecord(params.assistantMessageEvent) ? params.assistantMessageEvent : null;
267
293
  const completedMessage = isRecord(params.message) ? params.message : null;
268
294
  const rootType = typeof event.type === 'string' ? event.type : typeof params.event === 'string' ? params.event : '';
269
- if (rootType === 'agent_settled' || rootType === 'agent_end' || rootType === 'turn_end')
295
+ if (rootType === 'agent_start'
296
+ || rootType === 'agent_settled'
297
+ || rootType === 'agent_end'
298
+ || rootType === 'turn_start'
299
+ || rootType === 'turn_end'
300
+ || rootType === 'message_start'
301
+ || rootType === 'message_end')
270
302
  return null;
271
303
  const type = assistantEvent !== null && typeof assistantEvent.type === 'string' ? assistantEvent.type : rootType;
272
304
  const text = textValue(assistantEvent?.delta ?? params.delta ?? params.text ?? params.content ?? params.message);
@@ -309,4 +341,18 @@ function readSessionId(message) {
309
341
  return params[key].trim();
310
342
  return null;
311
343
  }
344
+ function readPiStateSessionId(value) {
345
+ if (!isRecord(value))
346
+ return null;
347
+ const data = isRecord(value.data) ? value.data : value;
348
+ return textValue(data.sessionId ?? data.session_id) ?? null;
349
+ }
350
+ function parsePiModelId(value) {
351
+ if (!value)
352
+ return null;
353
+ const separator = value.indexOf('/');
354
+ if (separator <= 0 || separator === value.length - 1)
355
+ return null;
356
+ return { provider: value.slice(0, separator), modelId: value.slice(separator + 1) };
357
+ }
312
358
  //# sourceMappingURL=pi-driver.js.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * 模型提供商注册表。
3
+ *
4
+ * Agent 只是运行入口,订阅归属属于模型提供商。这里集中维护提供商名称、
5
+ * 官方地址、余额能力和 Logo,调用方只传入 DSH 的 provider 名称与 baseURL。
6
+ */
7
+ export type ProviderSubscriptionCapability = 'official-balance' | 'official-usage' | 'subscription-window' | 'sub2api' | 'unsupported';
8
+ export type ProviderSubscriptionReader = 'deepseek-balance' | 'openrouter-balance' | 'minimax-usage' | 'zai-usage' | 'github-copilot-usage' | 'sub2api' | 'none';
9
+ export interface ProviderIdentity {
10
+ readonly name?: string | undefined;
11
+ readonly baseUrl?: string | undefined;
12
+ }
13
+ export interface ProviderDefinition {
14
+ readonly id: string;
15
+ readonly displayName: string;
16
+ readonly aliases: readonly string[];
17
+ readonly officialHosts: readonly string[];
18
+ readonly capability: ProviderSubscriptionCapability;
19
+ readonly reader: ProviderSubscriptionReader;
20
+ /** 浏览器可直接加载的公开 Logo 地址;Host 会尽量内联为 data URL。 */
21
+ readonly logoUrl: string;
22
+ }
23
+ /** DSH 内置模型提供商的统一订阅能力登记。 */
24
+ export declare const MODEL_PROVIDER_DEFINITIONS: readonly ProviderDefinition[];
25
+ /** 规范化名称,避免大小写、下划线和连字符造成重复提供商。 */
26
+ export declare function normalizeProviderName(value: string | undefined): string;
27
+ /** 去掉 path、查询参数和凭据,只保留可用于身份判断的 origin。 */
28
+ export declare function normalizeProviderBaseUrl(value: string | undefined): string;
29
+ /** 按名称和 baseURL 联合识别;同名第三方代理不会冒充官方提供商。 */
30
+ export declare function identifyModelProvider(identity: ProviderIdentity): ProviderDefinition | undefined;
31
+ /** 返回一个不依赖名称的第三方上游定义,供 Sub2API 统计使用。 */
32
+ export declare function thirdPartyProvider(identity: ProviderIdentity): ProviderDefinition;
33
+ //# sourceMappingURL=provider-registry.d.ts.map
@@ -0,0 +1,83 @@
1
+ const simpleIcon = (slug) => `https://cdn.simpleicons.org/${slug}`;
2
+ /** DSH 内置模型提供商的统一订阅能力登记。 */
3
+ export const MODEL_PROVIDER_DEFINITIONS = [
4
+ provider('amazon-bedrock', 'Amazon Bedrock', ['amazon-bedrock'], ['bedrock-runtime.us-east-1.amazonaws.com'], 'unsupported', 'amazonaws'),
5
+ provider('ant-ling', 'Ant Ling', ['ant-ling'], [], 'sub2api', 'antdesign'),
6
+ provider('anthropic', 'Anthropic', ['anthropic', 'claude'], ['api.anthropic.com'], 'official-usage', 'anthropic'),
7
+ provider('azure-openai-responses', 'Azure OpenAI', ['azure-openai-responses', 'azure-openai'], [], 'unsupported', 'microsoftazure'),
8
+ provider('baseten', 'Baseten', ['baseten'], ['inference.baseten.co'], 'official-usage', 'baseten'),
9
+ provider('cerebras', 'Cerebras', ['cerebras'], ['api.cerebras.ai'], 'unsupported', 'cerebras'),
10
+ provider('cloudflare-ai-gateway', 'Cloudflare AI Gateway', ['cloudflare-ai-gateway'], ['api.cloudflare.com'], 'official-usage', 'cloudflare'),
11
+ provider('cloudflare-workers-ai', 'Cloudflare Workers AI', ['cloudflare-workers-ai'], ['api.cloudflare.com'], 'unsupported', 'cloudflare'),
12
+ provider('deepseek', 'DeepSeek', ['deepseek', 'deepseek-official', 'official-deepseek'], ['api.deepseek.com', 'api.deepseek.com.cn'], 'official-balance', 'deepseek', 'deepseek-balance'),
13
+ provider('fireworks', 'Fireworks AI', ['fireworks'], ['api.fireworks.ai'], 'official-usage', 'fireworks'),
14
+ provider('github-copilot', 'GitHub Copilot', ['github-copilot'], ['api.githubcopilot.com', 'api.github.com'], 'subscription-window', 'github', 'github-copilot-usage'),
15
+ provider('google', 'Google Gemini', ['google', 'gemini'], ['generativelanguage.googleapis.com'], 'unsupported', 'googlegemini'),
16
+ provider('google-vertex', 'Google Vertex AI', ['google-vertex', 'vertex'], ['aiplatform.googleapis.com'], 'unsupported', 'googlecloud'),
17
+ provider('groq', 'Groq', ['groq'], ['api.groq.com'], 'unsupported', 'groq'),
18
+ provider('huggingface', 'Hugging Face', ['huggingface', 'hf'], ['api-inference.huggingface.co'], 'unsupported', 'huggingface'),
19
+ provider('kimi-coding', 'Kimi Coding', ['kimi-coding'], ['api.kimi.com'], 'official-usage', 'moonshot'),
20
+ provider('minimax', 'MiniMax', ['minimax'], ['api.minimax.io'], 'official-balance', 'minimax', 'minimax-usage'),
21
+ provider('minimax-cn', 'MiniMax 中国', ['minimax-cn'], ['api.minimaxi.com'], 'official-balance', 'minimax', 'minimax-usage'),
22
+ provider('mistral', 'Mistral AI', ['mistral'], ['api.mistral.ai'], 'official-usage', 'mistral'),
23
+ provider('moonshotai', 'Moonshot AI', ['moonshotai', 'moonshot'], ['api.moonshot.ai'], 'official-balance', 'moonshot'),
24
+ provider('moonshotai-cn', 'Moonshot AI 中国', ['moonshotai-cn'], ['api.moonshot.cn'], 'official-balance', 'moonshot'),
25
+ provider('nvidia', 'NVIDIA NIM', ['nvidia'], ['integrate.api.nvidia.com'], 'unsupported', 'nvidia'),
26
+ provider('openai', 'OpenAI', ['openai'], ['api.openai.com'], 'official-usage', 'openai'),
27
+ provider('openai-codex', 'OpenAI Codex', ['openai-codex'], ['chatgpt.com', 'api.openai.com'], 'subscription-window', 'openai'),
28
+ provider('opencode', 'OpenCode', ['opencode'], [], 'sub2api', 'opencode'),
29
+ provider('opencode-go', 'OpenCode Go', ['opencode-go'], [], 'sub2api', 'opencode'),
30
+ provider('openrouter', 'OpenRouter', ['openrouter'], ['openrouter.ai'], 'official-balance', 'openrouter', 'openrouter-balance'),
31
+ provider('qwen-token-plan', 'Qwen Token Plan', ['qwen-token-plan', 'qwen-token-plan-individual'], ['dashscope.aliyuncs.com'], 'unsupported', 'alibabacloud'),
32
+ provider('qwen-token-plan-cn', 'Qwen Token Plan 中国', ['qwen-token-plan-cn'], ['dashscope.aliyuncs.com.cn'], 'unsupported', 'alibabacloud'),
33
+ provider('together', 'Together AI', ['together'], ['api.together.xyz'], 'unsupported', 'together'),
34
+ provider('vercel-ai-gateway', 'Vercel AI Gateway', ['vercel-ai-gateway'], ['ai-gateway.vercel.sh'], 'official-usage', 'vercel'),
35
+ provider('xai', 'xAI', ['xai', 'grok'], ['api.x.ai'], 'unsupported', 'x'),
36
+ provider('xiaomi', 'Xiaomi MiMo', ['xiaomi', 'xiaomi-token-plan-ams', 'xiaomi-token-plan-cn', 'xiaomi-token-plan-sgp'], ['api.xiaomimimo.com'], 'unsupported', 'xiaomi'),
37
+ provider('zai', 'Z.ai', ['zai'], ['api.z.ai'], 'official-balance', 'zhipu', 'zai-usage'),
38
+ provider('zai-coding-cn', 'Z.ai Coding 中国', ['zai-coding-cn'], ['open.bigmodel.cn'], 'official-balance', 'zhipu', 'zai-usage'),
39
+ ];
40
+ function provider(id, displayName, aliases, officialHosts, capability, logoSlug, reader = capability === 'sub2api' ? 'sub2api' : 'none') {
41
+ return { id, displayName, aliases, officialHosts, capability, reader, logoUrl: simpleIcon(logoSlug) };
42
+ }
43
+ /** 规范化名称,避免大小写、下划线和连字符造成重复提供商。 */
44
+ export function normalizeProviderName(value) {
45
+ return (value ?? '').trim().toLowerCase().replace(/[_\s]+/gu, '-');
46
+ }
47
+ /** 去掉 path、查询参数和凭据,只保留可用于身份判断的 origin。 */
48
+ export function normalizeProviderBaseUrl(value) {
49
+ if (value === undefined || value.trim() === '')
50
+ return '';
51
+ try {
52
+ const url = new URL(value.trim());
53
+ return url.origin.toLowerCase();
54
+ }
55
+ catch {
56
+ return '';
57
+ }
58
+ }
59
+ function providerMatches(definition, identity) {
60
+ const name = normalizeProviderName(identity.name);
61
+ const nameMatches = name !== '' && definition.aliases.some((alias) => normalizeProviderName(alias) === name);
62
+ const host = normalizeProviderBaseUrl(identity.baseUrl);
63
+ const hostMatches = host !== '' && definition.officialHosts.some((officialHost) => normalizeProviderBaseUrl(`https://${officialHost}`) === host);
64
+ return nameMatches && (host === '' || hostMatches);
65
+ }
66
+ /** 按名称和 baseURL 联合识别;同名第三方代理不会冒充官方提供商。 */
67
+ export function identifyModelProvider(identity) {
68
+ return MODEL_PROVIDER_DEFINITIONS.find((definition) => providerMatches(definition, identity));
69
+ }
70
+ /** 返回一个不依赖名称的第三方上游定义,供 Sub2API 统计使用。 */
71
+ export function thirdPartyProvider(identity) {
72
+ const name = identity.name?.trim();
73
+ return {
74
+ id: name === undefined || name === '' ? 'custom' : normalizeProviderName(name),
75
+ displayName: name === undefined || name === '' ? '自定义提供商' : name,
76
+ aliases: [],
77
+ officialHosts: [],
78
+ capability: 'sub2api',
79
+ reader: 'sub2api',
80
+ logoUrl: '',
81
+ };
82
+ }
83
+ //# sourceMappingURL=provider-registry.js.map
@@ -1,5 +1,6 @@
1
1
  import { spawn, spawnSync } from 'node:child_process';
2
2
  import type { CliSubscriptionUsage } from '../../shared/contracts/subscription.js';
3
+ import { OfficialProviderSubscriptionService, type OfficialProviderSubscriptionOptions } from './official-provider-subscription.js';
3
4
  type FetchLike = typeof fetch;
4
5
  /** 统一读取 Codex、Claude Code、OpenCode 订阅摘要。所有原始凭据都留在 Host。 */
5
6
  export declare class ProviderSubscriptionService {
@@ -8,8 +9,11 @@ export declare class ProviderSubscriptionService {
8
9
  readonly claudeCode: ClaudeCodeSubscriptionService;
9
10
  readonly opencode: OpenCodeSubscriptionService;
10
11
  readonly sub2api: Sub2ApiUsageService;
12
+ readonly deepseek: DeepseekSubscriptionService;
13
+ readonly official: OfficialProviderSubscriptionService;
11
14
  constructor(options?: ProviderSubscriptionOptions);
12
- read(adapterId: string): Promise<CliSubscriptionUsage | null>;
15
+ read(adapterId: string, providerId?: string): Promise<CliSubscriptionUsage | null>;
16
+ private readDsh;
13
17
  private readSub2ApiFirst;
14
18
  }
15
19
  export interface ProviderSubscriptionOptions {
@@ -18,6 +22,8 @@ export interface ProviderSubscriptionOptions {
18
22
  readonly claudeCode?: ClaudeCodeSubscriptionOptions;
19
23
  readonly opencode?: OpenCodeSubscriptionOptions;
20
24
  readonly sub2api?: Sub2ApiUsageOptions;
25
+ readonly deepseek?: DeepseekSubscriptionOptions;
26
+ readonly official?: OfficialProviderSubscriptionOptions;
21
27
  }
22
28
  export interface SubscriptionReader {
23
29
  read(): Promise<CliSubscriptionUsage | null>;
@@ -26,6 +32,20 @@ export interface Sub2ApiSource {
26
32
  readonly baseUrl: string;
27
33
  readonly apiKey: string;
28
34
  }
35
+ export interface DeepseekSubscriptionOptions {
36
+ readonly fetch?: FetchLike;
37
+ readonly timeoutMs?: number;
38
+ readonly sources?: readonly Sub2ApiSource[];
39
+ }
40
+ /** 读取官方 DeepSeek API 的余额;凭据只在 Host 内使用。 */
41
+ export declare class DeepseekSubscriptionService {
42
+ private readonly request;
43
+ private readonly timeoutMs;
44
+ private readonly configuredSources;
45
+ constructor(options?: DeepseekSubscriptionOptions);
46
+ read(source?: Sub2ApiSource): Promise<CliSubscriptionUsage | null>;
47
+ private readSource;
48
+ }
29
49
  export interface Sub2ApiUsageOptions {
30
50
  readonly fetch?: FetchLike;
31
51
  readonly timeoutMs?: number;
@@ -37,8 +57,10 @@ export declare class Sub2ApiUsageService {
37
57
  private readonly timeoutMs;
38
58
  private readonly configuredSources;
39
59
  constructor(options?: Sub2ApiUsageOptions);
40
- hasSource(adapterId: string): boolean;
41
- read(adapterId: string): Promise<CliSubscriptionUsage | null>;
60
+ hasSource(adapterId: string, providerId?: string): boolean;
61
+ /** 只判断是否存在第三方上游;官方 Codex/Claude 源必须允许回退原生订阅读取器。 */
62
+ hasThirdPartySource(adapterId: string, providerId?: string): boolean;
63
+ read(adapterId: string, providerId?: string): Promise<CliSubscriptionUsage | null>;
42
64
  private readSource;
43
65
  }
44
66
  export interface CodexSubscriptionOptions {