@xdxer/dingtalk-agent 0.1.4-beta.8 → 0.1.4-beta.9

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.
Files changed (212) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.en.md +395 -0
  3. package/README.md +466 -35
  4. package/dist/bin/dingtalk-agent.js +1058 -10
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +98 -14
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +460 -0
  9. package/dist/src/agent-audit.js.map +1 -0
  10. package/dist/src/agent-bindings.js +132 -0
  11. package/dist/src/agent-bindings.js.map +1 -0
  12. package/dist/src/agent-definition.js +182 -0
  13. package/dist/src/agent-definition.js.map +1 -0
  14. package/dist/src/agent-enhance.js +678 -0
  15. package/dist/src/agent-enhance.js.map +1 -0
  16. package/dist/src/bootstrap.js +125 -17
  17. package/dist/src/bootstrap.js.map +1 -1
  18. package/dist/src/development-workspace.js +729 -0
  19. package/dist/src/development-workspace.js.map +1 -0
  20. package/dist/src/dws.js +145 -0
  21. package/dist/src/dws.js.map +1 -1
  22. package/dist/src/eval-evidence.js +193 -0
  23. package/dist/src/eval-evidence.js.map +1 -0
  24. package/dist/src/invocation.js +36 -0
  25. package/dist/src/invocation.js.map +1 -0
  26. package/dist/src/lab.js +679 -0
  27. package/dist/src/lab.js.map +1 -0
  28. package/dist/src/lease.js +100 -0
  29. package/dist/src/lease.js.map +1 -0
  30. package/dist/src/memory/candidates.js +451 -0
  31. package/dist/src/memory/candidates.js.map +1 -0
  32. package/dist/src/memory/completion-evidence.js +536 -0
  33. package/dist/src/memory/completion-evidence.js.map +1 -0
  34. package/dist/src/memory/operational.js +263 -0
  35. package/dist/src/memory/operational.js.map +1 -0
  36. package/dist/src/memory/remote-state.js +478 -0
  37. package/dist/src/memory/remote-state.js.map +1 -0
  38. package/dist/src/memory/task-checkpoints.js +204 -0
  39. package/dist/src/memory/task-checkpoints.js.map +1 -0
  40. package/dist/src/multica-deploy.js +1480 -0
  41. package/dist/src/multica-deploy.js.map +1 -0
  42. package/dist/src/multica-provider.js +685 -0
  43. package/dist/src/multica-provider.js.map +1 -0
  44. package/dist/src/opencode-evals.js +1062 -0
  45. package/dist/src/opencode-evals.js.map +1 -0
  46. package/dist/src/opencode-provider.js +531 -0
  47. package/dist/src/opencode-provider.js.map +1 -0
  48. package/dist/src/opencode-workspace.js +197 -0
  49. package/dist/src/opencode-workspace.js.map +1 -0
  50. package/dist/src/perception.js +225 -0
  51. package/dist/src/perception.js.map +1 -0
  52. package/dist/src/personal-event-evals.js +595 -0
  53. package/dist/src/personal-event-evals.js.map +1 -0
  54. package/dist/src/promotion.js +786 -0
  55. package/dist/src/promotion.js.map +1 -0
  56. package/dist/src/remote-semantic-state-live-evals.js +888 -0
  57. package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
  58. package/dist/src/remote-semantic-state-worker.js +38 -0
  59. package/dist/src/remote-semantic-state-worker.js.map +1 -0
  60. package/dist/src/remote-state-evals.js +501 -0
  61. package/dist/src/remote-state-evals.js.map +1 -0
  62. package/dist/src/response-gate.js +51 -0
  63. package/dist/src/response-gate.js.map +1 -0
  64. package/dist/src/robot-evals.js +770 -0
  65. package/dist/src/robot-evals.js.map +1 -0
  66. package/dist/src/sessions.js +66 -105
  67. package/dist/src/sessions.js.map +1 -1
  68. package/dist/src/skill-manager.js +25 -16
  69. package/dist/src/skill-manager.js.map +1 -1
  70. package/dist/src/skills.js.map +1 -1
  71. package/dist/src/storage-evals.js +26 -0
  72. package/dist/src/storage-evals.js.map +1 -0
  73. package/dist/src/types.js.map +1 -1
  74. package/dist/src/waits.js +5 -1
  75. package/dist/src/waits.js.map +1 -1
  76. package/dist/src/workspace.js +28 -3
  77. package/dist/src/workspace.js.map +1 -1
  78. package/docs/INSTALLATION.md +47 -0
  79. package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
  80. package/docs/architecture/agent-memory-topology.png +0 -0
  81. package/docs/architecture/agent-memory-topology.svg +132 -0
  82. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  83. package/docs/architecture/general-agent-kernel-topology.svg +149 -0
  84. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  85. package/docs/architecture/provider-bound-development-workspace.svg +141 -0
  86. package/docs/architecture/task-completion-gate.png +0 -0
  87. package/docs/architecture/task-completion-gate.svg +191 -0
  88. package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
  89. package/docs/schemas/agent-audit.schema.json +92 -0
  90. package/docs/schemas/agent-bindings.schema.json +54 -0
  91. package/docs/schemas/agent-definition.schema.json +78 -0
  92. package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
  93. package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
  94. package/docs/schemas/enriched-invocation.schema.json +46 -0
  95. package/docs/schemas/eval-candidate-plan.schema.json +28 -0
  96. package/docs/schemas/eval-candidate-result.schema.json +20 -0
  97. package/docs/schemas/eval-candidate.schema.json +30 -0
  98. package/docs/schemas/invocation.schema.json +19 -0
  99. package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
  100. package/docs/schemas/memory-candidate.schema.json +76 -0
  101. package/docs/schemas/memory-publish-target.schema.json +25 -0
  102. package/docs/schemas/multica-deployment-list.schema.json +29 -0
  103. package/docs/schemas/multica-deployment-operation.schema.json +51 -0
  104. package/docs/schemas/multica-deployment-plan.schema.json +70 -0
  105. package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
  106. package/docs/schemas/multica-deployment-status.schema.json +23 -0
  107. package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
  108. package/docs/schemas/multica-workspace-plan.schema.json +68 -0
  109. package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
  110. package/docs/schemas/multica-workspace-status.schema.json +34 -0
  111. package/docs/schemas/observation.schema.json +21 -0
  112. package/docs/schemas/operational-memory-provider.schema.json +36 -0
  113. package/docs/schemas/operational-memory-record.schema.json +24 -0
  114. package/docs/schemas/perception-input.schema.json +56 -0
  115. package/docs/schemas/project.schema.json +112 -0
  116. package/docs/schemas/promotion-list.schema.json +36 -0
  117. package/docs/schemas/promotion-plan.schema.json +60 -0
  118. package/docs/schemas/promotion-policy.schema.json +29 -0
  119. package/docs/schemas/promotion-receipt.schema.json +43 -0
  120. package/docs/schemas/promotion-status.schema.json +23 -0
  121. package/docs/schemas/release-readiness.schema.json +65 -0
  122. package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
  123. package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
  124. package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
  125. package/docs/schemas/response-gate.schema.json +20 -0
  126. package/docs/schemas/task-checkpoint.schema.json +71 -0
  127. package/docs/schemas/task-completion-evidence.schema.json +154 -0
  128. package/docs/schemas/workspace-doctor.schema.json +56 -0
  129. package/docs/schemas/workspace-state.schema.json +39 -0
  130. package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
  131. package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
  132. package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
  133. package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
  134. package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
  135. package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
  136. package/examples/agents/fde-coach/AGENTS.md +26 -0
  137. package/examples/agents/fde-coach/MEMORY.md +3 -0
  138. package/examples/agents/fde-coach/fields/default/field.json +24 -0
  139. package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
  140. package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
  141. package/examples/agents/release-manager/AGENTS.md +26 -0
  142. package/examples/agents/release-manager/MEMORY.md +3 -0
  143. package/examples/agents/release-manager/fields/default/field.json +24 -0
  144. package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
  145. package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
  146. package/lab/README.md +109 -0
  147. package/lab/agent-eval/catalog.json +91 -0
  148. package/lab/agent-eval/classic-failures.json +177 -0
  149. package/lab/agent-eval/completion-gate-regression.json +99 -0
  150. package/lab/agent-eval/personal-event-live.example.json +94 -0
  151. package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
  152. package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
  153. package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
  154. package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
  155. package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
  156. package/lab/agent-eval/remote-state.example.json +31 -0
  157. package/lab/agent-eval/workspace/AGENTS.md +7 -0
  158. package/lab/agent-eval/workspace/MEMORY.md +4 -0
  159. package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
  160. package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
  161. package/lab/agent-eval/workspace/opencode.json +20 -0
  162. package/lab/manifest.example.json +27 -0
  163. package/lab/manifest.personal-event.example.json +27 -0
  164. package/lab/project-workspace/README.md +11 -0
  165. package/lab/project-workspace/fake-multica-provider.mjs +266 -0
  166. package/lab/project-workspace/multica-deploy.fixture.json +29 -0
  167. package/lab/project-workspace/multica-readonly.fixture.json +69 -0
  168. package/lab/project-workspace/observation.fixture.json +14 -0
  169. package/lab/project-workspace/opencode-provider-suite.json +65 -0
  170. package/lab/project-workspace/project.fixture.json +44 -0
  171. package/lab/project-workspace/promotion-policy.fixture.json +15 -0
  172. package/lab/robot-eval/pool.example.json +30 -0
  173. package/lab/robot-eval/suite.json +123 -0
  174. package/lab/robot-eval/workspace/AGENTS.md +21 -0
  175. package/lab/robot-eval/workspace/MEMORY.md +3 -0
  176. package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
  177. package/lab/robot-eval/workspace/opencode.json +22 -0
  178. package/lab/schemas/agent-eval-catalog.schema.json +47 -0
  179. package/lab/schemas/lab-manifest.schema.json +70 -0
  180. package/lab/schemas/personal-event-eval.schema.json +91 -0
  181. package/lab/schemas/remote-state-eval.schema.json +66 -0
  182. package/lab/schemas/robot-eval-suite.schema.json +184 -0
  183. package/lab/schemas/robot-pool.schema.json +56 -0
  184. package/package.json +21 -3
  185. package/skills/dingtalk-agent-boot-multica/SKILL.md +40 -0
  186. package/skills/dingtalk-agent-compose/SKILL.md +110 -0
  187. package/skills/dingtalk-agent-compose/assets/AGENTS.template.md +26 -0
  188. package/skills/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
  189. package/skills/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
  190. package/skills/dingtalk-agent-compose/assets/opencode.template.json +12 -0
  191. package/skills/dingtalk-agent-compose/assets/role-skill.template.md +24 -0
  192. package/skills/dingtalk-agent-compose/evals/evals.json +94 -0
  193. package/skills/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
  194. package/skills/dingtalk-agent-compose/references/opencode-host-contract.md +65 -0
  195. package/skills/dingtalk-agent-compose/references/storage-routing.md +20 -0
  196. package/skills/dingtalk-agent-deploy/SKILL.md +60 -0
  197. package/skills/dingtalk-agent-deploy/references/multica-deployment-contract.md +49 -0
  198. package/skills/dingtalk-agent-deploy/references/promotion-observation-contract.md +49 -0
  199. package/skills/dingtalk-agent-eval/SKILL.md +116 -0
  200. package/skills/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
  201. package/skills/dingtalk-agent-eval/evals/evals.json +61 -0
  202. package/skills/dingtalk-agent-eval/references/eval-topology.md +34 -0
  203. package/skills/dingtalk-agent-eval/references/evidence-contract.md +31 -0
  204. package/skills/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
  205. package/skills/dingtalk-agent-eval/references/storage-modes.md +75 -0
  206. package/skills/dingtalk-basic-behavior/SKILL.md +63 -3
  207. package/skills/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
  208. package/skills/dingtalk-basic-behavior/assets/{task-checkpoint.md → task-checkpoint.json} +2 -21
  209. package/skills/dingtalk-basic-behavior/references/action-contract.md +2 -0
  210. package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +15 -1
  211. package/skills/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
  212. package/skills/dingtalk-basic-behavior/references/task-lifecycle.md +32 -7
