Skip to content

PLAN-FNOS-004 DSH 0.1.5-rc.2 适配与 FPK 运行修复

字段内容
计划编号PLAN-FNOS-004
计划日期2026-09-12
对应需求FNOS-004 DSH 0.1.5-rc.2 适配与 FPK 运行修复
本轮功能FNOS-004-01FNOS-004-09:DSH 适配、Codex/dshmarket 插件策略、应用私有 dsh CLI、Token 刷新、发布升级回滚门禁、CLI 插件管理、用量图标按供应商显隐和 fnOS 原生文件入口
上游依据本地 Harness checkout 的 dsh-v0.1.5-rc.2fb2c4b9e698e30edb738bca4cf0618587db7d203
计划状态已完成

计划目标

将 DSH 应用和仓库内四个插件的兼容性基线从 0.1.2-rc.1 升级到本地官方 Harness checkout 的 dsh-v0.1.5-rc.2,并让新 FPK 继续默认捆绑与 0.1.5-rc.2 适配的 Codex 插件。当前计划包含 DSH catalog、锁文件、插件 compatibility.json、上游破坏性 API 迁移、FPK native 构建配置、Codex 内置与安装策略、DSH CLI 插件管理、应用私有 CLI 权限、内部重启 Token 刷新和运行时验证。

本轮处理 FNOS-004-01FNOS-004-09。其中 FNOS-004-06作为发布、升级和回滚的一致性门禁,不新增独立运行时能力。计划不修改 DeepSeek Harness 上游源码,只在本仓库插件和 FPK 构建链内完成适配。

实现范围和边界

模块计划入口实现责任
DSH 依赖基线pnpm-workspace.yamlpnpm-lock.yaml统一 @deepseek-ai/dsh-* catalog 和允许提前安装的版本列表
fnOS 插件plugins/dsh-fnos-plugin迁移客户端输入、命令、附件、会话和 UI 接缝;在 fnOS iframe 内遮蔽官方「打开应用」并提供 fnOS 原生文件入口
Codex Auth 插件plugins/dsh-codex-auth-plugin迁移 attachment、LLM、pi-ai 和模型目录接缝;作为内置插件随 FPK 分发并保持老用户数据可用;conversation.input.right 的用量图标按选中模型供应商显隐
CodeBuddy 插件plugins/dsh-codebuddy-plugin迁移 LLM 流式、文件块和附件接缝;conversation.input.right 的用量图标在 showUsage 之上叠加选中模型供应商条件
Semi UI 插件packages/dsh-semi-uiplugins/dsh-semi-ui-showcase-plugin迁移共享 UI、layout、slots 和 renderer 接缝
FPK 应用apps/fn-deepseek-harness/cmd/install_callbackapp/scripts/install-callback-helper.mjsconfig/resourceconfig/privilegemanifest安装并校验 0.1.5-rc.2 DSH 运行时,真实 CLI 保留在应用私有目录且不注册系统命令,不清理 DSH_HOME;安装辅助入口由 packages/fnos-gateway/src/install-callback-helper/ 编译生成
FPK 插件策略apps/fn-deepseek-harness/app/published-dsh-plugins.jsonapp/bundled-dsh-plugins在 FPK 清单和内置目录中包含 Codex,改由 DSH CLI 管理插件,同时保护老用户已有数据
Native 构建.github/config/.github/scripts/prepare-dsh-native.sh.github/workflows/build-dsh-fn.yml使用新 DSH 依赖树准备 native 产物并生成版本化 FPK
文档与测试docs/development/docs/apps/、插件测试目录记录迁移差异、测试命令和本地/NAS 证据

FNOS-004-03 只通过 FNOS-004-07 规定的 DSH CLI 安装固定版本 dshmarket,并处理已安装时跳过,不另建插件安装实现。FNOS-004-04 负责把真实 CLI 固定在应用私有目录并以应用包用户身份运行,且不注册公开 dsh 命令(平台未提供非 root 可用的身份切换机制);它不修改 DSH CLI 上游实现。CLI 管理仍由 FNOS-004-07dsh plugin --profile web 边界承担。FNOS-004-05 负责网关代理和 DSH Web 重启之间的 Token 状态同步、原子持久化和并发请求处理。Codex 清单和内置目录属于 FNOS-004-02,本轮会修改:把 Codex 恢复为 FPK 默认内置插件并按清单精确版本安装,同时不清理老用户 profile 中的凭据和配置。FNOS-004-08 只改两个插件在 conversation.input.right 的挂出条件,不新增图标样式、交互,也不动 CodeBuddy 的 showUsage 偏好语义和两家插件的用量轮询实现。FNOS-004-09 只在 fnOS iframe 内遮蔽 DSH 官方「打开应用」按钮并改用 fnOS JS SDK 提供文件入口,不修改上游源码、不代理 /open-in-app 路由,也不动官方按钮在独立浏览器和桌面端的行为。

目标架构和数据流

text
DSH 0.1.5-rc.2 发布包

        ├─ pnpm catalog + lockfile
        │       │
        │       └─ 插件 peer/devDependencies
        │               └─ compatibility.json 与源码 API 迁移

        └─ native 依赖准备脚本
                └─ fn-deepseek-harness FPK
                        └─ install_callback 安装精确 DSH 版本
                                └─ dsh web 启动并加载四个插件

版本解析、插件编译和 FPK 运行验证使用同一个 0.1.5-rc.2 基线。安装回调只在运行时版本缺失或不匹配时处理依赖,不删除用户的 DSH_HOME、profile、凭据、工作区或会话数据。

分阶段任务

P0:建立 DSH 0.1.5-rc.2 依赖基线

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T01-01FNOS-004-01-AC-01先校验 ~/workspace/fork-pj/deepseek-harness 的 tag、commit、包版本和 pnpm@11.7.0,再盘点本仓库版本引用并统一到该 tag 的 0.1.5-rc.2适配证据固定为 dsh-v0.1.5-rc.2 / fb2c4b9e698e30edb738bca4cf0618587db7d203;当前配置、锁文件和构建参数只保留新基线
PLAN-FNOS-004-T01-02FNOS-004-01-AC-02按新依赖树更新 DSH catalog 和 minimumReleaseAgeExclude,用仓库固定的 pnpm@11.7.0 重建锁文件pnpm install 成功,锁文件解析出的 DSH 包版本可审计且没有混入旧基线
PLAN-FNOS-004-T01-03FNOS-004-01-AC-03核对 dsh-attachment-localnode-pty、Node.js 和 node-gyp 的实际版本;若 native 或持久化补丁锚点变化,按新依赖树更新配置和脚本native 配置、补丁锚点和构建机产物与实际依赖树一致;不凭包名假设 transitive 版本

P0:完成四个插件的兼容性迁移

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T02-01FNOS-004-01-AC-04更新四个插件的 compatibility.json,声明 dshPluginApi.version0.1.5-rc.2;四个插件发布版本统一为 0.1.5-rc.2 并同步 package.json、发布清单和文档dshPluginApi.version0.1.5-rc.2,声明的包集合覆盖实际 import,不引入无关包;插件版本与发布清单、文档一致
PLAN-FNOS-004-T02-02FNOS-004-01-AC-05fnOS 插件迁移 InputActionsSessionInput、附件字段、CommandContribution.description 及 primitives/layout/slots 的替换导出主题、/fn 指令、授权目录、NAS 引用和会话导出相关测试通过;不存在旧图片 API 引用
PLAN-FNOS-004-T02-03FNOS-004-01-AC-06Codex Auth 迁移 attachment 与 dsh-llm-pi-ai 接缝,适配 pi-ai 0.85.1 的 provider、模型目录和图片输入类型Codex Auth 类型检查、单元测试和构建通过;无凭据测试不泄漏密钥,老配置结构仍可读取
PLAN-FNOS-004-T02-04FNOS-004-01-AC-07CodeBuddy 迁移 dsh-llm 流式、文件块和附件序列化接缝,保留现有多账号、切换、签到和用量面板行为CodeBuddy 类型检查、单元测试和构建通过;文本、图片和错误流仍能被 UI 正确消费
PLAN-FNOS-004-T02-05FNOS-004-01-AC-08Semi UI 共享包和总览插件迁移 layout、renderer、slots、theme 与 primitives 接缝共享组件和总览路由在新客户端下能构建、渲染、刷新和卸载

