@vibesdotdev/runtime-client 0.0.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 (63) hide show
  1. package/README.md +97 -0
  2. package/SPEC.md +44 -0
  3. package/dist/base.d.ts +49 -0
  4. package/dist/base.d.ts.map +1 -0
  5. package/dist/base.js +86 -0
  6. package/dist/base.js.map +1 -0
  7. package/dist/contract.d.ts +23 -0
  8. package/dist/contract.d.ts.map +1 -0
  9. package/dist/contract.js +2 -0
  10. package/dist/contract.js.map +1 -0
  11. package/dist/docs/runtime-client.api.docs.descriptor.d.ts +8 -0
  12. package/dist/docs/runtime-client.api.docs.descriptor.d.ts.map +1 -0
  13. package/dist/docs/runtime-client.api.docs.descriptor.js +344 -0
  14. package/dist/docs/runtime-client.api.docs.descriptor.js.map +1 -0
  15. package/dist/docs/runtime-client.helpers.docs.descriptor.d.ts +8 -0
  16. package/dist/docs/runtime-client.helpers.docs.descriptor.d.ts.map +1 -0
  17. package/dist/docs/runtime-client.helpers.docs.descriptor.js +352 -0
  18. package/dist/docs/runtime-client.helpers.docs.descriptor.js.map +1 -0
  19. package/dist/docs/runtime-client.surface.docs.descriptor.d.ts +8 -0
  20. package/dist/docs/runtime-client.surface.docs.descriptor.d.ts.map +1 -0
  21. package/dist/docs/runtime-client.surface.docs.descriptor.js +464 -0
  22. package/dist/docs/runtime-client.surface.docs.descriptor.js.map +1 -0
  23. package/dist/docs/types.d.ts +19 -0
  24. package/dist/docs/types.d.ts.map +1 -0
  25. package/dist/docs/types.js +2 -0
  26. package/dist/docs/types.js.map +1 -0
  27. package/dist/helper.d.ts +14 -0
  28. package/dist/helper.d.ts.map +1 -0
  29. package/dist/helper.js +27 -0
  30. package/dist/helper.js.map +1 -0
  31. package/dist/index.d.ts +8 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +8 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/kind.d.ts +10 -0
  36. package/dist/kind.d.ts.map +1 -0
  37. package/dist/kind.js +12 -0
  38. package/dist/kind.js.map +1 -0
  39. package/dist/plugin.d.ts +10 -0
  40. package/dist/plugin.d.ts.map +1 -0
  41. package/dist/plugin.js +17 -0
  42. package/dist/plugin.js.map +1 -0
  43. package/dist/runtime-client.plugin.d.ts +13 -0
  44. package/dist/runtime-client.plugin.d.ts.map +1 -0
  45. package/dist/runtime-client.plugin.js +27 -0
  46. package/dist/runtime-client.plugin.js.map +1 -0
  47. package/dist/schema.d.ts +32 -0
  48. package/dist/schema.d.ts.map +1 -0
  49. package/dist/schema.js +8 -0
  50. package/dist/schema.js.map +1 -0
  51. package/package.json +61 -0
  52. package/src/base.ts +100 -0
  53. package/src/contract.ts +23 -0
  54. package/src/docs/runtime-client.api.docs.descriptor.ts +346 -0
  55. package/src/docs/runtime-client.helpers.docs.descriptor.ts +354 -0
  56. package/src/docs/runtime-client.surface.docs.descriptor.ts +466 -0
  57. package/src/docs/types.ts +18 -0
  58. package/src/helper.ts +32 -0
  59. package/src/index.ts +11 -0
  60. package/src/kind.ts +14 -0
  61. package/src/plugin.ts +19 -0
  62. package/src/runtime-client.plugin.ts +32 -0
  63. package/src/schema.ts +27 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Runtime Client Docs Plugin
