DSH / Atlas
2026-09-18implementedarchitecturearchived 2026-09-30

Plugin-owned localized display metadata

插件自有的多语言展示元信息

Plugin Manager needs readable titles and descriptions for installed bundles and individual plugins, including disabled plugins. One npm package can export several plugins with different purposes; a package-level introduction cannot describe each one. Registering introductions only during activation also leaves disabled or failed plugins without display text.

English

Problem

Plugin Manager needs readable titles and descriptions for installed bundles and individual plugins, including disabled plugins. One npm package can export several plugins with different purposes; a package-level introduction cannot describe each one. Registering introductions only during activation also leaves disabled or failed plugins without display text.

Decision

Each plugin supplies optional meta.title and meta.description strings in its locale/<language>.json resources, starting with locale/en.json. These strings directly provide its display title and description. Other top-level locale content belongs to its existing consumers and is not included in metadata responses.

{
  "meta": {
    "title": "File Search",
    "description": "Search files in your workspace."
  }
}

The configured Cordis plugin name owns the resource address. Node module resolution selects files through the applicable profile and package exports without evaluating plugin code:

Plugin formLocale resource
npm package my-pluginsmy-plugins/locale/en.json, exposed by ./locale/*.json
npm subpath my-plugins/searchmy-plugins/search/locale/en.json, exposed by ./search/locale/*.json
JavaScript path ./plugins/search.jsNo sibling-resource lookup; the configured path is the final title fallback

Locale addresses are not derived from a resolved JavaScript filename or an owning package directory. File paths and file URLs, including Windows drive and UNC paths, skip resource resolution and return no metadata; a file address alone is not a metadata error. They supply neither sibling locale metadata nor a neighboring package manifest. The package cookbook owns directory examples, export declarations, publication entries, and author verification.

Language files for one plugin share a directory. The Host resolves en.json, discovers language filenames in that directory, and resolves each resource using the same plugin specifier and parent URL. The English resource anchors discovery, but any language may omit either display field. Language identifiers are case-insensitive and duplicates are rejected. Present locale display fields must be non-empty strings.

The Host reads installed bundles and their declared plugin rows without importing or activating them. Remotes carry multilingual values or literal fallback text for the two display fields. The Client reuses its existing language selection and fallback chain at render time, without adding language registration, plugin-specific language defaults, or another language fallback policy.

Each field falls back independently before view-specific name formatting:

FieldExisting locale fallback chainPackage-root fallbackFinal fallback
Titlemeta.titleNon-empty name from <package name>/package.jsonComplete configured Cordis plugin name
Descriptionmeta.descriptionNon-empty description from <package name>/package.jsonNo package description

The package fallback obeys resource exports and applies only when the configured plugin name is the package itself. A subpath plugin is not a package: it never reads a package.json, even one exported at its address, and does not inherit its owning package's introduction. The Host supplies the package or final value as the English fallback for a field that has translations but no English value, preserving the existing Client locale API. Missing or unexported resources and missing fields use these fallbacks; invalid locale fields or malformed files report a diagnostic instead of silently falling back, while retaining management operations.

Icons follow the same address rule. A package root uses its manifest icon, or the exported <package name>/icon when that field is omitted. A subpath uses only <plugin specifier>/icon, resolved through Node exports like its locale resources and confined to its package.

Plugin Manager uses this metadata on installed bundle cards and details, component lists, and component configuration details, preserving complete technical-name fallbacks. Settings uses it in the plugin inventory, including preset plugins, but shortens literal package-name and module-name fallbacks by removing their npm scope and Cordis/DSH prefixes. Translated titles remain verbatim in both views; full module names, entry ids, search identities, and operation targets stay unchanged. The Settings inventory README owns the prefix rules.

A row configuration page uses its registered summary view only when the plugin has no display description. The bundle's raw description field remains available to Host and model consumers; it is not an additional UI fallback around resource exports. These rules preserve one displayed description while keeping configuration summaries available for plugins without one.

Disabled plugins remain readable without activation. The Install view still uses registry information from pnpm view; it does not replace that information with locale metadata. Registry, Git, and tarball inspection before installation does not read remote package contents for translation. Model tool results retain their existing package information and exclude multilingual UI dictionaries. Session events remain unchanged.

Built-in bundle introductions live in their exported language files. Beta markers, page grouping, configuration slot ownership, and enablement targets remain unchanged. Plugin introductions and component interaction copy retain separate owners.

Existing decisions

Public package declarations still govern manifest type and reader responsibilities; locale-owned UI copy still governs component wording and display identity; plugin configuration pages still determine configuration slot ownership. Plugin metadata extends display data without replacing those decisions.

Alternatives considered

Keep built-in package dictionaries in Plugin Manager. Every package addition requires changing the manager, and external plugins cannot independently supply translations.

Declare references in package.json. This duplicates the declaration between a manifest and locale files, and one package-level declaration cannot distinguish its exported plugins.

Read <subpath>/package.json for subpath plugins. A package has one manifest; exporting another at a subpath suggests that subpaths own manifests. Locale files and <subpath>/icon already give each subpath independent text and artwork.

Read locale beside the resolved JavaScript file. Build tools can put several plugin entries in the same directory. Resource exports preserve each plugin's identity independently of its compiled layout.

Register copy when the displayed plugin activates. Disabled packages, packages without a Client half, and packages that fail to load still need readable introductions.

Add base.json or package-specific fallback. This introduces a second policy alongside the existing English fallback and extension-language fallback chains.

Download remote packages for pre-installation previews. This expands lookup cost and the package contents that must be handled; this phase only reads files already present locally.

Verification

  • Bundles, child plugins, and read-only inventory display local metadata; disabled packages need no activation for reading.
  • Language switching updates titles and descriptions; Settings shortens only literal technical-name fallbacks, not translated titles, and keeps module identities and operation targets intact.
  • Direct metadata, unrelated locale content, absent resources, malformed JSON, missing display fields, and conflicting language identifiers have focused coverage.
  • Separate exports in one package and same-named packages under different parents retain independent metadata without executing plugin entries.
  • Windows drive paths, UNC paths, relative and absolute file paths, and file URLs return no metadata without invoking resource resolution.
  • Missing locale resources and individual fields fall back independently to package-root manifest fields, then the complete module specifier without a description; subpath plugins ignore exported manifests and read only <plugin specifier>/icon.
  • Publication checks require readable resource exports and included language files, without duplicate ownership of built-in copy in the manager and plugins.
  • Management tools preserve existing model output, and pre-installation inspection adds no package-content lookup.
  • Focused tests and the complete pnpm run build succeed.

Consequences

Omitted language files or exports can make metadata unavailable after publication, so verification covers both resolution and packaged files. Metadata errors remain per-plugin diagnostics without removing the manager's repair controls; file diagnostics retain their absolute paths. Display metadata is read per request without a metadata cache. Lookup retains the complete module specifier and its resolution parent; package-name-only caching cannot distinguish exported plugins or different installations.

中文

问题

Plugin Manager 需要为已安装的 bundle 与各个插件展示可读的标题和描述,包括尚未启用的插件。同一个 npm 包可以导出多个用途不同的插件,包级介绍无法分别描述它们。依赖激活来注册介绍,也会让禁用或加载失败的插件缺少展示文案。

决策

每个插件从 locale/en.json 开始,在自己的 locale/<language>.json 资源中提供可选的 meta.title 与 meta.description 字符串。这些字符串直接提供展示标题和描述。locale 的其他顶级内容仍归现有消费方所有,不进入元信息响应。

{
  "meta": {
    "title": "File Search",
    "description": "Search files in your workspace."
  }
}

资源地址归 Cordis 配置中的插件名所有。Node 模块解析通过适用的 profile 和包 exports 选择文件,不执行插件代码:

插件形式locale 资源
npm 包 my-plugins请求 my-plugins/locale/en.json,由 ./locale/*.json 导出
npm 子路径 my-plugins/search请求 my-plugins/search/locale/en.json,由 ./search/locale/*.json 导出
JavaScript 路径 ./plugins/search.js不查找同级资源;配置中的路径名作为标题的最终回退

locale 地址不从解析后的 JavaScript 文件名或所属包目录推导。文件路径与文件 URL(包括 Windows 盘符路径和 UNC 路径)跳过资源解析,返回无元信息;文件地址本身不构成元信息错误。它们既不提供同级 locale 元信息,也不提供旁边的包 manifest(元数据清单)。目录示例、exports 声明、发布条目与作者验证步骤由添加包实操手册维护。

同一插件的语言文件放在同一目录。Host 解析 en.json,从所在目录发现语言文件名,再用同一插件模块名与父 URL 解析各个资源。英文资源作为发现入口,但任何语言都可以省略任一展示字段。语言标识不区分大小写,重复标识拒绝。locale 中声明的展示字段必须是非空字符串。

Host 读取已安装 bundle 及其声明的插件行,不 import 或激活它们。Remote 携带两个展示字段的多语言值或纯文本回退值。Client 在渲染时复用现有 locale 的语言选择与回退链,不增加语言注册、插件级默认语言或另一套语言回退规则。

每个字段先独立回退,再按页面规则格式化技术名称:

字段现有 locale 语言回退链包根字段回退最终回退
标题meta.title<包名>/package.json 中非空的 nameCordis 配置中的完整插件名
描述meta.description<包名>/package.json 中非空的 description不提供包描述

包字段回退遵守资源 exports,仅在配置的插件名就是包本身时生效。子路径插件不是包:它从不读取 package.json,即使该地址导出了一个,也不继承所属包的介绍。字段有其他语言译文但没有英文值时,Host 将包字段或最终值放入英文回退位,保持现有 Client locale API 不变。资源不存在、未导出或缺少字段时使用上述回退;locale 字段无效或文件格式损坏时明确诊断,不静默回退,同时保留管理操作。

图标遵循相同的地址规则。包根使用清单 icon,省略该字段时使用导出的 <包名>/icon。子路径只使用 <插件模块名>/icon,像其 locale 资源一样经 Node exports 解析,并限制在所属包内。

插件管理页在已安装 bundle 的卡片和详情、组件列表、组件配置详情中使用这些元信息,保留完整技术名回退。设置中的插件清单也使用它,包括预设内插件,但会移除字面包名和模块名回退值的 npm scope 与 Cordis/DSH 前缀。两个页面都原样展示翻译标题;完整模块名、条目 id、搜索身份与操作目标保持不变。具体前缀规则由设置插件清单 README维护。

行配置页仅在插件没有展示描述时使用注册组件的 summary 视图。组合包原始的 description 字段仍供 Host 与模型消费方使用,不作为绕过资源 exports 的额外 UI 回退。这些规则只展示一份描述,同时保留无描述插件的配置摘要。

禁用插件不需要激活即可读取。Install 界面仍使用 pnpm view 返回的 registry 信息,不用 locale 元信息替换。安装前的 registry、Git 和 tarball 查询不为翻译读取远程包内容。模型工具结果保留现有包信息,不携带供 UI 使用的多语言字典。Session 事件不变。

内置 bundle 的介绍放在其导出的语言文件中。beta 标记、页面分组、配置槽归属与启停目标保持原样。插件介绍和组件自身的交互文案各自保持所有权。

现有决策

公共包声明 继续约束 manifest 类型和读取者的职责;locale-owned UI copy 继续约束组件文案和展示身份;插件配置页 继续决定配置槽归属。插件元信息只扩展展示数据,不取代这些决策。

考虑过的替代方案

在 Plugin Manager 中继续维护内置包词典。 每增加一个包都需要修改管理器,而且外部插件无法独立提供翻译。

在 package.json 中声明引用。 将声明重复放在 manifest 与 locale 文件中,而且一份包级声明无法区分包内导出的插件。

为子路径插件读取 <子路径>/package.json。 一个包只有一个清单;在子路径导出另一个清单会让人以为子路径拥有自己的清单。locale 文件和 <子路径>/icon 已经为每个子路径提供独立的文本和图片。

从解析后的 JavaScript 文件旁读取 locale。 构建工具可能把多个插件入口放在同一目录。资源 exports 让各插件的身份独立于编译产物布局。

由被展示插件激活时注册文案。 未启用包、无 Client 半边的包和加载失败的包仍然需要可读的介绍。

增加 base.json 或包级 fallback。 会与现有 locale 的英文兜底和扩展语言回退链产生第二套规则。

为安装前预览下载远程包。 扩大查询成本及需要处理的包内容;本期只处理已经存在于本地的文件。

验证

  • bundle、子插件与只读 inventory 展示本地元信息;禁用包不需要激活即可读取。
  • 切换语言更新标题和描述;设置页仅缩短字面技术名回退,不缩短翻译标题,也不改变模块身份和操作目标。
  • 直接元信息、无关 locale 内容、缺失资源、损坏 JSON、缺失展示字段及语言标识冲突均有针对性覆盖。
  • 同包的不同 exports,以及不同父目录中的同名包,各自保持独立元信息,读取不执行插件入口。
  • Windows 盘符路径、UNC 路径、相对与绝对文件路径及文件 URL 均不调用资源解析,直接返回无元信息。
  • locale 资源或个别字段缺失时,各字段独立回退到包根清单字段,再回退到完整模块名且不显示描述;子路径插件忽略导出的清单,只读取 <插件模块名>/icon。
  • 发布检查要求资源 exports 可解析且包含语言文件,内置文案不在管理器和插件中双份维护。
  • 管理工具保留现有模型输出,安装前查询不增加包内容探查。
  • 针对性测试以及完整 pnpm run build 通过。

影响

遗漏语言文件或 exports 会使发布后的元信息不可用,因此验证覆盖解析与打包后的文件。元信息错误作为单插件诊断呈现,不能让整个管理页失去修复入口;文件诊断保留绝对路径。展示元信息按请求读取,不设元信息缓存。查询保留完整模块名及其解析父地址;只按包名缓存无法区分导出插件或不同安装目录。