@xdxer/dingtalk-agent 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -80
- package/dist/bin/dingtalk-agent.js +685 -0
- package/dist/bin/dingtalk-agent.js.map +1 -0
- package/dist/src/actions.js +562 -0
- package/dist/src/actions.js.map +1 -0
- package/dist/src/boot.js +70 -0
- package/dist/src/boot.js.map +1 -0
- package/dist/src/bootstrap.js +144 -0
- package/dist/src/bootstrap.js.map +1 -0
- package/dist/src/config.js +86 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/driver.js +45 -0
- package/dist/src/driver.js.map +1 -0
- package/{src → dist/src}/duty.js +42 -44
- package/dist/src/duty.js.map +1 -0
- package/dist/src/dws.js +270 -0
- package/dist/src/dws.js.map +1 -0
- package/dist/src/events.js +233 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/fields.js +132 -0
- package/dist/src/fields.js.map +1 -0
- package/dist/src/init.js +41 -0
- package/dist/src/init.js.map +1 -0
- package/dist/src/kb.js +240 -0
- package/dist/src/kb.js.map +1 -0
- package/dist/src/package-root.js +17 -0
- package/dist/src/package-root.js.map +1 -0
- package/dist/src/runs.js +79 -0
- package/dist/src/runs.js.map +1 -0
- package/dist/src/sessions.js +668 -0
- package/dist/src/sessions.js.map +1 -0
- package/dist/src/skill-manager.js +273 -0
- package/dist/src/skill-manager.js.map +1 -0
- package/dist/src/skills.js +200 -0
- package/dist/src/skills.js.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/waits.js +945 -0
- package/dist/src/waits.js.map +1 -0
- package/dist/src/workspace.js +173 -0
- package/dist/src/workspace.js.map +1 -0
- package/docs/ARCHITECTURE.md +207 -0
- package/docs/MINIMAL-WORKSPACE-V1.md +172 -0
- package/docs/OPEN-SOURCE-REFERENCES.md +107 -0
- package/docs/SELF-TEST.md +252 -0
- package/docs/architecture/dingtalk-agent-blueprint.png +0 -0
- package/docs/architecture/dingtalk-agent-blueprint.svg +144 -0
- package/docs/architecture/durable-async-agent-runtime.png +0 -0
- package/docs/architecture/durable-async-agent-runtime.svg +234 -0
- package/docs//345/206/205/347/275/221/345/256/236/347/233/270.md +77 -0
- package/evals/baselines/2026-07-14/behavior-summary.json +28 -0
- package/evals/baselines/2026-07-14/contract-summary.json +18 -0
- package/evals/baselines/2026-07-14/live-canary-summary.json +25 -0
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/SKILL.md +72 -0
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/action-contract.md +31 -0
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/event-to-behavior.md +22 -0
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/memory-and-evolution.md +25 -0
- package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/runtime-modes.md +34 -0
- package/evals/baselines/2026-07-15/task-lifecycle-summary.json +50 -0
- package/evals/evals.json +293 -0
- package/evals/fixtures/dm-ambiguous-send.json +4 -0
- package/evals/fixtures/dm-blocked.json +4 -0
- package/evals/fixtures/dm-clear.json +4 -0
- package/evals/fixtures/dm-discussion.json +4 -0
- package/evals/fixtures/dm-doc-write-no-tool.json +4 -0
- package/evals/fixtures/dm-long-task-ack.json +4 -0
- package/evals/fixtures/dm-nonblocking-gap.json +4 -0
- package/evals/fixtures/dm-structured-task.json +4 -0
- package/evals/fixtures/group.json +10 -0
- package/evals/fixtures/mentioned.json +3 -0
- package/evals/run-contract-evals.mjs +1031 -0
- package/evals/run-shadow-evals.mjs +267 -0
- package/evals/runners/README.md +66 -0
- package/evals/runners/claude-shadow.mjs +533 -0
- package/evals/schemas/action-request.schema.json +77 -0
- package/evals/shadow-evals.json +133 -0
- package/package.json +28 -6
- package/skills/AGENTS.md +21 -3
- package/skills/dingtalk-basic-behavior/SKILL.md +86 -0
- package/skills/dingtalk-basic-behavior/assets/task-checkpoint.md +37 -0
- package/skills/dingtalk-basic-behavior/references/action-contract.md +31 -0
- package/skills/dingtalk-basic-behavior/references/event-to-behavior.md +24 -0
- package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +27 -0
- package/skills/dingtalk-basic-behavior/references/runtime-modes.md +34 -0
- package/skills/dingtalk-basic-behavior/references/task-lifecycle.md +108 -0
- package/skills//345/237/272/347/241/200/350/241/214/344/270/272.md +44 -0
- package/skills//345/277/203/350/267/263.md +11 -0
- package/skills//346/266/210/346/201/257.md +14 -14
- package/skills//350/257/204/346/265/213.md +14 -1
- package/skills//351/222/211/351/222/211.md +3 -2
- package/templates/behaviors/basic.json +68 -0
- package/templates/fields/default/field.json +25 -0
- package/bin/dingtalk-agent.js +0 -289
- package/src/boot.js +0 -65
- package/src/config.js +0 -42
- package/src/dws.js +0 -192
- package/src/init.js +0 -84
- package/src/kb.js +0 -221
- package/src/runs.js +0 -77
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// 把本次 Run 要遵守的 Agent Skill 冻结进沙箱(TypeScript source)。
|
|
2
|
+
// 运行中的 Run 永不热加载工作区后来修改的规则;重放时只认快照与 hash。
|
|
3
|
+
import { copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync, } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
6
|
+
import { digest, stableStringify } from './events.js';
|
|
7
|
+
import { resolvePackageRoot } from './package-root.js';
|
|
8
|
+
const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
9
|
+
const INSTALL_MARKER = '.dingtalk-agent-install.json';
|
|
10
|
+
export function snapshotSkills(root, runPath, sources, sessionPath) {
|
|
11
|
+
if (!Array.isArray(sources) || !sources.length || sources.some((x) => typeof x !== 'string')) {
|
|
12
|
+
throw new Error('Workspace skills 必须是非空 string[]');
|
|
13
|
+
}
|
|
14
|
+
const rootReal = realpathSync(resolve(root));
|
|
15
|
+
const snapshotRoot = join(sessionPath, 'skills');
|
|
16
|
+
const existingManifest = join(snapshotRoot, 'manifest.json');
|
|
17
|
+
if (existsSync(existingManifest)) {
|
|
18
|
+
const manifest = verifySnapshotRoot(snapshotRoot);
|
|
19
|
+
copySessionSnapshot(snapshotRoot, runPath);
|
|
20
|
+
return manifest;
|
|
21
|
+
}
|
|
22
|
+
rmSync(snapshotRoot, { recursive: true, force: true });
|
|
23
|
+
mkdirSync(snapshotRoot, { recursive: true });
|
|
24
|
+
const entries = [];
|
|
25
|
+
const names = new Set();
|
|
26
|
+
for (const sourceSpec of sources) {
|
|
27
|
+
const resolved = resolveSkillSource(rootReal, sourceSpec);
|
|
28
|
+
const source = resolved.path;
|
|
29
|
+
const skillFile = join(source, 'SKILL.md');
|
|
30
|
+
if (!existsSync(skillFile))
|
|
31
|
+
throw new Error(`Agent Skill 缺少 SKILL.md: ${sourceSpec}`);
|
|
32
|
+
const metadata = parseFrontmatter(readFileSync(skillFile, 'utf8'), sourceSpec);
|
|
33
|
+
const name = metadata.name || basename(source);
|
|
34
|
+
if (names.has(name))
|
|
35
|
+
throw new Error(`Workspace skills 出现重复 Skill name: ${name}`);
|
|
36
|
+
names.add(name);
|
|
37
|
+
const files = walk(source);
|
|
38
|
+
const contentIndex = files.map((path) => {
|
|
39
|
+
const rel = relative(source, path).split('\\').join('/');
|
|
40
|
+
return { path: rel, hash: digest(readFileSync(path).toString('base64')) };
|
|
41
|
+
});
|
|
42
|
+
const hash = digest(stableStringify(contentIndex));
|
|
43
|
+
const destination = join(snapshotRoot, name);
|
|
44
|
+
for (const path of files) {
|
|
45
|
+
const rel = relative(source, path);
|
|
46
|
+
const out = join(destination, rel);
|
|
47
|
+
mkdirSync(dirname(out), { recursive: true });
|
|
48
|
+
copyFileSync(path, out);
|
|
49
|
+
}
|
|
50
|
+
entries.push({
|
|
51
|
+
name,
|
|
52
|
+
description: metadata.description || '',
|
|
53
|
+
version: metadata.version || '',
|
|
54
|
+
sourcePath: resolved.label,
|
|
55
|
+
snapshotPath: `context/skills/${name}/SKILL.md`,
|
|
56
|
+
hash,
|
|
57
|
+
files: contentIndex.length,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const unsigned = {
|
|
61
|
+
$schema: 'dingtalk-agent/skill-snapshot-manifest@1',
|
|
62
|
+
entries,
|
|
63
|
+
};
|
|
64
|
+
const manifest = {
|
|
65
|
+
...unsigned,
|
|
66
|
+
hash: digest(stableStringify(unsigned)),
|
|
67
|
+
};
|
|
68
|
+
writeFileSync(join(snapshotRoot, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
69
|
+
copySessionSnapshot(snapshotRoot, runPath);
|
|
70
|
+
return manifest;
|
|
71
|
+
}
|
|
72
|
+
export function verifySkillSnapshot(runPath, expectedManifestHash) {
|
|
73
|
+
const snapshotRoot = join(runPath, 'context', 'skills');
|
|
74
|
+
return verifySnapshotRoot(snapshotRoot, expectedManifestHash);
|
|
75
|
+
}
|
|
76
|
+
function copySessionSnapshot(snapshotRoot, runPath) {
|
|
77
|
+
const runSnapshotRoot = join(runPath, 'context', 'skills');
|
|
78
|
+
rmSync(runSnapshotRoot, { recursive: true, force: true });
|
|
79
|
+
cpSync(snapshotRoot, runSnapshotRoot, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
function verifySnapshotRoot(snapshotRoot, expectedManifestHash = '') {
|
|
82
|
+
const manifestPath = join(snapshotRoot, 'manifest.json');
|
|
83
|
+
if (!existsSync(manifestPath))
|
|
84
|
+
throw new Error('Skill snapshot 缺少 manifest.json');
|
|
85
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
86
|
+
const { hash, ...unsigned } = manifest;
|
|
87
|
+
const actualManifestHash = digest(stableStringify(unsigned));
|
|
88
|
+
if (!hash || hash !== actualManifestHash ||
|
|
89
|
+
(expectedManifestHash && hash !== expectedManifestHash)) {
|
|
90
|
+
throw new Error('Skill snapshot manifest hash 不一致');
|
|
91
|
+
}
|
|
92
|
+
if (!Array.isArray(manifest.entries) || !manifest.entries.length) {
|
|
93
|
+
throw new Error('Skill snapshot manifest 没有 entries');
|
|
94
|
+
}
|
|
95
|
+
for (const entry of manifest.entries) {
|
|
96
|
+
const skillRoot = resolve(snapshotRoot, entry.name);
|
|
97
|
+
assertInside(realpathSync(snapshotRoot), realpathSync(skillRoot), `Skill snapshot ${entry.name}`);
|
|
98
|
+
const files = walk(skillRoot);
|
|
99
|
+
const contentIndex = files.map((path) => ({
|
|
100
|
+
path: relative(skillRoot, path).split('\\').join('/'),
|
|
101
|
+
hash: digest(readFileSync(path).toString('base64')),
|
|
102
|
+
}));
|
|
103
|
+
if (contentIndex.length !== entry.files || digest(stableStringify(contentIndex)) !== entry.hash) {
|
|
104
|
+
throw new Error(`Skill snapshot 内容漂移: ${entry.name}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return manifest;
|
|
108
|
+
}
|
|
109
|
+
function walk(dir) {
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const name of readdirSync(dir).sort()) {
|
|
112
|
+
// 安装管理元数据不是 Skill 内容,不进入 Session 快照。
|
|
113
|
+
if (name === INSTALL_MARKER)
|
|
114
|
+
continue;
|
|
115
|
+
const path = join(dir, name);
|
|
116
|
+
const stat = lstatSync(path);
|
|
117
|
+
if (stat.isSymbolicLink())
|
|
118
|
+
throw new Error(`Agent Skill 不允许符号链接: ${path}`);
|
|
119
|
+
if (stat.isDirectory())
|
|
120
|
+
out.push(...walk(path));
|
|
121
|
+
else if (stat.isFile())
|
|
122
|
+
out.push(path);
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
function parseFrontmatter(text, label) {
|
|
127
|
+
const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
|
|
128
|
+
if (!match)
|
|
129
|
+
throw new Error(`Agent Skill ${label}/SKILL.md 缺少 YAML frontmatter`);
|
|
130
|
+
const out = {};
|
|
131
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
132
|
+
const m = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/);
|
|
133
|
+
if (!m)
|
|
134
|
+
continue;
|
|
135
|
+
out[m[1]] = m[2].trim().replace(/^(['"])(.*)\1$/, '$2');
|
|
136
|
+
}
|
|
137
|
+
if (!out.name || !out.description) {
|
|
138
|
+
throw new Error(`Agent Skill ${label}/SKILL.md frontmatter 必须含 name 和 description`);
|
|
139
|
+
}
|
|
140
|
+
const nestedVersion = match[1].match(/^metadata:\s*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:\s*['"]?([^'"\r\n]+)['"]?\s*$/m);
|
|
141
|
+
if (nestedVersion?.[1])
|
|
142
|
+
out.version = nestedVersion[1].trim();
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
function resolveSkillSource(rootReal, sourceSpec) {
|
|
146
|
+
const spec = String(sourceSpec || '').trim();
|
|
147
|
+
if (!spec)
|
|
148
|
+
throw new Error('Workspace Skill name 不能为空');
|
|
149
|
+
// 显式路径只允许当前 Workspace 内,保留旧 workspace@1 兼容。
|
|
150
|
+
if (spec.includes('/') || spec.includes('\\') || spec.startsWith('.')) {
|
|
151
|
+
const candidate = resolve(rootReal, spec);
|
|
152
|
+
if (!existsSync(candidate) || !lstatSync(candidate).isDirectory()) {
|
|
153
|
+
throw new Error(`Agent Skill 不存在或不是目录: ${sourceSpec}`);
|
|
154
|
+
}
|
|
155
|
+
const actual = realpathSync(candidate);
|
|
156
|
+
assertInside(rootReal, actual, `Agent Skill ${sourceSpec}`);
|
|
157
|
+
return { path: actual, label: spec };
|
|
158
|
+
}
|
|
159
|
+
// bare name 的优先级:Workspace override → canonical global → client exposure
|
|
160
|
+
// → npm 内置。Session 创建后仍会冻结,运行中不会热切换。
|
|
161
|
+
const candidates = [
|
|
162
|
+
[`workspace:${spec}`, join(rootReal, 'skills', spec)],
|
|
163
|
+
[`global:${spec}`, join(homedir(), '.agents', 'skills', spec)],
|
|
164
|
+
[`claude:${spec}`, join(homedir(), '.claude', 'skills', spec)],
|
|
165
|
+
[`legacy-codex:${spec}`, join(homedir(), '.codex', 'skills', spec)],
|
|
166
|
+
[`bundled:${spec}`, join(PACKAGE_ROOT, 'skills', spec)],
|
|
167
|
+
];
|
|
168
|
+
for (const [label, candidate] of candidates) {
|
|
169
|
+
if (!existsSync(candidate) || !lstatSync(candidate).isDirectory())
|
|
170
|
+
continue;
|
|
171
|
+
const actual = realpathSync(candidate);
|
|
172
|
+
if (!isInsideKnownSkillRoot(actual, rootReal))
|
|
173
|
+
continue;
|
|
174
|
+
return { path: actual, label };
|
|
175
|
+
}
|
|
176
|
+
throw new Error(`找不到 Agent Skill: ${spec};请运行 dingtalk-agent skill install`);
|
|
177
|
+
}
|
|
178
|
+
function isInsideKnownSkillRoot(path, rootReal) {
|
|
179
|
+
const roots = [
|
|
180
|
+
join(rootReal, 'skills'),
|
|
181
|
+
join(homedir(), '.agents', 'skills'),
|
|
182
|
+
join(homedir(), '.claude', 'skills'),
|
|
183
|
+
join(homedir(), '.codex', 'skills'),
|
|
184
|
+
join(PACKAGE_ROOT, 'skills'),
|
|
185
|
+
];
|
|
186
|
+
return roots.some((root) => {
|
|
187
|
+
if (!existsSync(root))
|
|
188
|
+
return false;
|
|
189
|
+
const actualRoot = realpathSync(root);
|
|
190
|
+
const rel = relative(actualRoot, path);
|
|
191
|
+
return rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function assertInside(root, path, label) {
|
|
195
|
+
const rel = relative(root, path);
|
|
196
|
+
if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) || resolve(root, rel) !== path) {
|
|
197
|
+
throw new Error(`${label} 必须位于当前工作区内`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/skills.ts"],"names":[],"mappings":"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","sourcesContent":["// 把本次 Run 要遵守的 Agent Skill 冻结进沙箱(TypeScript source)。\n// 运行中的 Run 永不热加载工作区后来修改的规则;重放时只认快照与 hash。\n\nimport {\n copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync,\n realpathSync, rmSync, writeFileSync,\n} from 'node:fs'\nimport { homedir } from 'node:os'\nimport { basename, dirname, join, relative, resolve } from 'node:path'\nimport { digest, stableStringify } from './events.js'\nimport { resolvePackageRoot } from './package-root.js'\n\nconst PACKAGE_ROOT = resolvePackageRoot(import.meta.url)\nconst INSTALL_MARKER = '.dingtalk-agent-install.json'\n\ninterface SkillManifestEntry {\n name: string\n description: string\n version: string\n sourcePath: string\n snapshotPath: string\n hash: string\n files: number\n}\n\nexport interface SkillManifest {\n $schema: string\n entries: SkillManifestEntry[]\n hash: string\n}\n\nexport function snapshotSkills(\n root: string,\n runPath: string,\n sources: string[],\n sessionPath: string,\n): SkillManifest {\n if (!Array.isArray(sources) || !sources.length || sources.some((x) => typeof x !== 'string')) {\n throw new Error('Workspace skills 必须是非空 string[]')\n }\n\n const rootReal = realpathSync(resolve(root))\n const snapshotRoot = join(sessionPath, 'skills')\n const existingManifest = join(snapshotRoot, 'manifest.json')\n if (existsSync(existingManifest)) {\n const manifest = verifySnapshotRoot(snapshotRoot)\n copySessionSnapshot(snapshotRoot, runPath)\n return manifest\n }\n rmSync(snapshotRoot, { recursive: true, force: true })\n mkdirSync(snapshotRoot, { recursive: true })\n\n const entries: SkillManifestEntry[] = []\n const names = new Set()\n for (const sourceSpec of sources) {\n const resolved = resolveSkillSource(rootReal, sourceSpec)\n const source = resolved.path\n const skillFile = join(source, 'SKILL.md')\n if (!existsSync(skillFile)) throw new Error(`Agent Skill 缺少 SKILL.md: ${sourceSpec}`)\n\n const metadata = parseFrontmatter(readFileSync(skillFile, 'utf8'), sourceSpec)\n const name = metadata.name || basename(source)\n if (names.has(name)) throw new Error(`Workspace skills 出现重复 Skill name: ${name}`)\n names.add(name)\n\n const files = walk(source)\n const contentIndex = files.map((path) => {\n const rel = relative(source, path).split('\\\\').join('/')\n return { path: rel, hash: digest(readFileSync(path).toString('base64')) }\n })\n const hash = digest(stableStringify(contentIndex))\n const destination = join(snapshotRoot, name)\n for (const path of files) {\n const rel = relative(source, path)\n const out = join(destination, rel)\n mkdirSync(dirname(out), { recursive: true })\n copyFileSync(path, out)\n }\n entries.push({\n name,\n description: metadata.description || '',\n version: metadata.version || '',\n sourcePath: resolved.label,\n snapshotPath: `context/skills/${name}/SKILL.md`,\n hash,\n files: contentIndex.length,\n })\n }\n\n const unsigned = {\n $schema: 'dingtalk-agent/skill-snapshot-manifest@1',\n entries,\n }\n const manifest: SkillManifest = {\n ...unsigned,\n hash: digest(stableStringify(unsigned)),\n }\n writeFileSync(join(snapshotRoot, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n')\n copySessionSnapshot(snapshotRoot, runPath)\n return manifest\n}\n\nexport function verifySkillSnapshot(runPath, expectedManifestHash) {\n const snapshotRoot = join(runPath, 'context', 'skills')\n return verifySnapshotRoot(snapshotRoot, expectedManifestHash)\n}\n\nfunction copySessionSnapshot(snapshotRoot: string, runPath: string): void {\n const runSnapshotRoot = join(runPath, 'context', 'skills')\n rmSync(runSnapshotRoot, { recursive: true, force: true })\n cpSync(snapshotRoot, runSnapshotRoot, { recursive: true })\n}\n\nfunction verifySnapshotRoot(snapshotRoot: string, expectedManifestHash = ''): SkillManifest {\n const manifestPath = join(snapshotRoot, 'manifest.json')\n if (!existsSync(manifestPath)) throw new Error('Skill snapshot 缺少 manifest.json')\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as SkillManifest\n const { hash, ...unsigned } = manifest\n const actualManifestHash = digest(stableStringify(unsigned))\n if (!hash || hash !== actualManifestHash ||\n (expectedManifestHash && hash !== expectedManifestHash)) {\n throw new Error('Skill snapshot manifest hash 不一致')\n }\n if (!Array.isArray(manifest.entries) || !manifest.entries.length) {\n throw new Error('Skill snapshot manifest 没有 entries')\n }\n for (const entry of manifest.entries) {\n const skillRoot = resolve(snapshotRoot, entry.name)\n assertInside(realpathSync(snapshotRoot), realpathSync(skillRoot), `Skill snapshot ${entry.name}`)\n const files = walk(skillRoot)\n const contentIndex = files.map((path) => ({\n path: relative(skillRoot, path).split('\\\\').join('/'),\n hash: digest(readFileSync(path).toString('base64')),\n }))\n if (contentIndex.length !== entry.files || digest(stableStringify(contentIndex)) !== entry.hash) {\n throw new Error(`Skill snapshot 内容漂移: ${entry.name}`)\n }\n }\n return manifest\n}\n\nfunction walk(dir): string[] {\n const out: string[] = []\n for (const name of readdirSync(dir).sort()) {\n // 安装管理元数据不是 Skill 内容,不进入 Session 快照。\n if (name === INSTALL_MARKER) continue\n const path = join(dir, name)\n const stat = lstatSync(path)\n if (stat.isSymbolicLink()) throw new Error(`Agent Skill 不允许符号链接: ${path}`)\n if (stat.isDirectory()) out.push(...walk(path))\n else if (stat.isFile()) out.push(path)\n }\n return out\n}\n\nfunction parseFrontmatter(text, label): Record<string, string> {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/)\n if (!match) throw new Error(`Agent Skill ${label}/SKILL.md 缺少 YAML frontmatter`)\n const out: Record<string, string> = {}\n for (const line of match[1].split(/\\r?\\n/)) {\n const m = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\\s*(.*)$/)\n if (!m) continue\n out[m[1]] = m[2].trim().replace(/^(['\"])(.*)\\1$/, '$2')\n }\n if (!out.name || !out.description) {\n throw new Error(`Agent Skill ${label}/SKILL.md frontmatter 必须含 name 和 description`)\n }\n const nestedVersion = match[1].match(\n /^metadata:\\s*\\r?\\n(?:[ \\t]+.*\\r?\\n)*?[ \\t]+version:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m,\n )\n if (nestedVersion?.[1]) out.version = nestedVersion[1].trim()\n return out\n}\n\nfunction resolveSkillSource(rootReal: string, sourceSpec: string): {\n path: string\n label: string\n} {\n const spec = String(sourceSpec || '').trim()\n if (!spec) throw new Error('Workspace Skill name 不能为空')\n\n // 显式路径只允许当前 Workspace 内,保留旧 workspace@1 兼容。\n if (spec.includes('/') || spec.includes('\\\\') || spec.startsWith('.')) {\n const candidate = resolve(rootReal, spec)\n if (!existsSync(candidate) || !lstatSync(candidate).isDirectory()) {\n throw new Error(`Agent Skill 不存在或不是目录: ${sourceSpec}`)\n }\n const actual = realpathSync(candidate)\n assertInside(rootReal, actual, `Agent Skill ${sourceSpec}`)\n return { path: actual, label: spec }\n }\n\n // bare name 的优先级:Workspace override → canonical global → client exposure\n // → npm 内置。Session 创建后仍会冻结,运行中不会热切换。\n const candidates: Array<[string, string]> = [\n [`workspace:${spec}`, join(rootReal, 'skills', spec)],\n [`global:${spec}`, join(homedir(), '.agents', 'skills', spec)],\n [`claude:${spec}`, join(homedir(), '.claude', 'skills', spec)],\n [`legacy-codex:${spec}`, join(homedir(), '.codex', 'skills', spec)],\n [`bundled:${spec}`, join(PACKAGE_ROOT, 'skills', spec)],\n ]\n for (const [label, candidate] of candidates) {\n if (!existsSync(candidate) || !lstatSync(candidate).isDirectory()) continue\n const actual = realpathSync(candidate)\n if (!isInsideKnownSkillRoot(actual, rootReal)) continue\n return { path: actual, label }\n }\n throw new Error(`找不到 Agent Skill: ${spec};请运行 dingtalk-agent skill install`)\n}\n\nfunction isInsideKnownSkillRoot(path: string, rootReal: string): boolean {\n const roots = [\n join(rootReal, 'skills'),\n join(homedir(), '.agents', 'skills'),\n join(homedir(), '.claude', 'skills'),\n join(homedir(), '.codex', 'skills'),\n join(PACKAGE_ROOT, 'skills'),\n ]\n return roots.some((root) => {\n if (!existsSync(root)) return false\n const actualRoot = realpathSync(root)\n const rel = relative(actualRoot, path)\n return rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)\n })\n}\n\nfunction assertInside(root, path, label) {\n const rel = relative(root, path)\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`) || resolve(root, rel) !== path) {\n throw new Error(`${label} 必须位于当前工作区内`)\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type JsonPrimitive = null | boolean | number | string\nexport type JsonValue = JsonPrimitive | JsonValue[] | JsonObject\nexport interface JsonObject { [key: string]: JsonValue }\n\nexport type EventKind =\n | 'im.message.mentioned'\n | 'im.message.dm'\n | 'im.message.group'\n | 'agent.heartbeat'\n | (string & {})\n\nexport type ActionKind = 'ack' | 'reply' | 'ask' | 'silence'\nexport type ActionOutcome = 'confirmed' | 'accepted-unverified' | 'uncertain'\n\nexport interface Correlation {\n source: string\n key: string\n}\n\nexport interface ReplyTarget {\n tenantId: string\n conversationId: string\n messageId: string\n senderOpenDingTalkId: string\n}\n\nexport interface NormalizedEvent {\n $schema: 'dingtalk-agent/event@1'\n id: string\n idSource: 'source' | 'derived'\n kind: EventKind\n occurredAt: string | null\n source: { adapter: string; type: string; subscribeId: string }\n tenant: { id: string }\n actor: {\n id: string\n openDingTalkId: string\n userId: string\n displayName: string\n }\n conversation: { id: string; type: string }\n message: { id: string; text: string; threadId: string; rootMessageId: string }\n correlation: Correlation\n replyTarget: ReplyTarget | null\n}\n\nexport interface CompactEvent {\n $schema: 'dingtalk-agent/trigger@1'\n id: string\n type: EventKind\n contextId: string\n occurredAt: string | null\n conversationId: string\n messageId: string\n actorId: string\n actorName: string\n text: string\n}\n\nexport interface RuntimeConfig {\n sessionRoot: string\n eventIndexRoot: string\n waitRoot: string\n waitTtlMs: number\n}\n\nexport interface AgentConfig {\n schemaVersion: number\n agent: { name: string; userId: string; ownerId: string }\n dws: { profile: string; expectedUserId: string }\n runtime: RuntimeConfig\n fields: FieldEntry[]\n kb: Array<Record<string, any>>\n duties: Array<Record<string, any>>\n eval: { target: string }\n}\n\nexport interface FieldEntry {\n id: string\n path: string\n default?: boolean\n priority?: number\n}\n\nexport interface FieldDefinition {\n id: string\n name?: string\n description?: string\n match?: Partial<Record<'tenantIds' | 'conversationIds' | 'actorIds' | 'eventKinds', string[]>>\n transport: {\n mode: 'personal-event' | 'robot-connect'\n egressOwner: 'dingtalk-agent' | 'connector'\n }\n dws?: Partial<AgentConfig['dws']>\n behavior: { packs: string[] }\n memory?: Record<string, unknown>\n skills?: Record<string, unknown>\n evolution?: Record<string, unknown>\n}\n\nexport interface BehaviorRule {\n eligibility?: string\n defaultAction: ActionKind\n allowedActions: ActionKind[]\n replyPolicy?: string\n [key: string]: unknown\n}\n\nexport interface BehaviorSnapshot {\n $schema: 'dingtalk-agent/behavior-snapshot@1'\n id: string\n version: string\n description: string\n handles: Record<string, BehaviorRule>\n stateMachine: {\n initial: string\n transitions: Record<string, Partial<Record<ActionKind, string>>>\n terminal: string[]\n }\n limits: Partial<Record<'maxAckPerRun' | 'maxOutwardActionsPerRun' | 'maxTerminalMessagesPerRun' | 'maxTextCharacters', number>>\n invariants: string[]\n packs: Array<{ path: string; id: string; version: string; hash: string }>\n hash: string\n}\n\nexport type ResumeContext =\n | { mode: 'start' }\n | {\n mode: 'resume' | 'cancel'\n waitId: string\n waitScopeHash: string\n sourceRunId: string\n sourceActionId: string\n questionText: string\n questionDelivery: Record<string, unknown> | null\n claimedByEventId: string\n cancelRequested: boolean\n cancelEventId: string\n suppressedInput: boolean\n }\n\nexport interface ActionCounts {\n ack: number\n reply: number\n ask: number\n silence: number\n outward: number\n terminal: number\n}\n\nexport interface SessionRecord {\n $schema: 'dingtalk-agent/session@1'\n id: string\n contextId: string\n fieldId: string\n correlation: Correlation\n correlationScope: string\n createdAt: string\n generation: number\n principal: NormalizedEvent['actor']\n tenant: NormalizedEvent['tenant']\n conversation: NormalizedEvent['conversation']\n updatedAt?: string\n cancelledAt?: string\n lastCancelEventId?: string\n}\n\nexport interface RunRecord {\n $schema: 'dingtalk-agent/run@1'\n protocol: 'basic-behavior/v1'\n id: string\n contextId: string\n sessionId: string\n fieldId: string\n eventId: string\n eventHash: string\n eventKind: EventKind\n createdAt: string\n updatedAt: string\n sessionGeneration: number\n resume: ResumeContext\n state: string\n status: string\n actionCounts: ActionCounts\n appliedActionIds: string[]\n behavior: { id: string; version: string; hash: string }\n skills: { manifestHash: string; manifestPath: string }\n [key: string]: unknown\n}\n\nexport interface ActionReceipt {\n $schema: 'dingtalk-agent/action-receipt@1'\n actionId: string\n runId: string\n kind: ActionKind\n completedAt: string\n fromState: string\n toState: string\n outcome: ActionOutcome\n verified: boolean\n verification: string\n duplicate?: boolean\n [key: string]: unknown\n}\n"]}
|