@stina/extension-api 0.15.0 → 0.16.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/README.md CHANGED
@@ -84,12 +84,97 @@ src/
84
84
  dist/
85
85
  ```
86
86
 
87
+ ## Tools
88
+
89
+ Tools let your extension expose functionality that Stina's AI assistant can call on behalf of the user.
90
+
91
+ ### Registering a tool
92
+
93
+ Tools are registered via:
94
+
95
+ 1. **Manifest declaration** (`manifest.json`) – declares the tool's metadata
96
+ 2. **Runtime registration** (`context.tools.register()`) – provides the execute logic
97
+
98
+ Both approaches require the `tools.register` permission in your manifest.
99
+
100
+ ### Tool definition
101
+
102
+ ```ts
103
+ context.tools?.register({
104
+ id: 'my-extension.weather',
105
+ name: 'Get Weather',
106
+ description: 'Fetches current weather for a location',
107
+ parameters: {
108
+ type: 'object',
109
+ properties: {
110
+ location: { type: 'string', description: 'City name' },
111
+ },
112
+ required: ['location'],
113
+ },
114
+ execute: async (params) => {
115
+ const weather = await fetchWeather(params.location)
116
+ return { success: true, data: weather }
117
+ },
118
+ })
119
+ ```
120
+
121
+ ### Localized names and descriptions
122
+
123
+ To make your extension accessible to users in different languages, you can provide localized `name` and `description` fields using the `LocalizedString` type:
124
+
125
+ ```ts
126
+ type LocalizedString = string | Record<string, string>
127
+ ```
128
+
129
+ You can provide either a simple string (for English-only extensions) or an object with language codes:
130
+
131
+ ```ts
132
+ // Simple string (English only)
133
+ {
134
+ name: 'Get Weather',
135
+ description: 'Fetches current weather for a location',
136
+ }
137
+
138
+ // Localized for multiple languages
139
+ {
140
+ name: {
141
+ en: 'Get Weather',
142
+ sv: 'Hämta väder',
143
+ de: 'Wetter abrufen',
144
+ },
145
+ description: {
146
+ en: 'Fetches current weather for a location',
147
+ sv: 'Hämtar aktuellt väder för en plats',
148
+ de: 'Ruft das aktuelle Wetter für einen Ort ab',
149
+ },
150
+ }
151
+ ```
152
+
153
+ **How it works for your users:**
154
+
155
+ - **In the UI:** Users see the tool name in their preferred language (if you've provided it).
156
+ - **For the AI:** The AI always receives the English version to ensure consistent behavior.
157
+ - **Fallback:** If a translation is missing, Stina falls back to English, then to the first available language.
158
+
159
+ ### Tool result
160
+
161
+ Your `execute` function should return a `ToolResult`:
162
+
163
+ ```ts
164
+ interface ToolResult {
165
+ success?: boolean
166
+ data?: unknown
167
+ error?: string
168
+ }
169
+ ```
170
+
87
171
  ## Common patterns
88
172
 
89
173
  - Use `contributes` in `manifest.json` for UI definitions.
90
174
  - Use `context.tools?.register(...)` or `context.providers?.register(...)` at runtime.
91
175
  - Always include the permission that matches what you register (`tools.register`, `provider.register`, etc.).
92
- - Keep runtime code platform-agnostic; it runs in a worker.
176
+ - Keep runtime code platform-agnostic; it runs in a sandboxed worker.
177
+ - Provide localized `name` and `description` to reach more users.
93
178
 
94
179
  ## Publish to Stina Extension Library
95
180
 
package/dist/index.cjs CHANGED
@@ -20,16 +20,26 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- generateMessageId: () => generateMessageId
23
+ generateMessageId: () => generateMessageId,
24
+ resolveLocalizedString: () => resolveLocalizedString
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
26
27
 
28
+ // src/types.ts
29
+ function resolveLocalizedString(value, lang, fallbackLang = "en") {
30
+ if (typeof value === "string") {
31
+ return value;
32
+ }
33
+ return value[lang] ?? value[fallbackLang] ?? Object.values(value)[0] ?? "";
34
+ }
35
+
27
36
  // src/messages.ts
28
37
  function generateMessageId() {
29
38
  return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
30
39
  }
31
40
  // Annotate the CommonJS export names for ESM import in node:
32
41
  0 && (module.exports = {
33
- generateMessageId
42
+ generateMessageId,
43
+ resolveLocalizedString
34
44
  });
35
45
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/messages.ts"],"sourcesContent":["/**\n * @stina/extension-api\n *\n * Types and utilities for building Stina extensions.\n *\n * Extensions should import from this package for type definitions.\n * The runtime (worker-side code) should import from '@stina/extension-api/runtime'.\n */\n\n// Types\nexport type {\n // Manifest\n ExtensionManifest,\n Platform,\n ExtensionContributions,\n SettingDefinition,\n SettingOptionsMapping,\n SettingCreateMapping,\n ToolSettingsViewDefinition,\n ToolSettingsView,\n ToolSettingsListView,\n ToolSettingsListMapping,\n PanelDefinition,\n PanelView,\n PanelComponentView,\n PanelActionDataSource,\n PanelUnknownView,\n ProviderDefinition,\n PromptContribution,\n PromptSection,\n ToolDefinition,\n CommandDefinition,\n\n // Provider Configuration Schema\n ProviderConfigSchema,\n ProviderConfigProperty,\n ProviderConfigPropertyType,\n ProviderConfigSelectOption,\n ProviderConfigValidation,\n\n // Permissions\n Permission,\n NetworkPermission,\n StoragePermission,\n UserDataPermission,\n CapabilityPermission,\n SystemPermission,\n\n // Context\n ExtensionContext,\n Disposable,\n NetworkAPI,\n SettingsAPI,\n ProvidersAPI,\n ToolsAPI,\n ActionsAPI,\n EventsAPI,\n SchedulerAPI,\n SchedulerJobRequest,\n SchedulerSchedule,\n SchedulerFirePayload,\n UserAPI,\n UserProfile,\n ChatAPI,\n ChatInstructionMessage,\n DatabaseAPI,\n StorageAPI,\n LogAPI,\n\n // AI Provider\n AIProvider,\n ModelInfo,\n ChatMessage,\n ChatOptions,\n GetModelsOptions,\n StreamEvent,\n ToolCall,\n\n // Tools\n Tool,\n ToolResult,\n\n // Actions\n Action,\n ActionResult,\n\n // Entry point\n ExtensionModule,\n} from './types.js'\n\n// Messages (for host implementation)\nexport type {\n HostToWorkerMessage,\n WorkerToHostMessage,\n ActivateMessage,\n DeactivateMessage,\n SettingsChangedMessage,\n ProviderChatRequestMessage,\n ProviderModelsRequestMessage,\n ToolExecuteRequestMessage,\n ToolExecuteResponseMessage,\n ActionExecuteRequestMessage,\n ActionExecuteResponseMessage,\n ResponseMessage,\n ReadyMessage,\n RequestMessage,\n RequestMethod,\n ProviderRegisteredMessage,\n ToolRegisteredMessage,\n ActionRegisteredMessage,\n StreamEventMessage,\n LogMessage,\n PendingRequest,\n} from './messages.js'\n\nexport { generateMessageId } from './messages.js'\n\n// Component types (for extension UI components)\nexport type {\n // Styling\n AllowedCSSProperty,\n ExtensionComponentStyle,\n // Base types\n ExtensionComponentData,\n // Iteration & Children\n ExtensionComponentIterator,\n ExtensionComponentChildren,\n // Actions\n ExtensionActionCall,\n ExtensionActionRef,\n // Data Sources & Panel Definition\n ExtensionDataSource,\n ExtensionPanelDefinition,\n // Component Props\n HeaderProps,\n LabelProps,\n ParagraphProps,\n ButtonProps,\n TextInputProps,\n DateTimeInputProps,\n SelectProps,\n VerticalStackProps,\n HorizontalStackProps,\n GridProps,\n DividerProps,\n IconProps,\n IconButtonType,\n IconButtonProps,\n PanelAction,\n PanelProps,\n ToggleProps,\n CollapsibleProps,\n PillVariant,\n PillProps,\n CheckboxProps,\n MarkdownProps,\n ModalProps,\n} from './types.components.js'\n","/**\n * Message protocol between Extension Host and Extension Workers\n */\n\nimport type {\n ChatMessage,\n ChatOptions,\n GetModelsOptions,\n StreamEvent,\n ToolResult,\n ActionResult,\n ModelInfo,\n SchedulerFirePayload,\n} from './types.js'\n\n// ============================================================================\n// Host → Worker Messages\n// ============================================================================\n\nexport type HostToWorkerMessage =\n | ActivateMessage\n | DeactivateMessage\n | SettingsChangedMessage\n | SchedulerFireMessage\n | ProviderChatRequestMessage\n | ProviderModelsRequestMessage\n | ToolExecuteRequestMessage\n | ActionExecuteRequestMessage\n | ResponseMessage\n | StreamingFetchChunkMessage\n\nexport interface ActivateMessage {\n type: 'activate'\n id: string\n payload: {\n extensionId: string\n extensionVersion: string\n storagePath: string\n permissions: string[]\n settings: Record<string, unknown>\n }\n}\n\nexport interface DeactivateMessage {\n type: 'deactivate'\n id: string\n}\n\nexport interface SettingsChangedMessage {\n type: 'settings-changed'\n id: string\n payload: {\n key: string\n value: unknown\n }\n}\n\nexport interface SchedulerFireMessage {\n type: 'scheduler-fire'\n id: string\n payload: SchedulerFirePayload\n}\n\nexport interface ProviderChatRequestMessage {\n type: 'provider-chat-request'\n id: string\n payload: {\n providerId: string\n messages: ChatMessage[]\n options: ChatOptions\n }\n}\n\nexport interface ProviderModelsRequestMessage {\n type: 'provider-models-request'\n id: string\n payload: {\n providerId: string\n options?: GetModelsOptions\n }\n}\n\nexport interface ToolExecuteRequestMessage {\n type: 'tool-execute-request'\n id: string\n payload: {\n toolId: string\n params: Record<string, unknown>\n /** User ID if the tool is executed in a user context */\n userId?: string\n }\n}\n\nexport interface ActionExecuteRequestMessage {\n type: 'action-execute-request'\n id: string\n payload: {\n actionId: string\n params: Record<string, unknown>\n /** User ID if the action is executed in a user context */\n userId?: string\n }\n}\n\nexport interface ResponseMessage {\n type: 'response'\n id: string\n payload: {\n requestId: string\n success: boolean\n data?: unknown\n error?: string\n }\n}\n\n/**\n * Message sent from host to worker with streaming fetch data chunks.\n * Used for streaming network responses (e.g., NDJSON streams from Ollama).\n */\nexport interface StreamingFetchChunkMessage {\n type: 'streaming-fetch-chunk'\n id: string\n payload: {\n requestId: string\n chunk: string\n done: boolean\n error?: string\n }\n}\n\n// ============================================================================\n// Worker → Host Messages\n// ============================================================================\n\nexport type WorkerToHostMessage =\n | ReadyMessage\n | RequestMessage\n | ProviderRegisteredMessage\n | ToolRegisteredMessage\n | ActionRegisteredMessage\n | StreamEventMessage\n | LogMessage\n | ProviderModelsResponseMessage\n | ToolExecuteResponseMessage\n | ActionExecuteResponseMessage\n | StreamingFetchAckMessage\n\nexport interface ReadyMessage {\n type: 'ready'\n}\n\n/**\n * Message sent from worker to host to acknowledge receipt of a streaming fetch chunk.\n * This enables backpressure control to prevent unbounded memory growth.\n */\nexport interface StreamingFetchAckMessage {\n type: 'streaming-fetch-ack'\n payload: {\n requestId: string\n }\n}\n\nexport interface RequestMessage {\n type: 'request'\n id: string\n method: RequestMethod\n payload: unknown\n}\n\nexport type RequestMethod =\n | 'network.fetch'\n | 'network.fetch-stream'\n | 'settings.getAll'\n | 'settings.get'\n | 'settings.set'\n | 'user.getProfile'\n | 'events.emit'\n | 'scheduler.schedule'\n | 'scheduler.cancel'\n | 'chat.appendInstruction'\n | 'database.execute'\n | 'storage.get'\n | 'storage.set'\n | 'storage.delete'\n | 'storage.keys'\n | 'storage.getForUser'\n | 'storage.setForUser'\n | 'storage.deleteForUser'\n | 'storage.keysForUser'\n\nexport interface ProviderRegisteredMessage {\n type: 'provider-registered'\n payload: {\n id: string\n name: string\n }\n}\n\nexport interface ToolRegisteredMessage {\n type: 'tool-registered'\n payload: {\n id: string\n name: string\n description: string\n parameters?: Record<string, unknown>\n }\n}\n\nexport interface ActionRegisteredMessage {\n type: 'action-registered'\n payload: {\n id: string\n }\n}\n\nexport interface StreamEventMessage {\n type: 'stream-event'\n payload: {\n requestId: string\n event: StreamEvent\n }\n}\n\nexport interface ProviderModelsResponseMessage {\n type: 'provider-models-response'\n payload: {\n requestId: string\n models: ModelInfo[]\n error?: string\n }\n}\n\nexport interface ToolExecuteResponseMessage {\n type: 'tool-execute-response'\n payload: {\n requestId: string\n result: ToolResult\n error?: string\n }\n}\n\nexport interface ActionExecuteResponseMessage {\n type: 'action-execute-response'\n payload: {\n requestId: string\n result: ActionResult\n error?: string\n }\n}\n\nexport interface LogMessage {\n type: 'log'\n payload: {\n level: 'debug' | 'info' | 'warn' | 'error'\n message: string\n data?: Record<string, unknown>\n }\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\nexport interface PendingRequest<T = unknown> {\n resolve: (value: T) => void\n reject: (error: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgRO,SAAS,oBAA4B;AAC1C,SAAO,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACjE;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/messages.ts"],"sourcesContent":["/**\n * @stina/extension-api\n *\n * Types and utilities for building Stina extensions.\n *\n * Extensions should import from this package for type definitions.\n * The runtime (worker-side code) should import from '@stina/extension-api/runtime'.\n */\n\n// Localization\nexport type { LocalizedString } from './types.js'\nexport { resolveLocalizedString } from './types.js'\n\n// Types\nexport type {\n // Manifest\n ExtensionManifest,\n Platform,\n ExtensionContributions,\n SettingDefinition,\n SettingOptionsMapping,\n SettingCreateMapping,\n ToolSettingsViewDefinition,\n ToolSettingsView,\n ToolSettingsListView,\n ToolSettingsListMapping,\n ToolSettingsComponentView,\n ToolSettingsActionDataSource,\n PanelDefinition,\n PanelView,\n PanelComponentView,\n PanelActionDataSource,\n PanelUnknownView,\n ProviderDefinition,\n PromptContribution,\n PromptSection,\n ToolDefinition,\n CommandDefinition,\n\n // Provider Configuration Schema\n ProviderConfigSchema,\n ProviderConfigProperty,\n ProviderConfigPropertyType,\n ProviderConfigSelectOption,\n ProviderConfigValidation,\n\n // Permissions\n Permission,\n NetworkPermission,\n StoragePermission,\n UserDataPermission,\n CapabilityPermission,\n SystemPermission,\n\n // Context\n ExtensionContext,\n Disposable,\n NetworkAPI,\n SettingsAPI,\n ProvidersAPI,\n ToolsAPI,\n ActionsAPI,\n EventsAPI,\n SchedulerAPI,\n SchedulerJobRequest,\n SchedulerSchedule,\n SchedulerFirePayload,\n UserAPI,\n UserProfile,\n ChatAPI,\n ChatInstructionMessage,\n DatabaseAPI,\n StorageAPI,\n LogAPI,\n\n // AI Provider\n AIProvider,\n ModelInfo,\n ChatMessage,\n ChatOptions,\n GetModelsOptions,\n StreamEvent,\n ToolCall,\n\n // Tools\n Tool,\n ToolResult,\n\n // Actions\n Action,\n ActionResult,\n\n // Entry point\n ExtensionModule,\n} from './types.js'\n\n// Messages (for host implementation)\nexport type {\n HostToWorkerMessage,\n WorkerToHostMessage,\n ActivateMessage,\n DeactivateMessage,\n SettingsChangedMessage,\n ProviderChatRequestMessage,\n ProviderModelsRequestMessage,\n ToolExecuteRequestMessage,\n ToolExecuteResponseMessage,\n ActionExecuteRequestMessage,\n ActionExecuteResponseMessage,\n ResponseMessage,\n ReadyMessage,\n RequestMessage,\n RequestMethod,\n ProviderRegisteredMessage,\n ToolRegisteredMessage,\n ActionRegisteredMessage,\n StreamEventMessage,\n LogMessage,\n PendingRequest,\n} from './messages.js'\n\nexport { generateMessageId } from './messages.js'\n\n// Component types (for extension UI components)\nexport type {\n // Styling\n AllowedCSSProperty,\n ExtensionComponentStyle,\n // Base types\n ExtensionComponentData,\n // Iteration & Children\n ExtensionComponentIterator,\n ExtensionComponentChildren,\n // Actions\n ExtensionActionCall,\n ExtensionActionRef,\n // Data Sources & Panel Definition\n ExtensionDataSource,\n ExtensionPanelDefinition,\n // Component Props\n HeaderProps,\n LabelProps,\n ParagraphProps,\n ButtonProps,\n TextInputProps,\n DateTimeInputProps,\n SelectProps,\n VerticalStackProps,\n HorizontalStackProps,\n GridProps,\n DividerProps,\n IconProps,\n IconButtonType,\n IconButtonProps,\n PanelAction,\n PanelProps,\n ToggleProps,\n CollapsibleProps,\n PillVariant,\n PillProps,\n CheckboxProps,\n MarkdownProps,\n ModalProps,\n} from './types.components.js'\n","/**\n * A string that can be either a simple string or a map of language codes to localized strings.\n * When a simple string is provided, it's used as the default/fallback value.\n * When a map is provided, the appropriate language is selected at runtime.\n *\n * @example\n * // Simple string (backwards compatible)\n * name: \"Get Weather\"\n *\n * @example\n * // Localized strings\n * name: { en: \"Get Weather\", sv: \"Hämta väder\", de: \"Wetter abrufen\" }\n */\nexport type LocalizedString = string | Record<string, string>\n\n/**\n * Resolves a LocalizedString to an actual string value.\n * @param value The LocalizedString to resolve\n * @param lang The preferred language code (e.g., \"sv\", \"en\")\n * @param fallbackLang The fallback language code (defaults to \"en\")\n * @returns The resolved string value\n */\nexport function resolveLocalizedString(\n value: LocalizedString,\n lang: string,\n fallbackLang = 'en'\n): string {\n if (typeof value === 'string') {\n return value\n }\n // Try preferred language first, then fallback language, then first available, then empty string\n return value[lang] ?? value[fallbackLang] ?? Object.values(value)[0] ?? ''\n}\n\n/**\n * Extension manifest format (manifest.json)\n */\nexport interface ExtensionManifest {\n /** Unique identifier (e.g., \"ollama-provider\") */\n id: string\n /** Human-readable name */\n name: string\n /** Version string (semver) */\n version: string\n /** Short description */\n description: string\n /** Author information */\n author: {\n name: string\n url?: string\n }\n /** Repository URL */\n repository?: string\n /** License identifier */\n license?: string\n /** Minimum Stina version required */\n engines?: {\n stina: string\n }\n /** Supported platforms */\n platforms?: Platform[]\n /** Entry point file (relative to extension root) */\n main: string\n /** Required permissions */\n permissions: Permission[]\n /** What the extension contributes */\n contributes?: ExtensionContributions\n}\n\nexport type Platform = 'web' | 'electron' | 'tui'\n\n/**\n * What an extension can contribute to Stina\n */\nexport interface ExtensionContributions {\n /** User-configurable settings */\n settings?: SettingDefinition[]\n /** Tool settings views for UI */\n toolSettings?: ToolSettingsViewDefinition[]\n /** Right panel contributions */\n panels?: PanelDefinition[]\n /** AI providers */\n providers?: ProviderDefinition[]\n /** Tools for Stina to use */\n tools?: ToolDefinition[]\n /** Slash commands */\n commands?: CommandDefinition[]\n /** Prompt contributions for the system prompt */\n prompts?: PromptContribution[]\n}\n\n/**\n * Setting definition for the UI\n */\nexport interface SettingDefinition {\n /** Setting ID (namespaced automatically) */\n id: string\n /** Display title */\n title: string\n /** Help text */\n description?: string\n /** Setting type */\n type: 'string' | 'number' | 'boolean' | 'select'\n /** Default value */\n default?: unknown\n /** For select type: available options */\n options?: { value: string; label: string }[]\n /** For select type: load options from tool */\n optionsToolId?: string\n /** Params for options tool */\n optionsParams?: Record<string, unknown>\n /** Mapping for options tool response */\n optionsMapping?: SettingOptionsMapping\n /** Tool ID for creating a new option */\n createToolId?: string\n /** Label for create action */\n createLabel?: string\n /** Fields for create form */\n createFields?: SettingDefinition[]\n /** Static params always sent to create tool */\n createParams?: Record<string, unknown>\n /** Mapping for create tool response */\n createMapping?: SettingCreateMapping\n /** Validation rules */\n validation?: {\n required?: boolean\n min?: number\n max?: number\n pattern?: string\n }\n}\n\n/**\n * Mapping for select field options from tool response\n */\nexport interface SettingOptionsMapping {\n /** Key for items array in tool result data */\n itemsKey: string\n /** Key for option value */\n valueKey: string\n /** Key for option label */\n labelKey: string\n /** Optional key for description */\n descriptionKey?: string\n}\n\n/**\n * Mapping for create tool response\n */\nexport interface SettingCreateMapping {\n /** Key for result data object */\n resultKey?: string\n /** Key for option value (defaults to \"id\") */\n valueKey: string\n}\n\n/**\n * Tool settings view definition (UI schema)\n */\nexport interface ToolSettingsViewDefinition {\n /** Unique view ID within the extension */\n id: string\n /** Display title */\n title: string\n /** Help text */\n description?: string\n /** View configuration */\n view: ToolSettingsView\n /** Fields for create/edit forms (uses SettingDefinition) */\n fields?: SettingDefinition[]\n}\n\n/**\n * Tool settings view types\n */\nexport type ToolSettingsView = ToolSettingsListView | ToolSettingsComponentView\n\n/**\n * List view backed by tools\n */\nexport interface ToolSettingsListView {\n /** View kind */\n kind: 'list'\n /** Tool ID for listing items */\n listToolId: string\n /** Tool ID for fetching details (optional) */\n getToolId?: string\n /** Tool ID for creating/updating items (optional) */\n upsertToolId?: string\n /** Tool ID for deleting items (optional) */\n deleteToolId?: string\n /** Mapping from tool data to UI fields */\n mapping: ToolSettingsListMapping\n /** Param name for search query (default: \"query\") */\n searchParam?: string\n /** Param name for limit (default: \"limit\") */\n limitParam?: string\n /** Param name for get/delete ID (default: \"id\") */\n idParam?: string\n /** Static params always sent to list tool */\n listParams?: Record<string, unknown>\n}\n\n/**\n * Mapping from tool list data to UI fields\n */\nexport interface ToolSettingsListMapping {\n /** Key for items array in tool result data */\n itemsKey: string\n /** Key for total count in tool result data */\n countKey?: string\n /** Key for item ID */\n idKey: string\n /** Key for item label */\n labelKey: string\n /** Key for item description */\n descriptionKey?: string\n /** Key for secondary label */\n secondaryKey?: string\n}\n\n/**\n * Component-based tool settings view using the declarative DSL.\n * Reuses the same structure as PanelComponentView for consistency.\n */\nexport interface ToolSettingsComponentView {\n /** View kind */\n kind: 'component'\n /** Data sources. Keys become scope variables (e.g., \"$settings\"). */\n data?: Record<string, ToolSettingsActionDataSource>\n /** Root component to render */\n content: import('./types.components.js').ExtensionComponentData\n}\n\n/**\n * Action-based data source for tool settings.\n */\nexport interface ToolSettingsActionDataSource {\n /** Action ID to call for fetching data */\n action: string\n /** Parameters to pass to the action */\n params?: Record<string, unknown>\n /** Event names that trigger refresh */\n refreshOn?: string[]\n}\n\n/**\n * Panel definition for right panel views\n */\nexport interface PanelDefinition {\n /** Unique panel ID within the extension */\n id: string\n /** Display title */\n title: string\n /** Icon name (from huge-icons) */\n icon?: string\n /** Panel view schema */\n view: PanelView\n}\n\n/**\n * Panel view schema (declarative)\n */\nexport type PanelView = PanelComponentView | PanelUnknownView\n\nexport interface PanelUnknownView {\n /** View kind */\n kind: string\n /** Additional view configuration */\n [key: string]: unknown\n}\n\n/**\n * Action-based data source for declarative panels.\n * Uses actions (not tools) to fetch data.\n */\nexport interface PanelActionDataSource {\n /** Action ID to call for fetching data */\n action: string\n /** Parameters to pass to the action */\n params?: Record<string, unknown>\n /** Event names that should trigger a refresh of this data */\n refreshOn?: string[]\n}\n\n/**\n * Component-based panel view using the declarative DSL.\n * Data is fetched via actions, content is rendered via ExtensionComponent.\n */\nexport interface PanelComponentView {\n kind: 'component'\n /** Data sources available in the panel. Keys become variable names (e.g., \"$projects\"). */\n data?: Record<string, PanelActionDataSource>\n /** Root component to render */\n content: import('./types.components.js').ExtensionComponentData\n}\n\n/**\n * Provider definition (metadata only, implementation in code)\n */\nexport interface ProviderDefinition {\n /** Provider ID */\n id: string\n /** Display name */\n name: string\n /** Description */\n description?: string\n /** Suggested default model when creating a new model configuration */\n suggestedDefaultModel?: string\n /** Default settings for this provider (e.g., { url: \"http://localhost:11434\" }) */\n defaultSettings?: Record<string, unknown>\n /** Schema for provider-specific configuration UI */\n configSchema?: ProviderConfigSchema\n}\n\n// ============================================================================\n// Prompt Contributions\n// ============================================================================\n\nexport type PromptSection = 'system' | 'behavior' | 'tools'\n\nexport interface PromptContribution {\n /** Unique ID within the extension */\n id: string\n /** Optional title for the prompt chunk */\n title?: string\n /** Prompt section placement */\n section?: PromptSection\n /** Plain text prompt content */\n text?: string\n /** Optional localized prompt content (keyed by locale, e.g. \"en\", \"sv\") */\n i18n?: Record<string, string>\n /** Optional ordering hint (lower comes first) */\n order?: number\n}\n\n// ============================================================================\n// Provider Configuration Schema\n// ============================================================================\n\n/**\n * Schema for provider-specific configuration.\n * Used to generate UI forms for configuring provider settings.\n */\nexport interface ProviderConfigSchema {\n /** Property definitions */\n properties: Record<string, ProviderConfigProperty>\n /** Display order of properties in UI (optional, defaults to object key order) */\n order?: string[]\n}\n\n/**\n * Property types for provider configuration\n */\nexport type ProviderConfigPropertyType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'select'\n | 'password'\n | 'url'\n\n/**\n * Single property in a provider configuration schema.\n * Defines how a setting should be rendered and validated in the UI.\n */\nexport interface ProviderConfigProperty {\n /** Property type - determines UI control */\n type: ProviderConfigPropertyType\n /** Display label */\n title: string\n /** Help text shown below the input */\n description?: string\n /** Default value */\n default?: unknown\n /** Whether the field is required */\n required?: boolean\n /** Placeholder text for input fields */\n placeholder?: string\n /** For 'select' type: static options */\n options?: ProviderConfigSelectOption[]\n /** Validation rules */\n validation?: ProviderConfigValidation\n}\n\n/**\n * Option for select-type properties\n */\nexport interface ProviderConfigSelectOption {\n /** Value stored in settings */\n value: string\n /** Display label */\n label: string\n}\n\n/**\n * Validation rules for a property\n */\nexport interface ProviderConfigValidation {\n /** Regex pattern the value must match */\n pattern?: string\n /** Minimum string length */\n minLength?: number\n /** Maximum string length */\n maxLength?: number\n /** Minimum number value */\n min?: number\n /** Maximum number value */\n max?: number\n}\n\n/**\n * Tool definition (metadata only, implementation in code)\n */\nexport interface ToolDefinition {\n /** Tool ID */\n id: string\n /**\n * Display name - can be a simple string or localized strings.\n * @example \"Get Weather\"\n * @example { en: \"Get Weather\", sv: \"Hämta väder\" }\n */\n name: LocalizedString\n /**\n * Description for Stina - can be a simple string or localized strings.\n * Note: The AI always receives the English description (or fallback) for consistency.\n * Localized descriptions are used for UI display only.\n * @example \"Fetches current weather for a location\"\n * @example { en: \"Fetches current weather\", sv: \"Hämtar aktuellt väder\" }\n */\n description: LocalizedString\n /** Parameter schema (JSON Schema) */\n parameters?: Record<string, unknown>\n}\n\n/**\n * Command definition\n */\nexport interface CommandDefinition {\n /** Command ID (e.g., \"weather\" for /weather) */\n id: string\n /** Display name */\n name: string\n /** Description */\n description: string\n}\n\n// ============================================================================\n// Permissions\n// ============================================================================\n\nexport type Permission =\n | NetworkPermission\n | StoragePermission\n | UserDataPermission\n | CapabilityPermission\n | SystemPermission\n\n/** Network access permissions */\nexport type NetworkPermission =\n | 'network:*'\n | `network:localhost`\n | `network:localhost:${number}`\n | `network:${string}`\n\n/** Storage permissions */\nexport type StoragePermission = 'database.own' | 'storage.local'\n\n/** User data permissions */\nexport type UserDataPermission =\n | 'user.profile.read'\n | 'user.location.read'\n | 'chat.history.read'\n | 'chat.current.read'\n\n/** Capability permissions */\nexport type CapabilityPermission =\n | 'provider.register'\n | 'tools.register'\n | 'actions.register'\n | 'settings.register'\n | 'commands.register'\n | 'panels.register'\n | 'events.emit'\n | 'scheduler.register'\n | 'chat.message.write'\n\n/** System permissions */\nexport type SystemPermission =\n | 'files.read'\n | 'files.write'\n | 'clipboard.read'\n | 'clipboard.write'\n\n// ============================================================================\n// Extension Context (API available to extensions)\n// ============================================================================\n\n/**\n * Disposable resource that can be cleaned up\n */\nexport interface Disposable {\n dispose(): void\n}\n\n/**\n * Context provided to extension's activate function.\n *\n * ## User ID Context\n *\n * The `userId` field provides the current user context for extensions. It is set when:\n * - A tool is executed by a user\n * - An action is executed by a user\n * - A scheduled job fires (if the job was created with a userId)\n *\n * For extension activation, `userId` is undefined since activation happens at system level.\n * Extensions should check for `userId` in their tool/action handlers to access user-specific data.\n *\n * @example\n * ```typescript\n * // In a tool execute handler:\n * execute: async (params, context) => {\n * if (context.userId) {\n * // User-specific logic\n * const userData = await storage.getForUser(context.userId, 'preferences')\n * }\n * }\n * ```\n */\nexport interface ExtensionContext {\n /** Extension metadata */\n readonly extension: {\n readonly id: string\n readonly version: string\n readonly storagePath: string\n }\n\n /**\n * Current user ID if in a user context, undefined for global/system operations.\n * Set when tools or actions are executed by a user, or when a user-scoped job fires.\n */\n readonly userId?: string\n\n /** Network access (if permitted) */\n readonly network?: NetworkAPI\n\n /** Settings access (if permitted) */\n readonly settings?: SettingsAPI\n\n /** Provider registration (if permitted) */\n readonly providers?: ProvidersAPI\n\n /** Tool registration (if permitted) */\n readonly tools?: ToolsAPI\n\n /** Action registration (if permitted) */\n readonly actions?: ActionsAPI\n\n /** Event emission (if permitted) */\n readonly events?: EventsAPI\n\n /** Scheduler access (if permitted) */\n readonly scheduler?: SchedulerAPI\n\n /** User data access (if permitted) */\n readonly user?: UserAPI\n\n /** Chat access (if permitted) */\n readonly chat?: ChatAPI\n\n /** Database access (if permitted) */\n readonly database?: DatabaseAPI\n\n /** Local storage (if permitted) */\n readonly storage?: StorageAPI\n\n /** Logging (always available) */\n readonly log: LogAPI\n}\n\n/**\n * Network API for making HTTP requests\n */\nexport interface NetworkAPI {\n /**\n * Fetch a URL (permissions are enforced by host)\n */\n fetch(url: string, options?: RequestInit): Promise<Response>\n\n /**\n * Streaming fetch for responses like NDJSON or SSE.\n * Yields text chunks as they arrive from the server.\n *\n * @throws {Error} If the request fails or encounters a network error.\n * The error message will contain details about the failure.\n *\n * @example\n * ```typescript\n * try {\n * for await (const chunk of context.network.fetchStream(url, options)) {\n * // Process each chunk (may contain partial lines)\n * buffer += chunk\n * }\n * } catch (error) {\n * console.error('Streaming fetch failed:', error.message)\n * }\n * ```\n */\n fetchStream(url: string, options?: RequestInit): AsyncGenerator<string, void, unknown>\n}\n\n/**\n * Settings API for reading/writing extension settings\n */\nexport interface SettingsAPI {\n /**\n * Get all settings for this extension\n */\n getAll<T extends Record<string, unknown>>(): Promise<T>\n\n /**\n * Get a specific setting value\n */\n get<T>(key: string): Promise<T | undefined>\n\n /**\n * Set a setting value\n */\n set(key: string, value: unknown): Promise<void>\n\n /**\n * Listen for setting changes\n */\n onChange(callback: (key: string, value: unknown) => void): Disposable\n}\n\n/**\n * Providers API for registering AI providers\n */\nexport interface ProvidersAPI {\n /**\n * Register an AI provider\n */\n register(provider: AIProvider): Disposable\n}\n\n/**\n * Tools API for registering tools\n */\nexport interface ToolsAPI {\n /**\n * Register a tool that Stina can use\n */\n register(tool: Tool): Disposable\n}\n\n/**\n * Actions API for registering UI actions\n */\nexport interface ActionsAPI {\n /**\n * Register an action that UI components can invoke\n */\n register(action: Action): Disposable\n}\n\n/**\n * Events API for notifying the host\n */\nexport interface EventsAPI {\n /**\n * Emit a named event with optional payload\n */\n emit(name: string, payload?: Record<string, unknown>): Promise<void>\n}\n\n/**\n * Scheduler schedule types\n */\nexport type SchedulerSchedule =\n | { type: 'at'; at: string }\n | { type: 'cron'; cron: string; timezone?: string }\n | { type: 'interval'; everyMs: number }\n\n/**\n * Scheduler job request\n */\nexport interface SchedulerJobRequest {\n id: string\n schedule: SchedulerSchedule\n payload?: Record<string, unknown>\n misfire?: 'run_once' | 'skip'\n /**\n * Optional user ID for user-scoped jobs.\n * If set, the job is associated with a specific user and the userId\n * will be passed to the extension when the job fires.\n */\n userId?: string\n}\n\n/**\n * Scheduler fire payload\n */\nexport interface SchedulerFirePayload {\n id: string\n payload?: Record<string, unknown>\n scheduledFor: string\n firedAt: string\n delayMs: number\n /** User ID if this is a user-scoped job, undefined if global */\n userId?: string\n}\n\n/**\n * Scheduler API for registering jobs\n */\nexport interface SchedulerAPI {\n schedule(job: SchedulerJobRequest): Promise<void>\n cancel(jobId: string): Promise<void>\n onFire(callback: (payload: SchedulerFirePayload) => void): Disposable\n}\n\n/**\n * User profile data\n */\nexport interface UserProfile {\n firstName?: string\n nickname?: string\n language?: string\n timezone?: string\n}\n\n/**\n * User API for profile access\n */\nexport interface UserAPI {\n getProfile(): Promise<UserProfile>\n}\n\n/**\n * Chat instruction message\n */\nexport interface ChatInstructionMessage {\n text: string\n conversationId?: string\n}\n\n/**\n * Chat API for appending instructions\n */\nexport interface ChatAPI {\n appendInstruction(message: ChatInstructionMessage): Promise<void>\n}\n\n/**\n * Database API for extension-specific tables\n */\nexport interface DatabaseAPI {\n /**\n * Execute a SQL query (only extension's prefixed tables allowed)\n */\n execute<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>\n}\n\n/**\n * Simple key-value storage API with support for user-scoped storage.\n *\n * ## Global vs User-Scoped Storage\n *\n * Extensions have access to two types of storage:\n * - **Global storage**: Shared across all users, accessed via `get()`, `set()`, etc.\n * - **User-scoped storage**: Isolated per user, accessed via `getForUser()`, `setForUser()`, etc.\n *\n * Use global storage for extension-wide settings and user-scoped storage for\n * user preferences, session data, or any data that should be private to a user.\n *\n * @example\n * ```typescript\n * // Global storage (extension-wide)\n * await storage.set('apiEndpoint', 'https://api.example.com')\n * const endpoint = await storage.get<string>('apiEndpoint')\n *\n * // User-scoped storage (per-user)\n * if (context.userId) {\n * await storage.setForUser(context.userId, 'preferences', { theme: 'dark' })\n * const prefs = await storage.getForUser<Preferences>(context.userId, 'preferences')\n * }\n * ```\n */\nexport interface StorageAPI {\n /**\n * Get a value by key (global/extension-scoped)\n */\n get<T>(key: string): Promise<T | undefined>\n\n /**\n * Set a value (global/extension-scoped)\n */\n set(key: string, value: unknown): Promise<void>\n\n /**\n * Delete a key (global/extension-scoped)\n */\n delete(key: string): Promise<void>\n\n /**\n * Get all keys (global/extension-scoped)\n */\n keys(): Promise<string[]>\n\n /**\n * Get a value by key for a specific user (user-scoped)\n * @param userId The user ID\n * @param key The storage key\n */\n getForUser<T>(userId: string, key: string): Promise<T | undefined>\n\n /**\n * Set a value for a specific user (user-scoped)\n * @param userId The user ID\n * @param key The storage key\n * @param value The value to store\n */\n setForUser(userId: string, key: string, value: unknown): Promise<void>\n\n /**\n * Delete a key for a specific user (user-scoped)\n * @param userId The user ID\n * @param key The storage key\n */\n deleteForUser(userId: string, key: string): Promise<void>\n\n /**\n * Get all keys for a specific user (user-scoped)\n * @param userId The user ID\n */\n keysForUser(userId: string): Promise<string[]>\n}\n\n/**\n * Logging API\n */\nexport interface LogAPI {\n debug(message: string, data?: Record<string, unknown>): void\n info(message: string, data?: Record<string, unknown>): void\n warn(message: string, data?: Record<string, unknown>): void\n error(message: string, data?: Record<string, unknown>): void\n}\n\n// ============================================================================\n// AI Provider Types\n// ============================================================================\n\n/**\n * AI provider implementation\n */\nexport interface AIProvider {\n /** Provider ID (must match manifest) */\n id: string\n /** Display name */\n name: string\n\n /**\n * Get available models from this provider\n * @param options Optional settings for the provider (e.g., URL)\n */\n getModels(options?: GetModelsOptions): Promise<ModelInfo[]>\n\n /**\n * Chat completion with streaming\n */\n chat(\n messages: ChatMessage[],\n options: ChatOptions\n ): AsyncGenerator<StreamEvent, void, unknown>\n\n /**\n * Optional: Generate embeddings\n */\n embed?(texts: string[]): Promise<number[][]>\n}\n\n/**\n * Model information\n */\nexport interface ModelInfo {\n /** Model ID */\n id: string\n /** Display name */\n name: string\n /** Description */\n description?: string\n /** Context window size */\n contextLength?: number\n}\n\n/**\n * Chat message\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system' | 'tool'\n content: string\n /** For assistant messages: tool calls made by the model */\n tool_calls?: ToolCall[]\n /** For tool messages: the ID of the tool call this is a response to */\n tool_call_id?: string\n}\n\n/**\n * A tool call made by the model\n */\nexport interface ToolCall {\n /** Unique ID for this tool call */\n id: string\n /** Tool name/ID to invoke */\n name: string\n /** Arguments for the tool (as parsed object) */\n arguments: Record<string, unknown>\n}\n\n/**\n * Options for chat completion\n */\nexport interface ChatOptions {\n /** Model to use */\n model?: string\n /** Temperature (0-1) */\n temperature?: number\n /** Maximum tokens to generate */\n maxTokens?: number\n /** Abort signal for cancellation */\n signal?: AbortSignal\n /** Provider-specific settings from model configuration */\n settings?: Record<string, unknown>\n /** Available tools for this request */\n tools?: ToolDefinition[]\n}\n\n/**\n * Options for getModels\n */\nexport interface GetModelsOptions {\n /** Provider-specific settings (e.g., URL for Ollama) */\n settings?: Record<string, unknown>\n}\n\n/**\n * Streaming events from chat\n */\nexport type StreamEvent =\n | { type: 'content'; text: string }\n | { type: 'thinking'; text: string }\n | { type: 'tool_start'; name: string; input: unknown; toolCallId: string }\n | { type: 'tool_end'; name: string; output: unknown; toolCallId: string }\n | { type: 'done'; usage?: { inputTokens: number; outputTokens: number } }\n | { type: 'error'; message: string }\n\n// ============================================================================\n// Tool Types\n// ============================================================================\n\n/**\n * Tool implementation\n */\nexport interface Tool {\n /** Tool ID (must match manifest) */\n id: string\n /** Display name */\n name: string\n /** Description for Stina */\n description: string\n /** Parameter schema (JSON Schema) */\n parameters?: Record<string, unknown>\n\n /**\n * Execute the tool\n */\n execute(params: Record<string, unknown>): Promise<ToolResult>\n}\n\n/**\n * Tool execution result\n */\nexport interface ToolResult {\n /** Whether the tool succeeded */\n success: boolean\n /** Result data (for Stina to use) */\n data?: unknown\n /** Human-readable message */\n message?: string\n /** Error message if failed */\n error?: string\n}\n\n// ============================================================================\n// Action Types (for UI interactions, separate from Tools)\n// ============================================================================\n\n/**\n * Action implementation for UI interactions.\n * Actions are invoked by UI components, not by Stina (AI).\n */\nexport interface Action {\n /** Action ID (unique within the extension) */\n id: string\n\n /**\n * Execute the action\n * @param params Parameters from the UI component (with $-values already resolved)\n */\n execute(params: Record<string, unknown>): Promise<ActionResult>\n}\n\n/**\n * Action execution result\n */\nexport interface ActionResult {\n /** Whether the action succeeded */\n success: boolean\n /** Result data (returned to UI) */\n data?: unknown\n /** Error message if failed */\n error?: string\n}\n\n// ============================================================================\n// Extension Entry Point\n// ============================================================================\n\n/**\n * Extension entry point interface\n */\nexport interface ExtensionModule {\n /**\n * Called when extension is activated\n */\n activate(context: ExtensionContext): void | Disposable | Promise<void | Disposable>\n\n /**\n * Called when extension is deactivated\n */\n deactivate?(): void | Promise<void>\n}\n","/**\n * Message protocol between Extension Host and Extension Workers\n */\n\nimport type {\n ChatMessage,\n ChatOptions,\n GetModelsOptions,\n StreamEvent,\n ToolResult,\n ActionResult,\n ModelInfo,\n SchedulerFirePayload,\n} from './types.js'\n\n// ============================================================================\n// Host → Worker Messages\n// ============================================================================\n\nexport type HostToWorkerMessage =\n | ActivateMessage\n | DeactivateMessage\n | SettingsChangedMessage\n | SchedulerFireMessage\n | ProviderChatRequestMessage\n | ProviderModelsRequestMessage\n | ToolExecuteRequestMessage\n | ActionExecuteRequestMessage\n | ResponseMessage\n | StreamingFetchChunkMessage\n\nexport interface ActivateMessage {\n type: 'activate'\n id: string\n payload: {\n extensionId: string\n extensionVersion: string\n storagePath: string\n permissions: string[]\n settings: Record<string, unknown>\n }\n}\n\nexport interface DeactivateMessage {\n type: 'deactivate'\n id: string\n}\n\nexport interface SettingsChangedMessage {\n type: 'settings-changed'\n id: string\n payload: {\n key: string\n value: unknown\n }\n}\n\nexport interface SchedulerFireMessage {\n type: 'scheduler-fire'\n id: string\n payload: SchedulerFirePayload\n}\n\nexport interface ProviderChatRequestMessage {\n type: 'provider-chat-request'\n id: string\n payload: {\n providerId: string\n messages: ChatMessage[]\n options: ChatOptions\n }\n}\n\nexport interface ProviderModelsRequestMessage {\n type: 'provider-models-request'\n id: string\n payload: {\n providerId: string\n options?: GetModelsOptions\n }\n}\n\nexport interface ToolExecuteRequestMessage {\n type: 'tool-execute-request'\n id: string\n payload: {\n toolId: string\n params: Record<string, unknown>\n /** User ID if the tool is executed in a user context */\n userId?: string\n }\n}\n\nexport interface ActionExecuteRequestMessage {\n type: 'action-execute-request'\n id: string\n payload: {\n actionId: string\n params: Record<string, unknown>\n /** User ID if the action is executed in a user context */\n userId?: string\n }\n}\n\nexport interface ResponseMessage {\n type: 'response'\n id: string\n payload: {\n requestId: string\n success: boolean\n data?: unknown\n error?: string\n }\n}\n\n/**\n * Message sent from host to worker with streaming fetch data chunks.\n * Used for streaming network responses (e.g., NDJSON streams from Ollama).\n */\nexport interface StreamingFetchChunkMessage {\n type: 'streaming-fetch-chunk'\n id: string\n payload: {\n requestId: string\n chunk: string\n done: boolean\n error?: string\n }\n}\n\n// ============================================================================\n// Worker → Host Messages\n// ============================================================================\n\nexport type WorkerToHostMessage =\n | ReadyMessage\n | RequestMessage\n | ProviderRegisteredMessage\n | ToolRegisteredMessage\n | ActionRegisteredMessage\n | StreamEventMessage\n | LogMessage\n | ProviderModelsResponseMessage\n | ToolExecuteResponseMessage\n | ActionExecuteResponseMessage\n | StreamingFetchAckMessage\n\nexport interface ReadyMessage {\n type: 'ready'\n}\n\n/**\n * Message sent from worker to host to acknowledge receipt of a streaming fetch chunk.\n * This enables backpressure control to prevent unbounded memory growth.\n */\nexport interface StreamingFetchAckMessage {\n type: 'streaming-fetch-ack'\n payload: {\n requestId: string\n }\n}\n\nexport interface RequestMessage {\n type: 'request'\n id: string\n method: RequestMethod\n payload: unknown\n}\n\nexport type RequestMethod =\n | 'network.fetch'\n | 'network.fetch-stream'\n | 'settings.getAll'\n | 'settings.get'\n | 'settings.set'\n | 'user.getProfile'\n | 'events.emit'\n | 'scheduler.schedule'\n | 'scheduler.cancel'\n | 'chat.appendInstruction'\n | 'database.execute'\n | 'storage.get'\n | 'storage.set'\n | 'storage.delete'\n | 'storage.keys'\n | 'storage.getForUser'\n | 'storage.setForUser'\n | 'storage.deleteForUser'\n | 'storage.keysForUser'\n\nexport interface ProviderRegisteredMessage {\n type: 'provider-registered'\n payload: {\n id: string\n name: string\n }\n}\n\nexport interface ToolRegisteredMessage {\n type: 'tool-registered'\n payload: {\n id: string\n name: string\n description: string\n parameters?: Record<string, unknown>\n }\n}\n\nexport interface ActionRegisteredMessage {\n type: 'action-registered'\n payload: {\n id: string\n }\n}\n\nexport interface StreamEventMessage {\n type: 'stream-event'\n payload: {\n requestId: string\n event: StreamEvent\n }\n}\n\nexport interface ProviderModelsResponseMessage {\n type: 'provider-models-response'\n payload: {\n requestId: string\n models: ModelInfo[]\n error?: string\n }\n}\n\nexport interface ToolExecuteResponseMessage {\n type: 'tool-execute-response'\n payload: {\n requestId: string\n result: ToolResult\n error?: string\n }\n}\n\nexport interface ActionExecuteResponseMessage {\n type: 'action-execute-response'\n payload: {\n requestId: string\n result: ActionResult\n error?: string\n }\n}\n\nexport interface LogMessage {\n type: 'log'\n payload: {\n level: 'debug' | 'info' | 'warn' | 'error'\n message: string\n data?: Record<string, unknown>\n }\n}\n\n// ============================================================================\n// Utility Types\n// ============================================================================\n\nexport interface PendingRequest<T = unknown> {\n resolve: (value: T) => void\n reject: (error: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n\n/**\n * Generate a unique message ID\n */\nexport function generateMessageId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBO,SAAS,uBACd,OACA,MACA,eAAe,MACP;AACR,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,IAAI,KAAK,MAAM,YAAY,KAAK,OAAO,OAAO,KAAK,EAAE,CAAC,KAAK;AAC1E;;;ACgPO,SAAS,oBAA4B;AAC1C,SAAO,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACjE;","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SchedulerFirePayload, C as ChatMessage, a as ChatOptions, G as GetModelsOptions, b as StreamEvent, M as ModelInfo, T as ToolResult, A as ActionResult } from './types-DjRF9BP3.cjs';
2
- export { a3 as AIProvider, a6 as Action, Q as ActionsAPI, a8 as AllowedCSSProperty, ak as ButtonProps, D as CapabilityPermission, _ as ChatAPI, $ as ChatInstructionMessage, aB as CheckboxProps, ay as CollapsibleProps, t as CommandDefinition, a0 as DatabaseAPI, am as DateTimeInputProps, I as Disposable, ar as DividerProps, R as EventsAPI, ad as ExtensionActionCall, ae as ExtensionActionRef, ac as ExtensionComponentChildren, aa as ExtensionComponentData, ab as ExtensionComponentIterator, a9 as ExtensionComponentStyle, H as ExtensionContext, c as ExtensionContributions, af as ExtensionDataSource, E as ExtensionManifest, a7 as ExtensionModule, ag as ExtensionPanelDefinition, aq as GridProps, ah as HeaderProps, ap as HorizontalStackProps, au as IconButtonProps, at as IconButtonType, as as IconProps, ai as LabelProps, a2 as LogAPI, aC as MarkdownProps, aD as ModalProps, J as NetworkAPI, N as NetworkPermission, av as PanelAction, n as PanelActionDataSource, m as PanelComponentView, k as PanelDefinition, aw as PanelProps, o as PanelUnknownView, l as PanelView, aj as ParagraphProps, z as Permission, aA as PillProps, az as PillVariant, P as Platform, q as PromptContribution, r as PromptSection, v as ProviderConfigProperty, w as ProviderConfigPropertyType, u as ProviderConfigSchema, x as ProviderConfigSelectOption, y as ProviderConfigValidation, p as ProviderDefinition, L as ProvidersAPI, V as SchedulerAPI, W as SchedulerJobRequest, X as SchedulerSchedule, an as SelectProps, f as SettingCreateMapping, d as SettingDefinition, e as SettingOptionsMapping, K as SettingsAPI, a1 as StorageAPI, B as StoragePermission, F as SystemPermission, al as TextInputProps, ax as ToggleProps, a5 as Tool, a4 as ToolCall, s as ToolDefinition, j as ToolSettingsListMapping, i as ToolSettingsListView, h as ToolSettingsView, g as ToolSettingsViewDefinition, O as ToolsAPI, Y as UserAPI, U as UserDataPermission, Z as UserProfile, ao as VerticalStackProps } from './types-DjRF9BP3.cjs';
1
+ import { S as SchedulerFirePayload, C as ChatMessage, a as ChatOptions, G as GetModelsOptions, b as StreamEvent, M as ModelInfo, T as ToolResult, A as ActionResult } from './types-kRt2DzdL.cjs';
2
+ export { a7 as AIProvider, aa as Action, X as ActionsAPI, ac as AllowedCSSProperty, ao as ButtonProps, I as CapabilityPermission, a2 as ChatAPI, a3 as ChatInstructionMessage, aF as CheckboxProps, aC as CollapsibleProps, w as CommandDefinition, a4 as DatabaseAPI, aq as DateTimeInputProps, O as Disposable, av as DividerProps, Y as EventsAPI, ah as ExtensionActionCall, ai as ExtensionActionRef, ag as ExtensionComponentChildren, ae as ExtensionComponentData, af as ExtensionComponentIterator, ad as ExtensionComponentStyle, K as ExtensionContext, c as ExtensionContributions, aj as ExtensionDataSource, E as ExtensionManifest, ab as ExtensionModule, ak as ExtensionPanelDefinition, au as GridProps, al as HeaderProps, at as HorizontalStackProps, ay as IconButtonProps, ax as IconButtonType, aw as IconProps, am as LabelProps, L as LocalizedString, a6 as LogAPI, aG as MarkdownProps, aH as ModalProps, Q as NetworkAPI, N as NetworkPermission, az as PanelAction, p as PanelActionDataSource, o as PanelComponentView, m as PanelDefinition, aA as PanelProps, q as PanelUnknownView, n as PanelView, an as ParagraphProps, F as Permission, aE as PillProps, aD as PillVariant, P as Platform, t as PromptContribution, u as PromptSection, y as ProviderConfigProperty, z as ProviderConfigPropertyType, x as ProviderConfigSchema, B as ProviderConfigSelectOption, D as ProviderConfigValidation, s as ProviderDefinition, V as ProvidersAPI, Z as SchedulerAPI, _ as SchedulerJobRequest, $ as SchedulerSchedule, ar as SelectProps, f as SettingCreateMapping, d as SettingDefinition, e as SettingOptionsMapping, R as SettingsAPI, a5 as StorageAPI, H as StoragePermission, J as SystemPermission, ap as TextInputProps, aB as ToggleProps, a9 as Tool, a8 as ToolCall, v as ToolDefinition, l as ToolSettingsActionDataSource, k as ToolSettingsComponentView, j as ToolSettingsListMapping, i as ToolSettingsListView, h as ToolSettingsView, g as ToolSettingsViewDefinition, W as ToolsAPI, a0 as UserAPI, U as UserDataPermission, a1 as UserProfile, as as VerticalStackProps, r as resolveLocalizedString } from './types-kRt2DzdL.cjs';
3
3
 
