@vibedev-si/dsh-vibedev 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +155 -0
  3. package/THIRD-PARTY-NOTICES.txt +566 -0
  4. package/client/client.js +1368 -0
  5. package/cordis.patch.yml +5 -0
  6. package/icon.svg +7 -0
  7. package/lib/account/index.d.ts +118 -0
  8. package/lib/anthropic-messages-KOS0z8Fy.js +13472 -0
  9. package/lib/auth/credentials.d.ts +47 -0
  10. package/lib/auth/login.d.ts +154 -0
  11. package/lib/gateway/assets.d.ts +61 -0
  12. package/lib/gateway/catalog.d.ts +126 -0
  13. package/lib/gateway/errors.d.ts +76 -0
  14. package/lib/gateway/http.d.ts +94 -0
  15. package/lib/index.d.ts +105 -0
  16. package/lib/index.js +7301 -0
  17. package/lib/llm/adapter.d.ts +129 -0
  18. package/lib/llm/catalog.d.ts +75 -0
  19. package/lib/llm/context.d.ts +54 -0
  20. package/lib/llm/index.d.ts +69 -0
  21. package/lib/llm/limits.d.ts +19 -0
  22. package/lib/llm/models.d.ts +67 -0
  23. package/lib/llm/replay.d.ts +66 -0
  24. package/lib/llm/stream.d.ts +46 -0
  25. package/lib/media/chat.d.ts +49 -0
  26. package/lib/media/sources.d.ts +46 -0
  27. package/lib/models-CAcLevEN.js +1045 -0
  28. package/lib/node-Cujw_a4_.js +2403 -0
  29. package/lib/node-vkDR3GtK.js +25 -0
  30. package/lib/openai-completions-DqTCiqpS.js +983 -0
  31. package/lib/openai-prompt-cache-kzRZVokq.js +9567 -0
  32. package/lib/openai-responses-DygWnsye.js +832 -0
  33. package/lib/pricing.d.ts +49 -0
  34. package/lib/runtime.d.ts +150 -0
  35. package/lib/search/provider.d.ts +86 -0
  36. package/lib/service.d.ts +99 -0
  37. package/lib/tasks/remote.d.ts +47 -0
  38. package/lib/tasks/store.d.ts +132 -0
  39. package/lib/tasks/tracker.d.ts +127 -0
  40. package/lib/tools/account.d.ts +21 -0
  41. package/lib/tools/audio.d.ts +13 -0
  42. package/lib/tools/common.d.ts +77 -0
  43. package/lib/tools/image.d.ts +50 -0
  44. package/lib/tools/models.d.ts +13 -0
  45. package/lib/tools/tasks.d.ts +13 -0
  46. package/lib/tools/transcribe.d.ts +19 -0
  47. package/lib/tools/video.d.ts +48 -0
  48. package/lib/transform-messages-Csvf2ItW.js +1023 -0
  49. package/lib/util/files.d.ts +80 -0
  50. package/lib/video/plan.d.ts +96 -0
  51. package/locale/en.json +6 -0
  52. package/locale/zh.json +6 -0
  53. package/package.json +127 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Which VibeDev credential a gateway request carries, in order: the host's
