@stina/extension-api 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.
@@ -0,0 +1,540 @@
1
+ /**
2
+ * Extension manifest format (manifest.json)
3
+ */
4
+ interface ExtensionManifest {
5
+ /** Unique identifier (e.g., "ollama-provider") */
6
+ id: string;
7
+ /** Human-readable name */
8
+ name: string;
9
+ /** Version string (semver) */
10
+ version: string;
11
+ /** Short description */
12
+ description: string;
13
+ /** Author information */
14
+ author: {
15
+ name: string;
16
+ url?: string;
17
+ };
18
+ /** Repository URL */
19
+ repository?: string;
20
+ /** License identifier */
21
+ license?: string;
22
+ /** Minimum Stina version required */
23
+ engines?: {
24
+ stina: string;
25
+ };
26
+ /** Supported platforms */
27
+ platforms?: Platform[];
28
+ /** Entry point file (relative to extension root) */
29
+ main: string;
30
+ /** Required permissions */
31
+ permissions: Permission[];
32
+ /** What the extension contributes */
33
+ contributes?: ExtensionContributions;
34
+ }
35
+ type Platform = 'web' | 'electron' | 'tui';
36
+ /**
37
+ * What an extension can contribute to Stina
38
+ */
39
+ interface ExtensionContributions {
40
+ /** User-configurable settings */
41
+ settings?: SettingDefinition[];
42
+ /** Tool settings views for UI */
43
+ toolSettings?: ToolSettingsViewDefinition[];
44
+ /** AI providers */
45
+ providers?: ProviderDefinition[];
46
+ /** Tools for Stina to use */
47
+ tools?: ToolDefinition[];
48
+ /** Slash commands */
49
+ commands?: CommandDefinition[];
50
+ /** Prompt contributions for the system prompt */
51
+ prompts?: PromptContribution[];
52
+ }
53
+ /**
54
+ * Setting definition for the UI
55
+ */
56
+ interface SettingDefinition {
57
+ /** Setting ID (namespaced automatically) */
58
+ id: string;
59
+ /** Display title */
60
+ title: string;
61
+ /** Help text */
62
+ description?: string;
63
+ /** Setting type */
64
+ type: 'string' | 'number' | 'boolean' | 'select';
65
+ /** Default value */
66
+ default?: unknown;
67
+ /** For select type: available options */
68
+ options?: {
69
+ value: string;
70
+ label: string;
71
+ }[];
72
+ /** Validation rules */
73
+ validation?: {
74
+ required?: boolean;
75
+ min?: number;
76
+ max?: number;
77
+ pattern?: string;
78
+ };
79
+ }
80
+ /**
81
+ * Tool settings view definition (UI schema)
82
+ */
83
+ interface ToolSettingsViewDefinition {
84
+ /** Unique view ID within the extension */
85
+ id: string;
86
+ /** Display title */
87
+ title: string;
88
+ /** Help text */
89
+ description?: string;
90
+ /** View configuration */
91
+ view: ToolSettingsView;
92
+ /** Fields for create/edit forms (uses SettingDefinition) */
93
+ fields?: SettingDefinition[];
94
+ }
95
+ /**
96
+ * Tool settings view types
97
+ */
98
+ type ToolSettingsView = ToolSettingsListView;
99
+ /**
100
+ * List view backed by tools
101
+ */
102
+ interface ToolSettingsListView {
103
+ /** View kind */
104
+ kind: 'list';
105
+ /** Tool ID for listing items */
106
+ listToolId: string;
107
+ /** Tool ID for fetching details (optional) */
108
+ getToolId?: string;
109
+ /** Tool ID for creating/updating items (optional) */
110
+ upsertToolId?: string;
111
+ /** Tool ID for deleting items (optional) */
112
+ deleteToolId?: string;
113
+ /** Mapping from tool data to UI fields */
114
+ mapping: ToolSettingsListMapping;
115
+ /** Param name for search query (default: "query") */
116
+ searchParam?: string;
117
+ /** Param name for limit (default: "limit") */
118
+ limitParam?: string;
119
+ /** Param name for get/delete ID (default: "id") */
120
+ idParam?: string;
121
+ /** Static params always sent to list tool */
122
+ listParams?: Record<string, unknown>;
123
+ }
124
+ /**
125
+ * Mapping from tool list data to UI fields
126
+ */
127
+ interface ToolSettingsListMapping {
128
+ /** Key for items array in tool result data */
129
+ itemsKey: string;
130
+ /** Key for total count in tool result data */
131
+ countKey?: string;
132
+ /** Key for item ID */
133
+ idKey: string;
134
+ /** Key for item label */
135
+ labelKey: string;
136
+ /** Key for item description */
137
+ descriptionKey?: string;
138
+ /** Key for secondary label */
139
+ secondaryKey?: string;
140
+ }
141
+ /**
142
+ * Provider definition (metadata only, implementation in code)
143
+ */
144
+ interface ProviderDefinition {
145
+ /** Provider ID */
146
+ id: string;
147
+ /** Display name */
148
+ name: string;
149
+ /** Description */
150
+ description?: string;
151
+ /** Suggested default model when creating a new model configuration */
152
+ suggestedDefaultModel?: string;
153
+ /** Default settings for this provider (e.g., { url: "http://localhost:11434" }) */
154
+ defaultSettings?: Record<string, unknown>;
155
+ /** Schema for provider-specific configuration UI */
156
+ configSchema?: ProviderConfigSchema;
157
+ }
158
+ type PromptSection = 'system' | 'behavior' | 'tools';
159
+ interface PromptContribution {
160
+ /** Unique ID within the extension */
161
+ id: string;
162
+ /** Optional title for the prompt chunk */
163
+ title?: string;
164
+ /** Prompt section placement */
165
+ section?: PromptSection;
166
+ /** Plain text prompt content */
167
+ text?: string;
168
+ /** Optional localized prompt content (keyed by locale, e.g. "en", "sv") */
169
+ i18n?: Record<string, string>;
170
+ /** Optional ordering hint (lower comes first) */
171
+ order?: number;
172
+ }
173
+ /**
174
+ * Schema for provider-specific configuration.
175
+ * Used to generate UI forms for configuring provider settings.
176
+ */
177
+ interface ProviderConfigSchema {
178
+ /** Property definitions */
179
+ properties: Record<string, ProviderConfigProperty>;
180
+ /** Display order of properties in UI (optional, defaults to object key order) */
181
+ order?: string[];
182
+ }
183
+ /**
184
+ * Property types for provider configuration
185
+ */
186
+ type ProviderConfigPropertyType = 'string' | 'number' | 'boolean' | 'select' | 'password' | 'url';
187
+ /**
188
+ * Single property in a provider configuration schema.
189
+ * Defines how a setting should be rendered and validated in the UI.
190
+ */
191
+ interface ProviderConfigProperty {
192
+ /** Property type - determines UI control */
193
+ type: ProviderConfigPropertyType;
194
+ /** Display label */
195
+ title: string;
196
+ /** Help text shown below the input */
197
+ description?: string;
198
+ /** Default value */
199
+ default?: unknown;
200
+ /** Whether the field is required */
201
+ required?: boolean;
202
+ /** Placeholder text for input fields */
203
+ placeholder?: string;
204
+ /** For 'select' type: static options */
205
+ options?: ProviderConfigSelectOption[];
206
+ /** Validation rules */
207
+ validation?: ProviderConfigValidation;
208
+ }
209
+ /**
210
+ * Option for select-type properties
211
+ */
212
+ interface ProviderConfigSelectOption {
213
+ /** Value stored in settings */
214
+ value: string;
215
+ /** Display label */
216
+ label: string;
217
+ }
218
+ /**
219
+ * Validation rules for a property
220
+ */
221
+ interface ProviderConfigValidation {
222
+ /** Regex pattern the value must match */
223
+ pattern?: string;
224
+ /** Minimum string length */
225
+ minLength?: number;
226
+ /** Maximum string length */
227
+ maxLength?: number;
228
+ /** Minimum number value */
229
+ min?: number;
230
+ /** Maximum number value */
231
+ max?: number;
232
+ }
233
+ /**
234
+ * Tool definition (metadata only, implementation in code)
235
+ */
236
+ interface ToolDefinition {
237
+ /** Tool ID */
238
+ id: string;
239
+ /** Display name */
240
+ name: string;
241
+ /** Description for Stina */
242
+ description: string;
243
+ /** Parameter schema (JSON Schema) */
244
+ parameters?: Record<string, unknown>;
245
+ }
246
+ /**
247
+ * Command definition
248
+ */
249
+ interface CommandDefinition {
250
+ /** Command ID (e.g., "weather" for /weather) */
251
+ id: string;
252
+ /** Display name */
253
+ name: string;
254
+ /** Description */
255
+ description: string;
256
+ }
257
+ type Permission = NetworkPermission | StoragePermission | UserDataPermission | CapabilityPermission | SystemPermission;
258
+ /** Network access permissions */
259
+ type NetworkPermission = 'network:*' | `network:localhost` | `network:localhost:${number}` | `network:${string}`;
260
+ /** Storage permissions */
261
+ type StoragePermission = 'database.own' | 'storage.local';
262
+ /** User data permissions */
263
+ type UserDataPermission = 'user.profile.read' | 'user.location.read' | 'chat.history.read' | 'chat.current.read';
264
+ /** Capability permissions */
265
+ type CapabilityPermission = 'provider.register' | 'tools.register' | 'settings.register' | 'commands.register';
266
+ /** System permissions */
267
+ type SystemPermission = 'files.read' | 'files.write' | 'clipboard.read' | 'clipboard.write';
268
+ /**
269
+ * Disposable resource that can be cleaned up
270
+ */
271
+ interface Disposable {
272
+ dispose(): void;
273
+ }
274
+ /**
275
+ * Context provided to extension's activate function
276
+ */
277
+ interface ExtensionContext {
278
+ /** Extension metadata */
279
+ readonly extension: {
280
+ readonly id: string;
281
+ readonly version: string;
282
+ readonly storagePath: string;
283
+ };
284
+ /** Network access (if permitted) */
285
+ readonly network?: NetworkAPI;
286
+ /** Settings access (if permitted) */
287
+ readonly settings?: SettingsAPI;
288
+ /** Provider registration (if permitted) */
289
+ readonly providers?: ProvidersAPI;
290
+ /** Tool registration (if permitted) */
291
+ readonly tools?: ToolsAPI;
292
+ /** Database access (if permitted) */
293
+ readonly database?: DatabaseAPI;
294
+ /** Local storage (if permitted) */
295
+ readonly storage?: StorageAPI;
296
+ /** Logging (always available) */
297
+ readonly log: LogAPI;
298
+ }
299
+ /**
300
+ * Network API for making HTTP requests
301
+ */
302
+ interface NetworkAPI {
303
+ /**
304
+ * Fetch a URL (permissions are enforced by host)
305
+ */
306
+ fetch(url: string, options?: RequestInit): Promise<Response>;
307
+ }
308
+ /**
309
+ * Settings API for reading/writing extension settings
310
+ */
311
+ interface SettingsAPI {
312
+ /**
313
+ * Get all settings for this extension
314
+ */
315
+ getAll<T extends Record<string, unknown>>(): Promise<T>;
316
+ /**
317
+ * Get a specific setting value
318
+ */
319
+ get<T>(key: string): Promise<T | undefined>;
320
+ /**
321
+ * Set a setting value
322
+ */
323
+ set(key: string, value: unknown): Promise<void>;
324
+ /**
325
+ * Listen for setting changes
326
+ */
327
+ onChange(callback: (key: string, value: unknown) => void): Disposable;
328
+ }
329
+ /**
330
+ * Providers API for registering AI providers
331
+ */
332
+ interface ProvidersAPI {
333
+ /**
334
+ * Register an AI provider
335
+ */
336
+ register(provider: AIProvider): Disposable;
337
+ }
338
+ /**
339
+ * Tools API for registering tools
340
+ */
341
+ interface ToolsAPI {
342
+ /**
343
+ * Register a tool that Stina can use
344
+ */
345
+ register(tool: Tool): Disposable;
346
+ }
347
+ /**
348
+ * Database API for extension-specific tables
349
+ */
350
+ interface DatabaseAPI {
351
+ /**
352
+ * Execute a SQL query (only extension's prefixed tables allowed)
353
+ */
354
+ execute<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>;
355
+ }
356
+ /**
357
+ * Simple key-value storage API
358
+ */
359
+ interface StorageAPI {
360
+ /**
361
+ * Get a value by key
362
+ */
363
+ get<T>(key: string): Promise<T | undefined>;
364
+ /**
365
+ * Set a value
366
+ */
367
+ set(key: string, value: unknown): Promise<void>;
368
+ /**
369
+ * Delete a key
370
+ */
371
+ delete(key: string): Promise<void>;
372
+ /**
373
+ * Get all keys
374
+ */
375
+ keys(): Promise<string[]>;
376
+ }
377
+ /**
378
+ * Logging API
379
+ */
380
+ interface LogAPI {
381
+ debug(message: string, data?: Record<string, unknown>): void;
382
+ info(message: string, data?: Record<string, unknown>): void;
383
+ warn(message: string, data?: Record<string, unknown>): void;
384
+ error(message: string, data?: Record<string, unknown>): void;
385
+ }
386
+ /**
387
+ * AI provider implementation
388
+ */
389
+ interface AIProvider {
390
+ /** Provider ID (must match manifest) */
391
+ id: string;
392
+ /** Display name */
393
+ name: string;
394
+ /**
395
+ * Get available models from this provider
396
+ * @param options Optional settings for the provider (e.g., URL)
397
+ */
398
+ getModels(options?: GetModelsOptions): Promise<ModelInfo[]>;
399
+ /**
400
+ * Chat completion with streaming
401
+ */
402
+ chat(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamEvent, void, unknown>;
403
+ /**
404
+ * Optional: Generate embeddings
405
+ */
406
+ embed?(texts: string[]): Promise<number[][]>;
407
+ }
408
+ /**
409
+ * Model information
410
+ */
411
+ interface ModelInfo {
412
+ /** Model ID */
413
+ id: string;
414
+ /** Display name */
415
+ name: string;
416
+ /** Description */
417
+ description?: string;
418
+ /** Context window size */
419
+ contextLength?: number;
420
+ }
421
+ /**
422
+ * Chat message
423
+ */
424
+ interface ChatMessage {
425
+ role: 'user' | 'assistant' | 'system' | 'tool';
426
+ content: string;
427
+ /** For assistant messages: tool calls made by the model */
428
+ tool_calls?: ToolCall[];
429
+ /** For tool messages: the ID of the tool call this is a response to */
430
+ tool_call_id?: string;
431
+ }
432
+ /**
433
+ * A tool call made by the model
434
+ */
435
+ interface ToolCall {
436
+ /** Unique ID for this tool call */
437
+ id: string;
438
+ /** Tool name/ID to invoke */
439
+ name: string;
440
+ /** Arguments for the tool (as parsed object) */
441
+ arguments: Record<string, unknown>;
442
+ }
443
+ /**
444
+ * Options for chat completion
445
+ */
446
+ interface ChatOptions {
447
+ /** Model to use */
448
+ model?: string;
449
+ /** Temperature (0-1) */
450
+ temperature?: number;
451
+ /** Maximum tokens to generate */
452
+ maxTokens?: number;
453
+ /** Abort signal for cancellation */
454
+ signal?: AbortSignal;
455
+ /** Provider-specific settings from model configuration */
456
+ settings?: Record<string, unknown>;
457
+ /** Available tools for this request */
458
+ tools?: ToolDefinition[];
459
+ }
460
+ /**
461
+ * Options for getModels
462
+ */
463
+ interface GetModelsOptions {
464
+ /** Provider-specific settings (e.g., URL for Ollama) */
465
+ settings?: Record<string, unknown>;
466
+ }
467
+ /**
468
+ * Streaming events from chat
469
+ */
470
+ type StreamEvent = {
471
+ type: 'content';
472
+ text: string;
473
+ } | {
474
+ type: 'thinking';
475
+ text: string;
476
+ } | {
477
+ type: 'tool_start';
478
+ name: string;
479
+ input: unknown;
480
+ toolCallId: string;
481
+ } | {
482
+ type: 'tool_end';
483
+ name: string;
484
+ output: unknown;
485
+ toolCallId: string;
486
+ } | {
487
+ type: 'done';
488
+ usage?: {
489
+ inputTokens: number;
490
+ outputTokens: number;
491
+ };
492
+ } | {
493
+ type: 'error';
494
+ message: string;
495
+ };
496
+ /**
497
+ * Tool implementation
498
+ */
499
+ interface Tool {
500
+ /** Tool ID (must match manifest) */
501
+ id: string;
502
+ /** Display name */
503
+ name: string;
504
+ /** Description for Stina */
505
+ description: string;
506
+ /** Parameter schema (JSON Schema) */
507
+ parameters?: Record<string, unknown>;
508
+ /**
509
+ * Execute the tool
510
+ */
511
+ execute(params: Record<string, unknown>): Promise<ToolResult>;
512
+ }
513
+ /**
514
+ * Tool execution result
515
+ */
516
+ interface ToolResult {
517
+ /** Whether the tool succeeded */
518
+ success: boolean;
519
+ /** Result data (for Stina to use) */
520
+ data?: unknown;
521
+ /** Human-readable message */
522
+ message?: string;
523
+ /** Error message if failed */
524
+ error?: string;
525
+ }
526
+ /**
527
+ * Extension entry point interface
528
+ */
529
+ interface ExtensionModule {
530
+ /**
531
+ * Called when extension is activated
532
+ */
533
+ activate(context: ExtensionContext): void | Disposable | Promise<void | Disposable>;
534
+ /**
535
+ * Called when extension is deactivated
536
+ */
537
+ deactivate?(): void | Promise<void>;
538
+ }
539
+
540
+ export type { DatabaseAPI as A, StorageAPI as B, ChatMessage as C, Disposable as D, ExtensionManifest as E, AIProvider as F, GetModelsOptions as G, ToolCall as H, Tool as I, ExtensionModule as J, LogAPI as L, ModelInfo as M, NetworkPermission as N, Platform as P, StreamEvent as S, ToolResult as T, UserDataPermission as U, ChatOptions as a, ExtensionContributions as b, SettingDefinition as c, ToolSettingsViewDefinition as d, ToolSettingsView as e, ToolSettingsListView as f, ToolSettingsListMapping as g, ProviderDefinition as h, PromptContribution as i, PromptSection as j, ToolDefinition as k, CommandDefinition as l, ProviderConfigSchema as m, ProviderConfigProperty as n, ProviderConfigPropertyType as o, ProviderConfigSelectOption as p, ProviderConfigValidation as q, Permission as r, StoragePermission as s, CapabilityPermission as t, SystemPermission as u, ExtensionContext as v, NetworkAPI as w, SettingsAPI as x, ProvidersAPI as y, ToolsAPI as z };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@stina/extension-api",
3
+ "version": "0.5.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ },
14
+ "./runtime": {
15
+ "types": "./dist/runtime.d.ts",
16
+ "import": "./dist/runtime.js",
17
+ "require": "./dist/runtime.cjs"
18
+ }
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "tsup",
25
+ "dev": "tsup --watch",
26
+ "typecheck": "tsc --noEmit"
27
+ },
28
+ "devDependencies": {
29
+ "tsup": "^8.0.0",
30
+ "typescript": "^5.3.0"
31
+ }
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @stina/extension-api
3
+ *
4
+ * Types and utilities for building Stina extensions.
5
+ *
6
+ * Extensions should import from this package for type definitions.
7
+ * The runtime (worker-side code) should import from '@stina/extension-api/runtime'.
8
+ */
9
+
10
+ // Types
11
+ export type {
12
+ // Manifest
13
+ ExtensionManifest,
14
+ Platform,
15
+ ExtensionContributions,
16
+ SettingDefinition,
17
+ ToolSettingsViewDefinition,
18
+ ToolSettingsView,
19
+ ToolSettingsListView,
20
+ ToolSettingsListMapping,
21
+ ProviderDefinition,
22
+ PromptContribution,
23
+ PromptSection,
24
+ ToolDefinition,
25
+ CommandDefinition,
26
+
27
+ // Provider Configuration Schema
28
+ ProviderConfigSchema,
29
+ ProviderConfigProperty,
30
+ ProviderConfigPropertyType,
31
+ ProviderConfigSelectOption,
32
+ ProviderConfigValidation,
33
+
34
+ // Permissions
35
+ Permission,
36
+ NetworkPermission,
37
+ StoragePermission,
38
+ UserDataPermission,
39
+ CapabilityPermission,
40
+ SystemPermission,
41
+
42
+ // Context
43
+ ExtensionContext,
44
+ Disposable,
45
+ NetworkAPI,
46
+ SettingsAPI,
47
+ ProvidersAPI,
48
+ ToolsAPI,
49
+ DatabaseAPI,
50
+ StorageAPI,
51
+ LogAPI,
52
+
53
+ // AI Provider
54
+ AIProvider,
55
+ ModelInfo,
56
+ ChatMessage,
57
+ ChatOptions,
58
+ GetModelsOptions,
59
+ StreamEvent,
60
+ ToolCall,
61
+
62
+ // Tools
63
+ Tool,
64
+ ToolResult,
65
+
66
+ // Entry point
67
+ ExtensionModule,
68
+ } from './types.js'
69
+
70
+ // Messages (for host implementation)
71
+ export type {
72
+ HostToWorkerMessage,
73
+ WorkerToHostMessage,
74
+ ActivateMessage,
75
+ DeactivateMessage,
76
+ SettingsChangedMessage,
77
+ ProviderChatRequestMessage,
78
+ ProviderModelsRequestMessage,
79
+ ToolExecuteRequestMessage,
80
+ ToolExecuteResponseMessage,
81
+ ResponseMessage,
82
+ ReadyMessage,
83
+ RequestMessage,
84
+ RequestMethod,
85
+ ProviderRegisteredMessage,
86
+ ToolRegisteredMessage,
87
+ StreamEventMessage,
88
+ LogMessage,
89
+ PendingRequest,
90
+ } from './messages.js'
91
+
92
+ export { generateMessageId } from './messages.js'