P0:恢复 Codex 与 CodeBuddy 默认捆绑

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T05-01FNOS-004-02-AC-01published-dsh-plugins.jsonplugins 中维护 @tnnevol/dsh-codebuddy@tnnevol/dsh-codex-auth 的精确版本;仓库内插件使用 pnpm pack 生成精确版本归档,核验包名、版本和运行依赖,安装回调用 DSH CLI file: spec 安装;发现旧 link: 同版本安装时重新安装归档清单包含 CodeBuddy、Codex 且与内置归档元数据一致,干净及旧 profile 均能解析两个插件依赖并启动 Web
PLAN-FNOS-004-T05-02FNOS-004-02-AC-02确认安装/升级只按清单对 Codex 执行安装或精确版本校准,不删除用户凭据、模型配置、workspace、授权目录和 profile bundle老用户已有 Codex 凭据、配置和 bundle 在升级后逐项保持不变
PLAN-FNOS-004-T05-03FNOS-004-02-AC-03为安装回调增加新用户、老用户和重复升级场景的隔离回归夹具,记录安装、升级和跳过的日志新用户装到清单精确版本;老用户保留用户数据;重复执行幂等
PLAN-FNOS-004-T05-04FNOS-004-02-AC-04移除构建 CLI 与文档中的 Codex 排除规则,改为校验清单包含 Codex 且归档版本与清单一致;三方插件(dshmarket)仍不进入内置目录,安装回调通过 DSH CLI 单独安装构建产物内置 Codex 归档且无浮动版本安装;本地 FPK 检查和真实 NAS 升级验证结果一致
PLAN-FNOS-004-T05-05FNOS-004-02-AC-06把 FPK 内置插件 CodeBuddy 的 RPC 频道 /codebuddy 加入网关 builtinPaths,与 /api/plugins/open-in-app 同级;不改动用户规则与保留路径校验未配置任何自定义路径时 /codebuddy/<endpoint> 被补上应用前缀并转发到 DSH;/codebuddyx 仍留给 fnOS 宿主;用户规则不能覆盖或移除内置前缀

P0:使用 DSH CLI 管理 FPK 插件

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T06-01FNOS-004-07-AC-01install_callback 中先检测应用自己的 npm 全局目录是否已有可执行且版本精确的 pnpm@11.7.0@deepseek-ai/dsh@0.1.5-rc.2;两者均满足时跳过对应安装,否则只安装缺失、不可执行或版本不匹配的固定版本;同时设置应用用户可执行的 PATH、DSH_HOME、npm 前缀、${DSH_HOME}/.npmrc${DSH_HOME}/.pnpm-store-dir 持久配置官方 CLI 插件命令执行前,dsh --versionpnpm --version 均输出精确版本,重复安装不重复下载已满足版本的依赖,也不依赖 NAS 全局 pnpm;npm 源由 .npmrc 提供,pnpm store 由 PNPM_CONFIG_STORE_DIR 提供
PLAN-FNOS-004-T06-02FNOS-004-07-AC-02不再由应用单独初始化 profile;首次执行 dsh plugin --profile web add/update 时由官方 CLI 自动初始化,已有 profile 时复用,不覆盖用户配置,也不启动 Web官方 CLI 自动创建缺失 profile,已有依赖、patch 和配置保持不变
PLAN-FNOS-004-T06-03FNOS-004-07-AC-03将 install/upgrade callback 的插件操作改为 dsh plugin --profile web 的 add/update,内置本地插件时把 FPK 包路径交给 DSH CLI,不内置的三方插件继续按精确包名安装;移除 install-dsh-plugins.mjs 及其调用、npm 直装和手工 bundle 重建路径生命周期日志显示 DSH CLI 命令;本地插件不重复走 registry;三方插件不会因内置分流被漏装;FPK 产物不再包含旧插件安装脚本
PLAN-FNOS-004-T06-04FNOS-004-07-AC-04清单只接受插件名称和精确版本,生成 <package>@<version> 参数;捆绑包 package.json 版本必须与清单一致,拒绝 latestnext 和其他浮动 dist-tag所有自动安装命令可审计为精确版本,清单、捆绑包和 profile 依赖版本一致
PLAN-FNOS-004-T06-05FNOS-004-07-AC-05仅对清单中的缺失插件执行 add,对版本变化的插件执行精确 update;remove 只由明确的用户操作触发,不因清单缺少 Codex 等旧插件而自动移除新安装、升级和重复升级幂等,老用户旧插件和 bundle 保持不变
PLAN-FNOS-004-T06-06FNOS-004-07-AC-06区分 DSH、pnpm、清单校验和 profile 写入失败;从 .modules.yaml 复用既有 pnpm store 并持久化到 ${DSH_HOME}/.pnpm-store-dir,同时清理旧 .npmrc 中的 store-dir 配置,任何命令非零都中止回调并保留旧 profile 数据fake 命令夹具覆盖成功、旧 store 路径复用、npm 无未知配置警告、缺工具、权限不足和部分失败场景,错误可定位且生命周期返回非零
PLAN-FNOS-004-T06-08FNOS-004-07-AC-08网关启动 DSH Web 时从 ${DSH_HOME}/.pnpm-store-dir 读取安装期记录的 store,注入子进程 PNPM_CONFIG_STORE_DIR 并清理继承的同名变量;值缺失、为空或非绝对路径时不猜测运行期 pnpm store path 与该 profile node_modules/.modules.yamlstoreDir 一致,dsh plugin 与三方市场更新不再出现 ERR_PNPM_UNEXPECTED_STORE
PLAN-FNOS-004-T06-07FNOS-004-07-AC-07在当前 DSH 客户端验证非 fnOS 插件的 CLI 管理和 Bundle 重启生效;在真实 NAS 只验证 FPK、网关和 dsh-fnos两类环境证据分开记录,Codex Auth、CodeBuddy、Semi UI 和共享包不以 NAS 安装为前置条件

P0:固定并兼容安装 dshmarket

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T07-01FNOS-004-03-AC-01将 dshmarket 纳入 FPK 插件清单但不复制到 FPK,固定版本为 dshmarket@1.46.1;profile 中不存在该插件时生成 dsh plugin --profile web add dshmarket@1.46.1新用户安装日志包含精确 CLI 命令,profile 依赖和 bundle 写回成功,Web 重启后市场入口加载
PLAN-FNOS-004-T07-02FNOS-004-03-AC-02安装前检查 profile 包清单和实际包目录;任一位置已存在 dshmarket 即记录跳过,不执行 add/update/remove已安装任意版本的用户文件、版本、配置和 bundle 保持不变,重复升级幂等
PLAN-FNOS-004-T07-03FNOS-004-03-AC-03清单校验只允许精确版本 1.46.1,禁止 dshmarket 使用 latestnext 或其他浮动 dist-tag构建和 fake CLI 测试能证明命令参数始终带固定版本
PLAN-FNOS-004-T07-04FNOS-004-03-AC-04在当前 DSH 客户端验证 dshmarket 的 CLI 安装、跳过已安装和 Web 重启生效;NAS 只验证 FPK 安装链及 dsh-fnos客户端和 NAS 证据分开保存,不要求其他插件安装到 NAS

