Skip to content

[Bug] Theme plugins with package-relative assets pass pi-plugin check but cannot be installed (SDK/loader vs installer disagree after ADR 0255) #943

Description

@VMF-HIBIKI

What happened? / 问题描述

Three components implement two different contracts for contributes.themes[].assets, so a theme plugin that ships its wallpaper/font inside the package passes pi-plugin check, publishes to a catalog, and then cannot be installed by any user:

Component Accepts package-relative? Accepts absolute?
SDK validator isThemeAssetPath (packages/plugin-sdk/src/theme-css.ts) — used by pi-plugin check ✅ ✅
Runtime loader resolveThemeAssets (apps/desktop/electron/main/plugin-runtime.ts) — imports normalizeThemeAssetPath from the SDK ✅ (resolveInsidePlugin) ✅
Installer validator normalize_theme_asset_path (crates/host-core/src/plugins/validation.rs) ❌ ✅ but the path must already exist on the installing machine

ADR 0255 ("Theme assets are absolute paths", 2026-09-15, D422) decided absolute-only and states that normalizeThemeAssetPath (SDK) and normalize_theme_asset_path (host-core) both reject package-relative. The host-core side implements that decision; the SDK validator, the SDK doc comments ("may be package-relative or absolute"), the PluginThemeContrib.assets doc, and the loader were never aligned, and the SDK's own tests still assert package-relative acceptance (theme-css.test.ts, index.test.ts).

The result is a dead end for any distributed theme plugin with shipped image/font bytes:

  • package-relative asset → installer rejects: must be an absolute image or font path;
  • absolute asset → installer requires the file to already exist on the installing machine (asset missing) — impossible for a distributed package whose bytes live inside the .piplug;
  • the runtime route (data directory + pi.themes.upsert) is dynamic and cannot be declared in a static manifest at all.

Steps to reproduce / 复现步骤

  1. PI-Desktop 0.15.6.
  2. Plugins page → install local.miku-theme 1.0.0 from the community catalog (AIUO-Net/pi-desktop-plugins) — a plugin whose manifest declares "assets": ["themes/assets/wallpaper-dark.webp"] and which passes pi-plugin check.
  3. Installation fails with PLUGIN_INVALID: theme cyber-diva asset themes/assets/wallpaper-dark.webp must be an absolute image or font path.
  4. The same plugin loaded as a local directory (registry source: "dev") works: the theme renders and the wallpaper is served through plugin-asset://.

Expected behavior / 预期行为

Author-time validation and the installer agree. Either a package that passes pi-plugin check installs on every machine, or the check rejects it locally with a message that names the migration path — never the current state where the check approves what the installer refuses.

Actual behavior / 实际行为

Installation is rejected on every platform (Linux verified; the same host-core validation runs on Windows/macOS — nothing here is OS-specific). The error text gives the plugin author no hint that the bytes need to move out of the package, and the SDK docs/tests actively bless the rejected spelling.

App version / 应用版本

0.15.6

Operating system / 操作系统

Linux (deb, amd64) — reproduced on the shared host-core validation path used by all platforms.

Extra environment / 其他环境信息

Plugin: local.miku-theme 1.0.0, community catalog (AIUO-Net/pi-desktop-plugins), authored 2026-09-20/22 — after ADR 0255 but against the SDK-documented contract.

Logs / 日志

PLUGIN_INVALID: theme cyber-diva asset themes/assets/wallpaper-dark.webp must be an absolute image or font path

Impact / 影响

  • Every catalog theme plugin that follows the SDK documentation and passes pi-plugin check is uninstallable for every user, with an error that reads like a plugin bug but is a contract mismatch.
  • The community catalog accumulates broken packages (review approved local.miku-theme; pi-plugin check is the gate authors trust).
  • Users must fall back to manual directory installs (registry source: "dev"), which loses install-time validation and updates.

Proposed resolution / 解决方案

Two coherent directions; happy to follow up with either.

A. Complete ADR 0255 on the TS side (offered as PR #936-ready) — pi-plugin check fails package-relative assets at author time with an actionable message (bytes → pi.plugin.getDataPath(), reference by absolute path, or register at runtime via pi.themes.upsert). The shared normalizeThemeAssetPath, the SDK docs/tests, and the PluginThemeContrib.assets doc can then be aligned in a follow-up; whether the loader should stop resolving package-relative for already-installed plugins is a breaking change ADR 0255 already accepts, but the scheduling is a maintainer call.

B. Reconsider ADR 0255 for the installer — accept package-relative again (resolving inside the package root with the existing containment rules). I have a tested host-core patch implementing this (643 tests green), but I understand "allow both spellings" was explicitly rejected in ADR 0255's alternatives, so this direction needs an owner decision, not just code.


中文摘要:SDK 校验器/加载器与 host-core 安装器对主题资源路径的契约不一致(前者按 ADR 0248 接受包内相对路径,后者按 ADR 0255 只认绝对路径且要求文件已存在于用户机器)。结果是:遵循 SDK 文档、通过 pi-plugin check 的主题插件对任何用户都无法安装,且报错无迁移指引。与操作系统无关。方向 A(补齐 ADR 0255 在 TS 侧的落地,PR 已就绪)或方向 B(安装器重新接受包内相对路径,补丁已备好)二选一即可闭环。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions