description: "dsh profile 与临时 Python SDK 运行时的共享 Loader 启动支持:环境层、patch、诊断与配置预览。"
English | 中文
dsh-app-boot 是 dsh profile(包括 Python 运行时 wheel 包所含的 CLI(命令行界面))背后的共享 Loader 启动库。它加载环境层、组合 profile 组合包与 patch、启动每个插件,再返回运行中的应用,或指出失败插件与原因。产品应用使用 dsh launcher 而不发布单独 bin;直接配置 helper 只保留给低层嵌入方与测试。你还可以在启动前预览生效配置,按 profile 选择实时或仅启动时应用 patch,并让持有终端的应用在致命退出前恢复终端。
用此包启动应用是一个小而显式的入口:你给它一个配置文件,它运行整个启动过程。本节说明你能做什么、能得到什么;每个结果背后的 helper 调用记录在下方可折叠的实现章节中。
在实现共享 dsh launcher 或嵌入其低层启动 helper 时使用它。产品功能应放入 profile 组合包,而不是新增应用 bin;只向已运行应用添加插件的代码直接挂载插件即可。
你把配置文件交给入口,进程就会启动整个应用:加载环境层、应用 patch 与 profile、启动每个插件,并在应用运行后返回。在回放模式下,它会启动同级的 cordis.snapshot.yml 替代文件,使已记录的会话能够原样复现。最小的入口只需两次调用:
installFailLoud('dsh')
const ctx = await boot('dsh', resolveConfigPath(argv[2], process.env.DSH_SNAPSHOT))
有了这个入口,启动会保留所有能够激活的插件。启用但失败的插件会产生带标签的警告。required entry 失败时,启动会拆卸整个应用并以非零码退出;profile 中不存在的 required id 和已禁用的 required entry 不影响启动。全局 required list 覆盖共享 Agent 执行、应用 endpoint,以及 Web 启动与传输:agent-loop、webserver、modules、connection、headless-runner、acp 和 sdk-jsonrpc-server。
Profile 与组合包的声明类型从 @deepseek-ai/dsh-package-manifest 导入。App-boot 将 DshPackageManifest 适配为包身份可选的 ProfileManifest,因为本地 profile 无需发布版本。App-boot 负责 profile 加载、JSON 校验和解析后的运行时数据。
profile 是同一套 dsh 安装提供不同应用界面的方式:web、headless、acp、sdk 与 sdk-minimal 从同一 launcher 启动不同组合。profile 位于 $DSH_HOME/profiles/<name>,由可安装组合包、自身 cordis.patch.yml 与 patchReload: live | startup 组成;自定义 profile 省略 reload 策略时保留历史 live 默认值。随产品交付的 web 模板实时重载,其他随附模板只在启动时应用 patch。sdk-minimal 只列出自身的独立组合包,其他模板保留 base 加模式的组合包栈。dsh --profile <name> --from-default-profile <template> 从一个随附模板,在新的非内置名称处创建自定义 profile;dsh plugin 则初始化以 base 为基础的 profile,并管理其中安装的组合包。缺失组合包或未声明 patch 的组合包会让启动明确失败。由应用持有的 npm 项目(例如 Electron 保留的 Desktop profile)通过 loadProfileDirectory 加载已经初始化的目录,而不会将它暴露给 CLI profile 查找。
你的机器本地偏好同样位于 harness home 中:
.env——你的普通环境层:调用目录的文件优先于 harness home 的文件,两者都低于继承环境。在文件中设置的进程启动变量(如 PATH、DSH_*、XDG_*)会被拒绝:请改为导出这些变量。四个代理名(HTTP_PROXY、HTTPS_PROXY、ALL_PROXY、NO_PROXY)只从 harness home 的文件接受,绝不从调用目录的文件接受——后者随 clone 一起到来。对于只想加载某个目录 .env 的非产品 bin,文件缺失不影响启动,文件无法加载时输出一行带标签的警告。cordis.patch.yml——你的 tweak 层,应用在所有组合包层之后(先应用逐 profile 的文件,再应用 home 级文件,因此后者优先级更高):替换某个条目的整个配置(重述你要保留的字段)、插入新条目,或在启动时插值 !!js 表达式。patch 指定的条目不存在时输出 stderr 警告;空文件或仅含注释的文件会导致启动失败——如需禁用该层,请改用 []。带 patchReload: live 的 profile 会监视两份用户 patch 文件,并应用重载失败策略。startup profile 既不安装这些监视器,也不安装 launcher 的仅监视 HMR(热模块替换)回退。
插入条目的插件名可以是绝对文件系统路径、文件 URL 或包标识符。patch 加载会把 insert 条目及其嵌套分组中的绝对路径以及相对于 patch 文件的 ./ 或 ../ 路径转换为文件 URL;对已有条目名称的断言及替换用的 config 值保持原样。
启动前,你可以打印应用将挂载的确切配置:dump 会以 !!js 表达式原样展示组合后的条目列表,并按注释分组标明每个源文件及其 patch 层,输出是一份可加载的 YAML 文档。未匹配到任何行的 patch 会连同其层标签一起报告;配置缺失、无法解析或字段无效都会使 dump 失败。
Loader 结算后,app-boot 将 optional 失败报告为警告;若已启用的 required 条目无法激活,则拒绝启动。表中的“终止启动”指释放已挂载插件并以非零码退出,不报告就绪;“继续”指保留成功运行的插件。后续配置 HMR 不会再次执行 required 启动审计,也不会回滚整个更新。
| 失败模式 | Optional 条目启动时 | Required 条目启动时 | 后续配置 HMR |
|---|---|---|---|
| 根配置或必需 overlay 缺失、不可读、格式错误,或包含无效条目 | 终止启动 | 终止启动 | 拒绝格式错误或无效的实时 patch,不改变运行中的配置;有效修改可以应用 |
| 模块 import 失败或模块求值抛出异常 | 警告;继续 | 终止启动 | 报告错误;保留成功的兄弟插件;修正 import 后可以激活 |
| 插件配置 schema 校验失败 | 警告;继续 | 终止启动 | 新条目保持未激活;现有条目保留原实例与配置;有效修正可以应用 |
配置 !!js 求值抛出异常 |
警告;继续 | 终止启动 | 报告错误;保留成功的兄弟插件;有效修正后可以激活 |
disabled: !!js 求值抛出异常 |
警告;继续 | 终止启动 | 报告求值错误,不将条目当作已禁用;有效修正后可以激活 |
同步 apply() throw |
警告;继续 | 终止启动 | 报告错误;保留成功的兄弟插件;修正配置后可以激活 |
异步 apply() throw |
结算后警告;继续 | 结算后终止启动 | 结算后报告错误;保留成功的兄弟插件;修正配置后可以激活 |
| 注入的服务不可用 | 警告;继续,条目等待依赖 | 终止启动 | 条目继续等待;补上缺失的提供方后可以激活 |
| HTTP 端口绑定失败 | 警告;继续,但该端点不可用 | 终止启动 | 进程继续运行,但失败的端点不可用;修正配置后可以恢复 |
脱离 apply() 返回 Promise 的异步任务产生未处理 rejection |
致命错误:释放应用并以非零码退出 | 致命错误:释放应用并以非零码退出 | 致命错误:释放应用并以非零码退出,与条目 id 无关 |
| 条目缺失或被显式禁用 | 忽略 | 忽略 | 不激活该条目;不执行 required 启动审计 |
上面的 required 列表包含 modules 与 connection;只要其中一个已启用条目失败,Web 就无法成功启动。Optional 提供方失败也可能使 required 消费方无法激活。现有条目的新配置在更新前被 schema 校验拒绝,并不等于对兄弟插件的变更做事务回滚。
Web 进程矩阵和启动验收测试通过随附 Web profile 验证这些结果;app-boot 测试还覆盖根 Include 失败。
如果你的应用持有终端,它可以在进程退出前把终端交还,你的 shell 绝不会残留在 raw 模式。交还过程有界:卡住的清理只会延迟致命退出,而不会取消它。
当你的应用启动模型驱动的 agent 时,你可以告诉 agent DSH 实现代码 checkout 的位置:它得知该路径,也知道不得据此推断工作目录——它应使用 pwd。这条指示在系统提示词靠前位置出现一次。没有系统提示词服务的应用会跳过;开发环境中,重新加载系统提示词后它会消失,直至下次启动。
当包级约定不够用时阅读以下页面。它们从共享启动机制逐步进入组合模型及其背后的决策证据。
!!js 配置表达式,以及 include/group 语义。dsh bin。dsh --profile 的可安装 patch 层。resolveDshHome)。模型通过此包加载的插件树间接受影响——只有该树贡献模型上下文;唯一贡献模型可见文本的导出 addHarnessSourceSection,也只有在消费方启动后调用它时才会产生影响。
启动本身不改变请求前缀。addHarnessSourceSection 将源码路径放在第一方可复用指令之后,因此工具与配置一致时,不同 checkout 不会改变前置字节。不保证提供方复用缓存。
这些限制说明此启动库在何时不合适,或何时需要特别注意。它们是当前包约束,不是任务积压。
cordis.yml 或 cordis.yaml 结尾的配置会映射到同级 cordis.snapshot.yml;自定义配置名称需要调用方自行选择。loadLayeredEnv 只读取一次调用目录与 harness home 中的 .env;它不搜索父目录,也不跟随之后选择的 workspace。loadEnv 仍是非产品 bin 使用的单目录 helper。