DeepSeek Harness 双模式示例启动:从 tsx 源码回路到构建产物 lib 的 CI 严格验证
DeepSeek Harness 双模式示例启动从 tsx 源码回路到构建产物 lib 的 CI 严格验证【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness本篇技术指南以仓库归档决策笔记 .agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.md状态implemented为核心骨架讲解 DeepSeek Harness 中示例与 Cordis 测试项目在 CI 与本地开发中的双模式启动机制。读者将掌握srctsx 源码回路与lib构建产物 strict 模式两种启动方式的工作原理、DSH_EXAMPLE_MODE环境变量的选择策略、共享 Loader 测试 harness 的落地实现以及如何在仓库中配置、运行并验证这类示例冒烟测试。背景问题为什么 CI 必须与本地使用不同的启动方式在双模式机制引入之前CI 通过node --import tsx配合根 tsconfig 的paths映射来启动示例以及加载 Cordis 配置的测试项目。该做法存在两个结构性问题TypeScript 转换开销每次子进程启动都要经过 tsx 的运行时转换包解析行为失真由于paths映射的存在import语句解析到的是 workspace 中的源码而不是经包exports字段进入构建后的lib/目录。后者的影响最为致命测试运行的代码与解析路径和真实安装消费方实际经历的完全不同。其后果正如笔记所总结的——一个包即使构建导出图不完整或解析结果不同CI 仍可能通过A package can pass CI while its built export graph is incomplete or resolves differently。这正是该决策笔记要消除的验证盲区。核心决策src / lib 双模式执行机制笔记确立的执行机制包含两种模式彼此互补模式用途启动方式包解析方式典型场景src本地开发默认模式node --import tsx srcBin并设置TSX_TSCONFIG_PATH通过 tsconfigpaths映射解析到 workspace 源码免构建的本地开发回路lib严格 CI 模式plain Node 直接启动构建后的 binnode libBin不加载 tsx、不使用 paths 映射裸包经真实exports进入lib/CI 验证构建产物模式的适用边界非常明确CI 中启动示例、或启动签入仓库的cordis.yml的子进程一律使用lib模式仅实现 ACP 或 MCP 对端、且不加载 Cordis 的 TypeScript fixture直接由 Node 运行依赖 Node 内置的类型剥离能力只有显式验证源码路径的回归测试可以保留src模式。这一设计的核心动机是测试必须覆盖已安装消费方实际运行的代码与解析路径而不是让 CI 反复通过一套与消费体验脱节的模拟环境。源码落地dsh-loader-smoke 的 mode-aware 启动解析器双模式机制的共享实现位于 packages/test-support/loader-smoke/src/index.ts该包在 README 中定位为support-tier test infrastructure, not a product API。模式解析resolveExampleMode环境变量名与解析规则在源码中有严格定义EXAMPLE_MODE_ENV DSH_EXAMPLE_MODEsrc/index.tsresolveExampleMode()读取该变量undefined/ 空串 /src返回srclib返回lib其余任何值直接抛错——a typo in a gates env fails loud避免拼写错误被静默吞掉。也就是说CI 设置DSH_EXAMPLE_MODElib本地开发不设置该变量即自动退回src的快速源码回路。启动解析resolveExampleLaunch核心函数resolveExampleLaunch根据模式生成完整的 spawn 参数command / args / env其两种分支的行为如下src 模式node --import tsx srcBin configArgs # env 中额外设置 TSX_TSCONFIG_PATHtsconfigPath其中 tsx loader 通过import.meta.resolve(tsx)或tsx/esm解析TSX_TSCONFIG_PATH指向仓库根 tsconfig使 workspace 内未构建的裸包 import 经paths映射解析到源码。此模式要求调用方必须传入tsconfigPath否则直接抛错。lib 模式node libBin configArgs # 不附加任何 tsx 相关 env裸包插件通过真实exports解析到构建后的lib/相对路径的 example-local TypeScript 插件则以源码形式由 Node 内置类型剥离加载。libBin可由srcBin自动推导toLibBin将pkg/src/name.ts中的/src/段替换为/lib/并把.ts换成.jssrc/index.ts测试 fixture 也可通过libBin显式指定 plain-Node 入口。解析拓扑让每个测试 Cordis 配置都能解析裸模块笔记规定了一条全局约束每个测试 Cordis 配置都必须能从配置文件所在目录向上解析裸模块。具体拓扑规则有三条共享解析根examples/作为 pnpm workspace 的一个成员提供统一的examples/node_modules解析根。在当前仓库中该约定落地为 packages/examples/成员包如 packages/examples/agent-spine-demo其 peer/devDependencies 中声明了deepseek-ai/cordis、deepseek-ai/dsh-agent等一整套 workspace 依赖。配置归属映射所有签入仓库的测试 Cordis 配置含快照配置与包内 fixture都放在对应的examples/agent/目录树下归属packages/group/package/的配置映射为examples/agent/tests/fixtures/group/package/cordis.yml而测试驱动与断言仍留在包内。当前仓库中可以观察到大量该约定的实例例如 apps/cli/tests/fixtures/github-webhook/cordis.yml、packages/subagent/subagent-acp/tests/fixtures/loader/cordis.yml、packages/session/session-telemetry-otel/tests/fixtures/cordis.yml。双登记示例 Cordis 配置中引用的每个包都同时登记在examples/package.json支持lib模式下的裸包解析与根tsconfig.json的 references支持src模式的 paths 映射中。当前 loader-smoke README 也重申了这一约束the owning package manifest must also declare every package named by the config。这套拓扑的设计意图很朴素与其为每个测试单独构造一份消费方脚手架重复且容易漂移不如让每个 Cordis 配置共享同一条真实且显式声明的解析路径。启动策略DSH_EXAMPLE_MODE 如何串联测试与 CI共享 Loader harnessrunLoaderSmoke模式选择由共享的 Loader 测试 harness 统一完成。runLoaderSmokesrc/index.ts负责完整的子进程生命周期创建隔离临时 cwd、注入隔离的DSH_HOME与DSH_AGENTS_HOME、立即关闭 stdin、等待干净退出、在任何结局下清理临时目录。其核心参数如下参数含义label失败诊断中的人类可读示例名tempDirPrefix隔离临时 cwd 前缀binScriptapp bin 的 TS 源码入口pkg/src/bin.tslibbin 由它推导libBinScriptlib 模式显式 plain-Node 入口用于包外 fixtureconfigPath真实 Loader 配置路径默认作为唯一 bin 参数binArgs完整 argv覆盖默认的[configPath]tsconfigPath仓库 tsconfig 路径src模式必需mode显式指定src/lib默认取环境变量env叠加在隔离 home 之上的环境覆盖processTimeoutMs进程截止时间默认 30sprepare/inspect启动前世界状态准备 / 清理前断言钩子expectedExitCode期望退出码用于固定设计中的失败面任何其他结局包括成功都判失败harness 的失败诊断非常完备超时timedOut、退出码不符、spawn 错误都会同时携带完整 stdout/stderr 抛错且通过SIGKILL保障截止时间的强制执行。CI 门禁中的接线模式选择在 CI 门禁层面由 scripts/run-gates.ts 统一接线所有需要构建产物的门禁都显式设置DSH_EXAMPLE_MODE: lib并依赖build门禁snapshotGate()pnpm run test:snapshotenv: { DSH_EXAMPLE_MODE: lib }needs: [build]run-gates.tsexpectedOutputGate()pnpm run test:expected同样设置DSH_EXAMPLE_MODE: librun-gates.tsbuiltBinSmokeGate()针对 built-bin 冒烟测试的 e2e 集合设置DSH_EXAMPLE_MODE: librun-gates.ts在ci-consumers聚合中build→built-package-invariants→ snapshot / expected-output 的依赖顺序确保了先构建、后以 lib 模式验证的严格链路。此外vitest.snapshot.config.ts 中DSH_EXAMPLE_MODE lib还会额外纳入 Web 端快照测试apps/web/tests/**/*.snapshot.ts而 scripts/ci-workflow.spec.ts 也对这一环境变量组合做了工作流级断言。手动运行与本地回路本地快速验证不设置DSH_EXAMPLE_MODE直接pnpm run test:snapshot即走src的免构建源码回路手动验证构建产物先pnpm run buildpackage.json 中build脚本为tsx scripts/build.ts再DSH_EXAMPLE_MODElib pnpm run test:snapshot注意手动执行lib模式时可能读取到陈旧的本地构建产物因此必须在每次代码变更后重新构建。测试验证harness 自身的契约用例packages/test-support/loader-smoke/tests/loader-smoke.spec.ts 通过真实 spawn 路径逐条验证了 harness 契约隔离性src模式下子进程 stdout 中回显的DSH_HOME/DSH_AGENTS_HOME必须位于临时 cwd 之下且运行结束后临时目录被彻底清理任意 argv 透传binArgs: [--config, configPath, --output-format, json, ...]原样到达子进程prepare/inspect钩子可写入并断言世界状态非零退出诊断退出码 7 且未声明expectedExitCode时错误信息携带完整双流输出预期失败面声明expectedExitCode: 7后进程以 7 退出则通过反而以 0 退出仍判失败exited 0 (expected 7)截止时间强制挂起 fixture 在processTimeoutMs: 100下被SIGKILL错误信息为 did not exit within 0.1s.。在真实消费方侧packages/subagent/subagent-acp/tests/subagent-acp.e2e.ts 展示了resolveExampleLaunch的典型用法以apps/cli/src/bin.ts为srcBinsourceImport: tsx/esmconfigArgs: [--profile, acp, --patch, exampleConfig]tsconfigPath指向根 tsconfig.json。该 e2e 用真实子进程驱动 ACP 对端完成一次模型回合并独立断言文件系统副作用proof.txt内容包含约定标记与模型响应文本互相印证——这正是lib 模式验证真实解析路径设计目标在跨进程边界上的体现。曾考虑的替代方案笔记明确记录了三个被评估后否决的方案方案否决理由CI 继续使用 tsx保留转换开销与仅适用于源码的解析行为问题依旧存在所有环境一律使用 lib本地开发每次运行前都必须构建把成本带入了开发回路每个测试单独构造私有node_modules重复消费方脚手架且易与实际安装行为漂移以examples/作为 workspace 根提供单一真实解析路径更优双模式方案正是对这三者的取长补短CI 的严格性不牺牲本地开发的速度。工程后果与维护约束决策落地后带来如下明确的后果也是后续维护者必须遵守的约束收益CI 验证构建后的包导出不再受 tsx 改变模块解析的影响本地开发保留免构建的源码回路。二者各得其所。代价一构建前置。CI 必须在这些测试之前先构建手动lib运行可能观察陈旧的本地产物。代价二依赖同步。常规 TypeScript import 分析无法识别 Cordis 配置的依赖因此examples/package.json当前为各成员包的 workspace 依赖声明、根 tsconfig references 与配置文件三者必须保持同步——任何一方遗漏都会造成src/lib两模式解析行为不一致而这恰恰是本机制要消灭的验证盲区。延伸阅读决策笔记中文版.agents/notes/archived/process/2026-07-17-run-ci-examples-from-built-lib.zh.md共享 harness 实现packages/test-support/loader-smoke/src/index.ts 与 使用文档CI 门禁接线scripts/run-gates.tssnapshotGate/expectedOutputGate/builtBinSmokeGate快照测试配置vitest.snapshot.config.ts、vitest.expected.config.ts跨进程消费示例packages/subagent/subagent-acp/tests/subagent-acp.e2e.ts测试策略总览docs/testing.md【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考