3
+ * signed-in VibeDev account (the VibeDev app's account service hands out its
4
+ * token for the gateway origin), the plugin's own sign-in, then a development
5
+ * key named by an environment variable.
6
+ * @module dsh-vibedev/auth/credentials
7
+ */
8
+ import type { CredentialProvider } from '@deepseek-ai/dsh-credentials';
9
+ import type { DeepSeekAccount } from '@deepseek-ai/dsh-deepseek-account';
10
+ import type { GatewayCredential } from '../gateway/http.js';
11
+ import type { GrantStorage, PluginLogin } from './login.js';
12
+ /** Where a credential came from, for status lines. */
13
+ export type CredentialSource = GatewayCredential['kind'];
14
+ /** Construction options. */
15
+ export interface CredentialChainOptions {
16
+ /** Gateway origin; the host account is asked for a token for this origin. */
17
+ readonly origin: string;
18
+ /** The host's account service, when one is loaded. */
19
+ readonly account: () => DeepSeekAccount | undefined;
20
+ readonly plugin?: PluginLogin;
21
+ /** The development key, when configured. */
22
+ readonly apiKey: () => string | undefined;
23
+ }
24
+ /** Resolves the credential for each request and routes rejections back to its owner. */
25
+ export declare class CredentialChain {
26
+ private readonly options;
27
+ /**
28
+ * @param options - origin and the three sources.
29
+ */
30
+ constructor(options: CredentialChainOptions);
31
+ /** The credential for the next request, or undefined while nobody is signed in. */
32
+ resolve(): Promise<GatewayCredential | undefined>;
33
+ /**
34
+ * The gateway rejected a credential: let its owner refresh it.
35
+ * @param credential - the rejected credential.
36
+ */
37
+ reject(credential: GatewayCredential): Promise<void>;
38
+ }
39
+ /**
40
+ * Grant storage: the host's credential store when one is loaded (a grant
41
+ * record the store keeps verbatim), else a private file in the state
42
+ * directory. The device id is not a secret and lives in the state directory.
43
+ * @param stateDir - the plugin state directory.
44
+ * @param credentials - the host's credential store, when loaded.
45
+ * @returns the storage.
46
+ */
47
+ export declare function grantStorage(stateDir: string, credentials: () => CredentialProvider | undefined): GrantStorage;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * The plugin's own VibeDev sign-in, for hosts whose account service does not
3
+ * hold a VibeDev session (official DeepSeek Harness). Authorization code with
4
+ * PKCE (S256) through the system browser and a loopback callback on
5
+ * 127.0.0.1; the gateway issues a plugin session (`client=vibedev-plugin`)
6
+ * whose access token is refreshed with a rotating refresh token.
7
+ *
8
+ * Contract (gateway vibedev204):
9
+ * - browser: `{origin}/vibedev-link?callback=http://127.0.0.1:<port>/<path>&state&response_type=code&code_challenge&code_challenge_method=S256&client=vibedev-plugin`
10
+ * - `POST /api/v1/vibedev/link/redeem {code, code_verifier, token_type:'app', client, device_id, device_model, os_version}`
11
+ * - `POST /api/v1/vibedev/app-token/refresh {refresh_token, device_id}`: a new pair every time; the old refresh token dies
12
+ * - `POST /api/v1/vibedev/app-token/revoke` (bearer or `{refresh_token}`): always 204
13
+ * @module dsh-vibedev/auth/login
14
+ */
15
+ /** A stored plugin session. */
16
+ export interface PluginGrant {
17
+ readonly accessToken: string;
18
+ readonly refreshToken: string;
19
+ /** Epoch ms. */
20
+ readonly expiresAt: number;
21
+ readonly refreshExpiresAt: number;
22
+ readonly sessionId?: string;
23
+ readonly user?: {
24
+ readonly id?: string;
25
+ readonly email?: string;
26
+ readonly nickname?: string;
27
+ };
28
+ }
29
+ /** What a read-modify-write of the stored grant does. */
30
+ export type GrantChange = {
31
+ readonly kind: 'keep';
32
+ } | {
33
+ readonly kind: 'set';
34
+ readonly grant: PluginGrant;
35
+ } | {
36
+ readonly kind: 'delete';
37
+ };
38
+ /** Where the grant and the device id live. */
39
+ export interface GrantStorage {
40
+ read(): Promise<PluginGrant | undefined>;
41
+ write(grant: PluginGrant | undefined): Promise<void>;
42
+ /**
43
+ * Read-modify-write of the stored grant, one at a time across processes
44
+ * where the store supports it, so two processes never spend one refresh token.
45
+ * @param change - decides the change from the grant as stored now.
46
+ */
47
+ update(change: (current: PluginGrant | undefined) => Promise<GrantChange>): Promise<void>;
48
+ /** A stable id for this installation, sent on redeem and on every refresh. */
49
+ deviceId(): Promise<string>;
50
+ }
51
+ /** Construction options; `fetch`, the clock and `openBrowser` are test seams. */
52
+ export interface PluginLoginOptions {
53
+ readonly origin: string;
54
+ readonly storage: GrantStorage;
55
+ readonly userAgent: string;
56
+ readonly fetch?: typeof globalThis.fetch;
57
+ readonly now?: () => number;
58
+ /** Open a URL in the system browser; resolves whether that was attempted successfully. */
59
+ readonly openBrowser?: (url: string) => Promise<boolean>;
60
+ /** How long a started sign-in waits for the browser. Defaults to 5 minutes. */
61
+ readonly signInTimeoutMs?: number;
62
+ /** The client name the gateway records for the sign-in (it picks the key the usage is billed to). Defaults to `vibedev-plugin`. */
63
+ readonly client?: string;
64
+ readonly log?: (message: string) => void;
65
+ }
66
+ /** A sign-in waiting for the browser. */
67
+ export interface PendingSignIn {
68
+ readonly url: string;
69
+ readonly expiresAt: number;
70
+ /** Settles when the sign-in completes, fails or times out. */
71
+ readonly done: Promise<PluginGrant>;
72
+ }
73
+ /**
74
+ * Read a token answer (`redeem` or `refresh`).
75
+ * @param body - the parsed envelope `{code, data}` or a bare data object.
76
+ * @param now - current epoch ms.
77
+ * @param previous - the grant being refreshed, whose identity carries over.
78
+ * @returns the grant, or undefined when the answer lacks tokens.
79
+ */
80
+ export declare function parseGrant(body: unknown, now: number, previous?: PluginGrant): PluginGrant | undefined;
81
+ /**
82
+ * Open a URL in the system browser without a shell (an `&` in the URL must not split a command line).
83
+ * @param url - the URL.
84
+ * @returns whether the opener started.
85
+ */
86
+ export declare function openInBrowser(url: string): Promise<boolean>;
87
+ /** The plugin's VibeDev session. */
88
+ export declare class PluginLogin {
89
+ private readonly options;
90
+ private grant;
91
+ private loaded;
92
+ private refreshing;
93
+ private pending;
94
+ private readonly listeners;
95
+ private readonly now;
96
+ private readonly origin;
97
+ /**
98
+ * @param options - gateway origin, storage and test seams.
99
+ */
100
+ constructor(options: PluginLoginOptions);
101
+ private load;
102
+ /** Take a grant as current and tell listeners when it changed. */
103
+ private adopt;
104
+ private save;
105
+ /**
106
+ * Hear about sign-in and sign-out.
107
+ * @param listener - called after every change.
108
+ * @returns unsubscribe.
109
+ */
110
+ onChange(listener: () => void): () => void;
111
+ /** The signed-in user, or undefined while signed out. */
112
+ user(): Promise<PluginGrant['user'] | undefined>;
113
+ /** Whether a sign-in is waiting for the browser, and its link. */
114
+ pendingSignIn(): {
115
+ url: string;
116
+ expiresAt: number;
117
+ } | undefined;
118
+ /**
119
+ * The access token for the next request, refreshed when it is about to expire.
120
+ * @returns the token, or undefined while signed out.
121
+ */
122
+ token(): Promise<string | undefined>;
123
+ /**
124
+ * The gateway rejected a token (401): refresh once, unless it already changed.
125
+ * @param token - the rejected token.
126
+ */
127
+ reject(token: string): Promise<void>;
128
+ /**
129
+ * Refresh one grant; concurrent callers share the request. The refresh runs
130
+ * inside the store's read-modify-write: when another process has already
131
+ * rotated the token, its grant is adopted instead of spending the old refresh
132
+ * token, which the gateway would treat as reuse and revoke the session.
133
+ * A rejected refresh signs out.
134
+ */
135
+ private refresh;
136
+ private post;
137
+ /**
138
+ * Start a sign-in: listen on a loopback port, open the authorization page in
139
+ * the system browser, and finish in the background when the browser returns.
140
+ * Starting again while one is waiting returns the waiting one.
141
+ * @param request - `open: false` leaves opening the link to the caller (a page that opens it itself).
142
+ * @returns the authorization link, whether a browser was opened, and the completion.
143
+ */
144
+ startSignIn(request?: {
145
+ open?: boolean;
146
+ }): Promise<PendingSignIn & {
147
+ opened: boolean;
148
+ }>;
149
+ private redeem;
150
+ /** Sign out: revoke the session at the gateway (best effort) and forget it. */
151
+ signOut(): Promise<void>;
152
+ /** Stop a waiting sign-in. */
153
+ dispose(): void;
154
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The gateway media library (`/v1/media-assets`): every reference a video
3
+ * request carries is uploaded here first, so the gateway can check its type and
4
+ * measure its length, and the provider fetches it from the gateway instead of
5
+ * an arbitrary link.
6
+ *
7
+ * Flow: `POST /uploads` (deduplicated by content digest), `PUT upload_url` with
8
+ * the returned upload headers when an upload is needed, `POST /{id}/complete`.
9
+ * An asset the library already holds is read back through `/refresh`, which
10
+ * also carries its measured duration.
11
+ * @module dsh-vibedev/gateway/assets
12
+ */
13
+ import type { GatewayHttp } from './http.js';
14
+ import type { LoadedMedia } from '../media/sources.js';
15
+ /** A media library asset a request can reference. */
16
+ export interface UploadedAsset {
17
+ readonly assetId: string;
18
+ /** The URL to put in a generation request. */
19
+ readonly referenceUrl: string;
20
+ readonly contentUrl?: string;
21
+ readonly contentType: string;
22
+ readonly expiresAt?: string;
23
+ /** Measured length of an audio or video, in milliseconds. */
24
+ readonly durationMs?: number;
25
+ readonly sha256: string;
26
+ readonly bytes: number;
27
+ }
28
+ /** Purposes the plugin uploads under. */
29
+ export type AssetPurpose = 'video_reference';
30
+ /**
31
+ * Read an asset answer from `uploads`, `complete` or `refresh`.
32
+ * @param body - the parsed answer.
33
+ * @param fallbackType - the type the upload declared.
34
+ * @returns the asset facts, or undefined when the answer names no usable URL.
35
+ */
36
+ export declare function parseAsset(body: unknown, fallbackType: string): Omit<UploadedAsset, 'sha256' | 'bytes'> | undefined;
37
+ /** Uploads references and remembers them for the life of the plugin. */
38
+ export declare class MediaLibrary {
39
+ private readonly http;
40
+ private readonly now;
41
+ private readonly cache;
42
+ /**
43
+ * @param http - the gateway client.
44
+ * @param now - clock, for expiry checks.
45
+ */
46
+ constructor(http: GatewayHttp, now?: () => number);
47
+ /** Forget every remembered asset, as after an account change: assets belong to the account that uploaded them. */
48
+ clear(): void;
49
+ /**
50
+ * Upload one loaded input, or reuse the asset the library already holds.
51
+ * @param media - the loaded input.
52
+ * @param purpose - the asset purpose.
53
+ * @param signal - cancels the upload.
54
+ * @returns the asset.
55
+ */
56
+ upload(media: LoadedMedia, purpose: AssetPurpose, signal?: AbortSignal): Promise<UploadedAsset>;
57
+ private expiring;
58
+ private remember;
59
+ private refresh;
60
+ private read;
61
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * The media models of the VibeDev gateway catalog (`GET /v1/models`): image,
3
+ * video, music/podcast and transcription models, with each model's declared
4
+ * capabilities and price. Chat models and models the client drives itself
5
+ * (`internal_role`) are left out.
6
+ *
7
+ * Video capabilities follow the gateway's `video` block: model-level limits plus
8
+ * the versioned per-mode declarations (`modes_schema_version: 1`). A mode the
9
+ * model does not list is unsupported; an unknown schema version makes the model
10
+ * unusable rather than guessed at.
11
+ * @module dsh-vibedev/gateway/catalog
12
+ */
13
+ /** What a media model produces. */
14
+ export type MediaKind = 'image' | 'video' | 'audio' | 'transcription';
15
+ /** The video generation modes of catalog schema v1, under their wire names. */
16
+ export declare const VIDEO_MODES: readonly ["text_to_video", "first_frame", "first_last_frame", "omni_reference"];
17
+ export type VideoMode = typeof VIDEO_MODES[number];
18
+ /** The inputs a video request can carry, under the gateway's request field names. */
19
+ export declare const VIDEO_INPUTS: readonly ["firstFrame", "lastFrame", "referenceImages", "referenceVideos", "referenceAudios"];
20
+ export type VideoInput = typeof VIDEO_INPUTS[number];
21
+ /** How many of one input a mode accepts, and whether it must be a gateway-hosted asset. */
22
+ export interface VideoInputLimit {
23
+ readonly min: number;
24
+ readonly max: number;
25
+ /** The input must be uploaded to the gateway media library first. */
26
+ readonly hosted: boolean;
27
+ }
28
+ /** One mode's declaration. Lists that are absent inherit the model-level lists. */
29
+ export interface VideoModeConstraint {
30
+ readonly inputs: Partial<Record<VideoInput, VideoInputLimit>>;
31
+ /** At least one group must be fully present (each input at least once). Empty: no requirement. */
32
+ readonly requiredAnyOf: readonly (readonly VideoInput[])[];
33
+ readonly ratios?: readonly string[];
34
+ readonly resolutions?: readonly string[];
35
+ readonly durations?: readonly number[];
36
+ }
37
+ /** One allowed duration/ratio/resolution combination. */
38
+ export interface VideoCombination {
39
+ readonly duration?: number;
40
+ readonly ratio?: string;
41
+ readonly resolution?: string;
42
+ }
43
+ /** A video model's declared capabilities. */
44
+ export interface VideoCapabilities {
45
+ /**
46
+ * Per-mode declarations. `undefined` for a legacy entry without modes, whose
47
+ * modes are derived from the model-level fields by {@link effectiveVideoModes}.
48
+ */
49
+ readonly modes?: Partial<Record<VideoMode, VideoModeConstraint>>;
50
+ /** A modes block was present but its schema version is not one this plugin reads. */
51
+ readonly unreadableModesVersion?: number;
52
+ readonly ratios?: readonly string[];
53
+ readonly resolutions?: readonly string[];
54
+ readonly durations?: readonly number[];
55
+ readonly combinations?: readonly VideoCombination[];
56
+ readonly nativeAudio?: boolean;
57
+ readonly textToVideo?: boolean;
58
+ readonly imageToVideo?: boolean;
59
+ readonly firstFrame?: boolean;
60
+ readonly lastFrame?: boolean;
61
+ readonly maxReferenceImages?: number;
62
+ readonly maxReferenceVideos?: number;
63
+ readonly maxReferenceAudios?: number;
64
+ readonly allowedImageMimes?: readonly string[];
65
+ readonly allowedVideoMimes?: readonly string[];
66
+ readonly allowedAudioMimes?: readonly string[];
67
+ readonly maxReferenceImageBytes?: number;
68
+ readonly maxReferenceVideoBytes?: number;
69
+ readonly maxReferenceAudioBytes?: number;
70
+ readonly maxAssetBytes?: number;
71
+ readonly minReferenceVideoSeconds?: number;
72
+ readonly maxReferenceVideoSeconds?: number;
73
+ readonly maxTotalReferenceVideoSeconds?: number;
74
+ /** References must be relayed through the gateway media library. */
75
+ readonly gatewayRelayRequired?: boolean;
76
+ }
77
+ /** One price tier: video tiers are resolutions (`720p`), image tiers size buckets (`1K`). */
78
+ export interface MediaPriceTier {
79
+ readonly tier: string;
80
+ readonly unit: 'generation' | 'second';
81
+ readonly amount: number;
82
+ }
83
+ /** A model's selling price, account multiplier included. */
84
+ export interface MediaPricing {
85
+ readonly currency: string;
86
+ readonly tiers: readonly MediaPriceTier[];
87
+ readonly default?: {
88
+ readonly unit: 'generation' | 'second';
89
+ readonly amount: number;
90
+ };
91
+ }
92
+ /** One media model of the catalog. */
93
+ export interface MediaModel {
94
+ readonly id: string;
95
+ readonly name: string;
96
+ readonly description?: string;
97
+ readonly kind: MediaKind;
98
+ /** For audio models: what they produce. */
99
+ readonly audioKind?: 'music' | 'podcast';
100
+ /** Endpoints the catalog lists for the model. */
101
+ readonly endpoints: readonly string[];
102
+ readonly inputModalities: readonly string[];
103
+ readonly pricing?: MediaPricing;
104
+ readonly video?: VideoCapabilities;
105
+ }
106
+ type Json = Record<string, unknown>;
107
+ /**
108
+ * Parse a `video` capability block (or the legacy video fields inside `capabilities`).
109
+ * @param raw - the block.
110
+ * @returns the capabilities found.
111
+ */
112
+ export declare function parseVideoCapabilities(raw: Json): VideoCapabilities;
113
+ /**
114
+ * The modes a model can serve: its declared v1 modes, or for a legacy entry the
115
+ * conservative set its model-level fields imply. An unreadable modes block serves none.
116
+ * @param video - the model's capabilities.
117
+ * @returns the usable modes and their constraints.
118
+ */
119
+ export declare function effectiveVideoModes(video: VideoCapabilities): Partial<Record<VideoMode, VideoModeConstraint>>;
120
+ /**
121
+ * Parse a `/v1/models` body into its media models.
122
+ * @param body - `{data:[...]}` or a bare array.
123
+ * @returns the media models, in catalog order.
124
+ */
125
+ export declare function parseMediaCatalog(body: unknown): MediaModel[];
126
+ export {};
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Failures the plugin reports to the model: a gateway refusal, or a request the
3
+ * plugin refused before anything was sent or charged. Messages are written for
4
+ * the model to act on and relay to the user.
5
+ * @module dsh-vibedev/gateway/errors
6
+ */
7
+ import { HarnessError } from '@deepseek-ai/dsh-llm';
8
+ /** Machine-readable detail carried next to the message. */
9
+ export interface MediaErrorDetails {
10
+ /** HTTP status when the gateway answered. */
11
+ readonly status?: number;
12
+ /** Whether the same request may succeed later. */
13
+ readonly retryable?: boolean;
14
+ /** The request field the failure names, when the gateway says which. */
15
+ readonly field?: string;
16
+ /** Where the user tops up, on a balance refusal. */
17
+ readonly rechargeUrl?: string;
18
+ /** How long the gateway asked the client to wait. */
19
+ readonly retryAfterMs?: number;
20
+ /** The gateway was full and created nothing (a busy 429/503). */
21
+ readonly busy?: boolean;
22
+ /** On a task-limit refusal: tasks in progress and the account's limit. */
23
+ readonly active?: number;
24
+ readonly limit?: number;
25
+ /** On an admission balance refusal: amounts in CNY, as the gateway's two-decimal strings. */
26
+ readonly estimatedCny?: string;
27
+ readonly availableCny?: string;
28
+ readonly pendingCny?: string;
29
+ }
30
+ /**
31
+ * One failure, with a stable `code` to route on and a message to show. It is a
32
+ * harness error, so a tool failure keeps the code in the durable tool result
33
+ * where a client can route on it (sign-in card, top-up link).
34
+ */
35
+ export declare class MediaError extends HarnessError {
36
+ readonly details: MediaErrorDetails;
37
+ /**
38
+ * @param message - what happened and what to do next.
39
+ * @param code - stable failure class, such as `INSUFFICIENT_BALANCE` or `VIDEO_MODE_UNSUPPORTED`.
40
+ * @param details - status, retry and field facts.
41
+ * @param options - the underlying cause, when there is one.
42
+ */
43
+ constructor(message: string, code: string, details?: MediaErrorDetails, options?: ErrorOptions);
44
+ }
45
+ /** The parts of a gateway error body the plugin reads, whatever its shape. */
46
+ export interface GatewayFailure {
47
+ readonly code?: string;
48
+ readonly message?: string;
49
+ readonly field?: string;
50
+ readonly retryable?: boolean;
51
+ readonly rechargeUrl?: string;
52
+ readonly active?: number;
53
+ readonly limit?: number;
54
+ readonly estimatedCny?: string;
55
+ readonly availableCny?: string;
56
+ readonly pendingCny?: string;
57
+ }
58
+ /**
59
+ * Read a gateway error body. The gateway answers in several shapes: OpenAI's
60
+ * `{error:{code,message,type}}`, its own `{error:{code,message,retryable,field}}`,
61
+ * the account API's `{code,message,reason}`, and a top-level `recharge_url` on
62
+ * balance refusals. Media admission refusals add `active`/`limit` (task limit)
63
+ * or `estimated_cny`/`available_cny`/`pending_cny` (balance).
64
+ * @param body - the parsed JSON body, or undefined when it was not JSON.
65
+ * @returns the fields found.
66
+ */
67
+ export declare function parseGatewayFailure(body: unknown): GatewayFailure;
68
+ /**
69
+ * Milliseconds a `Retry-After` header asks for: delta seconds or an HTTP date.
70
+ * @param header - the header value, or null when absent.
71
+ * @param now - current epoch milliseconds, for an HTTP date.
72
+ * @returns the wait, or undefined when absent or unreadable.
73
+ */
74
+ export declare function retryAfterMs(header: string | null, now?: number): number | undefined;
75
+ /** `(CODE: message)`, for appending the gateway's own words to a message. */
76
+ export declare function gatewayWords(failure: GatewayFailure): string;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * HTTP client for the VibeDev gateway. Every gateway call goes through here so
3
+ * authentication, refresh after a 401, balance refusals, busy back-off and
4
+ * idempotency are handled once.
5
+ *
6
+ * The credential is attached only to requests on the gateway origin: upload
7
+ * URLs and third-party links never see it.
8
+ * @module dsh-vibedev/gateway/http
9
+ */
10
+ import { MediaError } from './errors.js';
11
+ import type { GatewayFailure } from './errors.js';
12
+ /** The credential one request carries. */
13
+ export interface GatewayCredential {
14
+ readonly token: string;
15
+ /**
16
+ * Where it came from: the host's VibeDev account (`account`), the plugin's own
17
+ * sign-in (`plugin`), or a development key from the environment (`key`). Only
18
+ * account and plugin tokens can be refreshed after a 401.
19
+ */
20
+ readonly kind: 'account' | 'plugin' | 'key';
21
+ }
22
+ /** Construction options; `fetch` and `sleep` are test seams. */
23
+ export interface GatewayHttpOptions {
24
+ /** Gateway origin, such as `https://vibedev.jzsaas.com`. */
25
+ readonly origin: string;
26
+ /** The credential for the next request; undefined while nobody is signed in. */
27
+ readonly resolveCredential: () => Promise<GatewayCredential | undefined>;
28
+ /** Report a token the gateway rejected, so its owner refreshes it. */
29
+ readonly rejectToken?: (credential: GatewayCredential) => Promise<void>;
30
+ /** `User-Agent` for every request. */
31
+ readonly userAgent: string;
32
+ readonly fetch?: typeof globalThis.fetch;
33
+ readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
34
+ }
35
+ /** One request. */
36
+ export interface GatewayRequest {
37
+ readonly method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
38
+ /** JSON body; serialized with `content-type: application/json`. */
39
+ readonly json?: unknown;
40
+ /** Raw body (multipart form, bytes) when `json` is not used. */
41
+ readonly body?: FormData | Uint8Array | string;
42
+ readonly headers?: Readonly<Record<string, string>>;
43
+ readonly signal?: AbortSignal;
44
+ /** Deadline for each attempt. */
45
+ readonly timeoutMs?: number;
46
+ /** Sent as `Idempotency-Key`; makes a retried submission return the original task. */
47
+ readonly idempotencyKey?: string;
48
+ /** Send without the credential (pre-signed upload URLs, public content links). */
49
+ readonly anonymous?: boolean;
50
+ /** Retries after a busy answer (429, or 503 with a busy code or `Retry-After`). Defaults to 2. */
51
+ readonly busyRetries?: number;
52
+ /** Longest single wait for a busy answer; a longer `Retry-After` fails at once. Defaults to 15 s. */
53
+ readonly maxBusyWaitMs?: number;
54
+ }
55
+ /** The message for a call made while nobody is signed in. */
56
+ export declare const SIGN_IN_MESSAGE: string;
57
+ /** Gateway HTTP client. */
58
+ export declare class GatewayHttp {
59
+ private readonly options;
60
+ readonly origin: string;
61
+ /**
62
+ * @param options - origin, credential plane, user agent and test seams.
63
+ */
64
+ constructor(options: GatewayHttpOptions);
65
+ /** Absolute URL for a gateway path, or the URL itself when already absolute. */
66
+ url(path: string): string;
67
+ /** Whether a URL is on the gateway origin, and so may carry the credential. */
68
+ isGatewayUrl(url: string): boolean;
69
+ /**
70
+ * Send one request and return the successful response.
71
+ * @param path - gateway path, or an absolute URL.
72
+ * @param request - method, body, headers and retry policy.
73
+ * @returns the 2xx response, body unread.
74
+ * @throws {@link MediaError} for every refusal, with the gateway's code.
75
+ */
76
+ send(path: string, request?: GatewayRequest): Promise<Response>;
77
+ /**
78
+ * Send one request and parse its JSON body.
79
+ * @param path - gateway path, or an absolute URL.
80
+ * @param request - method, body, headers and retry policy.
81
+ * @returns the parsed body.
82
+ */
83
+ json<T = unknown>(path: string, request?: GatewayRequest): Promise<T>;
84
+ private credential;
85
+ private attempt;
86
+ }
87
+ /**
88
+ * The error for an answer the client does not retry, worded for the model.
89
+ * @param status - HTTP status.
90
+ * @param failure - the parsed error body.
91
+ * @param wait - Retry-After in milliseconds, when given.
92
+ * @returns the error to throw.
93
+ */
94
+ export declare function failureError(status: number, failure: GatewayFailure, wait?: number): MediaError;
package/lib/index.d.ts ADDED
@@ -0,0 +1,105 @@
1
+ /**
2
+ * dsh-vibedev (formerly dsh-media): the VibeDev account and the VibeDev
3
+ * gateway for DeepSeek Harness — its chat models in the model pickers on their
4
+ * own route (`vibedev-gateway`), next to the DeepSeek account's, and image,
5
+ * video, music, podcast and speech-to-text tools for the agent.
6
+ *
7
+ * Everything is paid from the user's VibeDev balance: inside the VibeDev app
8
+ * the app's signed-in account is used; elsewhere the plugin signs in to
9
+ * VibeDev itself (the sidebar's "登录 VibeDev", Settings → VibeDev 账号, or the
10
+ * `media_account` tool). The DeepSeek account stays the Harness's own.
11
+ *
12
+ * Kept from dsh-media so an upgrade carries over: the sign-in record
13
+ * (`dsh-media/vibedev-session`), the data folder (`<harness home>/dsh-media`),
14
+ * the `vibedevMedia` host service and the media tool names.
15
+ *
16
+ * ```yaml
17
+ * - insert:
18
+ * - id: dsh-vibedev
19
+ * name: '@vibedev-si/dsh-vibedev'
20
+ * ```
21
+ * @module dsh-vibedev
22
+ */
23
+ import type { Context, Volatile } from '@deepseek-ai/cordis';
24
+ import Schema from '@deepseek-ai/schemastery';
25
+ export { MediaError } from './gateway/errors.js';
26
+ export { MediaHostService } from './service.js';
27
+ export type { HostTarget, MediaTaskView } from './service.js';
28
+ export type { ImageRequest } from './tools/image.js';
29
+ export type { VideoRequest } from './tools/video.js';
30
+ export { parseMediaCatalog } from './gateway/catalog.js';
31
+ export type { MediaModel, VideoCapabilities, VideoMode } from './gateway/catalog.js';
32
+ export { ACCOUNT_ROUTE_PREFIX, AccountService } from './account/index.js';
33
+ export type { AccountSource, AccountView } from './account/index.js';
34
+ export { GATEWAY_SEARCH_PROVIDER_ID as SEARCH_PROVIDER_ID } from './search/provider.js';
35
+ export { INSUFFICIENT_BALANCE_CODE, SIGN_IN_REQUIRED_CODE, VIBEDEV_ROUTE } from './llm/index.js';
36
+ /** The package version, sent in the `User-Agent` the gateway attributes plugin traffic by. */
37
+ export declare const version: string;
38
+ export declare const name = "dsh-vibedev";
39
+ export declare const inject: string[];
40
+ export interface Config {
41
+ /** Name the model pickers and the Models page show for the VibeDev models. */
42
+ displayName: string;
43
+ /** VibeDev chat models listed first, in this order, when the catalog offers them. */
44
+ preferredModels: string[];
45
+ /** Open the system browser when a sign-in starts (off: the page opens the link itself). */
46
+ openBrowserOnSignIn: boolean;
47
+ /** Minutes between catalog reads while the app runs. */
48
+ catalogRefreshMinutes: number;
49
+ /** Ask the user before each paid request. */
50
+ confirmSpending: Volatile<boolean>;
51
+ /** Output folder, relative to the workspace (or absolute). */
52
+ outputDir: Volatile<string>;
53
+ /** Pinned models; empty lets the agent choose from the catalog. */
54
+ imageModel: Volatile<string>;
55
+ videoModel: Volatile<string>;
56
+ musicModel: Volatile<string>;
57
+ podcastModel: Volatile<string>;
58
+ transcriptionModel: Volatile<string>;
59
+ /** Gateway origin. */
60
+ gatewayOrigin: string;
61
+ /** Client name sent with the sign-in (`vibedev-plugin` in DeepSeek Harness; the VibeDev app sets its own). */
62
+ client: string;
63
+ /** The VibeDev account is the app's main account: its row leads the sidebar foot and Settings (the VibeDev app). */
64
+ primary: boolean;
65
+ /** Environment variable holding a development key, used only while nobody is signed in. */
66
+ apiKeyEnv: string;
67
+ /** Where tasks and the plugin's own sign-in are kept; empty for `<harness home>/dsh-media`. */
68
+ stateDir: string;
69
+ }
70
+ export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
71
+ displayName: Schema<string, string, "defined">;
72
+ preferredModels: Schema<string[], string[], "defined">;
73
+ openBrowserOnSignIn: Schema<boolean, boolean, "defined">;
74
+ catalogRefreshMinutes: Schema<number, number, "defined">;
75
+ confirmSpending: Schema<boolean, boolean, "volatile-defined">;
76
+ outputDir: Schema<string, string, "volatile-defined">;
77
+ imageModel: Schema<string, string, "volatile-defined">;
78
+ videoModel: Schema<string, string, "volatile-defined">;
79
+ musicModel: Schema<string, string, "volatile-defined">;
80
+ podcastModel: Schema<string, string, "volatile-defined">;
81
+ transcriptionModel: Schema<string, string, "volatile-defined">;
82
+ gatewayOrigin: Schema<string, string, "defined">;
83
+ client: Schema<string, string, "defined">;
84
+ primary: Schema<boolean, boolean, "defined">;
85
+ apiKeyEnv: Schema<string, string, "defined">;
86
+ stateDir: Schema<string, string, "defined">;
87
+ }>>, Schemastery.ObjectT<NoInfer<{
88
+ displayName: Schema<string, string, "defined">;
89
+ preferredModels: Schema<string[], string[], "defined">;
90
+ openBrowserOnSignIn: Schema<boolean, boolean, "defined">;
91
+ catalogRefreshMinutes: Schema<number, number, "defined">;
92
+ confirmSpending: Schema<boolean, boolean, "volatile-defined">;
93
+ outputDir: Schema<string, string, "volatile-defined">;
94
+ imageModel: Schema<string, string, "volatile-defined">;
95
+ videoModel: Schema<string, string, "volatile-defined">;
96
+ musicModel: Schema<string, string, "volatile-defined">;
97
+ podcastModel: Schema<string, string, "volatile-defined">;
98
+ transcriptionModel: Schema<string, string, "volatile-defined">;
99
+ gatewayOrigin: Schema<string, string, "defined">;
100
+ client: Schema<string, string, "defined">;
101
+ primary: Schema<boolean, boolean, "defined">;
102
+ apiKeyEnv: Schema<string, string, "defined">;
103
+ stateDir: Schema<string, string, "defined">;
104
+ }>>, "plain">;
105
+ export declare function apply(ctx: Context, config: Config): void;