P0:应用私有 dsh CLI 与网关 Token 收敛

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T08-01FNOS-004-04-AC-01安装回调不再创建 ${TRIM_APPDEST}/app/bin/dshconfig/resource 不再声明 usr-local-linker;真实 CLI 固定在 ${TRIM_PKGHOME}/.npm-global/bin/dsh。构建校验改为拒绝重新引入 wrapper 的产物config/resourceusr-local-linker,安装回调无 CLI_WRAPPER;构建对重新引入 wrapper 的 FPK 报错失败
PLAN-FNOS-004-T08-02FNOS-004-04-AC-03应用包用户环境(DSH_HOMEHOMEPATHNPM_CONFIG_CACHENPM_CONFIG_PREFIXXDG_CONFIG_HOME)由安装回调与网关各自固定,不再经 wrapper 传递应用包用户下 dsh --versiondsh --helpdsh plugin --profile web ... 输出与真实 CLI 一致
PLAN-FNOS-004-T08-03FNOS-004-04-AC-02记录平台约束并据此取消公开入口:fnOS 未向非 root 调用者提供身份切换机制,runuser/su/setpriv/sudo 均不可用,需求禁止 setuid不存在由普通用户调用却声称以应用包用户执行的入口;NAS 上逐项记录四种切换机制的实测失败输出
PLAN-FNOS-004-T08-04FNOS-004-04-AC-04设置真实 CLI、Node/pnpm、profile 和插件依赖的所有权与最小权限;禁止普通用户修改配置或改变所有权使用 stat 和实际写入测试证明非应用用户不能篡改 DSH 配置,应用用户可以正常管理自己的 profile
PLAN-FNOS-004-T08-05FNOS-004-05-AC-01网关只在首次不带 DSH 会话 Cookie 的首页请求注入 Token,其余请求透传 Cookie;旧 Cookie 被拒绝时用当前 Token 重新换取一次iframe 打开首页返回 200 而非 303 循环;上游仅收到一次带 Token 的请求;失效 Cookie 可自动恢复

P0:内部重启后的代理 Token 刷新

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T09-01FNOS-004-05-AC-01保持 cmd/main 只负责启动网关,由网关直接运行应用私有目录中的真实 DSH CLI 启动 dsh web --no-open;梳理 cmd/config_callbackgateway-proxy.mjs 的重启状态、WebProcessController、Token 文件和统一网关代理链路;重启开始时明确标记 Token 失效/刷新中网关能捕获本轮 Web 启动 Token 并仅在内部代理请求中使用;浏览器 iframe 地址不携带 Token,旧 Token 在重启开始后不再用于健康检查或代理鉴权,状态接口能区分刷新中和错误
PLAN-FNOS-004-T09-02FNOS-004-05-AC-02DSH Web 启动后从启动输出捕获新 Token,先写临时文件并原子 rename,再更新内存 Token;设置应用包用户所有权和最小权限新 Token 文件内容完整、权限正确,进程内读取值与落盘值一致;写入失败不会发布半截 Token
PLAN-FNOS-004-T09-03FNOS-004-05-AC-03调整网关首页认证、健康检查和代理入口的 Token 读取顺序:刷新期间等待本轮启动结果或返回可恢复响应,禁止读取旧缓存;新 Token 生效后仅向 DSH 上游请求注入新值,并清理上游响应中的 Token 跳转浏览器 iframe 地址始终不携带 Token;页面、HTTP、SSE、WebSocket 和并发请求不会因旧 Token 返回未授权;成功后能自动恢复页面访问
PLAN-FNOS-004-T09-04FNOS-004-05-AC-04覆盖首次启动、配置触发的内部重启、异常退出恢复、连续重启和启动超时;清理旧临时文件、锁和失效 Token,保留可诊断错误隔离测试和真实 NAS 回归均能证明新旧 Token 正确切换,旧 Token 不再生效,失败时不会误报启动成功
PLAN-FNOS-004-T09-04aFNOS-004-05-AC-04网关在启动前恢复 DSH 凭据文件遗留锁:仅处理锁文件中 PID 已退出的情况,采用 rename 隔离后清理;活跃 PID 必须等待释放,锁内容异常必须保留并失败应用异常退出遗留 .credentials.yaml.lock 后可重新启动;活跃凭据写入不会被删除或并发启动破坏
PLAN-FNOS-004-T09-05FNOS-004-05-AC-04在真实 NAS 验证网关 iframe、HTTP/SSE/WebSocket、重启控制接口和并发请求;非 fnOS 插件继续只在当前 DSH 客户端验证NAS 记录重启前后 Token 状态、响应码、跳转地址和日志,确认问题不再复现

P1:发布、升级和回滚一致性门禁

状态:已完成

FNOS-004-06是贯穿构建、安装、升级和验收的发布门禁,不新增独立运行时能力。

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T10-01FNOS-004-06-AC-01增加构建前清单校验,统一核对 DSH 版本、native 配置、锁文件、published-dsh-plugins.json、捆绑包元数据、Codex 内置规则和 FPK 文件名版本或清单不一致时构建失败;成功产物的版本信息可从清单、文件和 FPK 元数据复核
PLAN-FNOS-004-T10-02FNOS-004-06-AC-02审计 install/upgrade callback 的幂等性,确保只处理当前精确清单,不清空 DSH_HOME,不自动移除旧插件,并保留升级前运行状态记录新装、升级和重复升级结果一致;用户 profile、凭据、工作区、会话和旧插件保持可读
PLAN-FNOS-004-T10-03FNOS-004-06-AC-03在升级变更前保存可恢复的 runtime/profile 元数据;失败时返回非零并恢复旧指针或旧配置,成功后写入完成标记模拟 DSH、pnpm、插件、native 和启动失败后,上一份 FPK 或受支持回滚流程可恢复启动,用户数据不变
PLAN-FNOS-004-T10-04FNOS-004-06-AC-04生成发布证据索引,关联 FPK、DSH/native/plugin 版本、安装升级日志、回滚结果及当前客户端/NAS 验收记录任一发布包都能追溯到构建输入和目标环境证据;本地结果不冒充 NAS 验收

P0:用量图标按模型供应商显隐

状态:已完成

实施提交:35f0e70 feat(plugin): gate usage icons on the selected model provider。相关实现、测试与构建已完成;根据用户确认,AC-01AC-05 均已验收通过,客户端证据见客户端验收记录

FNOS-004-08 只收敛两个用量图标在 conversation.input.right 的挂出条件。两个插件都注册在这个插槽(Codex id: codex-usage order: 1,CodeBuddy id: codebuddy-usage order: 2),各自只按自身登录态或偏好判断,选中某一家模型时另一家的图标照样显示。判断依据来自会话投影 modelSelectionprovider,和选中模型同源。

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T11-01FNOS-004-08-AC-01两个 dock 组件从插槽标准道具读取 useProjection('modelSelection'),取 next ?? lastUsedprovider;Codex 仅当 provider 为 openai-codex 时挂出,CodeBuddy 仅当 provider 为 codebuddy 时挂出(常量沿用各自插件已有的 provider 标识)选中 Codex 模型时只有 Codex 图标,选中 CodeBuddy 模型时只有 CodeBuddy 图标,同一轮对话不出现两家图标并存
PLAN-FNOS-004-T11-02FNOS-004-08-AC-02显隐条件走 React 订阅路径,选中模型变化立即重算,不缓存首次结果;切换模型不清空草稿、不触发页面刷新在两家模型间来回切换,图标即时跟随,草稿和滚动位置保持不变
PLAN-FNOS-004-T11-03FNOS-004-08-AC-03未选模型、投影缺失、provider 为空或为其它供应商时两者都不挂出;判断只依赖供应商,不依赖登录态或用量请求是否成功未选模型或选中第三方模型时两家图标均不出现
PLAN-FNOS-004-T11-04FNOS-004-08-AC-04CodeBuddy 的 showUsage 仍是更前置开关,供应商条件与之取与:偏好关闭时即使选中 CodeBuddy 模型也不显示;Codex 保持现有登录态前置条件不变关闭 showUsage 后选中 CodeBuddy 模型仍不显示图标,重新开启即恢复
PLAN-FNOS-004-T11-05FNOS-004-08-AC-05图标不挂出时不建立用量轮询(把供应商判断放在挂起轮询的 effect 之前,或让 effect 依赖该条件);条件变化时已在跑的刷新按现有 cleanup 正常收尾,不额外补一轮请求隐藏状态下无对应插件的后台用量请求;隐藏/显示切换不产生重复定时器
PLAN-FNOS-004-T11-06FNOS-004-08-AC-05为两个组件补单元测试:供应商匹配显示、不匹配隐藏、无投影隐藏、CodeBuddy 偏好取与、切换即时生效和不建立轮询Codex Auth 与 CodeBuddy 的类型检查、单元测试和构建通过;测试覆盖上述分支

