opencode-plugin-hub 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 meiyx7
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,271 @@
1
- # Temporary Holding Version
1
+ # opencode-plugin-hub
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ OpenCode 桌面版的插件管理器:在应用内部浏览社区精选插件、按 npm 搜索、安装与移除,不用手改 `opencode.json`。
4
+
5
+ > OpenCode Desktop plugin manager — browse community plugins, search npm, inspect README/downloads, install and update without editing JSON.
6
+
7
+ GitHub: <https://github.com/meiyx7/opencode-plugin-hub>
8
+
9
+ 入口:标题栏 **插件中心** Pill 或全局快捷键 `⌘⌥P` 打开独立弹窗;设置 → 插件中心 保留完整页面。
10
+
11
+ 搜索到插件之后可以点开详情,直接看它到底做什么:npm 周/月下载量、发布者、许可证、最新发布时间、README、项目主页、源码仓库、依赖和包体积都在同一个弹窗里,不用跳去 npm 页面猜。
12
+
13
+ ## 从 npm 安装
14
+
15
+ 包名:`opencode-plugin-hub`。发布后页面是 <https://www.npmjs.com/package/opencode-plugin-hub>。
16
+
17
+ 在 `~/.config/opencode/opencode.json` 的 `plugins` 里加一行:
18
+
19
+ ```json
20
+ {
21
+ "plugins": ["opencode-plugin-hub"]
22
+ }
23
+ ```
24
+
25
+ 然后完全退出 OpenCode 再打开。第一次安装时插件还没加载,不能用插件里的「彻底重启」,需要手动退出一次;之后就可以用标题栏 Pill、`⌘⌥P` 或设置页。
26
+
27
+ ## 入口放在哪
28
+
29
+ OpenCode 的 GUI 插件 SDK 目前没有提供左侧「主页 / 新建会话」同级的导航注册表,所以没法把插件中心直接插进那条列表里。现在用三种方式保证它随时可达:
30
+
31
+ | 入口 | 位置 | 打开形式 |
32
+ |---|---|---|
33
+ | 标题栏 Pill | 窗口顶部标题栏 | 独立 `x-large` 弹窗 |
34
+ | 快捷键 | 任意界面 | `⌘⌥P`(`mod+alt+p`),可在 设置 → 快捷键 里改 |
35
+ | 命令面板 | 命令面板搜「插件中心」 | 同一个独立弹窗 |
36
+ | 设置页 | 设置 → 插件中心 | 完整设置页面 |
37
+
38
+ 弹窗里保留了和设置页一致的紫渐变 Hero:说明文字和配置路径。统计合并到标签页(「已安装」标签带「可更新」数),打开配置 / 重载配置 / 彻底重启合并到标签页右侧的工具栏。只有大标题交给弹窗自己的标题栏,避免重复。标签栏做成 sticky,列表滚动时仍然能切换。弹窗最大约 980×600,内容在弹窗内滚动;想要更宽的空间就用设置页入口。
39
+
40
+ 如果以后 SDK 增加侧边栏导航注册表,可以把 Pill 换成真正的侧边栏同级项。
41
+
42
+ ## 关于「插件市场」的实际情况
43
+
44
+ OpenCode **没有官方插件市场**。官方只提供两种加载方式(配置文件里写 npm 包名、或往 `plugins/` 目录放文件)和一个手写的 [ecosystem 文档页](https://opencode.ai/docs/ecosystem),没有任何注册表接口、没有安装命令、也没有应用内商店。
45
+
46
+ 但社区有一个事实标准:**awesome-opencode** 这个 curated 列表,仓库里带了自动导出的 `dist/registry.json`(当前 198 条,其中 97 条是插件/MCP/主题)。这是唯一机器可读的 OpenCode 插件目录,本插件就以它为数据源。
47
+
48
+ 三条信息通道,按可信度排列:
49
+
50
+ | 来源 | 内容 | 能不能装 |
51
+ |---|---|---|
52
+ | 精选目录(registry.json) | 97 条人工筛选条目,带描述、分类、GitHub 地址 | 75 条可在应用内直接安装,其余 22 条只发布在 GitHub |
53
+ | npm 搜索 | 带 `opencode-plugin` 标签的包,约 3000 个 | 能,但没有筛选,噪音多 |
54
+ | 内置快照 | 上面 97 条的构建期副本,断网时兜底 | 同精选目录 |
55
+
56
+ ## 三个标签页
57
+
58
+ | 标签 | 说明 |
59
+ |---|---|
60
+ | 精选目录 | 社区 curated 列表,本地筛选(不打网络请求),可按类型过滤,标出可安装/仅 GitHub/已安装/可更新 |
61
+ | npm 搜索 | 直查 `keywords:opencode-plugin`,覆盖目录之外的长尾;显示周/月下载量、发布者、许可证,可按相关度、下载量或发布时间排序 |
62
+ | 已安装 | 读配置里的 `plugins` 数组,显示当前版本与最新版本,可查看详情、更新、移除 |
63
+
64
+ 每张卡片右侧都有操作区:`详情` 打开完整信息弹窗,`源码` / `主页` / `npm` 用系统浏览器打开,`安装` / `更新` / `移除` 直接改配置。卡片正文也可以点击(有键盘焦点支持)。
65
+
66
+ 安装 / 更新 / 移除成功后,提示条会提醒你点上方工具栏里的「彻底重启」;整个页面/弹窗只保留这一个常驻重启按钮,点一下就会退出应用、清掉旧的 `serve --service`,再自动打开。
67
+
68
+ 安装写入配置时刻意走 jsonc 单节点编辑,**保留你原有的注释、缩进和行序**。
69
+
70
+ ## 详情弹窗里有什么
71
+
72
+ 详情数据来自 npm registry 的完整 packument 和 downloads API,主进程查一次后缓存 10 分钟:
73
+
74
+ | 区域 | 内容 |
75
+ |---|---|
76
+ | 顶部 | 包名、最新版本、已安装版本、可更新/已废弃标记、一句话描述 |
77
+ | 统计 | 周下载、月下载、已发布版本数、解包体积与文件数 |
78
+ | 元信息 | 许可证、最新发布时间、首次发布时间、维护者、关键词 |
79
+ | 链接 | 项目主页、源码仓库(monorepo 会定位到子目录)、npm 页面、问题反馈 |
80
+ | README | 用应用自带的 Markdown 渲染器展示,图片、代码块、表格都保留;超长时截断到约 30k 字符 |
81
+ | 依赖 | 可折叠的依赖列表 |
82
+
83
+ README 是判断「这个插件具体干啥」最直接的来源。很多包的 npm 描述只有一句话,但 README 里会写清楚它监听什么、改哪些配置、需要什么权限。
84
+
85
+ **下载量是 npm 的统计,不是实际使用人数。** 它只能用来横向比较热度,不能当成精确安装量。
86
+
87
+ ## 搜索与详情的数据降级
88
+
89
+ - 搜索结果直接复用 npm search API 返回的 `downloads.weekly/monthly`,不额外发请求。
90
+ - 详情优先读完整 packument(包含 README)。超过 12MB 的包会退回只读 `/latest` manifest,此时没有 README 和发布时间。
91
+ - 下载量单独查 `api.npmjs.org/downloads/point`,查不到时显示 0,不影响详情其余部分。
92
+ - 详情查询失败会在弹窗里明确写出原因(404、网络错误、占位包没有发布版本等),不会伪装成空数据。
93
+
94
+ ## 版本检查与更新
95
+
96
+ 打开插件中心时会自动查一次 registry(只查已安装的插件,不查整个目录),也可以手动点「检查更新」。每个插件显示 `v当前 → v最新`,有新版本时出现「更新」按钮。结果在内存里缓存 5 分钟,重复切标签不会重复请求。
97
+
98
+ 两条更新路径是不一样的:
99
+
100
+ | 配置里的形态 | 更新方式 | 备份 |
101
+ |---|---|---|
102
+ | npm 包名(`foo` 或 `foo@1.2.3`) | 改配置为 `foo@<最新版>`,精确锁版本 | 不需要,旧版本仍在 npm 缓存里 |
103
+ | 本地目录(`/abs/path`) | 从 registry 下载 tarball 解包覆盖目录;若目录里有 `scripts/repatch.mjs`,自动用它重打补丁 | 目录同级生成 `<dir>.backup-<时间戳>`,失败自动还原 |
104
+
105
+ 本地目录这一路是为「从 npm 包复制出来再打补丁」的场景准备的(例如 `@magpie-community/opencode-trae-auth`)。两个细节:
106
+
107
+ - 目录里的真实包名和版本**从 `package.json` 读**,不是用文件夹名。所以已安装页显示的是 `@magpie-community/opencode-trae-auth v0.2.29`,而不是 `opencode-trae-auth`。
108
+ - 重打补丁时必须传 `--from <刚解包的目录>`。`repatch.mjs` 默认从 npm 缓存找源包,而缓存里还是旧版本,不加这个参数会用旧源把刚更新好的文件覆盖回去。
109
+
110
+ 判定「有新版本」用三段式数字比较,只认裸版本号:`^0.2.29`、`latest`、`1.x` 这类 range 不参与比较,避免把范围当成版本。
111
+
112
+ **查询失败不等于没有更新。** registry 会时不时返回 `ECONNRESET`(尤其连续请求后),如果把失败当成空结果,界面就会显示「全部已是最新」——这是错的。所以查不到时单独标记为「未能检查」,条目上直接写出来,汇总提示也会说「N 个插件未能检查」。只有 404 才算「这个包不存在」这种确定结论。
113
+
114
+ ## 包名是怎么确定的
115
+
116
+ `registry.json` 本身**不含 npm 包名**——只有 GitHub 地址和一段自由格式的安装说明。所以包名的确定方式是一套回退链:
117
+
118
+ 1. 从 `installation` 文本里抓 `"plugin": ["..."]`
119
+ 2. `displayName` 本身像包名时直接用
120
+ 3. 用仓库名
121
+ 4. 用 `@owner/repo`
122
+ 5. 上述的小写变体(npm scope 必须小写)
123
+
124
+ 每个候选都去 npm 实查,**优先选发布过 `latest` 的那个**。这一步很关键:`opencode-plugin-otel` 这种裸名在 npm 上存在,但只有 0 个版本(空壳占位),真身是 `@devtheops/opencode-plugin-otel`。不加这层判断就会装到一个装不上的包。
125
+
126
+ 核验结果在构建期固化进 `src/gui/registry-snapshot.json`,运行时零成本。目录更新后用 `npm run refresh` 重建。
127
+
128
+ ## 数据来源的降级链
129
+
130
+ ```
131
+ 网络(12 小时 TTL) → 本地缓存 ~/.cache/opencode/plugin-hub/registry.json → 内置快照
132
+ ```
133
+
134
+ 断网时页面不会空,只是顶部提示会显示来源是「内置快照」。点「更新目录」可强制跳过缓存。
135
+
136
+ ## 为什么装完要重启
137
+
138
+ OpenCode 在启动时对插件列表和 provider 模型目录做快照,改配置后运行中的进程不会重读。注意光关窗口不够,后台 `serve --service` 守护进程也要一起结束,而它经常比窗口活得久。
139
+
140
+ 插件中心里已经内置了「**彻底重启**」按钮(只在顶部工具栏里保留一个):
141
+
142
+ 1. 弹窗确认后,主进程启动一个 detached shell 脚本;
143
+ 2. 脚本先退出 OpenCode 桌面应用;
144
+ 3. 清理残留的 `serve --service`;
145
+ 4. 等进程真正退出后,用 `open -b ai.opencode.desktop` 重新拉起应用。
146
+
147
+ 所以正常流程是:安装 / 更新 / 移除插件 → 点上方工具栏里的「彻底重启」→ 确认 → 应用自动退出并重新打开,不需要再手敲命令。
148
+
149
+ 每次重启会往 `~/.cache/opencode/plugin-hub/restart.log` 追加时间、应用 PID、服务 PID 和当前步骤。自动重启没生效时,先看这个日志。
150
+
151
+ 脚本只在 macOS 上执行,且只对打包版 OpenCode 生效(按 `.app` 路径和 bundle id 识别)。如果自动重启失败,回退到手动方式:
152
+
153
+ ```bash
154
+ pkill -f "serve --service"
155
+ open -a OpenCode
156
+ ```
157
+
158
+ 第一次从旧版本升级到这个版本时,后台服务里还没有 `restart` 方法,需要手动彻底退出重开一次;之后就都可以用按钮了。
159
+
160
+ ## 安装(本地开发态)
161
+
162
+ ```bash
163
+ npm install
164
+ npm run build # 产出 dist/index.js + dist/gui-experimental.cjs
165
+ ```
166
+
167
+ 在 `~/.config/opencode/opencode.json` 的 `plugins` 里加目录的绝对路径:
168
+
169
+ ```json
170
+ {
171
+ "plugins": [
172
+ "opencode-qoder-bridge",
173
+ "/Users/you/code/opencode-plugin-hub"
174
+ ]
175
+ }
176
+ ```
177
+
178
+ 然后完全退出 OpenCode 再打开。
179
+
180
+ ## 开发
181
+
182
+ ```bash
183
+ npm run dev # vite build --watch
184
+ npm run refresh # 重建内置目录快照(会逐个查 npm,约 1-2 分钟)
185
+ ```
186
+
187
+ | 文件 | 职责 |
188
+ |---|---|
189
+ | `src/index.ts` | 服务端部分,只声明插件 id `plugin-hub` |
190
+ | `src/gui.tsx` | GUI 入口:设置页、标题栏 Pill、命令快捷键,统一打开弹窗或设置页 |
191
+ | `src/contract.ts` | 窗口与主进程的 IPC 契约(effect Schema),含搜索、详情、安装、更新等 |
192
+ | `src/gui/page.tsx` | UI(Solid):设置页与独立弹窗共用的三个标签页、卡片列表、详情弹窗、内联样式表 |
193
+ | `src/gui/admin.ts` | 主进程:读写配置、npm 搜索与详情、版本比对、更新(含目录插件)、打开链接/配置、reload |
194
+ | `src/gui/catalog.ts` | 主进程:拉取并降级解析社区目录 |
195
+ | `src/gui/registry-snapshot.json` | 构建期固化的目录快照,由 `npm run refresh` 生成 |
196
+ | `dist/index.js` | 服务端入口(npm 发布包使用) |
197
+ | `dist/gui-experimental.cjs` | GUI bundle(Vite 构建产物) |
198
+
199
+ 窗口进程是浏览器沙箱,读不了文件也打不开外链;所有 I/O 走 `main` + IPC。
200
+
201
+ ## 发布到 npm
202
+
203
+ 包名 `opencode-plugin-hub` 当前在 npm 上可用。注意:这台机器默认 registry 是 `registry.npmmirror.com`(淘宝镜像),**镜像不能发布**;`package.json` 的 `publishConfig.registry` 已经固定到官方 `registry.npmjs.org`,登录也要显式指定:
204
+
205
+ ```bash
206
+ npm config get registry # 当前大概率是 npmmirror
207
+ npm view opencode-plugin-hub version --registry=https://registry.npmjs.org/ # 404 = 名字可用
208
+ npm login --registry=https://registry.npmjs.org/
209
+ npm run typecheck
210
+ npm run build
211
+ npm pack --dry-run # 检查 tarball 内容
212
+ npm publish --access public # publishConfig 会把它发到 registry.npmjs.org
213
+ ```
214
+
215
+ 说明:
216
+
217
+ - `prepublishOnly` 会自动跑 `typecheck` + `build`;`dist/index.js` 是服务端入口,`dist/gui-experimental.cjs` 是 GUI bundle。
218
+ - `files` 只带 `dist`、`src`、`LICENSE`;`README.md`、`package.json` 由 npm 自动包含。
219
+ - `repository` / `homepage` / `bugs` 已指向 <https://github.com/meiyx7/opencode-plugin-hub>;如果你 fork 或转移仓库,记得同步改这三项。
220
+ - 如果 `opencode-plugin-hub` 被占用,改用带 scope 的名字,例如 `@your-name/opencode-plugin-hub`,同步改 `package.json` 的 `name` 和安装文档。
221
+ - 更新版本:`npm version patch`(或 `minor` / `major`),再 `npm publish`。
222
+ - 有 2FA 的账号发布时会提示输入一次性验证码。
223
+ - npm 发布是公开且难以撤回的,建议先 `npm pack`,在本地或测试机器上确认能装再发。
224
+ - 发布后用 `npm view opencode-plugin-hub version --registry=https://registry.npmjs.org/` 确认。npmmirror 是异步镜像,刚发布时可能还没同步;如果 OpenCode 通过镜像拉包暂时找不到,等几分钟或临时把 registry 指向官方 npm。
225
+
226
+ ### 后续版本:GitHub Actions + Trusted Publishing
227
+
228
+ `0.1.0` 已经手动发布。后续版本推荐用 Trusted Publishing,仓库里不存 `NPM_TOKEN`。
229
+
230
+ 先在 npm 配置 trusted publisher:
231
+
232
+ 1. 打开 <https://www.npmjs.com/package/opencode-plugin-hub/settings>
233
+ 2. **Trusted Publishing** → **Add a trusted publisher** → **GitHub Actions**
234
+ 3. 填:
235
+ - Organization or user: `meiyx7`
236
+ - Repository: `opencode-plugin-hub`
237
+ - Workflow filename: `publish.yml`
238
+ - Environment: 留空
239
+ 4. 保存
240
+
241
+ 之后发新版本:
242
+
243
+ ```bash
244
+ npm version patch
245
+ git push --follow-tags
246
+ ```
247
+
248
+ 然后在 GitHub 上为该 tag 创建 Release(或者在 Actions 里手动运行 **Publish to npm**)。`.github/workflows/publish.yml` 会用 `id-token: write` 和 `npm publish --provenance` 发布,不需要 `NPM_TOKEN`。
249
+
250
+ 注意:
251
+
252
+ - `package.json` 的 `version` 必须先 bump,且不能和 npm 上已有版本重复。
253
+ - 如果还没配置 Trusted Publishing 就运行 workflow,会发布失败。
254
+ - `.github/workflows/ci.yml` 会在 push / PR 时跑 typecheck 和 build。
255
+
256
+ ## 已知边界
257
+
258
+ - 只在 macOS 桌面版 2.2.5 上验证过。GUI Plugin SDK 仍是 experimental 接口,随时可能变。
259
+ - 精选目录来自社区维护的 awesome-opencode,**不是官方背书**,条目质量参差,装之前建议看一眼源码。
260
+ - 22 条只有 GitHub 发布,应用内装不了,只能点「源码」去看安装说明。
261
+ - 详情里的主页/仓库来自 npm 元数据。有些包(例如 `opencode-notify`)根本不填 `repository`,这时只能看 npm 页面和 README。
262
+ - 下载量来自 npm downloads API,统计的是 npm 安装/下载次数,不等于真实用户数。
263
+ - README 里可能包含外链图片(badge、截图),离线或被 CSP 拦截时不会显示,但不影响文字内容。
264
+ - 精选目录里的版本号是构建时的快照值;「可更新」判定用的是实时查到的 registry 版本,两者可能不一致。
265
+ - 目录插件的更新是覆盖式的:目录里自己手改的文件(除了 `package.json`、入口文件之外)如果被新版本同名文件覆盖,需要从 `.backup-*` 里取回。
266
+ - 本地目录插件的备份不会自动清理,确认新版稳定后可手动删掉 `<dir>.backup-*`。
267
+ - 不清理 `~/.cache/opencode/npm` 里的旧包,避免打断正在运行的插件。
268
+ - 不能移除插件中心自身。
269
+ - 「彻底重启」只在 macOS 上执行,依赖 `ps` / `kill` / `open`,并按 `.app` 路径和 bundle id `ai.opencode.desktop` 识别应用。开发态、绿色版或非标准安装路径可能识别不到,此时会提示你手动重启。
270
+ - 第一次从旧版本升级到带自动重启的版本时,后台服务里还没有 `restart` 方法,需要手动彻底退出一次;之后就能用按钮。
271
+ - 自动重启会关闭应用,正在运行的对话/任务会中断;会话通常会自动恢复,重新打开后可继续。