dsh-workbuddy-bridge 0.2.0 → 0.3.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/README.md +55 -54
- package/README_en.md +61 -63
- package/lib/bin.js +8 -7
- package/lib/client.js +1210 -411
- package/lib/{variants-DP0Ho0Tc.js → heartbeat-DihKwwFX.js} +152 -97
- package/lib/index.d.ts +187 -4
- package/lib/index.js +582 -88
- package/locale/README.md +10 -0
- package/package.json +40 -28
|
@@ -12,9 +12,8 @@ import { accessSync, constants, realpathSync, statSync } from "node:fs";
|
|
|
12
12
|
* The international desktop app's version, used as the `/v3/config` UA.
|
|
13
13
|
*
|
|
14
14
|
* The App-shaped catalog is served only to a User-Agent carrying the product
|
|
15
|
-
* name
|
|
16
|
-
*
|
|
17
|
-
* re-measured on 2026-09-11 the *space* form is rejected (HTTP 400, code
|
|
15
|
+
* name. The 2026-09-11 research recommended the space form `WorkBuddy AI/<v>`;
|
|
16
|
+
* re-measured the same day the *space* form is rejected (HTTP 400, code
|
|
18
17
|
* 12403) while the terse `WorkBuddyAI/<v>` form — with or without the space
|
|
19
18
|
* removed — returns the 21-model App document. The UA is therefore built from
|
|
20
19
|
* the form verified in code, not from the earlier prose.
|
|
@@ -150,8 +149,9 @@ function appUserAgent(version) {
|
|
|
150
149
|
//#endregion
|
|
151
150
|
//#region src/protocol/client-identity.ts
|
|
152
151
|
/**
|
|
153
|
-
* The desktop-client identity chat requests present as (phase 1 of
|
|
154
|
-
* `
|
|
152
|
+
* The desktop-client identity chat requests present as (phase 1 of the upstream
|
|
153
|
+
* identity alignment — unit-covered by `tests/client-identity.spec.ts`, and
|
|
154
|
+
* re-checked against the real upstream by `scripts/client-identity-live-matrix.mjs`).
|
|
155
155
|
*
|
|
156
156
|
* Chat and its probe sibling carry the User-Agent shape the official desktop
|
|
157
157
|
* client composes — `WorkBuddy/<v> <product>/<v> CLI/<cli>` — where the
|
|
@@ -163,7 +163,7 @@ function appUserAgent(version) {
|
|
|
163
163
|
* a missing extension).
|
|
164
164
|
*
|
|
165
165
|
* Scope: chat and probe requests ONLY. Refresh, catalog, and billing keep
|
|
166
|
-
* the headers they have always sent;
|
|
166
|
+
* the headers they have always sent; this phase holds the blast radius to
|
|
167
167
|
* one variable so the live verification matrix stays readable.
|
|
168
168
|
*
|
|
169
169
|
* @module dsh-workbuddy-bridge/client-identity
|
|
@@ -500,7 +500,7 @@ function parseJson(body) {
|
|
|
500
500
|
* The reasoning-effort probe: decide whether a model's `reasoning_effort`
|
|
501
501
|
* parameter is actually validated, and if so which canonical values it accepts.
|
|
502
502
|
*
|
|
503
|
-
*
|
|
503
|
+
* The order below is what `tests/probe.spec.ts` asserts. It matters and is
|
|
504
504
|
* not an optimization:
|
|
505
505
|
*
|
|
506
506
|
* 1. **Baseline** (no `reasoning_effort`) proves the model, credential, and
|
|
@@ -774,10 +774,10 @@ function originReferer(credential) {
|
|
|
774
774
|
/** Headers every upstream request shares. */
|
|
775
775
|
function commonHeaders(credential) {
|
|
776
776
|
return {
|
|
777
|
-
|
|
777
|
+
Accept: "application/json, text/plain, */*",
|
|
778
778
|
"X-Requested-With": "XMLHttpRequest",
|
|
779
|
-
|
|
780
|
-
|
|
779
|
+
Origin: originReferer(credential),
|
|
780
|
+
Referer: `${originReferer(credential)}/`,
|
|
781
781
|
"User-Agent": CLIENT_UA
|
|
782
782
|
};
|
|
783
783
|
}
|
|
@@ -812,8 +812,8 @@ function refreshHeaders(credential) {
|
|
|
812
812
|
/** Billing request headers. */
|
|
813
813
|
function billingHeaders(credential) {
|
|
814
814
|
const headers = {
|
|
815
|
-
|
|
816
|
-
|
|
815
|
+
Authorization: `Bearer ${credential.accessToken}`,
|
|
816
|
+
Accept: "application/json",
|
|
817
817
|
"Content-Type": "application/json"
|
|
818
818
|
};
|
|
819
819
|
if (credential.uid !== "") headers["X-User-Id"] = credential.uid;
|
|
@@ -952,7 +952,7 @@ var WorkBuddyUpstreamClient = class {
|
|
|
952
952
|
method: "POST",
|
|
953
953
|
headers: {
|
|
954
954
|
...chatHeaders(credential, userAgent),
|
|
955
|
-
|
|
955
|
+
Authorization: `Bearer ${credential.accessToken}`
|
|
956
956
|
},
|
|
957
957
|
body: region === "global" ? prepareInternationalChatBody(bodyJson) : bodyJson,
|
|
958
958
|
...signal === void 0 ? {} : { signal }
|
|
@@ -1288,7 +1288,7 @@ var WorkBuddyUpstreamClient = class {
|
|
|
1288
1288
|
method: "POST",
|
|
1289
1289
|
headers: {
|
|
1290
1290
|
...chatHeaders(credential, userAgent),
|
|
1291
|
-
|
|
1291
|
+
Authorization: `Bearer ${credential.accessToken}`
|
|
1292
1292
|
},
|
|
1293
1293
|
body: JSON.stringify(payload),
|
|
1294
1294
|
signal
|
|
@@ -2342,6 +2342,107 @@ function discoveryIncomplete(detail) {
|
|
|
2342
2342
|
const HELPER_SCRIPT = "process.stdout.write(String(process._linkedBinding(\"electron_browser_workbuddy_storage\").loggerGet()))";
|
|
2343
2343
|
const HELPER_SCRIPT_ARGUMENT_FLAG = "-e";
|
|
2344
2344
|
//#endregion
|
|
2345
|
+
//#region src/shared/paths.ts
|
|
2346
|
+
/** Node-free constants and types shared by the Host and browser halves. */
|
|
2347
|
+
/** Plugin-owned status endpoint consumed by its browser half. */
|
|
2348
|
+
const WORKBUDDY_STATUS_PATH = "/plugins/dsh-workbuddy-bridge/status";
|
|
2349
|
+
/**
|
|
2350
|
+
* Plugin-owned probe control endpoint.
|
|
2351
|
+
*
|
|
2352
|
+
* Separate from the status route because it accepts writes: the status route's
|
|
2353
|
+
* loopback Host/Origin guard protects against a DNS-rebinding *page*, which is
|
|
2354
|
+
* not the same as authorizing a state-changing action. This route therefore
|
|
2355
|
+
* also requires the in-memory key the browser half receives with the status
|
|
2356
|
+
* document.
|
|
2357
|
+
*/
|
|
2358
|
+
const WORKBUDDY_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/probe";
|
|
2359
|
+
/**
|
|
2360
|
+
* The international (WorkBuddy AI) variant's own pair of routes.
|
|
2361
|
+
*
|
|
2362
|
+
* Kept as separate constants rather than a computed suffix so both halves
|
|
2363
|
+
* reference literal strings: the browser bundle and the host bundle are built
|
|
2364
|
+
* independently, and a shared expression is one build-config drift away from
|
|
2365
|
+
* the desk asking a route the host never mounted.
|
|
2366
|
+
*/
|
|
2367
|
+
const WORKBUDDY_AI_STATUS_PATH = "/plugins/dsh-workbuddy-bridge/ai/status";
|
|
2368
|
+
const WORKBUDDY_AI_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/ai/probe";
|
|
2369
|
+
/**
|
|
2370
|
+
* Plugin-owned per-message credit route.
|
|
2371
|
+
*
|
|
2372
|
+
* A read-only GET taking `?sessionId=…`, answering `messageId → credit` for one
|
|
2373
|
+
* Session. It is its own route rather than a field of the status document
|
|
2374
|
+
* because the two have different lifetimes: the status document is per
|
|
2375
|
+
* *account* and is re-read when the account changes, while credit accounting
|
|
2376
|
+
* is per *Session* and grows as messages are sent.
|
|
2377
|
+
*
|
|
2378
|
+
* **One route for both variants, on purpose.** The accounting is attributed to
|
|
2379
|
+
* a DSH `messageId` before it is stored, and a message id belongs to one
|
|
2380
|
+
* Session regardless of which provider served it — a conversation can switch
|
|
2381
|
+
* between the two WorkBuddy products (or away from both) mid-thread. A route
|
|
2382
|
+
* per variant would force the message row to know which provider answered a
|
|
2383
|
+
* message *it is merely labelling*, and would strand every message whose turn
|
|
2384
|
+
* ran under the other variant.
|
|
2385
|
+
*
|
|
2386
|
+
* No key is required: the route only reads what this plugin already observed on
|
|
2387
|
+
* its own loopback stream, carries no credential material, and answers loopback
|
|
2388
|
+
* requests through the same Host/Origin guard as the status route.
|
|
2389
|
+
*/
|
|
2390
|
+
const WORKBUDDY_CREDIT_PATH = "/plugins/dsh-workbuddy-bridge/credit";
|
|
2391
|
+
//#endregion
|
|
2392
|
+
//#region src/variants.ts
|
|
2393
|
+
/**
|
|
2394
|
+
* The two WorkBuddy desktop apps this one plugin serves.
|
|
2395
|
+
*
|
|
2396
|
+
* Both products are the same client framework in different regions, and both
|
|
2397
|
+
* write their sign-in into the *same* shared `CodeBuddyExtension` auth
|
|
2398
|
+
* directory — they differ by file basename, base URL, catalog endpoint, and
|
|
2399
|
+
* display identity. Everything that varies between them is collected here as
|
|
2400
|
+
* one descriptor, so no module has to carry its own `if (international)`
|
|
2401
|
+
* branch and a third variant would be a data change rather than a refactor.
|
|
2402
|
+
*
|
|
2403
|
+
* This module is host-side (it names files and env vars). The browser half
|
|
2404
|
+
* takes the same ids and routes from the Node-free `status-paths.ts`, which
|
|
2405
|
+
* stays the single source shared by both halves.
|
|
2406
|
+
*
|
|
2407
|
+
* @module dsh-workbuddy-bridge/variants
|
|
2408
|
+
*/
|
|
2409
|
+
/** CN WorkBuddy first: the existing provider keeps its id, paths, and copy. */
|
|
2410
|
+
const WORKBUDDY_VARIANTS = [{
|
|
2411
|
+
id: "workbuddy",
|
|
2412
|
+
displayName: "WorkBuddy",
|
|
2413
|
+
appName: "WorkBuddy",
|
|
2414
|
+
region: "cn",
|
|
2415
|
+
env: "WORKBUDDY_AUTH_FILE",
|
|
2416
|
+
desktopFilename: "workbuddy-desktop.info",
|
|
2417
|
+
ownFilename: ".workbuddy-auth.json",
|
|
2418
|
+
probeFilename: ".workbuddy-probe.json",
|
|
2419
|
+
catalogFilename: ".workbuddy-catalog.json",
|
|
2420
|
+
visibilityFilename: ".workbuddy-model-visibility.json",
|
|
2421
|
+
statusPath: WORKBUDDY_STATUS_PATH,
|
|
2422
|
+
probePath: WORKBUDDY_PROBE_PATH
|
|
2423
|
+
}, {
|
|
2424
|
+
id: "workbuddy-ai",
|
|
2425
|
+
displayName: "WorkBuddy AI",
|
|
2426
|
+
appName: "WorkBuddy AI",
|
|
2427
|
+
region: "global",
|
|
2428
|
+
env: "WORKBUDDY_AI_AUTH_FILE",
|
|
2429
|
+
desktopFilename: "workbuddy-desktop-ai.info",
|
|
2430
|
+
ownFilename: ".workbuddy-ai-auth.json",
|
|
2431
|
+
probeFilename: ".workbuddy-ai-probe.json",
|
|
2432
|
+
catalogFilename: ".workbuddy-ai-catalog.json",
|
|
2433
|
+
visibilityFilename: ".workbuddy-ai-model-visibility.json",
|
|
2434
|
+
statusPath: WORKBUDDY_AI_STATUS_PATH,
|
|
2435
|
+
probePath: WORKBUDDY_AI_PROBE_PATH
|
|
2436
|
+
}];
|
|
2437
|
+
/** The CN variant; the plugin's long-standing default and compatibility anchor. */
|
|
2438
|
+
const CN_VARIANT = WORKBUDDY_VARIANTS[0];
|
|
2439
|
+
/** The international variant. */
|
|
2440
|
+
const AI_VARIANT = WORKBUDDY_VARIANTS[1];
|
|
2441
|
+
/** Look up a variant by provider id. */
|
|
2442
|
+
function variantFor(id) {
|
|
2443
|
+
return WORKBUDDY_VARIANTS.find((variant) => variant.id === id);
|
|
2444
|
+
}
|
|
2445
|
+
//#endregion
|
|
2345
2446
|
//#region src/credential/store.ts
|
|
2346
2447
|
/**
|
|
2347
2448
|
* WorkBuddy credential resolution. The primary source is the WorkBuddy
|
|
@@ -2528,6 +2629,38 @@ function isENOENT(error) {
|
|
|
2528
2629
|
return error?.code === "ENOENT";
|
|
2529
2630
|
}
|
|
2530
2631
|
/**
|
|
2632
|
+
* Which automatic at-rest key discovery this store may run, by variant.
|
|
2633
|
+
*
|
|
2634
|
+
* **One home for a rule that had three.** The choice used to be made at every
|
|
2635
|
+
* call site — `src/index.ts` and `src/cli/bin.ts` each spelled out
|
|
2636
|
+
* `discovery: variant.id === CN_VARIANT.id ? cnAppDiscovery() : 'none'` — and the
|
|
2637
|
+
* store's own default was a bare `new WorkBuddyAtRestKeyProvider()`, whose
|
|
2638
|
+
* discovery is `'none'`. So a caller that did neither got a provider that could
|
|
2639
|
+
* never open an encrypted credential: `scripts/live-e2e.mjs` was exactly that
|
|
2640
|
+
* caller, and it failed with `electron-binary-unavailable` on every platform
|
|
2641
|
+
* (2026-10-03, found by the release checklist). The store knows its variant, so
|
|
2642
|
+
* the choice belongs here.
|
|
2643
|
+
*
|
|
2644
|
+
* Why the difference is deliberate:
|
|
2645
|
+
*
|
|
2646
|
+
* - Only the CN WorkBuddy install has been verified to hold the key its envelopes
|
|
2647
|
+
* name, and only its macOS/Windows layout is known, so CN may look for the app.
|
|
2648
|
+
* - A Global (WorkBuddy AI) encrypted credential has never been seen live, so that
|
|
2649
|
+
* variant runs at `'none'` — no default path and no app search. A Global unlock
|
|
2650
|
+
* must not silently execute the *CN* app's Electron. An explicit
|
|
2651
|
+
* `WORKBUDDY_ELECTRON_BIN` still works for Global.
|
|
2652
|
+
*
|
|
2653
|
+
* **No variant** means the CN product's own default file —
|
|
2654
|
+
* `defaultDesktopAuthCandidates()` is the `workbuddy-desktop.info` path, never the
|
|
2655
|
+
* AI one — so it gets the same discovery CN does.
|
|
2656
|
+
*
|
|
2657
|
+
* A keyId mismatch is still reported as a diagnosis rather than a wrong open, and
|
|
2658
|
+
* the helper only runs if an encrypted credential is actually read.
|
|
2659
|
+
*/
|
|
2660
|
+
function atRestDiscoveryFor(variant) {
|
|
2661
|
+
return variant === void 0 || variant.id === CN_VARIANT.id ? cnAppDiscovery() : "none";
|
|
2662
|
+
}
|
|
2663
|
+
/**
|
|
2531
2664
|
* Read-only credential store with demand-driven refresh.
|
|
2532
2665
|
*
|
|
2533
2666
|
* Refresh policy: refresh only when the access token is inside the margin
|
|
@@ -2549,7 +2682,7 @@ var WorkBuddyCredentialStore = class {
|
|
|
2549
2682
|
this.refresh = options.refresh;
|
|
2550
2683
|
this.refreshMarginMs = options.refreshMarginMs ?? 3e5;
|
|
2551
2684
|
this.ownPath = options.ownPath ?? (options.variant ? join(resolveDshHome(), options.variant.ownFilename) : workbuddyOwnAuthPath());
|
|
2552
|
-
this.keyProvider = options.keyProvider ?? new WorkBuddyAtRestKeyProvider();
|
|
2685
|
+
this.keyProvider = options.keyProvider ?? new WorkBuddyAtRestKeyProvider({ discovery: atRestDiscoveryFor(options.variant) });
|
|
2553
2686
|
this.desktopPathOverride = options.desktopPath;
|
|
2554
2687
|
}
|
|
2555
2688
|
/**
|
|
@@ -2624,6 +2757,7 @@ var WorkBuddyCredentialStore = class {
|
|
|
2624
2757
|
expiresAtMs: credential.expiresAtMs,
|
|
2625
2758
|
...credential.refreshExpiresAtMs === void 0 ? {} : { refreshExpiresAtMs: credential.refreshExpiresAtMs },
|
|
2626
2759
|
...credential.nickname === void 0 ? {} : { nickname: credential.nickname },
|
|
2760
|
+
...credential.uid === "" ? {} : { uid: credential.uid },
|
|
2627
2761
|
...credential.domain === "" ? {} : { domain: credential.domain },
|
|
2628
2762
|
source: credential.source
|
|
2629
2763
|
};
|
|
@@ -2663,7 +2797,7 @@ var WorkBuddyCredentialStore = class {
|
|
|
2663
2797
|
return refreshed;
|
|
2664
2798
|
} catch (error) {
|
|
2665
2799
|
if (credential.expiresAtMs > Date.now() + 3e4) return credential;
|
|
2666
|
-
throw new Error(`workbuddy: token refresh failed and the access token is expired (${String(error)}); open the WorkBuddy desktop app once to sign in again
|
|
2800
|
+
throw new Error(`workbuddy: token refresh failed and the access token is expired (${String(error)}); open the WorkBuddy desktop app once to sign in again`, { cause: error });
|
|
2667
2801
|
}
|
|
2668
2802
|
}
|
|
2669
2803
|
async saveOwn(credential) {
|
|
@@ -3553,33 +3687,8 @@ var WorkBuddyCatalog = class {
|
|
|
3553
3687
|
}
|
|
3554
3688
|
};
|
|
3555
3689
|
//#endregion
|
|
3556
|
-
//#region src/shared/paths.ts
|
|
3557
|
-
/** Node-free constants and types shared by the Host and browser halves. */
|
|
3558
|
-
/** Plugin-owned status endpoint consumed by its browser half. */
|
|
3559
|
-
const WORKBUDDY_STATUS_PATH = "/plugins/dsh-workbuddy-bridge/status";
|
|
3560
|
-
/**
|
|
3561
|
-
* Plugin-owned probe control endpoint.
|
|
3562
|
-
*
|
|
3563
|
-
* Separate from the status route because it accepts writes: the status route's
|
|
3564
|
-
* loopback Host/Origin guard protects against a DNS-rebinding *page*, which is
|
|
3565
|
-
* not the same as authorizing a state-changing action. This route therefore
|
|
3566
|
-
* also requires the in-process key the browser half receives with the status
|
|
3567
|
-
* document.
|
|
3568
|
-
*/
|
|
3569
|
-
const WORKBUDDY_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/probe";
|
|
3570
|
-
/**
|
|
3571
|
-
* The international (WorkBuddy AI) variant's own pair of routes.
|
|
3572
|
-
*
|
|
3573
|
-
* Kept as separate constants rather than a computed suffix so both halves
|
|
3574
|
-
* reference literal strings: the browser bundle and the host bundle are built
|
|
3575
|
-
* independently, and a shared expression is one build-config drift away from
|
|
3576
|
-
* the desk asking a route the host never mounted.
|
|
3577
|
-
*/
|
|
3578
|
-
const WORKBUDDY_AI_STATUS_PATH = "/plugins/dsh-workbuddy-bridge/ai/status";
|
|
3579
|
-
const WORKBUDDY_AI_PROBE_PATH = "/plugins/dsh-workbuddy-bridge/ai/probe";
|
|
3580
|
-
//#endregion
|
|
3581
3690
|
//#region src/version.ts
|
|
3582
|
-
const WORKBUDDY_BRIDGE_VERSION = "0.
|
|
3691
|
+
const WORKBUDDY_BRIDGE_VERSION = "0.3.1";
|
|
3583
3692
|
//#endregion
|
|
3584
3693
|
//#region src/web/heartbeat.ts
|
|
3585
3694
|
/**
|
|
@@ -3750,58 +3859,4 @@ function isHeartbeatProcessAlive(heartbeat) {
|
|
|
3750
3859
|
return startAtMs <= heartbeat.registeredAt;
|
|
3751
3860
|
}
|
|
3752
3861
|
//#endregion
|
|
3753
|
-
|
|
3754
|
-
/**
|
|
3755
|
-
* The two WorkBuddy desktop apps this one plugin serves.
|
|
3756
|
-
*
|
|
3757
|
-
* Both products are the same client framework in different regions, and both
|
|
3758
|
-
* write their sign-in into the *same* shared `CodeBuddyExtension` auth
|
|
3759
|
-
* directory — they differ by file basename, base URL, catalog endpoint, and
|
|
3760
|
-
* display identity. Everything that varies between them is collected here as
|
|
3761
|
-
* one descriptor, so no module has to carry its own `if (international)`
|
|
3762
|
-
* branch and a third variant would be a data change rather than a refactor.
|
|
3763
|
-
*
|
|
3764
|
-
* This module is host-side (it names files and env vars). The browser half
|
|
3765
|
-
* takes the same ids and routes from the Node-free `status-paths.ts`, which
|
|
3766
|
-
* stays the single source shared by both halves.
|
|
3767
|
-
*
|
|
3768
|
-
* @module dsh-workbuddy-bridge/variants
|
|
3769
|
-
*/
|
|
3770
|
-
/** CN WorkBuddy first: the existing provider keeps its id, paths, and copy. */
|
|
3771
|
-
const WORKBUDDY_VARIANTS = [{
|
|
3772
|
-
id: "workbuddy",
|
|
3773
|
-
displayName: "WorkBuddy",
|
|
3774
|
-
appName: "WorkBuddy",
|
|
3775
|
-
region: "cn",
|
|
3776
|
-
env: "WORKBUDDY_AUTH_FILE",
|
|
3777
|
-
desktopFilename: "workbuddy-desktop.info",
|
|
3778
|
-
ownFilename: ".workbuddy-auth.json",
|
|
3779
|
-
probeFilename: ".workbuddy-probe.json",
|
|
3780
|
-
catalogFilename: ".workbuddy-catalog.json",
|
|
3781
|
-
visibilityFilename: ".workbuddy-model-visibility.json",
|
|
3782
|
-
statusPath: WORKBUDDY_STATUS_PATH,
|
|
3783
|
-
probePath: WORKBUDDY_PROBE_PATH
|
|
3784
|
-
}, {
|
|
3785
|
-
id: "workbuddy-ai",
|
|
3786
|
-
displayName: "WorkBuddy AI",
|
|
3787
|
-
appName: "WorkBuddy AI",
|
|
3788
|
-
region: "global",
|
|
3789
|
-
env: "WORKBUDDY_AI_AUTH_FILE",
|
|
3790
|
-
desktopFilename: "workbuddy-desktop-ai.info",
|
|
3791
|
-
ownFilename: ".workbuddy-ai-auth.json",
|
|
3792
|
-
probeFilename: ".workbuddy-ai-probe.json",
|
|
3793
|
-
catalogFilename: ".workbuddy-ai-catalog.json",
|
|
3794
|
-
visibilityFilename: ".workbuddy-ai-model-visibility.json",
|
|
3795
|
-
statusPath: WORKBUDDY_AI_STATUS_PATH,
|
|
3796
|
-
probePath: WORKBUDDY_AI_PROBE_PATH
|
|
3797
|
-
}];
|
|
3798
|
-
/** The CN variant; the plugin's long-standing default and compatibility anchor. */
|
|
3799
|
-
const CN_VARIANT = WORKBUDDY_VARIANTS[0];
|
|
3800
|
-
/** The international variant. */
|
|
3801
|
-
const AI_VARIANT = WORKBUDDY_VARIANTS[1];
|
|
3802
|
-
/** Look up a variant by provider id. */
|
|
3803
|
-
function variantFor(id) {
|
|
3804
|
-
return WORKBUDDY_VARIANTS.find((variant) => variant.id === id);
|
|
3805
|
-
}
|
|
3806
|
-
//#endregion
|
|
3807
|
-
export { normalizeCredits as A, FALLBACK_CN_APP_VERSION as B, desktopAuthCandidatesFor as C, cnAppDiscovery as D, WorkBuddyAtRestKeyProvider as E, PROBE_EFFORT_CANDIDATES as F, validCliVersion as G, fallbackChatIdentity as H, probeModel as I, installedAppVersion as J, WORKBUDDY_APP_VERSION_FILENAME as K, randomSentinel as L, prepareChatBody as M, prepareInternationalChatBody as N, WorkBuddyUpstreamClient as O, regionOf as P, classifyUpstreamError as R, defaultDesktopAuthPath as S, workbuddyOwnAuthPath as T, readCliVersion as U, chatUserAgent as V, resolveChatIdentity as W, resolveAppVersion as X, readBundleVersion as Y, validAppVersion as Z, WorkBuddyCatalog as _, WORKBUDDY_HOST_HEARTBEAT_FILENAME as a, WorkBuddyCredentialStore as b, processStartTimeMs as c, writeHostHeartbeat as d, WORKBUDDY_BRIDGE_VERSION as f, FALLBACK_WORKBUDDY_MODELS as g, FALLBACK_WORKBUDDY_AI_MODELS as h, variantFor as i, parseModelCatalog as j, modelWithCurrentPromotion as k, readHostHeartbeat as l, WORKBUDDY_STATUS_PATH as m, CN_VARIANT as n, clearHostHeartbeat as o, WORKBUDDY_PROBE_PATH as p, appUserAgent as q, WORKBUDDY_VARIANTS as r, isHeartbeatProcessAlive as s, AI_VARIANT as t, workbuddyHostHeartbeatPath as u, WORKBUDDY_AUTH_FILENAME as v, parseWorkBuddyAuth as w, defaultDesktopAuthCandidates as x, WORKBUDDY_AUTH_FILE_ENV as y, CN_APP_VERSION_FILENAME as z };
|
|
3862
|
+
export { parseModelCatalog as A, chatUserAgent as B, variantFor as C, WorkBuddyUpstreamClient as D, WORKBUDDY_STATUS_PATH as E, probeModel as F, WORKBUDDY_APP_VERSION_FILENAME as G, readCliVersion as H, randomSentinel as I, readBundleVersion as J, appUserAgent as K, classifyUpstreamError as L, prepareInternationalChatBody as M, regionOf as N, modelWithCurrentPromotion as O, PROBE_EFFORT_CANDIDATES as P, CN_APP_VERSION_FILENAME as R, WORKBUDDY_VARIANTS as S, WORKBUDDY_PROBE_PATH as T, resolveChatIdentity as U, fallbackChatIdentity as V, validCliVersion as W, validAppVersion as X, resolveAppVersion as Y, desktopAuthCandidatesFor as _, readHostHeartbeat as a, AI_VARIANT as b, WORKBUDDY_BRIDGE_VERSION as c, WorkBuddyCatalog as d, WORKBUDDY_AUTH_FILENAME as f, defaultDesktopAuthPath as g, defaultDesktopAuthCandidates as h, processStartTimeMs as i, prepareChatBody as j, normalizeCredits as k, FALLBACK_WORKBUDDY_AI_MODELS as l, WorkBuddyCredentialStore as m, clearHostHeartbeat as n, workbuddyHostHeartbeatPath as o, WORKBUDDY_AUTH_FILE_ENV as p, installedAppVersion as q, isHeartbeatProcessAlive as r, writeHostHeartbeat as s, WORKBUDDY_HOST_HEARTBEAT_FILENAME as t, FALLBACK_WORKBUDDY_MODELS as u, parseWorkBuddyAuth as v, WORKBUDDY_CREDIT_PATH as w, CN_VARIANT as x, workbuddyOwnAuthPath as y, FALLBACK_CN_APP_VERSION as z };
|
package/lib/index.d.ts
CHANGED
|
@@ -1,9 +1,51 @@
|
|
|
1
1
|
import z from "@deepseek-ai/schemastery";
|
|
2
2
|
import "@earendil-works/pi-ai";
|
|
3
3
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
4
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
4
5
|
import { Context, Volatile } from "@deepseek-ai/cordis";
|
|
5
6
|
import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
6
7
|
//#region src/shared/paths.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* Plugin-owned per-message credit route.
|
|
10
|
+
*
|
|
11
|
+
* A read-only GET taking `?sessionId=…`, answering `messageId → credit` for one
|
|
12
|
+
* Session. It is its own route rather than a field of the status document
|
|
13
|
+
* because the two have different lifetimes: the status document is per
|
|
14
|
+
* *account* and is re-read when the account changes, while credit accounting
|
|
15
|
+
* is per *Session* and grows as messages are sent.
|
|
16
|
+
*
|
|
17
|
+
* **One route for both variants, on purpose.** The accounting is attributed to
|
|
18
|
+
* a DSH `messageId` before it is stored, and a message id belongs to one
|
|
19
|
+
* Session regardless of which provider served it — a conversation can switch
|
|
20
|
+
* between the two WorkBuddy products (or away from both) mid-thread. A route
|
|
21
|
+
* per variant would force the message row to know which provider answered a
|
|
22
|
+
* message *it is merely labelling*, and would strand every message whose turn
|
|
23
|
+
* ran under the other variant.
|
|
24
|
+
*
|
|
25
|
+
* No key is required: the route only reads what this plugin already observed on
|
|
26
|
+
* its own loopback stream, carries no credential material, and answers loopback
|
|
27
|
+
* requests through the same Host/Origin guard as the status route.
|
|
28
|
+
*/
|
|
29
|
+
declare const WORKBUDDY_CREDIT_PATH = "/plugins/dsh-workbuddy-bridge/credit";
|
|
30
|
+
/**
|
|
31
|
+
* The credit route's answer: one Session's per-message costs.
|
|
32
|
+
*
|
|
33
|
+
* `credits` is keyed by DSH `messageId` and is always present (an empty object
|
|
34
|
+
* when nothing is recorded), so the browser half reads one shape instead of
|
|
35
|
+
* distinguishing "no data yet" from "no costs".
|
|
36
|
+
*
|
|
37
|
+
* A message *absent* from `credits` means this plugin observed no cost for it —
|
|
38
|
+
* a message predating the feature, a stream that failed before its final frame,
|
|
39
|
+
* or an upstream answer that carried no `credit` field. It never means zero, so
|
|
40
|
+
* the row renders nothing rather than a confident `0`.
|
|
41
|
+
*
|
|
42
|
+
* Distinct from {@link WorkBuddyWebCredits}, which is the account's *remaining*
|
|
43
|
+
* balance for the card. This one is what individual messages *spent*.
|
|
44
|
+
*/
|
|
45
|
+
interface WorkBuddyWebSessionCredits {
|
|
46
|
+
sessionId: string;
|
|
47
|
+
credits: Readonly<Record<string, number>>;
|
|
48
|
+
}
|
|
7
49
|
/**
|
|
8
50
|
* Why no credential is usable, as a closed enum the browser half switches on.
|
|
9
51
|
*
|
|
@@ -864,6 +906,14 @@ interface WorkBuddyAuthStatus {
|
|
|
864
906
|
expiresAtMs?: number;
|
|
865
907
|
refreshExpiresAtMs?: number;
|
|
866
908
|
nickname?: string;
|
|
909
|
+
/**
|
|
910
|
+
* The account's own id (`account.uid`), when the credential carries one.
|
|
911
|
+
*
|
|
912
|
+
* The fallback display name: the desktop document is the only source of a
|
|
913
|
+
* nickname, and it does not always have one. Non-secret — the same identity
|
|
914
|
+
* the per-account state is keyed by, sent upstream as `X-User-Id`.
|
|
915
|
+
*/
|
|
916
|
+
uid?: string;
|
|
867
917
|
domain?: string;
|
|
868
918
|
source?: 'desktop' | 'dsh';
|
|
869
919
|
/**
|
|
@@ -891,9 +941,10 @@ interface WorkBuddyStoreOptions {
|
|
|
891
941
|
refreshMarginMs?: number;
|
|
892
942
|
/**
|
|
893
943
|
* Resolver for WorkBuddy 5.6's at-rest protector key, needed when the
|
|
894
|
-
* desktop file stores encrypted token fields. Defaults to the real
|
|
895
|
-
*
|
|
896
|
-
*
|
|
944
|
+
* desktop file stores encrypted token fields. Defaults to the real provider
|
|
945
|
+
* with the discovery this store's variant may run — see
|
|
946
|
+
* {@link atRestDiscoveryFor}. Tests stand in a stub; the shape is structural
|
|
947
|
+
* so a store never depends on how the key is reached.
|
|
897
948
|
*/
|
|
898
949
|
keyProvider?: Pick<WorkBuddyAtRestKeyProvider, 'protectorKeyFor' | 'helperPath'>;
|
|
899
950
|
}
|
|
@@ -1234,6 +1285,15 @@ interface WorkBuddyShimOptions {
|
|
|
1234
1285
|
client: Pick<WorkBuddyUpstreamClient, 'chatStream'>;
|
|
1235
1286
|
catalog: WorkBuddyCatalog;
|
|
1236
1287
|
logger?: ShimLogger;
|
|
1288
|
+
/**
|
|
1289
|
+
* Observe what one upstream response cost, as the upstream reports it.
|
|
1290
|
+
*
|
|
1291
|
+
* Called at most once per response, at the frame carrying the number, with
|
|
1292
|
+
* the stream's own response id (`cmb-…`) — the same id DSH records on the
|
|
1293
|
+
* assistant message, which is what lets the Host half attribute a cost to a
|
|
1294
|
+
* message instead of guessing.
|
|
1295
|
+
*/
|
|
1296
|
+
observeCredit?: (responseId: string, credit: number) => void;
|
|
1237
1297
|
}
|
|
1238
1298
|
/**
|
|
1239
1299
|
* Start the loopback endpoint. Requests carry any bearer; the loopback bind
|
|
@@ -1292,6 +1352,129 @@ interface WorkBuddyAdapter {
|
|
|
1292
1352
|
*/
|
|
1293
1353
|
declare function createWorkBuddyAdapter(options: WorkBuddyAdapterOptions): WorkBuddyAdapter;
|
|
1294
1354
|
//#endregion
|
|
1355
|
+
//#region src/llm/credit-log.d.ts
|
|
1356
|
+
/**
|
|
1357
|
+
* Per-message credit accounting, as two plain registries the Host half fills.
|
|
1358
|
+
*
|
|
1359
|
+
* WorkBuddy reports what a message actually cost as a `credit` field on the
|
|
1360
|
+
* last usage frame of its OpenAI-compatible SSE stream. That number is
|
|
1361
|
+
* **server-supplied**: the desktop app accumulates `cost.amount` stage
|
|
1362
|
+
* increments and never multiplies tokens by the catalog's `x0.79` multiplier
|
|
1363
|
+
* (the multiplier is display copy). So the plugin must not invent a formula —
|
|
1364
|
+
* it observes the number where it exists.
|
|
1365
|
+
*
|
|
1366
|
+
* The field travels on the stream the shim already proxies, and the same
|
|
1367
|
+
* stream carries the upstream response id (`cmb-…`) that DSH records on the
|
|
1368
|
+
* assistant message as `source.replayState.response.responseId`. That pair is
|
|
1369
|
+
* what makes attribution exact rather than guessed:
|
|
1370
|
+
*
|
|
1371
|
+
* ```text
|
|
1372
|
+
* SSE id + SSE usage.credit ──► creditLog.record(id, credit)
|
|
1373
|
+
* │
|
|
1374
|
+
* session/event assistant/message ─────┴──► index.set(sessionId, messageId, credit)
|
|
1375
|
+
* (messageId, responseId) │
|
|
1376
|
+
* browser row fetches by messageId
|
|
1377
|
+
* ```
|
|
1378
|
+
*
|
|
1379
|
+
* Both structures are pure data with no Host dependencies, so the matching
|
|
1380
|
+
* rules are unit-testable without a Session, a socket, or an upstream.
|
|
1381
|
+
*
|
|
1382
|
+
* @module dsh-workbuddy-bridge/credit-log
|
|
1383
|
+
*/
|
|
1384
|
+
/**
|
|
1385
|
+
* Bounded `responseId → credit` registry, with one-shot waiters.
|
|
1386
|
+
*
|
|
1387
|
+
* The waiter exists because the two writes race in principle: the shim sees the
|
|
1388
|
+
* credit when the last SSE frame arrives, while the Session event that names
|
|
1389
|
+
* the response id is appended when the stream settles. Either order must
|
|
1390
|
+
* produce the same attribution, so a lookup that misses registers interest and
|
|
1391
|
+
* is answered by the next `record` instead of silently reporting "unknown".
|
|
1392
|
+
*/
|
|
1393
|
+
declare class WorkBuddyCreditLog {
|
|
1394
|
+
private readonly limit;
|
|
1395
|
+
/**
|
|
1396
|
+
* Insertion-ordered, so eviction is FIFO. A `Map` is used rather than an
|
|
1397
|
+
* object because the response id is attacker-influenced text: a plain object
|
|
1398
|
+
* would let `__proto__` reach the prototype chain.
|
|
1399
|
+
*/
|
|
1400
|
+
private readonly credits;
|
|
1401
|
+
/** Pending attributions, keyed by response id; each resolves at most once. */
|
|
1402
|
+
private readonly waiters;
|
|
1403
|
+
constructor(limit?: number);
|
|
1404
|
+
/**
|
|
1405
|
+
* Remember what one response cost.
|
|
1406
|
+
*
|
|
1407
|
+
* A non-finite or negative value is refused rather than stored: the field is
|
|
1408
|
+
* remote input, and a `NaN` reaching the browser would render as `NaN` in the
|
|
1409
|
+
* credit label instead of being reported as unknown.
|
|
1410
|
+
*/
|
|
1411
|
+
record(responseId: string, credit: number): void;
|
|
1412
|
+
/** What one response cost, or undefined when it was never observed. */
|
|
1413
|
+
lookup(responseId: string): number | undefined;
|
|
1414
|
+
/**
|
|
1415
|
+
* Call `onCredit` once, when this response's credit becomes known.
|
|
1416
|
+
*
|
|
1417
|
+
* @returns a canceller; calling it after the credit landed is a no-op.
|
|
1418
|
+
*/
|
|
1419
|
+
await(responseId: string, onCredit: (credit: number) => void): () => void;
|
|
1420
|
+
/** Drop the oldest entries until the log is inside its bound. */
|
|
1421
|
+
private evict;
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* `sessionId → messageId → credit`, the shape the browser row reads.
|
|
1425
|
+
*
|
|
1426
|
+
* Nested rather than a flat `messageId → credit` map so the route can answer
|
|
1427
|
+
* one Session without shipping every Session's accounting, and so a Session's
|
|
1428
|
+
* rows can be dropped as a unit.
|
|
1429
|
+
*/
|
|
1430
|
+
declare class WorkBuddySessionCreditIndex {
|
|
1431
|
+
private readonly perSessionLimit;
|
|
1432
|
+
/** Per-Session maps, each bounded independently. */
|
|
1433
|
+
private readonly sessions;
|
|
1434
|
+
constructor(perSessionLimit?: number);
|
|
1435
|
+
/** Attribute one message's cost, refreshing its position in its Session. */
|
|
1436
|
+
set(sessionId: string, messageId: string, credit: number): void;
|
|
1437
|
+
/**
|
|
1438
|
+
* One Session's accounting as a plain object, or an empty object when the
|
|
1439
|
+
* Session has none. Always an object, never undefined: the browser half then
|
|
1440
|
+
* needs no "no data yet" branch distinct from "no credits recorded".
|
|
1441
|
+
*/
|
|
1442
|
+
forSession(sessionId: string): Record<string, number>;
|
|
1443
|
+
/** Forget one Session's accounting, e.g. when it leaves the store. */
|
|
1444
|
+
delete(sessionId: string): void;
|
|
1445
|
+
}
|
|
1446
|
+
//#endregion
|
|
1447
|
+
//#region src/web/credit.d.ts
|
|
1448
|
+
/** Constructor dependencies. */
|
|
1449
|
+
interface WorkBuddyCreditRouteOptions {
|
|
1450
|
+
/** The accounting to read from; see {@link WorkBuddySessionCreditIndex}. */
|
|
1451
|
+
credits: WorkBuddySessionCreditIndex;
|
|
1452
|
+
/**
|
|
1453
|
+
* Route path to mount, defaulting to the CN variant's. The international
|
|
1454
|
+
* variant passes its own so the two halves never share a route: the browser
|
|
1455
|
+
* bundle and the host bundle are built independently, and a computed path is
|
|
1456
|
+
* one build-config drift away from asking a route that was never mounted.
|
|
1457
|
+
*/
|
|
1458
|
+
path?: string;
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* One Session's accounting.
|
|
1462
|
+
*
|
|
1463
|
+
* A missing `sessionId` is answered with an empty document rather than an
|
|
1464
|
+
* error: the browser half asks on behalf of whatever Session it is rendering,
|
|
1465
|
+
* and "this Session has no recorded costs" is a normal, silent state — the row
|
|
1466
|
+
* simply shows no label.
|
|
1467
|
+
*
|
|
1468
|
+
* @param deps - the accounting index.
|
|
1469
|
+
* @param sessionId - the Session to answer for.
|
|
1470
|
+
* @returns the document the browser half renders from.
|
|
1471
|
+
*/
|
|
1472
|
+
declare function workBuddySessionCredits(deps: WorkBuddyCreditRouteOptions, sessionId: string): WorkBuddyWebSessionCredits;
|
|
1473
|
+
/** The credit route's request handler, extracted so tests can mount it bare. */
|
|
1474
|
+
declare function workBuddyCreditHandler(deps: WorkBuddyCreditRouteOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
1475
|
+
/** Mount the GET credit route on an optional webServer context. */
|
|
1476
|
+
declare function registerWorkBuddyCreditRoute(ctx: Context, deps: WorkBuddyCreditRouteOptions): void;
|
|
1477
|
+
//#endregion
|
|
1295
1478
|
//#region src/catalog/store.d.ts
|
|
1296
1479
|
/** Basename of the CN variant's saved catalog inside the Harness home. */
|
|
1297
1480
|
declare const WORKBUDDY_CATALOG_FILENAME = ".workbuddy-catalog.json";
|
|
@@ -1639,4 +1822,4 @@ declare function visibilityAccountOf(credential: Pick<WorkBuddyCredential, 'uid'
|
|
|
1639
1822
|
*/
|
|
1640
1823
|
declare function apply(ctx: Context, refs: ConfigRefs): void;
|
|
1641
1824
|
//#endregion
|
|
1642
|
-
export { AI_VARIANT, type AppVersionInfo, CN_APP_VERSION_FILENAME, CN_VARIANT, type ChatIdentity, Config, ConfigRefs, FALLBACK_CN_APP_VERSION, FALLBACK_WORKBUDDY_AI_MODELS, FALLBACK_WORKBUDDY_MODELS, PROBE_EFFORT_CANDIDATES, type ProbeAttempt, type ProbeOutcome, type ProbeSender, type ResolveChatIdentityOptions, type UpstreamErrorKind, WORKBUDDY_APP_VERSION_FILENAME, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CATALOG_FILENAME, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_PROBE_FILENAME, WORKBUDDY_PROVIDER, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_VARIANTS, WORKBUDDY_VISIBILITY_FILENAME, type WorkBuddyAdapter, type WorkBuddyAppVersionSource, type WorkBuddyAuthStatus, WorkBuddyCatalog, type WorkBuddyCatalogFetch, WorkBuddyCatalogStore, type WorkBuddyChatResult, type WorkBuddyCredential, WorkBuddyCredentialStore, type WorkBuddyCredits, type WorkBuddyEffort, type WorkBuddyHostHeartbeat, type WorkBuddyModelBilling, type WorkBuddyModelInfo, type WorkBuddyModelReasoning, type WorkBuddyProbeRecord, WorkBuddyProbeService, type WorkBuddyProbeStatus, WorkBuddyProbeStore, type WorkBuddyProbeValidation, type WorkBuddyPromotion, type WorkBuddyRefreshOutcome, type WorkBuddyShim, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyVariant, WorkBuddyVisibilityStore, appUserAgent, apply, chatUserAgent, classifyUpstreamError, clearHostHeartbeat, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthPath, desktopAuthCandidatesFor, fallbackChatIdentity, fingerprintModel, inject, installedAppVersion, isHeartbeatProcessAlive, modelWithCurrentPromotion, name, normalizeCredits, parseModelCatalog, parseWorkBuddyAuth, prepareChatBody, prepareInternationalChatBody, probeModel, processStartTimeMs, randomSentinel, readBundleVersion, readCliVersion, readHostHeartbeat, regionOf, resolveAppVersion, resolveChatIdentity, validAppVersion, validCliVersion, variantFor, visibilityAccountOf, workbuddyCatalogPath, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, workbuddyProbePath, workbuddyVisibilityPath };
|
|
1825
|
+
export { AI_VARIANT, type AppVersionInfo, CN_APP_VERSION_FILENAME, CN_VARIANT, type ChatIdentity, Config, ConfigRefs, FALLBACK_CN_APP_VERSION, FALLBACK_WORKBUDDY_AI_MODELS, FALLBACK_WORKBUDDY_MODELS, PROBE_EFFORT_CANDIDATES, type ProbeAttempt, type ProbeOutcome, type ProbeSender, type ResolveChatIdentityOptions, type UpstreamErrorKind, WORKBUDDY_APP_VERSION_FILENAME, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CATALOG_FILENAME, WORKBUDDY_CREDIT_PATH, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_PROBE_FILENAME, WORKBUDDY_PROVIDER, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_VARIANTS, WORKBUDDY_VISIBILITY_FILENAME, type WorkBuddyAdapter, type WorkBuddyAppVersionSource, type WorkBuddyAuthStatus, WorkBuddyCatalog, type WorkBuddyCatalogFetch, WorkBuddyCatalogStore, type WorkBuddyChatResult, type WorkBuddyCredential, WorkBuddyCredentialStore, WorkBuddyCreditLog, type WorkBuddyCreditRouteOptions, type WorkBuddyCredits, type WorkBuddyEffort, type WorkBuddyHostHeartbeat, type WorkBuddyModelBilling, type WorkBuddyModelInfo, type WorkBuddyModelReasoning, type WorkBuddyProbeRecord, WorkBuddyProbeService, type WorkBuddyProbeStatus, WorkBuddyProbeStore, type WorkBuddyProbeValidation, type WorkBuddyPromotion, type WorkBuddyRefreshOutcome, WorkBuddySessionCreditIndex, type WorkBuddyShim, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyVariant, WorkBuddyVisibilityStore, type WorkBuddyWebSessionCredits, appUserAgent, apply, chatUserAgent, classifyUpstreamError, clearHostHeartbeat, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthPath, desktopAuthCandidatesFor, fallbackChatIdentity, fingerprintModel, inject, installedAppVersion, isHeartbeatProcessAlive, modelWithCurrentPromotion, name, normalizeCredits, parseModelCatalog, parseWorkBuddyAuth, prepareChatBody, prepareInternationalChatBody, probeModel, processStartTimeMs, randomSentinel, readBundleVersion, readCliVersion, readHostHeartbeat, regionOf, registerWorkBuddyCreditRoute, resolveAppVersion, resolveChatIdentity, validAppVersion, validCliVersion, variantFor, visibilityAccountOf, workBuddyCreditHandler, workBuddySessionCredits, workbuddyCatalogPath, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, workbuddyProbePath, workbuddyVisibilityPath };
|