Desktop 媒体存储与协议

September 8, 2026 · View on GitHub

状态:权威开发规则(authoritative) 读取时机:新增或修改图片、视频、音频、3D 模型的生成、导入、附件、缓存、 持久化、协议解析、远程传递或回收逻辑之前

本文治理 Desktop 中由 Cindy 管理副本的媒体字节。Electron 协议与进程安全另见 electron-security-and-process-boundaries.md, 数据库变更另见 database-and-migrations.md

增量适用原则:所有新媒体写入必须进入 cindy-media。历史协议和目录仅维持已有 地址兼容,不要求借普通功能改动迁移或删除存量文件。

事实来源

内容权威来源
统一入库流程apps/desktop/src/main/cindy-media/ingest.ts
内容寻址字节仓与安全解析apps/desktop/src/main/cindy-media/blobStore.ts
blob、引用和归属账本apps/desktop/src/main/cindy-media/ledger.ts
cindy-media:// 读取协议apps/desktop/src/main/cindy-media/cindyMediaProtocol.ts
引用归零与缓存回收apps/desktop/src/main/cindy-media/recycler.ts
行为与安全不变量apps/desktop/src/main/cindy-media/__tests__/

文档与实现冲突时先停下核对,不另建媒体存储或协议绕过现有契约。

哪些内容进入媒体总仓

  • Cindy 需要拥有、缓存或持久化副本的图片、视频、音频和 3D 模型,统一进入 apps/desktop/src/main/cindy-media/ 管理的内容寻址仓。
  • 用户磁盘上的原始文件如果只需就地读取,可以继续走已有受控本地文件通道;不要仅为 预览就复制一份。远程设备或 SSH 文件必须保留真实来源,不能把远程绝对路径当成本机路径。
  • docx、PDF、zip 等非媒体文件不进入媒体字节仓,继续使用已有 xdt-file 等受控文件 通道。xdt-audio 只保留播放用户本地散文件的直读职责,不作为新的托管媒体写入口。

写入与记账

  • 新写入优先调用 ingestMedia 或已有业务适配器,不新建专用媒体目录、cache store、 数据表或协议,也不在调用方重复实现“写 blob、记账、挂引用”。
  • 标准顺序是:主机核验媒体类型 → 按字节计算 SHA-256 并原子落盘 → 记录 blob → 挂业务 引用。外部、插件或远端自报的指纹、扩展名和 Content-Type 不能单独作为可信依据。
  • 持久附件或作品必须使用符合业务生命周期的引用。业务删除时只删除自己名下的引用, 不直接删除共享 blob;物理回收由 recycler.ts 根据账本统一处理。
  • isCache: true 只用于可以重新获取或重新生成的缓存。缓存一旦成为聊天历史、作品或其他 不可再生用户内容,必须沿用现有 pin/引用流程转为不可按缓存回收。
  • 零引用入仓只适用于已有草稿或生成结果提交链路。新增零引用窗口时,必须证明内容在消息 落库前不会被回收,并用测试覆盖成功、失败、取消和重试。

读取、协议与边界

  • 持久地址统一使用 cindy-media://blobs/<sha256>.<ext>。路径解析必须走 blobStore.resolveSafe 或现有上层适配器,不根据 URL 字符串手工拼磁盘路径。
  • cindy-media:// 的 scheme privilege 和 handler 只在现有集中入口注册。不要为单一功能 新增媒体协议;确需改变协议能力时,同时按 Electron 安全规则审查 CSP、fetch、Range、 路径校验和 Renderer 暴露面。
  • 默认不把媒体仓绝对路径直接暴露给 Renderer、插件或远端。跨边界传递使用托管 URL、 受控 grant/deposit/ledger,或已有上传与远程媒体服务。
  • 唯一的路径揭示例外是:用户明确询问某个受管媒体地址在本机的存储位置时,Host 先用 安全解析器核验为现存普通文件。Auto 档对精确单文件路径和用户请求进行 AI 审阅; allow 可返回当前 Agent,block 返回原因,ask 或服务故障才使用 Host-owned 确认卡。 其它档位仍须用户点击允许。路径进入会话记录,因此也可能同步到用户的配对设备。 Agent 自报“用户已同意”不是授权证据,也不能借路径揭示给插件或远端开放文件读取。
  • xdt-image://xdt-video://xdt-model://userData/cc-agent/ 是冻结的历史兼容层。 可以读取已有地址,不得新增写入路径、扩展生命周期或把新功能接回旧仓。
  • 删除或清理历史目录必须走已有的显式名单、复验和用户确认流程;不得新增任意 cc-agent 子目录删除能力。

