@stina/extension-api 0.14.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
 
@@ -14,4 +14,4 @@ export {
14
14
  __require,
15
15
  generateMessageId
16
16
  };
17
- //# sourceMappingURL=chunk-Q7KN57DE.js.map
17
+ //# sourceMappingURL=chunk-WIDGIYRV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/messages.ts"],"sourcesContent":["/**\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":";;;;;;;;AAgRO,SAAS,oBAA4B;AAC1C,SAAO,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,CAAC;AACjE;","names":[]}
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\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// 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\nexport interface ReadyMessage {\n type: 'ready'\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 | '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;;;ACmPO,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,11 +1,11 @@
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-D9nElTai.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-D9nElTai.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
6
6
  */
7
7
 
8
- type HostToWorkerMessage = ActivateMessage | DeactivateMessage | SettingsChangedMessage | SchedulerFireMessage | ProviderChatRequestMessage | ProviderModelsRequestMessage | ToolExecuteRequestMessage | ActionExecuteRequestMessage | ResponseMessage;
8
+ type HostToWorkerMessage = ActivateMessage | DeactivateMessage | SettingsChangedMessage | SchedulerFireMessage | ProviderChatRequestMessage | ProviderModelsRequestMessage | ToolExecuteRequestMessage | ActionExecuteRequestMessage | ResponseMessage | StreamingFetchChunkMessage;
9
9
  interface ActivateMessage {
10
10
  type: 'activate';
11
11
  id: string;
@@ -81,17 +81,41 @@ interface ResponseMessage {
81
81
  error?: string;
82
82
  };
83
83
  }
84
- type WorkerToHostMessage = ReadyMessage | RequestMessage | ProviderRegisteredMessage | ToolRegisteredMessage | ActionRegisteredMessage | StreamEventMessage | LogMessage | ProviderModelsResponseMessage | ToolExecuteResponseMessage | ActionExecuteResponseMessage;
84
+ /**
85
+ * Message sent from host to worker with streaming fetch data chunks.
86
+ * Used for streaming network responses (e.g., NDJSON streams from Ollama).
87
+ */
88
+ interface StreamingFetchChunkMessage {
89
+ type: 'streaming-fetch-chunk';
90
+ id: string;
91
+ payload: {
92
+ requestId: string;
93
+ chunk: string;
94
+ done: boolean;
95
+ error?: string;
96
+ };
97
+ }
98
+ type WorkerToHostMessage = ReadyMessage | RequestMessage | ProviderRegisteredMessage | ToolRegisteredMessage | ActionRegisteredMessage | StreamEventMessage | LogMessage | ProviderModelsResponseMessage | ToolExecuteResponseMessage | ActionExecuteResponseMessage | StreamingFetchAckMessage;
85
99
  interface ReadyMessage {
86
100
  type: 'ready';
87
101
  }
102
+ /**
103
+ * Message sent from worker to host to acknowledge receipt of a streaming fetch chunk.
104
+ * This enables backpressure control to prevent unbounded memory growth.
105
+ */
106
+ interface StreamingFetchAckMessage {
107
+ type: 'streaming-fetch-ack';
108
+ payload: {
109
+ requestId: string;
110
+ };
111
+ }
88
112
  interface RequestMessage {
89
113
  type: 'request';
90
114
  id: string;
91
115
  method: RequestMethod;
92
116
  payload: unknown;
93
117
  }
