资讯详情

资讯详情

Warp 通知插件更新流程(Plugin Update Flow)设计与实现:从安装提示到自动更新提示的完整演进

桌面应用开发者工具人工智能AI 应用AI Agent代码智能体【免费下载链接】warpWarp is an agentic development environment, born out of the terminal.项目地址https://gitcode.com/GitHub_Trending/wa/warp点击查看免费下载本文围绕 Warpagentic development environment仓库中specs/APP-3661的产品与技术规格系统讲解 Warp 如何为 Claude Code 通知插件设计并落地一套完整的插件版本检测 → 更新提示 → 自动/手动更新闭环流程。你将掌握为什么 Claude Code 原生的插件更新机制不可靠、Warp 如何借助SessionStart事件中的plugin_version字段判断插件是否过期、更新 Chip 与安装 Chip 的 8 条出现规则、本地一键自动更新与 SSH/失败场景下的手动更新命令以及这套流程在app/src中的具体源码实现与测试策略。背景Claude Code 的插件更新机制为什么不可靠Warp 为 Claude Code 提供了一个通知插件Warp notification plugin仓库位于warpdotdev/claude-code-warp。当 Warp 发布插件新版本如 v2.0.0时存量用户例如仍停留在 v1.1.0不会自动收到更新——因为 Claude Code 自身的插件更新系统并不可靠。specs/APP-3661/PRODUCT.md明确指出这正是本次产品规格要解决的原始问题We need Warp to detect outdated plugin versions and prompt users to update.也就是说Warp 需要在插件侧主动承担检测过期版本并引导用户升级的责任而不是寄希望于 Claude Code 自动完成。整个 APP-3661 的设计目标可以概括为两件事检测确定用户当前安装的插件版本是否低于 Warp 要求的最低版本引导在 CLI agent footer底部工具栏中给出与未安装提示同等醒目程度的需要更新提示并支持一键自动更新或手动更新两条路径。现状梳理Install Chip 的既有行为在引入更新流程之前Warp 的 footer 中只有一个绿色的安装提示install chip。specs/APP-3661/PRODUCT.md对其行为总结如下本地会话插件未安装时绿色 chip 出现点击后自动执行安装auto-installSSH 会话或此前安装失败点击 chip 会打开一个包含手动安装步骤的 modal插件已连接active或已安装chip 隐藏用户关闭过 chipchip 隐藏。关键在于这套逻辑里没有过期outdated这一概念。一个停留在 v1.1.0 的用户永远不会看到任何更新提示即使新版本已经发布。这就是新规格要填补的空缺。新行为总览Update Chip当插件已安装但版本过旧时footer 会出现一个更新 chip规格中定义如下属性值标签LabelUpdate Warp plugin悬浮提示TooltipA new version of the Warp plugin is available样式与安装 chip 相同的绿色样式 关闭X按钮本地会话点击自动执行更新auto-updateSSH 会话或自动更新失败后点击打开包含手动更新步骤的 modal更新 chip 与安装 chip占据同一位置且互斥出现The update chip replaces the install chip in the same position — they never appear simultaneously。版本检测机制plugin_version 字段与最小版本常量更新的核心前提是知道用户装的是哪个版本。规格给出的方案非常轻量The plugin reports its own version via aplugin_versionfield in theSessionStartevent when it connects. Warp compares this against a minimum required version.即插件在连接时通过SessionStart事件上报自身版本号Warp 拿到后与最低要求版本比较。这套机制对本地和远程会话一视同仁因为版本来自插件自报不需要访问远端文件系统。而缺失plugin_version的插件早于版本上报能力的旧构建一律视为过期。在源码app/src/terminal/cli_agent_sessions/plugin_manager/claude.rs中最低版本被定义为常量// Keep in sync with the plugin version in warpdotdev/claude-code-warp. // (See the Versioning section of that repos README.) const MINIMUM_PLUGIN_VERSION: str 2.1.0;注意产品规格撰写时的初始值为2.0.0而当前仓库中已演进为2.1.0。规格明确要求该常量与插件仓库的版本保持同步并在两端各留一条互指注释常量旁的注释指向插件仓库插件仓库 README 中也要有对应说明。版本比较通过compare_versions()完成位于app/src/terminal/cli_agent_sessions/plugin_manager/mod.rs/// Compares two X.Y.Z version strings. /// Returns Ordering::Less if a b, etc. /// Unparseable components are treated as 0. pub(crate) fn compare_versions(a: str, b: str) - Ordering { let parse |s: str| - [u64; 3] { let mut parts s.splitn(3, .); let major parts.next().and_then(|p| p.parse().ok()).unwrap_or(0); let minor parts.next().and_then(|p| p.parse().ok()).unwrap_or(0); let patch parts.next().and_then(|p| p.parse().ok()).unwrap_or(0); [major, minor, patch] }; parse(a).cmp(parse(b)) }实现要点仅解析X.Y.Z三段各段按整数比较解析失败的段按 0 处理因此畸形版本字符串不会引发 panic而是得到一个保守的比较结果。Chip 出现的完整决策矩阵8 条规则specs/APP-3661/PRODUCT.md给出了决定显示哪个 chip / 不显示 chip的完整规则表这是整个产品逻辑的核心骨架逐条列出如下插件已连接版本 最低版本 →无 chip插件已连接版本 最低版本或未上报版本 →更新 chip新增插件未连接本地未安装 →安装 chip既有行为插件未连接本地已安装磁盘上版本过期 →更新 chip针对太老、无法发送结构化事件的插件的文件系统兜底插件未连接本地已安装磁盘上版本最新 →无 chip等待连接远程会话无 listener →安装 chip远程无法检查文件系统刚刚完成安装/更新 →无 chip在收到下一次SessionStart前假定为最新版本针对当前版本已关闭 chip →无 chip源码落地plugin_chip_kind() 的三层检测这套矩阵在 footer 中被实现为plugin_chip_kind()位于app/src/ai/blocklist/agent_view/agent_input_footer/mod.rs。从源码结构看其判定逻辑分为三层第一层连接后的版本检测主路径本地与远程通用if session.supports_rich_status() manager.supports_update() { let needs_update match session.plugin_version { // No version reported pre-versioning plugin, definitely outdated. None true, Some(v) compare_versions(v, min_version).is_lt(), }; if !needs_update { return None; } // Check update chip dismissal. let dismissed_version ai_settings.plugin_update_chip_dismissed_version(chip_key); if !dismissed_version.is_empty() compare_versions(dismissed_version, min_version).is_ge() { return None; } return Some(PluginChipKind::Update); }对应规则 1、2、8listener 已连接且插件支持版本上报时plugin_version为None插件早于版本上报能力或低于最低版本 → 更新 chip已连接且版本达标 → 无 chip当前最低版本已被用户关闭过 → 无 chip。第二层连接前的文件系统兜底仅本地if manager.is_installed() { // Installed but no listener yet. Check the on-disk version as a fallback // — the plugin may be too old to send structured events. if manager.needs_update() { ... return Some(PluginChipKind::Update); } // Up to date on disk — wait for the listener to connect. return None; }对应规则 4、5无 listener、本地已安装、磁盘版本过期 → 更新 chip磁盘版本最新 → 无 chip等待连接。第三层未安装与远程// For remote sessions, we cant check the filesystem. if session.is_remote() { return (!install_chip_dismissed).then_some(PluginChipKind::Install); } ... // Not installed locally. (!install_chip_dismissed).then_some(PluginChipKind::Install)对应规则 3、6未安装或远程会话 → 安装 chip。此外还有若干总开关前置条件操作进行中plugin_operation_in_progress、共享 ambient agent 会话、HOANotifications功能标志未开启、show_agent_notifications设置关闭时一律不显示任何 chip。footer 还引入了一个 3 秒的防抖窗口PLUGIN_CHIP_DEBOUNCE给插件时间完成连接并发出SessionStart事件避免安装 chip 在插件即将上报版本时提前闪现。文件系统兜底needs_update()needs_update()用于插件太老、连结构化事件都不会发的场景定义在app/src/terminal/cli_agent_sessions/plugin_manager/claude.rsfn needs_update(self) - bool { let Ok(claude_dir) claude_home_dir() else { return false; }; match installed_version(claude_dir) { Some(v) compare_versions(v, MINIMUM_PLUGIN_VERSION).is_lt(), // No version field means very old plugin. None check_installed(claude_dir), } }它读取 Claude 的plugins/installed_plugins.json路径通过claude_home_dir()解析优先CLAUDE_CONFIG_DIR环境变量回退到~/.claude见claude_home_dir()的实现注释——必须与claude plugin install实际写入的目录一致否则检测会读到错误的目录条目存在且有版本字段 → 与MINIMUM_PLUGIN_VERSION比较低于则返回true条目存在但无版本字段非常老的插件→ 只要安装了就视为需要更新未安装 → 返回false此时应由安装 chip 负责。读取版本的具体实现installed_plugin_version()从installed_plugins.json中定位插件键warpclaude-code-warpPLUGIN_KEY常量取其数组首个元素的version字符串字段。本地会话一键自动更新Auto-Update本地会话中点击更新 chip 后Warp 调用插件管理器的update()方法整个过程沿用自动安装auto-install的既有 UX 模式操作期间显示持久化 toast完成后显示成功/失败 toast并在结束后执行一次磁盘版本确实变了的 sanity check。update() 的底层命令序列update()实现在app/src/terminal/cli_agent_sessions/plugin_manager/claude.rsasync fn update(self) - Result(), PluginInstallError { let mut log String::new(); // Remove/re-add the marketplace to ensure the local clone is fresh, then // reinstall the plugin. // We use plugin install (not plugin update) because marketplace // remove unlinks the plugin, so plugin update would fail with // Plugin is not installed. let _ self .run_logged([plugin, marketplace, remove, MARKETPLACE_NAME], mut log) .await; self.run_logged([plugin, marketplace, add, MARKETPLACE_REPO], mut log) .await?; self.run_logged([plugin, install, PLUGIN_KEY], mut log) .await?; // Sanity check: verify the on-disk version actually changed. let still_outdated claude_home_dir() .ok() .and_then(|dir| installed_version(dir)) .map(|v| compare_versions(v, MINIMUM_PLUGIN_VERSION).is_lt()) .unwrap_or(true); if still_outdated { log.push_str(Post-update version check: plugin is still outdated\n); return Err(PluginInstallError { message: Plugin update did not take effect.to_owned(), log, }); } Ok(()) }三个关键设计点源码注释中均有说明marketplace removemarketplace add刷新本地 clone确保拉取的是最新 marketplace 内容而不是缓存的旧版本使用plugin install而非plugin update因为marketplace remove已经解除了插件的链接此时若执行plugin update会报错Plugin warp is not installed。先重新 add marketplace、再 install等价于重装到最新版更新后 sanity check重读installed_plugins.json并比对版本若仍低于最低版本返回错误Plugin update did not take effectfooter 据此转入手动模式。run_logged会把每一步命令及其输出写入PluginInstallError.log字段见run_cli_command_logged()位于 plugin_manager/mod.rs方便用户排查失败原因。结果反馈成功toast 显示Warp plugin updated. Please run /reload-plugins to activate.与update_success_message()一致见claude.rs由于一键流程是通过程序化方式注册 listener 的因此只需/reload-plugins即可激活无需重启会话。失败整个会话剩余时间内转入手动模式modal。SSH 与失败场景手动更新Manual Update手动模式由两类场景触发远程SSH会话或本地自动更新/安装失败。此时点击 chip 打开的是 instructions modal。与安装 modal 不同安装 modal 使用会话内的/plugin斜杠命令更新 modal 使用的是 CLI 命令claude plugin ...原因是 Claude Code 中不存在可用的会话内更新斜杠命令there is no working in-session slash command for updating plugins。手动更新的完整步骤来自specs/APP-3661/TECH.md并在 claude.rs 的UPDATE_INSTRUCTIONS中落地为可执行命令步骤命令说明1claude plugin marketplace remove claude-code-warp移除既有 marketplace若存在2claude plugin marketplace add warpdotdev/claude-code-warp重新添加 marketplace拉取最新内容3claude plugin install warpclaude-code-warp安装最新版插件4重启 Claude Code 激活更新/exit手动安装的 hooks 需要完整重启才能生效modal 元数据TECH.md 中的定义标题Update Warp Plugin for Claude Code副标题Run the following commands in Claude Code by typing ! before each command, or in a separate terminal.成功 toast自动更新Warp plugin updated. Please run /reload-plugins to activate.成功 toast手动 modal提示用户重启 Claude Code执行方式有两种在独立终端中逐条运行或在 Claude Code 内每条命令前加!前缀透传给 shell 执行。modal 中每个步骤都提供复制按钮点击将命令复制到剪贴板并弹出绿色成功 toast。安装与更新的指令结构在源码中统一定义为PluginInstructions/PluginInstructionStep位于 plugin_manager/mod.rs字段包括title、subtitle、stepsdescriptioncommandexecutable 可选link以及post_install_notes。INSTALL_INSTRUCTIONS与UPDATE_INSTRUCTIONS均为LazyLockPluginInstructions静态变量。关闭Dismiss行为按版本记录而非按布尔值产品规格强调安装 chip 与更新 chip 的关闭状态互相独立关闭安装 chip → 仅隐藏安装 chip沿用既有布尔行为关闭更新 chip → 仅针对当前最低版本隐藏更新 chip若日后发布更高版本如 v3.0.0更新 chip 会重新出现。这意味着更新 chip 不能只记是否被关闭必须记录关闭时对应的最低版本号。TECH.md 中给出了对应的设置项settings/ai.rsplugin_chip_dismissed_for_version: PluginChipDismissedForVersion { type: String, default: , supported_platforms: SupportedPlatforms::DESKTOP, sync_to_cloud: SyncToCloud::Never, hierarchy: private, }判定逻辑用户关闭更新 chip 时写入当前的MINIMUM_PLUGIN_VERSION在should_show_plugin_chip/plugin_chip_kind()中若已关闭的版本号 当前最低版本则隐藏否则说明最低版本又提高了重新显示。在plugin_chip_kind()中这一判断可见let dismissed_version ai_settings.plugin_update_chip_dismissed_version(chip_key); if !dismissed_version.is_empty() compare_versions(dismissed_version, min_version).is_ge() { return None; }chip 关闭状态以agent × host为维度做 keyplugin_chip_key()本地为agent_prefix远程为agent_prefixhost与安装 chip 的既有做法一致。边界情况一览产品规格列出了 7 类边界情况完整呈现如下用户在 Claude Code 内手动更新listener 以新的plugin_version重连更新 chip 自动消失插件不报告版本一律视为过期——这些是版本上报能力之前的构建必然需要更新插件太老、无法发送结构化事件回退到磁盘版本检查即使没有 listener只要磁盘版本低于最低版本更新 chip 也会出现会话中途刚完成安装/更新会话的plugin_version被临时设置为MINIMUM_PLUGIN_VERSION从而抑制更新 chip直到用户运行/reload-plugins、插件发出真实的SessionStart多标签页所有标签页看到相同的会话状态更新失败记录跨标签页共享插件经 SSH 连接版本检测机制不变——插件自报版本与运行位置无关SSH 上的旧插件无结构化事件v1.1.0 旧公共插件不发送结构化事件因此没有 listener 连接、也无法检查远端文件系统此时显示安装 chip 而非更新 chip。这在功能上是正确的——安装指令同样能完成升级——只是标签写着 install 而非 update。技术实现深入会话层的版本跟踪与事件管道CLIAgentSession 新增 plugin_version 字段app/src/terminal/cli_agent_sessions/mod.rs中CLIAgentSession增加了plugin_version: OptionString字段/// The plugin version reported by structured plugin events. /// None if the plugin predates version reporting or Codex is using OSC9 fallback. pub plugin_version: OptionString,它通过两条路径被填充SessionStart事件路径主路径register_listener()现在接收plugin_version参数由SessionStart通知的 payload 传递进来同时apply_event()中遇到SessionStart事件类型时也会更新该字段self.plugin_version event.payload.plugin_version.clone()覆盖后续的SessionStart会话中途安装路径安装/更新成功后调用的register_cli_agent_listener()会把plugin_version置为MINIMUM_PLUGIN_VERSION抑制更新 chip直到用户/reload-plugins后插件上报真实版本。TECH.md 明确这是判断插件是否过期的权威信号authoritative signal本地与远程会话通用插件自报版本None表示插件早于版本上报能力、必然过期。失败跟踪plugin_auto_failuresCLIAgentSessionsModel上原有的plugin_install_failures: HashSet(CLIAgent, OptionString)被改名为plugin_auto_failures同时覆盖安装与更新两种操作的失败TECH.md 中说明由于PluginStatus已决定了 chip 显示哪种操作不存在需要区分安装失败与更新失败的场景且该集合每个会话都会重置。对应方法record_plugin_auto_failure()与has_plugin_auto_failed()均已落地。footer 的should_use_manual_mode()据此决定展示自动按钮还是指令按钮。事件管道与 Modal 泛化事件链AgentInputFooterEvent → Input::Event → TerminalView::Event → pane_group::Event → Workspace handler中原有的ShowPluginInstallModal(CLIAgent)被替换为ShowPluginInstructionsModal(CLIAgent, PluginModalKind)其中pub enum PluginModalKind { Install, Update, }位于 plugin_manager/mod.rsWorkspace handler 按 kind 分发调用对应的install_instructions()或update_instructions()把结果交给 modal 的set_instructions()后再打开。plugin_install_modal.rsapp/src/workspace/view/因此被泛化为指令渲染器从持有agent: OptionCLIAgent改为持有instructions: Optionstatic PluginInstructions并按步骤数调整代码块句柄。Trait 变更总结CliAgentPluginManagertraitplugin_manager/mod.rs在保留is_installed()文件系统检查installed_plugins.json中是否存在warpclaude-code-warp键且非空的基础上扩展出minimum_plugin_version()—— 返回该 Warp 构建要求的最低插件版本needs_update()—— 磁盘版本是否低于最低版本无 listener 时的兜底update()—— 一键自动更新update_instructions()—— 手动更新指令supports_update()—— 是否支持基于版本的更新检测为false时永不显示更新 chip以及can_auto_install()、install_success_message()/update_success_message()、平台插件相关方法等。其中install_instructions/update_instructions的返回类型为统一的PluginInstructions原PluginInstallInstructions/PluginInstallStep分别更名为PluginInstructions/PluginInstructionStep。trait 提供默认实现needs_update()默认false、update()默认返回Auto-update not supported错误只有支持自动操作的 agent如ClaudeCodePluginManager才覆盖。测试策略TECH.md 规划了覆盖单元、视图与集成三层的测试与仓库中 claude_tests.rs、mod_tests.rs、cli_agent_sessions/mod_tests.rs 等测试模块对应单元测试claude_tests.rscompare_versions覆盖相等、小于、大于、major/minor/patch 不同、不可解析段按 0 处理等情形既有check_installed测试继续有效现对应is_installed()。单元测试plugin_manager/mod_tests.rsclaude_manager_returns_update_instructions验证update_instructions()返回非空步骤claude_manager_returns_install_instructions验证install_instructions()返回非空步骤。单元测试cli_agent_sessions/mod_tests.rs将既有plugin_install_failure测试更名为plugin_auto_failure验证改名后的集合行为不变。视图测试terminal/view_tests.rs基于既有App::testCLIAgentSessionsModel模式update_chip_shown_when_plugin_version_below_minimum设plugin_version 1.1.0验证更新 chip 出现update_chip_shown_when_plugin_version_is_nonelistener 已连接但无版本验证更新 chip 出现no_chip_when_plugin_version_meets_minimum设plugin_version 2.0.0验证无 chipupdate_chip_hidden_when_dismissed_for_current_version/update_chip_shown_when_dismissed_for_older_version验证按版本关闭的语义update_chip_and_install_chip_dismiss_are_independent验证两种 chip 的关闭状态互相独立。集成测试integration/tests/integration/ui_tests.rstest_plugin_update_chip_appears_for_outdated_plugin通过 OSC 事件注入启动 Claude Code 会话预置旧版本installed_plugins.json验证 footer 渲染 Update Warp plugin chiptest_plugin_update_modal_opens先注入一次失败进入手动模式点击指令 chip验证 modal 打开并展示更新步骤test_plugin_update_chip_dismiss_persists点击关闭后验证 chip 保持隐藏再提升最低版本概念或重新渲染验证对新最低版本重新出现。涉及的修改文件TECH.md 第 9 节列出了本次功能涉及的完整文件清单整理如下文件变更内容app/src/terminal/cli_agent_sessions/plugin_manager/mod.rs结构体改名、trait 新增update()/update_instructions()/needs_update()等方法、PluginModalKind与 footer 侧PluginChipKind枚举app/src/terminal/cli_agent_sessions/plugin_manager/claude.rsupdate()实现、MINIMUM_PLUGIN_VERSION常量、compare_versions、更新指令LazyLockapp/src/terminal/cli_agent_sessions/mod.rsCLIAgentSession新增plugin_version字段plugin_install_failures更名plugin_auto_failuresapp/src/workspace/view/plugin_install_modal.rs泛化为通用指令渲染器set_instructions()步骤命令支持复制到剪贴板 成功 toastapp/src/ai/blocklist/agent_view/agent_input_footer/mod.rs新增两个按钮视图、plugin_chip_kind()可见性判定、handle_plugin_operation共享助手、plugin_operation_in_progress单布尔app/src/settings/ai.rs新增plugin_chip_dismissed_for_version设置app/src/terminal/input.rs、app/src/terminal/view.rs、app/src/pane_group/相关文件ShowPluginInstructionsModal事件替换旧的仅安装事件app/src/workspace/view.rs、app/src/workspace/mod.rs、app/src/workspace/util.rsmodal 更名与指令类型分发总结一条可复用的插件健康状态 → 引导升级闭环从产品到技术APP-3661 给出的是一条完整且可复用的插件更新闭环状态判定以SessionStart自报的plugin_version为权威信号辅以installed_plugins.json磁盘检查兜底配合compare_versions()与MINIMUM_PLUGIN_VERSION常量得出最新 / 过期 / 未安装 / 等待连接四种健康状态UI 引导footer 依据 8 条决策规则在安装 chip 与更新 chip 之间二选一或隐藏并通过按版本记录关闭保证新版本发布后提示会再次出现执行路径本地一键自动更新marketplace remove/addplugin install 版本 sanity checkSSH 或失败场景退回带复制按钮的分步 CLI 指令 modal状态同步会话层统一跟踪plugin_version与失败记录多标签页共享同一状态用户手动更新后 chip 自动消失。这套流程的价值在于它没有依赖 Claude Code 不可靠的插件更新系统而是把检测与引导的责任完全收归 Warp 自身同时为极端情况太老无法发事件、远程无法查文件系统、会话中途刚更新完逐一设计了兜底与抑制策略值得在同类面向第三方 CLI 的插件生命周期管理场景中直接借鉴。赞分享桌面应用开发者工具人工智能AI 应用AI Agent代码智能体【免费下载链接】warpWarp is an agentic development environment, born out of the terminal.项目地址https://gitcode.com/GitHub_Trending/wa/warp点击查看免费下载相关推荐如何实现Kazumi插件更新通知桌面通知与状态栏提示完整指南如何实现Kazumi插件更新通知桌面通知与状态栏提示完整指南 Kazumi是一款基于自定义规则的番剧采集APP支持流媒体在线观看和弹幕功能。对于插件驱动型应移动开发桌面应用音视频Warp 中 Claude Code 插件更新流的设计与实现从 SessionStart 版本检测到 Footer Update ChipWarp 中 Claude Code 插件更新流的设计与实现从 SessionStart 版本检测到 Footer Update Chip 本篇文章基于 Wa桌面应用开发者工具人工智能AI 应用AI Agent代码智能体Wox 更新插件Update Plugin使用指南从触发关键字到安装流程的完整解析Wox 更新插件Update Plugin使用指南从触发关键字到安装流程的完整解析 导读 Wox 内置的 更新插件Update Plugin 是负责桌面应用AI 应用插件系统创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →