intools-cli 1.0.2 → 1.0.3

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/PLUGIN_API.md ADDED
@@ -0,0 +1,434 @@
1
+ # InTools 插件 API 参考
2
+
3
+ > 本文档包含 InTools 插件开发可用的全部 API。
4
+ > - **UI/渲染进程**:`window.intools.{模块名}`
5
+ > - **插件后端**:`context.api.{模块名}`
6
+
7
+ ---
8
+
9
+ ## 1. 剪贴板 (clipboard)
10
+
11
+ | 方法 | 环境 | 说明 |
12
+ |------|------|------|
13
+ | `readText()` | R/B | 读取文本 → `string` |
14
+ | `writeText(text)` | R/B | 写入文本 |
15
+ | `readImage()` | R/B | 读取图片 → `Buffer | null` |
16
+ | `writeImage(image)` | R/B | 写入图片(路径/Buffer/DataURL) |
17
+ | `writeFiles(paths)` | R | 写入文件路径 |
18
+ | `readFiles()` | R/B | 读取文件列表 → `ClipboardFileInfo[]` |
19
+ | `getFormat()` | R/B | 获取格式 → `'text' | 'image' | 'files' | 'html' | 'empty'` |
20
+
21
+ ---
22
+
23
+ ## 2. 文件系统 (filesystem)
24
+
25
+ | 方法 | 环境 | 说明 |
26
+ |------|------|------|
27
+ | `readFile(path, encoding?)` | R/B | 读取文件 → `Buffer | string` |
28
+ | `writeFile(path, data, encoding?)` | R/B | 写入文件 |
29
+ | `exists(path)` | R/B | 检查是否存在 → `boolean` |
30
+ | `unlink(path)` | R/B | 删除文件 |
31
+ | `readdir(path)` | R/B | 读取目录 → `string[]` |
32
+ | `mkdir(path)` | R/B | 创建目录(递归) |
33
+ | `stat(path)` | R/B | 获取文件信息 → `FileStat` |
34
+ | `copy(src, dest)` | R/B | 复制文件 |
35
+ | `move(src, dest)` | R/B | 移动/重命名文件 |
36
+ | `extname(path)` | B | 获取扩展名 |
37
+ | `join(...paths)` | B | 拼接路径 |
38
+ | `dirname(path)` | B | 获取目录名 |
39
+ | `basename(path, ext?)` | B | 获取文件名 |
40
+
41
+ ---
42
+
43
+ ## 3. 存储 (storage)
44
+
45
+ | 方法 | 环境 | 说明 |
46
+ |------|------|------|
47
+ | `get(key, namespace?)` | R/B | 获取数据 |
48
+ | `set(key, value, namespace?)` | R/B | 存储数据 |
49
+ | `remove(key, namespace?)` | R/B | 删除数据 |
50
+ | `clear()` | B | 清空存储 |
51
+ | `keys()` | B | 获取所有键 |
52
+
53
+ ---
54
+
55
+ ## 4. 对话框 (dialog)
56
+
57
+ | 方法 | 环境 | 说明 |
58
+ |------|------|------|
59
+ | `showOpenDialog(options?)` | R/B | 打开文件对话框 → `string[]` |
60
+ | `showSaveDialog(options?)` | R/B | 保存文件对话框 → `string | null` |
61
+ | `showMessageBox(options)` | R/B | 消息框 → `{ response, checkboxChecked }` |
62
+ | `showErrorBox(title, content)` | R/B | 错误框(同步) |
63
+
64
+ **OpenDialogOptions**: `title`, `defaultPath`, `buttonLabel`, `filters`, `properties`
65
+ **properties**: `'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles'`
66
+
67
+ ---
68
+
69
+ ## 5. 通知 (notification)
70
+
71
+ | 方法 | 环境 | 说明 |
72
+ |------|------|------|
73
+ | `show(message, type?)` | R/B | 显示通知(`type='error'` 时不静音) |
74
+
75
+ ---
76
+
77
+ ## 6. Shell
78
+
79
+ | 方法 | 环境 | 说明 |
80
+ |------|------|------|
81
+ | `openPath(path)` | R/B | 用默认应用打开文件 |
82
+ | `openExternal(url)` | R/B | 用浏览器打开 URL |
83
+ | `showItemInFolder(path)` | R/B | 在文件管理器中显示 |
84
+ | `openFolder(path)` | R/B | 打开文件所在目录 |
85
+ | `trashItem(path)` | R/B | 移动到回收站 |
86
+ | `beep()` | R/B | 播放系统提示音 |
87
+
88
+ ---
89
+
90
+ ## 7. HTTP 请求 (http)
91
+
92
+ | 方法 | 环境 | 说明 |
93
+ |------|------|------|
94
+ | `request(options)` | R/B | 发起请求 → `HttpResponse` |
95
+ | `get(url, headers?)` | R/B | GET 请求 |
96
+ | `post(url, body?, headers?)` | R/B | POST 请求 |
97
+ | `put(url, body?, headers?)` | R/B | PUT 请求 |
98
+ | `delete(url, headers?)` | R/B | DELETE 请求 |
99
+
100
+ **HttpRequestOptions**: `url`, `method`, `headers`, `body`, `timeout`
101
+ **HttpResponse**: `{ status, statusText, headers, data }`
102
+
103
+ ---
104
+
105
+ ## 8. 系统 (system)
106
+
107
+ | 方法 | 环境 | 说明 |
108
+ |------|------|------|
109
+ | `getSystemInfo()` | R/B | 获取系统信息 → `SystemInfo` |
110
+ | `getAppInfo()` | R/B | 获取应用信息 → `AppInfo` |
111
+ | `getPath(name)` | R/B | 获取特定路径 |
112
+ | `getEnv(name)` | R/B | 获取环境变量 |
113
+ | `getIdleTime()` | R/B | 获取空闲时间(秒) |
114
+ | `getFileIcon(path)` | R/B | 获取文件图标 → base64 DataURL |
115
+ | `getNativeId()` | R/B | 获取设备唯一标识 |
116
+ | `isDev()` | R/B | 是否开发环境 |
117
+ | `isMacOS() / isWindows() / isLinux()` | R/B | 判断操作系统 |
118
+
119
+ **getPath 支持**: `'home' | 'appData' | 'userData' | 'temp' | 'exe' | 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos' | 'logs'`
120
+
121
+ ---
122
+
123
+ ## 9. 屏幕 (screen)
124
+
125
+ | 方法 | 环境 | 说明 |
126
+ |------|------|------|
127
+ | `getAllDisplays()` | R/B | 获取所有显示器 → `DisplayInfo[]` |
128
+ | `getPrimaryDisplay()` | R/B | 获取主显示器 |
129
+ | `getDisplayNearestPoint(point)` | R/B | 获取坐标位置的显示器 |
130
+ | `getCursorScreenPoint()` | R/B | 获取鼠标位置 |
131
+ | `getSources(options?)` | R/B | 获取捕获源列表 |
132
+ | `capture(options?)` | R/B | 截取屏幕 → `Buffer` |
133
+ | `captureRegion(region, options?)` | R/B | 截取指定区域 |
134
+ | `screenCapture()` | R | 交互式区域截图 → DataURL |
135
+ | `colorPick()` | R | 屏幕取色 → `{ hex, rgb, r, g, b }` |
136
+ | `getMediaStreamConstraints(options)` | R/B | 获取录屏约束配置 |
137
+
138
+ ---
139
+
140
+ ## 10. 输入 (input)
141
+
142
+ | 方法 | 环境 | 说明 |
143
+ |------|------|------|
144
+ | `hideMainWindowPasteText(text)` | R/B | 粘贴文本到焦点应用 |
145
+ | `hideMainWindowPasteImage(image)` | R/B | 粘贴图片到焦点应用 |
146
+ | `hideMainWindowPasteFile(paths)` | R/B | 粘贴文件到焦点应用 |
147
+ | `hideMainWindowTypeString(text)` | R/B | 模拟键入文本 |
148
+ | `simulateKeyboardTap(key, ...modifiers)` | R/B | 模拟按键 |
149
+ | `simulateMouseMove(x, y)` | R/B | 移动鼠标 |
150
+ | `simulateMouseClick(x, y)` | R/B | 左键单击 |
151
+ | `simulateMouseDoubleClick(x, y)` | R/B | 左键双击 |
152
+ | `simulateMouseRightClick(x, y)` | R/B | 右键点击 |
153
+
154
+ **修饰键**: `'ctrl' | 'alt' | 'shift' | 'command'`
155
+
156
+ ---
157
+
158
+ ## 11. 窗口 (window)
159
+
160
+ | 方法 | 环境 | 说明 |
161
+ |------|------|------|
162
+ | `hide(restorePreWindow?)` | R | 隐藏窗口 |
163
+ | `show()` | R | 显示窗口 |
164
+ | `setSize(width, height)` | R | 设置尺寸 |
165
+ | `setExpendHeight(height)` | R | 调整高度 |
166
+ | `center()` | R | 窗口居中 |
167
+ | `setAlwaysOnTop(flag)` | R | 设置置顶 |
168
+ | `detach()` | R | 分离为独立窗口 |
169
+ | `close()` | R | 关闭窗口 |
170
+ | `reload()` | R | 重新加载 |
171
+ | `getMode()` | R | 获取模式 → `'attached' | 'detached'` |
172
+ | `getWindowType()` | R | 获取类型 → `'main' | 'detach'` |
173
+ | `getState()` | R | 获取状态 |
174
+ | `minimize() / maximize()` | R | 最小化/最大化 |
175
+ | `create(url, options?)` | R | 创建子窗口 → `ChildWindowHandle` |
176
+ | `sendToParent(channel, ...args)` | R | 向父窗口发消息 |
177
+ | `onChildMessage(callback)` | R | 监听子窗口消息 |
178
+ | `findInPage(text, options?)` | R | 页面内查找 |
179
+ | `startDrag(filePath)` | R | 触发文件拖拽 |
180
+
181
+ ### 子输入框 (subInput)
182
+
183
+ | 方法 | 说明 |
184
+ |------|------|
185
+ | `set(placeholder?, isFocus?)` | 显示子输入框 |
186
+ | `remove()` | 移除子输入框 |
187
+ | `setValue(text)` | 设置内容 |
188
+ | `focus() / blur() / select()` | 焦点控制 |
189
+ | `onChange(callback)` | 监听变化 |
190
+
191
+ ---
192
+
193
+ ## 12. 主题 (theme)
194
+
195
+ | 方法 | 环境 | 说明 |
196
+ |------|------|------|
197
+ | `get()` | R | 获取主题信息 → `{ mode, actual }` |
198
+ | `set(mode)` | R | 设置主题 → `'light' | 'dark' | 'system'` |
199
+ | `getActual()` | R | 获取实际主题 → `'light' | 'dark'` |
200
+ | `onThemeChange(callback)` | R | 监听主题变化 |
201
+
202
+ ---
203
+
204
+ ## 13. 插件管理 (plugin)
205
+
206
+ | 方法 | 环境 | 说明 |
207
+ |------|------|------|
208
+ | `getAll()` | R | 获取所有插件 |
209
+ | `search(query)` | R | 搜索插件功能 |
210
+ | `run(name, featureCode, input?)` | R | 执行插件功能 |
211
+ | `install(filePath)` | R | 安装插件 |
212
+ | `enable(name) / disable(name)` | R | 启用/禁用插件 |
213
+ | `uninstall(name)` | R | 卸载插件 |
214
+ | `getReadme(name)` | R | 获取 README |
215
+ | `redirect(label, payload?)` | R | 跳转到其他插件 |
216
+ | `outPlugin(isKill?)` | R | 退出当前插件 |
217
+
218
+ ### 事件
219
+
220
+ | 事件 | 说明 |
221
+ |------|------|
222
+ | `onPluginInit(callback)` | 插件初始化 |
223
+ | `onPluginAttach(callback)` | 插件附着 |
224
+ | `onPluginDetached(callback)` | 插件分离 |
225
+
226
+ ---
227
+
228
+ ## 14. 动态指令 (features)
229
+
230
+ | 方法 | 环境 | 说明 |
231
+ |------|------|------|
232
+ | `getFeatures(codes?)` | B | 获取动态指令 |
233
+ | `setFeature(feature)` | B | 注册动态指令 |
234
+ | `removeFeature(code)` | B | 删除动态指令 |
235
+
236
+ **DynamicFeatureInput**: `code`, `explain`, `icon`, `platform`, `mode`, `route`, `cmds`
237
+ **mode**: `'ui' | 'silent' | 'detached'`
238
+
239
+ ---
240
+
241
+ ## 15. 快捷键 (shortcut)
242
+
243
+ | 方法 | 环境 | 说明 |
244
+ |------|------|------|
245
+ | `register(accelerator)` | R/B | 注册全局快捷键 |
246
+ | `unregister(accelerator)` | R/B | 注销快捷键 |
247
+ | `unregisterAll()` | R/B | 注销所有快捷键 |
248
+ | `isRegistered(accelerator)` | R/B | 检查是否已注册 |
249
+ | `onTriggered(callback)` | R | 监听触发事件 |
250
+
251
+ **accelerator 格式**: `CommandOrControl+Shift+X`, `Alt+P`, `F12`
252
+
253
+ ---
254
+
255
+ ## 16. 权限 (permission)
256
+
257
+ | 方法 | 环境 | 说明 |
258
+ |------|------|------|
259
+ | `getStatus(type)` | R/B | 获取权限状态 |
260
+ | `request(type)` | R/B | 请求权限 |
261
+ | `canRequest(type)` | R/B | 是否可请求 |
262
+ | `openSystemSettings(type)` | R/B | 打开系统设置 |
263
+ | `isAccessibilityTrusted()` | R/B | macOS 辅助功能权限 |
264
+
265
+ **type**: `'accessibility' | 'screen' | 'camera' | 'microphone' | 'geolocation' | 'notifications' | 'contacts' | 'calendar'`
266
+
267
+ ---
268
+
269
+ ## 17. 安全存储 (security)
270
+
271
+ | 方法 | 环境 | 说明 |
272
+ |------|------|------|
273
+ | `isEncryptionAvailable()` | R/B | 检查加密可用性 |
274
+ | `encryptString(plainText)` | R/B | 加密字符串 → `Buffer` |
275
+ | `decryptString(encrypted)` | R/B | 解密字符串 → `string` |
276
+
277
+ ---
278
+
279
+ ## 18. 托盘 (tray)
280
+
281
+ | 方法 | 环境 | 说明 |
282
+ |------|------|------|
283
+ | `create(options)` | R/B | 创建托盘图标 |
284
+ | `destroy()` | R/B | 销毁托盘 |
285
+ | `setIcon(icon)` | R/B | 更新图标 |
286
+ | `setTooltip(tooltip)` | R/B | 设置提示 |
287
+ | `setTitle(title)` | R/B | 设置标题(macOS) |
288
+ | `exists()` | R/B | 检查是否存在 |
289
+
290
+ **TrayOptions**: `icon`, `tooltip`, `title`
291
+
292
+ ---
293
+
294
+ ## 19. 菜单 (menu)
295
+
296
+ | 方法 | 环境 | 说明 |
297
+ |------|------|------|
298
+ | `showContextMenu(items)` | R | 显示右键菜单 → `id | null` |
299
+
300
+ **MenuItemOptions**: `label`, `type`, `checked`, `enabled`, `id`, `submenu`
301
+
302
+ ---
303
+
304
+ ## 20. 网络状态 (network)
305
+
306
+ | 方法 | 环境 | 说明 |
307
+ |------|------|------|
308
+ | `isOnline()` | R/B | 检查是否在线 |
309
+ | `onOnline(callback)` | R | 网络恢复事件 |
310
+ | `onOffline(callback)` | R | 网络断开事件 |
311
+
312
+ ---
313
+
314
+ ## 21. 电源 (power)
315
+
316
+ | 方法 | 环境 | 说明 |
317
+ |------|------|------|
318
+ | `getSystemIdleTime()` | R/B | 获取空闲时间 |
319
+ | `getSystemIdleState(threshold)` | R/B | 获取空闲状态 |
320
+ | `isOnBatteryPower()` | R/B | 是否电池供电 |
321
+ | `getCurrentThermalState()` | R/B | 获取热状态(macOS) |
322
+ | `onSuspend / onResume` | R | 休眠/唤醒事件 |
323
+ | `onAC / onBattery` | R | 电源切换事件 |
324
+ | `onLockScreen / onUnlockScreen` | R | 锁屏事件 |
325
+
326
+ ---
327
+
328
+ ## 22. 媒体 (media)
329
+
330
+ | 方法 | 环境 | 说明 |
331
+ |------|------|------|
332
+ | `getAccessStatus(type)` | R/B | 获取权限状态 |
333
+ | `askForAccess(type)` | R/B | 请求权限 |
334
+ | `hasCameraAccess()` | R/B | 检查摄像头权限 |
335
+ | `hasMicrophoneAccess()` | R/B | 检查麦克风权限 |
336
+
337
+ **type**: `'camera' | 'microphone'`
338
+
339
+ ---
340
+
341
+ ## 23. 地理位置 (geolocation)
342
+
343
+ | 方法 | 环境 | 说明 |
344
+ |------|------|------|
345
+ | `getAccessStatus()` | R | 获取权限状态 |
346
+ | `requestAccess()` | R | 请求权限 |
347
+ | `canGetPosition()` | R | 是否可获取位置 |
348
+ | `openSettings()` | R | 打开系统设置 |
349
+ | `getCurrentPosition()` | R | 获取当前位置 → `GeolocationPosition` |
350
+
351
+ ---
352
+
353
+ ## 24. TTS 语音合成 (tts)
354
+
355
+ | 方法 | 环境 | 说明 |
356
+ |------|------|------|
357
+ | `speak(text, options?)` | R | 朗读文本 |
358
+ | `stop()` | R | 停止朗读 |
359
+ | `pause() / resume()` | R | 暂停/恢复 |
360
+ | `getVoices()` | R | 获取语音列表 |
361
+ | `isSpeaking()` | R | 是否正在朗读 |
362
+
363
+ **options**: `lang`, `rate`, `pitch`, `volume`
364
+
365
+ ---
366
+
367
+ ## 25. Host 调用 (host)
368
+
369
+ | 方法 | 环境 | 说明 |
370
+ |------|------|------|
371
+ | `invoke(pluginName, method, ...args)` | R | 调用插件后端方法 |
372
+ | `status(pluginName)` | R | 获取 Host 状态 |
373
+ | `restart(pluginName)` | R | 重启 Host 进程 |
374
+
375
+ ---
376
+
377
+ ## 26. Sharp 图像处理 (sharp)
378
+
379
+ | 方法 | 说明 |
380
+ |------|------|
381
+ | `sharp(input?, options?)` | 创建实例 |
382
+ | `.resize(w?, h?, opts?)` | 调整尺寸 |
383
+ | `.extract({ left, top, width, height })` | 裁剪区域 |
384
+ | `.rotate(angle?)` | 旋转 |
385
+ | `.flip() / .flop()` | 翻转 |
386
+ | `.blur(sigma?) / .sharpen()` | 模糊/锐化 |
387
+ | `.grayscale() / .negate()` | 灰度/反相 |
388
+ | `.modulate({ brightness, saturation, hue })` | 调整色彩 |
389
+ | `.composite(images)` | 合成 |
390
+ | `.png() / .jpeg() / .webp()` | 设置格式 |
391
+ | `.toBuffer()` | 输出 ArrayBuffer |
392
+ | `.toFile(path)` | 输出文件 |
393
+ | `.metadata()` | 获取元数据 |
394
+
395
+ ---
396
+
397
+ ## 27. FFmpeg 音视频 (ffmpeg)
398
+
399
+ | 方法 | 环境 | 说明 |
400
+ |------|------|------|
401
+ | `isAvailable()` | R | 检查是否已安装 |
402
+ | `getVersion()` | R | 获取版本 |
403
+ | `getPath()` | R | 获取可执行文件路径 |
404
+ | `download(onProgress?)` | R | 下载 FFmpeg |
405
+ | `run(args, onProgress?)` | R | 执行命令 → `{ promise, kill, quit }` |
406
+
407
+ ---
408
+
409
+ ## 28. InBrowser 自动化 (inbrowser)
410
+
411
+ | 方法 | 说明 |
412
+ |------|------|
413
+ | `.goto(url, headers?, timeout?)` | 导航 |
414
+ | `.click(selector) / .dblclick(selector)` | 点击 |
415
+ | `.input(selector, text) / .type(selector, text)` | 输入 |
416
+ | `.press(key, modifiers?)` | 按键 |
417
+ | `.hover(selector) / .focus(selector)` | 悬停/聚焦 |
418
+ | `.wait(ms) / .wait(selector)` | 等待 |
419
+ | `.evaluate(func, ...args)` | 执行脚本 |
420
+ | `.screenshot(target?, savePath?)` | 截图 |
421
+ | `.pdf(options?, savePath?)` | 导出 PDF |
422
+ | `.cookies(filter?)` | 获取 Cookie |
423
+ | `.setCookies(...) / .clearCookies()` | 设置/清除 Cookie |
424
+ | `.viewport(w, h)` | 设置视口 |
425
+ | `.show() / .hide() / .end()` | 窗口控制 |
426
+ | `.run(options?)` | 执行队列 |
427
+
428
+ ---
429
+
430
+ ## 环境标识说明
431
+
432
+ - **R** = 渲染进程可用 (`window.intools.xxx`)
433
+ - **B** = 插件后端可用 (`context.api.xxx`)
434
+ - **R/B** = 两者都可用
package/README.md CHANGED
@@ -141,6 +141,7 @@ my-plugin/
141
141
  ├── tsconfig.json # TypeScript 配置
