dsh-plugin-subscription-oauth 0.16.0 → 0.16.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.
@@ -85,7 +85,7 @@ export declare function finishWorkBuddySignIn(start: WorkBuddySignInStart, fetch
85
85
  }>;
86
86
  /** The domain a token names, else the API host. */
87
87
  export declare function workbuddyDomain(token: Pick<WorkBuddyTokenSet, 'domain'>): string;
88
- /** The headers WorkBuddy's desktop app sends with a chat and its account. */
88
+ /** The headers WorkBuddy's chat gateway accepts: its own CLI's, nothing more. */
89
89
  export declare function workbuddyHeaders(token: WorkBuddyTokenSet): Record<string, string>;
90
90
  /** Whether a token is close enough to its end that a request should refresh it. */
91
91
  export declare function workbuddyStale(token: Pick<WorkBuddyTokenSet, 'expiresAt'>): boolean;
@@ -140,6 +140,7 @@ export declare function claimWorkBuddyCheckin(token: WorkBuddyTokenSet, fetchFn:
140
140
  /** The account's precise remaining credits, summed across its live packages. */
141
141
  export declare function readWorkBuddyCredits(token: WorkBuddyTokenSet, fetchFn: typeof fetch): Promise<{
142
142
  remaining: number;
143
+ total: number;
143
144
  nearestExpiryMs?: number;
144
145
  } | null>;
145
146
  /** Read the account's plan and metered credits for the Settings card. */
@@ -214,26 +214,21 @@ async function workbuddyEnterprise(token, who, fetchFn) {
214
214
  const pick = same.length === 1 ? same[0] : last.length === 1 ? last[0] : mine.length === 1 ? mine[0] : undefined;
215
215
  return pick && typeof pick.enterpriseId === 'string' ? pick.enterpriseId.trim() : '';
216
216
  }
217
- /** The headers WorkBuddy's desktop app sends with a chat and its account. */
217
+ /** The headers WorkBuddy's chat gateway accepts: its own CLI's, nothing more. */
218
218
  export function workbuddyHeaders(token) {
219
219
  const headers = {
220
+ 'Accept': 'application/json, text/plain, */*',
221
+ 'X-Requested-With': 'XMLHttpRequest',
222
+ 'Origin': 'https://copilot.tencent.com',
223
+ 'Referer': 'https://copilot.tencent.com/',
224
+ 'User-Agent': 'CLI/2.63.2 CodeBuddy/2.63.2',
225
+ 'Content-Type': 'application/json',
220
226
  'Authorization': `Bearer ${token.accessToken}`,
221
- 'X-User-Id': token.uid ?? '',
227
+ ...token.uid === undefined || token.uid === '' ? { 'X-No-User-Id': '1' } : { 'X-User-Id': token.uid },
228
+ ...token.enterpriseId === undefined || token.enterpriseId === '' ? { 'X-No-Enterprise-Id': '1' } : { 'X-Enterprise-Id': token.enterpriseId },
222
229
  'X-Domain': workbuddyDomain(token),
223
230
  'X-Product': 'SaaS',
224
- 'X-IDE-Type': 'WorkBuddy',
225
- 'User-Agent': `WorkBuddy/${WORKBUDDY_UA_VERSION}`,
226
- 'X-Requested-With': 'XMLHttpRequest',
227
- 'X-Agent-Intent': 'craft',
228
- 'X-Agent-Purpose': 'conversation',
229
- 'X-IDE-Name': 'WorkBuddy',
230
- 'X-IDE-Version': WORKBUDDY_UA_VERSION,
231
231
  };
232
- const enterprise = typeof token.enterpriseId === 'string' ? token.enterpriseId.trim() : '';
233
- if (enterprise !== '') {
234
- headers['X-Enterprise-Id'] = enterprise;
235
- headers['X-Tenant-Id'] = enterprise;
236
- }
237
232
  return headers;
238
233
  }
239
234
  /** Whether a token is close enough to its end that a request should refresh it. */
@@ -473,12 +468,14 @@ export async function readWorkBuddyCredits(token, fetchFn) {
473
468
  return undefined;
474
469
  };
475
470
  let remaining = 0;
471
+ let totalSize = 0;
476
472
  let nearestExpiryMs;
477
473
  let livePackages = 0;
478
474
  for (const account of accounts) {
479
475
  const num = (key) => capacity(account[key]);
480
476
  const monthly = num('CapacityType') === 4;
481
477
  const remain = monthly ? num('CycleCapacityRemain') : num('CapacityRemain');
478
+ const size = monthly ? num('CycleCapacitySize') : num('CapacitySize');
482
479
  const capped = remain < 0 ? 0 : remain;
483
480
  const cycleEndMs = parseDate(account.CycleEndTime);
484
481
  const expiresAtMs = monthly ? undefined : parseDate(account.ExpiredTime) ?? cycleEndMs;
@@ -486,6 +483,7 @@ export async function readWorkBuddyCredits(token, fetchFn) {
486
483
  continue;
487
484
  livePackages += 1;
488
485
  remaining += capped;
486
+ totalSize += size > 0 ? size : capped;
489
487
  if (expiresAtMs !== undefined && (nearestExpiryMs === undefined || expiresAtMs < nearestExpiryMs)) {
490
488
  nearestExpiryMs = expiresAtMs;
491
489
  }
@@ -494,7 +492,7 @@ export async function readWorkBuddyCredits(token, fetchFn) {
494
492
  // account, say — so the caller falls through to its own meter.
495
493
  if (livePackages === 0)
496
494
  return null;
497
- return { remaining, ...nearestExpiryMs === undefined ? {} : { nearestExpiryMs } };
495
+ return { remaining, total: totalSize, ...nearestExpiryMs === undefined ? {} : { nearestExpiryMs } };
498
496
  }
499
497
  /** The account's credits from its resource summary: the plan's used against granted. */
500
498
  function usageOfSummary(summary, plan) {
@@ -542,10 +540,15 @@ export async function readWorkBuddyUsage(token, plan, fetchFn, spend) {
542
540
  const credits = await readWorkBuddyCredits(token, fetchFn);
543
541
  if (credits !== null) {
544
542
  const window = { label: 'Credits', used: spend?.spent ?? 0 };
545
- if (credits.remaining > 0 || (spend?.spent ?? 0) > 0) {
546
- const limit = credits.remaining + (spend?.spent ?? 0);
547
- window.limit = limit;
548
- window.usedPercent = limit > 0 ? (100 * (spend?.spent ?? 0)) / limit : 0;
543
+ // The bar reads spent against the total the packages grant, not remaining-plus-spent,
544
+ // so a fresh cycle's spend shows small against its full grant.
545
+ if (credits.total > 0) {
546
+ window.limit = credits.total;
547
+ window.usedPercent = (100 * (spend?.spent ?? 0)) / credits.total;
548
+ }
549
+ else if ((spend?.spent ?? 0) > 0) {
550
+ window.limit = spend?.spent ?? 0;
551
+ window.usedPercent = 100;
549
552
  }
550
553
  if (credits.nearestExpiryMs !== undefined)
551
554
  window.resetsAt = credits.nearestExpiryMs;
@@ -12,7 +12,7 @@ import { LlmAdapter, errorChain, ReasoningEffortId, ToolCallId, } from '@deepsee
12
12
  import { idleWatchdog, mapFetchFailure } from './common.js';
13
13
  import { proxiedFetch } from '../http.js';
14
14
  import { findEntry } from './catalog.js';
15
- import { WORKBUDDY_ENDPOINT, WORKBUDDY_UA_VERSION, workbuddyHeaders } from '../auth/workbuddy-flow.js';
15
+ import { WORKBUDDY_ENDPOINT, workbuddyHeaders } from '../auth/workbuddy-flow.js';
16
16
  import { recordSpend } from './workbuddy-credits.js';
17
17
  /** The `workbuddy` provider route key (China build). */
18
18
  export const WORKBUDDY_PROVIDER_ID = 'workbuddy';
@@ -80,12 +80,6 @@ function unflagMessages(messages) {
80
80
  }
81
81
  return messages;
82
82
  }
83
- /** 32 hex digits, for the chat ids WorkBuddy's own client makes. */
84
- function randomHex() {
85
- const bytes = new Uint8Array(16);
86
- crypto.getRandomValues(bytes);
87
- return [...bytes].map((byte) => byte.toString(16).padStart(2, '0')).join('');
88
- }
89
83
  /** A tool's name may hold letters, digits, `_`, `-`; another character is refused. */
90
84
  const NAME_OK = /^[A-Za-z0-9_-]+$/;
91
85
  /** A name with each character WorkBuddy refuses as `_`, kept apart from `taken`. */
@@ -285,18 +279,7 @@ export class WorkBuddyAdapter extends LlmAdapter {
285
279
  const body = this.requestBody(options);
286
280
  const response = await this.fetchFn(WORKBUDDY_API, {
287
281
  method: 'POST',
288
- headers: {
289
- 'Content-Type': 'application/json',
290
- 'Accept': 'text/event-stream',
291
- ...workbuddyHeaders(token),
292
- // Name the chat the way WorkBuddy's own client does: the conversation, the
293
- // turn, and the message. Without these the gateway counts the request under no
294
- // client and cuts the stream, which is why the reply stopped after a few seconds.
295
- 'X-Conversation-Message-ID': randomHex(),
296
- 'X-Request-ID': randomHex(),
297
- 'X-Conversation-Request-ID': randomHex(),
298
- 'X-Conversation-ID': randomHex(),
299
- },
282
+ headers: workbuddyHeaders(token),
300
283
  body: JSON.stringify(body),
301
284
  signal: watchdog.signal,
302
285
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-subscription-oauth",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "Use subscription accounts as DeepSeek Harness LLM providers — Kimi Code (OAuth device flow), Grok / X Premium (OIDC + PKCE), Google Antigravity (Google OAuth + Cloud Code Assist) and GLM / BigModel (ZCode's browser sign-in) — with per-model visibility, drag-to-reorder Auto fallback and plan quotas from the web Settings page",
5
5
  "license": "MIT",
6
6
  "author": "EricFL1998",