dsh-connect-workbuddy 4.13.2 → 4.14.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/CHANGELOG.md +75 -0
- package/README.en.md +2 -1
- package/README.md +2 -1
- package/lib/bin.js +1 -1
- package/lib/client.js +381 -54
- package/lib/{host-heartbeat-BJAL9pEe.js → host-heartbeat-D1WnqQY2.js} +409 -61
- package/lib/index.d.ts +234 -21
- package/lib/index.js +6 -66
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -574,6 +574,179 @@ declare class WorkBuddyCredentialStore {
|
|
|
574
574
|
}>;
|
|
575
575
|
}
|
|
576
576
|
//#endregion
|
|
577
|
+
//#region src/promo.d.ts
|
|
578
|
+
/**
|
|
579
|
+
* WorkBuddy promotion & tier badges — the upstream's own "this model is on
|
|
580
|
+
* offer" annotation, parsed and resolved against the wall clock.
|
|
581
|
+
*
|
|
582
|
+
* WHY A SEPARATE MODULE, AND WHY IT COSTS NO REQUEST. The upstream ships the
|
|
583
|
+
* badges inside the SAME `/v3/config` document that already carries the model
|
|
584
|
+
* roster: `data.modelPromotions` and `data.modelTiers` sit beside
|
|
585
|
+
* `data.models` (observed on the global feed, 2026-10-21). The plugin already
|
|
586
|
+
* reads that document for the roster, so drawing a promotion badge adds ZERO
|
|
587
|
+
* upstream traffic — it only adds a parser, because the document is not a
|
|
588
|
+
* clean list of promotions: the same `modelPromotions` array also carries
|
|
589
|
+
* NON-promotion entries (`hy-image-3.5`, `kling-video-v3` — entries with
|
|
590
|
+
* `tags` / `videoGeneration` and no `modelIds` and no `badge`). Those must be
|
|
591
|
+
* dropped, not rendered.
|
|
592
|
+
*
|
|
593
|
+
* WHY THE RESOLUTION LIVES HERE AND NOT IN THE FETCHER. A badge is a function
|
|
594
|
+
* of the clock, not of the fetch: the upstream's windows are wall-clock
|
|
595
|
+
* windows in a named zone (`schedule.daily`, e.g. `23:00`–`7:50` in
|
|
596
|
+
* `Asia/Shanghai`) and absolute windows (`schedule.validFrom` /
|
|
597
|
+
* `schedule.validUntil`). Picking the badge once, at parse time, FREEZES it —
|
|
598
|
+
* a badge read at 22:59 would still claim "night discount" at 08:00 the next
|
|
599
|
+
* morning. So the parser keeps EVERY candidate and the RENDERER asks for the
|
|
600
|
+
* one that holds at the moment it draws. The card re-renders at least once a
|
|
601
|
+
* minute while it is open (it polls the usage route), so a window edge is
|
|
602
|
+
* picked up within a minute without a second timer.
|
|
603
|
+
*
|
|
604
|
+
* THE SHAPES THIS PARSER ACCEPTS (all observed on the global feed's
|
|
605
|
+
* `/v3/config`, 2026-10-21 — the CN feed publishes the same two arrays, with
|
|
606
|
+
* Chinese labels and the extra fields listed at the end of this header):
|
|
607
|
+
*
|
|
608
|
+
* {
|
|
609
|
+
* id: 'hy3-free-trial-202608',
|
|
610
|
+
* kind: 'discount',
|
|
611
|
+
* enabled: true,
|
|
612
|
+
* priority: 200,
|
|
613
|
+
* modelIds: ['hy3'],
|
|
614
|
+
* badge: { label: 'Free now', color: '#FF0000', display: 'activeOnly' },
|
|
615
|
+
* discount: { discountedCredits: '0x', displayMode: 'replace', factor: 0 },
|
|
616
|
+
* hover: { textZh: 'Aug 6 – Oct 31: Free daily use with unlimited credits.' },
|
|
617
|
+
* schedule: {
|
|
618
|
+
* timezone: 'Asia/Shanghai',
|
|
619
|
+
* validFrom: '2026-07-06T00:00:00+08:00',
|
|
620
|
+
* validUntil: '2026-11-01T00:00:00+08:00',
|
|
621
|
+
* },
|
|
622
|
+
* }
|
|
623
|
+
*
|
|
624
|
+
* and the tier shape (`data.modelTiers`), which has the same `badge` /
|
|
625
|
+
* `modelIds` / `priority` core, no `schedule`, and a `requiredUserType`:
|
|
626
|
+
*
|
|
627
|
+
* {
|
|
628
|
+
* id: 'gpt-pro-only',
|
|
629
|
+
* badge: { label: 'Pro Only', labelEn: 'Pro Only', color: '#009273' },
|
|
630
|
+
* hover: { textEn: 'Exclusive to Pro subscribers.', textZh: '模型仅面向 Pro 用户开放。' },
|
|
631
|
+
* modelIds: ['gpt-6-astra', …],
|
|
632
|
+
* priority: 200,
|
|
633
|
+
* requiredUserType: 'standard',
|
|
634
|
+
* tier: 'standard',
|
|
635
|
+
* }
|
|
636
|
+
*
|
|
637
|
+
* THE CN FEED IS THE SAME FEED, READ AS THE APP READS IT. The CN gateway
|
|
638
|
+
* publishes `modelPromotions` (8 entries, measured 2026-10-21) and
|
|
639
|
+
* `modelTiers` (1 entry) in the SAME `/v3/config` document — with Chinese
|
|
640
|
+
* labels (`夜间折扣` / `限时免费` / `夜间免费` / `独家限免` / `限时折扣` /
|
|
641
|
+
* `订阅优先`), a `schedule.daily` night window, a base64 `badge.icon` and an
|
|
642
|
+
* optional `badge.display: 'activeOnly'`. Those richer shapes are exactly what
|
|
643
|
+
* this parser accepts below.
|
|
644
|
+
*
|
|
645
|
+
* They are visible only to the APP's product identity: the CLI channel's
|
|
646
|
+
* answer to the same URL publishes neither array, because it is a strict
|
|
647
|
+
* subset of the app channel's document. The plugin therefore reads the
|
|
648
|
+
* product configuration as the app does (`PRODUCT_UA` in `src/upstream.ts`) —
|
|
649
|
+
* which is why a CN account sees the same badges here as in the WorkBuddy
|
|
650
|
+
* app, without a second upstream request.
|
|
651
|
+
*
|
|
652
|
+
* @module dsh-connect-workbuddy/promo
|
|
653
|
+
*/
|
|
654
|
+
/** How the upstream wants the badge to appear. */
|
|
655
|
+
interface WorkBuddyPromoBadge {
|
|
656
|
+
/**
|
|
657
|
+
* The badge's own wording, region-localized ("限时免费" on the CN feed,
|
|
658
|
+
* "Free now" on the global one).
|
|
659
|
+
*/
|
|
660
|
+
label: string;
|
|
661
|
+
/** The English wording, when the upstream publishes one. */
|
|
662
|
+
labelEn?: string;
|
|
663
|
+
/** A compact wording, when the upstream publishes one. */
|
|
664
|
+
shortLabel?: string;
|
|
665
|
+
/** The English compact wording, when the upstream publishes one. */
|
|
666
|
+
shortLabelEn?: string;
|
|
667
|
+
/**
|
|
668
|
+
* The badge's colour, as a hex string ("#009273").
|
|
669
|
+
*
|
|
670
|
+
* The upstream publishes it for most promotions and omits it for others
|
|
671
|
+
* (the CN tier entry has none), so the renderer treats it as optional.
|
|
672
|
+
*/
|
|
673
|
+
color?: string;
|
|
674
|
+
/**
|
|
675
|
+
* `'activeOnly'` — the badge belongs to the promotion's RUNNING period and
|
|
676
|
+
* must disappear when the promotion is over.
|
|
677
|
+
*
|
|
678
|
+
* Absent — the badge is STANDING: it describes the model for as long as the
|
|
679
|
+
* promotion itself lasts, while the promotion's daily window governs only
|
|
680
|
+
* the discount. The upstream uses this for its night-discount pairs, where
|
|
681
|
+
* one entry carries the badge plus the night hours and a second, separate
|
|
682
|
+
* entry carries the same badge plus the daytime hours.
|
|
683
|
+
*/
|
|
684
|
+
display?: 'activeOnly';
|
|
685
|
+
}
|
|
686
|
+
/** One daily window, as wall-clock times in `schedule.timezone`. */
|
|
687
|
+
interface WorkBuddyPromoWindow {
|
|
688
|
+
/** `'HH:mm'`, inclusive. */
|
|
689
|
+
start: string;
|
|
690
|
+
/**
|
|
691
|
+
* `'HH:mm'`, exclusive.
|
|
692
|
+
*
|
|
693
|
+
* `end` at or before `start` means the window CROSSES MIDNIGHT: `23:00` to
|
|
694
|
+
* `7:50` is the observed CN night window.
|
|
695
|
+
*/
|
|
696
|
+
end: string;
|
|
697
|
+
}
|
|
698
|
+
/** When a promotion runs. */
|
|
699
|
+
interface WorkBuddyPromoSchedule {
|
|
700
|
+
/** The IANA zone the daily windows are written in ("Asia/Shanghai"). */
|
|
701
|
+
timezone?: string;
|
|
702
|
+
/** Epoch milliseconds; the promotion has not started before it. */
|
|
703
|
+
validFrom?: number;
|
|
704
|
+
/** Epoch milliseconds; the promotion is over AT it. */
|
|
705
|
+
validUntil?: number;
|
|
706
|
+
/** The daily windows, when the upstream publishes them. */
|
|
707
|
+
daily?: readonly WorkBuddyPromoWindow[];
|
|
708
|
+
/**
|
|
709
|
+
* The upstream PUBLISHED `daily`, but not one entry of it could be evaluated.
|
|
710
|
+
*
|
|
711
|
+
* This is deliberately NOT the same as "no `daily`": an entry with no
|
|
712
|
+
* `daily` is a 24-hour campaign (the discount runs whenever the promotion
|
|
713
|
+
* does), while an entry whose every window failed to parse says nothing at
|
|
714
|
+
* all about when it runs. Reading the second as "always" would turn a live
|
|
715
|
+
* night-only campaign into a badge shown around the clock — the one
|
|
716
|
+
* direction that overstates what the upstream said. A promotion carrying
|
|
717
|
+
* this flag therefore never counts as running; the parse failure hides the
|
|
718
|
+
* badge instead of doubling it.
|
|
719
|
+
*/
|
|
720
|
+
dailyUnusable?: true;
|
|
721
|
+
}
|
|
722
|
+
/** The upstream's explanatory copy for the badge. */
|
|
723
|
+
interface WorkBuddyPromoHover {
|
|
724
|
+
/** The Chinese wording. */
|
|
725
|
+
textZh?: string;
|
|
726
|
+
/** The English wording. */
|
|
727
|
+
textEn?: string;
|
|
728
|
+
}
|
|
729
|
+
/** One upstream promotion or tier, resolved into the shape this plugin uses. */
|
|
730
|
+
interface WorkBuddyPromo {
|
|
731
|
+
/** The upstream's id ("hy3-free-trial-202608"). */
|
|
732
|
+
id: string;
|
|
733
|
+
/** Which upstream list the entry came from. */
|
|
734
|
+
source: 'promotion' | 'tier';
|
|
735
|
+
/** The models the badge applies to. */
|
|
736
|
+
modelIds: readonly string[];
|
|
737
|
+
/** What the badge says and how it looks. */
|
|
738
|
+
badge: WorkBuddyPromoBadge;
|
|
739
|
+
/** The upstream's explanatory copy, when it publishes one. */
|
|
740
|
+
hover?: WorkBuddyPromoHover;
|
|
741
|
+
/** When the promotion runs, when it publishes that. */
|
|
742
|
+
schedule?: WorkBuddyPromoSchedule;
|
|
743
|
+
/**
|
|
744
|
+
* The upstream's ordering weight: the higher the number, the more the
|
|
745
|
+
* badge matters. Used to pick ONE badge per model when several apply.
|
|
746
|
+
*/
|
|
747
|
+
priority: number;
|
|
748
|
+
}
|
|
749
|
+
//#endregion
|
|
577
750
|
//#region src/upstream.d.ts
|
|
578
751
|
/** WorkBuddy region selected by the credential's login domain. */
|
|
579
752
|
type WorkBuddyRegion = 'cn' | 'global';
|
|
@@ -677,6 +850,20 @@ interface WorkBuddyUpstreamModel {
|
|
|
677
850
|
descriptionZh?: string;
|
|
678
851
|
descriptionEn?: string;
|
|
679
852
|
supportsToolCall?: boolean;
|
|
853
|
+
/**
|
|
854
|
+
* The upstream's own promotion / tier badges that name THIS model.
|
|
855
|
+
*
|
|
856
|
+
* Not a field of the model entry: the upstream publishes the badges in
|
|
857
|
+
* sibling arrays keyed by `modelIds` (`data.modelPromotions` /
|
|
858
|
+
* `data.modelTiers`), inside the SAME `/v3/config` document that carries
|
|
859
|
+
* the roster — so reading them costs no extra request.
|
|
860
|
+
*
|
|
861
|
+
* They ride along UNRESOLVED, and that is deliberate: a badge is a function
|
|
862
|
+
* of the clock (the upstream's windows are wall-clock hours in a named
|
|
863
|
+
* zone), so the entry that holds NOW is decided where the badge is drawn,
|
|
864
|
+
* not where the document was read. See `src/promo.ts`.
|
|
865
|
+
*/
|
|
866
|
+
promos?: readonly WorkBuddyPromo[];
|
|
680
867
|
}
|
|
681
868
|
/** One billing package as the upstream returns it, dates already parsed. */
|
|
682
869
|
interface WorkBuddyCreditPackage {
|
|
@@ -1018,13 +1205,14 @@ declare class WorkBuddyUpstreamClient {
|
|
|
1018
1205
|
/**
|
|
1019
1206
|
* Read the model directory for the credential's region.
|
|
1020
1207
|
*
|
|
1021
|
-
* Both regions
|
|
1022
|
-
* consumes,
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
*
|
|
1026
|
-
*
|
|
1027
|
-
*
|
|
1208
|
+
* Both regions read `/v3/config`, the document the WorkBuddy app itself
|
|
1209
|
+
* consumes, and both read it as the APP's product identity
|
|
1210
|
+
* ({@link PRODUCT_UA}) — the header the app sends, not the CLI channel's.
|
|
1211
|
+
* That is load-bearing, not cosmetic: the CLI channel's answer is a strict
|
|
1212
|
+
* subset of the app channel's and publishes neither `modelPromotions` nor
|
|
1213
|
+
* `modelTiers`, so reading `/v3/config` as the CLI channel is what left the
|
|
1214
|
+
* CN card without a single promotion badge while the app showed one on the
|
|
1215
|
+
* same account (see {@link PRODUCT_UA}).
|
|
1028
1216
|
*
|
|
1029
1217
|
* CN falls back to the legacy {@link MODELS_CATALOG_PATH} when `/v3` fails,
|
|
1030
1218
|
* returns a non-zero envelope, or resolves to no usable model, so a gateway
|
|
@@ -1035,8 +1223,14 @@ declare class WorkBuddyUpstreamClient {
|
|
|
1035
1223
|
*
|
|
1036
1224
|
* No user-side toggle is involved: the region comes from the credential's
|
|
1037
1225
|
* `domain`.
|
|
1226
|
+
*
|
|
1227
|
+
* `keepModelIds` is the user's own selection, passed through to
|
|
1228
|
+
* {@link selectCliModels}: a model the upstream roster dropped but the SAME
|
|
1229
|
+
* document still publishes stays in the roster, so reading the directory
|
|
1230
|
+
* never withdraws a model the user is running (issue #32's failure mode,
|
|
1231
|
+
* one step upstream of it).
|
|
1038
1232
|
*/
|
|
1039
|
-
fetchModels(credential: WorkBuddyCredential, signal?: AbortSignal): Promise<readonly WorkBuddyUpstreamModel[]>;
|
|
1233
|
+
fetchModels(credential: WorkBuddyCredential, signal?: AbortSignal, keepModelIds?: readonly string[]): Promise<readonly WorkBuddyUpstreamModel[]>;
|
|
1040
1234
|
/** Query today's check-in status without changing account state. */
|
|
1041
1235
|
fetchCheckinStatus(credential: WorkBuddyCredential): Promise<WorkBuddyCheckinStatus>;
|
|
1042
1236
|
/**
|
|
@@ -1092,6 +1286,12 @@ type WorkBuddyModelInfo = WorkBuddyUpstreamModel;
|
|
|
1092
1286
|
* Static CLI models captured from the CN endpoint (2026-08-30). The upstream
|
|
1093
1287
|
* refresh replaces this list at startup; it exists so the provider registers
|
|
1094
1288
|
* with a usable catalog even while the first fetch is in flight or offline.
|
|
1289
|
+
*
|
|
1290
|
+
* The upstream's `auto` ROUTER is deliberately absent, matching what
|
|
1291
|
+
* `selectCliModels` now does to the live roster: it resolves to a different
|
|
1292
|
+
* model per request, so it is not a row this plugin can describe. Keeping it
|
|
1293
|
+
* here would have reintroduced it on the offline/第一帧 path only, which is the
|
|
1294
|
+
* hardest kind of inconsistency to notice.
|
|
1095
1295
|
*/
|
|
1096
1296
|
declare const FALLBACK_WORKBUDDY_MODELS: readonly WorkBuddyModelInfo[];
|
|
1097
1297
|
/**
|
|
@@ -1118,6 +1318,20 @@ declare function fallbackModelsFor(region: 'cn' | 'global'): readonly WorkBuddyM
|
|
|
1118
1318
|
* never been configured must still serve models rather than nothing.
|
|
1119
1319
|
*/
|
|
1120
1320
|
type WorkBuddyContextBudget = number;
|
|
1321
|
+
/**
|
|
1322
|
+
* Derive the runtime catalog from the last-refreshed directory plus the user's
|
|
1323
|
+
* selection.
|
|
1324
|
+
*
|
|
1325
|
+
* An empty selection means "never configured" and serves the whole directory.
|
|
1326
|
+
* But a NON-empty selection that intersects the directory in nothing must NOT
|
|
1327
|
+
* serve nothing: that is the issue #32 failure mode (the picker empties out),
|
|
1328
|
+
* and it now has a realistic trigger — a user whose only ticked model was the
|
|
1329
|
+
* upstream's `auto` router, which this version stops offering. Such a selection
|
|
1330
|
+
* degrades to the whole directory rather than to silence: the user asked for
|
|
1331
|
+
* "some models to be on", and the alternative is a region with no models at
|
|
1332
|
+
* all. An empty directory still yields an empty result; the guard is only about
|
|
1333
|
+
* a selection that no longer matches anything.
|
|
1334
|
+
*/
|
|
1121
1335
|
declare function deriveCatalog(catalog: readonly WorkBuddyModelInfo[], enabled: ReadonlySet<string>, budgets?: Readonly<Record<string, WorkBuddyContextBudget | undefined>>): WorkBuddyModelInfo[];
|
|
1122
1336
|
/**
|
|
1123
1337
|
* Mutable catalog shared by the shim's `/v1/models` and the adapter.
|
|
@@ -2393,19 +2607,6 @@ interface WorkBuddyPoolTestRow {
|
|
|
2393
2607
|
}
|
|
2394
2608
|
//#endregion
|
|
2395
2609
|
//#region src/status-paths.d.ts
|
|
2396
|
-
/**
|
|
2397
|
-
* Node-free constants and types shared by the Host and browser halves.
|
|
2398
|
-
*
|
|
2399
|
-
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
2400
|
-
* — 「3 条同源只读路由(usage / models:refresh / accounts:refresh)+ 一份
|
|
2401
|
-
* 与浏览器共享的 node-free 类型定义」的 host↔client 桥梁形态来自该项目
|
|
2402
|
-
* (其 `status-paths.ts` 亦如此,并注明沿用
|
|
2403
|
-
* corrinehu/dsh-workbuddy-connect 的 status-route 模式)。
|
|
2404
|
-
* 改动:路由路径改用本插件 id;类型字段按 WorkBuddy 上游实际给出的能力
|
|
2405
|
-
* (积分倍率、多模态、推理档位)调整,不保留 trae 的 1M 变体字段。
|
|
2406
|
-
*
|
|
2407
|
-
* @module dsh-connect-workbuddy/status-paths
|
|
2408
|
-
*/
|
|
2409
2610
|
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
2410
2611
|
declare const WORKBUDDY_USAGE_PATH = "/plugins/dsh-connect-workbuddy/usage";
|
|
2411
2612
|
/** Plugin-owned live model refresh endpoint. */
|
|
@@ -2641,6 +2842,18 @@ interface WorkBuddyWebModel {
|
|
|
2641
2842
|
refusesOff?: boolean;
|
|
2642
2843
|
};
|
|
2643
2844
|
description?: string;
|
|
2845
|
+
/**
|
|
2846
|
+
* The upstream's promotion / tier badges that name this model, UNRESOLVED.
|
|
2847
|
+
*
|
|
2848
|
+
* Every candidate that names the model rides along, in priority order, so
|
|
2849
|
+
* the card can pick the one that holds at the moment it draws — a badge is a
|
|
2850
|
+
* function of the clock, and a badge frozen at fetch time would keep
|
|
2851
|
+
* claiming a night discount after the night is over. See `src/promo.ts`.
|
|
2852
|
+
*
|
|
2853
|
+
* Persisted inside `lastCatalog` (it rides along in the saved entries) and
|
|
2854
|
+
* read back from there, which is why it must stay JSON-shaped.
|
|
2855
|
+
*/
|
|
2856
|
+
promos?: readonly WorkBuddyPromo[];
|
|
2644
2857
|
}
|
|
2645
2858
|
/**
|
|
2646
2859
|
* Project one card row into its persisted `lastCatalog` shape: the native
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as withEffectiveOff, A as workbuddyAccountId, B as modelIdOfBody, C as defaultDesktopAuthDirs, D as isVaultAccountId, E as isEncryptedCredentialError, F as WorkBuddyUpstreamClient, G as regionOf, H as parseReasoning, I as classifyUpstreamError, J as defaultOffModelIds, K as systemOpeningsOfBody, L as declaredTools, M as CREDENTIAL_REJECTED_CODE, N as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, O as legacyWorkbuddyOwnAuthPath, P as WorkBuddyCredentialRejectedError, Q as recordRefusal, R as isCredentialRejectedError, S as defaultDesktopAuthCandidates, T as hasEncryptedCredentialFields, U as parseUpstreamModel, V as parseCreditMultiplier, W as prepareChatBody, X as offDefaultFor, Y as lastRefusalFor, Z as offRefused, _ as WORKBUDDY_AUTH_FILENAME,
|
|
1
|
+
import { $ as withEffectiveOff, A as workbuddyAccountId, B as modelIdOfBody, C as defaultDesktopAuthDirs, D as isVaultAccountId, E as isEncryptedCredentialError, F as WorkBuddyUpstreamClient, G as regionOf, H as parseReasoning, I as classifyUpstreamError, J as defaultOffModelIds, K as systemOpeningsOfBody, L as declaredTools, M as CREDENTIAL_REJECTED_CODE, N as WORKBUDDY_FALLBACK_SYSTEM_PROMPT, O as legacyWorkbuddyOwnAuthPath, P as WorkBuddyCredentialRejectedError, Q as recordRefusal, R as isCredentialRejectedError, S as defaultDesktopAuthCandidates, T as hasEncryptedCredentialFields, U as parseUpstreamModel, V as parseCreditMultiplier, W as prepareChatBody, X as offDefaultFor, Y as lastRefusalFor, Z as offRefused, _ as WORKBUDDY_AUTH_FILENAME, a as readHostHeartbeat, at as deriveAtRestKey, b as WorkBuddyEncryptedCredentialError, bt as writeFileAtomic, c as WORKBUDDY_CONNECT_VERSION, ct as findWorkbuddyAppExecutable, d as FALLBACK_WORKBUDDY_MODELS_GLOBAL, dt as isWorkbuddyBundle, et as NATIVE_MODALITY_BY_MODEL_ID, f as WorkBuddyCatalog, ft as macosBundleExecutable, g as ENCRYPTED_CREDENTIAL_CODE, gt as workbuddyAppExecutableCandidates, h as fallbackModelsFor, ht as readAtRestKey, i as processStartTimeMs, it as clearAtRestKeyCache, j as workbuddyOwnAuthPath, k as parseWorkBuddyAuth, l as piAiRuntimeInfo, m as deriveCatalog, mt as openEncryptedField, n as clearHostHeartbeat, nt as nativeModalityOf, o as workbuddyHostHeartbeatPath, ot as deriveAtRestKeyId, p as applyContextBudgets, pt as macosNestedAppBundles, q as REFUSES_OFF_MODEL_IDS, r as isHeartbeatProcessAlive, rt as WORKBUDDY_APP_EXECUTABLE_ENV, s as writeHostHeartbeat, st as fetchAtRestKeyPayload, t as WORKBUDDY_HOST_HEARTBEAT_FILENAME, tt as imageDefaultFor, u as FALLBACK_WORKBUDDY_MODELS, ut as isEncryptedFieldWrapper, v as WORKBUDDY_AUTH_FILE_ENV, vt as resolveDshHome, w as defaultDesktopAuthPath, x as authFileName, y as WorkBuddyCredentialStore, yt as withFileLock, z as knownRegionOf } from "./host-heartbeat-D1WnqQY2.js";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import { appendFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
4
|
import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -5000,19 +5000,6 @@ async function writePoolProbes(region, updates) {
|
|
|
5000
5000
|
}
|
|
5001
5001
|
//#endregion
|
|
5002
5002
|
//#region src/status-paths.ts
|
|
5003
|
-
/**
|
|
5004
|
-
* Node-free constants and types shared by the Host and browser halves.
|
|
5005
|
-
*
|
|
5006
|
-
* 参考:dingminhua/dsh-connect-trae(MIT,Copyright (c) 2026 LaoDing)
|
|
5007
|
-
* — 「3 条同源只读路由(usage / models:refresh / accounts:refresh)+ 一份
|
|
5008
|
-
* 与浏览器共享的 node-free 类型定义」的 host↔client 桥梁形态来自该项目
|
|
5009
|
-
* (其 `status-paths.ts` 亦如此,并注明沿用
|
|
5010
|
-
* corrinehu/dsh-workbuddy-connect 的 status-route 模式)。
|
|
5011
|
-
* 改动:路由路径改用本插件 id;类型字段按 WorkBuddy 上游实际给出的能力
|
|
5012
|
-
* (积分倍率、多模态、推理档位)调整,不保留 trae 的 1M 变体字段。
|
|
5013
|
-
*
|
|
5014
|
-
* @module dsh-connect-workbuddy/status-paths
|
|
5015
|
-
*/
|
|
5016
5003
|
/** Plugin-owned usage endpoint consumed by its browser half. */
|
|
5017
5004
|
const WORKBUDDY_USAGE_PATH = "/plugins/dsh-connect-workbuddy/usage";
|
|
5018
5005
|
/**
|
|
@@ -5403,7 +5390,8 @@ function toWebModel(model, budgets) {
|
|
|
5403
5390
|
...model.reasoning.canDisableThinking === void 0 ? {} : { canDisableThinking: model.reasoning.canDisableThinking },
|
|
5404
5391
|
...offRefused(model.id) ? { offRefused: true } : {},
|
|
5405
5392
|
...model.reasoning.refusesOff === true ? { refusesOff: true } : {}
|
|
5406
|
-
} }
|
|
5393
|
+
} },
|
|
5394
|
+
...model.promos === void 0 ? {} : { promos: model.promos }
|
|
5407
5395
|
};
|
|
5408
5396
|
}
|
|
5409
5397
|
/**
|
|
@@ -6185,55 +6173,6 @@ function registerWorkBuddyStatusRoute(ctx, deps) {
|
|
|
6185
6173
|
}, "dsh-connect-workbuddy: Web status route");
|
|
6186
6174
|
}
|
|
6187
6175
|
//#endregion
|
|
6188
|
-
//#region src/native-modality.ts
|
|
6189
|
-
/**
|
|
6190
|
-
* Reviewed vendor classifications, keyed by EXACT model id (never a prefix).
|
|
6191
|
-
* Ids absent from this record are `unknown` — see {@link nativeModalityOf}.
|
|
6192
|
-
*/
|
|
6193
|
-
const NATIVE_MODALITY_BY_MODEL_ID = {
|
|
6194
|
-
"deepseek-v4-pro": "text",
|
|
6195
|
-
"glm-5.1": "text",
|
|
6196
|
-
"glm-5.2": "text",
|
|
6197
|
-
"glm-5.3": "text",
|
|
6198
|
-
"hy3": "text",
|
|
6199
|
-
"hy4-preview": "text",
|
|
6200
|
-
"deepseek-v4.1-flash": "multimodal",
|
|
6201
|
-
"glm-5.3-flash": "multimodal",
|
|
6202
|
-
"glm-5v-turbo": "multimodal",
|
|
6203
|
-
"kimi-k2.6": "multimodal",
|
|
6204
|
-
"kimi-k2.7": "multimodal",
|
|
6205
|
-
"kimi-k3-1": "multimodal",
|
|
6206
|
-
"minimax-m3": "multimodal"
|
|
6207
|
-
};
|
|
6208
|
-
/** The `auto` entry is a router that picks a model, not a model itself. */
|
|
6209
|
-
const ROUTER_MODEL_ID = "auto";
|
|
6210
|
-
/**
|
|
6211
|
-
* Native modality of one model id. Exact match only: a new model never
|
|
6212
|
-
* inherits a classification from its family, its display name, or the
|
|
6213
|
-
* platform's image flag.
|
|
6214
|
-
*/
|
|
6215
|
-
function nativeModalityOf(modelId) {
|
|
6216
|
-
if (modelId === ROUTER_MODEL_ID) return "router";
|
|
6217
|
-
return NATIVE_MODALITY_BY_MODEL_ID[modelId] ?? "unknown";
|
|
6218
|
-
}
|
|
6219
|
-
/**
|
|
6220
|
-
* Whether a model refresh should PRE-CHECK this model's image box.
|
|
6221
|
-
*
|
|
6222
|
-
* Only a documented `multimodal` is pre-checked. `text` is documented as
|
|
6223
|
-
* unable to read images, and `unknown` is deliberately left unchecked rather
|
|
6224
|
-
* than guessed — the whole reason this table exists is that the platform flag
|
|
6225
|
-
* guessed wrong. A platform `supportsImages: false` still vetoes, so a
|
|
6226
|
-
* documented-multimodal id can never be pre-checked against the platform's
|
|
6227
|
-
* explicit "no".
|
|
6228
|
-
*
|
|
6229
|
-
* The user can always tick a box by hand; this decides a DEFAULT only, and the
|
|
6230
|
-
* effective runtime flag remains the saved `imageModelIds`.
|
|
6231
|
-
*/
|
|
6232
|
-
function imageDefaultFor(info) {
|
|
6233
|
-
if (info.supportsImages === false) return false;
|
|
6234
|
-
return NATIVE_MODALITY_BY_MODEL_ID[info.id] === "multimodal";
|
|
6235
|
-
}
|
|
6236
|
-
//#endregion
|
|
6237
6176
|
//#region src/index.ts
|
|
6238
6177
|
/** Stable Cordis plugin name. */
|
|
6239
6178
|
const name = "dsh-connect-workbuddy";
|
|
@@ -6633,7 +6572,8 @@ function apply(ctx, config) {
|
|
|
6633
6572
|
const effectiveAccountFor = (region, value) => selectAccountFor(region, value, legacyAccountRegion);
|
|
6634
6573
|
const discoverModels = async (region, signal) => {
|
|
6635
6574
|
const credential = await stacks[region].store.resolve();
|
|
6636
|
-
|
|
6575
|
+
const keep = regionStateOf(current(), region).enabledModelIds ?? [];
|
|
6576
|
+
return client.fetchModels(credential, signal, keep);
|
|
6637
6577
|
};
|
|
6638
6578
|
/** Push the current config into every region's store selection and catalog. */
|
|
6639
6579
|
const applySelection = (value) => {
|
|
@@ -7635,7 +7575,7 @@ function apply(ctx, config) {
|
|
|
7635
7575
|
try {
|
|
7636
7576
|
const credential = await stacks[region].store.resolve();
|
|
7637
7577
|
if (stopped) return;
|
|
7638
|
-
const models = await client.fetchModels(credential);
|
|
7578
|
+
const models = await client.fetchModels(credential, void 0, regionStateOf(current(), region).enabledModelIds ?? []);
|
|
7639
7579
|
if (stopped) return;
|
|
7640
7580
|
const state = regionStateOf(current(), region);
|
|
7641
7581
|
stacks[region].catalog.set(withEffectiveOff(withImageSelection(deriveCatalog(models, new Set(state.enabledModelIds ?? []), state.contextBudgets ?? {}), new Set(state.imageModelIds ?? [])), new Set(savedOffModelIds(state, models))));
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-connect-workbuddy",
|
|
3
3
|
"displayName": "DSH Connect WorkBuddy",
|
|
4
4
|
"description": "把本机登录的 WorkBuddy 模型(国内版与国际版)接入 DeepSeek Harness:每次刷新按上游目录自动读取每个模型的积分倍率,支持逐模型图片输入开关、多账号切换与账号池自动换号,并提供每日签到、卡片与输入框里的胶囊积分读数等只读积分概览。",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.14.1",
|
|
6
6
|
"author": "dingminhua",
|
|
7
7
|
"copyright": "Copyright (c) 2026 LaoDing",
|
|
8
8
|
"license": "MIT",
|