@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.
@@ -8,7 +8,6 @@
8
8
  */
9
9
 
10
10
  import type { FileScanOptions } from './file-scan-constants'
11
- // eslint-disable-next-line @typescript-eslint/no-var-requires
12
11
  import {
13
12
  BASE_BLACKLISTED_DIRS,
14
13
  BLACKLISTED_EXTENSIONS,
@@ -3,6 +3,7 @@ export enum StorageList {
3
3
  SHORTCUT_SETTING = 'shortcut-setting.ini',
4
4
  OPENERS = 'openers.json',
5
5
  IntelligenceConfig = 'aisdk-config',
6
+ MARKET_SOURCES = 'market-sources.json',
6
7
  }
7
8
 
8
9
  /**
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-console */
1
2
  /**
2
3
  * @module polling
3
4
  * A high-precision, efficient, singleton polling service for scheduling periodic tasks.
@@ -75,7 +76,7 @@ export class PollingService {
75
76
  nextRunMs,
76
77
  })
77
78
 
78
- console.log(`[PollingService] Task '${id}' registered to run every ${options.interval} ${options.unit}.`)
79
+ console.debug(`[PollingService] Task '${id}' registered to run every ${options.interval} ${options.unit}.`)
79
80
 
80
81
  if (this.isRunning) {
81
82
  this._reschedule()
package/core-box/index.ts CHANGED
@@ -5,3 +5,4 @@ export * from './preview/index'
5
5
  * Search box core functionality package
6
6
  */
7
7
  export * from './tuff/index'
8
+ export * from './recommendation'
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Time-based usage pattern context for recommendation matching.
3
+ */
4
+ export interface TimePattern {
5
+ /** Hour of day (0-23) */
6
+ hourOfDay: number
7
+ /** Day of week (0-6, 0=Sunday) */
8
+ dayOfWeek: number
9
+ /** Whether current time falls within working hours (9-18, weekdays) */
10
+ isWorkingHours: boolean
11
+ /** Broad time categorization */
12
+ timeSlot: 'morning' | 'afternoon' | 'evening' | 'night'
13
+ }
14
+
15
+ /**
16
+ * Complete contextual signal for recommendation matching.
17
+ * Gathered from system state, clipboard, and active applications.
18
+ */
19
+ export interface ContextSignal {
20
+ time: TimePattern
21
+ clipboard?: {
22
+ type: string
23
+ /** Hashed content for privacy (not original text) */
24
+ content: string
25
+ timestamp: number
26
+ contentType?: 'url' | 'text' | 'code' | 'file'
27
+ meta?: {
28
+ isUrl?: boolean
29
+ urlDomain?: string
30
+ textLength?: number
31
+ fileExtension?: string
32
+ fileType?: 'code' | 'text' | 'image' | 'document' | 'other'
33
+ language?: string
34
+ }
35
+ }
36
+ foregroundApp?: {
37
+ bundleId: string
38
+ name: string
39
+ }
40
+ systemState?: {
41
+ isOnline: boolean
42
+ batteryLevel: number
43
+ isDNDEnabled: boolean
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Scored recommendation item from recommendation engine.
49
+ */
50
+ export interface ScoredItem {
51
+ sourceId: string
52
+ itemId: string
53
+ score: number
54
+ source: 'frequent' | 'time-based' | 'recent' | 'trending' | 'context'
55
+ reason?: string
56
+ }
57
+
58
+ /**
59
+ * Recommendation badge display configuration for UI rendering.
60
+ */
61
+ export interface RecommendationBadge {
62
+ text: string
63
+ icon: string
64
+ variant: 'frequent' | 'intelligent' | 'recent' | 'trending'
65
+ }
66
+
67
+ /**
68
+ * Enhanced item metadata for intelligent recommendations.
69
+ * Attached to TuffItem.meta for rendering and filtering.
70
+ */
71
+ export interface RecommendationMetadata {
72
+ score: number
73
+ source: ScoredItem['source']
74
+ reason: string
75
+ isIntelligent: boolean
76
+ badge: RecommendationBadge
77
+ }
package/electron/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './clipboard-helper'
2
1
  export * from './download-manager'
3
2
  export * from './env-tool'
3
+
package/index.ts CHANGED
@@ -11,3 +11,4 @@ export * from './types'
11
11
  export * from './types/download'
12
12
  export * from './types/icon'
13
13
  export * from './types/update'
14
+ export * from './market'
@@ -0,0 +1,95 @@
1
+ import { StorageList } from '../common/storage/constants'
2
+ import type {
3
+ MarketProviderDefinition,
4
+ MarketSourcesPayload,
5
+ MarketSourcesStorageInfo,
6
+ MarketProviderTrustLevel,
7
+ } from './types'
8
+
9
+ export const MARKET_SOURCES_STORAGE_KEY = StorageList.MARKET_SOURCES
10
+ export const MARKET_SOURCES_STORAGE_VERSION = 1
11
+
12
+ function defineProvider(
13
+ provider: Omit<MarketProviderDefinition, 'trustLevel'> & {
14
+ trustLevel?: MarketProviderTrustLevel
15
+ },
16
+ ): MarketProviderDefinition {
17
+ return {
18
+ trustLevel: provider.trustLevel ?? 'unverified',
19
+ ...provider,
20
+ }
21
+ }
22
+
23
+ export const DEFAULT_MARKET_PROVIDERS: MarketProviderDefinition[] = [
24
+ defineProvider({
25
+ id: 'talex-official',
26
+ name: 'Talex Official',
27
+ type: 'nexusStore',
28
+ url: 'https://raw.githubusercontent.com/talex-touch/tuff-official-plugins/main/plugins.json',
29
+ description: '官方插件市场,提供经过审核的核心插件。',
30
+ enabled: true,
31
+ priority: 100,
32
+ trustLevel: 'official',
33
+ readOnly: true,
34
+ config: {
35
+ manifestUrl:
36
+ 'https://raw.githubusercontent.com/talex-touch/tuff-official-plugins/main/plugins.json',
37
+ baseUrl: 'https://raw.githubusercontent.com/talex-touch/tuff-official-plugins/main/',
38
+ },
39
+ }),
40
+ defineProvider({
41
+ id: 'github-releases',
42
+ name: 'GitHub Releases',
43
+ type: 'repository',
44
+ description: '从 GitHub 仓库 releases / manifest 中读取插件。',
45
+ enabled: false,
46
+ priority: 80,
47
+ trustLevel: 'unverified',
48
+ config: {
49
+ platform: 'github',
50
+ apiBase: 'https://api.github.com',
51
+ },
52
+ }),
53
+ defineProvider({
54
+ id: 'gitee-repos',
55
+ name: 'Gitee 仓库',
56
+ type: 'repository',
57
+ description: 'Gitee 平台插件仓库,适合国内网络。',
58
+ enabled: false,
59
+ priority: 70,
60
+ trustLevel: 'unverified',
61
+ config: {
62
+ platform: 'gitee',
63
+ apiBase: 'https://gitee.com/api/v5',
64
+ },
65
+ }),
66
+ defineProvider({
67
+ id: 'npm-scope',
68
+ name: 'NPM 包',
69
+ type: 'npmPackage',
70
+ description: '基于 NPM 关键字或 scope 的插件发布渠道。',
71
+ enabled: false,
72
+ priority: 60,
73
+ trustLevel: 'unverified',
74
+ config: {
75
+ registryUrl: 'https://registry.npmjs.org',
76
+ keyword: 'talex-touch-plugin',
77
+ },
78
+ }),
79
+ ]
80
+
81
+ export const MARKET_SOURCES_STORAGE_INFO: MarketSourcesStorageInfo = {
82
+ storageKey: MARKET_SOURCES_STORAGE_KEY,
83
+ version: MARKET_SOURCES_STORAGE_VERSION,
84
+ }
85
+
86
+ export function createDefaultMarketSourcesPayload(): MarketSourcesPayload {
87
+ const clone = typeof structuredClone === 'function'
88
+ ? structuredClone(DEFAULT_MARKET_PROVIDERS)
89
+ : JSON.parse(JSON.stringify(DEFAULT_MARKET_PROVIDERS))
90
+
91
+ return {
92
+ version: MARKET_SOURCES_STORAGE_VERSION,
93
+ sources: clone,
94
+ }
95
+ }
@@ -0,0 +1,2 @@
1
+ export * from './types'
2
+ export * from './constants'
@@ -0,0 +1,118 @@
1
+ import type { StorageList } from '../common/storage/constants'
2
+
3
+ export type MarketProviderType = 'repository' | 'nexusStore' | 'npmPackage'
4
+
5
+ export type MarketProviderTrustLevel = 'official' | 'verified' | 'unverified'
6
+
7
+ export interface MarketProviderDefinition {
8
+ id: string
9
+ name: string
10
+ type: MarketProviderType
11
+ /**
12
+ * Base URL or identifier for the provider.
13
+ * Individual provider implementations can interpret this differently.
14
+ */
15
+ url?: string
16
+ /**
17
+ * Additional configuration object for provider specific options.
18
+ */
19
+ config?: Record<string, any>
20
+ description?: string
21
+ enabled: boolean
22
+ priority: number
23
+ trustLevel?: MarketProviderTrustLevel
24
+ tags?: string[]
25
+ /**
26
+ * Whether this provider should be treated as read-only (no install)
27
+ */
28
+ readOnly?: boolean
29
+ }
30
+
31
+ export interface MarketSourcesPayload {
32
+ /**
33
+ * Schema version, used for migrations.
34
+ */
35
+ version: number
36
+ sources: MarketProviderDefinition[]
37
+ }
38
+
39
+ export type MarketInstallInstruction =
40
+ | {
41
+ type: 'url'
42
+ url: string
43
+ format?: 'zip' | 'tar' | 'tgz' | 'tpex'
44
+ integrity?: string
45
+ }
46
+ | {
47
+ type: 'npm'
48
+ packageName: string
49
+ version?: string
50
+ registry?: string
51
+ }
52
+ | {
53
+ type: 'git'
54
+ repo: string
55
+ ref?: string
56
+ sparse?: boolean
57
+ }
58
+
59
+ export interface MarketPlugin {
60
+ id: string
61
+ name: string
62
+ version?: string
63
+ description?: string
64
+ category?: string
65
+ tags?: string[]
66
+ author?: string
67
+ icon?: string
68
+ metadata?: Record<string, unknown>
69
+ readmeUrl?: string
70
+ homepage?: string
71
+ downloadUrl?: string
72
+ install?: MarketInstallInstruction
73
+ providerId: string
74
+ providerName: string
75
+ providerType: MarketProviderType
76
+ providerTrustLevel: MarketProviderTrustLevel
77
+ trusted: boolean
78
+ official?: boolean
79
+ timestamp?: number | string
80
+ }
81
+
82
+ export interface MarketProviderResultMeta {
83
+ providerId: string
84
+ providerName: string
85
+ providerType: MarketProviderType
86
+ success: boolean
87
+ error?: string
88
+ fetchedAt: number
89
+ itemCount: number
90
+ }
91
+
92
+ export interface MarketProviderListOptions {
93
+ keyword?: string
94
+ force?: boolean
95
+ }
96
+
97
+ export interface MarketHttpRequestOptions {
98
+ url: string
99
+ method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
100
+ headers?: Record<string, string>
101
+ params?: Record<string, any>
102
+ data?: any
103
+ timeout?: number
104
+ responseType?: 'json' | 'text' | 'arraybuffer'
105
+ }
106
+
107
+ export interface MarketHttpResponse<T = unknown> {
108
+ status: number
109
+ statusText: string
110
+ headers: Record<string, string>
111
+ data: T
112
+ url: string
113
+ }
114
+
115
+ export interface MarketSourcesStorageInfo {
116
+ storageKey: StorageList
117
+ version: number
118
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@talex-touch/utils",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "private": false,
5
5
  "description": "Tuff series utils",
6
6
  "author": "TalexDreamSoul",
package/plugin/index.ts CHANGED
@@ -498,3 +498,4 @@ export type { IPluginLogger, LogDataType, LogItem, LogLevel } from './log/types'
498
498
  export * from './providers'
499
499
  export * from './risk'
500
500
  export * from './sdk/index'
501
+ export * from './widget'
@@ -0,0 +1,216 @@
1
+ # Plugin SDK 重构说明
2
+
3
+ ## 概述
4
+
5
+ Plugin SDK 已重构为统一的工厂函数模式,参考 `DivisionBoxSDK` 的设计。旧版本 API 已废弃,调用时会抛出错误。
6
+
7
+ ## 新的 SDK 结构
8
+
9
+ ### 1. BoxSDK - CoreBox 窗口控制
10
+
11
+ 控制 CoreBox 窗口的显示、大小和输入框状态。
12
+
13
+ ```typescript
14
+ // 隐藏/显示 CoreBox
15
+ plugin.box.hide()
16
+ plugin.box.show()
17
+
18
+ // 扩展窗口(显示更多结果)
19
+ plugin.box.expand({ length: 10 })
20
+ plugin.box.expand({ forceMax: true })
21
+
22
+ // 收缩窗口
23
+ plugin.box.shrink()
24
+
25
+ // 控制输入框
26
+ plugin.box.hideInput()
27
+ plugin.box.showInput()
28
+
29
+ // 获取当前输入
30
+ const input = await plugin.box.getInput()
31
+ ```
32
+
33
+ ### 2. FeatureSDK - 搜索结果管理
34
+
35
+ 管理插件推送的搜索结果项(TuffItems)。
36
+
37
+ ```typescript
38
+ // 推送多个结果
39
+ plugin.feature.pushItems([
40
+ { id: 'item-1', title: { text: 'Result 1' }, ... },
41
+ { id: 'item-2', title: { text: 'Result 2' }, ... }
42
+ ])
43
+
44
+ // 更新单个结果
45
+ plugin.feature.updateItem('item-1', {
46
+ title: { text: 'Updated Title' }
47
+ })
48
+
49
+ // 删除单个结果
50
+ plugin.feature.removeItem('item-1')
51
+
52
+ // 清空所有结果
53
+ plugin.feature.clearItems()
54
+
55
+ // 获取所有结果
56
+ const items = plugin.feature.getItems()
57
+
58
+ // 监听输入变化(实时搜索)
59
+ const unsubscribe = plugin.feature.onInputChange((input) => {
60
+ console.log('User typed:', input)
61
+ // 执行实时搜索
62
+ performSearch(input)
63
+ })
64
+
65
+ // 取消监听
66
+ unsubscribe()
67
+ ```
68
+
69
+ ## 废弃的 API
70
+
71
+ 以下 API 已废弃,调用时会抛出错误:
72
+
73
+ ### 旧的 Box API
74
+ ```typescript
75
+ // ❌ 废弃
76
+ plugin.$box.hide()
77
+ plugin.$box.show()
78
+
79
+ // ✅ 使用新 API
80
+ plugin.box.hide()
81
+ plugin.box.show()
82
+ ```
83
+
84
+ ### 旧的 Feature API
85
+ ```typescript
86
+ // ❌ 废弃
87
+ plugin.pushItems(items)
88
+ plugin.clearItems()
89
+ plugin.getItems()
90
+
91
+ // ✅ 使用新 API
92
+ plugin.feature.pushItems(items)
93
+ plugin.feature.clearItems()
94
+ plugin.feature.getItems()
95
+ ```
96
+
97
+ ## 迁移指南
98
+
99
+ ### 1. 更新 Box 控制代码
100
+
101
+ **旧代码:**
102
+ ```typescript
103
+ plugin.$box.hide()
104
+ plugin.$box.show()
105
+ ```
106
+
107
+ **新代码:**
108
+ ```typescript
109
+ plugin.box.hide()
110
+ plugin.box.show()
111
+ plugin.box.expand({ length: 10 })
112
+ plugin.box.shrink()
113
+ ```
114
+
115
+ ### 2. 更新搜索结果管理
116
+
117
+ **旧代码:**
118
+ ```typescript
119
+ plugin.pushItems([...])
120
+ plugin.clearItems()
121
+ const items = plugin.getItems()
122
+ ```
123
+
124
+ **新代码:**
125
+ ```typescript
126
+ plugin.feature.pushItems([...])
127
+ plugin.feature.updateItem('id', { ... })
128
+ plugin.feature.removeItem('id')
129
+ plugin.feature.clearItems()
130
+ const items = plugin.feature.getItems()
131
+ ```
132
+
133
+ ### 3. 添加实时搜索支持
134
+
135
+ **新功能:**
136
+ ```typescript
137
+ // 在插件初始化时注册监听器
138
+ onInit(context) {
139
+ context.utils.feature.onInputChange((input) => {
140
+ // 用户输入变化时触发
141
+ this.performRealTimeSearch(input)
142
+ })
143
+ }
144
+ ```
145
+
146
+ ## 完整示例
147
+
148
+ ```typescript
149
+ export default {
150
+ onInit(context) {
151
+ const { feature, box } = context.utils
152
+
153
+ // 监听输入变化
154
+ feature.onInputChange((input) => {
155
+ if (input.length > 2) {
156
+ // 执行搜索
157
+ const results = performSearch(input)
158
+ feature.pushItems(results)
159
+ } else {
160
+ feature.clearItems()
161
+ }
162
+ })
163
+ },
164
+
165
+ onFeatureTriggered(featureId, query, feature) {
166
+ const { feature: featureSDK, box } = this.context.utils
167
+
168
+ // 推送结果
169
+ featureSDK.pushItems([
170
+ {
171
+ id: 'result-1',
172
+ title: { text: 'Search Result' },
173
+ subtitle: { text: 'Description' },
174
+ source: { id: this.pluginName, name: this.pluginName }
175
+ }
176
+ ])
177
+
178
+ // 扩展窗口显示结果
179
+ box.expand({ length: 5 })
180
+
181
+ // 3秒后隐藏
182
+ setTimeout(() => {
183
+ box.hide()
184
+ }, 3000)
185
+ }
186
+ }
187
+ ```
188
+
189
+ ## 技术细节
190
+
191
+ ### SDK 工厂函数
192
+
193
+ 所有 SDK 都通过工厂函数创建:
194
+
195
+ - `createBoxSDK(channel)` - 创建 Box SDK 实例
196
+ - `createFeatureSDK(boxItems, channel)` - 创建 Feature SDK 实例
197
+ - `createDivisionBoxSDK(channel)` - 创建 DivisionBox SDK 实例
198
+
199
+ ### IPC 通道
200
+
201
+ 新增的 IPC 通道:
202
+
203
+ - `core-box:hide-input` - 隐藏输入框
204
+ - `core-box:show-input` - 显示输入框
205
+ - `core-box:get-input` - 获取当前输入值
206
+ - `core-box:input-changed` - 输入变化广播(主进程 → 插件)
207
+ - `core-box:set-input-visibility` - 设置输入框可见性(主进程 → 渲染进程)
208
+ - `core-box:request-input-value` - 请求输入值(主进程 → 渲染进程)
209
+
210
+ ### 架构优势
211
+
212
+ 1. **统一的 API 风格** - 所有 SDK 使用相同的工厂函数模式
213
+ 2. **更好的类型安全** - TypeScript 类型定义完整
214
+ 3. **功能分离** - Box 控制和 Feature 管理职责清晰
215
+ 4. **扩展性强** - 易于添加新功能
216
+ 5. **向后不兼容** - 强制迁移到新 API,避免技术债务