142
142
  ├── vite.config.ts # Vite 配置
143
143
  ├── icon.png # 插件图标
144
+ ├── PLUGIN_API.md # API 参考文档
144
145
  ├── src/
145
146
  │ ├── main.ts # 后端逻辑(沙箱运行)
146
147
  │ ├── types/
@@ -166,6 +167,7 @@ my-plugin/
166
167
  ├── package.json
167
168
  ├── manifest.json
168
169
  ├── icon.png
170
+ ├── PLUGIN_API.md # API 参考文档
169
171
  └── src/
170
172
  └── main.ts
171
173
  ```
@@ -364,131 +366,35 @@ npm run build
364
366
  ### 插件 API
365
367
 
366
368
  插件在沙箱中运行,通过 `context.api` 访问各种 API。
367
- 完整类型请参考模板生成的 `src/types/intools.d.ts`。
368
369
 
369
- #### 剪贴板 API (clipboard)
370
+ > 📚 **完整 API 参考请查看 [`PLUGIN_API.md`](./PLUGIN_API.md)**
371
+ >
372
+ > 该文件会在创建插件时自动生成,包含全部 28 个 API 模块的详细说明。
370
373
 
371
- ```typescript
372
- const { clipboard } = context.api
373
-
374
- // 读取文本
375
- const text = clipboard.readText()
376
-
377
- // 写入文本
378
- await clipboard.writeText('Hello World')
379
-
380
- // 读取图片(返回 PNG Buffer)
381
- const imageBuffer = clipboard.readImage()
382
-
383
- // 写入图片
384
- clipboard.writeImage(imageData)
385
-
386
- // 读取文件列表
387
- const files = clipboard.readFiles()
388
- // 返回: [{ path, name, size, isDirectory }]
389
-
390
- // 获取剪贴板格式
391
- const format = clipboard.getFormat()
392
- // 返回: 'text' | 'image' | 'files' | 'empty'
393
- ```
394
-
395
- #### 通知 API (notification)
374
+ #### 常用 API 快速示例
396
375
 
397
376
  ```typescript
