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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/README.en.md +167 -0
  3. package/README.md +101 -248
  4. package/dist/bin/dingtalk-agent.js +1255 -25
  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 +1385 -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 +711 -0
  15. package/dist/src/agent-enhance.js.map +1 -0
  16. package/dist/src/agent-platform.js +299 -0
  17. package/dist/src/agent-platform.js.map +1 -0
  18. package/dist/src/bootstrap.js +125 -17
  19. package/dist/src/bootstrap.js.map +1 -1
  20. package/dist/src/config.js +1 -7
  21. package/dist/src/config.js.map +1 -1
  22. package/dist/src/development-workspace.js +755 -0
  23. package/dist/src/development-workspace.js.map +1 -0
  24. package/dist/src/doctor.js +74 -15
  25. package/dist/src/doctor.js.map +1 -1
  26. package/dist/src/dws.js +145 -0
  27. package/dist/src/dws.js.map +1 -1
  28. package/dist/src/eval-evidence.js +193 -0
  29. package/dist/src/eval-evidence.js.map +1 -0
  30. package/dist/src/host-detect.js +146 -0
  31. package/dist/src/host-detect.js.map +1 -0
  32. package/dist/src/instruction-path.js +270 -0
  33. package/dist/src/instruction-path.js.map +1 -0
  34. package/dist/src/invocation.js +36 -0
  35. package/dist/src/invocation.js.map +1 -0
  36. package/dist/src/lab.js +679 -0
  37. package/dist/src/lab.js.map +1 -0
  38. package/dist/src/lease.js +100 -0
  39. package/dist/src/lease.js.map +1 -0
  40. package/dist/src/map.js +157 -0
  41. package/dist/src/map.js.map +1 -0
  42. package/dist/src/memory/candidates.js +451 -0
  43. package/dist/src/memory/candidates.js.map +1 -0
  44. package/dist/src/memory/completion-evidence.js +536 -0
  45. package/dist/src/memory/completion-evidence.js.map +1 -0
  46. package/dist/src/memory/operational.js +263 -0
  47. package/dist/src/memory/operational.js.map +1 -0
  48. package/dist/src/memory/remote-state.js +478 -0
  49. package/dist/src/memory/remote-state.js.map +1 -0
  50. package/dist/src/memory/task-checkpoints.js +204 -0
  51. package/dist/src/memory/task-checkpoints.js.map +1 -0
  52. package/dist/src/multica-deploy.js +1538 -0
  53. package/dist/src/multica-deploy.js.map +1 -0
  54. package/dist/src/multica-provider.js +685 -0
  55. package/dist/src/multica-provider.js.map +1 -0
  56. package/dist/src/opencode-evals.js +1547 -0
  57. package/dist/src/opencode-evals.js.map +1 -0
  58. package/dist/src/opencode-isolation.js +124 -0
  59. package/dist/src/opencode-isolation.js.map +1 -0
  60. package/dist/src/opencode-provider.js +532 -0
  61. package/dist/src/opencode-provider.js.map +1 -0
  62. package/dist/src/opencode-workspace.js +208 -0
  63. package/dist/src/opencode-workspace.js.map +1 -0
  64. package/dist/src/perception.js +225 -0
  65. package/dist/src/perception.js.map +1 -0
  66. package/dist/src/personal-event-evals.js +595 -0
  67. package/dist/src/personal-event-evals.js.map +1 -0
  68. package/dist/src/promotion.js +786 -0
  69. package/dist/src/promotion.js.map +1 -0
  70. package/dist/src/remote-semantic-state-live-evals.js +888 -0
  71. package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
  72. package/dist/src/remote-semantic-state-worker.js +38 -0
  73. package/dist/src/remote-semantic-state-worker.js.map +1 -0
  74. package/dist/src/remote-state-evals.js +502 -0
  75. package/dist/src/remote-state-evals.js.map +1 -0
  76. package/dist/src/response-gate.js +51 -0
  77. package/dist/src/response-gate.js.map +1 -0
  78. package/dist/src/robot-evals.js +771 -0
  79. package/dist/src/robot-evals.js.map +1 -0
  80. package/dist/src/sessions.js +66 -105
  81. package/dist/src/sessions.js.map +1 -1
  82. package/dist/src/setup.js +6 -5
  83. package/dist/src/setup.js.map +1 -1
  84. package/dist/src/skill-manager.js +162 -24
  85. package/dist/src/skill-manager.js.map +1 -1
  86. package/dist/src/skills.js +2 -1
  87. package/dist/src/skills.js.map +1 -1
  88. package/dist/src/storage-evals.js +26 -0
  89. package/dist/src/storage-evals.js.map +1 -0
  90. package/dist/src/types.js.map +1 -1
  91. package/dist/src/upgrade.js +23 -27
  92. package/dist/src/upgrade.js.map +1 -1
  93. package/dist/src/version.js +73 -0
  94. package/dist/src/version.js.map +1 -0
  95. package/dist/src/waits.js +5 -1
  96. package/dist/src/waits.js.map +1 -1
  97. package/dist/src/workspace.js +28 -3
  98. package/dist/src/workspace.js.map +1 -1
  99. package/docs/INSTALLATION.md +50 -3
  100. package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
  101. package/docs/architecture/agent-memory-topology.png +0 -0
  102. package/docs/architecture/agent-memory-topology.svg +132 -0
  103. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  104. package/docs/architecture/general-agent-kernel-topology.svg +149 -0
  105. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  106. package/docs/architecture/provider-bound-development-workspace.svg +141 -0
  107. package/docs/architecture/task-completion-gate.png +0 -0
  108. package/docs/architecture/task-completion-gate.svg +191 -0
  109. package/docs/assets/agent-delivery-lifecycle.svg +103 -0
  110. package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
  111. package/docs/schemas/agent-audit.schema.json +92 -0
  112. package/docs/schemas/agent-bindings.schema.json +54 -0
  113. package/docs/schemas/agent-definition.schema.json +78 -0
  114. package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
  115. package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
  116. package/docs/schemas/agent-platform.schema.json +13 -0
  117. package/docs/schemas/enriched-invocation.schema.json +46 -0
  118. package/docs/schemas/eval-candidate-plan.schema.json +28 -0
  119. package/docs/schemas/eval-candidate-result.schema.json +20 -0
  120. package/docs/schemas/eval-candidate.schema.json +30 -0
  121. package/docs/schemas/invocation.schema.json +19 -0
  122. package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
  123. package/docs/schemas/memory-candidate.schema.json +76 -0
  124. package/docs/schemas/memory-publish-target.schema.json +25 -0
  125. package/docs/schemas/multica-deployment-list.schema.json +29 -0
  126. package/docs/schemas/multica-deployment-operation.schema.json +51 -0
  127. package/docs/schemas/multica-deployment-plan.schema.json +70 -0
  128. package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
  129. package/docs/schemas/multica-deployment-status.schema.json +23 -0
  130. package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
  131. package/docs/schemas/multica-workspace-plan.schema.json +68 -0
  132. package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
  133. package/docs/schemas/multica-workspace-status.schema.json +34 -0
  134. package/docs/schemas/observation.schema.json +21 -0
  135. package/docs/schemas/operational-memory-provider.schema.json +36 -0
  136. package/docs/schemas/operational-memory-record.schema.json +24 -0
  137. package/docs/schemas/perception-input.schema.json +56 -0
  138. package/docs/schemas/project.schema.json +115 -0
  139. package/docs/schemas/promotion-list.schema.json +36 -0
  140. package/docs/schemas/promotion-plan.schema.json +60 -0
  141. package/docs/schemas/promotion-policy.schema.json +29 -0
  142. package/docs/schemas/promotion-receipt.schema.json +43 -0
  143. package/docs/schemas/promotion-status.schema.json +23 -0
  144. package/docs/schemas/release-readiness.schema.json +66 -0
  145. package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
  146. package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
  147. package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
  148. package/docs/schemas/response-gate.schema.json +20 -0
  149. package/docs/schemas/task-checkpoint.schema.json +71 -0
  150. package/docs/schemas/task-completion-evidence.schema.json +154 -0
  151. package/docs/schemas/workspace-doctor.schema.json +56 -0
  152. package/docs/schemas/workspace-state.schema.json +39 -0
  153. package/evals/README.md +17 -0
  154. package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
  155. package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
  156. package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
  157. package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
  158. package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
  159. package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
  160. package/examples/agents/fde-coach/AGENTS.md +26 -0
  161. package/examples/agents/fde-coach/MEMORY.md +3 -0
  162. package/examples/agents/fde-coach/fields/default/field.json +24 -0
  163. package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
  164. package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
  165. package/examples/agents/release-manager/AGENTS.md +26 -0
  166. package/examples/agents/release-manager/MEMORY.md +3 -0
  167. package/examples/agents/release-manager/fields/default/field.json +24 -0
  168. package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
  169. package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
  170. package/lab/README.md +109 -0
  171. package/lab/agent-eval/catalog.json +91 -0
  172. package/lab/agent-eval/classic-failures.json +177 -0
  173. package/lab/agent-eval/completion-gate-regression.json +99 -0
  174. package/lab/agent-eval/personal-event-live.example.json +94 -0
  175. package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
  176. package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
  177. package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
  178. package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
  179. package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
  180. package/lab/agent-eval/remote-state.example.json +31 -0
  181. package/lab/agent-eval/workspace/AGENTS.md +7 -0
  182. package/lab/agent-eval/workspace/MEMORY.md +4 -0
  183. package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
  184. package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
  185. package/lab/agent-eval/workspace/opencode.json +20 -0
  186. package/lab/manifest.example.json +27 -0
  187. package/lab/manifest.personal-event.example.json +27 -0
  188. package/lab/project-workspace/README.md +11 -0
  189. package/lab/project-workspace/fake-multica-provider.mjs +277 -0
  190. package/lab/project-workspace/multica-deploy.fixture.json +29 -0
  191. package/lab/project-workspace/multica-readonly.fixture.json +69 -0
  192. package/lab/project-workspace/observation.fixture.json +14 -0
  193. package/lab/project-workspace/opencode-provider-suite.json +65 -0
  194. package/lab/project-workspace/project.fixture.json +44 -0
  195. package/lab/project-workspace/promotion-policy.fixture.json +15 -0
  196. package/lab/robot-eval/pool.example.json +30 -0
  197. package/lab/robot-eval/suite.json +123 -0
  198. package/lab/robot-eval/workspace/AGENTS.md +21 -0
  199. package/lab/robot-eval/workspace/MEMORY.md +3 -0
  200. package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
  201. package/lab/robot-eval/workspace/opencode.json +22 -0
  202. package/lab/schemas/agent-eval-catalog.schema.json +47 -0
  203. package/lab/schemas/lab-manifest.schema.json +70 -0
  204. package/lab/schemas/personal-event-eval.schema.json +91 -0
  205. package/lab/schemas/remote-state-eval.schema.json +66 -0
  206. package/lab/schemas/robot-eval-suite.schema.json +184 -0
  207. package/lab/schemas/robot-pool.schema.json +56 -0
  208. package/package.json +28 -9
  209. package/skills/README.md +23 -0
  210. package/skills/core/dingtalk-agent-compose/SKILL.md +151 -0
  211. package/skills/core/dingtalk-agent-compose/assets/AGENTS.template.md +35 -0
  212. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
  213. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
  214. package/skills/core/dingtalk-agent-compose/assets/hosts/opencode/opencode.template.json +12 -0
  215. package/skills/core/dingtalk-agent-compose/assets/role-skill.template.md +32 -0
  216. package/skills/core/dingtalk-agent-compose/evals/evals.json +129 -0
  217. package/skills/core/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
  218. package/skills/core/dingtalk-agent-compose/references/host-loading-contract.md +58 -0
  219. package/skills/core/dingtalk-agent-compose/references/hosts/claude-code.md +48 -0
  220. package/skills/core/dingtalk-agent-compose/references/hosts/opencode.md +77 -0
  221. package/skills/core/dingtalk-agent-compose/references/storage-routing.md +20 -0
  222. package/skills/core/dingtalk-agent-eval/SKILL.md +140 -0
  223. package/skills/core/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
  224. package/skills/core/dingtalk-agent-eval/evals/evals.json +83 -0
  225. package/skills/core/dingtalk-agent-eval/references/eval-topology.md +48 -0
  226. package/skills/core/dingtalk-agent-eval/references/evidence-contract.md +52 -0
  227. package/skills/core/dingtalk-agent-eval/references/failure-to-case.md +35 -0
  228. package/skills/core/dingtalk-agent-eval/references/interactive-debug-channels.md +93 -0
  229. package/skills/core/dingtalk-agent-eval/references/local-connector-smoke.md +75 -0
  230. package/skills/core/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
  231. package/skills/core/dingtalk-agent-eval/references/storage-modes.md +75 -0
  232. package/skills/core/dingtalk-basic-behavior/SKILL.md +87 -0
  233. package/skills/core/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
  234. package/skills/{dingtalk-basic-behavior/assets/task-checkpoint.md → core/dingtalk-basic-behavior/assets/task-checkpoint.json} +2 -21
  235. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/action-contract.md +2 -0
  236. package/skills/core/dingtalk-basic-behavior/references/memory-and-evolution.md +53 -0
  237. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
  238. package/skills/core/dingtalk-basic-behavior/references/risk-authority-and-privacy.md +62 -0
  239. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/task-lifecycle.md +47 -10
  240. package/skills/core/dingtalk-basic-behavior/references/truth-and-recovery.md +65 -0
  241. package/skills/platforms/deap/PLATFORM.md +3 -0
  242. package/skills/platforms/deap/README.md +3 -0
  243. package/skills/platforms/multica-dingtalk/PLATFORM.md +40 -0
  244. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +40 -0
  245. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/SKILL.md +60 -0
  246. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +49 -0
  247. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/promotion-observation-contract.md +49 -0
  248. package/skills/platforms/multica-dingtalk/multica-external/SKILL.md +282 -0
  249. package/skills/platforms/multica-dingtalk/multica-external/scripts/bootstrap.sh +78 -0
  250. package/skills/platforms/multica-dingtalk/multica-external/scripts/multica_ext.py +1180 -0
  251. package/skills/dingtalk-basic-behavior/SKILL.md +0 -86
  252. package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +0 -27
  253. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/event-to-behavior.md +0 -0
  254. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/runtime-modes.md +0 -0
