@deepseek-ai/dsh-session-snapshot 0.2.1-alpha.2 → 0.2.1-alpha.3
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 +2 -2
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/lib/index.js +36 -4
- package/lib/types/manifest.d.ts +1 -1
- package/package.json +22 -21
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:
|
|
13
|
-
zh:
|
|
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
|
|
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
|
-
|
|
1410
|
-
|
|
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) {
|
package/lib/types/manifest.d.ts
CHANGED
|
@@ -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.
|
|
4
|
+
"version": "0.2.1-alpha.3",
|
|
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.
|
|
32
|
-
"@deepseek-ai/dsh-llm-replay": "0.2.1-alpha.
|
|
33
|
-
"@deepseek-ai/dsh-loader-smoke": "0.2.1-alpha.
|
|
34
|
-
"@deepseek-ai/dsh-session-format": "0.2.1-alpha.
|
|
31
|
+
"@deepseek-ai/cordis-plugin-include": "~1.0.10-alpha.2",
|
|
32
|
+
"@deepseek-ai/dsh-llm-replay": "0.2.1-alpha.3",
|
|
33
|
+
"@deepseek-ai/dsh-loader-smoke": "0.2.1-alpha.3",
|
|
34
|
+
"@deepseek-ai/dsh-session-format": "0.2.1-alpha.3",
|
|
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.
|
|
40
|
-
"@deepseek-ai/dsh-session": "0.2.1-alpha.
|
|
41
|
-
"@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.
|
|
39
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2",
|
|
40
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.3",
|
|
41
|
+
"@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@deepseek-ai/cordis": "~4.0.5-alpha.
|
|
45
|
-
"@deepseek-ai/dsh-agent": "0.2.1-alpha.
|
|
46
|
-
"@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.
|
|
47
|
-
"@deepseek-ai/dsh-
|
|
48
|
-
"@deepseek-ai/dsh-
|
|
49
|
-
"@deepseek-ai/dsh-
|
|
50
|
-
"@deepseek-ai/dsh-
|
|
51
|
-
"@deepseek-ai/dsh-sandbox
|
|
52
|
-
"@deepseek-ai/dsh-
|
|
53
|
-
"@deepseek-ai/dsh-
|
|
54
|
-
"@deepseek-ai/dsh-
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
44
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.3",
|
|
46
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.3",
|
|
47
|
+
"@deepseek-ai/dsh-agent-preset-registry": "0.2.1-alpha.3",
|
|
48
|
+
"@deepseek-ai/dsh-compaction": "0.2.1-alpha.3",
|
|
49
|
+
"@deepseek-ai/dsh-fs": "0.2.1-alpha.3",
|
|
50
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.3",
|
|
51
|
+
"@deepseek-ai/dsh-sandbox": "0.2.1-alpha.3",
|
|
52
|
+
"@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.3",
|
|
53
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.3",
|
|
54
|
+
"@deepseek-ai/dsh-subagent": "0.2.1-alpha.3",
|
|
55
|
+
"@deepseek-ai/dsh-tools": "0.2.1-alpha.3",
|
|
56
|
+
"@deepseek-ai/dsh-user-questions": "0.2.1-alpha.3",
|
|
56
57
|
"@types/js-yaml": "^4.0.9",
|
|
57
|
-
"@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.
|
|
58
|
+
"@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.3"
|
|
58
59
|
}
|
|
59
60
|
}
|