@xdxer/dingtalk-agent 0.1.5-beta.10 → 0.1.5-beta.11
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/CHANGELOG.md +8 -0
- package/dist/src/agent-bindings.js +4 -8
- package/dist/src/agent-bindings.js.map +1 -1
- package/dist/src/map.js +157 -0
- package/dist/src/map.js.map +1 -0
- package/dist/src/memory/candidates.js +8 -0
- package/dist/src/memory/candidates.js.map +1 -1
- package/dist/src/memory/noop-receipt.js +17 -3
- package/dist/src/memory/noop-receipt.js.map +1 -1
- package/dist/src/state-dir.js +120 -0
- package/dist/src/state-dir.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@xdxer/dingtalk-agent` are documented here. The project follows semantic versioning; prerelease entries describe release candidates and do not imply that Live canaries or registry publication have completed.
|
|
4
4
|
|
|
5
|
+
## 0.1.5-beta.11 - 2026-07-25
|
|
6
|
+
|
|
7
|
+
A one-fix release, and the fix is a boundary that was being checked with the wrong instrument: string comparison cannot prove that a directory belongs to the host. The state-directory contract now has exactly one owner, and both the receipt store and the candidate store read it instead of keeping private copies. Ships on the `beta` dist-tag; `latest` stays at 0.1.4. Merged as PR #54.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **A symlink inside the agent root let prepared no-op receipts be written outside it (closes #52).** #47 correctly widened the prepared write boundary from the literal `.dingtalk-agent` to "anywhere in the agent root", but it compared `resolve()` strings only. A directory symlink inside the root pointing outside it therefore passed containment, and `mkdirSync`/the atomic write then followed that link: `recordMemoryNoop(root, claim, {stateDir: '.state-link'})` returned a lexical path under the root while `realpath` landed in a directory the host does not own — which is exactly the deployment fact #42 rests authenticity on ("the state directory is host-owned"), so a lexical check can prove neither ownership nor containment. The stateDir contract now has a single owner (`src/state-dir.ts`): lexical containment, stateDir may not equal the root (the bindings "separate private directory" rule), and the realpath of the existing prefix — plus a re-check after the directory is created, covering nested segments and swap races — must stay inside the agent root; a dangling symlink fails closed instead of surfacing as `ENOENT`. `loadAgentBindings` and the prepared candidate store read that same contract instead of keeping private copies (candidate writes were escapable the same way). Legitimate `.agent-private` setups keep issuing and tracing; `../outside-root`, a root-internal symlink to the outside (as stateDir or as its nested `memory/`), and `stateDir='.'` are all refused, and scenario #75 asserts the outside directories stay receipt-free.
|
|
12
|
+
|
|
5
13
|
## 0.1.5-beta.10 - 2026-07-25
|
|
6
14
|
|
|
7
15
|
The registry-and-receipts wave: every "the declaration says X" now has a reader on the other side that can prove or refute it. Completion predicates became referenced registry entries with a readback-verified marker; the memory save-decision leaves a typed, forgery-hardened trace; and three review rounds on this very wave (#35/#38/#39, #42, #45/#46/#47) were folded back in before shipping. Ships on the `beta` dist-tag; `latest` stays at 0.1.4. Merged as PRs #34, #36, #37, #41, #43, #44, #48, #49.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
2
|
import { relative, resolve } from 'node:path';
|
|
3
3
|
import { digest, stableStringify } from './events.js';
|
|
4
|
+
import { resolvePrivateStateDir } from './state-dir.js';
|
|
4
5
|
const ROOT_KEYS = new Set([
|
|
5
6
|
'$schema', 'agent', 'skills', 'memory', 'knowledge', 'artifacts', 'stateDir', 'authority',
|
|
6
7
|
]);
|
|
@@ -75,14 +76,9 @@ function assertLocalRoutesStayInside(root, bindings) {
|
|
|
75
76
|
throw new Error(`${label} 本地真实路径越出 Agent 根目录: ${ref}`);
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (state === root)
|
|
82
|
-
throw new Error('stateDir 必须是 Agent 根目录内的独立私有目录,不能等于根目录');
|
|
83
|
-
if (existsSync(state) && !isInside(root, realpathSync(state))) {
|
|
84
|
-
throw new Error(`stateDir 真实路径越出 Agent 根目录: ${bindings.stateDir}`);
|
|
85
|
-
}
|
|
79
|
+
// stateDir 的词法 + realpath 合同由 src/state-dir.ts 单一持有(issue #52):
|
|
80
|
+
// memory 的 Prepared 写入路径读同一份判据,避免两处分叉。
|
|
81
|
+
resolvePrivateStateDir(root, bindings.stateDir);
|
|
86
82
|
}
|
|
87
83
|
function storage(value, providers, label) {
|
|
88
84
|
const text = requiredString(value, label);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-bindings.js","sourceRoot":"","sources":["../../src/agent-bindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport { relative, resolve } from 'node:path'\nimport type { BootstrapOptions } from './bootstrap.js'\nimport { digest, stableStringify } from './events.js'\n\nexport interface AgentBindings {\n $schema: 'dingtalk-agent/agent-bindings@1'\n agent: string\n skills: string\n memory: string\n knowledge: string\n artifacts: string\n stateDir: string\n authority: {\n profile: string\n expectedUserId: string\n }\n}\n\nexport interface LoadedAgentBindings {\n path: string\n hash: string\n value: AgentBindings\n context: NonNullable<BootstrapOptions['context']>\n}\n\nconst ROOT_KEYS = new Set([\n '$schema', 'agent', 'skills', 'memory', 'knowledge', 'artifacts', 'stateDir', 'authority',\n])\nconst AUTHORITY_KEYS = new Set(['profile', 'expectedUserId'])\n\nexport function loadAgentBindings(root: string, input: string): LoadedAgentBindings {\n const rootReal = realpathSync(resolve(root))\n const candidate = resolve(rootReal, input)\n if (!isInside(rootReal, candidate)) {\n throw new Error(`Agent bindings 必须位于当前 Agent 根目录内: ${input}`)\n }\n if (!existsSync(candidate)) throw new Error(`Agent bindings 不存在: ${input}`)\n const path = realpathSync(candidate)\n if (!isInside(rootReal, path)) throw new Error(`Agent bindings 真实路径越界: ${input}`)\n\n let raw: unknown\n try { raw = JSON.parse(readFileSync(path, 'utf8')) }\n catch (error) { throw new Error(`Agent bindings 不是合法 JSON: ${error.message}`) }\n const value = objectValue(raw, 'Agent bindings')\n assertExactKeys(value, ROOT_KEYS, 'Agent bindings')\n if (value.$schema !== 'dingtalk-agent/agent-bindings@1') {\n throw new Error(`Agent bindings schema 非法: ${String(value.$schema || '-')}`)\n }\n const authority = objectValue(value.authority, 'Agent bindings authority')\n assertExactKeys(authority, AUTHORITY_KEYS, 'Agent bindings authority')\n\n const bindings: AgentBindings = {\n $schema: 'dingtalk-agent/agent-bindings@1',\n agent: storage(value.agent, ['local-dir'], 'agent'),\n skills: storage(value.skills, ['local-dir', 'local-md'], 'skills'),\n memory: storage(value.memory, ['local-md', 'dingtalk-doc'], 'memory'),\n knowledge: storage(value.knowledge, ['local-md', 'dingtalk-doc'], 'knowledge'),\n artifacts: storage(value.artifacts, ['local-dir'], 'artifacts'),\n stateDir: localStateDir(value.stateDir),\n authority: {\n profile: optionalString(authority.profile, 'authority.profile'),\n expectedUserId: optionalString(authority.expectedUserId, 'authority.expectedUserId'),\n },\n }\n assertLocalRoutesStayInside(rootReal, bindings)\n return {\n path,\n hash: digest(stableStringify(bindings)),\n value: bindings,\n context: {\n agent: bindings.agent,\n skills: bindings.skills,\n memory: bindings.memory,\n knowledge: bindings.knowledge,\n artifacts: bindings.artifacts,\n stateDir: bindings.stateDir,\n profile: bindings.authority.profile,\n expectedUserId: bindings.authority.expectedUserId,\n },\n }\n}\n\nfunction assertLocalRoutesStayInside(root: string, bindings: AgentBindings): void {\n for (const [label, uri] of Object.entries({\n agent: bindings.agent, skills: bindings.skills, memory: bindings.memory,\n knowledge: bindings.knowledge, artifacts: bindings.artifacts,\n })) {\n if (!uri.startsWith('local-')) continue\n const ref = uri.slice(uri.indexOf(':') + 1)\n const candidate = resolve(root, ref)\n if (!isInside(root, candidate)) throw new Error(`${label} 本地路径越出 Agent 根目录: ${ref}`)\n if (existsSync(candidate) && !isInside(root, realpathSync(candidate))) {\n throw new Error(`${label} 本地真实路径越出 Agent 根目录: ${ref}`)\n }\n }\n const state = resolve(root, bindings.stateDir)\n if (!isInside(root, state)) throw new Error(`stateDir 越出 Agent 根目录: ${bindings.stateDir}`)\n if (state === root) throw new Error('stateDir 必须是 Agent 根目录内的独立私有目录,不能等于根目录')\n if (existsSync(state) && !isInside(root, realpathSync(state))) {\n throw new Error(`stateDir 真实路径越出 Agent 根目录: ${bindings.stateDir}`)\n }\n}\n\nfunction storage(value: unknown, providers: string[], label: string): string {\n const text = requiredString(value, label)\n const separator = text.indexOf(':')\n const provider = separator < 0 ? '' : text.slice(0, separator)\n const reference = separator < 0 ? '' : text.slice(separator + 1).trim()\n if (!providers.includes(provider) || !reference) {\n throw new Error(`${label} Storage 非法;允许 ${providers.map((item) => `${item}:<ref>`).join(' / ')}`)\n }\n return text\n}\n\nfunction localStateDir(value: unknown): string {\n const text = requiredString(value, 'stateDir')\n if (/^[a-z][a-z0-9-]*:/i.test(text)) {\n throw new Error('stateDir 必须是宿主本地目录,不能是远端 Provider URI')\n }\n return text\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} 必须是非空字符串`)\n return value.trim()\n}\n\nfunction optionalString(value: unknown, label: string): string {\n if (typeof value !== 'string') throw new Error(`${label} 必须是字符串`)\n return value.trim()\n}\n\nfunction objectValue(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} 必须是 JSON object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction assertExactKeys(\n value: Record<string, unknown>, allowed: Set<string>, label: string,\n): void {\n const unknown = Object.keys(value).filter((key) => !allowed.has(key))\n if (unknown.length) throw new Error(`${label} 包含未知字段: ${unknown.join(', ')}`)\n const missing = [...allowed].filter((key) => !(key in value))\n if (missing.length) throw new Error(`${label} 缺少字段: ${missing.join(', ')}`)\n}\n\nfunction isInside(root: string, candidate: string): boolean {\n const rel = relative(root, candidate)\n return rel === '' || (rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`))\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-bindings.js","sourceRoot":"","sources":["../../src/agent-bindings.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, realpathSync } from 'node:fs'\nimport { relative, resolve } from 'node:path'\nimport type { BootstrapOptions } from './bootstrap.js'\nimport { digest, stableStringify } from './events.js'\nimport { resolvePrivateStateDir } from './state-dir.js'\n\nexport interface AgentBindings {\n $schema: 'dingtalk-agent/agent-bindings@1'\n agent: string\n skills: string\n memory: string\n knowledge: string\n artifacts: string\n stateDir: string\n authority: {\n profile: string\n expectedUserId: string\n }\n}\n\nexport interface LoadedAgentBindings {\n path: string\n hash: string\n value: AgentBindings\n context: NonNullable<BootstrapOptions['context']>\n}\n\nconst ROOT_KEYS = new Set([\n '$schema', 'agent', 'skills', 'memory', 'knowledge', 'artifacts', 'stateDir', 'authority',\n])\nconst AUTHORITY_KEYS = new Set(['profile', 'expectedUserId'])\n\nexport function loadAgentBindings(root: string, input: string): LoadedAgentBindings {\n const rootReal = realpathSync(resolve(root))\n const candidate = resolve(rootReal, input)\n if (!isInside(rootReal, candidate)) {\n throw new Error(`Agent bindings 必须位于当前 Agent 根目录内: ${input}`)\n }\n if (!existsSync(candidate)) throw new Error(`Agent bindings 不存在: ${input}`)\n const path = realpathSync(candidate)\n if (!isInside(rootReal, path)) throw new Error(`Agent bindings 真实路径越界: ${input}`)\n\n let raw: unknown\n try { raw = JSON.parse(readFileSync(path, 'utf8')) }\n catch (error) { throw new Error(`Agent bindings 不是合法 JSON: ${error.message}`) }\n const value = objectValue(raw, 'Agent bindings')\n assertExactKeys(value, ROOT_KEYS, 'Agent bindings')\n if (value.$schema !== 'dingtalk-agent/agent-bindings@1') {\n throw new Error(`Agent bindings schema 非法: ${String(value.$schema || '-')}`)\n }\n const authority = objectValue(value.authority, 'Agent bindings authority')\n assertExactKeys(authority, AUTHORITY_KEYS, 'Agent bindings authority')\n\n const bindings: AgentBindings = {\n $schema: 'dingtalk-agent/agent-bindings@1',\n agent: storage(value.agent, ['local-dir'], 'agent'),\n skills: storage(value.skills, ['local-dir', 'local-md'], 'skills'),\n memory: storage(value.memory, ['local-md', 'dingtalk-doc'], 'memory'),\n knowledge: storage(value.knowledge, ['local-md', 'dingtalk-doc'], 'knowledge'),\n artifacts: storage(value.artifacts, ['local-dir'], 'artifacts'),\n stateDir: localStateDir(value.stateDir),\n authority: {\n profile: optionalString(authority.profile, 'authority.profile'),\n expectedUserId: optionalString(authority.expectedUserId, 'authority.expectedUserId'),\n },\n }\n assertLocalRoutesStayInside(rootReal, bindings)\n return {\n path,\n hash: digest(stableStringify(bindings)),\n value: bindings,\n context: {\n agent: bindings.agent,\n skills: bindings.skills,\n memory: bindings.memory,\n knowledge: bindings.knowledge,\n artifacts: bindings.artifacts,\n stateDir: bindings.stateDir,\n profile: bindings.authority.profile,\n expectedUserId: bindings.authority.expectedUserId,\n },\n }\n}\n\nfunction assertLocalRoutesStayInside(root: string, bindings: AgentBindings): void {\n for (const [label, uri] of Object.entries({\n agent: bindings.agent, skills: bindings.skills, memory: bindings.memory,\n knowledge: bindings.knowledge, artifacts: bindings.artifacts,\n })) {\n if (!uri.startsWith('local-')) continue\n const ref = uri.slice(uri.indexOf(':') + 1)\n const candidate = resolve(root, ref)\n if (!isInside(root, candidate)) throw new Error(`${label} 本地路径越出 Agent 根目录: ${ref}`)\n if (existsSync(candidate) && !isInside(root, realpathSync(candidate))) {\n throw new Error(`${label} 本地真实路径越出 Agent 根目录: ${ref}`)\n }\n }\n // stateDir 的词法 + realpath 合同由 src/state-dir.ts 单一持有(issue #52):\n // memory 的 Prepared 写入路径读同一份判据,避免两处分叉。\n resolvePrivateStateDir(root, bindings.stateDir)\n}\n\nfunction storage(value: unknown, providers: string[], label: string): string {\n const text = requiredString(value, label)\n const separator = text.indexOf(':')\n const provider = separator < 0 ? '' : text.slice(0, separator)\n const reference = separator < 0 ? '' : text.slice(separator + 1).trim()\n if (!providers.includes(provider) || !reference) {\n throw new Error(`${label} Storage 非法;允许 ${providers.map((item) => `${item}:<ref>`).join(' / ')}`)\n }\n return text\n}\n\nfunction localStateDir(value: unknown): string {\n const text = requiredString(value, 'stateDir')\n if (/^[a-z][a-z0-9-]*:/i.test(text)) {\n throw new Error('stateDir 必须是宿主本地目录,不能是远端 Provider URI')\n }\n return text\n}\n\nfunction requiredString(value: unknown, label: string): string {\n if (typeof value !== 'string' || !value.trim()) throw new Error(`${label} 必须是非空字符串`)\n return value.trim()\n}\n\nfunction optionalString(value: unknown, label: string): string {\n if (typeof value !== 'string') throw new Error(`${label} 必须是字符串`)\n return value.trim()\n}\n\nfunction objectValue(value: unknown, label: string): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error(`${label} 必须是 JSON object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction assertExactKeys(\n value: Record<string, unknown>, allowed: Set<string>, label: string,\n): void {\n const unknown = Object.keys(value).filter((key) => !allowed.has(key))\n if (unknown.length) throw new Error(`${label} 包含未知字段: ${unknown.join(', ')}`)\n const missing = [...allowed].filter((key) => !(key in value))\n if (missing.length) throw new Error(`${label} 缺少字段: ${missing.join(', ')}`)\n}\n\nfunction isInside(root: string, candidate: string): boolean {\n const rel = relative(root, candidate)\n return rel === '' || (rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`))\n}\n"]}
|
package/dist/src/map.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Managed Agents Platform(MAP)注册表与工作区归属解析。
|
|
2
|
+
//
|
|
3
|
+
// 一个 Agent 工作区归属于至多一个托管平台;归属解析顺序固定:
|
|
4
|
+
// DTA_MAP 环境变量 > dingtalk-agent.json#map > .dingtalk-agent/map.json > 按 Provider 声明推断。
|
|
5
|
+
// 平台相关的方法学不写进 CLI——它们随对应平台的 Skill 包分发,只在用户选择该平台时安装。
|
|
6
|
+
// 平台命令(如 deploy/promote/observe)必须先通过归属门禁;coming-soon 平台一律 fail-closed。
|
|
7
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { dirname, join, parse, resolve } from 'node:path';
|
|
9
|
+
import { findAgentProjectRoot } from './development-workspace.js';
|
|
10
|
+
import { installGlobalSkill } from './skill-manager.js';
|
|
11
|
+
export const MANAGED_AGENT_PLATFORMS = [
|
|
12
|
+
{
|
|
13
|
+
name: 'multica-dingtalk',
|
|
14
|
+
label: 'Multica (DingTalk)',
|
|
15
|
+
status: 'supported',
|
|
16
|
+
description: '钉钉 Multica 托管平台:受控部署、晋级与观测回流。',
|
|
17
|
+
skills: ['dingtalk-agent-deploy', 'dingtalk-agent-boot-multica'],
|
|
18
|
+
commands: ['deploy', 'promote', 'observe'],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'deap',
|
|
22
|
+
label: 'DEAP',
|
|
23
|
+
status: 'coming-soon',
|
|
24
|
+
description: '敬请期待。',
|
|
25
|
+
skills: [],
|
|
26
|
+
commands: [],
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
export const MAP_FILE = '.dingtalk-agent/map.json';
|
|
30
|
+
const PROJECT_FILE = 'dingtalk-agent.json';
|
|
31
|
+
export function mapDefinition(name) {
|
|
32
|
+
return MANAGED_AGENT_PLATFORMS.find((item) => item.name === name) || null;
|
|
33
|
+
}
|
|
34
|
+
export function resolveMap(start = process.cwd(), env = process.env) {
|
|
35
|
+
const fromEnv = String(env.DTA_MAP || '').trim();
|
|
36
|
+
if (fromEnv)
|
|
37
|
+
return resolution(fromEnv, 'env', '');
|
|
38
|
+
const projectRoot = findAgentProjectRoot(start);
|
|
39
|
+
if (projectRoot) {
|
|
40
|
+
const manifestPath = join(projectRoot, PROJECT_FILE);
|
|
41
|
+
if (existsSync(manifestPath) && !lstatSync(manifestPath).isSymbolicLink()) {
|
|
42
|
+
const manifest = readJsonOrNull(manifestPath);
|
|
43
|
+
const declared = typeof manifest?.map === 'string' ? manifest.map.trim() : '';
|
|
44
|
+
if (declared)
|
|
45
|
+
return resolution(declared, 'project-manifest', manifestPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const mapPath = findUp(start, MAP_FILE);
|
|
49
|
+
if (mapPath) {
|
|
50
|
+
const stored = readJsonOrNull(mapPath);
|
|
51
|
+
const declared = typeof stored?.map === 'string' ? stored.map.trim() : '';
|
|
52
|
+
if (declared)
|
|
53
|
+
return resolution(declared, 'map-file', mapPath);
|
|
54
|
+
}
|
|
55
|
+
if (projectRoot) {
|
|
56
|
+
const manifest = readJsonOrNull(join(projectRoot, PROJECT_FILE));
|
|
57
|
+
const providers = Object.values(manifest?.workspaces || {})
|
|
58
|
+
.map((workspace) => workspace?.provider?.kind);
|
|
59
|
+
if (providers.includes('multica')) {
|
|
60
|
+
return resolution('multica-dingtalk', 'inferred', join(projectRoot, PROJECT_FILE));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return resolution(null, 'none', '');
|
|
64
|
+
}
|
|
65
|
+
export function useMap(start, name, options) {
|
|
66
|
+
const definition = mapDefinition(name);
|
|
67
|
+
if (!definition) {
|
|
68
|
+
throw new Error(`未知 managed agents platform: ${name}\n` +
|
|
69
|
+
`可用: ${MANAGED_AGENT_PLATFORMS.map((item) => `${item.name}(${statusLabel(item.status)})`).join('、')}`);
|
|
70
|
+
}
|
|
71
|
+
if (definition.status !== 'supported') {
|
|
72
|
+
throw new Error(`${definition.label} 敬请期待——当前版本尚未开放该平台。`);
|
|
73
|
+
}
|
|
74
|
+
const projectRoot = findAgentProjectRoot(start);
|
|
75
|
+
let written;
|
|
76
|
+
if (projectRoot && existsSync(join(projectRoot, PROJECT_FILE))) {
|
|
77
|
+
const manifestPath = join(projectRoot, PROJECT_FILE);
|
|
78
|
+
if (lstatSync(manifestPath).isSymbolicLink()) {
|
|
79
|
+
throw new Error(`${PROJECT_FILE} 不能是符号链接`);
|
|
80
|
+
}
|
|
81
|
+
const manifest = readJsonOrNull(manifestPath);
|
|
82
|
+
if (!manifest || typeof manifest !== 'object') {
|
|
83
|
+
throw new Error(`${PROJECT_FILE} 不是合法 JSON,无法写入 map 归属`);
|
|
84
|
+
}
|
|
85
|
+
manifest.map = definition.name;
|
|
86
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
87
|
+
written = manifestPath;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const target = join(resolve(start), MAP_FILE);
|
|
91
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
92
|
+
writeFileSync(target, JSON.stringify({ $schema: 'dingtalk-agent/map@1', map: definition.name }, null, 2) + '\n');
|
|
93
|
+
written = target;
|
|
94
|
+
}
|
|
95
|
+
const skillInstalls = [];
|
|
96
|
+
if (options.installSkills !== false) {
|
|
97
|
+
for (const skill of definition.skills) {
|
|
98
|
+
skillInstalls.push(installGlobalSkill(options.packageRoot, {
|
|
99
|
+
name: skill, home: options.home, env: options.env,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { ...resolveMap(start, options.env || process.env), written, skillInstalls };
|
|
104
|
+
}
|
|
105
|
+
/** deploy/promote/observe 等平台命令的归属门禁:未归属、未知或 coming-soon 一律 fail-closed。 */
|
|
106
|
+
export function requireSupportedMap(command, start = process.cwd(), env = process.env) {
|
|
107
|
+
const resolved = resolveMap(start, env);
|
|
108
|
+
if (!resolved.map) {
|
|
109
|
+
throw new Error(`当前工作区未声明 managed agents platform,无法执行 \`${command}\`。\n` +
|
|
110
|
+
'先运行 `dta map use multica-dingtalk`,或设置 DTA_MAP 环境变量。');
|
|
111
|
+
}
|
|
112
|
+
if (!resolved.definition) {
|
|
113
|
+
throw new Error(`工作区声明了未知 platform: ${resolved.map}(来源 ${resolved.source})。\n` +
|
|
114
|
+
`可用: ${MANAGED_AGENT_PLATFORMS.map((item) => item.name).join('、')}`);
|
|
115
|
+
}
|
|
116
|
+
if (resolved.definition.status !== 'supported') {
|
|
117
|
+
throw new Error(`${resolved.definition.label} 敬请期待——\`${command}\` 尚未在该平台开放。`);
|
|
118
|
+
}
|
|
119
|
+
if (!resolved.definition.commands.includes(command)) {
|
|
120
|
+
throw new Error(`${resolved.definition.label} 不承接命令 \`${command}\`。`);
|
|
121
|
+
}
|
|
122
|
+
return resolved;
|
|
123
|
+
}
|
|
124
|
+
export function statusLabel(status) {
|
|
125
|
+
return status === 'supported' ? '已支持' : '敬请期待';
|
|
126
|
+
}
|
|
127
|
+
function resolution(name, source, file) {
|
|
128
|
+
return {
|
|
129
|
+
$schema: 'dingtalk-agent/map-resolution@1',
|
|
130
|
+
map: name,
|
|
131
|
+
source,
|
|
132
|
+
file,
|
|
133
|
+
definition: name ? mapDefinition(name) : null,
|
|
134
|
+
platforms: MANAGED_AGENT_PLATFORMS,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function readJsonOrNull(path) {
|
|
138
|
+
try {
|
|
139
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function findUp(start, relativePath) {
|
|
146
|
+
let dir = resolve(start);
|
|
147
|
+
while (true) {
|
|
148
|
+
const candidate = join(dir, relativePath);
|
|
149
|
+
if (existsSync(candidate) && !lstatSync(candidate).isSymbolicLink())
|
|
150
|
+
return candidate;
|
|
151
|
+
const parent = dirname(dir);
|
|
152
|
+
if (parent === dir || dir === parse(dir).root)
|
|
153
|
+
return null;
|
|
154
|
+
dir = parent;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"map.js","sourceRoot":"","sources":["../../src/map.ts"],"names":[],"mappings":"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","sourcesContent":["// Managed Agents Platform(MAP)注册表与工作区归属解析。\n//\n// 一个 Agent 工作区归属于至多一个托管平台;归属解析顺序固定:\n// DTA_MAP 环境变量 > dingtalk-agent.json#map > .dingtalk-agent/map.json > 按 Provider 声明推断。\n// 平台相关的方法学不写进 CLI——它们随对应平台的 Skill 包分发,只在用户选择该平台时安装。\n// 平台命令(如 deploy/promote/observe)必须先通过归属门禁;coming-soon 平台一律 fail-closed。\n\nimport { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join, parse, resolve } from 'node:path'\n\nimport { findAgentProjectRoot } from './development-workspace.js'\nimport { installGlobalSkill, type GlobalSkillStatus } from './skill-manager.js'\n\nexport type MapStatus = 'supported' | 'coming-soon'\n\nexport interface MapDefinition {\n name: string\n label: string\n status: MapStatus\n description: string\n skills: string[]\n commands: string[]\n}\n\nexport const MANAGED_AGENT_PLATFORMS: MapDefinition[] = [\n {\n name: 'multica-dingtalk',\n label: 'Multica (DingTalk)',\n status: 'supported',\n description: '钉钉 Multica 托管平台:受控部署、晋级与观测回流。',\n skills: ['dingtalk-agent-deploy', 'dingtalk-agent-boot-multica'],\n commands: ['deploy', 'promote', 'observe'],\n },\n {\n name: 'deap',\n label: 'DEAP',\n status: 'coming-soon',\n description: '敬请期待。',\n skills: [],\n commands: [],\n },\n]\n\nexport const MAP_FILE = '.dingtalk-agent/map.json'\nconst PROJECT_FILE = 'dingtalk-agent.json'\n\nexport type MapSource = 'env' | 'project-manifest' | 'map-file' | 'inferred' | 'none'\n\nexport interface MapResolution {\n $schema: 'dingtalk-agent/map-resolution@1'\n map: string | null\n source: MapSource\n file: string\n definition: MapDefinition | null\n platforms: MapDefinition[]\n}\n\nexport interface MapUseResult extends MapResolution {\n written: string\n skillInstalls: GlobalSkillStatus[]\n}\n\nexport function mapDefinition(name: string): MapDefinition | null {\n return MANAGED_AGENT_PLATFORMS.find((item) => item.name === name) || null\n}\n\nexport function resolveMap(start = process.cwd(), env: NodeJS.ProcessEnv = process.env): MapResolution {\n const fromEnv = String(env.DTA_MAP || '').trim()\n if (fromEnv) return resolution(fromEnv, 'env', '')\n\n const projectRoot = findAgentProjectRoot(start)\n if (projectRoot) {\n const manifestPath = join(projectRoot, PROJECT_FILE)\n if (existsSync(manifestPath) && !lstatSync(manifestPath).isSymbolicLink()) {\n const manifest = readJsonOrNull(manifestPath)\n const declared = typeof manifest?.map === 'string' ? manifest.map.trim() : ''\n if (declared) return resolution(declared, 'project-manifest', manifestPath)\n }\n }\n\n const mapPath = findUp(start, MAP_FILE)\n if (mapPath) {\n const stored = readJsonOrNull(mapPath)\n const declared = typeof stored?.map === 'string' ? stored.map.trim() : ''\n if (declared) return resolution(declared, 'map-file', mapPath)\n }\n\n if (projectRoot) {\n const manifest = readJsonOrNull(join(projectRoot, PROJECT_FILE))\n const providers = Object.values(manifest?.workspaces || {})\n .map((workspace: any) => workspace?.provider?.kind)\n if (providers.includes('multica')) {\n return resolution('multica-dingtalk', 'inferred', join(projectRoot, PROJECT_FILE))\n }\n }\n\n return resolution(null, 'none', '')\n}\n\nexport interface MapUseOptions {\n packageRoot: string\n home?: string\n env?: NodeJS.ProcessEnv\n installSkills?: boolean\n}\n\nexport function useMap(start: string, name: string, options: MapUseOptions): MapUseResult {\n const definition = mapDefinition(name)\n if (!definition) {\n throw new Error(\n `未知 managed agents platform: ${name}\\n` +\n `可用: ${MANAGED_AGENT_PLATFORMS.map((item) => `${item.name}(${statusLabel(item.status)})`).join('、')}`,\n )\n }\n if (definition.status !== 'supported') {\n throw new Error(`${definition.label} 敬请期待——当前版本尚未开放该平台。`)\n }\n\n const projectRoot = findAgentProjectRoot(start)\n let written: string\n if (projectRoot && existsSync(join(projectRoot, PROJECT_FILE))) {\n const manifestPath = join(projectRoot, PROJECT_FILE)\n if (lstatSync(manifestPath).isSymbolicLink()) {\n throw new Error(`${PROJECT_FILE} 不能是符号链接`)\n }\n const manifest = readJsonOrNull(manifestPath)\n if (!manifest || typeof manifest !== 'object') {\n throw new Error(`${PROJECT_FILE} 不是合法 JSON,无法写入 map 归属`)\n }\n manifest.map = definition.name\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\\n')\n written = manifestPath\n } else {\n const target = join(resolve(start), MAP_FILE)\n mkdirSync(dirname(target), { recursive: true })\n writeFileSync(target, JSON.stringify(\n { $schema: 'dingtalk-agent/map@1', map: definition.name }, null, 2,\n ) + '\\n')\n written = target\n }\n\n const skillInstalls: GlobalSkillStatus[] = []\n if (options.installSkills !== false) {\n for (const skill of definition.skills) {\n skillInstalls.push(installGlobalSkill(options.packageRoot, {\n name: skill, home: options.home, env: options.env,\n }))\n }\n }\n\n return { ...resolveMap(start, options.env || process.env), written, skillInstalls }\n}\n\n/** deploy/promote/observe 等平台命令的归属门禁:未归属、未知或 coming-soon 一律 fail-closed。 */\nexport function requireSupportedMap(\n command: string, start = process.cwd(), env: NodeJS.ProcessEnv = process.env,\n): MapResolution {\n const resolved = resolveMap(start, env)\n if (!resolved.map) {\n throw new Error(\n `当前工作区未声明 managed agents platform,无法执行 \\`${command}\\`。\\n` +\n '先运行 `dta map use multica-dingtalk`,或设置 DTA_MAP 环境变量。',\n )\n }\n if (!resolved.definition) {\n throw new Error(\n `工作区声明了未知 platform: ${resolved.map}(来源 ${resolved.source})。\\n` +\n `可用: ${MANAGED_AGENT_PLATFORMS.map((item) => item.name).join('、')}`,\n )\n }\n if (resolved.definition.status !== 'supported') {\n throw new Error(`${resolved.definition.label} 敬请期待——\\`${command}\\` 尚未在该平台开放。`)\n }\n if (!resolved.definition.commands.includes(command)) {\n throw new Error(`${resolved.definition.label} 不承接命令 \\`${command}\\`。`)\n }\n return resolved\n}\n\nexport function statusLabel(status: MapStatus): string {\n return status === 'supported' ? '已支持' : '敬请期待'\n}\n\nfunction resolution(name: string | null, source: MapSource, file: string): MapResolution {\n return {\n $schema: 'dingtalk-agent/map-resolution@1',\n map: name,\n source,\n file,\n definition: name ? mapDefinition(name) : null,\n platforms: MANAGED_AGENT_PLATFORMS,\n }\n}\n\nfunction readJsonOrNull(path: string): any {\n try { return JSON.parse(readFileSync(path, 'utf8')) } catch { return null }\n}\n\nfunction findUp(start: string, relativePath: string): string | null {\n let dir = resolve(start)\n while (true) {\n const candidate = join(dir, relativePath)\n if (existsSync(candidate) && !lstatSync(candidate).isSymbolicLink()) return candidate\n const parent = dirname(dir)\n if (parent === dir || dir === parse(dir).root) return null\n dir = parent\n }\n}\n"]}
|
|
@@ -4,6 +4,7 @@ import { dirname, join, relative, resolve } from 'node:path';
|
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { digest, stableStringify } from '../events.js';
|
|
6
6
|
import { acquireLease } from '../lease.js';
|
|
7
|
+
import { assertNoSymlinkEscape, assertRealpathInsideRoot } from '../state-dir.js';
|
|
7
8
|
import * as dws from '../dws.js';
|
|
8
9
|
export function proposeMemoryCandidate(root, value, options = {}) {
|
|
9
10
|
const proposal = validateProposal(value);
|
|
@@ -362,7 +363,14 @@ function candidateRoot(root, stateDir = '', prepared = false) {
|
|
|
362
363
|
if (prepared)
|
|
363
364
|
assertInside(resolve(root, '.dingtalk-agent'), base, 'Prepared candidate stateDir');
|
|
364
365
|
const path = join(base, 'memory', 'candidates');
|
|
366
|
+
// 词法 containment 挡不住 symlink:root 内指向外部的目录 symlink 会让上面的检查通过,
|
|
367
|
+
// 再沿 symlink 把 Candidate 写出 Agent root(issue #52 在 no-op Receipt 上的同一条逃逸)。
|
|
368
|
+
const guard = prepared
|
|
369
|
+
? () => assertRealpathInsideRoot(root, path, 'Prepared candidate 目录')
|
|
370
|
+
: () => assertNoSymlinkEscape(root, path, 'Candidate 目录');
|
|
371
|
+
guard();
|
|
365
372
|
mkdirSync(path, { recursive: true });
|
|
373
|
+
guard();
|
|
366
374
|
return path;
|
|
367
375
|
}
|
|
368
376
|
function candidatePath(root, id, stateDir = '') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/memory/candidates.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, relative, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { digest, stableStringify } from '../events.js'\nimport { acquireLease } from '../lease.js'\nimport * as dws from '../dws.js'\n\nexport interface MemoryCandidateProposal {\n $schema: 'dingtalk-agent/memory-candidate-proposal@1'\n kind: 'semantic' | 'procedural'\n scopeId: string\n title: string\n content: string\n sourceRefs: string[]\n confidence: number\n supersedes: string[]\n}\n\nexport interface MemoryCandidate {\n $schema: 'dingtalk-agent/memory-candidate@1'\n id: string\n revision: number\n kind: 'semantic' | 'procedural'\n scopeId: string\n title: string\n content: string\n sourceRefs: string[]\n confidence: number\n supersedes: string[]\n status: 'proposed' | 'approved' | 'rejected' | 'published'\n proposedAt: string\n proposer: {\n mode: 'prepared' | 'direct'\n runId: string\n eventId: string\n definitionHash: string\n }\n review: null | {\n decision: 'approve' | 'reject'\n reviewer: string\n reason: string\n reviewedAt: string\n }\n publication: null | {\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n targetHashBefore: string\n targetHashAfter: string\n verification: string\n concurrency: 'atomic-local-cas' | 'best-effort-read-check-append'\n publishedAt: string\n gitHead: string\n }\n hash: string\n}\n\nexport interface MemoryPublishTarget {\n $schema: 'dingtalk-agent/memory-publish-target@1'\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n profile?: string\n expectedUserId?: string\n}\n\nexport interface CandidateOptions {\n stateDir?: string\n runPath?: string\n}\n\nexport interface CandidateResult {\n $schema: 'dingtalk-agent/memory-candidate-result@1'\n duplicate: boolean\n path: string\n candidate: MemoryCandidate\n}\n\nexport interface CandidatePublishResult {\n $schema: 'dingtalk-agent/memory-publish-result@1'\n mode: 'dry-run' | 'published' | 'uncertain'\n sideEffect: boolean\n verified: boolean\n duplicate: boolean\n candidateId: string\n candidateRevision: number\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n currentTargetHash: string\n targetHashAfter: string\n markerCount: number\n verification: string\n concurrency: 'atomic-local-cas' | 'best-effort-read-check-append'\n candidate: MemoryCandidate\n}\n\nexport function proposeMemoryCandidate(\n root: string,\n value: unknown,\n options: CandidateOptions = {},\n): CandidateResult {\n const proposal = validateProposal(value)\n const run = proposerContext(root, options.runPath)\n if (run && proposal.scopeId !== run.contextId) {\n throw new Error(\n `Memory Candidate scopeId=${proposal.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`,\n )\n }\n const id = `memcand_${digest(stableStringify(proposal)).slice(0, 24)}`\n const rootPath = candidateRoot(root, options.stateDir, Boolean(run))\n const path = join(rootPath, `${id}.json`)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在创建`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n if (existsSync(path)) {\n const existing = readCandidate(path)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: true,\n path, candidate: existing }\n }\n const now = new Date().toISOString()\n const unsigned: Omit<MemoryCandidate, 'hash'> = {\n $schema: 'dingtalk-agent/memory-candidate@1',\n id,\n revision: 1,\n kind: proposal.kind,\n scopeId: proposal.scopeId,\n title: proposal.title,\n content: proposal.content,\n sourceRefs: proposal.sourceRefs,\n confidence: proposal.confidence,\n supersedes: proposal.supersedes,\n status: 'proposed',\n proposedAt: now,\n proposer: run ? {\n mode: 'prepared', runId: run.id, eventId: run.eventId,\n definitionHash: run.definition?.hash || '',\n } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },\n review: null,\n publication: null,\n }\n const candidate = signCandidate(unsigned)\n writeJsonAtomic(path, candidate)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n } finally {\n release()\n }\n}\n\nexport function showMemoryCandidate(\n root: string,\n id: string,\n options: CandidateOptions = {},\n): CandidateResult {\n const path = candidatePath(root, id, options.stateDir)\n if (!existsSync(path)) throw new Error(`找不到 Memory Candidate: ${id}`)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n}\n\nexport function reviewMemoryCandidate(\n root: string,\n id: string,\n decision: 'approve' | 'reject',\n reviewer: string,\n reason: string,\n expectedRevision: number,\n options: CandidateOptions = {},\n): CandidateResult {\n assertOffline('review', options.runPath)\n if (!['approve', 'reject'].includes(decision)) throw new Error('review decision 只能是 approve/reject')\n if (!clean(reviewer) || !clean(reason)) throw new Error('review 需要 reviewer 和 reason')\n const path = candidatePath(root, id, options.stateDir)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在评审`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n const current = readCandidate(path)\n assertCandidateRevision(current, expectedRevision)\n if (current.status !== 'proposed') {\n throw new Error(`Memory Candidate ${id} 当前状态是 ${current.status},不能再次评审`)\n }\n const unsigned: Omit<MemoryCandidate, 'hash'> = {\n ...withoutHash(current),\n revision: current.revision + 1,\n status: decision === 'approve' ? 'approved' : 'rejected',\n review: {\n decision,\n reviewer: clean(reviewer),\n reason: clean(reason),\n reviewedAt: new Date().toISOString(),\n },\n }\n const candidate = signCandidate(unsigned)\n writeJsonAtomic(path, candidate)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n } finally {\n release()\n }\n}\n\nexport function publishMemoryCandidate(\n root: string,\n id: string,\n targetValue: unknown,\n expectedRevision: number,\n expectedTargetHash = '',\n options: CandidateOptions & { execute?: boolean; yes?: boolean; live?: boolean } = {},\n): CandidatePublishResult {\n if (options.execute) assertOffline('publish', options.runPath)\n const target = validateTarget(targetValue)\n const path = candidatePath(root, id, options.stateDir)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在发布`, {\n waitMs: 3_000, staleAfterMs: 10 * 60_000,\n })\n try {\n const current = readCandidate(path)\n assertCandidateRevision(current, expectedRevision)\n if (!['approved', 'published'].includes(current.status)) {\n throw new Error(`Memory Candidate ${id} 状态为 ${current.status},必须先 approve`)\n }\n if (current.status === 'published' && current.publication?.uri !== target.uri) {\n throw new Error(\n `Memory Candidate ${id} 已发布到 ${current.publication?.uri || '-'},不能静默换目标`,\n )\n }\n const targetContext = readPublishTarget(root, target)\n const block = renderCandidate(current)\n const markerCount = countMarker(targetContext.content, current.id)\n const concurrency = target.provider === 'local-md'\n ? 'atomic-local-cas' as const : 'best-effort-read-check-append' as const\n const base = {\n $schema: 'dingtalk-agent/memory-publish-result@1' as const,\n sideEffect: false,\n verified: false,\n duplicate: false,\n candidateId: current.id,\n candidateRevision: current.revision,\n provider: target.provider,\n uri: target.uri,\n currentTargetHash: targetContext.hash,\n targetHashAfter: '',\n markerCount,\n verification: 'dry-run-target-inspected',\n concurrency,\n candidate: current,\n }\n if (!options.execute) return { ...base, mode: 'dry-run' }\n if (!options.yes) throw new Error('Memory Candidate 发布必须显式 --yes')\n if (!expectedTargetHash || expectedTargetHash !== targetContext.hash) {\n throw new Error(\n `发布目标 hash 冲突:expected=${expectedTargetHash || '-'}, actual=${targetContext.hash};` +\n '请重新 dry-run 并人工检查差异',\n )\n }\n if (markerCount > 1) {\n return { ...base, mode: 'uncertain', verification: 'duplicate-candidate-markers' }\n }\n let published\n if (target.provider === 'local-md') {\n published = publishLocal(targetContext.path, targetContext.content, block, current.id)\n } else {\n if (!options.live) throw new Error('钉钉文档发布必须显式 --live --yes')\n published = publishDingTalkDoc(target, targetContext.content, block, current.id)\n }\n if (!published.verified) {\n return {\n ...base,\n mode: 'uncertain',\n sideEffect: published.sideEffect,\n duplicate: published.duplicate,\n targetHashAfter: published.hash,\n markerCount: published.markerCount,\n verification: published.verification,\n }\n }\n const publication = {\n provider: target.provider,\n uri: target.uri,\n targetHashBefore: targetContext.hash,\n targetHashAfter: published.hash,\n verification: published.verification,\n concurrency,\n publishedAt: new Date().toISOString(),\n gitHead: target.provider === 'local-md' ? readGitHead(root) : '',\n }\n const candidate = current.status === 'published'\n ? current\n : signCandidate({\n ...withoutHash(current),\n revision: current.revision + 1,\n status: 'published',\n publication,\n })\n if (current.status !== 'published') writeJsonAtomic(path, candidate)\n return {\n ...base,\n mode: 'published',\n sideEffect: published.sideEffect,\n verified: true,\n duplicate: published.duplicate,\n candidateRevision: candidate.revision,\n targetHashAfter: published.hash,\n markerCount: published.markerCount,\n verification: published.verification,\n candidate: readCandidate(path),\n }\n } finally {\n release()\n }\n}\n\nfunction publishLocal(\n path: string,\n content: string,\n block: string,\n candidateId: string,\n): { verified: boolean; sideEffect: boolean; duplicate: boolean; hash: string;\n markerCount: number; verification: string } {\n const release = acquireLease(`${path}.dta-publish.lock`, `发布目标 ${path} 正在更新`, {\n waitMs: 3_000, staleAfterMs: 10 * 60_000,\n })\n try {\n const latest = readFileSync(path, 'utf8')\n if (latest !== content) throw new Error('本地发布目标在加锁前发生漂移,请重新 dry-run')\n const existing = countMarker(latest, candidateId)\n const next = existing === 1 ? latest : appendBlock(latest, block)\n if (!existing) writeTextAtomic(path, next)\n const readback = readFileSync(path, 'utf8')\n const markerCount = countMarker(readback, candidateId)\n const verified = markerCount === 1 && readback.includes(block.trim())\n return {\n verified,\n sideEffect: !existing,\n duplicate: existing === 1,\n hash: digest(readback),\n markerCount,\n verification: verified ? 'local-atomic-write-readback' : 'local-readback-mismatch',\n }\n } finally {\n release()\n }\n}\n\nfunction publishDingTalkDoc(\n target: MemoryPublishTarget,\n content: string,\n block: string,\n candidateId: string,\n): { verified: boolean; sideEffect: boolean; duplicate: boolean; hash: string;\n markerCount: number; verification: string } {\n const profile = clean(target.profile || process.env.DTA_DWS_PROFILE)\n const expectedUserId = clean(target.expectedUserId || process.env.DTA_EXPECTED_USER_ID)\n if (!profile || profile.includes(',') || !expectedUserId) {\n throw new Error('dingtalk-doc 发布必须固定单一 profile 和 expectedUserId')\n }\n const identity = dws.getSelf(profile)\n const actualUserId = String(findValue(identity, ['userId', 'user_id', 'userid']) || '')\n if (!actualUserId || actualUserId !== expectedUserId) {\n throw new Error(`DWS 执行身份不符:expected=${expectedUserId}, actual=${actualUserId || '-'}`)\n }\n const existing = countMarker(content, candidateId)\n let sideEffect = false\n if (!existing) {\n const directory = mkdtempSync(join(tmpdir(), 'dta-memory-publish-'))\n const file = join(directory, 'candidate.md')\n try {\n writeFileSync(file, block)\n dws.appendDoc(target.uri.slice('dingtalk-doc:'.length), file, profile)\n sideEffect = true\n } finally {\n rmSync(directory, { recursive: true, force: true })\n }\n }\n const readback = String(dws.readDoc(target.uri.slice('dingtalk-doc:'.length), profile))\n const markerCount = countMarker(readback, candidateId)\n const verified = markerCount === 1 && dws.words(readback).includes(dws.words(block))\n return {\n verified,\n sideEffect,\n duplicate: existing === 1,\n hash: digest(readback),\n markerCount,\n verification: verified\n ? 'dingtalk-doc-append-full-readback' : 'dingtalk-doc-readback-mismatch',\n }\n}\n\nfunction readPublishTarget(\n root: string,\n target: MemoryPublishTarget,\n): { path: string; content: string; hash: string } {\n if (target.provider === 'local-md') {\n const ref = target.uri.slice('local-md:'.length)\n const rootReal = realpathSync(resolve(root))\n const path = realpathSync(resolve(rootReal, ref))\n assertInside(rootReal, path, 'local-md 发布目标')\n const content = readFileSync(path, 'utf8')\n return { path, content, hash: digest(content) }\n }\n const ref = target.uri.slice('dingtalk-doc:'.length)\n const profile = clean(target.profile || process.env.DTA_DWS_PROFILE)\n if (!ref) throw new Error('dingtalk-doc 发布目标缺少 node/url')\n const info = dws.docInfo(ref, profile)\n if (String(info?.contentType || '').toUpperCase() !== 'ALIDOC' ||\n String(info?.extension || '').toLowerCase() !== 'adoc') {\n throw new Error('dingtalk-doc 发布目标必须是在线文档 adoc')\n }\n const content = String(dws.readDoc(ref, profile))\n return { path: '', content, hash: digest(content) }\n}\n\nfunction renderCandidate(candidate: MemoryCandidate): string {\n return `\\n> DTA Candidate: \\`${candidate.id}\\`\\n\\n` +\n `## ${candidate.title}\\n\\n` +\n `- Kind: ${candidate.kind}\\n` +\n `- Scope: ${candidate.scopeId}\\n` +\n `- Confidence: ${candidate.confidence}\\n` +\n `- Sources: ${candidate.sourceRefs.join(', ')}\\n` +\n `- Supersedes: ${candidate.supersedes.join(', ') || '-'}\\n\\n` +\n `${candidate.content.trim()}\\n`\n}\n\nfunction appendBlock(content: string, block: string): string {\n return `${content.trimEnd()}\\n${block.startsWith('\\n') ? block : `\\n${block}`}`\n}\n\nfunction countMarker(content: string, candidateId: string): number {\n return content.split(candidateId).length - 1\n}\n\nfunction validateProposal(value: unknown): MemoryCandidateProposal {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory Candidate proposal 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'kind', 'scopeId', 'title', 'content', 'sourceRefs', 'confidence', 'supersedes',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Memory Candidate proposal 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/memory-candidate-proposal@1' ||\n !['semantic', 'procedural'].includes(input.kind)) {\n throw new Error('Memory Candidate proposal schema/kind 非法')\n }\n for (const key of ['scopeId', 'title', 'content']) {\n if (!clean(input[key])) throw new Error(`Memory Candidate proposal 缺少 ${key}`)\n }\n if (Buffer.byteLength(input.content, 'utf8') > 32 * 1024) {\n throw new Error('Memory Candidate content 超过 32 KiB')\n }\n for (const key of ['sourceRefs', 'supersedes']) {\n if (!Array.isArray(input[key]) || input[key].some((item: unknown) => !clean(item))) {\n throw new Error(`Memory Candidate ${key} 必须是非空字符串数组`)\n }\n }\n if (!input.sourceRefs.length) throw new Error('Memory Candidate 至少需要一条 sourceRef')\n if (typeof input.confidence !== 'number' || input.confidence < 0 || input.confidence > 1) {\n throw new Error('Memory Candidate confidence 必须在 0..1')\n }\n return JSON.parse(JSON.stringify(input)) as MemoryCandidateProposal\n}\n\nfunction validateTarget(value: unknown): MemoryPublishTarget {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory publish target 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set(['$schema', 'provider', 'uri', 'profile', 'expectedUserId'])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Memory publish target 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/memory-publish-target@1' ||\n !['local-md', 'dingtalk-doc'].includes(input.provider)) {\n throw new Error('Memory publish target schema/provider 非法')\n }\n if (!clean(input.uri) || !input.uri.startsWith(`${input.provider}:`)) {\n throw new Error(`Memory publish target uri 必须以 ${input.provider}: 开头`)\n }\n return JSON.parse(JSON.stringify(input)) as MemoryPublishTarget\n}\n\nfunction candidateRoot(root: string, stateDir = '', prepared = false): string {\n const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent')\n if (prepared) assertInside(resolve(root, '.dingtalk-agent'), base, 'Prepared candidate stateDir')\n const path = join(base, 'memory', 'candidates')\n mkdirSync(path, { recursive: true })\n return path\n}\n\nfunction candidatePath(root: string, id: string, stateDir = ''): string {\n if (!/^memcand_[a-f0-9]{24}$/.test(id)) throw new Error(`Memory Candidate ID 非法: ${id}`)\n return join(candidateRoot(root, stateDir, false), `${id}.json`)\n}\n\nfunction proposerContext(root: string, runInput = ''): Record<string, any> | null {\n const value = clean(runInput || process.env.DTA_RUN)\n if (!value) return null\n const rootReal = realpathSync(resolve(root))\n const runPath = realpathSync(resolve(value))\n assertInside(rootReal, runPath, 'Prepared Run')\n const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'))\n if (!run.id || !run.contextId || !run.definition?.hash) {\n throw new Error('Prepared Run 缺少 id/contextId/definition hash')\n }\n return run\n}\n\nfunction readCandidate(path: string): MemoryCandidate {\n if (!existsSync(path)) throw new Error(`找不到 Memory Candidate: ${path}`)\n const value = JSON.parse(readFileSync(path, 'utf8')) as MemoryCandidate\n const { hash, ...unsigned } = value\n if (!hash || hash !== digest(stableStringify(unsigned))) {\n throw new Error(`Memory Candidate hash 不一致: ${value.id || path}`)\n }\n return value\n}\n\nfunction signCandidate(unsigned: Omit<MemoryCandidate, 'hash'>): MemoryCandidate {\n return { ...unsigned, hash: digest(stableStringify(unsigned)) }\n}\n\nfunction withoutHash(candidate: MemoryCandidate): Omit<MemoryCandidate, 'hash'> {\n const { hash: _hash, ...unsigned } = candidate\n return unsigned\n}\n\nfunction assertCandidateRevision(candidate: MemoryCandidate, expected: number): void {\n if (!Number.isInteger(expected) || expected < 1 || candidate.revision !== expected) {\n throw new Error(\n `Memory Candidate revision 冲突:expected=${expected}, actual=${candidate.revision}`,\n )\n }\n}\n\nfunction assertOffline(action: string, runPath = ''): void {\n if (process.env.DTA_RUN || runPath) {\n throw new Error(`在线 Prepared Run 只能 propose,不能 ${action} Memory Candidate`)\n }\n}\n\nfunction assertInside(root: string, path: string, label: string): void {\n const rel = relative(resolve(root), resolve(path))\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} 必须位于允许的 root 内`)\n }\n}\n\nfunction readGitHead(root: string): string {\n const run = spawnSync('git', ['-C', root, 'rev-parse', 'HEAD'], {\n encoding: 'utf8', timeout: 2_000,\n })\n return run.status === 0 ? String(run.stdout || '').trim() : ''\n}\n\nfunction findValue(value: unknown, keys: string[]): unknown {\n if (!value || typeof value !== 'object') return null\n for (const [key, child] of Object.entries(value)) {\n if (keys.includes(key) && child !== undefined && child !== null && child !== '') return child\n }\n for (const child of Object.values(value)) {\n const found = findValue(child, keys)\n if (found !== null) return found\n }\n return null\n}\n\nfunction writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true })\n writeTextAtomic(path, JSON.stringify(value, null, 2) + '\\n')\n}\n\nfunction writeTextAtomic(path: string, value: string): void {\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, value, { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
|
|
1
|
+
{"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/memory/candidates.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, relative, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { digest, stableStringify } from '../events.js'\nimport { acquireLease } from '../lease.js'\nimport { assertNoSymlinkEscape, assertRealpathInsideRoot } from '../state-dir.js'\nimport * as dws from '../dws.js'\n\nexport interface MemoryCandidateProposal {\n $schema: 'dingtalk-agent/memory-candidate-proposal@1'\n kind: 'semantic' | 'procedural'\n scopeId: string\n title: string\n content: string\n sourceRefs: string[]\n confidence: number\n supersedes: string[]\n}\n\nexport interface MemoryCandidate {\n $schema: 'dingtalk-agent/memory-candidate@1'\n id: string\n revision: number\n kind: 'semantic' | 'procedural'\n scopeId: string\n title: string\n content: string\n sourceRefs: string[]\n confidence: number\n supersedes: string[]\n status: 'proposed' | 'approved' | 'rejected' | 'published'\n proposedAt: string\n proposer: {\n mode: 'prepared' | 'direct'\n runId: string\n eventId: string\n definitionHash: string\n }\n review: null | {\n decision: 'approve' | 'reject'\n reviewer: string\n reason: string\n reviewedAt: string\n }\n publication: null | {\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n targetHashBefore: string\n targetHashAfter: string\n verification: string\n concurrency: 'atomic-local-cas' | 'best-effort-read-check-append'\n publishedAt: string\n gitHead: string\n }\n hash: string\n}\n\nexport interface MemoryPublishTarget {\n $schema: 'dingtalk-agent/memory-publish-target@1'\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n profile?: string\n expectedUserId?: string\n}\n\nexport interface CandidateOptions {\n stateDir?: string\n runPath?: string\n}\n\nexport interface CandidateResult {\n $schema: 'dingtalk-agent/memory-candidate-result@1'\n duplicate: boolean\n path: string\n candidate: MemoryCandidate\n}\n\nexport interface CandidatePublishResult {\n $schema: 'dingtalk-agent/memory-publish-result@1'\n mode: 'dry-run' | 'published' | 'uncertain'\n sideEffect: boolean\n verified: boolean\n duplicate: boolean\n candidateId: string\n candidateRevision: number\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n currentTargetHash: string\n targetHashAfter: string\n markerCount: number\n verification: string\n concurrency: 'atomic-local-cas' | 'best-effort-read-check-append'\n candidate: MemoryCandidate\n}\n\nexport function proposeMemoryCandidate(\n root: string,\n value: unknown,\n options: CandidateOptions = {},\n): CandidateResult {\n const proposal = validateProposal(value)\n const run = proposerContext(root, options.runPath)\n if (run && proposal.scopeId !== run.contextId) {\n throw new Error(\n `Memory Candidate scopeId=${proposal.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`,\n )\n }\n const id = `memcand_${digest(stableStringify(proposal)).slice(0, 24)}`\n const rootPath = candidateRoot(root, options.stateDir, Boolean(run))\n const path = join(rootPath, `${id}.json`)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在创建`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n if (existsSync(path)) {\n const existing = readCandidate(path)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: true,\n path, candidate: existing }\n }\n const now = new Date().toISOString()\n const unsigned: Omit<MemoryCandidate, 'hash'> = {\n $schema: 'dingtalk-agent/memory-candidate@1',\n id,\n revision: 1,\n kind: proposal.kind,\n scopeId: proposal.scopeId,\n title: proposal.title,\n content: proposal.content,\n sourceRefs: proposal.sourceRefs,\n confidence: proposal.confidence,\n supersedes: proposal.supersedes,\n status: 'proposed',\n proposedAt: now,\n proposer: run ? {\n mode: 'prepared', runId: run.id, eventId: run.eventId,\n definitionHash: run.definition?.hash || '',\n } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },\n review: null,\n publication: null,\n }\n const candidate = signCandidate(unsigned)\n writeJsonAtomic(path, candidate)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n } finally {\n release()\n }\n}\n\nexport function showMemoryCandidate(\n root: string,\n id: string,\n options: CandidateOptions = {},\n): CandidateResult {\n const path = candidatePath(root, id, options.stateDir)\n if (!existsSync(path)) throw new Error(`找不到 Memory Candidate: ${id}`)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n}\n\nexport function reviewMemoryCandidate(\n root: string,\n id: string,\n decision: 'approve' | 'reject',\n reviewer: string,\n reason: string,\n expectedRevision: number,\n options: CandidateOptions = {},\n): CandidateResult {\n assertOffline('review', options.runPath)\n if (!['approve', 'reject'].includes(decision)) throw new Error('review decision 只能是 approve/reject')\n if (!clean(reviewer) || !clean(reason)) throw new Error('review 需要 reviewer 和 reason')\n const path = candidatePath(root, id, options.stateDir)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在评审`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n const current = readCandidate(path)\n assertCandidateRevision(current, expectedRevision)\n if (current.status !== 'proposed') {\n throw new Error(`Memory Candidate ${id} 当前状态是 ${current.status},不能再次评审`)\n }\n const unsigned: Omit<MemoryCandidate, 'hash'> = {\n ...withoutHash(current),\n revision: current.revision + 1,\n status: decision === 'approve' ? 'approved' : 'rejected',\n review: {\n decision,\n reviewer: clean(reviewer),\n reason: clean(reason),\n reviewedAt: new Date().toISOString(),\n },\n }\n const candidate = signCandidate(unsigned)\n writeJsonAtomic(path, candidate)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n } finally {\n release()\n }\n}\n\nexport function publishMemoryCandidate(\n root: string,\n id: string,\n targetValue: unknown,\n expectedRevision: number,\n expectedTargetHash = '',\n options: CandidateOptions & { execute?: boolean; yes?: boolean; live?: boolean } = {},\n): CandidatePublishResult {\n if (options.execute) assertOffline('publish', options.runPath)\n const target = validateTarget(targetValue)\n const path = candidatePath(root, id, options.stateDir)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在发布`, {\n waitMs: 3_000, staleAfterMs: 10 * 60_000,\n })\n try {\n const current = readCandidate(path)\n assertCandidateRevision(current, expectedRevision)\n if (!['approved', 'published'].includes(current.status)) {\n throw new Error(`Memory Candidate ${id} 状态为 ${current.status},必须先 approve`)\n }\n if (current.status === 'published' && current.publication?.uri !== target.uri) {\n throw new Error(\n `Memory Candidate ${id} 已发布到 ${current.publication?.uri || '-'},不能静默换目标`,\n )\n }\n const targetContext = readPublishTarget(root, target)\n const block = renderCandidate(current)\n const markerCount = countMarker(targetContext.content, current.id)\n const concurrency = target.provider === 'local-md'\n ? 'atomic-local-cas' as const : 'best-effort-read-check-append' as const\n const base = {\n $schema: 'dingtalk-agent/memory-publish-result@1' as const,\n sideEffect: false,\n verified: false,\n duplicate: false,\n candidateId: current.id,\n candidateRevision: current.revision,\n provider: target.provider,\n uri: target.uri,\n currentTargetHash: targetContext.hash,\n targetHashAfter: '',\n markerCount,\n verification: 'dry-run-target-inspected',\n concurrency,\n candidate: current,\n }\n if (!options.execute) return { ...base, mode: 'dry-run' }\n if (!options.yes) throw new Error('Memory Candidate 发布必须显式 --yes')\n if (!expectedTargetHash || expectedTargetHash !== targetContext.hash) {\n throw new Error(\n `发布目标 hash 冲突:expected=${expectedTargetHash || '-'}, actual=${targetContext.hash};` +\n '请重新 dry-run 并人工检查差异',\n )\n }\n if (markerCount > 1) {\n return { ...base, mode: 'uncertain', verification: 'duplicate-candidate-markers' }\n }\n let published\n if (target.provider === 'local-md') {\n published = publishLocal(targetContext.path, targetContext.content, block, current.id)\n } else {\n if (!options.live) throw new Error('钉钉文档发布必须显式 --live --yes')\n published = publishDingTalkDoc(target, targetContext.content, block, current.id)\n }\n if (!published.verified) {\n return {\n ...base,\n mode: 'uncertain',\n sideEffect: published.sideEffect,\n duplicate: published.duplicate,\n targetHashAfter: published.hash,\n markerCount: published.markerCount,\n verification: published.verification,\n }\n }\n const publication = {\n provider: target.provider,\n uri: target.uri,\n targetHashBefore: targetContext.hash,\n targetHashAfter: published.hash,\n verification: published.verification,\n concurrency,\n publishedAt: new Date().toISOString(),\n gitHead: target.provider === 'local-md' ? readGitHead(root) : '',\n }\n const candidate = current.status === 'published'\n ? current\n : signCandidate({\n ...withoutHash(current),\n revision: current.revision + 1,\n status: 'published',\n publication,\n })\n if (current.status !== 'published') writeJsonAtomic(path, candidate)\n return {\n ...base,\n mode: 'published',\n sideEffect: published.sideEffect,\n verified: true,\n duplicate: published.duplicate,\n candidateRevision: candidate.revision,\n targetHashAfter: published.hash,\n markerCount: published.markerCount,\n verification: published.verification,\n candidate: readCandidate(path),\n }\n } finally {\n release()\n }\n}\n\nfunction publishLocal(\n path: string,\n content: string,\n block: string,\n candidateId: string,\n): { verified: boolean; sideEffect: boolean; duplicate: boolean; hash: string;\n markerCount: number; verification: string } {\n const release = acquireLease(`${path}.dta-publish.lock`, `发布目标 ${path} 正在更新`, {\n waitMs: 3_000, staleAfterMs: 10 * 60_000,\n })\n try {\n const latest = readFileSync(path, 'utf8')\n if (latest !== content) throw new Error('本地发布目标在加锁前发生漂移,请重新 dry-run')\n const existing = countMarker(latest, candidateId)\n const next = existing === 1 ? latest : appendBlock(latest, block)\n if (!existing) writeTextAtomic(path, next)\n const readback = readFileSync(path, 'utf8')\n const markerCount = countMarker(readback, candidateId)\n const verified = markerCount === 1 && readback.includes(block.trim())\n return {\n verified,\n sideEffect: !existing,\n duplicate: existing === 1,\n hash: digest(readback),\n markerCount,\n verification: verified ? 'local-atomic-write-readback' : 'local-readback-mismatch',\n }\n } finally {\n release()\n }\n}\n\nfunction publishDingTalkDoc(\n target: MemoryPublishTarget,\n content: string,\n block: string,\n candidateId: string,\n): { verified: boolean; sideEffect: boolean; duplicate: boolean; hash: string;\n markerCount: number; verification: string } {\n const profile = clean(target.profile || process.env.DTA_DWS_PROFILE)\n const expectedUserId = clean(target.expectedUserId || process.env.DTA_EXPECTED_USER_ID)\n if (!profile || profile.includes(',') || !expectedUserId) {\n throw new Error('dingtalk-doc 发布必须固定单一 profile 和 expectedUserId')\n }\n const identity = dws.getSelf(profile)\n const actualUserId = String(findValue(identity, ['userId', 'user_id', 'userid']) || '')\n if (!actualUserId || actualUserId !== expectedUserId) {\n throw new Error(`DWS 执行身份不符:expected=${expectedUserId}, actual=${actualUserId || '-'}`)\n }\n const existing = countMarker(content, candidateId)\n let sideEffect = false\n if (!existing) {\n const directory = mkdtempSync(join(tmpdir(), 'dta-memory-publish-'))\n const file = join(directory, 'candidate.md')\n try {\n writeFileSync(file, block)\n dws.appendDoc(target.uri.slice('dingtalk-doc:'.length), file, profile)\n sideEffect = true\n } finally {\n rmSync(directory, { recursive: true, force: true })\n }\n }\n const readback = String(dws.readDoc(target.uri.slice('dingtalk-doc:'.length), profile))\n const markerCount = countMarker(readback, candidateId)\n const verified = markerCount === 1 && dws.words(readback).includes(dws.words(block))\n return {\n verified,\n sideEffect,\n duplicate: existing === 1,\n hash: digest(readback),\n markerCount,\n verification: verified\n ? 'dingtalk-doc-append-full-readback' : 'dingtalk-doc-readback-mismatch',\n }\n}\n\nfunction readPublishTarget(\n root: string,\n target: MemoryPublishTarget,\n): { path: string; content: string; hash: string } {\n if (target.provider === 'local-md') {\n const ref = target.uri.slice('local-md:'.length)\n const rootReal = realpathSync(resolve(root))\n const path = realpathSync(resolve(rootReal, ref))\n assertInside(rootReal, path, 'local-md 发布目标')\n const content = readFileSync(path, 'utf8')\n return { path, content, hash: digest(content) }\n }\n const ref = target.uri.slice('dingtalk-doc:'.length)\n const profile = clean(target.profile || process.env.DTA_DWS_PROFILE)\n if (!ref) throw new Error('dingtalk-doc 发布目标缺少 node/url')\n const info = dws.docInfo(ref, profile)\n if (String(info?.contentType || '').toUpperCase() !== 'ALIDOC' ||\n String(info?.extension || '').toLowerCase() !== 'adoc') {\n throw new Error('dingtalk-doc 发布目标必须是在线文档 adoc')\n }\n const content = String(dws.readDoc(ref, profile))\n return { path: '', content, hash: digest(content) }\n}\n\nfunction renderCandidate(candidate: MemoryCandidate): string {\n return `\\n> DTA Candidate: \\`${candidate.id}\\`\\n\\n` +\n `## ${candidate.title}\\n\\n` +\n `- Kind: ${candidate.kind}\\n` +\n `- Scope: ${candidate.scopeId}\\n` +\n `- Confidence: ${candidate.confidence}\\n` +\n `- Sources: ${candidate.sourceRefs.join(', ')}\\n` +\n `- Supersedes: ${candidate.supersedes.join(', ') || '-'}\\n\\n` +\n `${candidate.content.trim()}\\n`\n}\n\nfunction appendBlock(content: string, block: string): string {\n return `${content.trimEnd()}\\n${block.startsWith('\\n') ? block : `\\n${block}`}`\n}\n\nfunction countMarker(content: string, candidateId: string): number {\n return content.split(candidateId).length - 1\n}\n\nfunction validateProposal(value: unknown): MemoryCandidateProposal {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory Candidate proposal 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'kind', 'scopeId', 'title', 'content', 'sourceRefs', 'confidence', 'supersedes',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Memory Candidate proposal 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/memory-candidate-proposal@1' ||\n !['semantic', 'procedural'].includes(input.kind)) {\n throw new Error('Memory Candidate proposal schema/kind 非法')\n }\n for (const key of ['scopeId', 'title', 'content']) {\n if (!clean(input[key])) throw new Error(`Memory Candidate proposal 缺少 ${key}`)\n }\n if (Buffer.byteLength(input.content, 'utf8') > 32 * 1024) {\n throw new Error('Memory Candidate content 超过 32 KiB')\n }\n for (const key of ['sourceRefs', 'supersedes']) {\n if (!Array.isArray(input[key]) || input[key].some((item: unknown) => !clean(item))) {\n throw new Error(`Memory Candidate ${key} 必须是非空字符串数组`)\n }\n }\n if (!input.sourceRefs.length) throw new Error('Memory Candidate 至少需要一条 sourceRef')\n if (typeof input.confidence !== 'number' || input.confidence < 0 || input.confidence > 1) {\n throw new Error('Memory Candidate confidence 必须在 0..1')\n }\n return JSON.parse(JSON.stringify(input)) as MemoryCandidateProposal\n}\n\nfunction validateTarget(value: unknown): MemoryPublishTarget {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory publish target 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set(['$schema', 'provider', 'uri', 'profile', 'expectedUserId'])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Memory publish target 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/memory-publish-target@1' ||\n !['local-md', 'dingtalk-doc'].includes(input.provider)) {\n throw new Error('Memory publish target schema/provider 非法')\n }\n if (!clean(input.uri) || !input.uri.startsWith(`${input.provider}:`)) {\n throw new Error(`Memory publish target uri 必须以 ${input.provider}: 开头`)\n }\n return JSON.parse(JSON.stringify(input)) as MemoryPublishTarget\n}\n\nfunction candidateRoot(root: string, stateDir = '', prepared = false): string {\n const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent')\n if (prepared) assertInside(resolve(root, '.dingtalk-agent'), base, 'Prepared candidate stateDir')\n const path = join(base, 'memory', 'candidates')\n // 词法 containment 挡不住 symlink:root 内指向外部的目录 symlink 会让上面的检查通过,\n // 再沿 symlink 把 Candidate 写出 Agent root(issue #52 在 no-op Receipt 上的同一条逃逸)。\n const guard = prepared\n ? () => assertRealpathInsideRoot(root, path, 'Prepared candidate 目录')\n : () => assertNoSymlinkEscape(root, path, 'Candidate 目录')\n guard()\n mkdirSync(path, { recursive: true })\n guard()\n return path\n}\n\nfunction candidatePath(root: string, id: string, stateDir = ''): string {\n if (!/^memcand_[a-f0-9]{24}$/.test(id)) throw new Error(`Memory Candidate ID 非法: ${id}`)\n return join(candidateRoot(root, stateDir, false), `${id}.json`)\n}\n\nfunction proposerContext(root: string, runInput = ''): Record<string, any> | null {\n const value = clean(runInput || process.env.DTA_RUN)\n if (!value) return null\n const rootReal = realpathSync(resolve(root))\n const runPath = realpathSync(resolve(value))\n assertInside(rootReal, runPath, 'Prepared Run')\n const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'))\n if (!run.id || !run.contextId || !run.definition?.hash) {\n throw new Error('Prepared Run 缺少 id/contextId/definition hash')\n }\n return run\n}\n\nfunction readCandidate(path: string): MemoryCandidate {\n if (!existsSync(path)) throw new Error(`找不到 Memory Candidate: ${path}`)\n const value = JSON.parse(readFileSync(path, 'utf8')) as MemoryCandidate\n const { hash, ...unsigned } = value\n if (!hash || hash !== digest(stableStringify(unsigned))) {\n throw new Error(`Memory Candidate hash 不一致: ${value.id || path}`)\n }\n return value\n}\n\nfunction signCandidate(unsigned: Omit<MemoryCandidate, 'hash'>): MemoryCandidate {\n return { ...unsigned, hash: digest(stableStringify(unsigned)) }\n}\n\nfunction withoutHash(candidate: MemoryCandidate): Omit<MemoryCandidate, 'hash'> {\n const { hash: _hash, ...unsigned } = candidate\n return unsigned\n}\n\nfunction assertCandidateRevision(candidate: MemoryCandidate, expected: number): void {\n if (!Number.isInteger(expected) || expected < 1 || candidate.revision !== expected) {\n throw new Error(\n `Memory Candidate revision 冲突:expected=${expected}, actual=${candidate.revision}`,\n )\n }\n}\n\nfunction assertOffline(action: string, runPath = ''): void {\n if (process.env.DTA_RUN || runPath) {\n throw new Error(`在线 Prepared Run 只能 propose,不能 ${action} Memory Candidate`)\n }\n}\n\nfunction assertInside(root: string, path: string, label: string): void {\n const rel = relative(resolve(root), resolve(path))\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} 必须位于允许的 root 内`)\n }\n}\n\nfunction readGitHead(root: string): string {\n const run = spawnSync('git', ['-C', root, 'rev-parse', 'HEAD'], {\n encoding: 'utf8', timeout: 2_000,\n })\n return run.status === 0 ? String(run.stdout || '').trim() : ''\n}\n\nfunction findValue(value: unknown, keys: string[]): unknown {\n if (!value || typeof value !== 'object') return null\n for (const [key, child] of Object.entries(value)) {\n if (keys.includes(key) && child !== undefined && child !== null && child !== '') return child\n }\n for (const child of Object.values(value)) {\n const found = findValue(child, keys)\n if (found !== null) return found\n }\n return null\n}\n\nfunction writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true })\n writeTextAtomic(path, JSON.stringify(value, null, 2) + '\\n')\n}\n\nfunction writeTextAtomic(path: string, value: string): void {\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, value, { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
|
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameS
|
|
|
2
2
|
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
3
3
|
import { digest, stableStringify } from '../events.js';
|
|
4
4
|
import { acquireLease } from '../lease.js';
|
|
5
|
+
import { assertNoSymlinkEscape, assertRealpathInsideRoot, resolvePrivateStateDir, } from '../state-dir.js';
|
|
5
6
|
/**
|
|
6
7
|
* no-op / nothing-to-save Receipt(issue #25)。
|
|
7
8
|
*
|
|
@@ -162,14 +163,27 @@ function validateClaim(value) {
|
|
|
162
163
|
return JSON.parse(JSON.stringify(input));
|
|
163
164
|
}
|
|
164
165
|
function receiptRoot(root, stateDir = '', prepared = false) {
|
|
165
|
-
const
|
|
166
|
+
const configured = stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent';
|
|
166
167
|
// Prepared 的安全边界是「Agent root 内的宿主管理状态目录」,不是字面 `.dingtalk-agent`:
|
|
167
168
|
// bindings/enhance 合同允许自定义私有 stateDir(如 .agent-private),把它拒了会让
|
|
168
169
|
// 合法隔离配置签不出 Receipt,运维把「配置不兼容」误读成「步骤没跑」(issue #47)。
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
// 但词法 containment 也证明不了「目录归宿主所有」:root 内指向外部的 symlink 能让
|
|
171
|
+
// resolve() 检查通过,再沿 symlink 把 Receipt 写到 root 之外(issue #52)——所以走
|
|
172
|
+
// bindings 的同一份 stateDir 合同(词法 + realpath),并在建目录后回读复验。
|
|
173
|
+
const base = prepared
|
|
174
|
+
? resolvePrivateStateDir(root, configured, 'Prepared no-op stateDir')
|
|
175
|
+
: resolve(root, configured);
|
|
171
176
|
const path = join(base, 'memory', 'noop-receipts');
|
|
177
|
+
// stateDir 自身合规,其下的 memory/ 仍可能是指向外部的 symlink:建之前先判已存在段,
|
|
178
|
+
// 建之后再判整条路径——中间目录被换成 symlink 的竞态也一并 fail-closed。
|
|
179
|
+
// 读路径(list/trace)不知道 prepared 与否,但同样不能被 symlink 骗:否则逃逸目录里
|
|
180
|
+
// 一份自制 Receipt 就能让 trace 判 ran-empty。
|
|
181
|
+
const guard = prepared
|
|
182
|
+
? () => assertRealpathInsideRoot(root, path, 'Prepared no-op Receipt 目录')
|
|
183
|
+
: () => assertNoSymlinkEscape(root, path, 'no-op Receipt 目录');
|
|
184
|
+
guard();
|
|
172
185
|
mkdirSync(path, { recursive: true });
|
|
186
|
+
guard();
|
|
173
187
|
return path;
|
|
174
188
|
}
|
|
175
189
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noop-receipt.js","sourceRoot":"","sources":["../../../src/memory/noop-receipt.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, join, relative, resolve, sep } from 'node:path'\nimport { digest, stableStringify } from '../events.js'\nimport { acquireLease } from '../lease.js'\n\n/**\n * no-op / nothing-to-save Receipt(issue #25)。\n *\n * dta-basic-behavior 要求「判存步骤跑过、判了没什么可存,也要留一条痕迹」,但此前\n * 没有定义写到哪、什么 schema、怎么回读——Agent 只能自行发明日志格式,运维侧依旧\n * 分不清「跑了判空」和「压根没跑」。本模块把这条痕迹变成宿主状态里的类型化 Receipt:\n *\n * - **身份 = (step, scopeId, occurrence)**:occurrence 是这次判定挂靠的事件锚\n * (Prepared Run 用 run:<runId>,Direct 模式由调用方显式给 eventId/心跳拍号)。\n * 同一 occurrence 重放幂等返回既有 Receipt;内容不一致则响亮报冲突,不静默覆盖。\n * - **脱敏红线**:reason 只收枚举,被判定过的内容只能以 sha256 digest 入档\n * (consideredDigest),自由文本字段在校验层直接拒绝——痕迹文件不携带原文。\n * - **回读即合同**:traceMemoryNoop 对 (scopeId, occurrence) 给出二值判定\n * ran-empty / no-trace,这正是运维要区分的那两个状态。\n *\n * 信任边界(issue #42,说清楚不装伪):Receipt 里的 hash 是【无密钥完整性校验】,\n * 不是宿主签名——任何能写 state 目录的调用方都能重算它。真实性边界 = 「state 目录\n * 归宿主所有、Prepared Run 的沙箱写不进来」这一部署事实;本模块能保证的是\n * fail-closed 的结构合同:结构不合法/身份对不上的文件绝不折成 ran-empty,\n * Prepared issuer 只认 canonical Session/runs 树里 run↔session 身份互证的 run,\n * 环境变量指向的任意目录冒充不了。需要密码学可验证签发时,走宿主密钥/MAC 或\n * 控制面回执机制,不要把这里的 digest 说成 signature。\n */\n\nexport const MEMORY_SAVE_DECISION_STEP = 'memory-save-decision'\n\nexport const MEMORY_NOOP_REASONS = [\n 'no-durable-content',\n 'below-confidence',\n 'duplicate-of-existing',\n 'out-of-scope',\n 'ephemeral-only',\n] as const\n\nexport type MemoryNoopReason = typeof MEMORY_NOOP_REASONS[number]\n\nexport interface MemoryNoopClaim {\n $schema: 'dingtalk-agent/memory-noop-claim@1'\n step: string\n scopeId: string\n reason: MemoryNoopReason\n occurrence?: string\n consideredDigest?: string\n}\n\nexport interface MemoryNoopReceipt {\n $schema: 'dingtalk-agent/memory-noop-receipt@1'\n id: string\n step: string\n scopeId: string\n occurrence: string\n reason: MemoryNoopReason\n consideredDigest: string\n issuer: {\n mode: 'prepared' | 'direct'\n runId: string\n eventId: string\n definitionHash: string\n }\n recordedAt: string\n hash: string\n}\n\nexport interface MemoryNoopOptions {\n stateDir?: string\n runPath?: string\n sessionPath?: string\n // Session state root(cfg.runtime.sessionRoot);Prepared issuer 校验用\n sessionRoot?: string\n now?: string\n}\n\nexport interface MemoryNoopRecordResult {\n $schema: 'dingtalk-agent/memory-noop-result@1'\n duplicate: boolean\n path: string\n receipt: MemoryNoopReceipt\n}\n\nexport interface MemoryNoopListResult {\n $schema: 'dingtalk-agent/memory-noop-list@1'\n count: number\n receipts: MemoryNoopReceipt[]\n}\n\nexport interface MemoryNoopTraceResult {\n $schema: 'dingtalk-agent/memory-noop-trace@1'\n verdict: 'ran-empty' | 'no-trace'\n scopeId: string\n occurrence: string\n step: string\n receiptId: string\n}\n\nconst STEP_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/\nconst DIGEST_PATTERN = /^[a-f0-9]{64}$/\nconst RECEIPT_ID_PATTERN = /^nop_[a-f0-9]{24}$/\n\nexport function recordMemoryNoop(\n root: string,\n value: unknown,\n options: MemoryNoopOptions = {},\n): MemoryNoopRecordResult {\n const claim = validateClaim(value)\n const run = issuerContext(root, options.runPath, options.sessionPath, options.sessionRoot)\n if (run && claim.scopeId !== run.contextId) {\n throw new Error(\n `Memory no-op scopeId=${claim.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`,\n )\n }\n // Prepared Run 的 occurrence 从受信 run 状态推导,不采纳正文声称的锚点;\n // Direct 模式没有受信锚可推,必须由调用方显式给出,缺了就拒绝——\n // 没有 occurrence 的痕迹回答不了「哪一拍判过」,等于没留。\n const derived = run ? `run:${run.id}` : ''\n if (run) {\n if (claim.occurrence && claim.occurrence !== derived) {\n throw new Error(\n `Memory no-op occurrence=${claim.occurrence} 与 Prepared Run 推导值 ${derived} 不一致`,\n )\n }\n } else if (!claim.occurrence) {\n throw new Error('Direct 模式的 memory no-op 需要显式 occurrence(eventId / 心跳拍号等事件锚)')\n }\n const occurrence = run ? derived : String(claim.occurrence)\n\n const id = `nop_${digest(stableStringify({\n step: claim.step, scopeId: claim.scopeId, occurrence,\n })).slice(0, 24)}`\n const path = join(receiptRoot(root, options.stateDir, Boolean(run)), `${id}.json`)\n const release = acquireLease(`${path}.lock`, `Memory no-op Receipt ${id} 正在写入`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n if (existsSync(path)) {\n const existing = readReceipt(path)\n if (existing.reason !== claim.reason ||\n existing.consideredDigest !== (claim.consideredDigest || '')) {\n throw new Error(\n `同一 occurrence(${occurrence}) 已有内容不一致的 no-op 痕迹(${existing.id}):` +\n '不静默覆盖,请先人工核对两次判定为何不同',\n )\n }\n return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: true, path,\n receipt: existing }\n }\n const unsigned: Omit<MemoryNoopReceipt, 'hash'> = {\n $schema: 'dingtalk-agent/memory-noop-receipt@1',\n id,\n step: claim.step,\n scopeId: claim.scopeId,\n occurrence,\n reason: claim.reason,\n consideredDigest: claim.consideredDigest || '',\n issuer: run ? {\n mode: 'prepared', runId: run.id, eventId: run.eventId || '',\n definitionHash: run.definition?.hash || '',\n } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },\n recordedAt: parseNow(options.now).toISOString(),\n }\n const receipt: MemoryNoopReceipt = { ...unsigned, hash: digest(stableStringify(unsigned)) }\n writeJsonAtomic(path, receipt)\n return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: false, path,\n receipt: readReceipt(path) }\n } finally {\n release()\n }\n}\n\nexport function listMemoryNoops(\n root: string,\n filter: { scopeId?: string; step?: string; occurrence?: string } = {},\n options: MemoryNoopOptions = {},\n): MemoryNoopListResult {\n const dir = receiptRoot(root, options.stateDir, false)\n const receipts = readdirSync(dir)\n .filter((name) => /^nop_[a-f0-9]{24}\\.json$/.test(name))\n .map((name) => readReceipt(join(dir, name)))\n .filter((receipt) => (!filter.scopeId || receipt.scopeId === filter.scopeId) &&\n (!filter.step || receipt.step === filter.step) &&\n (!filter.occurrence || receipt.occurrence === filter.occurrence))\n .sort((a, b) => a.recordedAt.localeCompare(b.recordedAt) || a.id.localeCompare(b.id))\n return { $schema: 'dingtalk-agent/memory-noop-list@1', count: receipts.length, receipts }\n}\n\n/** 运维侧要的那个二值判定:这一拍的判存步骤——跑了判空,还是没有任何痕迹。 */\nexport function traceMemoryNoop(\n root: string,\n query: { scopeId: string; occurrence: string; step?: string },\n options: MemoryNoopOptions = {},\n): MemoryNoopTraceResult {\n const scopeId = clean(query.scopeId)\n const occurrence = clean(query.occurrence)\n if (!scopeId || !occurrence) throw new Error('memory noop trace 需要 scopeId 和 occurrence')\n const step = clean(query.step) || MEMORY_SAVE_DECISION_STEP\n const { receipts } = listMemoryNoops(root, { scopeId, occurrence, step }, options)\n return {\n $schema: 'dingtalk-agent/memory-noop-trace@1',\n verdict: receipts.length ? 'ran-empty' : 'no-trace',\n scopeId, occurrence, step,\n receiptId: receipts[0]?.id || '',\n }\n}\n\nexport function isMemoryNoopReceiptId(value: string): boolean {\n return RECEIPT_ID_PATTERN.test(value)\n}\n\nfunction validateClaim(value: unknown): MemoryNoopClaim {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory no-op claim 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set(['$schema', 'step', 'scopeId', 'reason', 'occurrence', 'consideredDigest'])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) {\n // 脱敏红线的执行点:note/detail 之类的自由文本字段在这里被结构性拒绝,\n // 被判定过的内容只能以 consideredDigest(sha256)入档。\n throw new Error(`Memory no-op claim 含未知字段: ${extra.join(', ')}(原文不入痕迹文件,只收 digest)`)\n }\n if (input.$schema !== 'dingtalk-agent/memory-noop-claim@1') {\n throw new Error('Memory no-op claim schema 非法')\n }\n const step = clean(input.step)\n if (!STEP_PATTERN.test(step)) {\n throw new Error(`Memory no-op step 必须是 kebab-case(如 ${MEMORY_SAVE_DECISION_STEP}): ${step || '-'}`)\n }\n if (!clean(input.scopeId)) throw new Error('Memory no-op claim 缺少 scopeId')\n if (!MEMORY_NOOP_REASONS.includes(input.reason)) {\n throw new Error(`Memory no-op reason 必须是枚举之一: ${MEMORY_NOOP_REASONS.join(' / ')}`)\n }\n if (input.occurrence !== undefined) {\n const occurrence = clean(input.occurrence)\n if (!occurrence || occurrence.length > 128) {\n throw new Error('Memory no-op occurrence 必须是 ≤128 字符的非空字符串')\n }\n }\n if (input.consideredDigest !== undefined &&\n !DIGEST_PATTERN.test(String(input.consideredDigest))) {\n throw new Error('Memory no-op consideredDigest 必须是 64 位 sha256 hex')\n }\n return JSON.parse(JSON.stringify(input)) as MemoryNoopClaim\n}\n\nfunction receiptRoot(root: string, stateDir = '', prepared = false): string {\n const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent')\n // Prepared 的安全边界是「Agent root 内的宿主管理状态目录」,不是字面 `.dingtalk-agent`:\n // bindings/enhance 合同允许自定义私有 stateDir(如 .agent-private),把它拒了会让\n // 合法隔离配置签不出 Receipt,运维把「配置不兼容」误读成「步骤没跑」(issue #47)。\n if (prepared) assertInside(resolve(root), base, 'Prepared no-op stateDir')\n const path = join(base, 'memory', 'noop-receipts')\n mkdirSync(path, { recursive: true })\n return path\n}\n\n/**\n * Prepared issuer 只认 canonical Session/Run 树(issue #42):DTA_RUN 是调用方可覆盖\n * 的环境变量,「project root 内存在一个 run.json」不构成宿主证明。这里复用\n * task-checkpoints 的解析纪律:run 必须位于对应 Session 的 runs/ 之下,且\n * run↔session 的身份(sessionId/contextId)互证一致。\n */\nfunction issuerContext(\n root: string,\n runInput = '',\n sessionInput = '',\n sessionRoot = '',\n): Record<string, any> | null {\n const value = clean(runInput || process.env.DTA_RUN)\n if (!value) return null\n const sessionValue = clean(sessionInput || process.env.DTA_SESSION)\n if (!sessionValue) {\n throw new Error('Prepared memory no-op 需要 DTA_SESSION(run 必须挂在 canonical Session 之下)')\n }\n const configuredRoot = resolve(root, sessionRoot || '.dingtalk-agent/sessions')\n if (!existsSync(configuredRoot)) {\n throw new Error('当前 Workspace 还没有 Session state root,无法验证 Prepared Run')\n }\n const sessionPath = realpathSync(resolve(sessionValue))\n assertInside(realpathSync(configuredRoot), sessionPath, 'No-op Session')\n const session = JSON.parse(readFileSync(join(sessionPath, 'session.json'), 'utf8'))\n if (!session.id || !session.contextId) throw new Error('No-op Session 缺少 id/contextId')\n const runPath = realpathSync(resolve(value))\n assertInside(join(sessionPath, 'runs'), runPath, 'No-op Run')\n const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'))\n if (!run.id || !run.contextId || !run.definition?.hash) {\n throw new Error('Prepared Run 缺少 id/contextId/definition hash')\n }\n if (run.sessionId !== session.id || run.contextId !== session.contextId) {\n throw new Error('No-op Run 与 Session 身份不一致')\n }\n return run\n}\n\nconst RECEIPT_KEYS = [\n '$schema', 'id', 'step', 'scopeId', 'occurrence', 'reason',\n 'consideredDigest', 'issuer', 'recordedAt', 'hash',\n] as const\nconst ISSUER_KEYS = ['mode', 'runId', 'eventId', 'definitionHash'] as const\n\n/**\n * 严格结构校验(issue #42):hash 只证完整性、证不了签发方,所以形状合同必须自己\n * 站住——缺字段但 hash 自洽的手写文件、id 与文件名/三元组不一致的文件,一律\n * fail-closed 抛错,绝不折成一条「有效痕迹」去支撑 ran-empty。\n */\nfunction readReceipt(path: string): MemoryNoopReceipt {\n if (!existsSync(path)) throw new Error(`找不到 Memory no-op Receipt: ${path}`)\n const bad = (why: string): never => {\n throw new Error(`Memory no-op Receipt 非法(${why}): ${path} —— ` +\n '结构不合法的痕迹文件不参与 trace 判定,先人工核对来源')\n }\n const value = JSON.parse(readFileSync(path, 'utf8'))\n if (!value || typeof value !== 'object' || Array.isArray(value)) bad('不是 object')\n const keys = Object.keys(value)\n if (keys.length !== RECEIPT_KEYS.length || RECEIPT_KEYS.some((key) => !(key in value))) {\n bad(`字段集必须恰为 ${RECEIPT_KEYS.join('/')}`)\n }\n if (value.$schema !== 'dingtalk-agent/memory-noop-receipt@1') bad('$schema 不符')\n if (!RECEIPT_ID_PATTERN.test(value.id)) bad('id 文法不符')\n if (!STEP_PATTERN.test(clean(value.step))) bad('step 文法不符')\n if (!clean(value.scopeId)) bad('scopeId 为空')\n const occurrence = clean(value.occurrence)\n if (!occurrence || occurrence.length > 128) bad('occurrence 文法不符')\n if (!MEMORY_NOOP_REASONS.includes(value.reason)) bad('reason 不在枚举内')\n if (value.consideredDigest !== '' && !DIGEST_PATTERN.test(String(value.consideredDigest))) {\n bad('consideredDigest 文法不符')\n }\n const issuer = value.issuer\n if (!issuer || typeof issuer !== 'object' || Array.isArray(issuer) ||\n Object.keys(issuer).length !== ISSUER_KEYS.length ||\n ISSUER_KEYS.some((key) => !(key in issuer))) {\n bad(`issuer 字段集必须恰为 ${ISSUER_KEYS.join('/')}`)\n }\n if (issuer.mode === 'prepared') {\n if (!clean(issuer.runId) || `run:${issuer.runId}` !== occurrence) {\n bad('prepared issuer 的 runId 必须非空且与 occurrence(run:<runId>) 一致')\n }\n } else if (issuer.mode === 'direct') {\n if (issuer.runId !== '' || issuer.eventId !== '' || issuer.definitionHash !== '') {\n bad('direct issuer 的 runId/eventId/definitionHash 必须为空串')\n }\n } else bad('issuer.mode 不在枚举内')\n if (Number.isNaN(new Date(String(value.recordedAt)).getTime())) bad('recordedAt 不是合法时间')\n const { hash, ...unsigned } = value\n if (!hash || hash !== digest(stableStringify(unsigned))) bad('完整性 hash 不一致')\n // id 必须能从三元组重推导,且与文件名一致——身份即内容,改一处就露馅\n const derived = `nop_${digest(stableStringify({\n step: value.step, scopeId: value.scopeId, occurrence,\n })).slice(0, 24)}`\n if (value.id !== derived) bad('id 与 (step,scopeId,occurrence) 重推导不一致')\n if (!path.endsWith(`${sep}${value.id}.json`) && !path.endsWith(`/${value.id}.json`)) {\n bad('id 与文件名不一致')\n }\n return value as MemoryNoopReceipt\n}\n\nfunction writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true })\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, JSON.stringify(value, null, 2) + '\\n', { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction assertInside(root: string, path: string, label: string): void {\n const rel = relative(resolve(root), resolve(path))\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} 必须位于允许的 root 内`)\n }\n}\n\nfunction parseNow(value?: string): Date {\n if (!value) return new Date()\n const parsed = new Date(value)\n if (Number.isNaN(parsed.getTime())) throw new Error(`非法时间: ${value}`)\n return parsed\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
|
|
1
|
+
{"version":3,"file":"noop-receipt.js","sourceRoot":"","sources":["../../../src/memory/noop-receipt.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, writeFileSync } from 'node:fs'\nimport { dirname, join, relative, resolve, sep } from 'node:path'\nimport { digest, stableStringify } from '../events.js'\nimport { acquireLease } from '../lease.js'\nimport {\n assertNoSymlinkEscape, assertRealpathInsideRoot, resolvePrivateStateDir,\n} from '../state-dir.js'\n\n/**\n * no-op / nothing-to-save Receipt(issue #25)。\n *\n * dta-basic-behavior 要求「判存步骤跑过、判了没什么可存,也要留一条痕迹」,但此前\n * 没有定义写到哪、什么 schema、怎么回读——Agent 只能自行发明日志格式,运维侧依旧\n * 分不清「跑了判空」和「压根没跑」。本模块把这条痕迹变成宿主状态里的类型化 Receipt:\n *\n * - **身份 = (step, scopeId, occurrence)**:occurrence 是这次判定挂靠的事件锚\n * (Prepared Run 用 run:<runId>,Direct 模式由调用方显式给 eventId/心跳拍号)。\n * 同一 occurrence 重放幂等返回既有 Receipt;内容不一致则响亮报冲突,不静默覆盖。\n * - **脱敏红线**:reason 只收枚举,被判定过的内容只能以 sha256 digest 入档\n * (consideredDigest),自由文本字段在校验层直接拒绝——痕迹文件不携带原文。\n * - **回读即合同**:traceMemoryNoop 对 (scopeId, occurrence) 给出二值判定\n * ran-empty / no-trace,这正是运维要区分的那两个状态。\n *\n * 信任边界(issue #42,说清楚不装伪):Receipt 里的 hash 是【无密钥完整性校验】,\n * 不是宿主签名——任何能写 state 目录的调用方都能重算它。真实性边界 = 「state 目录\n * 归宿主所有、Prepared Run 的沙箱写不进来」这一部署事实;本模块能保证的是\n * fail-closed 的结构合同:结构不合法/身份对不上的文件绝不折成 ran-empty,\n * Prepared issuer 只认 canonical Session/runs 树里 run↔session 身份互证的 run,\n * 环境变量指向的任意目录冒充不了。需要密码学可验证签发时,走宿主密钥/MAC 或\n * 控制面回执机制,不要把这里的 digest 说成 signature。\n */\n\nexport const MEMORY_SAVE_DECISION_STEP = 'memory-save-decision'\n\nexport const MEMORY_NOOP_REASONS = [\n 'no-durable-content',\n 'below-confidence',\n 'duplicate-of-existing',\n 'out-of-scope',\n 'ephemeral-only',\n] as const\n\nexport type MemoryNoopReason = typeof MEMORY_NOOP_REASONS[number]\n\nexport interface MemoryNoopClaim {\n $schema: 'dingtalk-agent/memory-noop-claim@1'\n step: string\n scopeId: string\n reason: MemoryNoopReason\n occurrence?: string\n consideredDigest?: string\n}\n\nexport interface MemoryNoopReceipt {\n $schema: 'dingtalk-agent/memory-noop-receipt@1'\n id: string\n step: string\n scopeId: string\n occurrence: string\n reason: MemoryNoopReason\n consideredDigest: string\n issuer: {\n mode: 'prepared' | 'direct'\n runId: string\n eventId: string\n definitionHash: string\n }\n recordedAt: string\n hash: string\n}\n\nexport interface MemoryNoopOptions {\n stateDir?: string\n runPath?: string\n sessionPath?: string\n // Session state root(cfg.runtime.sessionRoot);Prepared issuer 校验用\n sessionRoot?: string\n now?: string\n}\n\nexport interface MemoryNoopRecordResult {\n $schema: 'dingtalk-agent/memory-noop-result@1'\n duplicate: boolean\n path: string\n receipt: MemoryNoopReceipt\n}\n\nexport interface MemoryNoopListResult {\n $schema: 'dingtalk-agent/memory-noop-list@1'\n count: number\n receipts: MemoryNoopReceipt[]\n}\n\nexport interface MemoryNoopTraceResult {\n $schema: 'dingtalk-agent/memory-noop-trace@1'\n verdict: 'ran-empty' | 'no-trace'\n scopeId: string\n occurrence: string\n step: string\n receiptId: string\n}\n\nconst STEP_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/\nconst DIGEST_PATTERN = /^[a-f0-9]{64}$/\nconst RECEIPT_ID_PATTERN = /^nop_[a-f0-9]{24}$/\n\nexport function recordMemoryNoop(\n root: string,\n value: unknown,\n options: MemoryNoopOptions = {},\n): MemoryNoopRecordResult {\n const claim = validateClaim(value)\n const run = issuerContext(root, options.runPath, options.sessionPath, options.sessionRoot)\n if (run && claim.scopeId !== run.contextId) {\n throw new Error(\n `Memory no-op scopeId=${claim.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`,\n )\n }\n // Prepared Run 的 occurrence 从受信 run 状态推导,不采纳正文声称的锚点;\n // Direct 模式没有受信锚可推,必须由调用方显式给出,缺了就拒绝——\n // 没有 occurrence 的痕迹回答不了「哪一拍判过」,等于没留。\n const derived = run ? `run:${run.id}` : ''\n if (run) {\n if (claim.occurrence && claim.occurrence !== derived) {\n throw new Error(\n `Memory no-op occurrence=${claim.occurrence} 与 Prepared Run 推导值 ${derived} 不一致`,\n )\n }\n } else if (!claim.occurrence) {\n throw new Error('Direct 模式的 memory no-op 需要显式 occurrence(eventId / 心跳拍号等事件锚)')\n }\n const occurrence = run ? derived : String(claim.occurrence)\n\n const id = `nop_${digest(stableStringify({\n step: claim.step, scopeId: claim.scopeId, occurrence,\n })).slice(0, 24)}`\n const path = join(receiptRoot(root, options.stateDir, Boolean(run)), `${id}.json`)\n const release = acquireLease(`${path}.lock`, `Memory no-op Receipt ${id} 正在写入`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n if (existsSync(path)) {\n const existing = readReceipt(path)\n if (existing.reason !== claim.reason ||\n existing.consideredDigest !== (claim.consideredDigest || '')) {\n throw new Error(\n `同一 occurrence(${occurrence}) 已有内容不一致的 no-op 痕迹(${existing.id}):` +\n '不静默覆盖,请先人工核对两次判定为何不同',\n )\n }\n return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: true, path,\n receipt: existing }\n }\n const unsigned: Omit<MemoryNoopReceipt, 'hash'> = {\n $schema: 'dingtalk-agent/memory-noop-receipt@1',\n id,\n step: claim.step,\n scopeId: claim.scopeId,\n occurrence,\n reason: claim.reason,\n consideredDigest: claim.consideredDigest || '',\n issuer: run ? {\n mode: 'prepared', runId: run.id, eventId: run.eventId || '',\n definitionHash: run.definition?.hash || '',\n } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },\n recordedAt: parseNow(options.now).toISOString(),\n }\n const receipt: MemoryNoopReceipt = { ...unsigned, hash: digest(stableStringify(unsigned)) }\n writeJsonAtomic(path, receipt)\n return { $schema: 'dingtalk-agent/memory-noop-result@1', duplicate: false, path,\n receipt: readReceipt(path) }\n } finally {\n release()\n }\n}\n\nexport function listMemoryNoops(\n root: string,\n filter: { scopeId?: string; step?: string; occurrence?: string } = {},\n options: MemoryNoopOptions = {},\n): MemoryNoopListResult {\n const dir = receiptRoot(root, options.stateDir, false)\n const receipts = readdirSync(dir)\n .filter((name) => /^nop_[a-f0-9]{24}\\.json$/.test(name))\n .map((name) => readReceipt(join(dir, name)))\n .filter((receipt) => (!filter.scopeId || receipt.scopeId === filter.scopeId) &&\n (!filter.step || receipt.step === filter.step) &&\n (!filter.occurrence || receipt.occurrence === filter.occurrence))\n .sort((a, b) => a.recordedAt.localeCompare(b.recordedAt) || a.id.localeCompare(b.id))\n return { $schema: 'dingtalk-agent/memory-noop-list@1', count: receipts.length, receipts }\n}\n\n/** 运维侧要的那个二值判定:这一拍的判存步骤——跑了判空,还是没有任何痕迹。 */\nexport function traceMemoryNoop(\n root: string,\n query: { scopeId: string; occurrence: string; step?: string },\n options: MemoryNoopOptions = {},\n): MemoryNoopTraceResult {\n const scopeId = clean(query.scopeId)\n const occurrence = clean(query.occurrence)\n if (!scopeId || !occurrence) throw new Error('memory noop trace 需要 scopeId 和 occurrence')\n const step = clean(query.step) || MEMORY_SAVE_DECISION_STEP\n const { receipts } = listMemoryNoops(root, { scopeId, occurrence, step }, options)\n return {\n $schema: 'dingtalk-agent/memory-noop-trace@1',\n verdict: receipts.length ? 'ran-empty' : 'no-trace',\n scopeId, occurrence, step,\n receiptId: receipts[0]?.id || '',\n }\n}\n\nexport function isMemoryNoopReceiptId(value: string): boolean {\n return RECEIPT_ID_PATTERN.test(value)\n}\n\nfunction validateClaim(value: unknown): MemoryNoopClaim {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory no-op claim 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set(['$schema', 'step', 'scopeId', 'reason', 'occurrence', 'consideredDigest'])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) {\n // 脱敏红线的执行点:note/detail 之类的自由文本字段在这里被结构性拒绝,\n // 被判定过的内容只能以 consideredDigest(sha256)入档。\n throw new Error(`Memory no-op claim 含未知字段: ${extra.join(', ')}(原文不入痕迹文件,只收 digest)`)\n }\n if (input.$schema !== 'dingtalk-agent/memory-noop-claim@1') {\n throw new Error('Memory no-op claim schema 非法')\n }\n const step = clean(input.step)\n if (!STEP_PATTERN.test(step)) {\n throw new Error(`Memory no-op step 必须是 kebab-case(如 ${MEMORY_SAVE_DECISION_STEP}): ${step || '-'}`)\n }\n if (!clean(input.scopeId)) throw new Error('Memory no-op claim 缺少 scopeId')\n if (!MEMORY_NOOP_REASONS.includes(input.reason)) {\n throw new Error(`Memory no-op reason 必须是枚举之一: ${MEMORY_NOOP_REASONS.join(' / ')}`)\n }\n if (input.occurrence !== undefined) {\n const occurrence = clean(input.occurrence)\n if (!occurrence || occurrence.length > 128) {\n throw new Error('Memory no-op occurrence 必须是 ≤128 字符的非空字符串')\n }\n }\n if (input.consideredDigest !== undefined &&\n !DIGEST_PATTERN.test(String(input.consideredDigest))) {\n throw new Error('Memory no-op consideredDigest 必须是 64 位 sha256 hex')\n }\n return JSON.parse(JSON.stringify(input)) as MemoryNoopClaim\n}\n\nfunction receiptRoot(root: string, stateDir = '', prepared = false): string {\n const configured = stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent'\n // Prepared 的安全边界是「Agent root 内的宿主管理状态目录」,不是字面 `.dingtalk-agent`:\n // bindings/enhance 合同允许自定义私有 stateDir(如 .agent-private),把它拒了会让\n // 合法隔离配置签不出 Receipt,运维把「配置不兼容」误读成「步骤没跑」(issue #47)。\n // 但词法 containment 也证明不了「目录归宿主所有」:root 内指向外部的 symlink 能让\n // resolve() 检查通过,再沿 symlink 把 Receipt 写到 root 之外(issue #52)——所以走\n // bindings 的同一份 stateDir 合同(词法 + realpath),并在建目录后回读复验。\n const base = prepared\n ? resolvePrivateStateDir(root, configured, 'Prepared no-op stateDir')\n : resolve(root, configured)\n const path = join(base, 'memory', 'noop-receipts')\n // stateDir 自身合规,其下的 memory/ 仍可能是指向外部的 symlink:建之前先判已存在段,\n // 建之后再判整条路径——中间目录被换成 symlink 的竞态也一并 fail-closed。\n // 读路径(list/trace)不知道 prepared 与否,但同样不能被 symlink 骗:否则逃逸目录里\n // 一份自制 Receipt 就能让 trace 判 ran-empty。\n const guard = prepared\n ? () => assertRealpathInsideRoot(root, path, 'Prepared no-op Receipt 目录')\n : () => assertNoSymlinkEscape(root, path, 'no-op Receipt 目录')\n guard()\n mkdirSync(path, { recursive: true })\n guard()\n return path\n}\n\n/**\n * Prepared issuer 只认 canonical Session/Run 树(issue #42):DTA_RUN 是调用方可覆盖\n * 的环境变量,「project root 内存在一个 run.json」不构成宿主证明。这里复用\n * task-checkpoints 的解析纪律:run 必须位于对应 Session 的 runs/ 之下,且\n * run↔session 的身份(sessionId/contextId)互证一致。\n */\nfunction issuerContext(\n root: string,\n runInput = '',\n sessionInput = '',\n sessionRoot = '',\n): Record<string, any> | null {\n const value = clean(runInput || process.env.DTA_RUN)\n if (!value) return null\n const sessionValue = clean(sessionInput || process.env.DTA_SESSION)\n if (!sessionValue) {\n throw new Error('Prepared memory no-op 需要 DTA_SESSION(run 必须挂在 canonical Session 之下)')\n }\n const configuredRoot = resolve(root, sessionRoot || '.dingtalk-agent/sessions')\n if (!existsSync(configuredRoot)) {\n throw new Error('当前 Workspace 还没有 Session state root,无法验证 Prepared Run')\n }\n const sessionPath = realpathSync(resolve(sessionValue))\n assertInside(realpathSync(configuredRoot), sessionPath, 'No-op Session')\n const session = JSON.parse(readFileSync(join(sessionPath, 'session.json'), 'utf8'))\n if (!session.id || !session.contextId) throw new Error('No-op Session 缺少 id/contextId')\n const runPath = realpathSync(resolve(value))\n assertInside(join(sessionPath, 'runs'), runPath, 'No-op Run')\n const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'))\n if (!run.id || !run.contextId || !run.definition?.hash) {\n throw new Error('Prepared Run 缺少 id/contextId/definition hash')\n }\n if (run.sessionId !== session.id || run.contextId !== session.contextId) {\n throw new Error('No-op Run 与 Session 身份不一致')\n }\n return run\n}\n\nconst RECEIPT_KEYS = [\n '$schema', 'id', 'step', 'scopeId', 'occurrence', 'reason',\n 'consideredDigest', 'issuer', 'recordedAt', 'hash',\n] as const\nconst ISSUER_KEYS = ['mode', 'runId', 'eventId', 'definitionHash'] as const\n\n/**\n * 严格结构校验(issue #42):hash 只证完整性、证不了签发方,所以形状合同必须自己\n * 站住——缺字段但 hash 自洽的手写文件、id 与文件名/三元组不一致的文件,一律\n * fail-closed 抛错,绝不折成一条「有效痕迹」去支撑 ran-empty。\n */\nfunction readReceipt(path: string): MemoryNoopReceipt {\n if (!existsSync(path)) throw new Error(`找不到 Memory no-op Receipt: ${path}`)\n const bad = (why: string): never => {\n throw new Error(`Memory no-op Receipt 非法(${why}): ${path} —— ` +\n '结构不合法的痕迹文件不参与 trace 判定,先人工核对来源')\n }\n const value = JSON.parse(readFileSync(path, 'utf8'))\n if (!value || typeof value !== 'object' || Array.isArray(value)) bad('不是 object')\n const keys = Object.keys(value)\n if (keys.length !== RECEIPT_KEYS.length || RECEIPT_KEYS.some((key) => !(key in value))) {\n bad(`字段集必须恰为 ${RECEIPT_KEYS.join('/')}`)\n }\n if (value.$schema !== 'dingtalk-agent/memory-noop-receipt@1') bad('$schema 不符')\n if (!RECEIPT_ID_PATTERN.test(value.id)) bad('id 文法不符')\n if (!STEP_PATTERN.test(clean(value.step))) bad('step 文法不符')\n if (!clean(value.scopeId)) bad('scopeId 为空')\n const occurrence = clean(value.occurrence)\n if (!occurrence || occurrence.length > 128) bad('occurrence 文法不符')\n if (!MEMORY_NOOP_REASONS.includes(value.reason)) bad('reason 不在枚举内')\n if (value.consideredDigest !== '' && !DIGEST_PATTERN.test(String(value.consideredDigest))) {\n bad('consideredDigest 文法不符')\n }\n const issuer = value.issuer\n if (!issuer || typeof issuer !== 'object' || Array.isArray(issuer) ||\n Object.keys(issuer).length !== ISSUER_KEYS.length ||\n ISSUER_KEYS.some((key) => !(key in issuer))) {\n bad(`issuer 字段集必须恰为 ${ISSUER_KEYS.join('/')}`)\n }\n if (issuer.mode === 'prepared') {\n if (!clean(issuer.runId) || `run:${issuer.runId}` !== occurrence) {\n bad('prepared issuer 的 runId 必须非空且与 occurrence(run:<runId>) 一致')\n }\n } else if (issuer.mode === 'direct') {\n if (issuer.runId !== '' || issuer.eventId !== '' || issuer.definitionHash !== '') {\n bad('direct issuer 的 runId/eventId/definitionHash 必须为空串')\n }\n } else bad('issuer.mode 不在枚举内')\n if (Number.isNaN(new Date(String(value.recordedAt)).getTime())) bad('recordedAt 不是合法时间')\n const { hash, ...unsigned } = value\n if (!hash || hash !== digest(stableStringify(unsigned))) bad('完整性 hash 不一致')\n // id 必须能从三元组重推导,且与文件名一致——身份即内容,改一处就露馅\n const derived = `nop_${digest(stableStringify({\n step: value.step, scopeId: value.scopeId, occurrence,\n })).slice(0, 24)}`\n if (value.id !== derived) bad('id 与 (step,scopeId,occurrence) 重推导不一致')\n if (!path.endsWith(`${sep}${value.id}.json`) && !path.endsWith(`/${value.id}.json`)) {\n bad('id 与文件名不一致')\n }\n return value as MemoryNoopReceipt\n}\n\nfunction writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true })\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, JSON.stringify(value, null, 2) + '\\n', { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction assertInside(root: string, path: string, label: string): void {\n const rel = relative(resolve(root), resolve(path))\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} 必须位于允许的 root 内`)\n }\n}\n\nfunction parseNow(value?: string): Date {\n if (!value) return new Date()\n const parsed = new Date(value)\n if (Number.isNaN(parsed.getTime())) throw new Error(`非法时间: ${value}`)\n return parsed\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { existsSync, lstatSync, realpathSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Agent 私有状态目录(stateDir)的**唯一**合同(issue #47 / #52)。
|
|
5
|
+
*
|
|
6
|
+
* 宿主状态目录是 no-op Receipt、Candidate、checkpoint 这些「真实性靠部署事实、
|
|
7
|
+
* 不靠密码学」的痕迹的落点:#42 把真实性边界定义成「state 目录归宿主所有、
|
|
8
|
+
* Prepared Run 的沙箱写不进来」。词法 containment 证明不了这件事——
|
|
9
|
+
* `resolve()` 只比较字符串,Agent root 内一个指向 root 外的目录 symlink 能让检查
|
|
10
|
+
* 通过,随后 `mkdirSync` / 原子写沿 symlink 把痕迹写到 root 之外(issue #52)。
|
|
11
|
+
*
|
|
12
|
+
* 所以合同有三条,词法与 realpath 都要过:
|
|
13
|
+
*
|
|
14
|
+
* 1. `resolve(root, stateDir)` 必须落在 Agent root 内(`../outside` 拒绝);
|
|
15
|
+
* 2. 不能等于 root 本身——stateDir 是 root 内的**独立**私有目录;
|
|
16
|
+
* 3. 已存在的部分(含中间目录、含 stateDir 自身)的 realpath 仍必须落在 root 内;
|
|
17
|
+
* 尚不存在的路径按「最近存在的祖先」判定,之后由调用方创建成真实目录,
|
|
18
|
+
* 并在创建后回读复验(`assertRealpathInsideRoot`)。
|
|
19
|
+
*
|
|
20
|
+
* 校验点只放在这里:agent-bindings 的 bindings 加载、memory 的 Prepared 写入路径
|
|
21
|
+
* 共用同一份判据,避免「一处放宽、一处收紧」再次分叉。
|
|
22
|
+
*/
|
|
23
|
+
/** 词法 + realpath 双过的 stateDir 解析;返回可安全创建/写入的绝对路径。 */
|
|
24
|
+
export function resolvePrivateStateDir(root, stateDir, label = 'stateDir') {
|
|
25
|
+
const rootReal = canonicalRoot(root);
|
|
26
|
+
const target = resolve(rootReal, stateDir);
|
|
27
|
+
if (!isInside(rootReal, target)) {
|
|
28
|
+
throw new Error(`${label} 必须位于 Agent 根目录内: ${stateDir}`);
|
|
29
|
+
}
|
|
30
|
+
if (target === rootReal) {
|
|
31
|
+
throw new Error(`${label} 必须是 Agent 根目录内的独立私有目录,不能等于根目录: ${stateDir}`);
|
|
32
|
+
}
|
|
33
|
+
assertRealpathInsideRoot(rootReal, target, label);
|
|
34
|
+
return target;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 已存在部分的 realpath 必须留在 root 内。目录尚不存在时判定它最近存在的祖先——
|
|
38
|
+
* 剩余段将由 `mkdirSync` 创建成真实目录,祖先在内则整条路径在内。
|
|
39
|
+
* 创建之后应再调用一次做回读复验(覆盖 stateDir 之下的嵌套 symlink 与竞态)。
|
|
40
|
+
*/
|
|
41
|
+
export function assertRealpathInsideRoot(root, target, label) {
|
|
42
|
+
const declaredRoot = resolve(root);
|
|
43
|
+
const rootReal = canonicalRoot(root);
|
|
44
|
+
const absolute = resolve(target);
|
|
45
|
+
const anchor = nearestExistingEntry(absolute);
|
|
46
|
+
// anchor 词法上严格位于 root 之上 = root 自身还没建:那么 anchor 之下的每一段(含 root)
|
|
47
|
+
// 都将由 mkdirSync 创建成真实目录,没有可跟随的 symlink,也就无从逃逸。
|
|
48
|
+
// 判据必须看 anchor 的**词法**位置,不能看 realpath 方向——否则 root 内一个指向 root
|
|
49
|
+
// 父目录的 symlink 会被当成「祖先方向的 containment」放过去。
|
|
50
|
+
if (anchor !== declaredRoot && isInside(anchor, declaredRoot))
|
|
51
|
+
return;
|
|
52
|
+
let real;
|
|
53
|
+
try {
|
|
54
|
+
real = realpathSync(anchor);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// 悬挂 symlink:lstat 有条目但 realpath 解析不出来,归宿无法证明 → fail-closed
|
|
58
|
+
throw new Error(`${label} 真实路径无法解析(悬挂符号链接?): ${target}`);
|
|
59
|
+
}
|
|
60
|
+
if (!isInside(rootReal, real)) {
|
|
61
|
+
throw new Error(`${label} 真实路径必须位于 Agent 根目录内(symlink 越界): ${target}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 「声称在 root 内」的路径必须真的在 root 内。词法在内、realpath 出界就是 symlink 逃逸,
|
|
66
|
+
* 一律拒绝;明确指向 root 之外的配置(例如绝对路径的 DTA_STATE_DIR)不在本合同内,
|
|
67
|
+
* 交给各自的 prepared 门禁判——读路径因此只收紧「被 symlink 骗」这一种情况:
|
|
68
|
+
* 逃逸后的 trace 会从调用方自己能写的目录读出 ran-empty,那正是运维要区分的判定。
|
|
69
|
+
*/
|
|
70
|
+
export function assertNoSymlinkEscape(root, target, label) {
|
|
71
|
+
// 词法比较用调用方给的 root 原样(target 由同一个字符串拼出):拿 realpath 化的 root 去比,
|
|
72
|
+
// 会把 /var → /private/var 这类 root 自身的前缀 symlink 误判成「明确指向 root 外」。
|
|
73
|
+
if (!isInside(resolve(root), resolve(target)))
|
|
74
|
+
return;
|
|
75
|
+
assertRealpathInsideRoot(root, target, label);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Agent root 的 canonical 形式。root 尚不存在时(首次写状态就顺带建 root 的调用方)
|
|
79
|
+
* 不能让 realpathSync 抛 ENOENT——那会把「目录还没建」伪装成边界错误。做法是把最近存在
|
|
80
|
+
* 祖先的 realpath 与剩余词法段拼回去:存在的部分解析 symlink,不存在的部分保持词法。
|
|
81
|
+
*/
|
|
82
|
+
function canonicalRoot(root) {
|
|
83
|
+
const absolute = resolve(root);
|
|
84
|
+
const anchor = nearestExistingEntry(absolute);
|
|
85
|
+
try {
|
|
86
|
+
const real = realpathSync(anchor);
|
|
87
|
+
return anchor === absolute ? real : join(real, relative(anchor, absolute));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return absolute;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** lstat 语义的存在判定:悬挂 symlink 也算「有条目」,不能被 existsSync 漏成不存在。 */
|
|
94
|
+
function nearestExistingEntry(target) {
|
|
95
|
+
let current = target;
|
|
96
|
+
while (!hasEntry(current)) {
|
|
97
|
+
const parent = dirname(current);
|
|
98
|
+
if (parent === current)
|
|
99
|
+
return current;
|
|
100
|
+
current = parent;
|
|
101
|
+
}
|
|
102
|
+
return current;
|
|
103
|
+
}
|
|
104
|
+
function hasEntry(path) {
|
|
105
|
+
if (existsSync(path))
|
|
106
|
+
return true;
|
|
107
|
+
try {
|
|
108
|
+
lstatSync(path);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function isInside(root, candidate) {
|
|
116
|
+
const rel = relative(root, candidate);
|
|
117
|
+
return rel === '' ||
|
|
118
|
+
(rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`));
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=state-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-dir.js","sourceRoot":"","sources":["../../src/state-dir.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, lstatSync, realpathSync } from 'node:fs'\nimport { dirname, join, relative, resolve } from 'node:path'\n\n/**\n * Agent 私有状态目录(stateDir)的**唯一**合同(issue #47 / #52)。\n *\n * 宿主状态目录是 no-op Receipt、Candidate、checkpoint 这些「真实性靠部署事实、\n * 不靠密码学」的痕迹的落点:#42 把真实性边界定义成「state 目录归宿主所有、\n * Prepared Run 的沙箱写不进来」。词法 containment 证明不了这件事——\n * `resolve()` 只比较字符串,Agent root 内一个指向 root 外的目录 symlink 能让检查\n * 通过,随后 `mkdirSync` / 原子写沿 symlink 把痕迹写到 root 之外(issue #52)。\n *\n * 所以合同有三条,词法与 realpath 都要过:\n *\n * 1. `resolve(root, stateDir)` 必须落在 Agent root 内(`../outside` 拒绝);\n * 2. 不能等于 root 本身——stateDir 是 root 内的**独立**私有目录;\n * 3. 已存在的部分(含中间目录、含 stateDir 自身)的 realpath 仍必须落在 root 内;\n * 尚不存在的路径按「最近存在的祖先」判定,之后由调用方创建成真实目录,\n * 并在创建后回读复验(`assertRealpathInsideRoot`)。\n *\n * 校验点只放在这里:agent-bindings 的 bindings 加载、memory 的 Prepared 写入路径\n * 共用同一份判据,避免「一处放宽、一处收紧」再次分叉。\n */\n\n/** 词法 + realpath 双过的 stateDir 解析;返回可安全创建/写入的绝对路径。 */\nexport function resolvePrivateStateDir(root: string, stateDir: string, label = 'stateDir'): string {\n const rootReal = canonicalRoot(root)\n const target = resolve(rootReal, stateDir)\n if (!isInside(rootReal, target)) {\n throw new Error(`${label} 必须位于 Agent 根目录内: ${stateDir}`)\n }\n if (target === rootReal) {\n throw new Error(`${label} 必须是 Agent 根目录内的独立私有目录,不能等于根目录: ${stateDir}`)\n }\n assertRealpathInsideRoot(rootReal, target, label)\n return target\n}\n\n/**\n * 已存在部分的 realpath 必须留在 root 内。目录尚不存在时判定它最近存在的祖先——\n * 剩余段将由 `mkdirSync` 创建成真实目录,祖先在内则整条路径在内。\n * 创建之后应再调用一次做回读复验(覆盖 stateDir 之下的嵌套 symlink 与竞态)。\n */\nexport function assertRealpathInsideRoot(root: string, target: string, label: string): void {\n const declaredRoot = resolve(root)\n const rootReal = canonicalRoot(root)\n const absolute = resolve(target)\n const anchor = nearestExistingEntry(absolute)\n // anchor 词法上严格位于 root 之上 = root 自身还没建:那么 anchor 之下的每一段(含 root)\n // 都将由 mkdirSync 创建成真实目录,没有可跟随的 symlink,也就无从逃逸。\n // 判据必须看 anchor 的**词法**位置,不能看 realpath 方向——否则 root 内一个指向 root\n // 父目录的 symlink 会被当成「祖先方向的 containment」放过去。\n if (anchor !== declaredRoot && isInside(anchor, declaredRoot)) return\n let real: string\n try {\n real = realpathSync(anchor)\n } catch {\n // 悬挂 symlink:lstat 有条目但 realpath 解析不出来,归宿无法证明 → fail-closed\n throw new Error(`${label} 真实路径无法解析(悬挂符号链接?): ${target}`)\n }\n if (!isInside(rootReal, real)) {\n throw new Error(`${label} 真实路径必须位于 Agent 根目录内(symlink 越界): ${target}`)\n }\n}\n\n/**\n * 「声称在 root 内」的路径必须真的在 root 内。词法在内、realpath 出界就是 symlink 逃逸,\n * 一律拒绝;明确指向 root 之外的配置(例如绝对路径的 DTA_STATE_DIR)不在本合同内,\n * 交给各自的 prepared 门禁判——读路径因此只收紧「被 symlink 骗」这一种情况:\n * 逃逸后的 trace 会从调用方自己能写的目录读出 ran-empty,那正是运维要区分的判定。\n */\nexport function assertNoSymlinkEscape(root: string, target: string, label: string): void {\n // 词法比较用调用方给的 root 原样(target 由同一个字符串拼出):拿 realpath 化的 root 去比,\n // 会把 /var → /private/var 这类 root 自身的前缀 symlink 误判成「明确指向 root 外」。\n if (!isInside(resolve(root), resolve(target))) return\n assertRealpathInsideRoot(root, target, label)\n}\n\n/**\n * Agent root 的 canonical 形式。root 尚不存在时(首次写状态就顺带建 root 的调用方)\n * 不能让 realpathSync 抛 ENOENT——那会把「目录还没建」伪装成边界错误。做法是把最近存在\n * 祖先的 realpath 与剩余词法段拼回去:存在的部分解析 symlink,不存在的部分保持词法。\n */\nfunction canonicalRoot(root: string): string {\n const absolute = resolve(root)\n const anchor = nearestExistingEntry(absolute)\n try {\n const real = realpathSync(anchor)\n return anchor === absolute ? real : join(real, relative(anchor, absolute))\n } catch {\n return absolute\n }\n}\n\n/** lstat 语义的存在判定:悬挂 symlink 也算「有条目」,不能被 existsSync 漏成不存在。 */\nfunction nearestExistingEntry(target: string): string {\n let current = target\n while (!hasEntry(current)) {\n const parent = dirname(current)\n if (parent === current) return current\n current = parent\n }\n return current\n}\n\nfunction hasEntry(path: string): boolean {\n if (existsSync(path)) return true\n try {\n lstatSync(path)\n return true\n } catch {\n return false\n }\n}\n\nfunction isInside(root: string, candidate: string): boolean {\n const rel = relative(root, candidate)\n return rel === '' ||\n (rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`))\n}\n"]}
|