@@ -0,0 +1,132 @@
1
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
2
+ import { relative, resolve } from 'node:path';
3
+ import { digest, stableStringify } from './events.js';
4
+ const ROOT_KEYS = new Set([
5
+ '$schema', 'agent', 'skills', 'memory', 'knowledge', 'artifacts', 'stateDir', 'authority',
6
+ ]);
7
+ const AUTHORITY_KEYS = new Set(['profile', 'expectedUserId']);
8
+ export function loadAgentBindings(root, input) {
9
+ const rootReal = realpathSync(resolve(root));
10
+ const candidate = resolve(rootReal, input);
11
+ if (!isInside(rootReal, candidate)) {
12
+ throw new Error(`Agent bindings 必须位于当前 Agent 根目录内: ${input}`);
13
+ }
14
+ if (!existsSync(candidate))
15
+ throw new Error(`Agent bindings 不存在: ${input}`);
16
+ const path = realpathSync(candidate);
17
+ if (!isInside(rootReal, path))
18
+ throw new Error(`Agent bindings 真实路径越界: ${input}`);
19
+ let raw;
20
+ try {
21
+ raw = JSON.parse(readFileSync(path, 'utf8'));
22
+ }
23
+ catch (error) {
24
+ throw new Error(`Agent bindings 不是合法 JSON: ${error.message}`);
25
+ }
26
+ const value = objectValue(raw, 'Agent bindings');
27
+ assertExactKeys(value, ROOT_KEYS, 'Agent bindings');
28
+ if (value.$schema !== 'dingtalk-agent/agent-bindings@1') {
29
+ throw new Error(`Agent bindings schema 非法: ${String(value.$schema || '-')}`);
30
+ }
31
+ const authority = objectValue(value.authority, 'Agent bindings authority');
32
+ assertExactKeys(authority, AUTHORITY_KEYS, 'Agent bindings authority');
33
+ const bindings = {
34
+ $schema: 'dingtalk-agent/agent-bindings@1',
35
+ agent: storage(value.agent, ['local-dir'], 'agent'),
36
+ skills: storage(value.skills, ['local-dir', 'local-md'], 'skills'),
37
+ memory: storage(value.memory, ['local-md', 'dingtalk-doc'], 'memory'),
38
+ knowledge: storage(value.knowledge, ['local-md', 'dingtalk-doc'], 'knowledge'),
39
+ artifacts: storage(value.artifacts, ['local-dir'], 'artifacts'),
40
+ stateDir: localStateDir(value.stateDir),
41
+ authority: {
42
+ profile: optionalString(authority.profile, 'authority.profile'),
43
+ expectedUserId: optionalString(authority.expectedUserId, 'authority.expectedUserId'),
44
+ },
45
+ };
46
+ assertLocalRoutesStayInside(rootReal, bindings);
47
+ return {
48
+ path,
49
+ hash: digest(stableStringify(bindings)),
50
+ value: bindings,
51
+ context: {
52
+ agent: bindings.agent,
53
+ skills: bindings.skills,
54
+ memory: bindings.memory,
55
+ knowledge: bindings.knowledge,
56
+ artifacts: bindings.artifacts,
57
+ stateDir: bindings.stateDir,
58
+ profile: bindings.authority.profile,
59
+ expectedUserId: bindings.authority.expectedUserId,
60
+ },
61
+ };
62
+ }
63
+ function assertLocalRoutesStayInside(root, bindings) {
64
+ for (const [label, uri] of Object.entries({
65
+ agent: bindings.agent, skills: bindings.skills, memory: bindings.memory,
66
+ knowledge: bindings.knowledge, artifacts: bindings.artifacts,
67
+ })) {
68
+ if (!uri.startsWith('local-'))
69
+ continue;
70
+ const ref = uri.slice(uri.indexOf(':') + 1);
71
+ const candidate = resolve(root, ref);
72
+ if (!isInside(root, candidate))
73
+ throw new Error(`${label} 本地路径越出 Agent 根目录: ${ref}`);
74
+ if (existsSync(candidate) && !isInside(root, realpathSync(candidate))) {
75
+ throw new Error(`${label} 本地真实路径越出 Agent 根目录: ${ref}`);
76
+ }
77
+ }
78
+ const state = resolve(root, bindings.stateDir);
79
+ if (!isInside(root, state))
80
+ throw new Error(`stateDir 越出 Agent 根目录: ${bindings.stateDir}`);
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
+ }
86
+ }
87
+ function storage(value, providers, label) {
88
+ const text = requiredString(value, label);
89
+ const separator = text.indexOf(':');
90
+ const provider = separator < 0 ? '' : text.slice(0, separator);
91
+ const reference = separator < 0 ? '' : text.slice(separator + 1).trim();
92
+ if (!providers.includes(provider) || !reference) {
93
+ throw new Error(`${label} Storage 非法;允许 ${providers.map((item) => `${item}:<ref>`).join(' / ')}`);
94
+ }
95
+ return text;
96
+ }
97
+ function localStateDir(value) {
98
+ const text = requiredString(value, 'stateDir');
99
+ if (/^[a-z][a-z0-9-]*:/i.test(text)) {
100
+ throw new Error('stateDir 必须是宿主本地目录,不能是远端 Provider URI');
101
+ }
102
+ return text;
103
+ }
104
+ function requiredString(value, label) {
105
+ if (typeof value !== 'string' || !value.trim())
106
+ throw new Error(`${label} 必须是非空字符串`);
107
+ return value.trim();
108
+ }
109
+ function optionalString(value, label) {
110
+ if (typeof value !== 'string')
111
+ throw new Error(`${label} 必须是字符串`);
112
+ return value.trim();
113
+ }
114
+ function objectValue(value, label) {
115
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
116
+ throw new Error(`${label} 必须是 JSON object`);
117
+ }
118
+ return value;
119
+ }
120
+ function assertExactKeys(value, allowed, label) {
121
+ const unknown = Object.keys(value).filter((key) => !allowed.has(key));
122
+ if (unknown.length)
123
+ throw new Error(`${label} 包含未知字段: ${unknown.join(', ')}`);
124
+ const missing = [...allowed].filter((key) => !(key in value));
125
+ if (missing.length)
126
+ throw new Error(`${label} 缺少字段: ${missing.join(', ')}`);
127
+ }
128
+ function isInside(root, candidate) {
129
+ const rel = relative(root, candidate);
130
+ return rel === '' || (rel !== '..' && !rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`));
131
+ }
132
+ //# sourceMappingURL=agent-bindings.js.map
@@ -0,0 +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"]}
@@ -0,0 +1,182 @@
1
+ import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { basename, dirname, join, relative, resolve } from 'node:path';
4
+ import { digest, stableStringify } from './events.js';
5
+ export function buildBootstrapDefinition(mounts, config, workspace = null) {
6
+ const bodyMount = mounts.find((item) => item.slot === 'body') ||
7
+ mounts.find((item) => item.slot === 'profile') ||
8
+ mounts.find((item) => item.slot === 'workspace') || null;
9
+ const discoveredSkills = mounts
10
+ .filter((item) => item.slot.startsWith('skill:'))
11
+ .map((item) => {
12
+ const metadata = readSkillMetadata(item.path);
13
+ return {
14
+ name: metadata.name || item.slot.slice('skill:'.length),
15
+ version: metadata.version, source: item.source,
16
+ path: item.path, hash: item.hash,
17
+ };
18
+ });
19
+ const configuredSkills = discoveredSkills.length
20
+ ? discoveredSkills
21
+ : (workspace?.skills || []).map((name) => ({
22
+ name, version: '', source: `workspace:${name}`, path: '', hash: '',
23
+ }));
24
+ const skills = configuredSkills.some((item) => item.name === 'dingtalk-basic-behavior')
25
+ ? configuredSkills
26
+ : [{
27
+ name: 'dingtalk-basic-behavior', version: '',
28
+ source: 'bundled:dingtalk-basic-behavior', path: '', hash: '',
29
+ }, ...configuredSkills];
30
+ const sourcePath = config.sourcePath ? resolve(config.sourcePath) : '';
31
+ const gitRevision = sourcePath ? readGitRevision(sourcePath) : '';
32
+ const sourceKind = workspace
33
+ ? 'workspace'
34
+ : config.source.startsWith('dingtalk-doc:')
35
+ ? 'dingtalk-doc'
36
+ : gitRevision ? 'git-checkout' : 'local-folder';
37
+ const id = cleanId(workspace?.id || (sourcePath ? basename(sourcePath) : config.source));
38
+ return finalize({
39
+ $schema: 'dingtalk-agent/agent-definition@1',
40
+ id,
41
+ source: { kind: sourceKind, uri: config.source, revision: gitRevision },
42
+ body: bodyMount ? { path: bodyMount.path, hash: bodyMount.hash } : null,
43
+ skills,
44
+ storage: {
45
+ memory: config.memory, knowledge: config.knowledge,
46
+ artifacts: config.artifacts, state: config.state,
47
+ },
48
+ authority: {
49
+ dwsProfile: config.dwsProfile,
50
+ expectedUserId: config.expectedUserId,
51
+ },
52
+ configuration: config.origins,
53
+ });
54
+ }
55
+ /**
56
+ * Definition 与 Skill 一样按 Session 冻结。新 Run 只复制已验证的 Session 快照,
57
+ * 因而在线修改 WORKSPACE.md、DWS profile 或启用 Skill 不会改变同一件事的身份。
58
+ */
59
+ export function snapshotPreparedDefinition(runPath, sessionPath, workspace, mounts, skillManifest) {
60
+ const sessionRoot = join(sessionPath, 'definition');
61
+ const definitionPath = join(sessionRoot, 'definition.json');
62
+ let definition;
63
+ if (existsSync(definitionPath)) {
64
+ definition = verifyDefinition(sessionRoot);
65
+ }
66
+ else {
67
+ mkdirSync(sessionRoot, { recursive: true });
68
+ const profile = mounts.find((item) => item.slot === 'profile');
69
+ let body = null;
70
+ if (profile?.snapshotPath) {
71
+ const source = join(runPath, profile.snapshotPath);
72
+ const destination = join(sessionRoot, 'body.md');
73
+ copyFileSync(source, destination);
74
+ const markdown = readFileSync(destination, 'utf8');
75
+ body = { path: 'body.md', hash: digest(markdown) };
76
+ }
77
+ definition = finalize({
78
+ $schema: 'dingtalk-agent/agent-definition@1',
79
+ id: cleanId(workspace.id),
80
+ source: {
81
+ kind: 'workspace', uri: `workspace:${workspace.id}`,
82
+ revision: digest(stableStringify(workspace)),
83
+ },
84
+ body,
85
+ skills: skillManifest.entries.map((entry) => ({
86
+ name: entry.name, version: entry.version, source: entry.sourcePath,
87
+ path: entry.snapshotPath, hash: entry.hash,
88
+ })),
89
+ storage: {
90
+ memory: workspace.mounts.memory,
91
+ knowledge: workspace.mounts.knowledge,
92
+ artifacts: 'session:artifacts',
93
+ state: 'session:control-state',
94
+ },
95
+ authority: {
96
+ dwsProfile: workspace.dws.profile,
97
+ expectedUserId: workspace.dws.expectedUserId,
98
+ },
99
+ configuration: {
100
+ agent: 'workspace', skills: 'workspace', memory: 'workspace',
101
+ knowledge: 'workspace', artifacts: 'convention', state: 'convention',
102
+ dwsProfile: 'workspace', expectedUserId: 'workspace',
103
+ },
104
+ });
105
+ writeAtomic(definitionPath, JSON.stringify(definition, null, 2) + '\n');
106
+ }
107
+ const destination = join(runPath, 'context', 'agent-definition');
108
+ rmSync(destination, { recursive: true, force: true });
109
+ cpSync(sessionRoot, destination, { recursive: true });
110
+ return definition;
111
+ }
112
+ export function verifyPreparedDefinition(runPath, expectedHash = '') {
113
+ return verifyDefinition(join(runPath, 'context', 'agent-definition'), expectedHash);
114
+ }
115
+ function finalize(input) {
116
+ const missing = [];
117
+ if (!input.body)
118
+ missing.push('body');
119
+ if (!input.skills.length)
120
+ missing.push('skills');
121
+ if (!input.storage.memory)
122
+ missing.push('storage.memory');
123
+ if (!input.storage.knowledge)
124
+ missing.push('storage.knowledge');
125
+ const unsigned = {
126
+ ...input,
127
+ status: missing.length ? 'partial' : 'ready',
128
+ missing,
129
+ };
130
+ return { ...unsigned, hash: digest(stableStringify(unsigned)) };
131
+ }
132
+ function verifyDefinition(root, expectedHash = '') {
133
+ const path = join(root, 'definition.json');
134
+ if (!existsSync(path))
135
+ throw new Error('Agent Definition snapshot 缺少 definition.json');
136
+ const value = JSON.parse(readFileSync(path, 'utf8'));
137
+ const { hash, ...unsigned } = value;
138
+ if (!hash || digest(stableStringify(unsigned)) !== hash || (expectedHash && hash !== expectedHash)) {
139
+ throw new Error('Agent Definition snapshot hash 不一致');
140
+ }
141
+ if (value.body) {
142
+ const rootPath = resolve(root);
143
+ const bodyPath = resolve(rootPath, value.body.path);
144
+ const rel = relative(rootPath, bodyPath);
145
+ if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)) {
146
+ throw new Error('Agent Definition body 必须位于 snapshot 内');
147
+ }
148
+ const body = readFileSync(bodyPath, 'utf8');
149
+ if (digest(body) !== value.body.hash)
150
+ throw new Error('Agent Definition body 内容漂移');
151
+ }
152
+ return value;
153
+ }
154
+ function readGitRevision(path) {
155
+ const run = spawnSync('git', ['-C', path, 'rev-parse', '--show-toplevel', 'HEAD'], {
156
+ encoding: 'utf8', timeout: 2_000,
157
+ });
158
+ if (run.status !== 0)
159
+ return '';
160
+ const lines = String(run.stdout || '').trim().split(/\r?\n/);
161
+ return lines.length >= 2 ? lines[1] : '';
162
+ }
163
+ function readSkillMetadata(path) {
164
+ if (!path || !existsSync(path))
165
+ return { name: '', version: '' };
166
+ const text = readFileSync(path, 'utf8');
167
+ const block = text.match(/^---\r?\n([\s\S]*?)\r?\n---/)?.[1] || '';
168
+ const scalar = (name) => block.match(new RegExp(`^${name}:\\s*['"]?([^'"\\r\\n]+)['"]?\\s*$`, 'm'))?.[1]?.trim() || '';
169
+ const nestedVersion = block.match(/^metadata:\s*\r?\n(?:[ \t]+.*\r?\n)*?[ \t]+version:\s*['"]?([^'"\r\n]+)['"]?\s*$/m)?.[1]?.trim() || '';
170
+ return { name: scalar('name'), version: nestedVersion || scalar('version') };
171
+ }
172
+ function writeAtomic(path, value) {
173
+ mkdirSync(dirname(path), { recursive: true });
174
+ const temp = `${path}.${process.pid}.${Date.now()}.tmp`;
175
+ writeFileSync(temp, value, { flag: 'wx' });
176
+ renameSync(temp, path);
177
+ }
178
+ function cleanId(value) {
179
+ return value.replace(/^[a-z-]+:/, '').replace(/[^a-zA-Z0-9._-]+/g, '-')
180
+ .replace(/^-+|-+$/g, '') || 'agent';
181
+ }
182
+ //# sourceMappingURL=agent-definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-definition.js","sourceRoot":"","sources":["../../src/agent-definition.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { spawnSync } from 'node:child_process'\nimport { basename, dirname, join, relative, resolve } from 'node:path'\nimport { digest, stableStringify } from './events.js'\nimport type { AgentDefinition } from './types.js'\nimport type { BootstrapMount } from './bootstrap.js'\nimport type { SkillManifest } from './skills.js'\nimport type { MountSnapshot, WorkspaceSpec } from './workspace.js'\n\ntype Origin = AgentDefinition['configuration'][string]\n\nexport interface DefinitionConfig {\n source: string\n sourcePath?: string\n memory: string\n knowledge: string\n artifacts: string\n state: string\n dwsProfile: string\n expectedUserId: string\n origins: Record<string, Origin>\n}\n\nexport function buildBootstrapDefinition(\n mounts: BootstrapMount[],\n config: DefinitionConfig,\n workspace: WorkspaceSpec | null = null,\n): AgentDefinition {\n const bodyMount = mounts.find((item) => item.slot === 'body') ||\n mounts.find((item) => item.slot === 'profile') ||\n mounts.find((item) => item.slot === 'workspace') || null\n const discoveredSkills = mounts\n .filter((item) => item.slot.startsWith('skill:'))\n .map((item) => {\n const metadata = readSkillMetadata(item.path)\n return {\n name: metadata.name || item.slot.slice('skill:'.length),\n version: metadata.version, source: item.source,\n path: item.path, hash: item.hash,\n }\n })\n const configuredSkills = discoveredSkills.length\n ? discoveredSkills\n : (workspace?.skills || []).map((name) => ({\n name, version: '', source: `workspace:${name}`, path: '', hash: '',\n }))\n const skills = configuredSkills.some((item) => item.name === 'dingtalk-basic-behavior')\n ? configuredSkills\n : [{\n name: 'dingtalk-basic-behavior', version: '',\n source: 'bundled:dingtalk-basic-behavior', path: '', hash: '',\n }, ...configuredSkills]\n const sourcePath = config.sourcePath ? resolve(config.sourcePath) : ''\n const gitRevision = sourcePath ? readGitRevision(sourcePath) : ''\n const sourceKind: AgentDefinition['source']['kind'] = workspace\n ? 'workspace'\n : config.source.startsWith('dingtalk-doc:')\n ? 'dingtalk-doc'\n : gitRevision ? 'git-checkout' : 'local-folder'\n const id = cleanId(workspace?.id || (sourcePath ? basename(sourcePath) : config.source))\n return finalize({\n $schema: 'dingtalk-agent/agent-definition@1',\n id,\n source: { kind: sourceKind, uri: config.source, revision: gitRevision },\n body: bodyMount ? { path: bodyMount.path, hash: bodyMount.hash } : null,\n skills,\n storage: {\n memory: config.memory, knowledge: config.knowledge,\n artifacts: config.artifacts, state: config.state,\n },\n authority: {\n dwsProfile: config.dwsProfile,\n expectedUserId: config.expectedUserId,\n },\n configuration: config.origins,\n })\n}\n\n/**\n * Definition 与 Skill 一样按 Session 冻结。新 Run 只复制已验证的 Session 快照,\n * 因而在线修改 WORKSPACE.md、DWS profile 或启用 Skill 不会改变同一件事的身份。\n */\nexport function snapshotPreparedDefinition(\n runPath: string,\n sessionPath: string,\n workspace: WorkspaceSpec,\n mounts: MountSnapshot[],\n skillManifest: SkillManifest,\n): AgentDefinition {\n const sessionRoot = join(sessionPath, 'definition')\n const definitionPath = join(sessionRoot, 'definition.json')\n let definition: AgentDefinition\n if (existsSync(definitionPath)) {\n definition = verifyDefinition(sessionRoot)\n } else {\n mkdirSync(sessionRoot, { recursive: true })\n const profile = mounts.find((item) => item.slot === 'profile')\n let body: AgentDefinition['body'] = null\n if (profile?.snapshotPath) {\n const source = join(runPath, profile.snapshotPath)\n const destination = join(sessionRoot, 'body.md')\n copyFileSync(source, destination)\n const markdown = readFileSync(destination, 'utf8')\n body = { path: 'body.md', hash: digest(markdown) }\n }\n definition = finalize({\n $schema: 'dingtalk-agent/agent-definition@1',\n id: cleanId(workspace.id),\n source: {\n kind: 'workspace', uri: `workspace:${workspace.id}`,\n revision: digest(stableStringify(workspace)),\n },\n body,\n skills: skillManifest.entries.map((entry) => ({\n name: entry.name, version: entry.version, source: entry.sourcePath,\n path: entry.snapshotPath, hash: entry.hash,\n })),\n storage: {\n memory: workspace.mounts.memory,\n knowledge: workspace.mounts.knowledge,\n artifacts: 'session:artifacts',\n state: 'session:control-state',\n },\n authority: {\n dwsProfile: workspace.dws.profile,\n expectedUserId: workspace.dws.expectedUserId,\n },\n configuration: {\n agent: 'workspace', skills: 'workspace', memory: 'workspace',\n knowledge: 'workspace', artifacts: 'convention', state: 'convention',\n dwsProfile: 'workspace', expectedUserId: 'workspace',\n },\n })\n writeAtomic(definitionPath, JSON.stringify(definition, null, 2) + '\\n')\n }\n\n const destination = join(runPath, 'context', 'agent-definition')\n rmSync(destination, { recursive: true, force: true })\n cpSync(sessionRoot, destination, { recursive: true })\n return definition\n}\n\nexport function verifyPreparedDefinition(runPath: string, expectedHash = ''): AgentDefinition {\n return verifyDefinition(join(runPath, 'context', 'agent-definition'), expectedHash)\n}\n\nfunction finalize(\n input: Omit<AgentDefinition, 'status' | 'missing' | 'hash'>,\n): AgentDefinition {\n const missing: string[] = []\n if (!input.body) missing.push('body')\n if (!input.skills.length) missing.push('skills')\n if (!input.storage.memory) missing.push('storage.memory')\n if (!input.storage.knowledge) missing.push('storage.knowledge')\n const unsigned = {\n ...input,\n status: missing.length ? 'partial' as const : 'ready' as const,\n missing,\n }\n return { ...unsigned, hash: digest(stableStringify(unsigned)) }\n}\n\nfunction verifyDefinition(root: string, expectedHash = ''): AgentDefinition {\n const path = join(root, 'definition.json')\n if (!existsSync(path)) throw new Error('Agent Definition snapshot 缺少 definition.json')\n const value = JSON.parse(readFileSync(path, 'utf8')) as AgentDefinition\n const { hash, ...unsigned } = value\n if (!hash || digest(stableStringify(unsigned)) !== hash || (expectedHash && hash !== expectedHash)) {\n throw new Error('Agent Definition snapshot hash 不一致')\n }\n if (value.body) {\n const rootPath = resolve(root)\n const bodyPath = resolve(rootPath, value.body.path)\n const rel = relative(rootPath, bodyPath)\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error('Agent Definition body 必须位于 snapshot 内')\n }\n const body = readFileSync(bodyPath, 'utf8')\n if (digest(body) !== value.body.hash) throw new Error('Agent Definition body 内容漂移')\n }\n return value\n}\n\nfunction readGitRevision(path: string): string {\n const run = spawnSync('git', ['-C', path, 'rev-parse', '--show-toplevel', 'HEAD'], {\n encoding: 'utf8', timeout: 2_000,\n })\n if (run.status !== 0) return ''\n const lines = String(run.stdout || '').trim().split(/\\r?\\n/)\n return lines.length >= 2 ? lines[1] : ''\n}\n\nfunction readSkillMetadata(path: string): { name: string; version: string } {\n if (!path || !existsSync(path)) return { name: '', version: '' }\n const text = readFileSync(path, 'utf8')\n const block = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---/)?.[1] || ''\n const scalar = (name: string) =>\n block.match(new RegExp(`^${name}:\\\\s*['\"]?([^'\"\\\\r\\\\n]+)['\"]?\\\\s*$`, 'm'))?.[1]?.trim() || ''\n const nestedVersion = block.match(\n /^metadata:\\s*\\r?\\n(?:[ \\t]+.*\\r?\\n)*?[ \\t]+version:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m,\n )?.[1]?.trim() || ''\n return { name: scalar('name'), version: nestedVersion || scalar('version') }\n}\n\nfunction writeAtomic(path: string, value: string): void {\n mkdirSync(dirname(path), { recursive: true })\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, value, { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction cleanId(value: string): string {\n return value.replace(/^[a-z-]+:/, '').replace(/[^a-zA-Z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'agent'\n}\n"]}