P1:fnOS 原生文件入口

状态:已完成

FNOS-004-09 在 fnOS iframe 内遮蔽 DSH 官方「打开应用」按钮(@deepseek-ai/dsh-client-ui-open-in-app,插槽 conversation.session.header.utilitiesid: open-in-apporder: -10priority 默认 0),改用 fnOS JS SDK 提供文件入口。遮蔽沿用插件已有手法:同 id、更低 priority(插件现有的 session log 入口即以 priority: -1 遮蔽 dsh-session-log-export)。上游按钮按编译期常量表 OPEN_IN_APP_CATALOG 探测本机应用,Linux 上 zed 条目只认 PATH 同名可执行文件,而 fnOS 自带 /usr/sbin/zed(ZFS Event Daemon),因此被误判且图标 404;该表不可配置、插件无注册接口、本仓库不提交上游补丁,故在插件侧遮蔽。

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T12-01FNOS-004-09-AC-01isEmbeddedFnosFrame() 为真时注册 conversation.session.header.utilities,使用与官方相同的 id: 'open-in-app' 和更低的 priority(不得同优先级,否则注册抛错)fnOS iframe 内官方按钮不再渲染;独立浏览器不受影响
PLAN-FNOS-004-T12-02FNOS-004-09-AC-02新增 fnOS 文件入口组件,结构与交互对齐官方 OpenInAppAction:28px 高的分体按钮,左半执行当前操作(仅图标,15px)、右半 chevron(11px)展开菜单,两半之间有 l4 发丝分隔线并各有 hover;用 ui-primitivesMenu/Tooltip,样式数值与官方 CSS 对齐;操作项由数组驱动,便于追加外观、尺寸和交互与官方入口一致;左半点击执行、右半点击展开
PLAN-FNOS-004-T12-03FNOS-004-09-AC-03菜单项「文件管理」调用 fnOS SDK 的 openFileManager(cwd),目标路径取当前会话工作目录;复用既有 createTrimApp() 与 web carrier 校验选择后 NAS 文件管理器打开并定位到会话工作目录
PLAN-FNOS-004-T12-04FNOS-004-09-AC-04工作目录未知或为空时不渲染入口;SDK 未就绪、非 web carrier 或调用失败时给出可见失败提示,不回退到 DSH 原生打开逻辑,不预检插件自己的授权目录列表无工作目录时不出现入口;调用失败有可见提示且不产生未处理异常
PLAN-FNOS-004-T12-05FNOS-004-09-AC-06补单元测试:iframe 框架判定、遮蔽注册的 id 与 priority、工作目录判定、SDK 调用与失败分支;更新插件文档fnOS 插件 typecheck、测试和构建通过;文档记录入口位置、可用能力和边界
PLAN-FNOS-004-T12-06FNOS-004-09-AC-07 / AC-08插件静态资源改由插件自己的路由提供:插件在 DSH 注册 /fnos-plugins/static/dsh-fnos 前缀路由,只按固定资源名映射读取包内文件并返回,拒绝路径穿越;网关把 /fnos-plugins/static 加入 builtinPaths,使浏览器 bridge 自动补上应用前缀客户端以该 URL 引用图标可正常加载;资源缺失返回 404;路由不读取 fnOS 宿主目录,也不放宽既有图片补前缀规则
PLAN-FNOS-004-T12-07FNOS-004-09-AC-09 / AC-10对齐官方头部布局:两个条目的 priority/order 取值集中到 header-utility-seats.ts(文件入口 order -10、Session log order 0),并在 index.ts 里展开使用;Session log 触发控件改为 28px 圆形纯图标按钮(透明、无边框、15px 字形),菜单项带图标左右顺序为「文件入口在左、Session log 在右」且不随注册先后改变;顺序测试用真实 SlotCore 驱动,把 order 打平会使测试失败;按钮不带可见文案与边框
PLAN-FNOS-004-T12-08FNOS-004-09-AC-11修复「导出到 NAS」的上游取数:原实现调 ctx.get('apiProxy').downloads.sessionLog(...),而全仓与上游 DSH 都没有该服务的提供方,取值恒为 undefined、必然 503。改为宿主向本机 loopback 请求 DSH 自己的 /api/session.export,并转发当前浏览器的 dsh-auth-* Cookie 完成 browser-session 认证(includeDescendants=true),复用既有流式写入与失败清理导出成功写入目标目录并返回 201;绑定 0.0.0.0 时回落到 loopback;上游 4xx 与会话不存在可区分;Cookie 缺失或认证失败时能明确报错;不再出现 ctx.get('apiProxy') 调用
PLAN-FNOS-004-T12-09FNOS-004-07-AC-09 / AC-10内置捆绑插件改为每次安装强制以 FPK 归档覆盖:在 install_callback 中新增 force_install_bundled_plugin,若 profile 已有该插件则先通过 DSH CLI remove,再以同一 spec add;不触碰 pnpm 内部状态文件,保留 profile 的依赖与 bundle 记录版本号不变但归档内容变化时,profile 中的副本仍被替换为归档内容;重复执行幂等;CLI 失败时生命周期返回非零并输出错误
PLAN-FNOS-004-T12-10FNOS-004-09-AC-12 / AC-13适配 DSH 的 presented-file 打开动作:客户端在 fnOS iframe 内包装 fetch,把 /api/present.host 报为可用、把 /api/present.open 改走网关到插件的 /fnos-plugins/present/resolve,由宿主按 Session 事件、工作区与文件系统校验出真实路径后再调用 fnOS SDK openFile/openFileManager/fnos-plugins/present 加入网关内置前缀;tooltip 改为动态模板不再出现 409 Host desktop unavailable;解析、路径校验和打开失败时可重试;非 fnOS 环境与非 present 请求完全保持原行为

P0:同步 FPK 运行时与构建入口

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T03-01FNOS-004-01-AC-09更新 cmd/install_callback 的 DSH 版本常量和版本校验,沿用 ${TRIM_*} 路径,不重建或清空用户 profile新安装可得到精确 0.1.5-rc.2;已有用户数据目录不被删除或重置
PLAN-FNOS-004-T03-02FNOS-004-01-AC-10更新 native 配置文件名、prepare-dsh-native.sh 默认值、构建 CLI 的 node-pty 内置选项和 build-dsh-fn.yml 参数workflow 输出的 FPK 文件名带 dsh-0.1.5-rc.2,构建流程自动准备并内置同一依赖树的 native 文件
PLAN-FNOS-004-T03-03FNOS-004-01-AC-11更新 DSH 版本相关应用与开发文档,区分当前运行基线和历史变更记录用户文档、开发文档、需求和计划中的当前版本一致;不提前写入本轮未实施的插件安装行为

P1:组合入口与目标环境验证

状态:已完成

