dsh-connect-workbuddy 2.0.6 → 2.0.11
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 +192 -0
- package/README.en.md +8 -1
- package/README.md +8 -1
- package/lib/bin.js +15 -2
- package/lib/client.js +425 -66
- package/lib/{host-heartbeat--iKDuwr5.js → host-heartbeat-BJdDmMSn.js} +738 -36
- package/lib/index.d.ts +541 -10
- package/lib/index.js +262 -27
- 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';
|
|
@@ -40,6 +65,36 @@ interface WorkBuddyAuthStatus {
|
|
|
40
65
|
domain?: string;
|
|
41
66
|
source?: 'desktop' | 'dsh';
|
|
42
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* Marker for a credential that EXISTS but could not be decrypted.
|
|
70
|
+
*
|
|
71
|
+
* Identified by {@link ENCRYPTED_CREDENTIAL_CODE} rather than `instanceof`, so
|
|
72
|
+
* the check keeps working when the thrower and the caller end up in different
|
|
73
|
+
* module instances (bundled host half vs. a test's source import) — the same
|
|
74
|
+
* convention `WorkBuddyCredentialRejectedError` uses.
|
|
75
|
+
*/
|
|
76
|
+
declare const ENCRYPTED_CREDENTIAL_CODE = "WORKBUDDY_ENCRYPTED_CREDENTIAL";
|
|
77
|
+
/**
|
|
78
|
+
* The user IS signed in, but the credential file cannot be read.
|
|
79
|
+
*
|
|
80
|
+
* This exists because "signed out" and "signed in with an unreadable credential"
|
|
81
|
+
* resolve to the same observable state — zero accounts — and were therefore
|
|
82
|
+
* reported with the same message. That message told a correctly signed-in user
|
|
83
|
+
* to sign in again, which cannot possibly help: from WorkBuddy 5.6.x the desktop
|
|
84
|
+
* app encrypts its token fields, and reading them requires asking the installed
|
|
85
|
+
* app for its key. If that app cannot be located, the fix is to point the plugin
|
|
86
|
+
* at it (`WORKBUDDY_APP_EXECUTABLE`), never to sign in again.
|
|
87
|
+
*
|
|
88
|
+
* No token material is carried: only the paths and the environment variable.
|
|
89
|
+
*/
|
|
90
|
+
declare class WorkBuddyEncryptedCredentialError extends Error {
|
|
91
|
+
readonly code = "WORKBUDDY_ENCRYPTED_CREDENTIAL";
|
|
92
|
+
/** Files that hold an encrypted credential, for the user to recognize. */
|
|
93
|
+
readonly paths: readonly string[];
|
|
94
|
+
constructor(paths: readonly string[]);
|
|
95
|
+
}
|
|
96
|
+
/** Whether an error reports an unreadable (encrypted) credential. */
|
|
97
|
+
declare function isEncryptedCredentialError(value: unknown): value is WorkBuddyEncryptedCredentialError;
|
|
43
98
|
/** Constructor options; only {@link refresh} is required. */
|
|
44
99
|
interface WorkBuddyStoreOptions {
|
|
45
100
|
/** Explicit desktop auth-file path, overriding env and platform defaults. */
|
|
@@ -69,13 +124,25 @@ interface WorkBuddyStoreOptions {
|
|
|
69
124
|
refresh: (credential: WorkBuddyCredential) => Promise<WorkBuddyRefreshOutcome>;
|
|
70
125
|
/** Refresh this long before actual expiry; default five minutes. */
|
|
71
126
|
refreshMarginMs?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Resolves the desktop app's at-rest field key, used to open documents whose
|
|
129
|
+
* token fields are encrypted (Windows builds). Defaults to asking the
|
|
130
|
+
* installed app; injectable so the encrypted path is testable.
|
|
131
|
+
*/
|
|
132
|
+
resolveAtRestKey?: () => Promise<Buffer | undefined>;
|
|
72
133
|
}
|
|
73
134
|
/** One selectable local account, token-free. */
|
|
74
135
|
interface WorkBuddyAccountChoice {
|
|
75
136
|
/** Stable id derived from `uin` (or `uid` when uin is absent). */
|
|
76
137
|
id: string;
|
|
138
|
+
/**
|
|
139
|
+
* The account's human name, or `''` when the desktop app recorded none.
|
|
140
|
+
*
|
|
141
|
+
* Never an identifier: `uin`/`uid` are opaque numbers and UUIDs, and using one
|
|
142
|
+
* as a display name reads as "the plugin does not know who this is". Callers
|
|
143
|
+
* that render a name choose their own placeholder for the empty case.
|
|
144
|
+
*/
|
|
77
145
|
accountName: string;
|
|
78
|
-
uin?: string;
|
|
79
146
|
domain: string;
|
|
80
147
|
source: 'desktop' | 'dsh';
|
|
81
148
|
tokenExpiresAtMs: number;
|
|
@@ -119,8 +186,24 @@ declare function defaultDesktopAuthPath(): string | undefined;
|
|
|
119
186
|
* Parse a WorkBuddy auth document in either on-disk shape: the plugin OAuth
|
|
120
187
|
* nested form `{"auth":{...},"account":{...}}` and the flat panel form.
|
|
121
188
|
* Returns undefined when the document carries no access token.
|
|
189
|
+
*
|
|
190
|
+
* `atRestKey` is required to read documents whose fields are encrypted
|
|
191
|
+
* (see {@link credentialField}); pass the key obtained from
|
|
192
|
+
* `readAtRestKey()` when the plain read reports no token.
|
|
193
|
+
*/
|
|
194
|
+
declare function parseWorkBuddyAuth(text: string, filePath: string, atRestKey?: Buffer): WorkBuddyCredential | undefined;
|
|
195
|
+
/**
|
|
196
|
+
* Whether a document carries any field the reader must decrypt — the token
|
|
197
|
+
* fields or the identity fields — i.e. whether reading it needs the at-rest key
|
|
198
|
+
* at all.
|
|
199
|
+
*
|
|
200
|
+
* Deciding this BEFORE asking the app for its key keeps the plain case (macOS
|
|
201
|
+
* and older Windows builds, and every plugin-owned copy) from paying for a
|
|
202
|
+
* child process on every credential read. Identity fields are included because
|
|
203
|
+
* a future build could encrypt the display name while leaving tokens plain;
|
|
204
|
+
* gating on tokens alone would then silently drop the name again.
|
|
122
205
|
*/
|
|
123
|
-
declare function
|
|
206
|
+
declare function hasEncryptedCredentialFields(text: string): boolean;
|
|
124
207
|
/**
|
|
125
208
|
* Filename of a path regardless of the host separator: Windows paths use `\`
|
|
126
209
|
* and this helper must keep working when a Windows path is compared on a
|
|
@@ -150,6 +233,7 @@ declare class WorkBuddyCredentialStore {
|
|
|
150
233
|
private readonly legacyOwnPath;
|
|
151
234
|
private readonly legacyOwnPathExplicit;
|
|
152
235
|
private readonly authDirs;
|
|
236
|
+
private readonly resolveAtRestKey;
|
|
153
237
|
private desktopPathOverride;
|
|
154
238
|
private accountId;
|
|
155
239
|
private inflight;
|
|
@@ -262,8 +346,33 @@ declare class WorkBuddyCredentialStore {
|
|
|
262
346
|
selectionLost(): Promise<boolean>;
|
|
263
347
|
/** The freshest stored credential for the current selection, no refresh. */
|
|
264
348
|
current(): Promise<WorkBuddyCredential | undefined>;
|
|
349
|
+
/**
|
|
350
|
+
* One account's stored credential by id, WITHOUT consulting or changing the
|
|
351
|
+
* current selection.
|
|
352
|
+
*
|
|
353
|
+
* Exists so a recovery probe can test whether some OTHER local account is
|
|
354
|
+
* still accepted upstream while a rejected one stays selected: mutating the
|
|
355
|
+
* live selection to find that out would be exactly the silent account switch
|
|
356
|
+
* this store refuses to perform (it would bill the wrong account mid-probe).
|
|
357
|
+
*/
|
|
358
|
+
credentialFor(accountId: string): Promise<WorkBuddyCredential | undefined>;
|
|
265
359
|
/** The credential to send upstream: {@link current}, refreshed on demand. */
|
|
266
360
|
resolve(): Promise<WorkBuddyCredential>;
|
|
361
|
+
/**
|
|
362
|
+
* WHY no credential resolved, as the error to throw.
|
|
363
|
+
*
|
|
364
|
+
* `resolve()` seeing zero accounts has two very different causes, and the
|
|
365
|
+
* generic "sign in once" message is only correct for one of them. When a
|
|
366
|
+
* probe finds a credential file whose fields are encrypted and the key could
|
|
367
|
+
* not be obtained, the user is signed in and re-authenticating cannot help —
|
|
368
|
+
* so that case gets {@link WorkBuddyEncryptedCredentialError} instead, naming
|
|
369
|
+
* the file and the environment variable that actually fixes it.
|
|
370
|
+
*
|
|
371
|
+
* The probe is only run on the failure path, so the healthy case pays nothing.
|
|
372
|
+
* A probe that itself throws must not replace the real error, hence the
|
|
373
|
+
* fallback to the generic message.
|
|
374
|
+
*/
|
|
375
|
+
private describeMissingCredential;
|
|
267
376
|
/** Read-only sign-in summary; never refreshes and never throws. */
|
|
268
377
|
status(): Promise<WorkBuddyAuthStatus>;
|
|
269
378
|
/**
|
|
@@ -284,6 +393,21 @@ declare class WorkBuddyCredentialStore {
|
|
|
284
393
|
private readOwns;
|
|
285
394
|
/** Whether any candidate file exists as a regular file; diagnostics only. */
|
|
286
395
|
desktopFilePresent(): Promise<boolean>;
|
|
396
|
+
/**
|
|
397
|
+
* Which paths were probed and why each one yielded no credential.
|
|
398
|
+
*
|
|
399
|
+
* Read-only and token-free: it exists so a signed-out card can explain
|
|
400
|
+
* itself. A bare "not signed in" is undiagnosable on a machine whose layout
|
|
401
|
+
* differs from the ones this plugin was written against — and on Windows it
|
|
402
|
+
* is actively misleading, because encrypted token fields need the desktop app
|
|
403
|
+
* present to be read at all. Only paths this store actually consults are
|
|
404
|
+
* reported, and only files that failed: one healthy sibling would make the
|
|
405
|
+
* whole list noise.
|
|
406
|
+
*/
|
|
407
|
+
diagnose(): Promise<{
|
|
408
|
+
tried: string[];
|
|
409
|
+
failures: WorkBuddyCandidateFailure[];
|
|
410
|
+
}>;
|
|
287
411
|
}
|
|
288
412
|
//#endregion
|
|
289
413
|
//#region src/upstream.d.ts
|
|
@@ -395,6 +519,28 @@ declare function regionOf(domain: string): WorkBuddyRegion;
|
|
|
395
519
|
* `tool_choice` (the upstream's field is a string; object forms return 400).
|
|
396
520
|
*/
|
|
397
521
|
declare function prepareChatBody(source: string): string;
|
|
522
|
+
/** Marker carried by {@link WorkBuddyCredentialRejectedError}; survives bundling. */
|
|
523
|
+
declare const CREDENTIAL_REJECTED_CODE = "WORKBUDDY_CREDENTIAL_REJECTED";
|
|
524
|
+
/**
|
|
525
|
+
* The upstream refused the CREDENTIAL itself rather than failing the request.
|
|
526
|
+
*
|
|
527
|
+
* This is a distinct, actionable class: the token is not usable and no retry
|
|
528
|
+
* with the same token will help. Callers use it to tell the user what to do
|
|
529
|
+
* about it (switch accounts, or sign in again) instead of showing a raw HTTP
|
|
530
|
+
* error, and the card must never confuse it with a transient upstream fault.
|
|
531
|
+
*
|
|
532
|
+
* Identified by {@link CREDENTIAL_REJECTED_CODE} rather than `instanceof`, so
|
|
533
|
+
* the check keeps working when the caller and the thrower end up in different
|
|
534
|
+
* module instances (bundled host half vs. a test's source import).
|
|
535
|
+
*/
|
|
536
|
+
declare class WorkBuddyCredentialRejectedError extends Error {
|
|
537
|
+
readonly code = "WORKBUDDY_CREDENTIAL_REJECTED";
|
|
538
|
+
/** HTTP status the upstream answered with (401 or 403). */
|
|
539
|
+
readonly status: number;
|
|
540
|
+
constructor(status: number);
|
|
541
|
+
}
|
|
542
|
+
/** Whether an error reports that the upstream refused the credential itself. */
|
|
543
|
+
declare function isCredentialRejectedError(value: unknown): value is WorkBuddyCredentialRejectedError;
|
|
398
544
|
/**
|
|
399
545
|
* Parse the upstream's `credits` string into a multiplier.
|
|
400
546
|
*
|
|
@@ -496,6 +642,18 @@ declare class WorkBuddyCatalog {
|
|
|
496
642
|
* serving the fallback rather than blanking a region that may be fine.
|
|
497
643
|
*/
|
|
498
644
|
private usable;
|
|
645
|
+
/**
|
|
646
|
+
* Whether the user has switched this region's provider ON. Opt-out: defaults
|
|
647
|
+
* to `true`, so a config predating this switch (and the pre-region-split flat
|
|
648
|
+
* fields, which never carry `enabled`) keeps both providers running. Set to
|
|
649
|
+
* `false` by `setRegionEnabled` to withdraw the region from DSH's model
|
|
650
|
+
* picker entirely (its adapter route and configurable-provider entry are
|
|
651
|
+
* pulled by the Host via `AdapterRegistrationHandle.replace([])` /
|
|
652
|
+
* `DirectoryRegistrationHandle.replace([])`). This is a USER choice, distinct
|
|
653
|
+
* from {@link usable}: a region the user switched off keeps its catalog,
|
|
654
|
+
* accounts, and model picks intact and reappears the moment they re-check it.
|
|
655
|
+
*/
|
|
656
|
+
private enabled;
|
|
499
657
|
/**
|
|
500
658
|
* @param region Seeds the static fallback for this region; each region's
|
|
501
659
|
* provider must never serve the other region's roster before its first
|
|
@@ -505,15 +663,19 @@ declare class WorkBuddyCatalog {
|
|
|
505
663
|
/**
|
|
506
664
|
* Current entries; the fallback list until the upstream answer lands.
|
|
507
665
|
*
|
|
508
|
-
* Empty while this region has no local sign-in
|
|
509
|
-
* registered (its row still hosts the settings card
|
|
510
|
-
* but it advertises nothing to pick. DSH drops empty
|
|
511
|
-
* the picker (`buildModelCatalog` filters
|
|
512
|
-
* disappears exactly when it would be pure
|
|
666
|
+
* Empty while this region has no local sign-in OR the user has switched it
|
|
667
|
+
* off: the provider stays registered (its row still hosts the settings card
|
|
668
|
+
* and the account picker), but it advertises nothing to pick. DSH drops empty
|
|
669
|
+
* provider groups from the picker (`buildModelCatalog` filters
|
|
670
|
+
* `models.length > 0`), so the group disappears exactly when it would be pure
|
|
671
|
+
* noise. The two empty causes are independent: `usable` is the automatic
|
|
672
|
+
* "no account" gate (issue #12), `enabled` is the user's explicit on/off.
|
|
513
673
|
*/
|
|
514
674
|
current(): readonly WorkBuddyModelInfo[];
|
|
515
675
|
/** Whether this region currently advertises any model. */
|
|
516
676
|
isRegionUsable(): boolean;
|
|
677
|
+
/** Whether the user has this region's provider switched on. */
|
|
678
|
+
isRegionEnabled(): boolean;
|
|
517
679
|
/**
|
|
518
680
|
* Record whether this region has a local sign-in.
|
|
519
681
|
*
|
|
@@ -526,6 +688,16 @@ declare class WorkBuddyCatalog {
|
|
|
526
688
|
* its adapter snapshots when nothing moved.
|
|
527
689
|
*/
|
|
528
690
|
setRegionUsable(usable: boolean): boolean;
|
|
691
|
+
/**
|
|
692
|
+
* Record the user's explicit on/off choice for this region's provider.
|
|
693
|
+
*
|
|
694
|
+
* Distinct from {@link setRegionUsable}: that is the automatic "no local
|
|
695
|
+
* account" gate, while this is a deliberate user action (issue #11-style
|
|
696
|
+
* region switch). The Host reads the same `enabled` flag through
|
|
697
|
+
* `regionStateOf(config, region).enabled !== false`, so the two halves never
|
|
698
|
+
* disagree. Returns whether the value changed.
|
|
699
|
+
*/
|
|
700
|
+
setRegionEnabled(enabled: boolean): boolean;
|
|
529
701
|
/** Replace the list; callers invalidate their adapter snapshot after this. */
|
|
530
702
|
set(models: readonly WorkBuddyModelInfo[]): void;
|
|
531
703
|
}
|
|
@@ -622,6 +794,228 @@ declare function workBuddyThinkingLevelMap(info: WorkBuddyModelInfo): WorkBuddyT
|
|
|
622
794
|
*/
|
|
623
795
|
declare function createWorkBuddyAdapter(options: WorkBuddyAdapterOptions): WorkBuddyAdapter;
|
|
624
796
|
//#endregion
|
|
797
|
+
//#region src/at-rest.d.ts
|
|
798
|
+
/**
|
|
799
|
+
* WorkBuddy desktop "at-rest" credential decryption.
|
|
800
|
+
*
|
|
801
|
+
* From 5.6.0 the WorkBuddy desktop app no longer stores `auth.accessToken` /
|
|
802
|
+
* `auth.refreshToken` as plain strings. It writes a field wrapper:
|
|
803
|
+
*
|
|
804
|
+
* { "$wbEncrypted": 1, "envelope": "<base64 of a JSON envelope>" }
|
|
805
|
+
*
|
|
806
|
+
* where the envelope is `{suite, keyId, nonce, authTag, ciphertext}` for
|
|
807
|
+
* AES-256-GCM with a 12-byte nonce and a 16-byte tag. The authenticated
|
|
808
|
+
* additional data is a length-prefixed transcript over the scheme, suite,
|
|
809
|
+
* keyId and framing, so the ciphertext can only be opened for the exact field
|
|
810
|
+
* shape it was sealed for.
|
|
811
|
+
*
|
|
812
|
+
* The field key itself is NOT a user secret: it is a build-time constant
|
|
813
|
+
* compiled into the app's own Electron native module
|
|
814
|
+
* (`electron_browser_workbuddy_storage`). The app fetches it through
|
|
815
|
+
* `loggerGet()` and hashes the returned base64 STRING (not the decoded bytes)
|
|
816
|
+
* to obtain the 32-byte key; `keyId` is the first 16 hex characters of that
|
|
817
|
+
* key's SHA-256.
|
|
818
|
+
*
|
|
819
|
+
* This module re-derives the same key by asking the installed app for the same
|
|
820
|
+
* payload, and caches it in memory for the process lifetime. Nothing is ever
|
|
821
|
+
* written to disk, and the payload is never logged.
|
|
822
|
+
*
|
|
823
|
+
* 改动:**「macOS 也加密」这一事实**(issue #15 真机取证)。本模块原先假设该
|
|
824
|
+
* policy 是 Windows 先行、macOS 只是「将来可能」,于是 macOS 的可执行文件
|
|
825
|
+
* 路径用 App 名拼成 `<bundle>/Contents/MacOS/WorkBuddy`——而两个真实 bundle
|
|
826
|
+
* 的 `CFBundleExecutable` 都是 `Electron`,该路径并不存在。结果是 macOS 上
|
|
827
|
+
* 加密凭据**永远**取不到密钥,用户却被报成「未登录」。现在二进制名向 bundle
|
|
828
|
+
* 自己问(`macosBundleExecutable()`),候选含国际版 `WorkBuddy AI.app`,
|
|
829
|
+
* 并允许 App 被归入 applications 目录的子目录——扫到的候选必须先用
|
|
830
|
+
* `CFBundleIdentifier` 确认身份才 `execFile`,因为**每个 Electron 应用的
|
|
831
|
+
* 二进制都叫 `Electron`**,只按名字匹配就可能启动另一个产品。
|
|
832
|
+
*
|
|
833
|
+
* @module dsh-connect-workbuddy/at-rest
|
|
834
|
+
*/
|
|
835
|
+
/** A `{$wbEncrypted:1,envelope}` field wrapper, the only shape this module opens. */
|
|
836
|
+
interface WorkBuddyEncryptedField {
|
|
837
|
+
$wbEncrypted: 1;
|
|
838
|
+
envelope: string;
|
|
839
|
+
}
|
|
840
|
+
/** Env override pointing at the WorkBuddy desktop executable. */
|
|
841
|
+
declare const WORKBUDDY_APP_EXECUTABLE_ENV = "WORKBUDDY_APP_EXECUTABLE";
|
|
842
|
+
/** Whether a value is the app's encrypted-field wrapper. */
|
|
843
|
+
declare function isEncryptedFieldWrapper(value: unknown): value is WorkBuddyEncryptedField;
|
|
844
|
+
/**
|
|
845
|
+
* The at-rest key id for a derived 32-byte key: the first 16 hex characters of
|
|
846
|
+
* its SHA-256. This is what the envelope's `keyId` is checked against, so a
|
|
847
|
+
* mismatched key fails loudly instead of returning garbage.
|
|
848
|
+
*/
|
|
849
|
+
declare function deriveAtRestKeyId(key: Buffer): string;
|
|
850
|
+
/**
|
|
851
|
+
* Derive the 32-byte field key from the app's key payload JSON.
|
|
852
|
+
*
|
|
853
|
+
* The app hashes the payload's base64 STRING — not its decoded bytes — so the
|
|
854
|
+
* same spelling is required here; hashing the decoded secret would produce a
|
|
855
|
+
* different key and every field would fail to open.
|
|
856
|
+
*/
|
|
857
|
+
declare function deriveAtRestKey(payloadJson: string): Buffer;
|
|
858
|
+
/**
|
|
859
|
+
* Open one encrypted field with a derived key and return its plaintext.
|
|
860
|
+
*
|
|
861
|
+
* Throws when the envelope is malformed, belongs to another key, or fails
|
|
862
|
+
* authentication — a GCM tag mismatch is the signal that the transcript or the
|
|
863
|
+
* key is wrong, and it must never degrade into a truncated token.
|
|
864
|
+
*/
|
|
865
|
+
declare function openEncryptedField(field: WorkBuddyEncryptedField, key: Buffer): string;
|
|
866
|
+
/**
|
|
867
|
+
* The executable inside a macOS app bundle, read from the bundle's own
|
|
868
|
+
* `Info.plist`.
|
|
869
|
+
*
|
|
870
|
+
* The binary is NOT reliably named after the app: the WorkBuddy bundles ship
|
|
871
|
+
* with `CFBundleExecutable` set to `Electron`, so a path assembled as
|
|
872
|
+
* `<bundle>/Contents/MacOS/WorkBuddy` does not exist and the app looks absent
|
|
873
|
+
* even when it is installed in the default location. Because the bundle
|
|
874
|
+
* documents the real name, asking it is both correct and robust to a future
|
|
875
|
+
* build that renames the binary.
|
|
876
|
+
*
|
|
877
|
+
* Returns undefined when the plist is absent, unreadable, or carries no usable
|
|
878
|
+
* name — never a guessed path, so a caller can keep probing.
|
|
879
|
+
*/
|
|
880
|
+
declare function macosBundleExecutable(bundle: string): string | undefined;
|
|
881
|
+
/**
|
|
882
|
+
* Candidate paths of the WorkBuddy desktop executable, in probe order.
|
|
883
|
+
*
|
|
884
|
+
* The Windows build is the one that encrypts credentials, so Windows leads;
|
|
885
|
+
* the macOS bundles are listed because the same native module ships there and
|
|
886
|
+
* the encryption policy is enabled on macOS builds too (observed from 5.6.x),
|
|
887
|
+
* and `undefined` entries (an unset env variable) are dropped.
|
|
888
|
+
*
|
|
889
|
+
* On macOS the executable name comes from each bundle (see
|
|
890
|
+
* {@link macosBundleExecutable}) rather than being assembled from the app name.
|
|
891
|
+
*
|
|
892
|
+
* `readBundleExecutable` is injectable, in the same spirit as `platform`/`home`/
|
|
893
|
+
* `env`: the macOS branch consults the real filesystem, so without a seam the
|
|
894
|
+
* expected candidates would depend on whether the host machine happens to have
|
|
895
|
+
* the app installed — and the test would pass on a developer's Mac while
|
|
896
|
+
* failing in CI.
|
|
897
|
+
*/
|
|
898
|
+
declare function workbuddyAppExecutableCandidates(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv, readBundleExecutable?: (bundle: string) => string | undefined): string[];
|
|
899
|
+
/**
|
|
900
|
+
* Whether a bundle identifies itself as the WorkBuddy desktop app.
|
|
901
|
+
*
|
|
902
|
+
* The match is on dot boundaries, so a hypothetical `com.workbuddyish` cannot
|
|
903
|
+
* pass as `com.workbuddy`.
|
|
904
|
+
*
|
|
905
|
+
* An unreadable or identifier-less plist is treated as NOT WorkBuddy: refusing
|
|
906
|
+
* a candidate only costs a fallback to another path, whereas accepting the
|
|
907
|
+
* wrong one would execute an unrelated application.
|
|
908
|
+
*/
|
|
909
|
+
declare function isWorkbuddyBundle(bundle: string): boolean;
|
|
910
|
+
/**
|
|
911
|
+
* Bundles of the desktop app found one level BELOW a macOS applications
|
|
912
|
+
* directory.
|
|
913
|
+
*
|
|
914
|
+
* Users do file apps into subfolders (`/Applications/IDE/WorkBuddy.app`), and
|
|
915
|
+
* a hardcoded `/Applications/<name>` then reports the app as missing while it
|
|
916
|
+
* is installed and signed in. The scan is deliberately ONE level deep and
|
|
917
|
+
* matches the known bundle names only, so it stays predictable and cheap; each
|
|
918
|
+
* candidate is then confirmed by {@link isWorkbuddyBundle} before use.
|
|
919
|
+
*
|
|
920
|
+
* Returns [] when the parent is absent or unreadable — a missing directory is
|
|
921
|
+
* the normal case, not an error.
|
|
922
|
+
*/
|
|
923
|
+
declare function macosNestedAppBundles(parent: string): string[];
|
|
924
|
+
/**
|
|
925
|
+
* The first candidate that exists as a file, or undefined when the desktop app
|
|
926
|
+
* is not installed where this platform expects it.
|
|
927
|
+
*/
|
|
928
|
+
declare function findWorkbuddyAppExecutable(platform?: NodeJS.Platform, home?: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
929
|
+
/**
|
|
930
|
+
* Ask the installed desktop app for its key payload by running its own binary
|
|
931
|
+
* as plain Node (`ELECTRON_RUN_AS_NODE`) and calling the native binding.
|
|
932
|
+
*
|
|
933
|
+
* The binding is the app's own public surface for this value, so the plugin
|
|
934
|
+
* never has to carry a copy of a build-specific constant: it asks the very
|
|
935
|
+
* build that wrote the file. The child is given no stdin and a hard timeout,
|
|
936
|
+
* and its stdout is the only thing read.
|
|
937
|
+
*/
|
|
938
|
+
declare function fetchAtRestKeyPayload(executable: string): Promise<string>;
|
|
939
|
+
/**
|
|
940
|
+
* The desktop app's at-rest field key, or undefined when it cannot be obtained
|
|
941
|
+
* (app not installed, an older build without the native module, or a future
|
|
942
|
+
* build that rotates the payload). Cached after the first success so the app is
|
|
943
|
+
* spawned at most once per process; a failure is retried on the next call,
|
|
944
|
+
* because the user may install or start the app between reads.
|
|
945
|
+
*/
|
|
946
|
+
declare function readAtRestKey(): Promise<Buffer | undefined>;
|
|
947
|
+
/** Drop the cached key; tests and diagnostics only. */
|
|
948
|
+
declare function clearAtRestKeyCache(): void;
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/credential-recovery.d.ts
|
|
951
|
+
/** What the user can do about a refused credential. */
|
|
952
|
+
interface WorkBuddyCredentialRecovery {
|
|
953
|
+
/**
|
|
954
|
+
* Another local account answered the upstream during this recovery, so
|
|
955
|
+
* switching to it is a fix that has been verified — not a guess.
|
|
956
|
+
*/
|
|
957
|
+
usableAccount?: {
|
|
958
|
+
accountId: string;
|
|
959
|
+
accountName: string;
|
|
960
|
+
};
|
|
961
|
+
/**
|
|
962
|
+
* Whether signing in again is the only remaining fix: no other local account
|
|
963
|
+
* exists at all, so there is nothing to switch to.
|
|
964
|
+
*/
|
|
965
|
+
reloginRequired: boolean;
|
|
966
|
+
}
|
|
967
|
+
/** One account as the recovery path needs to see it. */
|
|
968
|
+
interface WorkBuddyRecoveryCandidate {
|
|
969
|
+
id: string;
|
|
970
|
+
accountName: string;
|
|
971
|
+
}
|
|
972
|
+
/** Reads one account's credential for probing, without changing the selection. */
|
|
973
|
+
interface WorkBuddyProbeStore {
|
|
974
|
+
accounts(): Promise<readonly WorkBuddyRecoveryCandidate[]>;
|
|
975
|
+
credentialFor(accountId: string): Promise<WorkBuddyCredential | undefined>;
|
|
976
|
+
}
|
|
977
|
+
/** Constructor options for {@link createAccountUsabilityProbe}. */
|
|
978
|
+
interface WorkBuddyUsabilityProbeOptions {
|
|
979
|
+
/** The credential store for one region (its selection is never touched). */
|
|
980
|
+
store(region: WorkBuddyRegion): WorkBuddyProbeStore;
|
|
981
|
+
/** The upstream client; only its cheap read-only calls are used. */
|
|
982
|
+
client: Pick<WorkBuddyUpstreamClient, 'fetchCheckinStatus'>;
|
|
983
|
+
/**
|
|
984
|
+
* How long a probe verdict is reused. The card polls the usage route, so
|
|
985
|
+
* without this a broken selection would re-probe every account on every poll.
|
|
986
|
+
*/
|
|
987
|
+
ttlMs?: number;
|
|
988
|
+
/** Injectable clock, for tests. */
|
|
989
|
+
now?: () => number;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Cached "is this account still accepted upstream?" probe.
|
|
993
|
+
*
|
|
994
|
+
* The cache key includes the credential's own `lastRefreshAtMs`, so a fresh
|
|
995
|
+
* sign-in (which rewrites the file's issuance time) invalidates a stale verdict
|
|
996
|
+
* automatically — a rejection recorded before the user signed in again cannot
|
|
997
|
+
* keep labelling the account unusable afterwards, and no explicit invalidation
|
|
998
|
+
* is needed.
|
|
999
|
+
*/
|
|
1000
|
+
declare function createAccountUsabilityProbe(options: WorkBuddyUsabilityProbeOptions): (region: WorkBuddyRegion, account: WorkBuddyRecoveryCandidate) => Promise<boolean>;
|
|
1001
|
+
/**
|
|
1002
|
+
* Decide what to tell the user after the upstream refused the selected
|
|
1003
|
+
* credential: switch to a verified-usable account, or sign in again.
|
|
1004
|
+
*
|
|
1005
|
+
* The two answers are mutually exclusive by construction. `reloginRequired` is
|
|
1006
|
+
* set ONLY when there is no other local account to switch to — never as a
|
|
1007
|
+
* fallback for "the probe did not verify anything", because that would repeat
|
|
1008
|
+
* the misdirection this module exists to remove. When other accounts exist but
|
|
1009
|
+
* none was verified, both fields stay empty and the card says so honestly.
|
|
1010
|
+
*/
|
|
1011
|
+
declare function resolveCredentialRecovery(options: {
|
|
1012
|
+
region: WorkBuddyRegion;
|
|
1013
|
+
store: WorkBuddyProbeStore;
|
|
1014
|
+
rejectedAccountId?: string;
|
|
1015
|
+
/** Verifies whether one account is still accepted; see the probe factory. */
|
|
1016
|
+
probe: (region: WorkBuddyRegion, account: WorkBuddyRecoveryCandidate) => Promise<boolean>;
|
|
1017
|
+
}): Promise<WorkBuddyCredentialRecovery>;
|
|
1018
|
+
//#endregion
|
|
625
1019
|
//#region src/host-heartbeat.d.ts
|
|
626
1020
|
/**
|
|
627
1021
|
* Host-side heartbeat: a small JSON file written under `$DSH_HOME` once the
|
|
@@ -725,6 +1119,36 @@ declare function withWorkBuddyRegion(path: string, region: WorkBuddyWebRegion):
|
|
|
725
1119
|
* answer 400 instead of guessing.
|
|
726
1120
|
*/
|
|
727
1121
|
declare function regionOfStatusUrl(url: string): WorkBuddyWebRegion | undefined;
|
|
1122
|
+
/**
|
|
1123
|
+
* Whether one region's provider is switched on. Opt-out semantics: only an
|
|
1124
|
+
* explicit `false` disables it, so a config written before this switch existed
|
|
1125
|
+
* (and the pre-region-split flat fields, which never carry `enabled`) keep both
|
|
1126
|
+
* providers running exactly as before. The Host reads the same rule through
|
|
1127
|
+
* `regionStateOf`, so card and Host can never disagree about a region's state.
|
|
1128
|
+
*
|
|
1129
|
+
* `value` may be the whole settings section or the `regions` map (see
|
|
1130
|
+
* {@link regionsMapOf}).
|
|
1131
|
+
*/
|
|
1132
|
+
declare function regionEnabledOf(value: unknown, region: WorkBuddyWebRegion): boolean;
|
|
1133
|
+
/** Build the next `regions` settings value for a signed-in tab's save. */
|
|
1134
|
+
declare function nextRegionSlots<Slot extends object>(regions: unknown, region: WorkBuddyWebRegion, slot: Slot): Record<string, unknown>;
|
|
1135
|
+
/**
|
|
1136
|
+
* Build the next `regions` settings value for a provider on/off toggle. ONLY
|
|
1137
|
+
* the target region's `enabled` flag changes: every other field of that slot
|
|
1138
|
+
* (its directory, selection, image opt-ins, context budgets) and every other
|
|
1139
|
+
* region's slot are carried over verbatim, so switching a provider off never
|
|
1140
|
+
* discards the user's model picks and switching it back on restores them.
|
|
1141
|
+
*
|
|
1142
|
+
* This is deliberately separate from {@link nextRegionSlots}: that helper
|
|
1143
|
+
* writes a whole slot from a signed-in tab's draft, while this one must work
|
|
1144
|
+
* for a region that is signed OUT — which is precisely the region a user wants
|
|
1145
|
+
* to switch off (no international install, no international account).
|
|
1146
|
+
*
|
|
1147
|
+
* `value` may be the whole settings section or the `regions` map; the RETURN
|
|
1148
|
+
* value is always the `regions` map, i.e. exactly what `settingsScope.set(
|
|
1149
|
+
* 'regions', ...)` needs.
|
|
1150
|
+
*/
|
|
1151
|
+
declare function nextRegionEnabled(value: unknown, region: WorkBuddyWebRegion, enabled: boolean): Record<string, unknown>;
|
|
728
1152
|
/** One credit package as the upstream returns it, node-free. */
|
|
729
1153
|
interface WorkBuddyWebCreditPackage {
|
|
730
1154
|
packageName: string;
|
|
@@ -759,6 +1183,30 @@ interface WorkBuddyWebCheckin {
|
|
|
759
1183
|
streakBonusCredit: number;
|
|
760
1184
|
claimButtonText?: string;
|
|
761
1185
|
}
|
|
1186
|
+
/**
|
|
1187
|
+
* What the user can do about a credential the upstream refused.
|
|
1188
|
+
*
|
|
1189
|
+
* Two different fixes hide behind one 401, and naming the wrong one is worse
|
|
1190
|
+
* than saying nothing: with a stale account SELECTED but a healthy sign-in
|
|
1191
|
+
* sitting right there, "sign in again" sends the user to re-authenticate — which
|
|
1192
|
+
* changes nothing, because the credentials were never the problem.
|
|
1193
|
+
*/
|
|
1194
|
+
interface WorkBuddyWebRecovery {
|
|
1195
|
+
/**
|
|
1196
|
+
* Another local account answered the upstream during recovery, so switching
|
|
1197
|
+
* to it is a VERIFIED fix rather than a suggestion.
|
|
1198
|
+
*/
|
|
1199
|
+
usableAccount?: {
|
|
1200
|
+
accountId: string;
|
|
1201
|
+
accountName: string;
|
|
1202
|
+
};
|
|
1203
|
+
/**
|
|
1204
|
+
* Signing in again is the only remaining fix: this region has no other local
|
|
1205
|
+
* account to switch to. Set only in that case — never as a fallback for
|
|
1206
|
+
* "nothing could be verified".
|
|
1207
|
+
*/
|
|
1208
|
+
reloginRequired: boolean;
|
|
1209
|
+
}
|
|
762
1210
|
/** Editable WorkBuddy model row rendered by the plugin-owned settings card. */
|
|
763
1211
|
interface WorkBuddyWebModel {
|
|
764
1212
|
id: string;
|
|
@@ -789,14 +1237,39 @@ declare function toPersistedWorkBuddyModel(model: WorkBuddyWebModel): Omit<WorkB
|
|
|
789
1237
|
/** One selectable local account, token-free. */
|
|
790
1238
|
interface WorkBuddyWebAccount {
|
|
791
1239
|
id: string;
|
|
1240
|
+
/**
|
|
1241
|
+
* The account's human name, or `''` when the desktop app recorded none.
|
|
1242
|
+
* The card renders its own placeholder for the empty case.
|
|
1243
|
+
*/
|
|
792
1244
|
accountName: string;
|
|
793
|
-
uin?: string;
|
|
794
1245
|
domain: string;
|
|
795
1246
|
source: 'desktop' | 'dsh';
|
|
796
1247
|
tokenExpiresAtMs: number;
|
|
797
1248
|
selected: boolean;
|
|
798
1249
|
}
|
|
799
1250
|
type WorkBuddyWebPackage = WorkBuddyWebCreditPackage;
|
|
1251
|
+
/**
|
|
1252
|
+
* One probed candidate path and why it yielded no account.
|
|
1253
|
+
*
|
|
1254
|
+
* Safe to send to the browser: a path, its source, and a cause. No token
|
|
1255
|
+
* material, and no content read out of the files beyond an error string.
|
|
1256
|
+
*
|
|
1257
|
+
* `encrypted` exists because WorkBuddy (unlike a plain JSON-token app) can
|
|
1258
|
+
* refuse a correctly signed-in user: Windows builds encrypt the token fields,
|
|
1259
|
+
* and opening them needs the desktop app present to hand over its at-rest key.
|
|
1260
|
+
* Telling that user to "sign in again" is wrong — they already are.
|
|
1261
|
+
*
|
|
1262
|
+
* `wrong-region` is the other WorkBuddy-specific one: the file holds a valid
|
|
1263
|
+
* sign-in for the OTHER tab's region, so this tab filters it out of the account
|
|
1264
|
+
* list. Without this entry the file was reported nowhere at all, which both
|
|
1265
|
+
* undercounted "paths checked" and hid the user's real sign-in.
|
|
1266
|
+
*/
|
|
1267
|
+
interface WorkBuddyWebSearchPath {
|
|
1268
|
+
path: string;
|
|
1269
|
+
source: 'desktop' | 'dsh';
|
|
1270
|
+
reason: 'missing' | 'unreadable' | 'invalid' | 'encrypted' | 'wrong-region';
|
|
1271
|
+
message?: string;
|
|
1272
|
+
}
|
|
800
1273
|
/**
|
|
801
1274
|
* Region of the signed-in credential: the CN app (`codebuddy.cn` /
|
|
802
1275
|
* `workbuddy.cn`) or the international WorkBuddy AI app (`workbuddy.ai`).
|
|
@@ -822,19 +1295,36 @@ type WorkBuddyWebUsage =
|
|
|
822
1295
|
{
|
|
823
1296
|
status: 'signed-out';
|
|
824
1297
|
accounts: readonly WorkBuddyWebAccount[];
|
|
1298
|
+
/** Whether this region's provider is currently offered to DSH. */
|
|
1299
|
+
enabled?: boolean;
|
|
825
1300
|
message?: string;
|
|
826
1301
|
/** The persisted account id matches no local account. */
|
|
827
1302
|
selectionLost?: boolean;
|
|
828
1303
|
/** A saved per-region choice is in effect (false = following the app). */
|
|
829
1304
|
selectionExplicit: boolean;
|
|
1305
|
+
/**
|
|
1306
|
+
* The paths this region's store probed, and why each yielded nothing.
|
|
1307
|
+
*
|
|
1308
|
+
* Present only on the "nothing was found at all" branch — it is the
|
|
1309
|
+
* explanation for a state that is otherwise a dead end. A missing candidate
|
|
1310
|
+
* (`missing`) is normal noise on any machine and the card filters those out
|
|
1311
|
+
* of its default view; the interesting ones are `unreadable`, `invalid`,
|
|
1312
|
+
* and especially `encrypted`.
|
|
1313
|
+
*/
|
|
1314
|
+
searched?: readonly WorkBuddyWebSearchPath[];
|
|
830
1315
|
} | {
|
|
831
1316
|
status: 'signed-in';
|
|
832
1317
|
accountId: string;
|
|
1318
|
+
/**
|
|
1319
|
+
* The account's human name, or `''` when the desktop app recorded none.
|
|
1320
|
+
* Never an identifier — see {@link WorkBuddyWebAccount.accountName}.
|
|
1321
|
+
*/
|
|
833
1322
|
accountName: string;
|
|
834
|
-
uin?: string;
|
|
835
1323
|
domain?: string;
|
|
836
1324
|
/** Which per-region model directory and selection this account owns. */
|
|
837
1325
|
region: WorkBuddyWebRegion;
|
|
1326
|
+
/** Whether this region's provider is currently offered to DSH. */
|
|
1327
|
+
enabled?: boolean;
|
|
838
1328
|
source?: 'desktop' | 'dsh';
|
|
839
1329
|
tokenExpiresAtMs: number;
|
|
840
1330
|
/** A saved per-region choice is in effect (false = following the app). */
|
|
@@ -847,6 +1337,14 @@ type WorkBuddyWebUsage =
|
|
|
847
1337
|
creditsError?: string;
|
|
848
1338
|
checkin?: WorkBuddyWebCheckin;
|
|
849
1339
|
checkinError?: string;
|
|
1340
|
+
/**
|
|
1341
|
+
* The upstream refused the credential itself (a 401/403), as opposed to a
|
|
1342
|
+
* transient upstream fault. Distinguishes "your token is not usable" from
|
|
1343
|
+
* "the request failed", which need opposite advice.
|
|
1344
|
+
*/
|
|
1345
|
+
credentialRejected?: boolean;
|
|
1346
|
+
/** Present only alongside {@link credentialRejected}. */
|
|
1347
|
+
recovery?: WorkBuddyWebRecovery;
|
|
850
1348
|
} | {
|
|
851
1349
|
status: 'error';
|
|
852
1350
|
message: string;
|
|
@@ -873,6 +1371,12 @@ interface WorkBuddyStatusRouteOptions {
|
|
|
873
1371
|
contextBudgets(region: WorkBuddyRegion): Readonly<Record<string, number | undefined>>;
|
|
874
1372
|
/** Re-read the live catalog of one region from the upstream. */
|
|
875
1373
|
discoverModels?(region: WorkBuddyRegion, signal?: AbortSignal): Promise<readonly WorkBuddyModelInfo[]>;
|
|
1374
|
+
/**
|
|
1375
|
+
* Whether the requested region's provider is currently offered to DSH. The
|
|
1376
|
+
* card renders this as the tab's on/off checkbox, so the switch reflects the
|
|
1377
|
+
* committed settings value rather than a local guess.
|
|
1378
|
+
*/
|
|
1379
|
+
regionEnabled(region: WorkBuddyRegion): boolean;
|
|
876
1380
|
/**
|
|
877
1381
|
* Report whether a region still has at least one local sign-in.
|
|
878
1382
|
*
|
|
@@ -883,6 +1387,15 @@ interface WorkBuddyStatusRouteOptions {
|
|
|
883
1387
|
* no scan of its own.
|
|
884
1388
|
*/
|
|
885
1389
|
regionUsable?(region: WorkBuddyRegion, usable: boolean): void;
|
|
1390
|
+
/**
|
|
1391
|
+
* Verify whether one local account is still accepted by the upstream.
|
|
1392
|
+
*
|
|
1393
|
+
* Consulted ONLY after the selected credential has been refused, to tell
|
|
1394
|
+
* "switch accounts" apart from "sign in again". Left undefined, nothing is
|
|
1395
|
+
* claimed usable and the card falls back to the re-login advice that needs no
|
|
1396
|
+
* probe.
|
|
1397
|
+
*/
|
|
1398
|
+
accountUsable?(region: WorkBuddyRegion, account: WorkBuddyRecoveryCandidate): Promise<boolean>;
|
|
886
1399
|
}
|
|
887
1400
|
/**
|
|
888
1401
|
* Assemble one region's card document. `region` is the tab the card is on;
|
|
@@ -908,6 +1421,15 @@ declare const inject: string[];
|
|
|
908
1421
|
declare const WORKBUDDY_SETTINGS_NS: SettingsNamespace;
|
|
909
1422
|
/** One region's model directory and the user's selection within it. */
|
|
910
1423
|
interface WorkBuddyRegionState {
|
|
1424
|
+
/**
|
|
1425
|
+
* Whether this region's provider is switched on. Opt-out: only an explicit
|
|
1426
|
+
* `false` disables it, so a config predating this switch keeps both providers
|
|
1427
|
+
* running. A disabled region is fully withdrawn from the harness — its adapter
|
|
1428
|
+
* route and its configurable-provider entry both hold zero routes, so it
|
|
1429
|
+
* disappears from DSH's model picker instead of lingering as an unselectable
|
|
1430
|
+
* row (see `syncRegionRegistration`).
|
|
1431
|
+
*/
|
|
1432
|
+
enabled?: boolean;
|
|
911
1433
|
/** The last-refreshed directory for this region; what the card displays. */
|
|
912
1434
|
lastCatalog?: WorkBuddyModelInfo[];
|
|
913
1435
|
/** The user's selection in this region, as model ids. */
|
|
@@ -964,6 +1486,15 @@ declare const Config: z<Config>;
|
|
|
964
1486
|
* picks.
|
|
965
1487
|
*/
|
|
966
1488
|
declare function regionStateOf(config: Config, region: WorkBuddyRegion): WorkBuddyRegionState;
|
|
1489
|
+
/**
|
|
1490
|
+
* Whether one region's provider is switched on. Opt-out semantics: only an
|
|
1491
|
+
* explicit `false` disables it, so every config written before this switch
|
|
1492
|
+
* existed — including the pre-region-split flat fields, which never carry
|
|
1493
|
+
* `enabled` — keeps both providers running exactly as before. The card reads the
|
|
1494
|
+
* same rule through `regionEnabledOf`, so the two halves can never disagree
|
|
1495
|
+
* about a region's state.
|
|
1496
|
+
*/
|
|
1497
|
+
declare function regionEnabled(config: Config, region: WorkBuddyRegion): boolean;
|
|
967
1498
|
/**
|
|
968
1499
|
* The account id a region should select, or `undefined` for the documented
|
|
969
1500
|
* default: follow whatever the WorkBuddy app is currently signed in as.
|
|
@@ -1014,4 +1545,4 @@ declare function legacyAttributionRegion(value: Config, accountsFor: (region: Wo
|
|
|
1014
1545
|
*/
|
|
1015
1546
|
declare function apply(ctx: Context, config: Config): void;
|
|
1016
1547
|
//#endregion
|
|
1017
|
-
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 };
|
|
1548
|
+
export { CREDENTIAL_REJECTED_CODE, Config, ENCRYPTED_CREDENTIAL_CODE, 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, WorkBuddyEncryptedCredentialError, 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, isEncryptedCredentialError, isEncryptedFieldWrapper, isHeartbeatProcessAlive, isWorkbuddyBundle, legacyAttributionRegion, legacyWorkbuddyOwnAuthPath, macosBundleExecutable, macosNestedAppBundles, 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 };
|