已授权生成任务的结果下载

  • 下载是生成流程内部的一步,不新增“领取”状态、列表或用户操作。上游返回后,客户端 下载并通过 ingestMedia 返回受管媒体;需要确认时暂停同一次操作,批准后自动继续。
  • Guide 的 allowedUrlHosts 保留为已确认来源名单。名单内正常目标自动下载;名单外 来源、HTTP、特殊端口、地址内登录信息、受限网络等权限要求通过 Cindy 普通 permission 交互确认。卡片只说明实际地址、原因和本次范围,不出现 Guide、“模型说明”等内部概念,不使用仅限本机的 ghost_grant_confirm
  • 用户拒绝后结束本次下载,不自动重试或再次审批。网络失败由客户端最多自动尝试 三次,同一次操作及其只读地址刷新复用已经批准的来源和权限;只有目标或所需权限 变化才再次确认。不以浏览器或外部应用作为强制下载出口。
  • 默认经 guardedOutboundFetch 做 HTTPS、DNS/IP 校验及固定 IP 连接。人工例外只对 当前精确 URL 的单跳生效,不自动传递到重定向目标,不改变其他网络调用的默认策略。 来源批准按 origin 复用;受限网络例外按不含 fragment 的完整 URL 绑定,路径或 query 变化后须重新确认该受限目标,不能借同源跳转访问另一内部接口。受限网络卡片显示 当前目标的路径及脱敏后的 query,复用现有 URL 脱敏规则,不显示登录信息或签名值。 不附带生成接口凭证;地址内登录信息须单独确认,且不得沿重定向传递。
  • 网络时间累计最多 120 秒,连续 30 秒没有响应或数据则重试,单次人工审批最多等待八分钟。 上游生成沿用自身请求超时,不另加覆盖生成阶段的下载计时器。 正常跳转逐跳重验目标与权限,循环跳转作为下载故障处理,不为次数追加审批。 所有结束路径均释放 body 和 dispatcher。
  • URL 媒体逐块写入 Host 私有临时文件,类型识别使用有界探测,哈希与入仓同样分块处理。 不因原内存大小上限拒绝下载或追加大小审批;完成、失败、取消后尽力清理临时文件。 文件源仍走 ingestMedia 和现有字节仓的原子发布、去重与记账,不另建媒体存储。 base64 响应沿用原大小限制。
  • 下载失败保留原调用的成功响应。异步签名地址失效时只查询原上游任务刷新地址,不重新 付费生成;刷新结果成功入库前不覆盖原成功响应。本地入库失败由客户端对同一份已下载 字节最多尝试三次,期间复核账号和任务,不再次下载、生成或审批。 pending 且存在成功响应的记录不随六小时清理删除,也不占正在生成的名额; 不新增并行的领取状态或授权表。用户拒绝或客户端重试耗尽均返回非自动重试结果,避免模型另起一次调用而重复发起审批。
  • 真实 MIME 识别、账号/任务归属、受管入库规则持续有效。下载授权不包含执行文件、 安装程序或覆盖用户文件的授权。旧 Guide 快照与 base64 结果保持兼容。

多端与远程

  • 媒体记录必须保留设备、会话、插件或远程主机等真实归属信息,不能相信调用方自报的 本机路径或 owner id。
  • 远程来源无法证明、路径归属不明确或媒体类型无法安全确认时应 fail closed,不得回退读取 本机同名路径。
  • 跨端传递只改变传输形态,不改变账本和权限语义;上传缓存、临时副本和持久引用要分别 设计生命周期。

已知待收口项(不得随旧文档删除而视为完成)

以下缺口在触及相关链路时必须一并修复,或在 PR 中保留明确的正式跟踪,不得静默丢弃:

  • 插件持久引用的 per-插件 字节配额只覆盖 寄存ghost-deposit,cindy 槽 deposit_media):上限 GHOST_CINDY_DEPOSIT_QUOTA_BYTES,插件详情逐项展示该上限, 释放口是 release_media,卸载插件时按 refKind 清理。画廊(ghost-gallery:模型 代办产物与 network as:'media' 下载)仍无字节配额、仍不随卸载回收 —— 这两条是 存量语义,改动它们属于产品决策,触及时另行拍板,不得当作已完成。
  • 缓存默认上限与设置可见性、对账工具入口仍待收口。
  • userData/cc-agent/ 历史仓治理仍待收口(该目录是冻结的历史兼容层,见「读取、协议与 边界」节)。

Review 清单

  1. Cindy 是否真的需要拥有该媒体副本?非媒体或就地读取是否误进总仓?
  2. 新字节是否通过统一入库,且类型、指纹和路径均由主机验证?
  3. blob、引用、缓存属性和业务删除是否表达同一生命周期?
  4. 是否直接删除共享文件,或新增了专用目录、store、协议和旧仓写入?
  5. Renderer、插件、设备和 SSH 边界是否只收到必要且经过归属校验的引用?
  6. 定向测试是否覆盖去重、非法 URL、引用提交、回收、远程来源和失败清理?

修改媒体链路时,按 desktop-development.md 运行类型检查和 相关定向测试;涉及 schema、IPC 或协议时还必须追加对应专项规则要求的验证。