任务 ID对应验收实现内容验收
PLAN-FNOS-004-T04-01FNOS-004-01-AC-12执行四个插件及共享包的 typecheck、unit test、build,并执行仓库级相关检查受影响 workspace 全部通过;测试覆盖新 API 的加载、卸载、错误和回放路径
PLAN-FNOS-004-T04-02FNOS-004-01-AC-13构建 fn-deepseek-harness FPK,检查包内版本、入口、native 文件和安装脚本pnpm run build -- --fpk --app fn-deepseek-harness 成功;产物可被 fnOS 安装工具识别
PLAN-FNOS-004-T04-03FNOS-004-01-AC-14在真实 NAS 执行全新安装、启动、网关 iframe、HTTP/SSE/WebSocket 和 dsh-fnos 插件加载验证dsh --version0.1.5-rc.2;Web 可打开;fnOS 插件无加载异常;NAS 证据单独记录
PLAN-FNOS-004-T04-04FNOS-004-01-AC-15在当前 DSH 客户端使用同一 0.1.5-rc.2 基线验证 Codex Auth、CodeBuddy、Semi UI 及共享包的组合入口、插件加载和关键 UI/API 行为非 fnOS 插件不依赖 NAS 即可完成验证;客户端证据记录版本、组合入口、测试结果和失败日志

详细交互

P0:FPK 安装与 DSH Web 启动流程

  1. 在干净测试环境安装本轮 FPK;fnOS 执行 cmd/install_callback,安装回调按固定版本检查 DSH 运行时。
  2. 安装完成后启动应用,cmd/main 通过已有网关入口启动 DSH Web profile。
  3. 从应用日志和运行命令确认 DSH 运行时版本为 0.1.5-rc.2,再访问 fnOS iframe 入口。
  4. 在 NAS 端只确认 dsh-fnos 插件注册、fnOS API/网关交互和既有基础入口可用。
  5. 在当前 DSH 客户端确认 Codex Auth、CodeBuddy、Semi UI 及共享包注册和关键行为;这些插件的组合验证不以 NAS 安装为前置条件。
  6. 任一插件加载失败时保留对应环境的日志和错误堆栈,应用不得报告虚假的“启动成功”;基础 DSH 启动问题、fnOS 宿主问题和客户端插件契约问题分别记录。

P0:Codex 默认捆绑兼容流程

  1. 在构建产物检查中确认新 FPK 的发布清单和内置插件目录都包含 Codex,且归档 package.json 版本与清单精确版本一致。
  2. 在隔离的干净 profile 中执行安装,确认 Codex 按内置 file: 归档安装,DSH Web 能正常启动且不出现 settingsNamespace 一类接缝错误。
  3. 在隔离的老用户 profile 中预置 Codex 凭据、模型配置、workspace 和 bundle,执行升级与重复升级。
  4. 重新读取 profile 文件、包目录和日志,确认 Codex 用户数据保持原状,没有卸载、删除或覆盖;包本体校准到清单版本。

P0:DSH CLI 插件管理流程

  1. install_callback 先确认 Node.js、安装辅助入口和运行目录,再将向导选择的 npm 源持久化到 ${DSH_HOME}/.npmrc,将 pnpm store 路径持久化到 ${DSH_HOME}/.pnpm-store-dir,随后准备精确版本 DSH 与 pnpm@11.7.0
  2. published-dsh-plugins.json 读取插件名称和精确版本,对缺失插件执行 dsh plugin --profile web add <package>@<version>,对版本变化执行精确 update;缺失 profile 由官方 CLI 自动初始化。
  3. 对 dshmarket 先检查 profile 包清单和实际包目录;缺失时执行 dsh plugin --profile web add dshmarket@1.46.1,已存在时跳过,不因为版本不同而覆盖。构建阶段不复制 dshmarket,registry 安装失败直接报告错误,不使用 FPK 内置回退包。
  4. DSH CLI 在 profile 目录中调用 pnpm,并负责写入依赖和 reconcile dsh.profile.bundles;应用不再复制插件、手工初始化 profile 或手工修改 bundle 列表。
  5. 新 bundle 只在 Web profile 下次启动时生效;安装/更新完成后按既有流程重启 Web。清单未列出的老插件不执行自动 remove。
  6. upgrade_callback 复用同一流程,禁止回退到旧脚本;任一命令失败都停止回调并保留 profile 数据。

P0:应用私有 dsh CLI 运行边界

  1. install_callback 不创建公开 wrapper,也不在 config/resource 注册 usr-local-linker;真实 CLI 固定在应用私有 ${TRIM_PKGHOME}/.npm-global/bin/dsh。安装回调直接依赖 fnOS config/privilegerun-as=package,只初始化 DSH/npm/pnpm 所需环境,不自行检查 UID/GID、修复所有权或切换用户。
  2. 取消公开入口的依据是平台能力:fnOS 上 runuser 以非 root 执行报 may not be used by non-root users,指定 --grouponly root can specify alternative groupssu 需要密码,setprivOperation not permitted,且需求禁止 setuid 与不受控 sudo。没有可用切换机制时,任何普通用户调用都会以调用者身份运行,违反身份约束,因此不暴露入口。
  3. 网关以应用包用户直接启动 dsh web --no-open,并自行固定 DSH_HOMEHOMEPATHNPM_CONFIG_CACHENPM_CONFIG_PREFIXNPM_CONFIG_USERCONFIGXDG_CONFIG_HOME,不依赖调用者环境。
  4. 构建校验必须拒绝重新引入 wrapper 的产物:cmd/install_callback 不得出现 CLI_WRAPPER / setup_cli_wrapperconfig/resource 不得出现 usr-local-linker/bin/dsh
  5. 真实 CLI 与运行依赖不可被普通用户写入;profile 和插件依赖由应用用户拥有,取消公开入口不改变这些所有权约束。

P0:内部重启 Token 刷新流程

  1. 网关收到内部重启请求后,先将 Token 状态切换为刷新中,使旧 Token 不能再被健康检查或代理鉴权读取;浏览器 iframe 地址保持无 Token。
  2. cmd/main 停止旧 DSH Web 并启动新进程;gateway-proxy.mjs 从本轮启动输出捕获带 Token 的地址,只接受非空、格式有效且属于当前启动轮次的 Token。
  3. 新 Token 写入同目录临时文件,完成 flush/close 后通过原子 rename 替换正式 Token 文件,并设置应用包用户所有权和受限权限;确认落盘成功后再更新内存缓存和可用状态。
  4. 重启期间的页面和代理请求等待新 Token,或返回带重试语义的恢复页面/响应;Token 捕获、持久化或健康检查超时则返回明确错误,不复用旧 Token 掩盖失败。
  5. 新 Token 发布后,首页认证中间件、健康检查和代理请求统一从当前内存/文件状态读取;Token 只附加到网关到 DSH 的内部请求,上游响应中的 Token 跳转会被清理,连续重启不会把较早轮次的 Token 写回。

P1:发布与升级回滚流程

  1. 构建 FPK 前运行清单校验,确认 DSH/native/plugin 版本、Codex 内置规则、dshmarket 固定版本、未注册公开 dsh 入口和 FPK 元数据一致;校验失败不进入发布。
  2. 安装或升级前记录当前 runtime 指针、profile 关键元数据和应用版本;不复制或记录 Token、API Key 等敏感内容。
  3. 安装/升级只执行当前计划规定的幂等操作;完成 DSH CLI、插件、native 和 Web 启动验证后再写入成功标记。
  4. 任一阶段失败时返回非零,保留旧 profile 和用户数据,并按可用的旧 runtime/旧 FPK 回滚入口恢复;不能用清空 profile 的方式“回滚”。
  5. 发布后把构建输入、FPK、版本清单、升级日志、回滚结果和客户端/NAS 验收记录关联保存,作为完成 FNOS-004-06 的证据。

