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/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
@@ -29,6 +29,7 @@ export const RPC_ENDPOINTS = [
29
29
  'auto-state',
30
30
  'setAutoOn',
31
31
  'checkin',
32
+ 'tasks',
32
33
  'deepseek-balance',
33
34
  'ccswitch-balance',
34
35
  'model-variants',
@@ -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, 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.15.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",