4
4
  /**
5
5
  * Message protocol between Extension Host and Extension Workers
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SchedulerFirePayload, C as ChatMessage, a as ChatOptions, G as GetModelsOptions, b as StreamEvent, M as ModelInfo, T as ToolResult, A as ActionResult } from './types-DjRF9BP3.js';
2
- export { a3 as AIProvider, a6 as Action, Q as ActionsAPI, a8 as AllowedCSSProperty, ak as ButtonProps, D as CapabilityPermission, _ as ChatAPI, $ as ChatInstructionMessage, aB as CheckboxProps, ay as CollapsibleProps, t as CommandDefinition, a0 as DatabaseAPI, am as DateTimeInputProps, I as Disposable, ar as DividerProps, R as EventsAPI, ad as ExtensionActionCall, ae as ExtensionActionRef, ac as ExtensionComponentChildren, aa as ExtensionComponentData, ab as ExtensionComponentIterator, a9 as ExtensionComponentStyle, H as ExtensionContext, c as ExtensionContributions, af as ExtensionDataSource, E as ExtensionManifest, a7 as ExtensionModule, ag as ExtensionPanelDefinition, aq as GridProps, ah as HeaderProps, ap as HorizontalStackProps, au as IconButtonProps, at as IconButtonType, as as IconProps, ai as LabelProps, a2 as LogAPI, aC as MarkdownProps, aD as ModalProps, J as NetworkAPI, N as NetworkPermission, av as PanelAction, n as PanelActionDataSource, m as PanelComponentView, k as PanelDefinition, aw as PanelProps, o as PanelUnknownView, l as PanelView, aj as ParagraphProps, z as Permission, aA as PillProps, az as PillVariant, P as Platform, q as PromptContribution, r as PromptSection, v as ProviderConfigProperty, w as ProviderConfigPropertyType, u as ProviderConfigSchema, x as ProviderConfigSelectOption, y as ProviderConfigValidation, p as ProviderDefinition, L as ProvidersAPI, V as SchedulerAPI, W as SchedulerJobRequest, X as SchedulerSchedule, an as SelectProps, f as SettingCreateMapping, d as SettingDefinition, e as SettingOptionsMapping, K as SettingsAPI, a1 as StorageAPI, B as StoragePermission, F as SystemPermission, al as TextInputProps, ax as ToggleProps, a5 as Tool, a4 as ToolCall, s as ToolDefinition, j as ToolSettingsListMapping, i as ToolSettingsListView, h as ToolSettingsView, g as ToolSettingsViewDefinition, O as ToolsAPI, Y as UserAPI, U as UserDataPermission, Z as UserProfile, ao as VerticalStackProps } from './types-DjRF9BP3.js';
1
+ import { S as SchedulerFirePayload, C as ChatMessage, a as ChatOptions, G as GetModelsOptions, b as StreamEvent, M as ModelInfo, T as ToolResult, A as ActionResult } from './types-kRt2DzdL.js';
2
+ export { a7 as AIProvider, aa as Action, X as ActionsAPI, ac as AllowedCSSProperty, ao as ButtonProps, I as CapabilityPermission, a2 as ChatAPI, a3 as ChatInstructionMessage, aF as CheckboxProps, aC as CollapsibleProps, w as CommandDefinition, a4 as DatabaseAPI, aq as DateTimeInputProps, O as Disposable, av as DividerProps, Y as EventsAPI, ah as ExtensionActionCall, ai as ExtensionActionRef, ag as ExtensionComponentChildren, ae as ExtensionComponentData, af as ExtensionComponentIterator, ad as ExtensionComponentStyle, K as ExtensionContext, c as ExtensionContributions, aj as ExtensionDataSource, E as ExtensionManifest, ab as ExtensionModule, ak as ExtensionPanelDefinition, au as GridProps, al as HeaderProps, at as HorizontalStackProps, ay as IconButtonProps, ax as IconButtonType, aw as IconProps, am as LabelProps, L as LocalizedString, a6 as LogAPI, aG as MarkdownProps, aH as ModalProps, Q as NetworkAPI, N as NetworkPermission, az as PanelAction, p as PanelActionDataSource, o as PanelComponentView, m as PanelDefinition, aA as PanelProps, q as PanelUnknownView, n as PanelView, an as ParagraphProps, F as Permission, aE as PillProps, aD as PillVariant, P as Platform, t as PromptContribution, u as PromptSection, y as ProviderConfigProperty, z as ProviderConfigPropertyType, x as ProviderConfigSchema, B as ProviderConfigSelectOption, D as ProviderConfigValidation, s as ProviderDefinition, V as ProvidersAPI, Z as SchedulerAPI, _ as SchedulerJobRequest, $ as SchedulerSchedule, ar as SelectProps, f as SettingCreateMapping, d as SettingDefinition, e as SettingOptionsMapping, R as SettingsAPI, a5 as StorageAPI, H as StoragePermission, J as SystemPermission, ap as TextInputProps, aB as ToggleProps, a9 as Tool, a8 as ToolCall, v as ToolDefinition, l as ToolSettingsActionDataSource, k as ToolSettingsComponentView, j as ToolSettingsListMapping, i as ToolSettingsListView, h as ToolSettingsView, g as ToolSettingsViewDefinition, W as ToolsAPI, a0 as UserAPI, U as UserDataPermission, a1 as UserProfile, as as VerticalStackProps, r as resolveLocalizedString } from './types-kRt2DzdL.js';
3
3
 
4
4
  /**
5
5
  * Message protocol between Extension Host and Extension Workers
package/dist/index.js CHANGED
@@ -1,7 +1,16 @@
1
1
  import {
2
2
  generateMessageId
3
3
  } from "./chunk-WIDGIYRV.js";
4
+
5
+ // src/types.ts
6
+ function resolveLocalizedString(value, lang, fallbackLang = "en") {
7
+ if (typeof value === "string") {
8
+ return value;
9
+ }
10
+ return value[lang] ?? value[fallbackLang] ?? Object.values(value)[0] ?? "";
11
+ }
4
12
  export {
5
- generateMessageId
13
+ generateMessageId,
14
+ resolveLocalizedString
6
15
  };
7
16
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * A string that can be either a simple string or a map of language codes to localized strings.\n * When a simple string is provided, it's used as the default/fallback value.\n * When a map is provided, the appropriate language is selected at runtime.\n *\n * @example\n * // Simple string (backwards compatible)\n * name: \"Get Weather\"\n *\n * @example\n * // Localized strings\n * name: { en: \"Get Weather\", sv: \"Hämta väder\", de: \"Wetter abrufen\" }\n */\nexport type LocalizedString = string | Record<string, string>\n\n/**\n * Resolves a LocalizedString to an actual string value.\n * @param value The LocalizedString to resolve\n * @param lang The preferred language code (e.g., \"sv\", \"en\")\n * @param fallbackLang The fallback language code (defaults to \"en\")\n * @returns The resolved string value\n */\nexport function resolveLocalizedString(\n value: LocalizedString,\n lang: string,\n fallbackLang = 'en'\n): string {\n if (typeof value === 'string') {\n return value\n }\n // Try preferred language first, then fallback language, then first available, then empty string\n return value[lang] ?? value[fallbackLang] ?? Object.values(value)[0] ?? ''\n}\n\n/**\n * Extension manifest format (manifest.json)\n */\nexport interface ExtensionManifest {\n /** Unique identifier (e.g., \"ollama-provider\") */\n id: string\n /** Human-readable name */\n name: string\n /** Version string (semver) */\n version: string\n /** Short description */\n description: string\n /** Author information */\n author: {\n name: string\n url?: string\n }\n /** Repository URL */\n repository?: string\n /** License identifier */\n license?: string\n /** Minimum Stina version required */\n engines?: {\n stina: string\n }\n /** Supported platforms */\n platforms?: Platform[]\n /** Entry point file (relative to extension root) */\n main: string\n /** Required permissions */\n permissions: Permission[]\n /** What the extension contributes */\n contributes?: ExtensionContributions\n}\n\nexport type Platform = 'web' | 'electron' | 'tui'\n\n/**\n * What an extension can contribute to Stina\n */\nexport interface ExtensionContributions {\n /** User-configurable settings */\n settings?: SettingDefinition[]\n /** Tool settings views for UI */\n toolSettings?: ToolSettingsViewDefinition[]\n /** Right panel contributions */\n panels?: PanelDefinition[]\n /** AI providers */\n providers?: ProviderDefinition[]\n /** Tools for Stina to use */\n tools?: ToolDefinition[]\n /** Slash commands */\n commands?: CommandDefinition[]\n /** Prompt contributions for the system prompt */\n prompts?: PromptContribution[]\n}\n\n/**\n * Setting definition for the UI\n */\nexport interface SettingDefinition {\n /** Setting ID (namespaced automatically) */\n id: string\n /** Display title */\n title: string\n /** Help text */\n description?: string\n /** Setting type */\n type: 'string' | 'number' | 'boolean' | 'select'\n /** Default value */\n default?: unknown\n /** For select type: available options */\n options?: { value: string; label: string }[]\n /** For select type: load options from tool */\n optionsToolId?: string\n /** Params for options tool */\n optionsParams?: Record<string, unknown>\n /** Mapping for options tool response */\n optionsMapping?: SettingOptionsMapping\n /** Tool ID for creating a new option */\n createToolId?: string\n /** Label for create action */\n createLabel?: string\n /** Fields for create form */\n createFields?: SettingDefinition[]\n /** Static params always sent to create tool */\n createParams?: Record<string, unknown>\n /** Mapping for create tool response */\n createMapping?: SettingCreateMapping\n /** Validation rules */\n validation?: {\n required?: boolean\n min?: number\n max?: number\n pattern?: string\n }\n}\n\n/**\n * Mapping for select field options from tool response\n */\nexport interface SettingOptionsMapping {\n /** Key for items array in tool result data */\n itemsKey: string\n /** Key for option value */\n valueKey: string\n /** Key for option label */\n labelKey: string\n /** Optional key for description */\n descriptionKey?: string\n}\n\n/**\n * Mapping for create tool response\n */\nexport interface SettingCreateMapping {\n /** Key for result data object */\n resultKey?: string\n /** Key for option value (defaults to \"id\") */\n valueKey: string\n}\n\n/**\n * Tool settings view definition (UI schema)\n */\nexport interface ToolSettingsViewDefinition {\n /** Unique view ID within the extension */\n id: string\n /** Display title */\n title: string\n /** Help text */\n description?: string\n /** View configuration */\n view: ToolSettingsView\n /** Fields for create/edit forms (uses SettingDefinition) */\n fields?: SettingDefinition[]\n}\n\n/**\n * Tool settings view types\n */\nexport type ToolSettingsView = ToolSettingsListView | ToolSettingsComponentView\n\n/**\n * List view backed by tools\n */\nexport interface ToolSettingsListView {\n /** View kind */\n kind: 'list'\n /** Tool ID for listing items */\n listToolId: string\n /** Tool ID for fetching details (optional) */\n getToolId?: string\n /** Tool ID for creating/updating items (optional) */\n upsertToolId?: string\n /** Tool ID for deleting items (optional) */\n deleteToolId?: string\n /** Mapping from tool data to UI fields */\n mapping: ToolSettingsListMapping\n /** Param name for search query (default: \"query\") */\n searchParam?: string\n /** Param name for limit (default: \"limit\") */\n limitParam?: string\n /** Param name for get/delete ID (default: \"id\") */\n idParam?: string\n /** Static params always sent to list tool */\n listParams?: Record<string, unknown>\n}\n\n/**\n * Mapping from tool list data to UI fields\n */\nexport interface ToolSettingsListMapping {\n /** Key for items array in tool result data */\n itemsKey: string\n /** Key for total count in tool result data */\n countKey?: string\n /** Key for item ID */\n idKey: string\n /** Key for item label */\n labelKey: string\n /** Key for item description */\n descriptionKey?: string\n /** Key for secondary label */\n secondaryKey?: string\n}\n\n/**\n * Component-based tool settings view using the declarative DSL.\n * Reuses the same structure as PanelComponentView for consistency.\n */\nexport interface ToolSettingsComponentView {\n /** View kind */\n kind: 'component'\n /** Data sources. Keys become scope variables (e.g., \"$settings\"). */\n data?: Record<string, ToolSettingsActionDataSource>\n /** Root component to render */\n content: import('./types.components.js').ExtensionComponentData\n}\n\n/**\n * Action-based data source for tool settings.\n */\nexport interface ToolSettingsActionDataSource {\n /** Action ID to call for fetching data */\n action: string\n /** Parameters to pass to the action */\n params?: Record<string, unknown>\n /** Event names that trigger refresh */\n refreshOn?: string[]\n}\n\n/**\n * Panel definition for right panel views\n */\nexport interface PanelDefinition {\n /** Unique panel ID within the extension */\n id: string\n /** Display title */\n title: string\n /** Icon name (from huge-icons) */\n icon?: string\n /** Panel view schema */\n view: PanelView\n}\n\n/**\n * Panel view schema (declarative)\n */\nexport type PanelView = PanelComponentView | PanelUnknownView\n\nexport interface PanelUnknownView {\n /** View kind */\n kind: string\n /** Additional view configuration */\n [key: string]: unknown\n}\n\n/**\n * Action-based data source for declarative panels.\n * Uses actions (not tools) to fetch data.\n */\nexport interface PanelActionDataSource {\n /** Action ID to call for fetching data */\n action: string\n /** Parameters to pass to the action */\n params?: Record<string, unknown>\n /** Event names that should trigger a refresh of this data */\n refreshOn?: string[]\n}\n\n/**\n * Component-based panel view using the declarative DSL.\n * Data is fetched via actions, content is rendered via ExtensionComponent.\n */\nexport interface PanelComponentView {\n kind: 'component'\n /** Data sources available in the panel. Keys become variable names (e.g., \"$projects\"). */\n data?: Record<string, PanelActionDataSource>\n /** Root component to render */\n content: import('./types.components.js').ExtensionComponentData\n}\n\n/**\n * Provider definition (metadata only, implementation in code)\n */\nexport interface ProviderDefinition {\n /** Provider ID */\n id: string\n /** Display name */\n name: string\n /** Description */\n description?: string\n /** Suggested default model when creating a new model configuration */\n suggestedDefaultModel?: string\n /** Default settings for this provider (e.g., { url: \"http://localhost:11434\" }) */\n defaultSettings?: Record<string, unknown>\n /** Schema for provider-specific configuration UI */\n configSchema?: ProviderConfigSchema\n}\n\n// ============================================================================\n// Prompt Contributions\n// ============================================================================\n\nexport type PromptSection = 'system' | 'behavior' | 'tools'\n\nexport interface PromptContribution {\n /** Unique ID within the extension */\n id: string\n /** Optional title for the prompt chunk */\n title?: string\n /** Prompt section placement */\n section?: PromptSection\n /** Plain text prompt content */\n text?: string\n /** Optional localized prompt content (keyed by locale, e.g. \"en\", \"sv\") */\n i18n?: Record<string, string>\n /** Optional ordering hint (lower comes first) */\n order?: number\n}\n\n// ============================================================================\n// Provider Configuration Schema\n// ============================================================================\n\n/**\n * Schema for provider-specific configuration.\n * Used to generate UI forms for configuring provider settings.\n */\nexport interface ProviderConfigSchema {\n /** Property definitions */\n properties: Record<string, ProviderConfigProperty>\n /** Display order of properties in UI (optional, defaults to object key order) */\n order?: string[]\n}\n\n/**\n * Property types for provider configuration\n */\nexport type ProviderConfigPropertyType =\n | 'string'\n | 'number'\n | 'boolean'\n | 'select'\n | 'password'\n | 'url'\n\n/**\n * Single property in a provider configuration schema.\n * Defines how a setting should be rendered and validated in the UI.\n */\nexport interface ProviderConfigProperty {\n /** Property type - determines UI control */\n type: ProviderConfigPropertyType\n /** Display label */\n title: string\n /** Help text shown below the input */\n description?: string\n /** Default value */\n default?: unknown\n /** Whether the field is required */\n required?: boolean\n /** Placeholder text for input fields */\n placeholder?: string\n /** For 'select' type: static options */\n options?: ProviderConfigSelectOption[]\n /** Validation rules */\n validation?: ProviderConfigValidation\n}\n\n/**\n * Option for select-type properties\n */\nexport interface ProviderConfigSelectOption {\n /** Value stored in settings */\n value: string\n /** Display label */\n label: string\n}\n\n/**\n * Validation rules for a property\n */\nexport interface ProviderConfigValidation {\n /** Regex pattern the value must match */\n pattern?: string\n /** Minimum string length */\n minLength?: number\n /** Maximum string length */\n maxLength?: number\n /** Minimum number value */\n min?: number\n /** Maximum number value */\n max?: number\n}\n\n/**\n * Tool definition (metadata only, implementation in code)\n */\nexport interface ToolDefinition {\n /** Tool ID */\n id: string\n /**\n * Display name - can be a simple string or localized strings.\n * @example \"Get Weather\"\n * @example { en: \"Get Weather\", sv: \"Hämta väder\" }\n */\n name: LocalizedString\n /**\n * Description for Stina - can be a simple string or localized strings.\n * Note: The AI always receives the English description (or fallback) for consistency.\n * Localized descriptions are used for UI display only.\n * @example \"Fetches current weather for a location\"\n * @example { en: \"Fetches current weather\", sv: \"Hämtar aktuellt väder\" }\n */\n description: LocalizedString\n /** Parameter schema (JSON Schema) */\n parameters?: Record<string, unknown>\n}\n\n/**\n * Command definition\n */\nexport interface CommandDefinition {\n /** Command ID (e.g., \"weather\" for /weather) */\n id: string\n /** Display name */\n name: string\n /** Description */\n description: string\n}\n\n// ============================================================================\n// Permissions\n// ============================================================================\n\nexport type Permission =\n | NetworkPermission\n | StoragePermission\n | UserDataPermission\n | CapabilityPermission\n | SystemPermission\n\n/** Network access permissions */\nexport type NetworkPermission =\n | 'network:*'\n | `network:localhost`\n | `network:localhost:${number}`\n | `network:${string}`\n\n/** Storage permissions */\nexport type StoragePermission = 'database.own' | 'storage.local'\n\n/** User data permissions */\nexport type UserDataPermission =\n | 'user.profile.read'\n | 'user.location.read'\n | 'chat.history.read'\n | 'chat.current.read'\n\n/** Capability permissions */\nexport type CapabilityPermission =\n | 'provider.register'\n | 'tools.register'\n | 'actions.register'\n | 'settings.register'\n | 'commands.register'\n | 'panels.register'\n | 'events.emit'\n | 'scheduler.register'\n | 'chat.message.write'\n\n/** System permissions */\nexport type SystemPermission =\n | 'files.read'\n | 'files.write'\n | 'clipboard.read'\n | 'clipboard.write'\n\n// ============================================================================\n// Extension Context (API available to extensions)\n// ============================================================================\n\n/**\n * Disposable resource that can be cleaned up\n */\nexport interface Disposable {\n dispose(): void\n}\n\n/**\n * Context provided to extension's activate function.\n *\n * ## User ID Context\n *\n * The `userId` field provides the current user context for extensions. It is set when:\n * - A tool is executed by a user\n * - An action is executed by a user\n * - A scheduled job fires (if the job was created with a userId)\n *\n * For extension activation, `userId` is undefined since activation happens at system level.\n * Extensions should check for `userId` in their tool/action handlers to access user-specific data.\n *\n * @example\n * ```typescript\n * // In a tool execute handler:\n * execute: async (params, context) => {\n * if (context.userId) {\n * // User-specific logic\n * const userData = await storage.getForUser(context.userId, 'preferences')\n * }\n * }\n * ```\n */\nexport interface ExtensionContext {\n /** Extension metadata */\n readonly extension: {\n readonly id: string\n readonly version: string\n readonly storagePath: string\n }\n\n /**\n * Current user ID if in a user context, undefined for global/system operations.\n * Set when tools or actions are executed by a user, or when a user-scoped job fires.\n */\n readonly userId?: string\n\n /** Network access (if permitted) */\n readonly network?: NetworkAPI\n\n /** Settings access (if permitted) */\n readonly settings?: SettingsAPI\n\n /** Provider registration (if permitted) */\n readonly providers?: ProvidersAPI\n\n /** Tool registration (if permitted) */\n readonly tools?: ToolsAPI\n\n /** Action registration (if permitted) */\n readonly actions?: ActionsAPI\n\n /** Event emission (if permitted) */\n readonly events?: EventsAPI\n\n /** Scheduler access (if permitted) */\n readonly scheduler?: SchedulerAPI\n\n /** User data access (if permitted) */\n readonly user?: UserAPI\n\n /** Chat access (if permitted) */\n readonly chat?: ChatAPI\n\n /** Database access (if permitted) */\n readonly database?: DatabaseAPI\n\n /** Local storage (if permitted) */\n readonly storage?: StorageAPI\n\n /** Logging (always available) */\n readonly log: LogAPI\n}\n\n/**\n * Network API for making HTTP requests\n */\nexport interface NetworkAPI {\n /**\n * Fetch a URL (permissions are enforced by host)\n */\n fetch(url: string, options?: RequestInit): Promise<Response>\n\n /**\n * Streaming fetch for responses like NDJSON or SSE.\n * Yields text chunks as they arrive from the server.\n *\n * @throws {Error} If the request fails or encounters a network error.\n * The error message will contain details about the failure.\n *\n * @example\n * ```typescript\n * try {\n * for await (const chunk of context.network.fetchStream(url, options)) {\n * // Process each chunk (may contain partial lines)\n * buffer += chunk\n * }\n * } catch (error) {\n * console.error('Streaming fetch failed:', error.message)\n * }\n * ```\n */\n fetchStream(url: string, options?: RequestInit): AsyncGenerator<string, void, unknown>\n}\n\n/**\n * Settings API for reading/writing extension settings\n */\nexport interface SettingsAPI {\n /**\n * Get all settings for this extension\n */\n getAll<T extends Record<string, unknown>>(): Promise<T>\n\n /**\n * Get a specific setting value\n */\n get<T>(key: string): Promise<T | undefined>\n\n /**\n * Set a setting value\n */\n set(key: string, value: unknown): Promise<void>\n\n /**\n * Listen for setting changes\n */\n onChange(callback: (key: string, value: unknown) => void): Disposable\n}\n\n/**\n * Providers API for registering AI providers\n */\nexport interface ProvidersAPI {\n /**\n * Register an AI provider\n */\n register(provider: AIProvider): Disposable\n}\n\n/**\n * Tools API for registering tools\n */\nexport interface ToolsAPI {\n /**\n * Register a tool that Stina can use\n */\n register(tool: Tool): Disposable\n}\n\n/**\n * Actions API for registering UI actions\n */\nexport interface ActionsAPI {\n /**\n * Register an action that UI components can invoke\n */\n register(action: Action): Disposable\n}\n\n/**\n * Events API for notifying the host\n */\nexport interface EventsAPI {\n /**\n * Emit a named event with optional payload\n */\n emit(name: string, payload?: Record<string, unknown>): Promise<void>\n}\n\n/**\n * Scheduler schedule types\n */\nexport type SchedulerSchedule =\n | { type: 'at'; at: string }\n | { type: 'cron'; cron: string; timezone?: string }\n | { type: 'interval'; everyMs: number }\n\n/**\n * Scheduler job request\n */\nexport interface SchedulerJobRequest {\n id: string\n schedule: SchedulerSchedule\n payload?: Record<string, unknown>\n misfire?: 'run_once' | 'skip'\n /**\n * Optional user ID for user-scoped jobs.\n * If set, the job is associated with a specific user and the userId\n * will be passed to the extension when the job fires.\n */\n userId?: string\n}\n\n/**\n * Scheduler fire payload\n */\nexport interface SchedulerFirePayload {\n id: string\n payload?: Record<string, unknown>\n scheduledFor: string\n firedAt: string\n delayMs: number\n /** User ID if this is a user-scoped job, undefined if global */\n userId?: string\n}\n\n/**\n * Scheduler API for registering jobs\n */\nexport interface SchedulerAPI {\n schedule(job: SchedulerJobRequest): Promise<void>\n cancel(jobId: string): Promise<void>\n onFire(callback: (payload: SchedulerFirePayload) => void): Disposable\n}\n\n/**\n * User profile data\n */\nexport interface UserProfile {\n firstName?: string\n nickname?: string\n language?: string\n timezone?: string\n}\n\n/**\n * User API for profile access\n */\nexport interface UserAPI {\n getProfile(): Promise<UserProfile>\n}\n\n/**\n * Chat instruction message\n */\nexport interface ChatInstructionMessage {\n text: string\n conversationId?: string\n}\n\n/**\n * Chat API for appending instructions\n */\nexport interface ChatAPI {\n appendInstruction(message: ChatInstructionMessage): Promise<void>\n}\n\n/**\n * Database API for extension-specific tables\n */\nexport interface DatabaseAPI {\n /**\n * Execute a SQL query (only extension's prefixed tables allowed)\n */\n execute<T = unknown>(sql: string, params?: unknown[]): Promise<T[]>\n}\n\n/**\n * Simple key-value storage API with support for user-scoped storage.\n *\n * ## Global vs User-Scoped Storage\n *\n * Extensions have access to two types of storage:\n * - **Global storage**: Shared across all users, accessed via `get()`, `set()`, etc.\n * - **User-scoped storage**: Isolated per user, accessed via `getForUser()`, `setForUser()`, etc.\n *\n * Use global storage for extension-wide settings and user-scoped storage for\n * user preferences, session data, or any data that should be private to a user.\n *\n * @example\n * ```typescript\n * // Global storage (extension-wide)\n * await storage.set('apiEndpoint', 'https://api.example.com')\n * const endpoint = await storage.get<string>('apiEndpoint')\n *\n * // User-scoped storage (per-user)\n * if (context.userId) {\n * await storage.setForUser(context.userId, 'preferences', { theme: 'dark' })\n * const prefs = await storage.getForUser<Preferences>(context.userId, 'preferences')\n * }\n * ```\n */\nexport interface StorageAPI {\n /**\n * Get a value by key (global/extension-scoped)\n */\n get<T>(key: string): Promise<T | undefined>\n\n /**\n * Set a value (global/extension-scoped)\n */\n set(key: string, value: unknown): Promise<void>\n\n /**\n * Delete a key (global/extension-scoped)\n */\n delete(key: string): Promise<void>\n\n /**\n * Get all keys (global/extension-scoped)\n */\n keys(): Promise<string[]>\n\n /**\n * Get a value by key for a specific user (user-scoped)\n * @param userId The user ID\n * @param key The storage key\n */\n getForUser<T>(userId: string, key: string): Promise<T | undefined>\n\n /**\n * Set a value for a specific user (user-scoped)\n * @param userId The user ID\n * @param key The storage key\n * @param value The value to store\n */\n setForUser(userId: string, key: string, value: unknown): Promise<void>\n\n /**\n * Delete a key for a specific user (user-scoped)\n * @param userId The user ID\n * @param key The storage key\n */\n deleteForUser(userId: string, key: string): Promise<void>\n\n /**\n * Get all keys for a specific user (user-scoped)\n * @param userId The user ID\n */\n keysForUser(userId: string): Promise<string[]>\n}\n\n/**\n * Logging API\n */\nexport interface LogAPI {\n debug(message: string, data?: Record<string, unknown>): void\n info(message: string, data?: Record<string, unknown>): void\n warn(message: string, data?: Record<string, unknown>): void\n error(message: string, data?: Record<string, unknown>): void\n}\n\n// ============================================================================\n// AI Provider Types\n// ============================================================================\n\n/**\n * AI provider implementation\n */\nexport interface AIProvider {\n /** Provider ID (must match manifest) */\n id: string\n /** Display name */\n name: string\n\n /**\n * Get available models from this provider\n * @param options Optional settings for the provider (e.g., URL)\n */\n getModels(options?: GetModelsOptions): Promise<ModelInfo[]>\n\n /**\n * Chat completion with streaming\n */\n chat(\n messages: ChatMessage[],\n options: ChatOptions\n ): AsyncGenerator<StreamEvent, void, unknown>\n\n /**\n * Optional: Generate embeddings\n */\n embed?(texts: string[]): Promise<number[][]>\n}\n\n/**\n * Model information\n */\nexport interface ModelInfo {\n /** Model ID */\n id: string\n /** Display name */\n name: string\n /** Description */\n description?: string\n /** Context window size */\n contextLength?: number\n}\n\n/**\n * Chat message\n */\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system' | 'tool'\n content: string\n /** For assistant messages: tool calls made by the model */\n tool_calls?: ToolCall[]\n /** For tool messages: the ID of the tool call this is a response to */\n tool_call_id?: string\n}\n\n/**\n * A tool call made by the model\n */\nexport interface ToolCall {\n /** Unique ID for this tool call */\n id: string\n /** Tool name/ID to invoke */\n name: string\n /** Arguments for the tool (as parsed object) */\n arguments: Record<string, unknown>\n}\n\n/**\n * Options for chat completion\n */\nexport interface ChatOptions {\n /** Model to use */\n model?: string\n /** Temperature (0-1) */\n temperature?: number\n /** Maximum tokens to generate */\n maxTokens?: number\n /** Abort signal for cancellation */\n signal?: AbortSignal\n /** Provider-specific settings from model configuration */\n settings?: Record<string, unknown>\n /** Available tools for this request */\n tools?: ToolDefinition[]\n}\n\n/**\n * Options for getModels\n */\nexport interface GetModelsOptions {\n /** Provider-specific settings (e.g., URL for Ollama) */\n settings?: Record<string, unknown>\n}\n\n/**\n * Streaming events from chat\n */\nexport type StreamEvent =\n | { type: 'content'; text: string }\n | { type: 'thinking'; text: string }\n | { type: 'tool_start'; name: string; input: unknown; toolCallId: string }\n | { type: 'tool_end'; name: string; output: unknown; toolCallId: string }\n | { type: 'done'; usage?: { inputTokens: number; outputTokens: number } }\n | { type: 'error'; message: string }\n\n// ============================================================================\n// Tool Types\n// ============================================================================\n\n/**\n * Tool implementation\n */\nexport interface Tool {\n /** Tool ID (must match manifest) */\n id: string\n /** Display name */\n name: string\n /** Description for Stina */\n description: string\n /** Parameter schema (JSON Schema) */\n parameters?: Record<string, unknown>\n\n /**\n * Execute the tool\n */\n execute(params: Record<string, unknown>): Promise<ToolResult>\n}\n\n/**\n * Tool execution result\n */\nexport interface ToolResult {\n /** Whether the tool succeeded */\n success: boolean\n /** Result data (for Stina to use) */\n data?: unknown\n /** Human-readable message */\n message?: string\n /** Error message if failed */\n error?: string\n}\n\n// ============================================================================\n// Action Types (for UI interactions, separate from Tools)\n// ============================================================================\n\n/**\n * Action implementation for UI interactions.\n * Actions are invoked by UI components, not by Stina (AI).\n */\nexport interface Action {\n /** Action ID (unique within the extension) */\n id: string\n\n /**\n * Execute the action\n * @param params Parameters from the UI component (with $-values already resolved)\n */\n execute(params: Record<string, unknown>): Promise<ActionResult>\n}\n\n/**\n * Action execution result\n */\nexport interface ActionResult {\n /** Whether the action succeeded */\n success: boolean\n /** Result data (returned to UI) */\n data?: unknown\n /** Error message if failed */\n error?: string\n}\n\n// ============================================================================\n// Extension Entry Point\n// ============================================================================\n\n/**\n * Extension entry point interface\n */\nexport interface ExtensionModule {\n /**\n * Called when extension is activated\n */\n activate(context: ExtensionContext): void | Disposable | Promise<void | Disposable>\n\n /**\n * Called when extension is deactivated\n */\n deactivate?(): void | Promise<void>\n}\n"],"mappings":";;;;;AAsBO,SAAS,uBACd,OACA,MACA,eAAe,MACP;AACR,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO;AAAA,EACT;AAEA,SAAO,MAAM,IAAI,KAAK,MAAM,YAAY,KAAK,OAAO,OAAO,KAAK,EAAE,CAAC,KAAK;AAC1E;","names":[]}
@@ -1,5 +1,5 @@
1
- import { a7 as ExtensionModule } from './types-DjRF9BP3.cjs';
2
- export { a3 as AIProvider, a6 as Action, A as ActionResult, C as ChatMessage, a as ChatOptions, I as Disposable, H as ExtensionContext, G as GetModelsOptions, M as ModelInfo, b as StreamEvent, a5 as Tool, a4 as ToolCall, s as ToolDefinition, T as ToolResult } from './types-DjRF9BP3.cjs';
1
+ import { ab as ExtensionModule } from './types-kRt2DzdL.cjs';
2
+ export { a7 as AIProvider, aa as Action, A as ActionResult, C as ChatMessage, a as ChatOptions, O as Disposable, K as ExtensionContext, G as GetModelsOptions, M as ModelInfo, b as StreamEvent, a9 as Tool, a8 as ToolCall, v as ToolDefinition, T as ToolResult } from './types-kRt2DzdL.cjs';
3
3
 
4
4
  /**
5
5
  * Extension Runtime - Runs inside the worker
package/dist/runtime.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { a7 as ExtensionModule } from './types-DjRF9BP3.js';
2
- export { a3 as AIProvider, a6 as Action, A as ActionResult, C as ChatMessage, a as ChatOptions, I as Disposable, H as ExtensionContext, G as GetModelsOptions, M as ModelInfo, b as StreamEvent, a5 as Tool, a4 as ToolCall, s as ToolDefinition, T as ToolResult } from './types-DjRF9BP3.js';
1
+ import { ab as ExtensionModule } from './types-kRt2DzdL.js';
2
+ export { a7 as AIProvider, aa as Action, A as ActionResult, C as ChatMessage, a as ChatOptions, O as Disposable, K as ExtensionContext, G as GetModelsOptions, M as ModelInfo, b as StreamEvent, a9 as Tool, a8 as ToolCall, v as ToolDefinition, T as ToolResult } from './types-kRt2DzdL.js';
3
3
 
4
4
  /**
5
5
  * Extension Runtime - Runs inside the worker
@@ -307,6 +307,28 @@ interface ModalProps extends ExtensionComponentData {
307
307
  onCloseAction?: ExtensionActionRef;
308
308
  }
309
309
 
310
+ /**
311
+ * A string that can be either a simple string or a map of language codes to localized strings.
312
+ * When a simple string is provided, it's used as the default/fallback value.
313
+ * When a map is provided, the appropriate language is selected at runtime.
314
+ *
315
+ * @example
316
+ * // Simple string (backwards compatible)
317
+ * name: "Get Weather"
318
+ *
319
+ * @example
320
+ * // Localized strings
321
+ * name: { en: "Get Weather", sv: "Hämta väder", de: "Wetter abrufen" }
322
+ */
323
+ type LocalizedString = string | Record<string, string>;
324
+ /**
325
+ * Resolves a LocalizedString to an actual string value.
326
+ * @param value The LocalizedString to resolve
327
+ * @param lang The preferred language code (e.g., "sv", "en")
328
+ * @param fallbackLang The fallback language code (defaults to "en")
329
+ * @returns The resolved string value
330
+ */
331
+ declare function resolveLocalizedString(value: LocalizedString, lang: string, fallbackLang?: string): string;
310
332
  /**
311
333
  * Extension manifest format (manifest.json)
312
334
  */
@@ -444,7 +466,7 @@ interface ToolSettingsViewDefinition {
444
466
  /**
445
467
  * Tool settings view types
446
468
  */
447
- type ToolSettingsView = ToolSettingsListView;
469
+ type ToolSettingsView = ToolSettingsListView | ToolSettingsComponentView;
448
470
  /**
449
471
  * List view backed by tools
450
472
  */
@@ -487,6 +509,29 @@ interface ToolSettingsListMapping {
487
509
  /** Key for secondary label */
488
510
  secondaryKey?: string;
489
511
  }
512
+ /**
513
+ * Component-based tool settings view using the declarative DSL.
514
+ * Reuses the same structure as PanelComponentView for consistency.
515
+ */
516
+ interface ToolSettingsComponentView {
517
+ /** View kind */
518
+ kind: 'component';
519
+ /** Data sources. Keys become scope variables (e.g., "$settings"). */
520
+ data?: Record<string, ToolSettingsActionDataSource>;
521
+ /** Root component to render */
522
+ content: ExtensionComponentData;
523
+ }
524
+ /**
525
+ * Action-based data source for tool settings.
526
+ */
527
+ interface ToolSettingsActionDataSource {
528
+ /** Action ID to call for fetching data */
529
+ action: string;
530
+ /** Parameters to pass to the action */
531
+ params?: Record<string, unknown>;
532
+ /** Event names that trigger refresh */
533
+ refreshOn?: string[];
534
+ }
490
535
  /**
491
536
  * Panel definition for right panel views
492
537
  */
@@ -631,10 +676,20 @@ interface ProviderConfigValidation {
631
676
  interface ToolDefinition {
632
677
  /** Tool ID */
633
678
  id: string;
634
- /** Display name */
635
- name: string;
636
- /** Description for Stina */
637
- description: string;
679
+ /**
680
+ * Display name - can be a simple string or localized strings.
681
+ * @example "Get Weather"
682
+ * @example { en: "Get Weather", sv: "Hämta väder" }
683
+ */
684
+ name: LocalizedString;
685
+ /**
686
+ * Description for Stina - can be a simple string or localized strings.
687
+ * Note: The AI always receives the English description (or fallback) for consistency.
688
+ * Localized descriptions are used for UI display only.
689
+ * @example "Fetches current weather for a location"
690
+ * @example { en: "Fetches current weather", sv: "Hämtar aktuellt väder" }
691
+ */
692
+ description: LocalizedString;
638
693
  /** Parameter schema (JSON Schema) */
639
694
  parameters?: Record<string, unknown>;
640
695
  }
@@ -1153,4 +1208,4 @@ interface ExtensionModule {
1153
1208
  deactivate?(): void | Promise<void>;
1154
1209
  }
1155
1210
 
1156
- export type { ChatInstructionMessage as $, ActionResult as A, StoragePermission as B, ChatMessage as C, CapabilityPermission as D, ExtensionManifest as E, SystemPermission as F, GetModelsOptions as G, ExtensionContext as H, Disposable as I, NetworkAPI as J, SettingsAPI as K, ProvidersAPI as L, ModelInfo as M, NetworkPermission as N, ToolsAPI as O, Platform as P, ActionsAPI as Q, EventsAPI as R, SchedulerFirePayload as S, ToolResult as T, UserDataPermission as U, SchedulerAPI as V, SchedulerJobRequest as W, SchedulerSchedule as X, UserAPI as Y, UserProfile as Z, ChatAPI as _, ChatOptions as a, DatabaseAPI as a0, StorageAPI as a1, LogAPI as a2, AIProvider as a3, ToolCall as a4, Tool as a5, Action as a6, ExtensionModule as a7, AllowedCSSProperty as a8, ExtensionComponentStyle as a9, PillProps as aA, CheckboxProps as aB, MarkdownProps as aC, ModalProps as aD, ExtensionComponentData as aa, ExtensionComponentIterator as ab, ExtensionComponentChildren as ac, ExtensionActionCall as ad, ExtensionActionRef as ae, ExtensionDataSource as af, ExtensionPanelDefinition as ag, HeaderProps as ah, LabelProps as ai, ParagraphProps as aj, ButtonProps as ak, TextInputProps as al, DateTimeInputProps as am, SelectProps as an, VerticalStackProps as ao, HorizontalStackProps as ap, GridProps as aq, DividerProps as ar, IconProps as as, IconButtonType as at, IconButtonProps as au, PanelAction as av, PanelProps as aw, ToggleProps as ax, CollapsibleProps as ay, PillVariant as az, StreamEvent as b, ExtensionContributions as c, SettingDefinition as d, SettingOptionsMapping as e, SettingCreateMapping as f, ToolSettingsViewDefinition as g, ToolSettingsView as h, ToolSettingsListView as i, ToolSettingsListMapping as j, PanelDefinition as k, PanelView as l, PanelComponentView as m, PanelActionDataSource as n, PanelUnknownView as o, ProviderDefinition as p, PromptContribution as q, PromptSection as r, ToolDefinition as s, CommandDefinition as t, ProviderConfigSchema as u, ProviderConfigProperty as v, ProviderConfigPropertyType as w, ProviderConfigSelectOption as x, ProviderConfigValidation as y, Permission as z };
1211
+ export { type SchedulerSchedule as $, type ActionResult as A, type ProviderConfigSelectOption as B, type ChatMessage as C, type ProviderConfigValidation as D, type ExtensionManifest as E, type Permission as F, type GetModelsOptions as G, type StoragePermission as H, type CapabilityPermission as I, type SystemPermission as J, type ExtensionContext as K, type LocalizedString as L, type ModelInfo as M, type NetworkPermission as N, type Disposable as O, type Platform as P, type NetworkAPI as Q, type SettingsAPI as R, type SchedulerFirePayload as S, type ToolResult as T, type UserDataPermission as U, type ProvidersAPI as V, type ToolsAPI as W, type ActionsAPI as X, type EventsAPI as Y, type SchedulerAPI as Z, type SchedulerJobRequest as _, type ChatOptions as a, type UserAPI as a0, type UserProfile as a1, type ChatAPI as a2, type ChatInstructionMessage as a3, type DatabaseAPI as a4, type StorageAPI as a5, type LogAPI as a6, type AIProvider as a7, type ToolCall as a8, type Tool as a9, type PanelProps as aA, type ToggleProps as aB, type CollapsibleProps as aC, type PillVariant as aD, type PillProps as aE, type CheckboxProps as aF, type MarkdownProps as aG, type ModalProps as aH, type Action as aa, type ExtensionModule as ab, type AllowedCSSProperty as ac, type ExtensionComponentStyle as ad, type ExtensionComponentData as ae, type ExtensionComponentIterator as af, type ExtensionComponentChildren as ag, type ExtensionActionCall as ah, type ExtensionActionRef as ai, type ExtensionDataSource as aj, type ExtensionPanelDefinition as ak, type HeaderProps as al, type LabelProps as am, type ParagraphProps as an, type ButtonProps as ao, type TextInputProps as ap, type DateTimeInputProps as aq, type SelectProps as ar, type VerticalStackProps as as, type HorizontalStackProps as at, type GridProps as au, type DividerProps as av, type IconProps as aw, type IconButtonType as ax, type IconButtonProps as ay, type PanelAction as az, type StreamEvent as b, type ExtensionContributions as c, type SettingDefinition as d, type SettingOptionsMapping as e, type SettingCreateMapping as f, type ToolSettingsViewDefinition as g, type ToolSettingsView as h, type ToolSettingsListView as i, type ToolSettingsListMapping as j, type ToolSettingsComponentView as k, type ToolSettingsActionDataSource as l, type PanelDefinition as m, type PanelView as n, type PanelComponentView as o, type PanelActionDataSource as p, type PanelUnknownView as q, resolveLocalizedString as r, type ProviderDefinition as s, type PromptContribution as t, type PromptSection as u, type ToolDefinition as v, type CommandDefinition as w, type ProviderConfigSchema as x, type ProviderConfigProperty as y, type ProviderConfigPropertyType as z };
@@ -307,6 +307,28 @@ interface ModalProps extends ExtensionComponentData {
307
307
  onCloseAction?: ExtensionActionRef;
308
308
  }
309
309
 
310
+ /**
311
+ * A string that can be either a simple string or a map of language codes to localized strings.
312
+ * When a simple string is provided, it's used as the default/fallback value.
313
+ * When a map is provided, the appropriate language is selected at runtime.
314
+ *
315
+ * @example
316
+ * // Simple string (backwards compatible)
317
+ * name: "Get Weather"
318
+ *
319
+ * @example
320
+ * // Localized strings
321
+ * name: { en: "Get Weather", sv: "Hämta väder", de: "Wetter abrufen" }
322
+ */
323
+ type LocalizedString = string | Record<string, string>;
324
+ /**
325
+ * Resolves a LocalizedString to an actual string value.
326
+ * @param value The LocalizedString to resolve
327
+ * @param lang The preferred language code (e.g., "sv", "en")
328
+ * @param fallbackLang The fallback language code (defaults to "en")
329
+ * @returns The resolved string value
330
+ */
331
+ declare function resolveLocalizedString(value: LocalizedString, lang: string, fallbackLang?: string): string;
310
332
  /**
311
333
  * Extension manifest format (manifest.json)
312
334
  */
@@ -444,7 +466,7 @@ interface ToolSettingsViewDefinition {
444
466
  /**
445
467
  * Tool settings view types
446
468
  */
447
- type ToolSettingsView = ToolSettingsListView;
469
+ type ToolSettingsView = ToolSettingsListView | ToolSettingsComponentView;
448
470
  /**
449
471
  * List view backed by tools
450
472
  */
@@ -487,6 +509,29 @@ interface ToolSettingsListMapping {
487
509
  /** Key for secondary label */
488
510
  secondaryKey?: string;
489
511
  }
512
+ /**
513
+ * Component-based tool settings view using the declarative DSL.
514
+ * Reuses the same structure as PanelComponentView for consistency.
515
+ */
516
+ interface ToolSettingsComponentView {
517
+ /** View kind */
518
+ kind: 'component';
519
+ /** Data sources. Keys become scope variables (e.g., "$settings"). */
520
+ data?: Record<string, ToolSettingsActionDataSource>;
521
+ /** Root component to render */
522
+ content: ExtensionComponentData;
523
+ }
524
+ /**
525
+ * Action-based data source for tool settings.
526
+ */
527
+ interface ToolSettingsActionDataSource {
528
+ /** Action ID to call for fetching data */
529
+ action: string;
530
+ /** Parameters to pass to the action */
531
+ params?: Record<string, unknown>;
532
+ /** Event names that trigger refresh */
533
+ refreshOn?: string[];
534
+ }
490
535
  /**
491
536
  * Panel definition for right panel views
492
537
  */
@@ -631,10 +676,20 @@ interface ProviderConfigValidation {
631
676
  interface ToolDefinition {
632
677
  /** Tool ID */
633
678
  id: string;
634
- /** Display name */
635
- name: string;
636
- /** Description for Stina */
637
- description: string;
679
+ /**
680
+ * Display name - can be a simple string or localized strings.
681
+ * @example "Get Weather"
682
+ * @example { en: "Get Weather", sv: "Hämta väder" }
683
+ */
684
+ name: LocalizedString;
685
+ /**
686
+ * Description for Stina - can be a simple string or localized strings.
687
+ * Note: The AI always receives the English description (or fallback) for consistency.
688
+ * Localized descriptions are used for UI display only.
689
+ * @example "Fetches current weather for a location"
690
+ * @example { en: "Fetches current weather", sv: "Hämtar aktuellt väder" }
691
+ */
692
+ description: LocalizedString;
638
693
  /** Parameter schema (JSON Schema) */
639
694
  parameters?: Record<string, unknown>;
640
695
  }
@@ -1153,4 +1208,4 @@ interface ExtensionModule {
1153
1208
  deactivate?(): void | Promise<void>;
1154
1209
  }
1155
1210
 
1156
- export type { ChatInstructionMessage as $, ActionResult as A, StoragePermission as B, ChatMessage as C, CapabilityPermission as D, ExtensionManifest as E, SystemPermission as F, GetModelsOptions as G, ExtensionContext as H, Disposable as I, NetworkAPI as J, SettingsAPI as K, ProvidersAPI as L, ModelInfo as M, NetworkPermission as N, ToolsAPI as O, Platform as P, ActionsAPI as Q, EventsAPI as R, SchedulerFirePayload as S, ToolResult as T, UserDataPermission as U, SchedulerAPI as V, SchedulerJobRequest as W, SchedulerSchedule as X, UserAPI as Y, UserProfile as Z, ChatAPI as _, ChatOptions as a, DatabaseAPI as a0, StorageAPI as a1, LogAPI as a2, AIProvider as a3, ToolCall as a4, Tool as a5, Action as a6, ExtensionModule as a7, AllowedCSSProperty as a8, ExtensionComponentStyle as a9, PillProps as aA, CheckboxProps as aB, MarkdownProps as aC, ModalProps as aD, ExtensionComponentData as aa, ExtensionComponentIterator as ab, ExtensionComponentChildren as ac, ExtensionActionCall as ad, ExtensionActionRef as ae, ExtensionDataSource as af, ExtensionPanelDefinition as ag, HeaderProps as ah, LabelProps as ai, ParagraphProps as aj, ButtonProps as ak, TextInputProps as al, DateTimeInputProps as am, SelectProps as an, VerticalStackProps as ao, HorizontalStackProps as ap, GridProps as aq, DividerProps as ar, IconProps as as, IconButtonType as at, IconButtonProps as au, PanelAction as av, PanelProps as aw, ToggleProps as ax, CollapsibleProps as ay, PillVariant as az, StreamEvent as b, ExtensionContributions as c, SettingDefinition as d, SettingOptionsMapping as e, SettingCreateMapping as f, ToolSettingsViewDefinition as g, ToolSettingsView as h, ToolSettingsListView as i, ToolSettingsListMapping as j, PanelDefinition as k, PanelView as l, PanelComponentView as m, PanelActionDataSource as n, PanelUnknownView as o, ProviderDefinition as p, PromptContribution as q, PromptSection as r, ToolDefinition as s, CommandDefinition as t, ProviderConfigSchema as u, ProviderConfigProperty as v, ProviderConfigPropertyType as w, ProviderConfigSelectOption as x, ProviderConfigValidation as y, Permission as z };
1211
+ export { type SchedulerSchedule as $, type ActionResult as A, type ProviderConfigSelectOption as B, type ChatMessage as C, type ProviderConfigValidation as D, type ExtensionManifest as E, type Permission as F, type GetModelsOptions as G, type StoragePermission as H, type CapabilityPermission as I, type SystemPermission as J, type ExtensionContext as K, type LocalizedString as L, type ModelInfo as M, type NetworkPermission as N, type Disposable as O, type Platform as P, type NetworkAPI as Q, type SettingsAPI as R, type SchedulerFirePayload as S, type ToolResult as T, type UserDataPermission as U, type ProvidersAPI as V, type ToolsAPI as W, type ActionsAPI as X, type EventsAPI as Y, type SchedulerAPI as Z, type SchedulerJobRequest as _, type ChatOptions as a, type UserAPI as a0, type UserProfile as a1, type ChatAPI as a2, type ChatInstructionMessage as a3, type DatabaseAPI as a4, type StorageAPI as a5, type LogAPI as a6, type AIProvider as a7, type ToolCall as a8, type Tool as a9, type PanelProps as aA, type ToggleProps as aB, type CollapsibleProps as aC, type PillVariant as aD, type PillProps as aE, type CheckboxProps as aF, type MarkdownProps as aG, type ModalProps as aH, type Action as aa, type ExtensionModule as ab, type AllowedCSSProperty as ac, type ExtensionComponentStyle as ad, type ExtensionComponentData as ae, type ExtensionComponentIterator as af, type ExtensionComponentChildren as ag, type ExtensionActionCall as ah, type ExtensionActionRef as ai, type ExtensionDataSource as aj, type ExtensionPanelDefinition as ak, type HeaderProps as al, type LabelProps as am, type ParagraphProps as an, type ButtonProps as ao, type TextInputProps as ap, type DateTimeInputProps as aq, type SelectProps as ar, type VerticalStackProps as as, type HorizontalStackProps as at, type GridProps as au, type DividerProps as av, type IconProps as aw, type IconButtonType as ax, type IconButtonProps as ay, type PanelAction as az, type StreamEvent as b, type ExtensionContributions as c, type SettingDefinition as d, type SettingOptionsMapping as e, type SettingCreateMapping as f, type ToolSettingsViewDefinition as g, type ToolSettingsView as h, type ToolSettingsListView as i, type ToolSettingsListMapping as j, type ToolSettingsComponentView as k, type ToolSettingsActionDataSource as l, type PanelDefinition as m, type PanelView as n, type PanelComponentView as o, type PanelActionDataSource as p, type PanelUnknownView as q, resolveLocalizedString as r, type ProviderDefinition as s, type PromptContribution as t, type PromptSection as u, type ToolDefinition as v, type CommandDefinition as w, type ProviderConfigSchema as x, type ProviderConfigProperty as y, type ProviderConfigPropertyType as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stina/extension-api",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -7,6 +7,10 @@
7
7
  * The runtime (worker-side code) should import from '@stina/extension-api/runtime'.
8
8
  */
9
9
 
10
+ // Localization
11
+ export type { LocalizedString } from './types.js'
12
+ export { resolveLocalizedString } from './types.js'
13
+
10
14
  // Types
11
15
  export type {
12
16
  // Manifest
@@ -20,6 +24,8 @@ export type {
20
24
  ToolSettingsView,
21
25
  ToolSettingsListView,
22
26
  ToolSettingsListMapping,
27
+ ToolSettingsComponentView,
28
+ ToolSettingsActionDataSource,
23
29
  PanelDefinition,
24
30
  PanelView,
25
31
  PanelComponentView,
package/src/types.ts CHANGED
@@ -1,3 +1,37 @@
1
+ /**
2
+ * A string that can be either a simple string or a map of language codes to localized strings.
3
+ * When a simple string is provided, it's used as the default/fallback value.
4
+ * When a map is provided, the appropriate language is selected at runtime.
5
+ *
6
+ * @example
7
+ * // Simple string (backwards compatible)
8
+ * name: "Get Weather"
9
+ *
10
+ * @example
11
+ * // Localized strings
12
+ * name: { en: "Get Weather", sv: "Hämta väder", de: "Wetter abrufen" }
13
+ */
14
+ export type LocalizedString = string | Record<string, string>
15
+
16
+ /**
17
+ * Resolves a LocalizedString to an actual string value.
18
+ * @param value The LocalizedString to resolve
19
+ * @param lang The preferred language code (e.g., "sv", "en")
20
+ * @param fallbackLang The fallback language code (defaults to "en")
21
+ * @returns The resolved string value
22
+ */
23
+ export function resolveLocalizedString(
24
+ value: LocalizedString,
25
+ lang: string,
26
+ fallbackLang = 'en'
27
+ ): string {
28
+ if (typeof value === 'string') {
29
+ return value
30
+ }
31
+ // Try preferred language first, then fallback language, then first available, then empty string
32
+ return value[lang] ?? value[fallbackLang] ?? Object.values(value)[0] ?? ''
33
+ }
34
+
1
35
  /**
2
36
  * Extension manifest format (manifest.json)
3
37
  */
@@ -139,7 +173,7 @@ export interface ToolSettingsViewDefinition {
139
173
  /**
140
174
  * Tool settings view types
141
175
  */
142
- export type ToolSettingsView = ToolSettingsListView
176
+ export type ToolSettingsView = ToolSettingsListView | ToolSettingsComponentView
143
177
 
144
178
  /**
145
179
  * List view backed by tools
@@ -185,6 +219,31 @@ export interface ToolSettingsListMapping {
185
219
  secondaryKey?: string
186
220
  }
187
221
 
222
+ /**
223
+ * Component-based tool settings view using the declarative DSL.
224
+ * Reuses the same structure as PanelComponentView for consistency.
225
+ */
226
+ export interface ToolSettingsComponentView {
227
+ /** View kind */
228
+ kind: 'component'
229
+ /** Data sources. Keys become scope variables (e.g., "$settings"). */
230
+ data?: Record<string, ToolSettingsActionDataSource>
231
+ /** Root component to render */
232
+ content: import('./types.components.js').ExtensionComponentData
233
+ }
234
+
235
+ /**
236
+ * Action-based data source for tool settings.
237
+ */
238
+ export interface ToolSettingsActionDataSource {
239
+ /** Action ID to call for fetching data */
240
+ action: string
241
+ /** Parameters to pass to the action */
242
+ params?: Record<string, unknown>
243
+ /** Event names that trigger refresh */
244
+ refreshOn?: string[]
245
+ }
246
+
188
247
  /**
189
248
  * Panel definition for right panel views
190
249
  */
@@ -356,10 +415,20 @@ export interface ProviderConfigValidation {
356
415
  export interface ToolDefinition {
357
416
  /** Tool ID */
358
417
  id: string
359
- /** Display name */
360
- name: string
361
- /** Description for Stina */
362
- description: string
418
+ /**
419
+ * Display name - can be a simple string or localized strings.
420
+ * @example "Get Weather"
421
+ * @example { en: "Get Weather", sv: "Hämta väder" }
422
+ */
423
+ name: LocalizedString
424
+ /**
425
+ * Description for Stina - can be a simple string or localized strings.
426
+ * Note: The AI always receives the English description (or fallback) for consistency.
427
+ * Localized descriptions are used for UI display only.
428
+ * @example "Fetches current weather for a location"
429
+ * @example { en: "Fetches current weather", sv: "Hämtar aktuellt väder" }
430
+ */
431
+ description: LocalizedString
363
432
  /** Parameter schema (JSON Schema) */
364
433
  parameters?: Record<string, unknown>
365
434
  }