94
- type RequestMethod = 'network.fetch' | 'settings.getAll' | 'settings.get' | 'settings.set' | 'user.getProfile' | 'events.emit' | 'scheduler.schedule' | 'scheduler.cancel' | 'chat.appendInstruction' | 'database.execute' | 'storage.get' | 'storage.set' | 'storage.delete' | 'storage.keys' | 'storage.getForUser' | 'storage.setForUser' | 'storage.deleteForUser' | 'storage.keysForUser';
118
+ type RequestMethod = 'network.fetch' | 'network.fetch-stream' | 'settings.getAll' | 'settings.get' | 'settings.set' | 'user.getProfile' | 'events.emit' | 'scheduler.schedule' | 'scheduler.cancel' | 'chat.appendInstruction' | 'database.execute' | 'storage.get' | 'storage.set' | 'storage.delete' | 'storage.keys' | 'storage.getForUser' | 'storage.setForUser' | 'storage.deleteForUser' | 'storage.keysForUser';
95
119
  interface ProviderRegisteredMessage {
96
120
  type: 'provider-registered';
97
121
  payload: {
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
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-D9nElTai.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-D9nElTai.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
6
6
  */
7
7
 
8
- type HostToWorkerMessage = ActivateMessage | DeactivateMessage | SettingsChangedMessage | SchedulerFireMessage | ProviderChatRequestMessage | ProviderModelsRequestMessage | ToolExecuteRequestMessage | ActionExecuteRequestMessage | ResponseMessage;
8
+ type HostToWorkerMessage = ActivateMessage | DeactivateMessage | SettingsChangedMessage | SchedulerFireMessage | ProviderChatRequestMessage | ProviderModelsRequestMessage | ToolExecuteRequestMessage | ActionExecuteRequestMessage | ResponseMessage | StreamingFetchChunkMessage;
9
9
  interface ActivateMessage {
10
10
  type: 'activate';
11
11
  id: string;
@@ -81,17 +81,41 @@ interface ResponseMessage {
81
81
  error?: string;
82
82
  };
83
83
  }
84
- type WorkerToHostMessage = ReadyMessage | RequestMessage | ProviderRegisteredMessage | ToolRegisteredMessage | ActionRegisteredMessage | StreamEventMessage | LogMessage | ProviderModelsResponseMessage | ToolExecuteResponseMessage | ActionExecuteResponseMessage;
84
+ /**
85
+ * Message sent from host to worker with streaming fetch data chunks.
86
+ * Used for streaming network responses (e.g., NDJSON streams from Ollama).
87
+ */
88
+ interface StreamingFetchChunkMessage {
89
+ type: 'streaming-fetch-chunk';
90
+ id: string;
91
+ payload: {
92
+ requestId: string;
93
+ chunk: string;
94
+ done: boolean;
95
+ error?: string;
96
+ };
97
+ }
98
+ type WorkerToHostMessage = ReadyMessage | RequestMessage | ProviderRegisteredMessage | ToolRegisteredMessage | ActionRegisteredMessage | StreamEventMessage | LogMessage | ProviderModelsResponseMessage | ToolExecuteResponseMessage | ActionExecuteResponseMessage | StreamingFetchAckMessage;
85
99
  interface ReadyMessage {
86
100
  type: 'ready';
87
101
  }
102
+ /**
103
+ * Message sent from worker to host to acknowledge receipt of a streaming fetch chunk.
104
+ * This enables backpressure control to prevent unbounded memory growth.
105
+ */
106
+ interface StreamingFetchAckMessage {
107
+ type: 'streaming-fetch-ack';
108
+ payload: {
109
+ requestId: string;
110
+ };
111
+ }
88
112
  interface RequestMessage {
89
113
  type: 'request';
90
114
  id: string;
91
115
  method: RequestMethod;
92
116
  payload: unknown;
93
117
  }
94
- type RequestMethod = 'network.fetch' | 'settings.getAll' | 'settings.get' | 'settings.set' | 'user.getProfile' | 'events.emit' | 'scheduler.schedule' | 'scheduler.cancel' | 'chat.appendInstruction' | 'database.execute' | 'storage.get' | 'storage.set' | 'storage.delete' | 'storage.keys' | 'storage.getForUser' | 'storage.setForUser' | 'storage.deleteForUser' | 'storage.keysForUser';
118
+ type RequestMethod = 'network.fetch' | 'network.fetch-stream' | 'settings.getAll' | 'settings.get' | 'settings.set' | 'user.getProfile' | 'events.emit' | 'scheduler.schedule' | 'scheduler.cancel' | 'chat.appendInstruction' | 'database.execute' | 'storage.get' | 'storage.set' | 'storage.delete' | 'storage.keys' | 'storage.getForUser' | 'storage.setForUser' | 'storage.deleteForUser' | 'storage.keysForUser';
95
119
  interface ProviderRegisteredMessage {
96
120
  type: 'provider-registered';
97
121
  payload: {
package/dist/index.js CHANGED
@@ -1,7 +1,16 @@
1
1
  import {
2
2
  generateMessageId
3
- } from "./chunk-Q7KN57DE.js";
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":[]}
package/dist/runtime.cjs CHANGED
@@ -57,6 +57,7 @@ var registeredTools = /* @__PURE__ */ new Map();
57
57
  var registeredActions = /* @__PURE__ */ new Map();
58
58
  var settingsCallbacks = [];
59
59
  var schedulerCallbacks = [];
60
+ var streamingFetchRequests = /* @__PURE__ */ new Map();
60
61
  var REQUEST_TIMEOUT = 3e4;
61
62
  function postMessage(message) {
62
63
  messagePort.postMessage(message);
@@ -106,7 +107,32 @@ async function handleHostMessage(message) {
106
107
  case "response":
107
108
  handleResponse(message.payload);
108
109
  break;
110
+ case "streaming-fetch-chunk":
111
+ handleStreamingFetchChunk(message.payload);
112
+ break;
113
+ }
114
+ }
115
+ function handleStreamingFetchChunk(payload) {
116
+ const request = streamingFetchRequests.get(payload.requestId);
117
+ if (!request) return;
118
+ if (payload.error) {
119
+ request.error = payload.error;
120
+ request.done = true;
121
+ } else if (payload.chunk) {
122
+ request.chunks.push(payload.chunk);
109
123
  }
124
+ if (payload.done) {
125
+ request.done = true;
126
+ }
127
+ if (request.resolve) {
128
+ const resolve = request.resolve;
129
+ request.resolve = void 0;
130
+ resolve();
131
+ }
132
+ postMessage({
133
+ type: "streaming-fetch-ack",
134
+ payload: { requestId: payload.requestId }
135
+ });
110
136
  }
111
137
  function handleResponse(payload) {
112
138
  const pending = pendingRequests.get(payload.requestId);
@@ -388,6 +414,44 @@ function buildContext(extensionId, extensionVersion, storagePath, permissions) {
388
414
  statusText: result.statusText,
389
415
  headers: result.headers
390
416
  });
417
+ },
418
+ async *fetchStream(url, options) {
419
+ const requestId = generateMessageId();
420
+ const request = {
421
+ chunks: [],
422
+ done: false
423
+ };
424
+ streamingFetchRequests.set(requestId, request);
425
+ postMessage({
426
+ type: "request",
427
+ id: requestId,
428
+ method: "network.fetch-stream",
429
+ payload: { url, options, requestId }
430
+ });
431
+ try {
432
+ while (!request.done) {
433
+ await new Promise((resolve) => {
434
+ const resolver = () => {
435
+ if (request.resolve === resolver) {
436
+ request.resolve = void 0;
437
+ }
438
+ resolve();
439
+ };
440
+ request.resolve = resolver;
441
+ if (request.chunks.length > 0 || request.done) {
442
+ resolver();
443
+ }
444
+ });
445
+ if (request.error) {
446
+ throw new Error(request.error);
447
+ }
448
+ while (request.chunks.length > 0) {
449
+ yield request.chunks.shift();
450
+ }
451
+ }
452
+ } finally {
453
+ streamingFetchRequests.delete(requestId);
454
+ }
391
455
  }
392
456
  };
393
457
  context.network = networkApi;