@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,466 @@
1
+ import type { DocsTopicDescriptor } from './types.ts';
2
+
3
+ /**
4
+ * Descriptor for runtime-client.surface
5
+ * How surfaces (CLI, SSR, browser, worker) initialize runtime clients
6
+ */
7
+ const descriptor: DocsTopicDescriptor = {
8
+ kind: 'docs/topic',
9
+ id: 'runtime-client.surface',
10
+ title: 'Surface Initialization',
11
+ summary: 'How different surfaces (CLI, SSR, browser, worker) initialize runtime clients',
12
+ body: {
13
+ type: 'markdown',
14
+ sourceType: 'raw',
15
+ source: `---
16
+ title: Surface Initialization
17
+ summary: How different surfaces (CLI, SSR, browser, worker) initialize runtime clients
18
+ tags: [runtime-client, surfaces, initialization, cli, ssr, browser, worker]
19
+ parent: runtime-client
20
+ order: 3
21
+ surfaces: [cli, web, in-app]
22
+ hardware: [consumer, cloud]
23
+ ---
24
+
25
+ # Surface Initialization
26
+
27
+ Runtime clients are initialized differently depending on the **surface** (CLI, SSR, browser, worker) and **hardware** (consumer, cloud). This guide covers initialization patterns for each surface type.
28
+
29
+ ## Surface Types
30
+
31
+ The Vibes runtime supports four surface types:
32
+
33
+ | Surface | Description | Typical Use | Hardware |
34
+ |---------|-------------|-------------|----------|
35
+ | \`cli\` | Command-line interface | CLI commands, scripts | consumer |
36
+ | \`ssr\` | Server-side rendering | SvelteKit +page.server.ts | consumer |
37
+ | \`browser\` | Client-side browser | SvelteKit +page.svelte | consumer |
38
+ | \`worker\` | Cloudflare Workers | Edge functions, queues | cloud |
39
+
40
+ Each surface gets its own runtime instance with appropriate scope bindings:
41
+
42
+ \`\`\`ts
43
+ runtime.scope;
44
+ // {
45
+ // surface: 'cli' | 'ssr' | 'browser' | 'worker',
46
+ // hardware: 'consumer' | 'cloud',
47
+ // purpose?: 'direct' | 'embedded'
48
+ // }
49
+ \`\`\`
50
+
51
+ ## CLI Surface
52
+
53
+ ### Bootstrap Flow
54
+
55
+ The CLI bootstrap is defined in \`@vibesdotdev/cli/bootstrap\`:
56
+
57
+ \`\`\`ts
58
+ // packages/cli/src/bootstrap.ts
59
+ import { getVibesRuntime } from '@vibesdotdev/runtime';
60
+ import { CLISurface } from './surface';
61
+
62
+ export async function createVibesCliApp() {
63
+ const runtime = getVibesRuntime();
64
+
65
+ // Set CLI scope
66
+ runtime.setScope({
67
+ surface: 'cli',
68
+ hardware: 'consumer',
69
+ purpose: 'direct'
70
+ });
71
+
72
+ // Register core plugins (order matters)
73
+ await registerCorePlugins(runtime);
74
+
75
+ // Register project plugins
76
+ // ...
77
+
78
+ // Activate plugins (fires onActivate hooks)
79
+ await runtime.activatePlugins();
80
+
81
+ // Create CLI surface
82
+ const cli = new CLISurface(runtime, program);
83
+
84
+ return { runtime, program, cli };
85
+ }
86
+
87
+ async function registerCorePlugins(runtime: VibesRuntime) {
88
+ // Order: context → cli → runtime-client → hooks → logging → runtime.docs
89
+ const runtimeClientPlugin = (
90
+ await import('@vibesdotdev/runtime-client/plugin')
91
+ ).default;
92
+ await runtime.registerPlugin(runtimeClientPlugin);
93
+
94
+ // ... other plugins
95
+ }
96
+ \`\`\`
97
+
98
+ ### Key Points
99
+
100
+ 1. **runtime-client plugin registered early** — Before module plugins (ai, tools, etc.)
101
+ 2. **Plugin activation deferred** — \`activatePlugins()\` fires after all plugins registered
102
+ 3. **Module plugins register loaders** — In \`onActivate()\` hook, they register \`runtime/client\` loaders
103
+
104
+ ### Module Plugin Pattern
105
+
106
+ \`\`\`ts
107
+ // packages/ai/src/ai.plugin.ts
108
+ import { createRuntimePlugin } from '@vibesdotdev/runtime';
109
+
110
+ export const aiPlugin = createRuntimePlugin({
111
+ id: 'ai',
112
+ name: 'AI Module',
113
+ dependencies: ['runtime-client'], // Declare dependency
114
+
115
+ onActivate(runtime) {
116
+ // Register per-id loader for runtime/client kind
117
+ runtime.registerLoader('runtime/client', 'ai', async () => {
118
+ const { AIClient } = await import('./client/ai-client');
119
+ return new AIClient({
120
+ kind: 'runtime/client',
121
+ id: 'ai',
122
+ configManifestId: 'ai/config'
123
+ });
124
+ });
125
+ }
126
+ });
127
+ \`\`\`
128
+
129
+ ### Usage in CLI Commands
130
+
131
+ \`\`\`ts
132
+ // packages/cli/src/commands/ai/generate.ts
133
+ import { getVibesClient } from '@vibesdotdev/runtime-client';
134
+
135
+ export async function generateCommand(options: { prompt: string }) {
136
+ // Resolve client (runtime already bootstrapped by CLI)
137
+ const ai = await getVibesClient('ai');
138
+
139
+ // Generate
140
+ const response = await ai.generate({ prompt: options.prompt });
141
+ console.log(response);
142
+ }
143
+ \`\`\`
144
+
145
+ ## SSR Surface (SvelteKit)
146
+
147
+ ### Bootstrap Flow
148
+
149
+ SSR surfaces bootstrap in SvelteKit's \`hooks.server.ts\`:
150
+
151
+ \`\`\`ts
152
+ // apps/ai-web/src/hooks.server.ts
153
+ import { bootstrapVibesRuntime } from '@vibesdotdev/runtime';
154
+ import { consumerRuntimePlugin } from './runtime/consumer.plugin';
155
+
156
+ export async function handle({ event, resolve }) {
157
+ // Bootstrap runtime once per request (or use singleton)
158
+ await bootstrapVibesRuntime({
159
+ plugins: [consumerRuntimePlugin],
160
+ scope: {
161
+ surface: 'ssr',
162
+ hardware: 'consumer',
163
+ purpose: 'direct'
164
+ }
165
+ });
166
+
167
+ return resolve(event);
168
+ }
169
+ \`\`\`
170
+
171
+ ### Usage in +page.server.ts
172
+
173
+ \`\`\`ts
174
+ // apps/ai-web/src/routes/chat/+page.server.ts
175
+ import { getVibesClient } from '@vibesdotdev/runtime-client';
176
+ import type { PageServerLoad } from './$types';
177
+
178
+ export const load: PageServerLoad = async () => {
179
+ // Resolve client (runtime bootstrapped in hooks.server.ts)
180
+ const ai = await getVibesClient('ai');
181
+
182
+ // Use client
183
+ const models = await ai.listModels();
184
+
185
+ return { models };
186
+ };
187
+ \`\`\`
188
+
189
+ ### SSR-Specific Considerations
190
+
191
+ 1. **Request isolation** — Each request may get its own runtime instance
192
+ 2. **No global state** — Don't store client references in module scope
193
+ 3. **Lazy initialization** — Clients initialize on first use
194
+ 4. **Config loading** — Happens per-request if not cached
195
+
196
+ ## Browser Surface
197
+
198
+ ### Bootstrap Flow
199
+
200
+ Browser surfaces bootstrap in SvelteKit's \`+layout.svelte\` or \`app.html\`:
201
+
202
+ \`\`\`ts
203
+ // apps/ai-web/src/routes/+layout.svelte
204
+ <script lang="ts">
205
+ import { onMount } from 'svelte';
206
+ import { bootstrapVibesRuntime } from '@vibesdotdev/runtime';
207
+ import { browserRuntimePlugin } from '$lib/runtime/browser.plugin';
208
+
209
+ onMount(async () => {
210
+ await bootstrapVibesRuntime({
211
+ plugins: [browserRuntimePlugin],
212
+ scope: {
213
+ surface: 'browser',
214
+ hardware: 'consumer',
215
+ purpose: 'direct'
216
+ }
217
+ });
218
+ });
219
+ </script>
220
+
221
+ <slot />
222
+ \`\`\`
223
+
224
+ ### Usage in +page.svelte
225
+
226
+ \`\`\`ts
227
+ // apps/ai-web/src/routes/chat/+page.svelte
228
+ <script lang="ts">
229
+ import { onMount } from 'svelte';
230
+ import { getVibesClient } from '@vibesdotdev/runtime-client';
231
+ import type { AIClient } from '@vibesdotdev/ai/client';
232
+
233
+ let aiClient: AIClient | null = null;
234
+
235
+ onMount(async () => {
236
+ // Resolve client (runtime bootstrapped in +layout.svelte)
237
+ aiClient = await getVibesClient<AIClient>('ai');
238
+ });
239
+
240
+ async function generate(prompt: string) {
241
+ if (!aiClient) return;
242
+ const response = await aiClient.generate({ prompt });
243
+ // Handle response...
244
+ }
245
+ </script>
246
+
247
+ <button on:click={() => generate('Hello')}>Generate</button>
248
+ \`\`\`
249
+
250
+ ### Browser-Specific Considerations
251
+
252
+ 1. **Client-side only** — Browser surface can't access server-only plugins
253
+ 2. **API boundaries** — Use bridge pattern for server operations
254
+ 3. **Memory constraints** — Dispose clients on unmount if needed
255
+ 4. **Network latency** — Client methods may involve network calls
256
+
257
+ ## Worker Surface (Cloudflare)
258
+
259
+ ### Bootstrap Flow
260
+
261
+ Worker surfaces bootstrap in worker entrypoint:
262
+
263
+ \`\`\`ts
264
+ // workers/jobs/src/entrypoint.ts
265
+ import { bootstrapVibesRuntime } from '@vibesdotdev/runtime';
266
+ import { runtimeClientPlugin } from '@vibesdotdev/runtime-client';
267
+ import { workersPlugin } from '@vibesdotdev/workers';
268
+
269
+ export default {
270
+ async fetch(request, env, ctx) {
271
+ // Bootstrap runtime
272
+ await bootstrapVibesRuntime({
273
+ plugins: [runtimeClientPlugin, workersPlugin],
274
+ scope: {
275
+ surface: 'worker',
276
+ hardware: 'cloud',
277
+ purpose: 'direct'
278
+ },
279
+ env // Cloudflare env bindings
280
+ });
281
+
282
+ // Handle request
283
+ const runtime = getVibesRuntime();
284
+ const workers = await runtime
285
+ .query('runtime/client')
286
+ .withId('workers')
287
+ .resolve();
288
+
289
+ // ...
290
+ }
291
+ };
292
+ \`\`\`
293
+
294
+ ### Worker-Specific Considerations
295
+
296
+ 1. **Cold starts** — First request pays bootstrap cost
297
+ 2. **Stateless** — No persistent memory between requests
298
+ 3. **Env bindings** — Pass Cloudflare env to bootstrap
299
+ 4. **Limited plugins** — Only cloud-compatible plugins work
300
+
301
+ ## Cross-Surface Patterns
302
+
303
+ ### Pattern 1: Surface-Agnostic Services
304
+
305
+ Write services that work in any surface:
306
+
307
+ \`\`\`ts
308
+ // packages/my-lib/src/content-generator.ts
309
+ import { getVibesClient } from '@vibesdotdev/runtime-client';
310
+ import type { AIClient } from '@vibesdotdev/ai/client';
311
+
312
+ export class ContentGenerator {
313
+ async generate(topic: string): Promise<string> {
314
+ // Works in CLI, SSR, browser, worker
315
+ const ai = await getVibesClient<AIClient>('ai');
316
+ return ai.generate({
317
+ prompt: \`Write about \${topic}\`
318
+ });
319
+ }
320
+ }
321
+ \`\`\`
322
+
323
+ ### Pattern 2: Surface Detection
324
+
325
+ Detect current surface via runtime scope:
326
+
327
+ \`\`\`ts
328
+ import { getVibesRuntime } from '@vibesdotdev/runtime';
329
+
330
+ const runtime = getVibesRuntime();
331
+ const { surface, hardware } = runtime.scope;
332
+
333
+ if (surface === 'browser') {
334
+ // Browser-specific logic
335
+ } else if (surface === 'ssr') {
336
+ // SSR-specific logic
337
+ }
338
+ \`\`\`
339
+
340
+ ### Pattern 3: Surface-Specific Implementations
341
+
342
+ Register different implementations per surface:
343
+
344
+ \`\`\`ts
345
+ // packages/storage/src/storage.plugin.ts
346
+ import { createRuntimePlugin } from '@vibesdotdev/runtime';
347
+
348
+ export const storagePlugin = createRuntimePlugin({
349
+ id: 'storage',
350
+ onActivate(runtime) {
351
+ const { surface, hardware } = runtime.scope;
352
+
353
+ if (hardware === 'cloud') {
354
+ // Cloud implementation
355
+ runtime.registerLoader('runtime/client', 'storage', async () => {
356
+ const { CloudStorageClient } = await import('./client/cloud');
357
+ return new CloudStorageClient();
358
+ });
359
+ } else {
360
+ // Consumer implementation
361
+ runtime.registerLoader('runtime/client', 'storage', async () => {
362
+ const { LocalStorageClient } = await import('./client/local');
363
+ return new LocalStorageClient();
364
+ });
365
+ }
366
+ }
367
+ });
368
+ \`\`\`
369
+
370
+ ## WRONG patterns
371
+
372
+ :::card{title="Anti-patterns"}
373
+ - ❌ **Manual runtime instantiation** — Use \`bootstrapVibesRuntime()\` or surface helpers
374
+ - ❌ **Cross-surface state sharing** — Each surface has its own runtime instance
375
+ - ❌ **Storing clients in module scope** — Resolve at call site with \`getVibesClient()\`
376
+ - ❌ **Assuming surface** — Check \`runtime.scope\` if behavior differs
377
+ - ❌ **Skipping plugin activation** — Call \`activatePlugins()\` after registration
378
+ :::
379
+
380
+ ## Example: Multi-surface service
381
+
382
+ \`\`\`ts
383
+ // packages/notification-service/src/index.ts
384
+ import { getVibesRuntime, getVibesClient } from '@vibesdotdev/runtime';
385
+ import type { AIClient } from '@vibesdotdev/ai/client';
386
+
387
+ export class NotificationService {
388
+ async sendNotification(
389
+ userId: string,
390
+ message: string
391
+ ): Promise<void> {
392
+ const runtime = getVibesRuntime();
393
+ const { surface, hardware } = runtime.scope;
394
+
395
+ // Surface-specific notification strategy
396
+ if (surface === 'browser') {
397
+ // Browser: show toast notification
398
+ this.showBrowserNotification(message);
399
+ } else if (surface === 'ssr') {
400
+ // SSR: send email via server
401
+ const ai = await getVibesClient<AIClient>('ai');
402
+ const emailBody = await ai.generate({
403
+ prompt: \`Write email: \${message}\`
404
+ });
405
+ await this.sendEmail(userId, emailBody);
406
+ } else if (surface === 'worker') {
407
+ // Worker: queue notification job
408
+ await this.queueNotification(userId, message);
409
+ }
410
+ }
411
+
412
+ private showBrowserNotification(message: string) {
413
+ // Browser-specific: toast, badge, etc.
414
+ }
415
+
416
+ private async sendEmail(userId: string, body: string) {
417
+ // SSR-specific: email service
418
+ }
419
+
420
+ private async queueNotification(userId: string, message: string) {
421
+ // Worker-specific: job queue
422
+ }
423
+ }
424
+ \`\`\`
425
+
426
+ ## Code paths
427
+
428
+ - CLI bootstrap: [\`packages/cli/src/bootstrap.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/cli/src/bootstrap.ts)
429
+ - Runtime bootstrap: [\`packages/runtime/src/bootstrap/index.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime/src/bootstrap/index.ts)
430
+ - Helper: [\`packages/runtime-client/src/helper.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime-client/src/helper.ts)
431
+ - Plugin: [\`packages/runtime-client/src/plugin.ts\`](https://github.com/vibesdotdev/monorepo/tree/main/packages/runtime-client/src/plugin.ts)
432
+
433
+ :::card{title="See also"}
434
+ - [\`runtime-client.api\`](runtime-client.api) — BaseRuntimeClient and extension patterns
435
+ - [\`runtime-client.helpers\`](runtime-client.helpers) — getVibesClient() helper functions
436
+ - [\`runtime.scopes\`](runtime.scopes) — Consumer vs cloud scopes
437
+ - [\`bootstrapVibesRuntime\`](bootstrap) — Runtime bootstrap API
438
+ :::
439
+ `
440
+ },
441
+ parent: 'runtime-client',
442
+ order: 3,
443
+ tags: ['runtime-client', 'surfaces', 'initialization', 'cli', 'ssr', 'browser', 'worker'],
444
+ surfaces: ['cli', 'web', 'in-app'],
445
+ hardware: ['consumer', 'cloud'],
446
+ enabled: true,
447
+ man: {
448
+ name: 'runtime-client.surface — surface initialization patterns',
449
+ section: 1,
450
+ synopsis: 'vibes man runtime-client.surface',
451
+ options: [],
452
+ examples: [
453
+ {
454
+ description: 'CLI surface bootstrap',
455
+ command: 'await createVibesCliApp()'
456
+ },
457
+ {
458
+ description: 'SSR surface in SvelteKit',
459
+ command: 'await bootstrapVibesRuntime({ scope: { surface: "ssr" } })'
460
+ }
461
+ ],
462
+ seeAlso: ['runtime-client.api', 'runtime-client.helpers', 'runtime.scopes']
463
+ }
464
+ };
465
+
466
+ export default descriptor;
@@ -0,0 +1,18 @@
1
+ export type DocsTopicDescriptor = {
2
+ kind: 'docs/topic';
3
+ id: string;
4
+ title: string;
5
+ summary?: string;
6
+ body: {
7
+ type: 'markdown';
8
+ sourceType: 'raw';
9
+ source: string;
10
+ };
11
+ parent?: string;
12
+ order?: number;
13
+ enabled?: boolean;
14
+ man?: unknown;
15
+ tags?: string[];
16
+ surfaces?: string[];
17
+ hardware?: string[];
18
+ };
package/src/helper.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { getVibesRuntime } from '@vibesdotdev/runtime';
2
+ import type { RuntimeClient } from './contract.ts';
3
+ import { runtimeClientPlugin } from './plugin.ts';
4
+
5
+ /**
6
+ * Ambient helper to resolve a module-level client by id.
7
+ *
8
+ * ```ts
9
+ * const ai = await getVibesClient<AIClient>('ai');
10
+ * const response = await ai.generate({ prompt: 'Hello' });
11
+ * ```
12
+ *
13
+ * Equivalent to calling `runtime.query('runtime/client').withId(id).resolve()`
14
+ * on the ambient runtime, with a clearer error when the client isn't registered.
15
+ */
16
+ export async function getVibesClient<T extends RuntimeClient = RuntimeClient>(
17
+ id: string
18
+ ): Promise<T> {
19
+ const runtime = getVibesRuntime();
20
+ if (!runtime.hasKind('runtime/client')) {
21
+ await runtime.registerPlugin(runtimeClientPlugin);
22
+ }
23
+ const client = await runtime.query('runtime/client').withId(id).resolve();
24
+ if (!client) {
25
+ throw new Error(
26
+ `No runtime client registered with id "${id}". ` +
27
+ `Compose the owning module's plugin (e.g. aiPlugin for id="ai") before use, ` +
28
+ `and ensure runtimeClientPlugin is registered.`
29
+ );
30
+ }
31
+ return client as T;
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ // @vibesdotdev/runtime-client
2
+ // One-client-per-module pattern: shared base, kind, and resolver helper.
3
+
4
+ export { runtimeClientPlugin } from './plugin.ts';
5
+ export { runtimeClientKind } from './kind.ts';
6
+ export { BaseRuntimeClient } from './base.ts';
7
+ export { getVibesClient } from './helper.ts';
8
+
9
+ export type { RuntimeClient } from './contract.ts';
10
+ export type { RuntimeClientDescriptor } from './schema.ts';
11
+ export { RuntimeClientDescriptorSchema } from './schema.ts';
package/src/kind.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { RuntimeKindDescriptorRecord } from '@vibesdotdev/runtime';
2
+ import { RuntimeClientDescriptorSchema } from './schema.ts';
3
+ import type { RuntimeClient } from './contract.ts';
4
+
5
+ /**
6
+ * `runtime/client` kind descriptor record.
7
+ *
8
+ * No `defaultImplementation` — each module registers its own class via a
9
+ * per-descriptor loader (see `runtime.registerLoader('runtime/client', '<id>', …)`).
10
+ */
11
+ export const runtimeClientKind: RuntimeKindDescriptorRecord<RuntimeClient> = {
12
+ id: 'runtime/client',
13
+ descriptorSchema: RuntimeClientDescriptorSchema
14
+ };
package/src/plugin.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { createRuntimePlugin } from '@vibesdotdev/runtime';
2
+ import { runtimeClientKind } from './kind.ts';
3
+
4
+ /**
5
+ * Registers the `runtime/client` kind.
6
+ *
7
+ * Compose this plugin once at app bootstrap. Module plugins (ai, tools,
8
+ * knowledge, …) declare `dependencies: ['runtime-client', …]` and register
9
+ * their per-id loaders in their `onRegister` hook.
10
+ */
11
+ export const runtimeClientPlugin = createRuntimePlugin({
12
+ id: 'runtime-client',
13
+ name: 'Runtime Client',
14
+ description:
15
+ 'Shared `runtime/client` kind. Each module registers one descriptor; consumers resolve via `runtime.query(\"runtime/client\").withId(\"ai\")`.',
16
+ kinds: [runtimeClientKind]
17
+ });
18
+
19
+ export default runtimeClientPlugin;
@@ -0,0 +1,32 @@
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
+
12
+ import { createRuntimePlugin } from '@vibesdotdev/runtime';
13
+
14
+ // Docs descriptors
15
+ import runtimeClientApiDocs from './docs/runtime-client.api.docs.descriptor.ts';
16
+ import runtimeClientHelpersDocs from './docs/runtime-client.helpers.docs.descriptor.ts';
17
+ import runtimeClientSurfaceDocs from './docs/runtime-client.surface.docs.descriptor.ts';
18
+
19
+ export const runtimeClientDocsPlugin = createRuntimePlugin({
20
+ id: 'runtime-client.docs',
21
+ name: 'Runtime Client Documentation',
22
+ description:
23
+ 'Runtime client APIs: BaseRuntimeClient, getVibesClient helpers, surface initialization',
24
+
25
+ descriptors: [
26
+ runtimeClientApiDocs,
27
+ runtimeClientHelpersDocs,
28
+ runtimeClientSurfaceDocs
29
+ ]
30
+ });
31
+
32
+ export default runtimeClientDocsPlugin;
package/src/schema.ts ADDED
@@ -0,0 +1,27 @@
1
+ import * as z from 'zod/v4';
2
+ import {
3
+ RuntimeDescriptorSchema,
4
+ type RuntimeDescriptor
5
+ } from '@vibesdotdev/runtime/schemas/descriptor';
6
+
7
+ /**
8
+ * Descriptor for the `runtime/client` kind.
9
+ *
10
+ * Every module that exposes a top-level client registers exactly one of these.
11
+ * The descriptor id matches the module name (`ai`, `tools`, `knowledge`, …).
12
+ *
13
+ * `configManifestId`, if set, causes `BaseRuntimeClient.onLoad()` to load the
14
+ * corresponding config manifest and expose its values to subclasses.
15
+ */
16
+ export interface RuntimeClientDescriptor extends RuntimeDescriptor {
17
+ /** Narrows the base `kind: string` to the literal `'runtime/client'`. */
18
+ kind: 'runtime/client';
19
+ /** If set, BaseRuntimeClient.onLoad() loads the corresponding config manifest. */
20
+ configManifestId?: string;
21
+ }
22
+
23
+ export const RuntimeClientDescriptorSchema = RuntimeDescriptorSchema.extend({
24
+ kind: z.literal('runtime/client'),
25
+ configManifestId: z.string().optional(),
26
+ description: z.string().optional()
27
+ });