@talex-touch/utils 1.0.30 → 1.0.32
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/animation/window-node.ts +205 -0
- package/animation/window.ts +19 -15
- package/auth/clerk-types.ts +1 -1
- package/auth/index.ts +1 -1
- package/auth/useAuthState.ts +6 -5
- package/auth/useClerkConfig.ts +6 -6
- package/auth/useClerkProvider.ts +3 -2
- package/channel/index.ts +28 -21
- package/common/file-scan-constants.ts +137 -121
- package/common/file-scan-utils.ts +49 -25
- package/common/index.ts +3 -3
- package/common/search/gather.ts +1 -1
- package/common/search/index.ts +5 -6
- package/common/storage/constants.ts +3 -2
- package/common/storage/entity/app-settings.ts +19 -3
- package/common/storage/entity/shortcut-settings.ts +10 -10
- package/common/storage/shortcut-storage.ts +6 -4
- package/common/utils/file.ts +15 -4
- package/common/utils/index.ts +62 -52
- package/common/utils/polling.ts +114 -63
- package/common/utils/task-queue.ts +11 -10
- package/common/utils/time.ts +50 -47
- package/common/utils/timing.ts +41 -37
- package/core-box/builder/index.ts +1 -1
- package/core-box/builder/tuff-builder.ts +255 -230
- package/core-box/index.ts +3 -6
- package/core-box/preview/index.ts +1 -0
- package/core-box/preview/types.ts +43 -0
- package/core-box/tuff/index.ts +1 -1
- package/core-box/tuff/tuff-dsl.ts +419 -253
- package/electron/clipboard-helper.ts +20 -12
- package/electron/download-manager.ts +43 -42
- package/electron/env-tool.ts +19 -18
- package/electron/file-parsers/index.ts +2 -2
- package/electron/file-parsers/parsers/text-parser.ts +15 -14
- package/electron/file-parsers/registry.ts +9 -7
- package/electron/file-parsers/types.ts +4 -4
- package/electron/index.ts +1 -1
- package/eventbus/index.ts +11 -11
- package/index.ts +6 -5
- package/intelligence/client.ts +87 -0
- package/intelligence/index.ts +1 -0
- package/package.json +14 -14
- package/permission/index.ts +8 -8
- package/plugin/channel.ts +77 -68
- package/plugin/index.ts +113 -84
- package/plugin/install.ts +8 -8
- package/plugin/log/types.ts +5 -5
- package/plugin/node/index.ts +1 -1
- package/plugin/node/logger-manager.ts +14 -11
- package/plugin/node/logger.ts +8 -8
- package/plugin/plugin-source.ts +11 -11
- package/plugin/preload.ts +6 -3
- package/plugin/providers/registry.ts +8 -7
- package/plugin/providers/types.ts +6 -6
- package/plugin/sdk/channel.ts +20 -20
- package/plugin/sdk/clipboard.ts +8 -6
- package/plugin/sdk/common.ts +10 -6
- package/plugin/sdk/core-box.ts +2 -3
- package/plugin/sdk/division-box.ts +266 -0
- package/plugin/sdk/enum/bridge-event.ts +1 -1
- package/plugin/sdk/examples/storage-onDidChange-example.js +1 -1
- package/plugin/sdk/features.ts +34 -26
- package/plugin/sdk/hooks/bridge.ts +3 -6
- package/plugin/sdk/hooks/index.ts +1 -1
- package/plugin/sdk/hooks/life-cycle.ts +4 -10
- package/plugin/sdk/index.ts +9 -13
- package/plugin/sdk/service/index.ts +3 -3
- package/plugin/sdk/storage.ts +4 -4
- package/plugin/sdk/system.ts +1 -1
- package/plugin/sdk/types.ts +169 -143
- package/plugin/sdk/window/index.ts +8 -5
- package/preload/loading.ts +6 -6
- package/preload/renderer.ts +4 -2
- package/renderer/hooks/arg-mapper.ts +1 -2
- package/renderer/hooks/index.ts +2 -0
- package/renderer/hooks/initialize.ts +10 -8
- package/renderer/hooks/performance.ts +4 -4
- package/renderer/hooks/use-channel.ts +150 -0
- package/renderer/hooks/use-intelligence.ts +236 -0
- package/renderer/index.ts +6 -1
- package/renderer/ref.ts +32 -36
- package/renderer/slots.ts +29 -26
- package/renderer/storage/app-settings.ts +16 -6
- package/renderer/storage/base-storage.ts +236 -88
- package/renderer/storage/index.ts +3 -0
- package/renderer/storage/intelligence-storage.ts +215 -0
- package/renderer/storage/openers.ts +13 -3
- package/renderer/touch-sdk/env.ts +41 -41
- package/renderer/touch-sdk/index.ts +1 -1
- package/renderer/touch-sdk/terminal.ts +5 -5
- package/renderer/touch-sdk/utils.ts +4 -3
- package/search/levenshtein-utils.ts +11 -11
- package/search/types.ts +102 -103
- package/service/index.ts +11 -11
- package/service/protocol/index.ts +217 -14
- package/types/division-box.ts +248 -0
- package/types/download.ts +72 -34
- package/types/icon.ts +2 -1
- package/types/index.ts +3 -1
- package/types/intelligence.ts +413 -0
- package/types/modules/base.ts +16 -16
- package/types/modules/index.ts +1 -1
- package/types/modules/module-lifecycle.ts +21 -21
- package/types/modules/module-manager.ts +11 -11
- package/types/modules/module.ts +16 -16
- package/types/storage.ts +0 -1
- package/types/touch-app-core.ts +32 -32
- package/types/update.ts +79 -21
- package/core-box/README.md +0 -218
- package/core-box/builder/tuff-builder.example.ts.bak +0 -258
- package/core-box/run-tests.sh +0 -7
- package/core-box/search.ts +0 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import type { AiProviderConfig, AISDKGlobalConfig, AISDKStorageData } from '../../types/intelligence'
|
|
2
|
+
import { StorageList } from '../../common/storage/constants'
|
|
3
|
+
import {
|
|
4
|
+
|
|
5
|
+
AiProviderType,
|
|
6
|
+
|
|
7
|
+
DEFAULT_CAPABILITIES,
|
|
8
|
+
DEFAULT_GLOBAL_CONFIG,
|
|
9
|
+
DEFAULT_PROVIDERS,
|
|
10
|
+
} from '../../types/intelligence'
|
|
11
|
+
import { createStorageProxy, TouchStorage } from './base-storage'
|
|
12
|
+
|
|
13
|
+
// Re-export types for convenience
|
|
14
|
+
export { AiProviderType }
|
|
15
|
+
export type { AiProviderConfig, AISDKGlobalConfig }
|
|
16
|
+
|
|
17
|
+
const defaultIntelligenceData: AISDKStorageData = {
|
|
18
|
+
providers: [...DEFAULT_PROVIDERS],
|
|
19
|
+
globalConfig: { ...DEFAULT_GLOBAL_CONFIG },
|
|
20
|
+
capabilities: { ...DEFAULT_CAPABILITIES },
|
|
21
|
+
version: 1,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const INTELLIGENCE_STORAGE_KEY = `storage:${StorageList.IntelligenceConfig}`
|
|
25
|
+
|
|
26
|
+
class IntelligenceStorage extends TouchStorage<AISDKStorageData> {
|
|
27
|
+
constructor() {
|
|
28
|
+
super(StorageList.IntelligenceConfig, defaultIntelligenceData)
|
|
29
|
+
this.setAutoSave(true)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 添加新的提供商
|
|
34
|
+
*/
|
|
35
|
+
addProvider(provider: AiProviderConfig): void {
|
|
36
|
+
const currentData = this.get()
|
|
37
|
+
const updatedProviders = [...currentData.providers, provider]
|
|
38
|
+
this.set({
|
|
39
|
+
...currentData,
|
|
40
|
+
providers: updatedProviders,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 更新提供商配置
|
|
46
|
+
*/
|
|
47
|
+
updateProvider(id: string, updatedProvider: Partial<AiProviderConfig>): void {
|
|
48
|
+
const currentData = this.get()
|
|
49
|
+
const providerIndex = currentData.providers.findIndex(p => p.id === id)
|
|
50
|
+
|
|
51
|
+
if (providerIndex !== -1) {
|
|
52
|
+
const updatedProviders = [...currentData.providers]
|
|
53
|
+
updatedProviders[providerIndex] = {
|
|
54
|
+
...updatedProviders[providerIndex],
|
|
55
|
+
...updatedProvider,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.set({
|
|
59
|
+
...currentData,
|
|
60
|
+
providers: updatedProviders,
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 删除提供商
|
|
67
|
+
*/
|
|
68
|
+
removeProvider(id: string): void {
|
|
69
|
+
const currentData = this.get()
|
|
70
|
+
const updatedProviders = currentData.providers.filter(p => p.id !== id)
|
|
71
|
+
|
|
72
|
+
this.set({
|
|
73
|
+
...currentData,
|
|
74
|
+
providers: updatedProviders,
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 更新全局配置
|
|
80
|
+
*/
|
|
81
|
+
updateGlobalConfig(config: Partial<AISDKGlobalConfig>): void {
|
|
82
|
+
const currentData = this.get()
|
|
83
|
+
|
|
84
|
+
this.set({
|
|
85
|
+
...currentData,
|
|
86
|
+
globalConfig: {
|
|
87
|
+
...currentData.globalConfig,
|
|
88
|
+
...config,
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 获取特定类型的提供商
|
|
95
|
+
*/
|
|
96
|
+
getProvidersByType(type: AiProviderType): AiProviderConfig[] {
|
|
97
|
+
return this.get().providers.filter(p => p.type === type)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 获取启用的提供商
|
|
102
|
+
*/
|
|
103
|
+
getEnabledProviders(): AiProviderConfig[] {
|
|
104
|
+
return this.get().providers.filter(p => p.enabled)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 检查提供商是否已配置
|
|
109
|
+
*/
|
|
110
|
+
isProviderConfigured(id: string): boolean {
|
|
111
|
+
const provider = this.get().providers.find(p => p.id === id)
|
|
112
|
+
if (!provider || !provider.enabled)
|
|
113
|
+
return false
|
|
114
|
+
|
|
115
|
+
// 检查是否有必要的配置项
|
|
116
|
+
const hasApiKey = provider.type === AiProviderType.LOCAL || !!provider.apiKey
|
|
117
|
+
const hasModels = !!(provider.models && provider.models.length > 0)
|
|
118
|
+
|
|
119
|
+
return hasApiKey && hasModels
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Lazy-initialized Intelligence storage.
|
|
125
|
+
* The actual instance is created only when first accessed AND after initStorageChannel() is called.
|
|
126
|
+
*/
|
|
127
|
+
export const intelligenceStorage = createStorageProxy<IntelligenceStorage>(
|
|
128
|
+
INTELLIGENCE_STORAGE_KEY,
|
|
129
|
+
() => new IntelligenceStorage(),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Alias for backward compatibility
|
|
134
|
+
* @deprecated Use intelligenceStorage instead
|
|
135
|
+
*/
|
|
136
|
+
export const aisdkStorage = intelligenceStorage
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Alias for backward compatibility
|
|
140
|
+
* @deprecated Use intelligenceStorage instead
|
|
141
|
+
*/
|
|
142
|
+
export const intelligenceSettings = intelligenceStorage
|
|
143
|
+
|
|
144
|
+
export async function migrateIntelligenceSettings(): Promise<void> {
|
|
145
|
+
console.log('[Intelligence Storage] Starting migration check...')
|
|
146
|
+
const currentData = intelligenceStorage.data
|
|
147
|
+
|
|
148
|
+
if (!currentData.version || currentData.version < 1) {
|
|
149
|
+
console.log('[Intelligence Storage] Migrating settings to version 1')
|
|
150
|
+
|
|
151
|
+
const migratedProviders = currentData.providers.map(provider => ({
|
|
152
|
+
...provider,
|
|
153
|
+
enabled: provider.enabled ?? false,
|
|
154
|
+
priority: provider.priority ?? 2,
|
|
155
|
+
timeout: provider.timeout ?? 30000,
|
|
156
|
+
rateLimit: provider.rateLimit ?? {},
|
|
157
|
+
models: provider.models ?? [],
|
|
158
|
+
capabilities: provider.capabilities ?? [],
|
|
159
|
+
}))
|
|
160
|
+
|
|
161
|
+
const storedStrategy = currentData.globalConfig?.defaultStrategy
|
|
162
|
+
const normalizedStrategy
|
|
163
|
+
= storedStrategy === 'priority' ? 'rule-based-default' : storedStrategy ?? 'adaptive-default'
|
|
164
|
+
|
|
165
|
+
const migratedGlobalConfig: AISDKGlobalConfig = {
|
|
166
|
+
defaultStrategy: normalizedStrategy,
|
|
167
|
+
enableAudit: currentData.globalConfig?.enableAudit ?? false,
|
|
168
|
+
enableCache: currentData.globalConfig?.enableCache ?? true,
|
|
169
|
+
cacheExpiration: currentData.globalConfig?.cacheExpiration ?? 3600,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const migratedCapabilities = currentData.capabilities ?? { ...DEFAULT_CAPABILITIES }
|
|
173
|
+
|
|
174
|
+
intelligenceStorage.applyData({
|
|
175
|
+
providers: migratedProviders,
|
|
176
|
+
globalConfig: migratedGlobalConfig,
|
|
177
|
+
capabilities: migratedCapabilities,
|
|
178
|
+
version: 1,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
await intelligenceStorage.saveToRemote({ force: true })
|
|
182
|
+
|
|
183
|
+
console.log('[Intelligence Storage] Migration complete')
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
console.log('[Intelligence Storage] No migration needed, current version:', currentData.version)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.log('[Intelligence Storage] Final providers count:', intelligenceStorage.data.providers.length)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* @deprecated Use migrateIntelligenceSettings instead
|
|
194
|
+
*/
|
|
195
|
+
export const migrateAISDKSettings = migrateIntelligenceSettings
|
|
196
|
+
|
|
197
|
+
export async function resetIntelligenceConfig(): Promise<void> {
|
|
198
|
+
console.log('[Intelligence Storage] Resetting to default configuration')
|
|
199
|
+
|
|
200
|
+
intelligenceStorage.applyData({
|
|
201
|
+
providers: [...DEFAULT_PROVIDERS],
|
|
202
|
+
globalConfig: { ...DEFAULT_GLOBAL_CONFIG },
|
|
203
|
+
capabilities: { ...DEFAULT_CAPABILITIES },
|
|
204
|
+
version: 1,
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
await intelligenceStorage.saveToRemote({ force: true })
|
|
208
|
+
|
|
209
|
+
console.log('[Intelligence Storage] Reset complete')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @deprecated Use resetIntelligenceConfig instead
|
|
214
|
+
*/
|
|
215
|
+
export const resetAISDKConfig = resetIntelligenceConfig
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { openersOriginData, StorageList
|
|
1
|
+
import type { OpenersMap } from '../..'
|
|
2
|
+
import { openersOriginData, StorageList } from '../..'
|
|
3
|
+
import { createStorageProxy, TouchStorage } from './base-storage'
|
|
3
4
|
|
|
4
5
|
class OpenersStorage extends TouchStorage<OpenersMap> {
|
|
5
6
|
constructor() {
|
|
@@ -8,4 +9,13 @@ class OpenersStorage extends TouchStorage<OpenersMap> {
|
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
const OPENERS_STORAGE_KEY = `storage:${StorageList.OPENERS}`
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Lazy-initialized openers storage.
|
|
16
|
+
* The actual instance is created only when first accessed AND after initStorageChannel() is called.
|
|
17
|
+
*/
|
|
18
|
+
export const openersStorage = createStorageProxy<OpenersStorage>(
|
|
19
|
+
OPENERS_STORAGE_KEY,
|
|
20
|
+
() => new OpenersStorage(),
|
|
21
|
+
)
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
+
import type { ITouchClientChannel } from '@talex-touch/utils/channel'
|
|
1
2
|
import { Terminal } from './terminal'
|
|
2
|
-
import { ITouchClientChannel } from '@talex-touch/utils/channel'
|
|
3
3
|
|
|
4
4
|
export class EnvDetector {
|
|
5
|
-
private static channel: ITouchClientChannel
|
|
5
|
+
private static channel: ITouchClientChannel
|
|
6
6
|
|
|
7
7
|
public static init(channel: ITouchClientChannel) {
|
|
8
|
-
this.channel = channel
|
|
8
|
+
this.channel = channel
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
private static async checkCommand(
|
|
12
12
|
command: string,
|
|
13
13
|
versionArgs: string = '--version',
|
|
14
|
-
versionRegex: RegExp = /(\d+\.\d+\.\d+)
|
|
14
|
+
versionRegex: RegExp = /(\d+\.\d+\.\d+)/,
|
|
15
15
|
): Promise<string | false> {
|
|
16
16
|
if (!this.channel) {
|
|
17
|
-
throw new Error(
|
|
17
|
+
throw new Error('EnvDetector not initialized. Call EnvDetector.init(channel) first.')
|
|
18
18
|
}
|
|
19
19
|
return new Promise((resolve) => {
|
|
20
20
|
const terminal = new Terminal(this.channel)
|
|
21
21
|
let output = ''
|
|
22
|
-
let resolved = false
|
|
22
|
+
let resolved = false
|
|
23
23
|
|
|
24
24
|
const resolveOnce = (value: string | false) => {
|
|
25
25
|
if (!resolved) {
|
|
26
|
-
resolved = true
|
|
27
|
-
resolve(value)
|
|
26
|
+
resolved = true
|
|
27
|
+
resolve(value)
|
|
28
28
|
// For child_process, there's no explicit disconnect/kill needed after it exits.
|
|
29
29
|
// The process lifecycle is managed by the OS once it's started and exits.
|
|
30
30
|
}
|
|
@@ -51,7 +51,7 @@ export class EnvDetector {
|
|
|
51
51
|
// Timeout in case the command hangs or never returns
|
|
52
52
|
setTimeout(() => {
|
|
53
53
|
resolveOnce(false)
|
|
54
|
-
}, 2000)
|
|
54
|
+
}, 2000)
|
|
55
55
|
})
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -69,38 +69,38 @@ export class EnvDetector {
|
|
|
69
69
|
|
|
70
70
|
static async getDegit(): Promise<boolean> {
|
|
71
71
|
if (!this.channel) {
|
|
72
|
-
throw new Error(
|
|
72
|
+
throw new Error('EnvDetector not initialized. Call EnvDetector.init(channel) first.')
|
|
73
73
|
}
|
|
74
74
|
return new Promise((resolve) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
resolveOnce(receivedOutput)
|
|
103
|
-
|
|
104
|
-
})
|
|
75
|
+
const terminal = new Terminal(this.channel)
|
|
76
|
+
let receivedOutput = false
|
|
77
|
+
let resolved = false
|
|
78
|
+
|
|
79
|
+
const resolveOnce = (value: boolean) => {
|
|
80
|
+
if (!resolved) {
|
|
81
|
+
resolved = true
|
|
82
|
+
resolve(value)
|
|
83
|
+
// For child_process, there's no explicit disconnect/kill needed after it exits.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
terminal.onData(() => {
|
|
88
|
+
receivedOutput = true
|
|
89
|
+
resolveOnce(true) // As soon as we get any output, we know it's there.
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
terminal.onExit(() => {
|
|
93
|
+
resolveOnce(receivedOutput)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// Execute degit with --help
|
|
97
|
+
terminal.exec('degit', ['--help']).catch(() => {
|
|
98
|
+
resolveOnce(false)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
resolveOnce(receivedOutput)
|
|
103
|
+
}, 2000)
|
|
104
|
+
})
|
|
105
105
|
}
|
|
106
|
-
}
|
|
106
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ITouchClientChannel } from '@talex-touch/utils/channel'
|
|
1
|
+
import type { ITouchClientChannel } from '@talex-touch/utils/channel'
|
|
2
2
|
|
|
3
3
|
type DataCallback = (data: string) => void
|
|
4
4
|
type ExitCallback = (exitCode: number | null) => void
|
|
@@ -25,10 +25,10 @@ export class Terminal {
|
|
|
25
25
|
// If there's an existing process, it should ideally be killed first.
|
|
26
26
|
// However, for simplicity in this refactor, we'll assume exec is called for a new, independent command.
|
|
27
27
|
// A more robust implementation might track multiple concurrent processes.
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
const { id } = await this.channel.send('terminal:create', { command, args })
|
|
30
30
|
this.id = id
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// Re-register listeners for the new process ID
|
|
33
33
|
this.channel.regChannel('terminal:data', (channelData) => {
|
|
34
34
|
if (this.id === channelData.data.id && this.onDataCallback) {
|
|
@@ -42,7 +42,7 @@ export class Terminal {
|
|
|
42
42
|
this.id = null
|
|
43
43
|
}
|
|
44
44
|
})
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
return id
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -82,4 +82,4 @@ export class Terminal {
|
|
|
82
82
|
public onExit(callback: ExitCallback): void {
|
|
83
83
|
this.onExitCallback = callback
|
|
84
84
|
}
|
|
85
|
-
}
|
|
85
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TouchSDKOptions } from './index'
|
|
2
|
+
import { TouchSDK } from './index'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Factory function to create a TouchSDK instance
|
|
@@ -26,7 +27,7 @@ export function getTouchSDK(): TouchSDK {
|
|
|
26
27
|
|
|
27
28
|
export function useTouchSDK(options?: TouchSDKOptions) {
|
|
28
29
|
if (!sdkInstance) {
|
|
29
|
-
if (
|
|
30
|
+
if (!options) {
|
|
30
31
|
throw new Error('TouchSDK not initialized. Call initTouchSDK first. Cannot use hook here.')
|
|
31
32
|
}
|
|
32
33
|
initTouchSDK(options)
|
|
@@ -57,5 +58,5 @@ export const TouchUtils = {
|
|
|
57
58
|
|
|
58
59
|
async openPluginFolder(pluginName: string): Promise<void> {
|
|
59
60
|
return getTouchSDK().openPluginFolder(pluginName)
|
|
60
|
-
}
|
|
61
|
+
},
|
|
61
62
|
}
|
|
@@ -7,33 +7,33 @@
|
|
|
7
7
|
* @returns The Levenshtein distance.
|
|
8
8
|
*/
|
|
9
9
|
export function levenshteinDistance(s1: string, s2: string): number {
|
|
10
|
-
const m = s1.length
|
|
11
|
-
const n = s2.length
|
|
10
|
+
const m = s1.length
|
|
11
|
+
const n = s2.length
|
|
12
12
|
|
|
13
13
|
// Create a 2D array (m+1)x(n+1) to store distances
|
|
14
|
-
const dp: number[][] = Array(m + 1)
|
|
14
|
+
const dp: number[][] = new Array(m + 1)
|
|
15
15
|
.fill(0)
|
|
16
|
-
.map(() => Array(n + 1).fill(0))
|
|
16
|
+
.map(() => new Array(n + 1).fill(0))
|
|
17
17
|
|
|
18
18
|
// Initialize the DP table
|
|
19
19
|
for (let i = 0; i <= m; i++) {
|
|
20
|
-
dp[i][0] = i
|
|
20
|
+
dp[i][0] = i
|
|
21
21
|
}
|
|
22
22
|
for (let j = 0; j <= n; j++) {
|
|
23
|
-
dp[0][j] = j
|
|
23
|
+
dp[0][j] = j
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Fill the DP table
|
|
27
27
|
for (let i = 1; i <= m; i++) {
|
|
28
28
|
for (let j = 1; j <= n; j++) {
|
|
29
|
-
const cost = s1[i - 1] === s2[j - 1] ? 0 : 1
|
|
29
|
+
const cost = s1[i - 1] === s2[j - 1] ? 0 : 1
|
|
30
30
|
dp[i][j] = Math.min(
|
|
31
31
|
dp[i - 1][j] + 1, // Deletion
|
|
32
32
|
dp[i][j - 1] + 1, // Insertion
|
|
33
|
-
dp[i - 1][j - 1] + cost // Substitution
|
|
34
|
-
)
|
|
33
|
+
dp[i - 1][j - 1] + cost, // Substitution
|
|
34
|
+
)
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
return dp[m][n]
|
|
39
|
-
}
|
|
38
|
+
return dp[m][n]
|
|
39
|
+
}
|