dsh-connect-workbuddy 2.0.5 → 2.0.10
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 +172 -1
- package/README.en.md +7 -2
- package/README.md +7 -2
- package/lib/bin.js +15 -2
- package/lib/client.js +416 -66
- package/lib/{host-heartbeat-BOrNj3pY.js → host-heartbeat-DPbL9oi2.js} +578 -28
- package/lib/index.d.ts +481 -7
- package/lib/index.js +298 -29
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -31,6 +31,31 @@ interface WorkBuddyCredential {
|
|
|
31
31
|
*/
|
|
32
32
|
lastRefreshAtMs?: number;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Why one probed path did not yield an account.
|
|
36
|
+
*
|
|
37
|
+
* These are safe to surface: they carry paths and cause only, never token
|
|
38
|
+
* material. `encrypted` is the WorkBuddy-specific one — a build whose token
|
|
39
|
+
* fields are encrypted cannot be read at all unless the desktop app itself is
|
|
40
|
+
* present to hand over its at-rest key, so "sign in again" is the wrong advice
|
|
41
|
+
* for it (the user may be perfectly signed in).
|
|
42
|
+
*
|
|
43
|
+
* `wrong-region` is the second WorkBuddy-specific one, and it exists because of
|
|
44
|
+
* a real bug: a region-scoped store filters out every credential that belongs to
|
|
45
|
+
* the other region, so a candidate file holding a perfectly valid sign-in for
|
|
46
|
+
* the other tab was dropped by exactly the same `continue` that drops malformed
|
|
47
|
+
* files. The file then appeared in NO list at all — not an account (filtered by
|
|
48
|
+
* region) and not a failure (it parsed) — so a card could name two paths while
|
|
49
|
+
* its report listed one, and the user's actual, working sign-in was the one
|
|
50
|
+
* made invisible. Reporting it is also the most useful answer we can give: the
|
|
51
|
+
* user is signed in, and merely on the wrong tab.
|
|
52
|
+
*/
|
|
53
|
+
interface WorkBuddyCandidateFailure {
|
|
54
|
+
path: string;
|
|
55
|
+
source: 'desktop' | 'dsh';
|
|
56
|
+
reason: 'missing' | 'unreadable' | 'invalid' | 'encrypted' | 'wrong-region';
|
|
57
|
+
message?: string;
|
|
58
|
+
}
|
|
34
59
|
/** Read-only sign-in summary for status and doctor output. */
|
|
35
60
|
interface WorkBuddyAuthStatus {
|
|
36
61
|
state: 'signed-in' | 'signed-out';
|
|
@@ -69,13 +94,25 @@ interface WorkBuddyStoreOptions {
|
|
|
69
94
|
refresh: (credential: WorkBuddyCredential) => Promise<WorkBuddyRefreshOutcome>;
|
|
70
95
|
/** Refresh this long before actual expiry; default five minutes. */
|
|
71
96
|
refreshMarginMs?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Resolves the desktop app's at-rest field key, used to open documents whose
|
|
99
|
+
* token fields are encrypted (Windows builds). Defaults to asking the
|
|
100
|
+
* installed app; injectable so the encrypted path is testable.
|
|
101
|
+
*/
|
|
102
|
+
resolveAtRestKey?: () => Promise<Buffer | undefined>;
|
|
72
103
|
}
|
|
73
104
|
/** One selectable local account, token-free. */
|
|
74
105
|
interface WorkBuddyAccountChoice {
|
|
75
106
|
/** Stable id derived from `uin` (or `uid` when uin is absent). */
|
|
76
107
|
id: string;
|
|
108
|
+
/**
|
|
109
|
+
* The account's human name, or `''` when the desktop app recorded none.
|
|
110
|
+
*
|
|
111
|
+
* Never an identifier: `uin`/`uid` are opaque numbers and UUIDs, and using one
|
|
112
|
+
* as a display name reads as "the plugin does not know who this is". Callers
|
|
113
|
+
* that render a name choose their own placeholder for the empty case.
|
|
114
|
+
*/
|
|
77
115
|
accountName: string;
|
|
78
|
-
uin?: string;
|
|
79
116
|
domain: string;
|
|
80
117
|
source: 'desktop' | 'dsh';
|
|
81
118
|
tokenExpiresAtMs: number;
|
|
@@ -119,8 +156,24 @@ declare function defaultDesktopAuthPath(): string | undefined;
|
|
|
119
156
|
* Parse a WorkBuddy auth document in either on-disk shape: the plugin OAuth
|
|
120
157
|
* nested form `{"auth":{...},"account":{...}}` and the flat panel form.
|
|
121
158
|
* Returns undefined when the document carries no access token.
|
|
159
|
+
*
|
|
160
|
+
* `atRestKey` is required to read documents whose fields are encrypted
|
|
161
|
+
* (see {@link credentialField}); pass the key obtained from
|
|
162
|
+
* `readAtRestKey()` when the plain read reports no token.
|
|
122
163
|
*/
|
|
123
|
-
declare function parseWorkBuddyAuth(text: string, filePath: string): WorkBuddyCredential | undefined;
|
|
164
|
+
declare function parseWorkBuddyAuth(text: string, filePath: string, atRestKey?: Buffer): WorkBuddyCredential | undefined;
|
|
165
|
+
/**
|
|
166
|
+
* Whether a document carries any field the reader must decrypt — the token
|
|
167
|
+
* fields or the identity fields — i.e. whether reading it needs the at-rest key
|
|
168
|
+
* at all.
|
|
169
|
+
*
|
|
170
|
+
* Deciding this BEFORE asking the app for its key keeps the plain case (macOS
|
|
171
|
+
* and older Windows builds, and every plugin-owned copy) from paying for a
|
|
172
|
+
* child process on every credential read. Identity fields are included because
|
|
173
|
+
* a future build could encrypt the display name while leaving tokens plain;
|
|
174
|
+
* gating on tokens alone would then silently drop the name again.
|
|
175
|
+
*/
|
|
176
|
+
declare function hasEncryptedCredentialFields(text: string): boolean;
|
|
124
177
|
/**
|
|
125
178
|
* Filename of a path regardless of the host separator: Windows paths use `\`
|
|
126
179
|
* and this helper must keep working when a Windows path is compared on a
|
|
@@ -150,6 +203,7 @@ declare class WorkBuddyCredentialStore {
|
|
|
150
203
|
private readonly legacyOwnPath;
|
|
151
204
|
private readonly legacyOwnPathExplicit;
|
|
152
205
|
private readonly authDirs;
|
|
206
|
+
private readonly resolveAtRestKey;
|
|
153
207
|
private desktopPathOverride;
|
|
154
208
|
private accountId;
|
|
155
209
|
private inflight;
|
|
@@ -262,6 +316,16 @@ declare class WorkBuddyCredentialStore {
|
|
|
262
316
|
selectionLost(): Promise<boolean>;
|
|
263
317
|
/** The freshest stored credential for the current selection, no refresh. */
|
|
264
318
|
current(): Promise<WorkBuddyCredential | undefined>;
|
|
319
|
+
/**
|
|
320
|
+
* One account's stored credential by id, WITHOUT consulting or changing the
|
|
321
|
+
* current selection.
|
|
322
|
+
*
|
|
323
|
+
* Exists so a recovery probe can test whether some OTHER local account is
|
|
324
|
+
* still accepted upstream while a rejected one stays selected: mutating the
|
|
325
|
+
* live selection to find that out would be exactly the silent account switch
|
|
326
|
+
* this store refuses to perform (it would bill the wrong account mid-probe).
|
|
327
|
+
*/
|
|
328
|
+
credentialFor(accountId: string): Promise<WorkBuddyCredential | undefined>;
|
|
265
329
|
/** The credential to send upstream: {@link current}, refreshed on demand. */
|
|
266
330
|
resolve(): Promise<WorkBuddyCredential>;
|
|
267
331
|
/** Read-only sign-in summary; never refreshes and never throws. */
|
|
@@ -284,6 +348,21 @@ declare class WorkBuddyCredentialStore {
|
|
|
284
348
|
private readOwns;
|
|
285
349
|
/** Whether any candidate file exists as a regular file; diagnostics only. */
|
|
286
350
|
desktopFilePresent(): Promise<boolean>;
|
|
351
|
+
/**
|
|
352
|
+
* Which paths were probed and why each one yielded no credential.
|
|
353
|
+
*
|
|
354
|
+
* Read-only and token-free: it exists so a signed-out card can explain
|
|
355
|
+
* itself. A bare "not signed in" is undiagnosable on a machine whose layout
|
|
356
|
+
* differs from the ones this plugin was written against — and on Windows it
|
|
357
|
+
* is actively misleading, because encrypted token fields need the desktop app
|
|
358
|
+
* present to be read at all. Only paths this store actually consults are
|
|
359
|
+
* reported, and only files that failed: one healthy sibling would make the
|
|
360
|
+
* whole list noise.
|
|
361
|
+
*/
|
|
362
|
+
diagnose(): Promise<{
|
|
363
|
+
tried: string[];
|
|
364
|
+
failures: WorkBuddyCandidateFailure[];
|
|
365
|
+
}>;
|
|
287
366
|
}
|
|
288
367
|
//#endregion
|
|
289
368
|
//#region src/upstream.d.ts
|
|
@@ -395,6 +474,28 @@ declare function regionOf(domain: string): WorkBuddyRegion;
|
|
|
395
474
|
* `tool_choice` (the upstream's field is a string; object forms return 400).
|
|
396
475
|
*/
|
|
397
476
|
declare function prepareChatBody(source: string): string;
|
|
477
|
+
/** Marker carried by {@link WorkBuddyCredentialRejectedError}; survives bundling. */
|
|
478
|
+
declare const CREDENTIAL_REJECTED_CODE = "WORKBUDDY_CREDENTIAL_REJECTED";
|
|
479
|
+
/**
|
|
480
|
+
* The upstream refused the CREDENTIAL itself rather than failing the request.
|
|
481
|
+
*
|
|
482
|
+
* This is a distinct, actionable class: the token is not usable and no retry
|
|
483
|
+
* with the same token will help. Callers use it to tell the user what to do
|
|
484
|
+
* about it (switch accounts, or sign in again) instead of showing a raw HTTP
|
|
485
|
+
* error, and the card must never confuse it with a transient upstream fault.
|
|
486
|
+
*
|
|
487
|
+
* Identified by {@link CREDENTIAL_REJECTED_CODE} rather than `instanceof`, so
|
|
488
|
+
* the check keeps working when the caller and the thrower end up in different
|
|
489
|
+
* module instances (bundled host half vs. a test's source import).
|
|
490
|
+
*/
|
|
491
|
+
declare class WorkBuddyCredentialRejectedError extends Error {
|
|
492
|
+
readonly code = "WORKBUDDY_CREDENTIAL_REJECTED";
|
|
493
|
+
/** HTTP status the upstream answered with (401 or 403). */
|
|
494
|
+
readonly status: number;
|
|
495
|
+
constructor(status: number);
|
|
496
|
+
}
|
|
497
|
+
/** Whether an error reports that the upstream refused the credential itself. */
|
|
498
|
+
declare function isCredentialRejectedError(value: unknown): value is WorkBuddyCredentialRejectedError;
|
|
398
499
|
/**
|
|
399
500
|
* Parse the upstream's `credits` string into a multiplier.
|
|
400
501
|
*
|
|
@@ -479,17 +580,79 @@ declare function fallbackModelsFor(region: 'cn' | 'global'): readonly WorkBuddyM
|
|
|
479
580
|
*/
|
|
480
581
|
type WorkBuddyContextBudget = number;
|
|
481
582
|
declare function deriveCatalog(catalog: readonly WorkBuddyModelInfo[], enabled: ReadonlySet<string>, budgets?: Readonly<Record<string, WorkBuddyContextBudget | undefined>>): WorkBuddyModelInfo[];
|
|
482
|
-
/**
|
|
583
|
+
/**
|
|
584
|
+
* Mutable catalog shared by the shim's `/v1/models` and the adapter.
|
|
585
|
+
*
|
|
586
|
+
* The static fallback exists so an OFFLINE upstream never leaves a provider
|
|
587
|
+
* empty — but "offline" presumes the region is usable at all. A region with no
|
|
588
|
+
* local sign-in cannot serve one single request, so seeding it with a roster
|
|
589
|
+
* puts models in the picker that are guaranteed to 401 (issue #12). The host
|
|
590
|
+
* distinguishes the two cases through {@link WorkBuddyCatalog.setRegionUsable}.
|
|
591
|
+
*/
|
|
483
592
|
declare class WorkBuddyCatalog {
|
|
484
593
|
private models;
|
|
594
|
+
/**
|
|
595
|
+
* Whether this region has any local sign-in. Defaults to `true` — the
|
|
596
|
+
* permissive direction — so a scan that has not run yet (or failed) keeps
|
|
597
|
+
* serving the fallback rather than blanking a region that may be fine.
|
|
598
|
+
*/
|
|
599
|
+
private usable;
|
|
600
|
+
/**
|
|
601
|
+
* Whether the user has switched this region's provider ON. Opt-out: defaults
|
|
602
|
+
* to `true`, so a config predating this switch (and the pre-region-split flat
|
|
603
|
+
* fields, which never carry `enabled`) keeps both providers running. Set to
|
|
604
|
+
* `false` by `setRegionEnabled` to withdraw the region from DSH's model
|
|
605
|
+
* picker entirely (its adapter route and configurable-provider entry are
|
|
606
|
+
* pulled by the Host via `AdapterRegistrationHandle.replace([])` /
|
|
607
|
+
* `DirectoryRegistrationHandle.replace([])`). This is a USER choice, distinct
|
|
608
|
+
* from {@link usable}: a region the user switched off keeps its catalog,
|
|
609
|
+
* accounts, and model picks intact and reappears the moment they re-check it.
|
|
610
|
+
*/
|
|
611
|
+
private enabled;
|
|
485
612
|
/**
|
|
486
613
|
* @param region Seeds the static fallback for this region; each region's
|
|
487
614
|
* provider must never serve the other region's roster before its first
|
|
488
615
|
* live refresh lands.
|
|
489
616
|
*/
|
|
490
617
|
constructor(region?: 'cn' | 'global');
|
|
491
|
-
/**
|
|
618
|
+
/**
|
|
619
|
+
* Current entries; the fallback list until the upstream answer lands.
|
|
620
|
+
*
|
|
621
|
+
* Empty while this region has no local sign-in OR the user has switched it
|
|
622
|
+
* off: the provider stays registered (its row still hosts the settings card
|
|
623
|
+
* and the account picker), but it advertises nothing to pick. DSH drops empty
|
|
624
|
+
* provider groups from the picker (`buildModelCatalog` filters
|
|
625
|
+
* `models.length > 0`), so the group disappears exactly when it would be pure
|
|
626
|
+
* noise. The two empty causes are independent: `usable` is the automatic
|
|
627
|
+
* "no account" gate (issue #12), `enabled` is the user's explicit on/off.
|
|
628
|
+
*/
|
|
492
629
|
current(): readonly WorkBuddyModelInfo[];
|
|
630
|
+
/** Whether this region currently advertises any model. */
|
|
631
|
+
isRegionUsable(): boolean;
|
|
632
|
+
/** Whether the user has this region's provider switched on. */
|
|
633
|
+
isRegionEnabled(): boolean;
|
|
634
|
+
/**
|
|
635
|
+
* Record whether this region has a local sign-in.
|
|
636
|
+
*
|
|
637
|
+
* Separate from {@link set} on purpose: `set()` carries a live upstream
|
|
638
|
+
* answer and must never be empty, while "this region has no account" is a
|
|
639
|
+
* legitimate empty state that must survive across refreshes. Keeping them
|
|
640
|
+
* apart is what lets the non-empty guard stay strict.
|
|
641
|
+
*
|
|
642
|
+
* @returns whether the value changed, so the caller can skip invalidating
|
|
643
|
+
* its adapter snapshots when nothing moved.
|
|
644
|
+
*/
|
|
645
|
+
setRegionUsable(usable: boolean): boolean;
|
|
646
|
+
/**
|
|
647
|
+
* Record the user's explicit on/off choice for this region's provider.
|
|
648
|
+
*
|
|
649
|
+
* Distinct from {@link setRegionUsable}: that is the automatic "no local
|
|
650
|
+
* account" gate, while this is a deliberate user action (issue #11-style
|
|
651
|
+
* region switch). The Host reads the same `enabled` flag through
|
|
652
|
+
* `regionStateOf(config, region).enabled !== false`, so the two halves never
|
|
653
|
+
* disagree. Returns whether the value changed.
|
|
654
|
+
*/
|
|
655
|
+
setRegionEnabled(enabled: boolean): boolean;
|
|
493
656
|
/** Replace the list; callers invalidate their adapter snapshot after this. */
|
|
494
657
|
set(models: readonly WorkBuddyModelInfo[]): void;
|
|
495
658
|
}
|
|
@@ -586,6 +749,170 @@ declare function workBuddyThinkingLevelMap(info: WorkBuddyModelInfo): WorkBuddyT
|
|
|
586
749
|
*/
|
|
587
750
|
declare function createWorkBuddyAdapter(options: WorkBuddyAdapterOptions): WorkBuddyAdapter;
|
|
588
751
|
//#endregion
|
|
752
|
+
//#region src/at-rest.d.ts
|
|
753
|
+
/**
|
|
754
|
+
* WorkBuddy desktop "at-rest" credential decryption.
|
|
755
|
+
*
|
|
756
|
+
* The WorkBuddy desktop app (2.x, Windows builds first) no longer stores
|
|
757
|
+
* `auth.accessToken` / `auth.refreshToken` as plain strings. It now writes a
|
|
758
|
+
* field wrapper:
|
|
759
|
+
*
|
|
760
|
+
* { "$wbEncrypted": 1, "envelope": "<base64 of a JSON envelope>" }
|
|
761
|
+
*
|
|
762
|
+
* where the envelope is `{suite, keyId, nonce, authTag, ciphertext}` for
|
|
763
|
+
* AES-256-GCM with a 12-byte nonce and a 16-byte tag. The authenticated
|
|
764
|
+
* additional data is a length-prefixed transcript over the scheme, suite,
|
|
765
|
+
* keyId and framing, so the ciphertext can only be opened for the exact field
|
|
766
|
+
* shape it was sealed for.
|
|
767
|
+
*
|
|
768
|
+
* The field key itself is NOT a user secret: it is a build-time constant
|
|
769
|
+
* compiled into the app's own Electron native module
|
|
770
|
+
* (`electron_browser_workbuddy_storage`). The app fetches it through
|
|
771
|
+
* `loggerGet()` and hashes the returned base64 STRING (not the decoded bytes)
|
|
772
|
+
* to obtain the 32-byte key; `keyId` is the first 16 hex characters of that
|
|
773
|
+
* key's SHA-256.
|
|
774
|
+
*
|
|
775
|
+
* This module re-derives the same key by asking the installed app for the same
|
|
776
|
+
* payload, and caches it in memory for the process lifetime. Nothing is ever
|
|
777
|
+
* written to disk, and the payload is never logged.
|
|
778
|
+
*
|
|
779
|
+
* @module dsh-connect-workbuddy/at-rest
|
|
780
|
+
*/
|
|
781
|
+
/** A `{$wbEncrypted:1,envelope}` field wrapper, the only shape this module opens. */
|
|
782
|
+
interface WorkBuddyEncryptedField {
|
|
783
|
+
$wbEncrypted: 1;
|
|
784
|
+
envelope: string;
|
|
785
|
+
}
|
|
786
|
+
/** Env override pointing at the WorkBuddy desktop executable. */
|
|
787
|
+
declare const WORKBUDDY_APP_EXECUTABLE_ENV = "WORKBUDDY_APP_EXECUTABLE";
|
|
788
|
+
/** Whether a value is the app's encrypted-field wrapper. */
|
|
789
|
+
declare function isEncryptedFieldWrapper(value: unknown): value is WorkBuddyEncryptedField;
|
|
790
|
+
/**
|
|
791
|
+
* The at-rest key id for a derived 32-byte key: the first 16 hex characters of
|
|
792
|
+
* its SHA-256. This is what the envelope's `keyId` is checked against, so a
|
|
793
|
+
* mismatched key fails loudly instead of returning garbage.
|
|
794
|
+
*/
|
|
795
|
+
declare function deriveAtRestKeyId(key: Buffer): string;
|
|
796
|
+
/**
|
|
797
|
+
* Derive the 32-byte field key from the app's key payload JSON.
|
|
798
|
+
*
|
|
799
|
+
* The app hashes the payload's base64 STRING — not its decoded bytes — so the
|
|
800
|
+
* same spelling is required here; hashing the decoded secret would produce a
|
|
801
|
+
* different key and every field would fail to open.
|
|
802
|
+
*/
|
|
803
|
+
declare function deriveAtRestKey(payloadJson: string): Buffer;
|
|
804
|
+
/**
|
|
805
|
+
* Open one encrypted field with a derived key and return its plaintext.
|
|
806
|
+
*
|
|
807
|
+
* Throws when the envelope is malformed, belongs to another key, or fails
|
|
808
|
+
* authentication — a GCM tag mismatch is the signal that the transcript or the
|
|
809
|
+
* key is wrong, and it must never degrade into a truncated token.
|
|
810
|
+
*/
|
|
811
|
+
declare function openEncryptedField(field: WorkBuddyEncryptedField, key: Buffer): string;
|
|
812
|
+
/**
|
|
813
|
+
* Candidate paths of the WorkBuddy desktop executable, in probe order.
|
|
814
|
+
*
|
|
815
|
+
* The Windows build is the one that encrypts credentials, so Windows leads;
|
|
816
|
+
* the macOS bundle is listed because the same native module ships there and a
|
|
817
|
+
* future build may enable the policy, and `undefined` entries (an unset env
|
|
818
|
+
* variable) are dropped.
|
|
819
|
+
*/
|
|
820
|
+
declare function workbuddyAppExecutableCandidates(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv): string[];
|
|
821
|
+
/**
|
|
822
|
+
* The first candidate that exists as a file, or undefined when the desktop app
|
|
823
|
+
* is not installed where this platform expects it.
|
|
824
|
+
*/
|
|
825
|
+
declare function findWorkbuddyAppExecutable(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
826
|
+
/**
|
|
827
|
+
* Ask the installed desktop app for its key payload by running its own binary
|
|
828
|
+
* as plain Node (`ELECTRON_RUN_AS_NODE`) and calling the native binding.
|
|
829
|
+
*
|
|
830
|
+
* The binding is the app's own public surface for this value, so the plugin
|
|
831
|
+
* never has to carry a copy of a build-specific constant: it asks the very
|
|
832
|
+
* build that wrote the file. The child is given no stdin and a hard timeout,
|
|
833
|
+
* and its stdout is the only thing read.
|
|
834
|
+
*/
|
|
835
|
+
declare function fetchAtRestKeyPayload(executable: string): Promise<string>;
|
|
836
|
+
/**
|
|
837
|
+
* The desktop app's at-rest field key, or undefined when it cannot be obtained
|
|
838
|
+
* (app not installed, an older build without the native module, or a future
|
|
839
|
+
* build that rotates the payload). Cached after the first success so the app is
|
|
840
|
+
* spawned at most once per process; a failure is retried on the next call,
|
|
841
|
+
* because the user may install or start the app between reads.
|
|
842
|
+
*/
|
|
843
|
+
declare function readAtRestKey(): Promise<Buffer | undefined>;
|
|
844
|
+
/** Drop the cached key; tests and diagnostics only. */
|
|
845
|
+
declare function clearAtRestKeyCache(): void;
|
|
846
|
+
//#endregion
|
|
847
|
+
//#region src/credential-recovery.d.ts
|
|
848
|
+
/** What the user can do about a refused credential. */
|
|
849
|
+
interface WorkBuddyCredentialRecovery {
|
|
850
|
+
/**
|
|
851
|
+
* Another local account answered the upstream during this recovery, so
|
|
852
|
+
* switching to it is a fix that has been verified — not a guess.
|
|
853
|
+
*/
|
|
854
|
+
usableAccount?: {
|
|
855
|
+
accountId: string;
|
|
856
|
+
accountName: string;
|
|
857
|
+
};
|
|
858
|
+
/**
|
|
859
|
+
* Whether signing in again is the only remaining fix: no other local account
|
|
860
|
+
* exists at all, so there is nothing to switch to.
|
|
861
|
+
*/
|
|
862
|
+
reloginRequired: boolean;
|
|
863
|
+
}
|
|
864
|
+
/** One account as the recovery path needs to see it. */
|
|
865
|
+
interface WorkBuddyRecoveryCandidate {
|
|
866
|
+
id: string;
|
|
867
|
+
accountName: string;
|
|
868
|
+
}
|
|
869
|
+
/** Reads one account's credential for probing, without changing the selection. */
|
|
870
|
+
interface WorkBuddyProbeStore {
|
|
871
|
+
accounts(): Promise<readonly WorkBuddyRecoveryCandidate[]>;
|
|
872
|
+
credentialFor(accountId: string): Promise<WorkBuddyCredential | undefined>;
|
|
873
|
+
}
|
|
874
|
+
/** Constructor options for {@link createAccountUsabilityProbe}. */
|
|
875
|
+
interface WorkBuddyUsabilityProbeOptions {
|
|
876
|
+
/** The credential store for one region (its selection is never touched). */
|
|
877
|
+
store(region: WorkBuddyRegion): WorkBuddyProbeStore;
|
|
878
|
+
/** The upstream client; only its cheap read-only calls are used. */
|
|
879
|
+
client: Pick<WorkBuddyUpstreamClient, 'fetchCheckinStatus'>;
|
|
880
|
+
/**
|
|
881
|
+
* How long a probe verdict is reused. The card polls the usage route, so
|
|
882
|
+
* without this a broken selection would re-probe every account on every poll.
|
|
883
|
+
*/
|
|
884
|
+
ttlMs?: number;
|
|
885
|
+
/** Injectable clock, for tests. */
|
|
886
|
+
now?: () => number;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Cached "is this account still accepted upstream?" probe.
|
|
890
|
+
*
|
|
891
|
+
* The cache key includes the credential's own `lastRefreshAtMs`, so a fresh
|
|
892
|
+
* sign-in (which rewrites the file's issuance time) invalidates a stale verdict
|
|
893
|
+
* automatically — a rejection recorded before the user signed in again cannot
|
|
894
|
+
* keep labelling the account unusable afterwards, and no explicit invalidation
|
|
895
|
+
* is needed.
|
|
896
|
+
*/
|
|
897
|
+
declare function createAccountUsabilityProbe(options: WorkBuddyUsabilityProbeOptions): (region: WorkBuddyRegion, account: WorkBuddyRecoveryCandidate) => Promise<boolean>;
|
|
898
|
+
/**
|
|
899
|
+
* Decide what to tell the user after the upstream refused the selected
|
|
900
|
+
* credential: switch to a verified-usable account, or sign in again.
|
|
901
|
+
*
|
|
902
|
+
* The two answers are mutually exclusive by construction. `reloginRequired` is
|
|
903
|
+
* set ONLY when there is no other local account to switch to — never as a
|
|
904
|
+
* fallback for "the probe did not verify anything", because that would repeat
|
|
905
|
+
* the misdirection this module exists to remove. When other accounts exist but
|
|
906
|
+
* none was verified, both fields stay empty and the card says so honestly.
|
|
907
|
+
*/
|
|
908
|
+
declare function resolveCredentialRecovery(options: {
|
|
909
|
+
region: WorkBuddyRegion;
|
|
910
|
+
store: WorkBuddyProbeStore;
|
|
911
|
+
rejectedAccountId?: string;
|
|
912
|
+
/** Verifies whether one account is still accepted; see the probe factory. */
|
|
913
|
+
probe: (region: WorkBuddyRegion, account: WorkBuddyRecoveryCandidate) => Promise<boolean>;
|
|
914
|
+
}): Promise<WorkBuddyCredentialRecovery>;
|
|
915
|
+
//#endregion
|
|
589
916
|
//#region src/host-heartbeat.d.ts
|
|
590
917
|
/**
|
|
591
918
|
* Host-side heartbeat: a small JSON file written under `$DSH_HOME` once the
|
|
@@ -689,6 +1016,36 @@ declare function withWorkBuddyRegion(path: string, region: WorkBuddyWebRegion):
|
|
|
689
1016
|
* answer 400 instead of guessing.
|
|
690
1017
|
*/
|
|
691
1018
|
declare function regionOfStatusUrl(url: string): WorkBuddyWebRegion | undefined;
|
|
1019
|
+
/**
|
|
1020
|
+
* Whether one region's provider is switched on. Opt-out semantics: only an
|
|
1021
|
+
* explicit `false` disables it, so a config written before this switch existed
|
|
1022
|
+
* (and the pre-region-split flat fields, which never carry `enabled`) keep both
|
|
1023
|
+
* providers running exactly as before. The Host reads the same rule through
|
|
1024
|
+
* `regionStateOf`, so card and Host can never disagree about a region's state.
|
|
1025
|
+
*
|
|
1026
|
+
* `value` may be the whole settings section or the `regions` map (see
|
|
1027
|
+
* {@link regionsMapOf}).
|
|
1028
|
+
*/
|
|
1029
|
+
declare function regionEnabledOf(value: unknown, region: WorkBuddyWebRegion): boolean;
|
|
1030
|
+
/** Build the next `regions` settings value for a signed-in tab's save. */
|
|
1031
|
+
declare function nextRegionSlots<Slot extends object>(regions: unknown, region: WorkBuddyWebRegion, slot: Slot): Record<string, unknown>;
|
|
1032
|
+
/**
|
|
1033
|
+
* Build the next `regions` settings value for a provider on/off toggle. ONLY
|
|
1034
|
+
* the target region's `enabled` flag changes: every other field of that slot
|
|
1035
|
+
* (its directory, selection, image opt-ins, context budgets) and every other
|
|
1036
|
+
* region's slot are carried over verbatim, so switching a provider off never
|
|
1037
|
+
* discards the user's model picks and switching it back on restores them.
|
|
1038
|
+
*
|
|
1039
|
+
* This is deliberately separate from {@link nextRegionSlots}: that helper
|
|
1040
|
+
* writes a whole slot from a signed-in tab's draft, while this one must work
|
|
1041
|
+
* for a region that is signed OUT — which is precisely the region a user wants
|
|
1042
|
+
* to switch off (no international install, no international account).
|
|
1043
|
+
*
|
|
1044
|
+
* `value` may be the whole settings section or the `regions` map; the RETURN
|
|
1045
|
+
* value is always the `regions` map, i.e. exactly what `settingsScope.set(
|
|
1046
|
+
* 'regions', ...)` needs.
|
|
1047
|
+
*/
|
|
1048
|
+
declare function nextRegionEnabled(value: unknown, region: WorkBuddyWebRegion, enabled: boolean): Record<string, unknown>;
|
|
692
1049
|
/** One credit package as the upstream returns it, node-free. */
|
|
693
1050
|
interface WorkBuddyWebCreditPackage {
|
|
694
1051
|
packageName: string;
|
|
@@ -723,6 +1080,30 @@ interface WorkBuddyWebCheckin {
|
|
|
723
1080
|
streakBonusCredit: number;
|
|
724
1081
|
claimButtonText?: string;
|
|
725
1082
|
}
|
|
1083
|
+
/**
|
|
1084
|
+
* What the user can do about a credential the upstream refused.
|
|
1085
|
+
*
|
|
1086
|
+
* Two different fixes hide behind one 401, and naming the wrong one is worse
|
|
1087
|
+
* than saying nothing: with a stale account SELECTED but a healthy sign-in
|
|
1088
|
+
* sitting right there, "sign in again" sends the user to re-authenticate — which
|
|
1089
|
+
* changes nothing, because the credentials were never the problem.
|
|
1090
|
+
*/
|
|
1091
|
+
interface WorkBuddyWebRecovery {
|
|
1092
|
+
/**
|
|
1093
|
+
* Another local account answered the upstream during recovery, so switching
|
|
1094
|
+
* to it is a VERIFIED fix rather than a suggestion.
|
|
1095
|
+
*/
|
|
1096
|
+
usableAccount?: {
|
|
1097
|
+
accountId: string;
|
|
1098
|
+
accountName: string;
|
|
1099
|
+
};
|
|
1100
|
+
/**
|
|
1101
|
+
* Signing in again is the only remaining fix: this region has no other local
|
|
1102
|
+
* account to switch to. Set only in that case — never as a fallback for
|
|
1103
|
+
* "nothing could be verified".
|
|
1104
|
+
*/
|
|
1105
|
+
reloginRequired: boolean;
|
|
1106
|
+
}
|
|
726
1107
|
/** Editable WorkBuddy model row rendered by the plugin-owned settings card. */
|
|
727
1108
|
interface WorkBuddyWebModel {
|
|
728
1109
|
id: string;
|
|
@@ -753,14 +1134,39 @@ declare function toPersistedWorkBuddyModel(model: WorkBuddyWebModel): Omit<WorkB
|
|
|
753
1134
|
/** One selectable local account, token-free. */
|
|
754
1135
|
interface WorkBuddyWebAccount {
|
|
755
1136
|
id: string;
|
|
1137
|
+
/**
|
|
1138
|
+
* The account's human name, or `''` when the desktop app recorded none.
|
|
1139
|
+
* The card renders its own placeholder for the empty case.
|
|
1140
|
+
*/
|
|
756
1141
|
accountName: string;
|
|
757
|
-
uin?: string;
|
|
758
1142
|
domain: string;
|
|
759
1143
|
source: 'desktop' | 'dsh';
|
|
760
1144
|
tokenExpiresAtMs: number;
|
|
761
1145
|
selected: boolean;
|
|
762
1146
|
}
|
|
763
1147
|
type WorkBuddyWebPackage = WorkBuddyWebCreditPackage;
|
|
1148
|
+
/**
|
|
1149
|
+
* One probed candidate path and why it yielded no account.
|
|
1150
|
+
*
|
|
1151
|
+
* Safe to send to the browser: a path, its source, and a cause. No token
|
|
1152
|
+
* material, and no content read out of the files beyond an error string.
|
|
1153
|
+
*
|
|
1154
|
+
* `encrypted` exists because WorkBuddy (unlike a plain JSON-token app) can
|
|
1155
|
+
* refuse a correctly signed-in user: Windows builds encrypt the token fields,
|
|
1156
|
+
* and opening them needs the desktop app present to hand over its at-rest key.
|
|
1157
|
+
* Telling that user to "sign in again" is wrong — they already are.
|
|
1158
|
+
*
|
|
1159
|
+
* `wrong-region` is the other WorkBuddy-specific one: the file holds a valid
|
|
1160
|
+
* sign-in for the OTHER tab's region, so this tab filters it out of the account
|
|
1161
|
+
* list. Without this entry the file was reported nowhere at all, which both
|
|
1162
|
+
* undercounted "paths checked" and hid the user's real sign-in.
|
|
1163
|
+
*/
|
|
1164
|
+
interface WorkBuddyWebSearchPath {
|
|
1165
|
+
path: string;
|
|
1166
|
+
source: 'desktop' | 'dsh';
|
|
1167
|
+
reason: 'missing' | 'unreadable' | 'invalid' | 'encrypted' | 'wrong-region';
|
|
1168
|
+
message?: string;
|
|
1169
|
+
}
|
|
764
1170
|
/**
|
|
765
1171
|
* Region of the signed-in credential: the CN app (`codebuddy.cn` /
|
|
766
1172
|
* `workbuddy.cn`) or the international WorkBuddy AI app (`workbuddy.ai`).
|
|
@@ -786,19 +1192,36 @@ type WorkBuddyWebUsage =
|
|
|
786
1192
|
{
|
|
787
1193
|
status: 'signed-out';
|
|
788
1194
|
accounts: readonly WorkBuddyWebAccount[];
|
|
1195
|
+
/** Whether this region's provider is currently offered to DSH. */
|
|
1196
|
+
enabled?: boolean;
|
|
789
1197
|
message?: string;
|
|
790
1198
|
/** The persisted account id matches no local account. */
|
|
791
1199
|
selectionLost?: boolean;
|
|
792
1200
|
/** A saved per-region choice is in effect (false = following the app). */
|
|
793
1201
|
selectionExplicit: boolean;
|
|
1202
|
+
/**
|
|
1203
|
+
* The paths this region's store probed, and why each yielded nothing.
|
|
1204
|
+
*
|
|
1205
|
+
* Present only on the "nothing was found at all" branch — it is the
|
|
1206
|
+
* explanation for a state that is otherwise a dead end. A missing candidate
|
|
1207
|
+
* (`missing`) is normal noise on any machine and the card filters those out
|
|
1208
|
+
* of its default view; the interesting ones are `unreadable`, `invalid`,
|
|
1209
|
+
* and especially `encrypted`.
|
|
1210
|
+
*/
|
|
1211
|
+
searched?: readonly WorkBuddyWebSearchPath[];
|
|
794
1212
|
} | {
|
|
795
1213
|
status: 'signed-in';
|
|
796
1214
|
accountId: string;
|
|
1215
|
+
/**
|
|
1216
|
+
* The account's human name, or `''` when the desktop app recorded none.
|
|
1217
|
+
* Never an identifier — see {@link WorkBuddyWebAccount.accountName}.
|
|
1218
|
+
*/
|
|
797
1219
|
accountName: string;
|
|
798
|
-
uin?: string;
|
|
799
1220
|
domain?: string;
|
|
800
1221
|
/** Which per-region model directory and selection this account owns. */
|
|
801
1222
|
region: WorkBuddyWebRegion;
|
|
1223
|
+
/** Whether this region's provider is currently offered to DSH. */
|
|
1224
|
+
enabled?: boolean;
|
|
802
1225
|
source?: 'desktop' | 'dsh';
|
|
803
1226
|
tokenExpiresAtMs: number;
|
|
804
1227
|
/** A saved per-region choice is in effect (false = following the app). */
|
|
@@ -811,6 +1234,14 @@ type WorkBuddyWebUsage =
|
|
|
811
1234
|
creditsError?: string;
|
|
812
1235
|
checkin?: WorkBuddyWebCheckin;
|
|
813
1236
|
checkinError?: string;
|
|
1237
|
+
/**
|
|
1238
|
+
* The upstream refused the credential itself (a 401/403), as opposed to a
|
|
1239
|
+
* transient upstream fault. Distinguishes "your token is not usable" from
|
|
1240
|
+
* "the request failed", which need opposite advice.
|
|
1241
|
+
*/
|
|
1242
|
+
credentialRejected?: boolean;
|
|
1243
|
+
/** Present only alongside {@link credentialRejected}. */
|
|
1244
|
+
recovery?: WorkBuddyWebRecovery;
|
|
814
1245
|
} | {
|
|
815
1246
|
status: 'error';
|
|
816
1247
|
message: string;
|
|
@@ -837,6 +1268,31 @@ interface WorkBuddyStatusRouteOptions {
|
|
|
837
1268
|
contextBudgets(region: WorkBuddyRegion): Readonly<Record<string, number | undefined>>;
|
|
838
1269
|
/** Re-read the live catalog of one region from the upstream. */
|
|
839
1270
|
discoverModels?(region: WorkBuddyRegion, signal?: AbortSignal): Promise<readonly WorkBuddyModelInfo[]>;
|
|
1271
|
+
/**
|
|
1272
|
+
* Whether the requested region's provider is currently offered to DSH. The
|
|
1273
|
+
* card renders this as the tab's on/off checkbox, so the switch reflects the
|
|
1274
|
+
* committed settings value rather than a local guess.
|
|
1275
|
+
*/
|
|
1276
|
+
regionEnabled(region: WorkBuddyRegion): boolean;
|
|
1277
|
+
/**
|
|
1278
|
+
* Report whether a region still has at least one local sign-in.
|
|
1279
|
+
*
|
|
1280
|
+
* The card is where sign-in state actually changes under the plugin's nose
|
|
1281
|
+
* (the user signs in to the desktop app, then presses "detect accounts
|
|
1282
|
+
* again"), so the routes are the earliest honest place to notice. Both
|
|
1283
|
+
* callers already read `store.accounts()` for their own answer, so this adds
|
|
1284
|
+
* no scan of its own.
|
|
1285
|
+
*/
|
|
1286
|
+
regionUsable?(region: WorkBuddyRegion, usable: boolean): void;
|
|
1287
|
+
/**
|
|
1288
|
+
* Verify whether one local account is still accepted by the upstream.
|
|
1289
|
+
*
|
|
1290
|
+
* Consulted ONLY after the selected credential has been refused, to tell
|
|
1291
|
+
* "switch accounts" apart from "sign in again". Left undefined, nothing is
|
|
1292
|
+
* claimed usable and the card falls back to the re-login advice that needs no
|
|
1293
|
+
* probe.
|
|
1294
|
+
*/
|
|
1295
|
+
accountUsable?(region: WorkBuddyRegion, account: WorkBuddyRecoveryCandidate): Promise<boolean>;
|
|
840
1296
|
}
|
|
841
1297
|
/**
|
|
842
1298
|
* Assemble one region's card document. `region` is the tab the card is on;
|
|
@@ -862,6 +1318,15 @@ declare const inject: string[];
|
|
|
862
1318
|
declare const WORKBUDDY_SETTINGS_NS: SettingsNamespace;
|
|
863
1319
|
/** One region's model directory and the user's selection within it. */
|
|
864
1320
|
interface WorkBuddyRegionState {
|
|
1321
|
+
/**
|
|
1322
|
+
* Whether this region's provider is switched on. Opt-out: only an explicit
|
|
1323
|
+
* `false` disables it, so a config predating this switch keeps both providers
|
|
1324
|
+
* running. A disabled region is fully withdrawn from the harness — its adapter
|
|
1325
|
+
* route and its configurable-provider entry both hold zero routes, so it
|
|
1326
|
+
* disappears from DSH's model picker instead of lingering as an unselectable
|
|
1327
|
+
* row (see `syncRegionRegistration`).
|
|
1328
|
+
*/
|
|
1329
|
+
enabled?: boolean;
|
|
865
1330
|
/** The last-refreshed directory for this region; what the card displays. */
|
|
866
1331
|
lastCatalog?: WorkBuddyModelInfo[];
|
|
867
1332
|
/** The user's selection in this region, as model ids. */
|
|
@@ -918,6 +1383,15 @@ declare const Config: z<Config>;
|
|
|
918
1383
|
* picks.
|
|
919
1384
|
*/
|
|
920
1385
|
declare function regionStateOf(config: Config, region: WorkBuddyRegion): WorkBuddyRegionState;
|
|
1386
|
+
/**
|
|
1387
|
+
* Whether one region's provider is switched on. Opt-out semantics: only an
|
|
1388
|
+
* explicit `false` disables it, so every config written before this switch
|
|
1389
|
+
* existed — including the pre-region-split flat fields, which never carry
|
|
1390
|
+
* `enabled` — keeps both providers running exactly as before. The card reads the
|
|
1391
|
+
* same rule through `regionEnabledOf`, so the two halves can never disagree
|
|
1392
|
+
* about a region's state.
|
|
1393
|
+
*/
|
|
1394
|
+
declare function regionEnabled(config: Config, region: WorkBuddyRegion): boolean;
|
|
921
1395
|
/**
|
|
922
1396
|
* The account id a region should select, or `undefined` for the documented
|
|
923
1397
|
* default: follow whatever the WorkBuddy app is currently signed in as.
|
|
@@ -968,4 +1442,4 @@ declare function legacyAttributionRegion(value: Config, accountsFor: (region: Wo
|
|
|
968
1442
|
*/
|
|
969
1443
|
declare function apply(ctx: Context, config: Config): void;
|
|
970
1444
|
//#endregion
|
|
971
|
-
export { Config, FALLBACK_WORKBUDDY_MODELS, FALLBACK_WORKBUDDY_MODELS_GLOBAL, type UpstreamErrorKind, WORKBUDDY_ACCOUNTS_REFRESH_PATH, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CHECKIN_PATH, WORKBUDDY_CONNECT_VERSION, WORKBUDDY_GLOBAL_PROVIDER, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_MODELS_REFRESH_PATH, WORKBUDDY_PROVIDER, WORKBUDDY_PROVIDERS, WORKBUDDY_PROVIDER_DISPLAY_NAMES, WORKBUDDY_REGIONS, WORKBUDDY_REGION_PARAM, WORKBUDDY_SETTINGS_NS, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_USAGE_PATH, type WorkBuddyAccountChoice, type WorkBuddyAdapter, type WorkBuddyAuthStatus, WorkBuddyCatalog, type WorkBuddyChatResult, type WorkBuddyCredential, WorkBuddyCredentialStore, type WorkBuddyCreditPackage, type WorkBuddyCredits, type WorkBuddyHostHeartbeat, type WorkBuddyModelInfo, type WorkBuddyReasoning, type WorkBuddyRefreshOutcome, WorkBuddyRegionState, type WorkBuddyShim, type WorkBuddyStatusRouteOptions, type WorkBuddyStoreOptions, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyWebAccount, type WorkBuddyWebCheckin, type WorkBuddyWebCredits, type WorkBuddyWebModel, type WorkBuddyWebPackage, type WorkBuddyWebRegion, type WorkBuddyWebUsage, apply, authFileName, classifyUpstreamError, clearHostHeartbeat, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthDirs, defaultDesktopAuthPath, deriveCatalog, fallbackModelsFor, inject, isHeartbeatProcessAlive, legacyAttributionRegion, legacyWorkbuddyOwnAuthPath, name, parseCreditMultiplier, parseReasoning, parseUpstreamModel, parseWorkBuddyAuth, prepareChatBody, processStartTimeMs, readHostHeartbeat, regionCleared, regionOf, regionOfProvider, regionOfStatusUrl, regionStateOf, registerWorkBuddyStatusRoute, selectAccountFor, toPersistedWorkBuddyModel, withWorkBuddyRegion, workBuddyDisplayName, workBuddyModelInput, workBuddyThinkingLevelMap, workBuddyWebStatus, workbuddyAccountId, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, writeHostHeartbeat };
|
|
1445
|
+
export { CREDENTIAL_REJECTED_CODE, Config, FALLBACK_WORKBUDDY_MODELS, FALLBACK_WORKBUDDY_MODELS_GLOBAL, type UpstreamErrorKind, WORKBUDDY_ACCOUNTS_REFRESH_PATH, WORKBUDDY_APP_EXECUTABLE_ENV, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CHECKIN_PATH, WORKBUDDY_CONNECT_VERSION, WORKBUDDY_GLOBAL_PROVIDER, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_MODELS_REFRESH_PATH, WORKBUDDY_PROVIDER, WORKBUDDY_PROVIDERS, WORKBUDDY_PROVIDER_DISPLAY_NAMES, WORKBUDDY_REGIONS, WORKBUDDY_REGION_PARAM, WORKBUDDY_SETTINGS_NS, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_USAGE_PATH, type WorkBuddyAccountChoice, type WorkBuddyAdapter, type WorkBuddyAuthStatus, type WorkBuddyCandidateFailure, WorkBuddyCatalog, type WorkBuddyChatResult, type WorkBuddyCredential, type WorkBuddyCredentialRecovery, WorkBuddyCredentialRejectedError, WorkBuddyCredentialStore, type WorkBuddyCreditPackage, type WorkBuddyCredits, type WorkBuddyEncryptedField, type WorkBuddyHostHeartbeat, type WorkBuddyModelInfo, type WorkBuddyProbeStore, type WorkBuddyReasoning, type WorkBuddyRecoveryCandidate, type WorkBuddyRefreshOutcome, WorkBuddyRegionState, type WorkBuddyShim, type WorkBuddyStatusRouteOptions, type WorkBuddyStoreOptions, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyUsabilityProbeOptions, type WorkBuddyWebAccount, type WorkBuddyWebCheckin, type WorkBuddyWebCredits, type WorkBuddyWebModel, type WorkBuddyWebPackage, type WorkBuddyWebRegion, type WorkBuddyWebSearchPath, type WorkBuddyWebUsage, apply, authFileName, classifyUpstreamError, clearAtRestKeyCache, clearHostHeartbeat, createAccountUsabilityProbe, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthDirs, defaultDesktopAuthPath, deriveAtRestKey, deriveAtRestKeyId, deriveCatalog, fallbackModelsFor, fetchAtRestKeyPayload, findWorkbuddyAppExecutable, hasEncryptedCredentialFields, inject, isCredentialRejectedError, isEncryptedFieldWrapper, isHeartbeatProcessAlive, legacyAttributionRegion, legacyWorkbuddyOwnAuthPath, name, nextRegionEnabled, nextRegionSlots, openEncryptedField, parseCreditMultiplier, parseReasoning, parseUpstreamModel, parseWorkBuddyAuth, prepareChatBody, processStartTimeMs, readAtRestKey, readHostHeartbeat, regionCleared, regionEnabled, regionEnabledOf, regionOf, regionOfProvider, regionOfStatusUrl, regionStateOf, registerWorkBuddyStatusRoute, resolveCredentialRecovery, selectAccountFor, toPersistedWorkBuddyModel, withWorkBuddyRegion, workBuddyDisplayName, workBuddyModelInput, workBuddyThinkingLevelMap, workBuddyWebStatus, workbuddyAccountId, workbuddyAppExecutableCandidates, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, writeHostHeartbeat };
|