@deepseek-ai/dsh-session-snapshot 0.2.1-alpha.2 → 0.2.1-alpha.4

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
@@ -9,8 +9,8 @@
9
9
  en: b184b97e2d1e1fa7
10
10
  zh: 7d4b4cc8d73446af
11
11
  /deepseek-ai-dsh-session-snapshot/summary:
12
- en: 71cd3441e7189ac4
13
- zh: 874ae7ac5fd231c9
12
+ en: 5d11e1dbbf5dd1cf
13
+ zh: 7a54089ed26ddd8f
14
14
  /deepseek-ai-dsh-session-snapshot/table-of-contents:
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- `dsh-session-snapshot` provides the shared support behind keyless recorded-session tests (`pnpm run test:snapshot`): closed manifests, typed identity redaction, normalization, workspace comparison, fixture guards, and protocol adapters for headless, SDK, ACP, and Web owners. The ACP adapter launches the tested profile as a real subprocess, drives a deterministic input script, and registers the complete record, replay, and refresh suite. Every scenario owns enough committed evidence to prove model-visible output and filesystem effects without trusting the agent's report. The package entry imports vitest and is therefore available only inside a vitest run.
12
+ `dsh-session-snapshot` provides the shared support behind keyless recorded-session tests (`pnpm run test:snapshot`): closed manifests, typed identity redaction, normalization, workspace comparison, fixture guards, and protocol adapters for headless, SDK (`sdk` and `sdk-minimal`), ACP, and Web owners. The ACP adapter launches the tested profile as a real subprocess, drives a deterministic input script, and registers the complete record, replay, and refresh suite. Every scenario owns enough committed evidence to prove model-visible output and filesystem effects without trusting the agent's report. The package entry imports vitest and is therefore available only inside a vitest run.
13
13
 
14
14
  ## Table of Contents
15
15
 
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-library"
9
9
 
10
10
  ## 概述
11
11
 
12
- `dsh-session-snapshot` 提供无密钥已记录会话测试(`pnpm run test:snapshot`)背后的共享支持:封闭 manifest、类型化身份脱敏、规范化、workspace 比较、fixture(测试前置数据)保护,以及 headless、SDK、ACP(Agent Client Protocol)与 Web owner 使用的协议适配器。ACP 适配器以真实子进程启动被测 profile,驱动确定性输入脚本,并注册完整的录制、回放与刷新套件。每个场景都提交足够证据来证明模型可见输出与文件系统效果,不依赖 agent(智能体)自述。包入口会导入 vitest,因此只能在 vitest 运行中使用。
12
+ `dsh-session-snapshot` 提供无密钥已记录会话测试(`pnpm run test:snapshot`)背后的共享支持:封闭 manifest、类型化身份脱敏、规范化、workspace 比较、fixture(测试前置数据)保护,以及 headless、SDK(`sdk` 与 `sdk-minimal`)、ACP(Agent Client Protocol)与 Web owner 使用的协议适配器。ACP 适配器以真实子进程启动被测 profile,驱动确定性输入脚本,并注册完整的录制、回放与刷新套件。每个场景都提交足够证据来证明模型可见输出与文件系统效果,不依赖 agent(智能体)自述。包入口会导入 vitest,因此只能在 vitest 运行中使用。
13
13
 
14
14
  ## 目录
15
15
 
package/lib/index.js CHANGED
@@ -20,6 +20,7 @@ import { isSurfaceEligibleType } from "@deepseek-ai/dsh-session/surface";
20
20
  //#region lib/types/identity.js
21
21
  /** Relationship-preserving identity redaction for committed session snapshots. */
22
22
  const UUID_FRAGMENT_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
23
+ const SHORT_JOB_ID_RE$1 = /-[0-9a-f]{16}$/i;
23
24
  const LEGACY_TOKEN_RE = /^\{\{(?:sessionId|messageId)\}\}$/;
24
25
  const CANONICAL_TOKEN_RE = /^\{\{(session|message|approval|workflow|command|rpc|retry|id):([1-9]\d*)\}\}$/;
25
26
  const ID_KEY_RE = /(?:^id$|Id$|Ids$)/;
@@ -37,7 +38,7 @@ function messageId(value) {
37
38
  return value.id;
38
39
  }
39
40
  function redactedCandidate(value) {
40
- return UUID_FRAGMENT_RE.test(value) || LEGACY_TOKEN_RE.test(value) || CANONICAL_TOKEN_RE.test(value);
41
+ return UUID_FRAGMENT_RE.test(value) || SHORT_JOB_ID_RE$1.test(value) || LEGACY_TOKEN_RE.test(value) || CANONICAL_TOKEN_RE.test(value);
41
42
  }
