From 023e4c5514e2f4dcf82f63b8a88135c634c13b50 Mon Sep 17 00:00:00 2001 From: xintaofei Date: Sun, 12 Apr 2026 11:56:55 +0800 Subject: [PATCH] fix(acp): pin @latest for all plugins and enable button when only floating versions exist - install_missing_plugins now pins ALL @latest specs (not just newly installed) - When nothing is missing but @latest exists, the pin-only path runs - Modal button switches to 'Pin @latest Versions' when no missing plugins - Added pinVersions i18n key for 10 languages --- src-tauri/src/acp/opencode_plugins.rs | 49 ++++++++++++++++--- .../settings/opencode-plugins-modal.tsx | 10 +++- src/i18n/messages/ar.json | 1 + src/i18n/messages/de.json | 1 + src/i18n/messages/en.json | 1 + src/i18n/messages/es.json | 1 + src/i18n/messages/fr.json | 1 + src/i18n/messages/ja.json | 1 + src/i18n/messages/ko.json | 1 + src/i18n/messages/pt.json | 1 + src/i18n/messages/zh-CN.json | 1 + src/i18n/messages/zh-TW.json | 1 + 12 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src-tauri/src/acp/opencode_plugins.rs b/src-tauri/src/acp/opencode_plugins.rs index c8bb7d5..dc8a9ca 100644 --- a/src-tauri/src/acp/opencode_plugins.rs +++ b/src-tauri/src/acp/opencode_plugins.rs @@ -435,12 +435,44 @@ pub async fn install_missing_plugins( .collect(); if missing.is_empty() { - emit_plugin_event( - emitter, - &task_id, - PluginInstallEventKind::Completed, - "Nothing to install — all plugins are already present", - ); + // Nothing to install, but still pin any @latest specs + let all_specs: Vec<(String, String)> = summary + .plugins + .iter() + .map(|p| (p.name.clone(), p.declared_spec.clone())) + .collect(); + match pin_latest_specs(&summary.config_path, &summary.cache_dir, &all_specs) { + Ok(n) if n > 0 => { + emit_plugin_event( + emitter, + &task_id, + PluginInstallEventKind::Log, + format!("Pinned {n} @latest plugin(s) to installed versions in opencode.json"), + ); + emit_plugin_event( + emitter, + &task_id, + PluginInstallEventKind::Completed, + format!("Pinned {n} @latest plugin(s) — no missing plugins to install"), + ); + } + Err(e) => { + emit_plugin_event( + emitter, + &task_id, + PluginInstallEventKind::Failed, + format!("Failed to pin @latest versions: {e}"), + ); + } + _ => { + emit_plugin_event( + emitter, + &task_id, + PluginInstallEventKind::Completed, + "Nothing to install — all plugins are already present", + ); + } + } return Ok(()); } @@ -518,7 +550,10 @@ pub async fn install_missing_plugins( if exit_status.success() { // Pin @latest specs to actual installed versions to avoid // opencode hitting the npm registry on every startup. - let spec_pairs: Vec<(String, String)> = missing + // Pin ALL plugins (not just the ones we installed), so already-installed + // @latest plugins also get pinned. + let spec_pairs: Vec<(String, String)> = summary + .plugins .iter() .map(|p| (p.name.clone(), p.declared_spec.clone())) .collect(); diff --git a/src/components/settings/opencode-plugins-modal.tsx b/src/components/settings/opencode-plugins-modal.tsx index 90cd4af..30c7d8c 100644 --- a/src/components/settings/opencode-plugins-modal.tsx +++ b/src/components/settings/opencode-plugins-modal.tsx @@ -117,6 +117,10 @@ export function OpencodePluginsModal({ const missingCount = summary?.plugins.filter((p) => p.status === "missing").length ?? 0 + const floatingCount = + summary?.plugins.filter((p) => p.declared_spec.endsWith("@latest")) + .length ?? 0 + const hasActionablePlugins = missingCount > 0 || floatingCount > 0 return ( @@ -209,7 +213,7 @@ export function OpencodePluginsModal({