dsh-connect-workbuddy 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -33,8 +33,22 @@ interface WorkBuddyAuthStatus {
33
33
  interface WorkBuddyStoreOptions {
34
34
  /** Explicit desktop auth-file path, overriding env and platform defaults. */
35
35
  desktopPath?: string;
36
- /** Explicit plugin-owned copy path, defaulting under `$DSH_HOME`. */
36
+ /**
37
+ * Explicit plugin-owned copy path, overriding the per-region default.
38
+ * Injectable so the copy/refresh cycle is testable without a real machine.
39
+ */
37
40
  ownPath?: string;
41
+ /**
42
+ * Region this store serves. When set, only credentials whose login domain
43
+ * maps to this region are discovered, selected, or refreshed — the two
44
+ * regions' stores run side by side without seeing each other's accounts.
45
+ */
46
+ region?: WorkBuddyRegion;
47
+ /**
48
+ * Legacy single-copy path read as a migration source; defaults to the
49
+ * pre-dual-provider location. Injectable for tests.
50
+ */
51
+ legacyOwnPath?: string;
38
52
  /**
39
53
  * Auth directories to scan, overriding the platform defaults. Injectable so
40
54
  * the multi-account scan is testable without touching a real machine.
@@ -58,12 +72,22 @@ interface WorkBuddyAccountChoice {
58
72
  filePath: string;
59
73
  selected: boolean;
60
74
  }
61
- /** Basename of the plugin-owned credential copy inside the Harness home. */
75
+ /** Legacy single-copy basename (pre-dual-provider); kept as migration source. */
62
76
  declare const WORKBUDDY_AUTH_FILENAME = ".workbuddy-auth.json";
63
77
  /** Env variable that overrides the desktop auth-file location. */
64
78
  declare const WORKBUDDY_AUTH_FILE_ENV = "WORKBUDDY_AUTH_FILE";
65
- /** Plugin-owned copy path inside the Harness home. */
66
- declare function workbuddyOwnAuthPath(): string;
79
+ /**
80
+ * Plugin-owned copy path for one region inside the Harness home. Each
81
+ * region's store refreshes into its own file so two simultaneously signed-in
82
+ * regions never overwrite each other's refreshed token.
83
+ */
84
+ declare function workbuddyOwnAuthPath(region: WorkBuddyRegion): string;
85
+ /**
86
+ * Pre-dual-provider single-copy path. Still read as a migration source (a
87
+ * legacy credential serves the region it belongs to until that region's own
88
+ * first refresh writes the per-region file), and removed by `logout`.
89
+ */
90
+ declare function legacyWorkbuddyOwnAuthPath(): string;
67
91
  /**
68
92
  * Platform-default directories holding the WorkBuddy desktop app's auth file.
69
93
  *
@@ -110,12 +134,34 @@ declare function workbuddyAccountId(credential: Pick<WorkBuddyCredential, 'uin'
110
134
  declare class WorkBuddyCredentialStore {
111
135
  private readonly refresh;
112
136
  private readonly refreshMarginMs;
113
- private readonly ownPath;
137
+ private readonly region;
138
+ private readonly ownPathExplicit;
139
+ private readonly legacyOwnPath;
140
+ private readonly legacyOwnPathExplicit;
114
141
  private readonly authDirs;
115
142
  private desktopPathOverride;
116
143
  private accountId;
117
144
  private inflight;
118
145
  constructor(options: WorkBuddyStoreOptions);
146
+ /** Whether a credential's login domain belongs to this store's region. */
147
+ private matchesRegion;
148
+ /**
149
+ * The path this store refreshes into: the per-region file for a
150
+ * region-scoped store, the legacy single file otherwise, or an explicitly
151
+ * injected path in tests.
152
+ */
153
+ ownAuthPath(): string;
154
+ /**
155
+ * Every plugin-owned copy to read, most preferred first. A region-scoped
156
+ * store reads the legacy single copy as its migration source (readAll's
157
+ * region filter drops it when it carries the other region's credential); an
158
+ * unscoped store reads everything so diagnostics see both regions.
159
+ *
160
+ * With an explicitly injected own path the legacy source is read ONLY when
161
+ * it was injected too — a test that pins one file must not accidentally see
162
+ * the real machine's legacy copy.
163
+ */
164
+ private ownCandidates;
119
165
  /** Repoint the desktop file or directory; applies on the next read. */
120
166
  setDesktopPath(path: string | undefined): void;
121
167
  /** Select an account by id; tokens stay outside settings. */
@@ -126,8 +172,6 @@ declare class WorkBuddyCredentialStore {
126
172
  private resolveDesktopCandidates;
127
173
  /** The resolved desktop auth-file path, for diagnostics. */
128
174
  desktopAuthPath(): string | undefined;
129
- /** The plugin-owned copy path, for diagnostics. */
130
- ownAuthPath(): string;
131
175
  /**
132
176
  * Every auth file to scan: the live file plus the timestamped backups
133
177
  * WorkBuddy leaves beside it.
@@ -146,6 +190,10 @@ declare class WorkBuddyCredentialStore {
146
190
  /**
147
191
  * Read every local credential, deduplicated by account id. Files are
148
192
  * probed newest-first, so the first entry for an account is its freshest.
193
+ *
194
+ * A region-scoped store sees only its own region's credentials: the other
195
+ * region's accounts are invisible to selection, refresh, and status alike,
196
+ * which is what keeps the two regions' providers from cross-billing.
149
197
  */
150
198
  private readAll;
151
199
  /**
@@ -164,12 +212,22 @@ declare class WorkBuddyCredentialStore {
164
212
  resolve(): Promise<WorkBuddyCredential>;
165
213
  /** Read-only sign-in summary; never refreshes and never throws. */
166
214
  status(): Promise<WorkBuddyAuthStatus>;
167
- /** Remove the plugin-owned copy; the desktop files are untouched. */
215
+ /**
216
+ * Remove every plugin-owned copy this store could read (per-region file,
217
+ * legacy single file, and their lock siblings); the desktop files are
218
+ * untouched. A region store's logout therefore also clears the legacy
219
+ * migration source — deliberate: `logout` is the user's "forget what the
220
+ * plugin stored" action, not a per-account toggle.
221
+ */
168
222
  logout(): Promise<void>;
169
223
  private needsRefresh;
170
224
  private refreshNow;
171
225
  private saveOwn;
172
- private readOwn;
226
+ /**
227
+ * Every readable plugin-owned copy, in candidate order; absent or corrupt
228
+ * files are skipped rather than propagated.
229
+ */
230
+ private readOwns;
173
231
  /** Whether any candidate file exists as a regular file; diagnostics only. */
174
232
  desktopFilePresent(): Promise<boolean>;
175
233
  }
@@ -355,6 +413,12 @@ declare function deriveCatalog(catalog: readonly WorkBuddyModelInfo[], enabled:
355
413
  /** Mutable catalog shared by the shim's `/v1/models` and the adapter. */
356
414
  declare class WorkBuddyCatalog {
357
415
  private models;
416
+ /**
417
+ * @param region Seeds the static fallback for this region; each region's
418
+ * provider must never serve the other region's roster before its first
419
+ * live refresh lands.
420
+ */
421
+ constructor(region?: 'cn' | 'global');
358
422
  /** Current entries; the fallback list until the upstream answer lands. */
359
423
  current(): readonly WorkBuddyModelInfo[];
360
424
  /** Replace the list; callers invalidate their adapter snapshot after this. */
@@ -397,8 +461,16 @@ interface WorkBuddyShimOptions {
397
461
  declare function createWorkBuddyShim(options: WorkBuddyShimOptions): WorkBuddyShim;
398
462
  //#endregion
399
463
  //#region src/adapter.d.ts
400
- /** Provider route this bundle owns. */
464
+ /** Provider route this bundle owns for the domestic (CN) gateway. */
401
465
  declare const WORKBUDDY_PROVIDER = "workbuddy";
466
+ /** Provider route this bundle owns for the international gateway. */
467
+ declare const WORKBUDDY_GLOBAL_PROVIDER = "workbuddy-global";
468
+ /** The provider id each region registers as. */
469
+ declare const WORKBUDDY_PROVIDERS: Readonly<Record<WorkBuddyRegion, string>>;
470
+ /** Region a provider route id belongs to. */
471
+ declare function regionOfProvider(provider: string): WorkBuddyRegion | undefined;
472
+ /** Human-readable provider name, shown in the DSH model picker. */
473
+ declare const WORKBUDDY_PROVIDER_DISPLAY_NAMES: Readonly<Record<WorkBuddyRegion, string>>;
402
474
  /** Provider idle ceiling while one stream read is outstanding. */
403
475
  declare const WORKBUDDY_STREAM_IDLE_TIMEOUT_MS = 300000;
404
476
  /** Constructor dependencies. */
@@ -406,6 +478,10 @@ interface WorkBuddyAdapterOptions {
406
478
  shim: WorkBuddyShim;
407
479
  store: WorkBuddyCredentialStore;
408
480
  catalog: WorkBuddyCatalog;
481
+ /** Provider route id this instance serves; defaults to the CN route. */
482
+ provider?: string;
483
+ /** pi-ai provider name and profile display name; defaults to the CN name. */
484
+ displayName?: string;
409
485
  /** Resolve the durable attachment service at request time, when present. */
410
486
  resolveAttachments?: () => AttachmentStore | undefined;
411
487
  }
@@ -529,6 +605,21 @@ declare const WORKBUDDY_MODELS_REFRESH_PATH = "/plugins/dsh-connect-workbuddy/mo
529
605
  declare const WORKBUDDY_ACCOUNTS_REFRESH_PATH = "/plugins/dsh-connect-workbuddy/accounts/refresh";
530
606
  /** Plugin-owned daily check-in action endpoint. */
531
607
  declare const WORKBUDDY_CHECKIN_PATH = "/plugins/dsh-connect-workbuddy/checkin";
608
+ /** Query parameter naming the region a card request addresses. */
609
+ declare const WORKBUDDY_REGION_PARAM = "region";
610
+ /** Every region, in card tab order. */
611
+ declare const WORKBUDDY_REGIONS: readonly WorkBuddyWebRegion[];
612
+ /**
613
+ * Address one region's status route. The two regions are separate provider
614
+ * stacks; every card request carries the region whose tab the user is on.
615
+ */
616
+ declare function withWorkBuddyRegion(path: string, region: WorkBuddyWebRegion): string;
617
+ /**
618
+ * Read the region parameter off a status-route URL. Absent means the domestic
619
+ * tab (`cn`); a present-but-unknown value returns undefined so the route can
620
+ * answer 400 instead of guessing.
621
+ */
622
+ declare function regionOfStatusUrl(url: string): WorkBuddyWebRegion | undefined;
532
623
  /** One credit package as the upstream returns it, node-free. */
533
624
  interface WorkBuddyWebCreditPackage {
534
625
  packageName: string;
@@ -638,30 +729,33 @@ type WorkBuddyWebUsage = {
638
729
  //#region src/web-status.d.ts
639
730
  /** Constructor dependencies. */
640
731
  interface WorkBuddyStatusRouteOptions {
641
- store: WorkBuddyCredentialStore;
732
+ /** The region-scoped credential store backing each region's requests. */
733
+ store(region: WorkBuddyRegion): WorkBuddyCredentialStore;
642
734
  client: Pick<WorkBuddyUpstreamClient, 'fetchCredits' | 'fetchCheckinStatus' | 'claimDailyCheckin'>;
643
735
  /**
644
- * The selected region's last-refreshed model directory (unfiltered) for card
645
- * display. Region-scoped because the CN and international apps expose
736
+ * The requested region's last-refreshed model directory (unfiltered) for
737
+ * card display. Region-scoped because the CN and international apps expose
646
738
  * different rosters; showing one region's directory on the other account is
647
739
  * the bug this parameter exists to prevent.
648
740
  */
649
741
  displayModels(region: WorkBuddyRegion): readonly WorkBuddyModelInfo[];
650
- /** The selected region's selection, stored as model ids. */
742
+ /** The requested region's selection, stored as model ids. */
651
743
  enabledModelIds(region: WorkBuddyRegion): readonly string[];
652
- /** Model ids the user opted into image input, for the selected region. */
744
+ /** Model ids the user opted into image input, for the requested region. */
653
745
  imageModelIds(region: WorkBuddyRegion): readonly string[];
654
- /** Saved local DSH context budgets by model id, for the selected region. */
746
+ /** Saved local DSH context budgets by model id, for the requested region. */
655
747
  contextBudgets(region: WorkBuddyRegion): Readonly<Record<string, number | undefined>>;
656
- /** Re-read the live catalog from the upstream. */
657
- discoverModels?(signal?: AbortSignal): Promise<readonly WorkBuddyModelInfo[]>;
748
+ /** Re-read the live catalog of one region from the upstream. */
749
+ discoverModels?(region: WorkBuddyRegion, signal?: AbortSignal): Promise<readonly WorkBuddyModelInfo[]>;
658
750
  }
659
751
  /**
660
- * Assemble the card's usage document. Sign-in state is read-only; credit is a
661
- * live billing answer whose failure degrades to `creditsError` rather than
662
- * failing the whole document.
752
+ * Assemble one region's card document. `region` is the tab the card is on;
753
+ * the region-scoped store already answers with only that region's accounts,
754
+ * so the document's model slots and account list are that region's by
755
+ * construction. Sign-in state is read-only; credit is a live billing answer
756
+ * whose failure degrades to `creditsError` rather than failing the document.
663
757
  */
664
- declare function workBuddyWebStatus(deps: WorkBuddyStatusRouteOptions): Promise<WorkBuddyWebUsage>;
758
+ declare function workBuddyWebStatus(deps: WorkBuddyStatusRouteOptions, region: WorkBuddyRegion): Promise<WorkBuddyWebUsage>;
665
759
  /**
666
760
  * Mount the read-only routes on a context where `webServer` is available.
667
761
  * The caller uses `ctx.inject(['webServer'], ...)`, so Desktop startup order
@@ -691,8 +785,18 @@ interface WorkBuddyRegionState {
691
785
  interface Config {
692
786
  /** Explicit WorkBuddy desktop auth-file path, overriding env and platform defaults. */
693
787
  authFile?: string;
694
- /** Stable local account selector; tokens remain outside settings. */
788
+ /**
789
+ * @deprecated Legacy single-slot account selector from before the dual
790
+ * provider split. It is attributed to whichever region the account actually
791
+ * belongs to (resolved once at startup from the local account scan); new
792
+ * writes go to {@link Config.accounts}.
793
+ */
695
794
  accountId?: string;
795
+ /**
796
+ * Per-region account selections, keyed `cn` | `global`. Each region's tab
797
+ * writes its own slot; tokens remain outside settings.
798
+ */
799
+ accounts?: Partial<Record<WorkBuddyRegion, string>>;
696
800
  /**
697
801
  * Per-region model state, keyed `cn` | `global`. The CN app and the
698
802
  * international WorkBuddy AI app expose different rosters, so each keeps its
@@ -725,11 +829,12 @@ declare const Config: z<Config>;
725
829
  */
726
830
  declare function regionStateOf(config: Config, region: WorkBuddyRegion): WorkBuddyRegionState;
727
831
  /**
728
- * Start the loopback endpoint, register the `workbuddy` provider, and
729
- * refresh the model catalog from the upstream once credentials allow it.
730
- * The static fallback catalog serves from the first moment, so an offline
731
- * upstream never leaves the provider empty.
832
+ * Start both regions' loopback endpoints, register the `workbuddy` (CN) and
833
+ * `workbuddy-global` (international) providers, and refresh each region's
834
+ * model catalog from the upstream once that region's credentials allow it.
835
+ * The static fallback catalogs serve from the first moment, so an offline
836
+ * upstream never leaves a provider empty.
732
837
  */
733
838
  declare function apply(ctx: Context, config: Config): void;
734
839
  //#endregion
735
- 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_HOST_HEARTBEAT_FILENAME, WORKBUDDY_MODELS_REFRESH_PATH, WORKBUDDY_PROVIDER, 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 WorkBuddyWebUsage, apply, authFileName, classifyUpstreamError, clearHostHeartbeat, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthDirs, defaultDesktopAuthPath, deriveCatalog, fallbackModelsFor, inject, isHeartbeatProcessAlive, name, parseCreditMultiplier, parseReasoning, parseUpstreamModel, parseWorkBuddyAuth, prepareChatBody, processStartTimeMs, readHostHeartbeat, regionOf, regionStateOf, registerWorkBuddyStatusRoute, toPersistedWorkBuddyModel, workBuddyDisplayName, workBuddyModelInput, workBuddyThinkingLevelMap, workBuddyWebStatus, workbuddyAccountId, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, writeHostHeartbeat };
840
+ 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, legacyWorkbuddyOwnAuthPath, name, parseCreditMultiplier, parseReasoning, parseUpstreamModel, parseWorkBuddyAuth, prepareChatBody, processStartTimeMs, readHostHeartbeat, regionOf, regionOfProvider, regionOfStatusUrl, regionStateOf, registerWorkBuddyStatusRoute, toPersistedWorkBuddyModel, withWorkBuddyRegion, workBuddyDisplayName, workBuddyModelInput, workBuddyThinkingLevelMap, workBuddyWebStatus, workbuddyAccountId, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, writeHostHeartbeat };