@xdxer/dingtalk-agent 0.1.4-beta.1 → 0.1.4-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.en.md +397 -0
  3. package/README.md +500 -47
  4. package/dist/bin/dingtalk-agent.js +1263 -351
  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/agent-platform.js +158 -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 +736 -0
  23. package/dist/src/development-workspace.js.map +1 -0
  24. package/dist/src/doctor.js +49 -22
  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/init.js +1 -1
  31. package/dist/src/init.js.map +1 -1
  32. package/dist/src/invocation.js +36 -0
  33. package/dist/src/invocation.js.map +1 -0
  34. package/dist/src/lab.js +679 -0
  35. package/dist/src/lab.js.map +1 -0
  36. package/dist/src/lease.js +100 -0
  37. package/dist/src/lease.js.map +1 -0
  38. package/dist/src/map.js +157 -0
  39. package/dist/src/map.js.map +1 -0
  40. package/dist/src/memory/candidates.js +451 -0
  41. package/dist/src/memory/candidates.js.map +1 -0
  42. package/dist/src/memory/completion-evidence.js +536 -0
  43. package/dist/src/memory/completion-evidence.js.map +1 -0
  44. package/dist/src/memory/operational.js +263 -0
  45. package/dist/src/memory/operational.js.map +1 -0
  46. package/dist/src/memory/remote-state.js +478 -0
  47. package/dist/src/memory/remote-state.js.map +1 -0
  48. package/dist/src/memory/task-checkpoints.js +204 -0
  49. package/dist/src/memory/task-checkpoints.js.map +1 -0
  50. package/dist/src/multica-deploy.js +1480 -0
  51. package/dist/src/multica-deploy.js.map +1 -0
  52. package/dist/src/multica-provider.js +685 -0
  53. package/dist/src/multica-provider.js.map +1 -0
  54. package/dist/src/opencode-evals.js +1062 -0
  55. package/dist/src/opencode-evals.js.map +1 -0
  56. package/dist/src/opencode-provider.js +531 -0
  57. package/dist/src/opencode-provider.js.map +1 -0
  58. package/dist/src/opencode-workspace.js +197 -0
  59. package/dist/src/opencode-workspace.js.map +1 -0
  60. package/dist/src/perception.js +225 -0
  61. package/dist/src/perception.js.map +1 -0
  62. package/dist/src/personal-event-evals.js +595 -0
  63. package/dist/src/personal-event-evals.js.map +1 -0
  64. package/dist/src/promotion.js +786 -0
  65. package/dist/src/promotion.js.map +1 -0
  66. package/dist/src/remote-semantic-state-live-evals.js +888 -0
  67. package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
  68. package/dist/src/remote-semantic-state-worker.js +38 -0
  69. package/dist/src/remote-semantic-state-worker.js.map +1 -0
  70. package/dist/src/remote-state-evals.js +501 -0
  71. package/dist/src/remote-state-evals.js.map +1 -0
  72. package/dist/src/response-gate.js +51 -0
  73. package/dist/src/response-gate.js.map +1 -0
  74. package/dist/src/robot-evals.js +770 -0
  75. package/dist/src/robot-evals.js.map +1 -0
  76. package/dist/src/sessions.js +66 -105
  77. package/dist/src/sessions.js.map +1 -1
  78. package/dist/src/setup.js +14 -12
  79. package/dist/src/setup.js.map +1 -1
  80. package/dist/src/skill-manager.js +128 -203
  81. package/dist/src/skill-manager.js.map +1 -1
  82. package/dist/src/skills.js.map +1 -1
  83. package/dist/src/storage-evals.js +26 -0
  84. package/dist/src/storage-evals.js.map +1 -0
  85. package/dist/src/types.js.map +1 -1
  86. package/dist/src/upgrade.js +137 -0
  87. package/dist/src/upgrade.js.map +1 -0
  88. package/dist/src/waits.js +5 -1
  89. package/dist/src/waits.js.map +1 -1
  90. package/dist/src/workspace.js +28 -3
  91. package/dist/src/workspace.js.map +1 -1
  92. package/docs/INSTALLATION.md +119 -14
  93. package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
  94. package/docs/architecture/agent-memory-topology.png +0 -0
  95. package/docs/architecture/agent-memory-topology.svg +132 -0
  96. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  97. package/docs/architecture/general-agent-kernel-topology.svg +149 -0
  98. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  99. package/docs/architecture/provider-bound-development-workspace.svg +141 -0
  100. package/docs/architecture/task-completion-gate.png +0 -0
  101. package/docs/architecture/task-completion-gate.svg +191 -0
  102. package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
  103. package/docs/schemas/agent-audit.schema.json +92 -0
  104. package/docs/schemas/agent-bindings.schema.json +54 -0
  105. package/docs/schemas/agent-definition.schema.json +78 -0
  106. package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
  107. package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
  108. package/docs/schemas/agent-platform.schema.json +13 -0
  109. package/docs/schemas/enriched-invocation.schema.json +46 -0
  110. package/docs/schemas/eval-candidate-plan.schema.json +28 -0
  111. package/docs/schemas/eval-candidate-result.schema.json +20 -0
  112. package/docs/schemas/eval-candidate.schema.json +30 -0
  113. package/docs/schemas/invocation.schema.json +19 -0
  114. package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
  115. package/docs/schemas/memory-candidate.schema.json +76 -0
  116. package/docs/schemas/memory-publish-target.schema.json +25 -0
  117. package/docs/schemas/multica-deployment-list.schema.json +29 -0
  118. package/docs/schemas/multica-deployment-operation.schema.json +51 -0
  119. package/docs/schemas/multica-deployment-plan.schema.json +70 -0
  120. package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
  121. package/docs/schemas/multica-deployment-status.schema.json +23 -0
  122. package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
  123. package/docs/schemas/multica-workspace-plan.schema.json +68 -0
  124. package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
  125. package/docs/schemas/multica-workspace-status.schema.json +34 -0
  126. package/docs/schemas/observation.schema.json +21 -0
  127. package/docs/schemas/operational-memory-provider.schema.json +36 -0
  128. package/docs/schemas/operational-memory-record.schema.json +24 -0
  129. package/docs/schemas/perception-input.schema.json +56 -0
  130. package/docs/schemas/project.schema.json +113 -0
  131. package/docs/schemas/promotion-list.schema.json +36 -0
  132. package/docs/schemas/promotion-plan.schema.json +60 -0
  133. package/docs/schemas/promotion-policy.schema.json +29 -0
  134. package/docs/schemas/promotion-receipt.schema.json +43 -0
  135. package/docs/schemas/promotion-status.schema.json +23 -0
  136. package/docs/schemas/release-readiness.schema.json +66 -0
  137. package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
  138. package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
  139. package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
  140. package/docs/schemas/response-gate.schema.json +20 -0
  141. package/docs/schemas/task-checkpoint.schema.json +71 -0
  142. package/docs/schemas/task-completion-evidence.schema.json +154 -0
  143. package/docs/schemas/workspace-doctor.schema.json +56 -0
  144. package/docs/schemas/workspace-state.schema.json +39 -0
  145. package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
  146. package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
  147. package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
  148. package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
  149. package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
  150. package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
  151. package/examples/agents/fde-coach/AGENTS.md +26 -0
  152. package/examples/agents/fde-coach/MEMORY.md +3 -0
  153. package/examples/agents/fde-coach/fields/default/field.json +24 -0
  154. package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
  155. package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
  156. package/examples/agents/release-manager/AGENTS.md +26 -0
  157. package/examples/agents/release-manager/MEMORY.md +3 -0
  158. package/examples/agents/release-manager/fields/default/field.json +24 -0
  159. package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
  160. package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
  161. package/lab/README.md +109 -0
  162. package/lab/agent-eval/catalog.json +91 -0
  163. package/lab/agent-eval/classic-failures.json +177 -0
  164. package/lab/agent-eval/completion-gate-regression.json +99 -0
  165. package/lab/agent-eval/personal-event-live.example.json +94 -0
  166. package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
  167. package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
  168. package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
  169. package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
  170. package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
  171. package/lab/agent-eval/remote-state.example.json +31 -0
  172. package/lab/agent-eval/workspace/AGENTS.md +7 -0
  173. package/lab/agent-eval/workspace/MEMORY.md +4 -0
  174. package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
  175. package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
  176. package/lab/agent-eval/workspace/opencode.json +20 -0
  177. package/lab/manifest.example.json +27 -0
  178. package/lab/manifest.personal-event.example.json +27 -0
  179. package/lab/project-workspace/README.md +11 -0
  180. package/lab/project-workspace/fake-multica-provider.mjs +266 -0
  181. package/lab/project-workspace/multica-deploy.fixture.json +29 -0
  182. package/lab/project-workspace/multica-readonly.fixture.json +69 -0
  183. package/lab/project-workspace/observation.fixture.json +14 -0
  184. package/lab/project-workspace/opencode-provider-suite.json +65 -0
  185. package/lab/project-workspace/project.fixture.json +44 -0
  186. package/lab/project-workspace/promotion-policy.fixture.json +15 -0
  187. package/lab/robot-eval/pool.example.json +30 -0
  188. package/lab/robot-eval/suite.json +123 -0
  189. package/lab/robot-eval/workspace/AGENTS.md +21 -0
  190. package/lab/robot-eval/workspace/MEMORY.md +3 -0
  191. package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
  192. package/lab/robot-eval/workspace/opencode.json +22 -0
  193. package/lab/schemas/agent-eval-catalog.schema.json +47 -0
  194. package/lab/schemas/lab-manifest.schema.json +70 -0
  195. package/lab/schemas/personal-event-eval.schema.json +91 -0
  196. package/lab/schemas/remote-state-eval.schema.json +66 -0
  197. package/lab/schemas/robot-eval-suite.schema.json +184 -0
  198. package/lab/schemas/robot-pool.schema.json +56 -0
  199. package/package.json +26 -14
  200. package/skills/dingtalk-agent-boot-multica/SKILL.md +40 -0
  201. package/skills/dingtalk-agent-compose/SKILL.md +110 -0
  202. package/skills/dingtalk-agent-compose/assets/AGENTS.template.md +26 -0
  203. package/skills/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
  204. package/skills/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
  205. package/skills/dingtalk-agent-compose/assets/opencode.template.json +12 -0
  206. package/skills/dingtalk-agent-compose/assets/role-skill.template.md +24 -0
  207. package/skills/dingtalk-agent-compose/evals/evals.json +94 -0
  208. package/skills/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
  209. package/skills/dingtalk-agent-compose/references/opencode-host-contract.md +65 -0
  210. package/skills/dingtalk-agent-compose/references/storage-routing.md +20 -0
  211. package/skills/dingtalk-agent-deploy/SKILL.md +60 -0
  212. package/skills/dingtalk-agent-deploy/references/multica-deployment-contract.md +49 -0
  213. package/skills/dingtalk-agent-deploy/references/promotion-observation-contract.md +49 -0
  214. package/skills/dingtalk-agent-eval/SKILL.md +116 -0
  215. package/skills/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
  216. package/skills/dingtalk-agent-eval/evals/evals.json +61 -0
  217. package/skills/dingtalk-agent-eval/references/eval-topology.md +34 -0
  218. package/skills/dingtalk-agent-eval/references/evidence-contract.md +31 -0
  219. package/skills/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
  220. package/skills/dingtalk-agent-eval/references/storage-modes.md +75 -0
  221. package/skills/dingtalk-basic-behavior/SKILL.md +63 -3
  222. package/skills/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
  223. package/skills/dingtalk-basic-behavior/assets/{task-checkpoint.md → task-checkpoint.json} +2 -21
  224. package/skills/dingtalk-basic-behavior/references/action-contract.md +2 -0
  225. package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +15 -1
  226. package/skills/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
  227. package/skills/dingtalk-basic-behavior/references/task-lifecycle.md +32 -7
  228. package/dist/src/boot.js +0 -70
  229. package/dist/src/boot.js.map +0 -1
  230. package/dist/src/duty.js +0 -74
  231. package/dist/src/duty.js.map +0 -1
  232. package/dist/src/kb.js +0 -240
  233. package/dist/src/kb.js.map +0 -1
  234. package/dist/src/runs.js +0 -79
  235. package/dist/src/runs.js.map +0 -1
  236. package/docs/ARCHITECTURE.md +0 -217
  237. package/docs/MINIMAL-WORKSPACE-V1.md +0 -172
  238. package/docs/OPEN-SOURCE-REFERENCES.md +0 -107
  239. package/docs/SELF-TEST.md +0 -252
  240. package/docs//345/206/205/347/275/221/345/256/236/347/233/270.md +0 -77
  241. package/evals/baselines/2026-07-14/behavior-summary.json +0 -28
  242. package/evals/baselines/2026-07-14/contract-summary.json +0 -18
  243. package/evals/baselines/2026-07-14/live-canary-summary.json +0 -25
  244. package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/SKILL.md +0 -72
  245. package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/action-contract.md +0 -31
  246. package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/event-to-behavior.md +0 -22
  247. package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/memory-and-evolution.md +0 -25
  248. package/evals/baselines/2026-07-15/dingtalk-basic-behavior-0.3.0/references/runtime-modes.md +0 -34
  249. package/evals/baselines/2026-07-15/task-lifecycle-summary.json +0 -50
  250. package/evals/evals.json +0 -316
  251. package/evals/fixtures/dm-ambiguous-send.json +0 -4
  252. package/evals/fixtures/dm-blocked.json +0 -4
  253. package/evals/fixtures/dm-clear.json +0 -4
  254. package/evals/fixtures/dm-discussion.json +0 -4
  255. package/evals/fixtures/dm-doc-write-no-tool.json +0 -4
  256. package/evals/fixtures/dm-long-task-ack.json +0 -4
  257. package/evals/fixtures/dm-nonblocking-gap.json +0 -4
  258. package/evals/fixtures/dm-structured-task.json +0 -4
  259. package/evals/fixtures/group.json +0 -10
  260. package/evals/fixtures/mentioned.json +0 -3
  261. package/evals/run-contract-evals.mjs +0 -1106
  262. package/evals/run-shadow-evals.mjs +0 -267
  263. package/evals/runners/README.md +0 -66
  264. package/evals/runners/claude-shadow.mjs +0 -533
  265. package/evals/schemas/action-request.schema.json +0 -77
  266. package/evals/shadow-evals.json +0 -133
  267. package/skills/AGENTS.md +0 -104
  268. package/skills//344/273/273/345/212/241.md +0 -48
  269. package/skills//345/237/272/347/241/200/350/241/214/344/270/272.md +0 -44
  270. package/skills//345/277/203/350/267/263.md +0 -79
  271. package/skills//346/266/210/346/201/257.md +0 -50
  272. package/skills//347/237/245/350/257/206.md +0 -55
  273. package/skills//350/257/204/346/265/213.md +0 -62
  274. package/skills//351/222/211/351/222/211.md +0 -64
  275. package/templates/ontology/index.md +0 -24
  276. package/templates/ontology/self/access.md +0 -38
  277. package/templates/ontology/self/role-spec.md +0 -34
  278. package/templates/ontology/self/workspace.md +0 -41
