Skip to content

feat(plugin-market): 插件市场多源发现 + 可信度分层 + GitHub topic 实时通道 (issue #46) - #47

Merged
Gu-ZT merged 23 commits into
dsh-plugins:mainfrom
yukitakasama:feat/46-plugin-sources
Sep 14, 2026
Merged

Gu-ZT merged 23 commits into
dsh-plugins:mainfrom
yukitakasama:feat/46-plugin-sources

Conversation

@yukitakasama

Copy link
Copy Markdown
Contributor

概述

修复 #46:插件市场此前只消费两个硬编码 URL(plugins.rsMARKET_URL / AWESOME_URL),主源 dsh-plug.in 近乎为空,实际只靠 awesome 单源,用户既看不到更多插件也无法增减来源。

本 PR 把「源」抽象为可配置的源描述符 + adapter 注册表,新增 dshget 聚合目录与可选的 GitHub topic 实时通道,并对条目做可信度分层,在安装前对未验证来源做二次确认。

变更内容

1. 源注册表 + adapter 分派

  • fetch_plugin_market 不再写死两个常量:按 SourceKind 分派到 4 个 adapter —— Primary / Awesome / DshGet / GithubTopic
  • JoinSet 并发抓取 + 总预算超时;单源失败仅告警并被跳过,不阻塞其余源。

2. dshget 聚合目录(默认启用)

  • 解析 catalog.json(2460 条,2.6 MB);installdsh plugin --profile web add github:owner/repo 完全复用既有的 parse_awesome_install,无需新解析器。
  • 跳过 installable === false(605 条);description{en,zh} 双语兼容;上游 sources[] 透传为归属。
  • 默认走 jsDelivr CDN 而非 raw.githubusercontent.com —— 实测后者在国内网络不可达,而 CDN 返回字节数完全相同的快照。

3. 源可配置化

  • LauncherSettings.plugin_sources 持久化;新增 list_plugin_sources 命令;设置页支持增删 / 排序 / 自定义 URL(含镜像)/ 启用开关
  • DSHLAUNCHER_PLUGIN_SOURCES 环境变量可整体覆盖启用列表(仅作用于本进程,不回写配置)。

4. 可信度分层与去重

  • Confidence = Official | Curated | Aggregated | Unverified;同 id 去重取最高层,同级按源 order 优先;stars/downloads 取最大、sources 取并集。
  • 市场列表显示可信度标签;未验证来源在安装向导有警告横幅 + 勾选后才可提交。

5. 粒度红线(硬性)

  • 任何源(含用户自定义源)产出的条目,只要 install target 以 @deepseek-ai/ 开头或 github: owner 为 deepseek-ai,一律丢弃并告警。单测覆盖。

6. GitHub topic 实时通道(默认关闭,需用户在设置页开启)

  • topic:dsh-plugin 搜索,2 页 × 100 条,页级预算 + 3 次指数退避。
  • 降噪:仓库名匹配 dsh-* package.json 声明 dsh.bundle 根有 cordis.patch.yml;另加核心仓 denylist。
  • data_dir/plugin-cache/github-topic.json,TTL 24h + 断点分页 + last-good 兜底。

7. 降级与缓存

  • 每源 last-good 缓存(data_dir/plugin-cache/<id>.json);源不可达时降级为缓存,首次运行无缓存则如实报错并跳过,不影响其余源。

8. 顺带修复

  • alpha_commit 原先靠静态市场回查定位 repo,实时通道新增的插件必然查不到 → 改为接受条目自带 repo 提示,resolve_repo 统一解析。

9. CI 门禁修复(独立提交 d245626)

  • .github/workflows/ci.yml 要求 cargo fmt --checkclippy -D warnings,而本分支前几轮后端改动已引入 15 处未格式化位置 + 1 处 clippy::unnecessary_to_owned ⇒ 修复前该 PR 的 CI 必然失败。此提交只做门禁修复,无行为变更。

验证

CI 五步本地全绿:

门禁 结果
cargo fmt --all -- --check ✅ exit 0
cargo clippy --workspace --all-targets --locked -- -D warnings ✅ exit 0
cargo test --workspace --locked ✅ 134 passed / 3 ignored
vue-tsc --noEmit ✅ 0 错
vite build ✅ 11.06s

联网冒烟(--ignored):

  • live_fetch_market ✅ —— 三个默认源各自贡献条目(dsh-plugins / awesome-dsh-plugin / dshget),全程无「获取失败」告警,零核心包。该测试新增「每个已启用源都必须在合并结果里出现自己的 source id」硬断言:源失败原先只 log_warn! 静默跳过,没有任何断言能发现「某源其实没贡献」。
  • live_dshget_catalog_parses_and_filters_core ✅ —— >1000 条,全部带 source/confidence,github 条目全部带 repo 提示,无核心包。
  • live_fetch_plugin_versions ⚠️ —— 需 api.github.com,本机不可达(需代理),未能实抓;与 topic 通道同一网络限制(见下)。

已知限制

  • topic 通道的端到端未能实抓:本机 api.github.com / raw.githubusercontent.com 不可达,故降噪逻辑仅有单测覆盖(4 项),无线上实测。正因如此该通道默认关闭,由用户开启并自备可用代理。
  • jsDelivr 单点依赖:dshget 默认源与 topic 探测都走 cdn.jsdelivr.net。若该 CDN 不可达,dshget 降级为 last-good 缓存(首次运行则无缓存,仅剩 2 源);用户可在设置页改回 raw.githubusercontent.com 或自建镜像。
  • plugin.dshx.dev 无公开 JSON API(Nuxt SSR),暂不接入。
  • 代码搜索 / npm 反链通道列为可选延期:前者需用户 token,后者与 dshget(已聚合 npm 元数据)重叠;源注册表可直接容纳(加一个 SourceKind 变体 + adapter)。

文档

  • docs/ISSUE46_TASK_TREE.md —— 阶段任务树 + 逐轮回填日志(含验收标准对照、风险与开放问题)。

依赖说明

本分支基于 PR #44 的 8 个提交(issue #43 数据目录可迁移)构建 —— 设置页与 config.rs 的改动需要它。若 #43 先合入 main,本 PR 会自动只显示 #46 的增量。

yukitakasama and others added 19 commits September 12, 2026 14:59
…sue dsh-plugins#43)

- migrate.rs: bootstrap resolution chain (env DSH_LAUNCHER_DATA_HOME >
  pointer file data-home.txt > default app data dir), one-shot migration
  before the log handle opens: copy config/versions/homes/logs/.pnpm-store/
  tools/icons/bin -> verify -> switch -> snapshot old dir as .old-<ts>.
  Failure rolls back to the default dir and drops the pointer.
- AppState gains data_dir_source + data_dir_notice; commands pick_data_dir
  (blocking folder dialog), commit_data_dir (validate + write pointer),
  get_data_dir_source (path + source + fallback notice).
- lib.rs setup calls migrate::bootstrap before applog::init and
  ensure_local_node_on_path, so logs/ and tools/ move cleanly.
- 4 unit tests for paths_equal/dir_is_empty/copy_tree/tree_stats.
…sh-plugins#43)

- Settings.vue: data-dir card gains a 'Change location' button that opens
  the folder dialog (pick_data_dir), validates + writes the pending pointer
  file (commit_data_dir), then shows a restart hint modal; the card also
  displays the current source ('env' / 'pointer' / 'default') and surfaces
  the startup fallback notice as a toast.
- api/index.ts: pickDataDir / commitDataDir / getDataDirSource wired with
  browser-preview mock branches; types.ts adds DataDirInfo.
- i18n: zh-CN + en-US keys for moveTo/restartHint/migrating/migratedToast/
  source*/rollback/confirmMove.
…cords (issue dsh-plugins#43)

- copy_tree handles file sources (no create_dir_all on files) — fixes
  os error 267 when migrating config.json.
- New tests: migrate_data_dir_copies_and_clears_flag,
  migrate_data_dir_rejects_non_empty_target,
  migrate_data_dir_failure_removes_partial_target.
- Full suite: 119 passed; tauri build produced exe/msi/nsis bundles.
- 核验基线 3a802ae 为 HEAD 祖先,plugins.rs 零漂移
- 实测 dshget catalog.json(2460 条/2.6MB):install 行兼容 parse_awesome_install,
  605 条 installable=false,21 条 @deepseek-ai/* 需硬性排除
- 定稿 SourceKind/Confidence/PluginSourceConfig、去重优先级、默认源表、
  DSHLAUNCHER_PLUGIN_SOURCES 解析规则、topic 降噪与 denylist
…ns#46)

后端:
- config.rs: SourceKind/Confidence/PluginSourceConfig + 默认源表(3 启用 + topic 默认关)
  LauncherSettings.plugin_sources / SettingsPatch / sanitize_plugin_sources(去重+重编号)
- plugins.rs: fetch_plugin_market 改为遍历已启用源并按 kind 分派 adapter
  (primary/awesome/dshget/github-topic),JoinSet 并发、单源失败降级 last-good 缓存
- 去重取最高 confidence 层,union sources/stars/category/repo
- 红线:@deepseek-ai/* 与 owner=deepseek-ai 的条目一律丢弃
- dshget: 解析 catalog.json,跳过 installable:false,install 行复用 parse_awesome_install
- topic 通道: 2 页×100 预算 + 指数退避,名匹配 dsh-* 或探测 dsh.bundle/cordis.patch.yml,
  denylist 排除核心仓/目录仓,TTL 24h 缓存 + 断点分页
- list_plugin_sources 命令;DSHLAUNCHER_PLUGIN_SOURCES 覆盖
- 修复 alpha_commit 静态市场回查:fetch_plugin_versions/InstallPluginInput 新增 repo 提示
- 新增 13 个单测(核心包排除/去重分层/dshget 解析/降噪/TTL 缓存/env 解析)
- types.ts: PluginSource 改为字符串源 id,新增 SourceKind/Confidence/PluginSourceConfig,
  MarketPlugin 增加 confidence/sources/repo/verification,InstallPluginInput 增加 repo
- api/index.ts: listPluginSources;fetchPluginVersions 增加 repo 参数;浏览器预览 mock
  补齐 4 源与 dshget/github-topic 两条样本条目,可观察源过滤与未验证标签
- stores/launcher.ts: pluginSources 状态 + refreshPluginSources(带缓存)
- Market.vue: 源过滤改为动态渲染;非主源显示来源标签 + 可信度标签(unverified 红色)
- Settings.vue: 新增「插件来源」卡片(启用开关/增删/上移下移/自定义 URL + 校验)
- InstallWizard.vue: unverified 来源显示警告横幅并需勾选确认才能安装
- VersionPick.vue: alpha 版本解析传入 repo 提示,修复实时条目回查失败
- i18n zh-CN/en-US: plugins.source.* / plugins.confidence.* / plugins.unverified* /
  settings.pluginSources.* 双语同键集

附带后端: dshget 默认源与 topic 探测改走 jsDelivr CDN(实测 raw.githubusercontent 不可达),
探测请求 8s 超时上限。
1. topic 条目未打源标签: GithubTopic 分支漏调 tag_entry,导致实时插件被
   序列化为 dsh-plugins(官方源),市场按源过滤失效、自定义 topic 源 id/可信度
   被忽略。抽出 tag_all 统一打标,新 adapter 无法再遗漏。
2. repo 提示可能来自低可信源: merge_into 在置信度替换分支未复制 repo,
   低层级源的 repo 会残留 → alpha 版本解析/安装指向与 UI 条目不一致的仓库。
   现在高置信度源整体胜出(含 repo);同层级仅在缺位时补全。
3. 慢源阻塞整个市场: 增加 MARKET_FETCH_BUDGET(45s)总预算,超时源 abort 后
   改用其 last-good 缓存,不再让 topic 通道的搜索重试+探测把市场拖住。
4. is_core_package 可被绕过: 归一化(trim/npm: 前缀/大小写),并新增
   entry_is_core 同时检查 repo 提示(良性 id + 核心仓 repo 也会被拦)。
5. 缓存文件名冲突: 不同 id 可能 sanitize 同名(a/b 与 a_b),改用
   sanitize_name + sha256 前 6 字节,互不串cache。

另: alpha_commit 对 github: id 以 id 为准(含 monorepo 子路径),仅对无法
自证仓库的 id 使用前端传入的 repo 提示。
测试: 新增置信度分层(高优先级在前/在后两种顺序 + 同层补位)、核心包
变体与 repo 提示、缓存不冲突、TTL 过期后仍走 last-good 共 5 项;134 测试全过。
复核后端契约后修正四处前端缺陷:

- Settings.vue: `github-topic` 源本就无静态 URL(default_plugin_sources 的
  url 为空字符串),新增校验却要求所有源都填 http(s) URL — 用户无法添加或
  保存实时通道源。改为仅对静态源校验 URL,与 config.rs`sanitize_plugin_sources`
  的放行规则保持一致。
- Settings.vue: 源增删/排序/开关在保存期间无互斥,连续点击会基于旧的
  `store.settings.plugin_sources` 互相覆盖;补 `pluginSourceBusy` 守卫并禁用
  对应按钮。
- Settings.vue: `patchSettings` 内部吞掉后端错误,添加源失败时表单已被清空,
  用户输入丢失;改为确认源真的落到刷新后的 settings 再清空。
- InstallWizard.vue / Market.vue: `confidence` 缺失(旧缓存或第三方源未带该
  字段)被当成"已可信"既不显示标签也不要求确认;统一按最保守的 `unverified`
  处理。Market.vue 另补:持久化的源过滤 id 指向已删除/已禁用的源时清零,过滤
  下拉只列已启用源,避免市场静默显示空列表。
- api/index.ts: 浏览器预览 mock 的 `list_plugin_sources` 返回硬编码源,与设置
  页读写脱节;改为读 `db.settings.plugin_sources`(缺省回退种子数据)。

验证:`vue-tsc --noEmit` 0 错;`vite build` ✓ 10.5s。

暂存内容来自上一轮复核修复,本轮复核确认与后端契约一致后提交。
…s#46)

本分支前几轮的后端改动引入了未格式化代码和一处 clippy 告警,`cargo fmt
--check`` 与 `clippy -D warnings` 均会失败,PR 的 CI 无法通过。本提交只做
门禁修复,不含行为变更:

- `cargo fmt --all` 覆盖 plugins.rs / migrate.rs(长宏参数换行、断言折行、
  结尾多余空行、缺文件末尾换行)。
- migrate.rs `snapshot_default_dir`:`fs::write` 接受 `AsRef<[u8]>`,去掉
  `pointer_content.trim().to_string()` 的冗余分配(clippy::unnecessary_to_owned)。

验证:`cargo fmt --all -- --check` 退出 0;`cargo clippy --workspace
--all-targets --locked -- -D warnings` 退出 0;`cargo test --workspace
--locked` 134 passed / 3 ignored。
原 `live_fetch_market_and_versions` 把「三源市场抓取」与「npm/GitHub 版本解析」
混在一个 `#[ignore]` 测试里,而后者必须走 `api.github.com` — 在无 GitHub 代理
的网络(本机实测)整条测试必然失败,导致验收标准 1 的端到端证据无法复现。

- 拆为 `live_fetch_market`(只抓三个静态目录源,不碰 `api.github.com`)与
  `live_fetch_plugin_versions`(npm + GitHub alpha 通道)。
- 市场半边新增硬断言:每个已启用源都必须在合并结果里出现自己的 `source` id
  —— 源失败只会 `log_warn!` 并被静默跳过,原先没有任何断言能发现「某源其实
  没贡献」;再补一条核心包红线断言。

实测:`cargo test --lib plugins::tests::live_fetch_market -- --ignored --nocapture`
通过,三源(dsh-plugins / awesome-dsh-plugin / dshget)均贡献条目,无「获取失败」
告警。`live_fetch_plugin_versions` 仍需代理,在本机不可跑(与 §7 记录一致)。
- 文档状态 draft v1 → final v2,补分支与基线信息。
- §3 阶段 2/3/5 勾选框统一为完成态;新增「阶段 6:复核收尾」任务树。
- §4 验收标准逐条重写证据:第 1 条由「无告警」的间接观察改为
  `live_fetch_market` 的「每源必须贡献」硬断言实测;第 4/5 条补测例名与
  134 passed / 3 ignored 的准确计数。
- §5 增加「实际轮数」列(实际约 9 轮,阶段 4 未做、阶段 6 为新增收尾轮)。
- §6 回填第 5/6 轮(前端复核修复 60595b1、CI 门禁 d245626 + live 测试拆分
  83c14ef),并列出完整提交序列与「未 push / 未提 PR」的待办。
- §7 新增两条过程风险:CI 门禁此前已破(15 处格式 + 1 处 clippy,本轮修复)、
  拆分提交时 `git apply --recount` 静默漏 hunk 的坑与隔离复跑的检出方式。
`stale_topic_cache_is_refetched_instead_of_served` 断言的是「过期缓存会走
last-good 兜底并返回 github:stale/x」——但那条路径只在**网络失败**时成立。
本机 `api.github.com` 不可达所以本地一直通过,而 PR dsh-plugins#47 的 CI(Linux/macOS/
Windows 三个平台)runner 网络可达,`fetch_catalog` 成功并返回线上目录,断言
随即失败。这不是 flake,是该测试把「离线环境」写进了断言。

改为在**两个方向**上断言真实契约(TTL 只在缓存新鲜时短路网络调用,故过期条目
必然走到 `fetch_catalog`):

- 刷新成功 → 缓存文件被重写(时间戳新鲜、旧条目已被替换);
- 刷新失败 → 缓存文件**未被改写**(saved_at 不变)且旧载荷作为 last-good 返回。

两条分支都由「读回磁盘」验证,不依赖哪一条在本地/CI 发生;「失败时降级为
last-good」另由 `unreachable_source_falls_back_to_last_good_cache`(连 1 端口
立即被拒,与主机无关)覆盖。

验证:`cargo fmt --check` 0;`cargo clippy -D warnings` 0;
`cargo test --workspace` 134 passed / 3 ignored;本机(离线分支)该测试通过。
- §3 阶段 6 补一条:推送 + 开 PR + 修掉 CI 首轮暴露的环境依赖测试。
- §6 新增第 7 行记录 PR dsh-plugins#47 首轮三平台全挂的根因(断言把「离线」写进测试)
  与修正方式;提交序列补 `fafbcb8` / `b0f7bfa`,并把「待办:push/PR」替换为
  已提 PR 的信息(dsh-plugins#43 合入后自动只显示 dsh-plugins#46 增量)。
- §7 新增一条风险:断言「网络失败后如何」的测试必须 ignore、双向断言或改用
  必然失败的端点,否则本地绿 / CI 红。
* fix(instance): 修复实例窗口 431 与认证失效

- 每个实例使用独立浏览器数据目录:Windows/Linux 走 WebView2 data_directory,macOS 走 WKWebView data store id,避免按 authority 命名、有效期 30 天的 dsh-auth cookie 随实例换端口无限累积,撑破 node:http 16 KiB maxHeaderSize 后所有请求(含携带 token 的)直接返回 431
- 打开已存在的实例窗口时重新导航到最新的 dsh web 令牌 URL,并记录每个窗口最后使用的地址,实例重启后不再停留在过期的认证失败页面
- 导航前清除该实例自身的失效 dsh-auth cookie;Windows 上 cookie 读取放在工作线程,规避 wry 记录的同步命令/事件处理器死锁
- 无可用地址且实例已不在运行时清理该实例浏览器数据并报错,实例仍在启动中则保留窗口不导航
- 删除实例时一并清理其浏览器数据目录
- 新增 loopback_origin 与 dsh-auth cookie 名派生单测

* fix(windows): macOS 上 clear_instance_webview_data_from 触发 dead_code 门禁

- macOS/iOS 走 clear_all_browsing_data 分支,该目录级 helper 在该平台无调用点,
  clippy -D warnings 以 never used 报错导致 Quality (macos) 失败
- 按仓库既有约定(wsl.rs 的 cfg_attr(not(windows), allow(dead_code)))为 Apple
  平台加 cfg_attr allow(dead_code),行为与三平台语义均不变

---------

Co-authored-by: Gu-ZT <administration@ztxy666.cn>
@Gu-ZT

Gu-ZT commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

请求修改(request changes)

设计方向正确且实现质量高:SourceKind 四变体分派穷举完整(fetch_catalog 无不可达分支)、Confidence 用有序枚举支撑「同 id 取最高层」、JoinSet 并发 + 页级预算 + last-good 磁盘缓存、核心包红线做了归一化匹配、i18n 中英 591 键双向零差异、联网测试全部 #[ignore](CI 稳定)。但有 2 处与 issue #46 验收标准("未验证来源有明确标识与安装确认;绝不误装核心包")直接冲突的问题,需修复后合入。

阻塞项 1:上游 verification: "rejected" 条目被当作 Aggregated 收录

dshget_to_marketplugins.rs:368-399)只过滤 installable == falseverificationclone() 透传(plugins.rs:394),且该字段在前端只有类型声明、没有任何渲染src/api/types.tsverification?: string | null 是唯一消费点)。

我实测了默认源(https://cdn.jsdelivr.net/gh/bobby-sheng/dshget-data@main/catalog.json,HTTP 200 / 2,603,554 B / count=2460):

verification 条数
(空) 1460
rejected 826
unverified 173
verified 1

其中 installable == trueverification == "rejected" 的有 221 条,会被本 PR 原样收录,且因为源级 confidence 是 Aggregated,它们比 Unverified 条目更可信、连二次确认都不会触发。样例(都是真实大仓):

  • open-design(nexu-io,87,354 stars,Apache-2.0)——本地优先的设计工具
  • reactive-resume(amruthpillai,40,528 stars)——简历生成器
  • OpenViking(volcengine,28,617 stars)、deepseek-harness-desktopdsh-web-ui

这些正是 issue #46 里点名要降噪的对象(「14,783 个公开仓库……噪声大」),上游已用 rejected 明确标注,本 PR 却把上游的拒绝信号丢掉了。

最小修复(二选一):

  • dshget_to_marketverification 归一化(大小写不敏感、trim)后命中 rejected 时返回 None,与 installable == false 同列;或
  • 保留条目但把它的 confidence 降为 Unverified并且Market.vue 上把 verification 显示出来(否则用户无从判断)。

无论哪条,都请补一条单测覆盖 rejected 分支——现有 dshget_entries_are_parsed_and_uninstallable_skippedplugins.rs:3681)只测了 installable=false

阻塞项 2:可信度可被用户自证,未验证二次确认可绕过

需要说明的是:issue #46 的 D 节确实把 confidence 列为 PluginSourceConfig 的字段,所以"用户可配 confidence"本身不算违背 issue。问题在于它被当成安全门来用,而配置面没有任何约束:

  • entry.confidence = src.confidenceplugins.rs:287-293tag_entry),即条目的可信层级完全由用户持久化的源配置决定;
  • sanitize_plugin_sourcesconfig.rs)只校验 id 非空 / http(s) URL / id 去重,不校验 confidence 与 kind 的对应关系
  • Settings 表单把可信度做成自由下拉,officialSOURCE_CONFIDENCE_OPTIONS);
  • merge_intoplugins.rs:935-964)在 src.confidence > dst.confidence整体覆盖官方源的 name / description / urls / repo / verification;
  • 前端 InstallWizard.vue:23-25needsUnverifiedAck 只看 confidence,于是被提升为 official 的第三方条目既不显示横幅也不显示勾选框canSubmitInstallWizard.vue:100)直接放行。

即:添加一个 kind: dsh-get + confidence: official 的自定义源(指向任意第三方 URL),其条目即可覆盖官方源条目并跳过所有确认。这与 issue 验收标准里的"未验证来源有明确标识与安装确认"冲突。

最小修复(建议前者):

  • sanitize_plugin_sources 里锁死内置 id 的 kind/confidence(dsh-plugins→Official、awesome-dsh-plugin→Curated、dshget→Aggregated、github-topic→Unverified),非内置 id 一律强制 Confidence::Unverified
  • 或把 confidence 从可写面移除(改为按 kind 推导),Settings 相应改为只读展示。

非阻塞建议

  1. plugins.rs:1027-1058 的「超预算 → last-good」分支实际很难命中:fetch_sourceplugins.rs:825-859)已在失败时自行降级到 last-good 并 Ok,所以只有任务被 abort(超预算)或 panic 才会走到这里,而 abort 掉的任务必然还没写缓存,读到的只会是上一次刷新的内容——日志文案「超出预算,改用 last-good 缓存」在这种情况下是误导。建议把降级统一收敛到一处(fetch_source 只回报 Err,由 fetch_market_impl 统一兜底),并同步修正 live_fetch_market 注释里「源失败即不出现在合并结果里」的假设。
  2. plugins.rs:1031Err(e) => log_warn!("插件源任务异常: {e}") 丢掉了源 id(id 绑到了 _),排障时无法定位是哪个源 panic,建议保留。
  3. Market.vue 沿用 sourceOf(p) !== 'dsh-plugins'(base 行为),导致官方源不显示 plugins.source.dsh-plugins 标签,该文案成为死键;既然官方源也是多源之一,建议统一显示。
  4. mock 与真实后端在「源过滤」上分叉:case 'fetch_plugin_market' 固定返回 6 条,不看 db.settings.plugin_sources;而默认设置里 github-topicenabled: falseMarket.vueenabledSources 只过滤下拉选项、不过滤列表,于是预览里「GitHub topic」标签始终可见但下拉里没有该项;在预览的 Settings 里停用/删除源也不影响列表。建议 mock 按启用源过滤,否则本 PR 的核心交互在预览中无法验证。
  5. sanitize_plugin_sources 承担 id 去重 / URL 白名单 / order 重编号三项持久化契约,但 config.rs 整文件没有测试模块。建议补 3~4 条硬断言(空 id 丢弃、非 http(s) 丢弃、重复 id 保留首个、order 重编号、github-topic 空 URL 放行)——修阻塞项 2 时正好一起补。
  6. Market.vue:62CONFIDENCE_COLORS[confidenceOf(p)] 对未知字符串会得到 undefined 颜色(TS 层保证不了后端运行时值),建议加 fallback。
  7. docs/ISSUE46_TASK_TREE.md 里「后端不做额外拦截(用户自选 confidence 即视为信任)」这句与验收标准有张力,修完阻塞项 2 后请一并更新,避免后来者照着它继续放宽。

验证情况

  • 增量口径:本 PR 堆叠在 feat: 支持修改启动器数据目录位置(issue #43) #44 之上,我按 git diff pr-44...pr-47(15 文件 / +2416 −167)审查 [Feature] 扩展插件市场发现来源:可配置多目录源 + GitHub topic 实时发现 + 可信度分层 #46 增量,未把 migrate.rsdocs/ISSUE43_TASK_TREE.md 计入。
  • 逐行读过:plugins.rs(源注册表、adapter 分派、tag_entrydshget_to_marketfetch_sourcemerge_plugins/merge_intofetch_market_impl、topic 通道与缓存、去重/核心包/降噪相关单测)、config.rsSourceKind/Confidence/PluginSourceConfig/sanitize_plugin_sources/default_plugin_sources)、lib.rscommands.rs,以及前端 Market.vue/InstallWizard.vue/VersionPick.vue/Settings.vue/stores/launcher.ts/api/index.ts/types.ts 与双语 locale。
  • 实测:默认 dshget 源的真实响应(HTTP 200 / 2,603,554 B / 2460 条),并统计出 rejected 826 / 其中 installable 221,样例条目已列出(阻塞项 1 的硬证据)。
  • 已确认:github_repo_of 全仓无残留(无死代码)、sha2/chrono 依赖来自 feat: 支持修改启动器数据目录位置(issue #43) #44(本 PR 未动 Cargo.toml)、verification 在前端无消费点、联网测试(live_dshget_catalog_parses_and_filters_corelive_fetch_marketlive_fetch_plugin_versions)均带 #[ignore]stale_topic_cache_is_refetched_instead_of_served 在联网与离线两种环境都走稳定分支。
  • CI 4/4 通过;未跑重型本地构建。

修好两个阻塞项后即可合入。另外请注意合并顺序:本 PR 依赖 #44,需 #44 先合入(#44 我提了两个阻塞项,见该 PR 评论)。

yukitakasama and others added 4 commits September 14, 2026 14:29
- 扫描导入报告逐项 added/skipped 结果及原因,支持绑定首选版本
- mock 的 import_scanned 补齐 items 明细,修复浏览器预览 TypeError
- ImportScanDialog 清理未使用代码,版本行判断改为直接谓词
- resolved dsh-plugins#39
- DSH_LAUNCHER_DATA_HOME > 指针文件 > 默认目录 的解析链
- 启动时一次性迁移:复制/校验/切换/旧目录快照,失败回退
- 迁移后重写 config.json 中落在旧目录下的 versions[].dir / homes[].path
- 修复每次启动累积 .old-* 快照;补 30 天快照保留期裁剪
- 设置页数据目录卡片 + e2e 迁移测试
- resolved dsh-plugins#43
- dshget_to_market 丢弃上游审查 rejected 的条目:rejected 是主动否定
  信号,不应以 Aggregated 可信度出现在市场(线上目录有 221 条
  rejected 且 installable 的条目)
- sanitize_plugin_sources 锁定信任指派:内置来源 id 的 kind/confidence
  恢复为预置值(URL 镜像定制保留),自定义来源一律强制 Unverified,
  杜绝自我声明 official 覆盖合并去重与绕过未验证安装确认
- load_config 对存量配置自愈,清除已持久化的自我声明信任等级
- Settings 添加来源表单移除可信度选择器(改为展示性标签),
  双语 hint 说明信任等级由启动器指派
- config.rs 新增 4 个 sanitize 测试;plugins.rs dshget 测试补 rejected 用例
@Gu-ZT
Gu-ZT merged commit ba6d005 into dsh-plugins:main Sep 14, 2026
8 checks passed
@Gu-ZT

Gu-ZT commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

审查后修复并合入(ba6d005)。

合入前由我修复的阻断问题:

  1. dshget rejected 条目上架dshget_to_market 只过滤 !installableverification 原样透传 —— 线上目录实测有 221 条 rejected 且 installable 的条目(含数万 star 的热门仓库)会以 Aggregated 可信度出现在市场。rejected 是上游审查的主动否定信号,现在一律丢弃;测试补 rejected 用例。
  2. 可信度自我声明sanitize_plugin_sources 不校验 confidence,自定义来源可自称 official —— 既能在合并去重时覆盖官方条目的 repo hint(安装目标劫持),又能绕过前端的未验证安装确认(needsUnverifiedAck 只看 confidence)。现在信任等级由启动器指派:内置 id 锁定预置 kind/confidence(URL 镜像定制保留),自定义来源一律强制 Unverified;load_config 对存量配置自愈;设置页添加表单移除可信度选择器(改为展示性标签),双语 hint 已说明。

另外将本 PR 分支重新基于含 #40/#44/#45 的新 main(migrate.rs 冲突取 main 侧),PR diff 收敛为纯增量 14 文件。

新增 config.rs 4 个 sanitize 测试。本地门禁:fmt ✓ / clippy -D warnings ✓ / cargo test 153 ✓ / vue-tsc ✓ / 前端构建 ✓;CI Quality 三平台 ✓。

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants