@stina/extension-api 0.19.1 → 0.20.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,404 @@
1
+ /**
2
+ * Contribution Types
3
+ *
4
+ * Types for extension contributions: settings, panels, providers, tools, commands, prompts.
5
+ */
6
+
7
+ import type { LocalizedString } from './types.localization.js'
8
+ import type { ExtensionComponentData } from './types.components.js'
9
+
10
+ /**
11
+ * What an extension can contribute to Stina
12
+ */
13
+ export interface ExtensionContributions {
14
+ /** User-configurable settings */
15
+ settings?: SettingDefinition[]
16
+ /** Tool settings views for UI */
17
+ toolSettings?: ToolSettingsViewDefinition[]
18
+ /** Right panel contributions */
19
+ panels?: PanelDefinition[]
20
+ /** AI providers */
21
+ providers?: ProviderDefinition[]
22
+ /** Tools for Stina to use */
23
+ tools?: ToolDefinition[]
24
+ /** Slash commands */
25
+ commands?: CommandDefinition[]
26
+ /** Prompt contributions for the system prompt */
27
+ prompts?: PromptContribution[]
28
+ }
29
+
30
+ // ============================================================================
31
+ // Settings
32
+ // ============================================================================
33
+
34
+ /**
35
+ * Setting definition for the UI
36
+ */
37
+ export interface SettingDefinition {
38
+ /** Setting ID (namespaced automatically) */
39
+ id: string
40
+ /** Display title */
41
+ title: string
42
+ /** Help text */
43
+ description?: string
44
+ /** Setting type */
45
+ type: 'string' | 'number' | 'boolean' | 'select'
46
+ /** Default value */
47
+ default?: unknown
48
+ /** For select type: available options */
49
+ options?: { value: string; label: string }[]
50
+ /** For select type: load options from tool */
51
+ optionsToolId?: string
52
+ /** Params for options tool */
53
+ optionsParams?: Record<string, unknown>
54
+ /** Mapping for options tool response */
55
+ optionsMapping?: SettingOptionsMapping
56
+ /** Tool ID for creating a new option */
57
+ createToolId?: string
58
+ /** Label for create action */
59
+ createLabel?: string
60
+ /** Fields for create form */
61
+ createFields?: SettingDefinition[]
62
+ /** Static params always sent to create tool */
63
+ createParams?: Record<string, unknown>
64
+ /** Mapping for create tool response */
65
+ createMapping?: SettingCreateMapping
66
+ /** Validation rules */
67
+ validation?: {
68
+ required?: boolean
69
+ min?: number
70
+ max?: number
71
+ pattern?: string
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Mapping for select field options from tool response
77
+ */
78
+ export interface SettingOptionsMapping {
79
+ /** Key for items array in tool result data */
80
+ itemsKey: string
81
+ /** Key for option value */
82
+ valueKey: string
83
+ /** Key for option label */
84
+ labelKey: string
85
+ /** Optional key for description */
86
+ descriptionKey?: string
87
+ }
88
+
89
+ /**
90
+ * Mapping for create tool response
91
+ */
92
+ export interface SettingCreateMapping {
93
+ /** Key for result data object */
94
+ resultKey?: string
95
+ /** Key for option value (defaults to "id") */
96
+ valueKey: string
97
+ }
98
+
99
+ // ============================================================================
100
+ // Tool Settings Views
101
+ // ============================================================================
102
+
103
+ /**
104
+ * Tool settings view definition (UI schema)
105
+ */
106
+ export interface ToolSettingsViewDefinition {
107
+ /** Unique view ID within the extension */
108
+ id: string
109
+ /** Display title */
110
+ title: string
111
+ /** Help text */
112
+ description?: string
113
+ /** View configuration */
114
+ view: ToolSettingsView
115
+ /** Fields for create/edit forms (uses SettingDefinition) */
116
+ fields?: SettingDefinition[]
117
+ }
118
+
119
+ /**
120
+ * Tool settings view types
121
+ */
122
+ export type ToolSettingsView = ToolSettingsListView | ToolSettingsComponentView
123
+
124
+ /**
125
+ * List view backed by tools
126
+ */
127
+ export interface ToolSettingsListView {
128
+ /** View kind */
129
+ kind: 'list'
130
+ /** Tool ID for listing items */
131
+ listToolId: string
132
+ /** Tool ID for fetching details (optional) */
133
+ getToolId?: string
134
+ /** Tool ID for creating/updating items (optional) */
135
+ upsertToolId?: string
136
+ /** Tool ID for deleting items (optional) */
137
+ deleteToolId?: string
138
+ /** Mapping from tool data to UI fields */
139
+ mapping: ToolSettingsListMapping
140
+ /** Param name for search query (default: "query") */
141
+ searchParam?: string
142
+ /** Param name for limit (default: "limit") */
143
+ limitParam?: string
144
+ /** Param name for get/delete ID (default: "id") */
145
+ idParam?: string
146
+ /** Static params always sent to list tool */
147
+ listParams?: Record<string, unknown>
148
+ }
149
+
150
+ /**
151
+ * Mapping from tool list data to UI fields
152
+ */
153
+ export interface ToolSettingsListMapping {
154
+ /** Key for items array in tool result data */
155
+ itemsKey: string
156
+ /** Key for total count in tool result data */
157
+ countKey?: string
158
+ /** Key for item ID */
159
+ idKey: string
160
+ /** Key for item label */
161
+ labelKey: string
162
+ /** Key for item description */
163
+ descriptionKey?: string
164
+ /** Key for secondary label */
165
+ secondaryKey?: string
166
+ }
167
+
168
+ /**
169
+ * Component-based tool settings view using the declarative DSL.
170
+ * Reuses the same structure as PanelComponentView for consistency.
171
+ */
172
+ export interface ToolSettingsComponentView {
173
+ /** View kind */
174
+ kind: 'component'
175
+ /** Data sources. Keys become scope variables (e.g., "$settings"). */
176
+ data?: Record<string, ToolSettingsActionDataSource>
177
+ /** Root component to render */
178
+ content: ExtensionComponentData
179
+ }
180
+
181
+ /**
182
+ * Action-based data source for tool settings.
183
+ */
184
+ export interface ToolSettingsActionDataSource {
185
+ /** Action ID to call for fetching data */
186
+ action: string
187
+ /** Parameters to pass to the action */
188
+ params?: Record<string, unknown>
189
+ /** Event names that trigger refresh */
190
+ refreshOn?: string[]
191
+ }
192
+
193
+ // ============================================================================
194
+ // Panels
195
+ // ============================================================================
196
+
197
+ /**
198
+ * Panel definition for right panel views
199
+ */
200
+ export interface PanelDefinition {
201
+ /** Unique panel ID within the extension */
202
+ id: string
203
+ /** Display title */
204
+ title: string
205
+ /** Icon name (from huge-icons) */
206
+ icon?: string
207
+ /** Panel view schema */
208
+ view: PanelView
209
+ }
210
+
211
+ /**
212
+ * Panel view schema (declarative)
213
+ */
214
+ export type PanelView = PanelComponentView | PanelUnknownView
215
+
216
+ export interface PanelUnknownView {
217
+ /** View kind */
218
+ kind: string
219
+ /** Additional view configuration */
220
+ [key: string]: unknown
221
+ }
222
+
223
+ /**
224
+ * Action-based data source for declarative panels.
225
+ * Uses actions (not tools) to fetch data.
226
+ */
227
+ export interface PanelActionDataSource {
228
+ /** Action ID to call for fetching data */
229
+ action: string
230
+ /** Parameters to pass to the action */
231
+ params?: Record<string, unknown>
232
+ /** Event names that should trigger a refresh of this data */
233
+ refreshOn?: string[]
234
+ }
235
+
236
+ /**
237
+ * Component-based panel view using the declarative DSL.
238
+ * Data is fetched via actions, content is rendered via ExtensionComponent.
239
+ */
240
+ export interface PanelComponentView {
241
+ kind: 'component'
242
+ /** Data sources available in the panel. Keys become variable names (e.g., "$projects"). */
243
+ data?: Record<string, PanelActionDataSource>
244
+ /** Root component to render */
245
+ content: ExtensionComponentData
246
+ }
247
+
248
+ // ============================================================================
249
+ // Providers
250
+ // ============================================================================
251
+
252
+ /**
253
+ * Provider definition (metadata only, implementation in code)
254
+ */
255
+ export interface ProviderDefinition {
256
+ /** Provider ID */
257
+ id: string
258
+ /** Display name */
259
+ name: string
260
+ /** Description */
261
+ description?: string
262
+ /** Suggested default model when creating a new model configuration */
263
+ suggestedDefaultModel?: string
264
+ /** Default settings for this provider (e.g., { url: "http://localhost:11434" }) */
265
+ defaultSettings?: Record<string, unknown>
266
+ /** Schema for provider-specific configuration UI */
267
+ configSchema?: ProviderConfigSchema
268
+ }
269
+
270
+ /**
271
+ * Schema for provider-specific configuration.
272
+ * Used to generate UI forms for configuring provider settings.
273
+ */
274
+ export interface ProviderConfigSchema {
275
+ /** Property definitions */
276
+ properties: Record<string, ProviderConfigProperty>
277
+ /** Display order of properties in UI (optional, defaults to object key order) */
278
+ order?: string[]
279
+ }
280
+
281
+ /**
282
+ * Property types for provider configuration
283
+ */
284
+ export type ProviderConfigPropertyType =
285
+ | 'string'
286
+ | 'number'
287
+ | 'boolean'
288
+ | 'select'
289
+ | 'password'
290
+ | 'url'
291
+
292
+ /**
293
+ * Single property in a provider configuration schema.
294
+ * Defines how a setting should be rendered and validated in the UI.
295
+ */
296
+ export interface ProviderConfigProperty {
297
+ /** Property type - determines UI control */
298
+ type: ProviderConfigPropertyType
299
+ /** Display label */
300
+ title: string
301
+ /** Help text shown below the input */
302
+ description?: string
303
+ /** Default value */
304
+ default?: unknown
305
+ /** Whether the field is required */
306
+ required?: boolean
307
+ /** Placeholder text for input fields */
308
+ placeholder?: string
309
+ /** For 'select' type: static options */
310
+ options?: ProviderConfigSelectOption[]
311
+ /** Validation rules */
312
+ validation?: ProviderConfigValidation
313
+ }
314
+
315
+ /**
316
+ * Option for select-type properties
317
+ */
318
+ export interface ProviderConfigSelectOption {
319
+ /** Value stored in settings */
320
+ value: string
321
+ /** Display label */
322
+ label: string
323
+ }
324
+
325
+ /**
326
+ * Validation rules for a property
327
+ */
328
+ export interface ProviderConfigValidation {
329
+ /** Regex pattern the value must match */
330
+ pattern?: string
331
+ /** Minimum string length */
332
+ minLength?: number
333
+ /** Maximum string length */
334
+ maxLength?: number
335
+ /** Minimum number value */
336
+ min?: number
337
+ /** Maximum number value */
338
+ max?: number
339
+ }
340
+
341
+ // ============================================================================
342
+ // Tools
343
+ // ============================================================================
344
+
345
+ /**
346
+ * Tool definition (metadata only, implementation in code)
347
+ */
348
+ export interface ToolDefinition {
349
+ /** Tool ID */
350
+ id: string
351
+ /**
352
+ * Display name - can be a simple string or localized strings.
353
+ * @example "Get Weather"
354
+ * @example { en: "Get Weather", sv: "Hämta väder" }
355
+ */
356
+ name: LocalizedString
357
+ /**
358
+ * Description for Stina - can be a simple string or localized strings.
359
+ * Note: The AI always receives the English description (or fallback) for consistency.
360
+ * Localized descriptions are used for UI display only.
361
+ * @example "Fetches current weather for a location"
362
+ * @example { en: "Fetches current weather", sv: "Hämtar aktuellt väder" }
363
+ */
364
+ description: LocalizedString
365
+ /** Parameter schema (JSON Schema) */
366
+ parameters?: Record<string, unknown>
367
+ }
368
+
369
+ // ============================================================================
370
+ // Commands
371
+ // ============================================================================
372
+
373
+ /**
374
+ * Command definition
375
+ */
376
+ export interface CommandDefinition {
377
+ /** Command ID (e.g., "weather" for /weather) */
378
+ id: string
379
+ /** Display name */
380
+ name: string
381
+ /** Description */
382
+ description: string
383
+ }
384
+
385
+ // ============================================================================
386
+ // Prompts
387
+ // ============================================================================
388
+
389
+ export type PromptSection = 'system' | 'behavior' | 'tools'
390
+
391
+ export interface PromptContribution {
392
+ /** Unique ID within the extension */
393
+ id: string
394
+ /** Optional title for the prompt chunk */
395
+ title?: string
396
+ /** Prompt section placement */
397
+ section?: PromptSection
398
+ /** Plain text prompt content */
399
+ text?: string
400
+ /** Optional localized prompt content (keyed by locale, e.g. "en", "sv") */
401
+ i18n?: Record<string, string>
402
+ /** Optional ordering hint (lower comes first) */
403
+ order?: number
404
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Localization Types
3
+ *
4
+ * Types and utilities for localized strings in extensions.
5
+ */
6
+
7
+ /**
8
+ * A string that can be either a simple string or a map of language codes to localized strings.
9
+ * When a simple string is provided, it's used as the default/fallback value.
10
+ * When a map is provided, the appropriate language is selected at runtime.
11
+ *
12
+ * @example
13
+ * // Simple string (backwards compatible)
14
+ * name: "Get Weather"
15
+ *
16
+ * @example
17
+ * // Localized strings
18
+ * name: { en: "Get Weather", sv: "Hämta väder", de: "Wetter abrufen" }
19
+ */
20
+ export type LocalizedString = string | Record<string, string>
21
+
22
+ /**
23
+ * Resolves a LocalizedString to an actual string value.
24
+ * @param value The LocalizedString to resolve
25
+ * @param lang The preferred language code (e.g., "sv", "en")
26
+ * @param fallbackLang The fallback language code (defaults to "en")
27
+ * @returns The resolved string value
28
+ */
29
+ export function resolveLocalizedString(
30
+ value: LocalizedString,
31
+ lang: string,
32
+ fallbackLang = 'en'
33
+ ): string {
34
+ if (typeof value === 'string') {
35
+ return value
36
+ }
37
+ // Try preferred language first, then fallback language, then first available, then empty string
38
+ return value[lang] ?? value[fallbackLang] ?? Object.values(value)[0] ?? ''
39
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Manifest Types
3
+ *
4
+ * Types for extension manifest files (manifest.json).
5
+ */
6
+
7
+ import type { Permission } from './types.permissions.js'
8
+ import type { ExtensionContributions } from './types.contributions.js'
9
+
10
+ /**
11
+ * Extension manifest format (manifest.json)
12
+ */
13
+ export interface ExtensionManifest {
14
+ /** Unique identifier (e.g., "ollama-provider") */
15
+ id: string
16
+ /** Human-readable name */
17
+ name: string
18
+ /** Version string (semver) */
19
+ version: string
20
+ /** Short description */
21
+ description: string
22
+ /** Author information */
23
+ author: {
24
+ name: string
25
+ url?: string
26
+ }
27
+ /** Repository URL */
28
+ repository?: string
29
+ /** License identifier */
30
+ license?: string
31
+ /** Minimum Stina version required */
32
+ engines?: {
33
+ stina: string
34
+ }
35
+ /** Supported platforms */
36
+ platforms?: Platform[]
37
+ /** Entry point file (relative to extension root) */
38
+ main: string
39
+ /** Required permissions */
40
+ permissions: Permission[]
41
+ /** What the extension contributes */
42
+ contributes?: ExtensionContributions
43
+ }
44
+
45
+ export type Platform = 'web' | 'electron' | 'tui'
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Permission Types
3
+ *
4
+ * Defines all permission types for extensions.
5
+ */
6
+
7
+ export type Permission =
8
+ | NetworkPermission
9
+ | StoragePermission
10
+ | UserDataPermission
11
+ | CapabilityPermission
12
+ | SystemPermission
13
+
14
+ /** Network access permissions */
15
+ export type NetworkPermission =
16
+ | 'network:*'
17
+ | `network:localhost`
18
+ | `network:localhost:${number}`
19
+ | `network:${string}`
20
+
21
+ /** Storage permissions */
22
+ export type StoragePermission = 'database.own' | 'storage.local'
23
+
24
+ /** User data permissions */
25
+ export type UserDataPermission =
26
+ | 'user.profile.read'
27
+ | 'user.location.read'
28
+ | 'chat.history.read'
29
+ | 'chat.current.read'
30
+
31
+ /** Capability permissions */
32
+ export type CapabilityPermission =
33
+ | 'provider.register'
34
+ | 'tools.register'
35
+ | 'actions.register'
36
+ | 'settings.register'
37
+ | 'commands.register'
38
+ | 'panels.register'
39
+ | 'events.emit'
40
+ | 'scheduler.register'
41
+ | 'chat.message.write'
42
+
43
+ /** System permissions */
44
+ export type SystemPermission =
45
+ | 'files.read'
46
+ | 'files.write'
47
+ | 'clipboard.read'
48
+ | 'clipboard.write'
@@ -0,0 +1,111 @@
1
+ /**
2
+ * AI Provider Types
3
+ *
4
+ * Types for AI providers, models, and chat interactions.
5
+ */
6
+
7
+ import type { ToolDefinition } from './types.contributions.js'
8
+
9
+ /**
10
+ * AI provider implementation
11
+ */
12
+ export interface AIProvider {
13
+ /** Provider ID (must match manifest) */
14
+ id: string
15
+ /** Display name */
16
+ name: string
17
+
18
+ /**
19
+ * Get available models from this provider
20
+ * @param options Optional settings for the provider (e.g., URL)
21
+ */
22
+ getModels(options?: GetModelsOptions): Promise<ModelInfo[]>
23
+
24
+ /**
25
+ * Chat completion with streaming
26
+ */
27
+ chat(
28
+ messages: ChatMessage[],
29
+ options: ChatOptions
30
+ ): AsyncGenerator<StreamEvent, void, unknown>
31
+
32
+ /**
33
+ * Optional: Generate embeddings
34
+ */
35
+ embed?(texts: string[]): Promise<number[][]>
36
+ }
37
+
38
+ /**
39
+ * Model information
40
+ */
41
+ export interface ModelInfo {
42
+ /** Model ID */
43
+ id: string
44
+ /** Display name */
45
+ name: string
46
+ /** Description */
47
+ description?: string
48
+ /** Context window size */
49
+ contextLength?: number
50
+ }
51
+
52
+ /**
53
+ * Chat message
54
+ */
55
+ export interface ChatMessage {
56
+ role: 'user' | 'assistant' | 'system' | 'tool'
57
+ content: string
58
+ /** For assistant messages: tool calls made by the model */
59
+ tool_calls?: ToolCall[]
60
+ /** For tool messages: the ID of the tool call this is a response to */
61
+ tool_call_id?: string
62
+ }
63
+
64
+ /**
65
+ * A tool call made by the model
66
+ */
67
+ export interface ToolCall {
68
+ /** Unique ID for this tool call */
69
+ id: string
70
+ /** Tool name/ID to invoke */
71
+ name: string
72
+ /** Arguments for the tool (as parsed object) */
73
+ arguments: Record<string, unknown>
74
+ }
75
+
76
+ /**
77
+ * Options for chat completion
78
+ */
79
+ export interface ChatOptions {
80
+ /** Model to use */
81
+ model?: string
82
+ /** Temperature (0-1) */
83
+ temperature?: number
84
+ /** Maximum tokens to generate */
85
+ maxTokens?: number
86
+ /** Abort signal for cancellation */
87
+ signal?: AbortSignal
88
+ /** Provider-specific settings from model configuration */
89
+ settings?: Record<string, unknown>
90
+ /** Available tools for this request */
91
+ tools?: ToolDefinition[]
92
+ }
93
+
94
+ /**
95
+ * Options for getModels
96
+ */
97
+ export interface GetModelsOptions {
98
+ /** Provider-specific settings (e.g., URL for Ollama) */
99
+ settings?: Record<string, unknown>
100
+ }
101
+
102
+ /**
103
+ * Streaming events from chat
104
+ */
105
+ export type StreamEvent =
106
+ | { type: 'content'; text: string }
107
+ | { type: 'thinking'; text: string }
108
+ | { type: 'tool_start'; name: string; input: unknown; toolCallId: string }
109
+ | { type: 'tool_end'; name: string; output: unknown; toolCallId: string }
110
+ | { type: 'done'; usage?: { inputTokens: number; outputTokens: number } }
111
+ | { type: 'error'; message: string }