P0:插件兼容性回归流程

  1. 先在无真实凭据的组合入口运行插件加载、配置校验、卸载和错误路径测试。
  2. 在当前 DSH 客户端使用测试凭据或 mock,验证 Codex Auth 模型目录、CodeBuddy 流式响应和 Semi UI 页面行为;这些验证不要求安装到 NAS。
  3. 使用当前客户端的真实 DSH Web 入口验证非 fnOS 插件的 bundle、Host 服务、Remote 调用和页面刷新;在 NAS 端单独验证 dsh-fnos 的 fnOS API、路径和网关行为,不只验证单独构造的 Context。
  4. 发现 API 接缝不匹配时,优先根据 0.1.5-rc.2 当前源码和生成类型修复插件,不改上游源码;无法等价迁移时停止发布并记录影响。

P0:用量图标供应商显隐流程

  1. 两个插件分别注册在 conversation.input.right 的两个 cell(codex-usagecodebuddy-usage),互不遮蔽;各自组件在渲染前读取当前会话的 modelSelection 投影。
  2. 从投影值取 next ?? lastUsedprovidernext 是下一次请求将使用的选择,lastUsed 兜底,二者都为空表示本会话还没确定模型。
  3. 只有 provider 与本插件一致时组件继续渲染;不一致、为空或投影缺失时返回 null。这一步在挂起用量轮询的 effect 之前完成,隐藏状态不建立定时器。
  4. CodeBuddy 额外保留 showUsage 作为更前置开关,供应商条件与该偏好取与;Codex 保留现有的登录态前置条件。这些条件只决定图标挂不挂出,不改动图标样式、tooltip 和点击展开行为。
  5. 选中模型变化时投影推送新值,React 订阅触发重算,图标随切换即时增减;已在跑的刷新由现有 cleanup 收尾,不因条件翻转补发请求。

P1:fnOS 原生文件入口流程

  1. 插件只在 isEmbeddedFnosFrame() 为真时注册会话头部入口,使用与官方相同的 id: 'open-in-app' 和更低的 priority。列表插槽的遮蔽按「同 id、不同 priority、低者生效」判定,因此官方条目不再渲染,且不会出现两个入口。
  2. 入口读取当前会话的工作目录;工作目录未知或为空时返回 null,不渲染锚点。
  3. 锚点用 Semi UI 的按钮加图标,外观与官方入口在头部的位置和尺寸一致;点击展开下拉菜单,菜单项由数据驱动,当前只有「文件管理」。
  4. 选择菜单项后调用 fnOS JS SDK 的 openFileManager(cwd):复用既有的 createTrimApp(),等待 ready(),校验 isWeb 且非 isStandaloneWeb 再调用。目标路径直接交给 fnOS,不做本地授权预检。
  5. 调用失败时设置可见错误提示并复位忙碌状态;不抛出未处理异常,不阻塞 DSH,也不回退到 NAS 上不存在的 xdg-open