@@ -9,23 +9,37 @@
9
9
  //
10
10
  // 因为:文档会被漏读、误读、自我说服;**撞到闸门上就没得商量。**
11
11
  import { parseArgs } from 'node:util';
12
- import { join, resolve } from 'node:path';
13
- import { readFileSync } from 'node:fs';
12
+ import { join, relative, resolve } from 'node:path';
13
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
14
14
  import { spawn, spawnSync } from 'node:child_process';
15
15
  import * as cfgmod from '../src/config.js';
16
- import * as kbmod from '../src/kb.js';
17
- import * as runsmod from '../src/runs.js';
18
- import * as dutymod from '../src/duty.js';
19
- import { boot } from '../src/boot.js';
20
16
  import { init } from '../src/init.js';
21
17
  import { ackDispatch, listPendingDispatches, prepareSession } from '../src/sessions.js';
22
18
  import { readEventFile, consumeNdjson, heartbeatEvent } from '../src/driver.js';
23
19
  import { findRun, previewAction, executeAction } from '../src/actions.js';
24
20
  import { resolvePackageRoot } from '../src/package-root.js';
25
21
  import { bootstrap } from '../src/bootstrap.js';
22
+ import { loadAgentBindings } from '../src/agent-bindings.js';
23
+ import { auditAgent } from '../src/agent-audit.js';
24
+ import { applyAgentEnhancement, planAgentEnhancement, } from '../src/agent-enhance.js';
25
+ import { doctorLab, runLab, teardownLab, verifyLab } from '../src/lab.js';
26
+ import { runRobotEvaluation } from '../src/robot-evals.js';
27
+ import { runOpenCodeEvaluation } from '../src/opencode-evals.js';
28
+ import { runStorageEvaluation } from '../src/storage-evals.js';
29
+ import { runPersonalEventEvaluation } from '../src/personal-event-evals.js';
26
30
  import { doctor } from '../src/doctor.js';
31
+ import { doctorDevelopmentWorkspace, inspectAgentProject, showDevelopmentWorkspace, } from '../src/development-workspace.js';
32
+ import { applyOpenCodeWorkspace, evalOpenCodeWorkspace, planOpenCodeWorkspace, runOpenCodeWorkspace, useOpenCodeWorkspace, } from '../src/opencode-provider.js';
33
+ import { inspectMulticaWorkspace, listMulticaWorkspaceResources, planMulticaWorkspace, statusMulticaWorkspace, } from '../src/multica-provider.js';
34
+ import { applyMulticaDeployment, listMulticaDeployments, planMulticaDeployment, statusMulticaDeployment, } from '../src/multica-deploy.js';
35
+ import { applyObservation, applyPromotion, listPromotions, planObservation, planPromotion, statusPromotion, } from '../src/promotion.js';
27
36
  import { setup } from '../src/setup.js';
28
- import { installGlobalSkill, skillStatus, uninstallGlobalSkill, upgradeGlobalSkill, } from '../src/skill-manager.js';
37
+ import { upgradeAgent } from '../src/upgrade.js';
38
+ import { checkpointTask, showTaskCheckpoint } from '../src/memory/task-checkpoints.js';
39
+ import { upsertOperationalMemory } from '../src/memory/operational.js';
40
+ import { proposeMemoryCandidate, publishMemoryCandidate, reviewMemoryCandidate, showMemoryCandidate, } from '../src/memory/candidates.js';
41
+ import { installBundledSkills, installGlobalSkill, skillStatus, skillSuiteStatus, uninstallBundledSkills, uninstallGlobalSkill, upgradeBundledSkills, upgradeGlobalSkill, } from '../src/skill-manager.js';
42
+ import { MANAGED_AGENT_PLATFORMS, requireSupportedAgentPlatform, resolveAgentPlatform, statusLabel as platformStatusLabel, useAgentPlatform, } from '../src/agent-platform.js';
29
43
  const PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
30
44
  const PACKAGE_JSON = JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8'));
31
45
  // ROOT = **你的工作区**(当前目录),不是包所在的目录。