@@ -1,32 +1,88 @@
1
1
  // Skill 安装生命周期由开放生态的 `npx skills` 负责。
2
2
  // dingtalk-agent 只做两件事:把内置 Skill 目录交给上游 CLI;只读验证客户端能否发现。
3
- import { existsSync, lstatSync, readFileSync, readlinkSync } from 'node:fs';
3
+ // 默认(不指定 name)对全部内置 Skill 生效:基础行为 + Agent 装配 + 交付后评测;指定 name 时只操作该 Skill。
4
+ import { existsSync, lstatSync, readdirSync, readFileSync, readlinkSync } from 'node:fs';
4
5
  import { homedir } from 'node:os';
5
6
  import { dirname, join, resolve } from 'node:path';
6
7
  import { spawnSync } from 'node:child_process';
8
+ import { createHash } from 'node:crypto';
9
+ import { cleanVersion, compareVersions, isValidVersion } from './version.js';
7
10
  export const GLOBAL_SKILL_NAME = 'dingtalk-basic-behavior';
11
+ // 默认套装:所有机器都装的通用 Skill。平台 Skill(deploy/boot-multica 等)不在默认套装内,
12
+ // 只有工作区通过 `dta agent-platform use` 选择对应 managed agent platform 时才按名安装。
13
+ export const BUNDLED_SKILL_NAMES = [
14
+ GLOBAL_SKILL_NAME, 'dingtalk-agent-compose', 'dingtalk-agent-eval',
15
+ ];
16
+ export const INSTALLABLE_SKILL_NAMES = [
17
+ ...BUNDLED_SKILL_NAMES,
18
+ 'dingtalk-agent-deploy-multica', 'dingtalk-agent-boot-multica', 'multica-external',
19
+ ];
20
+ // 仓库/包内的 Skill 源码路径注册表:core 为通用套装,platforms/<platform> 按平台装填。
21
+ // 安装后的 canonical 布局仍是扁平的 ~/.agents/skills/<name>;分层只存在于包内。
22
+ const BUNDLED_SKILL_DIRS = {
23
+ 'dingtalk-basic-behavior': 'skills/core/dingtalk-basic-behavior',
24
+ 'dingtalk-agent-compose': 'skills/core/dingtalk-agent-compose',
25
+ 'dingtalk-agent-eval': 'skills/core/dingtalk-agent-eval',
26
+ 'dingtalk-agent-deploy-multica': 'skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica',
27
+ 'dingtalk-agent-boot-multica': 'skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica',
28
+ 'multica-external': 'skills/platforms/multica-dingtalk/multica-external',
29
+ };
30
+ /** 解析包内 Skill 源码目录;未注册的名字回退到历史扁平布局。 */
31
+ export function bundledSkillPath(packageRoot, name) {
32
+ return join(packageRoot, BUNDLED_SKILL_DIRS[name] || join('skills', name));
33
+ }
8
34
  const SKILLS_PACKAGE = 'skills@latest';
