feat(plugin-market): 插件市场多源发现 + 可信度分层 + GitHub topic 实时通道 (issue #46) - #47
Conversation
…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>
请求修改(request changes)设计方向正确且实现质量高: 阻塞项 1:上游
|
| verification | 条数 |
|---|---|
| (空) | 1460 |
rejected |
826 |
unverified |
173 |
verified |
1 |
其中 installable == true 且 verification == "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-desktop、dsh-web-ui
这些正是 issue #46 里点名要降噪的对象(「14,783 个公开仓库……噪声大」),上游已用 rejected 明确标注,本 PR 却把上游的拒绝信号丢掉了。
最小修复(二选一):
dshget_to_market对verification归一化(大小写不敏感、trim)后命中rejected时返回None,与installable == false同列;或- 保留条目但把它的 confidence 降为
Unverified,并且在Market.vue上把verification显示出来(否则用户无从判断)。
无论哪条,都请补一条单测覆盖 rejected 分支——现有 dshget_entries_are_parsed_and_uninstallable_skipped(plugins.rs:3681)只测了 installable=false。
阻塞项 2:可信度可被用户自证,未验证二次确认可绕过
需要说明的是:issue #46 的 D 节确实把 confidence 列为 PluginSourceConfig 的字段,所以"用户可配 confidence"本身不算违背 issue。问题在于它被当成安全门来用,而配置面没有任何约束:
entry.confidence = src.confidence(plugins.rs:287-293的tag_entry),即条目的可信层级完全由用户持久化的源配置决定;sanitize_plugin_sources(config.rs)只校验 id 非空 / http(s) URL / id 去重,不校验 confidence 与 kind 的对应关系;- Settings 表单把可信度做成自由下拉,含
official(SOURCE_CONFIDENCE_OPTIONS); merge_into(plugins.rs:935-964)在src.confidence > dst.confidence时整体覆盖官方源的 name / description / urls / repo / verification;- 前端
InstallWizard.vue:23-25的needsUnverifiedAck只看confidence,于是被提升为official的第三方条目既不显示横幅也不显示勾选框,canSubmit(InstallWizard.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 相应改为只读展示。
非阻塞建议
plugins.rs:1027-1058的「超预算 → last-good」分支实际很难命中:fetch_source(plugins.rs:825-859)已在失败时自行降级到 last-good 并Ok,所以只有任务被abort(超预算)或 panic 才会走到这里,而 abort 掉的任务必然还没写缓存,读到的只会是上一次刷新的内容——日志文案「超出预算,改用 last-good 缓存」在这种情况下是误导。建议把降级统一收敛到一处(fetch_source只回报Err,由fetch_market_impl统一兜底),并同步修正live_fetch_market注释里「源失败即不出现在合并结果里」的假设。plugins.rs:1031的Err(e) => log_warn!("插件源任务异常: {e}")丢掉了源 id(id绑到了_),排障时无法定位是哪个源 panic,建议保留。Market.vue沿用sourceOf(p) !== 'dsh-plugins'(base 行为),导致官方源不显示plugins.source.dsh-plugins标签,该文案成为死键;既然官方源也是多源之一,建议统一显示。- mock 与真实后端在「源过滤」上分叉:
case 'fetch_plugin_market'固定返回 6 条,不看db.settings.plugin_sources;而默认设置里github-topic是enabled: false,Market.vue的enabledSources只过滤下拉选项、不过滤列表,于是预览里「GitHub topic」标签始终可见但下拉里没有该项;在预览的 Settings 里停用/删除源也不影响列表。建议 mock 按启用源过滤,否则本 PR 的核心交互在预览中无法验证。 sanitize_plugin_sources承担 id 去重 / URL 白名单 / order 重编号三项持久化契约,但config.rs整文件没有测试模块。建议补 3~4 条硬断言(空 id 丢弃、非 http(s) 丢弃、重复 id 保留首个、order 重编号、github-topic 空 URL 放行)——修阻塞项 2 时正好一起补。Market.vue:62的CONFIDENCE_COLORS[confidenceOf(p)]对未知字符串会得到undefined颜色(TS 层保证不了后端运行时值),建议加 fallback。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.rs、docs/ISSUE43_TASK_TREE.md计入。 - 逐行读过:
plugins.rs(源注册表、adapter 分派、tag_entry、dshget_to_market、fetch_source、merge_plugins/merge_into、fetch_market_impl、topic 通道与缓存、去重/核心包/降噪相关单测)、config.rs(SourceKind/Confidence/PluginSourceConfig/sanitize_plugin_sources/default_plugin_sources)、lib.rs、commands.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 条),并统计出
rejected826 / 其中installable221,样例条目已列出(阻塞项 1 的硬证据)。 - 已确认:
github_repo_of全仓无残留(无死代码)、sha2/chrono依赖来自 feat: 支持修改启动器数据目录位置(issue #43) #44(本 PR 未动Cargo.toml)、verification在前端无消费点、联网测试(live_dshget_catalog_parses_and_filters_core、live_fetch_market、live_fetch_plugin_versions)均带#[ignore]、stale_topic_cache_is_refetched_instead_of_served在联网与离线两种环境都走稳定分支。 - CI 4/4 通过;未跑重型本地构建。
修好两个阻塞项后即可合入。另外请注意合并顺序:本 PR 依赖 #44,需 #44 先合入(#44 我提了两个阻塞项,见该 PR 评论)。
- 扫描导入报告逐项 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 用例
|
审查后修复并合入(ba6d005)。 合入前由我修复的阻断问题:
另外将本 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 三平台 ✓。 |
概述
修复 #46:插件市场此前只消费两个硬编码 URL(
plugins.rs的MARKET_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);install行dsh plugin --profile web add github:owner/repo完全复用既有的parse_awesome_install,无需新解析器。installable === false(605 条);description{en,zh}双语兼容;上游sources[]透传为归属。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. 粒度红线(硬性)
@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. 降级与缓存
data_dir/plugin-cache/<id>.json);源不可达时降级为缓存,首次运行无缓存则如实报错并跳过,不影响其余源。8. 顺带修复
alpha_commit原先靠静态市场回查定位 repo,实时通道新增的插件必然查不到 → 改为接受条目自带repo提示,resolve_repo统一解析。9. CI 门禁修复(独立提交
d245626).github/workflows/ci.yml要求cargo fmt --check与clippy -D warnings,而本分支前几轮后端改动已引入 15 处未格式化位置 + 1 处clippy::unnecessary_to_owned⇒ 修复前该 PR 的 CI 必然失败。此提交只做门禁修复,无行为变更。验证
CI 五步本地全绿:
cargo fmt --all -- --checkcargo clippy --workspace --all-targets --locked -- -D warningscargo test --workspace --lockedvue-tsc --noEmitvite build联网冒烟(
--ignored):live_fetch_market✅ —— 三个默认源各自贡献条目(dsh-plugins / awesome-dsh-plugin / dshget),全程无「获取失败」告警,零核心包。该测试新增「每个已启用源都必须在合并结果里出现自己的sourceid」硬断言:源失败原先只log_warn!静默跳过,没有任何断言能发现「某源其实没贡献」。live_dshget_catalog_parses_and_filters_core✅ —— >1000 条,全部带source/confidence,github 条目全部带repo提示,无核心包。live_fetch_plugin_versionsapi.github.com,本机不可达(需代理),未能实抓;与 topic 通道同一网络限制(见下)。已知限制
api.github.com/raw.githubusercontent.com不可达,故降噪逻辑仅有单测覆盖(4 项),无线上实测。正因如此该通道默认关闭,由用户开启并自备可用代理。cdn.jsdelivr.net。若该 CDN 不可达,dshget 降级为 last-good 缓存(首次运行则无缓存,仅剩 2 源);用户可在设置页改回raw.githubusercontent.com或自建镜像。plugin.dshx.dev无公开 JSON API(Nuxt SSR),暂不接入。SourceKind变体 + adapter)。文档
docs/ISSUE46_TASK_TREE.md—— 阶段任务树 + 逐轮回填日志(含验收标准对照、风险与开放问题)。依赖说明
本分支基于 PR #44 的 8 个提交(issue #43 数据目录可迁移)构建 —— 设置页与
config.rs的改动需要它。若 #43 先合入 main,本 PR 会自动只显示 #46 的增量。