@deepseek-ai/dsh-session-snapshot 0.1.5-alpha.1 → 0.1.5-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/session-snapshot/README.md
5
- README.md: 533baf73e4913d1c64ea018e7c99099da1a1348b
6
- README.zh.md: c3926c3e7d7ec53064a5d3dac3048e0d934b4c5c
5
+ README.md: a73ea265516f965bec8d11c41d6eb5bb028c7ac6
6
+ README.zh.md: 544694a9fe9678d89cffb1f3293ea4e648e89f5d
package/README.md CHANGED
@@ -70,15 +70,15 @@ defineAcpSnapshotSuite({
70
70
 
71
71
  Each recorded-session directory carries a closed `snapshot.yml` manifest plus canonical parent and contiguous child roles. Parent filenames are `session[.vN].jsonl`; children are `session.<ordinal>[.vN].jsonl`; v0 omits `.v0`, positive versions use lowercase `.vN`, and every filename agrees with its header. A role may retain older generations, but the harness selects the numerically highest one. An owning manifest may declare `sessionFormat.version` plus one or more closed `coverage` names to keep that historical generation as an explicit migration fixture; absence tracks the current writer. The manifest also names the scenario, shipped profile, composition/header class, recording source, and only the replay, platform, permission, environment, workspace, or input facts the completed Session cannot reconstruct. Storage guards check tool results and portable paths in every selected parent and child role. Prompt/schema scrubbing, message identity, and prompt-before-request ordering apply to current generations; retained predecessors keep their historical representation. The adapter registers expected-output, Session-log, and optional `workspace.expected/` comparisons; guards reject orphan directories, missing roles, noncanonical names, absolute paths, malformed manifests, and platform-specific separators.
72
72
 
73
- `normalizeSessionSnapshot` retains the complete Session header and event payloads but omits top-level `seq`/`time` envelopes from committed fixtures after normalizing paths and scrubbing system-prompt text and tool schemas; it also normalizes embedded stream clocks and historical packed-row `seq0`/`time0` envelopes. Replay synthesizes the top-level envelopes in memory, while runtime persistence continues to write complete logs. Multi-session comparison validates expected and harvested logs through the strict build-static Session format catalog before identity redaction and normalization; source filenames cannot alter format validation. A retained historical replay input is not the native V3 writer-output oracle: structural migration preserves request meaning but can produce a different event layout. Normalization preserves unexpected request-header fields, including `system`, so regressions remain visible. Versionless protocol-adapter unit fixtures remain outside the released Session format corpus. Current v3 fixtures use one row per event; retained v0/v1 fixtures may use canonical packed rows. The [temporary repository migrator](../../../scripts/migrate-packed-session-fixtures.ts) (`pnpm run migrate:packed-session-fixtures`) rewrites older historical layouts, and its [removal proposal](../../../.agents/notes/proposed/process/2026-07-26-remove-packed-session-fixture-migrator.md) owns its deletion.
73
+ `normalizeSessionSnapshot` retains the complete Session header and event payloads but omits top-level `seq`/`time` envelopes from committed fixtures after normalizing paths and scrubbing system-prompt text and tool schemas; it also normalizes embedded stream clocks and historical packed-row `seq0`/`time0` envelopes, and catalog child-creation clocks. Event order and source-event references are preserved. Replay synthesizes the top-level envelopes in memory, while runtime persistence continues to write complete logs. Multi-session comparison validates expected and harvested logs through the strict build-static Session format catalog before identity redaction and normalization; source filenames cannot alter format validation. A retained historical replay input is not the native current-format writer-output oracle: structural migration preserves request meaning but can produce a different event layout. Normalization preserves unexpected request-header fields, including `system`, so regressions remain visible. Versionless protocol-adapter unit fixtures remain outside the released Session format corpus. Fixtures in the [current writer format](../../../docs/session-format-status.md) use one row per event; retained v0/v1 fixtures may use canonical packed rows. The [temporary repository migrator](../../../scripts/migrate-packed-session-fixtures.ts) (`pnpm run migrate:packed-session-fixtures`) rewrites older historical layouts, and its [removal proposal](../../../.agents/notes/proposed/process/2026-07-26-remove-packed-session-fixture-migrator.md) owns its deletion.
74
74
 
75
75
  Spill scenarios save through the real local provider under a private temporary root. Their fixture adapter exposes fixed-length logical locators and maps only this run’s saved locators back to real files for retrieval, preserving preview budgets without writing into a shared logical path. Known snapshot spill paths normalize to stable locator tokens, including paths quoted inside JSON omission notices with JSON-escaped Windows separators. Refresh extraction preserves the matched serialized path spelling for literal replacement. Normalization changes only the locator: saved byte lengths and omission counts remain comparison evidence.
76
76
 
77
- Retained historical scenarios keep their canonical Session files unchanged and selected for replay, with no canonical V3 sibling in the pinned directory. Their exact normalized native V3 output is recorded separately in `writer.expected.jsonl` for the parent and `writer.<ordinal>.expected.jsonl` for children; these are output oracles, not replay generations. Retained SDK scenarios use `notifications.current.expected.jsonl` for current protocol output. Comparisons neither project current events back into a historical format nor strip structural differences. Independent migration tests verify the official transform rather than treating native writer layout as its expected event sequence.
77
+ Retained historical scenarios keep their canonical Session files unchanged and selected for replay, with no newer canonical sibling in the pinned directory. Their exact normalized native current-format output is recorded separately in `writer.expected.jsonl` for the parent and `writer.<ordinal>.expected.jsonl` for children; these are output oracles, not replay generations. Retained SDK scenarios use `notifications.current.expected.jsonl` for current protocol output. Comparisons neither project current events back into a historical format nor strip structural differences. Independent migration tests verify the official transform rather than treating native writer layout as its expected event sequence.
78
78
 
79
79
  ### Record, replay, and refresh
80
80
 
81
- `pnpm run test:snapshot:record` calls the live LLM and writes the harvested current generation under its canonical versioned filename. Record and refresh never rename or delete a completed generation, including generations of a child role absent from a later run; reviewed source-tree curation removes a predecessor only after the same role has a verified current replacement. Scenarios with an explicit `sessionFormat` remain read-only in record mode. `pnpm run test:snapshot:refresh` stays keyless, runs the selected highest replay input, and writes stdout, owned prompt and tool-schema sidecars, and a fresh current-generation comparable Session output; retained historical scenarios write the separate writer-output oracles instead of a canonical V3 replay generation. Each composition owner keeps its replay patch beside its live patch; top-level `snapshots/` owns Session-driven scenarios, while other expected outputs stay beside their owning package. [`dsh-llm-replay`](../llm-replay/README.md) serves the recorded streams selected through `DSH_SNAPSHOT_*` environment values.
81
+ `pnpm run test:snapshot:record` calls the live LLM and writes the harvested current generation under its canonical versioned filename. Record and refresh never rename or delete a completed generation, including generations of a child role absent from a later run; reviewed source-tree curation removes a predecessor only after the same role has a verified current replacement. Scenarios with an explicit `sessionFormat` remain read-only in record mode. `pnpm run test:snapshot:refresh` stays keyless, runs the selected highest replay input, and writes stdout, owned prompt and tool-schema sidecars, and a fresh current-generation comparable Session output; retained historical scenarios write the separate writer-output oracles instead of a canonical current-format replay generation. Each composition owner keeps its replay patch beside its live patch; top-level `snapshots/` owns Session-driven scenarios, while other expected outputs stay beside their owning package. [`dsh-llm-replay`](../llm-replay/README.md) serves the recorded streams selected through `DSH_SNAPSHOT_*` environment values.
82
82
 
83
83
  ### Pinning request headers and system prompts
84
84
 
package/README.zh.md CHANGED
@@ -70,15 +70,15 @@ defineAcpSnapshotSuite({
70
70
 
71
71
  每个已记录 Session 目录携带封闭的 `snapshot.yml` manifest,以及规范 parent 与连续 child 角色。parent 文件名是 `session[.vN].jsonl`;child 是 `session.<ordinal>[.vN].jsonl`;v0 省略 `.v0`,正版本使用小写 `.vN`,且每个文件名与其 header 一致。一个角色可以保留旧 generation,但 harness 会选择数值最高的一项。拥有 fixture 的 manifest 可以声明 `sessionFormat.version` 与一个或多个封闭 `coverage` 名称,把该历史 generation 保留为显式迁移 fixture;省略此字段时跟随当前 writer。manifest 还会指名场景、随附 profile、组合/header 类别、录制来源,以及已完成 Session 无法重建的 replay、平台、权限、环境、workspace 或输入事实。存储保护检查每个选定 parent 与 child 角色的工具结果和可移植路径。提示词/schema 擦除、消息身份及提示词先于请求的顺序检查适用于当前 generation;保留的前代维持其历史表示。适配器注册预期输出、Session 日志与可选 `workspace.expected/` 比较;保护会拒绝遗留目录、缺失角色、非规范名称、绝对路径、malformed manifest 与平台专用分隔符。
72
72
 
73
- `normalizeSessionSnapshot` 在规范化路径并擦除系统提示文本与工具 schema 后,会保留完整 Session header 与事件 payload,但从已提交 fixture 中省略顶层 `seq`/`time` envelope;它还会规范化嵌入式 stream clock 与历史 packed-row 的 `seq0`/`time0` envelope。Replay 只在内存中合成顶层 envelope,而运行时持久化仍写入完整日志。多 Session 比较会先通过严格的构建期静态 Session 格式目录校验预期日志与收集日志,再进行身份脱敏与规范化;来源文件名不能改变格式校验。保留的历史 replay 输入不是原生 V3 writer 输出的比较基准:结构迁移保留请求含义,但可以产生不同的事件布局。归一化保留意外的 request-header 字段(包括 `system`),使回归保持可见。无版本的协议适配器单元测试 fixture 不属于已发布 Session 格式语料。当前 v3 fixture 每个事件占一行;保留的 v0/v1 fixture 可以使用规范 packed row。[临时仓库迁移器](../../../scripts/migrate-packed-session-fixtures.ts)(`pnpm run migrate:packed-session-fixtures`)会改写更旧的历史布局,由其[移除提案](../../../.agents/notes/proposed/process/2026-07-26-remove-packed-session-fixture-migrator.zh.md)负责删除该迁移器。
73
+ `normalizeSessionSnapshot` 在规范化路径并擦除系统提示文本与工具 schema 后,会保留完整 Session header 与事件 payload,但从已提交 fixture 中省略顶层 `seq`/`time` envelope;它还会规范化嵌入式 stream clock 与历史 packed-row 的 `seq0`/`time0` envelope 与 catalog child 创建时钟。事件顺序与来源事件引用保持不变。Replay 只在内存中合成顶层 envelope,而运行时持久化仍写入完整日志。多 Session 比较会先通过严格的构建期静态 Session 格式目录校验预期日志与收集日志,再进行身份脱敏与规范化;来源文件名不能改变格式校验。保留的历史 replay 输入不是原生当前格式 writer 输出的比较基准:结构迁移保留请求含义,但可以产生不同的事件布局。归一化保留意外的 request-header 字段(包括 `system`),使回归保持可见。无版本的协议适配器单元测试 fixture 不属于已发布 Session 格式语料。[当前写入器格式](../../../docs/session-format-status.zh.md)的 fixture 每个事件占一行;保留的 v0/v1 fixture 可以使用规范 packed row。[临时仓库迁移器](../../../scripts/migrate-packed-session-fixtures.ts)(`pnpm run migrate:packed-session-fixtures`)会改写更旧的历史布局,由其[移除提案](../../../.agents/notes/proposed/process/2026-07-26-remove-packed-session-fixture-migrator.zh.md)负责删除该迁移器。
74
74
 
75
75
  Spill 场景通过真实本地 provider 保存到私有临时根目录。夹具适配器提供固定长度的逻辑定位符,并仅将本次运行已保存的定位符映射回实际文件以供检索,在不写入共享逻辑路径的情况下保留预览预算。已知的快照 spill 路径会规范化为稳定的定位信息 token,包括 JSON 省略通知中带引号、使用 JSON 转义 Windows 分隔符的路径。刷新提取会保留匹配路径的序列化写法,以便进行字面替换。规范化只改变定位信息:保存字节数与省略计数仍作为比较证据。
76
76
 
77
- 保留历史输入的场景保持规范 Session 文件不变,并继续选择它们进行回放;固定历史版本的目录中没有规范 V3 同角色文件。其精确的规范化原生 V3 输出单独记录在父会话的 `writer.expected.jsonl` 和子会话的 `writer.<ordinal>.expected.jsonl` 中;这些是输出比较基准,而非 replay 代际。保留历史输入的 SDK 场景使用 `notifications.current.expected.jsonl` 记录当前协议输出。比较既不将当前事件反向投影为历史格式,也不剥除结构差异。独立迁移测试验证正式转换,而不把原生 writer 布局当作其预期事件序列。
77
+ 保留历史输入的场景保持规范 Session 文件不变,并继续选择它们进行回放;固定历史版本的目录中没有更新的规范同角色文件。其精确的规范化原生当前格式输出单独记录在父会话的 `writer.expected.jsonl` 和子会话的 `writer.<ordinal>.expected.jsonl` 中;这些是输出比较基准,而非 replay 代际。保留历史输入的 SDK 场景使用 `notifications.current.expected.jsonl` 记录当前协议输出。比较既不将当前事件反向投影为历史格式,也不剥除结构差异。独立迁移测试验证正式转换,而不把原生 writer 布局当作其预期事件序列。
78
78
 
79
79
  ### 录制、回放与刷新
80
80
 
81
- `pnpm run test:snapshot:record` 调用在线 LLM(大语言模型),并在规范具名版本文件下写入收集到的当前 generation。record 与 refresh 绝不重命名或删除已完成的 generation,即使后续运行不再产生某个 child 角色也一样;受审阅的源树整理只有在同角色存在已验证的当前替代文件后才移除前代。显式声明 `sessionFormat` 的场景在录制模式下保持只读。`pnpm run test:snapshot:refresh` 保持无密钥,运行选定的最高 replay 输入,并写入 stdout、各 pin 自有的 prompt 与工具 schema sidecar,以及新鲜当前 generation 的可比较 Session 输出;保留历史输入的场景写入单独的 writer 输出比较基准,而非规范 V3 replay 代际。每个组合 owner 把 replay patch 放在 live patch 旁;顶层 `snapshots/` 拥有 Session 驱动场景,其他预期输出留在其 package owner 旁。[`dsh-llm-replay`](../llm-replay/README.zh.md) 提供通过 `DSH_SNAPSHOT_*` 环境值选择的已记录流。
81
+ `pnpm run test:snapshot:record` 调用在线 LLM(大语言模型),并在规范具名版本文件下写入收集到的当前 generation。record 与 refresh 绝不重命名或删除已完成的 generation,即使后续运行不再产生某个 child 角色也一样;受审阅的源树整理只有在同角色存在已验证的当前替代文件后才移除前代。显式声明 `sessionFormat` 的场景在录制模式下保持只读。`pnpm run test:snapshot:refresh` 保持无密钥,运行选定的最高 replay 输入,并写入 stdout、各 pin 自有的 prompt 与工具 schema sidecar,以及新鲜当前 generation 的可比较 Session 输出;保留历史输入的场景写入单独的 writer 输出比较基准,而非规范当前格式 replay 代际。每个组合 owner 把 replay patch 放在 live patch 旁;顶层 `snapshots/` 拥有 Session 驱动场景,其他预期输出留在其 package owner 旁。[`dsh-llm-replay`](../llm-replay/README.zh.md) 提供通过 `DSH_SNAPSHOT_*` 环境值选择的已记录流。
82
82
 
83
83
  ### 固定请求 header 与系统提示
84
84
 
package/lib/index.js CHANGED
@@ -1361,8 +1361,9 @@ function normalizeStdout(rawStdout, ctx, options = {}) {
1361
1361
  /**
1362
1362
  * Normalize a session JSONL log into a stable expected output: the header line's
1363
1363
  * volatile fields (`createdAt`, `id`, `cwd`) are zeroed/scrubbed; event,
1364
- * historical packed-row, embedded Assistant-stream, and goal lifecycle clocks
1365
- * are zeroed; and all volatile strings are scrubbed. Projected inputs remain
1364
+ * historical packed-row, embedded Assistant-stream, goal lifecycle, and
1365
+ * catalog child-creation clocks are zeroed; and all volatile strings are
1366
+ * scrubbed. Projected inputs remain
1366
1367
  * projected. Packed `data.dt` gaps are normalized even when the projected row
1367
1368
  * omits its `time0` anchor.
1368
1369
  * Output is JSONL in the same shape as the input — one compact record per
@@ -1405,6 +1406,10 @@ function normalizeSessionLog(rawLog, ctx, options = {}) {
1405
1406
  if ("createdAt" in data) data.createdAt = 0;
1406
1407
  if ("updatedAt" in data) data.updatedAt = 0;
1407
1408
  }
1409
+ if (record.type === "subagent/catalog" && record.data !== null && typeof record.data === "object") {
1410
+ const data = record.data;
1411
+ if ("childCreatedAt" in data) data.childCreatedAt = 0;
1412
+ }
1408
1413
  if (Object.hasOwn(record, "sourceEventSeqs")) record.sourceEventSeqs = decodeSeqRanges(record.sourceEventSeqs);
1409
1414
  return scrubValue(record, ctx, cwdPathMode, identityMode);
1410
1415
  }).map((r) => JSON.stringify(r)).join("\n") + "\n";
@@ -1418,9 +1423,9 @@ function projectSessionSnapshot(rawLog) {
1418
1423
  return [
1419
1424
  lines.shift(),
1420
1425
  ...lines.map((line) => {
1421
- const projected = { ...JSON.parse(line) };
1422
- omitFixtureEnvelope(projected);
1423
- return JSON.stringify(projected);
1426
+ const record = JSON.parse(line);
1427
+ omitFixtureEnvelope(record);
1428
+ return JSON.stringify(record);
1424
1429
  }),
1425
1430
  ""
1426
1431
  ].join("\n");
@@ -1429,7 +1434,8 @@ function projectSessionSnapshot(rawLog) {
1429
1434
  * Normalize and project persisted session JSONL for a committed fixture.
1430
1435
  * This composes ordinary log normalization with request-header scrubbing and
1431
1436
  * persistence-envelope projection, then writes the v3 logical event stream as
1432
- * one record per event, independent of persistence flush boundaries.
1437
+ * one record per event, independent of persistence flush boundaries. Event order
1438
+ * and source-event references are preserved.
1433
1439
  *
1434
1440
  * @param rawLog - persisted or already-projected session JSONL.
1435
1441
  * @param ctx - the run's volatile values to scrub.
@@ -56,8 +56,9 @@ export declare function normalizeStdout(rawStdout: string, ctx: NormalizeContext
56
56
  /**
57
57
  * Normalize a session JSONL log into a stable expected output: the header line's
58
58
  * volatile fields (`createdAt`, `id`, `cwd`) are zeroed/scrubbed; event,
59
- * historical packed-row, embedded Assistant-stream, and goal lifecycle clocks
60
- * are zeroed; and all volatile strings are scrubbed. Projected inputs remain
59
+ * historical packed-row, embedded Assistant-stream, goal lifecycle, and
60
+ * catalog child-creation clocks are zeroed; and all volatile strings are
61
+ * scrubbed. Projected inputs remain
61
62
  * projected. Packed `data.dt` gaps are normalized even when the projected row
62
63
  * omits its `time0` anchor.
63
64
  * Output is JSONL in the same shape as the input — one compact record per
@@ -73,7 +74,8 @@ export declare function normalizeSessionLog(rawLog: string, ctx: NormalizeContex
73
74
  * Normalize and project persisted session JSONL for a committed fixture.
74
75
  * This composes ordinary log normalization with request-header scrubbing and
75
76
  * persistence-envelope projection, then writes the v3 logical event stream as
76
- * one record per event, independent of persistence flush boundaries.
77
+ * one record per event, independent of persistence flush boundaries. Event order
78
+ * and source-event references are preserved.
77
79
  *
78
80
  * @param rawLog - persisted or already-projected session JSONL.
79
81
  * @param ctx - the run's volatile values to scrub.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-session-snapshot",
3
3
  "description": "Session-log snapshot core with an ACP protocol adapter, expected-output normalization, and fixture invariants",
4
- "version": "0.1.5-alpha.1",
4
+ "version": "0.1.5-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -31,28 +31,28 @@
31
31
  "js-yaml": "^4.2.0",
32
32
  "vitest": "^4.1.8",
33
33
  "@deepseek-ai/cordis-plugin-include": "1.0.7",
34
- "@deepseek-ai/dsh-llm-replay": "^0.1.5-alpha.1",
35
- "@deepseek-ai/dsh-loader-smoke": "0.1.5-alpha.1",
36
- "@deepseek-ai/dsh-session-format": "^0.1.5-alpha.1"
34
+ "@deepseek-ai/dsh-loader-smoke": "0.1.5-alpha.2",
35
+ "@deepseek-ai/dsh-session-format": "^0.1.5-alpha.2",
36
+ "@deepseek-ai/dsh-llm-replay": "^0.1.5-alpha.2"
37
37
  },
38
38
  "peerDependencies": {
39
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.2",
39
40
  "@deepseek-ai/cordis": "^4.0.2",
40
- "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
41
- "@deepseek-ai/dsh-http-proxy": "^0.1.5-alpha.1"
41
+ "@deepseek-ai/dsh-http-proxy": "^0.1.5-alpha.2"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/js-yaml": "^4.0.9",
45
45
  "@deepseek-ai/cordis": "^4.0.2",
46
- "@deepseek-ai/dsh-agent": "^0.1.5-alpha.1",
47
- "@deepseek-ai/dsh-agent-loop": "^0.1.5-alpha.1",
48
- "@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
49
- "@deepseek-ai/dsh-sandbox": "^0.1.5-alpha.1",
50
- "@deepseek-ai/dsh-sandbox-policy": "^0.1.5-alpha.1",
51
- "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
52
- "@deepseek-ai/dsh-subagent": "^0.1.5-alpha.1",
53
- "@deepseek-ai/dsh-user-questions": "^0.1.5-alpha.1",
54
- "@deepseek-ai/dsh-http-proxy": "^0.1.5-alpha.1",
55
- "@deepseek-ai/dsh-compaction": "^0.1.5-alpha.1",
56
- "@deepseek-ai/dsh-tools": "^0.1.5-alpha.1"
46
+ "@deepseek-ai/dsh-agent": "^0.1.5-alpha.2",
47
+ "@deepseek-ai/dsh-compaction": "^0.1.5-alpha.2",
48
+ "@deepseek-ai/dsh-agent-loop": "^0.1.5-alpha.2",
49
+ "@deepseek-ai/dsh-llm": "^0.1.5-alpha.2",
50
+ "@deepseek-ai/dsh-sandbox": "^0.1.5-alpha.2",
51
+ "@deepseek-ai/dsh-sandbox-policy": "^0.1.5-alpha.2",
52
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.2",
53
+ "@deepseek-ai/dsh-subagent": "^0.1.5-alpha.2",
54
+ "@deepseek-ai/dsh-tools": "^0.1.5-alpha.2",
55
+ "@deepseek-ai/dsh-user-questions": "^0.1.5-alpha.2",
56
+ "@deepseek-ai/dsh-http-proxy": "^0.1.5-alpha.2"
57
57
  }
58
58
  }