9
35
  const REGISTRY = 'https://registry.npmjs.org';
10
36
  const AGENTS = ['claude-code', 'codex', 'opencode'];
37
+ export function skillSuiteStatus(packageRoot, options = {}) {
38
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => skillStatus(packageRoot, { ...options, name })));
39
+ }
40
+ export function installBundledSkills(packageRoot, options = {}) {
41
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => installGlobalSkill(packageRoot, { ...options, name })));
42
+ }
43
+ export function upgradeBundledSkills(packageRoot, options = {}) {
44
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => upgradeGlobalSkill(packageRoot, { ...options, name })));
45
+ }
46
+ export function uninstallBundledSkills(packageRoot, options = {}) {
47
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => uninstallGlobalSkill(packageRoot, { ...options, name })));
48
+ }
49
+ function suiteOf(skills) {
50
+ return {
51
+ $schema: 'dingtalk-agent/skill-status-suite@1',
52
+ manager: 'skills-cli',
53
+ names: skills.map((skill) => skill.name),
54
+ skills,
55
+ };
56
+ }
11
57
  export function skillStatus(packageRoot, options = {}) {
12
- const paths = globalPaths(packageRoot, options.home);
13
- const bundled = bundledInfo(packageRoot);
58
+ const name = bundledSkillName(options.name);
59
+ const paths = globalPaths(packageRoot, options.home, name);
60
+ const bundled = bundledInfo(packageRoot, name);
14
61
  const canonicalExists = isDirectory(paths.canonical);
15
- const installedVersion = canonicalExists
16
- ? parseSkillFrontmatter(readFileSync(join(paths.canonical, 'SKILL.md'), 'utf8')).version
17
- : '';
62
+ const installedVersion = canonicalExists ? readInstalledVersion(paths.canonical) : '';
63
+ const installedHash = canonicalExists ? skillContentHash(paths.canonical) : '';
64
+ const drift = driftOf({
65
+ exists: canonicalExists,
66
+ installedVersion,
67
+ installedHash,
68
+ bundledVersion: bundled.skillVersion,
69
+ bundledHash: bundled.contentHash,
70
+ });
18
71
  const claude = inspectExposure(paths.claude, paths.canonical);
19
72
  const sharedState = canonicalExists ? 'ok' : 'missing';
20
73
  return {
21
74
  $schema: 'dingtalk-agent/skill-status@2',
22
- name: GLOBAL_SKILL_NAME,
75
+ name,
23
76
  manager: 'skills-cli',
24
77
  bundled,
25
78
  canonical: {
26
79
  path: paths.canonical,
27
80
  exists: canonicalExists,
28
81
  installedVersion,
29
- current: Boolean(canonicalExists && installedVersion === bundled.skillVersion),
82
+ installedHash,
83
+ state: drift.state,
84
+ comparison: drift.comparison,
85
+ current: drift.state === 'current',
30
86
  },
31
87
  claude: { path: paths.claude, ...claude },
32
88
  clients: [
@@ -47,20 +103,20 @@ export function skillStatus(packageRoot, options = {}) {
47
103
  }
48
104
  export function installGlobalSkill(packageRoot, options = {}) {
49
105
  return runSkills(packageRoot, 'install', [
50
- 'add', globalPaths(packageRoot).source,
106
+ 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,
51
107
  '--global', '--yes', '--agent', ...AGENTS,
52
108
  ], options);
53
109
  }
54
110
  export function upgradeGlobalSkill(packageRoot, options = {}) {
55
111
  // Skill 随 npm 包发布;重新 add 当前包内目录,让 skills CLI 执行自己的覆盖/链接语义。
56
112
  return runSkills(packageRoot, 'upgrade', [
57
- 'add', globalPaths(packageRoot).source,
113
+ 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,
58
114
  '--global', '--yes', '--agent', ...AGENTS,
59
115
  ], options);
60
116
  }
61
117
  export function uninstallGlobalSkill(packageRoot, options = {}) {
62
118
  return runSkills(packageRoot, 'uninstall', [
63
- 'remove', GLOBAL_SKILL_NAME,
119
+ 'remove', bundledSkillName(options.name),
64
120
  '--global', '--yes', '--agent', ...AGENTS,
65
121
  ], options);
66
122
  }
@@ -70,12 +126,21 @@ function runSkills(packageRoot, action, args, options) {
70
126
  ];
71
127
  const command = ['npx', ...commandArgs].map(shellQuote).join(' ');
72
128
  const before = skillStatus(packageRoot, options);
129
+ const beforeState = { installedVersion: before.canonical.installedVersion, state: before.canonical.state };
73
130
  if (options.dryRun) {
74
131
  return {
75
132
  ...before,
76
- operation: { action, command, executed: false, exitCode: null, output: '' },
133
+ operation: {
134
+ action, command, executed: false, exitCode: null, output: '',
135
+ before: beforeState, after: null,
136
+ },
77
137
  };
78
138
  }
139
+ // 本机比包内新时覆盖就是降级;与 npm 包升级策略一致,默认拒绝。
140
+ if (action !== 'uninstall' && before.canonical.state === 'ahead' && !options.allowDowngrade) {
141
+ throw new Error(`拒绝降级 ${before.name}: 本机 ${before.canonical.installedVersion} 高于包内 ` +
142
+ `${before.bundled.skillVersion};确认要覆盖时加 --allow-downgrade`);
143
+ }
79
144
  const env = {
80
145
  ...process.env,
81
146
  ...(options.env || {}),
@@ -92,27 +157,89 @@ function runSkills(packageRoot, action, args, options) {
92
157
  throw new Error(`skills CLI ${action} 失败: ${reason}\n` +
93
158
  `可手动执行: ${command}`);
94
159
  }
160
+ // 退出码 0 不等于本机副本已经是目标版本;升级/安装后必须回读确认。
161
+ const after = skillStatus(packageRoot, options);
162
+ if (action !== 'uninstall' && after.canonical.state !== 'current') {
163
+ throw new Error(`skills CLI ${action} 退出码为 0,但回读 ${after.name} 仍为 ${after.canonical.state}` +
164
+ `(本机 ${after.canonical.installedVersion || '未声明'} / 包内 ${after.bundled.skillVersion})\n` +
165
+ `可手动执行: ${command}`);
166
+ }
95
167
  return {
96
- ...skillStatus(packageRoot, options),
97
- operation: { action, command, executed: true, exitCode: run.status, output },
168
+ ...after,
169
+ operation: {
170
+ action, command, executed: true, exitCode: run.status, output,
171
+ before: beforeState,
172
+ after: { installedVersion: after.canonical.installedVersion, state: after.canonical.state },
173
+ },
98
174
  };
99
175
  }
100
- function globalPaths(packageRoot, home = homedir()) {
176
+ function globalPaths(packageRoot, home = homedir(), name = GLOBAL_SKILL_NAME) {
101
177
  return {
102
- source: join(packageRoot, 'skills', GLOBAL_SKILL_NAME),
103
- canonical: join(home, '.agents', 'skills', GLOBAL_SKILL_NAME),
104
- claude: join(home, '.claude', 'skills', GLOBAL_SKILL_NAME),
178
+ source: bundledSkillPath(packageRoot, name),
179
+ canonical: join(home, '.agents', 'skills', name),
180
+ claude: join(home, '.claude', 'skills', name),
105
181
  };
106
182
  }
107
- function bundledInfo(packageRoot) {
108
- const source = globalPaths(packageRoot).source;
109
- validateSkill(source);
183
+ function bundledInfo(packageRoot, name) {
184
+ const source = globalPaths(packageRoot, undefined, name).source;
185
+ validateSkill(source, name);
110
186
  const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
111
187
  const frontmatter = parseSkillFrontmatter(readFileSync(join(source, 'SKILL.md'), 'utf8'));
112
188
  return {
113
189
  path: source,
114
190
  packageVersion: String(pkg.version || ''),
115
191
  skillVersion: frontmatter.version,
192
+ contentHash: skillContentHash(source),
193
+ };
194
+ }
195
+ /** 本机副本的版本号;用户手改坏格式时返回空串并由调用方降级为 unknown,不抛错。 */
196
+ function readInstalledVersion(canonical) {
197
+ try {
198
+ return parseSkillFrontmatter(readFileSync(join(canonical, 'SKILL.md'), 'utf8')).version;
199
+ }
200
+ catch {
201
+ return '';
202
+ }
203
+ }
204
+ /**
205
+ * 全树内容 hash:按相对路径排序,逐个 update(相对路径 + \0 + 内容)。
206
+ * 它证明 references/assets 完整一致,补上"改了正文但没 bump 版本"这类版本号测不出的漂移。
207
+ */
208
+ export function skillContentHash(root) {
209
+ const hash = createHash('sha256');
210
+ for (const relative of listSkillFiles(root)) {
211
+ hash.update(relative);
212
+ hash.update('\0');
213
+ hash.update(readFileSync(join(root, relative)));
214
+ }
215
+ return `sha256:${hash.digest('hex').slice(0, 16)}`;
216
+ }
217
+ function listSkillFiles(root, prefix = '') {
218
+ const files = [];
219
+ for (const entry of readdirSync(join(root, prefix), { withFileTypes: true })) {
220
+ if (entry.name === '.DS_Store' || entry.isSymbolicLink())
221
+ continue;
222
+ const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
223
+ if (entry.isDirectory())
224
+ files.push(...listSkillFiles(root, relative));
225
+ else if (entry.isFile())
226
+ files.push(relative);
227
+ }
228
+ return files.sort();
229
+ }
230
+ function driftOf(input) {
231
+ if (!input.exists)
232
+ return { state: 'missing', comparison: null };
233
+ if (!isValidVersion(input.installedVersion))
234
+ return { state: 'unknown', comparison: null };
235
+ const comparison = compareVersions(input.installedVersion, input.bundledVersion);
236
+ if (comparison > 0)
237
+ return { state: 'ahead', comparison };
238
+ if (comparison < 0)
239
+ return { state: 'outdated', comparison };
240
+ return {
241
+ state: input.installedHash === input.bundledHash ? 'current' : 'modified',
242
+ comparison,
116
243
  };
117
244
  }
118
245
  function inspectExposure(exposure, canonical) {
@@ -126,18 +253,29 @@ function inspectExposure(exposure, canonical) {
126
253
  ? { state: 'ok', target: raw }
127
254
  : { state: 'conflict', target: raw };
128
255
  }
129
- function validateSkill(root) {
256
+ function validateSkill(root, name) {
130
257
  if (!isDirectory(root))
131
258
  throw new Error(`内置 Skill 不存在: ${root}`);
132
259
  const file = join(root, 'SKILL.md');
133
260
  if (!existsSync(file))
134
261
  throw new Error(`Skill 缺少 SKILL.md: ${root}`);
135
262
  const metadata = parseSkillFrontmatter(readFileSync(file, 'utf8'));
136
- if (metadata.name !== GLOBAL_SKILL_NAME) {
137
- throw new Error(`Skill name=${metadata.name} 与目录名 ${GLOBAL_SKILL_NAME} 不一致`);
263
+ if (metadata.name !== name) {
264
+ throw new Error(`Skill name=${metadata.name} 与目录名 ${name} 不一致`);
138
265
  }
139
266
  if (!metadata.description)
140
267
  throw new Error('Skill frontmatter 缺少 description');
268
+ // 包内 Skill 缺版本号是仓库缺陷:没有版本就无法判断本机副本是否过期,直接 fail closed。
269
+ if (!metadata.version)
270
+ throw new Error(`Skill 缺少 metadata.version: ${root}`);
271
+ cleanVersion(metadata.version);
272
+ }
273
+ function bundledSkillName(value = '') {
274
+ const name = value.trim() || GLOBAL_SKILL_NAME;
275
+ if (!INSTALLABLE_SKILL_NAMES.includes(name)) {
276
+ throw new Error(`不支持的内置 Skill: ${name};可用: ${INSTALLABLE_SKILL_NAMES.join(', ')}`);
277
+ }
278
+ return name;
141
279
  }
142
280
  function parseSkillFrontmatter(text) {
143
281
  const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manager.js","sourceRoot":"","sources":["../../src/skill-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Skill 安装生命周期由开放生态的 `npx skills` 负责。\n// dingtalk-agent 只做两件事:把内置 Skill 目录交给上游 CLI;只读验证客户端能否发现。\n\nimport { existsSync, lstatSync, readFileSync, readlinkSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\n\nexport const GLOBAL_SKILL_NAME = 'dingtalk-basic-behavior'\nconst SKILLS_PACKAGE = 'skills@latest'\nconst REGISTRY = 'https://registry.npmjs.org'\nconst AGENTS = ['claude-code', 'codex', 'opencode']\n\nexport interface SkillManagerOptions {\n home?: string\n dryRun?: boolean\n env?: NodeJS.ProcessEnv\n}\n\nexport interface GlobalSkillStatus {\n $schema: 'dingtalk-agent/skill-status@2'\n name: string\n manager: 'skills-cli'\n bundled: { path: string; packageVersion: string; skillVersion: string }\n canonical: {\n path: string\n exists: boolean\n installedVersion: string\n current: boolean\n }\n claude: { path: string; state: 'ok' | 'missing' | 'conflict'; target: string }\n clients: Array<{\n name: 'claude-code' | 'codex' | 'opencode'\n label: string\n discovery: 'symlink' | 'shared-agent-skills'\n path: string\n state: 'ok' | 'missing' | 'conflict'\n }>\n operation?: {\n action: 'install' | 'upgrade' | 'uninstall'\n command: string\n executed: boolean\n exitCode: number | null\n output: string\n }\n}\n\nexport function skillStatus(packageRoot: string, options: SkillManagerOptions = {}): GlobalSkillStatus {\n const paths = globalPaths(packageRoot, options.home)\n const bundled = bundledInfo(packageRoot)\n const canonicalExists = isDirectory(paths.canonical)\n const installedVersion = canonicalExists\n ? parseSkillFrontmatter(readFileSync(join(paths.canonical, 'SKILL.md'), 'utf8')).version\n : ''\n const claude = inspectExposure(paths.claude, paths.canonical)\n const sharedState = canonicalExists ? 'ok' : 'missing'\n return {\n $schema: 'dingtalk-agent/skill-status@2',\n name: GLOBAL_SKILL_NAME,\n manager: 'skills-cli',\n bundled,\n canonical: {\n path: paths.canonical,\n exists: canonicalExists,\n installedVersion,\n current: Boolean(canonicalExists && installedVersion === bundled.skillVersion),\n },\n claude: { path: paths.claude, ...claude },\n clients: [\n {\n name: 'claude-code', label: 'Claude Code', discovery: 'symlink',\n path: paths.claude, state: claude.state,\n },\n {\n name: 'codex', label: 'Codex', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n {\n name: 'opencode', label: 'OpenCode', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n ],\n }\n}\n\nexport function installGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'install', [\n 'add', globalPaths(packageRoot).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function upgradeGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n // Skill 随 npm 包发布;重新 add 当前包内目录,让 skills CLI 执行自己的覆盖/链接语义。\n return runSkills(packageRoot, 'upgrade', [\n 'add', globalPaths(packageRoot).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function uninstallGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'uninstall', [\n 'remove', GLOBAL_SKILL_NAME,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nfunction runSkills(\n packageRoot: string,\n action: 'install' | 'upgrade' | 'uninstall',\n args: string[],\n options: SkillManagerOptions,\n): GlobalSkillStatus {\n const commandArgs = [\n '--yes', `--registry=${REGISTRY}`, `--package=${SKILLS_PACKAGE}`, '--', 'skills', ...args,\n ]\n const command = ['npx', ...commandArgs].map(shellQuote).join(' ')\n const before = skillStatus(packageRoot, options)\n if (options.dryRun) {\n return {\n ...before,\n operation: { action, command, executed: false, exitCode: null, output: '' },\n }\n }\n\n const env = {\n ...process.env,\n ...(options.env || {}),\n HOME: options.home || options.env?.HOME || process.env.HOME || homedir(),\n }\n const run = spawnSync('npx', commandArgs, {\n encoding: 'utf8', env, timeout: 120_000,\n })\n const output = [run.stdout, run.stderr].filter(Boolean).join('\\n').trim()\n if (run.error || run.status !== 0) {\n const reason = (run.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT'\n ? 'PATH 找不到 npx;请安装带 npm/npx 的 Node.js 18.3+'\n : run.error?.message || output || `退出码 ${run.status}`\n throw new Error(\n `skills CLI ${action} 失败: ${reason}\\n` +\n `可手动执行: ${command}`,\n )\n }\n return {\n ...skillStatus(packageRoot, options),\n operation: { action, command, executed: true, exitCode: run.status, output },\n }\n}\n\nfunction globalPaths(packageRoot: string, home = homedir()) {\n return {\n source: join(packageRoot, 'skills', GLOBAL_SKILL_NAME),\n canonical: join(home, '.agents', 'skills', GLOBAL_SKILL_NAME),\n claude: join(home, '.claude', 'skills', GLOBAL_SKILL_NAME),\n }\n}\n\nfunction bundledInfo(packageRoot: string) {\n const source = globalPaths(packageRoot).source\n validateSkill(source)\n const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))\n const frontmatter = parseSkillFrontmatter(readFileSync(join(source, 'SKILL.md'), 'utf8'))\n return {\n path: source,\n packageVersion: String(pkg.version || ''),\n skillVersion: frontmatter.version,\n }\n}\n\nfunction inspectExposure(exposure: string, canonical: string): {\n state: 'ok' | 'missing' | 'conflict'\n target: string\n} {\n if (!pathExists(exposure)) return { state: 'missing', target: '' }\n const stat = lstatSync(exposure)\n if (!stat.isSymbolicLink()) return { state: 'conflict', target: '' }\n const raw = readlinkSync(exposure)\n return resolve(dirname(exposure), raw) === resolve(canonical)\n ? { state: 'ok', target: raw }\n : { state: 'conflict', target: raw }\n}\n\nfunction validateSkill(root: string): void {\n if (!isDirectory(root)) throw new Error(`内置 Skill 不存在: ${root}`)\n const file = join(root, 'SKILL.md')\n if (!existsSync(file)) throw new Error(`Skill 缺少 SKILL.md: ${root}`)\n const metadata = parseSkillFrontmatter(readFileSync(file, 'utf8'))\n if (metadata.name !== GLOBAL_SKILL_NAME) {\n throw new Error(`Skill name=${metadata.name} 与目录名 ${GLOBAL_SKILL_NAME} 不一致`)\n }\n if (!metadata.description) throw new Error('Skill frontmatter 缺少 description')\n}\n\nfunction parseSkillFrontmatter(text: string): { name: string; description: string; version: string } {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/)\n if (!match) throw new Error('SKILL.md 缺少 YAML frontmatter')\n const block = match[1]\n const readScalar = (key: string) => {\n const found = block.match(new RegExp(`^${key}:\\\\s*(.+)$`, 'm'))\n return found ? found[1].trim().replace(/^(['\"])(.*)\\1$/, '$2') : ''\n }\n const nestedVersion = block.match(/^metadata:\\s*\\r?\\n(?:[ \\t]+.*\\r?\\n)*?[ \\t]+version:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m)\n return {\n name: readScalar('name'),\n description: readScalar('description'),\n version: nestedVersion?.[1]?.trim() || readScalar('version'),\n }\n}\n\nfunction isDirectory(path: string): boolean {\n try { return lstatSync(path).isDirectory() } catch { return false }\n}\n\nfunction pathExists(path: string): boolean {\n try { lstatSync(path); return true } catch { return false }\n}\n\nfunction shellQuote(value: string): string {\n return /^[A-Za-z0-9_./:=@-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\"'\"'`)}'`\n}\n"]}
1
+ {"version":3,"file":"skill-manager.js","sourceRoot":"","sources":["../../src/skill-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Skill 安装生命周期由开放生态的 `npx skills` 负责。\n// dingtalk-agent 只做两件事:把内置 Skill 目录交给上游 CLI;只读验证客户端能否发现。\n// 默认(不指定 name)对全部内置 Skill 生效:基础行为 + Agent 装配 + 交付后评测;指定 name 时只操作该 Skill。\n\nimport { existsSync, lstatSync, readdirSync, readFileSync, readlinkSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { createHash } from 'node:crypto'\nimport { cleanVersion, compareVersions, isValidVersion } from './version.js'\n\nexport const GLOBAL_SKILL_NAME = 'dingtalk-basic-behavior'\n// 默认套装:所有机器都装的通用 Skill。平台 Skill(deploy/boot-multica 等)不在默认套装内,\n// 只有工作区通过 `dta agent-platform use` 选择对应 managed agent platform 时才按名安装。\nexport const BUNDLED_SKILL_NAMES = [\n GLOBAL_SKILL_NAME, 'dingtalk-agent-compose', 'dingtalk-agent-eval',\n] as const\nexport const INSTALLABLE_SKILL_NAMES = [\n ...BUNDLED_SKILL_NAMES,\n 'dingtalk-agent-deploy-multica', 'dingtalk-agent-boot-multica', 'multica-external',\n] as const\n\n// 仓库/包内的 Skill 源码路径注册表:core 为通用套装,platforms/<platform> 按平台装填。\n// 安装后的 canonical 布局仍是扁平的 ~/.agents/skills/<name>;分层只存在于包内。\nconst BUNDLED_SKILL_DIRS: Record<string, string> = {\n 'dingtalk-basic-behavior': 'skills/core/dingtalk-basic-behavior',\n 'dingtalk-agent-compose': 'skills/core/dingtalk-agent-compose',\n 'dingtalk-agent-eval': 'skills/core/dingtalk-agent-eval',\n 'dingtalk-agent-deploy-multica': 'skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica',\n 'dingtalk-agent-boot-multica': 'skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica',\n 'multica-external': 'skills/platforms/multica-dingtalk/multica-external',\n}\n\n/** 解析包内 Skill 源码目录;未注册的名字回退到历史扁平布局。 */\nexport function bundledSkillPath(packageRoot: string, name: string): string {\n return join(packageRoot, BUNDLED_SKILL_DIRS[name] || join('skills', name))\n}\nconst SKILLS_PACKAGE = 'skills@latest'\nconst REGISTRY = 'https://registry.npmjs.org'\nconst AGENTS = ['claude-code', 'codex', 'opencode']\n\nexport interface SkillManagerOptions {\n home?: string\n dryRun?: boolean\n env?: NodeJS.ProcessEnv\n name?: string\n allowDowngrade?: boolean\n}\n\n/**\n * 本机副本相对包内 Skill 的漂移状态。`current` 是它的派生布尔,保留给既有读者。\n * 版本相等但内容不同(用户手改过)必须与真正一致区分开,否则升级提示会漏掉这类漂移。\n */\nexport type SkillDriftState =\n | 'missing' // canonical 不存在\n | 'current' // 版本相等且内容 hash 相等\n | 'modified' // 版本相等但内容 hash 不等\n | 'outdated' // 已装版本低于包内版本\n | 'ahead' // 已装版本高于包内版本\n | 'unknown' // 已装版本缺失或非法\n\nexport interface GlobalSkillStatus {\n $schema: 'dingtalk-agent/skill-status@2'\n name: string\n manager: 'skills-cli'\n bundled: { path: string; packageVersion: string; skillVersion: string; contentHash: string }\n canonical: {\n path: string\n exists: boolean\n installedVersion: string\n installedHash: string\n state: SkillDriftState\n comparison: number | null\n current: boolean\n }\n claude: { path: string; state: 'ok' | 'missing' | 'conflict'; target: string }\n clients: Array<{\n name: 'claude-code' | 'codex' | 'opencode'\n label: string\n discovery: 'symlink' | 'shared-agent-skills'\n path: string\n state: 'ok' | 'missing' | 'conflict'\n }>\n operation?: {\n action: 'install' | 'upgrade' | 'uninstall'\n command: string\n executed: boolean\n exitCode: number | null\n output: string\n before: { installedVersion: string; state: SkillDriftState }\n after: { installedVersion: string; state: SkillDriftState } | null\n }\n}\n\nexport interface GlobalSkillSuiteStatus {\n $schema: 'dingtalk-agent/skill-status-suite@1'\n manager: 'skills-cli'\n names: string[]\n skills: GlobalSkillStatus[]\n}\n\nexport function skillSuiteStatus(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => skillStatus(packageRoot, { ...options, name })))\n}\n\nexport function installBundledSkills(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => installGlobalSkill(packageRoot, { ...options, name })))\n}\n\nexport function upgradeBundledSkills(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => upgradeGlobalSkill(packageRoot, { ...options, name })))\n}\n\nexport function uninstallBundledSkills(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => uninstallGlobalSkill(packageRoot, { ...options, name })))\n}\n\nfunction suiteOf(skills: GlobalSkillStatus[]): GlobalSkillSuiteStatus {\n return {\n $schema: 'dingtalk-agent/skill-status-suite@1',\n manager: 'skills-cli',\n names: skills.map((skill) => skill.name),\n skills,\n }\n}\n\nexport function skillStatus(packageRoot: string, options: SkillManagerOptions = {}): GlobalSkillStatus {\n const name = bundledSkillName(options.name)\n const paths = globalPaths(packageRoot, options.home, name)\n const bundled = bundledInfo(packageRoot, name)\n const canonicalExists = isDirectory(paths.canonical)\n const installedVersion = canonicalExists ? readInstalledVersion(paths.canonical) : ''\n const installedHash = canonicalExists ? skillContentHash(paths.canonical) : ''\n const drift = driftOf({\n exists: canonicalExists,\n installedVersion,\n installedHash,\n bundledVersion: bundled.skillVersion,\n bundledHash: bundled.contentHash,\n })\n const claude = inspectExposure(paths.claude, paths.canonical)\n const sharedState = canonicalExists ? 'ok' : 'missing'\n return {\n $schema: 'dingtalk-agent/skill-status@2',\n name,\n manager: 'skills-cli',\n bundled,\n canonical: {\n path: paths.canonical,\n exists: canonicalExists,\n installedVersion,\n installedHash,\n state: drift.state,\n comparison: drift.comparison,\n current: drift.state === 'current',\n },\n claude: { path: paths.claude, ...claude },\n clients: [\n {\n name: 'claude-code', label: 'Claude Code', discovery: 'symlink',\n path: paths.claude, state: claude.state,\n },\n {\n name: 'codex', label: 'Codex', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n {\n name: 'opencode', label: 'OpenCode', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n ],\n }\n}\n\nexport function installGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'install', [\n 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function upgradeGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n // Skill 随 npm 包发布;重新 add 当前包内目录,让 skills CLI 执行自己的覆盖/链接语义。\n return runSkills(packageRoot, 'upgrade', [\n 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function uninstallGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'uninstall', [\n 'remove', bundledSkillName(options.name),\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nfunction runSkills(\n packageRoot: string,\n action: 'install' | 'upgrade' | 'uninstall',\n args: string[],\n options: SkillManagerOptions,\n): GlobalSkillStatus {\n const commandArgs = [\n '--yes', `--registry=${REGISTRY}`, `--package=${SKILLS_PACKAGE}`, '--', 'skills', ...args,\n ]\n const command = ['npx', ...commandArgs].map(shellQuote).join(' ')\n const before = skillStatus(packageRoot, options)\n const beforeState = { installedVersion: before.canonical.installedVersion, state: before.canonical.state }\n if (options.dryRun) {\n return {\n ...before,\n operation: {\n action, command, executed: false, exitCode: null, output: '',\n before: beforeState, after: null,\n },\n }\n }\n // 本机比包内新时覆盖就是降级;与 npm 包升级策略一致,默认拒绝。\n if (action !== 'uninstall' && before.canonical.state === 'ahead' && !options.allowDowngrade) {\n throw new Error(\n `拒绝降级 ${before.name}: 本机 ${before.canonical.installedVersion} 高于包内 ` +\n `${before.bundled.skillVersion};确认要覆盖时加 --allow-downgrade`,\n )\n }\n\n const env = {\n ...process.env,\n ...(options.env || {}),\n HOME: options.home || options.env?.HOME || process.env.HOME || homedir(),\n }\n const run = spawnSync('npx', commandArgs, {\n encoding: 'utf8', env, timeout: 120_000,\n })\n const output = [run.stdout, run.stderr].filter(Boolean).join('\\n').trim()\n if (run.error || run.status !== 0) {\n const reason = (run.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT'\n ? 'PATH 找不到 npx;请安装带 npm/npx 的 Node.js 18.3+'\n : run.error?.message || output || `退出码 ${run.status}`\n throw new Error(\n `skills CLI ${action} 失败: ${reason}\\n` +\n `可手动执行: ${command}`,\n )\n }\n // 退出码 0 不等于本机副本已经是目标版本;升级/安装后必须回读确认。\n const after = skillStatus(packageRoot, options)\n if (action !== 'uninstall' && after.canonical.state !== 'current') {\n throw new Error(\n `skills CLI ${action} 退出码为 0,但回读 ${after.name} 仍为 ${after.canonical.state}` +\n `(本机 ${after.canonical.installedVersion || '未声明'} / 包内 ${after.bundled.skillVersion})\\n` +\n `可手动执行: ${command}`,\n )\n }\n return {\n ...after,\n operation: {\n action, command, executed: true, exitCode: run.status, output,\n before: beforeState,\n after: { installedVersion: after.canonical.installedVersion, state: after.canonical.state },\n },\n }\n}\n\nfunction globalPaths(packageRoot: string, home = homedir(), name = GLOBAL_SKILL_NAME) {\n return {\n source: bundledSkillPath(packageRoot, name),\n canonical: join(home, '.agents', 'skills', name),\n claude: join(home, '.claude', 'skills', name),\n }\n}\n\nfunction bundledInfo(packageRoot: string, name: string) {\n const source = globalPaths(packageRoot, undefined, name).source\n validateSkill(source, name)\n const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))\n const frontmatter = parseSkillFrontmatter(readFileSync(join(source, 'SKILL.md'), 'utf8'))\n return {\n path: source,\n packageVersion: String(pkg.version || ''),\n skillVersion: frontmatter.version,\n contentHash: skillContentHash(source),\n }\n}\n\n/** 本机副本的版本号;用户手改坏格式时返回空串并由调用方降级为 unknown,不抛错。 */\nfunction readInstalledVersion(canonical: string): string {\n try {\n return parseSkillFrontmatter(readFileSync(join(canonical, 'SKILL.md'), 'utf8')).version\n } catch {\n return ''\n }\n}\n\n/**\n * 全树内容 hash:按相对路径排序,逐个 update(相对路径 + \\0 + 内容)。\n * 它证明 references/assets 完整一致,补上\"改了正文但没 bump 版本\"这类版本号测不出的漂移。\n */\nexport function skillContentHash(root: string): string {\n const hash = createHash('sha256')\n for (const relative of listSkillFiles(root)) {\n hash.update(relative)\n hash.update('\\0')\n hash.update(readFileSync(join(root, relative)))\n }\n return `sha256:${hash.digest('hex').slice(0, 16)}`\n}\n\nfunction listSkillFiles(root: string, prefix = ''): string[] {\n const files: string[] = []\n for (const entry of readdirSync(join(root, prefix), { withFileTypes: true })) {\n if (entry.name === '.DS_Store' || entry.isSymbolicLink()) continue\n const relative = prefix ? `${prefix}/${entry.name}` : entry.name\n if (entry.isDirectory()) files.push(...listSkillFiles(root, relative))\n else if (entry.isFile()) files.push(relative)\n }\n return files.sort()\n}\n\nfunction driftOf(input: {\n exists: boolean\n installedVersion: string\n installedHash: string\n bundledVersion: string\n bundledHash: string\n}): { state: SkillDriftState; comparison: number | null } {\n if (!input.exists) return { state: 'missing', comparison: null }\n if (!isValidVersion(input.installedVersion)) return { state: 'unknown', comparison: null }\n const comparison = compareVersions(input.installedVersion, input.bundledVersion)\n if (comparison > 0) return { state: 'ahead', comparison }\n if (comparison < 0) return { state: 'outdated', comparison }\n return {\n state: input.installedHash === input.bundledHash ? 'current' : 'modified',\n comparison,\n }\n}\n\nfunction inspectExposure(exposure: string, canonical: string): {\n state: 'ok' | 'missing' | 'conflict'\n target: string\n} {\n if (!pathExists(exposure)) return { state: 'missing', target: '' }\n const stat = lstatSync(exposure)\n if (!stat.isSymbolicLink()) return { state: 'conflict', target: '' }\n const raw = readlinkSync(exposure)\n return resolve(dirname(exposure), raw) === resolve(canonical)\n ? { state: 'ok', target: raw }\n : { state: 'conflict', target: raw }\n}\n\nfunction validateSkill(root: string, name: string): void {\n if (!isDirectory(root)) throw new Error(`内置 Skill 不存在: ${root}`)\n const file = join(root, 'SKILL.md')\n if (!existsSync(file)) throw new Error(`Skill 缺少 SKILL.md: ${root}`)\n const metadata = parseSkillFrontmatter(readFileSync(file, 'utf8'))\n if (metadata.name !== name) {\n throw new Error(`Skill name=${metadata.name} 与目录名 ${name} 不一致`)\n }\n if (!metadata.description) throw new Error('Skill frontmatter 缺少 description')\n // 包内 Skill 缺版本号是仓库缺陷:没有版本就无法判断本机副本是否过期,直接 fail closed。\n if (!metadata.version) throw new Error(`Skill 缺少 metadata.version: ${root}`)\n cleanVersion(metadata.version)\n}\n\nfunction bundledSkillName(value = ''): string {\n const name = value.trim() || GLOBAL_SKILL_NAME\n if (!(INSTALLABLE_SKILL_NAMES as readonly string[]).includes(name)) {\n throw new Error(`不支持的内置 Skill: ${name};可用: ${INSTALLABLE_SKILL_NAMES.join(', ')}`)\n }\n return name\n}\n\nfunction parseSkillFrontmatter(text: string): { name: string; description: string; version: string } {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/)\n if (!match) throw new Error('SKILL.md 缺少 YAML frontmatter')\n const block = match[1]\n const readScalar = (key: string) => {\n const found = block.match(new RegExp(`^${key}:\\\\s*(.+)$`, 'm'))\n return found ? found[1].trim().replace(/^(['\"])(.*)\\1$/, '$2') : ''\n }\n const nestedVersion = block.match(/^metadata:\\s*\\r?\\n(?:[ \\t]+.*\\r?\\n)*?[ \\t]+version:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m)\n return {\n name: readScalar('name'),\n description: readScalar('description'),\n version: nestedVersion?.[1]?.trim() || readScalar('version'),\n }\n}\n\nfunction isDirectory(path: string): boolean {\n try { return lstatSync(path).isDirectory() } catch { return false }\n}\n\nfunction pathExists(path: string): boolean {\n try { lstatSync(path); return true } catch { return false }\n}\n\nfunction shellQuote(value: string): string {\n return /^[A-Za-z0-9_./:=@-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\"'\"'`)}'`\n}\n"]}
@@ -5,6 +5,7 @@ import { homedir } from 'node:os';
5
5
  import { basename, dirname, join, relative, resolve } from 'node:path';
6
6
  import { digest, stableStringify } from './events.js';
7
7
  import { resolvePackageRoot } from './package-root.js';
8
+ import { bundledSkillPath } from './skill-manager.js';
8
9
  const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
9
10
  const INSTALL_MARKER = '.dingtalk-agent-install.json';
10
11
  export function snapshotSkills(root, runPath, sources, sessionPath) {
@@ -163,7 +164,7 @@ function resolveSkillSource(rootReal, sourceSpec) {
163
164
  [`global:${spec}`, join(homedir(), '.agents', 'skills', spec)],
164
165
  [`claude:${spec}`, join(homedir(), '.claude', 'skills', spec)],
165
166
  [`legacy-codex:${spec}`, join(homedir(), '.codex', 'skills', spec)],
166
- [`bundled:${spec}`, join(PACKAGE_ROOT, 'skills', spec)],
167
+ [`bundled:${spec}`, bundledSkillPath(PACKAGE_ROOT, spec)],
167
168
  ];
168
169
  for (const [label, candidate] of candidates) {
169
170
  if (!existsSync(candidate) || !lstatSync(candidate).isDirectory())
@@ -1 +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"]}
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'\nimport { bundledSkillPath } from './skill-manager.js'\n\nconst PACKAGE_ROOT = resolvePackageRoot(import.meta.url)\nconst INSTALL_MARKER = '.dingtalk-agent-install.json'\n\nexport interface 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}`, bundledSkillPath(PACKAGE_ROOT, 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,26 @@
1
+ import { lstatSync, readFileSync, realpathSync } from 'node:fs';
2
+ import { relative, resolve } from 'node:path';
3
+ import { runRemoteSemanticStateLiveEvaluation, } from './remote-semantic-state-live-evals.js';
4
+ import { runRemoteStateEvaluation } from './remote-state-evals.js';
5
+ export function runStorageEvaluation(root, workspacePath, suitePath, options = {}) {
6
+ const rootReal = realpathSync(resolve(root));
7
+ const suiteCandidate = resolve(rootReal, suitePath);
8
+ if (lstatSync(suiteCandidate).isSymbolicLink()) {
9
+ throw new Error('Storage Eval suite 不能是 symlink');
10
+ }
11
+ const suiteFile = realpathSync(suiteCandidate);
12
+ const rel = relative(rootReal, suiteFile);
13
+ if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
14
+ !lstatSync(suiteFile).isFile() || lstatSync(suiteFile).isSymbolicLink()) {
15
+ throw new Error('Storage Eval suite 必须是工作区内的普通文件');
16
+ }
17
+ const value = JSON.parse(readFileSync(suiteFile, 'utf8'));
18
+ if (value.$schema === 'dingtalk-agent/remote-semantic-state-live-eval@1') {
19
+ return runRemoteSemanticStateLiveEvaluation(rootReal, workspacePath, suitePath, options);
20
+ }
21
+ if (value.$schema === 'dingtalk-agent/remote-state-eval@1') {
22
+ return runRemoteStateEvaluation(rootReal, workspacePath, suitePath, options);
23
+ }
24
+ throw new Error(`Storage Eval suite schema 不支持: ${String(value.$schema || '-')}`);
25
+ }
26
+ //# sourceMappingURL=storage-evals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-evals.js","sourceRoot":"","sources":["../../src/storage-evals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EACL,oCAAoC,GAErC,MAAM,uCAAuC,CAAA;AAC9C,OAAO,EAAE,wBAAwB,EAA+B,MAAM,yBAAyB,CAAA;AAE/F,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,aAAqB,EACrB,SAAiB,EACjB,UAAmE,EAAE;IAErE,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5C,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IACnD,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IACD,MAAM,SAAS,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;IACzC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAChF,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAA4B,CAAA;IACpF,IAAI,KAAK,CAAC,OAAO,KAAK,kDAAkD,EAAE,CAAC;QACzE,OAAO,oCAAoC,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;IAC1F,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,oCAAoC,EAAE,CAAC;QAC3D,OAAO,wBAAwB,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;IAC9E,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,GAAG,CAAC,EAAE,CAAC,CAAA;AACnF,CAAC","sourcesContent":["import { lstatSync, readFileSync, realpathSync } from 'node:fs'\nimport { relative, resolve } from 'node:path'\nimport {\n runRemoteSemanticStateLiveEvaluation,\n type RemoteSemanticStateLiveOptions,\n} from './remote-semantic-state-live-evals.js'\nimport { runRemoteStateEvaluation, type RemoteStateEvalOptions } from './remote-state-evals.js'\n\nexport function runStorageEvaluation(\n root: string,\n workspacePath: string,\n suitePath: string,\n options: RemoteStateEvalOptions & RemoteSemanticStateLiveOptions = {},\n): Record<string, any> {\n const rootReal = realpathSync(resolve(root))\n const suiteCandidate = resolve(rootReal, suitePath)\n if (lstatSync(suiteCandidate).isSymbolicLink()) {\n throw new Error('Storage Eval suite 不能是 symlink')\n }\n const suiteFile = realpathSync(suiteCandidate)\n const rel = relative(rootReal, suiteFile)\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`) ||\n !lstatSync(suiteFile).isFile() || lstatSync(suiteFile).isSymbolicLink()) {\n throw new Error('Storage Eval suite 必须是工作区内的普通文件')\n }\n const value = JSON.parse(readFileSync(suiteFile, 'utf8')) as Record<string, unknown>\n if (value.$schema === 'dingtalk-agent/remote-semantic-state-live-eval@1') {\n return runRemoteSemanticStateLiveEvaluation(rootReal, workspacePath, suitePath, options)\n }\n if (value.$schema === 'dingtalk-agent/remote-state-eval@1') {\n return runRemoteStateEvaluation(rootReal, workspacePath, suitePath, options)\n }\n throw new Error(`Storage Eval suite schema 不支持: ${String(value.$schema || '-')}`)\n}\n"]}
@@ -1 +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"]}
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 type InvocationMode =\n | 'direct'\n | 'dm'\n | 'mention'\n | 'ambient'\n | 'heartbeat'\n | 'continuation'\n\nexport interface InvocationContext {\n $schema: 'dingtalk-agent/invocation@1'\n mode: InvocationMode\n authority: 'default' | 'host' | 'event'\n eventId: string\n sessionKey: string\n occurredAt: string | null\n actor: NormalizedEvent['actor'] | null\n target: ReplyTarget | null\n conversation: NormalizedEvent['conversation'] | null\n}\n\nexport interface EnrichmentItem {\n status: 'available' | 'missing' | 'rejected'\n source: string\n fetchedAt: string | null\n confidence: number\n truncated: boolean\n reason: string\n data: Record<string, unknown> | null\n}\n\nexport interface EnrichedInvocation {\n $schema: 'dingtalk-agent/enriched-invocation@1'\n invocation: InvocationContext\n message: { originalText: string; effectiveText: string }\n enrichments: {\n quote: EnrichmentItem\n burst: EnrichmentItem\n identity: EnrichmentItem\n }\n missing: string[]\n hash: string\n}\n\nexport interface ResponseGateSnapshot {\n $schema: 'dingtalk-agent/response-gate@1'\n decision: 'engage' | 'silent' | 'inspect'\n reason: string\n hardAllowedActions: ActionKind[]\n softChecks: string[]\n perceptionHash: string\n hash: string\n}\n\nexport interface AgentDefinition {\n $schema: 'dingtalk-agent/agent-definition@1'\n id: string\n source: {\n kind: 'local-folder' | 'git-checkout' | 'dingtalk-doc' | 'workspace'\n uri: string\n revision: string\n }\n body: { path: string; hash: string } | null\n skills: Array<{\n name: string\n version: string\n source: string\n path: string\n hash: string\n }>\n storage: {\n memory: string\n knowledge: string\n artifacts: string\n state: string\n }\n authority: { dwsProfile: string; expectedUserId: string }\n configuration: Record<string, 'explicit' | 'context' | 'environment' | 'workspace' | 'convention'>\n status: 'ready' | 'partial'\n missing: string[]\n hash: string\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}\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 definition?: { id: string; hash: string }\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 definition?: { id: string; hash: string; snapshotPath: string }\n invocation?: { mode: InvocationMode; authority: InvocationContext['authority'] }\n perception?: { hash: string }\n responseGate?: { decision: ResponseGateSnapshot['decision']; hash: 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"]}