@@ -33,50 +47,41 @@ const PACKAGE_JSON = JSON.parse(readFileSync(join(PACKAGE_ROOT, 'package.json'),
33
47
  const ROOT = process.env.DTA_ROOT
34
48
  ? resolve(process.env.DTA_ROOT)
35
49
  : (cfgmod.findRoot(process.cwd()) || process.cwd());
50
+ const PROJECT_START = process.env.DTA_ROOT ? resolve(process.env.DTA_ROOT) : process.cwd();
36
51
  const HELP = `
37
- dingtalk-agent —— Skill-first 的钉钉数字员工行为容器
52
+ dta —— Agent 安装钉钉员工的基础行为和工作环境
38
53
 
39
- 首次使用(无全局命令时: npx --yes --registry=https://registry.npmjs.org @xdxer/dingtalk-agent@${PACKAGE_JSON.version} setup)
40
- setup 用户级安装 CLI、修复 PATH、安装 Skill、检查 DWS
41
- doctor 检查 PATH / Node / DWS / Skill / Agent 客户端
54
+ 装好后,Agent 可以:
55
+ · 判断 @、单聊和群消息是否应该回应
56
+ · 通过 DWS 回复消息、协作并使用钉钉标准产品
57
+ · 从本地目录或钉钉文档加载身份、记忆和知识
42
58
 
43
- Skill(不要求 Workspace)
44
- skill install 安装全局 Basic Behavior(Claude Code + Codex + OpenCode)
45
- skill status 检查版本、漂移和客户端可发现性
46
- skill upgrade 升级本工具管理的全局 Skill
47
- skill uninstall 安全卸载本工具管理的全局 Skill
48
- 通用: [--dry-run] [--json] [--discard-local-changes]
59
+ 开始使用:
60
+ dta setup 首次配置 CLI、DWS 和内置 Skill(基础行为 + Agent 装配)
61
+ dta bootstrap --json 为当前 Agent 会话加载工作区
62
+ dta agent enhance / audit 安全增强已有仓库,再审计定义、存储与 Skill 真加载
63
+ dta info / dta workspace doctor <name> 查看 Project 并只读诊断 Workspace
64
+ dta agent-platform use <platform> → dta deploy / dta promote 声明平台归属并装平台技能包,再受控部署与晋级
49
65
 
50
- 每个 Agent Session(不要求 init)
51
- bootstrap 发现当前本地 Workspace;不修改项目文件
52
- [--storage <uri>] local-dir:<path> | dingtalk-doc:<node-or-url>
53
- [--state-dir <path>] 远端文档只读快照目录
54
- [--profile <dws-profile>] [--json]
66
+ 维护环境:
67
+ dta doctor 检查哪里没装好,并给出修复提示
68
+ dta upgrade 自升级,再重新检查完整环境
69
+ dta skill status 查看 Claude Code、Codex、OpenCode 能否发现内置 Skill(可加 name 只查一个)
55
70
 
56
- 可信事件模式(可选;需要一次 init)
57
- init [--context-id X] 仅为 Prepared Run 建最小 Workspace
58
- prepare --event-file <file|-> 事件 → Session → Run
59
- act ack 对原消息贴「收到」;不代表接单
60
- act reply --text "…" 引用回复原消息
61
- act ask --text "…" 只问一个真正阻塞的问题
62
- act silence [--reason "…"] 不外发,但留下行为回执
63
- 通用: [--run <path>] [--dry-run] [--json]
64
-
65
- smoke 极简本地验收(不写钉钉)
66
- eval contract / behavior 完整合同或模型行为评测
67
-
68
- help runtime 事件宿主与 controller 命令
69
- help adapters 可选 DWS listen 适配器
70
- help legacy 查看兼容的本体、KB、值班与进化命令
71
+ 接入钉钉事件和可靠外发:dta help runtime
71
72
  `;
72
73
  const RUNTIME_HELP = `
73
74
  dingtalk-agent 可信事件运行时(可选宿主能力)
74
75
 
75
76
  init [--context-id X] [--memory <uri>] [--knowledge <uri>]
76
- prepare --event-file <file|->
77
+ prepare --event-file <file|-> [--perception-file <file>]
77
78
  run --stdin | --event-file <file> | --heartbeat
78
79
  dispatch pending
79
80
  dispatch ack --event-id X --run-id X
81
+ task show --json
82
+ task checkpoint --input checkpoint.json --expect-revision N
83
+ memory operational upsert --provider provider.json --input record.json [--live --yes]
84
+ memory candidate propose|show|review|publish
80
85
  act ack|reply|ask|silence
81
86
 
82
87
  这些命令负责目标冻结、Session/Run、Wait、幂等和回执;普通 Agent Session 不必使用。
@@ -90,19 +95,90 @@ dingtalk-agent 可选 Driver / 开发联调适配器
90
95
 
91
96
  listen 不是 Agent 主入口。Claude Code、DWS 云端或其他宿主都可以直接提供事件。
92
97
  `;
93
- const LEGACY_HELP = `
94
- dingtalk-agent 兼容命令(不属于 P0 四对象主链)
98
+ const LAB_HELP = `
99
+ dingtalk-agent 真实世界联调控制面
100
+
101
+ lab doctor --manifest lab/manifest.local.json
102
+ lab run --manifest <file> --event-file <file> --case-id <id> [--reply <text>]
103
+ lab verify --evidence <run-dir>
104
+ lab teardown --manifest <file> --evidence <run-dir>
105
+ lab eval --pool <pool.local.json> --suite <suite.json> [--lanes stateless,stateful]
106
+ lab eval --engine opencode --workspace <agent-dir> --suite <suite.json> [--cases id1,id2] [--runs 3] [--previous-skill <dir>]
107
+ lab eval --engine storage --workspace <agent-dir> --suite <remote-state.json> [--execute --live --yes]
108
+ lab eval --engine personal-event --workspace <agent-dir> --suite <suite.json> [--execute --live --yes]
109
+
110
+ mock-integration 还要求 DTA_LAB_FAKE_DWS=1;robot/personal Live 必须显式 --live --yes。
111
+ lab eval 默认只输出计划;Robot Live 用 --live --yes,OpenCode A/B 用 --execute --yes。
112
+ Remote State 用 --execute --yes 读取 DWS/调用模型,再加 --live 才执行唯一写探针。
113
+ OpenCode 对照强制验证每个 Basic Skill 的 load probe;提供 --previous-skill 时运行 current/previous,不连接 DWS。
114
+ Lab 只管理 allowlist、预算、marker、证据和清理;事件触发器仍在外部。
115
+ `;
116
+ const AGENT_HELP = `
117
+ dingtalk-agent 开发者装配验收
118
+
119
+ agent audit [--bindings agent.bindings.json] [--require-skill <name>]
120
+ agent audit [--bindings <file>] [--require-skill <name>] --verify-load --yes
121
+ agent audit [--bindings <file>] --load-report <agent-audit-load-evidence.json> [--remote-report <report.json>]
122
+ agent enhance --role-skill <name>[,<name>] [--project-name <name>] [--dry-run] [--json]
123
+ agent enhance --role-skill <name>[,<name>] --plan-id <current-plan-id> --yes [--json]
124
+
125
+ 默认只做本地静态审计,不访问 DWS、不调用模型;状态为 partial 时返回退出码 2。
126
+ --verify-load --yes 会运行隔离的 OpenCode load probe,但仍不访问钉钉。
127
+ 远端语义状态由 storage eval 独立验收,再通过 --remote-report 绑定证据。
128
+ `;
129
+ const WORKSPACE_HELP = `
130
+ dingtalk-agent Project / Development Workspace
131
+
132
+ info [--json]
133
+ workspace list [--json]
134
+ workspace show <name> [--json]
135
+ workspace doctor <name> [--json]
136
+ workspace plan <multica-name> [--json]
137
+ workspace inspect <multica-name> [--execute --yes] [--json]
138
+ workspace remote-list <multica-name> [--execute --yes] [--json]
139
+ workspace status <multica-name> [--json]
140
+ workspace create <name> [--dry-run | --yes] [--json]
141
+ workspace use <name> [--json]
142
+ workspace run <name> --prompt-file <file> [--execute --yes] [--json]
143
+ workspace eval <name> --suite <file> [--execute --yes] [--runs N] [--json]
144
+
145
+ 命令会从当前目录向上发现 dingtalk-agent.json;旧 workspace@1 只读显示为 legacy-prepared。
146
+ Multica plan/status 默认不调用 Provider;inspect/remote-list 只有 --execute --yes 才读取当前 profile 和远端 scope。
147
+ Multica readback 只保存脱敏事实,不执行 create/update/apply/deploy;OpenCode create 只物化本地环境。
148
+ 这些命令都不访问 DWS;Multica 远端写入只通过 dta deploy 的冻结 plan 闸门。
149
+ `;
150
+ const DEPLOY_HELP = `
151
+ dingtalk-agent Multica 受控部署
152
+
153
+ deploy --workspace <name> --dry-run [--json]
154
+ deploy --workspace <name> --plan-id <id> --yes [--no-wait] [--json]
155
+ deploy --workspace <name> --status [--operation-id <id>] [--json]
156
+ deploy --workspace <name> --status --operation-id <id> --execute --yes [--json]
157
+ deploy --workspace <name> --list [--json]
158
+ deploy --workspace <name> --retire --dry-run [--json]
159
+ deploy --workspace <name> --retire --plan-id <id> --yes [--json]
160
+
161
+ dry-run 不启动 Multica。apply/retire 必须携带当前 planId;scope 或源码漂移会在写入前拒绝。
162
+ status 默认只验本地脱敏 operation/Receipt;--execute --yes 才做远端独立回读。
163
+ deploy 只管理 Agent、完整 Skill tree、assignment 和 load smoke,不创建机器人、Webhook、Autopilot 或定时 Trigger。
164
+ `;
165
+ const PROMOTION_HELP = `
166
+ dingtalk-agent 已验版本晋级与反馈候选
95
167
 
96
- boot
97
- kb mount|list|sync|search
98
- duty --check|--run|--list
99
- todo
100
- log / feedback / runs / evolve
168
+ promote --policy <file> --route <id> --dry-run [--json]
169
+ promote --policy <file> --route <id> --plan-id <id> --yes [--no-wait] [--json]
170
+ promote --status [--promotion-id <id>] [--json]
171
+ promote --list [--json]
172
+ observe --promotion-id <id> --input <observation.json> --dry-run [--json]
173
+ observe --promotion-id <id> --input <observation.json> --yes [--json]
101
174
 
102
- 这些能力继续可用,但新增 Agent 应先安装全局 Skill;只有可信事件宿主才需要 runtime
175
+ Promotion 只接受指定 suite load/hard/surface gate 与精确 W2 evidence hash,并委托 W4 deploy
176
+ Observe 只写 gitignored、proposed、不可直接发布的 Eval candidate;不修改 AGENTS.md、Prompt、Skill 或 Trigger。
103
177
  `;
104
- function fail(msg, code = 1) {
105
- console.error(msg);
178
+ function fail(msg, code = 1, hint = '') {
179
+ console.error(`错误: ${msg}`);
180
+ if (hint)
181
+ console.error(`提示: ${hint}`);
106
182
  process.exit(code);
107
183
  }
108
184
  const argv = process.argv.slice(2);
@@ -112,15 +188,11 @@ try {
112
188
  await main();
113
189
  }
114
190
  catch (e) {
115
- if (e.exitCode)
116
- process.exit(e.exitCode);
117
- fail(String(e.message || e), 2);
191
+ const error = e;
192
+ const message = String(error?.message || error);
193
+ fail(message, Number(error?.exitCode) || 2, errorHint(message));
118
194
  }
119
195
  async function main() {
120
- if (cmd === 'help' && sub === 'legacy') {
121
- console.log(LEGACY_HELP);
122
- return;
123
- }
124
196
  if (cmd === 'help' && sub === 'runtime') {
125
197
  console.log(RUNTIME_HELP);
126
198
  return;
@@ -129,6 +201,29 @@ async function main() {
129
201
  console.log(ADAPTER_HELP);
130
202
  return;
131
203
  }
204
+ if (cmd === 'help' && sub === 'lab') {
205
+ console.log(LAB_HELP);
206
+ return;
207
+ }
208
+ if (cmd === 'help' && sub === 'agent') {
209
+ console.log(AGENT_HELP);
210
+ return;
211
+ }
212
+ if (cmd === 'help' && sub === 'workspace') {
213
+ console.log(WORKSPACE_HELP);
214
+ return;
215
+ }
216
+ if (cmd === 'help' && sub === 'deploy') {
217
+ console.log(DEPLOY_HELP);
218
+ return;
219
+ }
220
+ if (cmd === 'help' && ['promote', 'observe'].includes(sub || '')) {
221
+ console.log(PROMOTION_HELP);
222
+ return;
223
+ }
224
+ if (cmd === 'help' && sub) {
225
+ fail(`不认识的帮助主题: ${sub}`, 1, '运行 dta --help 回到产品入口;事件宿主可用 dta help runtime。');
226
+ }
132
227
  if (!cmd || cmd === '--help' || cmd === '-h' || cmd === 'help') {
133
228
  console.log(HELP);
134
229
  return;
@@ -137,7 +232,390 @@ async function main() {
137
232
  console.log(PACKAGE_JSON.version);
138
233
  return;
139
234
  }
140
- // ── setup / doctor:npx 永远可启动的首次使用入口。──
235
+ if (cmd === 'deploy') {
236
+ requireSupportedAgentPlatform('deploy', PROJECT_START);
237
+ const { values: o, positionals } = parseArgs({
238
+ args: argv.slice(1), allowPositionals: true,
239
+ options: {
240
+ workspace: { type: 'string' }, json: { type: 'boolean' },
241
+ 'dry-run': { type: 'boolean' }, yes: { type: 'boolean' },
242
+ 'plan-id': { type: 'string' }, 'no-wait': { type: 'boolean' },
243
+ status: { type: 'boolean' }, list: { type: 'boolean' },
244
+ execute: { type: 'boolean' }, 'operation-id': { type: 'string' },
245
+ timeout: { type: 'string' }, 'smoke-timeout': { type: 'string' },
246
+ retire: { type: 'boolean' },
247
+ },
248
+ });
249
+ if (positionals.length)
250
+ fail('deploy 不接受位置参数;使用 --workspace <name>');
251
+ if (!o.workspace)
252
+ fail('deploy 必须显式传 --workspace <name>');
253
+ const modes = [
254
+ Boolean(o.status), Boolean(o.list), Boolean(o['dry-run']), Boolean(o.yes && !o.status),
255
+ ]
256
+ .filter(Boolean).length;
257
+ if (modes !== 1) {
258
+ fail('deploy 必须且只能选择 --dry-run、--yes、--status 或 --list 之一');
259
+ }
260
+ const timeoutMs = parseOptionalTimeout(o.timeout, '--timeout');
261
+ const smokeTimeoutMs = parseOptionalTimeout(o['smoke-timeout'], '--smoke-timeout');
262
+ let out;
263
+ if (o.list) {
264
+ if (o.execute || o['operation-id'] || o.retire || o['plan-id'] || o['no-wait'] ||
265
+ o.timeout || o['smoke-timeout']) {
266
+ fail('deploy --list 只接受 --workspace 和 --json');
267
+ }
268
+ out = listMulticaDeployments(PROJECT_START, o.workspace, PACKAGE_JSON.version);
269
+ }
270
+ else if (o.status) {
271
+ if (o.retire || o['plan-id'] || o['no-wait'] || o['dry-run'] || o['smoke-timeout']) {
272
+ fail('deploy --status 不接受 retire/plan-id/no-wait/dry-run/smoke-timeout');
273
+ }
274
+ if (Boolean(o.execute) !== Boolean(o.yes)) {
275
+ fail('deploy --status 远端 reconcile 必须同时传 --execute --yes');
276
+ }
277
+ out = statusMulticaDeployment(PROJECT_START, o.workspace, {
278
+ execute: o.execute, yes: o.yes, operationId: o['operation-id'], timeoutMs,
279
+ cliVersion: PACKAGE_JSON.version,
280
+ });
281
+ }
282
+ else if (o['dry-run']) {
283
+ if (o.execute || o['operation-id'] || o['plan-id'] || o['no-wait'] ||
284
+ o.timeout || o['smoke-timeout']) {
285
+ fail('deploy --dry-run 不接受 execute/operation-id/plan-id/no-wait/timeout/smoke-timeout');
286
+ }
287
+ out = planMulticaDeployment(PROJECT_START, o.workspace, {
288
+ action: o.retire ? 'retire' : 'apply', cliVersion: PACKAGE_JSON.version,
289
+ });
290
+ }
291
+ else {
292
+ if (o.execute || o['operation-id'] || o.status || o.list || o['dry-run']) {
293
+ fail('deploy apply 不接受 execute/operation-id/status/list/dry-run');
294
+ }
295
+ if (o.retire && (o['no-wait'] || o['smoke-timeout'])) {
296
+ fail('deploy --retire 不接受 no-wait/smoke-timeout');
297
+ }
298
+ out = applyMulticaDeployment(PROJECT_START, o.workspace, {
299
+ yes: o.yes, planId: o['plan-id'], noWait: o['no-wait'],
300
+ timeoutMs, smokeTimeoutMs, cliVersion: PACKAGE_JSON.version,
301
+ }, o.retire ? 'retire' : 'apply');
302
+ }
303
+ if (o.json)
304
+ console.log(JSON.stringify(out, null, 2));
305
+ else
306
+ printMulticaDeployment(out);
307
+ if ('passed' in out && out.passed === false && out.status !== 'verifying')
308
+ process.exitCode = 2;
309
+ return;
310
+ }
311
+ if (cmd === 'promote') {
312
+ requireSupportedAgentPlatform('promote', PROJECT_START);
313
+ const { values: o, positionals } = parseArgs({
314
+ args: argv.slice(1), allowPositionals: true,
315
+ options: {
316
+ policy: { type: 'string' }, route: { type: 'string' },
317
+ 'dry-run': { type: 'boolean' }, yes: { type: 'boolean' }, json: { type: 'boolean' },
318
+ 'plan-id': { type: 'string' }, status: { type: 'boolean' }, list: { type: 'boolean' },
319
+ 'promotion-id': { type: 'string' }, 'no-wait': { type: 'boolean' },
320
+ timeout: { type: 'string' }, 'smoke-timeout': { type: 'string' },
321
+ },
322
+ });
323
+ if (positionals.length)
324
+ fail('promote 不接受位置参数');
325
+ const modes = [Boolean(o['dry-run']), Boolean(o.yes), Boolean(o.status), Boolean(o.list)]
326
+ .filter(Boolean).length;
327
+ if (modes !== 1)
328
+ fail('promote 必须且只能选择 --dry-run、--yes、--status 或 --list 之一');
329
+ let out;
330
+ if (o.list) {
331
+ if (o.policy || o.route || o['plan-id'] || o['promotion-id'] || o['no-wait'] ||
332
+ o.timeout || o['smoke-timeout'])
333
+ fail('promote --list 只接受 --json');
334
+ out = listPromotions(PROJECT_START);
335
+ }
336
+ else if (o.status) {
337
+ if (o.policy || o.route || o['plan-id'] || o['no-wait'] || o.timeout || o['smoke-timeout']) {
338
+ fail('promote --status 只接受 --promotion-id 和 --json');
339
+ }
340
+ out = statusPromotion(PROJECT_START, o['promotion-id'] || '');
341
+ }
342
+ else {
343
+ if (!o.policy || !o.route)
344
+ fail('promote dry-run/apply 必须传 --policy <file> --route <id>');
345
+ if (o['promotion-id'])
346
+ fail('promote dry-run/apply 不接受 --promotion-id');
347
+ if (o['dry-run']) {
348
+ if (o['plan-id'] || o['no-wait'] || o.timeout || o['smoke-timeout']) {
349
+ fail('promote --dry-run 不接受 plan-id/no-wait/timeout/smoke-timeout');
350
+ }
351
+ out = planPromotion(PROJECT_START, o.policy, o.route, { cliVersion: PACKAGE_JSON.version });
352
+ }
353
+ else {
354
+ out = applyPromotion(PROJECT_START, o.policy, o.route, {
355
+ yes: true, planId: o['plan-id'], noWait: o['no-wait'],
356
+ timeoutMs: parseOptionalTimeout(o.timeout, '--timeout'),
357
+ smokeTimeoutMs: parseOptionalTimeout(o['smoke-timeout'], '--smoke-timeout'),
358
+ cliVersion: PACKAGE_JSON.version,
359
+ });
360
+ }
361
+ }
362
+ if (o.json)
363
+ console.log(JSON.stringify(out, null, 2));
364
+ else
365
+ printPromotion(out);
366
+ if ('passed' in out && out.passed === false && out.status !== 'verifying' && out.status !== 'missing') {
367
+ process.exitCode = 2;
368
+ }
369
+ return;
370
+ }
371
+ if (cmd === 'observe') {
372
+ requireSupportedAgentPlatform('observe', PROJECT_START);
373
+ const { values: o, positionals } = parseArgs({
374
+ args: argv.slice(1), allowPositionals: true,
375
+ options: {
376
+ 'promotion-id': { type: 'string' }, input: { type: 'string' },
377
+ 'dry-run': { type: 'boolean' }, yes: { type: 'boolean' }, json: { type: 'boolean' },
378
+ },
379
+ });
380
+ if (positionals.length)
381
+ fail('observe 不接受位置参数');
382
+ if (!o['promotion-id'] || !o.input) {
383
+ fail('observe 必须传 --promotion-id <id> --input <observation.json>');
384
+ }
385
+ if (Boolean(o['dry-run']) === Boolean(o.yes)) {
386
+ fail('observe 必须且只能选择 --dry-run 或 --yes');
387
+ }
388
+ const out = o['dry-run']
389
+ ? planObservation(PROJECT_START, o['promotion-id'], o.input)
390
+ : applyObservation(PROJECT_START, o['promotion-id'], o.input, { yes: true });
391
+ if (o.json)
392
+ console.log(JSON.stringify(out, null, 2));
393
+ else
394
+ printPromotion(out);
395
+ return;
396
+ }
397
+ // ── Project / Development Workspace:W1 只读发现、状态与 Provider 诊断。──
398
+ if (cmd === 'info') {
399
+ const { values: o } = parseArgs({
400
+ args: argv.slice(1), options: { json: { type: 'boolean' } },
401
+ });
402
+ const out = inspectAgentProject(PROJECT_START, PACKAGE_JSON.version);
403
+ if (o.json)
404
+ console.log(JSON.stringify(out, null, 2));
405
+ else
406
+ printProjectInfo(out);
407
+ return;
408
+ }
409
+ if (cmd === 'workspace') {
410
+ const { values: o, positionals } = parseArgs({
411
+ args: argv.slice(2), allowPositionals: true,
412
+ options: {
413
+ json: { type: 'boolean' }, yes: { type: 'boolean' },
414
+ 'dry-run': { type: 'boolean' }, execute: { type: 'boolean' },
415
+ 'prompt-file': { type: 'string' }, suite: { type: 'string' },
416
+ cases: { type: 'string' }, lanes: { type: 'string' }, runs: { type: 'string' },
417
+ out: { type: 'string' }, timeout: { type: 'string' },
418
+ 'previous-skill': { type: 'string' },
419
+ },
420
+ });
421
+ if (sub === 'list') {
422
+ rejectWorkspaceOptions(o, ['json'], 'workspace list');
423
+ if (positionals.length)
424
+ fail('workspace list 不接受 Workspace name');
425
+ const info = inspectAgentProject(PROJECT_START, PACKAGE_JSON.version);
426
+ const out = {
427
+ $schema: 'dingtalk-agent/workspace-list@1',
428
+ root: info.root,
429
+ currentWorkspace: info.currentWorkspace,
430
+ workspaces: info.workspaces,
431
+ sideEffect: false,
432
+ dingtalkSideEffect: false,
433
+ };
434
+ if (o.json)
435
+ console.log(JSON.stringify(out, null, 2));
436
+ else
437
+ printWorkspaceList(info);
438
+ return;
439
+ }
440
+ if (sub === 'show') {
441
+ rejectWorkspaceOptions(o, ['json'], 'workspace show');
442
+ if (positionals.length !== 1)
443
+ fail('workspace show 需要且只接受一个 Workspace name');
444
+ const workspace = showDevelopmentWorkspace(PROJECT_START, positionals[0], PACKAGE_JSON.version);
445
+ const out = {
446
+ $schema: 'dingtalk-agent/development-workspace@1',
447
+ ...workspace,
448
+ sideEffect: false,
449
+ dingtalkSideEffect: false,
450
+ };
451
+ if (o.json)
452
+ console.log(JSON.stringify(out, null, 2));
453
+ else
454
+ printDevelopmentWorkspace(workspace);
455
+ return;
456
+ }
457
+ if (sub === 'doctor') {
458
+ rejectWorkspaceOptions(o, ['json'], 'workspace doctor');
459
+ if (positionals.length !== 1)
460
+ fail('workspace doctor 需要且只接受一个 Workspace name');
461
+ const out = doctorDevelopmentWorkspace(PROJECT_START, positionals[0], {
462
+ cliVersion: PACKAGE_JSON.version,
463
+ });
464
+ if (o.json)
465
+ console.log(JSON.stringify(out, null, 2));
466
+ else
467
+ printDevelopmentWorkspaceDoctor(out);
468
+ if (!out.ready)
469
+ process.exitCode = 2;
470
+ return;
471
+ }
472
+ if (sub === 'plan') {
473
+ rejectWorkspaceOptions(o, ['json', 'dry-run'], 'workspace plan');
474
+ if (positionals.length !== 1)
475
+ fail('workspace plan 需要且只接受一个 Multica Workspace name');
476
+ const out = planMulticaWorkspace(PROJECT_START, positionals[0], {
477
+ cliVersion: PACKAGE_JSON.version,
478
+ });
479
+ if (o.json)
480
+ console.log(JSON.stringify(out, null, 2));
481
+ else
482
+ printMulticaWorkspaceOperation(out);
483
+ if (out.blocking.length)
484
+ process.exitCode = 2;
485
+ return;
486
+ }
487
+ if (sub === 'inspect') {
488
+ rejectWorkspaceOptions(o, ['json', 'execute', 'yes', 'out', 'timeout'], 'workspace inspect');
489
+ if (positionals.length !== 1)
490
+ fail('workspace inspect 需要且只接受一个 Multica Workspace name');
491
+ if (Boolean(o.execute) !== Boolean(o.yes)) {
492
+ fail('workspace inspect 读取远端时必须同时传 --execute --yes');
493
+ }
494
+ const timeoutMs = o.timeout === undefined ? undefined : Number(o.timeout);
495
+ const out = inspectMulticaWorkspace(PROJECT_START, positionals[0], {
496
+ execute: o.execute, yes: o.yes, out: o.out, timeoutMs,
497
+ cliVersion: PACKAGE_JSON.version,
498
+ });
499
+ if (o.json)
500
+ console.log(JSON.stringify(out, null, 2));
501
+ else
502
+ printMulticaWorkspaceOperation(out);
503
+ if (o.execute && 'passed' in out && !out.passed)
504
+ process.exitCode = 2;
505
+ return;
506
+ }
507
+ if (sub === 'remote-list') {
508
+ rejectWorkspaceOptions(o, ['json', 'execute', 'yes', 'timeout'], 'workspace remote-list');
509
+ if (positionals.length !== 1)
510
+ fail('workspace remote-list 需要且只接受一个 Multica Workspace name');
511
+ if (Boolean(o.execute) !== Boolean(o.yes)) {
512
+ fail('workspace remote-list 读取远端时必须同时传 --execute --yes');
513
+ }
514
+ const timeoutMs = o.timeout === undefined ? undefined : Number(o.timeout);
515
+ const out = listMulticaWorkspaceResources(PROJECT_START, positionals[0], {
516
+ execute: o.execute, yes: o.yes, timeoutMs, cliVersion: PACKAGE_JSON.version,
517
+ });
518
+ if (o.json)
519
+ console.log(JSON.stringify(out, null, 2));
520
+ else
521
+ printMulticaWorkspaceOperation(out);
522
+ if (o.execute && 'passed' in out && !out.passed)
523
+ process.exitCode = 2;
524
+ return;
525
+ }
526
+ if (sub === 'status') {
527
+ rejectWorkspaceOptions(o, ['json'], 'workspace status');
528
+ if (positionals.length !== 1)
529
+ fail('workspace status 需要且只接受一个 Multica Workspace name');
530
+ const out = statusMulticaWorkspace(PROJECT_START, positionals[0], PACKAGE_JSON.version);
531
+ if (o.json)
532
+ console.log(JSON.stringify(out, null, 2));
533
+ else
534
+ printMulticaWorkspaceOperation(out);
535
+ if (!out.readyForApply)
536
+ process.exitCode = 2;
537
+ return;
538
+ }
539
+ if (sub === 'create') {
540
+ rejectWorkspaceOptions(o, ['json', 'yes', 'dry-run'], 'workspace create');
541
+ if (positionals.length !== 1)
542
+ fail('workspace create 需要且只接受一个 Workspace name');
543
+ if (o.yes && o['dry-run'])
544
+ fail('workspace create 的 --dry-run 与 --yes 不能同时使用');
545
+ const out = o.yes
546
+ ? applyOpenCodeWorkspace(PROJECT_START, positionals[0], {
547
+ yes: true, cliVersion: PACKAGE_JSON.version,
548
+ })
549
+ : planOpenCodeWorkspace(PROJECT_START, positionals[0], PACKAGE_JSON.version);
550
+ if (o.json)
551
+ console.log(JSON.stringify(out, null, 2));
552
+ else
553
+ printOpenCodeWorkspaceOperation(out);
554
+ return;
555
+ }
556
+ if (sub === 'use') {
557
+ rejectWorkspaceOptions(o, ['json'], 'workspace use');
558
+ if (positionals.length !== 1)
559
+ fail('workspace use 需要且只接受一个 Workspace name');
560
+ const out = useOpenCodeWorkspace(PROJECT_START, positionals[0], PACKAGE_JSON.version);
561
+ if (o.json)
562
+ console.log(JSON.stringify(out, null, 2));
563
+ else
564
+ console.log(`✅ current workspace: ${out.previous || '-'} → ${out.current}`);
565
+ return;
566
+ }
567
+ if (sub === 'run') {
568
+ rejectWorkspaceOptions(o, ['json', 'yes', 'execute', 'prompt-file', 'out', 'timeout'], 'workspace run');
569
+ if (positionals.length !== 1 || !o['prompt-file']) {
570
+ fail('workspace run 需要一个 Workspace name 和 --prompt-file <file>');
571
+ }
572
+ const timeoutMs = o.timeout === undefined ? undefined : Number(o.timeout);
573
+ const prompt = readProjectText(PROJECT_START, o['prompt-file'], 'workspace run prompt');
574
+ const out = runOpenCodeWorkspace(PROJECT_START, positionals[0], prompt, {
575
+ execute: o.execute, yes: o.yes, timeoutMs, out: o.out,
576
+ });
577
+ if (o.json)
578
+ console.log(JSON.stringify(out, null, 2));
579
+ else if (out.$schema === 'dingtalk-agent/opencode-workspace-run-plan@1') {
580
+ console.log(`DRY-RUN workspace=${out.workspace} model=${out.model} prompt=${out.promptHash}`);
581
+ }
582
+ else {
583
+ console.log(`${out.passed ? '✅' : '❌'} workspace run ${out.runId}`);
584
+ if (out.execution?.answer)
585
+ console.log(out.execution.answer);
586
+ if (out.evidencePath)
587
+ console.log(`evidence=${out.evidencePath}`);
588
+ }
589
+ if (o.execute && !out.passed)
590
+ process.exitCode = 2;
591
+ return;
592
+ }
593
+ if (sub === 'eval') {
594
+ rejectWorkspaceOptions(o, ['json', 'yes', 'execute', 'suite', 'cases', 'lanes', 'runs', 'out', 'previous-skill'], 'workspace eval');
595
+ if (positionals.length !== 1 || !o.suite) {
596
+ fail('workspace eval 需要一个 Workspace name 和 --suite <file>');
597
+ }
598
+ const lanes = String(o.lanes || '').split(',').map((item) => item.trim()).filter(Boolean);
599
+ const invalid = lanes.filter((item) => !['stateless', 'stateful', 'role'].includes(item));
600
+ if (invalid.length)
601
+ fail(`workspace eval lanes 非法: ${invalid.join(',')}`);
602
+ const cases = String(o.cases || '').split(',').map((item) => item.trim()).filter(Boolean);
603
+ const runs = o.runs === undefined ? undefined : Number(o.runs);
604
+ const out = evalOpenCodeWorkspace(PROJECT_START, positionals[0], o.suite, {
605
+ lanes: lanes, caseIds: cases, runs, out: o.out,
606
+ previousSkill: o['previous-skill'], execute: o.execute, yes: o.yes,
607
+ });
608
+ if (o.json)
609
+ console.log(JSON.stringify(out, null, 2));
610
+ else
611
+ printLab(out.report || out);
612
+ if (o.execute && !out.passed)
613
+ process.exitCode = 2;
614
+ return;
615
+ }
616
+ fail(`不认识的 workspace 子命令: ${sub || '(缺失)'}`, 1, `可用命令: dta workspace list | show | doctor | plan | inspect | remote-list | status | create | use | run | eval${suggest(sub || '', ['list', 'show', 'doctor', 'plan', 'inspect', 'remote-list', 'status', 'create', 'use', 'run', 'eval'], 'dta workspace')}`);
617
+ }
618
+ // ── setup / upgrade / doctor:机器级安装与环境闭环。──
141
619
  if (cmd === 'setup') {
142
620
  const { values: o } = parseArgs({
143
621
  args: argv.slice(1),
@@ -174,53 +652,147 @@ async function main() {
174
652
  process.exitCode = 2;
175
653
  return;
176
654
  }
655
+ if (cmd === 'upgrade') {
656
+ const { values: o } = parseArgs({
657
+ args: argv.slice(1),
658
+ options: {
659
+ channel: { type: 'string' }, version: { type: 'string' }, prefix: { type: 'string' },
660
+ 'dry-run': { type: 'boolean' }, force: { type: 'boolean' }, json: { type: 'boolean' },
661
+ },
662
+ });
663
+ const out = upgradeAgent(PACKAGE_ROOT, {
664
+ channel: o.channel,
665
+ version: o.version, prefix: o.prefix,
666
+ dryRun: o['dry-run'], force: o.force,
667
+ });
668
+ if (o.json)
669
+ console.log(JSON.stringify(out, null, 2));
670
+ else
671
+ printUpgrade(out);
672
+ if (!out.dryRun && !out.ready)
673
+ process.exitCode = 2;
674
+ return;
675
+ }
177
676
  // ── skill:唯一一次性的主入口;完全不依赖 Workspace。──
178
677
  if (cmd === 'skill') {
179
- const { values: o } = parseArgs({
678
+ const { values: o, positionals } = parseArgs({
180
679
  args: argv.slice(2),
680
+ allowPositionals: true,
181
681
  options: {
182
- 'dry-run': { type: 'boolean' }, json: { type: 'boolean' },
183
- 'discard-local-changes': { type: 'boolean' },
682
+ name: { type: 'string' }, 'dry-run': { type: 'boolean' }, json: { type: 'boolean' },
184
683
  },
185
684
  });
186
- const options = {
187
- dryRun: o['dry-run'],
188
- discardLocalChanges: o['discard-local-changes'],
189
- };
685
+ if (positionals.length > 1)
686
+ fail('skill 最多接受一个 Skill name');
687
+ const name = o.name || positionals[0];
688
+ const dryRun = Boolean(o['dry-run']);
190
689
  let out;
191
- if (sub === 'install')
192
- out = installGlobalSkill(PACKAGE_ROOT, options);
193
- else if (sub === 'status')
194
- out = skillStatus(PACKAGE_ROOT, options);
195
- else if (sub === 'upgrade')
196
- out = upgradeGlobalSkill(PACKAGE_ROOT, options);
197
- else if (sub === 'uninstall')
198
- out = uninstallGlobalSkill(PACKAGE_ROOT, options);
199
- else
200
- fail('skill 的子命令: install / status / upgrade / uninstall');
690
+ if (sub === 'install') {
691
+ out = name
692
+ ? installGlobalSkill(PACKAGE_ROOT, { dryRun, name })
693
+ : installBundledSkills(PACKAGE_ROOT, { dryRun });
694
+ }
695
+ else if (sub === 'status') {
696
+ out = name ? skillStatus(PACKAGE_ROOT, { dryRun, name }) : skillSuiteStatus(PACKAGE_ROOT, { dryRun });
697
+ }
698
+ else if (sub === 'upgrade') {
699
+ out = name
700
+ ? upgradeGlobalSkill(PACKAGE_ROOT, { dryRun, name })
701
+ : upgradeBundledSkills(PACKAGE_ROOT, { dryRun });
702
+ }
703
+ else if (sub === 'uninstall') {
704
+ out = name
705
+ ? uninstallGlobalSkill(PACKAGE_ROOT, { dryRun, name })
706
+ : uninstallBundledSkills(PACKAGE_ROOT, { dryRun });
707
+ }
708
+ else {
709
+ fail(`不认识的 skill 子命令: ${sub || '(缺失)'}`, 1, `可用命令: dta skill install | status | upgrade | uninstall${suggest(sub || '', ['install', 'status', 'upgrade', 'uninstall'], 'dta skill')}`);
710
+ }
201
711
  if (o.json)
202
712
  console.log(JSON.stringify(out, null, 2));
713
+ else if ('skills' in out)
714
+ for (const item of out.skills)
715
+ printSkillStatus(item, sub, dryRun);
203
716
  else
204
- printSkillStatus(out, sub, Boolean(o['dry-run']));
717
+ printSkillStatus(out, sub, dryRun);
205
718
  return;
206
719
  }
720
+ // ── agent-platform:工作区归属的 managed agent platform;平台工具包按选择惰性安装。──
721
+ if (cmd === 'agent-platform') {
722
+ const { values: o, positionals } = parseArgs({
723
+ args: argv.slice(2),
724
+ allowPositionals: true,
725
+ options: { json: { type: 'boolean' }, 'no-install': { type: 'boolean' } },
726
+ });
727
+ if (sub === 'list') {
728
+ if (positionals.length)
729
+ fail('agent-platform list 不接受位置参数');
730
+ const out = { $schema: 'dingtalk-agent/agent-platform-list@1', platforms: MANAGED_AGENT_PLATFORMS };
731
+ if (o.json)
732
+ console.log(JSON.stringify(out, null, 2));
733
+ else
734
+ for (const platform of MANAGED_AGENT_PLATFORMS)
735
+ printAgentPlatform(platform);
736
+ return;
737
+ }
738
+ if (sub === 'show') {
739
+ if (positionals.length)
740
+ fail('agent-platform show 不接受位置参数');
741
+ const out = resolveAgentPlatform(PROJECT_START);
742
+ if (o.json)
743
+ console.log(JSON.stringify(out, null, 2));
744
+ else
745
+ printAgentPlatformResolution(out);
746
+ return;
747
+ }
748
+ if (sub === 'use') {
749
+ if (positionals.length !== 1)
750
+ fail('agent-platform use 需要且只接受一个 platform name');
751
+ const out = useAgentPlatform(PROJECT_START, positionals[0], {
752
+ packageRoot: PACKAGE_ROOT, installSkills: !o['no-install'],
753
+ });
754
+ if (o.json)
755
+ console.log(JSON.stringify(out, null, 2));
756
+ else {
757
+ console.log(`✅ 工作区已归属 ${out.definition?.label}(写入 ${out.written})`);
758
+ for (const install of out.skillInstalls)
759
+ printSkillStatus(install, 'install', false);
760
+ if (!out.skillInstalls.length) {
761
+ console.log(out.definition?.skills.length
762
+ ? ` 已跳过平台技能包安装(--no-install):${out.definition.skills.join(', ')}`
763
+ : ' 该平台无需额外技能包。');
764
+ }
765
+ }
766
+ return;
767
+ }
768
+ fail(`不认识的 agent-platform 子命令: ${sub || '(缺失)'}`, 1, `可用命令: dta agent-platform list | show | use <platform>${suggest(sub || '', ['list', 'show', 'use'], 'dta agent-platform')}`);
769
+ }
207
770
  // ── bootstrap:当前 Agent Session 按需发现/拉取语义上下文。──
208
771
  if (cmd === 'bootstrap') {
209
772
  const { values: o } = parseArgs({
210
773
  args: argv.slice(1),
211
774
  options: {
212
- storage: { type: 'string' }, 'state-dir': { type: 'string' },
213
- profile: { type: 'string' }, json: { type: 'boolean' },
775
+ agent: { type: 'string' }, storage: { type: 'string' },
776
+ memory: { type: 'string' }, knowledge: { type: 'string' },
777
+ skills: { type: 'string' }, artifacts: { type: 'string' },
778
+ 'state-dir': { type: 'string' }, profile: { type: 'string' },
779
+ 'expected-user-id': { type: 'string' }, bindings: { type: 'string' },
780
+ json: { type: 'boolean' },
214
781
  },
215
782
  });
783
+ const loaded = loadConventionalBindings(o.bindings);
216
784
  const out = bootstrap(ROOT, {
217
- storage: o.storage, stateDir: o['state-dir'], profile: o.profile,
785
+ agent: o.agent, storage: o.storage,
786
+ memory: o.memory, knowledge: o.knowledge, skills: o.skills,
787
+ artifacts: o.artifacts, stateDir: o['state-dir'], profile: o.profile,
788
+ expectedUserId: o['expected-user-id'], context: loaded?.context,
218
789
  });
219
790
  if (o.json)
220
791
  console.log(JSON.stringify(out, null, 2));
221
792
  else {
222
793
  console.log(`✅ ${out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式'}`);
223
794
  console.log(` scope=${out.scopeId} initialized=${out.initialized}`);
795
+ console.log(` agent=${out.definition.id} definition=${out.definition.status}`);
224
796
  if (!out.mounts.length)
225
797
  console.log(' 没有发现持久上下文;这不是错误,也不需要自动 init。');
226
798
  for (const mount of out.mounts)
@@ -229,6 +801,189 @@ async function main() {
229
801
  }
230
802
  return;
231
803
  }
804
+ // ── agent audit:本地定义、Host exposure、真加载与存储证据的稳定验收面。──
805
+ if (cmd === 'agent') {
806
+ if (!['audit', 'enhance'].includes(sub || ''))
807
+ fail(`不认识的 agent 子命令: ${sub || '(缺失)'}`, 1, `可用命令: dta agent audit / dta agent enhance${suggest(sub || '', ['audit', 'enhance'], 'dta agent')}`);
808
+ if (sub === 'enhance') {
809
+ const { values: o } = parseArgs({
810
+ args: argv.slice(2),
811
+ options: {
812
+ bindings: { type: 'string' }, 'project-name': { type: 'string' },
813
+ 'role-skill': { type: 'string' }, model: { type: 'string' },
814
+ memory: { type: 'string' }, knowledge: { type: 'string' },
815
+ artifacts: { type: 'string' }, 'state-dir': { type: 'string' },
816
+ profile: { type: 'string' }, 'expected-user-id': { type: 'string' },
817
+ 'plan-id': { type: 'string' }, 'dry-run': { type: 'boolean' },
818
+ yes: { type: 'boolean' }, json: { type: 'boolean' },
819
+ },
820
+ });
821
+ if (o.yes && o['dry-run'])
822
+ fail('agent enhance 的 --dry-run 与 --yes 不能同时使用');
823
+ if (!o.yes && o['plan-id'])
824
+ fail('agent enhance plan 不接受 --plan-id;它由 dry-run 生成');
825
+ const options = {
826
+ bindings: o.bindings, projectName: o['project-name'],
827
+ roleSkills: o['role-skill']?.split(','), model: o.model,
828
+ memory: o.memory, knowledge: o.knowledge, artifacts: o.artifacts,
829
+ stateDir: o['state-dir'], profile: o.profile,
830
+ expectedUserId: o['expected-user-id'], cliVersion: PACKAGE_JSON.version,
831
+ planId: o['plan-id'], yes: o.yes,
832
+ };
833
+ const out = o.yes
834
+ ? applyAgentEnhancement(ROOT, options)
835
+ : planAgentEnhancement(ROOT, options);
836
+ if (o.json)
837
+ console.log(JSON.stringify(out, null, 2));
838
+ else
839
+ printAgentEnhance(out);
840
+ if ('$schema' in out && out.$schema === 'dingtalk-agent/agent-enhancement-plan@1' && !out.ready) {
841
+ process.exitCode = 2;
842
+ }
843
+ return;
844
+ }
845
+ const { values: o } = parseArgs({
846
+ args: argv.slice(2),
847
+ options: {
848
+ bindings: { type: 'string' }, agent: { type: 'string' }, storage: { type: 'string' },
849
+ memory: { type: 'string' }, knowledge: { type: 'string' },
850
+ skills: { type: 'string' }, artifacts: { type: 'string' },
851
+ 'state-dir': { type: 'string' }, profile: { type: 'string' },
852
+ 'expected-user-id': { type: 'string' }, 'require-skill': { type: 'string' },
853
+ 'verify-load': { type: 'boolean' }, yes: { type: 'boolean' },
854
+ model: { type: 'string' }, out: { type: 'string' },
855
+ 'load-report': { type: 'string' }, 'remote-report': { type: 'string' },
856
+ json: { type: 'boolean' },
857
+ },
858
+ });
859
+ const loaded = loadConventionalBindings(o.bindings);
860
+ const out = auditAgent(ROOT, {
861
+ bootstrap: {
862
+ agent: o.agent, storage: o.storage,
863
+ memory: o.memory, knowledge: o.knowledge, skills: o.skills,
864
+ artifacts: o.artifacts, stateDir: o['state-dir'], profile: o.profile,
865
+ expectedUserId: o['expected-user-id'], context: loaded?.context,
866
+ },
867
+ bindings: loaded ? { path: loaded.path, hash: loaded.hash } : undefined,
868
+ requiredSkills: o['require-skill']?.split(','),
869
+ verifyLoad: o['verify-load'], yes: o.yes, model: o.model, out: o.out,
870
+ loadReport: o['load-report'], remoteReport: o['remote-report'],
871
+ });
872
+ if (o.json)
873
+ console.log(JSON.stringify(out, null, 2));
874
+ else
875
+ printAgentAudit(out);
876
+ if (!out.ready)
877
+ process.exitCode = 2;
878
+ return;
879
+ }
880
+ // ── lab:测试控制面;默认无副作用,Live 必须 manifest + --live --yes。──
881
+ if (cmd === 'lab') {
882
+ const { values: o } = parseArgs({
883
+ args: argv.slice(2),
884
+ options: {
885
+ manifest: { type: 'string' }, evidence: { type: 'string' },
886
+ 'event-file': { type: 'string' }, 'case-id': { type: 'string' },
887
+ pool: { type: 'string' }, suite: { type: 'string' }, lanes: { type: 'string' },
888
+ cases: { type: 'string' },
889
+ engine: { type: 'string' }, workspace: { type: 'string' }, model: { type: 'string' },
890
+ runs: { type: 'string' }, out: { type: 'string' },
891
+ 'previous-skill': { type: 'string' }, execute: { type: 'boolean' },
892
+ reply: { type: 'string' }, input: { type: 'string' },
893
+ live: { type: 'boolean' }, yes: { type: 'boolean' }, json: { type: 'boolean' },
894
+ },
895
+ });
896
+ let out;
897
+ if (sub === 'doctor') {
898
+ if (!o.manifest)
899
+ fail('lab doctor 需要 --manifest <file>');
900
+ out = doctorLab(ROOT, o.manifest);
901
+ if (!out.ready)
902
+ process.exitCode = 2;
903
+ }
904
+ else if (sub === 'run') {
905
+ if (!o.manifest || !o['case-id'])
906
+ fail('lab run 需要 --manifest 和 --case-id');
907
+ const rawEvent = o['event-file']
908
+ ? readEventFile(o['event-file']) : null;
909
+ out = runLab(ROOT, cfgmod.must(ROOT), o.manifest, rawEvent, {
910
+ caseId: o['case-id'], replyText: o.reply, inputText: o.input,
911
+ live: o.live, yes: o.yes,
912
+ });
913
+ }
914
+ else if (sub === 'verify') {
915
+ if (!o.evidence)
916
+ fail('lab verify 需要 --evidence <run-dir>');
917
+ out = verifyLab(ROOT, o.evidence);
918
+ if (!out.passed)
919
+ process.exitCode = 2;
920
+ }
921
+ else if (sub === 'teardown') {
922
+ if (!o.manifest || !o.evidence)
923
+ fail('lab teardown 需要 --manifest 和 --evidence');
924
+ out = teardownLab(ROOT, o.manifest, o.evidence, { live: o.live, yes: o.yes });
925
+ }
926
+ else if (sub === 'eval') {
927
+ if (!o.suite)
928
+ fail('lab eval 需要 --suite');
929
+ const lanes = String(o.lanes || '').split(',').map((item) => item.trim()).filter(Boolean);
930
+ const invalid = lanes.filter((item) => !['stateless', 'stateful', 'role'].includes(item));
931
+ if (invalid.length)
932
+ fail(`lab eval lanes 非法: ${invalid.join(',')}`);
933
+ const cases = String(o.cases || '').split(',').map((item) => item.trim()).filter(Boolean);
934
+ const engine = o.engine || 'robot';
935
+ if (engine === 'opencode') {
936
+ if (!o.workspace)
937
+ fail('OpenCode eval 需要 --workspace <agent-dir>');
938
+ const runs = o.runs === undefined ? undefined : Number(o.runs);
939
+ out = runOpenCodeEvaluation(ROOT, o.workspace, o.suite, {
940
+ lanes: lanes, model: o.model, runs,
941
+ caseIds: cases, previousSkill: o['previous-skill'],
942
+ execute: o.execute, yes: o.yes, out: o.out,
943
+ });
944
+ if (o.execute && !out.passed)
945
+ process.exitCode = 2;
946
+ }
947
+ else if (engine === 'storage') {
948
+ if (!o.workspace)
949
+ fail('Remote State eval 需要 --workspace <agent-dir>');
950
+ out = runStorageEvaluation(ROOT, o.workspace, o.suite, {
951
+ model: o.model, execute: o.execute, live: o.live, yes: o.yes, out: o.out,
952
+ });
953
+ if (o.execute && !out.passed)
954
+ process.exitCode = 2;
955
+ }
956
+ else if (engine === 'personal-event') {
957
+ if (!o.workspace)
958
+ fail('Personal Event eval 需要 --workspace <agent-dir>');
959
+ out = runPersonalEventEvaluation(ROOT, o.workspace, o.suite, {
960
+ execute: o.execute, live: o.live, yes: o.yes, out: o.out,
961
+ });
962
+ if (o.execute && !out.passed)
963
+ process.exitCode = 2;
964
+ }
965
+ else if (engine === 'robot') {
966
+ if (!o.pool)
967
+ fail('Robot eval 需要 --pool <pool.local.json>');
968
+ out = runRobotEvaluation(ROOT, o.pool, o.suite, {
969
+ lanes: lanes, live: o.live, yes: o.yes,
970
+ });
971
+ if (o.live && !out.passed)
972
+ process.exitCode = 2;
973
+ }
974
+ else {
975
+ fail(`lab eval engine 非法: ${engine};只支持 robot、opencode、storage 或 personal-event`);
976
+ }
977
+ }
978
+ else {
979
+ fail(`不认识的 lab 子命令: ${sub || '(缺失)'}`, 1, '可用命令: dta lab doctor | run | verify | teardown | eval;详见 dta help lab。');
980
+ }
981
+ if (o.json)
982
+ console.log(JSON.stringify(out, null, 2));
983
+ else
984
+ printLab(out);
985
+ return;
986
+ }
232
987
  // ── init ──
233
988
  if (cmd === 'init') {
234
989
  const { values: o } = parseArgs({
@@ -253,6 +1008,7 @@ async function main() {
253
1008
  options: {
254
1009
  'event-file': { type: 'string' }, field: { type: 'string' },
255
1010
  'session-key': { type: 'string' }, 'context-id': { type: 'string' },
1011
+ 'perception-file': { type: 'string' },
256
1012
  json: { type: 'boolean' },
257
1013
  },
258
1014
  });
@@ -261,6 +1017,7 @@ async function main() {
261
1017
  fail('prepare 需要 --event-file <file|->');
262
1018
  const out = prepareSession(ROOT, cfg, readEventFile(file), {
263
1019
  fieldId: o.field, sessionKey: o['session-key'], contextId: o['context-id'],
1020
+ perception: o['perception-file'] ? readEventFile(o['perception-file']) : undefined,
264
1021
  });
265
1022
  printDispatch(out, o.json);
266
1023
  return;
@@ -274,12 +1031,14 @@ async function main() {
274
1031
  stdin: { type: 'boolean' }, 'event-file': { type: 'string' },
275
1032
  field: { type: 'string' }, 'session-key': { type: 'string' },
276
1033
  'context-id': { type: 'string' },
1034
+ 'perception-file': { type: 'string' },
277
1035
  heartbeat: { type: 'boolean' }, 'heartbeat-key': { type: 'string' },
278
1036
  'heartbeat-event-id': { type: 'string' },
279
1037
  },
280
1038
  });
281
1039
  const options = {
282
1040
  fieldId: o.field, sessionKey: o['session-key'], contextId: o['context-id'],
1041
+ perception: o['perception-file'] ? readEventFile(o['perception-file']) : undefined,
283
1042
  };
284
1043
  const modes = [Boolean(o.stdin), Boolean(o.heartbeat), Boolean(o['event-file'] || positionals[0])];
285
1044
  if (modes.filter(Boolean).length !== 1) {
@@ -391,6 +1150,133 @@ async function main() {
391
1150
  }
392
1151
  fail('dispatch 的子命令: pending / ack');
393
1152
  }
1153
+ // ── task:Session 语义 checkpoint;revision CAS,不承担 Wait/锁/Receipt。──
1154
+ if (cmd === 'task') {
1155
+ const cfg = cfgmod.must(ROOT);
1156
+ const { values: o } = parseArgs({
1157
+ args: argv.slice(2),
1158
+ options: {
1159
+ input: { type: 'string' }, session: { type: 'string' },
1160
+ 'expect-revision': { type: 'string' }, json: { type: 'boolean' },
1161
+ },
1162
+ });
1163
+ let out;
1164
+ if (sub === 'show') {
1165
+ out = showTaskCheckpoint(ROOT, cfg, {
1166
+ sessionPath: o.session || process.env.DTA_SESSION,
1167
+ runPath: process.env.DTA_RUN,
1168
+ });
1169
+ }
1170
+ else if (sub === 'checkpoint') {
1171
+ if (!o.input || o['expect-revision'] === undefined) {
1172
+ fail('task checkpoint 需要 --input 和 --expect-revision');
1173
+ }
1174
+ const expectedRevision = Number(o['expect-revision']);
1175
+ out = checkpointTask(ROOT, cfg, readEventFile(o.input), expectedRevision, {
1176
+ sessionPath: o.session || process.env.DTA_SESSION,
1177
+ runPath: process.env.DTA_RUN,
1178
+ });
1179
+ }
1180
+ else {
1181
+ fail('task 的子命令: show / checkpoint');
1182
+ }
1183
+ if (o.json)
1184
+ console.log(JSON.stringify(out, null, 2));
1185
+ else if (!out.found)
1186
+ console.log('当前 Session 尚无 Task checkpoint。');
1187
+ else {
1188
+ console.log(`✅ Task ${out.checkpoint.taskId} · ${out.checkpoint.status}`);
1189
+ console.log(` revision=${out.checkpoint.revision} hash=${out.hash}`);
1190
+ console.log(` next=${out.checkpoint.nextAction || '-'}`);
1191
+ }
1192
+ return;
1193
+ }
1194
+ // ── memory:Provider-neutral 语义路由;当前首个远端事实源是 AI 表格。──
1195
+ if (cmd === 'memory') {
1196
+ const action = argv[2];
1197
+ if (sub === 'operational' && action === 'upsert') {
1198
+ const { values: o } = parseArgs({
1199
+ args: argv.slice(3),
1200
+ options: {
1201
+ provider: { type: 'string' }, input: { type: 'string' },
1202
+ live: { type: 'boolean' }, yes: { type: 'boolean' }, json: { type: 'boolean' },
1203
+ },
1204
+ });
1205
+ const providerPath = o.provider || process.env.DTA_OPERATIONAL_MEMORY_PROVIDER;
1206
+ if (!providerPath || !o.input) {
1207
+ fail('memory operational upsert 需要 --provider(或 DTA_OPERATIONAL_MEMORY_PROVIDER)和 --input');
1208
+ }
1209
+ const out = upsertOperationalMemory(readEventFile(providerPath), readEventFile(o.input), { execute: Boolean(o.live), yes: Boolean(o.yes) });
1210
+ if (o.json || !o.live)
1211
+ console.log(JSON.stringify(out, null, 2));
1212
+ else {
1213
+ console.log(`${out.verified ? '✅' : '⚠️'} Operational Memory · ${out.mode}`);
1214
+ console.log(` record=${out.recordId || '-'} verification=${out.verification}`);
1215
+ }
1216
+ if (out.mode === 'uncertain')
1217
+ process.exitCode = 2;
1218
+ return;
1219
+ }
1220
+ if (sub === 'candidate') {
1221
+ const { values: o } = parseArgs({
1222
+ args: argv.slice(3),
1223
+ options: {
1224
+ input: { type: 'string' }, id: { type: 'string' }, target: { type: 'string' },
1225
+ decision: { type: 'string' }, reviewer: { type: 'string' }, reason: { type: 'string' },
1226
+ 'state-dir': { type: 'string' }, 'expect-revision': { type: 'string' },
1227
+ 'expect-target-hash': { type: 'string' },
1228
+ live: { type: 'boolean' }, yes: { type: 'boolean' }, json: { type: 'boolean' },
1229
+ },
1230
+ });
1231
+ const options = { stateDir: o['state-dir'], runPath: process.env.DTA_RUN };
1232
+ let out;
1233
+ if (action === 'propose') {
1234
+ if (!o.input)
1235
+ fail('memory candidate propose 需要 --input');
1236
+ out = proposeMemoryCandidate(ROOT, readEventFile(o.input), options);
1237
+ }
1238
+ else if (action === 'show') {
1239
+ if (!o.id)
1240
+ fail('memory candidate show 需要 --id');
1241
+ out = showMemoryCandidate(ROOT, o.id, options);
1242
+ }
1243
+ else if (action === 'review') {
1244
+ if (!o.id || !o.decision || !o.reviewer || !o.reason ||
1245
+ o['expect-revision'] === undefined) {
1246
+ fail('memory candidate review 需要 --id/--decision/--reviewer/--reason/--expect-revision');
1247
+ }
1248
+ out = reviewMemoryCandidate(ROOT, o.id, o.decision, o.reviewer, o.reason, Number(o['expect-revision']), options);
1249
+ }
1250
+ else if (action === 'publish') {
1251
+ if (!o.id || !o.target || o['expect-revision'] === undefined) {
1252
+ fail('memory candidate publish 需要 --id/--target/--expect-revision');
1253
+ }
1254
+ out = publishMemoryCandidate(ROOT, o.id, readEventFile(o.target), Number(o['expect-revision']), o['expect-target-hash'] || '', {
1255
+ ...options,
1256
+ execute: Boolean(o.yes || o.live),
1257
+ yes: Boolean(o.yes),
1258
+ live: Boolean(o.live),
1259
+ });
1260
+ }
1261
+ else {
1262
+ fail('memory candidate 的子命令: propose / show / review / publish');
1263
+ }
1264
+ if (o.json)
1265
+ console.log(JSON.stringify(out, null, 2));
1266
+ else if (action === 'publish') {
1267
+ console.log(`${out.verified ? '✅' : out.mode === 'dry-run' ? '🔎' : '⚠️'} Candidate ${o.id}`);
1268
+ console.log(` mode=${out.mode} targetHash=${out.currentTargetHash}`);
1269
+ }
1270
+ else {
1271
+ console.log(`✅ Candidate ${out.candidate.id} · ${out.candidate.status}`);
1272
+ console.log(` revision=${out.candidate.revision} path=${out.path}`);
1273
+ }
1274
+ if (action === 'publish' && out.mode === 'uncertain')
1275
+ process.exitCode = 2;
1276
+ return;
1277
+ }
1278
+ fail('memory 当前支持: operational upsert / candidate propose|show|review|publish');
1279
+ }
394
1280
  // ── act:元语化动作;目标/身份/预算/状态转移都由 Run 固定 ──
395
1281
  if (cmd === 'act') {
396
1282
  const kind = sub;
@@ -423,284 +1309,71 @@ async function main() {
423
1309
  process.exitCode = 2;
424
1310
  return;
425
1311
  }
426
- // ── eval:宿主评测入口;shadow 永不调用 act / DWS。──
427
- if (cmd === 'eval') {
428
- const script = sub === 'contract'
429
- ? join(PACKAGE_ROOT, 'evals', 'run-contract-evals.mjs')
430
- : sub === 'shadow'
431
- ? join(PACKAGE_ROOT, 'evals', 'runners', 'claude-shadow.mjs')
432
- : sub === 'behavior'
433
- ? join(PACKAGE_ROOT, 'evals', 'run-shadow-evals.mjs')
434
- : '';
435
- if (!script)
436
- fail('eval 的子命令: contract / shadow / behavior');
437
- const childEnv = { ...process.env };
438
- // 合同评测会创建隔离工作区;继承宿主 DTA_ROOT 会让 Action Gate 错读外层 control store。
439
- delete childEnv.DTA_ROOT;
440
- const child = spawnSync(process.execPath, [script, ...argv.slice(2)], {
441
- cwd: ROOT,
442
- env: childEnv,
443
- stdio: 'inherit',
444
- });
445
- if (child.error)
446
- throw child.error;
447
- if (child.signal)
448
- throw new Error(`评测进程被 ${child.signal} 终止`);
449
- process.exitCode = child.status ?? 2;
450
- return;
1312
+ fail(`不认识的命令: ${cmd}`, 1, `运行 dta --help 查看全部命令${suggest(cmd, [
1313
+ 'setup', 'upgrade', 'doctor', 'skill', 'agent-platform', 'bootstrap', 'init', 'prepare', 'run', 'dispatch', 'task', 'memory', 'act',
1314
+ 'lab', 'listen', 'deploy', 'promote', 'observe',
1315
+ 'agent',
1316
+ 'info', 'workspace',
1317
+ ])}`);
1318
+ }
1319
+ function loadConventionalBindings(input) {
1320
+ const conventional = 'agent.bindings.json';
1321
+ const selected = input || (existsSync(resolve(ROOT, conventional)) ? conventional : '');
1322
+ return selected ? loadAgentBindings(ROOT, selected) : null;
1323
+ }
1324
+ function errorHint(message) {
1325
+ if (/unknown option|未知选项|unexpected argument/i.test(message)) {
1326
+ return '检查参数拼写;运行 dta --help 查看当前版本支持的参数。';
451
1327
  }
452
- if (cmd === 'smoke') {
453
- const script = join(PACKAGE_ROOT, 'evals', 'run-contract-evals.mjs');
454
- const childEnv = { ...process.env };
455
- delete childEnv.DTA_ROOT;
456
- const child = spawnSync(process.execPath, [script, '--smoke'], {
457
- cwd: ROOT, env: childEnv, stdio: 'inherit',
458
- });
459
- if (child.error)
460
- throw child.error;
461
- if (child.signal)
462
- throw new Error(`Smoke 被 ${child.signal} 终止`);
463
- process.exitCode = child.status ?? 2;
464
- return;
1328
+ if (/找不到当前 Run|必须由能访问 DTA_ROOT 的宿主侧执行/.test(message)) {
1329
+ return 'act 只能用于可信事件 Run;先由宿主执行 dta prepare --event-file <file>,再进入返回的 cwd。';
465
1330
  }
466
- // ── kb ──
467
- if (cmd === 'kb') {
468
- const cfg = cfgmod.must(ROOT);
469
- const { values: o } = parseArgs({
470
- args: argv.slice(2), allowPositionals: true,
471
- options: {
472
- name: { type: 'string' }, from: { type: 'string' }, own: { type: 'string' },
473
- sync: { type: 'string' }, local: { type: 'string' }, force: { type: 'boolean' },
474
- },
475
- });
476
- if (sub === 'mount') {
477
- if (!o.name || !o.from)
478
- fail('要 --name 和 --from。源的写法见 --help');
479
- kbmod.parseSource(o.from); // 写错了当场炸
480
- const own = o.own || kbmod.EXTERNAL;
481
- const sync = o.sync || (own === kbmod.OWNED ? kbmod.PUSH : kbmod.PULL);
482
- if (own === kbmod.OWNED && sync === kbmod.PULL) {
483
- fail('owned 的真值在 Git,不该 pull —— 那会把远端的东西覆盖到本地。\n' +
484
- ' **所有权决定真值方向。** owned → push;external → pull。');
485
- }
486
- const local = o.local || join('.cache/kb', o.name);
487
- cfg.kb = (cfg.kb || []).filter((k) => k.name !== o.name);
488
- cfg.kb.push({ name: o.name, from: o.from, own, sync, local });
489
- cfgmod.save(ROOT, cfg);
490
- console.log(`✅ 挂上「${o.name}」 ${o.from}`);
491
- console.log(` 所有权=${own} · 同步=${sync} · 落在 ${local}`);
492
- console.log(own === kbmod.OWNED
493
- ? ' (真值在 Git,钉钉是暴露层。人在钉钉里改了 → sync 时会【停下来问】,不盲覆盖。)'
494
- : ' (真值在钉钉,本地只是【可丢弃的缓存】。过期了 kb search 会警告。)');
495
- return;
496
- }
497
- if (sub === 'list') {
498
- if (!cfg.kb?.length)
499
- return console.log('一个都没挂。 kb mount --help');
500
- for (const kb of cfg.kb) {
501
- const s = kbmod.stale(kb);
502
- console.log(` ${s ? '⚠️' : '·'} ${kb.name.padEnd(14)} ${kb.own.padEnd(9)} ${kb.sync.padEnd(5)} ${kb.from}`);
503
- console.log(` 落在 ${kb.local} 上次同步 ${kb._syncedAt || '从未'}${s ? ' ← **过期了,不许拿来回答**' : ''}`);
504
- }
505
- return;
506
- }
507
- if (sub === 'sync') {
508
- const targets = (cfg.kb || []).filter((k) => !o.name || k.name === o.name);
509
- if (!targets.length)
510
- fail('没有这个知识库。 kb list');
511
- for (const kb of targets) {
512
- if (kb.sync === kbmod.NONE) {
513
- console.log(` skip ${kb.name}(sync=none)`);
514
- continue;
515
- }
516
- if (kb.sync === kbmod.PULL)
517
- kbmod.pull(kb, ROOT, o.force);
518
- else
519
- kbmod.push(kb, ROOT, o.force);
520
- }
521
- cfgmod.save(ROOT, cfg);
522
- return;
523
- }
524
- if (sub === 'search') {
525
- const kw = argv[2];
526
- if (!kw)
527
- fail('要给关键词。 kb search "<关键词>"');
528
- kbmod.search(cfg, ROOT, kw);
529
- return;
530
- }
531
- fail('kb 的子命令: mount / list / sync / search');
1331
+ if (/OpenCode/.test(message)) {
1332
+ return '检查 OpenCode 版本、模型认证与项目 Skill/config;运行 dta workspace doctor <name> 查看精确缺口。';
532
1333
  }
533
- // ── boot ──
534
- if (cmd === 'boot') {
535
- boot(cfgmod.must(ROOT), ROOT);
536
- return;
1334
+ if (/Multica|multica/.test(message)) {
1335
+ return '先运行 dta workspace plan <name> 和 doctor;确认 profile/ID 来源后,再用 inspect --execute --yes 做只读回读。';
537
1336
  }
538
- // ── duty ──
539
- if (cmd === 'duty') {
540
- const cfg = cfgmod.must(ROOT);
541
- const { values: o } = parseArgs({
542
- args: argv.slice(1), allowPositionals: true,
543
- options: { check: { type: 'boolean' }, run: { type: 'string' },
544
- list: { type: 'boolean' }, force: { type: 'boolean' } },
545
- });
546
- const duties = dutymod.loadDuties(cfg, ROOT);
547
- if (o.list) {
548
- const ks = Object.keys(duties);
549
- console.log(ks.length ? ks.join('\n')
550
- : '(值班表是空的 —— 母体出厂如此,这是【正确】的。在 .dingtalk-agent/config.json 的 duties 里加。)');
551
- return;
552
- }
553
- if (o.run) {
554
- const fn = duties[o.run];
555
- if (!fn)
556
- fail(`没有这个值班: ${o.run}(有: ${Object.keys(duties).join('、') || '无'})`);
557
- const s = fn();
558
- if (s.kind === '交付' && !dutymod.inDeliver() && !o.force) {
559
- return console.log(`⏸ 「${o.run}」是外发动作,静默时段顺延,**不打扰第三方**。`);
560
- }
561
- if (s.done)
562
- return console.log(`✅ 「${o.run}」已完成,本拍无需执行。${s.detail}`);
563
- console.log(`【${o.run}】该做了。${s.gap}`);
564
- console.log(` 剧本: ${s.playbook || '(没写剧本 —— 这个值班不合格)'}`);
565
- console.log(` ⚠️ 送达【回读确认】之后才准记 pass。没送达就写 pass = 自己骗自己。`);
566
- return;
567
- }
568
- // --check(默认)
569
- console.log('值班表(**完成状态在数据里,不在记忆里**;幂等,漏拍下一拍自愈)');
570
- console.log(` 现在 ${runsmod.now().slice(11, 16)} · ${dutymod.inNight() ? '夜间窗口(重活可跑)' : '白天(重活挂起)'} · 外发窗口${dutymod.inDeliver() ? '开' : '关'}`);
571
- const ids = Object.keys(duties);
572
- if (!ids.length) {
573
- console.log('\n (值班表是空的 —— 母体出厂如此。)');
574
- return;
575
- }
576
- const todo = [];
577
- for (const id of ids) {
578
- const s = duties[id]();
579
- const mark = s.done ? '✅ 已完成' : (s.due ? '⬜ 待补齐' : '⏸ 不在窗口');
580
- console.log(` ${s.id.padEnd(8)} [${s.kind}] ${mark} ${s.detail}${s.gap ? ' → ' + s.gap : ''}`);
581
- if (!s.done && s.due)
582
- todo.push(s.id);
583
- }
584
- if (todo.length) {
585
- console.log(`\n本拍要做: ${todo.map((t) => 'duty --run ' + t).join('、')}`);
586
- process.exit(1);
587
- }
588
- console.log('\n全部补齐,静默即可(**不要为此打扰主人**)');
589
- return;
1337
+ if (/\bDWS\b|\bdws\b/.test(message)) {
1338
+ return '运行 dta doctor 检查 DWS 路径、版本和认证;需要登录时执行 dws auth login。';
590
1339
  }
591
- // ── 留痕与进化 ──
592
- if (cmd === 'log' || cmd === 'logq') {
593
- const { values: o } = parseArgs({
594
- args: argv.slice(1),
595
- options: { did: { type: 'string' }, asked: { type: 'string' }, kind: { type: 'string' },
596
- secs: { type: 'string' }, r: { type: 'string' }, ev: { type: 'string' },
597
- ch: { type: 'string' }, issue: { type: 'string' },
598
- conv: { type: 'string' }, msg: { type: 'string' } },
599
- });
600
- if (!o.did)
601
- fail('要 --did(我怎么答的)');
602
- const t = runsmod.logq(ROOT, {
603
- ...o, did: o.did, secs: +(o.secs || 0), r: o.r || 'pass',
604
- });
605
- console.log(`运行记录已落: runs/${runsmod.today()}.md @${t}`);
606
- if (!o.conv)
607
- console.log(' ⚠️ 没带 --conv —— 事后【拉不出对话流】,这一条基本没有训练价值。');
608
- return;
1340
+ if (/dingtalk-agent\.json|Project 未声明|current-workspace|Development Workspace/.test(message)) {
1341
+ return '在 Agent Project 内运行 dta info;用 dta workspace list/show/doctor 检查声明和漂移。';
609
1342
  }
610
- if (cmd === 'feedback') {
611
- const { values: o } = parseArgs({
612
- args: argv.slice(1),
613
- options: { kind: { type: 'string' }, text: { type: 'string' },
614
- conv: { type: 'string' }, at: { type: 'string' } },
615
- });
616
- if (!o.kind || ![runsmod.FB_OK, runsmod.FB_MORE, runsmod.FB_FIX].includes(o.kind)) {
617
- fail('--kind 只能是 认可 / 追问 / 纠正');
618
- }
619
- const day = runsmod.today();
620
- const rows = runsmod.read(ROOT, day);
621
- let cand = rows.filter((r) => r.asked);
622
- if (o.conv)
623
- cand = cand.filter((r) => r.conv === o.conv);
624
- if (!cand.length)
625
- fail(`今天没有可回填的问答行 —— **是不是答完忘了 logq?**`);
626
- const tgt = o.at ? cand.find((r) => r.t === o.at) : cand[cand.length - 1];
627
- if (!tgt)
628
- fail(`找不到 t=${o.at} 的行`);
629
- tgt.fb = o.kind;
630
- if (o.text)
631
- tgt.fbt = o.text.slice(0, 600);
632
- runsmod.write(ROOT, day, rows);
633
- console.log(`已回填: ${day} @${tgt.t} → 「${o.kind}」(原问: ${(tgt.asked || '').slice(0, 40)})`);
634
- return;
1343
+ if (/skills CLI|\bnpx\b/.test(message)) {
1344
+ return '确认 node、npm、npx PATH 中;也可以复制错误中的 npx skills 命令单独执行。';
635
1345
  }
636
- if (cmd === 'runs') {
637
- const { values: o } = parseArgs({
638
- args: argv.slice(1),
639
- options: { days: { type: 'string' }, conv: { type: 'string' },
640
- issue: { type: 'string' }, top: { type: 'string' } },
641
- });
642
- let rows = runsmod.scan(ROOT, +(o.days || 1));
643
- if (o.conv) {
644
- rows = rows.filter((r) => r.conv === o.conv);
645
- console.log(`【对话流】会话 ${o.conv} · ${rows.length} 条 —— **这就是训练素材**`);
646
- for (const r of rows) {
647
- console.log(` ── ${r._day} ${r.t} issue=${r.issue || '-'} msg=${r.msg || '-'}`);
648
- if (r.asked)
649
- console.log(` 主人: ${r.asked}`);
650
- console.log(` 我 : ${r.did} [${r.r}]`);
651
- if (r.fb)
652
- console.log(` 反馈: ${r.fb}${r.fbt ? ` 「${r.fbt}」` : ''}`);
653
- }
654
- if (!rows.length)
655
- console.log(' (空 —— 这个会话没留痕。**没留痕 = 这些交互等于没发生过。**)');
656
- return;
657
- }
658
- if (o.issue) {
659
- const issue = o.issue;
660
- rows = rows.filter((r) => (r.issue || '').startsWith(issue));
661
- }
662
- console.log(`运行记录 runs/ · ${rows.length} 条`);
663
- for (const r of rows.slice(-(+(o.top || 30)))) {
664
- console.log(` ${r._day} ${r.t} [${(r.r || '').padEnd(11)}] ${(r.ch || '').padEnd(6)} ${(r.did || '').slice(0, 30)} ${r.fb ? '← ' + r.fb : ''}`);
665
- }
666
- return;
1346
+ if (/升级目标|CLI 升级|npm view|npm install/.test(message)) {
1347
+ return '检查 npm registry 与网络后重试 dta upgrade;可先运行 dta upgrade --dry-run 查看目标和完整命令。';
667
1348
  }
668
- if (cmd === 'evolve') {
669
- const { values: o } = parseArgs({ args: argv.slice(1), options: { days: { type: 'string' } } });
670
- const rows = runsmod.scan(ROOT, +(o.days || 7));
671
- const ans = rows.filter((r) => r.asked);
672
- const bad = ans.filter((r) => [runsmod.FB_FIX, runsmod.FB_MORE].includes(r.fb || ''));
673
- const unk = ans.filter((r) => !r.fb);
674
- const failed = rows.filter((r) => ['fail', 'unsupported', 'degraded'].includes(r.r));
675
- console.log(`【进化清单】近 ${o.days || 7} 天`);
676
- console.log(` 面向主人的回答 ${ans.length} 条 · 被【打回】${bad.length} 条 · 引擎层没答出来 ${failed.length} 条`);
677
- if (unk.length)
678
- console.log(` ⚠️ ${unk.length} 条【没收到反馈就结案了】—— 答完没回填,这次交互等于白跑。`);
679
- if (bad.length) {
680
- console.log('\n── 主人打回的(**直接就是这周该改什么**)──');
681
- for (const r of bad) {
682
- console.log(` ${r._day} ${r.t} [${r.fb}] 会话=${r.conv || '-'}`);
683
- console.log(` 主人问: ${(r.asked || '').slice(0, 60)}`);
684
- console.log(` 我答 : ${(r.did || '').slice(0, 60)}`);
685
- console.log(` 他说 : ${r.fbt || '(没记下来)'}`);
686
- console.log(` 复盘 : dingtalk-agent runs --conv ${r.conv || '<会话id>'}`);
687
- }
688
- }
689
- if (!bad.length && !failed.length) {
690
- console.log('\n (没有打回,也没有失败 —— 要么真的都对,要么【没人回填反馈】。看上面那行。)');
691
- }
692
- return;
1349
+ if (/Workspace|Field|Storage|contextId/.test(message)) {
1350
+ return '先运行 dta bootstrap --json 查看当前上下文;确实需要持久 Workspace 时再运行 dta init。';
693
1351
  }
694
- // ── todo:把待办拉全(心跳收件用)──
695
- if (cmd === 'todo') {
696
- const dws = await import('../src/dws.js');
697
- const all = dws.todosAll('false');
698
- console.log(`未完成待办 ${all.length} 条(**已翻页拉全** —— 只看第一页会漏掉循环件)`);
699
- for (const t of all)
700
- console.log(` ${t.taskId} ${(t.subject || '').slice(0, 60)}`);
701
- return;
1352
+ return '运行 dta doctor 检查环境;运行 dta --help 查看可用命令。';
1353
+ }
1354
+ function suggest(input, candidates, prefix = 'dta') {
1355
+ if (!input)
1356
+ return '';
1357
+ const ranked = candidates
1358
+ .map((candidate) => ({ candidate, distance: editDistance(input, candidate) }))
1359
+ .sort((a, b) => a.distance - b.distance);
1360
+ const best = ranked[0];
1361
+ return best && best.distance <= Math.max(2, Math.floor(best.candidate.length / 3))
1362
+ ? `;你是否想输入 ${prefix} ${best.candidate}?`
1363
+ : '';
1364
+ }
1365
+ function editDistance(a, b) {
1366
+ const row = Array.from({ length: b.length + 1 }, (_, index) => index);
1367
+ for (let i = 1; i <= a.length; i += 1) {
1368
+ let previous = row[0];
1369
+ row[0] = i;
1370
+ for (let j = 1; j <= b.length; j += 1) {
1371
+ const before = row[j];
1372
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
1373
+ previous = before;
1374
+ }
702
1375
  }
703
- fail(`不认识的命令: ${cmd}\n${HELP}`);
1376
+ return row[b.length];
704
1377
  }
705
1378
  function printDispatch(out, json = false) {
706
1379
  if (json)
@@ -714,20 +1387,95 @@ function printDispatch(out, json = false) {
714
1387
  console.log(` allowed=${out.allowedActions.join(', ')} default=${out.defaultAction}`);
715
1388
  console.log(' Local 模式可直接用 cwd/env;生产模式由宿主 Broker 保留 DWS 与 control 权限。');
716
1389
  }
1390
+ function printLab(out) {
1391
+ const passed = out.ready ?? out.passed ?? out.assertions?.passed;
1392
+ console.log(`${passed === false ? '❌' : '✅'} ${out.$schema || 'dingtalk-agent/lab'}`);
1393
+ if (out.mode)
1394
+ console.log(` mode=${out.mode}`);
1395
+ if (out.marker)
1396
+ console.log(` marker=${out.marker}`);
1397
+ if (out.evidencePath)
1398
+ console.log(` evidence=${out.evidencePath}`);
1399
+ if (Array.isArray(out.checks)) {
1400
+ for (const check of out.checks) {
1401
+ console.log(` ${check.passed ? 'PASS' : 'FAIL'} ${check.id}: ${check.detail}`);
1402
+ }
1403
+ }
1404
+ }
1405
+ function printAgentAudit(out) {
1406
+ console.log(`dingtalk-agent agent audit · ${out.ready ? 'READY' : 'PARTIAL'}`);
1407
+ console.log(` definition=${out.definition.hash} storage=${out.storageMode}`);
1408
+ console.log(` dingtalkSideEffect=${out.dingtalkSideEffect} sideEffect=${out.sideEffect}`);
1409
+ for (const check of out.checks) {
1410
+ const mark = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1411
+ console.log(` ${mark} ${check.id}: ${check.summary}`);
1412
+ }
1413
+ if (out.repairs.length) {
1414
+ console.log('\n修复建议:');
1415
+ for (const repair of out.repairs) {
1416
+ console.log(` ${repair.id}: ${repair.why}`);
1417
+ for (const action of repair.actions)
1418
+ console.log(` - ${action}`);
1419
+ }
1420
+ }
1421
+ }
1422
+ function printAgentEnhance(out) {
1423
+ if (out.$schema === 'dingtalk-agent/agent-enhancement-plan@1') {
1424
+ console.log(`dingtalk-agent agent enhance · ${out.ready ? 'READY PLAN' : 'BLOCKED'}`);
1425
+ console.log(` planId=${out.planId} project=${out.projectName}`);
1426
+ console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1427
+ for (const operation of out.operations) {
1428
+ console.log(` ${operation.kind.toUpperCase()} ${operation.path}: ${operation.reason}`);
1429
+ }
1430
+ if (out.semanticReview.required) {
1431
+ console.log(` REVIEW ${out.semanticReview.files.join(', ')}: ${out.semanticReview.why}`);
1432
+ }
1433
+ for (const blocker of out.blockers)
1434
+ console.log(` BLOCK ${blocker}`);
1435
+ if (out.ready)
1436
+ console.log(`\nApply:\n ${out.apply.command}`);
1437
+ return;
1438
+ }
1439
+ console.log('dingtalk-agent agent enhance · APPLIED');
1440
+ console.log(` operation=${out.operationId} planId=${out.planId}`);
1441
+ console.log(` changes=${out.changes.length} idempotent=${out.idempotent}`);
1442
+ if (out.backupRoot)
1443
+ console.log(` backup=${out.backupRoot}`);
1444
+ console.log(` audit=${out.audit.status} missing=${out.audit.missing.join(', ') || '-'}`);
1445
+ }
1446
+ function printAgentPlatform(platform) {
1447
+ console.log(`${platform.status === 'supported' ? '✅' : '⏳'} ${platform.name} · ${platform.label} · ${platformStatusLabel(platform.status)}`);
1448
+ console.log(` ${platform.description}`);
1449
+ if (platform.skills.length)
1450
+ console.log(` 技能包: ${platform.skills.join(', ')}`);
1451
+ if (platform.commands.length)
1452
+ console.log(` 平台命令: ${platform.commands.map((item) => `dta ${item}`).join(' · ')}`);
1453
+ }
1454
+ function printAgentPlatformResolution(out) {
1455
+ if (!out.platform) {
1456
+ console.log('⚠️ 当前工作区未声明 managed agent platform');
1457
+ console.log(' 运行 `dta agent-platform use multica-dingtalk`,或设置 DTA_AGENT_PLATFORM 环境变量。');
1458
+ return;
1459
+ }
1460
+ const known = out.definition;
1461
+ console.log(`${known ? '✅' : '❌'} 当前 platform: ${out.platform}${known ? ` · ${known.label} · ${platformStatusLabel(known.status)}` : '(未知)'}`);
1462
+ console.log(` 来源: ${out.source}${out.file ? ` · ${out.file}` : ''}`);
1463
+ if (known?.skills.length)
1464
+ console.log(` 技能包: ${known.skills.join(', ')}`);
1465
+ }
717
1466
  function printSkillStatus(out, action, dryRun) {
718
1467
  const prefix = dryRun ? 'DRY-RUN' : '✅';
719
1468
  const verb = action === 'status' ? '全局 Skill 状态' : `skill ${action}`;
720
1469
  console.log(`${prefix} ${verb}: ${out.name}`);
721
- console.log(` bundled=${out.bundled.skillVersion || '-'} hash=${out.bundled.hash.slice(0, 12)}`);
1470
+ console.log(` manager=${out.manager} bundled=${out.bundled.skillVersion || '-'}`);
722
1471
  console.log(` canonical=${out.canonical.path}`);
723
- console.log(` installed=${out.canonical.exists} managed=${out.canonical.managed} ` +
724
- `modified=${out.canonical.modified} current=${out.canonical.current}`);
1472
+ console.log(` installed=${out.canonical.exists} installedVersion=${out.canonical.installedVersion || '-'} ` +
1473
+ `current=${out.canonical.current}`);
1474
+ if (out.operation)
1475
+ console.log(` delegated: ${out.operation.command}`);
725
1476
  for (const client of out.clients) {
726
1477
  console.log(` ${client.label}=${client.state} (${client.discovery}: ${client.path})`);
727
1478
  }
728
- if (out.legacyCodex.conflict) {
729
- console.log(` ⚠️ legacy Codex 同名路径存在: ${out.legacyCodex.path}`);
730
- }
731
1479
  if (action === 'install' && !dryRun) {
732
1480
  console.log(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。');
733
1481
  }
@@ -748,9 +1496,156 @@ function printDoctor(out) {
748
1496
  console.log(` ${step}`);
749
1497
  }
750
1498
  }
1499
+ function printProjectInfo(out) {
1500
+ console.log(`dingtalk-agent Project · ${out.project.name}`);
1501
+ console.log(` root=${out.root}`);
1502
+ console.log(` source=${out.source} manifest=${out.manifest || '(synthetic legacy)'}`);
1503
+ console.log(` hash=${out.manifestHash} dta=${out.project.dtaVersion}`);
1504
+ console.log(` current=${out.currentWorkspace || '(not selected)'}`);
1505
+ for (const workspace of out.workspaces) {
1506
+ console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} · ${workspace.provider.kind} · ${workspace.status}`);
1507
+ }
1508
+ }
1509
+ function printWorkspaceList(out) {
1510
+ console.log(`dingtalk-agent workspaces · ${out.project.name}`);
1511
+ if (!out.workspaces.length)
1512
+ console.log(' 尚未声明 Development Workspace。');
1513
+ for (const workspace of out.workspaces) {
1514
+ console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} provider=${workspace.provider.kind} ` +
1515
+ `stage=${workspace.stage} status=${workspace.status}`);
1516
+ }
1517
+ }
1518
+ function printDevelopmentWorkspace(out) {
1519
+ console.log(`dingtalk-agent workspace · ${out.name}`);
1520
+ console.log(` provider=${out.provider.kind} stage=${out.stage} status=${out.status}`);
1521
+ console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1522
+ console.log(` current=${out.current} legacy=${out.legacy}`);
1523
+ for (const [slot, route] of Object.entries(out.storage))
1524
+ console.log(` ${slot}=${route}`);
1525
+ for (const source of out.configSources)
1526
+ console.log(` source=${source}`);
1527
+ }
1528
+ function printDevelopmentWorkspaceDoctor(out) {
1529
+ console.log(`dingtalk-agent workspace doctor · ${out.workspace} · ${out.ready ? 'READY' : 'PARTIAL'}`);
1530
+ console.log(` provider=${out.provider} status=${out.status}`);
1531
+ console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1532
+ for (const check of out.checks) {
1533
+ const mark = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1534
+ console.log(` ${mark} ${check.id}: ${check.summary}`);
1535
+ if (check.fix && check.level !== 'pass')
1536
+ console.log(` fix: ${check.fix}`);
1537
+ }
1538
+ }
1539
+ function printOpenCodeWorkspaceOperation(out) {
1540
+ const applied = out.$schema === 'dingtalk-agent/opencode-workspace-apply@1';
1541
+ console.log(`${applied ? out.applied ? '✅' : '↩️' : 'DRY-RUN'} OpenCode Workspace ${out.workspace}`);
1542
+ console.log(` action=${out.action} model=${out.model}`);
1543
+ console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1544
+ console.log(` managed=${out.managedPath}`);
1545
+ if (!applied && out.writes?.length)
1546
+ console.log(` writes=${out.writes.join(', ')}`);
1547
+ }
1548
+ function printMulticaWorkspaceOperation(out) {
1549
+ const passed = out.passed ?? out.readyForApply ?? out.blocking?.length === 0;
1550
+ const mode = out.remoteRead ? 'REMOTE-READ' : 'DRY-RUN';
1551
+ console.log(`${passed ? '✅' : '⚠️'} ${mode} Multica Workspace ${out.workspace}`);
1552
+ console.log(` schema=${out.$schema} profile=${out.profile || '-'}`);
1553
+ if (out.planId)
1554
+ console.log(` plan=${out.planId}`);
1555
+ if (out.inspectionId)
1556
+ console.log(` inspection=${out.inspectionId}`);
1557
+ if (out.desiredHash)
1558
+ console.log(` desired=${out.desiredHash}`);
1559
+ if (out.observedHash)
1560
+ console.log(` observed=${out.observedHash}`);
1561
+ if (out.diff?.length)
1562
+ console.log(` diff=${out.diff.join(', ')}`);
1563
+ if (out.blocking?.length)
1564
+ console.log(` blocking=${out.blocking.join(', ')}`);
1565
+ if (out.failures?.length)
1566
+ console.log(` failures=${out.failures.join(', ')}`);
1567
+ if (out.evidencePath)
1568
+ console.log(` evidence=${out.evidencePath}`);
1569
+ console.log(` remoteWrite=${out.remoteWrite} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1570
+ }
1571
+ function printMulticaDeployment(out) {
1572
+ console.log(`Multica deploy: ${out.workspace || '<unknown>'}`);
1573
+ if (out.planId)
1574
+ console.log(` plan: ${out.planId}`);
1575
+ if (out.operationId)
1576
+ console.log(` operation: ${out.operationId}`);
1577
+ if (out.receiptId)
1578
+ console.log(` receipt: ${out.receiptId}`);
1579
+ if (out.action)
1580
+ console.log(` action: ${out.action}`);
1581
+ if (out.status)
1582
+ console.log(` status: ${out.status}`);
1583
+ if (typeof out.providerReady === 'boolean')
1584
+ console.log(` provider ready: ${out.providerReady}`);
1585
+ if (Array.isArray(out.blocking) && out.blocking.length) {
1586
+ console.log(` blocking: ${out.blocking.join(', ')}`);
1587
+ }
1588
+ if (Array.isArray(out.failures) && out.failures.length) {
1589
+ console.log(` failures: ${out.failures.join(', ')}`);
1590
+ }
1591
+ if (out.triggerWrite === false)
1592
+ console.log(' triggers: unchanged');
1593
+ }
1594
+ function printPromotion(out) {
1595
+ console.log(`Promotion: ${out.promotionId || out.candidateId || out.candidate?.candidateId || '<none>'}`);
1596
+ if (out.planId)
1597
+ console.log(` plan: ${out.planId}`);
1598
+ if (out.routeId)
1599
+ console.log(` route: ${out.routeId}`);
1600
+ if (out.status)
1601
+ console.log(` status: ${out.status}`);
1602
+ if (out.target?.observedHash)
1603
+ console.log(` observed: ${out.target.observedHash}`);
1604
+ if (out.candidatePath)
1605
+ console.log(` candidate: ${out.candidatePath}`);
1606
+ if (out.candidate?.evidencePath)
1607
+ console.log(` candidate: ${out.candidate.evidencePath}`);
1608
+ if (Array.isArray(out.blocking) && out.blocking.length)
1609
+ console.log(` blocking: ${out.blocking.join(', ')}`);
1610
+ if (out.triggerWrite === false)
1611
+ console.log(' triggers: unchanged');
1612
+ }
1613
+ function parseOptionalTimeout(value, label) {
1614
+ if (value === undefined)
1615
+ return undefined;
1616
+ const parsed = Number(value);
1617
+ if (!Number.isInteger(parsed) || parsed < 100 || parsed > 300_000) {
1618
+ fail(`${label} 必须是 100..300000 的整数毫秒`);
1619
+ }
1620
+ return parsed;
1621
+ }
1622
+ function readProjectText(start, ref, label) {
1623
+ const root = inspectAgentProject(start, PACKAGE_JSON.version).root;
1624
+ const candidate = resolve(root, ref);
1625
+ const lexical = relative(root, candidate);
1626
+ if (lexical === '..' || lexical.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)) {
1627
+ throw new Error(`${label} 必须位于 Agent Project 内: ${ref}`);
1628
+ }
1629
+ if (!existsSync(candidate))
1630
+ throw new Error(`${label} 不存在: ${ref}`);
1631
+ const actual = realpathSync(candidate);
1632
+ const resolved = relative(root, actual);
1633
+ if (resolved === '..' || resolved.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)) {
1634
+ throw new Error(`${label} 真实路径越出 Agent Project: ${ref}`);
1635
+ }
1636
+ return readFileSync(actual, 'utf8');
1637
+ }
1638
+ function rejectWorkspaceOptions(values, allowed, command) {
1639
+ const extras = Object.entries(values)
1640
+ .filter(([key, value]) => !allowed.includes(key) && value !== undefined && value !== false)
1641
+ .map(([key]) => `--${key}`);
1642
+ if (extras.length)
1643
+ fail(`${command} 不接受参数: ${extras.join(', ')}`);
1644
+ }
751
1645
  function printSetup(out) {
752
1646
  console.log(`${out.dryRun ? 'DRY-RUN' : '✅'} dingtalk-agent setup`);
753
1647
  console.log(` CLI: ${out.cli.executable}`);
1648
+ console.log(` 短命令: ${out.cli.alias}`);
754
1649
  console.log(` Skill: ${out.skill.canonical.path}`);
755
1650
  if (!out.shell.pathReady) {
756
1651
  console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${out.shell.activateCommand}`);
@@ -760,4 +1655,21 @@ function printSetup(out) {
760
1655
  printDoctor(out.doctor);
761
1656
  console.log(`\n开始使用: ${out.nextCommand}`);
762
1657
  }
1658
+ function printUpgrade(out) {
1659
+ const mark = out.dryRun ? 'DRY-RUN' : out.ready ? '✅' : '⚠️';
1660
+ const relation = out.changed ? `${out.currentVersion} → ${out.targetVersion}` : `${out.targetVersion}(已是当前版本)`;
1661
+ console.log(`${mark} dta upgrade: ${relation}`);
1662
+ console.log(` target=${out.target}`);
1663
+ console.log(` CLI=${out.executable}`);
1664
+ if (out.dryRun) {
1665
+ console.log(` 将执行: ${out.commands.install}`);
1666
+ console.log(` 将复核: ${out.commands.verify}`);
1667
+ }
1668
+ else if (out.ready) {
1669
+ console.log(' setup / DWS / Skill / Claude Code / Codex / OpenCode 全部 ready');
1670
+ }
1671
+ else {
1672
+ console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${out.commands.verify}`);
1673
+ }
1674
+ }
763
1675
  //# sourceMappingURL=dingtalk-agent.js.map