@deepseek-ai/dsh-loader-smoke 0.1.5-rc.2 → 0.1.6-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/test-support/loader-smoke/README.md
5
- README.md: dd618358aeb6dca2fbaf3a4945d09aa529b28f48
6
- README.zh.md: 14a812aba42625474e73a0770b3184ec8c7f2463
5
+ README.md: 2b903a1a4ecd558b8839dba082b9c3ee0b9fdaa4
6
+ README.zh.md: a207804e158745adcc5b2a41fa0892b60ad33d84
package/README.md CHANGED
@@ -29,7 +29,7 @@ This package boots an application fixture the way an installed consumer would an
29
29
 
30
30
  ### Booting an application fixture
31
31
 
32
- `runLoaderSmoke` takes bin and config paths, optional complete bin arguments, environment overrides, stdin, pre-run setup, and pre-cleanup inspection. It owns the isolated cwd, DSH homes, diagnostics, deadline, termination, EOF, and cleanup, and returns both streams after a zero exit or rejects with both streams on failure:
32
+ `runLoaderSmoke` takes bin and config paths, optional complete bin arguments, environment overrides, stdin, pre-run setup, and pre-cleanup inspection. It owns the isolated cwd, DSH homes, diagnostics, deadline, termination, EOF, and cleanup of a cwd it created (a caller-provided cwd is left in place), and returns both streams after a zero exit or rejects with both streams on failure:
33
33
 
