intools-cli 1.0.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 ADDED
@@ -0,0 +1,780 @@
1
+ # InTools CLI
2
+
3
+ InTools 插件开发的命令行工具,帮助你快速创建、调试、构建和打包插件。
4
+
5
+ ## 目录
6
+
7
+ - [安装](#安装)
8
+ - [快速开始](#快速开始)
9
+ - [命令参考](#命令参考)
10
+ - [插件开发指南](#插件开发指南)
11
+ - [项目结构](#项目结构)
12
+ - [manifest.json 配置](#manifestjson-配置)
13
+ - [开发模式](#开发模式)
14
+ - [使用第三方库](#使用第三方库)
15
+ - [插件 API](#插件-api)
16
+ - [构建与打包](#构建与打包)
17
+ - [完整示例](#完整示例)
18
+
19
+ ---
20
+
21
+ ## 安装
22
+
23
+ ```bash
24
+ # 全局安装
25
+ npm install -g intools-cli
26
+
27
+ # 或在项目中作为开发依赖
28
+ npm install -D intools-cli
29
+ ```
30
+
31
+ ---
32
+
33
+ ## 快速开始
34
+
35
+ ### 5 分钟创建你的第一个插件
36
+
37
+ ```bash
38
+ # 1. 创建插件项目
39
+ intools create my-plugin
40
+
41
+ # 2. 进入项目目录
42
+ cd my-plugin
43
+
44
+ # 3. 安装依赖
45
+ npm install
46
+
47
+ # 4. 启动开发模式
48
+ npm run dev
49
+
50
+ # 5. 构建插件
51
+ npm run build
52
+
53
+ # 6. 打包发布
54
+ npm run pack
55
+ ```
56
+
57
+ 执行完成后,你将得到一个 `my-plugin-1.0.0.inplugin` 文件,可以直接安装到 InTools 中。
58
+
59
+ ---
60
+
61
+ ## 命令参考
62
+
63
+ ### `intools create <name>`
64
+
65
+ 创建新的插件项目。
66
+
67
+ ```bash
68
+ # 创建 React 插件(默认,带 UI)
69
+ intools create my-plugin
70
+
71
+ # 创建基础插件(无 UI)
72
+ intools create my-plugin --template basic
73
+ ```
74
+
75
+ **选项:**
76
+
77
+ | 选项 | 说明 | 默认值 |
78
+ |------|------|--------|
79
+ | `-t, --template <type>` | 模板类型:`react` 或 `basic` | `react` |
80
+
81
+ ### `intools dev`
82
+
83
+ 启动开发模式,支持热重载。
84
+
85
+ ```bash
86
+ # 在插件目录中运行
87
+ intools dev
88
+
89
+ # 或通过 npm
90
+ npm run dev
91
+ ```
92
+
93
+ **功能:**
94
+ - 后端代码变化时自动重新构建
95
+ - 有 UI 的插件会自动启动 Vite 开发服务器
96
+ - 支持 sourcemap 便于调试
97
+
98
+ ### `intools build`
99
+
100
+ 构建插件,生成生产环境代码。
101
+
102
+ ```bash
103
+ intools build
104
+
105
+ # 或通过 npm
106
+ npm run build
107
+ ```
108
+
109
+ **输出:**
110
+ - 后端代码:`dist/main.js`(压缩后)
111
+ - UI 代码:`ui/` 目录
112
+
113
+ ### `intools pack`
114
+
115
+ 将插件打包成 `.inplugin` 文件,用于发布和安装。
116
+
117
+ ```bash
118
+ intools pack
119
+
120
+ # 或通过 npm
121
+ npm run pack
122
+ ```
123
+
124
+ **输出:** `<插件名>-<版本号>.inplugin`
125
+
126
+ > ⚠️ **注意:** 打包前请先运行 `intools build` 或 `npm run build`
127
+
128
+ ---
129
+
130
+ ## 插件开发指南
131
+
132
+ ### 项目结构
133
+
134
+ #### React 插件(默认模板)
135
+
136
+ ```
137
+ my-plugin/
138
+ ├── package.json # npm 配置
139
+ ├── manifest.json # 插件配置(核心文件)
140
+ ├── tsconfig.json # TypeScript 配置
141
+ ├── vite.config.ts # Vite 配置
142
+ ├── icon.png # 插件图标
143
+ ├── src/
144
+ │ ├── main.ts # 后端逻辑(沙箱运行)
145
+ │ ├── types/
146
+ │ │ └── intools.d.ts # API 类型定义
147
+ │ └── ui/ # React UI 源码
148
+ │ ├── index.html
149
+ │ ├── main.tsx
150
+ │ ├── App.tsx
151
+ │ └── styles.css
152
+ ├── dist/ # 后端构建输出
153
+ │ └── main.js
154
+ └── ui/ # UI 构建输出
155
+ ├── index.html
156
+ └── assets/
157
+ ```
158
+
159
+ #### 基础插件(无 UI)
160
+
161
+ ```
162
+ my-plugin/
163
+ ├── package.json
164
+ ├── manifest.json
165
+ ├── icon.png
166
+ └── src/
167
+ └── main.ts
168
+ ```
169
+
170
+ ---
171
+
172
+ ### manifest.json 配置
173
+
174
+ `manifest.json` 是插件的核心配置文件,定义了插件的基本信息和触发条件。
175
+
176
+ ```json
177
+ {
178
+ "name": "my-plugin",
179
+ "version": "1.0.0",
180
+ "displayName": "我的插件",
181
+ "description": "插件功能描述",
182
+ "main": "dist/main.js",
183
+ "ui": "ui/index.html",
184
+ "icon": "icon.png",
185
+ "features": [
186
+ {
187
+ "code": "main",
188
+ "explain": "主功能",
189
+ "cmds": [
190
+ { "type": "keyword", "value": "myplugin" }
191
+ ]
192
+ }
193
+ ]
194
+ }
195
+ ```
196
+
197
+ #### 顶层字段说明
198
+
199
+ | 字段 | 类型 | 必需 | 说明 |
200
+ |------|------|------|------|
201
+ | `name` | string | ✅ | 插件唯一标识(小写字母、数字、连字符) |
202
+ | `version` | string | ✅ | 语义化版本 (x.y.z) |
203
+ | `displayName` | string | ✅ | 用户看到的名称 |
204
+ | `description` | string | ✅ | 功能描述 |
205
+ | `main` | string | ✅ | 后端入口文件路径 |
206
+ | `ui` | string | ❌ | UI 文件路径(有界面时必填) |
207
+ | `icon` | string/object | ❌ | 插件图标 |
208
+ | `features` | array | ✅ | 功能入口列表 |
209
+ | `author` | string | ❌ | 作者名 |
210
+ | `homepage` | string | ❌ | 项目主页 |
211
+ | `minAppVersion` | string | ❌ | 最低 InTools 版本要求 |
212
+
213
+ #### 功能入口 (features)
214
+
215
+ 一个插件可以有多个功能入口,每个入口可以有不同的触发方式:
216
+
217
+ ```json
218
+ {
219
+ "features": [
220
+ {
221
+ "code": "format",
222
+ "explain": "格式化 JSON",
223
+ "cmds": [
224
+ { "type": "keyword", "value": "json" },
225
+ { "type": "keyword", "value": "格式化" },
226
+ { "type": "regex", "match": "^\\s*[{\\[]", "explain": "检测到 JSON" }
227
+ ]
228
+ },
229
+ {
230
+ "code": "minify",
231
+ "explain": "压缩 JSON",
232
+ "cmds": [
233
+ { "type": "keyword", "value": "json压缩" }
234
+ ]
235
+ }
236
+ ]
237
+ }
238
+ ```
239
+
240
+ | 字段 | 类型 | 必需 | 说明 |
241
+ |------|------|------|------|
242
+ | `code` | string | ✅ | 功能代码,传递给插件 |
243
+ | `explain` | string | ✅ | 功能说明,显示给用户 |
244
+ | `cmds` | array | ✅ | 触发命令列表 |
245
+
246
+ #### 触发命令类型 (cmds)
247
+
248
+ | type | 说明 | 额外字段 |
249
+ |------|------|----------|
250
+ | `keyword` | 关键词触发 | `value`: 关键词 |
251
+ | `regex` | 正则匹配 | `match`: 正则表达式, `explain`: 说明 |
252
+ | `files` | 文件类型 | `exts`: [".json", ".txt"] |
253
+ | `img` | 图片 | - |
254
+ | `over` | 选中文本 | - |
255
+
256
+ #### 图标配置
257
+
258
+ 支持三种格式:
259
+
260
+ ```json
261
+ // 1. 本地文件(推荐)
262
+ "icon": "icon.png"
263
+
264
+ // 2. URL
265
+ "icon": "https://example.com/icon.png"
266
+
267
+ // 3. 内联 SVG
268
+ "icon": "<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"...\"/></svg>"
269
+ ```
270
+
271
+ > 💡 **提示:** 未设置 `icon` 时,会自动尝试加载插件目录下的 `icon.png`
272
+
273
+ ---
274
+
275
+ ### 开发模式
276
+
277
+ #### 启动开发服务器
278
+
279
+ ```bash
280
+ npm run dev
281
+ ```
282
+
283
+ 开发模式会:
284
+ 1. **监听后端代码变化** - `src/main.ts` 及其依赖变化时自动重新构建
285
+ 2. **启动 Vite 开发服务器** - 有 UI 时自动启动,支持 HMR(热模块替换)
286
+
287
+ #### 在 InTools 中预览
288
+
289
+ 1. 打开 InTools 设置
290
+ 2. 添加开发目录(插件项目路径)
291
+ 3. 输入关键词触发插件
292
+
293
+ ---
294
+
295
+ ### 使用第三方库
296
+
297
+ InTools CLI 使用 **esbuild** 打包,会将所有依赖内联到 `dist/main.js` 中,因此你可以自由使用任何 npm 包。
298
+
299
+ #### 示例:使用 dayjs 处理日期
300
+
301
+ **1. 安装依赖**
302
+
303
+ ```bash
304
+ npm install dayjs
305
+ ```
306
+
307
+ **2. 在代码中使用**
308
+
309
+ ```typescript
310
+ // src/main.ts
311
+ import dayjs from 'dayjs'
312
+
313
+ module.exports = {
314
+ async run(context: any) {
315
+ const { clipboard, notification } = context.api
316
+ const text = context.input || await clipboard.readText()
317
+
318
+ // 使用 dayjs 格式化日期
319
+ const result = dayjs(text).format('YYYY-MM-DD HH:mm:ss')
320
+
321
+ await clipboard.writeText(result)
322
+ notification.show('日期格式化完成')
323
+ }
324
+ }
325
+ ```
326
+
327
+ **3. 构建**
328
+
329
+ ```bash
330
+ npm run build
331
+ ```
332
+
333
+ 构建后,`dayjs` 的代码会被内联到 `dist/main.js` 中,无需用户单独安装。
334
+
335
+ ---
336
+
337
+ ### 插件 API
338
+
339
+ 插件在沙箱中运行,通过 `context.api` 访问各种 API。
340
+
341
+ #### 剪贴板 API (clipboard)
342
+
343
+ ```typescript
344
+ const { clipboard } = context.api
345
+
346
+ // 读取文本
347
+ const text = clipboard.readText()
348
+
349
+ // 写入文本
350
+ await clipboard.writeText('Hello World')
351
+
352
+ // 读取图片(返回 PNG Buffer)
353
+ const imageBuffer = clipboard.readImage()
354
+
355
+ // 写入图片
356
+ clipboard.writeImage(imageData)
357
+
358
+ // 读取文件列表
359
+ const files = clipboard.readFiles()
360
+ // 返回: [{ path, name, size, isDirectory }]
361
+
362
+ // 获取剪贴板格式
363
+ const format = clipboard.getFormat()
364
+ // 返回: 'text' | 'image' | 'files' | 'empty'
365
+ ```
366
+
367
+ #### 通知 API (notification)
368
+
369
+ ```typescript
370
+ const { notification } = context.api
371
+
372
+ notification.show('操作成功')
373
+ notification.show('发生错误', 'error')
374
+ // type: 'info' | 'success' | 'warning' | 'error'
375
+ ```
376
+
377
+ #### 存储 API (storage)
378
+
379
+ ```typescript
380
+ const { storage } = context.api
381
+
382
+ // 存储数据
383
+ await storage.set('key', { foo: 'bar' })
384
+
385
+ // 读取数据
386
+ const data = await storage.get('key')
387
+
388
+ // 删除数据
389
+ await storage.remove('key')
390
+ ```
391
+
392
+ #### 网络 API (http)
393
+
394
+ ```typescript
395
+ const { http } = context.api
396
+
397
+ // 完整请求
398
+ const response = await http.request({
399
+ url: 'https://api.example.com/data',
400
+ method: 'POST',
401
+ headers: { 'Authorization': 'Bearer token' },
402
+ body: { key: 'value' },
403
+ timeout: 5000
404
+ })
405
+
406
+ // 快捷方法
407
+ await http.get(url, headers?)
408
+ await http.post(url, body?, headers?)
409
+ await http.put(url, body?, headers?)
410
+ await http.delete(url, headers?)
411
+ ```
412
+
413
+ #### 窗口 API (window)
414
+
415
+ ```typescript
416
+ const { window } = context.api
417
+
418
+ // 设置窗口大小
419
+ await window.setSize(600, 400)
420
+
421
+ // 隐藏窗口
422
+ await window.hide()
423
+ ```
424
+
425
+ #### 文件系统 API (filesystem)
426
+
427
+ ```typescript
428
+ const { filesystem } = context.api
429
+
430
+ // 读写文件
431
+ const buffer = filesystem.readFile('/path/to/file.png')
432
+ const text = filesystem.readFile('/path/to/file.txt', 'utf-8')
433
+ filesystem.writeFile('/path/to/output.txt', 'content', 'utf-8')
434
+
435
+ // 文件操作
436
+ filesystem.exists('/path')
437
+ filesystem.unlink('/path')
438
+ filesystem.mkdir('/path')
439
+ filesystem.readdir('/path')
440
+ filesystem.stat('/path')
441
+ filesystem.copy(src, dest)
442
+ filesystem.move(src, dest)
443
+
444
+ // 路径工具
445
+ filesystem.extname('/file.txt') // '.txt'
446
+ filesystem.dirname('/path/file') // '/path'
447
+ filesystem.basename('/path/file.txt') // 'file.txt'
448
+ filesystem.join('/path', 'to', 'file')
449
+ ```
450
+
451
+ ---
452
+
453
+ ### 插件 UI
454
+
455
+ #### 在 UI 中访问 API
456
+
457
+ UI 通过 `window.intools` 全局对象访问 API:
458
+
459
+ ```tsx
460
+ // src/ui/App.tsx
461
+ import { useEffect, useState } from 'react'
462
+
463
+ export default function App() {
464
+ const [input, setInput] = useState('')
465
+
466
+ // 接收插件初始化数据
467
+ useEffect(() => {
468
+ window.intools?.onPluginInit?.((data) => {
469
+ if (data.input) setInput(data.input)
470
+ })
471
+ }, [])
472
+
473
+ const handleProcess = async () => {
474
+ const result = input.toUpperCase()
475
+ // 复制到剪贴板
476
+ await window.intools?.clipboard?.writeText(result)
477
+ // 显示通知
478
+ window.intools?.notification?.show('已复制到剪贴板')
479
+ }
480
+
481
+ return (
482
+ <div>
483
+ <textarea value={input} onChange={(e) => setInput(e.target.value)} />
484
+ <button onClick={handleProcess}>处理</button>
485
+ </div>
486
+ )
487
+ }
488
+ ```
489
+
490
+ #### 主题适配
491
+
492
+ 插件 UI 应跟随 InTools 主题:
493
+
494
+ ```tsx
495
+ // 获取初始主题
496
+ function getInitialTheme(): 'light' | 'dark' {
497
+ const params = new URLSearchParams(window.location.search)
498
+ return (params.get('theme') as 'light' | 'dark') || 'light'
499
+ }
500
+
501
+ // 监听主题变化
502
+ useEffect(() => {
503
+ window.intools?.onThemeChange?.((theme) => {
504
+ document.documentElement.classList.toggle('dark', theme === 'dark')
505
+ })
506
+ }, [])
507
+ ```
508
+
509
+ ---
510
+
511
+ ### 生命周期钩子
512
+
513
+ 插件支持生命周期钩子函数:
514
+
515
+ ```typescript
516
+ module.exports = {
517
+ // 插件加载时调用
518
+ onLoad() {
519
+ console.log('插件已加载')
520
+ },
521
+
522
+ // 插件卸载时调用
523
+ onUnload() {
524
+ console.log('插件即将卸载')
525
+ },
526
+
527
+ // 插件启用时调用
528
+ onEnable() {
529
+ console.log('插件已启用')
530
+ },
531
+
532
+ // 插件禁用时调用
533
+ onDisable() {
534
+ console.log('插件已禁用')
535
+ },
536
+
537
+ // 主执行函数
538
+ async run(context) {
539
+ // 插件主逻辑
540
+ }
541
+ }
542
+ ```
543
+
544
+ | 钩子 | 触发时机 | 用途 |
545
+ |------|----------|------|
546
+ | `onLoad` | 插件加载时 | 初始化资源、注册服务 |
547
+ | `onUnload` | 插件卸载时 | 清理资源、保存状态 |
548
+ | `onEnable` | 插件启用时 | 恢复服务、重新注册 |
549
+ | `onDisable` | 插件禁用时 | 暂停服务、释放资源 |
550
+
551
+ ---
552
+
553
+ ## 构建与打包
554
+
555
+ ### 构建流程
556
+
557
+ ```bash
558
+ # 构建生产版本
559
+ npm run build
560
+ ```
561
+
562
+ 构建命令会:
563
+ 1. 使用 esbuild 打包后端代码到 `dist/main.js`(压缩)
564
+ 2. 使用 Vite 构建 UI 到 `ui/` 目录(如果有 UI)
565
+
566
+ ### 打包发布
567
+
568
+ ```bash
569
+ # 打包成 .inplugin 文件
570
+ npm run pack
571
+ ```
572
+
573
+ 生成的 `.inplugin` 文件实际上是 ZIP 格式,包含:
574
+
575
+ ```
576
+ my-plugin-1.0.0.inplugin
577
+ ├── manifest.json # 插件配置
578
+ ├── main.js # 打包后的后端代码
579
+ ├── icon.png # 图标(可选)
580
+ └── ui/ # UI 资源(可选)
581
+ ├── index.html
582
+ └── assets/
583
+ ```
584
+
585
+ ### 安装插件
586
+
587
+ 用户可以通过以下方式安装 `.inplugin` 文件:
588
+
589
+ 1. **双击安装** - 直接双击 `.inplugin` 文件
590
+ 2. **拖拽安装** - 将文件拖入 InTools 窗口
591
+ 3. **命令安装** - `intools install ./my-plugin.inplugin`
592
+
593
+ ---
594
+
595
+ ## 完整示例
596
+
597
+ ### 示例 1:JSON 格式化插件(无 UI)
598
+
599
+ ```bash
600
+ intools create json-formatter --template basic
601
+ cd json-formatter
602
+ ```
603
+
604
+ **manifest.json:**
605
+ ```json
606
+ {
607
+ "name": "json-formatter",
608
+ "version": "1.0.0",
609
+ "displayName": "JSON 格式化",
610
+ "description": "格式化或压缩 JSON 数据",
611
+ "main": "dist/main.js",
612
+ "icon": "<svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M5 3h2v2H5v5a2 2 0 01-2 2 2 2 0 012 2v5h2v2H5c-1.1 0-2-.9-2-2v-4a2 2 0 00-2-2H0v-2h1a2 2 0 002-2V5a2 2 0 012-2zm14 0a2 2 0 012 2v4a2 2 0 002 2h1v2h-1a2 2 0 00-2 2v4a2 2 0 01-2 2h-2v-2h2v-5a2 2 0 012-2 2 2 0 01-2-2V5h-2V3h2z\"/></svg>",
613
+ "features": [
614
+ {
615
+ "code": "format",
616
+ "explain": "格式化 JSON",
617
+ "cmds": [
618
+ { "type": "keyword", "value": "json" },
619
+ { "type": "regex", "match": "^\\s*[{\\[]", "explain": "检测到 JSON" }
620
+ ]
621
+ }
622
+ ]
623
+ }
624
+ ```
625
+
626
+ **src/main.ts:**
627
+ ```typescript
628
+ module.exports = {
629
+ async run(context: any) {
630
+ const { clipboard, notification } = context.api
631
+ const text = context.input || await clipboard.readText()
632
+
633
+ try {
634
+ const obj = JSON.parse(text)
635
+ const formatted = JSON.stringify(obj, null, 2)
636
+ await clipboard.writeText(formatted)
637
+ notification.show('JSON 格式化成功')
638
+ } catch (e) {
639
+ notification.show('无效的 JSON', 'error')
640
+ }
641
+ }
642
+ }
643
+ ```
644
+
645
+ ### 示例 2:翻译插件(带 UI)
646
+
647
+ ```bash
648
+ intools create translator
649
+ cd translator
650
+ npm install
651
+ ```
652
+
653
+ **manifest.json:**
654
+ ```json
655
+ {
656
+ "name": "translator",
657
+ "version": "1.0.0",
658
+ "displayName": "快速翻译",
659
+ "description": "中英文互译",
660
+ "main": "dist/main.js",
661
+ "ui": "ui/index.html",
662
+ "features": [
663
+ {
664
+ "code": "translate",
665
+ "explain": "翻译文本",
666
+ "cmds": [
667
+ { "type": "keyword", "value": "fy" },
668
+ { "type": "keyword", "value": "翻译" }
669
+ ]
670
+ }
671
+ ]
672
+ }
673
+ ```
674
+
675
+ **src/main.ts:**
676
+ ```typescript
677
+ module.exports = {
678
+ onLoad() {
679
+ console.log('翻译插件已加载')
680
+ },
681
+
682
+ async run(context: any) {
683
+ // UI 插件通常不需要在 run 中做太多事
684
+ // 主要逻辑在 UI 中处理
685
+ }
686
+ }
687
+ ```
688
+
689
+ **src/ui/App.tsx:**
690
+ ```tsx
691
+ import { useEffect, useState } from 'react'
692
+
693
+ export default function App() {
694
+ const [input, setInput] = useState('')
695
+ const [output, setOutput] = useState('')
696
+ const [loading, setLoading] = useState(false)
697
+
698
+ useEffect(() => {
699
+ window.intools?.onPluginInit?.((data) => {
700
+ if (data.input) setInput(data.input)
701
+ })
702
+ }, [])
703
+
704
+ const handleTranslate = async () => {
705
+ if (!input.trim()) return
706
+
707
+ setLoading(true)
708
+ try {
709
+ // 调用翻译 API
710
+ const response = await fetch('https://api.translate.com/v1/translate', {
711
+ method: 'POST',
712
+ headers: { 'Content-Type': 'application/json' },
713
+ body: JSON.stringify({ text: input, from: 'auto', to: 'en' })
714
+ })
715
+ const data = await response.json()
716
+ setOutput(data.translation)
717
+ } catch (error) {
718
+ window.intools?.notification?.show('翻译失败', 'error')
719
+ } finally {
720
+ setLoading(false)
721
+ }
722
+ }
723
+
724
+ const handleCopy = async () => {
725
+ await window.intools?.clipboard?.writeText(output)
726
+ window.intools?.notification?.show('已复制')
727
+ }
728
+
729
+ return (
730
+ <div className="app">
731
+ <div className="titlebar">快速翻译</div>
732
+ <div className="container">
733
+ <textarea
734
+ value={input}
735
+ onChange={(e) => setInput(e.target.value)}
736
+ placeholder="输入要翻译的文本..."
737
+ />
738
+ <button onClick={handleTranslate} disabled={loading}>
739
+ {loading ? '翻译中...' : '翻译'}
740
+ </button>
741
+ <textarea
742
+ value={output}
743
+ readOnly
744
+ placeholder="翻译结果..."
745
+ />
746
+ {output && <button onClick={handleCopy}>复制结果</button>}
747
+ </div>
748
+ </div>
749
+ )
750
+ }
751
+ ```
752
+
753
+ ---
754
+
755
+ ## 常见问题
756
+
757
+ ### Q: 如何调试插件?
758
+
759
+ A: 使用 `npm run dev` 启动开发模式,后端代码支持 sourcemap。可以在 InTools 的开发者工具中查看日志和调试。
760
+
761
+ ### Q: 为什么我的第三方库不能用?
762
+
763
+ A: 确保依赖已安装(`npm install`)并且使用 `npm run build` 构建。CLI 会自动将依赖打包到 `dist/main.js` 中。
764
+
765
+ ### Q: 如何更新已安装的插件?
766
+
767
+ A: 修改 `manifest.json` 中的 `version` 字段,重新打包后安装即可。InTools 会检测版本变化并更新。
768
+
769
+ ### Q: 插件可以访问系统命令吗?
770
+
771
+ A: 出于安全考虑,默认不开放 `shell` 权限。如需使用,请在 `manifest.json` 的 `permissions` 中声明,并等待审核。
772
+
773
+ ---
774
+
775
+ ## 相关文档
776
+
777
+ - [InTools 插件开发规范](../../docs/plugin-spec.md)
778
+ - [InTools API 接口参考](../../docs/api-reference.md)
779
+ - [Manifest 规范 v2](../../docs/manifest-v2.md)
780
+ - [插件打包说明](../../docs/plugin-packaging.md)