@justsilver/opencode-providers 0.3.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -7,6 +7,20 @@
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.1] - 2026-10-07
11
+
12
+ ### Fixed
13
+
14
+ - **`/connect-providers` 强制刷新后列表不更新**:`doRefresh` 刷新成功只调了
15
+ `ctx.data.location.integration.invalidate()`,而 `invalidate` 仅删除 sync 标记、**不会重新拉取**,`list()`
16
+ 读到的仍是旧的客户端缓存(此时服务端其实已注册新供应商)→ 重开的弹窗还是旧列表。
17
+ 改用与其它操作一致的 `reloadIntegrations()`(`invalidate` + `await sync`),刷新后重开的列表与服务端
18
+ `/api/integration` 一致。证据:`packages/client/src/solid/data.ts` 的 `locationResource`
19
+ (`list` 读 store、`sync` 才 `sync.run` 拉取、`invalidate` 只 `sync.invalidate`)
20
+ - **`/connect-providers` 刷新进度模态看不到**:`refreshWithProgress` 用 `void` 打开 `dialog.alert` 后
21
+ 在 `finally` 里立即 `clear()`,刷新一返回就把模态抹掉(快则一帧都看不到)。改为刷新期间不再自行 `clear`:
22
+ 列表路径由重开的列表弹窗顶替模态,空态路径(无后续弹窗)显式 `clear`,模态在整个刷新期间保持可见
23
+
10
24
  ## [0.3.0] - 2026-10-07
11
25
 
12
26
  ### Added
@@ -136,7 +150,8 @@
136
150
  - 插件源码从 `.opencode/plugins/opencode-providers/` 移到 `plugin/opencode-providers/`:仓库自身不再是插件发现根,避免在仓库里跑 opencode 时与全局安装的同 id 副本相撞(`Duplicate plugin ID` → 面板里一条 `failed`)
137
151
  - 安装后**通常无需重启**(插件目录被文件监视热重载),不再要求 `opencode service restart`
138
152
 
139
- [Unreleased]: https://github.com/Just-Silver/opencode-providers/compare/v0.3.0...HEAD
153
+ [Unreleased]: https://github.com/Just-Silver/opencode-providers/compare/v0.3.1...HEAD
154
+ [0.3.1]: https://github.com/Just-Silver/opencode-providers/releases/tag/v0.3.1
140
155
  [0.3.0]: https://github.com/Just-Silver/opencode-providers/releases/tag/v0.3.0
141
156
  [0.1.0]: https://github.com/Just-Silver/opencode-providers/releases/tag/v0.1.0
142
157
  [0.1.0-beta.2]: https://github.com/Just-Silver/opencode-providers/releases/tag/v0.1.0-beta.2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justsilver/opencode-providers",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "Register providers missing from the models.dev catalog in OpenCode V2 from a self-hosted registry — no opencode.json needed",
6
6
  "license": "MIT",
@@ -40,7 +40,10 @@ export async function connectProviders(ctx: Context): Promise<void> {
40
40
  label: { confirm: "Force refresh" },
41
41
  })
42
42
  if (confirmed) {
43
- if (await refreshWithProgress(ctx)) {
43
+ const ok = await refreshWithProgress(ctx)
44
+ // No dialog follows this branch, so close the refresh modal ourselves.
45
+ ctx.ui.dialog.clear()
46
+ if (ok) {
44
47
  ctx.ui.toast.show({
45
48
  variant: "info",
46
49
  message: "Reloaded. Run /connect-providers again to connect a provider.",
@@ -88,21 +91,17 @@ export async function connectProviders(ctx: Context): Promise<void> {
88
91
  }
89
92
 
90
93
  /**
91
- * Re-fetch the registry behind a blocking modal, then drop the modal.
94
+ * Show the "Refreshing registry…" modal and force a refresh.
92
95
  *
93
- * `dialog.alert` is the only JSX-free primitive that actually blocks: while it
94
- * is open the host pushes the `modal` keymap mode, so the prompt (and therefore
95
- * `/connect-providers` and the `ctrl+r` binding that lives on the list dialog)
96
- * is unreachable. The modal has `ok`/`esc` affordances, but we always close it
97
- * ourselves in `finally` — the user never has to.
96
+ * The modal is intentionally **not** cleared here: clearing it the moment the
97
+ * refresh resolves raced the renderer and turned it into a sub-frame flash the
98
+ * user never sees. The caller closes it explicitly (the empty state, which opens
99
+ * no follow-up dialog) or lets the reopened dialog replace it (the list state),
100
+ * so it stays up for the whole refresh.
98
101
  */
99
102
  async function refreshWithProgress(ctx: Context): Promise<boolean> {
100
103
  void ctx.ui.dialog.alert({ title: "Connect providers", message: "Refreshing registry…" })
101
- try {
102
- return await forceRefresh(ctx)
103
- } finally {
104
- ctx.ui.dialog.clear()
105
- }
104
+ return forceRefresh(ctx)
106
105
  }
107
106
 
108
107
  /**
@@ -134,7 +133,10 @@ async function doRefresh(ctx: Context): Promise<boolean> {
134
133
  ctx.ui.toast.show({ variant: "error", message: `Registry refresh failed: ${detail}` })
135
134
  return false
136
135
  }
137
- ctx.data.location.integration.invalidate(ctx.location)
136
+ // `invalidate` alone only drops the sync marker — it does not refetch, so
137
+ // `list()` would keep returning the stale integrations. `reloadIntegrations`
138
+ // also awaits the sync, so the reopened list shows the freshly registered set.
139
+ await reloadIntegrations(ctx)
138
140
  ctx.ui.toast.show({
139
141
  variant: "success",
140
142
  message: `Registry refreshed: ${result.providers ?? 0} providers, ${result.models ?? 0} models`,