34
34
  ```text
35
35
  const result = await runLoaderSmoke({
@@ -45,7 +45,7 @@ Set `expectedExitCode` when the scenario pins a designed failure surface — a o
45
45
 
46
46
  ### Testing a shipped profile
47
47
 
48
- Profile integration drivers use the repository-only `tests/fixtures/production-profile.ts` helper. It loads the named shipped profile and its bundle patches through `loadProfile`, reconciles the profile's module fallback, and passes the bundle patches followed by the test's `*.patch.yml` files to the root `cordis:include` mounted by `boot`. Those patches should contain only the test provider or model, isolated persistence paths, and subject-specific changes. Package-level unit tests that need an agent loop without profile integration mount `dsh-agent-loop-testkit` locally instead.
48
+ Profile integration drivers use the repository-only `tests/fixtures/production-profile.ts` helper. It loads the named shipped profile and its bundle patches through `loadProfile`, materializes the retained link-mode fallback, mounts `PluginPackages` with native lookup as the link-mode launcher does, and passes the bundle patches followed by the test's `*.patch.yml` files to the root `cordis:include` mounted by `boot`. Those patches should contain only the test provider or model, isolated persistence paths, and subject-specific changes. Package-level unit tests that need an agent loop without profile integration mount `dsh-agent-loop-testkit` locally instead.
49
49
 
50
50
  ### Driving a fixture turn
51
51
 
@@ -73,7 +73,7 @@ This section explains the design of the harness; the observable behavior is full
73
73
 
74
74
  ### Design
75
75
 
76
- The harness is built on one separation: the smoke runs in a child process under an isolated world, and the test process only observes and asserts. `runLoaderSmoke` creates a temporary cwd, prepares world state there, spawns the resolved bin with isolated DSH homes (`DSH_HOME`, `DSH_AGENTS_HOME` under the temp cwd), closes stdin immediately, and awaits a clean exit within the deadline before inspecting and cleaning up on every outcome. `runFixtureTurn` stays in-process: it looks up the composition's single root agent, follows the task from its durable inbox receipt through whole-agent idle, sums per-step usage, and flushes the session before returning.
76
+ The harness is built on one separation: the smoke runs in a child process under an isolated world, and the test process only observes and asserts. `runLoaderSmoke` creates a temporary cwd (or reuses a caller-provided one), prepares world state there, spawns the resolved bin with isolated DSH homes (`DSH_HOME`, `DSH_AGENTS_HOME` under that cwd), closes stdin immediately, and awaits a clean exit within the deadline before inspecting on every outcome and removing only a cwd it created. `runFixtureTurn` stays in-process: it looks up the composition's single root agent, follows the task from its durable inbox receipt through whole-agent idle, sums per-step usage, and flushes the session before returning.
77
77
 
78
78
  ### Source map
79
79
 
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "面向无密钥示例冒烟测试的共享子进程与直接 agent harness,供测试作者启动真实 Loader 组合。"
2
+ description: "面向无密钥示例冒烟测试的共享子进程与直接 agent(智能体) harness,供测试作者启动真实 Loader 组合。"
3
3
  kind: "package-library"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ kind: "package-library"
9
9
 
10
10
  ## 概述
11
11
 
12
- 使用 `dsh-loader-smoke` 可从应用 fixture 的真实可执行文件及其 `cordis.yml` 启动应用,并在隔离的临时目录中捕获输出和完成清理。`runFixtureTurn` 让一项任务通过已配置的根 agent(智能体),并返回最终 assistant 文本与 token 用量。测试可以选择零构建的源码执行或已构建包执行,使本地和 CI 冒烟测试分别采用对应环境预期的消费路径。这个支持层库面向测试作者,不用于产品集成。
12
+ 使用 `dsh-loader-smoke` 可从应用 fixture(测试前置数据)的真实可执行文件及其 `cordis.yml` 启动应用,并在隔离的临时目录中捕获输出和完成清理。`runFixtureTurn` 通过已配置的根 agent 驱动一项任务,并返回最终 assistant 文本与 token 用量。测试可以选择零构建的源码执行或已构建包执行,使本地和 CI 冒烟测试分别采用对应环境预期的消费路径。这个支持层库面向测试作者,不用于产品集成。
13
13
 
14
14
  ## 目录
15
15
 
@@ -29,7 +29,7 @@ kind: "package-library"
29
29
 
30
30
  ### 启动应用 fixture
31
31
 
32
- `runLoaderSmoke` 接受可执行文件与配置路径、可选的完整可执行文件参数、环境覆盖、标准输入、运行前准备与清理前检查。它负责隔离工作目录、DSH 主目录、诊断、截止时间、终止、EOF 与清理;进程以零状态退出后返回两个流,失败时则拒绝并附带两个流:
32
+ `runLoaderSmoke` 接受可执行文件与配置路径、可选的完整可执行文件参数、环境覆盖、标准输入、运行前准备与清理前检查。它负责隔离工作目录、DSH 主目录、诊断、截止时间、终止、EOF 与清理(只清理自己创建的 cwd,调用方自带的 cwd 原样保留);进程以零状态退出后返回两个流,失败时则拒绝并附带两个流:
33
33
 
34
34
  ```text