静态资源的取用链路:客户端以 /fnos-plugins/static/dsh-fnos/<资源> 引用图标;浏览器 bridge 判定其为图片资源(该前缀同时在网关 builtinPaths 内,非图片资源同样成立)并补上 /app/fn-deepseek-harness 前缀;fnOS 把 /app/fn-deepseek-harness/* 路由到网关 socket;网关按既有规则剥掉网关前缀后转发给 DSH;DSH 侧由插件注册的同名前缀路由返回包内资源字节。资源随插件包发布,网关与插件都不读取 fnOS 宿主文件系统。

数据、权限和错误处理

  • 所有应用路径使用 ${TRIM_*} 环境变量;安装、升级和验证不得写死 NAS 安装目录。
  • 版本升级不得删除 DSH_HOME、profile、凭据、工作区、会话、授权目录或现有插件配置;安装回调失败时保留旧数据并输出明确错误。
  • 依赖安装使用仓库和安装向导约定的 npm registry,锁文件负责可重复解析;网络失败不能静默回退到浮动版本。
  • DSH CLI 和 pnpm、profile manifest、node_modules 及配置文件都必须由 DSH 应用包用户可读写;权限不足时直接失败,不通过 root 绕过应用权限。
  • 不记录 Token、API Key 或完整凭据;插件管理日志只记录包名、精确版本、命令阶段和错误原因。
  • 安装回调与网关都不能信任调用者传入的 DSH_HOME、HOME、PATH、npm/pnpm 前缀或配置目录;需要保留的代理设置必须由应用固定配置或显式白名单提供。
  • 平台缺少非 root 可用的身份切换机制时,不暴露需要切换身份的公开入口;不得静默降级为调用者身份,也不得改用 root 绕过应用权限。
  • Token 刷新采用“失效旧状态 → 捕获新 Token → 原子持久化 → 发布内存状态”的顺序;任何中间步骤失败都不能继续对外宣称 Web 已恢复,也不能回退使用旧 Token。
  • Token 文件、临时文件和锁文件都必须位于应用运行目录,由应用包用户拥有;日志只能记录 Token 轮次和状态,不能记录 Token 内容。
  • runtime 指针、profile 快照和升级完成标记不能包含凭据;回滚只恢复版本和配置元数据,不删除用户数据。
  • Native 依赖准备失败、补丁锚点不唯一、Node ABI 不匹配和插件 API 不匹配分别记录错误,不以跳过检查的方式生成 FPK。
  • Host 与 Client 仍遵守 DSH Remote、附件持久化、会话可回放和插件生命周期约束;测试覆盖重复加载、卸载和异常退出清理。
  • 用量图标的显隐只读会话投影,不改写会话数据,也不新增会话事件;投影缺失就当作不显示,不去猜供应商,也不拿登录态或用量请求结果顶替供应商判断。
  • fnOS 文件入口的目标路径来自会话工作目录,只读会话状态,不改写会话数据、不新增会话事件;工作目录缺失时按「不渲染」处理。
  • 插件静态资源只从插件包内目录读取,不读取也不依赖 fnOS 宿主的静态资源布局;请求路径只用于匹配固定资源名,未命中返回 404,不把请求路径拼进文件系统路径。
  • 文件入口不预检插件展示的授权目录列表:该列表用于浏览和选择,可能滞后于 fnOS ACL 状态,预检会误拒合法路径;是否允许由 fnOS 判断。调用失败只影响本次操作,不写入持久化状态,也不移除入口。
  • 供应商标识以各插件已有的常量或 provider 注册名为准,不在 dock 组件里硬编码第二份字符串;未匹配任何已注册供应商时不显示任何图标。

依赖、风险和决策

项目风险或决策处理方式
上游 API目标 tag 对附件、命令描述、LLM 流式、pi-ai 和 UI 导出有破坏性变化以本地 dsh-v0.1.5-rc.2 源码/生成类型逐项迁移并补组合入口测试,不提交上游补丁
依赖树dsh-attachment-localnode-pty 的实际版本可能与 DSH 主版本不同以锁文件和已安装依赖树为准,native 配置跟随实际版本
Native 构建macOS 本地无法代替 Linux runner 生成目标 native 文件本地验证脚本和配置,CI/Linux 生成正式 native 产物,NAS 只安装构建结果
外部服务Codex Auth、CodeBuddy 的完整模型调用需要凭据和网络无密钥测试验证契约与错误路径;真实服务只在受控环境验收,不提交凭据
回滚新 bundle 或构建产物可能无法在旧运行时加载发布前保留旧 FPK;回滚只恢复应用和依赖版本,不删除用户数据
CLI 迁移DSH CLI 的 plugin 命令实际转发给 pnpm,应用自定义脚本与官方行为可能不一致以本地 dsh-v0.1.5-rc.2apps/cli/src/plugin.ts 为准,使用 fake CLI 夹具和客户端组合入口验证
内置包来源DSH CLI 不会自动读取 FPK 的 bundled-dsh-plugins 目录实施时移除本地复制路径,或改用 DSH CLI 支持的精确版本包 spec;不得绕过 CLI
跨用户调用由普通用户调用的入口无法切换身份,会以调用者身份运行并污染 profile 权限不暴露该入口;需要 CLI 时由应用包用户在应用私有路径直接调用,并用 id、环境和文件所有权验证
公开入口篡改入口或其依赖可写时,调用者可替换真实 CLI 或修改 DSH 配置不注册公开入口;真实 CLI、Node/pnpm 和配置由受控所有者维护,非应用用户无写权限
Token 竞态重启时旧缓存、旧文件和新进程输出可能交错,导致页面继续携带旧 Token使用重启轮次、锁、原子文件替换和刷新中状态;并发请求只等待新 Token 或返回可恢复响应
Token 持久化异步写文件可能尚未完成就更新内存,或留下半截文件写临时文件并完成持久化后再 rename 和发布内存值;写入失败直接进入错误状态
投影可用性modelSelection 投影缺失或尚未送达时读不到选中模型,可能导致图标该显示时不显示缺失一律按不显示处理并保留其余前置条件;不缓存首次结果,投影到达后随即重算
供应商标识漂移dock 组件里再写一份 provider 字符串,后续改名会出现两边不一致复用各插件已有的 provider 常量或注册名,测试断言显隐与常量同源
轮询残留图标隐藏后仍保留定时器,会在看不见的情况下继续请求用量接口供应商判断置于挂起轮询之前或纳入 effect 依赖,隐藏状态不建立定时器并用测试断言
遮蔽失效与官方条目同 priority 会让注册直接抛错,插件整体加载失败使用更低 priority 并写断言固定该值;只影响 fnOS iframe,独立浏览器不注册
上游变更官方 idorder 或插槽名变化会让遮蔽目标失配断言固定被遮蔽的 id 与插槽名,上游变更时测试先失败而不是静默出现两个入口
SDK 差异openFileManager 在非 web carrier 或旧宿主上不存在沿用既有 createTrimApp()isWeb/isStandaloneWeb 校验,失败给出可见提示而不回退到 NAS 上不存在的 xdg-open
静态资源泄露路径插件静态路由若直接拼接请求路径,可能被路径穿越读取包外文件只按固定资源名映射到已知文件,未命中即 404,不拼接用户输入
上游取数认证信息缺失原实现调用的 apiProxy 全仓与上游都没有提供方,改为 loopback 后若不转发浏览器 Cookie,DSH browser-session 仍返回 401回源请求 DSH 已注册的 /api/session.export 时转发当前请求的 dsh-auth-* Cookie;loopback 只免 Host/Origin 信任检查,不免 browser-session 认证;行为测试覆盖 Cookie 转发、loopback 回落与非 2xx 透传
内置插件同版本号不更新pnpm 对相同 spec 只看 node_modules/.modules.yaml 与 lockfile integrity;归档内容变了也报 Already up to date,安装后仍跑旧代码(install --force--fix-lockfileupdaterebuildstore prune 实测均无效)捆绑插件不比较版本,覆盖前通过 DSH CLI remove 再以同一 spec add;测试断言 remove→add 顺序,并用真实 pnpm 端到端验证
CLI 覆盖操作失败remove 成功后 add 失败会让插件暂时缺失生命周期立即返回非零,保留 profile 依赖/bundle 记录,下一次安装可重新 add;错误日志包含插件名和归档路径
头部条目顺序静默反转两个条目的 priority/order 一旦打平,位置改由注册顺序决定、与官方相反,且不会报错取值集中在 header-utility-seats.ts 并由测试用真实 SlotCore 注册后断言最终顺序;index.ts 必须以展开方式使用该座位(契约测试断言展开写法,防止改回硬编码)
资源未随包发布package.jsonfiles 只含 lib,构建若不拷贝资源则运行时 404在 node 构建的 onSuccess 中把资源拷入 lib/assets/,并用测试断言产物中存在该文件

测试、打包和发布

插件与共享包检查

bash
pnpm --filter @tnnevol/dsh-fnos run typecheck
pnpm --filter @tnnevol/dsh-fnos run test:unit
pnpm --filter @tnnevol/dsh-fnos run build
pnpm --filter @tnnevol/dsh-codex-auth run typecheck
pnpm --filter @tnnevol/dsh-codex-auth run test:unit
pnpm --filter @tnnevol/dsh-codex-auth run build
pnpm --filter @tnnevol/dsh-codebuddy run typecheck
pnpm --filter @tnnevol/dsh-codebuddy run test:unit
pnpm --filter @tnnevol/dsh-codebuddy run build
pnpm --filter @tnnevol/dsh-semi-ui-showcase run typecheck
pnpm --filter @tnnevol/dsh-semi-ui-showcase run test:unit
pnpm --filter @tnnevol/dsh-semi-ui-showcase run build
pnpm --filter @tnnevol/dsh-semi-ui run typecheck
pnpm --filter @tnnevol/dsh-semi-ui run test:unit
pnpm --filter @tnnevol/dsh-semi-ui run build

应用与文档检查

bash
pnpm install
pnpm run typecheck
pnpm run build -- --fpk --app fn-deepseek-harness
pnpm run check -- --sdd
pnpm run build -- --docs
git diff --check

本地构建只能证明依赖、脚本和产物结构正确,不能代替真实 NAS 验收。若当前环境无法访问 NAS,阶段保持“规划中”,并将缺少的环境证据标为阻塞项。

当前 DSH 客户端验证

  • 使用本地官方 Harness checkout 的 dsh-v0.1.5-rc.2 组合入口,验证 Codex Auth、CodeBuddy、Semi UI 及共享包的插件加载、关键 UI、Remote/Host 和错误路径。
  • 在同一入口验证用量图标的供应商显隐:分别选中 Codex 与 CodeBuddy 模型,确认只有对应图标出现;关闭 CodeBuddy showUsage 后选中其模型仍不显示;两处切换过程不刷新页面、不丢草稿。
  • 保存客户端版本、启动命令、插件加载日志、测试结果和失败场景证据;需要外部服务时使用测试凭据或 mock,不写入真实密钥。
  • fnOS 原生文件入口的遮蔽与外观在独立浏览器中无法验证:isEmbeddedFnosFrame() 为真才会注册,且 openFileManager 需要 fnOS 宿主桥接。该功能的验收在真实 fnOS NAS 的 iframe 内完成,本地只覆盖 iframe 判定、注册参数、工作目录判定和 SDK 调用分支的单元测试,不把本地结果当 NAS 结论。

真实 NAS 验证

  • 使用新 FPK 完成全新安装,确认 DSH Web 入口、应用网关和 dsh-fnos 插件加载。
  • 在应用升级场景确认已有 DSH_HOME、profile、凭据、工作区和会话仍可读取,并确认老用户已有 Codex 和 dshmarket 安装不被清理;同时验证内部重启后的 Token 刷新。
  • 在真实 NAS 确认应用包用户能执行 DSH 和 pnpm,profile 初始化、FPK 插件管理和 dsh-fnos 加载成功;非 fnOS 插件使用当前 DSH 客户端证据,不重复要求在 NAS 安装。
  • 在 NAS 验证 HTTP、SSE、WebSocket、iframe 页面、fnOS API/路径和 DSH Web 刷新,并记录 Token 轮换前后的状态和响应;非 fnOS 插件不重复要求在 NAS 安装。
  • 保存 dsh --version、应用日志、fnOS 插件加载结果、网关请求和失败场景证据,写入 docs/validation/ 后才能回写完成状态。

发布和回滚

  • 仅在插件级检查、FPK 构建和真实 NAS 验收都通过后发布 DSH 0.1.5-rc.2 适配包。
  • FPK 产物名称包含 dsh-0.1.5-rc.2,发布说明标明该版本基线和已验证环境。
  • 回滚使用上一份完整 FPK 和对应 native 依赖;不得通过回滚删除用户数据或清空 DSH profile。

参考资料

能力用途参考资料
DSH CLI 与 profile版本启动、Web profile、参数边界和组合层行为DSH CLI 与 profile 参考DeepSeek Harness 源码
DSH 插件开发Cordis 生命周期、Remote、附件和组合插件契约DSH 扩展开发DSH Slots
fnOS 应用框架cmd/install_callbackcmd/main 和生命周期边界fnOS 应用框架
fnOS 环境变量${TRIM_*} 路径和应用配置边界fnOS 环境变量
fnOS 应用权限包用户、运行权限和最小权限边界fnOS 应用权限
fnOS FPK 构建应用构建和真实设备安装路径fnOS fnpackfnOS 应用测试
本地 DSH 源码目标 tag 的源码、生成类型和构建命令~/workspace/fork-pj/deepseek-harnessdsh-v0.1.5-rc.2,commit fb2c4b9e698e30edb738bca4cf0618587db7d203(只读参考,不修改)

完成状态

阶段状态完成条件
P0 DSH 依赖基线已完成catalog、锁文件、版本常量和 native 配置统一到 0.1.5-rc.2
P0 插件兼容性迁移已完成四个插件及共享包完成类型检查、单元测试、构建和组合入口验证
P0 Codex 默认捆绑恢复已完成新 FPK 内置并安装与 0.1.5-rc.2 适配的 Codex;老用户升级不卸载、不删除、不覆盖已有用户数据
P0 DSH CLI 插件管理已完成固定 DSH/pnpm、使用官方 CLI 自动初始化 profile、add/update 和 bundle 写回;移除旧插件脚本及重复初始化逻辑
P0 dshmarket 固定安装已完成缺失时通过 DSH CLI 安装 dshmarket@1.46.1,已存在时跳过并保留原版本
P0 应用私有 dsh CLI已完成不注册公开入口,固定应用包用户环境并保护真实 CLI 与配置权限
P0 内部重启 Token 刷新已完成重启期间失效旧 Token,捕获并原子持久化新 Token,代理请求等待新状态
P1 发布升级回滚一致性已完成构建前版本门禁、升级幂等、失败恢复和发布证据可追溯
P0 FPK 构建已完成FPK 构建成功,安装后 DSH 版本和启动入口正确
P0 用量图标按模型供应商显隐已完成两个用量图标只在选中对应供应商模型时挂出,切换即时生效且隐藏时不轮询
P1 fnOS 原生文件入口已完成fnOS iframe 内遮蔽官方「打开应用」,用 fnOS JS SDK 提供文件管理器入口;静态资源走插件自有前缀
P1 当前 DSH 客户端验证已完成Codex Auth、CodeBuddy、Semi UI 和共享包完成组合入口与关键行为验证
P1 fnOS NAS 验收已完成Web、网关、dsh-fnos、Codex 老用户保留、升级数据保留和失败路径均有 NAS 证据

本计划汇总 FNOS-004-01FNOS-004-09。其中 FNOS-004-06以发布、升级和回滚一致性门禁形式实施,不新增独立运行时能力;FNOS-004-08 只收敛两个用量图标在输入框 dock 的挂出条件。

变更记录

日期变更说明
2026-09-12建立 PLAN-FNOS-004仅将 FNOS-004-01 DSH 与插件适配 0.1.5-rc.2 纳入当前实施计划,明确依赖基线、插件迁移、FPK 构建和 NAS 验收边界
2026-09-12固定上游适配依据确认本地官方 Harness checkout 已切到 dsh-v0.1.5-rc.2,后续以 commit fb2c4b9e698e30edb738bca4cf0618587db7d203 的源码和生成类型为准
2026-09-12纳入 FNOS-004-02增加 Codex 默认捆绑策略、新用户/老用户升级差异、非破坏性安装回归和 FPK/NAS 验收任务
2026-09-13改为恢复 Codex 默认捆绑原「移除 Codex 默认捆绑」被证伪:registry 上 Codex 的 latest/rc 基线过旧,安装后 DSH Web 因 settingsNamespace 缺失启动失败;改为 FPK 内置 Codex 归档并按清单精确版本安装,保留非破坏性升级约束
2026-09-12纳入 FNOS-004-07将 FPK 插件管理迁移到目标 tag 提供的 DSH CLI,固定 DSH/pnpm/插件版本并移除自定义安装脚本
2026-09-12纳入 FNOS-004-03通过 DSH CLI 安装固定版本 dshmarket@1.46.1,已安装时跳过且不覆盖用户插件
2026-09-12纳入 FNOS-004-04增加应用 bin 中的 dsh CLI wrapper,固定运行环境并强制真实 CLI 使用应用包用户权限
2026-09-13修订 FNOS-004-04NAS 复现 runuser: only root can specify alternative groups;平台无非 root 身份切换机制,改为不注册公开 dsh 入口,并在构建校验中拒绝重新引入 wrapper
2026-09-12纳入 FNOS-004-05增加内部重启 Token 的失效、捕获、原子持久化、代理等待和 NAS 并发回归任务
2026-09-12纳入 FNOS-004-06增加构建版本门禁、升级幂等、失败恢复、回滚入口和发布证据追踪任务
2026-09-13统一插件发布版本四个运行时插件发布版本由 0.1.5-rc.2.4 改为 0.1.5-rc.2,与 DSH 运行时基线同号;同步 package.json、发布清单和文档,dshPluginApi.version 仍单独承载兼容基线
2026-09-13纳入 FNOS-004-08增加用量图标按选中模型供应商显隐计划:读取 modelSelection 投影的 provider,Codex 与 CodeBuddy 各自只在选中本家模型时挂出,切换即时生效,隐藏时不建立用量轮询
2026-09-13完成 FNOS-004-08T11-01T11-06 落地(35f0e70):新增 @deepseek-ai/dsh-client-ui-session 类型依赖与座位标准套件导入,CODEX_PROVIDER 移至 contracts/,显隐合取收敛为纯函数;AC-01 经 DSH 客户端浏览器实测通过,AC-02/AC-03/AC-04 待补人工复现
2026-09-13纳入 FNOS-004-09增加 fnOS 原生文件入口计划(T12-01T12-05):在 fnOS iframe 内以同 id、更低 priority 遮蔽官方「打开应用」,用 Semi UI 还原锚点与下拉菜单,并以 fnOS JS SDK 的 openFileManager 打开会话工作目录;预览与编辑器因只支持文件路径而不在本轮范围
2026-09-13补充 FNOS-004-09 静态资源方案新增 T12-06:插件静态资源不再内联,改由插件注册 /fnos-plugins/static/dsh-fnos 路由返回包内资源,网关把 /fnos-plugins/static 加入内置前缀;不读取 fnOS 宿主静态目录,也不放宽既有图片补前缀规则
2026-09-13补充 FNOS-004-09 头部布局任务新增 T12-07:对齐官方左右顺序并把顺序取值集中可测;Session log 改为纯图标按钮
2026-09-13修复 FNOS-004-09「导出到 NAS」上游取数新增 T12-08:数据源由不存在的 apiProxy 注入服务改为回源 /api/session.export
2026-09-13新增 FNOS-004-07 内置插件强制覆盖新增 T12-09:捆绑插件每次安装按 FPK 归档覆盖(不比较版本),并约束删除路径的推导与校验
2026-09-14内置 CodeBuddy RPC 频道进网关新增 T05-05:把内置插件的浏览器同级路由 /codebuddy 加入网关内置前缀,用户无需在设置页手工登记;补充 FNOS-004-02-AC-06
2026-09-13修复 FNOS-004-09 presented-file 打开新增 T12-10/api/present.open 在 fnOS 上报 409 Host desktop unavailable,改为经插件解析真实路径后调用 fnOS SDK;present.host 在 iframe 内报可用;tooltip 改为动态模板
2026-09-14PLAN-FNOS-004 全部完成并验收根据用户确认,T01T12 全部任务及对应验收条件完成并通过验收;计划状态更新为已完成

基于 VitePress 构建