feat: v0.3.8–v0.3.14 工作区汇总(依赖升级、整理来源、手动入库、原地入库等)

生产 v0.3.8~v0.3.13 均由 8013196 加工作区修改构建部署,此前未提交;本提交补齐源码,
并含未部署的 v0.3.14 原地入库。中间各版本源码状态未保存,无法逐版拆分,详见
docs/plan/17-full-upgrade.md 与 docs/plan/18-organize-release.md。

- v0.3.8 全面升级:Deno workspace 依赖、Router 8 / Vite 8、camofox 1.18.0 / Node 24、
  PostgreSQL 18.6、备份客户端 18.6、演示 qB 5.2.4
- v0.3.9 媒体整理:分类规则、整理来源与目录快照(0059)、文件管理整理入口
- v0.3.10 手动下载与入库:独立手动下载、详情页资源下载、TMDB / Local 元数据兜底
  (metadata.resolve_organize)、正常多版本 / 一次性洗版(0060)
- v0.3.11 搜索详情与桌面黑边修复
- v0.3.12 列表分页、搜索历史、首页概况
- v0.3.13 统一整理弹窗与队列
- v0.3.14 原地入库(0061,未部署)

同批审计修复:
- 刮削入队:确认原记录存在后才删重放产生的新记录;写回 run 关联失败时保持 queued,
  由处理器补关联(对齐 MP 先登记、只在入队失败时记失败)
- 识别升级链只在结果更确定时采用,不再用 no_match 顶替原有歧义候选
- bluray_dir 资产以原盘目录本身为刮削根(MP 同做法)
- metadata.resolve_organize 登记到入库排障 Skill 与能力地图
- db/src/types.ts 按迁移重新生成;contracts 整理动作枚举顺序与数据库对齐
- 测试:原地入库用例改为直接查记录表;domain 测试模板补 version
- 前端:通知铃铛弹层与用户菜单统一样式;站点卡片共用卡头、底栏贴底、分页间距

依赖升级证据只提交摘要文件,registry-snapshot.json 移至 .local/(SHA-256 记于文档)。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-02 15:47:17 +08:00
1 parent 8013196e3f
commit ceb66f8c77
265 files changed
+17751 -2483

No files matched your search

+6
View File
@@ -1,5 +1,11 @@
# Pi 模型上游与订阅登录(pi-ai / pi-coding-agent 0.87.1)
> 2026-10-01 升级补充:当前接入目标已更新为 pi-agent-core/pi-ai 0.99.2,执行结果见 [全面升级记录](../plan/17-full-upgrade.md)。下文保留 0.87.1 的研究基线,不用历史计数验收新版。
>
> 新版实际目录为 42 个内置 provider(新增 TypeSafe 分类服务),合同和目录回归已同步;TypeSafe 没有 Agent 聊天模型,目录说明已标明。OAuth 共 9 个 provider:新增 `openai` 原生 Sign in with ChatGPT,浏览器流程与回调端口 1455;现有 `openai-codex` 仍保留 device/browser 两种模式。新版 `openai` 是动态注册的公开客户端流程,没有照搬旧 Codex 客户端身份提示。来源:[0.99.2 OpenAI provider](https://github.com/earendil-works/pi/blob/v0.99.2/packages/ai/src/providers/openai.ts)、[原生 ChatGPT OAuth](https://github.com/earendil-works/pi/blob/v0.99.2/packages/ai/src/auth/oauth/openai-chatgpt.ts)。
>
> Pi 原生 MCP 客户端可复用,但本次依赖升级没有新增外部 MCP 工具配置;本项目对外 MCP 服务端、权限和审批仍按既有设计运行。
> 只读研究结论,依据本机 `~/.cache/deno/npm/registry.npmjs.org/@earendil-works/{pi-ai,pi-coding-agent}/0.87.1` 的 dist 源码与随包 docs(`docs/providers.md`、`models.md`、`custom-provider.md`)。
> 目的:设置页支持 pi 的全部上游与订阅式登录。结论以代码为准,未核实的不写。
+3 -1
View File
@@ -1,5 +1,7 @@
# 首个可用版本(v0.1)工程规划
> 本文保留最初任务书与用户追加要求的历史记录。后续段落里的分支状态、未做清单和粗估不作为当前排期;继续开发前请先看 [当前开发情况基线](13-development-baseline.md)(2026-10-01,v0.3.7)。
编制:2026-09-27。需求基线:`../../media_automation_requirements_architecture_v0.7.md`(下称 REQ)。本文件是所有开发子任务的统一任务书;与 REQ 冲突时以 REQ 的产品要求为准,技术选型以本文件为准。
## 1. 技术决策(ADR 摘要,详见 docs/adr/)
@@ -12,7 +14,7 @@
| 数据库 | PostgreSQL 16;Kysely + pg;SQL 迁移文件 + Kysely Migrator;`kysely-codegen` 或手写 DB 类型 | 开发用 docker-compose 起 `postgres:16-alpine`,端口 55433。 |
| 持久任务引擎 | 优先 `[email protected]`(peer: postgres.js);**须先通过 spike 验证**(重启恢复/等待信号/取消/重试)。未通过则用 `packages/tasks` 内的 PG 租约式任务表(lease + attempts + dead-letter)。 | 结论写 ADR-002。 |
| Agent 内核 | `@earendil-works/[email protected]` + `@earendil-works/[email protected]`,锁版本;通过自有 `AgentRuntimePort` 封装,显式工具白名单,不开放 bash/文件系统/任意网络 | 测试用脚本化 fake 模型 provider;真实上游由设置页配置。 |
| 校验/测试 | vitest 5(`deno run -A npm:vitest run`,`deno task test` 逐成员执行);类型门禁两道:tsc 7.0.2(`npm:[email protected]`,Go 原生实现,入口 `tsc`)+ `deno check`(Deno 内置 TS 6.0.3);lint/format 用 biome 2.5.14(开启 `useImportExtensions`,相对 import 必须带扩展名);web 沿用 token 守卫脚本 | `deno task ci` = typecheck(tsc 7.0.2 + deno check)+ lint + test + check:tokens + build(web 构建 + `deno compile` 单文件 server)。W1.5 实测(2026-09-27)连跑 3 次全绿,约 75 秒/次(v0.1 验收时已涨到约 135 秒/次,server 与 tasks 测试是主要耗时,见 04);测试数 server 24、adapters 214(+2 skip)、agent 27、contracts 361、db 11、domain 230、tasks 15、testkit 1、web 2 |
| 校验/测试 | vitest 5(`deno run -A npm:vitest run`,`deno task test` 逐成员执行);类型门禁两道:tsc 7.0.2(`npm:[email protected]`,Go 原生实现,入口 `tsc`)+ `deno check`(Deno 内置 TS 6.0.3);lint/format 用 biome 2.5.14(开启 `useImportExtensions`,相对 import 必须带扩展名);web 沿用 token 守卫脚本 | 当前 `deno task ci` = typecheck(tsc 7.0.2 + deno check)+ lint + test + check:tokens + check:copy + build(web 构建 + `deno compile` 单文件 server)+ check:binary。W1.5 实测(2026-09-27)连跑 3 次全绿,约 75 秒/次(v0.1 验收时已涨到约 135 秒/次,server 与 tasks 测试是主要耗时,见 04);测试数 server 24、adapters 214(+2 skip)、agent 27、contracts 361、db 11、domain 230、tasks 15、testkit 1、web 2 |
| 端口 | web dev 5180,API 4380,PG 55433 | 本机 3000/5175/5176/55432 已被占用,不要用 |
| 参考源码 | MoviePilot v3: `/opt/moviepilot-plus/upstream/MoviePilot`(提交 e6820a8,GPLv3,只做行为对照与 TS 重写,不复制文件)。**数据来源适配(站点 spider、馒头、RSS、TMDB、qB)照抄 MP v3 实现迁移**(用户 2026-09-27 明确):`app/modules/indexer/spider/__init__.py`、`spider/mtorrent.py`、`app/application/rss.py`、`app/modules/themoviedb/tmdbapi.py`、`app/modules/qbittorrent/qbittorrent.py`;站点定义按 `app/application/site/sites.pyi` 的 schema 手写(MP 的定义文件 `user.sites.v3.bin` 是加密的,无法取用)。**用户 2026-09-27 追加:MP 开源的站点框架全部移植**——所有专用 spider(haidan/hddolby/rousi/sunnypt/tnode/torrentleech/yema/mtorrent)与所有站点类型用户信息解析器(nexus_php/nexus_audiences/nexus_hhanclub/nexus_project/nexus_rabbit/gazelle/unit3d/discuz/ipt/file_list/small_horse/zhixing/bitpt/…),文件与函数一一对应,并维护 `docs/porting/mp-sync-ledger.md` + `scripts/mp-sync` 差异脚本,以后跟随 MP 提交增量移植;MovieClaw 若本机不存在则按 REQ 附录链接对照 | 迁移对照记录写 `docs/porting/` |
+2
View File
@@ -1,5 +1,7 @@
# 主线程解耦审计(2026-09-27,只读审计结论 → W4-D 修复清单)
> 历史审计:本文记录当时的问题和修复过程。当前 `GET /inventory/media-servers` 已在 `routes/library.ts` 实现多实例并行、单实例并发限制和总超时,末尾「串行 Emby」不再是当前遗留。v0.3.7 的状态与新的工程检查见 [开发情况基线](13-development-baseline.md) 和 [工程检查与调整建议](14-engineering-review.md)。
## 结论
生产容器 API 与 worker 分进程;RSS/快照/刮削/入库主链路走任务引擎 + outbox。漏网三类:
1. HTTP 请求内同步重活:`POST /library/reconcile`(全量 stat)、`POST /download-cache/cleanup`(删种删数据)、`POST /organization`(planImport 递归 walk)、`POST /capabilities/{id}/invoke` 中 release.search/release.inspect/identity.resolve/catalog.lookup(远程站点/TMDB)、`GET /inventory/media-servers`(串行 Emby)。
+2
View File
@@ -1,5 +1,7 @@
# 需求覆盖矩阵与后续计划
> 历史报告:本文核对的是 2026-09-28 的 `57346d4`,其中未做 / 待合并 / 真机验证状态与数字不代表当前版本。2026-10-01 的 v0.3.7 现状、R01–R32 复核及验证边界见 [当前开发情况基线](13-development-baseline.md)。
2026-09-28。对照 REQ v0.7(`../../media_automation_requirements_architecture_v0.7.md`)逐条核对 main HEAD `57346d4` 的实现。证据来自代码 grep、测试文件与已有验收文档(`04`、`07`、`08`、`10-v0.2.1-check.md`),没有跑新的测试。
标记:
+188
View File
@@ -0,0 +1,188 @@
# 当前开发情况基线
> 此文保留升级前 v0.3.7 的业务基线,下面版本和数量均属该历史核对。后续依赖升级见 [v0.3.8 升级记录](17-full-upgrade.md),当前 v0.3.9 分类/来源功能部署见 [发布记录](18-organize-release.md)。新一批手动下载、详情页下载、Local 元数据与一次性洗版已接入源码、尚未部署,状态见 [MP 对照 §5.6](15-moviepilot-v3-comparison.md#56-本轮实现与验收未部署)。
本报告用于在继续开发前核对 UHD Media Tool 的实际状态。当前已有收录、下载、整理、刮削和智能体的主流程,也有运行中的部署;需求 v0.7 所要求的完整首版仍有缺口。继续开发前应先确定下一阶段要交付的使用场景和验收边界,不能用版本号、页面数或测试数代替需求验收。
核对日期:2026-10-01,时区 Asia/Shanghai。代码基线:`main`,提交 `8013196e3f5e6a8c4ea0cd26cf77294a82a13ddd`,标签 `v0.3.7`。本轮只梳理现状、运行检查和修正文档,没有修改业务实现、部署服务或用户配置。
## 1 证据和判定口径
需求基线是 [需求与架构 v0.7](../../media_automation_requirements_architecture_v0.7.md),后续范围调整以 [工程规划](00-first-version-plan.md) 中用户确认的追加要求为准。历史验收记录只证明当时的版本和场景;本报告结合当前代码重新判断。
| 证据 | 能证明什么 | 不能据此推断什么 |
| --- | --- | --- |
| 当前代码与装配 | 有实现、已接进正式调用路径 | 用户环境里的全部边界均可用 |
| 当前自动化检查 | 指定测试、类型与构建检查通过 | 所有真实站点、模型、挂载都已验证 |
| 脱敏真实样本回放 | 对这些真实页面或标题的解析符合预期 | 登录、下载和风控在真实账号上都能通过 |
| 历史真机记录 | 指定版本和场景曾通过 | 当前版本已重新做过同样验收 |
| 本轮部署只读检查 | 服务健康、报告版本和迁移状态 | 镜像中的每个文件与源码逐字相同、业务全链路无故障 |
下文「已实现」指当前代码与对应回归覆盖已存在;「部分实现」说明缺哪一段;「未实现」指缺少所要求的完整业务能力;「待核验」是证据缺口,不能直接当作代码缺失。
## 2 工程与部署状态
| 项目 | 本轮核对结果 | 证据 |
| --- | --- | --- |
| 工程形态 | Deno workspace,2 个应用、8 个共享包,模块化单体 | [deno.json](../../deno.json)、[仓库结构](../../README.md) |
| 运行时与前后端 | Deno 2.9.7、TypeScript;React 控制台、Hono API、PostgreSQL 16、OpenWorkflow、Pi | [ADR](../adr/ADR-004-deno-runtime.md)、根依赖清单 |
| 服务装配 | 14 个服务模块,18 个注册任务;最初 9 个任务均由正式模块处理器覆盖,没有落到空壳 | [模块清单](../../apps/server/src/modules/index.ts)、[任务装配](../../apps/server/src/context.ts);本轮调用 `buildTaskRegistry` 核对 |
| 公开合同 | 346 个 REST 端点定义,41 个智能体能力;这是合同数量,不是完整需求的完成比例 | 本轮调用 `listEndpoints()` 和读取 `CAPABILITY_IDS`,来源 [api.ts](../../packages/contracts/src/api.ts)、[capability.ts](../../packages/contracts/src/capability.ts) |
| 站点定义 | 23 个内置定义;定义存在不代表该站真实账号已验收 | [定义加载](../../packages/adapters/src/sites/definitions/index.ts)、[移植账本](../porting/mp-sync-ledger.md) |
| 数据迁移 | 56 个迁移文件,最新编号 `0058_scrape_record`;部署数据库也已应用到该迁移 | [迁移目录](../../packages/db/migrations)、本轮只读查询 `kysely_migration` |
| 当前部署 | 应用、PostgreSQL、浏览器容器健康;应用健康接口报告 v0.3.7、数据库 `ok` | 本轮 `docker ps` 和 `GET /api/v1/health`,2026-10-01 13:02 左右 |
| 部署组成 | 核心应用容器含 API、IO worker、Agent worker 和 web 静态文件;PG、浏览器分别部署,可选 Caddy 提供 HTTPS | [compose](../../docker-compose.yml)、[运行手册](../runbook/deploy.md) |
| 本机附加组件 | 另有代理中继、本地模拟 qB 和开发 PG;不能把模拟 qB 当作真实 PT 下载验收 | [本地模拟说明](../runbook/deploy.md)、本轮容器状态 |
应用版本和迁移编号与代码基线一致。镜像标签没有源码提交号,本轮没有核对构建来源的精确提交;后续发布可补记录构建提交和镜像摘要。
本轮记录的运行应用 image ID 为 `sha256:9d65bf0170f35e685a1ddd9ebfab74088f378138e7c02879488e97b089691629`,对应本机 `uhd-media-tool:latest` 的同一摘要。该摘要只标识运行产物,不补足缺失的源码 revision 标签。
## 3 主流程实际覆盖
| 流程 | 已有行为 | 当前边界 |
| --- | --- | --- |
| 获取资源 | RSS 抓取去重、站点快照、实时搜索、详情缓存、23 个站点定义、账号与健康管理 | 站点实测覆盖不完整;Torznab 索引器仅定义结构 |
| 确认作品 | 标题与副标题解析、本地召回、TMDB、字段锁、人工纠错、待识别池;认不准时升级到详情页 ID | 真实标题样本不能代表全库识别准确率;综艺分类与覆盖仍不完整 |
| 决定收录 | 新作品、追更、升级模式;规则组、多版本目标、分集账本、日历和覆盖矩阵 | 独立双版本组合校验未接入;智能体主观选片与规则学习未实现 |
| 提交和跟踪下载 | 多 qB、管理标签、授权、去重、磁盘水位、下载面板、接管与下载历史 | 未完成四站真实下载全链路验收;默认不会自动换源 |
| 整理入库 | Copy / Move、跨卷恢复、固定路径绑定、命名模板、字幕随行、逐文件结果和回收站 | 不支持整理硬链接、软链接和 Rclone;旧库全量接管不完整 |
| 刮削与展示 | 就地写 NFO、海报、季海报和剧照;任意目录识别与候选选择;整理记录筛选、统计和批量操作 | 与 MP 有明确登记的文件布局差异;不能把刮削成功视作 Emby 已完成索引 |
| 持续自动化 | 持久任务、后台调查与授权内恢复、巡检、审批、预算、子会话、SSE、审计 | 最新提示的真实模型前后对比未跑;自动化成功率与人工介入率缺持续运行基线 |
主流程回归见 [E1 收录入库](../../apps/server/test/e2e/e1-rss-to-library.test.ts)、[E2 智能体委托](../../apps/server/test/e2e/e2-agent-delegate.test.ts)、[E4 崩溃恢复](../../apps/server/test/e2e/e4-crash-recovery.test.ts)、[E6 授权内恢复](../../apps/server/test/e2e/e6-auto-recover.test.ts)、[E7 剧集](../../apps/server/test/e2e/e7-tv-series.test.ts)、[E9 持续追更](../../apps/server/test/e2e/e9-continuous-series.test.ts)。外部系统主要由 mock 或样本回放提供,持久任务与数据库集成使用真实开发 PG。
## 4 需求逐项核对
本表重新核对 R01 至 R32 的主要实现与缺口,不计算整体完成百分比。测试明细以本报告第 7 节为准,真实交互边界以第 6 节为准。
| 需求 | 当前实现状态 | 当前证据与剩余边界 |
| --- | --- | --- |
| R01 多个 RSS | 已实现 | [来源测试](../../apps/server/test/sources-identity)覆盖抓取、窗口和去重;跨 Feed 并发摄取的专项证据仍需单独核对 |
| R02 综艺正片覆盖 | 部分实现 | 能解析内容类型、上下分段;尚无「上+下满足一期」及节目级附加内容策略 |
| R03 TMDB 滞后不阻断 | 已实现主要行为 | 本地临时季集、总集数账本和追更已接入;一对多编号关系未完整建模 |
| R04 独立双版本 | 部分实现 | 多个收录版本目标存在;[checkDistinctAssets](../../packages/domain/src/slot/completion.ts)未被服务端调用,同一资产不能算两个目标的校验未落地 |
| R05 每日新增自动收录 | 已实现 | 新作品、追更、升级模式与规则评估存在;每日汇总视图不是现有交付 |
| R06 浏览器辅助站点 | 部分实现 | camofox、视觉操作、人工接管及 Cloudflare 级联已接入;通用 HTTP 失败转浏览器不完整,真实挑战仍待验证 |
| R07 固定最终路径 | 已实现 | 路径绑定与整理回归保证译名变化不自动改目录;显式文件移动另记修订 |
| R08 本地身份独立 | 已实现 | 本地实体、外部映射、别名、人工锁与合并修订存在 |
| R09 映射与巡检 | 部分实现 | 库根与资产存在性对账存在;外部身份巡检、媒体服务器对账缺完整流程 |
| R10 辅助刮削 | 部分实现 | 智能体辅助识别与元数据补全、NFO/图片写入已做;没有独立字段级 `metadata.apply` 能力,不能因此把刮削写成「未做」 |
| R11 参考项目迁移 | 已实现主要工程 | 有来源账本、MP 差分与偏离登记;文件布局也有运行差分,但不代表所有转移场景均有运行对照 |
| R12 Pi 推理内核 | 已实现 | Pi 封装、能力白名单与有界执行已接入;模型供应商的联网覆盖另算 |
| R13 API 和 MCP | 已实现 | REST、OpenAPI、MCP、鉴权和 SDK 集成测试存在;合同数为 346、能力数为 41,旧文档数字过期 |
| R14 qB 标签纳管 | 已实现 | 提交、接管、去标签后停止管理及保留历史有回归 |
| R15 整理与缓存清理 | 已实现主要行为 | Copy/Move、跨卷、校验、保留期和 H&R 保护;硬链接与 Rclone 不在现有实现范围 |
| R16 条件和智能体选片 | 部分实现 | 确定性规则已做;独立预算下的主观偏好选片未实现,不能用会话内手动委托代替 |
| R17 自动执行与授权 | 已实现 | 发布规则的持续授权、单次审批、服务端权限与自动化总开关有实现和回归 |
| R18 旧库分范围接管 | 部分实现 | 已有库根只登记/纳管模式及逐项整理;缺首次扫描、影响预览与按作品启用 |
| R19 控制台和智能体双入口 | 已实现 | 同一业务能力注册、页面上下文、审批与待处理入口已连接 |
| R20 偏好标签与学习 | 部分实现 | 标签迁入规则组,编辑、抑制与修订存在;旧「标签不参与评估」需按规则串和兼容字段区分,自动学习与样本回放未完成 |
| R21 缓存硬阈值 | 已实现主要行为 | 同卷多 qB 汇总、阈值暂停与恢复水位存在;未纳管占用的专项验收仍待确认 |
| R22 跨季召回与治理 | 部分实现 | 本地别名、季年份、续作判别、待识别池、详情 ID 识别和真实标题差分均有进展;缺全面召回率、误关联和新节目评估 |
| R23 公开整理记录 | 已实现 | 列表、文件结果、游标增量;本版另加统计、删除和批量操作。删除记录不发增量墓碑,见 [整理手册](../runbook/organize.md) |
| R24 Emby 辅助查询 | 部分实现 | 多实例查询、超时与 unknown 状态存在;库存未用于满足收录目标,缺本地资产对账与真实 Emby 验收 |
| R25 站点快照与限流 | 已实现 | 快照和实时补查已做;PG 令牌桶、共享缓存已在 0041/0042 落地,不再是「c2a 待合并」 |
| R26 模型与能力配置 | 已实现,联网覆盖不完整 | 上游、模型、思考、预算、压缩与登录配置存在;有部分真实模型历史记录,41 个 provider 和各订阅登录未逐一实测 |
| R27 不默认自动换源 | 已实现默认边界 | 无进展记录证据,不默认换源;委托换源的「新任务+原任务处置」尚未合成一个替换计划 |
| R28 单管理员与多实例 | 已实现 | 登录、TOTP/Passkey、API Key、多下载器/媒体服务器及路径映射存在 |
| R29 自然语言交互执行 | 已实现 | 步骤清单、方案、内联审批、先给方案和后台续跑有回归 |
| R30 PT 工作台 | 已实现,站点验收不完整 | 搜索、资源、详情、账号、下载入口存在;观众和憨憨有真实样本/局部核对,四站完整验收仍缺 |
| R31 同会话人工接管 | 已实现主要行为 | 截图模式、Webtop/Selkies 同会话桌面、租约、交还与视觉操作已做;真实输入法和客户端兼容性尚未全测 |
| R32 浏览器后端配置 | 已实现一种后端 | camofox 配置与版本核验存在,固定 v1.17.0 有真机记录;其它 fork/版本不能直接沿用核验结果 |
对应运行说明:[身份](../runbook/identity.md)、[订阅](../runbook/subscriptions.md)、[规则](../runbook/rules.md)、[整理](../runbook/organize.md)、[文件](../runbook/files.md)、[智能体](../runbook/agent.md)、[浏览器](../runbook/browser.md)、[缓存](../runbook/cache.md)、[MCP](../runbook/mcp.md)。
## 5 历史状态需要纠正的地方
历史文档按当时的基线保留,不把其中每条「未做」直接搬到当前待办。
| 历史说法 | 当前核对结果 | 证据 |
| --- | --- | --- |
| 所有能力只在 mock 上验证 | 已有浏览器、TMDB、部分模型及短剧补全的真机记录;覆盖仍有限 | [浏览器手册](../runbook/browser.md)、[工程规划后续记录](00-first-version-plan.md)、[身份手册](../runbook/identity.md) |
| 刮削不写 NFO 和图片 | SCR-1/SCR-2 已实现,任意目录可就地刮削 | [刮削服务](../../apps/server/src/modules/acquisition-organize/services/scrape.ts)、[刮削测试](../../apps/server/test/file-manager/scrape.test.ts) |
| 跨进程限流和缓存正在 c2a 分支 | 已合入,PG 令牌桶、UNLOGGED 缓存与图片代理存在 | [缓存手册](../runbook/cache.md)、0041/0042 迁移 |
| 原站视图还是占位或只有截图 | 已有同会话桌面,截图作为回退;camofox v1.17.0 有真机核验 | [浏览器手册](../runbook/browser.md)、[桌面模块](../../apps/server/src/modules/desktop/index.ts) |
| `agent.spawn {await:true}` 一直占 worker 槽 | 当前正常会话驱动支持挂起与恢复,E11 直接验证等待期间槽位空闲 | [子会话实现](../../apps/server/src/modules/agent/subagents.ts)、[E11](../../apps/server/test/e2e/e11-subagents.test.ts) |
| 版本规格只能在订阅侧看 | 作品详情已有分集资产版本与目标比对 | [版本服务](../../apps/server/src/modules/acquisition-organize/services/library-versions.ts) |
| 任何站点 HTTP 失败都不会转浏览器 | Cloudflare 页面挑战已有自动/视觉/人工级联与浏览器代抓;通用失败转浏览器仍不完整 | [Cloudflare 服务](../../apps/server/src/modules/sources-identity/service/cloudflare.ts) |
| 库根离线没有按根因去重 | 整理入口已有 `library_root_offline:<rootId>` 去重;跨业务的统一根因聚合未完整确认 | [整理服务](../../apps/server/src/modules/acquisition-organize/services/organize.ts) |
| 备份恢复完全没做过演练 | 早期临时环境中实际备份、清库、恢复和映射比对通过;当前版本自动定期演练未做 | [部署验证记录](../runbook/deploy.md)、[备份手册](../runbook/backup-restore.md) |
| 看到 tasks 中的 stub 就说明主流程未实现 | 正式装配已覆盖最初 9 个任务,stub 仍作为注册兜底保留 | 本轮比较正式和默认处理器,见第 2 节 |
另有历史问题未确认终态:能力统计可能把正常挂起记成失败、个别浏览器状态提示及跨版本流程恢复。现有统计按审计中的 error/invalid 计失败,不能仅凭旧截图判为已修或仍有故障,需要针对当前版本复现。
## 6 真实环境验证边界
| 对象 | 已找到的证据 | 仍需补的证据 |
| --- | --- | --- |
| TMDB | 工程规划记载真实搜索、识别、订阅季集、海报和缓存验证 | 对下一阶段的固定样本重新验收;不能将历史记录等同于本轮重跑 |
| 浏览器 | v1.17.0 实容器的登录保持、捕获下载、同标签接管与重启;Webtop 原型、视觉点击和插件可信鼠标事件 | 四站真实挑战、输入法组字、客户端浏览器差异;保活、自愈等新变化的实机边界 |
| 憨憨与观众 | 憨憨真实标题差分和局部核对;观众真实脱敏列表/详情样本 | 逐站账号登录、搜索、下载、促销、H&R、过期恢复、文件清单的完整验收 |
| 馒头与 CHD | 定义、适配器和 mock/离线样本测试 | 真实账号全流程证据 |
| qB | 多版本兼容代码、mock 回归、本机运行的 qB 5.1.2 模拟容器 | 用户真实下载目录、挂载与 PT 下载全链路;模拟器可运行不证明真实服务已验收 |
| Emby/Jellyfin | 兼容查询实现和 mock 测试 | 真实认证、分页、库存及资产映射验收 |
| 模型上游 | 规划记载 OpenCode Go/DeepSeek 的部分历史场景;视觉与网页补全有局部真机记录 | AG-5 分层提示的真实前后对比明确未跑;不应声称所有 provider 已实测 |
| 媒体挂载 | 临时文件系统、跨卷和故障恢复回归 | 真实 NFS/FUSE/mergerfs 等规模与故障基准;不能承诺大库性能 |
真实模型前后对比的缺口来自 [评测记录](../design/agent-prompt-eval.md);浏览器核验细节见 [浏览器手册](../runbook/browser.md)。本轮没有连接真实 PT 账号或模型上游,也没有产生下载、刮削或清理用户文件的动作。
## 7 本轮检查结果
同一会话上一轮已完成:全仓 TypeScript 检查通过;domain 21 个文件、642 个测试通过;E1、详情 ID 识别、NFO 与布局差分共 4 个文件、25 个测试通过。
本轮对同一业务代码基线运行完整 `deno task ci`,明确指定开发 PG `127.0.0.1:55433/umt`,集成测试使用临时 schema。检查退出码为 0,完整通过;server 测试于 13:08:06 开始,耗时 538.15 秒,随后其它包检查、构建和编译自检均通过。
| 包 | 通过文件 | 跳过文件 | 通过测试 | 跳过测试 |
| --- | --- | --- | --- | --- |
| server | 122 | 1 | 756 | 1 |
| adapters | 58 | 1 | 459 | 3 |
| agent | 9 | 0 | 82 | 0 |
| contracts | 7 | 0 | 1036 | 0 |
| db | 4 | 0 | 21 | 0 |
| domain | 21 | 0 | 642 | 0 |
| mapping | 2 | 0 | 22 | 0 |
| tasks | 6 | 0 | 17 | 0 |
| testkit | 2 | 0 | 5 | 0 |
| web | 24 | 0 | 224 | 0 |
| 合计 | 255 | 2 | 3264 | 4 |
跳过条件按源码核对:server 的真实模型评测未启用;adapters 的真实 qB 兼容测试没有配置 `QB_REAL`,整个文件未运行;以 root 执行时,三个目录/文件权限拒绝测试主动跳过。真实 qB 文件在没有目标时不生成测试,因此不能仅凭「4 个测试跳过」理解全部外部验证缺口。数据库包与任务包测试均实际执行;server 只有一个文件跳过,没有把 PG 集成文件整体跳过。
非阻断输出:Biome 有一条测试代码 literal-key 提示;web 构建有依赖注释和 sourcemap 提示,构建成功。本轮没有为消除这些提示修改实现。
完整 CI 包含 tsc 与 Deno 类型检查、Biome、各包 Vitest、设计 token 守卫、文案标点、web 构建、server 编译与二进制启动自检。前端全页面 Playwright 冒烟和真实模型评测不包含在普通 CI 内;即使 CI 全绿,也不将这两类算作本轮通过。
本轮原始日志:`/tmp/umt-development-baseline-ci.log`。日志是本机临时证据,最终结果汇总写在本节,不能依赖临时日志长期存在。
完整 CI 后的文档勘误不改变业务代码;文档本身另外核对了本地链接、事实引用和差异格式。本轮没有运行镜像重新构建或前端页面冒烟。
## 8 当前缺口和工程风险
| 项目 | 分类 | 当前判断 | 可验收的交付边界 |
| --- | --- | --- | --- |
| 综艺完整性 | 核心功能缺口 | R02 未完整交付 | 用真实节目样本验证分段组合、正片完整性、附加内容策略和完整版替换 |
| 独立双版本 | 核心功能缺口 | R04 的开关和域层校验未接入服务端 | 同一物理资产不能同时满足要求独立的两个目标,覆盖预留和最终入库 |
| 旧库接管 | 核心功能缺口 | R18 缺完整扫描、预览和分范围启用 | 首扫可续跑、错误不当完成,先预览再按范围开启,既有路径保持稳定 |
| 智能体选片与规则优化 | 核心功能缺口 | R16/R20 缺完整实现 | 在硬规则和授权内做偏好判断,理由可查;反馈、回放、发布和回滚可验收 |
| 外部映射和媒体服务器对账 | 功能缺口 | R09/R24 不完整 | 区分 unknown 与缺失,核对资产映射;是否允许外部库存满足目标需显式策略 |
| 换源替换计划 | 功能缺口 | 新提交与原任务处置尚未绑定 | 一份可审核方案说明两边动作,分别匹配授权并处理部分失败 |
| 备份自动化 | 运维缺口 | 看板 `maintain.backup` 仍 unavailable;脚本和早期手工演练存在 | 当前版定期备份与隔离恢复演练,行数、映射和只读恢复状态可核对 |
| 增量扫描错误语义 | 已确认的代码边界 | [scanIncremental](../../packages/adapters/src/fs/scan.ts)收集目录/stat 错误后仍可能返回 complete;当前服务端未调用 | 接旧库流程前明确 partial/失败及续扫规则;不能把跳过文件算完整扫描 |
| 空壳任务兜底 | 维护风险 | 当前正式任务已覆盖,但遗漏注册会静默回显 todo | 后续新增或重构时核对正式注册与任务版本,不只看默认注册表 |
| 关键故障场景 | 验收证据缺口 | 历史清单中的 AT18、AT29、AT42、AT73 和流程版本升级,尚未逐项重新形成当前验收记录 | 恶意标题、部分入库不清理、未纳管占用、多实例同 hash、旧任务跨版本恢复分别给出证据 |
| 性能与自动化效果 | 验收证据缺口 | 未建立按真实负载统计的持续基线 | 记录规模、挂载、延迟、无人干预完成率、人工介入、误关联、费用与待处理年龄 |
| 文档与发布来源 | 工程管理缺口 | 旧计划、README、覆盖表、部分手册状态互相矛盾;镜像未记源码提交 | 当前基线作为讨论入口,历史报告标清日期;发布记录附构建提交、镜像摘要和验证结果 |
上表不是已批准的开发排期,也不对缺口给出未经验证的固定工期。主观选片、规则学习和现有故障修复应按用户场景确定边界,不能在一次任务中笼统打包为「做完智能体」。
用户确认开展独立检查后,两项中等思考强度的只读代码/验证检查和一项低思考强度的文档检查发现了更具体的恢复与验收边界。见 [工程检查与调整建议](14-engineering-review.md),其中区分代码已确认、实际影响待查和纯证据缺口。
## 9 里程碑判断与下一阶段讨论
按需求 §15 的口径,工程底座和 M1 主流程已有较完整实现,M2 的一部分能力也已交付,但 M0 的部分验收证据和 M2 的核心差异化需求仍不完整。因此不能直接宣称 M0/M1 全部验收完成,也不能继续沿用历史「M2 约三分之一」作为当前精确进度。
下一阶段讨论应基于以下四项材料:本报告中的当前能力、真实环境证据、缺口清单、现有检查结果。先确认目标使用场景,再选择范围:是先稳定现有电影/剧集收录,还是优先完成综艺与独立双版本,或先解决旧库接管。这里列的是待讨论的选择,不自动开工。
建议在恢复功能开发前,为选定范围写清:用户从哪里触发、最终看到什么结果、哪些失败需要调查或人工处理、用哪些固定样本验收、需要哪些真实环境。每项工作完成后更新本报告或后续阶段验收记录,避免再次积累「待合并」和「未做」的过期状态。
本轮仍未确认的事项应继续标为待核验,不据此删减原需求;已做但缺真机证据的能力应优先按场景验收,不重新从零实现。
+107
View File
@@ -0,0 +1,107 @@
# 工程检查与调整建议
本报告回答「继续开发之前是否需要先处理工程问题」。当前版本完整 CI 通过,主流程实现和部署均存在;检查仍发现任务升级、入队与业务记录一致性、故障状态判定以及验收口径需要先厘清。建议先做一轮范围明确的恢复与验收补强,再确定后续功能范围。
日期:2026-10-01。升级前业务代码基线:`main`,`8013196`,`v0.3.7`。开发情况与 R01 至 R32 覆盖见 [当前开发情况基线](13-development-baseline.md)。本轮采用两个中等思考强度的独立代码/验证检查、一个低思考强度的文档检查,由主代理复核和汇总。该检查阶段没有修改业务实现、提交、部署或执行数据修复。后续用户授权的依赖与容器升级执行状态见 [完整升级记录](17-full-upgrade.md)。
后续核查按用户确认先逐项参考 MoviePilot v3 的业务逻辑,再讨论调整。进度见 [MoviePilot v3 逐项业务对照](15-moviepilot-v3-comparison.md):已固定 v3.0.10-1 源码,第一项任务恢复与升级兼容完成源码对照;后续已实施局部恢复修正并做故障注入,见下方当前落实情况。
并行完成的版本检查见 [依赖与程序版本报告](16-dependency-version-review.md):记录 58 个直接依赖、主锁文件和浏览器独立审计、运行程序版本,以及 PG 18/Pi 原生 MCP 的迁移边界;该版本检查阶段没有执行依赖更新或部署。
## 当前落实情况(2026-10-01)
用户讨论后授权的恢复修正已落到源码:引擎接受任务后回填关联失败保留 queued 并记日志;worker 执行时补关联;巡检优先查最新 run 并修复关联,查询失败跳过当前轮次,不误判成不存在补投。刮削去重复用原业务记录,不让回填失败把已接受的任务标成失败。
`enqueue-recovery.test.ts` 在隔离 PostgreSQL schema 中完成 9 个故障测试,包括关联写失败、原 run 修复、已有活跃 run 的查询异常。连同接管、刮削和手动季集覆盖回归,5 个测试文件共 34 个测试通过。发布前旧任务检查补到 [部署手册](../runbook/deploy.md#6-升级)。没有引入新恢复器、任务状态机或永久旧 handler。
后续媒体整理范围经过用户逐项讨论后实现:可编辑 TMDB 分类 YAML、单来源配置、复制/移动、qB 标签接管、首次基线+增量快照、一次性存量向导。运行说明见 [整理手册](../runbook/organize.md)。这轮功能已发布为 v0.3.9,见 [发布记录](18-organize-release.md);下文检查表保留检查阶段的事实和其他仍需讨论的项目。
## 1 结论如何使用
「代码已确认」说明能从当前控制流或配置看到该边界;「影响待复现」说明尚未做故障注入,也未证明用户已经受影响;「验收证据不足」说明已有实现不能用当前证据验收完整要求。下文建议是供讨论的工作范围,不是已执行的修复或已批准的排期。
完整 CI 的 3264 个通过测试能证明现有固定回归通过;不能证明未结束的旧版本任务、线上故障下的双写恢复、真实模型行为或真实媒体挂载已经验收。应为这些具体边界补证据,而不是只扩大通过测试的总数。
### 1.1 用户确认的工程取舍
用户认可任务恢复的调整方向,同时明确本产品面向团队内部,避免过度设计和过度防御。后续优先修复已确认、会影响正常使用的局部问题,复用现有任务引擎、幂等键、巡检和记录页面。MoviePilot 用于参考同一场景的业务处理,不照搬其全部基础设施。
临时查询异常保留日志并等待下一轮,不新增人工审核流程;普通可重试失败使用已有重试,最终失败说明原因并支持现有入口重试。只有删除、覆盖、替换文件等操作出现实际状态不明或冲突时,才停止自动执行并提示处理。没有复现需要之前,不增加通用恢复框架、第二套任务状态机或新的补偿服务。
旧任务兼容先用发布前检查和处置清单解决;没有在途旧任务时,不为假设场景长期维护旧处理器。验证围绕本次改动的失败分支和文件保护展开,T01 至 T06 是场景清单,不作为继续所有开发的统一前置门槛。当前版备份恢复和部署验收已在升级阶段完成,见 [升级记录](17-full-upgrade.md),后续针对实际变更补充验证。
## 2 建议优先核对的恢复边界
### 2.1 刮削任务升级后的旧任务承接
**代码已确认,当前部署未发现未结束的旧刮削任务。** [handlers.ts](../../apps/server/src/modules/acquisition-organize/handlers.ts) 第 193 行起只注册 `scrapeMedia` v2,输入是 `recordId`。旧版本 v1 使用作品 ID 和触发方式等输入。worker 在 [openworkflow-engine.ts](../../packages/tasks/src/openworkflow-engine.ts) 第 221 行起按已注册的任务名和版本过滤认领,当前清单没有 v1。
因此升级前未结束的 v1 run 如果存在,当前 worker 没有对应处理器。0058 迁移还将原 `media_scrape` 表替换为 `scrape_record`,不能简单恢复旧处理器而不核对数据结构。需要明确旧任务应完成、迁移、取消还是以说明终止。
本轮对部署数据库只读聚合:`scrapeMedia|v1|completed|1`,没有其它刮削任务状态;`scrape_record` 没有记录。**这次没有发现受影响的活动旧任务,也没有据此做任何取消或补投。** 这个结论只对应本次检查时点。
最小下一步:把「升级前未结束的任务版本清单及处置」加入发布记录。在隔离环境用上一版本入队、当前版本恢复验证兼容方案,避免只验证同版本崩溃恢复。
### 2.2 入队成功和业务记录关联回填不是一个原子操作
**控制流已确认,故障影响待复现。** [scrape.ts](../../apps/server/src/modules/acquisition-organize/services/scrape.ts) 第 152 行起先插入 `queued` 记录,第 192 行入队,第 207 行回填 `engine_run_id`。入队成功而回填失败,也进入同一个 catch,将记录标为 `failed/task_enqueue_failed`。第 476 行的执行器对 failed 记录直接返回。
可能出现两种不一致:插入后、入队前进程退出,留下没有 run 的 queued 记录;入队已成功、回填失败后记录先被标为 failed,worker 再读取时跳过。实际结果取决于失败时点,本轮没有通过故障注入证明发生概率,也没有把它写成已发生的线上故障。
[common.ts](../../apps/server/src/modules/acquisition-organize/services/common.ts) 第 134 行的 `enqueueTracked` 也依次执行业务行、引擎入队和回填,应一起定义恢复口径。稳定幂等键可以帮助找到已有 run,但本身不等于已完成关联恢复。
最小下一步:在隔离测试中分别注入这三个时点的失败,确认最终状态。再选择恢复回填与补投方案,或复用现有事务 outbox;保持改动集中在这些入口。
### 2.3 引擎查询失败被当成查无任务
**异常处理行为已确认,重复补投的实际影响待复现。** [common.ts](../../apps/server/src/modules/acquisition-organize/services/common.ts) 第 171 行在巡检中使用 `engine.get(...).catch(() => null)`,查询异常和明确不存在共用 null。下一时间槽可能补投新 run,而旧 run 仍在运行,共享同一业务任务行。
下载与文件操作已有底层幂等账本,不能直接推断会重复下载或覆盖文件。但两条 run 竞争业务行、回填关联和状态的风险,需要单独验证。
最小下一步:故障注入中模拟一次引擎查询异常;讨论让查询异常记录并跳过本轮,仅在明确查无 run 或终态时补投。这个边界适合与 2.2 一起检查。
### 2.4 默认空壳可以掩盖正式任务注册遗漏
**维护风险已确认,当前核心任务都有正式处理器。** [context.ts](../../apps/server/src/context.ts) 第 96 行为缺失的核心任务注册 stub;[modules.test.ts](../../apps/server/test/modules.test.ts) 第 86 行主要检查任务名存在。未来如果漏注册真实 handler,名字检查仍可能通过,stub 回显 todo 后可以成功结束。
本轮装配核对确认最初 9 个核心任务均已由业务模块覆盖,不应把当前主流程描述成「还是空壳」。
最小下一步:下一次触及模块或任务注册时,增加完整生产模块装配的处理器来源断言;讨论是否只允许局部测试装配使用 stub。无需因此重写任务系统。
## 3 应先明确的验收口径
| 检查项 | 当前事实 | 需要补的最小证据 |
| --- | --- | --- |
| PG 测试必执行 | 部分 server/tasks harness 在 PG 探测失败时跳过;默认 db 包连接失败会报错,所以不能称默认整条 CI 会在无 PG 时全绿 | 在 CI 汇总中保留跳过清单,讨论严格 PG 模式;区分允许跳过的真实模型和真实 qB |
| 前端冒烟 | 独立于普通 CI;[smoke.mjs](../../apps/web/scripts/smoke.mjs) 第 188 行详情页数据获取失败或为空会 skip,最终主要按失败数退出 | 固定演示数据、必须执行的详情页,以及接口错误和合法空数据的不同判定;本轮没有跑页面冒烟 |
| 模型行为 | E13 有恶意网页清洗、URL 与不可信标注回归,但用固定 FakeScript;AG-5 真实前后评测默认关闭且历史记录明确未跑 | AT18 的真实模型行为单独评测,不用 fake 模型脚本替代;模型调用须在明确范围内进行 |
| 部分入库后的清理 | [downloads.ts](../../apps/server/src/modules/acquisition-organize/services/downloads.ts) 第 1043 行检查最近整理成功并拒绝失败/排队/运行/取消文件,已有保护 | AT29 构造部分成功仍有源文件的反例,核对不会整种清理;不能写成「没有删除保护」 |
| 未纳管占用 | 域层有 `managed:false` 和增长风险断言;服务层现有阈值测试主要使用假磁盘 | AT42 用固定同卷场景核对汇总占用和暂停范围 |
| 多实例同 hash | 多下载器选择有测试,未找到两个实例同 hash 后分别同步、暂停、删除的完整专项断言 | AT73 在 mock qB 的两个实例中核对任务与清理隔离 |
| 备份一致性和恢复 | [backup.sh](../../scripts/backup.sh) 依次 pg_dump、导出映射、归档在线会话,产物不是同一时点;早期临时恢复演练曾通过 | 当前版隔离恢复演练,明确在线变更如何影响映射和会话比对,再决定是否需要一致性改造 |
| 镜像运行与来源 | 编译自检在空环境验证模块图可加载,不能替代最终镜像的进程、工具、静态文件、权限和挂载检查 | 下一次发布记录源码提交和镜像摘要,并做隔离镜像启动验收 |
本轮完整 CI 中 PG 集成实际运行;上述 PG 问题属于后续执行环境变化时的验收可靠性,不是本轮大量跳过集成测试。没有新增或改写测试来掩盖缺口。
## 4 已解决的工程问题与文档调整
已有 cleanup/reconcile 入队、后台任务编排、IO 与 Agent worker 隔离、文件/网络/维护分道、请求限制器、整理 walk 上限、sha256 子进程和操作账本。`GET /inventory/media-servers` 已多实例并行、限制实例内并发并设总超时,旧串行遗留不能继续作为待开发项。
本轮文档调整集中在影响当前判断和操作的内容:建立需求基线与工程检查报告;将早期覆盖表和解耦审计标为历史;校正 README 的能力数、刮削、验证和部署形态;统一当前部署示例的 `.env.deploy`;修正默认桌面镜像构建前提、浏览器内存配置、MCP 工具数、站点详情补请求和识别异步说明。
基线中的所有本地文件链接均另行检查。历史演练表和对应日期、测试数继续保留,避免把新结论改写进旧验收记录。源码中的旧注释与较早手册可能仍有残留,遇到冲突以当前代码和这两份基线报告为准。
## 5 供讨论的下一阶段范围
建议下一阶段先以「任务升级和异常恢复可核验」为范围,交付 2.1 至 2.3 的故障与升级证据、当前恢复演练、明确的测试跳过清单和发布来源记录。2.4 可在同一轮触及装配时补强。这里是建议,尚未修改对应实现或开始功能开发。
然后再确定功能阶段:综艺完整性、独立双版本、旧库接管、智能体选片与规则优化都仍有需求缺口,但应按具体场景分别验收。每阶段要明确触发入口、最终结果、失败和等待处理、固定样本与真实环境需求。
讨论时需要决定的是下一阶段的目标和边界,以及哪些验收证据必须先补。已有授权、稳定路径和清理保护不需要重新设计;尚未复现的问题应先做有针对性的核查,再确定最小实现调整。
## 6 升级核验新增的待讨论证据
2026-10-01 的 1.18 浏览器升级核验已覆盖正常重启、空闲回收、旧元素引用拒绝、登录保持与 SIGKILL 后未落盘登录丢失识别。现有核验脚本原先会捕获错误后返回成功,且仍期待自动重连之前的行为,本次已修正并收紧下载关联和脱敏断言。
精确恢复页面地址仍有证据缺口:核验 a 阶段末尾曾导航回列表,b/idle 恢复观测地址为详情页,缺少 a 末尾的数据库 URL 与最终快照对照,目前不能判定为已复现业务故障。后续应在重启前记录 `BrowserService.view(sid).currentUrl`、`snapshot.url`、`browser_session.current_url` 与当前 `browser_tab.url`,重启后逐一比较;恢复入口见 `apps/server/src/modules/browser/service.ts` 的 `restoreUrl(row.current_url)` 及适配器 `reopenSession`。十项能力核验不等同于精确 URL 恢复已经验收,下一轮业务对照应补这个场景。
+310
View File
@@ -0,0 +1,310 @@
# MoviePilot v3 逐项业务对照
继续开发前,先逐项核对现有业务与 MoviePilot v3 的处理逻辑。每项同时说明业务结果、失败边界、本项目差异和需要补的证据;完成对照后再讨论实现调整。本文是当前对照记录,尚未完成的项目明确列为待核对。
日期:2026-10-01。本项目业务代码基线:`8013196e3f5e6a8c4ea0cd26cf77294a82a13ddd`,`v0.3.7`。前置材料:[开发情况基线](13-development-baseline.md)、[工程检查](14-engineering-review.md)。初始对照阶段只读源码并更新文档;后续用户授权的实现状态见第 4、5 节。
## 1 参考基线和判定方法
| 项目 | 本轮固定基线 |
| --- | --- |
| MoviePilot 仓库 | [jxxghp/MoviePilot](https://github.com/jxxghp/MoviePilot) |
| 参考发布版本 | `v3.0.10-1`,提交 [`0aa857173f77de31c7c8d9d2e12052d99f37bcc1`](https://github.com/jxxghp/MoviePilot/tree/0aa857173f77de31c7c8d9d2e12052d99f37bcc1),2026-09-28;`version.py` 已核对 |
| 分支查询 | 本轮只读查询时 `v3` 分支为 `5741d3c56d761d87868d4f2d0515ac5c498f94d6`;本报告采用上面的发布标签,后续逐项核对不随分支移动 |
| 本地参考位置 | `/tmp/umt-moviepilot-v3-review-20261001`,独立浅克隆,未改上游源码 |
| 旧资料 | [既有移植文档](../porting/moviepilot-transfer.md)使用 `e6820a8`/早期 v3.0.0;原参考仓库保持不变,旧样本结论不直接升级为本轮结论 |
| 证据范围 | 阅读当前源码、迁移和测试断言;没有启动 MP 服务或运行上游测试,也没有对本项目新增故障注入 |
MP 是优先采用的业务参考;用户已确认尽量复用其成熟业务逻辑和实现,存在明确需求差异时再讨论调整。最终行为仍由本项目需求和用户确认决定。两边使用不同任务和数据机制,只比较同一场景的业务结果,不因模块名字相近就认定能力相同。已有 MP 差分样本、运行记录和有意偏离登记继续保留,按各自提交解释。
每项记录五件事:触发场景;MP 的明确处理分支;本项目正式调用路径;差异属于实现缺口、验收缺口、有意调整还是暂不适用;拟采用的规则及最小验证场景。源码结论、未复现影响和讨论建议分开。参考行为与来源登记沿用 [移植规范](../porting/license-and-provenance.md)。
## 2 顺序和进度
按下面顺序逐项讨论。状态「源码对照完成」只表示这一项的控制流核对已完成,不表示故障验收或实现调整已经完成。
| 顺序 | 业务主题 | 核对重点/需求 | 本轮状态 |
| --- | --- | --- | --- |
| 01 | 任务持久化、恢复和升级兼容 | 接受请求、入队、回填、中断恢复、旧任务处置;工程检查 §2 | 源码对照完成,恢复原则已认可;局部恢复修正和 9 个故障测试已完成,见第 4 节 |
| 02 | 下载纳管与实例隔离 | 管理标签、接管、去标签、同 hash 多实例、暂停/删除范围;R14、R28 | 正在逐项讨论;下载入口与浏览器详情页交接已确认,见第 5 节;其余待核对 |
| 03 | 部分入库、缓存清理与磁盘水位 | 未完成文件、H&R、保留期、未纳管占用、同卷汇总;R15、R21 | 待核对 |
| 04 | 整理计划、替换、路径与记录 | 冻结目标、跨卷、字幕随行、替换旧版本、记录删除;R07、R15、R23 | 待核对;01 仅覆盖恢复机制 |
| 05 | 刮削与媒体文件布局 | NFO/图片、缺失与覆盖、部分失败、任意目录、自动触发;R10、R11 | 待核对;01 仅覆盖刮削任务入队 |
| 06 | 识别、身份与映射治理 | 本地身份、人工锁、详情 ID、跨季、元数据滞后、错误关联;R03、R08、R09、R22 | 待核对 |
| 07 | 订阅完成条件与多版本 | 追更、综艺正片/上下段、整季包、独立双版本;R02、R04、R05 | 待核对 |
| 08 | 规则、选片、升级与换源 | 硬条件、优先级、偏好学习、替换计划、授权边界;R16、R20、R27 | 待核对 |
| 09 | RSS、站点快照、搜索与详情 | 去重补漏、缓存新鲜度、限流、文件清单、四站证据;R01、R25、R30 | 待核对 |
| 10 | 浏览器辅助与人工接管 | HTTP/浏览器切换、挑战升级、同会话、交还与重启;R06、R31、R32 | 待核对 |
| 11 | 旧库接管、库存与媒体服务器 | 初次扫描、影响预览、分范围纳管、查询 unknown、资产对账;R09、R18、R24 | 待核对 |
| 12 | 智能体执行与授权 | 能力调用、审批、后台等待、预算、恢复与模型证据;R12、R17、R19、R26、R29 | 待核对 |
| 13 | API、公开记录与管理员入口 | 双入口行为、增量、鉴权、多实例配置;R13、R23、R28 | 待核对 |
| 14 | 验收、备份恢复与发布 | 必执行测试、页面样本、版本迁移、恢复演练、镜像来源;工程检查 §3 | 待核对;MP 中无等价要求的部分独立验收 |
## 3 第一项:任务持久化、恢复和升级兼容
### 3.1 业务场景与对照结论
| 场景 | MP v3.0.10-1 | 本项目 v0.3.7 | 差异判定与建议 |
| --- | --- | --- | --- |
| 请求已接受,执行队列暂时失败 | 整理入口先持久化 admission 并取得租约,再入进程内队列;入队失败保留持久记录和错误,交给恢复路径 | `enqueueTracked` 依次写业务任务、引擎入队、回填 run;`queueScrape` 也有三步,回填失败共用入队失败 catch | **恢复边界需要补强。** 已接受但未关联成功应保留可恢复事实;不能仅因回填失败就宣称外部入队失败。具体双写方案待故障验证后选择 |
| 查询恢复记录失败 | `__replay_pending` 的 claim 查询异常记录日志并返回,本轮不恢复;明确空结果另行返回 | `enqueueSweep` 的 `engine.get(...).catch(() => null)` 把查询异常与不存在合并,随后可按新时间槽补投 | **状态判定需要调整。** 查询失败应记录并跳过本轮;补投必须依据明确的不存在/可重投终态,并保留现有幂等与租约边界 |
| 升级后遇到旧任务/检查点 | 有版本化输入和检查点;当前和指定 legacy 检查点显式解码,未知版本拒绝;一次执行账本迁移将有旧执行迹象的任务隔离到 `manual_review` | 当前只注册 `scrapeMedia` v2,旧 v1 输入不同;0058 删除旧 `media_scrape` 表,worker 对旧版本没有对应认领处理器 | **升级处置缺口。** 不能无限承诺自动兼容,也不能让旧任务无声悬空。升级前列出在途版本,再决定兼容执行、迁移或带理由终止;无法确定副作用时保留证据并人工处理 |
| 已完成的外部步骤遇到进程中断 | 成功步骤直接返回持久结果;遗留 `started` 先观察,已发生则补成功,未发生才重做,未知/冲突进入人工复核 | OpenWorkflow 持久步骤、`tasks_op_ledger` fencing、`asset_operation`、冻结计划和文件恢复已经存在;E4 和 tasks 崩溃恢复测试覆盖同版本 worker 中断 | **保留现有机制,补指定故障证据。** 不能把入队关联缺口扩展成「没有崩溃恢复」。完整文件冲突和替换场景留在 04 逐项核对 |
| 业务结果提交与后续事件通知 | 整理历史、终态结算、receipt 和 outbox 由同一短事务提交,提交后再派发 | 整理核验中资产/路径、业务记录和 `organization.changed` 在业务事务内提交;outbox 中继再向引擎派发 | **方向一致。** 本项目已有 outbox,但刮削与通用任务入口尚未因此获得原子关联;还需核对中继的重投窗口和业务唯一约束 |
| 正式 handler 意外漏注册 | MP 的 `runtime/tasks.py` 管理进程内异步任务生命周期,与本项目的任务名+版本 handler 注册不是同一机制 | `buildTaskRegistry` 缺核心任务时注册 stub;现有测试主要断言名称。当前正式装配已覆盖最初 9 个核心任务 | **本项目独立维护风险。** 建议正式装配验证 handler 来源,缺失时明确失败;MP 的生命周期 TaskRegistry 不能证明这个问题已有等价解决 |
这里的 MP 行为限定在已读的整理任务链,不能推广成 MP 的全部刮削、下载或任意任务都遵守同一协议。尤其 MP 的「持久准入+内存队列」与本项目的「业务库+持久引擎库」不等价:可以借鉴恢复规则,不能照搬队列实现。MP claim 的未命中也可能表示没有取得租约,并非严格等价于本项目查询 run 得到「不存在」。
升级兼容也有明确范围:MP 的分类检查点 v1→v2 迁移遇到已有执行状态、执行载荷或步骤证据时不重写旧计划,继续使用已知旧版本解码路径。这支持「保留已经产生的执行证据」的规则,不能据此承诺任意旧 handler 都能继续执行。见 [检查点迁移](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/database/versions/d8f2b6a4c1e7_3_0_28.py#L290)。
本项目刮削双写控制流已确认,但本轮没有故障注入证明实际受影响。上一轮线上只读检查未发现未结束的旧版刮削 run,也没有 `scrape_record` 记录;该时点结论不代替升级策略。见 [工程检查 §2](14-engineering-review.md#2-建议优先核对的恢复边界)。
### 3.2 精确来源
以下 MP 链接全部固定在 `0aa8571`,行号仅适用于该提交。上游测试名称说明已存在对应断言,**本轮没有运行这些测试**。
| 结论 | MP 源码与测试 | 本项目源码/已有验证 |
| --- | --- | --- |
| 先持久接受,再安排执行 | [workflow.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/application/transfer/workflow.py#L116) `TransferQueueService.put`;[queue.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/chain/transfer/queue.py#L1194) `__record_enqueue_failure`;[test_transfer_queue_service.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/tests/test_transfer_queue_service.py#L139) `test_transfer_queue_service_commits_admission_before_failed_enqueue` 使用 SQLite 仓储注入队列失败 | [common.ts](../../apps/server/src/modules/acquisition-organize/services/common.ts) `enqueueTracked` 第 134 行;[scrape.ts](../../apps/server/src/modules/acquisition-organize/services/scrape.ts) `queueScrape` 第 152 行 |
| 查询异常不当作不存在 | [queue.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/chain/transfer/queue.py#L754) `__replay_pending` 第 754 行;[admission.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/db/adapters/transfer/admission.py#L296) `claim_recoverable`;[test_transfer_pending_replay.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/tests/test_transfer_pending_replay.py#L423) `test_replay_survives_db_failure` 断言不执行恢复 | [common.ts](../../apps/server/src/modules/acquisition-organize/services/common.ts) `enqueueSweep` 第 159 行起 |
| 旧执行迹象保守隔离 | [models.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/application/transfer/models.py#L485) `TransferPlanCheckpoint.from_payload`;[迁移](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/database/versions/e5c7a9b1d3f6_3_0_16.py#L404) `_backfill_pending`;[test_transfer_execution_migration.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/tests/test_transfer_execution_migration.py#L282) `test_upgrade_is_conservative_and_repairs_interrupted_indexes` | [handlers.ts](../../apps/server/src/modules/acquisition-organize/handlers.ts) 第 193 行;[0058](../../packages/db/migrations/0058_scrape_record.ts);[引擎](../../packages/tasks/src/openworkflow-engine.ts) `startWorker` 第 221 行 |
| 步骤恢复先看已有结果和实际副作用 | [execution.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/chain/transfer/execution.py#L193) `_DurableTransferStepRunner.run`;[test_transfer_execution_runner.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/tests/test_transfer_execution_runner.py#L148) 成功步骤不重做、未知孤立步骤进入人工复核断言 | [op-ledger.ts](../../packages/tasks/src/op-ledger.ts);[organize.ts](../../apps/server/src/modules/acquisition-organize/services/organize.ts);[E4](../../apps/server/test/e2e/e4-crash-recovery.test.ts)、[tasks 崩溃恢复](../../packages/tasks/test/crash-recovery.test.ts) |
| 结果和事件共同提交 | [chain.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/db/adapters/chain.py#L219) `TransactionalChainDurableEventWriter.transfer_result` | [organize.ts](../../apps/server/src/modules/acquisition-organize/services/organize.ts) 核验事务第 1386 行、`emitRecord` 第 1710 行;[outbox-relay.ts](../../packages/tasks/src/outbox-relay.ts) 第 46 行起 |
| handler 装配风险不可强行类比 | [runtime/tasks.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/app/runtime/tasks.py) | [context.ts](../../apps/server/src/context.ts) 第 96 行;[modules.test.ts](../../apps/server/test/modules.test.ts) 第 86 行 |
另有结算回滚/重放专项断言:[test_chain_durable_events.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/tests/test_chain_durable_events.py#L1373) 检查 outbox 冲突回滚历史与 pending、陈旧租约不写业务、并发结算只提交一次。这些场景值得纳入后续验收,不能把本项目已有的业务事务直接等同于全部专项均已通过。
MP 还在 [test_transfer_planning_checkpoint.py](https://github.com/jxxghp/MoviePilot/blob/0aa857173f77de31c7c8d9d2e12052d99f37bcc1/tests/test_transfer_planning_checkpoint.py#L474) 检查非预览整理缺少 durable writer/execution repository 时,在副作用前拒绝执行。这可支持本项目「关键装配缺失应明确失败」的原则,仍不是相同的 handler 注册方案。
### 3.3 已确认的恢复原则和验收场景
用户认可这一项的恢复方向,并明确避免过度设计和过度防御。以下原则按团队内部产品的规模执行,讨论阶段的原则已落实局部修正,见第 4 节。
1. **请求接受后必须可追踪、可恢复。** 已创建的业务记录、稳定身份和原输入要能关联到已有 run;关联回填失败与真正入队失败要能区分。查不清入队结果时记录不确定性,不能直接假定没有副作用。
2. **不存在、已结束和查不到是三种不同事实。** 临时查询失败跳过本轮并保留诊断;明确查无 run 才进入补投判断;已有运行不能只因到达新时间槽就替换。
3. **升级检查实际在途任务。** 优先等待旧任务结束,或明确说明后终止并通过现有入口重新发起;确有未完成任务必须继续且不能重做时,再评估兼容或迁移。没有在途旧任务时,不新增旧处理器和通用兼容层。涉及已经执行的文件操作时保留原输入和执行证据。
4. **恢复复用已有结果。** 沿用现有冻结计划和已完成步骤;普通查询故障等待下轮重查,可重试失败使用已有重试。删除、覆盖或替换文件的实际状态不明或冲突时,停止自动重放并在现有记录中说明,不为所有异常新增人工审核流程。
最小验收样本:
| 样本 | 注入点 | 应核对的结果 |
| --- | --- | --- |
| T01 | 业务记录插入后、引擎入队前退出 | 能补投或显式结束,不能永远只显示 queued;保留同一业务身份 |
| T02 | 引擎已接受,但 run 关联回填失败 | 找到原 run 并修复关联;不能错误标成入队失败而让 worker 跳过;不能创建第二次外部动作 |
| T03 | 引擎提交后响应丢失,调用方不知道是否接受 | 通过稳定身份与原输入确认已有 run;确认不了时有诊断及等待/人工路径 |
| T04 | 已有 active run,巡检查询一次失败 | 本轮无新增 run;原关联不被覆盖;下一轮查询正常时恢复判断 |
| T05 | 上一版本存在未完成 `scrapeMedia` v1,再启动当前版本与迁移 | 兼容、转换、终止或人工处置有明确结果和证据;无旧 run 永久悬空;迁移前后输入可解释 |
| T06 | 正式装配遗漏一个核心 handler | 装配检查失败或启动时给出明确错误;不能以 stub 的成功回显通过验收 |
已有同版本 kill-worker 测试继续作为回归。T01 至 T06 是针对不同改动的验收场景清单,按实际修复选择,不要求每个功能开发前全部执行。T02、T03 涉及两边不同的队列机制,因此样本按本项目的引擎接口设计,不机械复用 MP 测试。
**当前取舍:保留 OpenWorkflow、冻结计划和现有账本;优先局部修正查询异常判定与入队/关联回填的异常分类,再核实是否可以用已有幂等和巡检完成恢复。** 只有故障样本证明现有机制无法处理时,才评估复用 outbox 等进一步调整;专门恢复器、新状态机和补偿服务不作为默认方案。旧任务处置先落实发布检查清单。第一项实现细节确定后,第二项核对下载纳管与多实例隔离,再进入部分入库后的清理保护。
## 4 用户确认后的当前实现
### 4.1 局部任务恢复
已按第 3 节原则修正入队后关联回填、查询失败补投判定、run 关联恢复与刮削去重。9 个真实 PG 故障样本通过;未新增另一套恢复基础设施。旧版本实际在途任务的发布处置写入部署手册。T05 的跨版本专项和 T06 的 handler 装配强化仍不能因这 9 个测试而宣称完成。
### 4.2 分类、来源与存量
参考插件 [`categoryeditor` v1.3](https://github.com/jxxghp/MoviePilot-Plugins/tree/9b9b14bc0f0bb3890b0f699a84f9bd0df063b2e3/plugins/categoryeditor):插件保存 YAML 并刷新分类 helper,匹配由 MP core 实现。参考 v3 的 `app/domain/classification/projection.py` 的 legacy TMDB 匹配分支:顺序首次匹配、字段 AND、值 OR、排除、年份和空规则兜底。我们内置同类规则编辑能力,保留用户提供的全部名称和兜底习惯;不复制 v3 的完整分类策略版本发布体系。
目录接管参考 MP `app/application/transfer/monitor/snapshot.py`、`poller.py`:先快照现状,再比对新增/变化;完整存量作为单独手动操作。我们采用数据库持久快照、已有识别与整理计划,一条配置一个来源路径。同分类可配置多条不同来源,综艺归 tv;只有复制与移动。qB 标签继续使用现有任务管理和实例范围。
当前源码已接入分类编辑和测试、来源选择、自动/固定分类、qB 配置标签、快照与存量向导。已有路径绑定保留,不按新规则迁移旧库;源离线保留基线,已知 qB 任务不被目录扫描重复接管。具体入口和分批限制见 [整理手册](../runbook/organize.md)。测试使用本项目临时目录与隔离 PG,不是运行 MP 服务;未完成浏览器截图审查;后续 v0.3.9 已发布,见 [发布记录](18-organize-release.md)。
其他主题仍按第 2 节逐项讨论。这轮只补齐与已讨论整理功能有关的分类、标签与目录接管行为,不宣称整个下载隔离、清理、订阅和智能体业务对照已完成。
### 4.3 本次验证记录
- 分类匹配 domain 12 个定向测试;domain 全量 22 文件 / 654 测试通过。contracts 全量 7 文件 / 1048 测试、db 全量 4 文件 / 21 测试通过。
- source monitor 13 个真实 PG/临时文件/HTTP mock qB 测试:基线不处理存量、稳定观察、旧基线保留、分类和失败文件处理、存量只读与分批、文件事实变化、无标签未登记下载等待并在完成后接管。
- 最终合并复验分类 API、来源规划和 source monitor:3 文件 / 23 个真实 PG 测试全部通过。分类 API 与来源规划其中 10 个,包括并发配置保存、固定目录不重复、自动目录层级、已有绑定保留、qB 标签与来源/实例范围,以及媒体类型限制。
- 文件执行、移动、恢复、刮削、接管和向导覆盖最终回归 7 文件 / 38 测试通过;worker lane 注册与文档归属 8 测试通过。
- server 完整回归初次运行 127 文件,783 测试通过、2 失败、1 跳过;失败涉及新任务文档归属及开发过程中分类并发合并,最终相关 3 文件 / 23 测试和 worker lane 8 测试单独复验通过。完整回归不是最终同一时间源码的全绿报告,环境条件跳过也不计为完成验收。
- web 全量 25 文件 / 228 测试、web typecheck 与 production build 通过。workspace TypeScript / Deno 检查、Biome 检查和 `git diff --check` 通过。
没有使用浏览器截图替代或冒充前端验收;本次未替换线上镜像、未执行线上迁移,也未修改宿主机程序。
### 4.4 v0.3.9 发布与文件管理入口
用户要求部署后,核对发现文件管理入口原来只复用向导,没有携带来源配置。本次补齐同根/目录边界/最长来源匹配、唯一匹配自动应用、多配置明确选择及首击等待加载;H&R 与根目录保护保留。新增匹配测试后 web 全量 26 文件 / 232 项通过,typecheck、Biome 和 production build 通过。
v0.3.9 Docker 镜像完成 web build、server compile 和空环境二进制自检后部署;执行 `0059` 迁移,注册 `scanOrganizeSource@1` 和 `organize.sources`。发布前没有在途业务或引擎任务,备份校验通过;部署后 HTTP / HTTPS、版本一致、登录后的分类/来源/文件根读取以及 3 个分类预览通过。详细镜像与证据见发布记录。
## 5 下载入口与浏览器详情页交接(讨论记录)
2026-10-01 用户继续逐项讨论后确认以下业务决策,并随后授权实施。实现与验证见第 5.6 节;这批变更已部署为 v0.3.10。
### 5.1 已确认
- 常规入口包括订阅自动下载、手动搜索选择下载、外部 qB 任务接管,前两种使用较多。三种入口进入共同的后续下载管理和整理流程,保留来源。
- 手动下载独立于订阅,不要求先建订阅,不自动创建持续订阅。
- 优先沿用 MP 普通订阅的完成口径:下载器成功接收资源后记录下载事实,按目标覆盖判断完成,不以整理入库成功作为普通订阅完成的前置条件。下载与整理状态分别展示;洗版和多版本口径后续单独核对。
- 浏览器手动下载入口位于串流窗口外的工具操作栏,桌面串流与截图模式共用。用户进入原站资源详情页后点击「下载当前资源」,复用现有详情解析和下载提交能力,不要求用户点击原站下载按钮或等待文件捕获。
- 下载按钮绑定当前浏览器标签页的资源详情;按站点定义解析资源身份和详情,使用对应站点的种子获取方式。默认下载器与保存目录可直接提交,也提供修改选项;提交结果及下载任务入口在工具操作栏显示。
- 浏览器详情页入口不以资源预先存在于本地搜索/快照索引或已有订阅为条件。需要新增当前页面与详情解析、手动下载的衔接;本地缺少记录不能阻止用户选择的资源进入手动流程。
### 5.2 已核对的代码依据与现有差异
MP 固定基线中的 `app/api/endpoints/download.py` 手动入口使用 `source="Manual"`,不创建订阅;`app/chain/subscribe/search.py` 提交订阅下载后调用完成判断,`app/chain/subscribe/completion.py` 普通电影可在取得下载结果后完成,普通剧集按剩余目标和下载事实判断。外部 qB 任务在配置管理标签时按标签筛选,并由 `app/chain/transfer/queue.py` 检查下载完成、来源监控目录及已有整理状态;无下载历史的任务由文件重新识别。
本项目已有 `packages/adapters/src/browser/camofox/client.ts` 的 `pageContent` 当前页面读取、`packages/adapters/src/sites/spider/detail.ts` 的可配置详情解析,以及 M-Team 等站点的 `detail`/`downloadTarget` 能力。现有 `apps/server/src/modules/browser/routes.ts` 文件捕获入口要求匹配本地资源,不能替代本次确认的详情页直接下载入口。现有搜索/工作台手动提交与收录版本的关联限制也需在后续实现中梳理。
### 5.3 已确认:未识别资源与 TMDB/Local 元数据
MP 手动添加入口识别失败时返回 `requires_confirmation`;前端 `AddDownloadDialog.vue` 允许用户确认继续下载,通过 `allow_unrecognized` 提交最小媒体上下文。该分支不强制用户先指定 TMDB 身份。
用户确认未识别资源可以下载。整理阶段采用以下识别与元数据补全流程:
1. 常规识别先匹配 TMDB;成功后按 TMDB 元数据整理。
2. 自动匹配失败时由 Agent 接棒,读取 PT 详情页并结合网络搜索核对原名、译名、别名、年份及季集信息,再尝试匹配 TMDB。因翻译/别名导致的失败应在查明正确条目后回到 TMDB 模式。
3. 找不到合适 TMDB 条目时进入 Local 模式,由 Agent 基于 PT 详情页及搜寻资料补全标题、简介、年份、类型、演职人员等信息,选取封面,生成本地 NFO 和图片。有依据的字段补全,缺少资料的字段留空。
4. TMDB 与 Local 模式共用分类、命名、复制/移动、整理记录和入库流程。Local 保存独立身份及资料来源,后续可以重新匹配 TMDB;不为 Local 新建一套整理系统。
5. Local 使用补全后的语种、国家、类型等字段匹配现有分类配置;字段不足时使用对应电影/剧集的兜底分类,允许手动调整。
实现复用现有身份候选、元数据补全、字段投影与 NFO 刮削链路;资料不足或候选冲突仍保留待处理。具体实现和验收范围见第 5.6 节。
### 5.4 已确认:已有任务与已有作品
用户认可同种子复用已有下载任务,同一作品的不同资源仍允许手动下载。媒体详情需要展示库内已有版本及规格,用户据此决定下载何种资源;已有作品不作为手动下载的阻断条件。
### 5.5 已确认:正常入库与一次性洗版入库
用户确认在本次下载中选择「正常入库」或「洗版入库」:正常模式允许多版本并存;洗版模式在下载完成后整理时用新版本替换旧版本,是本次任务的一次性规划,不自动变成持续洗版订阅。
- 洗版允许用户选择替换哪些已有版本。只有一个旧版本时默认选中,有多个时由用户勾选,未选择的版本保留。
- 新文件成功落库后再清理对应旧文件;部分整理失败时保留相应旧文件。
- 剧集按实际成功入库的季集范围替换。例如旧版有第 1–10 集、新资源只包含第 1–6 集,只替换前六集。特殊编号、上下段及合并集由 Agent 辅助核对,不能明确对应时供用户调整。
固定 MP 基线 `app/modules/filemanager/transhandler.py` 提供 `always`/`size`/`never`/`latest` 覆盖模式;`latest` 其它版本清理按同目录、季集与 Part 匹配视频文件。它的清理步骤在新文件转移前执行,不能把本项目拟采用的「新文件成功落库后清理旧文件」描述为 MP 原样行为。
多版本是否产生不同路径取决于命名模板。MP 的 `app/runtime/config.py` 默认电影文件名包含 `videoFormat`,默认剧集文件名没有分辨率/编码等版本字段;本项目 `packages/domain/src/naming/defaults.ts` 当前沿用这两条模板。因此需要明确多版本命名方案,不能假定不同资源会自动产生不同文件名。已有 `path_binding` 仍按前述约定保留,模板调整不自动迁移旧库。
用户要求模板可配置,并提供目前使用的两条模板作为参考配置,原样记录如下。本轮未修改线上命名设置。
电影:
```jinja
{{title}}{% if year %} ({{year}}){% endif %}/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{% if edition %} - {{edition}}{% endif %}{{fileExt}}
```
电视剧:
```jinja
{{title}}{% if year %} ({{year}}){% endif %}/Season {{season}}/{{title}} - {{season_episode}}{% if part %}-{{part}}{% endif %}{% if episode %} - 第 {{episode}} 集{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{% if edition %} - {{edition}}{% endif %}{{fileExt}}
```
已核对本项目支持模板编辑、`videoFormat` 和 `edition`。`edition` 按 MP 语义为来源与特效组合(如 `WEB-DL DV`),剪辑版本另有 `cut` 变量,不改变用户提供的模板。模板不能区分的同名文件冲突需沿用整理冲突处理;不据此宣称模板可以区分所有同规格版本。
使用现有命名引擎直接编译并渲染上述两条模板,完整字段及年份/分辨率/edition 缺失的样本均通过;文档差异空白检查通过。此验证未修改任何媒体文件或线上配置。
一次性洗版已接入手动计划和冻结整理计划;同路径与不同路径替换复用现有整理记录、文件执行和操作账本。用户选择的旧版本及季集范围随本次计划保存,验证记录见第 5.6 节。
后续仍需讨论手动选择与自动筛选规则、同 hash 多实例及删除范围。
### 5.6 本轮实现与验收(已部署 v0.3.10)
手动搜索、站点工作台与原站详情共用独立手动下载入口,支持下载器、映射保存目录和正常/一次性洗版选择。未识别先尝试现有身份解析,仍未识别时返回确认结果;确认后建立无 Slot 的手动计划,不创建订阅。迁移 `0060_manual_acquisition` 允许计划无 Slot,并添加 `download_task.import_plan_id` 保存本次入库选择,原下载任务的订阅计划关联继续保留。
原站详情入口在桌面串流/截图之外显示「下载当前资源」与「下载选项」。`POST /browser/sessions/{id}/resource` 从当前可见标签按站点定义读取详情,登记此前没有索引的资源并缓存 PT 内容;不点击原站下载按钮。桌面新增 popup 会被发现,无法唯一确定当前标签时给出明确提示,不提交旧页面。普通 Agent 浏览器动作沿用原标签选择。原生桌面新页未被上游登记时,仍需回到已登记详情页;本轮没有改浏览器插件登记协议。
整理增加 `metadata.resolve_organize`:常规匹配 → 详情页/网络补全与模型抽取 → 别名重查 TMDB → 有资料的 Local 身份。复用现有预算、补全记录、字段来源、分类和刮削;不能将 TMDB 查询故障视为没有条目,候选冲突或资料不足保留待处理。Local 身份不锁定,后续可重新识别。公网封面通过现有图片抓取能力写入;成功的 Local 入库安排 NFO/图片任务,普通 TMDB 自动刮削继续遵循原设置。
一次性洗版冻结用户所选旧文件及事实;新文件核验和资产登记成功后,按实际季集/Part 覆盖清理所选旧版及私有附属文件。同路径替换先暂存旧文件,核验失败恢复旧文件;未选文件、未成功替换的季集、未完整覆盖的合并集、共享图片/NFO及下载缓存保留。清理复用现有回收站与 `asset_operation`;不增加持续洗版订阅。命名模板仍通过设置编辑,本轮没有修改用户线上模板或已有路径绑定。
普通订阅现在按下载器确认接收及实际目标覆盖结束;多目标必须全部满足,TV 未知总集数不伪造完整覆盖。Slot 与下载任务继续表示真实下载/核验进度,洗版目标沿用入库后的判定。
本轮验证:
- 手动下载/订阅/面板 15 项与搜索入口 11 项隔离 PG 测试通过;覆盖未知资源确认、无假订阅、映射目录、同 hash 原路径及新入库计划、多目标订阅完成。
- 浏览器详情入口及既有浏览器 API 共 13 项通过;适配器全量 58 文件/461 项通过、1 文件/3 项环境跳过,其中可见标签交接 12 项定向通过。没有用 fixture 结果替代用户真实浏览器验收。
- 整理、分类与来源 4 文件/18 项通过,包含同路径失败恢复、旧文件变化保护、剧集部分失败/合并集保留,以及 Local 在自动刮削关闭时仍排 NFO/图片任务。领域整理专项 22 项通过。
- Local 与既有元数据补全 21 项通过;NFO/Local/刮削差分 25 项通过,Local 内部人物编号不会写成负 TMDB ID。模型和外部服务使用受控 fixture,没有声称真实模型或全部 PT 站已验收。
- server 完整回归 132 文件:804 项通过、9 项失败、1 项环境跳过。9 个失败集中在 4 个旧测试文件,仍把手动提交视作订阅评估、使用旧订阅完成原因或固定 41 能力。修正测试准备入口和新口径后,这 4 文件合并复验 19 项全部通过;保留实际入库、季集覆盖、资产/文件保留和不重复下载断言,并增加独立手动不创建订阅/Slot 的验证。没有将这次分批复验描述为最终同一时点的单次全量全绿报告。
- contracts 全量 1052 项、db 21 项、domain 656 项、web 232 项通过。workspace TypeScript/Deno、Biome、设计 token、文案标点和 `git diff --check` 通过。
- 用本机 Chromium 与真实 React 组件验证单旧版默认选择、无选择禁用洗版、勾选洗版、切回正常、未知资源二次确认、串流外按钮交接;API 为 fixture,未产生真实下载,页面无未捕获异常。
- web production build、server compile 与空环境二进制模块自检通过。局部证据存于本机 `.local/manual-download-ui/`。
以上业务回归主要为源码与隔离环境验证。随后于 2026-10-01 发布 v0.3.10,线上 `0060` 迁移、HTTP/HTTPS、管理员接口及 6 个生产页面冒烟通过,未触发真实下载或媒体整理;镜像、备份与验证证据见 [发布记录](18-organize-release.md#v0310-手动下载与入库发布)。
### 5.7 v0.3.11 体验修复
搜索资源标题接入与站点工作台同一详情抽屉与读取接口,复用按需详情抓取和缓存,不增加第二套解析器。详情抽屉仍提供下载选项、库存和 Agent 入口。桌面浏览器的最大化规则修复后,上下黑边消失。已部署并经过组件交互、生产真实缓存详情接口与 HTTPS 页面验证,范围和证据见 [发布记录](18-organize-release.md#v0311-搜索详情与桌面黑边修复)。
## 6 整理使用方式与文件管理器专项研究(2026-10-02)
本节只记录研究与最少改动建议,未修改业务代码。MP 后端仍使用 §1 固定提交;补充前端固定源码 `/tmp/umt-moviepilot-frontend-v3-review-20261001`,提交 `63515db2e873d6adaf6aa385a89c5901e3bc1ea6`。**MP 仅源码对照,没有 MP 实际页面截图。** 本项目截图来自本轮 `https://localhost:4380` 已登录页面,使用 Chromium / Playwright,只打开页面、选择项与整理对话框;未点击执行整理、下载、接管或清理,未新增测试数据和来源配置。
### 6.1 实际页面步骤与证据
截图均在 `.local/organize-flow-review-20261002/`,已打开检查;这是本机研究证据,不作为发布包。
| 步骤 | 实际操作与健康情况 | 截图 |
| --- | --- | --- |
| 1 | 整理记录页正常显示作品、源→目标、复制、失败原因和来源;手动整理入口可见 | `01-organize-history.png` |
| 2 | 点击手动整理,当前环境没有整理来源配置,仅显示「手动选择其他来源目录」;可以继续,但空状态没有去新增来源的入口 | `02-manual-source-picker.png` |
| 3 | 打开手动来源目录对话框,下载根与媒体库根可浏览;尚未选择时确认禁用,正常 | `08-manual-directory.png` |
| 4 | 文件管理器打开下载目录,选择一个电影目录后出现底部整理/移动/复制工具栏;移动因做种义务禁用,正常 | `03-file-manager.png`、`05-file-selection.png` |
| 5 | 点击整理,目录展开为一个视频,自动识别作品、显示已有记录和 H&R;页面显示「已选 0 项」但下一步可点,执行范围表达容易混淆 | `06-file-organize-wizard.png` |
| 6 | 下一步显示复制/移动、冲突/跳过/替换、自动/媒体库/指定目录、命名和元数据刷新;H&R 禁用移动,正常;没有提交预览或执行 | `07-file-organize-options.png` |
| 7 | 失败记录菜单点击重新整理,源文件与原作品进入相同向导,正常;未执行 | `10-record-reorganize.png` |
| 8 | 设置页实际显示媒体库、整理方式、刮削、分类、来源与命名;本环境没有来源配置 | `04-settings.png` |
| 9 | 下载面板切换已完成正常,显示已入库与入库失败及原因;下载盘独立展示。未操作下载或接管,下载详情整理仅做源码核对 | `09-download-board.png`、`11-download-completed.png` |
### 6.2 业务边界与 MP 差异
| 场景 | MP 固定源码行为 | 本项目当前路径、差异与最少建议 |
| --- | --- | --- |
| 文件管理器单项/多选整理 | `components/filebrowser/FileList.vue:562`、`:568` 将当前项或去重后的 selected 传给同一个 `ReorganizeDialog`,不是另建整理系统。对话框 `ReorganizeDialog.vue:667` 使用文件项或历史 ID 查询 `transfer/manual/target-path`,展示匹配目的目录;用户明确选择目标后不再覆盖 | `routes/console/files.tsx:392` 过滤视频/目录,进入 `FileSourceSelection` 再共用三步向导,方向一致。来源匹配按根、目录边界和最长路径,唯一匹配自动应用,多匹配需用户选择(`components/organize/source-match.ts:4`、`file-source-selection.tsx:23`)。保留已有保护和预览,不需要再做第二个简化整理弹窗 |
| 手动整理、文件整理、历史重整的来源默认 | MP 相同对话框对 fileitems 与 logids 都查询自动目标,匹配结果包含整理方式和刮削/分类目录选项;后端 `app/api/endpoints/transfer.py:549` 针对各来源匹配目录,不同目标时不宣称共同匹配 | 本项目来源存量带 `sourceConfigId/defaultAction`,文件管理器先匹配来源;但「其他来源目录」直接创建不含配置的 files 来源(`source-selection.tsx:37`),历史和下载详情也直接进向导(`routes/console/organize.tsx:319`、`downloads/download-detail.tsx:233`)。默认方式因此回到全局(`organize-wizard.tsx:233`),请求只在 files 分支透传配置(`:327`、`:341`)。服务器 `services/organize-config.ts:17` 对手动文件不会按目录自动匹配,只有显式配置或带实例/标签的 qB 自动来源。这是入口默认不一致,建议解析完 FileRef 后共用已有来源选择,不另建配置体系;历史重新整理应优先保留原次策略或明确展示当前匹配策略 |
| 成功移动后的重新整理 | MP `app/api/endpoints/transfer.py:737` 对成功且方式含 move 的历史,用历史目标文件作为本次输入;失败/复制使用原源文件 | 本项目 `file-manager/tree.ts:75` 的 `recordSources` 只解析原 source_path/主文件 source_path;源不存在则进入 unresolved。`record-parts.ts:30` 仍让已结束移动记录显示重新整理入口。这会让成功移动后的正常重整无可用文件。最少修正是按成功移动历史选择现存目标,源缺失其他场景说明不可重整;不承诺任意丢失文件恢复。此项为源码确定差异,本轮没有制造真实移动样本 |
| 已有成功整理记录的手动扫描 | MP `ReorganizeDialog.vue:1388` 查询历史,显示成功记录处理选项,`:1314` 对预览与提交一致传 `reorganize/skip_success` | 本项目文件行显示「有 N 条整理记录」,但勾选框是批量修改作品/季集的选择,不是纳入整理范围;所有未排除行仍进入预览(`organize-wizard.tsx:274`、`:588`)。已有文件靠冲突/跳过/替换处理,而「跳过目标已有」与「跳过成功记录」不是相同概念。先把「已选」改为「批量修改已选」,明确「本次整理 N 个未排除视频」;历史成功跳过有实际需求再复用已有记录判断,不默认新增整套状态 |
| 下载接管和手动整理 | MP 管理标签决定外部下载纳管,完成后进入整理;文件管理器整理是明确选中文件的单次操作 | 本项目 qB 标签来源用于自动纳管/整理(`organize-config.ts:55`、`:64`),文件管理器单次整理和来源存量不等于下载任务接管,也不改变目录监控基线。下载详情可以在完成/importing/imported 时打开向导(`download-detail.tsx:98`),内容路径先转换为登记根 FileRef(`organize-wizard.tsx:126`);向导请求没有传下载 taskId/instance/tags(`model.ts:248`)。建议文案明确「整理所选文件」与「接管下载」;不在文件整理时隐式增加标签或接管任务 |
| 整理、刷新元数据和刮削 | MP 对话框支持 scrape;匹配目录可给出 scraping 默认(`ReorganizeDialog.vue:711`),设置用于长期默认,本次选项用于本次操作 | 本项目第 2 步的「刷新元数据」是字段级 refreshMetadata(`file-manager/organize.ts:523`),不是 NFO/海报刮削;页面底部已经说明现有 NFO/图片不搬,可整理后刮削。Local 成功/部分成功后另有 NFO/图片任务(`acquisition-organize/services/organize.ts:1225`),应保留 §5 已确认的 Agent→TMDB/Local,不因对标 MP 强迫仅 TMDB。最少先区分刷新资料与写入 NFO/图片;如需本次刮削开关,复用现有 queue,不创建第二套刮削 |
### 6.3 保留与最小验证
保留仅复制/移动、同分类多个来源、固定/自动分类、已绑定作品沿用原路径、执行前预览、跨卷核验后删源、H&R、来源监控不回填存量,以及 Agent/TMDB/Local 共用整理。不要照抄 MP 的软/硬链接、rclone、音乐或额外分类发布系统。
建议优先处理:① 文件/手动/下载/历史入口统一来源策略展示;② 成功移动历史改用目标重整;③ 向导明确批量修改选择与实际整理范围;④ 无来源空状态加现有设置入口。完成这些后再讨论成功记录跳过和本次刮削,不把它们提前扩成新业务系统。
最小验证使用同一来源下同一目录,从文件管理、手动其他目录、下载详情、历史入口进入,核对所选来源、方式、目标、分类一致;增加成功移动后源已删除、多个来源同路径、跨不同来源多选及部分失败样本。H&R 在本轮文件入口可见且禁用移动;其他入口及服务器执行保护还需定向验证。预览冻结、实际文件执行、Agent 实际补全、来源多配置和源离线没有在本轮页面运行,不把源码能力等同浏览器验收。截图也不能证明完整可访问性;批量单选的方向键导航、焦点与读屏说明仍需交互验证。
### 6.4 用户反馈与后续讨论(2026-10-02)
用户要求以下样式问题先记下,等整理模块讨论完成后一并修改;当前不改样式:
- 右上角通知数字角标目前为金色,与用户期望的整体样式不一致;具体替代颜色尚未确定。
- 分页的每页条数选择控件仍呈现原生样式,应复用项目现有选择控件与统一样式。
整理讨论按实际场景逐项进行,每项对照「MP 行为 → 当前行为 → 希望的行为 → 验收示例」,讨论确认后再实施。建议顺序:入口和来源默认;文件范围与已有记录;作品识别、目标命名与刮削;执行结果、失败重试与历史重新整理。前面已确认的复制/移动、分类 YAML、存量单次触发、qB 标签/快照、TMDB/Local 和多版本/洗版约定继续沿用,不重新扩展需求。
用户进一步倾向于 MP 的独立、共用整理弹窗方案,整理流程也优先参考 MP。据此讨论统一弹窗:手动整理、文件管理器、下载详情和历史重整传入各自上下文,共用来源/目标配置、识别修正、整理选项、预览和提交逻辑。「全局生效」指规则与交互在各入口一致;单次调整只作用于本次整理,长期默认在设置中保存。自动整理共用业务规则,后台执行不要求弹出窗口。弹窗具体操作结构与细节继续讨论,尚未授权据此实施业务改动。
后续讨论中用户认可「本次设置作用于整个所选范围」:单文件只处理该文件,目录递归处理其中视频,多选合并去重;自动识别按文件进行,手动指定作品作用于本批范围,混合批次中需要单独纠正的作品另行选择整理。用户要求参考 MP 的弹窗能力:手动指定电影/剧集,直接输入 TMDB ID 或调用 TMDB 搜索并选择作品,选择转移模式与目标路径、是否刮削,并通过队列执行。既有范围仍仅复制/移动,TMDB/Local 与 Agent 兜底继续沿用。
用户另提出学习 MP 的「整理队列/整理记录」划分。当前本项目整理页将记录和进行中状态集中展示;底层已有 task、引擎调度与整理记录关联(`file-manager/organize.ts`),可优先复用。拟将等待/执行中的任务展示于整理队列,将处理结果展示于整理记录;整理成功的文件在开启刮削时再触发 NFO/图片任务,界面区分整理与刮削状态。MP 固定前端提供预览、加入队列和立即整理按钮,是否完整沿用按钮组合尚未确定;本项目不因拆分视图另造调度机制。以上仍为需求讨论记录,未实施业务改动。
用户随后确认提交按钮只保留「加入整理队列」,不提供「立即整理」。任务受理成功后即可关闭弹窗或继续其他操作,不要求用户停留等待文件处理完成;进度和结果通过整理队列/整理记录查看。仍沿用既有执行前预览约定。本项已定,下一项继续讨论已有成功整理记录的跳过与重新整理语义。
已有成功记录的处理,用户要求采用 MP 做法。重新核对固定前端源码:`ReorganizeDialog.vue` 的 `skipSuccessfulRecords` 初始为 `false`;手动文件/目录入口查询成功历史,有记录时显示数量和「跳过成功记录」开关,默认关闭,用户本次开启后才跳过;改变开关会清除旧预览,预览与提交共用该参数。历史 ID 入口直接采用重新整理语义,不走上述手动历史提示查询。本项目采用这些默认与交互,先前讨论提出的「普通整理默认跳过」不采用。成功记录跳过和目标文件冲突仍是两个独立判断;保留本项目只提供「加入整理队列」的已确认差异。
### 6.5 本轮落实(v0.3.13)
用户授权「一鼓作气做完」。共用整理弹窗已改为单个配置表单与可展开预览,手动、文件管理、下载详情、历史重整统一来源匹配和选项;支持自动/电影/剧集、TMDB 搜索与 ID 定位、本批作品与季号、复制/移动、目标路径、命名/冲突、刮削开关,只提交现有整理队列。成功受理即可关闭;部分受理后已入队文件从本批移除,避免重新预览时重复提交。异步定位取消后不会覆盖用户新选择,选项或识别变化使旧预览失效。
整理页分队列与记录:队列直接查询现有 `verifyAndImport` 与 `scrapeMedia` 的 pending/running/sleeping 任务,覆盖未生成记录的下载核验任务;记录默认终态且聚焦整理行为,旧记录/筛选深链接仍可打开。成功移动重整用结果的媒体库目标路径;复制和失败仍用源。成功历史判断同时要求完整成功记录与成功主文件,识别提示与执行共用查询;手动跳过默认关闭,目标冲突另行判断。本次刮削值冻结到计划,TMDB/Local 及恢复执行都复用原刮削任务机制。
通知数字角标改为主题 primary/primary-foreground;每页条数控件改为项目现有 Select,保留分页行为。使用手册同步更新。验证与发布证据集中于 `.local/organize-final-20261002/`,浏览器交互的写请求使用拦截响应,不对用户媒体进行实际下载、移动、替换或刮削;真正文件执行由隔离数据库与临时目录回归验证。
### 6.6 原地入库补充(2026-10-02,v0.3.14 待部署)
用户指出文件管理整理不应一律复制/移动,并要求修复和记录。核对已有固定 MP 前后端源码:`api/constants.ts` 的整理方式是 copy/move/link/softlink,没有独立的原地登记枚举;文件管理的 `ScrapeDialog.vue`/`app/chain/scraping.py` 提供独立就地刮削。`storages/local.py` 的同路径 move 快速返回只是底层保护,不能据此认定上层整理流程已支持原地入库。
本项目既有「刮削」可就地写 NFO/图片,`addToLibrary` 仅创建作品条目,不登记视频位置、资产及季集覆盖;保留原文件名选项仍会搬运到模板目录。新增共用弹窗「原地入库」,保留路径和名称,复用识别、预览、队列、逐文件结果与资产登记事务;记录方式为 `in_place`,迁移 `0061` 扩展两个枚举约束。媒体库内选择默认原地入库,下载缓存继续原复制/移动。原地模式不使用分类搬运目标和命名模板、不建立路径绑定,配对字幕一并登记;可选刮削只针对本次成功文件。
这是为本项目资产管理补齐的行为,参考 MP 就地刮削语义,并非声称 MP 有同名模式。未改动自动接管配置或加入链接方式。实现与验证边界见发布记录和整理手册。
+145
View File
@@ -0,0 +1,145 @@
# 依赖与程序版本检查
> 本文保存升级前的检查与候选建议。用户随后要求全面升级,实际修改、验证与部署状态统一见 [全面升级执行记录](17-full-upgrade.md);下文“没有执行升级”对应检查阶段。
检查日期:2026-10-01;业务代码基线:`8013196e3f5e6a8c4ea0cd26cf77294a82a13ddd`/`v0.3.7`。本轮只读检查声明、锁文件、实际程序版本和官方发布信息,并保存文档与证据。没有安装新依赖、更新锁文件、重建镜像、迁移数据库或变更部署。
结论:应先处理安全补丁和运行环境维护,再分别评估 PostgreSQL 18、Pi 原生 MCP 和构建工具的大版本变更。建议将 **PostgreSQL 18.6 列为数据库迁移目标**;16.15 是迁移前的同分支补丁选项。**Pi 0.99.2 已有可复用的 MCP 客户端 SDK**,应评估接入;它与当前对外 MCP 服务端承担不同职责。Caddy 已是当前最新版本,是否保留取决于部署是否已有 HTTPS 网关。
## 1 检查范围与证据
| 范围 | 本轮覆盖 | 证据/限制 |
| --- | --- | --- |
| 主 workspace 直接 npm 依赖 | 58 个不同包,逐包查询官方 npm registry;19 个锁定版本不同于 latest,39 个相同 | [完整直接依赖表](evidence/2026-10-01-dependencies/direct-dependencies.csv),包含声明、实际锁定、latest 与建议 |
| 主 workspace 间接 npm 依赖 | `deno.lock` 648 个 npm 实例、633 个不同包名,逐包查询;191 个包名存在不同于 latest 的锁定版本 | [完整锁定依赖表](evidence/2026-10-01-dependencies/locked-npm.csv);不同版本不等于漏洞,不强制覆盖所有传递依赖 |
| JSR | `@std/path` 1.1.6、`@std/internal` 1.0.14,均与查询时最新相同 | [补充元数据](evidence/2026-10-01-dependencies/additional-metadata.json) |
| 安全公告 | 主锁文件 `deno audit`;已部署浏览器独立 package-lock 的生产依赖 `npm audit --omit=dev` | [主项目审计](evidence/2026-10-01-dependencies/workspace-audit.txt)、[浏览器审计](evidence/2026-10-01-dependencies/browser-audit.json);公告命中仍需判断使用路径 |
| 实际运行环境 | 应用、数据库、浏览器和可选入口容器;宿主 Docker/Compose/Node/FFprobe;默认下载器演示实例 | 实际版本见第 3 节。外部用户自建的下载器、Emby 和其它主机未做全面资产扫描 |
| 浏览器独立依赖 | 6 个直接 npm 包逐个查询,独立 lock 做生产依赖安全审计;上游 1.18.0 manifest 对照 | 不属于主 workspace 的 58/633 统计;浏览器全部传递包没有逐个做新旧版本查询 |
| 系统组件 | Debian 发行版、Python、Selkies/pixelflux/labwc 与浏览器基础镜像摘要 | 未做全量 dpkg 包清单与系统 CVE 扫描,不能据此声称所有系统包均为最新或无漏洞 |
| 历史 spike 和参考源码 | 额外查询部分 spike 工具版本,识别其独立作用域 | `spikes/` 不属于生产 workspace;`spikes/movieclaw-src/repo` 是参考源码,不把其依赖计作正在发布的程序 |
完整 registry 查询快照、查询时间与源码提交保存在本地 `.local/evidence/2026-10-01-dependencies/registry-snapshot.json`(约 240 KB,未进 git;SHA-256 `4ca6c78ecc62f881e2219d6068fdb9e9e48c1b47d79c57ab40e32cc107edd948`)。版本结论是这个检查时点的快照,后续执行升级应重新查询。锁文件 SHA-256:`f4c517c88acac3656ce94bfe6f6e19daf5410c4187624f46110c41cf29e200a0`。
`deno outdated --recursive --no-lock --node-modules-dir=manual` 在允许联网后及加入 `--reload=npm:` 后都列出 12 个包;逐包官方 registry 查询发现 19 个。本轮没有查明这 7 个差异的工具原因,不能简单认定刷新缓存即可解决。报告采用逐包 registry 版本,并用 Pi 等官方发布记录交叉核对;工具结果差异继续保留为检查限制。
## 2 直接依赖的更新建议
下表列出 19 个不同于 latest 的直接依赖。建议版本是后续隔离验证的候选,尚未执行安装或兼容验收。完整 58 个包见证据 CSV。
| 包 | 当前锁定 | 查询时 latest | 建议 |
| --- | --- | --- | --- |
| `@biomejs/biome` | 2.5.14 | 2.5.15 | 补丁候选;检查格式/lint 变化 |
| `@earendil-works/pi-agent-core` | 0.87.1 | 0.99.2 | 与 pi-ai 同步评估;会话、工具与嵌入接口回归 |
| `@earendil-works/pi-ai` | 0.87.1 | 0.99.2 | provider、模型、OAuth、流与取消回归 |
| `@modelcontextprotocol/sdk` | 1.30.1 | 1.31.0 | 同主版本候选;对外鉴权、工具、错误和流式连接回归 |
| `@simplewebauthn/server` | 13.3.3 | 14.0.3 | 与 browser 配套评估;存量凭据、注册、登录和恢复入口 |
| `@simplewebauthn/browser` | 13.3.0 | 14.0.0 | 配套大版本变更,不混入普通补丁批次 |
| `@types/node` | 24.19.0 | 26.6.3 | 保持 Node 24 兼容目标,另核对 24.x 补丁;不直接追 26 |
| `fast-xml-parser` | 5.11.1 | 5.11.2 | 补丁候选;RSS、XML 与 NFO 固定样本 |
| `hono` | 4.13.9 | 4.13.12 | 补丁候选;API、静态回退、鉴权与流式接口 |
| `pg` | 8.23.0 | 8.23.1 | 补丁候选;连接、迁移、事务与任务恢复 |
| `typebox` | 1.3.27 | 1.3.34 | 同主版本候选;Agent 工具 schema |
| `vitest` | 5.0.2 | 5.0.3 | 补丁候选;PG 集成实际执行与跳过清单 |
| `react-router` | 7.12.0 | 8.4.0 | **先验证 7.18.4 安全修复**;8.4.0 单独迁移 |
| `@react-router/dev` | 7.12.0 | 8.4.0 | 与另外两个包统一 7.18.4;检查 peer 和构建 |
| `@react-router/node` | 7.12.0 | 8.4.0 | 统一 7.18.4;保留编译所需作用域检查 |
| `lucide-react` | 0.576.0 | 1.49.0 | 图标导出和视觉变更独立评估 |
| `react-day-picker` | 10.0.1 | 10.0.2 | 补丁候选;日期、时区和日历样本 |
| `vite-tsconfig-paths` | 5.1.4 | 6.1.1 | 配合构建工具链评估 |
| `vite` | 7.3.6 | 8.3.1 | 大版本构建迁移;单独核对 Rolldown/Oxc、插件和 Deno 执行 |
已经与 registry latest 相同的依赖包括:TypeScript 7.0.2、OpenWorkflow 0.10.1、React/React DOM 19.3.0、Zod 4.6.5、Kysely 0.29.6、postgres 3.4.9、主项目 playwright-core 1.63.0、Pino 10.3.1、Tailwind 4.3.3 等。声明里的旧范围下限不等于正在运行旧版本,应以 lock 实际解析结果判断。官方 npm 元数据快照见上文本地 registry-snapshot.json
### 2.1 安全审计的实际意义
主项目审计命中 **13 条 React Router 公告:6 high、6 moderate、1 low,0 critical**。完整公告 ID、受影响范围和链接保存在审计证据中。当前 [React Router 配置](../../apps/web/react-router.config.ts) 为 Framework SPA(`ssr: false`),生产由 [Hono 静态托管](../../apps/server/src/http/static.ts) 返回构建文件和 `index.html`,没有部署 React Router SSR/single-fetch/RSC 服务端处理器。
其中 9 条依赖服务端 SSR、single-fetch、manifest 或 RSC 路径,本轮没有发现对应生产调用路径;不能将审计里的 6 条 high 直接表述成 6 个可利用的线上漏洞。3 条客户端导航公告仍需检查不可信 URL,`ssr:false` 不能排除它们。登录 `safeNext` 有过滤,但不能据此宣称任意编码路径都已验收。另 1 条涉及构建时 prerender 的 Location HTML 注入;SPA 构建仍有根预渲染,但当前没有发现外部输入驱动根 loader 重定向的触发路径。本轮没有复现利用。
建议三个 Router 包先统一到 7.18.4,再做 URL/跳转、构建和页面冒烟。该版本包含本轮公告所需的修复;但 `@react-router/dev` 和 `@react-router/node` 的 TypeScript peer 声明为 `^5.1.0 || ^6.0.0`,本项目是 7.0.2,**候选仍需验证,不能称无兼容风险**。来源:[7.18.4 发布](https://github.com/remix-run/react-router/releases/tag/[email protected])、[7.x changelog](https://reactrouter.com/7.18.4/start/changelog)、[SPA 官方说明](https://reactrouter.com/how-to/spa)。
浏览器独立生产 lock 审计命中 **5 个受影响包、16 个不同公告 URL**,npm 聚合严重性是 2 个 high 包、3 个 moderate 包。包为 `adm-zip` 0.6.0、`brace-expansion` 5.0.9、`fast-uri` 3.1.7、`hono` 4.13.5、`ip-address` 10.4.0。包数、公告数与主项目审计的统计单位不同,不相加成「18 条漏洞」。浏览器里的 Hono 与主应用 Hono 是两个独立版本。
应沿浏览器下载/解压、请求解析和可访问入口核对公告条件,再在候选镜像重跑 audit。上游 1.18.0 的 manifest 仍含 `hono:4.13.5` override 等旧约束,不能承诺只更新 camofox tag 就清除全部命中;npm 的聚合 `fixAvailable:true` 也不能替代每条公告修复范围核对。[浏览器审计与原始公告链接](evidence/2026-10-01-dependencies/browser-audit.json)
## 3 程序和镜像版本
| 程序/环境 | 本次实际版本 | 官方查询结果 | 建议 |
| --- | --- | --- | --- |
| 项目应用 | v0.3.7 | 本项目发布基线 | 是否发布新版本取决于验收,不是依赖 latest |
| Deno(宿主/构建) | 2.9.7 | 2.9.7 | 保持 |
| PostgreSQL(部署/开发) | 16.14 | 稳定主版本 18.6;16 分支 16.15 | 18.6 作为迁移目标;耗时较长时先安排 16.15 补丁 |
| 应用 pg_dump 客户端 | 17.11 | 17 分支 17.11;18 分支 18.6 | 升 PG 18 时必须一并升客户端 |
| Caddy(可选 TLS) | 2.11.4 | 2.11.4 | 保持,按入口部署决定是否启用 |
| camofox-browser | 1.17.0 | 1.18.0 | 候选镜像验证后更新,重新审计独立 lock |
| Camoufox 浏览器二进制 | 152.0.4-beta.28 | 152.0.4-beta.30 | 仍是 beta;配套验证,不当作稳定版自动切换 |
| 浏览器 Node | 22.22.3 | 22 LTS:22.23.3 | 同 LTS 补丁候选,随镜像重建验收 |
| 宿主 Node(非应用主运行时) | 24.15.0 | 24 LTS:24.21.0;Current:26.10.0 | 选 24 LTS 补丁,不因 latest 跳 26 |
| 生产 FFprobe/FFmpeg | 9.0.2 | 稳定 9.0.2 | 保持 |
| 宿主 FFprobe | 7.1.3 | 7.1 分支 7.1.5 | 同分支补丁候选,区别于生产容器工具 |
| 默认 qB 演示实例 | 5.1.2 | 5.2.4 | 先核对 API、标签、暂停/删除和多实例隔离;不替用户外部 qB 升级 |
| Docker Engine(宿主) | 29.2.1 | 29.8.2 | 单列宿主维护窗口,涉及其它项目;核对安全发布说明 |
| Docker Compose(宿主) | 5.0.2 | 5.5.1 | 随宿主维护验证 compose 行为 |
| containerd/runc(宿主) | 2.2.1/1.3.4 | 2.4.1/1.5.2 | 跟随选定 Docker 发行包兼容组合,不单独替换二进制 |
| Debian(应用镜像) | 13.5 | 13.7 | 重建候选层并更新发行版补丁,验证工具和权限 |
| Debian(浏览器桌面镜像) | 13.7 | 13.7 | 发行版一致;仍需判断实际包补丁与镜像构建日期 |
| Python(宿主/浏览器) | 3.13.5 | 上游 3.13.16;稳定主版本 3.14.8 | Debian 管理的软件随发行包更新,不能仅凭上游版本判定系统补丁缺失 |
| Selkies/pixelflux | 2.0.0/2.1.0 | 2.0.0/2.1.0 | 保持,随桌面基础镜像验证 |
| labwc(桌面基础镜像) | 0.9.7-dirty | 上游 0.20.2 | vendor 定制构建,跟随基础镜像,不直接替换 |
| socat(开发转发容器) | 1.8.0.0 | 官方最新未完成核验 | 官方查询超时/证书错误,记录未知;开发辅助,不冒充生产主依赖 |
版本来源:[PostgreSQL 支持表](https://www.postgresql.org/support/versioning/)、[Node 官方发行索引](https://nodejs.org/dist/index.json)、[FFmpeg 下载与版本](https://ffmpeg.org/download.html)、[Debian 新闻](https://www.debian.org/News/)、[Python 发行列表](https://www.python.org/downloads/)、[PyPI Selkies](https://pypi.org/project/selkies/)、[PyPI pixelflux](https://pypi.org/project/pixelflux/)。其余上游 GitHub 发布标签、URL 和日期见本地查询快照 registry-snapshot.json 及[补充快照](evidence/2026-10-01-dependencies/additional-metadata.json)。
桌面基础镜像 `ghcr.io/linuxserver/baseimage-selkies:debiantrixie` 当前配置固定摘要 `sha256:f3ca0b10e923a603941a996ea1c3356b9527cc53163259f4e836f61fd4523e12`;本轮远端 manifest 查询仍为同一摘要。该镜像没有可用的 GitHub release/latest 记录,不能把 release API 的 404 当作已过期。供应方说明基础镜像更新可能破坏兼容,应按镜像组合验收。[供应方说明](https://github.com/linuxserver/docker-baseimage-selkies)
应用与部分服务的 `debian:trixie-slim`、`postgres:16-alpine`、`caddy:2-alpine` 等是可移动标签。实际运行版本由已经构建/拉取的镜像决定;修改 tag 或再次构建都应记录摘要与源码来源,不以配置文字直接证明部署已经更新。
### 3.1 PostgreSQL 18 的迁移边界
PG 18 已是正式稳定分支,当前 18.6。16 仍受支持到 2028-11-09,因此 16.15 是有效的过渡补丁,不能将「最新 16」表述为「最新 PostgreSQL」。本轮没有找到必须永久停留在 16 的业务约束,也没有执行 PG 18 兼容验证。[官方版本策略](https://www.postgresql.org/support/versioning/)
当前 [生产 compose](../../docker-compose.yml) 使用 `postgres:16-alpine`,卷挂载 `/var/lib/postgresql/data`。官方 PG 18 镜像默认 `PGDATA` 改为 `/var/lib/postgresql/18/docker`,声明卷改为 `/var/lib/postgresql`;升级需一起核对卷、目录和权限。PG 大版本不能直接复用原数据目录,需要导出/恢复或经过验证的 `pg_upgrade` 方案。[官方镜像 PGDATA 说明](https://github.com/docker-library/docs/blob/master/postgres/README.md#pgdata)
应用现有 `pg_dump` 是 17.11,不能导出 PG 18 服务端;更新数据库时须同步升备份/恢复客户端至 18.x,并确认脚本调用实际新版本。[pg_dump 官方说明](https://www.postgresql.org/docs/current/app-pgdump.html)
候选验收至少包括:独立 PG 18 实例从当前备份恢复;56 个迁移后的业务和 OpenWorkflow schema 核对;真实 PG 集成测试;旧任务、outbox 和操作账本的一致性;备份再次导出和恢复;回滚时使用原 PG 16 数据/快照。不能将「容器健康」作为数据库迁移完成证据。16.15 的补丁升级也应阅读[发布说明](https://www.postgresql.org/docs/release/16.15/),按实际扩展和配置判断是否有额外步骤。
### 3.2 Pi 原生 MCP 的作用
本项目当前嵌入 `pi-agent-core`/`pi-ai` 0.87.1。官方 0.99.2 已提供 MCP 客户端能力,包括 stdio、Streamable HTTP、OAuth、工具发现和调用。新版还发布独立 `@earendil-works/pi-mcp` 和 `@earendil-works/pi-codemode` 0.99.2;官方 Agent 示例说明可以将其包装成 `AgentTool`,进入工具调用钩子。它不只限于命令行产品,可以评估在本项目嵌入层复用。[官方 MCP 文档](https://github.com/earendil-works/pi/blob/v0.99.2/packages/coding-agent/docs/mcp.md)、[Agent SDK 说明](https://github.com/earendil-works/pi/blob/v0.99.2/packages/agent/README.md#mcp-and-codemode)
本轮读取官方 0.99.2 发布 tarball 的声明文件,确认顶层仍导出 `AgentHarness`,没有依据认定必须重写整个 Agent 接入。其它方法签名、会话兼容、provider 导出和 Deno 行为仍未实际编译/运行验证。两个新 SDK 声明 Node `>=22.19.0`,项目主运行时是 Deno,不能用 Node engines 达标代替 Deno 验收。
当前 [MCP 模块](../../apps/server/src/modules/mcp) 是**服务端**:对外提供本项目能力,并复用 API Key 鉴权、审批、幂等与审计。Pi 原生模块是**客户端**:让内部 Agent 调用外部 MCP 服务。应保留对外服务端;若接入客户端,需定义外部工具如何经过已有权限/审批和审计,避免仅升级包版本就默认开放所有外部工具。新版能力的存在也不证明当前项目已经接入它。
### 3.3 Caddy 当前负责什么
当前 [Caddyfile](../../docker/browser-desktop/Caddyfile) 和 compose 中的 `tls` profile 表明,它是可选 HTTPS 入口:证书、TLS、zstd/gzip 压缩,以及向 `app:4380` 的反向代理。`flush_interval -1` 配合代理保持 Agent SSE 和桌面 WebSocket 的流式传输。默认使用内部 CA;设置域名和 issuer 后可以配置 ACME,实际公网条件仍需符合部署配置。
请求链路为「用户浏览器 → Caddy HTTPS → 应用 4380」;桌面路径再由应用鉴权、会话与租约检查后代理到 Selkies 3000。桌面视频 WebCodecs 与剪贴板要求 HTTPS 或 localhost 的安全上下文,因此入口 TLS 有具体用途。Caddy 不承担 Agent 执行、数据库访问或浏览器会话授权。
已有 Nginx/Traefik/统一 Caddy HTTPS 网关时,可由现有入口提供证书和转发,本项目无需另启 Caddy profile;应验证 SSE、WebSocket 和安全上下文仍正常。当前 Caddy 2.11.4 已是查询时最新,无需为了版本检查更新。
### 3.4 浏览器依赖的独立组合
| 包 | 部署 lock | latest | 边界 |
| --- | --- | --- | --- |
| better-sqlite3 | 13.0.1 | 13.0.3 | 原生模块,随 Node 与镜像重建 |
| camoufox-js | 0.11.5 | 0.12.0 | 新版 peer `playwright-core <1.61.0`,与现有 1.62.1 冲突,不能单独更新 |
| express | 5.2.1 | 5.2.1 | 保持 |
| playwright-core | 1.62.1 | 1.63.0 | 配套浏览器与 camoufox-js 验证 |
| prom-client | 15.1.3 | 15.1.3 | 保持 |
| swagger-jsdoc | 6.3.0 | 6.3.0 | 保持 |
camofox 1.18.0 manifest 的直接依赖仍固定 camoufox-js 0.11.5;更新服务版本并不意味着自动更新这个包到 0.12.0。该发布含 Docker postinstall 等调整,应重新检查本地 Docker 补丁是否仍适用,再验证 Cookie 登录、挑战页、页面操作、人工接管、交还、重启、下载捕获和权限。[1.18.0 官方发布](https://github.com/jo-inc/camofox-browser/releases/tag/v1.18.0)
## 4 建议的处理顺序与验收
1. **安全补丁与候选镜像**:三个 Router 包统一 7.18.4;复核浏览器 audit 并验证 1.18.0 候选;若 PG 18 迁移需较长时间,先安排 16.15。主项目其它补丁包可在同一明确范围内更新,重新生成 lock 并跑现有 CI,确认 PG 测试实际执行,再跑有固定数据的页面冒烟。
2. **PG 18.6 专项**:数据库、18.x 客户端、卷结构、隔离恢复与回滚一起处理,形成可审阅迁移方案,再进入部署。
3. **Pi 0.99.2 与原生 MCP 专项**:先验证原有 Agent 接口和会话,再决定外部 MCP 客户端所需场景;复用已有授权、审批与审计;真实模型验证仍按独立范围进行。
4. **宿主运行环境维护**:Docker/Compose/发行版与 Node 补丁单列维护窗口,核对受影响的其它项目与镜像启动,不混在业务依赖安装中。
5. **其它大版本**:Vite 8/Router 8、Passkey 14 和图标等分别评估价值与兼容;当前没有证据要求全部同时迁移。
本轮完成版本与公告核对,**没有完成候选升级验收**。此前 CI 通过仍只对应现有版本。版本工作与 [MoviePilot v3 逐项业务对照](15-moviepilot-v3-comparison.md) 并行准备,不改变对照表中 02 至 14 尚待核对的状态;恢复问题也不能因依赖更新自动视为解决。
+86
View File
@@ -0,0 +1,86 @@
# 全面升级执行记录
执行日期:2026-10-01,Asia/Shanghai。**本次项目全面升级已完成,部署验收通过。** 全面升级发布应用为 v0.3.8(后续整理功能已发布 [v0.3.9](18-organize-release.md)),生产与开发 PostgreSQL 为 18.6,浏览器为 1.18.0,演示 qB 为 5.2.4;宿主与其它项目不在升级范围。下文保留隔离验证和阶段记录,并明确已退休的旧回退资源。升级前版本与官方查询证据见 [版本检查](16-dependency-version-review.md),运行时决策见 [ADR-004](../adr/ADR-004-deno-runtime.md)。
## 范围与状态
本次范围仅为 UHD Media Tool 项目依赖、项目容器及生产/开发数据库。宿主操作系统、Docker Engine、Compose、宿主 Node 和其它项目均不在此次升级范围,也不是本次剩余待办。
发布应用版本为 **0.3.8**。以下展示升级前基线、验证结果与最终部署状态。
| 范围 | 升级前 → 当前 | 隔离验证 | 实际部署 |
| --- | --- | --- | --- |
| 根 workspace 与 Pi | Pi 0.87.1 → 0.99.2;主 workspace 直接依赖更新至查询时 latest | 已安装;主 deno audit 0 公告;全 workspace tsc 与 Deno check 通过,完整 CI exit 0:3264 通过、4 跳过 | 已部署,验收通过 |
| Web 与构建工具 | Router 7.12.0 → 8.4.0、Vite 7.3.6 → 8.3.1 等 latest | 已安装并通过类型检查;完整 CI 与 web 构建通过;最终页面冒烟 83 通过、1 跳过(无订阅详情数据) | 已部署,验收通过 |
| 浏览器独立依赖与镜像 | camofox 1.17.0 → 1.18.0;Node 22.22.3 → 24.21.0;Camoufox beta.28 → beta.30 | 两套最终镜像构建 exit 0;174 个实际安装依赖 audit 0;隔离桌面与真实 BrowserService 25 项验证通过 | 已部署,验收通过 |
| PostgreSQL 生产实例 | 16.14 → 18.6,新卷逻辑恢复 | 隔离演练及正式停写恢复通过;56 迁移齐全,89 表行数与内容指纹全匹配 | 已部署,验收通过 |
| PostgreSQL 开发实例 | 16.14 → 18.6,新卷逻辑恢复 | 88 表行数与内容 fingerprints 全匹配 | 正式迁移与恢复验证完成;旧开发卷已授权清理 |
| 应用备份客户端 | pg_dump/pg_restore/psql 17.11 → 18.6 | 最终镜像构建 exit 0;client18 / server18 隔离备份恢复 E2E 通过,含校验和、映射计数与 Agent 会话恢复 | 已部署,验收通过 |
| Deno、Caddy、生产 ffprobe | 2.9.7、2.11.4、9.0.2 → 保持当前已核验版本 | 与新镜像一起验证 | 已验证并部署;Caddy 固定最新 2.11.4 |
| 项目代理中继 | socat 1.8.0.0 → 1.8.1.3 | 更新项目容器 | 已部署 |
| 应用 Debian 基础层 | 已部署 13.5 → 当前 13.7 补丁层 | 最终应用镜像已更新容器内 apt 最新补丁,实际 Debian 13.7 | 已部署,验收通过 |
| 演示 qB | 5.1.2 → 5.2.4 | 5.2.4 候选真实 API 测试:3 通过、1 跳过 | 已部署 5.2.4;不升级外部用户下载器 |
## 升级前只读部署检查(历史)
本节记录迁移开始前的位置。表中保留旧卷的要求在迁移验收期间已执行;验收后用户授权清理旧版本,旧 PG16 卷现已退休删除,不能再据此回滚。
生产 Compose 项目 `umt` 位于 `/opt/uhd_media_tool`,装配 `docker-compose.yml` 与本机 `docker-compose.override.yml`。检查没有输出环境文件或容器凭证。应用、PG 与浏览器健康。
| 对象 | 当前持久化位置 | 升级要求 |
| --- | --- | --- |
| 生产 PG16 | `umt_umt-pg-data` → `/var/lib/postgresql/data` | 保留旧卷;PG18 使用另一个明确命名的新卷 |
| 开发 PG16 | `umt-dev_umt-pg-data` → `/var/lib/postgresql/data` | 独立迁移,不与生产库共卷 |
| 应用数据 | `umt_umt-data` → `/data` | 保留备份、Agent 会话与导出;候选实例使用隔离副本 |
| 媒体目录 | `/opt/umt-demo/media` → `/media`;`/opt/umt-demo/downloads` → `/downloads` | 保持路径映射;隔离验证不写真实挂载 |
| 浏览器登录状态 | `umt_umt-camofox` → `/root/.camofox` | 保留旧卷与旧镜像回退证据;候选实例先使用隔离副本 |
| 桌面配置 | 浏览器另挂匿名 `/config` 卷 | 重建时记录并保持其绑定,不能只检查登录状态卷 |
生产数据库已应用 56 条迁移,最新 `0058_scrape_record`。检查时现有备份目录为 `/data/backups/20260929T103808Z`,manifest 声明服务端 16.14、pg_dump 17.11;初始只读检查只确认该历史备份存在和版本;随后主代理已将生产 dump 恢复到隔离 PG18,但尚未确认所用 dump 与该历史目录是同一份。切换前需生成新的停写备份。宿主数据所在文件系统约有 1023 GiB 可用,不代替目标数据大小与峰值空间核算。
## PostgreSQL 16 → 18 执行与回滚边界(迁移阶段历史)
以下步骤描述验收前的迁移与回退安排,已完成迁移。旧镜像、旧 PG16 卷及旧回退脚本已在最终验收后按用户授权删除;当前仅支持用保留的新版 PG18 备份恢复 PG18,不再承诺第 6 步的旧卷回退。
1. 保存旧应用镜像 ID、Compose 配置及 PG16 镜像 ID;保留原主密钥并避免写入文档。确认数据库、Agent 会话、映射清单备份和校验和完整。
2. 在隔离 PG18 新卷演练逻辑恢复;核对表、扩展、迁移、映射行数以及任务引擎 schema,运行 PG18 集成与编译产物检查。候选应用关闭自动化并避免连接真实下载器、模型与站点。
3. 正式切换前停止应用写入,再生成最终一致的数据库及会话备份。恢复到新的 PG18 卷,保留原 PG16 卷不变;新应用先以只读对账状态启动,确认迁移、健康、映射、凭证和挂载后再决定恢复自动化。
4. PG18 官方镜像默认 `PGDATA=/var/lib/postgresql/18/docker`,卷应挂在 `/var/lib/postgresql`,不能将 PG16 数据目录直接交给 PG18 启动。[官方镜像说明](https://hub.docker.com/_/postgres)
5. 升级应用镜像内备份工具到 18 客户端,避免 17 版 pg_dump 无法备份 18 服务端。恢复脚本当前过滤 `SET transaction_timeout` 以兼容旧服务端,更新说明并分别验证旧备份恢复与新库备份。
6. 如切换验收失败,停止新应用和 PG18,恢复旧配置、旧镜像与 PG16 原卷。此回滚返回最终切换备份时点;PG18 上线后产生的新写入不能自动落回旧卷,需另行处理,不能承诺零数据损失的降级。
不得用 `compose down -v`、卷 prune 或覆盖旧数据目录完成迁移。最终部署镜像和清理对象见文末 JSON 证据。
## 范围外检查说明
前期只读检查曾记录宿主版本、软件路径及共享 Docker daemon 上的其它项目;这些检查用于确认项目容器变更的边界,不构成本次宿主升级计划。此次未升级或重启宿主服务,也不更新其它项目。
## 安装与验证进展
依赖安装首次因 Deno 2.9 默认 24 小时 `minimumDependencyAge` 拒绝刚发布的 Biome 等包。按用户全面升级至最新的明确要求,本次安装使用一次性 `--minimum-dependency-age=0`;不写入永久禁用配置,依赖仍精确锁定。这是安装策略例外,不代表依赖已通过安全审计或兼容检查。主代理已拉取 `postgres:18.6-alpine`,并完成隔离库恢复;生产迁移现已完成。qB 适配器已有 5.2 的 HTTP 204 登录与 `QBT_SID` 测试,旧 override 的“只能 5.1.2”注释待同步纠正。
主 workspace 共 58 个外部直接依赖已安装;除 `@types/node` 保持官方 24.x 最新 24.19.0,其余更新至查询时 latest。主 `deno audit` 为 0 公告,不涵盖浏览器独立 lock、系统包或实际业务兼容。全 workspace tsc 与 Deno check 通过。首次完整 CI 停在根 deno.json 格式错误,修复后完整 CI **exit 0,3264 通过、4 跳过**;主 npm 安全审计为 0 公告。最终应用镜像 `uhd-media-tool:v0.3.8` 构建 **exit 0**,镜像 ID 为 `sha256:6f4f73d8ea53057cdf5bf4aa2904a360ea953adb1270a7b9f783a757b7e70559`,已正式部署并验收通过。最终页面冒烟 **83 通过、1 跳过**,跳过原因为没有订阅详情数据。
Pi 初次测试因 TypeSafe provider 与 OpenAI 原生 ChatGPT OAuth 新增导致旧计数断言过期,合同已随升级更新为 42 providers / 9 OAuth,并纳入上述通过的完整 CI。另对 **35 份旧 Pi JSONL 会话完成兼容检查并通过**。Pi 提供独立的 `@earendil-works/pi-mcp` 客户端 SDK,本次升级 `pi-agent-core` 不会自动接入外部 MCP 工具;该功能拓展不属于本次依赖升级交付。
qB 5.2.4 候选的真实 API 兼容测试 **3 通过、1 跳过**;该结果不代表用户 PT 下载全链路已经验收,演示实例随后已正式切换并完成旧密文凭据连接验证。
浏览器采用 `camoufox-js` 0.12 与 Playwright 1.60.0 的兼容组合:上游协议对 `viewport.isMobile` 有限制,不能简单提升该独立 Playwright 至主 workspace 的 1.63.0。这是浏览器独立依赖的协议兼容例外,主 workspace 的 Playwright 不降级;已结合实际镜像与安装依赖审计验证。浏览器目标 Node 改为 24.21.0。
浏览器最终纯截图镜像 1.18.0(ID 前缀 `92ea962`)和桌面镜像(ID 前缀 `eb6c8e`)均构建 exit 0。实际安装的 174 个依赖安全审计 0 公告;MCP SDK 1.31 initialize 与原生 SQLite 3.53.4 检查通过。此处 MCP initialize 验证浏览器依赖兼容,不表示应用智能体新增外部 MCP 工具入口。
生产浏览器 profiles/config 的独立副本完成重启前、重启及重启后隔离检查,授权、固定身份保持、cookies、PNG、可信鼠标与 profile 隔离均通过。实际 BrowserService 的 setup / a / b / idle / c / d 六阶段 **25 项通过**,1.18 的原 10 项能力已登记;相关回归 14 个文件、100 个测试以及登记相关 19 个测试通过。SIGKILL 后最近一次落盘以来的新登录会丢失,验证确认能明确识别,不能据此宣称无损恢复。URL 恢复证据缺口见 [工程化检查第 6 节](14-engineering-review.md),本次没有业务修复。
开发 PG16 → 18.6 正式迁移已完成,88 表行数与内容 fingerprints 全匹配,旧开发卷在验收期间保留,随后按用户授权清理。client18 / server18 隔离备份恢复 E2E 的校验和、映射计数与 Agent 会话恢复通过。生产停写备份及 PG18 迁移完成,89 表的源库与恢复库行数、内容 fingerprints 全一致,56 条迁移齐全。原主密钥与全部非数据库持久挂载(包括浏览器匿名 `/config`)完全一致;旧密文凭据通过新版应用成功连接 qB 5.2.4。API、IO worker 和 Agent worker 均以 UID 10001 存活,HTTP / HTTPS 健康,映射计数吻合,验收期间 error 级日志为 0。源库只读对账设置原为 false,迁移验证后已恢复 false,应用正常重启且健康。最终发布镜像的页面冒烟再次通过:83 通过、1 跳过。
新版生产备份 `/data/backups/20261001T072536Z` 已在隔离 PG18 完成恢复,校验和、映射计数、89 表一致;35 个 Agent 会话文件逐字节 hash 一致。新版开发备份 `.local/backups/dev-pg18-20261001.dump` 也完成隔离恢复,88 表 fingerprints 一致。
执行证据:[版本与锁文件](evidence/2026-10-01-dependencies/upgrade-locks-and-direct-versions.json)、[验证汇总](evidence/2026-10-01-dependencies/upgrade-verification.json)、[最终部署容器](evidence/2026-10-01-dependencies/deployed-containers.json)、[授权清理记录](evidence/2026-10-01-dependencies/upgrade-cleanup.json)。
## 验收后的授权清理与当前恢复路径
用户在验收通过后明确授权:“确认没问题的话,老的备份和老的版本都可以干掉的”。已清理 5 个隔离容器、8 个卷(2 个旧 PG16 卷及 6 个隔离卷)、14 个旧镜像标签,以及旧数据归档、PG16 dump、旧环境配置与回退脚本。旧备份 `20260929T103808Z` 和最终停写阶段备份 `20261001T072253Z` 也已删除。`uhd-media-tool:latest` 已指向新的 v0.3.8 镜像。
当前仅保留上述新版生产和开发 PG18 备份作为恢复依据。其它项目仍使用的共享 `postgres:16-alpine` 镜像保留;宿主服务和其它项目未升级。旧镜像/旧 PG16 卷回退路径已退休,发生故障时应使用新版备份恢复 PG18。
本次依赖、容器与数据库升级及部署验收完成;已有业务和工程问题仍以 [工程化检查](14-engineering-review.md) 与 MP02–MP14 的待办为准,本次没有继续功能开发,也不据此宣称全部业务无缺陷。
+126
View File
@@ -0,0 +1,126 @@
# 媒体整理与下载发布记录
当前生产应用为 **v0.3.13**,健康检查通过,见下方新增发布记录。
## v0.3.9 媒体整理发布
2026-10-01,Asia/Shanghai。用户授权部署,应用发布为 **v0.3.9**,健康检查通过。分类规则、整理来源、目录快照、手动存量和文件管理入口一起发布。详细行为见 [整理手册](../runbook/organize.md)。
## 发布范围与来源
- 版本:workspace / server / web 0.3.9;前端 `version.json` 为 v0.3.9,健康接口为 0.3.9。
- 源码:HEAD `8013196` 加用户已授权的工作区修改,未创建提交。镜像标记 `8013196-dirty-121ab989fb4a427b`;对应源码文件指纹 `121ab989fb4a427b`,完整值保存在本地发布证据。
- 镜像:`uhd-media-tool:v0.3.9`,ID `sha256:4db9dda97358a5adc5e6f3472d88b4cd05d5522eb6183663f2659d86b5401163`。
- 迁移:`0059_organize_source_snapshot`;新增持久快照表,已有 settings 读取时补分类 YAML 和空来源列表。发布不会扫描或导入存量。
- 本次只替换 app 容器。PostgreSQL、qB、浏览器、Caddy 和宿主程序没有更换。
## 发布前检查
引擎 pending / running / sleeping、业务 task queued / running / waiting、整理记录、刮削记录及 Agent 在途数量均为 0。备份完成于 `/data/backups/20261001T095557Z`,数据库、映射和 Agent 会话的 SHA256 校验全部通过。
最终 web 回归 26 文件 / 232 项通过;来源匹配新增根范围、目录边界、全部所选项、最长路径和多候选测试。typecheck、Biome 与 production build 通过。服务端验证范围和完整回归的阶段性失败及复验口径见 [业务对照 §4.3](15-moviepilot-v3-comparison.md#43-本次验证记录)。Docker 构建完成冻结依赖安装、设计 token 检查、web build、server compile 和编译二进制模块图自检。
## 部署后验证
- `umt-app-1` healthy,运行镜像 ID 与发布镜像一致。
- HTTP 4380 与 Caddy HTTPS 健康均为 ok;API / IO worker / Agent worker 存活,UID 10001。
- `0059` 已登记,快照表存在;`scanOrganizeSource@1` 进入 maintenance worker,`organize.sources` 可用并启用。
- 通过现有管理员登录验证分类配置、整理来源、settings 和文件根读取;华语电影、澳大利亚兜底欧美电影、TV 综艺三个预览结果正确。
- 文件管理、整理记录、设置三个 SPA 地址返回正常;部署静态资产包含文件管理策略选择入口。
- 验证时来源配置仍为空,留待用户手动选目录;没有新增来源配置或对用户媒体执行整理。
- 部署后验证窗口内 error 级应用日志为 0。
本次没有运行浏览器截图或完整交互冒烟,用户可以刷新现有页面,进入「设置 → 媒体库与目录」检查分类规则与来源配置,再从文件管理器进入同一整理向导。
本地证据:`.local/deploy-organize-20261001/release.json`、`http-check.json`;构建日志 `/tmp/umt-organize-docker-build.log`。部署配置的版本和源码标记已更新,当次部署配置使用 v0.3.9;下方 v0.3.10 发布已更新配置。
## v0.3.10 手动下载与入库发布
2026-10-01 23:18,Asia/Shanghai。用户授权部署,本批独立手动下载、串流外详情页下载、TMDB/Local 元数据兜底、正常多版本/一次性洗版与订阅完成口径调整已上线。实现、业务边界与回归结果见 [MP 对照 §5.6](15-moviepilot-v3-comparison.md#56-本轮实现与验收已部署-v0310)。
- 应用与前端版本:0.3.10/v0.3.10。镜像 `uhd-media-tool:v0.3.10`,ID `sha256:cbf3081281c75f4e60dba9a9ce18de63b0c5665c66b2b133baebaa7f05aabdd2`。
- 源码标记:`8013196-dirty-5ecf10d5b4f89432`,HEAD 加用户授权的工作区修改;1552 个源码文件指纹记录保存在本地,部署后逐项复核未变化。没有创建提交。
- 迁移:`0060_manual_acquisition` 已执行;计划允许无 Slot,下载任务新增 `import_plan_id` 外键并使用 `ON DELETE SET NULL`。
- 升级前引擎、业务任务、整理、刮削、Agent 在途均为 0;备份 `/data/backups/20261001T151510Z` 的数据库、映射和 Agent 会话 SHA256 校验通过。
- Docker 构建的冻结依赖、设计 token、web production build、server compile 与空环境二进制自检通过。
- 只替换 app;PostgreSQL、qB、浏览器、Caddy 等其他容器 ID 保持不变。
部署后 app healthy,运行镜像与构建镜像一致;HTTP/HTTPS 返回 ok,前后端版本一致,API、IO 与 Agent 三个进程运行于 UID 10001。管理员登录及分类/来源/settings/文件根/下载任务/浏览器会话读取通过,3 个分类预览符合原配置。能力目录为 42 项,包含 `metadata.resolve_organize`;线上 OpenAPI 包含详情页资源解析与手动入库选项。
使用 Chromium 在真实生产入口登录,下载面板、计划列表、整理记录、文件管理、设置及媒体库共 6 个页面冒烟通过,无未捕获页面异常或失败 API,并保存截图。部署验证窗口内 error 级应用日志为 0;计划、下载、媒体资产、整理记录和订阅数量均保持一致。没有以验收为由提交下载、洗版或移动用户媒体;实际 PT 下载、外部模型与入库执行仍以真实任务验收为准。
本地证据:`.local/deploy-manual-20261001/release.json`、`source-manifest.json`、`http-check.json`、`ui-check.json` 及页面截图。构建日志 `/tmp/umt-manual-docker-build.log`。`.env.deploy` 已固定 v0.3.10 及本次源码标记,后续普通 Compose 启动使用本版本。
### 4380 自签 HTTPS 入口调整
随后按用户测试要求,将 4380 的宿主端口交给 Caddy:`https://服务器地址:4380` 使用现有 Caddy 内部 CA 证书,443 HTTPS 入口继续保留;app HTTP 仅映射 `127.0.0.1:4381`,容器内仍监听 4380。仅重建 app/Caddy 容器,无镜像升级或新增迁移。配置写入本机 override 与 `.env.deploy`。
4380/443 HTTPS 健康、管理员接口、版本一致及新接口描述验证通过;真实 HTTPS 下 6 个生产页面冒烟通过,无页面异常或失败 API,Chromium 报告 `isSecureContext=true`。证据为同目录 `https-http-check.json`、`https-ui-check.json`、`https-switch.log`,汇入 `release.json`。
## v0.3.11 搜索详情与桌面黑边修复
2026-10-01 23:58,Asia/Shanghai。搜索资源标题现在可以点击,打开与站点工作台相同的详情抽屉;加载完整资源后复用已有详情缓存、按需抓取、简介/规格/截图/文件展示、下载选项与 Agent 入口。抽屉关闭后搜索词、筛选和分页保留。读取失败显示原有错误与重试,打开详情不会提交下载。
- 镜像 `uhd-media-tool:v0.3.11`,ID `sha256:fa54237f250c92bee1436912275cb0b8da97d1b7c9bf9489dc1152144908b944`;源码标记 `8013196-dirty-a2f3f773724cbde4`,1553 个文件的指纹部署后复核一致。
- 前端 typecheck、Biome、232 项测试通过;Docker 内设计 token、web build、server compile 与空环境二进制自检通过。真实 React 组件验证点击标题、未缓存自动抓取一次、缓存不额外抓取、失败显示与详情下载选项,无实际提交。
- 切换前业务、引擎和 Agent 在途为 0;备份 `/data/backups/20261001T155308Z` 的数据库、映射与会话校验通过。仅替换 app,数据库迁移仍为 `0060`。4380/443 自签 HTTPS 入口保留。
- app healthy,前后端版本一致,42 项能力及管理员接口检查通过;6 个 HTTPS 生产页面无异常或失败 API。另使用生产构建、真实缓存资源详情 API 和受控搜索结果验证点击后的简介展示及下载选项;未触发下载。验证窗口内 error 级应用日志为 0。
桌面黑边修复先于应用发布部署。实际视频与 iframe 都为 1280×900,黑边是浏览器窗口未最大化造成:底座初始化脚本把快捷键 XML 按行注释,产生无效 XML,连带最大化规则无法读取。内置完整 `/defaults/umt-labwc.xml` 在底座初始化后覆盖配置,保留既有快捷键/桌面菜单行为,并为窗口设置 `Maximize` 与 `serverDecoration="no"`。配置语法对应 [labwc 窗口规则](https://labwc.github.io/labwc-config.5.html)。
浏览器修复镜像 `umt-browser-desktop:1.18.0-umt.1`,ID `sha256:cf31c83524b260b22c65f39a759771e6861e65a951c89c0382043794aebfadb6`,基于当时运行的 1.18.0 镜像只替换初始化脚本与 XML,基础依赖保持一致;完整构建入口也已包含这两份源码。`.env.deploy` 固定修复标签。浏览器容器 healthy,登录状态卷保留;真实串流前后截图中心线上下黑边从 65/66 像素变为 0/0,画面铺满,视频尺寸保持 1280×900。
发布证据:`.local/deploy-search-detail-20261001/` 中的 `release.json`、`source-manifest.json`、API/页面/搜索检查与截图。桌面证据:`.local/desktop-sizing/` 中的修复前后截图、测量值、有效 XML、补丁构建与发布记录。
## v0.3.12 列表分页、搜索历史与首页概况
2026-10-02,本次将表格和卡片列表统一为 `Pagination` + `useListPagination`,自定义详情列表复用 `PaginatedList`。每页 10/20/50/100 条,默认 50 条,浏览器记住选择;筛选和目录变化回到第一页。支持页码、上一页/下一页、已知集合的首页/末页。游标接口仍按需拉取,返回上一页使用缓存;没有总数时准确写「已加载」,不将已加载数量当完整总数。
覆盖整理记录、审计、下载/业务任务、任务流、媒体库/身份/别名、订阅、站点卡片与资源、搜索作品候选与资源、待处理、智能体历史、媒体详情季集/版本/历史、整理预览、来源配置、计划与运行历史、设置里的规则/偏好/路径映射/Passkey,以及文件管理器和目录选择小窗。表格默认共用分页,订阅和整理批量勾选明确按本页操作,跨页已选项目保持可见计数。少量嵌套季集或版本(不超过 10 条)保留展开列表,避免同一项内重复出现翻页工具;首页近期摘要和导航通知预览不做完整列表分页,仍链接到完整页面。
小规模配置 API 跟随游标取齐,保留原返回形状;主要历史列表继续按需游标请求。作品详情的下载、整理和未提交成功的失败计划取消原先 100/100/50 条读取上限,前端分页呈现;这是现有单作品详情接口的完整查询,不新增多套 API。定时运行记录后端只保留最近 50 次,本次分页覆盖其实际保存的记录。聚合作品搜索仍是本地与 TMDB 的候选结果集合(每来源至多 50),资源列表走完整的 `/search/releases` 游标;未扩展 TMDB 跨页搜索业务。目录树接口原有数量截断提示保留,右侧文件列表仍可完整按游标浏览。
搜索历史在当前浏览器按账号隔离保存最近 30 个已搜索关键词,重复搜索前移,搜索页和 Ctrl/⌘ K 共用,支持点击重搜、删除单条与清空;输入过程不写入历史。通知铃铛、角标、浮层、条目、严重度、加载/空/错误状态共用控制台按钮和样式,修正手机边距与暗色角标对比。
首页新增存储和下载器两张概况卡:媒体库/下载目录所在磁盘的剩余、已用、总容量、占用比例与健康状态;各下载器连接状态和上下行速度、全系统进行中任务数。容量按所在文件系统展示,不把共用磁盘的多个目录相加;进行中数量包含等待计划、暂停和异常任务。不可读容量和离线速度显示未知。存储每 60 秒更新、下载器每 15 秒更新,首页只请求一条面板记录,速度和计数由完整汇总提供。详情分别链接运行状态和下载面板。
验证证据:`.local/pagination-release-20261002/` 的类型/测试/格式/浏览器结果、页面截图和构建发布记录;`.local/notification-style/` 的通知前图、首页手机/桌面与离线/容量未知检查。前端 29 文件 242 测试通过;服务端媒体版本 4 项通过,新增跨旧上限的 105 条下载、105 条整理和 51 条失败计划验证。浏览器用受控审计响应验证 10/100 条切换、跨游标下一页、缓存上一页、末页和筛选复位,搜索历史验证刷新、删除、重搜、快捷面板和清空;未执行实际下载或整理。
整理使用方式另完成 MP 固定源码与本项目实际页面对照,结论见 [对照第 6 节](15-moviepilot-v3-comparison.md#6-整理使用方式与文件管理器专项研究2026-10-02)。来源默认一致性、成功移动后重整、向导勾选语义和空配置入口仍待讨论;本次只调整分页,不实施这些业务改动。
## v0.3.13 统一整理弹窗与队列
2026-10-02,用户确认 MP 方案并授权完成本轮与部署。手动、文件管理、下载详情和历史重整共用单表单弹窗,支持电影/剧集、TMDB 搜索或 ID 定位、来源配置、复制/移动、目标路径、本次刮削及可展开预览。只提供「加入整理队列」,后台受理后关闭;部分受理时移除已入队文件,剩余文件再预览。整理页分队列与记录,直接复用原任务引擎;默认队列也展示尚未生成整理记录的下载核验任务。
成功历史跳过遵循 MP:手动入口有成功历史才显示开关,默认关闭,预览与执行同参数;失败/部分成功记录不计入成功数。成功移动历史从媒体库目标重整,失败/复制仍使用源。刮削开关冻结到既有计划,TMDB/Local 与恢复执行均遵守本次值。通知数字角标改为主题 primary 配色,每页条数使用现有 Select。
无新增迁移,沿用 `0060_manual_acquisition`;只发布应用镜像,浏览器、Caddy、PostgreSQL、qB 和宿主版本保持当前状态。部署配置固定 `v0.3.13` 及本次源码指纹。备份、镜像、健康和前后端版本证据记录于 `.local/organize-final-20261002/release.json`。
前端全套与相关服务端回归通过;服务端用隔离数据库/临时文件验证移动后重整、成功跳过、配对字幕、TMDB/Local 刮削开关和任务恢复。类型与格式检查通过。浏览器验证统一 Select、成功历史开关、预览失效、过时 TMDB 回包、受理期关闭行为、部分受理后只提交剩余文件以及手机布局,所有整理写请求均使用拦截响应,未对用户媒体执行整理、移动、替换或刮削。生产构建与应用发布检查同目录保存。
部署后核验:前端 250 项、相关服务端 64 项测试通过;4380 HTTPS 的前后端版本一致,应用 healthy,启动 error 级日志为 0,其它服务容器未替换。生产入口 13 个主页面、媒体详情及整理记录详情冒烟通过,无页面异常或失败 API;刮削队列与关联记录、桌面/手机弹窗和分页交互验证通过。备份 `/data/backups/20261001T184721Z` 三个文件的 SHA256 校验通过。发布文档在验收后补充,此文件不进入 Docker 构建上下文。
业务对照与决策见 [第 6.4/6.5 节](15-moviepilot-v3-comparison.md#64-用户反馈与后续讨论2026-10-02),使用方式见 [整理手册](../runbook/organize.md)。
## v0.3.14 原地入库(代码完成,未部署)
2026-10-02。用户要求文件管理整理补齐原地处理,参考 MP,并记录改动。新增共用整理弹窗「原地入库 · 保留位置与名称」:已登记媒体库内的选择默认原地登记,可切回复制/移动;下载缓存维持原有方式。源目标相同,隐藏搬运目标/命名/替换选项,识别和预览后仍只加入既有队列。
执行只读核验源文件,不复制、移动、改名、创建目标目录或清理临时文件;复用逐文件账本和最终事务登记视频、字幕、位置、版本与季集覆盖,同作品既有资产不重复创建。结果和重新整理入口识别 `in_place`。不新建目录绑定,不原地洗版;已登记为其它作品或计划后改变的文件会提示失败。可选刮削只针对本次成功主视频,不扫描整个同目录/作品其它版本;只登记库根不写元数据。
MP 固定源码没有独立原地入库模式,其文件管理提供就地刮削;本项目原有刮削仅创建作品条目和元数据文件,未登记视频资产。此改动补齐本工具的资产管理,参考依据见 [业务对照 §6.6](15-moviepilot-v3-comparison.md#66-原地入库补充2026-10-02v0314-待部署)。
迁移 `0061_organize_in_place` 为整理记录 action 和文件结果 mode 增加 `in_place`,未执行生产迁移。workspace/server/web 源码版本准备为 0.3.14;`.env.deploy` 与当前生产保留 v0.3.13。
验证:前端 30 文件/252 项测试,整理计划 22 项、枚举映射 22 项、执行只读核验 3 项通过;前后端类型检查(含新增服务端测试)、格式和差异检查通过。服务端编译及编译二进制模块图自检通过。新增 6 项隔离 PostgreSQL 集成用例覆盖实际文件、重复登记、字幕、季集、刮削范围、变更/归属冲突和只读库根,但当前会话不能连接测试数据库,全部跳过,不计为通过。
前端 production build 的客户端与服务端打包已完成,最后 React Router 预渲染需要监听 localhost,被当前沙箱以 `listen EACCES` 拒绝,完整构建未通过。Docker socket 访问同样被拒绝,因此未构建发布镜像、未部署、未进行生产浏览器验收。早期 Deno Vitest forks/threads 受运行时兼容问题影响;前端与执行核验改用 Node 复验通过,其它结果按实际日志记录。没有修改用户实际媒体文件。
证据位于 `.local/in-place-20261002/`。待有正常部署权限时,先补跑这 6 项数据库用例和完整前端构建,再按现有发布流程备份、检查在途任务、构建新镜像并仅更新 app。不得直接把旧 v0.3.13 镜像改标签当作新版。
### 2026-10-02 补充验证与修复(仍未部署)
开发库补齐迁移至 `0061` 后补跑:原地入库 6 项数据库用例全部通过(其中 1 项原先断言调用了文件管理装配未挂载的整理记录接口,改为直接查记录表)。全 workspace 类型检查、Biome 与各包测试通过:server 840(1 跳过)、adapters 464(3 跳过)、contracts 1053、domain 658、agent 82、db 21、mapping 22、tasks 17、testkit 5、web 252。
同批修复:识别升级链不再用更差的结果(`no_match`)顶替原有歧义候选,与 MP 识别兜底"只在前一步没有结果时采用"一致;作品目录刮削对 `bluray_dir` 资产直接以原盘目录为刮削根(MP 同做法);`metadata.resolve_organize` 补登记到入库排障 Skill 与能力地图;`db/src/types.ts` 按迁移重新生成,contracts 整理动作枚举顺序与数据库对齐。前端统一通知铃铛弹层与站点卡片样式。前端完整 production build 与镜像构建仍按上文发布流程执行。
@@ -0,0 +1,466 @@
{
"jsr_path": {
"scope": "std",
"name": "path",
"latest": "1.1.6",
"versions": {
"0.204.0": {
"createdAt": "2024-04-24T06:22:04.054652Z"
},
"0.219.0": {
"createdAt": "2024-03-08T07:11:36.056284Z"
},
"1.1.6": {
"createdAt": "2026-06-30T10:24:29.944663Z"
},
"0.213.0": {
"createdAt": "2024-01-26T08:16:46.618940Z"
},
"1.0.0-rc.3": {
"createdAt": "2024-07-02T11:46:57.873141Z"
},
"0.218.1": {
"createdAt": "2024-03-01T03:44:36.998490Z"
},
"0.212.0": {
"createdAt": "2024-01-16T10:22:10.013057Z"
},
"1.1.5": {
"createdAt": "2026-05-26T09:57:13.079190Z"
},
"0.205.0": {
"createdAt": "2024-04-24T06:20:40.855663Z"
},
"0.198.0": {
"createdAt": "2024-04-24T06:54:01.469929Z"
},
"1.0.3": {
"createdAt": "2024-08-26T08:37:13.530991Z"
},
"1.0.0-rc.4": {
"createdAt": "2024-07-09T06:17:02.990512Z"
},
"0.211.0": {
"createdAt": "2024-04-23T14:29:25.560075Z"
},
"1.1.3": {
"createdAt": "2025-11-17T08:24:43.343051Z"
},
"0.223.0": {
"createdAt": "2024-04-16T11:36:08.884192Z"
},
"1.1.4": {
"createdAt": "2025-12-24T07:18:31.658575Z"
},
"0.216.0": {
"createdAt": "2024-02-16T06:12:39.561859Z"
},
"0.214.0": {
"createdAt": "2024-02-06T09:55:45.141761Z"
},
"0.225.2": {
"createdAt": "2024-06-03T06:47:44.310028Z"
},
"0.218.0": {
"createdAt": "2024-02-29T23:28:16.999233Z"
},
"0.196.0": {
"createdAt": "2024-04-25T05:40:21.193428Z"
},
"0.203.0": {
"createdAt": "2024-04-24T06:33:50.897004Z"
},
"0.197.0": {
"createdAt": "2024-04-25T05:37:18.401737Z"
},
"0.215.0": {
"createdAt": "2024-02-08T21:57:13.585426Z"
},
"0.213.1": {
"createdAt": "2024-01-26T19:07:59.609934Z"
},
"1.0.7": {
"createdAt": "2024-10-24T10:27:26.548716Z"
},
"1.0.8": {
"createdAt": "2024-11-01T10:38:03.318975Z"
},
"1.0.6": {
"createdAt": "2024-09-12T17:00:19.414985Z"
},
"1.0.0": {
"createdAt": "2024-07-12T10:50:37.927014Z"
},
"0.225.1": {
"createdAt": "2024-05-16T11:15:16.445309Z"
},
"0.217.0": {
"createdAt": "2024-02-22T05:47:42.790539Z"
},
"0.207.0": {
"createdAt": "2024-04-24T06:15:28.582574Z"
},
"1.0.5": {
"createdAt": "2024-09-12T10:26:27.814650Z"
},
"1.0.2": {
"createdAt": "2024-07-26T10:49:53.428735Z"
},
"1.0.1": {
"createdAt": "2024-07-19T11:25:58.680433Z"
},
"0.200.0": {
"createdAt": "2024-04-24T06:44:40.616320Z"
},
"1.0.9": {
"createdAt": "2025-04-24T06:23:27.551197Z"
},
"0.224.0": {
"createdAt": "2024-04-25T07:39:27.314783Z"
},
"0.221.0": {
"createdAt": "2024-03-28T00:04:19.321412Z"
},
"1.1.2": {
"createdAt": "2025-08-13T12:38:19.728538Z"
},
"0.210.0": {
"createdAt": "2023-12-22T11:26:40.901028Z"
},
"0.220.1": {
"createdAt": "2024-03-15T02:40:27.584710Z"
},
"0.206.0": {
"createdAt": "2024-04-24T06:19:17.889544Z"
},
"1.1.1": {
"createdAt": "2025-07-01T07:43:30.791791Z"
},
"0.222.1": {
"createdAt": "2024-04-11T11:12:26.247290Z"
},
"1.0.0-rc.2": {
"createdAt": "2024-06-17T09:56:55.865334Z"
},
"0.219.1": {
"createdAt": "2024-03-08T09:39:27.810189Z"
},
"0.218.2": {
"createdAt": "2024-03-01T04:33:16.720737Z"
},
"1.0.0-rc.1": {
"createdAt": "2024-06-06T11:30:54.416826Z"
},
"1.0.4": {
"createdAt": "2024-09-04T10:41:45.785792Z"
},
"1.1.0": {
"createdAt": "2025-05-27T07:30:38.330934Z"
},
"0.225.0": {
"yanked": true,
"createdAt": "2024-04-29T16:05:05.405226Z"
},
"0.208.0": {
"createdAt": "2024-04-24T06:08:36.973193Z"
},
"0.199.0": {
"createdAt": "2024-04-24T06:50:53.628212Z"
},
"0.201.0": {
"createdAt": "2024-04-24T06:39:27.098273Z"
},
"0.222.0": {
"createdAt": "2024-04-11T05:45:10.832896Z"
},
"0.209.0": {
"createdAt": "2024-04-23T15:22:26.240920Z"
},
"0.202.0": {
"createdAt": "2024-04-24T06:37:25.846681Z"
}
}
},
"jsr_internal": {
"scope": "std",
"name": "internal",
"latest": "1.0.14",
"versions": {
"0.197.0": {
"createdAt": "2024-04-25T05:37:04.008388Z"
},
"0.202.0": {
"createdAt": "2024-04-24T06:37:17.278025Z"
},
"1.0.9": {
"createdAt": "2025-07-01T07:43:25.269328Z"
},
"1.0.10": {
"createdAt": "2025-07-22T13:14:56.088744Z"
},
"0.216.0": {
"createdAt": "2024-02-16T06:12:14.762854Z"
},
"1.0.0": {
"createdAt": "2024-05-22T11:08:19.499017Z"
},
"0.215.0": {
"createdAt": "2024-02-08T21:56:50.207994Z"
},
"0.205.0": {
"createdAt": "2024-04-24T06:20:31.113119Z"
},
"0.225.1": {
"createdAt": "2024-05-16T11:15:06.195844Z"
},
"0.225.0": {
"yanked": true,
"createdAt": "2024-04-29T16:04:59.888254Z"
},
"0.214.0": {
"createdAt": "2024-02-06T05:50:11.102748Z"
},
"0.213.1": {
"createdAt": "2024-01-26T19:07:53.131686Z"
},
"0.201.0": {
"createdAt": "2024-04-24T06:39:20.704773Z"
},
"0.196.0": {
"createdAt": "2024-04-25T05:40:15.000809Z"
},
"1.0.5": {
"createdAt": "2024-11-01T10:38:01.932266Z"
},
"0.207.0": {
"createdAt": "2024-04-24T06:15:05.941336Z"
},
"1.0.6": {
"createdAt": "2025-03-25T07:17:06.921973Z"
},
"0.199.0": {
"createdAt": "2024-04-24T06:50:41.464255Z"
},
"1.0.13": {
"createdAt": "2026-04-20T13:57:46.913983Z"
},
"0.206.0": {
"createdAt": "2024-04-24T06:19:08.538414Z"
},
"0.208.0": {
"createdAt": "2024-04-24T06:08:11.707171Z"
},
"1.0.8": {
"createdAt": "2025-05-27T07:30:44.423577Z"
},
"0.204.0": {
"createdAt": "2024-04-24T06:21:55.527004Z"
},
"0.213.0": {
"createdAt": "2024-01-26T08:09:52.150304Z"
},
"0.198.0": {
"createdAt": "2024-04-24T06:53:55.032868Z"
},
"1.0.3": {
"createdAt": "2024-09-04T10:41:43.017156Z"
},
"1.0.14": {
"createdAt": "2026-05-26T09:57:07.159939Z"
},
"0.203.0": {
"createdAt": "2024-04-24T06:33:28.861052Z"
},
"1.0.7": {
"createdAt": "2025-05-13T07:25:42.233848Z"
},
"1.0.2": {
"createdAt": "2024-08-26T08:37:19.813343Z"
},
"0.200.0": {
"createdAt": "2024-04-24T06:44:21.451197Z"
},
"1.0.12": {
"createdAt": "2025-10-07T08:24:12.939816Z"
},
"1.0.4": {
"createdAt": "2024-09-24T10:31:08.642379Z"
},
"0.224.0": {
"createdAt": "2024-04-25T07:39:12.537935Z"
},
"1.0.1": {
"createdAt": "2024-07-02T11:47:12.495023Z"
}
}
},
"pi_release": {
"tag_name": "v0.99.2",
"published_at": "2026-09-30T19:30:47Z",
"html_url": "https://github.com/earendil-works/pi/releases/tag/v0.99.2"
},
"camofox_118_manifest": {
"name": "@askjo/camofox-browser",
"version": "1.18.0",
"engines": {
"node": ">=22"
},
"dependencies": {
"better-sqlite3": "13.0.1",
"camoufox-js": "0.11.5",
"express": "^5.2.1",
"playwright-core": "^1.58.0",
"prom-client": "^15.1.3",
"swagger-jsdoc": "^6.2.8"
},
"optionalDependencies": {
"@modelcontextprotocol/sdk": "^1.30.0"
},
"overrides": {
"@jest/reporters": {
"glob": "13.0.6"
},
"babel-plugin-istanbul": {
"test-exclude": "8.0.0"
},
"jest-config": {
"glob": "13.0.6"
},
"jest-runtime": {
"glob": "13.0.6"
},
"swagger-jsdoc": {
"glob": "13.0.6"
},
"qs": "6.16.0",
"fast-uri": "3.1.8",
"hono": "4.13.5"
}
},
"static_ffmpeg_release": {
"error": "HTTP Error 404: Not Found"
},
"pixelflux": {
"version": "2.1.0",
"requires_python": ">=3.9",
"project_urls": {
"Homepage": "https://github.com/selkies-project/pixelflux"
}
},
"selkies": {
"version": "2.0.0",
"requires_python": ">=3.9",
"project_urls": {
"Bug Tracker": "https://github.com/selkies-project/selkies/issues",
"Homepage": "https://github.com/selkies-project/selkies"
}
},
"labwc_release": {
"tag_name": "0.20.2",
"published_at": "2026-08-21T17:28:56Z",
"html_url": "https://github.com/labwc/labwc/releases/tag/0.20.2"
},
"rr7": {
"name": "react-router",
"version": "7.18.4",
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"rrdev7": {
"name": "@react-router/dev",
"version": "7.18.4",
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"vite": "^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"wrangler": "^3.28.2 || ^4.0.0",
"typescript": "^5.1.0 || ^6.0.0",
"react-router": "^7.18.4",
"@vitejs/plugin-rsc": "~0.5.21",
"@react-router/serve": "^7.18.4",
"react-server-dom-webpack": "^19.2.3"
}
},
"rrnode7": {
"name": "@react-router/node",
"version": "7.18.4",
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"typescript": "^5.1.0 || ^6.0.0",
"react-router": "7.18.4"
}
},
"browser:better-sqlite3": {
"name": "better-sqlite3",
"version": "13.0.3",
"engines": {
"node": ">=22"
}
},
"browser:camoufox-js": {
"name": "camoufox-js",
"version": "0.12.0",
"engines": {
"node": ">= 22"
},
"peerDependencies": {
"playwright-core": "<1.61.0"
}
},
"browser:express": {
"name": "express",
"version": "5.2.1",
"engines": {
"node": ">= 18"
}
},
"browser:playwright-core": {
"name": "playwright-core",
"version": "1.63.0",
"engines": {
"node": ">=20"
}
},
"browser:prom-client": {
"name": "prom-client",
"version": "15.1.3",
"engines": {
"node": "^16 || ^18 || >=20"
}
},
"browser:swagger-jsdoc": {
"name": "swagger-jsdoc",
"version": "6.3.0",
"engines": {
"node": ">=20.0.0"
}
},
"pi_mcp": {
"name": "@earendil-works/pi-mcp",
"version": "0.99.2",
"engines": {
"node": ">=22.19.0"
},
"dependencies": {
"cross-spawn": "7.0.6"
}
},
"pi_codemode": {
"name": "@earendil-works/pi-codemode",
"version": "0.99.2",
"engines": {
"node": ">=22.19.0"
},
"dependencies": {
"quickjs-wasi": "3.6.2"
}
}
}
@@ -0,0 +1,353 @@
{
"auditReportVersion": 2,
"vulnerabilities": {
"adm-zip": {
"name": "adm-zip",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1193734,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip extraction follows destination symlinks, allowing arbitrary file overwrite",
"url": "https://github.com/advisories/GHSA-vwc7-r8mq-g2x9",
"severity": "moderate",
"cwe": [
"CWE-59"
],
"cvss": {
"score": 6.5,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:N"
},
"range": ">=0.5.9 <=0.6.0"
},
{
"source": 1239030,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS)",
"url": "https://github.com/advisories/GHSA-7q85-xj36-vmfc",
"severity": "high",
"cwe": [
"CWE-789"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<0.6.1"
},
{
"source": 1240032,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip: Decompression-bomb protection (fix for CVE-2026-39244) can be bypassed by declaring uncompressed size as 0",
"url": "https://github.com/advisories/GHSA-rcw4-f5rp-g42v",
"severity": "high",
"cwe": [
"CWE-409"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<=0.6.0"
},
{
"source": 1240034,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip extraction preserves SUID/SGID bits from untrusted ZIPs -> local privilege escalation",
"url": "https://github.com/advisories/GHSA-j5f4-cc29-5x44",
"severity": "high",
"cwe": [
"CWE-732"
],
"cvss": {
"score": 7.1,
"vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N"
},
"range": "<=0.6.0"
},
{
"source": 1240064,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip: Duplicate ZIP entry names: getEntry() and extractAllTo() resolve to different content",
"url": "https://github.com/advisories/GHSA-p634-w6r4-rjp2",
"severity": "moderate",
"cwe": [
"CWE-436",
"CWE-696"
],
"cvss": {
"score": 5.9,
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N"
},
"range": "<=0.6.0"
},
{
"source": 1240065,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip: getDataAsync() bypasses the maxOutputLength size guard enforced by the synchronous getData() path",
"url": "https://github.com/advisories/GHSA-c6fg-446q-cg94",
"severity": "moderate",
"cwe": [
"CWE-400",
"CWE-770"
],
"cvss": {
"score": 5.3,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
},
"range": "<=0.6.0"
},
{
"source": 1240066,
"name": "adm-zip",
"dependency": "adm-zip",
"title": "adm-zip: Unhandled error event in async DEFLATE decompression crashes Node.js process (DoS)",
"url": "https://github.com/advisories/GHSA-8238-w5pm-2374",
"severity": "high",
"cwe": [
"CWE-248",
"CWE-400"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": "<=0.6.0"
}
],
"effects": [],
"range": "<=0.6.0",
"nodes": [
"node_modules/adm-zip"
],
"fixAvailable": true
},
"brace-expansion": {
"name": "brace-expansion",
"severity": "high",
"isDirect": false,
"via": [
{
"source": 1240103,
"name": "brace-expansion",
"dependency": "brace-expansion",
"title": "brace-expansion: Quadratic-time expansion of the `{a},b}` rewrite causes CPU denial of service",
"url": "https://github.com/advisories/GHSA-q2hr-2g5m-vwhr",
"severity": "moderate",
"cwe": [
"CWE-400",
"CWE-407"
],
"cvss": {
"score": 5.3,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L"
},
"range": ">=4.0.0 <5.0.12"
},
{
"source": 1240107,
"name": "brace-expansion",
"dependency": "brace-expansion",
"title": "brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion",
"url": "https://github.com/advisories/GHSA-qhr7-859c-m2p7",
"severity": "high",
"cwe": [
"CWE-400",
"CWE-674"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": ">=4.0.0 <5.0.11"
},
{
"source": 1240111,
"name": "brace-expansion",
"dependency": "brace-expansion",
"title": "brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion",
"url": "https://github.com/advisories/GHSA-6j4f-fj2g-mc7p",
"severity": "high",
"cwe": [
"CWE-400",
"CWE-674"
],
"cvss": {
"score": 7.5,
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
},
"range": ">=4.0.0 <5.0.10"
}
],
"effects": [],
"range": "4.0.0 - 5.0.11",
"nodes": [
"node_modules/brace-expansion"
],
"fixAvailable": true
},
"fast-uri": {
"name": "fast-uri",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1240091,
"name": "fast-uri",
"dependency": "fast-uri",
"title": "fast-uri vulnerable to inconsistent host case normalization via percent-encoded octets",
"url": "https://github.com/advisories/GHSA-hrr3-gc8f-f4qj",
"severity": "moderate",
"cwe": [
"CWE-178"
],
"cvss": {
"score": 4.8,
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N"
},
"range": ">=3.0.0 <3.1.8"
}
],
"effects": [],
"range": "3.0.0 - 3.1.7",
"nodes": [
"node_modules/fast-uri"
],
"fixAvailable": true
},
"hono": {
"name": "hono",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1240640,
"name": "hono",
"dependency": "hono",
"title": "hono/jsx renders plain strings unescaped in boundary components, leading to XSS",
"url": "https://github.com/advisories/GHSA-hxh3-vqpv-xpqv",
"severity": "moderate",
"cwe": [
"CWE-79"
],
"cvss": {
"score": 4.7,
"vectorString": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:L/I:L/A:N"
},
"range": "<4.13.7"
}
],
"effects": [],
"range": "<4.13.7",
"nodes": [
"node_modules/hono"
],
"fixAvailable": true
},
"ip-address": {
"name": "ip-address",
"severity": "moderate",
"isDirect": false,
"via": [
{
"source": 1239948,
"name": "ip-address",
"dependency": "ip-address",
"title": "ip-address: Address6.isLinkLocal() recognizes fe80::/64 rather than fe80::/10, allowing SSRF and trust-boundary bypass to on-link hosts",
"url": "https://github.com/advisories/GHSA-rpw4-54j3-4h4q",
"severity": "moderate",
"cwe": [
"CWE-697",
"CWE-918"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<=10.5.0"
},
{
"source": 1239949,
"name": "ip-address",
"dependency": "ip-address",
"title": "ip-address: no classifier recognizes the NAT64 local-use range 64:ff9b:1::/48, allowing SSRF and trust-boundary bypass",
"url": "https://github.com/advisories/GHSA-2vr4-cq9g-pvrc",
"severity": "moderate",
"cwe": [
"CWE-918"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": ">=10.2.0 <=10.5.0"
},
{
"source": 1240097,
"name": "ip-address",
"dependency": "ip-address",
"title": "ip-address: isInSubnet() and isHostInSubnet() compare addresses of different families as if they shared an address space, allowing an allowlist check to admit an address outside its range",
"url": "https://github.com/advisories/GHSA-j6r3-76f7-8jcv",
"severity": "moderate",
"cwe": [
"CWE-697",
"CWE-843"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<=10.7.0"
},
{
"source": 1240098,
"name": "ip-address",
"dependency": "ip-address",
"title": "ip-address: Address6 builds a parse diagnostic proportional to the input with no length bound, allowing a single long string to stall or crash the process",
"url": "https://github.com/advisories/GHSA-h3mg-xc3c-68pw",
"severity": "moderate",
"cwe": [
"CWE-400",
"CWE-770"
],
"cvss": {
"score": 0,
"vectorString": null
},
"range": "<=10.7.0"
}
],
"effects": [],
"range": "<=10.7.0",
"nodes": [
"node_modules/ip-address"
],
"fixAvailable": true
}
},
"metadata": {
"vulnerabilities": {
"info": 0,
"low": 0,
"moderate": 3,
"high": 2,
"critical": 0,
"total": 5
},
"dependencies": {
"prod": 171,
"dev": 501,
"optional": 84,
"peer": 1,
"peerOptional": 0,
"total": 680
}
}
}
@@ -0,0 +1,51 @@
[
{
"name": "umt-app-1",
"image": "uhd-media-tool:v0.3.8",
"imageId": "sha256:6f4f73d8ea53057cdf5bf4aa2904a360ea953adb1270a7b9f783a757b7e70559",
"health": "healthy",
"status": "running"
},
{
"name": "umt-postgres-1",
"image": "postgres:18.6-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873",
"imageId": "sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873",
"health": "healthy",
"status": "running"
},
{
"name": "umt-dev-postgres-1",
"image": "postgres:18.6-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873",
"imageId": "sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873",
"health": "healthy",
"status": "running"
},
{
"name": "umt-camofox-1",
"image": "umt-browser-desktop:1.18.0",
"imageId": "sha256:eb6c8e8e43e573ad5e3223619b77328e12fb54fe40c283b9de02c7f6d03f5cda",
"health": "healthy",
"status": "running"
},
{
"name": "umt-qbittorrent-1",
"image": "lscr.io/linuxserver/qbittorrent:5.2.4@sha256:b522f9f4b769f8f36d49d22d5eb6a92e9aa18904c6a1830b1439df511ec21983",
"imageId": "sha256:b522f9f4b769f8f36d49d22d5eb6a92e9aa18904c6a1830b1439df511ec21983",
"health": null,
"status": "running"
},
{
"name": "umt-caddy-1",
"image": "caddy:2.11.4-alpine@sha256:6aeddd44c3078b0f9a35206472a11420648a79c184603ef95957d0a20044cb2b",
"imageId": "sha256:6aeddd44c3078b0f9a35206472a11420648a79c184603ef95957d0a20044cb2b",
"health": null,
"status": "running"
},
{
"name": "umt-proxy-relay-1",
"image": "alpine/socat:1.8.1.3@sha256:5ffbd6ae916cbad86a58fabe0d6d5a6fd5c2b47ddf031e82996baac9300e732f",
"imageId": "sha256:5ffbd6ae916cbad86a58fabe0d6d5a6fd5c2b47ddf031e82996baac9300e732f",
"health": null,
"status": "running"
}
]
@@ -0,0 +1,59 @@
package,declared,locked,registry_latest,candidate,decision
@biomejs/biome,2.5.14,2.5.14,2.5.15,2.5.15,候选升级,未验证
@earendil-works/pi-agent-core,0.87.1,0.87.1,0.99.2,0.99.2,同步升级并验证嵌入接口;另评估 pi-mcp SDK
@earendil-works/pi-ai,0.87.1,0.87.1,0.99.2,0.99.2,同步升级并验证嵌入接口;另评估 pi-mcp SDK
@fontsource-variable/inter-tight,^5.2.7,5.3.0,5.3.0,5.3.0,保持
@fontsource-variable/space-grotesk,^5.2.10,5.3.0,5.3.0,5.3.0,保持
@hono/swagger-ui,0.6.1,0.6.1,0.6.1,0.6.1,保持
@hono/zod-openapi,1.6.3,1.6.3,1.6.3,1.6.3,保持
@modelcontextprotocol/sdk,1.30.1,1.30.1,1.31.0,1.31.0,候选升级,未验证
@react-router/dev,7.12.0,7.12.0,8.4.0,7.18.4,先同主版本安全修复;8.4.0 另评估
@react-router/node,7.12.0,7.12.0,8.4.0,7.18.4,先同主版本安全修复;8.4.0 另评估
@simplewebauthn/browser,^13.3.0,13.3.0,14.0.0,14.0.0,独立兼容评估后决定,不直接更新
@simplewebauthn/server,13.3.3,13.3.3,14.0.3,14.0.3,独立兼容评估后决定,不直接更新
@tailwindcss/vite,^4.1.13,4.3.3,4.3.3,4.3.3,保持
@tanstack/react-query,^5.90.21,5.104.0,5.104.0,5.104.0,保持
@types/node,24.19.0,24.19.0,26.6.3,24.x,维持与 Node 24 兼容目标;不跟随 26
@types/nunjucks,3.2.6,3.2.6,3.2.6,3.2.6,保持
@types/pg,8.23.1,8.23.1,8.23.1,8.23.1,保持
@types/react,^19.2.7,19.3.0,19.3.0,19.3.0,保持
@types/react-dom,^19.2.3,19.3.0,19.3.0,19.3.0,保持
@xmldom/xmldom,0.9.12,0.9.12,0.9.12,0.9.12,保持
cheerio,1.2.0,1.2.0,1.2.0,1.2.0,保持
class-variance-authority,~0.7.1,0.7.1,0.7.1,0.7.1,保持
clsx,^2.1.1,2.1.1,2.1.1,2.1.1,保持
date-fns,^4.1.0,4.4.0,4.4.0,4.4.0,保持
fast-xml-parser,5.11.1,5.11.1,5.11.2,5.11.2,候选升级,未验证
hash-wasm,4.12.0,4.12.0,4.12.0,4.12.0,保持
hono,4.13.9,4.13.9,4.13.12,4.13.12,候选升级,未验证
isbot,^5.1.31,5.2.2,5.2.2,5.2.2,保持
jpeg-js,0.4.4,0.4.4,0.4.4,0.4.4,保持
kysely,0.29.6,0.29.6,0.29.6,0.29.6,保持
lucide-react,0.576,0.576.0,1.49.0,1.49.0,独立兼容评估后决定,不直接更新
next-themes,~0.4.6,0.4.6,0.4.6,0.4.6,保持
nunjucks,3.2.4,3.2.4,3.2.4,3.2.4,保持
openworkflow,0.10.1,0.10.1,0.10.1,0.10.1,保持
pg,8.23.0,8.23.0,8.23.1,8.23.1,候选升级,未验证
pino,10.3.1,10.3.1,10.3.1,10.3.1,保持
pino-pretty,13.1.3,13.1.3,13.1.3,13.1.3,保持
playwright-core,1.63.0,1.63.0,1.63.0,1.63.0,保持
postgres,3.4.9,3.4.9,3.4.9,3.4.9,保持
qr-code-styling,^1.9.2,1.9.2,1.9.2,1.9.2,保持
radix-ui,^1.4.3,1.6.7,1.6.7,1.6.7,保持
react,^19.2.4,19.3.0,19.3.0,19.3.0,保持
react-day-picker,^10.0.1,10.0.1,10.0.2,10.0.2,候选升级,未验证
react-dom,^19.2.4,19.3.0,19.3.0,19.3.0,保持
react-router,7.12.0,7.12.0,8.4.0,7.18.4,先同主版本安全修复;8.4.0 另评估
recharts,^3.10.1,3.10.1,3.10.1,3.10.1,保持
sonner,^2.0.7,2.0.8,2.0.8,2.0.8,保持
tailwind-merge,^3.5.0,3.7.0,3.7.0,3.7.0,保持
tailwindcss,^4.1.13,4.3.3,4.3.3,4.3.3,保持
tw-animate-css,^1.4.0,1.4.0,1.4.0,1.4.0,保持
typebox,1.3.27,1.3.27,1.3.34,1.3.34,候选升级,未验证
typescript,7.0.2,7.0.2,7.0.2,7.0.2,保持
vite,^7.1.7,7.3.6,8.3.1,8.3.1,独立兼容评估后决定,不直接更新
vite-tsconfig-paths,^5.1.4,5.1.4,6.1.1,6.1.1,独立兼容评估后决定,不直接更新
vitest,5.0.2,5.0.2,5.0.3,5.0.3,候选升级,未验证
xpath,0.0.34,0.0.34,0.0.34,0.0.34,保持
yaml,2.9.1,2.9.1,2.9.1,2.9.1,保持
zod,4.6.5;^4.3.6,4.6.5,4.6.5,4.6.5,保持
1 package declared locked registry_latest candidate decision
2 @biomejs/biome 2.5.14 2.5.14 2.5.15 2.5.15 候选升级,未验证
3 @earendil-works/pi-agent-core 0.87.1 0.87.1 0.99.2 0.99.2 同步升级并验证嵌入接口;另评估 pi-mcp SDK
4 @earendil-works/pi-ai 0.87.1 0.87.1 0.99.2 0.99.2 同步升级并验证嵌入接口;另评估 pi-mcp SDK
5 @fontsource-variable/inter-tight ^5.2.7 5.3.0 5.3.0 5.3.0 保持
6 @fontsource-variable/space-grotesk ^5.2.10 5.3.0 5.3.0 5.3.0 保持
7 @hono/swagger-ui 0.6.1 0.6.1 0.6.1 0.6.1 保持
8 @hono/zod-openapi 1.6.3 1.6.3 1.6.3 1.6.3 保持
9 @modelcontextprotocol/sdk 1.30.1 1.30.1 1.31.0 1.31.0 候选升级,未验证
10 @react-router/dev 7.12.0 7.12.0 8.4.0 7.18.4 先同主版本安全修复;8.4.0 另评估
11 @react-router/node 7.12.0 7.12.0 8.4.0 7.18.4 先同主版本安全修复;8.4.0 另评估
12 @simplewebauthn/browser ^13.3.0 13.3.0 14.0.0 14.0.0 独立兼容评估后决定,不直接更新
13 @simplewebauthn/server 13.3.3 13.3.3 14.0.3 14.0.3 独立兼容评估后决定,不直接更新
14 @tailwindcss/vite ^4.1.13 4.3.3 4.3.3 4.3.3 保持
15 @tanstack/react-query ^5.90.21 5.104.0 5.104.0 5.104.0 保持
16 @types/node 24.19.0 24.19.0 26.6.3 24.x 维持与 Node 24 兼容目标;不跟随 26
17 @types/nunjucks 3.2.6 3.2.6 3.2.6 3.2.6 保持
18 @types/pg 8.23.1 8.23.1 8.23.1 8.23.1 保持
19 @types/react ^19.2.7 19.3.0 19.3.0 19.3.0 保持
20 @types/react-dom ^19.2.3 19.3.0 19.3.0 19.3.0 保持
21 @xmldom/xmldom 0.9.12 0.9.12 0.9.12 0.9.12 保持
22 cheerio 1.2.0 1.2.0 1.2.0 1.2.0 保持
23 class-variance-authority ~0.7.1 0.7.1 0.7.1 0.7.1 保持
24 clsx ^2.1.1 2.1.1 2.1.1 2.1.1 保持
25 date-fns ^4.1.0 4.4.0 4.4.0 4.4.0 保持
26 fast-xml-parser 5.11.1 5.11.1 5.11.2 5.11.2 候选升级,未验证
27 hash-wasm 4.12.0 4.12.0 4.12.0 4.12.0 保持
28 hono 4.13.9 4.13.9 4.13.12 4.13.12 候选升级,未验证
29 isbot ^5.1.31 5.2.2 5.2.2 5.2.2 保持
30 jpeg-js 0.4.4 0.4.4 0.4.4 0.4.4 保持
31 kysely 0.29.6 0.29.6 0.29.6 0.29.6 保持
32 lucide-react 0.576 0.576.0 1.49.0 1.49.0 独立兼容评估后决定,不直接更新
33 next-themes ~0.4.6 0.4.6 0.4.6 0.4.6 保持
34 nunjucks 3.2.4 3.2.4 3.2.4 3.2.4 保持
35 openworkflow 0.10.1 0.10.1 0.10.1 0.10.1 保持
36 pg 8.23.0 8.23.0 8.23.1 8.23.1 候选升级,未验证
37 pino 10.3.1 10.3.1 10.3.1 10.3.1 保持
38 pino-pretty 13.1.3 13.1.3 13.1.3 13.1.3 保持
39 playwright-core 1.63.0 1.63.0 1.63.0 1.63.0 保持
40 postgres 3.4.9 3.4.9 3.4.9 3.4.9 保持
41 qr-code-styling ^1.9.2 1.9.2 1.9.2 1.9.2 保持
42 radix-ui ^1.4.3 1.6.7 1.6.7 1.6.7 保持
43 react ^19.2.4 19.3.0 19.3.0 19.3.0 保持
44 react-day-picker ^10.0.1 10.0.1 10.0.2 10.0.2 候选升级,未验证
45 react-dom ^19.2.4 19.3.0 19.3.0 19.3.0 保持
46 react-router 7.12.0 7.12.0 8.4.0 7.18.4 先同主版本安全修复;8.4.0 另评估
47 recharts ^3.10.1 3.10.1 3.10.1 3.10.1 保持
48 sonner ^2.0.7 2.0.8 2.0.8 2.0.8 保持
49 tailwind-merge ^3.5.0 3.7.0 3.7.0 3.7.0 保持
50 tailwindcss ^4.1.13 4.3.3 4.3.3 4.3.3 保持
51 tw-animate-css ^1.4.0 1.4.0 1.4.0 1.4.0 保持
52 typebox 1.3.27 1.3.27 1.3.34 1.3.34 候选升级,未验证
53 typescript 7.0.2 7.0.2 7.0.2 7.0.2 保持
54 vite ^7.1.7 7.3.6 8.3.1 8.3.1 独立兼容评估后决定,不直接更新
55 vite-tsconfig-paths ^5.1.4 5.1.4 6.1.1 6.1.1 独立兼容评估后决定,不直接更新
56 vitest 5.0.2 5.0.2 5.0.3 5.0.3 候选升级,未验证
57 xpath 0.0.34 0.0.34 0.0.34 0.0.34 保持
58 yaml 2.9.1 2.9.1 2.9.1 2.9.1 保持
59 zod 4.6.5;^4.3.6 4.6.5 4.6.5 4.6.5 保持
@@ -0,0 +1,634 @@
package,locked_versions,registry_latest,workspace_direct,has_older_or_different_version
@anthropic-ai/sdk,0.124.0,0.131.0,False,True
@asteasolutions/zod-to-openapi,9.1.0,9.1.0,False,False
@aws-sdk/client-bedrock-runtime,3.1127.0,3.1144.0,False,True
@aws-sdk/core,3.978.1,3.978.1,False,False
@aws-sdk/credential-provider-env,3.972.72,3.972.72,False,False
@aws-sdk/credential-provider-http,3.972.74,3.972.74,False,False
@aws-sdk/credential-provider-ini,3.973.17,3.973.17,False,False
@aws-sdk/credential-provider-login,3.972.79,3.972.79,False,False
@aws-sdk/credential-provider-node,3.972.84,3.972.84,False,False
@aws-sdk/credential-provider-process,3.972.72,3.972.72,False,False
@aws-sdk/credential-provider-sso,3.973.16,3.973.16,False,False
@aws-sdk/credential-provider-web-identity,3.972.78,3.972.78,False,False
@aws-sdk/eventstream-handler-node,3.972.35,3.972.35,False,False
@aws-sdk/middleware-eventstream,3.972.30,3.972.30,False,False
@aws-sdk/middleware-websocket,3.972.54,3.972.54,False,False
@aws-sdk/nested-clients,3.997.46,3.997.46,False,False
@aws-sdk/signature-v4-multi-region,3.996.47,3.996.47,False,False
@aws-sdk/token-providers,3.1127.0;3.1138.0,3.1144.0,False,True
@aws-sdk/types,3.974.6,3.974.6,False,False
@aws-sdk/xml-builder,3.972.41,3.972.41,False,False
@aws/lambda-invoke-store,0.3.0,0.3.0,False,False
@babel/code-frame,7.29.7,8.0.6,False,True
@babel/compat-data,7.29.7,8.0.5,False,True
@babel/core,7.29.7,8.0.6,False,True
@babel/generator,7.29.8,8.0.6,False,True
@babel/helper-annotate-as-pure,7.29.7,8.0.0,False,True
@babel/helper-compilation-targets,7.29.7,8.0.6,False,True
@babel/helper-create-class-features-plugin,7.29.7,8.0.6,False,True
@babel/helper-globals,7.29.7,8.0.6,False,True
@babel/helper-member-expression-to-functions,7.29.7,8.0.5,False,True
@babel/helper-module-imports,7.29.7,8.0.0,False,True
@babel/helper-module-transforms,7.29.7,8.0.6,False,True
@babel/helper-optimise-call-expression,7.29.7,8.0.0,False,True
@babel/helper-plugin-utils,7.29.7,8.0.1,False,True
@babel/helper-replace-supers,7.29.7,8.0.1,False,True
@babel/helper-skip-transparent-expression-wrappers,7.29.7,8.0.0,False,True
@babel/helper-string-parser,7.29.7,8.0.6,False,True
@babel/helper-validator-identifier,7.29.7,8.0.6,False,True
@babel/helper-validator-option,7.29.7,8.0.0,False,True
@babel/helpers,7.29.7,8.0.5,False,True
@babel/parser,7.29.9,7.29.9,False,False
@babel/plugin-syntax-jsx,7.29.7,8.0.1,False,True
@babel/plugin-syntax-typescript,7.29.7,8.0.3,False,True
@babel/plugin-transform-modules-commonjs,7.29.7,8.0.1,False,True
@babel/plugin-transform-typescript,7.29.9,7.29.9,False,False
@babel/preset-typescript,7.29.7,8.0.1,False,True
@babel/runtime,7.29.7,8.0.5,False,True
@babel/template,7.29.7,8.0.0,False,True
@babel/traverse,7.29.8,8.0.6,False,True
@babel/types,7.29.8,8.0.6,False,True
@biomejs/biome,2.5.14,2.5.15,True,True
@biomejs/cli-darwin-arm64,2.5.14,2.5.15,False,True
@biomejs/cli-darwin-x64,2.5.14,2.5.15,False,True
@biomejs/cli-linux-arm64,2.5.14,2.5.15,False,True
@biomejs/cli-linux-arm64-musl,2.5.14,2.5.15,False,True
@biomejs/cli-linux-x64,2.5.14,2.5.15,False,True
@biomejs/cli-linux-x64-musl,2.5.14,2.5.15,False,True
@biomejs/cli-win32-arm64,2.5.14,2.5.15,False,True
@biomejs/cli-win32-x64,2.5.14,2.5.15,False,True
@date-fns/tz,1.5.0,1.5.0,False,False
@earendil-works/chord,0.87.1,0.99.2,False,True
@earendil-works/pi-agent-core,0.87.1,0.99.2,True,True
@earendil-works/pi-ai,0.87.1,0.99.2,True,True
@earendil-works/pi-telemetry,0.87.1,0.99.2,False,True
@esbuild/aix-ppc64,0.28.2,0.28.2,False,False
@esbuild/android-arm,0.28.2,0.28.2,False,False
@esbuild/android-arm64,0.28.2,0.28.2,False,False
@esbuild/android-x64,0.28.2,0.28.2,False,False
@esbuild/darwin-arm64,0.28.2,0.28.2,False,False
@esbuild/darwin-x64,0.28.2,0.28.2,False,False
@esbuild/freebsd-arm64,0.28.2,0.28.2,False,False
@esbuild/freebsd-x64,0.28.2,0.28.2,False,False
@esbuild/linux-arm,0.28.2,0.28.2,False,False
@esbuild/linux-arm64,0.28.2,0.28.2,False,False
@esbuild/linux-ia32,0.28.2,0.28.2,False,False
@esbuild/linux-loong64,0.28.2,0.28.2,False,False
@esbuild/linux-mips64el,0.28.2,0.28.2,False,False
@esbuild/linux-ppc64,0.28.2,0.28.2,False,False
@esbuild/linux-riscv64,0.28.2,0.28.2,False,False
@esbuild/linux-s390x,0.28.2,0.28.2,False,False
@esbuild/linux-x64,0.28.2,0.28.2,False,False
@esbuild/netbsd-arm64,0.28.2,0.28.2,False,False
@esbuild/netbsd-x64,0.28.2,0.28.2,False,False
@esbuild/openbsd-arm64,0.28.2,0.28.2,False,False
@esbuild/openbsd-x64,0.28.2,0.28.2,False,False
@esbuild/openharmony-arm64,0.28.2,0.28.2,False,False
@esbuild/sunos-x64,0.28.2,0.28.2,False,False
@esbuild/win32-arm64,0.28.2,0.28.2,False,False
@esbuild/win32-ia32,0.28.2,0.28.2,False,False
@esbuild/win32-x64,0.28.2,0.28.2,False,False
@floating-ui/core,1.8.0,1.8.0,False,False
@floating-ui/dom,1.8.0,1.8.0,False,False
@floating-ui/react-dom,2.1.9,2.1.9,False,False
@floating-ui/utils,0.2.12,0.2.12,False,False
@fontsource-variable/inter-tight,5.3.0,5.3.0,True,False
@fontsource-variable/space-grotesk,5.3.0,5.3.0,True,False
@google/genai,2.21.0,2.25.0,False,True
@hexagon/base64,1.1.28,2.0.4,False,True
@hono/node-server,2.1.1,2.1.3,False,True
@hono/swagger-ui,0.6.1,0.6.1,True,False
@hono/zod-openapi,1.6.3,1.6.3,True,False
@hono/zod-validator,0.9.1,0.9.1,False,False
@jridgewell/gen-mapping,0.3.13,0.3.13,False,False
@jridgewell/remapping,2.3.5,2.3.5,False,False
@jridgewell/resolve-uri,3.1.2,3.1.2,False,False
@jridgewell/sourcemap-codec,1.6.0,1.6.0,False,False
@jridgewell/trace-mapping,0.3.31,0.3.31,False,False
@levischuck/tiny-cbor,0.2.11,0.3.6,False,True
@mjackson/node-fetch-server,0.2.0,0.7.0,False,True
@modelcontextprotocol/sdk,1.30.1,1.31.0,True,True
@napi-rs/lzma-linux-x64-gnu,1.5.1,1.5.1,False,False
@nodable/entities,3.0.0,3.1.0,False,True
@peculiar/asn1-android,2.9.5,2.10.0,False,True
@peculiar/asn1-cms,2.9.5,2.10.0,False,True
@peculiar/asn1-csr,2.9.5,2.10.0,False,True
@peculiar/asn1-ecc,2.9.5,2.10.0,False,True
@peculiar/asn1-pfx,2.9.5,2.10.0,False,True
@peculiar/asn1-pkcs8,2.9.5,2.10.0,False,True
@peculiar/asn1-pkcs9,2.9.5,2.10.0,False,True
@peculiar/asn1-rsa,2.9.5,2.10.0,False,True
@peculiar/asn1-schema,2.9.5,2.10.0,False,True
@peculiar/asn1-x509,2.9.5,2.10.0,False,True
@peculiar/asn1-x509-attr,2.9.5,2.10.0,False,True
@peculiar/utils,2.0.3,2.0.3,False,False
@peculiar/x509,1.14.3,2.1.0,False,True
@pinojs/redact,0.4.0,0.4.0,False,False
@protobufjs/aspromise,1.1.2,1.1.2,False,False
@protobufjs/base64,1.1.2,1.1.2,False,False
@protobufjs/codegen,2.0.5,2.0.5,False,False
@protobufjs/eventemitter,1.1.1,1.1.1,False,False
@protobufjs/fetch,1.1.1,1.1.1,False,False
@protobufjs/float,1.0.2,1.0.2,False,False
@protobufjs/path,1.1.2,1.1.2,False,False
@protobufjs/pool,1.1.0,1.1.0,False,False
@protobufjs/utf8,1.1.2,1.1.2,False,False
@radix-ui/number,1.1.3,1.1.3,False,False
@radix-ui/primitive,1.1.7,1.1.7,False,False
@radix-ui/react-accessible-icon,1.1.15,1.1.15,False,False
@radix-ui/react-accordion,1.2.20,1.2.20,False,False
@radix-ui/react-alert-dialog,1.1.23,1.1.23,False,False
@radix-ui/react-arrow,1.1.15,1.1.15,False,False
@radix-ui/react-aspect-ratio,1.1.15,1.1.15,False,False
@radix-ui/react-avatar,1.2.6,1.2.6,False,False
@radix-ui/react-checkbox,1.3.11,1.3.11,False,False
@radix-ui/react-collapsible,1.1.20,1.1.20,False,False
@radix-ui/react-collection,1.1.15,1.1.15,False,False
@radix-ui/react-compose-refs,1.1.5,1.1.5,False,False
@radix-ui/react-context,1.2.2,1.2.2,False,False
@radix-ui/react-context-menu,2.3.7,2.3.7,False,False
@radix-ui/react-dialog,1.1.23,1.1.23,False,False
@radix-ui/react-direction,1.1.4,1.1.4,False,False
@radix-ui/react-dismissable-layer,1.1.19,1.1.19,False,False
@radix-ui/react-dropdown-menu,2.1.24,2.1.24,False,False
@radix-ui/react-focus-guards,1.1.6,1.1.6,False,False
@radix-ui/react-focus-scope,1.1.16,1.1.16,False,False
@radix-ui/react-form,0.1.16,0.1.16,False,False
@radix-ui/react-hover-card,1.1.23,1.1.23,False,False
@radix-ui/react-id,1.1.4,1.1.4,False,False
@radix-ui/react-label,2.1.15,2.1.15,False,False
@radix-ui/react-menu,2.1.24,2.1.24,False,False
@radix-ui/react-menubar,1.1.24,1.1.24,False,False
@radix-ui/react-navigation-menu,1.2.22,1.2.22,False,False
@radix-ui/react-one-time-password-field,0.1.16,0.1.16,False,False
@radix-ui/react-password-toggle-field,0.1.11,0.1.11,False,False
@radix-ui/react-popover,1.1.23,1.1.23,False,False
@radix-ui/react-popper,1.3.7,1.3.7,False,False
@radix-ui/react-portal,1.1.17,1.1.17,False,False
@radix-ui/react-presence,1.1.10,1.1.10,False,False
@radix-ui/react-primitive,2.1.10,2.1.10,False,False
@radix-ui/react-progress,1.1.16,1.1.16,False,False
@radix-ui/react-radio-group,1.4.7,1.4.7,False,False
@radix-ui/react-roving-focus,1.1.19,1.1.19,False,False
@radix-ui/react-scroll-area,1.2.18,1.2.18,False,False
@radix-ui/react-select,2.3.7,2.3.7,False,False
@radix-ui/react-separator,1.1.15,1.1.15,False,False
@radix-ui/react-slider,1.4.7,1.4.7,False,False
@radix-ui/react-slot,1.3.3,1.3.3,False,False
@radix-ui/react-switch,1.3.7,1.3.7,False,False
@radix-ui/react-tabs,1.1.21,1.1.21,False,False
@radix-ui/react-toast,1.2.23,1.2.23,False,False
@radix-ui/react-toggle,1.1.18,1.1.18,False,False
@radix-ui/react-toggle-group,1.1.19,1.1.19,False,False
@radix-ui/react-toolbar,1.1.19,1.1.19,False,False
@radix-ui/react-tooltip,1.2.16,1.2.16,False,False
@radix-ui/react-use-callback-ref,1.1.4,1.1.4,False,False
@radix-ui/react-use-controllable-state,1.2.6,1.2.6,False,False
@radix-ui/react-use-effect-event,0.0.5,0.0.5,False,False
@radix-ui/react-use-escape-keydown,1.1.5,1.1.5,False,False
@radix-ui/react-use-is-hydrated,0.1.3,0.1.3,False,False
@radix-ui/react-use-layout-effect,1.1.4,1.1.4,False,False
@radix-ui/react-use-previous,1.1.4,1.1.4,False,False
@radix-ui/react-use-rect,1.1.4,1.1.4,False,False
@radix-ui/react-use-size,1.1.4,1.1.4,False,False
@radix-ui/react-visually-hidden,1.2.11,1.2.11,False,False
@radix-ui/rect,1.1.3,1.1.3,False,False
@react-router/dev,7.12.0,8.4.0,True,True
@react-router/node,7.12.0,8.4.0,True,True
@reduxjs/toolkit,2.12.0,2.13.0,False,True
@remix-run/node-fetch-server,0.9.0,0.14.2,False,True
@rollup/rollup-android-arm-eabi,4.63.5,4.63.5,False,False
@rollup/rollup-android-arm64,4.63.5,4.63.5,False,False
@rollup/rollup-darwin-arm64,4.63.5,4.63.5,False,False
@rollup/rollup-darwin-x64,4.63.5,4.63.5,False,False
@rollup/rollup-freebsd-arm64,4.63.5,4.63.5,False,False
@rollup/rollup-freebsd-x64,4.63.5,4.63.5,False,False
@rollup/rollup-linux-arm-gnueabihf,4.63.5,4.63.5,False,False
@rollup/rollup-linux-arm-musleabihf,4.63.5,4.63.5,False,False
@rollup/rollup-linux-arm64-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-linux-arm64-musl,4.63.5,4.63.5,False,False
@rollup/rollup-linux-loong64-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-linux-loong64-musl,4.63.5,4.63.5,False,False
@rollup/rollup-linux-ppc64-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-linux-ppc64-musl,4.63.5,4.63.5,False,False
@rollup/rollup-linux-riscv64-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-linux-riscv64-musl,4.63.5,4.63.5,False,False
@rollup/rollup-linux-s390x-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-linux-x64-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-linux-x64-musl,4.63.5,4.63.5,False,False
@rollup/rollup-openbsd-x64,4.63.5,4.63.5,False,False
@rollup/rollup-openharmony-arm64,4.63.5,4.63.5,False,False
@rollup/rollup-win32-arm64-msvc,4.63.5,4.63.5,False,False
@rollup/rollup-win32-ia32-msvc,4.63.5,4.63.5,False,False
@rollup/rollup-win32-x64-gnu,4.63.5,4.63.5,False,False
@rollup/rollup-win32-x64-msvc,4.63.5,4.63.5,False,False
@simplewebauthn/browser,13.3.0,14.0.0,True,True
@simplewebauthn/server,13.3.3,14.0.3,True,True
@smithy/core,3.35.0,3.35.1,False,True
@smithy/credential-provider-imds,4.5.2,4.5.2,False,False
@smithy/fetch-http-handler,5.8.0,5.8.0,False,False
@smithy/node-http-handler,4.12.1,4.12.1,False,False
@smithy/signature-v4,5.7.4,5.7.4,False,False
@smithy/types,4.19.0,4.19.0,False,False
@stablelib/base64,1.0.1,2.0.1,False,True
@standard-schema/spec,1.1.0,1.1.0,False,False
@standard-schema/utils,0.3.0,0.3.0,False,False
@tailwindcss/node,4.3.3,4.3.3,False,False
@tailwindcss/oxide,4.3.3,4.3.3,False,False
@tailwindcss/oxide-android-arm64,4.3.3,4.3.3,False,False
@tailwindcss/oxide-darwin-arm64,4.3.3,4.3.3,False,False
@tailwindcss/oxide-darwin-x64,4.3.3,4.3.3,False,False
@tailwindcss/oxide-freebsd-x64,4.3.3,4.3.3,False,False
@tailwindcss/oxide-linux-arm-gnueabihf,4.3.3,4.3.3,False,False
@tailwindcss/oxide-linux-arm64-gnu,4.3.3,4.3.3,False,False
@tailwindcss/oxide-linux-arm64-musl,4.3.3,4.3.3,False,False
@tailwindcss/oxide-linux-x64-gnu,4.3.3,4.3.3,False,False
@tailwindcss/oxide-linux-x64-musl,4.3.3,4.3.3,False,False
@tailwindcss/oxide-wasm32-wasi,4.3.3,4.3.3,False,False
@tailwindcss/oxide-win32-arm64-msvc,4.3.3,4.3.3,False,False
@tailwindcss/oxide-win32-x64-msvc,4.3.3,4.3.3,False,False
@tailwindcss/vite,4.3.3,4.3.3,True,False
@tanstack/query-core,5.104.0,5.104.0,False,False
@tanstack/react-query,5.104.0,5.104.0,True,False
@types/chai,5.2.3,5.2.3,False,False
@types/d3-array,3.2.2,3.2.2,False,False
@types/d3-color,3.1.3,3.1.3,False,False
@types/d3-ease,3.0.2,3.0.2,False,False
@types/d3-interpolate,3.0.4,3.0.4,False,False
@types/d3-path,3.1.1,3.1.1,False,False
@types/d3-scale,4.0.9,4.0.9,False,False
@types/d3-shape,3.2.0,3.2.0,False,False
@types/d3-time,3.0.4,3.0.4,False,False
@types/d3-timer,3.0.2,3.0.2,False,False
@types/deep-eql,4.0.2,4.0.2,False,False
@types/estree,1.0.9,1.0.9,False,False
@types/node,24.19.0,26.6.3,True,True
@types/nunjucks,3.2.6,3.2.6,True,False
@types/pg,8.23.1,8.23.1,True,False
@types/react,19.3.0,19.3.0,True,False
@types/react-dom,19.3.0,19.3.0,True,False
@types/retry,0.12.0,0.12.5,False,True
@types/use-sync-external-store,0.0.6,1.7.0,False,True
@typescript/typescript-aix-ppc64,7.0.2,7.0.2,False,False
@typescript/typescript-darwin-arm64,7.0.2,7.0.2,False,False
@typescript/typescript-darwin-x64,7.0.2,7.0.2,False,False
@typescript/typescript-freebsd-arm64,7.0.2,7.0.2,False,False
@typescript/typescript-freebsd-x64,7.0.2,7.0.2,False,False
@typescript/typescript-linux-arm,7.0.2,7.0.2,False,False
@typescript/typescript-linux-arm64,7.0.2,7.0.2,False,False
@typescript/typescript-linux-loong64,7.0.2,7.0.2,False,False
@typescript/typescript-linux-mips64el,7.0.2,7.0.2,False,False
@typescript/typescript-linux-ppc64,7.0.2,7.0.2,False,False
@typescript/typescript-linux-riscv64,7.0.2,7.0.2,False,False
@typescript/typescript-linux-s390x,7.0.2,7.0.2,False,False
@typescript/typescript-linux-x64,7.0.2,7.0.2,False,False
@typescript/typescript-netbsd-arm64,7.0.2,7.0.2,False,False
@typescript/typescript-netbsd-x64,7.0.2,7.0.2,False,False
@typescript/typescript-openbsd-arm64,7.0.2,7.0.2,False,False
@typescript/typescript-openbsd-x64,7.0.2,7.0.2,False,False
@typescript/typescript-sunos-x64,7.0.2,7.0.2,False,False
@typescript/typescript-win32-arm64,7.0.2,7.0.2,False,False
@typescript/typescript-win32-x64,7.0.2,7.0.2,False,False
@vitest/mocker,5.0.2,5.0.3,False,True
@vitest/spy,5.0.2,5.0.3,False,True
@xmldom/xmldom,0.9.12,0.9.12,True,False
a-sync-waterfall,1.0.1,1.0.1,False,False
accepts,2.0.0,1.3.8,False,True
agent-base,7.1.4;9.0.0,9.0.0,False,True
ajv,8.20.0,8.20.0,False,False
ajv-formats,3.0.1,3.0.1,False,False
anynum,1.0.1,1.0.1,False,False
arg,5.0.2,5.0.2,False,False
aria-hidden,1.2.6,1.2.6,False,False
asap,2.0.6,2.0.6,False,False
asn1js,3.0.10,3.0.10,False,False
assertion-error,2.0.1,2.0.1,False,False
atomic-sleep,1.0.0,1.0.0,False,False
babel-dead-code-elimination,1.0.12,2.0.0,False,True
base64-js,1.5.1,1.5.1,False,False
baseline-browser-mapping,2.11.26,2.11.26,False,False
bignumber.js,9.3.1,11.1.5,False,True
body-parser,2.3.0,2.3.0,False,False
boolbase,1.0.0,2.0.0,False,True
bowser,2.14.1,2.14.1,False,False
browserslist,4.29.1,4.29.3,False,True
buffer-equal-constant-time,1.0.1,1.0.1,False,False
bytes,3.1.2,3.1.2,False,False
cac,6.7.14,7.0.0,False,True
call-bind-apply-helpers,1.0.2,1.0.2,False,False
call-bound,1.0.4,1.0.4,False,False
caniuse-lite,1.0.30001812,1.0.30001814,False,True
chai,6.2.2,6.3.0,False,True
cheerio,1.2.0,1.2.0,True,False
cheerio-select,2.1.0,2.1.0,False,False
chokidar,4.0.3,5.0.0,False,True
class-variance-authority,0.7.1,0.7.1,True,False
clsx,2.1.1,2.1.1,True,False
colorette,2.0.20,2.0.20,False,False
commander,5.1.0,15.0.0,False,True
confbox,0.3.1,0.3.1,False,False
content-disposition,1.1.0,3.0.0,False,True
content-type,1.0.5;2.1.0,3.1.1,False,True
convert-source-map,2.0.0,2.0.0,False,False
cookie,0.7.2;1.1.1,2.0.1,False,True
cookie-signature,1.2.2,1.2.2,False,False
cors,2.8.6,2.8.6,False,False
cross-spawn,7.0.6,7.0.6,False,False
css-select,5.2.2,7.0.0,False,True
css-what,6.2.2,8.0.0,False,True
csstype,3.2.3,3.2.3,False,False
d3-array,3.2.4,3.2.4,False,False
d3-color,3.1.0,3.1.0,False,False
d3-ease,3.0.1,3.0.1,False,False
d3-format,3.1.2,3.1.2,False,False
d3-interpolate,3.0.1,3.0.1,False,False
d3-path,3.1.0,3.1.0,False,False
d3-scale,4.0.2,4.0.2,False,False
d3-shape,3.2.0,3.2.0,False,False
d3-time,3.1.0,3.1.0,False,False
d3-time-format,4.1.0,4.1.0,False,False
d3-timer,3.0.1,3.0.1,False,False
data-uri-to-buffer,4.0.1,8.0.0,False,True
date-fns,4.4.0,4.4.0,True,False
dateformat,4.6.3,5.0.3,False,True
debug,4.4.3,4.4.3,False,False
decimal.js-light,2.5.1,2.5.1,False,False
dedent,1.7.2,1.7.2,False,False
depd,2.0.0,2.0.0,False,False
detect-libc,2.1.2,2.1.2,False,False
detect-node-es,1.1.0,1.1.0,False,False
diff,8.0.4,9.0.0,False,True
dom-serializer,2.0.0,3.1.1,False,True
domelementtype,2.3.0,3.0.0,False,True
domhandler,5.0.3,6.0.1,False,True
domutils,3.2.2,4.0.2,False,True
dunder-proto,1.0.1,1.0.1,False,False
ecdsa-sig-formatter,1.0.11,1.0.11,False,False
ee-first,1.1.1,1.1.1,False,False
electron-to-chromium,1.5.439,1.5.443,False,True
encodeurl,2.0.0,2.0.0,False,False
encoding-sniffer,0.2.1,1.0.2,False,True
end-of-stream,1.4.5,1.4.5,False,False
enhanced-resolve,5.25.1,5.26.0,False,True
entities,4.5.0;6.0.1;7.0.1,8.1.0,False,True
es-define-property,1.0.1,1.0.1,False,False
es-errors,1.3.0,1.3.0,False,False
es-module-lexer,1.7.0;2.3.2,3.0.2,False,True
es-object-atoms,1.1.2,1.1.2,False,False
es-toolkit,1.52.0,1.52.0,False,False
esbuild,0.28.2,0.28.2,False,False
escalade,3.2.0,3.2.0,False,False
escape-html,1.0.3,1.0.3,False,False
estree-walker,3.0.3,3.0.3,False,False
etag,1.8.1,1.8.1,False,False
eventemitter3,5.0.4,5.0.4,False,False
eventsource,3.0.7,5.1.2,False,True
eventsource-parser,3.1.1,4.1.1,False,True
exit-hook,2.2.1,5.1.0,False,True
expect-type,1.4.0,1.4.0,False,False
express,5.2.1,5.2.1,False,False
express-rate-limit,8.7.0,8.7.0,False,False
exsolve,1.1.1,1.1.1,False,False
extend,3.0.2,3.0.2,False,False
fast-copy,4.1.1,4.1.1,False,False
fast-deep-equal,3.1.3,3.1.3,False,False
fast-safe-stringify,2.1.1,2.1.1,False,False
fast-sha256,1.3.0,1.3.0,False,False
fast-uri,3.1.8,4.2.1,False,True
fast-xml-builder,1.3.1,1.3.1,False,False
fast-xml-parser,5.11.1,5.11.2,True,True
fdir,6.5.0,6.5.0,False,False
fetch-blob,3.2.0,4.0.0,False,True
finalhandler,2.1.1,2.1.1,False,False
formdata-polyfill,4.0.10,4.0.10,False,False
forwarded,0.2.0,0.2.0,False,False
fresh,2.0.0,0.5.2,False,True
fsevents,2.3.3,2.3.3,False,False
function-bind,1.1.2,1.1.2,False,False
gaxios,7.3.1,8.1.0,False,True
gcp-metadata,8.1.2,9.0.4,False,True
gensync,1.0.0-beta.2,1.0.0-beta.2,False,False
get-intrinsic,1.3.0,1.3.0,False,False
get-nonce,1.0.1,1.0.1,False,False
get-proto,1.0.1,1.0.1,False,False
globrex,0.1.2,0.1.2,False,False
google-auth-library,10.9.1,11.1.0,False,True
google-logging-utils,1.1.3,2.0.1,False,True
gopd,1.2.0,1.2.0,False,False
graceful-fs,4.2.11,4.2.11,False,False
has-symbols,1.1.0,1.1.0,False,False
hash-wasm,4.12.0,4.12.0,True,False
hasown,2.0.4,2.0.4,False,False
help-me,5.0.0,5.0.0,False,False
hono,4.13.9,4.13.12,True,True
htmlparser2,10.1.0,12.0.0,False,True
http-errors,2.0.1,2.0.1,False,False
http-proxy-agent,9.1.0,9.1.0,False,False
https-proxy-agent,7.0.6;9.1.0,9.1.0,False,True
iconv-lite,0.6.3;0.7.3,0.7.3,False,True
ignore,7.0.8,7.0.11,False,True
immer,11.1.18,11.1.18,False,False
inherits,2.0.4,2.0.4,False,False
internmap,2.0.3,2.0.3,False,False
ip-address,10.7.2,10.7.2,False,False
ipaddr.js,1.9.1,2.5.0,False,True
is-promise,4.0.0,4.0.0,False,False
is-unsafe,2.0.2,2.0.2,False,False
isbot,5.2.2,5.2.2,True,False
isexe,2.0.0,4.0.0,False,True
jiti,2.7.0,2.7.0,False,False
jose,6.2.12,6.2.12,False,False
joycon,3.1.1,3.1.1,False,False
jpeg-js,0.4.4,0.4.4,True,False
js-tokens,4.0.0,10.0.0,False,True
jsesc,3.0.2,3.1.0,False,True
json-bigint,1.0.0,1.0.0,False,False
json-schema-to-ts,3.1.1,3.1.1,False,False
json-schema-traverse,1.0.0,1.0.0,False,False
json-schema-typed,8.0.2,8.0.2,False,False
json5,2.2.3,2.2.3,False,False
jwa,2.0.1,2.0.1,False,False
jws,4.0.1,4.0.1,False,False
kysely,0.29.6,0.29.6,True,False
lightningcss,1.32.0,1.33.0,False,True
lightningcss-android-arm64,1.32.0,1.33.0,False,True
lightningcss-darwin-arm64,1.32.0,1.33.0,False,True
lightningcss-darwin-x64,1.32.0,1.33.0,False,True
lightningcss-freebsd-x64,1.32.0,1.33.0,False,True
lightningcss-linux-arm-gnueabihf,1.32.0,1.33.0,False,True
lightningcss-linux-arm64-gnu,1.32.0,1.33.0,False,True
lightningcss-linux-arm64-musl,1.32.0,1.33.0,False,True
lightningcss-linux-x64-gnu,1.32.0,1.33.0,False,True
lightningcss-linux-x64-musl,1.32.0,1.33.0,False,True
lightningcss-win32-arm64-msvc,1.32.0,1.33.0,False,True
lightningcss-win32-x64-msvc,1.32.0,1.33.0,False,True
lodash,4.18.1,4.18.1,False,False
long,5.3.2,5.3.2,False,False
lru-cache,5.1.1,11.5.3,False,True
lucide-react,0.576.0,1.49.0,True,True
magic-string,0.30.21;1.4.2,1.4.2,False,True
math-intrinsics,1.1.0,1.1.0,False,False
media-typer,1.1.1,2.0.0,False,True
merge-descriptors,2.0.0,2.0.0,False,False
mime-db,1.54.0,1.54.0,False,False
mime-types,3.0.2,3.0.2,False,False
minimist,1.2.8,1.2.8,False,False
ms,2.1.3,2.1.3,False,False
nanoid,3.3.19,6.0.1,False,True
negotiator,1.1.0,1.1.0,False,False
next-themes,0.4.6,0.4.6,True,False
node-domexception,1.0.0,2.0.2,False,True
node-fetch,3.3.2,3.3.2,False,False
node-releases,2.0.57,2.0.57,False,False
nth-check,2.1.1,3.0.1,False,True
nunjucks,3.2.4,3.2.4,True,False
object-assign,4.1.1,4.1.1,False,False
object-inspect,1.13.4,1.13.4,False,False
obug,2.2.1,3.0.0,False,True
on-exit-leak-free,2.1.2,2.1.2,False,False
on-finished,2.4.1,2.4.1,False,False
once,1.4.0,1.4.0,False,False
openai,6.40.0,7.25.0,False,True
openapi3-ts,4.6.1,4.6.1,False,False
openworkflow,0.10.1,0.10.1,True,False
p-map,7.0.8,7.0.8,False,False
p-retry,4.6.2,8.0.1,False,True
parse5,7.3.0,8.0.1,False,True
parse5-htmlparser2-tree-adapter,7.1.0,8.0.1,False,True
parse5-parser-stream,7.1.2,8.0.0,False,True
parseurl,1.3.3,1.3.3,False,False
partial-json,0.1.7,0.1.7,False,False
path-expression-matcher,1.6.2,1.6.2,False,False
path-key,3.1.1,4.0.0,False,True
path-to-regexp,8.4.2,8.4.2,False,False
pathe,1.1.2;2.0.3,2.0.3,False,True
pg,8.23.0,8.23.1,True,True
pg-cloudflare,1.4.0,1.4.1,False,True
pg-connection-string,2.14.0,2.14.1,False,True
pg-int8,1.0.1,1.0.1,False,False
pg-pool,3.14.0,3.14.0,False,False
pg-protocol,1.16.0,1.16.1,False,True
pg-types,2.2.0,4.1.0,False,True
pgpass,1.0.5,1.0.6,False,True
picocolors,1.1.1,1.1.1,False,False
picomatch,4.0.7,4.0.7,False,False
pino,10.3.1,10.3.1,True,False
pino-abstract-transport,3.0.0,3.0.0,False,False
pino-pretty,13.1.3,13.1.3,True,False
pino-std-serializers,7.1.0,7.1.0,False,False
pkce-challenge,5.0.1,6.0.0,False,True
pkg-types,2.3.3,2.3.3,False,False
playwright-core,1.63.0,1.63.0,True,False
postcss,8.5.28,8.5.28,False,False
postgres,3.4.9,3.4.9,True,False
postgres-array,2.0.0,3.0.4,False,True
postgres-bytea,1.0.1,3.0.0,False,True
postgres-date,1.0.7,2.1.0,False,True
postgres-interval,1.2.0,4.1.0,False,True
prettier,3.9.9,3.9.9,False,False
process-warning,5.1.0,5.1.0,False,False
protobufjs,7.6.6,8.8.0,False,True
proxy-addr,2.0.8,2.0.8,False,False
proxy-agent-negotiate,1.1.0,1.1.0,False,False
pump,3.0.4,3.0.4,False,False
pvtsutils,1.3.6,1.3.6,False,False
pvutils,1.2.0,1.2.0,False,False
qr-code-styling,1.9.2,1.9.2,True,False
qrcode-generator,1.5.2,2.0.4,False,True
qs,6.16.0,6.16.0,False,False
quick-format-unescaped,4.0.4,4.0.4,False,False
radix-ui,1.6.7,1.6.7,True,False
range-parser,1.3.0,1.3.0,False,False
raw-body,3.0.2,4.0.0,False,True
react,19.3.0,19.3.0,True,False
react-day-picker,10.0.1,10.0.2,True,True
react-dom,19.3.0,19.3.0,True,False
react-is,19.3.0,19.3.0,False,False
react-redux,9.3.0,9.3.0,False,False
react-refresh,0.14.2,0.19.0,False,True
react-remove-scroll,2.7.2,2.7.2,False,False
react-remove-scroll-bar,2.3.8,2.3.8,False,False
react-router,7.12.0,8.4.0,True,True
react-style-singleton,2.2.3,2.2.3,False,False
readdirp,4.1.2,5.1.1,False,True
real-require,0.2.0;1.0.0,1.0.0,False,True
recharts,3.10.1,3.10.1,True,False
redux,5.0.1,5.0.1,False,False
redux-thunk,3.1.0,3.1.0,False,False
reflect-metadata,0.2.2,0.2.2,False,False
require-from-string,2.0.2,2.0.2,False,False
reselect,5.2.0,5.3.0,False,True
retry,0.13.1,0.13.1,False,False
rollup,4.63.5,4.63.5,False,False
router,2.2.0,2.2.0,False,False
safe-buffer,5.2.1,5.2.1,False,False
safe-stable-stringify,2.5.0,2.5.0,False,False
safer-buffer,2.1.2,2.1.2,False,False
scheduler,0.28.0,0.28.0,False,False
secure-json-parse,4.1.0,4.1.0,False,False
semver,6.3.1;7.8.5,7.8.5,False,True
send,1.2.1,1.2.1,False,False
serve-static,2.2.1,2.2.1,False,False
set-cookie-parser,2.7.2,3.1.2,False,True
setprototypeof,1.2.0,1.2.0,False,False
shebang-command,2.0.0,2.0.0,False,False
shebang-regex,3.0.0,4.0.0,False,True
side-channel,1.1.1,1.1.1,False,False
side-channel-list,1.0.1,1.0.1,False,False
side-channel-map,1.0.1,1.0.1,False,False
side-channel-weakmap,1.0.2,1.0.2,False,False
sonic-boom,4.2.1,5.0.1,False,True
sonner,2.0.8,2.0.8,True,False
source-map-js,1.2.1,1.2.2,False,True
split2,4.2.0,4.2.0,False,False
standardwebhooks,1.1.1,1.1.1,False,False
statuses,2.0.2,2.0.2,False,False
std-env,4.2.0,4.3.0,False,True
strip-json-comments,5.0.3,5.0.3,False,False
strnum,2.4.2,2.4.2,False,False
tailwind-merge,3.7.0,3.7.0,True,False
tailwindcss,4.3.3,4.3.3,True,False
tapable,2.3.3,2.3.3,False,False
thread-stream,4.2.0,4.2.0,False,False
tiny-invariant,1.3.3,1.3.3,False,False
tinybench,6.2.0,6.2.0,False,False
tinyexec,1.3.1,1.3.1,False,False
tinyglobby,0.2.17,0.2.17,False,False
toidentifier,1.0.1,1.0.1,False,False
ts-algebra,2.0.0,2.0.0,False,False
tsconfck,3.1.6,3.1.6,False,False
tslib,1.14.1;2.8.1,2.8.1,False,True
tsyringe,4.10.0,4.10.0,False,False
tw-animate-css,1.4.0,1.4.0,True,False
type-is,2.1.0,3.0.0,False,True
typebox,1.3.27,1.3.34,True,True
typescript,7.0.2,7.0.2,True,False
undici,7.30.0,8.11.2,False,True
undici-types,7.24.6,8.11.2,False,True
unpipe,1.0.0,1.0.0,False,False
update-browserslist-db,1.3.3,1.3.3,False,False
use-callback-ref,1.3.3,1.3.3,False,False
use-sidecar,1.1.3,1.1.3,False,False
use-sync-external-store,1.7.0,1.7.0,False,False
valibot,1.5.0,1.5.0,False,False
vary,1.1.2,1.1.2,False,False
victory-vendor,37.3.6,37.3.6,False,False
vite,7.3.6,8.3.1,True,True
vite-node,3.2.4,6.0.0,False,True
vite-tsconfig-paths,5.1.4,6.1.1,True,True
vitest,5.0.2,5.0.3,True,True
web-streams-polyfill,3.3.3,4.3.0,False,True
whatwg-encoding,3.1.1,3.1.1,False,False
whatwg-mimetype,4.0.0,5.0.0,False,True
which,2.0.2,7.0.0,False,True
why-is-node-running,3.2.2,3.2.2,False,False
wrappy,1.0.2,1.0.2,False,False
ws,8.21.3,8.22.0,False,True
xml-naming,0.3.0,0.3.0,False,False
xpath,0.0.34,0.0.34,True,False
xtend,4.0.2,4.0.2,False,False
yallist,3.1.1,5.0.0,False,True
yaml,2.9.0;2.9.1,2.9.1,True,True
zod,4.6.5,4.6.5,True,False
zod-to-json-schema,3.25.2,3.25.2,False,False
1 package locked_versions registry_latest workspace_direct has_older_or_different_version
2 @anthropic-ai/sdk 0.124.0 0.131.0 False True
3 @asteasolutions/zod-to-openapi 9.1.0 9.1.0 False False
4 @aws-sdk/client-bedrock-runtime 3.1127.0 3.1144.0 False True
5 @aws-sdk/core 3.978.1 3.978.1 False False
6 @aws-sdk/credential-provider-env 3.972.72 3.972.72 False False
7 @aws-sdk/credential-provider-http 3.972.74 3.972.74 False False
8 @aws-sdk/credential-provider-ini 3.973.17 3.973.17 False False
9 @aws-sdk/credential-provider-login 3.972.79 3.972.79 False False
10 @aws-sdk/credential-provider-node 3.972.84 3.972.84 False False
11 @aws-sdk/credential-provider-process 3.972.72 3.972.72 False False
12 @aws-sdk/credential-provider-sso 3.973.16 3.973.16 False False
13 @aws-sdk/credential-provider-web-identity 3.972.78 3.972.78 False False
14 @aws-sdk/eventstream-handler-node 3.972.35 3.972.35 False False
15 @aws-sdk/middleware-eventstream 3.972.30 3.972.30 False False
16 @aws-sdk/middleware-websocket 3.972.54 3.972.54 False False
17 @aws-sdk/nested-clients 3.997.46 3.997.46 False False
18 @aws-sdk/signature-v4-multi-region 3.996.47 3.996.47 False False
19 @aws-sdk/token-providers 3.1127.0;3.1138.0 3.1144.0 False True
20 @aws-sdk/types 3.974.6 3.974.6 False False
21 @aws-sdk/xml-builder 3.972.41 3.972.41 False False
22 @aws/lambda-invoke-store 0.3.0 0.3.0 False False
23 @babel/code-frame 7.29.7 8.0.6 False True
24 @babel/compat-data 7.29.7 8.0.5 False True
25 @babel/core 7.29.7 8.0.6 False True
26 @babel/generator 7.29.8 8.0.6 False True
27 @babel/helper-annotate-as-pure 7.29.7 8.0.0 False True
28 @babel/helper-compilation-targets 7.29.7 8.0.6 False True
29 @babel/helper-create-class-features-plugin 7.29.7 8.0.6 False True
30 @babel/helper-globals 7.29.7 8.0.6 False True
31 @babel/helper-member-expression-to-functions 7.29.7 8.0.5 False True
32 @babel/helper-module-imports 7.29.7 8.0.0 False True
33 @babel/helper-module-transforms 7.29.7 8.0.6 False True
34 @babel/helper-optimise-call-expression 7.29.7 8.0.0 False True
35 @babel/helper-plugin-utils 7.29.7 8.0.1 False True
36 @babel/helper-replace-supers 7.29.7 8.0.1 False True
37 @babel/helper-skip-transparent-expression-wrappers 7.29.7 8.0.0 False True
38 @babel/helper-string-parser 7.29.7 8.0.6 False True
39 @babel/helper-validator-identifier 7.29.7 8.0.6 False True
40 @babel/helper-validator-option 7.29.7 8.0.0 False True
41 @babel/helpers 7.29.7 8.0.5 False True
42 @babel/parser 7.29.9 7.29.9 False False
43 @babel/plugin-syntax-jsx 7.29.7 8.0.1 False True
44 @babel/plugin-syntax-typescript 7.29.7 8.0.3 False True
45 @babel/plugin-transform-modules-commonjs 7.29.7 8.0.1 False True
46 @babel/plugin-transform-typescript 7.29.9 7.29.9 False False
47 @babel/preset-typescript 7.29.7 8.0.1 False True
48 @babel/runtime 7.29.7 8.0.5 False True
49 @babel/template 7.29.7 8.0.0 False True
50 @babel/traverse 7.29.8 8.0.6 False True
51 @babel/types 7.29.8 8.0.6 False True
52 @biomejs/biome 2.5.14 2.5.15 True True
53 @biomejs/cli-darwin-arm64 2.5.14 2.5.15 False True
54 @biomejs/cli-darwin-x64 2.5.14 2.5.15 False True
55 @biomejs/cli-linux-arm64 2.5.14 2.5.15 False True
56 @biomejs/cli-linux-arm64-musl 2.5.14 2.5.15 False True
57 @biomejs/cli-linux-x64 2.5.14 2.5.15 False True
58 @biomejs/cli-linux-x64-musl 2.5.14 2.5.15 False True
59 @biomejs/cli-win32-arm64 2.5.14 2.5.15 False True
60 @biomejs/cli-win32-x64 2.5.14 2.5.15 False True
61 @date-fns/tz 1.5.0 1.5.0 False False
62 @earendil-works/chord 0.87.1 0.99.2 False True
63 @earendil-works/pi-agent-core 0.87.1 0.99.2 True True
64 @earendil-works/pi-ai 0.87.1 0.99.2 True True
65 @earendil-works/pi-telemetry 0.87.1 0.99.2 False True
66 @esbuild/aix-ppc64 0.28.2 0.28.2 False False
67 @esbuild/android-arm 0.28.2 0.28.2 False False
68 @esbuild/android-arm64 0.28.2 0.28.2 False False
69 @esbuild/android-x64 0.28.2 0.28.2 False False
70 @esbuild/darwin-arm64 0.28.2 0.28.2 False False
71 @esbuild/darwin-x64 0.28.2 0.28.2 False False
72 @esbuild/freebsd-arm64 0.28.2 0.28.2 False False
73 @esbuild/freebsd-x64 0.28.2 0.28.2 False False
74 @esbuild/linux-arm 0.28.2 0.28.2 False False
75 @esbuild/linux-arm64 0.28.2 0.28.2 False False
76 @esbuild/linux-ia32 0.28.2 0.28.2 False False
77 @esbuild/linux-loong64 0.28.2 0.28.2 False False
78 @esbuild/linux-mips64el 0.28.2 0.28.2 False False
79 @esbuild/linux-ppc64 0.28.2 0.28.2 False False
80 @esbuild/linux-riscv64 0.28.2 0.28.2 False False
81 @esbuild/linux-s390x 0.28.2 0.28.2 False False
82 @esbuild/linux-x64 0.28.2 0.28.2 False False
83 @esbuild/netbsd-arm64 0.28.2 0.28.2 False False
84 @esbuild/netbsd-x64 0.28.2 0.28.2 False False
85 @esbuild/openbsd-arm64 0.28.2 0.28.2 False False
86 @esbuild/openbsd-x64 0.28.2 0.28.2 False False
87 @esbuild/openharmony-arm64 0.28.2 0.28.2 False False
88 @esbuild/sunos-x64 0.28.2 0.28.2 False False
89 @esbuild/win32-arm64 0.28.2 0.28.2 False False
90 @esbuild/win32-ia32 0.28.2 0.28.2 False False
91 @esbuild/win32-x64 0.28.2 0.28.2 False False
92 @floating-ui/core 1.8.0 1.8.0 False False
93 @floating-ui/dom 1.8.0 1.8.0 False False
94 @floating-ui/react-dom 2.1.9 2.1.9 False False
95 @floating-ui/utils 0.2.12 0.2.12 False False
96 @fontsource-variable/inter-tight 5.3.0 5.3.0 True False
97 @fontsource-variable/space-grotesk 5.3.0 5.3.0 True False
98 @google/genai 2.21.0 2.25.0 False True
99 @hexagon/base64 1.1.28 2.0.4 False True
100 @hono/node-server 2.1.1 2.1.3 False True
101 @hono/swagger-ui 0.6.1 0.6.1 True False
102 @hono/zod-openapi 1.6.3 1.6.3 True False
103 @hono/zod-validator 0.9.1 0.9.1 False False
104 @jridgewell/gen-mapping 0.3.13 0.3.13 False False
105 @jridgewell/remapping 2.3.5 2.3.5 False False
106 @jridgewell/resolve-uri 3.1.2 3.1.2 False False
107 @jridgewell/sourcemap-codec 1.6.0 1.6.0 False False
108 @jridgewell/trace-mapping 0.3.31 0.3.31 False False
109 @levischuck/tiny-cbor 0.2.11 0.3.6 False True
110 @mjackson/node-fetch-server 0.2.0 0.7.0 False True
111 @modelcontextprotocol/sdk 1.30.1 1.31.0 True True
112 @napi-rs/lzma-linux-x64-gnu 1.5.1 1.5.1 False False
113 @nodable/entities 3.0.0 3.1.0 False True
114 @peculiar/asn1-android 2.9.5 2.10.0 False True
115 @peculiar/asn1-cms 2.9.5 2.10.0 False True
116 @peculiar/asn1-csr 2.9.5 2.10.0 False True
117 @peculiar/asn1-ecc 2.9.5 2.10.0 False True
118 @peculiar/asn1-pfx 2.9.5 2.10.0 False True
119 @peculiar/asn1-pkcs8 2.9.5 2.10.0 False True
120 @peculiar/asn1-pkcs9 2.9.5 2.10.0 False True
121 @peculiar/asn1-rsa 2.9.5 2.10.0 False True
122 @peculiar/asn1-schema 2.9.5 2.10.0 False True
123 @peculiar/asn1-x509 2.9.5 2.10.0 False True
124 @peculiar/asn1-x509-attr 2.9.5 2.10.0 False True
125 @peculiar/utils 2.0.3 2.0.3 False False
126 @peculiar/x509 1.14.3 2.1.0 False True
127 @pinojs/redact 0.4.0 0.4.0 False False
128 @protobufjs/aspromise 1.1.2 1.1.2 False False
129 @protobufjs/base64 1.1.2 1.1.2 False False
130 @protobufjs/codegen 2.0.5 2.0.5 False False
131 @protobufjs/eventemitter 1.1.1 1.1.1 False False
132 @protobufjs/fetch 1.1.1 1.1.1 False False
133 @protobufjs/float 1.0.2 1.0.2 False False
134 @protobufjs/path 1.1.2 1.1.2 False False
135 @protobufjs/pool 1.1.0 1.1.0 False False
136 @protobufjs/utf8 1.1.2 1.1.2 False False
137 @radix-ui/number 1.1.3 1.1.3 False False
138 @radix-ui/primitive 1.1.7 1.1.7 False False
139 @radix-ui/react-accessible-icon 1.1.15 1.1.15 False False
140 @radix-ui/react-accordion 1.2.20 1.2.20 False False
141 @radix-ui/react-alert-dialog 1.1.23 1.1.23 False False
142 @radix-ui/react-arrow 1.1.15 1.1.15 False False
143 @radix-ui/react-aspect-ratio 1.1.15 1.1.15 False False
144 @radix-ui/react-avatar 1.2.6 1.2.6 False False
145 @radix-ui/react-checkbox 1.3.11 1.3.11 False False
146 @radix-ui/react-collapsible 1.1.20 1.1.20 False False
147 @radix-ui/react-collection 1.1.15 1.1.15 False False
148 @radix-ui/react-compose-refs 1.1.5 1.1.5 False False
149 @radix-ui/react-context 1.2.2 1.2.2 False False
150 @radix-ui/react-context-menu 2.3.7 2.3.7 False False
151 @radix-ui/react-dialog 1.1.23 1.1.23 False False
152 @radix-ui/react-direction 1.1.4 1.1.4 False False
153 @radix-ui/react-dismissable-layer 1.1.19 1.1.19 False False
154 @radix-ui/react-dropdown-menu 2.1.24 2.1.24 False False
155 @radix-ui/react-focus-guards 1.1.6 1.1.6 False False
156 @radix-ui/react-focus-scope 1.1.16 1.1.16 False False
157 @radix-ui/react-form 0.1.16 0.1.16 False False
158 @radix-ui/react-hover-card 1.1.23 1.1.23 False False
159 @radix-ui/react-id 1.1.4 1.1.4 False False
160 @radix-ui/react-label 2.1.15 2.1.15 False False
161 @radix-ui/react-menu 2.1.24 2.1.24 False False
162 @radix-ui/react-menubar 1.1.24 1.1.24 False False
163 @radix-ui/react-navigation-menu 1.2.22 1.2.22 False False
164 @radix-ui/react-one-time-password-field 0.1.16 0.1.16 False False
165 @radix-ui/react-password-toggle-field 0.1.11 0.1.11 False False
166 @radix-ui/react-popover 1.1.23 1.1.23 False False
167 @radix-ui/react-popper 1.3.7 1.3.7 False False
168 @radix-ui/react-portal 1.1.17 1.1.17 False False
169 @radix-ui/react-presence 1.1.10 1.1.10 False False
170 @radix-ui/react-primitive 2.1.10 2.1.10 False False
171 @radix-ui/react-progress 1.1.16 1.1.16 False False
172 @radix-ui/react-radio-group 1.4.7 1.4.7 False False
173 @radix-ui/react-roving-focus 1.1.19 1.1.19 False False
174 @radix-ui/react-scroll-area 1.2.18 1.2.18 False False
175 @radix-ui/react-select 2.3.7 2.3.7 False False
176 @radix-ui/react-separator 1.1.15 1.1.15 False False
177 @radix-ui/react-slider 1.4.7 1.4.7 False False
178 @radix-ui/react-slot 1.3.3 1.3.3 False False
179 @radix-ui/react-switch 1.3.7 1.3.7 False False
180 @radix-ui/react-tabs 1.1.21 1.1.21 False False
181 @radix-ui/react-toast 1.2.23 1.2.23 False False
182 @radix-ui/react-toggle 1.1.18 1.1.18 False False
183 @radix-ui/react-toggle-group 1.1.19 1.1.19 False False
184 @radix-ui/react-toolbar 1.1.19 1.1.19 False False
185 @radix-ui/react-tooltip 1.2.16 1.2.16 False False
186 @radix-ui/react-use-callback-ref 1.1.4 1.1.4 False False
187 @radix-ui/react-use-controllable-state 1.2.6 1.2.6 False False
188 @radix-ui/react-use-effect-event 0.0.5 0.0.5 False False
189 @radix-ui/react-use-escape-keydown 1.1.5 1.1.5 False False
190 @radix-ui/react-use-is-hydrated 0.1.3 0.1.3 False False
191 @radix-ui/react-use-layout-effect 1.1.4 1.1.4 False False
192 @radix-ui/react-use-previous 1.1.4 1.1.4 False False
193 @radix-ui/react-use-rect 1.1.4 1.1.4 False False
194 @radix-ui/react-use-size 1.1.4 1.1.4 False False
195 @radix-ui/react-visually-hidden 1.2.11 1.2.11 False False
196 @radix-ui/rect 1.1.3 1.1.3 False False
197 @react-router/dev 7.12.0 8.4.0 True True
198 @react-router/node 7.12.0 8.4.0 True True
199 @reduxjs/toolkit 2.12.0 2.13.0 False True
200 @remix-run/node-fetch-server 0.9.0 0.14.2 False True
201 @rollup/rollup-android-arm-eabi 4.63.5 4.63.5 False False
202 @rollup/rollup-android-arm64 4.63.5 4.63.5 False False
203 @rollup/rollup-darwin-arm64 4.63.5 4.63.5 False False
204 @rollup/rollup-darwin-x64 4.63.5 4.63.5 False False
205 @rollup/rollup-freebsd-arm64 4.63.5 4.63.5 False False
206 @rollup/rollup-freebsd-x64 4.63.5 4.63.5 False False
207 @rollup/rollup-linux-arm-gnueabihf 4.63.5 4.63.5 False False
208 @rollup/rollup-linux-arm-musleabihf 4.63.5 4.63.5 False False
209 @rollup/rollup-linux-arm64-gnu 4.63.5 4.63.5 False False
210 @rollup/rollup-linux-arm64-musl 4.63.5 4.63.5 False False
211 @rollup/rollup-linux-loong64-gnu 4.63.5 4.63.5 False False
212 @rollup/rollup-linux-loong64-musl 4.63.5 4.63.5 False False
213 @rollup/rollup-linux-ppc64-gnu 4.63.5 4.63.5 False False
214 @rollup/rollup-linux-ppc64-musl 4.63.5 4.63.5 False False
215 @rollup/rollup-linux-riscv64-gnu 4.63.5 4.63.5 False False
216 @rollup/rollup-linux-riscv64-musl 4.63.5 4.63.5 False False
217 @rollup/rollup-linux-s390x-gnu 4.63.5 4.63.5 False False
218 @rollup/rollup-linux-x64-gnu 4.63.5 4.63.5 False False
219 @rollup/rollup-linux-x64-musl 4.63.5 4.63.5 False False
220 @rollup/rollup-openbsd-x64 4.63.5 4.63.5 False False
221 @rollup/rollup-openharmony-arm64 4.63.5 4.63.5 False False
222 @rollup/rollup-win32-arm64-msvc 4.63.5 4.63.5 False False
223 @rollup/rollup-win32-ia32-msvc 4.63.5 4.63.5 False False
224 @rollup/rollup-win32-x64-gnu 4.63.5 4.63.5 False False
225 @rollup/rollup-win32-x64-msvc 4.63.5 4.63.5 False False
226 @simplewebauthn/browser 13.3.0 14.0.0 True True
227 @simplewebauthn/server 13.3.3 14.0.3 True True
228 @smithy/core 3.35.0 3.35.1 False True
229 @smithy/credential-provider-imds 4.5.2 4.5.2 False False
230 @smithy/fetch-http-handler 5.8.0 5.8.0 False False
231 @smithy/node-http-handler 4.12.1 4.12.1 False False
232 @smithy/signature-v4 5.7.4 5.7.4 False False
233 @smithy/types 4.19.0 4.19.0 False False
234 @stablelib/base64 1.0.1 2.0.1 False True
235 @standard-schema/spec 1.1.0 1.1.0 False False
236 @standard-schema/utils 0.3.0 0.3.0 False False
237 @tailwindcss/node 4.3.3 4.3.3 False False
238 @tailwindcss/oxide 4.3.3 4.3.3 False False
239 @tailwindcss/oxide-android-arm64 4.3.3 4.3.3 False False
240 @tailwindcss/oxide-darwin-arm64 4.3.3 4.3.3 False False
241 @tailwindcss/oxide-darwin-x64 4.3.3 4.3.3 False False
242 @tailwindcss/oxide-freebsd-x64 4.3.3 4.3.3 False False
243 @tailwindcss/oxide-linux-arm-gnueabihf 4.3.3 4.3.3 False False
244 @tailwindcss/oxide-linux-arm64-gnu 4.3.3 4.3.3 False False
245 @tailwindcss/oxide-linux-arm64-musl 4.3.3 4.3.3 False False
246 @tailwindcss/oxide-linux-x64-gnu 4.3.3 4.3.3 False False
247 @tailwindcss/oxide-linux-x64-musl 4.3.3 4.3.3 False False
248 @tailwindcss/oxide-wasm32-wasi 4.3.3 4.3.3 False False
249 @tailwindcss/oxide-win32-arm64-msvc 4.3.3 4.3.3 False False
250 @tailwindcss/oxide-win32-x64-msvc 4.3.3 4.3.3 False False
251 @tailwindcss/vite 4.3.3 4.3.3 True False
252 @tanstack/query-core 5.104.0 5.104.0 False False
253 @tanstack/react-query 5.104.0 5.104.0 True False
254 @types/chai 5.2.3 5.2.3 False False
255 @types/d3-array 3.2.2 3.2.2 False False
256 @types/d3-color 3.1.3 3.1.3 False False
257 @types/d3-ease 3.0.2 3.0.2 False False
258 @types/d3-interpolate 3.0.4 3.0.4 False False
259 @types/d3-path 3.1.1 3.1.1 False False
260 @types/d3-scale 4.0.9 4.0.9 False False
261 @types/d3-shape 3.2.0 3.2.0 False False
262 @types/d3-time 3.0.4 3.0.4 False False
263 @types/d3-timer 3.0.2 3.0.2 False False
264 @types/deep-eql 4.0.2 4.0.2 False False
265 @types/estree 1.0.9 1.0.9 False False
266 @types/node 24.19.0 26.6.3 True True
267 @types/nunjucks 3.2.6 3.2.6 True False
268 @types/pg 8.23.1 8.23.1 True False
269 @types/react 19.3.0 19.3.0 True False
270 @types/react-dom 19.3.0 19.3.0 True False
271 @types/retry 0.12.0 0.12.5 False True
272 @types/use-sync-external-store 0.0.6 1.7.0 False True
273 @typescript/typescript-aix-ppc64 7.0.2 7.0.2 False False
274 @typescript/typescript-darwin-arm64 7.0.2 7.0.2 False False
275 @typescript/typescript-darwin-x64 7.0.2 7.0.2 False False
276 @typescript/typescript-freebsd-arm64 7.0.2 7.0.2 False False
277 @typescript/typescript-freebsd-x64 7.0.2 7.0.2 False False
278 @typescript/typescript-linux-arm 7.0.2 7.0.2 False False
279 @typescript/typescript-linux-arm64 7.0.2 7.0.2 False False
280 @typescript/typescript-linux-loong64 7.0.2 7.0.2 False False
281 @typescript/typescript-linux-mips64el 7.0.2 7.0.2 False False
282 @typescript/typescript-linux-ppc64 7.0.2 7.0.2 False False
283 @typescript/typescript-linux-riscv64 7.0.2 7.0.2 False False
284 @typescript/typescript-linux-s390x 7.0.2 7.0.2 False False
285 @typescript/typescript-linux-x64 7.0.2 7.0.2 False False
286 @typescript/typescript-netbsd-arm64 7.0.2 7.0.2 False False
287 @typescript/typescript-netbsd-x64 7.0.2 7.0.2 False False
288 @typescript/typescript-openbsd-arm64 7.0.2 7.0.2 False False
289 @typescript/typescript-openbsd-x64 7.0.2 7.0.2 False False
290 @typescript/typescript-sunos-x64 7.0.2 7.0.2 False False
291 @typescript/typescript-win32-arm64 7.0.2 7.0.2 False False
292 @typescript/typescript-win32-x64 7.0.2 7.0.2 False False
293 @vitest/mocker 5.0.2 5.0.3 False True
294 @vitest/spy 5.0.2 5.0.3 False True
295 @xmldom/xmldom 0.9.12 0.9.12 True False
296 a-sync-waterfall 1.0.1 1.0.1 False False
297 accepts 2.0.0 1.3.8 False True
298 agent-base 7.1.4;9.0.0 9.0.0 False True
299 ajv 8.20.0 8.20.0 False False
300 ajv-formats 3.0.1 3.0.1 False False
301 anynum 1.0.1 1.0.1 False False
302 arg 5.0.2 5.0.2 False False
303 aria-hidden 1.2.6 1.2.6 False False
304 asap 2.0.6 2.0.6 False False
305 asn1js 3.0.10 3.0.10 False False
306 assertion-error 2.0.1 2.0.1 False False
307 atomic-sleep 1.0.0 1.0.0 False False
308 babel-dead-code-elimination 1.0.12 2.0.0 False True
309 base64-js 1.5.1 1.5.1 False False
310 baseline-browser-mapping 2.11.26 2.11.26 False False
311 bignumber.js 9.3.1 11.1.5 False True
312 body-parser 2.3.0 2.3.0 False False
313 boolbase 1.0.0 2.0.0 False True
314 bowser 2.14.1 2.14.1 False False
315 browserslist 4.29.1 4.29.3 False True
316 buffer-equal-constant-time 1.0.1 1.0.1 False False
317 bytes 3.1.2 3.1.2 False False
318 cac 6.7.14 7.0.0 False True
319 call-bind-apply-helpers 1.0.2 1.0.2 False False
320 call-bound 1.0.4 1.0.4 False False
321 caniuse-lite 1.0.30001812 1.0.30001814 False True
322 chai 6.2.2 6.3.0 False True
323 cheerio 1.2.0 1.2.0 True False
324 cheerio-select 2.1.0 2.1.0 False False
325 chokidar 4.0.3 5.0.0 False True
326 class-variance-authority 0.7.1 0.7.1 True False
327 clsx 2.1.1 2.1.1 True False
328 colorette 2.0.20 2.0.20 False False
329 commander 5.1.0 15.0.0 False True
330 confbox 0.3.1 0.3.1 False False
331 content-disposition 1.1.0 3.0.0 False True
332 content-type 1.0.5;2.1.0 3.1.1 False True
333 convert-source-map 2.0.0 2.0.0 False False
334 cookie 0.7.2;1.1.1 2.0.1 False True
335 cookie-signature 1.2.2 1.2.2 False False
336 cors 2.8.6 2.8.6 False False
337 cross-spawn 7.0.6 7.0.6 False False
338 css-select 5.2.2 7.0.0 False True
339 css-what 6.2.2 8.0.0 False True
340 csstype 3.2.3 3.2.3 False False
341 d3-array 3.2.4 3.2.4 False False
342 d3-color 3.1.0 3.1.0 False False
343 d3-ease 3.0.1 3.0.1 False False
344 d3-format 3.1.2 3.1.2 False False
345 d3-interpolate 3.0.1 3.0.1 False False
346 d3-path 3.1.0 3.1.0 False False
347 d3-scale 4.0.2 4.0.2 False False
348 d3-shape 3.2.0 3.2.0 False False
349 d3-time 3.1.0 3.1.0 False False
350 d3-time-format 4.1.0 4.1.0 False False
351 d3-timer 3.0.1 3.0.1 False False
352 data-uri-to-buffer 4.0.1 8.0.0 False True
353 date-fns 4.4.0 4.4.0 True False
354 dateformat 4.6.3 5.0.3 False True
355 debug 4.4.3 4.4.3 False False
356 decimal.js-light 2.5.1 2.5.1 False False
357 dedent 1.7.2 1.7.2 False False
358 depd 2.0.0 2.0.0 False False
359 detect-libc 2.1.2 2.1.2 False False
360 detect-node-es 1.1.0 1.1.0 False False
361 diff 8.0.4 9.0.0 False True
362 dom-serializer 2.0.0 3.1.1 False True
363 domelementtype 2.3.0 3.0.0 False True
364 domhandler 5.0.3 6.0.1 False True
365 domutils 3.2.2 4.0.2 False True
366 dunder-proto 1.0.1 1.0.1 False False
367 ecdsa-sig-formatter 1.0.11 1.0.11 False False
368 ee-first 1.1.1 1.1.1 False False
369 electron-to-chromium 1.5.439 1.5.443 False True
370 encodeurl 2.0.0 2.0.0 False False
371 encoding-sniffer 0.2.1 1.0.2 False True
372 end-of-stream 1.4.5 1.4.5 False False
373 enhanced-resolve 5.25.1 5.26.0 False True
374 entities 4.5.0;6.0.1;7.0.1 8.1.0 False True
375 es-define-property 1.0.1 1.0.1 False False
376 es-errors 1.3.0 1.3.0 False False
377 es-module-lexer 1.7.0;2.3.2 3.0.2 False True
378 es-object-atoms 1.1.2 1.1.2 False False
379 es-toolkit 1.52.0 1.52.0 False False
380 esbuild 0.28.2 0.28.2 False False
381 escalade 3.2.0 3.2.0 False False
382 escape-html 1.0.3 1.0.3 False False
383 estree-walker 3.0.3 3.0.3 False False
384 etag 1.8.1 1.8.1 False False
385 eventemitter3 5.0.4 5.0.4 False False
386 eventsource 3.0.7 5.1.2 False True
387 eventsource-parser 3.1.1 4.1.1 False True
388 exit-hook 2.2.1 5.1.0 False True
389 expect-type 1.4.0 1.4.0 False False
390 express 5.2.1 5.2.1 False False
391 express-rate-limit 8.7.0 8.7.0 False False
392 exsolve 1.1.1 1.1.1 False False
393 extend 3.0.2 3.0.2 False False
394 fast-copy 4.1.1 4.1.1 False False
395 fast-deep-equal 3.1.3 3.1.3 False False
396 fast-safe-stringify 2.1.1 2.1.1 False False
397 fast-sha256 1.3.0 1.3.0 False False
398 fast-uri 3.1.8 4.2.1 False True
399 fast-xml-builder 1.3.1 1.3.1 False False
400 fast-xml-parser 5.11.1 5.11.2 True True
401 fdir 6.5.0 6.5.0 False False
402 fetch-blob 3.2.0 4.0.0 False True
403 finalhandler 2.1.1 2.1.1 False False
404 formdata-polyfill 4.0.10 4.0.10 False False
405 forwarded 0.2.0 0.2.0 False False
406 fresh 2.0.0 0.5.2 False True
407 fsevents 2.3.3 2.3.3 False False
408 function-bind 1.1.2 1.1.2 False False
409 gaxios 7.3.1 8.1.0 False True
410 gcp-metadata 8.1.2 9.0.4 False True
411 gensync 1.0.0-beta.2 1.0.0-beta.2 False False
412 get-intrinsic 1.3.0 1.3.0 False False
413 get-nonce 1.0.1 1.0.1 False False
414 get-proto 1.0.1 1.0.1 False False
415 globrex 0.1.2 0.1.2 False False
416 google-auth-library 10.9.1 11.1.0 False True
417 google-logging-utils 1.1.3 2.0.1 False True
418 gopd 1.2.0 1.2.0 False False
419 graceful-fs 4.2.11 4.2.11 False False
420 has-symbols 1.1.0 1.1.0 False False
421 hash-wasm 4.12.0 4.12.0 True False
422 hasown 2.0.4 2.0.4 False False
423 help-me 5.0.0 5.0.0 False False
424 hono 4.13.9 4.13.12 True True
425 htmlparser2 10.1.0 12.0.0 False True
426 http-errors 2.0.1 2.0.1 False False
427 http-proxy-agent 9.1.0 9.1.0 False False
428 https-proxy-agent 7.0.6;9.1.0 9.1.0 False True
429 iconv-lite 0.6.3;0.7.3 0.7.3 False True
430 ignore 7.0.8 7.0.11 False True
431 immer 11.1.18 11.1.18 False False
432 inherits 2.0.4 2.0.4 False False
433 internmap 2.0.3 2.0.3 False False
434 ip-address 10.7.2 10.7.2 False False
435 ipaddr.js 1.9.1 2.5.0 False True
436 is-promise 4.0.0 4.0.0 False False
437 is-unsafe 2.0.2 2.0.2 False False
438 isbot 5.2.2 5.2.2 True False
439 isexe 2.0.0 4.0.0 False True
440 jiti 2.7.0 2.7.0 False False
441 jose 6.2.12 6.2.12 False False
442 joycon 3.1.1 3.1.1 False False
443 jpeg-js 0.4.4 0.4.4 True False
444 js-tokens 4.0.0 10.0.0 False True
445 jsesc 3.0.2 3.1.0 False True
446 json-bigint 1.0.0 1.0.0 False False
447 json-schema-to-ts 3.1.1 3.1.1 False False
448 json-schema-traverse 1.0.0 1.0.0 False False
449 json-schema-typed 8.0.2 8.0.2 False False
450 json5 2.2.3 2.2.3 False False
451 jwa 2.0.1 2.0.1 False False
452 jws 4.0.1 4.0.1 False False
453 kysely 0.29.6 0.29.6 True False
454 lightningcss 1.32.0 1.33.0 False True
455 lightningcss-android-arm64 1.32.0 1.33.0 False True
456 lightningcss-darwin-arm64 1.32.0 1.33.0 False True
457 lightningcss-darwin-x64 1.32.0 1.33.0 False True
458 lightningcss-freebsd-x64 1.32.0 1.33.0 False True
459 lightningcss-linux-arm-gnueabihf 1.32.0 1.33.0 False True
460 lightningcss-linux-arm64-gnu 1.32.0 1.33.0 False True
461 lightningcss-linux-arm64-musl 1.32.0 1.33.0 False True
462 lightningcss-linux-x64-gnu 1.32.0 1.33.0 False True
463 lightningcss-linux-x64-musl 1.32.0 1.33.0 False True
464 lightningcss-win32-arm64-msvc 1.32.0 1.33.0 False True
465 lightningcss-win32-x64-msvc 1.32.0 1.33.0 False True
466 lodash 4.18.1 4.18.1 False False
467 long 5.3.2 5.3.2 False False
468 lru-cache 5.1.1 11.5.3 False True
469 lucide-react 0.576.0 1.49.0 True True
470 magic-string 0.30.21;1.4.2 1.4.2 False True
471 math-intrinsics 1.1.0 1.1.0 False False
472 media-typer 1.1.1 2.0.0 False True
473 merge-descriptors 2.0.0 2.0.0 False False
474 mime-db 1.54.0 1.54.0 False False
475 mime-types 3.0.2 3.0.2 False False
476 minimist 1.2.8 1.2.8 False False
477 ms 2.1.3 2.1.3 False False
478 nanoid 3.3.19 6.0.1 False True
479 negotiator 1.1.0 1.1.0 False False
480 next-themes 0.4.6 0.4.6 True False
481 node-domexception 1.0.0 2.0.2 False True
482 node-fetch 3.3.2 3.3.2 False False
483 node-releases 2.0.57 2.0.57 False False
484 nth-check 2.1.1 3.0.1 False True
485 nunjucks 3.2.4 3.2.4 True False
486 object-assign 4.1.1 4.1.1 False False
487 object-inspect 1.13.4 1.13.4 False False
488 obug 2.2.1 3.0.0 False True
489 on-exit-leak-free 2.1.2 2.1.2 False False
490 on-finished 2.4.1 2.4.1 False False
491 once 1.4.0 1.4.0 False False
492 openai 6.40.0 7.25.0 False True
493 openapi3-ts 4.6.1 4.6.1 False False
494 openworkflow 0.10.1 0.10.1 True False
495 p-map 7.0.8 7.0.8 False False
496 p-retry 4.6.2 8.0.1 False True
497 parse5 7.3.0 8.0.1 False True
498 parse5-htmlparser2-tree-adapter 7.1.0 8.0.1 False True
499 parse5-parser-stream 7.1.2 8.0.0 False True
500 parseurl 1.3.3 1.3.3 False False
501 partial-json 0.1.7 0.1.7 False False
502 path-expression-matcher 1.6.2 1.6.2 False False
503 path-key 3.1.1 4.0.0 False True
504 path-to-regexp 8.4.2 8.4.2 False False
505 pathe 1.1.2;2.0.3 2.0.3 False True
506 pg 8.23.0 8.23.1 True True
507 pg-cloudflare 1.4.0 1.4.1 False True
508 pg-connection-string 2.14.0 2.14.1 False True
509 pg-int8 1.0.1 1.0.1 False False
510 pg-pool 3.14.0 3.14.0 False False
511 pg-protocol 1.16.0 1.16.1 False True
512 pg-types 2.2.0 4.1.0 False True
513 pgpass 1.0.5 1.0.6 False True
514 picocolors 1.1.1 1.1.1 False False
515 picomatch 4.0.7 4.0.7 False False
516 pino 10.3.1 10.3.1 True False
517 pino-abstract-transport 3.0.0 3.0.0 False False
518 pino-pretty 13.1.3 13.1.3 True False
519 pino-std-serializers 7.1.0 7.1.0 False False
520 pkce-challenge 5.0.1 6.0.0 False True
521 pkg-types 2.3.3 2.3.3 False False
522 playwright-core 1.63.0 1.63.0 True False
523 postcss 8.5.28 8.5.28 False False
524 postgres 3.4.9 3.4.9 True False
525 postgres-array 2.0.0 3.0.4 False True
526 postgres-bytea 1.0.1 3.0.0 False True
527 postgres-date 1.0.7 2.1.0 False True
528 postgres-interval 1.2.0 4.1.0 False True
529 prettier 3.9.9 3.9.9 False False
530 process-warning 5.1.0 5.1.0 False False
531 protobufjs 7.6.6 8.8.0 False True
532 proxy-addr 2.0.8 2.0.8 False False
533 proxy-agent-negotiate 1.1.0 1.1.0 False False
534 pump 3.0.4 3.0.4 False False
535 pvtsutils 1.3.6 1.3.6 False False
536 pvutils 1.2.0 1.2.0 False False
537 qr-code-styling 1.9.2 1.9.2 True False
538 qrcode-generator 1.5.2 2.0.4 False True
539 qs 6.16.0 6.16.0 False False
540 quick-format-unescaped 4.0.4 4.0.4 False False
541 radix-ui 1.6.7 1.6.7 True False
542 range-parser 1.3.0 1.3.0 False False
543 raw-body 3.0.2 4.0.0 False True
544 react 19.3.0 19.3.0 True False
545 react-day-picker 10.0.1 10.0.2 True True
546 react-dom 19.3.0 19.3.0 True False
547 react-is 19.3.0 19.3.0 False False
548 react-redux 9.3.0 9.3.0 False False
549 react-refresh 0.14.2 0.19.0 False True
550 react-remove-scroll 2.7.2 2.7.2 False False
551 react-remove-scroll-bar 2.3.8 2.3.8 False False
552 react-router 7.12.0 8.4.0 True True
553 react-style-singleton 2.2.3 2.2.3 False False
554 readdirp 4.1.2 5.1.1 False True
555 real-require 0.2.0;1.0.0 1.0.0 False True
556 recharts 3.10.1 3.10.1 True False
557 redux 5.0.1 5.0.1 False False
558 redux-thunk 3.1.0 3.1.0 False False
559 reflect-metadata 0.2.2 0.2.2 False False
560 require-from-string 2.0.2 2.0.2 False False
561 reselect 5.2.0 5.3.0 False True
562 retry 0.13.1 0.13.1 False False
563 rollup 4.63.5 4.63.5 False False
564 router 2.2.0 2.2.0 False False
565 safe-buffer 5.2.1 5.2.1 False False
566 safe-stable-stringify 2.5.0 2.5.0 False False
567 safer-buffer 2.1.2 2.1.2 False False
568 scheduler 0.28.0 0.28.0 False False
569 secure-json-parse 4.1.0 4.1.0 False False
570 semver 6.3.1;7.8.5 7.8.5 False True
571 send 1.2.1 1.2.1 False False
572 serve-static 2.2.1 2.2.1 False False
573 set-cookie-parser 2.7.2 3.1.2 False True
574 setprototypeof 1.2.0 1.2.0 False False
575 shebang-command 2.0.0 2.0.0 False False
576 shebang-regex 3.0.0 4.0.0 False True
577 side-channel 1.1.1 1.1.1 False False
578 side-channel-list 1.0.1 1.0.1 False False
579 side-channel-map 1.0.1 1.0.1 False False
580 side-channel-weakmap 1.0.2 1.0.2 False False
581 sonic-boom 4.2.1 5.0.1 False True
582 sonner 2.0.8 2.0.8 True False
583 source-map-js 1.2.1 1.2.2 False True
584 split2 4.2.0 4.2.0 False False
585 standardwebhooks 1.1.1 1.1.1 False False
586 statuses 2.0.2 2.0.2 False False
587 std-env 4.2.0 4.3.0 False True
588 strip-json-comments 5.0.3 5.0.3 False False
589 strnum 2.4.2 2.4.2 False False
590 tailwind-merge 3.7.0 3.7.0 True False
591 tailwindcss 4.3.3 4.3.3 True False
592 tapable 2.3.3 2.3.3 False False
593 thread-stream 4.2.0 4.2.0 False False
594 tiny-invariant 1.3.3 1.3.3 False False
595 tinybench 6.2.0 6.2.0 False False
596 tinyexec 1.3.1 1.3.1 False False
597 tinyglobby 0.2.17 0.2.17 False False
598 toidentifier 1.0.1 1.0.1 False False
599 ts-algebra 2.0.0 2.0.0 False False
600 tsconfck 3.1.6 3.1.6 False False
601 tslib 1.14.1;2.8.1 2.8.1 False True
602 tsyringe 4.10.0 4.10.0 False False
603 tw-animate-css 1.4.0 1.4.0 True False
604 type-is 2.1.0 3.0.0 False True
605 typebox 1.3.27 1.3.34 True True
606 typescript 7.0.2 7.0.2 True False
607 undici 7.30.0 8.11.2 False True
608 undici-types 7.24.6 8.11.2 False True
609 unpipe 1.0.0 1.0.0 False False
610 update-browserslist-db 1.3.3 1.3.3 False False
611 use-callback-ref 1.3.3 1.3.3 False False
612 use-sidecar 1.1.3 1.1.3 False False
613 use-sync-external-store 1.7.0 1.7.0 False False
614 valibot 1.5.0 1.5.0 False False
615 vary 1.1.2 1.1.2 False False
616 victory-vendor 37.3.6 37.3.6 False False
617 vite 7.3.6 8.3.1 True True
618 vite-node 3.2.4 6.0.0 False True
619 vite-tsconfig-paths 5.1.4 6.1.1 True True
620 vitest 5.0.2 5.0.3 True True
621 web-streams-polyfill 3.3.3 4.3.0 False True
622 whatwg-encoding 3.1.1 3.1.1 False False
623 whatwg-mimetype 4.0.0 5.0.0 False True
624 which 2.0.2 7.0.0 False True
625 why-is-node-running 3.2.2 3.2.2 False False
626 wrappy 1.0.2 1.0.2 False False
627 ws 8.21.3 8.22.0 False True
628 xml-naming 0.3.0 0.3.0 False False
629 xpath 0.0.34 0.0.34 True False
630 xtend 4.0.2 4.0.2 False False
631 yallist 3.1.1 5.0.0 False True
632 yaml 2.9.0;2.9.1 2.9.1 True True
633 zod 4.6.5 4.6.5 True False
634 zod-to-json-schema 3.25.2 3.25.2 False False
@@ -0,0 +1,63 @@
{
"removedContainers": [
"umt-upgrade-app",
"umt-upgrade-browser",
"umt-upgrade-mock",
"umt-upgrade-qb",
"umt-upgrade-pg18"
],
"removedVolumes": [
"umt_umt-pg-data",
"umt-dev_umt-pg-data",
"umt-upgrade-pg18-data",
"umt-upgrade-app-data",
"umt-upgrade-restore-data",
"umt-upgrade-production-restore-data",
"umt-upgrade-browser-profiles",
"umt-upgrade-browser-config"
],
"removedImageTags": [
"uhd-media-tool:upgrade-20261001",
"uhd-media-tool:pre-upgrade-20261001",
"umt-browser-desktop:1.17.0",
"uhd-media-tool:v0.2.4",
"uhd-media-tool:v0.2.3",
"camofox-browser:1.17.0",
"uhd-media-tool:v0.2.2",
"uhd-media-tool:v0.2.1",
"uhd-media-tool:v0.2.0",
"uhd-media-tool:v0.2.0-rc",
"uhd-media-tool:v0.1.0",
"lscr.io/linuxserver/qbittorrent:5.1.2",
"caddy:2-alpine",
"alpine/socat:1.8.0.0"
],
"removedBuildImages": [],
"preservedSharedImages": [
"postgres:16-alpine"
],
"removedBackups": [
"/data/backups/20260929T103808Z",
"/data/backups/20261001T072253Z",
".local/upgrade-20261001/rollback-docker-compose.yml",
".local/upgrade-20261001/dev-pg16.dump",
".local/upgrade-20261001/rollback-images.json",
".local/upgrade-20261001/umt_umt-camofox.tar.gz",
".local/upgrade-20261001/umt_umt-qb-config.tar.gz",
".local/upgrade-20261001/production-app.env",
".local/upgrade-20261001/rollback-development.sh",
".local/upgrade-20261001/umt_umt-data.tar.gz",
".local/upgrade-20261001/container-inventory-private.json",
".local/upgrade-20261001/rollback-docker-compose.dev.yml",
".local/upgrade-20261001/rollback-production.sh",
".local/upgrade-20261001/current-container-inventory-private.json",
".local/upgrade-20261001/umt_umt-caddy.tar.gz",
".local/upgrade-20261001/4af29d25d939f585d86fb8382ec6f00e8d3b0fe14725e611ce9ae3c0875c0ecf.tar.gz",
".local/upgrade-20261001/original-env.deploy",
".local/upgrade-20261001/original-docker-compose.override.yml"
],
"retainedBackups": [
"/data/backups/20261001T072536Z",
".local/backups/dev-pg18-20261001.dump"
]
}
@@ -0,0 +1,91 @@
{
"workspace": {
"@biomejs/biome": "npm:@biomejs/[email protected]",
"@earendil-works/pi-agent-core": "npm:@earendil-works/[email protected]",
"@earendil-works/pi-ai": "npm:@earendil-works/[email protected]",
"@hono/swagger-ui": "npm:@hono/[email protected]",
"@hono/zod-openapi": "npm:@hono/[email protected]",
"@modelcontextprotocol/sdk": "npm:@modelcontextprotocol/[email protected]",
"@simplewebauthn/server": "npm:@simplewebauthn/[email protected]",
"@types/node": "npm:@types/[email protected]",
"@types/nunjucks": "npm:@types/[email protected]",
"@types/pg": "npm:@types/[email protected]",
"@xmldom/xmldom": "npm:@xmldom/[email protected]",
"cheerio": "npm:[email protected]",
"fast-xml-parser": "npm:[email protected]",
"hash-wasm": "npm:[email protected]",
"hono": "npm:[email protected]",
"jpeg-js": "npm:[email protected]",
"kysely": "npm:[email protected]",
"nunjucks": "npm:[email protected]",
"openworkflow": "npm:[email protected]",
"pg": "npm:[email protected]",
"pino": "npm:[email protected]",
"pino-pretty": "npm:[email protected]",
"playwright-core": "npm:[email protected]",
"postgres": "npm:[email protected]",
"typebox": "npm:[email protected]",
"typescript": "npm:[email protected]",
"vitest": "npm:[email protected]",
"xpath": "npm:[email protected]",
"yaml": "npm:[email protected]",
"zod": "npm:[email protected]"
},
"web": {
"dependencies": {
"@fontsource-variable/inter-tight": "^5.3.0",
"@fontsource-variable/space-grotesk": "^5.3.0",
"@react-router/node": "8.4.0",
"@simplewebauthn/browser": "^14.0.0",
"@tanstack/react-query": "^5.104.0",
"@umt/contracts": "workspace:*",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"date-fns": "^4.4.0",
"isbot": "^5.2.2",
"lucide-react": "^1.49.0",
"next-themes": "^0.4.6",
"qr-code-styling": "^1.9.2",
"radix-ui": "^1.6.7",
"react": "^19.3.0",
"react-day-picker": "^10.0.2",
"react-dom": "^19.3.0",
"react-router": "8.4.0",
"recharts": "^3.10.1",
"sonner": "^2.0.8",
"tailwind-merge": "^3.7.0",
"zod": "^4.6.5"
},
"devDependencies": {
"@react-router/dev": "8.4.0",
"@tailwindcss/vite": "^4.3.3",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"tailwindcss": "^4.3.3",
"tw-animate-css": "^1.4.0",
"vite": "^8.3.1",
"vite-tsconfig-paths": "^6.1.1"
}
},
"browser": {
"dependencies": {
"better-sqlite3": "13.0.3",
"camoufox-js": "0.12.0",
"express": "5.2.1",
"playwright-core": "1.60.0",
"prom-client": "15.1.3",
"swagger-jsdoc": "6.3.0"
},
"optionalDependencies": {
"@modelcontextprotocol/sdk": "1.31.0"
}
},
"sha256": {
"deno.json": "1a136fefa2afecb8084dd41bbbfd415994ca4c073402c00e604452aca2bcd4a0",
"deno.lock": "c18843d7db6039a22c97634b7e112b7dee2ae5acfac08a61cebd11c3f6d23e4c",
"apps/web/package.json": "fe3ab24d9f77beee36e7872a261bd96261161cba84aa08dcf65e4a0136cf8e58",
"docker/camofox/package.json": "911a051f515b68abc3301fa11caaa3b446b4af8895c76e4f0a1f8373541464b5",
"docker/camofox/package-lock.json": "040b7a1c91b4536149b67a7291be70c089171752c639e8231b01b4ef4c695b46"
},
"policy": "Latest verified direct stable dependencies, preserving upstream transitive version constraints; Node type definitions target runtime24, browser Playwright1.60 is required by official Camoufox protocol."
}
@@ -0,0 +1,173 @@
{
"applicationVersion": "0.3.8",
"hostUpgrade": false,
"ci": {
"exitCode": 0,
"passed": 3264,
"skipped": 4
},
"workspaceAudit": {
"vulnerabilities": 0
},
"webSmoke": {
"passed": 83,
"skipped": 1,
"reason": "no subscription detail data"
},
"piSessionCompatibility": {
"oldJsonlOpened": 35,
"passed": 35
},
"qbittorrentRealApi": {
"target": "5.2.4",
"passed": 3,
"skipped": 1,
"reason": "no API key configured"
},
"browserInstalledAudit": {
"dependencyCount": 174,
"vulnerabilities": 0
},
"backupRestoreE2E": {
"server": "18.6",
"client": "18.6",
"mappingCountsMatch": true,
"checksumsVerified": true
},
"developmentDatabaseMigration": {
"source": "16.14",
"target": "18.6",
"tables": 88,
"allCountsAndContentFingerprintsMatch": true,
"newBackupRestore": "PG18 dump restored on isolated PG18; all 88 table fingerprints match"
},
"productionDatabaseMigration": {
"source": "16.14",
"target": "18.6",
"tables": 89,
"allCountsAndContentFingerprintsMatch": true,
"finalStoppedWriteBackup": "20261001T072253Z",
"deployedVersion": "0.3.8",
"mode": "original readonly=false restored; deployment accepted",
"oldPG16Volumes": "removed after acceptance with user authorization"
},
"oldCredentialsCompatibility": {
"clonedDatabaseSecrets": "original key preserved",
"downloaderConnection": "v5.1.2 existing deployment authenticated successfully"
},
"browserDesktopIsolated": {
"sourceProfiles": "independent copy of existing production volume",
"version": "1.18.0",
"node": "24.21.0",
"camoufox": "152.0.4-beta.30",
"playwright": "1.60.0",
"beforeAfterRestart": "passed",
"checks": [
"authorization",
"fixed identity preserved",
"new context and page",
"evaluate",
"snapshot",
"PNG screenshot",
"selector click",
"trusted mouse click",
"profile isolation",
"persisted cookies after graceful restart"
],
"mcpInitialize": "passed SDK1.31.0"
},
"browserServiceRealVerification": {
"version": "1.18.0",
"phases": {
"setup": {
"passed": 2,
"failed": 0,
"items": [
"provider:env 登记 + 探测",
"auth:无 Bearer 被拒"
]
},
"a": {
"passed": 16,
"failed": 0,
"items": [
"public:导航/快照/截图",
"sessions:关闭公开页会话",
"login:未登录识别为登录页",
"screenshot:登录页",
"takeover:接管期间自动化被拒",
"takeover:坐标点击/焦点输入/回车",
"redact:密码框值不出现在快照",
"same-tab:交还后 Agent 读到人工操作结果(同一 tabId)",
"login:登录后 Cookie 生效(Agent 直接打开受保护列表页)",
"screenshot:列表页",
"snapshot:列表页",
"extract:列表",
"extract:详情",
"download:捕获 + sha256 一致 + 匹配本地资源",
"download:已消费的下载不重复返回",
"interact:后退/前进/刷新/滚动"
]
},
"b": {
"passed": 2,
"failed": 0,
"items": [
"restart(SIGTERM):自动重连 + 旧标签页 lost + 旧引用不重放",
"restart(SIGTERM):登录状态保持"
]
},
"idle": {
"passed": 2,
"failed": 0,
"items": [
"idle(SESSION_TIMEOUT_MS):自动重连 + 旧标签页 lost + 旧引用不重放",
"idle(SESSION_TIMEOUT_MS):登录状态保持"
]
},
"c": {
"passed": 1,
"failed": 0,
"items": [
"agent-login:凭证注入登录(账号 2)"
]
},
"d": {
"passed": 2,
"failed": 0,
"items": [
"restart(SIGKILL) 账号 2:自动重连 + 旧标签页 lost + 旧引用不重放",
"restart(SIGKILL) 账号 2:未落盘登录丢失被明确识别"
]
}
},
"totalPassed": 25,
"verifiedCapabilities": 10,
"regressionTests": {
"passed": 100,
"files": 14
},
"sigkill": "new login since last save is lost and correctly detected; not claimed lossless"
},
"productionAcceptance": {
"httpAndHttpsHealth": "0.3.8 DB ok",
"mappingCountsMatch": true,
"originalMasterKeyAndAllNonDatabaseMountsPreserved": true,
"oldEncryptedDownloaderCredentials": "successful authentication to v5.2.4",
"apiWorkerAndAgentRoles": "all alive as uid10001",
"appErrorLevelMessages": 0,
"latestPG18Backup": "20261001T072536Z",
"latestBackupRestore": "passed on isolated PG18, checksums and mappings verified",
"restoredTables": 89,
"restoredAgentSessionFiles": 35,
"allSessionFilesByteIdentical": true,
"releaseWebSmoke": {
"passed": 83,
"skipped": 1
},
"cleanup": "completed; see upgrade-cleanup.json",
"originalReadonlyStateRestored": true,
"readonlyValue": false
},
"status": "completed"
}
@@ -0,0 +1,80 @@
╭ React Router: Open redirect via backslash in <Link> and useNavigate (CVE-2025-68470 bypass)
│ Severity: moderate
│ Package: react-router
│ Vulnerable: >=6.0.0 <7.18.0
╰ Info: https://github.com/advisories/GHSA-wrjc-x8rr-h8h6
╭ React Router: Arbitrary Constructor Injection via deserializeErrors() in React Router SSR Hydration
│ Severity: moderate
│ Package: react-router
│ Vulnerable: >=6.4.0 <7.18.0
╰ Info: https://github.com/advisories/GHSA-337j-9hxr-rhxg
╭ React Router vulnerable to Denial of Service via reflected user input in single-fetch
│ Severity: high
│ Package: react-router
│ Vulnerable: >=7.0.0 <7.14.0
╰ Info: https://github.com/advisories/GHSA-rxv8-25v2-qmq8
╭ React Router's same-origin redirect with path starting // causes open redirect via protocol-relative URL reinterpretation
│ Severity: moderate
│ Package: react-router
│ Vulnerable: >=7.0.0 <7.14.1
╰ Info: https://github.com/advisories/GHSA-2j2x-hqr9-3h42
╭ React Router vulnerable to DoS via unbounded path expansion in __manifest endpoint
│ Severity: high
│ Package: react-router
│ Vulnerable: >=7.0.0 <7.15.0
╰ Info: https://github.com/advisories/GHSA-8x6r-g9mw-2r78
╭ React Router: Unauthenticated Denial of Service via Inefficient Route Matching
│ Severity: high
│ Package: react-router
│ Vulnerable: >=7.0.0 <7.18.0
╰ Info: https://github.com/advisories/GHSA-chx6-hx7r-mcp5
╭ React Router's vendored turbo-stream v2 allows arbitrary constructor invocation via TYPE_ERROR deserialization leading to Unauth RCE
│ Severity: high
│ Package: react-router
│ Vulnerable: >=7.0.0 <=7.14.1
╰ Info: https://github.com/advisories/GHSA-49rj-9fvp-4h2h
╭ React Router: RSCErrorHandler Missing Protocol Validation (XSS)
│ Severity: moderate
│ Package: react-router
│ Vulnerable: >=7.11.0 <7.18.0
╰ Info: https://github.com/advisories/GHSA-h8fp-f39c-q6mh
╭ React Router: Potential CSRF via PUT/PATCH/DELETE document requests
│ Severity: low
│ Package: react-router
│ Vulnerable: >=7.12.0 <7.15.1
╰ Info: https://github.com/advisories/GHSA-84g9-w2xq-vcv6
╭ React Router: RSC Mode CSRF Bypass Allows Action Execution Before 400 Response
│ Severity: high
│ Package: react-router
│ Vulnerable: >=7.12.0 <7.18.2
╰ Info: https://github.com/advisories/GHSA-qwww-vcr4-c8h2
╭ React Router has stored XSS via unescaped Location header in prerendered redirect HTML
│ Severity: moderate
│ Package: react-router
│ Vulnerable: >=7.5.1 <7.13.2
╰ Info: https://github.com/advisories/GHSA-f22v-gfqf-p8f3
╭ React Router vulnerable to XSS in unstable RSC redirect handling via javascript: redirect targets
│ Severity: high
│ Package: react-router
│ Vulnerable: >=7.7.0 <7.13.2
╰ Info: https://github.com/advisories/GHSA-8646-j5j9-6r62
╭ React Router: Open redirect leading to XSS
│ Severity: moderate
│ Package: react-router
│ Vulnerable: >=7.9.6 <=7.12.0
╰ Info: https://github.com/advisories/GHSA-jjmj-jmhj-qwj2
Found 13 vulnerabilities
Severity: 1 low, 6 moderate, 6 high, 0 critical
+1 -1
View File
@@ -52,7 +52,7 @@ AG-3 补的只读摘要(类别 read,scope `read`,都在后台调查 / 巡检白
| `POST /approvals {planType, planId}`、`PATCH /approvals/{id} {status, payloadHash, reason?}` | 单次审批。**只接受控制台管理员会话**(API Key 一律 403,持 `organize.execute` 的 Key 不能给自己的计划开审批再自批)。批准时要回传 payloadHash;计划 payload hash / revision 变化、过期、撤销后旧审批失效,执行成功一次即 consumed,不可重放(`test/agent/approvals.test.ts`)。会话内审批(见「会话交互」)决定后写关联待处理事项并唤醒挂起的会话 |
| `GET /capabilities`、`POST /capabilities/{id}/invoke` | 能力目录与调用,HTTP scope 按能力描述符再校验一次 |
| `GET /tasks[/{id}]`、`POST /tasks/{id}/cancel`、`POST /tasks/{id}/retry` | 业务任务;`?subjectId=` 按业务对象查(submitDownload 的 subject 是计划,verifyAndImport 的是下载任务) |
| `POST /acquisition-plans {sourceReleaseId, slotId? \| entityId?, note?}` | 手动提交下载(工作台下载入口):依次调 `download.plan` → `download.submit`,和 Agent 同一条能力路径(授权 / 审计 / 幂等键 / 账本)。没给 slotId 时按作品的 Slot 创建顺序逐个尝试,第一个生成计划的胜出;都没生成时 `submitted=false` 并逐个 Slot 给出原因。控制台管理员算人工授权;API Key 需要持续授权或单次审批 |
| `POST /acquisition-plans {sourceReleaseId, entityId?, downloaderInstanceId?, savePath?, allowUnrecognized?, importMode?, replacementAssetIds?, note?}` | 独立手动下载,不要求订阅或 Slot;未知资源返回 `requiresConfirmation`,确认后允许提交。下载计划复用已有任务提交、审计、幂等与缓存卷检查;自动订阅评估和 Agent `download.plan` 保持自动规则。`importMode` 为 `normal`/`replace`,洗版选择仅本次有效。此批已部署为 v0.3.10,迁移 `0060` 已执行。 |
| `GET /artifacts[/{id}]` | 产物只读:整理 dryRun 计划(kind=plan)、目标汇报(report)、候选评估(evidence)等 |
**增量推送**:事件先写 `agent_run_event`(run_id + seq 唯一),再经 `ctx.events` 推到全局 SSE(`GET /events`)。推送的类型有 `agent.run_status`、`agent.text_delta`、`agent.tool_call`;未授权导致的工具失败,`phase` 为 `denied`。断线后,先用全局 `?after=<seq>` 补读总线事件,再用 `GET /agent/runs/{id}?afterSeq=<最后收到的 runSeq>` 补读单个 run 的完整事件。SSE 只给控制台(cookie 会话);API Key 调用者用 `GET /events?after=<seq>&limit=<n>` 取 JSON 页轮询(见 auth.md「SSE 多进程总线」)。
+12 -12
View File
@@ -18,41 +18,41 @@
先写到 `.<时间戳>.partial/`,全部成功才改名,不会留下半截备份。`BACKUP_KEEP=N`(compose 缺省 14)时只保留最近 N 份。
**SECRET_MASTER_KEY 不在备份里。** 它和备份必须分开保管:备份泄露时密文仍然安全;主密钥丢失时备份里的站点/下载器/模型凭证无法解密(需要重新录入)。
恢复到新机器时,`.env` 里的 `SECRET_MASTER_KEY` 必须与备份时一致。
恢复到新机器时,`.env.deploy` 里的 `SECRET_MASTER_KEY` 必须与备份时一致。
## 日常备份
```sh
docker compose exec app umt backup # 在线备份(pg_dump 一致性快照,不停服)
docker compose exec app ls /data/backups
docker compose --env-file .env.deploy exec app umt backup # 在线备份(pg_dump 一致性快照,不停服)
docker compose --env-file .env.deploy exec app ls /data/backups
# 拷到机器外(示例):
docker compose cp app:/data/backups/20260927T120000Z ./offsite/
docker compose --env-file .env.deploy cp app:/data/backups/20260927T120000Z ./offsite/
```
定时:宿主 cron `0 4 * * * cd /opt/umt && docker compose exec -T app umt backup >> /var/log/umt-backup.log 2>&1`。
单独导出映射清单:`docker compose exec app umt export-mappings`(写到 `/data/exports/`)。
定时:宿主 cron `0 4 * * * cd /opt/umt && docker compose --env-file .env.deploy exec -T app umt backup >> /var/log/umt-backup.log 2>&1`。
单独导出映射清单:`docker compose --env-file .env.deploy exec app umt export-mappings`(写到 `/data/exports/`)。
## 恢复
恢复会删除并重建备份里的全部对象。**先停 app**,脚本检测到库里还有其它连接会拒绝(`--force` 可跳过,不建议)。
```sh
docker compose stop app
docker compose run --rm --no-deps app restore 20260927T120000Z --yes # 或绝对路径 /data/backups/...
docker compose up -d app
docker compose --env-file .env.deploy stop app
docker compose --env-file .env.deploy run --rm --no-deps app restore 20260927T120000Z --yes # 或绝对路径 /data/backups/...
docker compose --env-file .env.deploy up -d app
```
`restore.sh` 依次:
1. 校验 `SHA256SUMS`;
2. `pg_restore --clean --if-exists --no-owner` 生成 SQL,经 `psql --single-transaction -v ON_ERROR_STOP=1` 回放(失败整体回滚,库保持恢复前状态)。镜像里是 17 版客户端,回放前去掉 16 版服务端不认识的 `SET transaction_timeout`;
2. `pg_restore --clean --if-exists --no-owner` 生成 SQL,经 `psql --single-transaction -v ON_ERROR_STOP=1` 回放(失败整体回滚,库保持恢复前状态)。当前镜像使用 18.6 客户端,支持 PG18 备份;回放前仍过滤 `SET transaction_timeout`,以兼容回滚到 PG16;
3. 还原 `agent-sessions.tar.gz`;
4. `--role read-only-on`:把 `automation.readOnlyReconcile` 置为 true(保留 automation 其它字段),写审计 `ops.read_only_reconcile_on`;
5. 重新导出映射清单到 `DATA_DIR/tmp/restore-check-*.json`,逐表与备份里的 `counts` 比对,不一致以退出码 3 结束;
6. 打印"恢复后先对账再关闭只读"提示。
从别的机器恢复:把备份目录拷进目标机器的 `umt-data` 卷(`docker compose cp ./20260927T120000Z app:/data/backups/`),
`.env` 用原来的 `SECRET_MASTER_KEY`,空库上照上面的命令执行。备份早于当前镜像版本时,`up -d app` 会自动跑后续迁移。
从别的机器恢复:把备份目录拷进目标机器的 `umt-data` 卷(`docker compose --env-file .env.deploy cp ./20260927T120000Z app:/data/backups/`),
`.env.deploy` 用原来的 `SECRET_MASTER_KEY`,空库上照上面的命令执行。备份早于当前镜像版本时,`up -d app` 会自动跑后续迁移。
## 恢复后:先对账,再关闭只读
+50 -24
View File
@@ -4,44 +4,50 @@
代码:`packages/adapters/src/browser/**`(适配器)、`apps/server/src/modules/browser/**`(会话/接管/能力)、
`apps/web/app/components/browser/**`(原站视图)。
> 当前状态:已对真实 camofox-browser **v1.17.0**(jo-inc,commit `389c996`)容器逐项核验(§7),十项能力全部通过;
> 当前版本:**v1.18.0**(jo-inc,commit `f94c81b`)已重新核验原有十项能力,六阶段 25 项检查和隔离重启验证通过(§16)。
> §7 等带日期的 v1.17.0 验收表保留历史证据;
> 探测到其它版本 / fork 时一律显示"未核验",需按 §6 重新核验。
## 1. 浏览器服务从哪来
### 1.1 部署自带(缺省)
`docker compose up -d` 同时起 `camofox` 服务(`docker-compose.yml`,只在内网、不映射端口,卷 `umt-camofox`)。
当前部署配置使用 `.env.deploy`。首次启动前,先完成本节下方的基础镜像构建;已有镜像时再执行启停命令。
`docker compose --env-file .env.deploy up -d` 同时起 `camofox` 服务(`docker-compose.yml`,只在内网、不映射端口,卷 `umt-camofox`)。
app 的 `BROWSER_PROVIDER_URL` 缺省 `http://camofox:9377`,启动后第一次用到浏览器时登记为 **`camofox-env`**
(`browser_provider.config.managedBy = "env"`,访问凭据取 `BROWSER_ACCESS_KEY` / `CAMOFOX_ACCESS_KEY`,只在进程内,不入库),
并在后台探测一次能力。地址与凭据只能改部署配置;设置页只能改它的启用。
```sh
# .env(部署目录)
# .env.deploy(部署目录)
CAMOFOX_ACCESS_KEY=$(openssl rand -hex 24) # camofox 与 app 共用
docker compose --env-file .env.deploy up -d --build
docker compose ps camofox # healthy 即可
docker compose --env-file .env.deploy ps camofox # healthy 即可
```
上游不发布镜像。compose 缺省用的是**浏览器桌面镜像** `umt-browser-desktop:1.17.0`(`docker/browser-desktop`,§8),
它从纯截图镜像 `camofox-browser:1.17.0` 复制 camofox,所以**先构建旧镜像**:`docker/camofox/Dockerfile` 从 git tag `v1.17.0`
上游不发布镜像。compose 缺省用的是**浏览器桌面镜像** `umt-browser-desktop:1.18.0`(`docker/browser-desktop`,§8),
当前默认版本为 1.18.0,构建补丁、锁文件和 Playwright 1.60 协议兼容例外见 [镜像说明](../../docker/camofox/README.md)。以下旧日期的验收表保留历史版本。
它从纯截图镜像 `camofox-browser:1.18.0` 复制 camofox,所以**先构建基础镜像**:`docker/camofox/Dockerfile` 从 git tag `v1.18.0`
构建(修了上游 Dockerfile 的两个问题,见文件头)。首次构建要从 GitHub 拉源码与约 630 MB 的 Camoufox 浏览器包:
```sh
git clone --depth 1 --branch v1.17.0 https://github.com/jo-inc/camofox-browser.git /tmp/camofox-src
docker build -t camofox-browser:1.17.0 --build-arg APT_MIRROR=mirrors.ustc.edu.cn \
git clone --depth 1 --branch v1.18.0 https://github.com/jo-inc/camofox-browser.git /tmp/camofox-src
git -C /tmp/camofox-src rev-parse HEAD # 必须为 f94c81babf4bfd44cdd4bd46e1f2e1fb1d91c753
docker build -t camofox-browser:1.18.0 --build-arg APT_MIRROR=mirrors.ustc.edu.cn \
--build-context upstream=/tmp/camofox-src docker/camofox
# 走宿主代理时加 --network host --build-arg https_proxy=http://127.0.0.1:7890 --build-arg http_proxy=...
docker compose build camofox # 再构建桌面镜像(或 docker build -t umt-browser-desktop:1.17.0 docker/browser-desktop)
docker compose --env-file .env.deploy build camofox # 再构建桌面镜像(或 docker build -t umt-browser-desktop:1.18.0 docker/browser-desktop)
```
只要截图模式(不要桌面、省约 400 MB 常驻内存与 3 GB 磁盘):`.env` 里 `CAMOFOX_IMAGE=camofox-browser:1.17.0`,同一个卷,登录状态通用。
只要截图模式(不要桌面、省约 400 MB 常驻内存与 3 GB 磁盘):`.env.deploy` 里 `CAMOFOX_IMAGE=camofox-browser:1.18.0`,同一个卷,登录状态通用。
### 1.2 接自有实例
`.env` 里 `BROWSER_PROVIDER_URL=http://<host>:9377`、`BROWSER_ACCESS_KEY=<它的 CAMOFOX_ACCESS_KEY>`、`CAMOFOX_REPLICAS=0`
`.env.deploy` 里 `BROWSER_PROVIDER_URL=http://<host>:9377`、`BROWSER_ACCESS_KEY=<它的 CAMOFOX_ACCESS_KEY>`、`CAMOFOX_REPLICAS=0`
(不再起自带容器)。或者不设环境变量,在 **设置 → 站点默认 → 浏览器服务** 里"添加浏览器服务":名称、服务地址、访问凭据
(加密存凭证库,只写不回显)、启用。自有实例的版本不是 1.17.0 时能力一律显示"未核验"。
(加密存凭证库,只写不回显)、启用。自有实例的版本不是 1.18.0 时能力一律显示"未核验"。
### 1.3 不用浏览器
@@ -127,7 +133,7 @@ execute 类需要持续授权(`automation_grant`)或审批。元素引用只来
- **坐标系**:服务端对每次截图读页面视口与 DPR(`evaluate`),`页面 CSS 像素 = 截图像素 × 视口宽 / 截图宽`;
输出的 `coordinates` 记录截图尺寸、原始尺寸、视口、DPR(取不到时 `assumed = true`,按原图、DPR 1)。动作之后旧坐标系作废,
必须用新截图的坐标。点击(CF-2 起)先走 umt 插件的 `POST /umt/tabs/{id}/mouse-click`——Playwright `page.mouse.click` 发真实鼠标事件,
**跨域 iframe 里的控件(Cloudflare Turnstile)和画布也点得到**;插件没有这个端点(旧镜像、纯截图镜像)时退回 1.17.0 的做法:
**跨域 iframe 里的控件(Cloudflare Turnstile)和画布也点得到**;插件没有这个端点(旧镜像、纯截图镜像)时退回 1.18.0 的做法:
`elementFromPoint` 打标记再按选择器点(跨域 iframe / 画布点不到具体位置)。
- **动作前提**:会话在自动化控制下(人工接管 / 等待处理中一律拒绝),当前页面主机在站点域名白名单内。
- **敏感截图**:登录页地址、页面上有密码框、地址带凭据 → `sensitive = true`,默认不交给模型(不做像素遮蔽),改给已脱敏的文字快照;
@@ -156,7 +162,12 @@ execute 类需要持续授权(`automation_grant`)或审批。元素引用只来
不承诺通过 Cloudflare 等挑战(REQ §4.4):上游浏览器指纹与点击方式都可能被识别,失败按上面第 4 步转人工。
## 4. 下载产物
## 4. 详情页下载与下载产物
本轮源码新增:进入站点资源详情页后,在串流/截图窗口外点「下载当前资源」,解析当前详情并用默认下载器和目录提交。点「下载选项」可选择下载器、保存目录与一次性洗版。未识别资源会提示确认继续下载,整理阶段再补全元数据;不用点击源站下载按钮,也不用先建立订阅或本地搜索索引。此变更已于 2026-10-01 随 v0.3.10 部署,迁移 `0060` 已执行。
`POST /browser/sessions/{id}/resource {tabId?}` 返回登记后的资源与详情地址。默认读取唯一可见的已登记标签页,能发现上游登记的 popup;无法确定当前标签时明确报错,不提交旧页。显式 `tabId` 读取指定标签。下面的文件捕获接口仍保留给已有 Agent 流程使用。
- 暂存:`DATA_DIR/tmp/browser-downloads/<artifactId>.bin`(目录 0700、文件 0600),超过 24 小时的在下一次捕获时清理。
合同里只出现引用(`bytes.ref`),来源地址去掉 passkey。
@@ -176,10 +187,10 @@ execute 类需要持续授权(`automation_grant`)或审批。元素引用只来
| "连接中断" | 截图请求失败;看 API 日志 `component: browser` 的方法 / 路径 / 状态(日志不含正文与凭据) |
| 测试连通提示"访问凭据不对" | `/health` 免认证所以能连上,但 `/openapi.json` 401:`BROWSER_ACCESS_KEY` 与 camofox 的 `CAMOFOX_ACCESS_KEY` 不一致 |
| 原站视图"浏览器已重启,正在重新连接…" | camofox 重启 / 会话空闲回收后的自动重连(§10),正常几秒内恢复 |
| 503 `browser_reconnect_failed` / "浏览器连接已断开" | 自动重连失败,消息里是原因(camofox 没起来、`POST /tabs` 5xx 等);`docker compose ps camofox`、容器日志;恢复后点"重新连接" |
| 503 `browser_reconnect_failed` / "浏览器连接已断开" | 自动重连失败,消息里是原因(camofox 没起来、`POST /tabs` 5xx 等);`docker compose --env-file .env.deploy ps camofox`、容器日志;恢复后点"重新连接" |
| 409"标签页已被浏览器服务回收" | 只在显式指定了已被回收的 `tabId` 时出现(会话里还有别的标签页活着);不指定 `tabId` 重试即可 |
| 重启 camofox 后要重新登录 | 容器是被 SIGKILL / OOM 杀掉的(`docker inspect` 看 `OOMKilled`、退出码 137):只有 SIGTERM 正常停止、会话空闲回收、关闭会话时才落盘登录状态;加大 `CAMOFOX_MEM_LIMIT` |
| 设置页显示"未核验" | 探测到的上游版本不在核验表里(不是 1.17.0,或 fork);按 §6 核验后在适配器 `CAMOFOX_VERIFIED_RELEASES` 加一行,或临时写 `config.verified` |
| 设置页显示"未核验" | 探测到的上游版本不在核验表里(不是 1.18.0,或 fork);按 §6 核验后在适配器 `CAMOFOX_VERIFIED_RELEASES` 加一行,或临时写 `config.verified` |
## 6. 真实实例核验清单(REQ §4.7.4)
@@ -191,7 +202,7 @@ execute 类需要持续授权(`automation_grant`)或审批。元素引用只来
自动化核验脚本:`scripts/browser-verify/run.sh`(临时栈 `umtbr`:postgres 127.0.0.1:55447、camofox 127.0.0.1:49377、
compose 网络里的 mock NexusPHP 站 `mocknexus:8080`;服务层在宿主进程里装配,与生产同一套代码;
阶段之间重启 / SIGKILL camofox;结果写 `.browser-verify-out/results-*.json` 与截图)。跑完 `docker compose -p umtbr down -v`。
阶段之间重启 / SIGKILL camofox;结果写 `.browser-verify-out/results-*.json` 与截图)。跑完 `docker compose --env-file .env.deploy -p umtbr down -v`。
| # | 项目 | 做法 | 通过标准 | 对应 verified 键 |
| --- | --- | --- | --- | --- |
@@ -206,7 +217,7 @@ compose 网络里的 mock NexusPHP 站 `mocknexus:8080`;服务层在宿主进程
| 日期 | 仓库 / fork | 版本 | 启动方式 / 认证 | 通过项 | 备注 |
| --- | --- | --- | --- | --- | --- |
| 2026-09-28 | jo-inc/camofox-browser | v1.17.0(`389c996`),Camoufox 152.0.4-beta.28 | `docker/camofox/Dockerfile` + compose;`CAMOFOX_ACCESS_KEY` Bearer | 十项全部 | mock NexusPHP 站 + example.com;四个真实站点未测,见 §7 |
| 2026-09-28 | jo-inc/camofox-browser | v1.18.0(`f94c81b`),Camoufox 152.0.4-beta.28 | `docker/camofox/Dockerfile` + compose;`CAMOFOX_ACCESS_KEY` Bearer | 十项全部 | mock NexusPHP 站 + example.com;四个真实站点未测,见 §7 |
## 7. 真机核验(版本 1.17.0)
@@ -272,7 +283,7 @@ pixelflux + labwc Wayland 桌面 + Selkies 2.0 Web 客户端)+ camofox 1.17.0 **
| 自愈(INT-3 / FIX-5) | 同上 | 打开桌面先调一次幂等 `POST /browser/sessions/{id}/reconnect`(iframe 直连 Selkies 不触发被动重连),等它返回后才加载桌面 iframe(期间显示「正在确认浏览器会话…」,FIX-5 起不再先连上黑屏);画面 5 秒未加载或视频流未出帧 → 每个会话自动重连一次并重建桌面连接,之后靠「重新连接」按钮 |
| HTTPS | compose `caddy`(profile `tls`)+ `docker/browser-desktop/Caddyfile` | 可选;已有反代终结 TLS 时不用 |
窗口:无标题栏、最大化铺满 1280×900(`BROWSER_DESKTOP_WIDTH/HEIGHT`),`HARDEN_DESKTOP` 去掉终端 / sudo / xdg-open,
窗口:由内置 `/defaults/umt-labwc.xml` 设为无服务端装饰、最大化铺满 1280×900(`BROWSER_DESKTOP_WIDTH/HEIGHT`),`HARDEN_DESKTOP` 去掉终端 / sudo / xdg-open,
`HARDEN_OPENBOX` 去掉关闭按钮与右键 / 中键菜单、禁 Alt+F4 等。音频、麦克风、摄像头、手柄、文件传输、打印、命令、共享全部关闭并锁定,
剪贴板只允许文本。
@@ -303,21 +314,23 @@ pixelflux + labwc Wayland 桌面 + Selkies 2.0 Web 客户端)+ camofox 1.17.0 **
### 8.4 HTTPS
当前测试部署于 2026-10-01 将 **4380 改为 Caddy 自签 HTTPS**,访问 `https://服务器地址:4380`,原 443 HTTPS 入口保留。首次访问需在浏览器继续接受内部 CA 证书。app 的 HTTP 调试映射为 `127.0.0.1:4381`,容器间仍使用 `app:4380`。管理员登录、6 个页面加载与 Chromium `isSecureContext` 检查通过。此映射写在本机 `docker-compose.override.yml`,应用监听参数写入 `.env.deploy`。
WebCodecs 视频解码与剪贴板 API 只在安全上下文(HTTPS 或 `localhost`)可用;用 IP / 局域网主机名经 HTTP 访问时只能用截图模式。
```sh
# 已有反代(nginx / Caddy / Traefik)终结 TLS:无需改动,WebSocket 需透传 Upgrade、读超时 ≥ 1 小时、不缓冲
# 没有反代:启用 compose 自带 Caddy
docker compose --profile tls up -d # 自签:Caddy 内部 CA 按访问的主机名现场签发,浏览器需放行或导入根证书
docker compose cp caddy:/data/caddy/pki/authorities/local/root.crt ./umt-root.crt # 导入到客户端受信任根
# 有公网域名:.env 里 TLS_DOMAIN=media.example.com、TLS_ISSUER=you@example.com(ACME,80/443 需可达)
docker compose --env-file .env.deploy --profile tls up -d # 自签:Caddy 内部 CA 按访问的主机名现场签发,浏览器需放行或导入根证书
docker compose --env-file .env.deploy cp caddy:/data/caddy/pki/authorities/local/root.crt ./umt-root.crt # 导入到客户端受信任根
# 有公网域名:.env.deploy 里 TLS_DOMAIN=media.example.com、TLS_ISSUER=you@example.com(ACME,80/443 需可达)
```
`TLS_PORT`(缺省 443)、`TLS_BIND` 可改;4380 仍可直连(截图模式)。
`TLS_PORT`(缺省 443)、`TLS_BIND` 可改;标准 Compose 可通过 app 的 `UMT_PORT` 保留 HTTP 直连。本机已将 4380 用于 HTTPS,HTTP 调试改为 `127.0.0.1:4381`。
### 8.5 回退
- 桌面容器起不来 / 桌面异常:`.env` 设 `CAMOFOX_IMAGE=camofox-browser:1.17.0` 后 `docker compose up -d camofox`,原站视图自动回到截图模式,
- 桌面容器起不来 / 桌面异常:`.env.deploy` 设 `CAMOFOX_IMAGE=camofox-browser:1.17.0` 后 `docker compose --env-file .env.deploy up -d camofox`,原站视图自动回到截图模式,
Agent 能力不受影响(实测同一个卷,切换前后登录状态都在)。
- 只关桌面、保留镜像:不设 `CAMOFOX_ACCESS_KEY` 即可(桌面口令随机,app 探测为不可用)。
- 容器内输入法(本机输入法不可用时的备选):`BROWSER_DESKTOP_IME=fcitx5`,Ctrl+Space 切换;与本机输入法同时开会重复组字,缺省关闭。
@@ -674,3 +687,16 @@ camofox 按 **API 调用**判断活动,有三道空闲回收(`docker-compose.yml
| 日期 | 做法 | 结果 |
| --- | --- | --- |
| 2026-09-30 | 临时容器 `umt-cf2-camofox`(镜像 `umt-browser-desktop:1.17.0`,只读挂载新插件目录),容器内 node 起两个本地页面:父页 `localhost:8001`(标题 Just a moment...)内嵌**跨域** iframe `localhost:8002`(复选框,`change` 事件 `isTrusted` 才向父页 postMessage);适配器 `openSession` → `pageContent` → `click({x, y})` → `pageContent` | 插件路径:`POST /umt/tabs/{id}/mouse-click` 命中复选框,iframe 里收到可信事件,父页标题变为 passed;`pageContent` 读到 UA `…Windows NT 10.0; Win64; x64; rv:152.0…`。旧路径(elementFromPoint)只能标到 iframe 元素本身、按元素中心点击,点不到指定坐标。未访问任何外部站点,容器已删除 |
## 16 2026-10-01 的 1.18 升级复测
当前默认桌面镜像为 `umt-browser-desktop:1.18.0`,基础镜像 `camofox-browser:1.18.0` 锁定上游 `f94c81babf4bfd44cdd4bd46e1f2e1fb1d91c753`。Node 24.21.0、Camoufox 152.0.4-beta.30、camoufox-js 0.12.0;Playwright 保持官方协议可兼容的 1.60.0,原因和独立锁见 [构建说明](../../docker/camofox/README.md)。
用生产 profile 与桌面配置的独立副本验证了鉴权、原身份保持、Cookie 正常重启落盘、上下文/页面、evaluate、快照、PNG、选择器与可信坐标点击、profile 隔离。现有真实 BrowserService/Agent 能力核验脚本 `scripts/browser-verify/verify.ts` 的 setup/a/b/idle/c/d 共 25 项严格通过,包含登录、脱敏、提取、下载文件哈希及资源关联、正常重启与空闲回收自动重连、旧引用拒绝、SIGKILL 未落盘登录丢失识别。适配器能力表现已登记 1.18.0 的原十项能力,未知版本不继承核验结果。
完整执行与恢复/清理状态见 [升级记录](../plan/17-full-upgrade.md),机器可读结果见 [验证证据](../plan/evidence/2026-10-01-dependencies/upgrade-verification.json)。这些检查不增加真实 PT 挑战、ARM64 或精确 URL 恢复的验收声明。SIGKILL/OOM 后仅能使用上次落盘状态的限制继续保留。
### 桌面上下黑边排查记录
2026-10-01 已修复底座初始化脚本生成无效 labwc XML 的问题;部署镜像为 `umt-browser-desktop:1.18.0-umt.1`。初始化在 `init-selkies-config` 完成后写入完整 XML,浏览器窗口自动最大化。实际视频尺寸与前端 iframe 同为 1280×900;前后串流截图确认上下黑边消失。若需要调整桌面尺寸,可改 `BROWSER_DESKTOP_WIDTH/HEIGHT`,不要以拉伸或裁剪视频修正窗口布局。证据见 [发布记录](../plan/18-organize-release.md#v0311-搜索详情与桌面黑边修复)。
+45 -27
View File
@@ -1,18 +1,18 @@
# 部署运行手册(W4-B)
形态:**除 PostgreSQL 外全部在一个容器里**。镜像 `uhd-media-tool` 内一个 `deno compile` 出的二进制 `umt-server`,
形态:**核心应用在一个容器里,PostgreSQL 与浏览器分别部署**。镜像 `uhd-media-tool` 内一个 `deno compile` 出的二进制 `umt-server`,
容器里同时跑 api、worker(io 组)、worker:agent(Agent 会话)三个进程,api 同端口托管 web 静态产物(`WEB_ROOT=/app/public`),对外只有 **4380** 一个端口。
compose 有三个服务:`app` + `postgres` + `camofox`(浏览器服务,只在内网,不映射端口;可关掉或换成自有实例,见 §2.1)。
compose 默认有三个服务:`app` + `postgres` + `camofox`(浏览器服务,只在内网,不映射端口;可关掉或换成自有实例,见 §2.1);`tls` profile 可额外启用 Caddy 提供 HTTPS。
## 1. 构建镜像
```sh
docker build -t uhd-media-tool:latest . # 或 docker compose build
APP_VERSION=v0.1.0 docker compose build # 版本号写进 web 的 version.json
docker build -t uhd-media-tool:latest . # 或 docker compose --env-file .env.deploy build
APP_VERSION=v0.3.11 docker compose --env-file .env.deploy build app # 示例:发布时填写对应版本,写进 web 的 version.json
```
- 多阶段:`denoland/deno:2.9.7`(装依赖 → web 构建 → server 编译)→ `debian:trixie-slim` 运行镜像。
- 运行镜像只额外装 `gosu`(降权)与 `postgresql-client`(备份/恢复用 pg_dump/pg_restore/psql,17 版客户端兼容 16 版服务端),
- 运行镜像额外装 `gosu`(降权)及 PG 客户端动态库,从固定的 `postgres:18.6-trixie` 官方镜像复制 pg_dump/pg_restore/psql 与 libpq 18,
外加 `/usr/local/bin/ffprobe`:从 `mwader/static-ffmpeg:9.0.2` 拷单个静态二进制(约 135 MB;Debian `ffmpeg` 包要 200+ 个依赖约 450 MB)。
换来源用 `--build-arg FFPROBE_IMAGE=<含 /ffprobe 的镜像>`。
- `/app` 下的二进制、静态产物、脚本全部 root 属主只读;运行用户改不了它们。
@@ -27,32 +27,33 @@ APP_VERSION=v0.1.0 docker compose build # 版本号写
## 2. 启动
部署目录须包含完整仓库构建上下文。首次启用默认浏览器前,先完成 [浏览器手册 §1.1](browser.md#11-部署自带缺省) 的基础镜像构建,再执行以下 compose 命令。部署配置统一放 `.env.deploy`,开发配置仍用仓库根 `.env`。
```sh
mkdir -p /opt/umt && cd /opt/umt # 部署目录(放 docker-compose.yml 与 .env)
mkdir -p /opt/umt && cd /opt/umt # 部署目录(完整仓库构建上下文与 .env.deploy)
cp <仓库>/docker/compose.env.example .env.deploy # 部署配置独立于开发用 .env
sed -i "s/^SECRET_MASTER_KEY=.*/SECRET_MASTER_KEY=$(openssl rand -hex 32)/" .env
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$(openssl rand -hex 16)/" .env
sed -i "s/^SECRET_MASTER_KEY=.*/SECRET_MASTER_KEY=$(openssl rand -hex 32)/" .env.deploy
sed -i "s/^POSTGRES_PASSWORD=.*/POSTGRES_PASSWORD=$(openssl rand -hex 16)/" .env.deploy
docker compose --env-file .env.deploy up -d --build
docker compose ps # app 变成 healthy 即可访问
docker compose --env-file .env.deploy ps # app 变成 healthy 即可访问
curl -s localhost:4380/api/v1/health
```
### 2.1 浏览器服务(camofox)
缺省随栈起一个 camofox-browser 容器(jo-inc/camofox-browser **v1.17.0**,commit `389c996`),给原站视图与 Agent 浏览器能力用。
缺省随栈起一个 camofox-browser 容器(jo-inc/camofox-browser **v1.18.0**,commit `f94c81b`),给原站视图与 Agent 浏览器能力用。
app 启动时按 `BROWSER_PROVIDER_URL`(缺省 `http://camofox:9377`)自动登记名为 `camofox-env` 的浏览器服务,
`depends_on` 只要求已启动、不等健康:camofox 挂了 app 照常运行,界面标"浏览器不可用"。
- **镜像**:上游不发布镜像,compose 用 `docker/camofox/Dockerfile` 从锁定的 git tag 构建(修了上游 v1.17.0 Dockerfile 的
构建错误与信号转发,见文件头注释)。首次 `up --build` 要拉 GitHub 源码与约 630 MB 的 Camoufox 浏览器包,
镜像约 3.6 GB;国内网络按 `docs/runbook/browser.md` §1 先在本机构建同名镜像 `camofox-browser:1.17.0`,之后 compose 直接复用。
- **访问凭据**:`.env` 里设 `CAMOFOX_ACCESS_KEY`(`openssl rand -hex 24`),camofox 与 app 共用;不设则内网免认证。
- **资源**:空闲约 200 MB(浏览器空闲 5 分钟自动退出后更低);每个站点会话一个 BrowserContext,
`mem_limit` 缺省 2g、`shm_size` 2gb(Firefox 多进程需要)。
- **镜像**:上游不发布镜像。先按 [浏览器手册 §1.1](browser.md#11-部署自带缺省),用 `docker/camofox/Dockerfile` 构建基础镜像 `camofox-browser:1.18.0`(锁上游 git tag,修正构建与信号转发)。
compose 再用 `docker/browser-desktop/Dockerfile` 从该基础镜像构建默认桌面镜像 `umt-browser-desktop:1.18.0`。基础镜像首次构建需要 GitHub 源码和约 630 MB 的 Camoufox 包;桌面层复用浏览器包。
- **访问凭据**:`.env.deploy` 里设 `CAMOFOX_ACCESS_KEY`(`openssl rand -hex 24`),camofox 与 app 共用;不设则内网免认证。
- **资源**:当前默认桌面镜像 `mem_limit` 为 3g、`shm_size` 为 2gb;每个站点会话一个 BrowserContext,另有桌面常驻进程。
早期约 200 MB 的空闲测量属于纯截图镜像,不能直接作为桌面模式的内存基准。
- **登录状态**:按站点/账号存在卷 `umt-camofox`(`/root/.camofox/profiles`,cookies + localStorage),
在会话空闲回收、关闭会话与 `docker compose stop/restart`(SIGTERM)时落盘;**容器被 SIGKILL / OOM 杀掉时,
在会话空闲回收、关闭会话与 `docker compose --env-file .env.deploy stop/restart`(SIGTERM)时落盘;**容器被 SIGKILL / OOM 杀掉时,
上次落盘之后的新登录会丢**(需重新登录)。
- **接自有实例**:`.env` 里 `BROWSER_PROVIDER_URL=<地址>`、`BROWSER_ACCESS_KEY=<它的 CAMOFOX_ACCESS_KEY>`、`CAMOFOX_REPLICAS=0`。
- **接自有实例**:`.env.deploy` 里 `BROWSER_PROVIDER_URL=<地址>`、`BROWSER_ACCESS_KEY=<它的 CAMOFOX_ACCESS_KEY>`、`CAMOFOX_REPLICAS=0`。
- **不要浏览器**:`CAMOFOX_REPLICAS=0` + `BROWSER_ENABLED=false`。
**SECRET_MASTER_KEY** 生成一次后不再更换:站点 Cookie、下载器密码、模型 API Key 都用它加密存在 `secret` 表。
@@ -77,7 +78,7 @@ app 启动时按 `BROWSER_PROVIDER_URL`(缺省 `http://camofox:9377`)自动登
api 首次启动时在日志里打印一次性 setup token(重启会换新的,旧的作废):
```sh
docker compose logs app | grep 'setup token'
docker compose --env-file .env.deploy logs app | grep 'setup token'
```
浏览器打开 `http://<主机>:4380`,登录页进入初始化模式,填 token、用户名、密码(≥10 字符)。
@@ -90,7 +91,7 @@ docker compose logs app | grep 'setup token'
| `/data` | 命名卷 `umt-data`(或宿主目录) | `agent-sessions/`(Pi JSONL 会话,崩溃恢复点)、`backups/`、`exports/`(映射清单)、`tmp/`(`TMPDIR`) | entrypoint 自动 chown 给 `PUID:PGID` |
| `/media/...` | 用户 bind mount | 媒体库根:控制台 设置 → 媒体库根 登记的 `localPath` | 需对 `PUID:PGID` 可读写;**不会被自动 chown** |
| `/downloads/...` | 用户 bind mount | 下载缓存:路径映射的 local 前缀(下载器报告的 remote 路径 → 容器内路径) | 同上 |
| `/var/lib/postgresql/data`(postgres) | 命名卷 `umt-pg-data` | 数据库 | — |
| `/var/lib/postgresql`(postgres) | 命名卷 `umt-pg18-data`,内部 `18/docker` | PG18 数据库;旧16卷不能直接挂入 | — |
| `/root/.camofox`(camofox) | 命名卷 `umt-camofox` | 浏览器登录状态(`profiles/`,按站点/账号)、上游 cookies/uploads/traces 目录 | — |
- 媒体目录在 `docker-compose.yml` 的 `app.volumes` 里取消注释或另写 `docker-compose.override.yml`:
@@ -106,7 +107,7 @@ docker compose logs app | grep 'setup token'
- bind mount 的相对路径按**第一个 compose 文件所在目录**解析,不是按当前目录;不确定时写绝对路径。
源目录不存在时 Docker 会以 root 属主新建它,库根登记就会因哨兵写不进而失败。
- 路径映射:下载器容器里看到的是 `/downloads/complete/...`,本容器也挂成 `/downloads` 时 remote 前缀与 local 前缀相同;
挂到别处就登记 `remote_prefix=/downloads`、`local_prefix=<本容器内路径>`。硬链接要求下载目录与库根在同一文件系统、同一挂载点内。
挂到别处就登记 `remote_prefix=/downloads`、`local_prefix=<本容器内路径>`。目前整理只支持复制和移动。
- 登记库根时服务端会在目录里写哨兵文件 `.uhd-root`,写不进去直接 400(提示检查挂载与属主)。
- **PUID/PGID**:设成宿主媒体目录的属主(`stat -c '%u:%g' /srv/media`)。改 PUID/PGID 后重启容器,entrypoint 会把 `/data` 重新 chown。
也可以 `docker run --user` 直接指定(此时跳过 chown,`/data` 需事先可写)。
@@ -141,25 +142,30 @@ docker compose logs app | grep 'setup token'
## 6. 升级
发布前检查旧镜像的实际在途任务:在任务页核对 queued / running / waiting,尤其是本次变更的任务名称和版本。优先等它们完成;需要中止的任务先保留原输入、冻结计划和操作记录,确认中止后通过现有入口重新发起。已经产生文件操作证据的任务要先核实执行结果,再决定后续处理。没有旧在途任务时不长期保留旧 handler;业务表前滚不能替代任务版本兼容判断。
本次整理来源功能增加 `scanOrganizeSource@1` 和迁移 `0059_organize_source_snapshot`,沿用 `verifyAndImport`。迁移不会扫描或整理已有目录;用户新增来源后先建立基线,存量必须单独触发。
```sh
cd <仓库> && git pull
docker compose exec app umt backup # 升级前先备份
docker compose --env-file .env.deploy exec app umt backup # 升级前先备份
docker compose --env-file .env.deploy up -d --build app # 重建镜像并替换容器;启动时自动迁移
docker compose ps && docker compose logs --tail=50 app
docker compose --env-file .env.deploy ps && docker compose --env-file .env.deploy logs --tail=50 app
```
迁移只前滚。升级失败要回退时:用旧镜像 + 升级前的备份恢复(见 [backup-restore.md](backup-restore.md)),不要用旧镜像直接连新库。
## 7. 日志与排障
- `docker compose logs -f app`:pino JSON,一行一条;worker 日志带 `group`(io / agent)。
- `docker compose --env-file .env.deploy logs -f app`:pino JSON,一行一条;worker 日志带 `group`(io / agent)。
- `worker 事件循环延迟超过阈值`(warn,`lagMs`):worker 主线程被同步重活占住超过 5s,租约续期可能受影响,带上前后日志排查。json-file 驱动,单文件 10 MB × 5 份。
- entrypoint 自身的输出(`entrypoint: ...`)说明哪个进程先退出、退出码多少。
- 自检失败(`check=data_dir`):`/data` 卷不可写,检查是否挂了只读卷或 `--user` 与卷属主不一致。
- 挂载路径告警(`挂载路径不可用`):看审计页 `preflight.path_unavailable` 事件,核对 bind mount 与 PUID/PGID。
- 进容器排查:`docker compose exec app bash`(root);以运行用户执行命令用 `gosu 10001:10001 <cmd>`。
- 一次性子命令:`docker compose exec app umt migrate|preflight|export-mappings|backup`、
`docker compose run --rm --no-deps app restore <备份>`。
- 进容器排查:`docker compose --env-file .env.deploy exec app bash`(root);以运行用户执行命令用 `gosu 10001:10001 <cmd>`。
- 一次性子命令:`docker compose --env-file .env.deploy exec app umt migrate|preflight|export-mappings|backup`、
`docker compose --env-file .env.deploy run --rm --no-deps app restore <备份>`。
## 验证记录
@@ -303,3 +309,15 @@ API Key 在 qB 5.2+ WebUI 选项 → WebUI → API Key 处生成 / 轮换(等价
- 实测矩阵(`packages/adapters/src/qbittorrent/qbittorrent.real.test.ts`,设 `QB_REAL` 才跑):5.1.2 账密 / 无认证 / 失败分类,
5.2.4 账密 / API Key / 无认证 / 失败分类,各跑 登录 → 添加(testkit `makeTorrent({ realPieces: true })` 真实 piece 哈希,
内容写进保存目录,qB 校验即完成)→ 查询 → 标签 → 暂停恢复 → 删除(不删数据)。
## v0.3.10 发布补充
2026-10-01 已发布 v0.3.10,执行 `0060_manual_acquisition`:`acquisition_plan.slot_id` 允许为空,支持独立手动下载;`download_task.import_plan_id` 保存本次入库规划,并以外键引用计划。部署前备份与校验通过,只替换 app 容器;线上接口、版本一致及页面冒烟通过。后续普通 Compose 启动使用已更新的 `.env.deploy` 版本与源码标记。具体证据见 [发布记录](../plan/18-organize-release.md#v0310-手动下载与入库发布)。
### 当前测试入口
用户要求测试自签 HTTPS 后,4380 已由 Caddy 接管为 `https://服务器地址:4380`;原 443 入口保留,app 本机 HTTP 调试入口为 `http://127.0.0.1:4381`。配置保存在 `.env.deploy` 与本机 `docker-compose.override.yml`,重建了 app/Caddy 容器,镜像及数据库版本保持 v0.3.10/0060。证书由原 Caddy 内部 CA 签发,健康、管理员接口和 HTTPS 页面冒烟通过。
## v0.3.11 修复发布
搜索结果标题接入已有资源详情抽屉,已发布 v0.3.11;数据库保持 `0060`。浏览器桌面修复镜像为 `umt-browser-desktop:1.18.0-umt.1`,内置有效的最大化配置,已验证上下黑边消失。`.env.deploy` 已记录当前应用版本、源码标记和浏览器镜像,4380 HTTPS/443 HTTPS/本机 4381 HTTP 映射保留。具体验证见 [发布记录](../plan/18-organize-release.md#v0311-搜索详情与桌面黑边修复)。
+1
View File
@@ -109,6 +109,7 @@ ci 逐行核对这张表与任务注册表(`apps/server/test/worker-lanes.test.t
| `refreshPiTokens` | network | 模型服务 OAuth 令牌刷新 |
| `reconcileLibrary` | maintenance | 资产对账(扫库) |
| `purgeTrash` | maintenance | 回收站到期清除 |
| `scanOrganizeSource` | maintenance | 整理来源基线与增量快照,候选整理进入文件道 |
| `runAgent` | agent | Agent 会话(worker:agent) |
| `resolveDecision` | agent | 决策处理(worker:agent) |
+1 -1
View File
@@ -32,7 +32,7 @@
| delete | 默认回收站:`<根>/.umt-trash/<yyyymmdd>/<uuid>/<原相对路径>`(同卷 rename);根不可写/跨卷 → `DATA_DIR/trash/...` 复制(上限 `FILES_TRASH_CROSS_MAX_BYTES`,默认 2 GiB,超出请永久删除)。引用检查:纳管任务未完成或 H&R 未满足 409;已登记资产需 `retireAssets`(location→removed、asset 无其他位置→retired、满足的 Slot→attention + 待处理);绑定目录需 `unbind`(→superseded);根本身/只读根拒绝;离线 503。永不连带下载器任务。执行写 `organization_record(action=trash|delete)`,文件级结果(目录展开到 2000 个文件,超过只记目录一行),返回 `recordId` |
| 永久删除 | `FILES_ALLOW_PERMANENT_DELETE=true` 才可用,且仅管理员会话;单项需 `confirmName` = 文件名 |
| 回收站 | `GET /files/trash`;`restore`(原位被占 → 该项 `exists`,可带 `target` 还原到别处;还原不恢复资产状态,需要时重新整理登记;有成功项时写 `organization_record(action=restore)`,返回 `recordId`);`purge` 仅管理员会话,缺省只清过期项。"还原到…"的目标必须是可写的 managed 库根(否则 403 `not_writable`);原位还原时缺失的父目录在根内逐级重建(已存在的必须是真目录,符号链接拒绝 `path_escape`);跨卷还原受 `FILES_TRASH_CROSS_MAX_BYTES` 上限(超出该项 `too_large`),复制经 fsproxy。持久任务 `purgeTrash` 每日入队(`FILES_TRASH_RETENTION_DAYS`,默认 7);清除前复核行仍存在,且路径必须在某根的 `.umt-trash` 或 `DATA_DIR/trash` 下 |
| identify | 只读:`parseReleasePath`(文件 + 父/祖父目录)→ 本地召回(别名 pg_trgm + 外部身份)→ `catalog.lookup` 能力取远端候选(经进程共享的 TMDB 信号量与 15 s 超时;单次请求去重后最多 20 个远端查询,超出的项只本地召回并给 warning;失败只给 warning)→ `rankCandidates` 前 5;目录展开视频上限 200;不建作品、不进待识别池 |
| identify | 默认先本地解析并入队 `identifyRemote`,以下远端查询过程描述 `?wait=true` 的同步模式(默认异步结果经 SSE / 复查获取)。 只读:`parseReleasePath`(文件 + 父/祖父目录)→ 本地召回(别名 pg_trgm + 外部身份)→ `catalog.lookup` 能力取远端候选(经进程共享的 TMDB 信号量与 15 s 超时;单次请求去重后最多 20 个远端查询,超出的项只本地召回并给 warning;失败只给 warning)→ `rankCandidates` 前 5;目录展开视频上限 200;不建作品、不进待识别池 |
| probe | 需要 `organize.execute`;≤20 项;已登记资产写回 `media_asset.media_info.probe`;未登记缓存 24 h(`DATA_DIR/cache/probe`) |
| scrape | SCR-2 照 MP:任意视频文件或目录就地刮削(不要求已登记):已登记目录用其作品,否则按路径识别(本地 + TMDB),认不准返回 `needsChoice` 候选,选定后带 `mediaEntityId` / `external` 再提交;`addToLibrary` 顺手建作品;每项一条刮削记录,排 `scrapeMedia`,请求内最多等 `FILES_TRANSFER_WAIT_SEC`;`GET /files/scrape-records?ids=` 回查。只登记库根跳过。见 `scrape.md`。界面「刷新元数据」只刷字段(`scrape-batch`),「刮削…」走 `/files/scrape` |
| download | `GET /files/download?root=&path=&inline=`:仅管理员会话(API Key 含 admin scope 也 403);只允许 NFO/字幕/图片(视频 403),≤ `FILES_DOWNLOAD_MAX_BYTES`(默认 20 MiB,超出 413 `too_large:`);路径守卫同其它接口,打开前再 realpath 复核、按文件句柄 stat;流式返回(非 JSON 信封),`inline=true` 仅对图片生效(SVG 一律附件),带 `nosniff` + `CSP sandbox`;写审计 `files.download` |
+1 -1
View File
@@ -46,7 +46,7 @@ curl -s -X POST https://umt.example.lan/api/v1/mcp \
| resources | `umt://settings/summary`(自动化开关、预算、Agent 上限,不含凭证)、`umt://decisions/pending`(未结束的待处理,最多 50 条)、`umt://subscriptions/overview`(各状态计数 + 最近 20 个订阅);需要 `read` scope |
| prompts | `triage_pending`、`acquire_title(title, year?)`、`diagnose_task(taskId)` |
工具可见性(`mcpToolVisible`):Key 的 scope 覆盖能力的 scope;没有 `organize.execute` / `admin` 时只给 read / preview 类。`agent.*`(派生子会话等)只在 Agent 会话内可用,不经 MCP 暴露。当前能力集下:`read` 9 个,`read + organize.execute` 18 个,`admin` 23 个(界面「可见工具」按实时注册表计算)。
工具可见性(`mcpToolVisible`):Key 的 scope 覆盖能力的 scope;没有 `organize.execute` / `admin` 时只给 read / preview 类。`agent.*`(派生子会话等)只在 Agent 会话内可用,不经 MCP 暴露。当前 41 个能力下:`read` 18 个,`read + organize.execute` 28 个,`admin` 37 个(2026-10-01 按 `mcpToolVisible` 核对;界面「可见工具」按实时注册表计算)。
## 安全边界:MCP 不绕过授权
+67 -10
View File
@@ -1,12 +1,56 @@
# 整理记录(`/console/organize`,HIS-1)
# 媒体整理(`/console/organize`)
整理记录页列出每次整理(复制 / 移动 / 硬链接)以及文件管理的改名、删除、还原。HIS-1 按 MoviePilot 历史记录页逐项补齐。
原地入库为 v0.3.14 的待部署改动;当前生产 v0.3.13 的整理方式仍为复制/移动,独立就地刮削继续可用。
整理页分为「整理队列」与「整理记录」。队列显示等待、执行和等待继续的后台入库任务;记录显示复制/移动/原地入库的处理结果。文件管理的改名、删除、还原账本继续保存,通用记录接口仍可查询。
实现:
- 列表 / 统计 / 详情:`apps/server/src/modules/acquisition-organize/routes/organization.ts`(筛选 `recordFilters`,通配 `likePattern`);公开字段在 `services/organize.ts` 的 `loadRecordsPublic`。
- 删除:`apps/server/src/modules/file-manager/record-delete.ts`(复用文件管理删除 `deleteFiles`)。
- 契约:`packages/contracts/src/organization.ts`(`OrganizationListQuery`、`OrganizationStats*`、`OrganizationDelete*`),端点 `Api.organization.stats / remove`。
- 前端:`apps/web/app/routes/console/organize.tsx`、`organize.$id.tsx`,`components/organize/`(删除确认框、标题 / 季集小件),批量重新整理走整理向导的 `{ kind: "records" }` 来源。
- 前端:`apps/web/app/routes/console/organize.tsx`、`organize.$id.tsx`,`components/organize/`(删除确认框、标题 / 季集小件),批量重新整理走共用整理弹窗的 `{ kind: "records" }` 来源。
## 统一整理弹窗(v0.3.13)
手动选目录、文件管理器、下载详情与历史重新整理打开同一个弹窗。单文件只处理该文件,目录递归展开视频,多选合并去重。媒体类型可自动、电影或剧集;作品可自动识别、搜索本地/TMDB,也可选定类型后输入 TMDB ID 定位。手动指定作品与季号作用于整个本次范围,混合批次中需单独纠正的作品另行选取;文件明细可核对和修正季集、排除文件,没有另一套批量勾选语义。
各入口匹配相同来源配置,唯一匹配自动带出方式和分类/目标,多个匹配在弹窗内选定;不使用来源配置时沿用全局默认并手动指定。下载详情优先按已有 qB 标签匹配覆盖当前路径的来源。历史原配置仍覆盖可用输入时优先采用;成功移动后的目标不再属于旧来源时显示当前匹配配置或手动选项。
本次可选择原地入库、复制或移动。复制/移动可调整目标媒体库或具体目录、命名、目标冲突及整理后刮削。刮削默认沿用全局配置,显式开关只影响本次;整理成功的文件再进入现有 NFO/图片任务,TMDB 和 Local 均适用。做种义务未满足时不提供移动,复制与原地登记不改变视频文件,服务端继续核对实际状态。
手动来源发现真正成功历史时显示数量及「跳过成功记录」,**默认关闭**,开启后仅本次跳过;失败/部分成功记录不算完整成功,最新失败也不会遮盖较早成功。目标已存在策略单独处理。从历史记录进入直接采用重新整理语义。修改识别或选项后旧预览失效,需重新生成。
确认预览后只提供「加入整理队列」。后台受理成功后弹窗自动关闭,可以继续操作,进度到队列查看,整理后的刮削任务也显示在队列,整理详情单独展示刮削结果;部分受理时已受理文件从本次范围移除,剩余文件可修改后再预览提交。队列复用现有后台调度,不要求浏览器停留到文件处理结束。记录、队列及弹窗明细均复用统一分页。
## 来源、分类与存量整理
设置 → 媒体库与目录中维护分类 YAML 和整理来源。新功能已于 2026-10-01 部署为 v0.3.9,迁移 `0059_organize_source_snapshot` 已执行,见 [发布记录](../plan/18-organize-release.md)。
- 一条来源配置选一个来源目录、一个媒体库目标目录、复制或移动方式。通过弹窗浏览已登记的目录选择,不需要填写宿主机任意路径。不同来源可以使用相同分类,规则只维护一次。
- 分类一级固定为 `movie` / `tv`。规则按顺序首次匹配;同一规则的字段同时满足,同字段逗号值为任一匹配,`!` 排除。`release_year` 支持年份或区间;原始 TMDB 详情的一级字段也可使用。
- 空条件是兜底,应放在最后。默认保留「欧美电影」「欧美剧集」承接所有未命中的习惯。TV 默认顺序为儿童剧集、动漫剧集、纪录片、综艺、华语剧集、亚洲剧集、欧美剧集。尚未取得 TMDB 详情不能冒充分类成功。
- 自动分类在目标目录下追加分类目录,再使用现有作品/季目录模板。固定分类直接以所选目标为分类目录,避免追加第二遍分类名称。预览显示完整目标路径。已有作品沿用路径绑定,保存新规则不会移动旧库。
- YAML 保存后用于后续计划,重启保留;语法或目录名不合法时拒绝保存,已有规则保留。
来源触发方式可以选手动、qB 标签或目录快照。qB 标签同时限定下载器实例和来源范围;只有完成的任务进入整理,去掉标签后停止接管,已有管理标签继续有效。
新增来源或更改来源路径时,先将当前视频文件记录为基线,**这些文件不会因此自动入库**。快照持久化在数据库,重启保留。后续新增或改变的文件,在连续两次扫描确认大小和修改时间稳定后再处理。已知 qB 任务由下载器接管流程负责,避免两种触发重复整理。下载器目录会查询当前全部 qB 任务,即使未打标签、尚无数据库任务行,也会等下载完成。下载器不可达或目录读取失败会记录错误并保留此前快照。
「整理存量」是可重复触发的一次性扫描:排除同一源文件事实已成功整理的文件及未完成下载,历史部分成功中的失败文件、同路径发生变化的文件仍可选,候选进入同一个整理弹窗,确认识别、操作和完整目标路径后执行。单次候选按识别上限分批;完成后再次触发可处理余下文件。这个操作不重建或清空基线。识别不确定时也可打开现有智能助手协助判断,再加入整理队列。
文件管理器选中文件或目录后点「整理」,会读取来源配置并按同根、目录边界和最长来源路径匹配所选全部项目。唯一匹配自动带入复制/移动方式、分类和目标策略;多个同等匹配让用户选择,也可不用配置手动指定。不同来源混合选择或没有匹配时使用共用整理弹窗的手动选项。媒体类型在预览时核对,配置目标可由本次明确的目标选择覆写。
实现复用既有识别、冻结计划、文件操作账本、整理记录与任务引擎;未增加软链接、硬链接或另一套 AI 执行流程。
## 手动下载、Local 元数据与一次性洗版(已部署 v0.3.10)
搜索、站点工作台和原站详情均可独立下载,不要求订阅。下载时默认正常入库,也可选择一次性洗版并勾选旧版本;只有一个旧版本时默认选中,多个由用户选择。媒体详情与下载窗口展示已有文件和规格。正常入库保留已有版本;不同版本路径由可编辑的命名模板决定,同名冲突仍需处理。
未识别资源确认后允许下载。整理时先匹配 TMDB,再由现有网络/Agent 元数据补全能力核对译名、原名和别名;能够找到正确条目时回到 TMDB,找不到且详情资料充分时使用 Local 身份。Local 共用现有分类、命名、复制/移动和 NFO/图片任务,并保留字段来源;信息不足或候选冲突保留待处理。Agent 搜寻依赖已配置的模型/搜索能力和现有每日补全预算;没有封面资料时不会虚构图片。Local 入库安排元数据文件写入,普通 TMDB 自动刮削保持原设置。
洗版在本次冻结计划中保存选中的旧文件。新文件核验登记成功后才清理所选旧版本,剧集只处理成功对应的季集与 Part;覆盖不完整的合并集保留。相同目标路径会先暂存旧文件,失败后恢复。旧版的私有字幕等随之清理,共享 NFO/图片、未选版本及下载缓存保留;按现有文件替换设置移入回收站或删除。
关联迁移 `0060_manual_acquisition`,已于 2026-10-01 随 v0.3.10 发布执行。业务依据与验收见 [MP 对照 §5.6](../plan/15-moviepilot-v3-comparison.md#56-本轮实现与验收已部署-v0310)。
## 与 MP 的对照
@@ -16,13 +60,13 @@ MP 对照源:`MoviePilot-Frontend/src/views/reorganize/TransferHistoryView.vue`
| --- | --- | --- |
| 海报 | 新增 | 作品海报(`media.posterPath`),没有时显示首字占位 |
| 标题 / 年份 / 季集 | 已有 | `作品 (年) S01E02`;未识别的显示「未识别 · 源文件名」 |
| 二级分类(华语电影等) | 不做 | 我们没有二级分类;按类型(电影 / 剧集)筛选代替 |
| 二级分类(华语电影等) | 已接入 | 分类规则在设置编辑 YAML;电影 / 剧集为母分类,综艺属于剧集 |
| 源路径 → 目标路径 | 新增 | 列表加「源 → 目标」列(只显示末两段,悬停看全路径);详情「整理前 / 整理后」已有 |
| 存储标签(本地 / SMB…) | 不做 | 只有本地存储,标签不提供信息 |
| 整理方式 复制 / 移动 / 硬链接 | 已有 | 列表「方式」列;文件管理的改名、移入回收站、还原也在这里 |
| 整理方式 复制 / 移动 | 已有 | 列表「方式」列;整理页聚焦复制/移动结果 |
| 软链接、Rclone 复制 / 移动 | 不做 | 整理服务不支持这几种方式 |
| 大小 | 新增 | 逐文件源大小之和(`sizeBytes`) |
| 状态 成功 / 失败 + 失败原因 | 已有,改 | 加「部分成功」「执行中」;成功不加徽章;失败原因走 `reasons.ts` 一句话,原码进详情「技术信息」 |
| 状态 成功 / 失败 + 失败原因 | 已有,改 | 支持「部分成功」;执行中任务在队列查看;成功不加徽章;失败原因走 `reasons.ts` 一句话,原码进详情「技术信息」 |
| 时间 | 已有,改 | 相对时间,悬停看完整时间 |
| 来源 下载器 / 手动 / 自动 | 新增下载器 | 来源列加下载器名称;详情加「下载任务」一行,种子 hash 进「技术信息」 |
| 关键字搜索(标题、源、目标;`*` `?` 通配) | 已有,补 | 补通配、逐文件的源 / 目标路径、种子 hash |
@@ -31,17 +75,17 @@ MP 对照源:`MoviePilot-Frontend/src/views/reorganize/TransferHistoryView.vue`
| 类型筛选 | 新增 | 电影 / 剧集 / 未识别(`kind=movie\|series\|none`) |
| 时间筛选 | 新增 | 今天 / 最近 7 天 / 最近 30 天(`since`)。MP 没有,任务单要求 |
| 统计(总数 / 成功 / 失败) | 新增 | 列表上方一行计数,只列非零项,点一下按该状态筛选(`GET /organization-records/stats`) |
| 分页、每页条数 | 已有(不同) | 游标「加载更多」,MP 手机端同样是触底加载;不做页码与每页条数 |
| 分页、每页条数 | 已有(不同) | 共享分页组件,10/20/50/100 条和翻页;游标按需加载,无总数时显示「已加载」 |
| 列排序 | 不做 | 按时间倒序;分组模式下按作品聚合 |
| 分组模式(按标题) | 新增 | 「按作品分组」,组头可折叠 |
| 筛选写进地址栏 | 新增 | 状态 / 类型 / 来源 / 时间 / 关键字 / 分组都在 URL,刷新不丢 |
| 单条:重新整理 | 已有,补 | 详情已有;列表行菜单新增。走整理向导(识别 → 选项 → 预览执行) |
| 单条:重新整理 | 已有,补 | 详情已有;列表行菜单新增。走共用弹窗(配置、展开预览、加入队列) |
| 单条:智能助手整理 | 已有(不同) | 「让智能体排查」:失败 / 部分成功的记录在行菜单和详情里 |
| 单条:删除(只删记录 / 连源文件 / 连媒体库文件 / 全部) | 新增 | 确认框里两个勾选项,先核对再执行,写清删几个文件、多大、哪些删不了、会不会被自动整理再处理 |
| 查看详情 | 已有 | 详情加海报、大小、下载任务、删除按钮 |
| 批量选择 / 全选 | 新增 | 「批量」进入选择模式,表头全选 |
| 批量删除 | 新增 | 同单条删除确认框;删不了的逐条列出,其余照删 |
| 批量重新整理 | 新增 | 选中记录的源文件一起进整理向导;同属一个作品时预选作品 |
| 批量重新整理 | 新增 | 选中记录的可用文件一起进整理弹窗(成功移动取目标,其他取源);同属一个作品时预选作品 |
| 清空整理记录 | 不做 | 整理记录同时是文件变更的追溯记录;清理按保留期由计划页负责 |
## 删除
@@ -50,7 +94,7 @@ MP 对照源:`MoviePilot-Frontend/src/views/reorganize/TransferHistoryView.vue`
- 文件一律移入回收站,走文件管理删除(`deleteFiles`,mode=trash,`retireAssets=true`):已入库文件同时从媒体库移除(位置 removed、资产 retired、满足的收录版本转需关注 + 待处理)。回收站里能还原。
- 源文件 = 该记录逐文件结果的 `source_path`(只认执行进程本地视图);媒体库文件 = 成功文件的 `target_path`(相对库根时按库根拼)。已经不在的文件跳过、不拦。
- 只有复制 / 移动 / 硬链接记录有文件可删;改名、移入回收站、还原类记录只删记录本身。
- 只有复制 / 移动 / 原地入库 / 硬链接记录有文件可删;改名、移入回收站、还原类记录只删记录本身。
- 一条记录的任一文件不能删(做种未满足或下载中 `download_active`、绑定目录 `needs_unbind`、不在登记目录 `outside_roots`、目录离线等),这条记录连同它的文件都不动;还在整理的记录(`running`)不删。其余照删。
- 文件移入回收站会写一条「移入回收站」整理记录(同文件管理删除),`trashRecordId` 返回它。
- 下载器里的任务不删(同文件管理删除原则)。
@@ -63,3 +107,16 @@ MP 对照源:`MoviePilot-Frontend/src/views/reorganize/TransferHistoryView.vue`
- 删媒体库文件只删整理记录里的文件,目录里的 NFO、图片与空目录保留(MP 在没有剩余视频时会连目录删掉)。
- 分组只对已加载的记录生效(同 MP 分组模式)。
- 统计的「进行中」= 排队 + 执行中;点它时列表只筛执行中。
## 原地入库(v0.3.14 待部署)
文件管理器选择已登记媒体库目录中的视频或目录,进入整理弹窗,默认选择「原地入库 · 保留位置与名称」。识别作品、手动指定电影/剧集、TMDB 和季集的方式与复制/移动相同,生成预览后加入现有整理队列。
- 源与目标路径相同;不复制、不移动、不重命名,不清理媒体目录中的临时文件。配对字幕/音轨同步登记,文件名和内容保持原样。
- 登记视频资产、所在库根、实际相对路径、版本信息与季集覆盖,已有同作品资产不重复创建;不新建会改变以后整理目标的目录绑定。
- 原地模式不使用来源配置的搬运目标、命名模板或替换策略,弹窗隐藏这些选项;不支持借此洗版或替换已有文件。
- 开启「整理后刮削」时,仅针对本次成功登记的视频在原目录补写 NFO/图片,不递归刮削整个同目录或该作品的其它版本。只登记/只读库根可原地入库,刮削关闭。
- 文件必须位于已登记、启用的媒体库根;下载缓存仍使用复制/移动或独立「刮削」。希望将现有目录直接作为媒体库时,先在设置登记该目录,然后原地入库。
- 预览与入队复用原计划校验;执行时确认文件未变化,不把已经归属其它作品的文件悄悄改绑。结果标为「原地入库」,可从整理记录重新整理。
此功能代码已实现,当前生产仍为 v0.3.13;本会话不能访问 Docker 或测试 PostgreSQL,部署及真实数据库回归尚待补验,见发布记录。
+3 -3
View File
@@ -120,7 +120,7 @@
- 憨憨详情页(HH-2 按真实页面 `probe.labels` 核对):没有 `#kdescr`,内容分节为「标签 div + 相邻值 div」:`mediainfo`、`海报`、`豆瓣`(内有 `span.font-bold` 小标签 片名 / 年代 / 类别 / 导演 …)、`截图`、`种子文件`(只有「查看列表」按钮)、`发布者`、`发布时间`。对应规则:简介没有容器时取「豆瓣 / 影片信息 / IMDb」信息块,小标签补冒号、一项一行;截图取「截图」一节的 img(`data-src` 优先,海报不算截图),没有再取简介里的图;IMDb 依次取页面链接 → 简介 / 信息块 / MediaInfo 里的 `imdb.com/title/tt…` 或 `IMDB : tt…` 行(只收 `tt` + 7~8 位,不收孤立 tt 串),TMDB 取链接或 `TMDB : tv/294990` 行,豆瓣取链接或 `douban.com/subject/…`;兜底出的 IMDb / 豆瓣也回填到 `SiteRelease.imdbId / doubanId`;发布时间没有 `span[title]` 时取「发布时间 / 上传时间」字段文本。文件清单:定义 `umt.detail.page.fileListPath`(憨憨 `viewfilelist.php?id={id}`)配置了且页面上没有内联清单时,同一次详情刷新里再请求 1 次(走同一限流器、计数),失败只是没有清单。fixture `HHANCLUB_DETAIL_PAGE_2026` / `HHANCLUB_FILELIST_FRAGMENT`:标签名称与顺序来自真实页面,嵌套按已验证的标题 / 副标题结构推定,部署后打开一条憨憨资源的详情抽屉核对一次。
- 观众详情页(DET-2 按真实页面核对,样本 `packages/adapters/test/differential/inputs/detail/rl-audiences-detail-*.html.txt` 已脱敏,回归测试 `test/differential/detail.test.ts`;列表页样本 `inputs/indexer/rl-audiences-list.html.txt` 进 MP 差分):标准 rowhead 表格,但有几处与通用 NexusPHP 不同,写在定义里。h1 的促销是 `font.free / font.halfdown …`(列表是 `img.pro_*`)加「剩余时间:」和到期 `span[title]`,用 `umt.detail.promo` 覆盖列表的促销字段;h1 的「剩余时间:」文本不进标题,标题区里的 `span[title]` 也不当发布时间(发布时间取「下载」行「发布于」的 span)。没有「同伴」行,做种 / 下载 / 完成数取基本信息行右侧 `#seeders / #leechers / a[title=完成]`(`umt.detail.fields.seeders / leechers / snatched`);种子 Hash 取 `#copyTorrentHashLink[data-hash]`(`fields.infoHash`,回填 `infoHash`)。副标题行右侧有豆瓣 / IMDb / 烂番茄 / Metacritic 评分徽标(`[title*=评分]`),解析时去掉;评分本身本工具没有字段,不收。标签是 `span.detail-tag-list > span.tags`,只取最内层。上传者在「下载」行的 `span.torrent-uploader-wrap`(匿名发布为「匿名」);另有「发布者带宽」一行,所以上传者标签改为精确匹配。简介开头的站点声明 `#ad_torrentdetail` 用 `umt.detail.page.descriptionStrip` 去掉;MediaInfo / BDInfo 是 `div.codetop`(文件名 / BDInfo)+ `div.show`(摘要表或同一份 BDInfo)+ `div.hide > div.codemain`(原文),三者都从简介里去掉;简介是 `<br />\r\n`,源码换行不再算一行(以前每行之间多一空行)。截图排除豆瓣海报(站点经 `dbimgs.audiences.me/?…doubanio.com…poster` 代理)与站点横幅 `/banners/`。IMDb / 豆瓣 ID 取简介里的链接;TMDB 页面上没有;单种 H&R 标记页面上没有(列表也没有),保持「未知」。文件清单不在页面上(点「N个文件」后 AJAX 加载,端点未核对),暂不另发请求。列表副标题改取 `span.torrent-subtitle-text`(`span.torrent-subtitle-line` 里先是标签,以前副标题前面会粘着「官方中字DIY…」)。
- 截图代理的 Referer:截图与站点同根域(憨憨图床 `pic.hhanclub.net`、`proxy-cover.hhanclub.net`)时带 `Referer: <站点地址>/`(防盗链),外部图床(如 pixhost)不带;任何情况都不带 Cookie。
- 解析:`packages/adapters/src/sites/spider/detail-page.ts`。简介取 MovieClaw `detail_description_css`(缺省 `#kdescr`);MediaInfo 取定义 `umt.detail.page.mediaInfo` → 「MediaInfo」字段标签 → 简介里第一个像 MediaInfo 的引用 / 代码块;文件清单取 `umt.detail.page.files` → MovieClaw `detail_file_list_css` → 「文件列表」字段 → `#filelist` 表格,不额外请求 `viewfilelist.php`。字段标签除 `td.rowhead` 外可在 `umt.detail.page.labelSelectors` 加(憨憨:`div.font-bold.leading-6`、`span.font-bold`)。`page.probe` 记录页面上找到的字段标签,只存缓存不展示,站点改版时用来排查。馒头从 API 的 `descr`(BBCode)与 `mediainfo` 取同样的结构。
- 解析:`packages/adapters/src/sites/spider/detail-page.ts`。简介取 MovieClaw `detail_description_css`(缺省 `#kdescr`);MediaInfo 取定义 `umt.detail.page.mediaInfo` → 「MediaInfo」字段标签 → 简介里第一个像 MediaInfo 的引用 / 代码块;文件清单取 `umt.detail.page.files` → MovieClaw `detail_file_list_css` → 「文件列表」字段 → `#filelist` 表格,默认不额外请求;定义配置了 `umt.detail.page.fileListPath` 且页面没有内联清单时,按配置补请求(憨憨为 `viewfilelist.php`)。字段标签除 `td.rowhead` 外可在 `umt.detail.page.labelSelectors` 加(憨憨:`div.font-bold.leading-6`、`span.font-bold`)。`page.probe` 记录页面上找到的字段标签,只存缓存不展示,站点改版时用来排查。馒头从 API 的 `descr`(BBCode)与 `mediainfo` 取同样的结构。
## Agent 能力(W10-pre2)
@@ -135,8 +135,8 @@
- 授权:两个 execute 能力走通用授权,Agent / API Key / 后台调用必须有 `automation_grant`(`action` 为能力 ID 或 `*`),自动化总开关关闭或只读对账时一律拒绝;控制台管理员从 Web 直接调用视为人工授权。没有计划可绑定,所以不走单次审批。
- 脱敏:输出按白名单逐字段拼装,没有 `secretRef` / `sessionSecretRef` / `passkeySecretRef`、Cookie、密码、登录名、UA 与站点 `config`;凭证只给 `hasSession` / `hasPasskey` 两个布尔。测试 `apps/server/test/sources-identity/site-capabilities.test.ts` 逐项断言。
- 注册数:首批能力 17 → 21,启动断言 `assertCapabilityCount` 跟随 `CAPABILITY_IDS.length`。
- 未接:`agent/invoke-limits.ts` 的站点并发上限还没把 `site.health_check` / `site.refresh_login` 算作外部站点调用;Agent 默认只读白名单(`agent/runner.ts`)也还没加 `site.list` / `site.user_data`。两处都在 agent 模块,留给该模块的负责人。
- 注册数:这组站点能力最初将能力集由 17 扩到 21;当前完整能力集为 41,启动断言 `assertCapabilityCount` 跟随 `CAPABILITY_IDS.length`。
- Agent 默认只读白名单(`agent/runner.ts`)已包含 `site.list` / `site.user_data`;`agent/invoke-limits.ts` 的能力级站点并发上限尚未纳入 `site.health_check` / `site.refresh_login`,底层站点访问仍走站点限流。
## 出口:哪些请求走哪条(CF-2)
+7
View File
@@ -178,3 +178,10 @@ PATCH `status` 仍可直接改(旧行为),完成写 `subscription_history` 的
- 日历不做 MP 的"日历缓存预热"任务;季详情只在元数据刷新时拉。综艺按播出日期的分段单元仍只在矩阵列上标 `segment`。
- 综艺分段列(同一播出日的上/中/下拆成独立列)等身份层按分段建单元后启用;现在只在列上标 `segment`。
- 版本目标新建(`POST /acquisition-slots`)position 缺省 0,与主版本同值时按 created_at 排在后面;需要调整顺序用 slot-order。
## 本轮完成口径调整(已部署 v0.3.10)
普通订阅按下载器确认接收和目标覆盖判断完成,完成原因 `download_accepted`;Slot 与下载/整理任务仍继续记录实际下载、核验和入库状态。多目标必须全部满足,剧集只有明确季集范围才能计覆盖,未知总集数不按整个季的通配预留伪造完成。洗版订阅仍按入库结果判断。
手动搜索、工作台和原站详情下载独立于订阅,不创建假订阅,也不会占用原订阅 Slot。要对现有订阅补全仍使用上面的 Slot 补全或自动评估入口。来源与验证见 [MP 对照 §5](../plan/15-moviepilot-v3-comparison.md#5-下载入口与浏览器详情页交接讨论记录)。