42
43
  /**
43
44
  * Replace volatile opaque ids while preserving equality relationships across a parent and its child logs.
@@ -1216,6 +1217,7 @@ const PATH_TEXT_BOUNDARY_RE = /[\s<>'"`()\[\]{},;:!?=]/;
1216
1217
  const FILE_URI_PATH_PREFIX_RE = /(?:^|[^a-z0-9+.-])file:\/\/\/?$/i;
1217
1218
  /** A UUID v4 string, the shape `randomUUID()` produces for session ids. */
1218
1219
  const UUID_RE$1 = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;
1220
+ const SHORT_JOB_ID_RE = /-[0-9a-f]{16}$/i;
1219
1221
  const LOCAL_SPILL_PATH_RE = new RegExp(String.raw`\{\{cwd\}\}[\\/]+\.spill[\\/]+session-[0-9a-f]{12}[\\/]+[0-9a-f]{12}-([A-Za-z0-9._~-]+?)` + String.raw`(?=\. Use read with offset/limit|[\s)"]|\\+"|$)`, "g");
1220
1222
  const SNAPSHOT_SPILL_PATH_RE = new RegExp(String.raw`(?:[A-Za-z]:)?[\\/]+(?:tmp|t)[\\/]+(?:dsh-acp-snap-[0-9a-f]{9}|dsh-acp-snapshot-spill)[\\/]+session-[0-9a-f]{12}[\\/]+[0-9a-f]{12}-([A-Za-z0-9._~-]+?)` + String.raw`(?=\. Use read with offset/limit|[\s)"]|\\+"|$)`, "g");
