@talex-touch/utils 1.0.32 → 1.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Box SDK for Plugin Development
3
+ *
4
+ * Provides a unified API for plugins to control the CoreBox window behavior,
5
+ * including visibility, size, input field control, and input value access.
6
+ */
7
+
8
+ /**
9
+ * Expand options for CoreBox window
10
+ */
11
+ export interface BoxExpandOptions {
12
+ /** Number of items to show (affects window height) */
13
+ length?: number
14
+ /** Force maximum expansion */
15
+ forceMax?: boolean
16
+ }
17
+
18
+ /**
19
+ * Box SDK interface for plugins
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Hide CoreBox
24
+ * plugin.box.hide()
25
+ *
26
+ * // Show CoreBox
27
+ * plugin.box.show()
28
+ *
29
+ * // Expand to show 10 items
30
+ * plugin.box.expand({ length: 10 })
31
+ *
32
+ * // Get current input
33
+ * const input = plugin.box.getInput()
34
+ * ```
35
+ */
36
+ export interface BoxSDK {
37
+ /**
38
+ * Hides the CoreBox window
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * plugin.box.hide()
43
+ * ```
44
+ */
45
+ hide(): void
46
+
47
+ /**
48
+ * Shows the CoreBox window
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * plugin.box.show()
53
+ * ```
54
+ */
55
+ show(): void
56
+
57
+ /**
58
+ * Expands the CoreBox window
59
+ *
60
+ * @param options - Optional expansion configuration
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * // Expand to show 10 items
65
+ * plugin.box.expand({ length: 10 })
66
+ *
67
+ * // Force maximum expansion
68
+ * plugin.box.expand({ forceMax: true })
69
+ *
70
+ * // Default expansion
71
+ * plugin.box.expand()
72
+ * ```
73
+ */
74
+ expand(options?: BoxExpandOptions): Promise<void>
75
+
76
+ /**
77
+ * Shrinks the CoreBox window to compact size
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * plugin.box.shrink()
82
+ * ```
83
+ */
84
+ shrink(): Promise<void>
85
+
86
+ /**
87
+ * Hides the input field in CoreBox
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * plugin.box.hideInput()
92
+ * ```
93
+ */
94
+ hideInput(): Promise<void>
95
+
96
+ /**
97
+ * Shows the input field in CoreBox
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * plugin.box.showInput()
102
+ * ```
103
+ */
104
+ showInput(): Promise<void>
105
+
106
+ /**
107
+ * Gets the current input value from CoreBox search field
108
+ *
109
+ * @returns Promise resolving to the current input string
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const input = await plugin.box.getInput()
114
+ * console.log('Current input:', input)
115
+ * ```
116
+ */
117
+ getInput(): Promise<string>
118
+ }
119
+
120
+ /**
121
+ * Creates a Box SDK instance for plugin use
122
+ *
123
+ * @param channel - The plugin channel bridge for IPC communication
124
+ * @returns Configured Box SDK instance
125
+ *
126
+ * @internal
127
+ */
128
+ export function createBoxSDK(channel: any): BoxSDK {
129
+ const sendFn = channel.sendToMain || channel.send
130
+
131
+ if (!sendFn) {
132
+ throw new Error('[Box SDK] Channel send function not available')
133
+ }
134
+
135
+ return {
136
+ hide(): void {
137
+ sendFn('core-box:hide').catch((error: any) => {
138
+ console.error('[Box SDK] Failed to hide CoreBox:', error)
139
+ })
140
+ },
141
+
142
+ show(): void {
143
+ sendFn('core-box:show').catch((error: any) => {
144
+ console.error('[Box SDK] Failed to show CoreBox:', error)
145
+ })
146
+ },
147
+
148
+ async expand(options?: BoxExpandOptions): Promise<void> {
149
+ try {
150
+ await sendFn('core-box:expand', options || {})
151
+ } catch (error) {
152
+ console.error('[Box SDK] Failed to expand CoreBox:', error)
153
+ throw error
154
+ }
155
+ },
156
+
157
+ async shrink(): Promise<void> {
158
+ try {
159
+ await sendFn('core-box:expand', { mode: 'collapse' })
160
+ } catch (error) {
161
+ console.error('[Box SDK] Failed to shrink CoreBox:', error)
162
+ throw error
163
+ }
164
+ },
165
+
166
+ async hideInput(): Promise<void> {
167
+ try {
168
+ await sendFn('core-box:hide-input')
169
+ } catch (error) {
170
+ console.error('[Box SDK] Failed to hide input:', error)
171
+ throw error
172
+ }
173
+ },
174
+
175
+ async showInput(): Promise<void> {
176
+ try {
177
+ await sendFn('core-box:show-input')
178
+ } catch (error) {
179
+ console.error('[Box SDK] Failed to show input:', error)
180
+ throw error
181
+ }
182
+ },
183
+
184
+ async getInput(): Promise<string> {
185
+ try {
186
+ const result = await sendFn('core-box:get-input')
187
+ return result?.data?.input || result?.input || ''
188
+ } catch (error) {
189
+ console.error('[Box SDK] Failed to get input:', error)
190
+ throw error
191
+ }
192
+ }
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Hook for using Box SDK in plugin context
198
+ *
199
+ * @returns Box SDK instance
200
+ *
201
+ * @example
202
+ * ```typescript
203
+ * const box = useBox()
204
+ *
205
+ * box.hide()
206
+ * box.expand({ length: 10 })
207
+ * const input = await box.getInput()
208
+ * ```
209
+ */
210
+ export function useBox(): BoxSDK {
211
+ // @ts-ignore - window.$channel is injected by the plugin system
212
+ const channel = window.$channel
213
+
214
+ if (!channel) {
215
+ throw new Error('[Box SDK] Channel not available. Make sure this is called in a plugin context.')
216
+ }
217
+
218
+ return createBoxSDK(channel)
219
+ }
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Feature SDK for Plugin Development
3
+ *
4
+ * Provides a unified API for plugins to manage search result items (TuffItems)
5
+ * in the CoreBox interface. This SDK handles item lifecycle, updates, and
6
+ * input change notifications.
7
+ */
8
+
9
+ import type { TuffItem } from '../../core-box/tuff'
10
+
11
+ /**
12
+ * Input change event handler
13
+ */
14
+ export type InputChangeHandler = (input: string) => void
15
+
16
+ /**
17
+ * Feature SDK interface for plugins
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Push items to CoreBox
22
+ * plugin.feature.pushItems([
23
+ * { id: 'item-1', title: 'Result 1', ... },
24
+ * { id: 'item-2', title: 'Result 2', ... }
25
+ * ])
26
+ *
27
+ * // Update a specific item
28
+ * plugin.feature.updateItem('item-1', { title: 'Updated Title' })
29
+ *
30
+ * // Listen for input changes
31
+ * plugin.feature.onInputChange((input) => {
32
+ * console.log('User typed:', input)
33
+ * })
34
+ * ```
35
+ */
36
+ export interface FeatureSDK {
37
+ /**
38
+ * Pushes multiple items to the CoreBox search results
39
+ *
40
+ * @param items - Array of TuffItem objects to display
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * plugin.feature.pushItems([
45
+ * {
46
+ * id: 'calc-result',
47
+ * title: { text: '42' },
48
+ * subtitle: { text: 'Calculation result' },
49
+ * source: { id: 'calculator', name: 'Calculator' }
50
+ * }
51
+ * ])
52
+ * ```
53
+ */
54
+ pushItems(items: TuffItem[]): void
55
+
56
+ /**
57
+ * Updates a specific item by ID
58
+ *
59
+ * @param id - The unique ID of the item to update
60
+ * @param updates - Partial TuffItem with fields to update
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * // Update title and subtitle
65
+ * plugin.feature.updateItem('item-1', {
66
+ * title: { text: 'New Title' },
67
+ * subtitle: { text: 'Updated subtitle' }
68
+ * })
69
+ * ```
70
+ */
71
+ updateItem(id: string, updates: Partial<TuffItem>): void
72
+
73
+ /**
74
+ * Removes a specific item by ID
75
+ *
76
+ * @param id - The unique ID of the item to remove
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * plugin.feature.removeItem('item-1')
81
+ * ```
82
+ */
83
+ removeItem(id: string): void
84
+
85
+ /**
86
+ * Clears all items pushed by this plugin
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * plugin.feature.clearItems()
91
+ * ```
92
+ */
93
+ clearItems(): void
94
+
95
+ /**
96
+ * Gets all items currently pushed by this plugin
97
+ *
98
+ * @returns Array of TuffItem objects
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * const items = plugin.feature.getItems()
103
+ * console.log(`Currently showing ${items.length} items`)
104
+ * ```
105
+ */
106
+ getItems(): TuffItem[]
107
+
108
+ /**
109
+ * Registers a listener for input changes in the CoreBox search field
110
+ *
111
+ * @param handler - Callback function invoked when input changes
112
+ * @returns Unsubscribe function
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const unsubscribe = plugin.feature.onInputChange((input) => {
117
+ * console.log('User typed:', input)
118
+ * // Perform real-time search
119
+ * performSearch(input)
120
+ * })
121
+ *
122
+ * // Later, unsubscribe
123
+ * unsubscribe()
124
+ * ```
125
+ */
126
+ onInputChange(handler: InputChangeHandler): () => void
127
+ }
128
+
129
+ /**
130
+ * Creates a Feature SDK instance for plugin use
131
+ *
132
+ * @param boxItemsAPI - The boxItems API object from plugin context
133
+ * @param channel - The plugin channel bridge for IPC communication
134
+ * @returns Configured Feature SDK instance
135
+ *
136
+ * @internal
137
+ */
138
+ export function createFeatureSDK(boxItemsAPI: any, channel: any): FeatureSDK {
139
+ const inputChangeHandlers: Set<InputChangeHandler> = new Set()
140
+
141
+ // Register listener for input change events from main process
142
+ const registerListener = () => {
143
+ if (channel.onMain) {
144
+ // Main process plugin context
145
+ channel.onMain('core-box:input-changed', (event: any) => {
146
+ const input = event.data?.input || event.input || ''
147
+ inputChangeHandlers.forEach(handler => handler(input))
148
+ })
149
+ } else if (channel.on) {
150
+ // Renderer process context
151
+ channel.on('core-box:input-changed', (data: any) => {
152
+ const input = data?.input || data || ''
153
+ inputChangeHandlers.forEach(handler => handler(input))
154
+ })
155
+ }
156
+ }
157
+
158
+ registerListener()
159
+
160
+ return {
161
+ pushItems(items: TuffItem[]): void {
162
+ if (!boxItemsAPI || !boxItemsAPI.pushItems) {
163
+ throw new Error('[Feature SDK] boxItems API not available')
164
+ }
165
+ boxItemsAPI.pushItems(items)
166
+ },
167
+
168
+ updateItem(id: string, updates: Partial<TuffItem>): void {
169
+ if (!boxItemsAPI || !boxItemsAPI.update) {
170
+ throw new Error('[Feature SDK] boxItems API not available')
171
+ }
172
+ boxItemsAPI.update(id, updates)
173
+ },
174
+
175
+ removeItem(id: string): void {
176
+ if (!boxItemsAPI || !boxItemsAPI.remove) {
177
+ throw new Error('[Feature SDK] boxItems API not available')
178
+ }
179
+ boxItemsAPI.remove(id)
180
+ },
181
+
182
+ clearItems(): void {
183
+ if (!boxItemsAPI || !boxItemsAPI.clear) {
184
+ throw new Error('[Feature SDK] boxItems API not available')
185
+ }
186
+ boxItemsAPI.clear()
187
+ },
188
+
189
+ getItems(): TuffItem[] {
190
+ if (!boxItemsAPI || !boxItemsAPI.getItems) {
191
+ throw new Error('[Feature SDK] boxItems API not available')
192
+ }
193
+ return boxItemsAPI.getItems()
194
+ },
195
+
196
+ onInputChange(handler: InputChangeHandler): () => void {
197
+ inputChangeHandlers.add(handler)
198
+
199
+ return () => {
200
+ inputChangeHandlers.delete(handler)
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Hook for using Feature SDK in plugin context
208
+ *
209
+ * @returns Feature SDK instance
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * const feature = useFeature()
214
+ *
215
+ * feature.pushItems([
216
+ * { id: '1', title: { text: 'Item 1' }, ... }
217
+ * ])
218
+ * ```
219
+ */
220
+ export function useFeature(): FeatureSDK {
221
+ // @ts-ignore - window.$boxItems and window.$channel are injected by the plugin system
222
+ const boxItemsAPI = window.$boxItems
223
+ // @ts-ignore
224
+ const channel = window.$channel
225
+
226
+ if (!boxItemsAPI) {
227
+ throw new Error('[Feature SDK] boxItems API not available. Make sure this is called in a plugin context.')
228
+ }
229
+
230
+ if (!channel) {
231
+ throw new Error('[Feature SDK] Channel not available. Make sure this is called in a plugin context.')
232
+ }
233
+
234
+ return createFeatureSDK(boxItemsAPI, channel)
235
+ }
@@ -7,10 +7,12 @@ export interface ITouchSDK {
7
7
 
8
8
  // Note: Window.$touchSDK is declared in ../preload.ts to avoid duplicate declarations
9
9
 
10
+ export * from './box-sdk'
10
11
  export * from './channel'
11
12
  export * from './clipboard'
12
13
  export * from './core-box'
13
14
  export * from './division-box'
15
+ export * from './feature-sdk'
14
16
  export { createFeaturesManager, useFeatures } from './features'
15
17
 
16
18
  export * from './hooks/index'
@@ -183,6 +183,18 @@ export interface IPluginUtils {
183
183
  */
184
184
  divisionBox: import('./division-box').DivisionBoxSDK
185
185
 
186
+ /**
187
+ * Box SDK for controlling CoreBox window behavior
188
+ * @see {@link BoxSDK}
189
+ */
190
+ box: import('./box-sdk').BoxSDK
191
+
192
+ /**
193
+ * Feature SDK for managing search result items
194
+ * @see {@link FeatureSDK}
195
+ */
196
+ feature: import('./feature-sdk').FeatureSDK
197
+
186
198
  /**
187
199
  * Opens a URL in the default browser
188
200
  * @param url - The URL to open
@@ -190,21 +202,22 @@ export interface IPluginUtils {
190
202
  openUrl: (url: string) => void
191
203
 
192
204
  /**
193
- * Pushes search result items to the search interface
194
- * @param items - Array of search result items to add
205
+ * @deprecated Use plugin.feature.pushItems() instead
206
+ * @throws Error indicating the API is deprecated
195
207
  */
196
- pushItems: (items: any[]) => void
208
+ pushItems: (items: any[]) => never
197
209
 
198
210
  /**
199
- * Clears all current search results
211
+ * @deprecated Use plugin.feature.clearItems() instead
212
+ * @throws Error indicating the API is deprecated
200
213
  */
201
- clearItems: () => void
214
+ clearItems: () => never
202
215
 
203
216
  /**
204
- * Gets all current search result items
205
- * @returns Array of current search result items
217
+ * @deprecated Use plugin.feature.getItems() instead
218
+ * @throws Error indicating the API is deprecated
206
219
  */
207
- getItems: () => any[]
220
+ getItems: () => never
208
221
 
209
222
  /**
210
223
  * Features manager for dynamic feature management
@@ -0,0 +1,25 @@
1
+ export const DEFAULT_WIDGET_RENDERERS = {
2
+ CORE_PREVIEW_CARD: 'core-preview-card',
3
+ CORE_INTELLIGENCE_ANSWER: 'core-intelligence-answer',
4
+ } as const
5
+
6
+ const values = Object.values(DEFAULT_WIDGET_RENDERERS)
7
+ export const DEFAULT_WIDGET_RENDERER_IDS = new Set<string>(values)
8
+
9
+ export function isDefaultWidgetRenderer(id: string | undefined): boolean {
10
+ return Boolean(id) && DEFAULT_WIDGET_RENDERER_IDS.has(id!)
11
+ }
12
+
13
+ export interface WidgetRegistrationPayload {
14
+ widgetId: string
15
+ pluginName: string
16
+ featureId: string
17
+ filePath: string
18
+ code: string
19
+ styles: string
20
+ hash: string
21
+ }
22
+
23
+ export function makeWidgetId(pluginName: string, featureId: string): string {
24
+ return `${pluginName}::${featureId}`
25
+ }
@@ -18,7 +18,7 @@ const defaultIntelligenceData: AISDKStorageData = {
18
18
  providers: [...DEFAULT_PROVIDERS],
19
19
  globalConfig: { ...DEFAULT_GLOBAL_CONFIG },
20
20
  capabilities: { ...DEFAULT_CAPABILITIES },
21
- version: 1,
21
+ version: 2,
22
22
  }
23
23
 
24
24
  const INTELLIGENCE_STORAGE_KEY = `storage:${StorageList.IntelligenceConfig}`
@@ -145,8 +145,9 @@ export async function migrateIntelligenceSettings(): Promise<void> {
145
145
  console.log('[Intelligence Storage] Starting migration check...')
146
146
  const currentData = intelligenceStorage.data
147
147
 
148
- if (!currentData.version || currentData.version < 1) {
149
- console.log('[Intelligence Storage] Migrating settings to version 1')
148
+ // Version 2: Force update capabilities to include all new ones
149
+ if (!currentData.version || currentData.version < 2) {
150
+ console.log('[Intelligence Storage] Migrating settings to version 2')
150
151
 
151
152
  const migratedProviders = currentData.providers.map(provider => ({
152
153
  ...provider,
@@ -169,24 +170,26 @@ export async function migrateIntelligenceSettings(): Promise<void> {
169
170
  cacheExpiration: currentData.globalConfig?.cacheExpiration ?? 3600,
170
171
  }
171
172
 
172
- const migratedCapabilities = currentData.capabilities ?? { ...DEFAULT_CAPABILITIES }
173
-
173
+ // Force update to latest DEFAULT_CAPABILITIES (version 2)
174
+ console.log('[Intelligence Storage] Updating capabilities to latest defaults')
175
+
174
176
  intelligenceStorage.applyData({
175
177
  providers: migratedProviders,
176
178
  globalConfig: migratedGlobalConfig,
177
- capabilities: migratedCapabilities,
178
- version: 1,
179
+ capabilities: { ...DEFAULT_CAPABILITIES },
180
+ version: 2,
179
181
  })
180
182
 
181
183
  await intelligenceStorage.saveToRemote({ force: true })
182
184
 
183
- console.log('[Intelligence Storage] Migration complete')
185
+ console.log('[Intelligence Storage] Migration to v2 complete, capabilities count:', Object.keys(DEFAULT_CAPABILITIES).length)
184
186
  }
185
187
  else {
186
188
  console.log('[Intelligence Storage] No migration needed, current version:', currentData.version)
187
189
  }
188
190
 
189
191
  console.log('[Intelligence Storage] Final providers count:', intelligenceStorage.data.providers.length)
192
+ console.log('[Intelligence Storage] Final capabilities count:', Object.keys(intelligenceStorage.data.capabilities).length)
190
193
  }
191
194
 
192
195
  /**
@@ -201,7 +204,7 @@ export async function resetIntelligenceConfig(): Promise<void> {
201
204
  providers: [...DEFAULT_PROVIDERS],
202
205
  globalConfig: { ...DEFAULT_GLOBAL_CONFIG },
203
206
  capabilities: { ...DEFAULT_CAPABILITIES },
204
- version: 1,
207
+ version: 2,
205
208
  })
206
209
 
207
210
  await intelligenceStorage.saveToRemote({ force: true })