398
- const { notification } = context.api
377
+ // 剪贴板
378
+ const text = clipboard.readText()
379
+ await clipboard.writeText('Hello')
399
380
 
381
+ // 通知
400
382
  notification.show('操作成功')
401
383
  notification.show('发生错误', 'error')
402
- // type: 'info' | 'success' | 'warning' | 'error'
403
- ```
404
-
405
- #### 存储 API (storage)
406
-
407
- ```typescript
408
- const { storage } = context.api
409
-
410
- // 存储数据
411
- await storage.set('key', { foo: 'bar' })
412
384
 
413
- // 读取数据
385
+ // 存储
386
+ await storage.set('key', { data: 'value' })
414
387
  const data = await storage.get('key')
415
388
 
416
- // 删除数据
417
- await storage.remove('key')
418
- ```
419
-
420
- #### 网络 API (http)
421
-
422
- ```typescript
423
- const { http } = context.api
424
-
425
- // 完整请求
426
- const response = await http.request({
427
- url: 'https://api.example.com/data',
428
- method: 'POST',
429
- headers: { 'Authorization': 'Bearer token' },
430
- body: { key: 'value' },
431
- timeout: 5000
432
- })
433
-
434
- // 快捷方法
435
- await http.get(url, headers?)
436
- await http.post(url, body?, headers?)
437
- await http.put(url, body?, headers?)
438
- await http.delete(url, headers?)
439
- ```
440
-
441
- #### 窗口 API (window,仅 UI)
389
+ // 文件系统
390
+ const content = filesystem.readFile('/path/file.txt', 'utf-8')
391
+ filesystem.writeFile('/path/output.txt', 'content', 'utf-8')
442
392
 
443
- ```typescript
444
- const { window } = window.intools
445
-
446
- // 设置窗口大小
447
- await window.setSize(600, 400)
448
-
449
- // 隐藏窗口
450
- await window.hide()
451
- ```
393
+ // HTTP 请求
394
+ const response = await http.post('https://api.example.com', { key: 'value' })
452
395
 
453
- #### 输入 API (input,仅 UI)
454
-
455
- ```typescript
456
- const { input } = window.intools
457
-
458
- await input.hideMainWindowPasteText('Hello')
459
- await input.simulateKeyboardTap('A', 'cmd')
460
- ```
461
-
462
- #### 权限 API (permission,仅 UI)
463
-
464
- ```typescript
465
- const status = await window.intools?.permission?.getStatus('screen')
466
- ```
467
-
468
- #### 文件系统 API (filesystem)
469
-
470
- ```typescript
471
- const { filesystem } = context.api
472
-
473
- // 读写文件
474
- const buffer = filesystem.readFile('/path/to/file.png')
475
- const text = filesystem.readFile('/path/to/file.txt', 'utf-8')
476
- filesystem.writeFile('/path/to/output.txt', 'content', 'utf-8')
477
-
478
- // 文件操作
479
- filesystem.exists('/path')
480
- filesystem.unlink('/path')
481
- filesystem.mkdir('/path')
482
- filesystem.readdir('/path')
483
- filesystem.stat('/path')
484
- filesystem.copy(src, dest)
485
- filesystem.move(src, dest)
486
-
487
- // 路径工具
488
- filesystem.extname('/file.txt') // '.txt'
489
- filesystem.dirname('/path/file') // '/path'
490
- filesystem.basename('/path/file.txt') // 'file.txt'
491
- filesystem.join('/path', 'to', 'file')
396
+ // 对话框
397
+ const files = await dialog.showOpenDialog({ properties: ['openFile'] })
492
398
  ```
493
399
 
494
400
  ---
@@ -668,21 +574,34 @@ cd json-formatter
668
574
 
669
575
  **src/main.ts:**
670
576
  ```typescript
