dsh-workbuddy-connect 0.4.0 → 0.5.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/README.en.md +27 -9
- package/README.md +28 -9
- package/lib/bin.js +71 -23
- package/lib/client.js +1123 -970
- package/lib/index.d.ts +402 -19
- package/lib/index.js +733 -183
- package/lib/{host-heartbeat-0UAWqWac.js → variants-GgLTJgZs.js} +1896 -1002
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -4,6 +4,76 @@ import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
|
4
4
|
import { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
import { SettingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
6
6
|
import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
7
|
+
//#region src/app-version.d.ts
|
|
8
|
+
/** Basename of the saved version under `$DSH_HOME`. */
|
|
9
|
+
declare const WORKBUDDY_APP_VERSION_FILENAME = ".workbuddy-ai-version.json";
|
|
10
|
+
/** Where the version came from, for `doctor` output. */
|
|
11
|
+
type WorkBuddyAppVersionSource = 'installed' | 'saved' | 'fallback';
|
|
12
|
+
/** Resolved version plus provenance. */
|
|
13
|
+
interface AppVersionInfo {
|
|
14
|
+
version: string;
|
|
15
|
+
source: WorkBuddyAppVersionSource;
|
|
16
|
+
/** Basename of the App bundle the version was read from, when installed. */
|
|
17
|
+
bundle?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Whether a string is safe to interpolate into an HTTP header.
|
|
21
|
+
*
|
|
22
|
+
* Strict on purpose: the value reaches a header, so anything that could split
|
|
23
|
+
* the request (CR, LF, spaces beyond the separator) or inject a second UA
|
|
24
|
+
* token must never pass. The App's own version is always `N.N.N` or `N.N.N.N`.
|
|
25
|
+
*/
|
|
26
|
+
declare function validAppVersion(value: unknown): value is string;
|
|
27
|
+
/**
|
|
28
|
+
* Read `CFBundleShortVersionString` out of an `Info.plist`.
|
|
29
|
+
*
|
|
30
|
+
* Parsed as XML rather than grepped, because the plist contains several
|
|
31
|
+
* `<string>` values and a regex would be one unrelated key away from
|
|
32
|
+
* returning the wrong one. A binary plist has no `<dict>` in its bytes and is
|
|
33
|
+
* reported as unreadable (the saved value then applies) rather than guessed at.
|
|
34
|
+
*/
|
|
35
|
+
declare function readBundleVersion(plistPath: string): Promise<string | undefined>;
|
|
36
|
+
/**
|
|
37
|
+
* The installed international App's version, or `undefined` when it is not
|
|
38
|
+
* installed (or not readable).
|
|
39
|
+
*
|
|
40
|
+
* Windows and Linux have no verified bundle-metadata location yet, so this
|
|
41
|
+
* returns `undefined` there and the saved/fallback value is used instead of
|
|
42
|
+
* guessing a path — the same discipline the credential discovery follows.
|
|
43
|
+
*/
|
|
44
|
+
declare function installedAppVersion(): Promise<{
|
|
45
|
+
version: string;
|
|
46
|
+
bundle: string;
|
|
47
|
+
} | undefined>;
|
|
48
|
+
/** Constructor dependencies; all injectable so tests never touch the real FS. */
|
|
49
|
+
interface ResolveAppVersionOptions {
|
|
50
|
+
/** Installed-version reader; defaults to {@link installedAppVersion}. */
|
|
51
|
+
installed?: () => Promise<{
|
|
52
|
+
version: string;
|
|
53
|
+
bundle: string;
|
|
54
|
+
} | undefined>;
|
|
55
|
+
/** Saved-version path; defaults to {@link appVersionPath}. */
|
|
56
|
+
path?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolve the UA version: installed App first, then the last saved value, then
|
|
60
|
+
* the compiled-in fallback.
|
|
61
|
+
*
|
|
62
|
+
* A value read from the App is written back immediately, so an uninstalled App
|
|
63
|
+
* or an unreadable plist later still has the last real version to fall back
|
|
64
|
+
* on. The write is best-effort: failing to cache a version must never fail the
|
|
65
|
+
* catalog request that asked for it.
|
|
66
|
+
*/
|
|
67
|
+
declare function resolveAppVersion(options?: ResolveAppVersionOptions): Promise<AppVersionInfo>;
|
|
68
|
+
/**
|
|
69
|
+
* Build the App-shaped User-Agent for catalog requests.
|
|
70
|
+
*
|
|
71
|
+
* `WorkBuddyAI/<version>` with no space is the form measured to reach the App
|
|
72
|
+
* document; the space form is rejected with 400/12403. Throws on an invalid
|
|
73
|
+
* version rather than sending a malformed header.
|
|
74
|
+
*/
|
|
75
|
+
declare function appUserAgent(version: string): string;
|
|
76
|
+
//#endregion
|
|
7
77
|
//#region src/probe.d.ts
|
|
8
78
|
/**
|
|
9
79
|
* The canonical values a probe tests, in a fixed order.
|
|
@@ -71,6 +141,9 @@ interface WorkBuddyUpstreamModel {
|
|
|
71
141
|
id: string;
|
|
72
142
|
name: string;
|
|
73
143
|
contextWindow: number;
|
|
144
|
+
maxInputTokens?: number;
|
|
145
|
+
supportedContextWindows?: readonly number[];
|
|
146
|
+
promotions?: readonly WorkBuddyPromotion[];
|
|
74
147
|
maxTokens: number;
|
|
75
148
|
/**
|
|
76
149
|
* Upstream-declared image input capability. Missing or false upstream data
|
|
@@ -121,6 +194,17 @@ interface WorkBuddyModelBilling {
|
|
|
121
194
|
badges?: readonly string[];
|
|
122
195
|
/** Whether the model is currently free (`x0.00` credits). */
|
|
123
196
|
free: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* The rate cannot be stated for this model right now.
|
|
199
|
+
*
|
|
200
|
+
* Set when a row that arrived with promotions attached has no promotion in
|
|
201
|
+
* force: the upstream bakes the discounted value into `credits`, so the
|
|
202
|
+
* cached rate describes a discount that has ended. The original price is not
|
|
203
|
+
* recoverable from the row, so the plugin reports "unknown, refresh needed"
|
|
204
|
+
* rather than repeating a figure it can no longer stand behind — in
|
|
205
|
+
* particular it never keeps claiming the model is free.
|
|
206
|
+
*/
|
|
207
|
+
rateUnknown?: boolean;
|
|
124
208
|
}
|
|
125
209
|
/** One billing package and its remaining credit. */
|
|
126
210
|
interface WorkBuddyCreditAccount {
|
|
@@ -182,17 +266,57 @@ declare function regionOf(domain: string): WorkBuddyRegion;
|
|
|
182
266
|
* compatible spelling the upstream accepts.
|
|
183
267
|
*/
|
|
184
268
|
declare function prepareChatBody(source: string): string;
|
|
269
|
+
/** Provenance of one successful catalog fetch, surfaced by the status card. */
|
|
270
|
+
interface WorkBuddyCatalogFetch {
|
|
271
|
+
fetchedAtMs: number;
|
|
272
|
+
/** Which document answered, e.g. `workbuddy-ai:app`. */
|
|
273
|
+
source: string;
|
|
274
|
+
/** UA version used, when the request needed one. */
|
|
275
|
+
appVersion?: AppVersionInfo;
|
|
276
|
+
}
|
|
277
|
+
/** Constructor dependencies. */
|
|
278
|
+
interface WorkBuddyUpstreamClientOptions {
|
|
279
|
+
/** App-version resolver for international catalog requests; injectable for tests. */
|
|
280
|
+
resolveAppVersion?: () => Promise<AppVersionInfo>;
|
|
281
|
+
}
|
|
185
282
|
/**
|
|
186
283
|
* Upstream HTTP client. One instance serves the whole plugin; requests take
|
|
187
284
|
* the credential explicitly so token refreshes apply on the next call.
|
|
285
|
+
*
|
|
286
|
+
* One instance is *per variant*: the international provider needs its own
|
|
287
|
+
* catalog source, UA version, and probe differences, and keeping them on the
|
|
288
|
+
* instance avoids passing a variant through every call signature.
|
|
188
289
|
*/
|
|
189
290
|
declare class WorkBuddyUpstreamClient {
|
|
291
|
+
/**
|
|
292
|
+
* Resolves the App-shaped UA version for international catalog requests.
|
|
293
|
+
* Injectable so tests never read the real filesystem.
|
|
294
|
+
*/
|
|
295
|
+
private readonly resolveAppVersion;
|
|
296
|
+
/** Provenance of the most recent successful catalog fetch, for the card. */
|
|
297
|
+
lastCatalog: WorkBuddyCatalogFetch | undefined;
|
|
298
|
+
constructor(options?: WorkBuddyUpstreamClientOptions);
|
|
190
299
|
/** POST the chat endpoint; a successful answer is the raw SSE response. */
|
|
191
300
|
chatStream(credential: WorkBuddyCredential, bodyJson: string, signal?: AbortSignal): Promise<WorkBuddyChatResult>;
|
|
192
301
|
/** POST the token-refresh endpoint; the caller merges the outcome. */
|
|
193
302
|
refreshToken(credential: WorkBuddyCredential): Promise<WorkBuddyRefreshOutcome>;
|
|
194
|
-
/**
|
|
195
|
-
|
|
303
|
+
/**
|
|
304
|
+
* GET the personal model catalog.
|
|
305
|
+
*
|
|
306
|
+
* Two upstream documents feed this, one per variant:
|
|
307
|
+
*
|
|
308
|
+
* - CN (`workbuddy`): `/console/enterprises/personal/models`, the document
|
|
309
|
+
* the official CLI itself consumes. Unchanged behaviour.
|
|
310
|
+
* - International (`workbuddy-ai`): `/v3/config`, the product document the
|
|
311
|
+
* App's main process fetches. The gateway splits it by User-Agent, so this
|
|
312
|
+
* request carries the App-shaped UA while every other request keeps the
|
|
313
|
+
* CLI UA it has always sent.
|
|
314
|
+
*
|
|
315
|
+
* Both are unwrapped and classified the same way — `readEnvelope` plus
|
|
316
|
+
* `envelopeError` — so an expired session or exhausted credit is reported as
|
|
317
|
+
* such rather than as a generic catalog failure.
|
|
318
|
+
*/
|
|
319
|
+
fetchModels(credential: WorkBuddyCredential, signal?: AbortSignal): Promise<readonly WorkBuddyUpstreamModel[]>;
|
|
196
320
|
/** POST the billing endpoint for the aggregated remaining credit. */
|
|
197
321
|
fetchCredits(credential: WorkBuddyCredential): Promise<WorkBuddyCredits>;
|
|
198
322
|
/**
|
|
@@ -207,9 +331,112 @@ declare class WorkBuddyUpstreamClient {
|
|
|
207
331
|
* assembled into an answer. `reasoning_effort` is omitted entirely (rather
|
|
208
332
|
* than sent empty) when `effort` is undefined, so the baseline case is a
|
|
209
333
|
* genuinely bare request.
|
|
334
|
+
*
|
|
335
|
+
* Two international differences, both measured on 2026-09-11:
|
|
336
|
+
*
|
|
337
|
+
* - The gateway requires a leading `system` message (400/11128 otherwise), so
|
|
338
|
+
* one is prepended for the global region only.
|
|
339
|
+
* - `max_tokens: 1` is below some models' floor (the GPT-5.6 family rejects it
|
|
340
|
+
* with 400/11133 `integer_below_min_value`), so the international probe asks
|
|
341
|
+
* for a slightly larger minimum. This is a floor the plugin must clear, not
|
|
342
|
+
* evidence about any model's effort support: a model still refusing that
|
|
343
|
+
* minimum is reported as an incompatible request, never as "effort
|
|
344
|
+
* unsupported", and the ceiling is never raised further to force an answer.
|
|
210
345
|
*/
|
|
211
346
|
probeEffort(credential: WorkBuddyCredential, model: string, effort: string | undefined, signal: AbortSignal): Promise<ProbeAttempt>;
|
|
212
347
|
}
|
|
348
|
+
/** Parse either response shape after its envelope has been checked. */
|
|
349
|
+
declare function parseModelCatalog(data: Record<string, unknown>, international?: boolean): readonly WorkBuddyUpstreamModel[];
|
|
350
|
+
/**
|
|
351
|
+
* One verified promotion entry.
|
|
352
|
+
*
|
|
353
|
+
* Only the shape actually observed in the international App document is
|
|
354
|
+
* modelled — an enabled, time-boxed, `displayMode: "replace"` discount. An
|
|
355
|
+
* entry that does not match is dropped rather than guessed at: rendering a
|
|
356
|
+
* discount the plugin does not understand could understate what the user pays.
|
|
357
|
+
*/
|
|
358
|
+
interface WorkBuddyPromotion {
|
|
359
|
+
/** Window start, epoch ms, parsed from the document's offset timestamp. */
|
|
360
|
+
start: number;
|
|
361
|
+
/** Window end, epoch ms. */
|
|
362
|
+
end: number;
|
|
363
|
+
/** Badge text as the upstream wrote it, e.g. `Free now`. */
|
|
364
|
+
label: string;
|
|
365
|
+
/** Multiplier applied to the model's rate; `0` replaces it outright. */
|
|
366
|
+
factor: number;
|
|
367
|
+
/** Higher wins when several promotions cover one model. */
|
|
368
|
+
priority: number;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Re-evaluate a model's promotion against the current time.
|
|
372
|
+
*
|
|
373
|
+
* Promotions are time-boxed, and the catalog they arrive in is cached for the
|
|
374
|
+
* life of the process. Frozen at parse time, a cached "Free now" would keep
|
|
375
|
+
* claiming a discount after `validUntil` had passed, and would keep showing the
|
|
376
|
+
* pre-discount rate as the discounted one. Re-deriving on every read means the
|
|
377
|
+
* badge disappears on its own and the rate reverts, with no refresh needed.
|
|
378
|
+
*
|
|
379
|
+
* Non-destructive: the model's own `credits` and `badges` are the base, and the
|
|
380
|
+
* promotion is layered onto a copy. A model with no live promotion is returned
|
|
381
|
+
* as-is, so the common case allocates nothing.
|
|
382
|
+
*/
|
|
383
|
+
declare function modelWithCurrentPromotion(model: WorkBuddyUpstreamModel, now?: number): WorkBuddyUpstreamModel;
|
|
384
|
+
/**
|
|
385
|
+
* Apply the international endpoint's extra chat requirement: the first message
|
|
386
|
+
* must be a system prompt.
|
|
387
|
+
*
|
|
388
|
+
* The international gateway rejects a body whose first message is not `system`
|
|
389
|
+
* with HTTP 400 code 11128 ("first message is not system prompt"). Note that
|
|
390
|
+
* the *same* code means something else on the CN endpoint — there it reports a
|
|
391
|
+
* rejected `developer` role — so the two are never branched on by code alone.
|
|
392
|
+
*
|
|
393
|
+
* The added prompt is deliberately empty of user content and prepended, never
|
|
394
|
+
* merged: existing messages keep their order and wording. A body that is not a
|
|
395
|
+
* JSON object is returned unchanged, exactly as {@link prepareChatBody} does,
|
|
396
|
+
* so this is safe to run over an already-prepared-or-not body.
|
|
397
|
+
*/
|
|
398
|
+
declare function prepareInternationalChatBody(source: string): string;
|
|
399
|
+
//#endregion
|
|
400
|
+
//#region src/variants.d.ts
|
|
401
|
+
/** One WorkBuddy product variant. */
|
|
402
|
+
interface WorkBuddyVariant {
|
|
403
|
+
/** Provider id registered with DSH, e.g. `workbuddy-ai`. */
|
|
404
|
+
id: string;
|
|
405
|
+
/** Model-group heading and card title stem, e.g. `WorkBuddy AI`. */
|
|
406
|
+
displayName: string;
|
|
407
|
+
/** Desktop app name as users know it, for diagnostics and error copy. */
|
|
408
|
+
appName: string;
|
|
409
|
+
/** Which upstream region this variant's credentials must belong to. */
|
|
410
|
+
region: WorkBuddyRegion;
|
|
411
|
+
/** Env var overriding the desktop auth-file location. */
|
|
412
|
+
env: string;
|
|
413
|
+
/** Basename of the desktop app's own auth file in the shared auth directory. */
|
|
414
|
+
desktopFilename: string;
|
|
415
|
+
/** Basename of the plugin-owned credential copy under `$DSH_HOME`. */
|
|
416
|
+
ownFilename: string;
|
|
417
|
+
/** Basename of the plugin-owned probe-record file under `$DSH_HOME`. */
|
|
418
|
+
probeFilename: string;
|
|
419
|
+
/**
|
|
420
|
+
* Basename of the plugin-owned saved-catalog file under `$DSH_HOME`.
|
|
421
|
+
*
|
|
422
|
+
* One per variant, like the probe records: the two endpoints disagree about
|
|
423
|
+
* rates, windows, and even which models exist for a shared id, so a catalog
|
|
424
|
+
* saved from one must never be served as the other's.
|
|
425
|
+
*/
|
|
426
|
+
catalogFilename: string;
|
|
427
|
+
/** Same-origin status route consumed by this variant's card. */
|
|
428
|
+
statusPath: string;
|
|
429
|
+
/** Same-origin probe-control route consumed by this variant's card. */
|
|
430
|
+
probePath: string;
|
|
431
|
+
}
|
|
432
|
+
/** CN WorkBuddy first: the existing provider keeps its id, paths, and copy. */
|
|
433
|
+
declare const WORKBUDDY_VARIANTS: readonly WorkBuddyVariant[];
|
|
434
|
+
/** The CN variant; the plugin's long-standing default and compatibility anchor. */
|
|
435
|
+
declare const CN_VARIANT: WorkBuddyVariant;
|
|
436
|
+
/** The international variant. */
|
|
437
|
+
declare const AI_VARIANT: WorkBuddyVariant;
|
|
438
|
+
/** Look up a variant by provider id. */
|
|
439
|
+
declare function variantFor(id: string): WorkBuddyVariant | undefined;
|
|
213
440
|
//#endregion
|
|
214
441
|
//#region src/auth.d.ts
|
|
215
442
|
/** Normalized WorkBuddy credential, timestamps in epoch milliseconds. */
|
|
@@ -233,9 +460,16 @@ interface WorkBuddyAuthStatus {
|
|
|
233
460
|
nickname?: string;
|
|
234
461
|
domain?: string;
|
|
235
462
|
source?: 'desktop' | 'dsh';
|
|
463
|
+
/**
|
|
464
|
+
* Why no credential is usable, when the reason is diagnosable rather than
|
|
465
|
+
* "nobody is signed in" — a region mismatch being the case that matters.
|
|
466
|
+
* Present only on `signed-out`, and never a substitute for fixing the file.
|
|
467
|
+
*/
|
|
468
|
+
reason?: string;
|
|
236
469
|
}
|
|
237
470
|
/** Constructor options; only {@link refresh} is required. */
|
|
238
471
|
interface WorkBuddyStoreOptions {
|
|
472
|
+
variant?: WorkBuddyVariant;
|
|
239
473
|
/** Explicit desktop auth-file path, overriding env and platform defaults. */
|
|
240
474
|
desktopPath?: string;
|
|
241
475
|
/** Explicit plugin-owned copy path, defaulting under `$DSH_HOME`. */
|
|
@@ -259,8 +493,16 @@ declare function workbuddyOwnAuthPath(): string;
|
|
|
259
493
|
* native Linux location.
|
|
260
494
|
*/
|
|
261
495
|
declare function defaultDesktopAuthCandidates(): string[];
|
|
496
|
+
/**
|
|
497
|
+
* The platform-default candidates for one variant, in probe order.
|
|
498
|
+
*
|
|
499
|
+
* Both apps write into the *same* shared `CodeBuddyExtension` auth directory
|
|
500
|
+
* and differ only in the file's basename, so the per-platform ordering above
|
|
501
|
+
* is reused verbatim and just the filename is swapped.
|
|
502
|
+
*/
|
|
503
|
+
declare function desktopAuthCandidatesFor(variant: WorkBuddyVariant): string[];
|
|
262
504
|
/** First platform-default candidate; see {@link defaultDesktopAuthCandidates}. */
|
|
263
|
-
declare function defaultDesktopAuthPath(): string | undefined;
|
|
505
|
+
declare function defaultDesktopAuthPath(variant?: WorkBuddyVariant): string | undefined;
|
|
264
506
|
/**
|
|
265
507
|
* Parse a WorkBuddy auth document in either on-disk shape: the plugin OAuth
|
|
266
508
|
* nested form `{"auth":{...},"account":{...}}` and the flat panel form.
|
|
@@ -277,6 +519,7 @@ declare function parseWorkBuddyAuth(text: string): WorkBuddyCredential | undefin
|
|
|
277
519
|
* not take down a working session.
|
|
278
520
|
*/
|
|
279
521
|
declare class WorkBuddyCredentialStore {
|
|
522
|
+
private readonly variant;
|
|
280
523
|
private readonly refresh;
|
|
281
524
|
private readonly refreshMarginMs;
|
|
282
525
|
private readonly ownPath;
|
|
@@ -334,19 +577,55 @@ type WorkBuddyModelInfo = WorkBuddyUpstreamModel;
|
|
|
334
577
|
* registers with a usable catalog even while the first fetch is in flight or
|
|
335
578
|
* offline.
|
|
336
579
|
*
|
|
337
|
-
* The list tracks the `cli` agent's model roster exactly: the
|
|
580
|
+
* The list tracks the `cli` agent's model roster exactly: the 16 models the
|
|
338
581
|
* desktop CLI offers. Reasoning metadata is taken verbatim from the live
|
|
339
582
|
* endpoint — each model's supported effort set and whether thinking can be
|
|
340
583
|
* disabled — and the `free` flag follows the upstream `x0.00` credits marker.
|
|
341
584
|
*/
|
|
342
585
|
declare const FALLBACK_WORKBUDDY_MODELS: readonly WorkBuddyModelInfo[];
|
|
343
|
-
/**
|
|
586
|
+
/**
|
|
587
|
+
* Static CLI models for the international endpoint, captured 2026-09-11 from
|
|
588
|
+
* the App-form `/v3/config` document (the 20 ids of its `cli` agent, in order).
|
|
589
|
+
*
|
|
590
|
+
* Same purpose and same discipline as {@link FALLBACK_WORKBUDDY_MODELS}: it
|
|
591
|
+
* covers the window before the first successful fetch and an offline start,
|
|
592
|
+
* and it is deliberately *not* a promise about the upstream's current state.
|
|
593
|
+
* Reasoning metadata is verbatim from that snapshot. No promo badge is baked
|
|
594
|
+
* in: promotions are time-boxed (`modelPromotions` carries `validFrom`/
|
|
595
|
+
* `validUntil`), so hard-coding a "Free now" label would keep claiming a
|
|
596
|
+
* discount the upstream may have already ended.
|
|
597
|
+
*/
|
|
598
|
+
declare const FALLBACK_WORKBUDDY_AI_MODELS: readonly WorkBuddyModelInfo[];
|
|
599
|
+
/**
|
|
600
|
+
* Mutable catalog shared by the shim's `/v1/models` and the adapter.
|
|
601
|
+
*
|
|
602
|
+
* Visibility is separate from content. A variant whose app has no credentials
|
|
603
|
+
* must expose *no* models rather than a fallback roster: the DSH model picker
|
|
604
|
+
* drops an empty group, so an empty catalog is exactly how a provider hides
|
|
605
|
+
* without touching registration. Serving the fallback to a signed-out user
|
|
606
|
+
* instead offers models that can only fail (`store.resolve()` throws on the
|
|
607
|
+
* first message), which is worse than showing nothing.
|
|
608
|
+
*
|
|
609
|
+
* The flag defaults to visible so a directly-constructed catalog behaves as it
|
|
610
|
+
* always has; the plugin runtime applies the credential gate.
|
|
611
|
+
*/
|
|
344
612
|
declare class WorkBuddyCatalog {
|
|
345
613
|
private models;
|
|
346
|
-
|
|
614
|
+
private visible;
|
|
615
|
+
constructor(initial?: readonly WorkBuddyModelInfo[]);
|
|
616
|
+
/** Current entries; empty while the variant has no usable credential. */
|
|
347
617
|
current(): readonly WorkBuddyModelInfo[];
|
|
348
618
|
/** Replace the list; callers invalidate their adapter snapshot after this. */
|
|
349
619
|
set(models: readonly WorkBuddyModelInfo[]): void;
|
|
620
|
+
/** Whether this variant's models are exposed at all. */
|
|
621
|
+
isVisible(): boolean;
|
|
622
|
+
/**
|
|
623
|
+
* Show or hide the whole catalog. Returns whether the value changed, so the
|
|
624
|
+
* caller can skip an invalidation that would re-render an identical list.
|
|
625
|
+
*/
|
|
626
|
+
setVisible(visible: boolean): boolean;
|
|
627
|
+
/** Models to fall back to when the upstream fetch fails; ignores visibility. */
|
|
628
|
+
fallback(): readonly WorkBuddyModelInfo[];
|
|
350
629
|
}
|
|
351
630
|
//#endregion
|
|
352
631
|
//#region src/probe-store.d.ts
|
|
@@ -374,9 +653,28 @@ interface WorkBuddyProbeRecord {
|
|
|
374
653
|
probedAtMs: number;
|
|
375
654
|
/** Plugin version that produced the record. */
|
|
376
655
|
pluginVersion: string;
|
|
656
|
+
/**
|
|
657
|
+
* The account this observation was made under, as `uid:enterpriseId`.
|
|
658
|
+
*
|
|
659
|
+
* An effort set is a fact about one account's entitlement as much as about
|
|
660
|
+
* the model: the same model id can accept different levels under a different
|
|
661
|
+
* subscription. Without this a record outlived the account that produced it,
|
|
662
|
+
* so signing out and in as someone else inherited the previous account's
|
|
663
|
+
* detected levels. Records written before this field existed carry no
|
|
664
|
+
* identity and are therefore never reused.
|
|
665
|
+
*/
|
|
666
|
+
account?: string;
|
|
377
667
|
}
|
|
378
|
-
/**
|
|
379
|
-
|
|
668
|
+
/**
|
|
669
|
+
* Plugin-owned probe record path inside the Harness home.
|
|
670
|
+
*
|
|
671
|
+
* One file per variant. Same-named models exist on both endpoints (the
|
|
672
|
+
* international catalog repeats `glm-5.3`, `glm-5.2`, `hy3`, `kimi-k2.6`), and
|
|
673
|
+
* {@link fingerprintModel} covers only `id`/`reasoning`/`supportsImages` —
|
|
674
|
+
* never the provider — so a single shared file would let one variant's
|
|
675
|
+
* observation answer for the other. The paths differ; the format does not.
|
|
676
|
+
*/
|
|
677
|
+
declare function workbuddyProbePath(filename?: string): string;
|
|
380
678
|
/**
|
|
381
679
|
* Fingerprint the catalog fields a probe depends on.
|
|
382
680
|
*
|
|
@@ -413,9 +711,13 @@ declare class WorkBuddyProbeStore {
|
|
|
413
711
|
private load;
|
|
414
712
|
/**
|
|
415
713
|
* The usable record for a model, or `undefined` when there is none, it is
|
|
416
|
-
* expired,
|
|
714
|
+
* expired, it was taken against a different catalog row, or it belongs to a
|
|
715
|
+
* different account.
|
|
716
|
+
*
|
|
717
|
+
* @param account - the account in effect, as `uid:enterpriseId`. Records are
|
|
718
|
+
* only returned for the account that produced them.
|
|
417
719
|
*/
|
|
418
|
-
get(modelId: string, fingerprint: string): WorkBuddyProbeRecord | undefined;
|
|
720
|
+
get(modelId: string, fingerprint: string, account: string): WorkBuddyProbeRecord | undefined;
|
|
419
721
|
/**
|
|
420
722
|
* Store one observation. Only a decisive answer (`validating` /
|
|
421
723
|
* `non-validating`) replaces an existing decisive record: a transient
|
|
@@ -426,8 +728,8 @@ declare class WorkBuddyProbeStore {
|
|
|
426
728
|
clear(): void;
|
|
427
729
|
/** Every record currently held, for status display. */
|
|
428
730
|
all(): Readonly<Record<string, WorkBuddyProbeRecord>>;
|
|
429
|
-
/** Build a record stamped with this store's clock and
|
|
430
|
-
record(fingerprint: string, validation: WorkBuddyProbeValidation, efforts: readonly WorkBuddyEffort[]): WorkBuddyProbeRecord;
|
|
731
|
+
/** Build a record stamped with this store's clock, version, and account. */
|
|
732
|
+
record(fingerprint: string, validation: WorkBuddyProbeValidation, efforts: readonly WorkBuddyEffort[], account: string): WorkBuddyProbeRecord;
|
|
431
733
|
/**
|
|
432
734
|
* Write through a temporary file and rename, so a crash mid-write cannot
|
|
433
735
|
* leave a half-parsed document that reads as "no records" and silently drops
|
|
@@ -478,6 +780,8 @@ declare const WORKBUDDY_PROVIDER = "workbuddy";
|
|
|
478
780
|
declare const WORKBUDDY_STREAM_IDLE_TIMEOUT_MS = 300000;
|
|
479
781
|
/** Constructor dependencies. */
|
|
480
782
|
interface WorkBuddyAdapterOptions {
|
|
783
|
+
providerId?: string;
|
|
784
|
+
displayName?: string;
|
|
481
785
|
shim: WorkBuddyShim;
|
|
482
786
|
store: WorkBuddyCredentialStore;
|
|
483
787
|
catalog: WorkBuddyCatalog;
|
|
@@ -509,6 +813,56 @@ interface WorkBuddyAdapter {
|
|
|
509
813
|
*/
|
|
510
814
|
declare function createWorkBuddyAdapter(options: WorkBuddyAdapterOptions): WorkBuddyAdapter;
|
|
511
815
|
//#endregion
|
|
816
|
+
//#region src/catalog-store.d.ts
|
|
817
|
+
/** Basename of the CN variant's saved catalog inside the Harness home. */
|
|
818
|
+
declare const WORKBUDDY_CATALOG_FILENAME = ".workbuddy-catalog.json";
|
|
819
|
+
/** One saved catalog: the account it belonged to, and the models it listed. */
|
|
820
|
+
interface SavedCatalog {
|
|
821
|
+
/** `uid:enterpriseId` the catalog was fetched for. */
|
|
822
|
+
account: string;
|
|
823
|
+
/** Which document answered, so a CN roster is never served as an AI one. */
|
|
824
|
+
source: string;
|
|
825
|
+
/** When the fetch succeeded, epoch milliseconds. */
|
|
826
|
+
fetchedAtMs: number;
|
|
827
|
+
models: readonly WorkBuddyUpstreamModel[];
|
|
828
|
+
/** App version used as the UA, when the variant needed one. */
|
|
829
|
+
appVersion?: string;
|
|
830
|
+
}
|
|
831
|
+
/** Plugin-owned saved-catalog path inside the Harness home. */
|
|
832
|
+
declare function workbuddyCatalogPath(filename?: string): string;
|
|
833
|
+
/** Options for {@link WorkBuddyCatalogStore}. */
|
|
834
|
+
interface WorkBuddyCatalogStoreOptions {
|
|
835
|
+
/** Explicit state-file path, overriding the `$DSH_HOME` default. */
|
|
836
|
+
path?: string;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* The last successful catalog per account, read once and written atomically.
|
|
840
|
+
*
|
|
841
|
+
* Malformed content reads as "nothing saved" rather than throwing: this file
|
|
842
|
+
* is an optimization for the offline and first-seconds cases, and a corrupt one
|
|
843
|
+
* must never be able to stop the plugin from serving models.
|
|
844
|
+
*/
|
|
845
|
+
declare class WorkBuddyCatalogStore {
|
|
846
|
+
private readonly path;
|
|
847
|
+
private entries;
|
|
848
|
+
constructor(options?: WorkBuddyCatalogStoreOptions | string);
|
|
849
|
+
/** Resolved state-file path, for the CLI and tests. */
|
|
850
|
+
filePath(): string;
|
|
851
|
+
private load;
|
|
852
|
+
/** The saved catalog for one account, or `undefined` when there is none. */
|
|
853
|
+
get(account: string): SavedCatalog | undefined;
|
|
854
|
+
/**
|
|
855
|
+
* Remember a catalog for an account, replacing whatever was saved before.
|
|
856
|
+
*
|
|
857
|
+
* A failed write is swallowed: the plugin has already served these models,
|
|
858
|
+
* and losing the *memory* of them is not worth surfacing.
|
|
859
|
+
*/
|
|
860
|
+
set(account: string, catalog: Omit<SavedCatalog, 'account'>): void;
|
|
861
|
+
/** Forget one account's catalog — used when that account signs out. */
|
|
862
|
+
delete(account: string): void;
|
|
863
|
+
private persist;
|
|
864
|
+
}
|
|
865
|
+
//#endregion
|
|
512
866
|
//#region src/probe-service.d.ts
|
|
513
867
|
/** What the caller learns about a completed probe. */
|
|
514
868
|
type WorkBuddyProbeStatus = {
|
|
@@ -528,6 +882,17 @@ interface WorkBuddyProbeServiceOptions {
|
|
|
528
882
|
client: WorkBuddyUpstreamClient;
|
|
529
883
|
/** Whether probing is permitted at all; consulted before every sweep. */
|
|
530
884
|
consent: () => boolean;
|
|
885
|
+
/**
|
|
886
|
+
* The account currently in effect, as `uid:enterpriseId`, or `undefined`
|
|
887
|
+
* while signed out.
|
|
888
|
+
*
|
|
889
|
+
* Records are read and written against this identity, and it is re-checked
|
|
890
|
+
* after the sweep finishes: an observation produced under account A must not
|
|
891
|
+
* be stored once account B is in effect, however long the probe took. The
|
|
892
|
+
* caller's `clear()` on an account switch is not sufficient on its own,
|
|
893
|
+
* because an in-flight probe completes *after* that clear.
|
|
894
|
+
*/
|
|
895
|
+
account: () => string | undefined;
|
|
531
896
|
sentinel?: SentinelFactory;
|
|
532
897
|
/** Injectable for tests; defaults to the live upstream sender. */
|
|
533
898
|
send?: (modelId: string) => ProbeSender;
|
|
@@ -633,7 +998,7 @@ declare const name = "llm-workbuddy";
|
|
|
633
998
|
/** The model registry required before the provider can register. */
|
|
634
999
|
declare const inject: string[];
|
|
635
1000
|
/**
|
|
636
|
-
* Settings namespace owning the
|
|
1001
|
+
* Settings namespace owning the CN card's section.
|
|
637
1002
|
*
|
|
638
1003
|
* DSH 0.1.2 dropped the `settingsNamespace()` branding function: a namespace is
|
|
639
1004
|
* now a nominal string, validated by the type system where it is used rather
|
|
@@ -645,10 +1010,24 @@ declare const inject: string[];
|
|
|
645
1010
|
* their namespaces as plain string literals).
|
|
646
1011
|
*/
|
|
647
1012
|
declare const WORKBUDDY_SETTINGS_NS: SettingsNamespace;
|
|
1013
|
+
/**
|
|
1014
|
+
* Settings namespace owning the international card's section.
|
|
1015
|
+
*
|
|
1016
|
+
* One namespace per card, not one shared: the settings Plugins tab dispatches a
|
|
1017
|
+
* card by rendering `settings.plugin.item` with `entryKey = ns` for each
|
|
1018
|
+
* namespace the Host serves, and skips an entry whose key names no served
|
|
1019
|
+
* namespace. With a single installed section, the international card registers
|
|
1020
|
+
* into the slot but is never rendered — the card list is built from the Host's
|
|
1021
|
+
* sections, not from the slot's entries. Each card therefore needs its own
|
|
1022
|
+
* installed section whose namespace equals the card's slot key.
|
|
1023
|
+
*/
|
|
1024
|
+
declare const WORKBUDDY_AI_SETTINGS_NS: SettingsNamespace;
|
|
648
1025
|
/** Plugin configuration. */
|
|
649
1026
|
interface Config {
|
|
650
|
-
/** Explicit WorkBuddy desktop auth-file path, overriding env and platform defaults. */
|
|
1027
|
+
/** Explicit WorkBuddy (CN) desktop auth-file path, overriding env and platform defaults. */
|
|
651
1028
|
authFile?: string;
|
|
1029
|
+
/** Explicit WorkBuddy AI (international) desktop auth-file path, overriding env and platform defaults. */
|
|
1030
|
+
authFileAI?: string;
|
|
652
1031
|
/**
|
|
653
1032
|
* Whether the user has authorized sending probe requests about reasoning
|
|
654
1033
|
* efforts. Off by default: a probe spends real credit, so nothing is sent
|
|
@@ -658,11 +1037,15 @@ interface Config {
|
|
|
658
1037
|
}
|
|
659
1038
|
declare const Config: z<Config>;
|
|
660
1039
|
/**
|
|
661
|
-
* Start
|
|
662
|
-
*
|
|
663
|
-
*
|
|
664
|
-
*
|
|
1040
|
+
* Start both variants: their loopback endpoints, the `workbuddy` and
|
|
1041
|
+
* `workbuddy-ai` providers, their configuration cards, and their
|
|
1042
|
+
* credential-driven catalog lifecycles.
|
|
1043
|
+
*
|
|
1044
|
+
* Each variant registers unconditionally; what varies is whether its catalog is
|
|
1045
|
+
* *visible*. An empty catalog is how DSH hides a model group (the host filters
|
|
1046
|
+
* out groups with no models), which keeps a sign-in that happens after startup
|
|
1047
|
+
* working without re-registering the provider.
|
|
665
1048
|
*/
|
|
666
1049
|
declare function apply(ctx: Context, config: Config): void;
|
|
667
1050
|
//#endregion
|
|
668
|
-
export { Config, FALLBACK_WORKBUDDY_MODELS, PROBE_EFFORT_CANDIDATES, type ProbeAttempt, type ProbeOutcome, type ProbeSender, type UpstreamErrorKind, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_PROBE_FILENAME, WORKBUDDY_PROVIDER, WORKBUDDY_SETTINGS_NS, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, type WorkBuddyAdapter, type WorkBuddyAuthStatus, WorkBuddyCatalog, type WorkBuddyChatResult, type WorkBuddyCredential, WorkBuddyCredentialStore, type WorkBuddyCredits, type WorkBuddyEffort, type WorkBuddyHostHeartbeat, type WorkBuddyModelBilling, type WorkBuddyModelInfo, type WorkBuddyModelReasoning, type WorkBuddyProbeRecord, WorkBuddyProbeService, type WorkBuddyProbeStatus, WorkBuddyProbeStore, type WorkBuddyProbeValidation, type WorkBuddyRefreshOutcome, type WorkBuddyShim, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, apply, classifyUpstreamError, clearHostHeartbeat, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthPath, fingerprintModel, inject, isHeartbeatProcessAlive, name, normalizeCredits, parseWorkBuddyAuth, prepareChatBody, probeModel, processStartTimeMs, randomSentinel, readHostHeartbeat, regionOf, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, workbuddyProbePath };
|
|
1051
|
+
export { AI_VARIANT, type AppVersionInfo, CN_VARIANT, Config, FALLBACK_WORKBUDDY_AI_MODELS, FALLBACK_WORKBUDDY_MODELS, PROBE_EFFORT_CANDIDATES, type ProbeAttempt, type ProbeOutcome, type ProbeSender, type UpstreamErrorKind, WORKBUDDY_AI_SETTINGS_NS, WORKBUDDY_APP_VERSION_FILENAME, WORKBUDDY_AUTH_FILENAME, WORKBUDDY_AUTH_FILE_ENV, WORKBUDDY_CATALOG_FILENAME, WORKBUDDY_HOST_HEARTBEAT_FILENAME, WORKBUDDY_PROBE_FILENAME, WORKBUDDY_PROVIDER, WORKBUDDY_SETTINGS_NS, WORKBUDDY_STREAM_IDLE_TIMEOUT_MS, WORKBUDDY_VARIANTS, type WorkBuddyAdapter, type WorkBuddyAppVersionSource, type WorkBuddyAuthStatus, WorkBuddyCatalog, type WorkBuddyCatalogFetch, WorkBuddyCatalogStore, type WorkBuddyChatResult, type WorkBuddyCredential, WorkBuddyCredentialStore, type WorkBuddyCredits, type WorkBuddyEffort, type WorkBuddyHostHeartbeat, type WorkBuddyModelBilling, type WorkBuddyModelInfo, type WorkBuddyModelReasoning, type WorkBuddyProbeRecord, WorkBuddyProbeService, type WorkBuddyProbeStatus, WorkBuddyProbeStore, type WorkBuddyProbeValidation, type WorkBuddyPromotion, type WorkBuddyRefreshOutcome, type WorkBuddyShim, WorkBuddyUpstreamClient, type WorkBuddyUpstreamModel, type WorkBuddyVariant, appUserAgent, apply, classifyUpstreamError, clearHostHeartbeat, createWorkBuddyAdapter, createWorkBuddyShim, defaultDesktopAuthCandidates, defaultDesktopAuthPath, desktopAuthCandidatesFor, fingerprintModel, inject, installedAppVersion, isHeartbeatProcessAlive, modelWithCurrentPromotion, name, normalizeCredits, parseModelCatalog, parseWorkBuddyAuth, prepareChatBody, prepareInternationalChatBody, probeModel, processStartTimeMs, randomSentinel, readBundleVersion, readHostHeartbeat, regionOf, resolveAppVersion, validAppVersion, variantFor, workbuddyCatalogPath, workbuddyHostHeartbeatPath, workbuddyOwnAuthPath, workbuddyProbePath };
|