3
+ *
4
+ * Registers documentation descriptors for runtime-client APIs:
5
+ * - runtime-client.api — BaseRuntimeClient class, client patterns, how to extend
6
+ * - runtime-client.helpers — getVibesClient() helper functions, surface detection
7
+ * - runtime-client.surface — How surfaces (CLI, SSR, browser, worker) initialize clients
8
+ *
9
+ * This plugin is surface-neutral — docs descriptors work in CLI, SSR, and worker contexts.
10
+ */
11
+ import { createRuntimePlugin } from '@vibesdotdev/runtime';
12
+ // Docs descriptors
13
+ import runtimeClientApiDocs from "./docs/runtime-client.api.docs.descriptor.js";
14
+ import runtimeClientHelpersDocs from "./docs/runtime-client.helpers.docs.descriptor.js";
15
+ import runtimeClientSurfaceDocs from "./docs/runtime-client.surface.docs.descriptor.js";
16
+ export const runtimeClientDocsPlugin = createRuntimePlugin({
17
+ id: 'runtime-client.docs',
18
+ name: 'Runtime Client Documentation',
19
+ description: 'Runtime client APIs: BaseRuntimeClient, getVibesClient helpers, surface initialization',
20
+ descriptors: [
21
+ runtimeClientApiDocs,
22
+ runtimeClientHelpersDocs,
23
+ runtimeClientSurfaceDocs
24
+ ]
25
+ });
26
+ export default runtimeClientDocsPlugin;
27
+ //# sourceMappingURL=runtime-client.plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-client.plugin.js","sourceRoot":"","sources":["../src/runtime-client.plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,mBAAmB;AACnB,OAAO,oBAAoB,MAAM,8CAA8C,CAAC;AAChF,OAAO,wBAAwB,MAAM,kDAAkD,CAAC;AACxF,OAAO,wBAAwB,MAAM,kDAAkD,CAAC;AAExF,MAAM,CAAC,MAAM,uBAAuB,GAAG,mBAAmB,CAAC;IACzD,EAAE,EAAE,qBAAqB;IACzB,IAAI,EAAE,8BAA8B;IACpC,WAAW,EACT,wFAAwF;IAE1F,WAAW,EAAE;QACX,oBAAoB;QACpB,wBAAwB;QACxB,wBAAwB;KACzB;CACF,CAAC,CAAC;AAEH,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import * as z from 'zod/v4';
2
+ import { type RuntimeDescriptor } from '@vibesdotdev/runtime/schemas/descriptor';
3
+ /**
4
+ * Descriptor for the `runtime/client` kind.
5
+ *
6
+ * Every module that exposes a top-level client registers exactly one of these.
7
+ * The descriptor id matches the module name (`ai`, `tools`, `knowledge`, …).
8
+ *
9
+ * `configManifestId`, if set, causes `BaseRuntimeClient.onLoad()` to load the
10
+ * corresponding config manifest and expose its values to subclasses.
11
+ */
12
+ export interface RuntimeClientDescriptor extends RuntimeDescriptor {
13
+ /** Narrows the base `kind: string` to the literal `'runtime/client'`. */
14
+ kind: 'runtime/client';
15
+ /** If set, BaseRuntimeClient.onLoad() loads the corresponding config manifest. */
16
+ configManifestId?: string;
17
+ }
18
+ export declare const RuntimeClientDescriptorSchema: z.ZodObject<{
19
+ id: z.ZodString;
20
+ name: z.ZodOptional<z.ZodString>;
21
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
22
+ hardware: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
+ enabled: z.ZodOptional<z.ZodBoolean>;
24
+ priority: z.ZodOptional<z.ZodNumber>;
25
+ requiredContext: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
+ optionalContext: z.ZodOptional<z.ZodArray<z.ZodString>>;
27
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
28
+ kind: z.ZodLiteral<"runtime/client">;
29
+ configManifestId: z.ZodOptional<z.ZodString>;
30
+ description: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>;
32
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAEN,KAAK,iBAAiB,EACtB,MAAM,yCAAyC,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,WAAW,uBAAwB,SAAQ,iBAAiB;IACjE,yEAAyE;IACzE,IAAI,EAAE,gBAAgB,CAAC;IACvB,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;iBAIxC,CAAC"}
package/dist/schema.js ADDED
@@ -0,0 +1,8 @@
1
+ import * as z from 'zod/v4';
2
+ import { RuntimeDescriptorSchema } from '@vibesdotdev/runtime/schemas/descriptor';
3
+ export const RuntimeClientDescriptorSchema = RuntimeDescriptorSchema.extend({
4
+ kind: z.literal('runtime/client'),
5
+ configManifestId: z.string().optional(),
6
+ description: z.string().optional()
7
+ });
8
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAC5B,OAAO,EACN,uBAAuB,EAEvB,MAAM,yCAAyC,CAAC;AAkBjD,MAAM,CAAC,MAAM,6BAA6B,GAAG,uBAAuB,CAAC,MAAM,CAAC;IAC3E,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACjC,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@vibesdotdev/runtime-client",
3
+ "version": "0.0.1",
4
+ "description": "Shared base + `runtime/client` kind for module-level vibes clients (one client per module, runtime-resolved).",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "bun": "./src/index.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./plugin": {
16
+ "types": "./dist/plugin.d.ts",
17
+ "bun": "./src/plugin.ts",
18
+ "import": "./dist/plugin.js",
19
+ "default": "./dist/plugin.js"
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "@vibesdotdev/runtime": "0.0.1"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "check": "bun --bun tsc -p tsconfig.json --noEmit"
28
+ },
29
+ "license": "MIT",
30
+ "files": [
31
+ "dist",
32
+ "src",
33
+ "bin",
34
+ "README.md",
35
+ "SPEC.md",
36
+ "LICENSE",
37
+ "!src/**/__tests__/**",
38
+ "!src/**/__stubs__/**",
39
+ "!src/**/*.test.ts",
40
+ "!src/**/*.test.tsx",
41
+ "!src/**/*.spec.ts",
42
+ "!src/**/*.spec.tsx",
43
+ "!dist/**/__tests__/**",
44
+ "!dist/**/__stubs__/**",
45
+ "!dist/**/*.test.js",
46
+ "!dist/**/*.test.js.map",
47
+ "!dist/**/*.test.d.ts",
48
+ "!dist/**/*.test.d.ts.map",
49
+ "!dist/**/*.spec.js",
50
+ "!dist/**/*.spec.js.map",
51
+ "!dist/**/*.spec.d.ts",
52
+ "!dist/**/*.spec.d.ts.map"
53
+ ],
54
+ "publishConfig": {
55
+ "registry": "https://registry.npmjs.org",
56
+ "access": "public"
57
+ },
58
+ "vibes": {
59
+ "visibility": "public-framework"
60
+ }
61
+ }
package/src/base.ts ADDED
@@ -0,0 +1,100 @@
1
+ import { getVibesRuntime, type VibesRuntime } from '@vibesdotdev/runtime';
2
+ import type { RuntimeClient } from './contract.ts';
3
+ import type { RuntimeClientDescriptor } from './schema.ts';
4
+
5
+ /**
6
+ * Shared base for module-level clients.
7
+ *
8
+ * Handles:
9
+ * - ambient runtime acquisition (via `getVibesRuntime()`)
10
+ * - idempotent lazy init (`ensureLoaded()`)
11
+ * - `config/manifest` auto-loading when `descriptor.configManifestId` is set
12
+ * - lifecycle hooks (`onLoad`, `onDispose`) for subclasses
13
+ *
14
+ * Subclasses (AIClient, ToolsClient, …) add their domain methods and call
15
+ * `this.ensureLoaded()` at method entry points when their behavior depends
16
+ * on loaded config.
17
+ *
18
+ * Constructor signature matches the runtime's kind-instantiation contract:
19
+ * `(descriptor, context?)`. Context is not currently consumed — runtime
20
+ * access goes through the ambient singleton — but remains a parameter for
21
+ * forward compatibility with kind contexts that carry scope metadata.
22
+ */
23
+ export abstract class BaseRuntimeClient implements RuntimeClient {
24
+ readonly id: string;
25
+ readonly runtime: VibesRuntime;
26
+
27
+ protected readonly descriptor: RuntimeClientDescriptor;
28
+ protected configValues: unknown | null = null;
29
+
30
+ private loadPromise?: Promise<void>;
31
+
32
+ constructor(
33
+ descriptor: RuntimeClientDescriptor,
34
+ _context?: unknown,
35
+ runtime?: VibesRuntime
36
+ ) {
37
+ this.descriptor = descriptor;
38
+ this.id = descriptor.id;
39
+ // Ambient runtime is the default path (matches `getVibesClient<T>(id)`).
40
+ // Explicit runtime override is available for legacy factory callers and
41
+ // advanced scenarios (e.g. multi-runtime test harnesses).
42
+ this.runtime = runtime ?? getVibesRuntime();
43
+ }
44
+
45
+ /**
46
+ * Idempotent lazy init. First call drives `onLoad()`; subsequent calls
47
+ * await the same promise. Subclasses call this at method entry points
48
+ * when they need config loaded.
49
+ */
50
+ async ensureLoaded(): Promise<void> {
51
+ if (!this.loadPromise) {
52
+ this.loadPromise = this.runLoad();
53
+ }
54
+ return this.loadPromise;
55
+ }
56
+
57
+ /** Public `load()` matching the `RuntimeClient` contract. Alias of `ensureLoaded()`. */
58
+ async load(): Promise<void> {
59
+ return this.ensureLoaded();
60
+ }
61
+
62
+ dispose(): void {
63
+ this.loadPromise = undefined;
64
+ this.configValues = null;
65
+ this.onDispose();
66
+ }
67
+
68
+ /**
69
+ * Override to perform module-specific initialization. Default behavior:
70
+ * if `descriptor.configManifestId` is set, resolve the corresponding
71
+ * `config/manifest` and load its values into `this.configValues`.
72
+ */
73
+ protected async onLoad(): Promise<void> {
74
+ const manifestId = this.descriptor.configManifestId;
75
+ if (!manifestId) return;
76
+ try {
77
+ const manifest = (await this.runtime
78
+ .query('config/manifest')
79
+ .withId(manifestId)
80
+ .resolve()) as { load?: () => Promise<unknown> } | undefined;
81
+ if (manifest?.load) {
82
+ this.configValues = await manifest.load();
83
+ }
84
+ } catch {
85
+ // Config is best-effort at the base layer. Subclasses handle required/missing config.
86
+ this.configValues = null;
87
+ }
88
+ }
89
+
90
+ protected onDispose(): void {}
91
+
92
+ /** Subclass accessor for loaded config values (null if load hasn't run or failed). */
93
+ protected getConfigValues<T = unknown>(): T | null {
94
+ return this.configValues as T | null;
95
+ }
96
+
97
+ private async runLoad(): Promise<void> {
98
+ await this.onLoad();
99
+ }
100
+ }
@@ -0,0 +1,23 @@
1
+ import type { VibesRuntime } from '@vibesdotdev/runtime';
2
+
3
+ /**
4
+ * Base contract every module-level client satisfies.
5
+ *
6
+ * Module-specific clients extend this with domain methods:
7
+ * AIClient adds `generate`, `getProvider`, `listModels`, …
8
+ * ToolsClient adds `listTools`, `runTool`, …
9
+ * KnowledgeClient adds `search`, `ingest`, …
10
+ *
11
+ * All clients share the same shape for lifecycle + runtime access so that
12
+ * consumers, tests, and tooling can treat them uniformly.
13
+ */
14
+ export interface RuntimeClient {
15
+ /** The descriptor id this client was registered with. */
16
+ readonly id: string;
17
+ /** Runtime reference the client uses for internal resolution. */
18
+ readonly runtime: VibesRuntime;
19
+ /** Idempotent load. Safe to call repeatedly; internal state cached. */
20
+ load(): Promise<void>;
21
+ /** Release any client-held resources (subscriptions, caches, etc.). */
22
+ dispose(): void;
23
+ }
@@ -0,0 +1,346 @@
1
+ import type { DocsTopicDescriptor } from './types.ts';
2
+
3
+ /**
4
+ * Descriptor for runtime-client.api
5
+ * BaseRuntimeClient class, client patterns, how to extend
6
+ */
7
+ const descriptor: DocsTopicDescriptor = {
8
+ kind: 'docs/topic',
9
+ id: 'runtime-client.api',
10
+ title: 'Runtime Client API',
11
+ summary: 'BaseRuntimeClient base class and patterns for extending module-level clients',
12
+ body: {
13
+ type: 'markdown',
14
+ sourceType: 'raw',
15
+ source: `---
16
+ title: Runtime Client API
17
+ summary: BaseRuntimeClient base class and patterns for extending module-level clients
18
+ tags: [runtime-client, base-class, extension, api, patterns]
19
+ parent: runtime-client
20
+ order: 1
21
+ surfaces: [cli, web, in-app]
22
+ hardware: [consumer, cloud]
23
+ ---
24
+
25
+ # Runtime Client API
26
+
27
+ The \`BaseRuntimeClient\` class provides a shared foundation for module-level clients (AIClient, ToolsClient, KnowledgeClient, etc.). It handles runtime acquisition, idempotent lazy initialization, config loading, and lifecycle management.
28
+
29
+ ## Architecture
30
+
31
+ Module clients follow a **one-client-per-module** pattern:
32
+
33
+ \`\`\`
34
+ ┌─────────────────────────────────────────────────────────┐
35
+ │ Module Plugin (ai, tools, knowledge, etc.) │
36
+ │ - Registers runtime/client descriptor │
37
+ │ - Provides implementation class via loader │
38
+ └─────────────────────────────────────────────────────────┘
39
+
40
+
41
+ ┌─────────────────────────────────────────────────────────┐
42
+ │ RuntimeClient Implementation (extends BaseRuntimeClient)│
43
+ │ - Domain methods (generate, listTools, search, etc.) │
44
+ │ - Config access via this.getConfigValues<T>() │
45
+ │ - Runtime access via this.runtime │
46
+ └─────────────────────────────────────────────────────────┘
47
+
48
+
49
+ ┌─────────────────────────────────────────────────────────┐
50
+ │ BaseRuntimeClient (shared base) │
51
+ │ - Ambient runtime acquisition │
52
+ │ - Idempotent lazy init (ensureLoaded()) │
53
+ │ - Config manifest auto-loading │
54
+ │ - Lifecycle hooks (onLoad, onDispose) │
55
+ └─────────────────────────────────────────────────────────┘
56
+ \`\`\`
57
+
58
+ ## BaseRuntimeClient
59
+
60
+ ### Constructor
61
+
62
+ \`\`\`ts
63
+ constructor(
64
+ descriptor: RuntimeClientDescriptor,
65
+ _context?: unknown,
66
+ runtime?: VibesRuntime
67
+ )
68
+ \`\`\`
69
+
70
+ **Parameters:**
71
+ - \`descriptor\` — The \`runtime/client\` descriptor this client represents
72
+ - \`_context\` — Reserved for future scope metadata (not currently used)
73
+ - \`runtime\` — Optional explicit runtime override (defaults to \`getVibesRuntime()\`)
74
+
75
+ ### Properties
76
+
77
+ \`\`\`ts
78
+ readonly id: string; // From descriptor.id
79
+ readonly runtime: VibesRuntime; // Ambient runtime singleton
80
+ \`\`\`
81
+
82
+ ### Lifecycle Methods
83
+
84
+ #### ensureLoaded() / load()
85
+
86
+ Idempotent lazy initialization. First call drives \`onLoad()\`; subsequent calls await the same promise.
87
+
88
+ \`\`\`ts
89
+ async ensureLoaded(): Promise<void>
90
+ async load(): Promise<void> // Alias of ensureLoaded()
91
+ \`\`\`
92
+
93
+ **When to call:** At method entry points when your client depends on loaded config.
94
+
95
+ \`\`\`ts
96
+ export class AIClient extends BaseRuntimeClient {
97
+ async generate(prompt: string): Promise<GenerationResponse> {
98
+ await this.ensureLoaded(); // Ensure config is loaded
99
+
100
+ const config = this.getConfigValues<AIConfig>();
101
+ const provider = await this.runtime.query('ai/provider')
102
+ .withId(config?.defaultProvider ?? 'anthropic')
103
+ .resolve();
104
+
105
+ return provider.generate({ prompt });
106
+ }
107
+ }
108
+ \`\`\`
109
+
110
+ #### dispose()
111
+
112
+ Releases client-held resources:
113
+
114
+ \`\`\`ts
115
+ dispose(): void {
116
+ this.loadPromise = undefined;
117
+ this.configValues = null;
118
+ this.onDispose(); // Subclass hook
119
+ }
120
+ \`\`\`
121
+
122
+ Call when shutting down the client (e.g., test teardown, hot reload).
123
+
124
+ ### Protected Hooks for Subclasses
125
+
126
+ #### onLoad()
127
+
128
+ Override to perform module-specific initialization. Default behavior: if \`descriptor.configManifestId\` is set, resolves the corresponding \`config/manifest\` and loads its values.
129
+
130
+ \`\`\`ts
131
+ protected async onLoad(): Promise<void> {
132
+ // Default: load config manifest if specified
133
+ const manifestId = this.descriptor.configManifestId;
134
+ if (!manifestId) return;
135
+
136
+ try {
137
+ const manifest = await this.runtime
138
+ .query('config/manifest')
139
+ .withId(manifestId)
140
+ .resolve();
141
+
142
+ if (manifest?.load) {
143
+ this.configValues = await manifest.load();
144
+ }
145
+ } catch {
146
+ // Config is best-effort at base layer
147
+ this.configValues = null;
148
+ }
149
+
150
+ // Subclasses can extend:
151
+ // - Initialize domain-specific caches
152
+ // - Validate required config
153
+ // - Establish connections
154
+ }
155
+ \`\`\`
156
+
157
+ #### onDispose()
158
+
159
+ Override to release resources:
160
+
161
+ \`\`\`ts
162
+ protected onDispose(): void {
163
+ // Close connections, clear caches, cancel subscriptions
164
+ }
165
+ \`\`\`
166
+
167
+ #### getConfigValues<T>()
168
+
169
+ Accessor for loaded config values (null if load hasn't run or failed):
170
+
171
+ \`\`\`ts
172
+ protected getConfigValues<T = unknown>(): T | null
173
+ \`\`\`
174
+
175
+ ## Extending BaseRuntimeClient
176
+
177
+ ### Minimal Example
178
+
179
+ \`\`\`ts
180
+ // packages/my-module/src/client.ts
181
+ import { BaseRuntimeClient, type RuntimeClientDescriptor } from '@vibesdotdev/runtime-client';
182
+
183
+ export interface MyModuleDescriptor extends RuntimeClientDescriptor {
184
+ kind: 'runtime/client';
185
+ id: 'my-module';
186
+ configManifestId?: string;
187
+ }
188
+
189
+ export class MyModuleClient extends BaseRuntimeClient {
190
+ constructor(descriptor: MyModuleDescriptor) {
191
+ super(descriptor);
192
+ }
193
+
194
+ async doSomething(input: string): Promise<string> {
195
+ await this.ensureLoaded();
196
+
197
+ const runtime = this.runtime;
198
+ // Use runtime APIs...
199
+ return \`Processed: \${input}\`;
200
+ }
201
+ }
202
+ \`\`\`
203
+
204
+ ### Full Example with Config
205
+
206
+ \`\`\`ts
207
+ // packages/ai/src/client/ai-client.ts
208
+ import { BaseRuntimeClient, type RuntimeClientDescriptor } from '@vibesdotdev/runtime-client';
209
+
210
+ interface AIConfig {
211
+ defaultProvider: string;
212
+ maxTokens: number;
213
+ temperature: number;
214
+ }
215
+
216
+ export class AIClient extends BaseRuntimeClient {
217
+ constructor(descriptor: RuntimeClientDescriptor) {
218
+ super(descriptor);
219
+ }
220
+
221
+ async generate(options: {
222
+ prompt: string;
223
+ model?: string;
224
+ maxTokens?: number;
225
+ }): Promise<string> {
226
+ await this.ensureLoaded();
227
+
228
+ const config = this.getConfigValues<AIConfig>();
229
+ if (!config) {
230
+ throw new Error('AI config not loaded');
231
+ }
232
+
233
+ const provider = await this.runtime
234
+ .query('ai/provider')
235
+ .withId(config.defaultProvider)
236
+ .resolve();
237
+
238
+ const response = await provider.generate({
239
+ prompt: options.prompt,
240
+ model: options.model,
241
+ maxTokens: options.maxTokens ?? config.maxTokens,
242
+ temperature: config.temperature
243
+ });
244
+
245
+ return response.text;
246
+ }
247
+
248
+ async listModels(): Promise<string[]> {
249
+ await this.ensureLoaded();
250
+
251
+ const models = await this.runtime
252
+ .query('ai/model')
253
+ .descriptors();
254
+
255
+ return models.map(m => m.id);
256
+ }
257
+
258
+ protected async onLoad(): Promise<void> {
259
+ await super.onLoad(); // Load config manifest
260
+
261
+ // Additional AI-specific initialization
262
+ // e.g., warm provider caches, validate API keys
263
+ }
264
+
265
+ protected onDispose(): void {
266
+ // Cancel pending generations, clear caches
267
+ super.onDispose();
268
+ }
269
+ }
270
+ \`\`\`
271
+
272
+ ### Registering the Client
273
+
274
+ \`\`\`ts
275
+ // packages/ai/src/ai.plugin.ts
276
+ import { createRuntimePlugin } from '@vibesdotdev/runtime';
277
+ import { AIClient } from './client/ai-client';
278
+
279
+ export const aiPlugin = createRuntimePlugin({
280
+ id: 'ai',
281
+ name: 'AI Module',
282
+ onRegister(runtime) {
283
+ // Register per-id loader for runtime/client kind
284
+ runtime.registerLoader('runtime/client', 'ai', async () => {
285
+ return new AIClient({
286
+ kind: 'runtime/client',
287
+ id: 'ai',
288
+ configManifestId: 'ai/config'
289
+ });
290
+ });
291
+ }
292
+ });
293
+ \`\`\`
294
+
295
+ ## WRONG patterns
296
+
297
+ :::card{title="Anti-patterns"}
298
+ - ❌ **Direct runtime instantiation** — Don't \`new VibesRuntime()\`; use ambient \`this.runtime\`
299
+ - ❌ **Storing runtime references** — Call \`getVibesRuntime()\` at construction, store as \`this.runtime\`
300
+ - ❌ **Skipping ensureLoaded()** — Always call at method entry if you need config
301
+ - ❌ **Multiple config loads** — Base class handles idempotent loading; don't re-implement
302
+ - ❌ **Throwing on missing config** — Config is best-effort; validate in subclass if required
303
+ - ❌ **Direct config manifest resolution** — Use base class \`onLoad()\` pattern
304
+ :::
305
+
306
+ ## Code paths
307
+
308
+ - Base class: [\`packages/runtime-client/src/base.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime-client/src/base.ts)
309
+ - Contract: [\`packages/runtime-client/src/contract.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime-client/src/contract.ts)
310
+ - Schema: [\`packages/runtime-client/src/schema.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime-client/src/schema.ts)
311
+ - Kind: [\`packages/runtime-client/src/kind.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime-client/src/kind.ts)
312
+
313
+ :::card{title="See also"}
314
+ - [\`runtime-client.helpers\`](runtime-client.helpers) — \`getVibesClient()\` helper functions
315
+ - [\`runtime-client.surface\`](runtime-client.surface) — Surface initialization patterns
316
+ - [\`runtime.query\`](runtime.query) — Runtime query API for resolving clients
317
+ - [\`runtime.plugins\`](runtime.plugins) — Plugin registration and loaders
318
+ :::
319
+ `
320
+ },
321
+ parent: 'runtime-client',
322
+ order: 1,
323
+ tags: ['runtime-client', 'base-class', 'extension', 'api', 'patterns'],
324
+ surfaces: ['cli', 'web', 'in-app'],
325
+ hardware: ['consumer', 'cloud'],
326
+ enabled: true,
327
+ man: {
328
+ name: 'runtime-client.api — BaseRuntimeClient and extension patterns',
329
+ section: 1,
330
+ synopsis: 'vibes man runtime-client.api',
331
+ options: [],
332
+ examples: [
333
+ {
334
+ description: 'Extend BaseRuntimeClient',
335
+ command: 'class MyClient extends BaseRuntimeClient { ... }'
336
+ },
337
+ {
338
+ description: 'Load config in onLoad()',
339
+ command: 'protected async onLoad() { await super.onLoad(); ... }'
340
+ }
341
+ ],
342
+ seeAlso: ['runtime-client.helpers', 'runtime-client.surface', 'runtime.query']
343
+ }
344
+ };
345
+
346
+ export default descriptor;