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
|
|
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
|
|
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
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
window.
|
|
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,
|
|
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.
|
|
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",
|