35
35
  const result = await runLoaderSmoke({
@@ -41,11 +41,11 @@ const result = await runLoaderSmoke({
41
41
  })
42
42
  ```
43
43
 
44
- 当场景固定一个设计好的失败面——例如一次性轮次以错误结果结束——时设置 `expectedExitCode`;以任何其他方式退出(包括成功退出)都会使冒烟测试失败。
44
+ 当场景固定一个设计好的失败面——即一次性轮次以错误结果结束——时设置 `expectedExitCode`;以任何其他方式退出(包括成功退出)都会使冒烟测试失败。
45
45
 
46
46
  ### 测试交付 profile
47
47
 
48
- Profile 集成 driver 使用仅限仓库内部的 `tests/fixtures/production-profile.ts` helper。它通过 `loadProfile` 加载指定的已交付 profile 及其组合包 patch,修复 profile 的模块回退,然后把组合包 patch 与测试 `*.patch.yml` 文件依次交给 `boot` 挂载的根 `cordis:include`。这些 patch 应只包含测试提供方或模型、隔离持久化路径及被测对象专用变更。只需要 agent loop 而不测试 profile 集成的包级单元测试改为在本地挂载 `dsh-agent-loop-testkit`。
48
+ Profile 集成 driver 使用仅限仓库内部的 `tests/fixtures/production-profile.ts` helper。它通过 `loadProfile` 加载指定的已交付 profile 及其组合包 patch,物化保留的 link-mode fallback,并像 link-mode launcher 一样挂载使用原生查询的 `PluginPackages`,然后把组合包 patch 与测试 `*.patch.yml` 文件依次交给 `boot` 挂载的根 `cordis:include`。这些 patch 应只包含测试提供方或模型、隔离持久化路径及被测对象专用变更。只需要 agent loop 而不测试 profile 集成的包级单元测试改为在本地挂载 `dsh-agent-loop-testkit`。
49
49
 
50
50
  ### 驱动 fixture 轮次
51
51
 
@@ -57,8 +57,8 @@ Profile 集成 driver 使用仅限仓库内部的 `tests/fixtures/production-pro
57
57
 
58
58
  ### 可能出什么问题
59
59
 
60
- - **进程永不退出**——冒烟测试强制执行截止时间,并在失败信息中报告捕获的流;生成自身进程树的有故障 fixture(测试前置数据)可能比冒烟测试存活更久,需要外部清理。
61
- - **构建模式需要事先构建**——选择 `DSH_EXAMPLE_MODE=lib` 前先运行 `pnpm run build`;拥有该配置的包 manifest 还必须声明配置中点名的每个包。
60
+ - **进程永不退出**——冒烟测试强制执行截止时间,并在失败信息中报告捕获的流;会 spawn 自身进程树的故障 fixture 可能比冒烟测试存活更久,需要外部清理。
61
+ - **构建模式需要事先构建**——选择 `DSH_EXAMPLE_MODE=lib` 前先运行 `pnpm run build`;拥有该配置的包 manifest(元数据清单)还必须声明配置中点名的每个包。
62
62
  - **捕获输出受 execa 默认 100 MB `maxBuffer` 约束**——失控子进程在该上限处被终止,而不是在冒烟测试自选的预算处。
63
63
 
64
64
  -----
@@ -73,7 +73,7 @@ Profile 集成 driver 使用仅限仓库内部的 `tests/fixtures/production-pro
73
73
 
74
74
  ### 设计
75
75
 
76
- harness 建立在一个分离之上:冒烟测试在隔离世界中的子进程里运行,测试进程只观察与断言。`runLoaderSmoke` 创建临时 cwd、在那里准备世界状态、以隔离的 DSH 主目录(临时 cwd 下的 `DSH_HOME`、`DSH_AGENTS_HOME`)spawn 解析出的可执行文件、立即关闭 stdin,并在截止时间内等待干净退出,然后在每种结果下都执行检查与清理。`runFixtureTurn` 停留在进程内:它查找组合中的唯一根 agent,跟踪任务从持久收件箱接收到整个 agent 完全停稳,汇总每步用量,并在返回前刷写会话。
76
+ harness 建立在一个分离之上:冒烟测试在隔离世界中的子进程里运行,测试进程只观察与断言。`runLoaderSmoke` 创建临时 cwd(或复用调用方提供的 cwd)、在那里准备世界状态、以隔离的 DSH 主目录(该 cwd 下的 `DSH_HOME`、`DSH_AGENTS_HOME`)spawn 解析出的可执行文件、立即关闭 stdin,并在截止时间内等待干净退出,然后在每种结果下都执行检查,且只删除自己创建的 cwd。`runFixtureTurn` 留在进程内运行:它查找组合中的唯一根 agent,从持久收件箱收到任务起持续跟踪,直至整个 agent 完全停稳;随后汇总每步用量,并在返回前刷写会话。
77
77
 
78
78
  ### 源码地图
79
79
 
@@ -81,7 +81,7 @@ harness 建立在一个分离之上:冒烟测试在隔离世界中的子进程
81
81
  |---|---|
82
82
  | [`src/index.ts`](src/index.ts) | 模式解析器、`runLoaderSmoke` 子进程 harness、选项与结果类型 |
83
83
  | [`src/agent-turn.ts`](src/agent-turn.ts) | `runFixtureTurn` 直接 agent driver 与结果信封 |
84
- | — | 不发布运行时不变量伴生入口;消费它的测试套件会检验该 harness。 |
84
+ | — | 不发布运行时不变量伴生入口;该测试支持包不负责维护生产事件流或可变数据;消费它的测试套件会检验该 harness。 |
85
85
  | [`tests/fixtures/production-profile.ts`](tests/fixtures/production-profile.ts) | 仅限仓库内部、供集成 fixture 使用的交付 profile 组装 helper |
86
86
 
87
87
  </details>
@@ -93,7 +93,7 @@ harness 建立在一个分离之上:冒烟测试在隔离世界中的子进程
93
93
 
94
94
  当包级约定不够用时阅读以下页面。它们从 harness 逐步进入它启动的组合以及它所服务的 fixture。
95
95
 
96
- - [llm-replay](../llm-replay/README.zh.md)——冒烟组合为无密钥运行而挂载的模型 fixture 来源。
96
+ - [llm-replay](../llm-replay/README.zh.md)——冒烟测试组合为在没有提供方密钥的情况下运行而挂载的无密钥模型 fixture
97
97
  - [Agent 包](../../core/agent/README.zh.md)——`runFixtureTurn` 驱动的根 agent。
98
98
  - [测试策略](../../../docs/testing.zh.md)——无密钥快照与冒烟层级。
99
99
  - [test-support 组地图](../README.zh.md)——兄弟 harness 与支持包。
package/lib/index.js CHANGED
@@ -173,15 +173,22 @@ function resolveExampleLaunch(options) {
173
173
  env
174
174
  };
175
175
  }
176
+ /** Whether the options supply the cwd instead of a prefix the harness expands. */
177
+ function hasProvidedCwd(options) {
178
+ return options.cwd !== void 0;
179
+ }
176
180
  /**
177
181
  * Boot one real Loader tree from an isolated cwd, close stdin immediately, and
178
- * await a clean exit. The helper owns process kill and temp-directory cleanup on
179
- * every outcome, and picks src/lib via {@link resolveExampleLaunch}.
182
+ * await a clean exit. The helper owns process kill on every outcome and removes
183
+ * the temporary directory it created; a caller-provided cwd is left in place so
184
+ * consecutive smokes can share one world. It picks src/lib via
185
+ * {@link resolveExampleLaunch}.
180
186
  * @param options - example paths, mode, environment, and diagnostic identity.
181
187
  * @returns captured stdout and stderr after a zero exit.
182
188
  */
183
189
  async function runLoaderSmoke(options) {
184
- const cwd = await mkdtemp(join(options.tempDirParent ?? tmpdir(), options.tempDirPrefix));
190
+ const providedCwd = hasProvidedCwd(options);
191
+ const cwd = providedCwd ? options.cwd : await mkdtemp(join(options.tempDirParent ?? tmpdir(), options.tempDirPrefix));
185
192
  const processTimeoutMs = options.processTimeoutMs ?? DEFAULT_PROCESS_TIMEOUT_MS;
186
193
  try {
187
194
  await options.prepare?.(cwd);
@@ -215,7 +222,7 @@ async function runLoaderSmoke(options) {
215
222
  stderr: result.stderr
216
223
  };
217
224
  } finally {
218
- await rm(cwd, {
225
+ if (!providedCwd) await rm(cwd, {
219
226
  recursive: true,
220
227
  force: true
221
228
  });
@@ -65,14 +65,10 @@ export interface ExampleLaunch {
65
65
  * @returns the command, argument vector, and mode-specific environment to spawn with.
66
66
  */
67
67
  export declare function resolveExampleLaunch(options: ExampleLaunchOptions): ExampleLaunch;
68
- /** Inputs that vary between real-Loader example smokes. */
69
- export interface LoaderSmokeOptions {
68
+ /** Inputs every real-Loader example smoke supplies. */
69
+ interface LoaderSmokeBaseOptions {
70
70
  /** Human-readable example name used in failure diagnostics. */
71
71
  readonly label: string;
72
- /** Prefix for the isolated temporary process cwd. */
73
- readonly tempDirPrefix: string;
74
- /** Existing parent for the generated cwd; defaults to the platform temporary directory. */
75
- readonly tempDirParent?: string;
76
72
  /** Absolute app-bin source path (`<pkg>/src/bin.ts`); the `lib` bin is derived from it. */
77
73
  readonly binScript: string;
78
74
  /** Explicit plain-Node entry for `lib` mode; intended for test fixtures outside a package `src/` tree. */
@@ -101,6 +97,23 @@ export interface LoaderSmokeOptions {
101
97
  */
102
98
  readonly expectedExitCode?: number;
103
99
  }
100
+ /**
101
+ * Inputs that vary between real-Loader example smokes. The cwd is either one
102
+ * the harness expands from a prefix and owns, or a caller-provided directory it
103
+ * reuses and leaves in place; the two cannot be combined.
104
+ */
105
+ export type LoaderSmokeOptions = LoaderSmokeBaseOptions & ({
106
+ /** Prefix for the isolated temporary process cwd. */
107
+ readonly tempDirPrefix: string;
108
+ /** Existing parent for the generated cwd; defaults to the platform temporary directory. */
109
+ readonly tempDirParent?: string;
110
+ readonly cwd?: never;
111
+ } | {
112
+ /** Existing directory to use as the process cwd; the caller owns its cleanup. */
113
+ readonly cwd: string;
114
+ readonly tempDirPrefix?: never;
115
+ readonly tempDirParent?: never;
116
+ });
104
117
  /** Captured output from a Loader smoke that exited successfully. */
105
118
  export interface LoaderSmokeResult {
106
119
  /** Complete stdout after clean exit. */
@@ -110,8 +123,10 @@ export interface LoaderSmokeResult {
110
123
  }
111
124
  /**
112
125
  * Boot one real Loader tree from an isolated cwd, close stdin immediately, and
113
- * await a clean exit. The helper owns process kill and temp-directory cleanup on
114
- * every outcome, and picks src/lib via {@link resolveExampleLaunch}.
126
+ * await a clean exit. The helper owns process kill on every outcome and removes
127
+ * the temporary directory it created; a caller-provided cwd is left in place so
128
+ * consecutive smokes can share one world. It picks src/lib via
129
+ * {@link resolveExampleLaunch}.
115
130
  * @param options - example paths, mode, environment, and diagnostic identity.
116
131
  * @returns captured stdout and stderr after a zero exit.
117
132
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-loader-smoke",
3
3
  "description": "Shared subprocess and direct-agent harness for keyless real-Loader example smoke tests",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,18 +31,18 @@
31
31
  "tsx": "^4.22.4"
32
32
  },
33
33
  "peerDependencies": {
34
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
35
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
36
34
  "@deepseek-ai/cordis": "^4.0.2",
37
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
38
- "@deepseek-ai/dsh-http-proxy": "^0.1.5-rc.2"
35
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
36
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
37
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
38
+ "@deepseek-ai/dsh-http-proxy": "^0.1.6-alpha.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
42
- "@deepseek-ai/dsh-app-boot": "^0.1.5-rc.2",
43
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
44
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
45
- "@deepseek-ai/dsh-http-proxy": "^0.1.5-rc.2",
46
- "@deepseek-ai/cordis": "^4.0.2"
41
+ "@deepseek-ai/cordis": "^4.0.2",
42
+ "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
43
+ "@deepseek-ai/dsh-app-boot": "^0.1.6-alpha.2",
44
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
45
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
46
+ "@deepseek-ai/dsh-http-proxy": "^0.1.6-alpha.2"
47
47
  }
48
48
  }