@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.
package/src/types.ts ADDED
@@ -0,0 +1,634 @@
1
+ /**
2
+ * Extension manifest format (manifest.json)
3
+ */
4
+ export 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
+
36
+ export type Platform = 'web' | 'electron' | 'tui'
37
+
38
+ /**
39
+ * What an extension can contribute to Stina
40
+ */
41
+ export interface ExtensionContributions {
42
+ /** User-configurable settings */
43
+ settings?: SettingDefinition[]
44
+ /** Tool settings views for UI */
45
+ toolSettings?: ToolSettingsViewDefinition[]
46
+ /** AI providers */
47
+ providers?: ProviderDefinition[]
48
+ /** Tools for Stina to use */
49
+ tools?: ToolDefinition[]
50
+ /** Slash commands */
51
+ commands?: CommandDefinition[]
52
+ /** Prompt contributions for the system prompt */
53
+ prompts?: PromptContribution[]
54
+ }
55
+
56
+ /**
57
+ * Setting definition for the UI
58
+ */
59
+ export interface SettingDefinition {
60
+ /** Setting ID (namespaced automatically) */
61
+ id: string
62
+ /** Display title */
63
+ title: string
64
+ /** Help text */
65
+ description?: string
66
+ /** Setting type */
67
+ type: 'string' | 'number' | 'boolean' | 'select'
68
+ /** Default value */
69
+ default?: unknown
70
+ /** For select type: available options */
71
+ options?: { value: string; label: string }[]
72
+ /** Validation rules */
73
+ validation?: {
74
+ required?: boolean
75
+ min?: number
76
+ max?: number
77
+ pattern?: string
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Tool settings view definition (UI schema)
83
+ */
84
+ export interface ToolSettingsViewDefinition {
85
+ /** Unique view ID within the extension */
86
+ id: string
87
+ /** Display title */
88
+ title: string
89
+ /** Help text */
90
+ description?: string
91
+ /** View configuration */
92
+ view: ToolSettingsView
93
+ /** Fields for create/edit forms (uses SettingDefinition) */
94
+ fields?: SettingDefinition[]
95
+ }
96
+
97
+ /**
98
+ * Tool settings view types
99
+ */
100
+ export type ToolSettingsView = ToolSettingsListView
101
+
102
+ /**
103
+ * List view backed by tools
104
+ */
105
+ export interface ToolSettingsListView {
106
+ /** View kind */
107
+ kind: 'list'
108
+ /** Tool ID for listing items */
109
+ listToolId: string
110
+ /** Tool ID for fetching details (optional) */
111
+ getToolId?: string
112
+ /** Tool ID for creating/updating items (optional) */
113
+ upsertToolId?: string
114
+ /** Tool ID for deleting items (optional) */
115
+ deleteToolId?: string
116
+ /** Mapping from tool data to UI fields */
117
+ mapping: ToolSettingsListMapping
118
+ /** Param name for search query (default: "query") */
119
+ searchParam?: string
120
+ /** Param name for limit (default: "limit") */
121
+ limitParam?: string
122
+ /** Param name for get/delete ID (default: "id") */
123
+ idParam?: string
124
+ /** Static params always sent to list tool */
125
+ listParams?: Record<string, unknown>
126
+ }
127
+
128
+ /**
129
+ * Mapping from tool list data to UI fields
130
+ */
131
+ export interface ToolSettingsListMapping {
132
+ /** Key for items array in tool result data */
133
+ itemsKey: string
134
+ /** Key for total count in tool result data */
135
+ countKey?: string
136
+ /** Key for item ID */
137
+ idKey: string
138
+ /** Key for item label */
139
+ labelKey: string
140
+ /** Key for item description */
141
+ descriptionKey?: string
142
+ /** Key for secondary label */
143
+ secondaryKey?: string
144
+ }
145
+
146
+ /**
147
+ * Provider definition (metadata only, implementation in code)
148
+ */
149
+ export interface ProviderDefinition {
150
+ /** Provider ID */
151
+ id: string
152
+ /** Display name */
153
+ name: string
154
+ /** Description */
155
+ description?: string
156
+ /** Suggested default model when creating a new model configuration */
157
+ suggestedDefaultModel?: string
158
+ /** Default settings for this provider (e.g., { url: "http://localhost:11434" }) */
159
+ defaultSettings?: Record<string, unknown>
160
+ /** Schema for provider-specific configuration UI */
161
+ configSchema?: ProviderConfigSchema
162
+ }
163
+
164
+ // ============================================================================
165
+ // Prompt Contributions
166
+ // ============================================================================
167
+
168
+ export type PromptSection = 'system' | 'behavior' | 'tools'
169
+
170
+ export interface PromptContribution {
171
+ /** Unique ID within the extension */
172
+ id: string
173
+ /** Optional title for the prompt chunk */
174
+ title?: string
175
+ /** Prompt section placement */
176
+ section?: PromptSection
177
+ /** Plain text prompt content */
178
+ text?: string
179
+ /** Optional localized prompt content (keyed by locale, e.g. "en", "sv") */
180
+ i18n?: Record<string, string>
181
+ /** Optional ordering hint (lower comes first) */
182
+ order?: number
183
+ }
184
+
185
+ // ============================================================================
186
+ // Provider Configuration Schema
187
+ // ============================================================================
188
+
189
+ /**
190
+ * Schema for provider-specific configuration.
191
+ * Used to generate UI forms for configuring provider settings.
192
+ */
193
+ export interface ProviderConfigSchema {
194
+ /** Property definitions */
195
+ properties: Record<string, ProviderConfigProperty>
196
+ /** Display order of properties in UI (optional, defaults to object key order) */
197
+ order?: string[]
198
+ }
199
+
200
+ /**
201
+ * Property types for provider configuration
202
+ */
203
+ export type ProviderConfigPropertyType =
204
+ | 'string'
205
+ | 'number'
206
+ | 'boolean'
207
+ | 'select'
208
+ | 'password'
209
+ | 'url'
210
+
211
+ /**
212
+ * Single property in a provider configuration schema.
213
+ * Defines how a setting should be rendered and validated in the UI.
214
+ */
215
+ export interface ProviderConfigProperty {
216
+ /** Property type - determines UI control */
217
+ type: ProviderConfigPropertyType
218
+ /** Display label */
219
+ title: string
220
+ /** Help text shown below the input */
221
+ description?: string
222
+ /** Default value */
223
+ default?: unknown
224
+ /** Whether the field is required */
225
+ required?: boolean
226
+ /** Placeholder text for input fields */
227
+ placeholder?: string
228
+ /** For 'select' type: static options */
229
+ options?: ProviderConfigSelectOption[]
230
+ /** Validation rules */
231
+ validation?: ProviderConfigValidation
232
+ }
233
+
234
+ /**
235
+ * Option for select-type properties
236
+ */
237
+ export interface ProviderConfigSelectOption {
238
+ /** Value stored in settings */
239
+ value: string
240
+ /** Display label */
241
+ label: string
242
+ }
243
+
244
+ /**
245
+ * Validation rules for a property
246
+ */
247
+ export interface ProviderConfigValidation {
248
+ /** Regex pattern the value must match */
249
+ pattern?: string
250
+ /** Minimum string length */
251
+ minLength?: number
252
+ /** Maximum string length */
253
+ maxLength?: number
254
+ /** Minimum number value */
255
+ min?: number
256
+ /** Maximum number value */
257
+ max?: number
258
+ }
259
+
260
+ /**
261
+ * Tool definition (metadata only, implementation in code)
262
+ */
263
+ export interface ToolDefinition {
264
+ /** Tool ID */
265
+ id: string
266
+ /** Display name */
267
+ name: string
268
+ /** Description for Stina */
269
+ description: string
270
+ /** Parameter schema (JSON Schema) */
271
+ parameters?: Record<string, unknown>
272
+ }
273
+
274
+ /**
275
+ * Command definition
276
+ */
277
+ export interface CommandDefinition {
278
+ /** Command ID (e.g., "weather" for /weather) */
279
+ id: string
280
+ /** Display name */
281
+ name: string
282
+ /** Description */
283
+ description: string
284
+ }
285
+
286
+ // ============================================================================
287
+ // Permissions
288
+ // ============================================================================
289
+
290
+ export type Permission =
291
+ | NetworkPermission
292
+ | StoragePermission
293
+ | UserDataPermission
294
+ | CapabilityPermission
295
+ | SystemPermission
296
+
297
+ /** Network access permissions */
298
+ export type NetworkPermission =
299
+ | 'network:*'
300
+ | `network:localhost`
301
+ | `network:localhost:${number}`
302
+ | `network:${string}`
303
+
304
+ /** Storage permissions */
305
+ export type StoragePermission = 'database.own' | 'storage.local'
306
+
307
+ /** User data permissions */
308
+ export type UserDataPermission =
309
+ | 'user.profile.read'
310
+ | 'user.location.read'
311
+ | 'chat.history.read'
312
+ | 'chat.current.read'
313
+
314
+ /** Capability permissions */
315
+ export type CapabilityPermission =
316
+ | 'provider.register'
317
+ | 'tools.register'
318
+ | 'settings.register'
319
+ | 'commands.register'
320
+
321
+ /** System permissions */
322
+ export type SystemPermission =
323
+ | 'files.read'
324
+ | 'files.write'
325
+ | 'clipboard.read'
326
+ | 'clipboard.write'
327
+
328
+ // ============================================================================
329
+ // Extension Context (API available to extensions)
330
+ // ============================================================================
331
+
332
+ /**
333
+ * Disposable resource that can be cleaned up
334
+ */
335
+ export interface Disposable {
336
+ dispose(): void
337
+ }
338
+
339
+ /**
340
+ * Context provided to extension's activate function
341
+ */
342
+ export interface ExtensionContext {
343
+ /** Extension metadata */
344
+ readonly extension: {
345
+ readonly id: string
346
+ readonly version: string
347
+ readonly storagePath: string
348
+ }
349
+
350
+ /** Network access (if permitted) */
351
+ readonly network?: NetworkAPI
352
+
353
+ /** Settings access (if permitted) */
354
+ readonly settings?: SettingsAPI
355
+
356
+ /** Provider registration (if permitted) */
357
+ readonly providers?: ProvidersAPI
358
+
359
+ /** Tool registration (if permitted) */
360
+ readonly tools?: ToolsAPI
361
+
362
+ /** Database access (if permitted) */
363
+ readonly database?: DatabaseAPI
364
+
365
+ /** Local storage (if permitted) */
366
+ readonly storage?: StorageAPI
367
+
368
+ /** Logging (always available) */
369
+ readonly log: LogAPI
370
+ }
371
+
372
+ /**
373
+ * Network API for making HTTP requests
374
+ */
375
+ export interface NetworkAPI {
376
+ /**
377
+ * Fetch a URL (permissions are enforced by host)
378
+ */
379
+ fetch(url: string, options?: RequestInit): Promise<Response>
380
+ }
381
+
382
+ /**
383
+ * Settings API for reading/writing extension settings
384
+ */
385
+ export interface SettingsAPI {
386
+ /**
387
+ * Get all settings for this extension
388
+ */
389
+ getAll<T extends Record<string, unknown>>(): Promise<T>
390
+
391
+ /**
392
+ * Get a specific setting value
393
+ */
394
+ get<T>(key: string): Promise<T | undefined>
395
+
396
+ /**
397
+ * Set a setting value
398
+ */
399
+ set(key: string, value: unknown): Promise<void>
400
+
401
+ /**
402
+ * Listen for setting changes
403
+ */
404
+ onChange(callback: (key: string, value: unknown) => void): Disposable
405
+ }
406
+
407
+ /**
408
+ * Providers API for registering AI providers
409
+ */
410
+ export interface ProvidersAPI {
411
+ /**
412
+ * Register an AI provider
413
+ */
414
+ register(provider: AIProvider): Disposable
415
+ }
416
+
417
+ /**
418
+ * Tools API for registering tools
419
+ */
420
+ export interface ToolsAPI {
421
+ /**
422
+ * Register a tool that Stina can use
423
+ */
424
+ register(tool: Tool): Disposable
425
+ }
426
+
427
+ /**
428
+ * Database API for extension-specific tables
429
+ */
430
+ export interface DatabaseAPI {
431
+ /**
432
+ * Execute a SQL query (only extension's prefixed tables allowed)
433
+ */
434
+ execute<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>
435
+ }
436
+
437
+ /**
438
+ * Simple key-value storage API
439
+ */
440
+ export interface StorageAPI {
441
+ /**
442
+ * Get a value by key
443
+ */
444
+ get<T>(key: string): Promise<T | undefined>
445
+
446
+ /**
447
+ * Set a value
448
+ */
449
+ set(key: string, value: unknown): Promise<void>
450
+
451
+ /**
452
+ * Delete a key
453
+ */
454
+ delete(key: string): Promise<void>
455
+
456
+ /**
457
+ * Get all keys
458
+ */
459
+ keys(): Promise<string[]>
460
+ }
461
+
462
+ /**
463
+ * Logging API
464
+ */
465
+ export interface LogAPI {
466
+ debug(message: string, data?: Record<string, unknown>): void
467
+ info(message: string, data?: Record<string, unknown>): void
468
+ warn(message: string, data?: Record<string, unknown>): void
469
+ error(message: string, data?: Record<string, unknown>): void
470
+ }
471
+
472
+ // ============================================================================
473
+ // AI Provider Types
474
+ // ============================================================================
475
+
476
+ /**
477
+ * AI provider implementation
478
+ */
479
+ export interface AIProvider {
480
+ /** Provider ID (must match manifest) */
481
+ id: string
482
+ /** Display name */
483
+ name: string
484
+
485
+ /**
486
+ * Get available models from this provider
487
+ * @param options Optional settings for the provider (e.g., URL)
488
+ */
489
+ getModels(options?: GetModelsOptions): Promise<ModelInfo[]>
490
+
491
+ /**
492
+ * Chat completion with streaming
493
+ */
494
+ chat(
495
+ messages: ChatMessage[],
496
+ options: ChatOptions
497
+ ): AsyncGenerator<StreamEvent, void, unknown>
498
+
499
+ /**
500
+ * Optional: Generate embeddings
501
+ */
502
+ embed?(texts: string[]): Promise<number[][]>
503
+ }
504
+
505
+ /**
506
+ * Model information
507
+ */
508
+ export interface ModelInfo {
509
+ /** Model ID */
510
+ id: string
511
+ /** Display name */
512
+ name: string
513
+ /** Description */
514
+ description?: string
515
+ /** Context window size */
516
+ contextLength?: number
517
+ }
518
+
519
+ /**
520
+ * Chat message
521
+ */
522
+ export interface ChatMessage {
523
+ role: 'user' | 'assistant' | 'system' | 'tool'
524
+ content: string
525
+ /** For assistant messages: tool calls made by the model */
526
+ tool_calls?: ToolCall[]
527
+ /** For tool messages: the ID of the tool call this is a response to */
528
+ tool_call_id?: string
529
+ }
530
+
531
+ /**
532
+ * A tool call made by the model
533
+ */
534
+ export interface ToolCall {
535
+ /** Unique ID for this tool call */
536
+ id: string
537
+ /** Tool name/ID to invoke */
538
+ name: string
539
+ /** Arguments for the tool (as parsed object) */
540
+ arguments: Record<string, unknown>
541
+ }
542
+
543
+ /**
544
+ * Options for chat completion
545
+ */
546
+ export interface ChatOptions {
547
+ /** Model to use */
548
+ model?: string
549
+ /** Temperature (0-1) */
550
+ temperature?: number
551
+ /** Maximum tokens to generate */
552
+ maxTokens?: number
553
+ /** Abort signal for cancellation */
554
+ signal?: AbortSignal
555
+ /** Provider-specific settings from model configuration */
556
+ settings?: Record<string, unknown>
557
+ /** Available tools for this request */
558
+ tools?: ToolDefinition[]
559
+ }
560
+
561
+ /**
562
+ * Options for getModels
563
+ */
564
+ export interface GetModelsOptions {
565
+ /** Provider-specific settings (e.g., URL for Ollama) */
566
+ settings?: Record<string, unknown>
567
+ }
568
+
569
+ /**
570
+ * Streaming events from chat
571
+ */
572
+ export type StreamEvent =
573
+ | { type: 'content'; text: string }
574
+ | { type: 'thinking'; text: string }
575
+ | { type: 'tool_start'; name: string; input: unknown; toolCallId: string }
576
+ | { type: 'tool_end'; name: string; output: unknown; toolCallId: string }
577
+ | { type: 'done'; usage?: { inputTokens: number; outputTokens: number } }
578
+ | { type: 'error'; message: string }
579
+
580
+ // ============================================================================
581
+ // Tool Types
582
+ // ============================================================================
583
+
584
+ /**
585
+ * Tool implementation
586
+ */
587
+ export interface Tool {
588
+ /** Tool ID (must match manifest) */
589
+ id: string
590
+ /** Display name */
591
+ name: string
592
+ /** Description for Stina */
593
+ description: string
594
+ /** Parameter schema (JSON Schema) */
595
+ parameters?: Record<string, unknown>
596
+
597
+ /**
598
+ * Execute the tool
599
+ */
600
+ execute(params: Record<string, unknown>): Promise<ToolResult>
601
+ }
602
+
603
+ /**
604
+ * Tool execution result
605
+ */
606
+ export interface ToolResult {
607
+ /** Whether the tool succeeded */
608
+ success: boolean
609
+ /** Result data (for Stina to use) */
610
+ data?: unknown
611
+ /** Human-readable message */
612
+ message?: string
613
+ /** Error message if failed */
614
+ error?: string
615
+ }
616
+
617
+ // ============================================================================
618
+ // Extension Entry Point
619
+ // ============================================================================
620
+
621
+ /**
622
+ * Extension entry point interface
623
+ */
624
+ export interface ExtensionModule {
625
+ /**
626
+ * Called when extension is activated
627
+ */
628
+ activate(context: ExtensionContext): void | Disposable | Promise<void | Disposable>
629
+
630
+ /**
631
+ * Called when extension is deactivated
632
+ */
633
+ deactivate?(): void | Promise<void>
634
+ }
Binary file
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": "./src",
6
+ "lib": ["ES2022", "WebWorker"]
7
+ },
8
+ "include": ["src/**/*"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['src/index.ts', 'src/runtime.ts'],
5
+ format: ['esm', 'cjs'],
6
+ dts: true,
7
+ clean: true,
8
+ sourcemap: true,
9
+ })