dsh-plugin-subscription-oauth 0.15.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.
- package/lib/auth/registry.d.ts +28 -0
- package/lib/auth/registry.js +7 -0
- package/lib/auth/rpc.js +6 -0
- package/lib/auth/workbuddy-flow.d.ts +24 -1
- package/lib/auth/workbuddy-flow.js +134 -19
- package/lib/client/SubscriptionsSection.js +40 -5
- package/lib/client/locales.d.ts +8 -0
- package/lib/client/locales.js +8 -0
- package/lib/client.js +64 -14
- package/lib/client.js.map +1 -1
- package/lib/protocol.d.ts +28 -1
- package/lib/protocol.js +1 -0
- package/lib/providers/workbuddy-provider.js +46 -1
- package/lib/providers/workbuddy.js +2 -19
- package/package.json +1 -1
package/lib/protocol.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
/** Prefix of every RPC method this plugin serves. */
|
|
13
13
|
export declare const RPC_PREFIX = "subscription-oauth.";
|
|
14
14
|
/** Endpoints the Settings page may call. */
|
|
15
|
-
export declare const RPC_ENDPOINTS: readonly ["status", "login", "cancel", "logout", "setDefault", "refresh", "discover", "setModelVisible", "setModelOrder", "addModel", "removeModel", "usage", "reload", "auto-state", "setAutoOn", "checkin", "deepseek-balance", "ccswitch-balance", "model-variants"];
|
|
15
|
+
export declare const RPC_ENDPOINTS: readonly ["status", "login", "cancel", "logout", "setDefault", "refresh", "discover", "setModelVisible", "setModelOrder", "addModel", "removeModel", "usage", "reload", "auto-state", "setAutoOn", "checkin", "tasks", "deepseek-balance", "ccswitch-balance", "model-variants"];
|
|
16
16
|
/** One endpoint name. */
|
|
17
17
|
export type RpcEndpoint = typeof RPC_ENDPOINTS[number];
|
|
18
18
|
/** Client → host envelope. */
|
|
@@ -334,6 +334,10 @@ export interface RpcMap {
|
|
|
334
334
|
payload: CheckinRequest;
|
|
335
335
|
value: CheckinResult;
|
|
336
336
|
};
|
|
337
|
+
tasks: {
|
|
338
|
+
payload: TasksRequest;
|
|
339
|
+
value: TasksResult;
|
|
340
|
+
};
|
|
337
341
|
'deepseek-balance': {
|
|
338
342
|
payload: DeepSeekBalanceRequest;
|
|
339
343
|
value: DeepSeekBalanceResult;
|
|
@@ -420,6 +424,29 @@ export interface CheckinResult {
|
|
|
420
424
|
streakDays: number;
|
|
421
425
|
already: boolean;
|
|
422
426
|
}
|
|
427
|
+
/** Payload of `tasks`: which account to read and auto-claim. */
|
|
428
|
+
export interface TasksRequest {
|
|
429
|
+
provider: string;
|
|
430
|
+
account: string;
|
|
431
|
+
/** Claim every claimable reward; false only lists. */
|
|
432
|
+
claim?: boolean;
|
|
433
|
+
}
|
|
434
|
+
/** One task's state for the card. */
|
|
435
|
+
export interface WorkBuddyTaskState {
|
|
436
|
+
taskCode: string;
|
|
437
|
+
title: string;
|
|
438
|
+
credit: number;
|
|
439
|
+
target: number;
|
|
440
|
+
current: number;
|
|
441
|
+
state: 'pending' | 'claimable' | 'claimed' | 'locked';
|
|
442
|
+
}
|
|
443
|
+
/** Result of `tasks`: the task list and what auto-claiming earned. */
|
|
444
|
+
export interface TasksResult {
|
|
445
|
+
tasks: WorkBuddyTaskState[];
|
|
446
|
+
claimed: number;
|
|
447
|
+
claimable: number;
|
|
448
|
+
creditEarned: number;
|
|
449
|
+
}
|
|
423
450
|
/** Payload of `deepseek-balance`. */
|
|
424
451
|
export interface DeepSeekBalanceRequest {
|
|
425
452
|
/** Client metadata the host's account service expects. */
|
package/lib/protocol.js
CHANGED
|
@@ -10,7 +10,7 @@ import { TokenManager } from '../auth/tokens.js';
|
|
|
10
10
|
import { LOGIN_CANCELLED_MESSAGE } from '../auth/device-flow.js';
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import { readSpendLedger } from './workbuddy-credits.js';
|
|
13
|
-
import { finishWorkBuddySignIn, parseWorkBuddySession, readWorkBuddyUsage, refreshWorkBuddyToken, startWorkBuddySignIn, workbuddyRefreshable, workbuddyStale, claimWorkBuddyCheckin, WORKBUDDY_EARLY_MS, } from '../auth/workbuddy-flow.js';
|
|
13
|
+
import { finishWorkBuddySignIn, parseWorkBuddySession, readWorkBuddyUsage, refreshWorkBuddyToken, startWorkBuddySignIn, workbuddyRefreshable, workbuddyStale, claimWorkBuddyCheckin, listWorkBuddyTasks, acceptWorkBuddyTasks, claimWorkBuddyTask, WORKBUDDY_EARLY_MS, } from '../auth/workbuddy-flow.js';
|
|
14
14
|
import { WorkBuddyAdapter, WORKBUDDY_CODE_URL, WORKBUDDY_CATALOG, WORKBUDDY_DEFAULT_MODEL, WORKBUDDY_PROVIDER_ID, WORKBUDDY_PROVIDER_NAME, } from './workbuddy.js';
|
|
15
15
|
import { ProviderController } from '../auth/provider-controller.js';
|
|
16
16
|
import { proxiedFetch } from '../http.js';
|
|
@@ -223,5 +223,50 @@ export function createWorkBuddyProvider(options) {
|
|
|
223
223
|
throw new ProviderError(`WorkBuddy check-in failed: ${message}`, REAUTH_REQUIRED);
|
|
224
224
|
}
|
|
225
225
|
},
|
|
226
|
+
tasks: async (account, claim) => {
|
|
227
|
+
const held = await store.get(account);
|
|
228
|
+
if (held === undefined)
|
|
229
|
+
throw new ProviderError('WorkBuddy account not signed in', REAUTH_REQUIRED);
|
|
230
|
+
const token = tokenOf(held);
|
|
231
|
+
// Enrol in every open task first: accepting is the sign-up half, and replaying it is
|
|
232
|
+
// a safe no-op, so progress a chat or an activity report lights is never missed.
|
|
233
|
+
const tasks = await listWorkBuddyTasks(token, fetchFn);
|
|
234
|
+
const open = tasks.filter((task) => !task.claimed && !task.locked && task.acceptStatus !== 'claimed').map((task) => task.taskCode);
|
|
235
|
+
try {
|
|
236
|
+
await acceptWorkBuddyTasks(token, open, fetchFn);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// Accepting is best-effort; a failure here does not block reading or claiming.
|
|
240
|
+
}
|
|
241
|
+
const fresh = await listWorkBuddyTasks(token, fetchFn);
|
|
242
|
+
let creditEarned = 0;
|
|
243
|
+
let claimedCount = 0;
|
|
244
|
+
if (claim) {
|
|
245
|
+
for (const task of fresh.filter((entry) => entry.claimable && !entry.locked)) {
|
|
246
|
+
try {
|
|
247
|
+
const reward = await claimWorkBuddyTask(token, task.taskCode, fetchFn);
|
|
248
|
+
creditEarned += reward.credit;
|
|
249
|
+
claimedCount += 1;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// One task's refusal does not stop the others.
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
const stateOf = (task) => task.claimed ? 'claimed' : task.locked ? 'locked' : task.claimable ? 'claimable' : 'pending';
|
|
257
|
+
return {
|
|
258
|
+
tasks: fresh.map((task) => ({
|
|
259
|
+
taskCode: task.taskCode,
|
|
260
|
+
title: task.title,
|
|
261
|
+
credit: task.credit,
|
|
262
|
+
target: task.target,
|
|
263
|
+
current: task.current,
|
|
264
|
+
state: stateOf(task),
|
|
265
|
+
})),
|
|
266
|
+
claimed: claimedCount,
|
|
267
|
+
claimable: fresh.filter((task) => task.claimable && !task.locked).length,
|
|
268
|
+
creditEarned,
|
|
269
|
+
};
|
|
270
|
+
},
|
|
226
271
|
};
|
|
227
272
|
}
|
|
@@ -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.
|
|
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",
|