1221
1223
  /**
@@ -1406,8 +1408,32 @@ function normalizeStdout(rawStdout, ctx, options = {}) {
1406
1408
  function normalizeSessionLog(rawLog, ctx, options = {}) {
1407
1409
  const cwdPathMode = options.cwdPathMode ?? "canonical";
1408
1410
  const identityMode = options.identityMode ?? "legacy";
1409
- return rawLog.split("\n").filter((line) => line.trim().length > 0).map((line) => {
1410
- const record = JSON.parse(line);
1411
+ const parsed = rawLog.split("\n").filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
1412
+ const jobTokens = /* @__PURE__ */ new Map();
1413
+ const reservedTokens = new Set(rawLog.match(/\{\{id:[1-9]\d*\}\}/g) ?? []);
1414
+ let nextJobToken = 1;
1415
+ if (identityMode === "legacy") for (const record of parsed) {
1416
+ if (record.type !== "job/registered" && record.type !== "job/settled" || record.data === null || typeof record.data !== "object") continue;
1417
+ const id = record.data.jobId;
1418
+ if (typeof id !== "string" || id.search(UUID_RE$1) < 0 && !SHORT_JOB_ID_RE.test(id) || jobTokens.has(id)) continue;
1419
+ let token;
1420
+ do
1421
+ token = `{{id:${nextJobToken++}}}`;
1422
+ while (reservedTokens.has(token));
1423
+ jobTokens.set(id, token);
1424
+ }
1425
+ const replaceJobs = (value) => {
1426
+ if (typeof value === "string") {
1427
+ let output = value;
1428
+ for (const [id, token] of jobTokens) output = output.split(id).join(token);
1429
+ return output;
1430
+ }
1431
+ if (Array.isArray(value)) return value.map(replaceJobs);
1432
+ if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, replaceJobs(item)]));
1433
+ return value;
1434
+ };
1435
+ return parsed.map((raw) => {
1436
+ const record = jobTokens.size === 0 ? raw : replaceJobs(raw);
1411
1437
  if (record.type === "session") {
1412
1438
  if ("createdAt" in record) record.createdAt = 0;
1413
1439
  } else if (isPackedFixtureRow(record)) {
@@ -1430,6 +1456,11 @@ function normalizeSessionLog(rawLog, ctx, options = {}) {
1430
1456
  if ("durationMs" in data) data.durationMs = 0;
1431
1457
  }
1432
1458
  normalizeFeedbackClocks(record);
1459
+ if ((record.type === "job/registered" || record.type === "job/settled") && record.data !== null && typeof record.data === "object") {
1460
+ const data = record.data;
1461
+ if ("startedAt" in data) data.startedAt = 0;
1462
+ if ("finishedAt" in data) data.finishedAt = 0;
1463
+ }
1433
1464
  if (record.type === "goal/change" && record.data !== null && typeof record.data === "object") {
1434
1465
  const data = record.data;
1435
1466
  if ("createdAt" in data) data.createdAt = 0;
@@ -1653,6 +1684,7 @@ function writesCurrentSessionFixtures(manifest, mode) {
1653
1684
  const PROFILES = new Set([
1654
1685
  "headless",
1655
1686
  "sdk",
1687
+ "sdk-minimal",
1656
1688
  "acp",
1657
1689
  "web"
1658
1690
  ]);
@@ -1725,7 +1757,7 @@ function parseSnapshotManifest(source, path = "snapshot.yml") {
1725
1757
  ], "manifest");
1726
1758
  if (root.version !== 1) throw new Error("manifest.version must equal 1");
1727
1759
  const scenario = root.scenario === void 0 ? void 0 : name(root.scenario, "manifest.scenario");
1728
- if (typeof root.profile !== "string" || !PROFILES.has(root.profile)) throw new Error("manifest.profile must be headless, sdk, acp, or web");
1760
+ if (typeof root.profile !== "string" || !PROFILES.has(root.profile)) throw new Error("manifest.profile must be headless, sdk, sdk-minimal, acp, or web");
1729
1761
  const composition = root.composition === void 0 ? void 0 : name(root.composition, "manifest.composition");
1730
1762
  let recording;
1731
1763
  if (root.recording !== void 0) {
@@ -1,6 +1,6 @@
1
1
  /** Parse and validate one recorded-session snapshot manifest. */
2
2
  /** Public `dsh` profile used to control a recorded-session scenario. */
3
- export type SnapshotProfile = 'headless' | 'sdk' | 'acp' | 'web';
3
+ export type SnapshotProfile = 'headless' | 'sdk' | 'sdk-minimal' | 'acp' | 'web';
4
4
  /** How a canonical session may be regenerated. */
5
5
  export type SnapshotRecording = 'live' | 'authored';
6
6
  /** Request-header ownership metadata for one composition. */
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.2.1-alpha.2",
4
+ "version": "0.2.1-alpha.4",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -28,32 +28,33 @@
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
30
  "@agentclientprotocol/sdk": "1.4.0",
31
- "@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.1",
32
- "@deepseek-ai/dsh-llm-replay": "0.2.1-alpha.2",
33
- "@deepseek-ai/dsh-loader-smoke": "0.2.1-alpha.2",
34
- "@deepseek-ai/dsh-session-format": "0.2.1-alpha.2",
31
+ "@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.2",
32
+ "@deepseek-ai/dsh-llm-replay": "0.2.1-alpha.4",
33
+ "@deepseek-ai/dsh-loader-smoke": "0.2.1-alpha.4",
34
+ "@deepseek-ai/dsh-session-format": "0.2.1-alpha.4",
35
35
  "js-yaml": "^4.3.2",
36
36
  "vitest": "^4.1.11"
37
37
  },
38
38
  "peerDependencies": {
39
- "@deepseek-ai/cordis": "~4.0.5-alpha.1",
40
- "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
41
- "@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.2"
39
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2",
40
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.4",
41
+ "@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.4"
42
42
  },
43
43
  "devDependencies": {
44
- "@deepseek-ai/cordis": "~4.0.5-alpha.1",
45
- "@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
46
- "@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.2",
47
- "@deepseek-ai/dsh-compaction": "0.2.1-alpha.2",
48
- "@deepseek-ai/dsh-fs": "0.2.1-alpha.2",
49
- "@deepseek-ai/dsh-llm": "0.2.1-alpha.2",
50
- "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.2",
51
- "@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.2",
52
- "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
53
- "@deepseek-ai/dsh-subagent": "0.2.1-alpha.2",
54
- "@deepseek-ai/dsh-tools": "0.2.1-alpha.2",
55
- "@deepseek-ai/dsh-user-questions": "0.2.1-alpha.2",
44
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2",
45
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.4",
46
+ "@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.4",
47
+ "@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.4",
48
+ "@deepseek-ai/dsh-compaction": "0.2.1-alpha.4",
49
+ "@deepseek-ai/dsh-fs": "0.2.1-alpha.4",
50
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.4",
51
+ "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.4",
52
+ "@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.4",
53
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.4",
54
+ "@deepseek-ai/dsh-subagent": "0.2.1-alpha.4",
55
+ "@deepseek-ai/dsh-tools": "0.2.1-alpha.4",
56
+ "@deepseek-ai/dsh-user-questions": "0.2.1-alpha.4",
56
57
  "@types/js-yaml": "^4.0.9",
57
- "@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.2"
58
+ "@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.4"
58
59
  }
59
60
  }