671
- module.exports = {
672
- async run(context: any) {
673
- const { clipboard, notification } = context.api
674
- const text = context.input || await clipboard.readText()
675
-
676
- try {
677
- const obj = JSON.parse(text)
678
- const formatted = JSON.stringify(obj, null, 2)
679
- await clipboard.writeText(formatted)
680
- notification.show('JSON 格式化成功')
681
- } catch (e) {
682
- notification.show('无效的 JSON', 'error')
577
+ interface PluginContext {
578
+ api: {
579
+ clipboard: {
580
+ readText: () => string
581
+ writeText: (text: string) => Promise<void>
683
582
  }
583
+ notification: {
584
+ show: (message: string, type?: string) => void
585
+ }
586
+ }
587
+ input?: string
588
+ }
589
+
590
+ export async function run(context: PluginContext) {
591
+ const { clipboard, notification } = context.api
592
+ const text = context.input || clipboard.readText()
593
+
594
+ try {
595
+ const obj = JSON.parse(text)
596
+ const formatted = JSON.stringify(obj, null, 2)
597
+ await clipboard.writeText(formatted)
598
+ notification.show('JSON 格式化成功')
599
+ } catch (e) {
600
+ notification.show('无效的 JSON', 'error')
684
601
  }
685
602
  }
603
+
604
+ export default { run }
686
605
  ```
687
606
 
688
607
  ### 示例 2:翻译插件(带 UI)
@@ -717,16 +636,16 @@ npm install
717
636
 
718
637
  **src/main.ts:**
719
638
  ```typescript
720
- module.exports = {
721
- onLoad() {
722
- console.log('翻译插件已加载')
723
- },
639
+ export function onLoad() {
640
+ console.log('翻译插件已加载')
641
+ }
724
642
 
725
- async run(context: any) {
726
- // UI 插件通常不需要在 run 中做太多事
727
- // 主要逻辑在 UI 中处理
728
- }
643
+ export async function run() {
644
+ // UI 插件通常不需要在 run 中做太多事
645
+ // 主要逻辑在 UI 中处理
729
646
  }
647
+
648
+ export default { onLoad, run }
730
649
  ```
731
650
 
732
651
  **src/ui/App.tsx:**
@@ -813,11 +732,3 @@ A: 修改 `manifest.json` 中的 `version` 字段,重新打包后安装即可
813
732
 
814
733
  A: 前端通过 `window.intools.shell` 调用系统能力;后端运行在沙箱中,仅能使用 `context.api` 暴露的接口。具体能力以 `intools.d.ts` 为准。
815
734
 
816
- ---
817
-
818
- ## 相关文档
819
-
820
- - [InTools 插件开发规范](../../docs/plugin-spec.md)
821
- - [InTools API 接口参考](../../docs/api-reference.md)
822
- - [Manifest 规范 v2](../../docs/manifest-v2.md)
823
- - [插件打包说明](../../docs/plugin-packaging.md)
@@ -55,4 +55,10 @@ async function createBasicProject(targetDir, name) {
55
55
  const mainTs = (0, basic_1.buildBasicMain)(name);
56
56
  fs.writeFileSync(path.join(targetDir, 'src/main.ts'), mainTs);
57
57
  console.log(chalk_1.default.green(' ✓ src/main.ts'));
58
+ // 复制 API 参考文档
59
+ const apiDocSrc = path.join(__dirname, '../../..', 'PLUGIN_API.md');
60
+ if (fs.existsSync(apiDocSrc)) {
61
+ fs.copyFileSync(apiDocSrc, path.join(targetDir, 'PLUGIN_API.md'));
62
+ console.log(chalk_1.default.green(' ✓ PLUGIN_API.md'));
63
+ }
58
64
  }
@@ -54,6 +54,12 @@ async function createReactProject(targetDir, name) {
54
54
  createBackendMain(targetDir, name);
55
55
  createReactUI(targetDir, name);
56
56
  createIntoolsTypes(targetDir);
57
+ // 复制 API 参考文档
58
+ const apiDocSrc = path.join(__dirname, '../../..', 'PLUGIN_API.md');
59
+ if (fs.existsSync(apiDocSrc)) {
60
+ fs.copyFileSync(apiDocSrc, path.join(targetDir, 'PLUGIN_API.md'));
61
+ console.log(chalk_1.default.green(' ✓ PLUGIN_API.md'));
62
+ }
57
63
  }
58
64
  function createReactManifest(targetDir, name) {
59
65
  const manifest = (0, react_1.buildReactManifest)(name);
@@ -98,7 +98,31 @@ async function startViteDevServer(cwd) {
98
98
  console.log(chalk_1.default.yellow('跳过 UI 开发服务器: 未找到 vite.config.ts'));
99
99
  return;
100
100
  }
101
+ // 每次启动开发模式都构建 UI
102
+ // 这样应用可以加载最新的插件 UI
103
+ console.log(chalk_1.default.blue('构建 UI...'));
104
+ await new Promise((resolve, reject) => {
105
+ const viteBuild = (0, child_process_1.spawn)('npx', ['vite', 'build'], {
106
+ cwd,
107
+ stdio: 'inherit',
108
+ shell: true
109
+ });
110
+ viteBuild.on('close', (code) => {
111
+ if (code === 0) {
112
+ console.log(chalk_1.default.green('✓ UI 构建完成: ui/'));
113
+ resolve();
114
+ }
115
+ else {
116
+ reject(new Error(`Vite 构建失败,退出码: ${code}`));
117
+ }
118
+ });
119
+ viteBuild.on('error', reject);
120
+ });
121
+ console.log();
101
122
  console.log(chalk_1.default.blue('启动 Vite 开发服务器...'));
123
+ console.log(chalk_1.default.gray(' 💡 提示: Vite 开发服务器提供 UI 预览,修改 UI 代码后'));
124
+ console.log(chalk_1.default.gray(' 在 InTools 中点击「刷新插件」或执行 npm run build 更新'));
125
+ console.log();
102
126
  viteProcess = (0, child_process_1.spawn)('npx', ['vite', '--host'], {
103
127
  cwd,
104
128
  stdio: 'inherit',
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "intools-cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "InTools 插件开发 CLI 工具",
5
5
  "main": "dist/index.js",
6
6
  "files": [
7
7
  "dist",
8
- "assets"
8
+ "assets",
9
+ "PLUGIN_API.md"
9
10
  ],
10
11
  "bin": {
11
12
  "intools": "dist/index.js"
@@ -28,4 +29,4 @@
28
29
  "@types/fs-extra": "^11.0.0",
29
30
  "typescript": "^5.0.0"
30
31
  }
31
- }
32
+ }