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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/CHANGELOG.md +233 -0
  2. package/README.en.md +167 -0
  3. package/README.md +101 -248
  4. package/dist/bin/dingtalk-agent.js +1255 -25
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +98 -14
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +1385 -0
  9. package/dist/src/agent-audit.js.map +1 -0
  10. package/dist/src/agent-bindings.js +132 -0
  11. package/dist/src/agent-bindings.js.map +1 -0
  12. package/dist/src/agent-definition.js +182 -0
  13. package/dist/src/agent-definition.js.map +1 -0
  14. package/dist/src/agent-enhance.js +711 -0
  15. package/dist/src/agent-enhance.js.map +1 -0
  16. package/dist/src/agent-platform.js +299 -0
  17. package/dist/src/agent-platform.js.map +1 -0
  18. package/dist/src/bootstrap.js +125 -17
  19. package/dist/src/bootstrap.js.map +1 -1
  20. package/dist/src/config.js +1 -7
  21. package/dist/src/config.js.map +1 -1
  22. package/dist/src/development-workspace.js +755 -0
  23. package/dist/src/development-workspace.js.map +1 -0
  24. package/dist/src/doctor.js +74 -15
  25. package/dist/src/doctor.js.map +1 -1
  26. package/dist/src/dws.js +145 -0
  27. package/dist/src/dws.js.map +1 -1
  28. package/dist/src/eval-evidence.js +193 -0
  29. package/dist/src/eval-evidence.js.map +1 -0
  30. package/dist/src/host-detect.js +146 -0
  31. package/dist/src/host-detect.js.map +1 -0
  32. package/dist/src/instruction-path.js +270 -0
  33. package/dist/src/instruction-path.js.map +1 -0
  34. package/dist/src/invocation.js +36 -0
  35. package/dist/src/invocation.js.map +1 -0
  36. package/dist/src/lab.js +679 -0
  37. package/dist/src/lab.js.map +1 -0
  38. package/dist/src/lease.js +100 -0
  39. package/dist/src/lease.js.map +1 -0
  40. package/dist/src/map.js +157 -0
  41. package/dist/src/map.js.map +1 -0
  42. package/dist/src/memory/candidates.js +451 -0
  43. package/dist/src/memory/candidates.js.map +1 -0
  44. package/dist/src/memory/completion-evidence.js +536 -0
  45. package/dist/src/memory/completion-evidence.js.map +1 -0
  46. package/dist/src/memory/operational.js +263 -0
  47. package/dist/src/memory/operational.js.map +1 -0
  48. package/dist/src/memory/remote-state.js +478 -0
  49. package/dist/src/memory/remote-state.js.map +1 -0
  50. package/dist/src/memory/task-checkpoints.js +204 -0
  51. package/dist/src/memory/task-checkpoints.js.map +1 -0
  52. package/dist/src/multica-deploy.js +1538 -0
  53. package/dist/src/multica-deploy.js.map +1 -0
  54. package/dist/src/multica-provider.js +685 -0
  55. package/dist/src/multica-provider.js.map +1 -0
  56. package/dist/src/opencode-evals.js +1547 -0
  57. package/dist/src/opencode-evals.js.map +1 -0
  58. package/dist/src/opencode-isolation.js +124 -0
  59. package/dist/src/opencode-isolation.js.map +1 -0
  60. package/dist/src/opencode-provider.js +532 -0
  61. package/dist/src/opencode-provider.js.map +1 -0
  62. package/dist/src/opencode-workspace.js +208 -0
  63. package/dist/src/opencode-workspace.js.map +1 -0
  64. package/dist/src/perception.js +225 -0
  65. package/dist/src/perception.js.map +1 -0
  66. package/dist/src/personal-event-evals.js +595 -0
  67. package/dist/src/personal-event-evals.js.map +1 -0
  68. package/dist/src/promotion.js +786 -0
  69. package/dist/src/promotion.js.map +1 -0
  70. package/dist/src/remote-semantic-state-live-evals.js +888 -0
  71. package/dist/src/remote-semantic-state-live-evals.js.map +1 -0
  72. package/dist/src/remote-semantic-state-worker.js +38 -0
  73. package/dist/src/remote-semantic-state-worker.js.map +1 -0
  74. package/dist/src/remote-state-evals.js +502 -0
  75. package/dist/src/remote-state-evals.js.map +1 -0
  76. package/dist/src/response-gate.js +51 -0
  77. package/dist/src/response-gate.js.map +1 -0
  78. package/dist/src/robot-evals.js +771 -0
  79. package/dist/src/robot-evals.js.map +1 -0
  80. package/dist/src/sessions.js +66 -105
  81. package/dist/src/sessions.js.map +1 -1
  82. package/dist/src/setup.js +6 -5
  83. package/dist/src/setup.js.map +1 -1
  84. package/dist/src/skill-manager.js +162 -24
  85. package/dist/src/skill-manager.js.map +1 -1
  86. package/dist/src/skills.js +2 -1
  87. package/dist/src/skills.js.map +1 -1
  88. package/dist/src/storage-evals.js +26 -0
  89. package/dist/src/storage-evals.js.map +1 -0
  90. package/dist/src/types.js.map +1 -1
  91. package/dist/src/upgrade.js +23 -27
  92. package/dist/src/upgrade.js.map +1 -1
  93. package/dist/src/version.js +73 -0
  94. package/dist/src/version.js.map +1 -0
  95. package/dist/src/waits.js +5 -1
  96. package/dist/src/waits.js.map +1 -1
  97. package/dist/src/workspace.js +28 -3
  98. package/dist/src/workspace.js.map +1 -1
  99. package/docs/INSTALLATION.md +50 -3
  100. package/docs/SECOND-AGENT-ACCEPTANCE.md +62 -0
  101. package/docs/architecture/agent-memory-topology.png +0 -0
  102. package/docs/architecture/agent-memory-topology.svg +132 -0
  103. package/docs/architecture/general-agent-kernel-topology.png +0 -0
  104. package/docs/architecture/general-agent-kernel-topology.svg +149 -0
  105. package/docs/architecture/provider-bound-development-workspace.png +0 -0
  106. package/docs/architecture/provider-bound-development-workspace.svg +141 -0
  107. package/docs/architecture/task-completion-gate.png +0 -0
  108. package/docs/architecture/task-completion-gate.svg +191 -0
  109. package/docs/assets/agent-delivery-lifecycle.svg +103 -0
  110. package/docs/schemas/agent-audit-load-evidence.schema.json +14 -0
  111. package/docs/schemas/agent-audit.schema.json +92 -0
  112. package/docs/schemas/agent-bindings.schema.json +54 -0
  113. package/docs/schemas/agent-definition.schema.json +78 -0
  114. package/docs/schemas/agent-enhancement-plan.schema.json +88 -0
  115. package/docs/schemas/agent-enhancement-receipt.schema.json +37 -0
  116. package/docs/schemas/agent-platform.schema.json +13 -0
  117. package/docs/schemas/enriched-invocation.schema.json +46 -0
  118. package/docs/schemas/eval-candidate-plan.schema.json +28 -0
  119. package/docs/schemas/eval-candidate-result.schema.json +20 -0
  120. package/docs/schemas/eval-candidate.schema.json +30 -0
  121. package/docs/schemas/invocation.schema.json +19 -0
  122. package/docs/schemas/memory-candidate-proposal.schema.json +18 -0
  123. package/docs/schemas/memory-candidate.schema.json +76 -0
  124. package/docs/schemas/memory-publish-target.schema.json +25 -0
  125. package/docs/schemas/multica-deployment-list.schema.json +29 -0
  126. package/docs/schemas/multica-deployment-operation.schema.json +51 -0
  127. package/docs/schemas/multica-deployment-plan.schema.json +70 -0
  128. package/docs/schemas/multica-deployment-receipt.schema.json +87 -0
  129. package/docs/schemas/multica-deployment-status.schema.json +23 -0
  130. package/docs/schemas/multica-workspace-inspection.schema.json +77 -0
  131. package/docs/schemas/multica-workspace-plan.schema.json +68 -0
  132. package/docs/schemas/multica-workspace-resource-list.schema.json +27 -0
  133. package/docs/schemas/multica-workspace-status.schema.json +34 -0
  134. package/docs/schemas/observation.schema.json +21 -0
  135. package/docs/schemas/operational-memory-provider.schema.json +36 -0
  136. package/docs/schemas/operational-memory-record.schema.json +24 -0
  137. package/docs/schemas/perception-input.schema.json +56 -0
  138. package/docs/schemas/project.schema.json +115 -0
  139. package/docs/schemas/promotion-list.schema.json +36 -0
  140. package/docs/schemas/promotion-plan.schema.json +60 -0
  141. package/docs/schemas/promotion-policy.schema.json +29 -0
  142. package/docs/schemas/promotion-receipt.schema.json +43 -0
  143. package/docs/schemas/promotion-status.schema.json +23 -0
  144. package/docs/schemas/release-readiness.schema.json +66 -0
  145. package/docs/schemas/remote-semantic-state-live-eval.schema.json +60 -0
  146. package/docs/schemas/remote-semantic-state-manifest.schema.json +79 -0
  147. package/docs/schemas/remote-semantic-state-provider.schema.json +98 -0
  148. package/docs/schemas/response-gate.schema.json +20 -0
  149. package/docs/schemas/task-checkpoint.schema.json +71 -0
  150. package/docs/schemas/task-completion-evidence.schema.json +154 -0
  151. package/docs/schemas/workspace-doctor.schema.json +56 -0
  152. package/docs/schemas/workspace-state.schema.json +39 -0
  153. package/evals/README.md +17 -0
  154. package/evals/baselines/2026-07-16/opencode-basic-010-completion-summary.json +123 -0
  155. package/evals/baselines/2026-07-16/opencode-basic-skill-required-summary.json +69 -0
  156. package/evals/baselines/2026-07-16/opencode-multi-surface-summary.json +63 -0
  157. package/evals/baselines/2026-07-16/remote-state-live-summary.json +70 -0
  158. package/evals/baselines/2026-07-17/agent-enhance-opencode-dogfood-summary.json +98 -0
  159. package/evals/baselines/2026-07-17/personal-event-live-readiness-summary.json +68 -0
  160. package/examples/agents/fde-coach/AGENTS.md +26 -0
  161. package/examples/agents/fde-coach/MEMORY.md +3 -0
  162. package/examples/agents/fde-coach/fields/default/field.json +24 -0
  163. package/examples/agents/fde-coach/knowledge/INDEX.md +4 -0
  164. package/examples/agents/fde-coach/skills/fde-coach/SKILL.md +13 -0
  165. package/examples/agents/release-manager/AGENTS.md +26 -0
  166. package/examples/agents/release-manager/MEMORY.md +3 -0
  167. package/examples/agents/release-manager/fields/default/field.json +24 -0
  168. package/examples/agents/release-manager/knowledge/INDEX.md +4 -0
  169. package/examples/agents/release-manager/skills/release-manager/SKILL.md +13 -0
  170. package/lab/README.md +109 -0
  171. package/lab/agent-eval/catalog.json +91 -0
  172. package/lab/agent-eval/classic-failures.json +177 -0
  173. package/lab/agent-eval/completion-gate-regression.json +99 -0
  174. package/lab/agent-eval/personal-event-live.example.json +94 -0
  175. package/lab/agent-eval/remote-semantic-state-live.example.json +70 -0
  176. package/lab/agent-eval/remote-semantic-state-provider.fixture.json +47 -0
  177. package/lab/agent-eval/remote-state-workspace/AGENTS.md +8 -0
  178. package/lab/agent-eval/remote-state-workspace/opencode.json +7 -0
  179. package/lab/agent-eval/remote-state-workspace/skills/remote-state-operator/SKILL.md +13 -0
  180. package/lab/agent-eval/remote-state.example.json +31 -0
  181. package/lab/agent-eval/workspace/AGENTS.md +7 -0
  182. package/lab/agent-eval/workspace/MEMORY.md +4 -0
  183. package/lab/agent-eval/workspace/artifacts/pending-review.md +3 -0
  184. package/lab/agent-eval/workspace/knowledge/INDEX.md +4 -0
  185. package/lab/agent-eval/workspace/opencode.json +20 -0
  186. package/lab/manifest.example.json +27 -0
  187. package/lab/manifest.personal-event.example.json +27 -0
  188. package/lab/project-workspace/README.md +11 -0
  189. package/lab/project-workspace/fake-multica-provider.mjs +277 -0
  190. package/lab/project-workspace/multica-deploy.fixture.json +29 -0
  191. package/lab/project-workspace/multica-readonly.fixture.json +69 -0
  192. package/lab/project-workspace/observation.fixture.json +14 -0
  193. package/lab/project-workspace/opencode-provider-suite.json +65 -0
  194. package/lab/project-workspace/project.fixture.json +44 -0
  195. package/lab/project-workspace/promotion-policy.fixture.json +15 -0
  196. package/lab/robot-eval/pool.example.json +30 -0
  197. package/lab/robot-eval/suite.json +123 -0
  198. package/lab/robot-eval/workspace/AGENTS.md +21 -0
  199. package/lab/robot-eval/workspace/MEMORY.md +3 -0
  200. package/lab/robot-eval/workspace/knowledge/INDEX.md +5 -0
  201. package/lab/robot-eval/workspace/opencode.json +22 -0
  202. package/lab/schemas/agent-eval-catalog.schema.json +47 -0
  203. package/lab/schemas/lab-manifest.schema.json +70 -0
  204. package/lab/schemas/personal-event-eval.schema.json +91 -0
  205. package/lab/schemas/remote-state-eval.schema.json +66 -0
  206. package/lab/schemas/robot-eval-suite.schema.json +184 -0
  207. package/lab/schemas/robot-pool.schema.json +56 -0
  208. package/package.json +28 -9
  209. package/skills/README.md +23 -0
  210. package/skills/core/dingtalk-agent-compose/SKILL.md +151 -0
  211. package/skills/core/dingtalk-agent-compose/assets/AGENTS.template.md +35 -0
  212. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +13 -0
  213. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.local.template.json +13 -0
  214. package/skills/core/dingtalk-agent-compose/assets/hosts/opencode/opencode.template.json +12 -0
  215. package/skills/core/dingtalk-agent-compose/assets/role-skill.template.md +32 -0
  216. package/skills/core/dingtalk-agent-compose/evals/evals.json +129 -0
  217. package/skills/core/dingtalk-agent-compose/references/agent-definition-contract.md +55 -0
  218. package/skills/core/dingtalk-agent-compose/references/host-loading-contract.md +58 -0
  219. package/skills/core/dingtalk-agent-compose/references/hosts/claude-code.md +48 -0
  220. package/skills/core/dingtalk-agent-compose/references/hosts/opencode.md +77 -0
  221. package/skills/core/dingtalk-agent-compose/references/storage-routing.md +20 -0
  222. package/skills/core/dingtalk-agent-eval/SKILL.md +140 -0
  223. package/skills/core/dingtalk-agent-eval/assets/eval-catalog.template.json +18 -0
  224. package/skills/core/dingtalk-agent-eval/evals/evals.json +83 -0
  225. package/skills/core/dingtalk-agent-eval/references/eval-topology.md +48 -0
  226. package/skills/core/dingtalk-agent-eval/references/evidence-contract.md +52 -0
  227. package/skills/core/dingtalk-agent-eval/references/failure-to-case.md +35 -0
  228. package/skills/core/dingtalk-agent-eval/references/interactive-debug-channels.md +93 -0
  229. package/skills/core/dingtalk-agent-eval/references/local-connector-smoke.md +75 -0
  230. package/skills/core/dingtalk-agent-eval/references/scenario-taxonomy.md +25 -0
  231. package/skills/core/dingtalk-agent-eval/references/storage-modes.md +75 -0
  232. package/skills/core/dingtalk-basic-behavior/SKILL.md +87 -0
  233. package/skills/core/dingtalk-basic-behavior/assets/memory-candidate-proposal.json +10 -0
  234. package/skills/{dingtalk-basic-behavior/assets/task-checkpoint.md → core/dingtalk-basic-behavior/assets/task-checkpoint.json} +2 -21
  235. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/action-contract.md +2 -0
  236. package/skills/core/dingtalk-basic-behavior/references/memory-and-evolution.md +53 -0
  237. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +28 -0
  238. package/skills/core/dingtalk-basic-behavior/references/risk-authority-and-privacy.md +62 -0
  239. package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/task-lifecycle.md +47 -10
  240. package/skills/core/dingtalk-basic-behavior/references/truth-and-recovery.md +65 -0
  241. package/skills/platforms/deap/PLATFORM.md +3 -0
  242. package/skills/platforms/deap/README.md +3 -0
  243. package/skills/platforms/multica-dingtalk/PLATFORM.md +40 -0
  244. package/skills/platforms/multica-dingtalk/dingtalk-agent-boot-multica/SKILL.md +40 -0
  245. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/SKILL.md +60 -0
  246. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/multica-deployment-contract.md +49 -0
  247. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/references/promotion-observation-contract.md +49 -0
  248. package/skills/platforms/multica-dingtalk/multica-external/SKILL.md +282 -0
  249. package/skills/platforms/multica-dingtalk/multica-external/scripts/bootstrap.sh +78 -0
  250. package/skills/platforms/multica-dingtalk/multica-external/scripts/multica_ext.py +1180 -0
  251. package/skills/dingtalk-basic-behavior/SKILL.md +0 -86
  252. package/skills/dingtalk-basic-behavior/references/memory-and-evolution.md +0 -27
  253. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/event-to-behavior.md +0 -0
  254. /package/skills/{dingtalk-basic-behavior → core/dingtalk-basic-behavior}/references/runtime-modes.md +0 -0
@@ -0,0 +1,451 @@
1
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { dirname, join, relative, resolve } from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { digest, stableStringify } from '../events.js';
6
+ import { acquireLease } from '../lease.js';
7
+ import * as dws from '../dws.js';
8
+ export function proposeMemoryCandidate(root, value, options = {}) {
9
+ const proposal = validateProposal(value);
10
+ const run = proposerContext(root, options.runPath);
11
+ if (run && proposal.scopeId !== run.contextId) {
12
+ throw new Error(`Memory Candidate scopeId=${proposal.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`);
13
+ }
14
+ const id = `memcand_${digest(stableStringify(proposal)).slice(0, 24)}`;
15
+ const rootPath = candidateRoot(root, options.stateDir, Boolean(run));
16
+ const path = join(rootPath, `${id}.json`);
17
+ const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在创建`, {
18
+ waitMs: 3_000, staleAfterMs: 2 * 60_000,
19
+ });
20
+ try {
21
+ if (existsSync(path)) {
22
+ const existing = readCandidate(path);
23
+ return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: true,
24
+ path, candidate: existing };
25
+ }
26
+ const now = new Date().toISOString();
27
+ const unsigned = {
28
+ $schema: 'dingtalk-agent/memory-candidate@1',
29
+ id,
30
+ revision: 1,
31
+ kind: proposal.kind,
32
+ scopeId: proposal.scopeId,
33
+ title: proposal.title,
34
+ content: proposal.content,
35
+ sourceRefs: proposal.sourceRefs,
36
+ confidence: proposal.confidence,
37
+ supersedes: proposal.supersedes,
38
+ status: 'proposed',
39
+ proposedAt: now,
40
+ proposer: run ? {
41
+ mode: 'prepared', runId: run.id, eventId: run.eventId,
42
+ definitionHash: run.definition?.hash || '',
43
+ } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },
44
+ review: null,
45
+ publication: null,
46
+ };
47
+ const candidate = signCandidate(unsigned);
48
+ writeJsonAtomic(path, candidate);
49
+ return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,
50
+ path, candidate: readCandidate(path) };
51
+ }
52
+ finally {
53
+ release();
54
+ }
55
+ }
56
+ export function showMemoryCandidate(root, id, options = {}) {
57
+ const path = candidatePath(root, id, options.stateDir);
58
+ if (!existsSync(path))
59
+ throw new Error(`找不到 Memory Candidate: ${id}`);
60
+ return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,
61
+ path, candidate: readCandidate(path) };
62
+ }
63
+ export function reviewMemoryCandidate(root, id, decision, reviewer, reason, expectedRevision, options = {}) {
64
+ assertOffline('review', options.runPath);
65
+ if (!['approve', 'reject'].includes(decision))
66
+ throw new Error('review decision 只能是 approve/reject');
67
+ if (!clean(reviewer) || !clean(reason))
68
+ throw new Error('review 需要 reviewer 和 reason');
69
+ const path = candidatePath(root, id, options.stateDir);
70
+ const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在评审`, {
71
+ waitMs: 3_000, staleAfterMs: 2 * 60_000,
72
+ });
73
+ try {
74
+ const current = readCandidate(path);
75
+ assertCandidateRevision(current, expectedRevision);
76
+ if (current.status !== 'proposed') {
77
+ throw new Error(`Memory Candidate ${id} 当前状态是 ${current.status},不能再次评审`);
78
+ }
79
+ const unsigned = {
80
+ ...withoutHash(current),
81
+ revision: current.revision + 1,
82
+ status: decision === 'approve' ? 'approved' : 'rejected',
83
+ review: {
84
+ decision,
85
+ reviewer: clean(reviewer),
86
+ reason: clean(reason),
87
+ reviewedAt: new Date().toISOString(),
88
+ },
89
+ };
90
+ const candidate = signCandidate(unsigned);
91
+ writeJsonAtomic(path, candidate);
92
+ return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,
93
+ path, candidate: readCandidate(path) };
94
+ }
95
+ finally {
96
+ release();
97
+ }
98
+ }
99
+ export function publishMemoryCandidate(root, id, targetValue, expectedRevision, expectedTargetHash = '', options = {}) {
100
+ if (options.execute)
101
+ assertOffline('publish', options.runPath);
102
+ const target = validateTarget(targetValue);
103
+ const path = candidatePath(root, id, options.stateDir);
104
+ const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在发布`, {
105
+ waitMs: 3_000, staleAfterMs: 10 * 60_000,
106
+ });
107
+ try {
108
+ const current = readCandidate(path);
109
+ assertCandidateRevision(current, expectedRevision);
110
+ if (!['approved', 'published'].includes(current.status)) {
111
+ throw new Error(`Memory Candidate ${id} 状态为 ${current.status},必须先 approve`);
112
+ }
113
+ if (current.status === 'published' && current.publication?.uri !== target.uri) {
114
+ throw new Error(`Memory Candidate ${id} 已发布到 ${current.publication?.uri || '-'},不能静默换目标`);
115
+ }
116
+ const targetContext = readPublishTarget(root, target);
117
+ const block = renderCandidate(current);
118
+ const markerCount = countMarker(targetContext.content, current.id);
119
+ const concurrency = target.provider === 'local-md'
120
+ ? 'atomic-local-cas' : 'best-effort-read-check-append';
121
+ const base = {
122
+ $schema: 'dingtalk-agent/memory-publish-result@1',
123
+ sideEffect: false,
124
+ verified: false,
125
+ duplicate: false,
126
+ candidateId: current.id,
127
+ candidateRevision: current.revision,
128
+ provider: target.provider,
129
+ uri: target.uri,
130
+ currentTargetHash: targetContext.hash,
131
+ targetHashAfter: '',
132
+ markerCount,
133
+ verification: 'dry-run-target-inspected',
134
+ concurrency,
135
+ candidate: current,
136
+ };
137
+ if (!options.execute)
138
+ return { ...base, mode: 'dry-run' };
139
+ if (!options.yes)
140
+ throw new Error('Memory Candidate 发布必须显式 --yes');
141
+ if (!expectedTargetHash || expectedTargetHash !== targetContext.hash) {
142
+ throw new Error(`发布目标 hash 冲突:expected=${expectedTargetHash || '-'}, actual=${targetContext.hash};` +
143
+ '请重新 dry-run 并人工检查差异');
144
+ }
145
+ if (markerCount > 1) {
146
+ return { ...base, mode: 'uncertain', verification: 'duplicate-candidate-markers' };
147
+ }
148
+ let published;
149
+ if (target.provider === 'local-md') {
150
+ published = publishLocal(targetContext.path, targetContext.content, block, current.id);
151
+ }
152
+ else {
153
+ if (!options.live)
154
+ throw new Error('钉钉文档发布必须显式 --live --yes');
155
+ published = publishDingTalkDoc(target, targetContext.content, block, current.id);
156
+ }
157
+ if (!published.verified) {
158
+ return {
159
+ ...base,
160
+ mode: 'uncertain',
161
+ sideEffect: published.sideEffect,
162
+ duplicate: published.duplicate,
163
+ targetHashAfter: published.hash,
164
+ markerCount: published.markerCount,
165
+ verification: published.verification,
166
+ };
167
+ }
168
+ const publication = {
169
+ provider: target.provider,
170
+ uri: target.uri,
171
+ targetHashBefore: targetContext.hash,
172
+ targetHashAfter: published.hash,
173
+ verification: published.verification,
174
+ concurrency,
175
+ publishedAt: new Date().toISOString(),
176
+ gitHead: target.provider === 'local-md' ? readGitHead(root) : '',
177
+ };
178
+ const candidate = current.status === 'published'
179
+ ? current
180
+ : signCandidate({
181
+ ...withoutHash(current),
182
+ revision: current.revision + 1,
183
+ status: 'published',
184
+ publication,
185
+ });
186
+ if (current.status !== 'published')
187
+ writeJsonAtomic(path, candidate);
188
+ return {
189
+ ...base,
190
+ mode: 'published',
191
+ sideEffect: published.sideEffect,
192
+ verified: true,
193
+ duplicate: published.duplicate,
194
+ candidateRevision: candidate.revision,
195
+ targetHashAfter: published.hash,
196
+ markerCount: published.markerCount,
197
+ verification: published.verification,
198
+ candidate: readCandidate(path),
199
+ };
200
+ }
201
+ finally {
202
+ release();
203
+ }
204
+ }
205
+ function publishLocal(path, content, block, candidateId) {
206
+ const release = acquireLease(`${path}.dta-publish.lock`, `发布目标 ${path} 正在更新`, {
207
+ waitMs: 3_000, staleAfterMs: 10 * 60_000,
208
+ });
209
+ try {
210
+ const latest = readFileSync(path, 'utf8');
211
+ if (latest !== content)
212
+ throw new Error('本地发布目标在加锁前发生漂移,请重新 dry-run');
213
+ const existing = countMarker(latest, candidateId);
214
+ const next = existing === 1 ? latest : appendBlock(latest, block);
215
+ if (!existing)
216
+ writeTextAtomic(path, next);
217
+ const readback = readFileSync(path, 'utf8');
218
+ const markerCount = countMarker(readback, candidateId);
219
+ const verified = markerCount === 1 && readback.includes(block.trim());
220
+ return {
221
+ verified,
222
+ sideEffect: !existing,
223
+ duplicate: existing === 1,
224
+ hash: digest(readback),
225
+ markerCount,
226
+ verification: verified ? 'local-atomic-write-readback' : 'local-readback-mismatch',
227
+ };
228
+ }
229
+ finally {
230
+ release();
231
+ }
232
+ }
233
+ function publishDingTalkDoc(target, content, block, candidateId) {
234
+ const profile = clean(target.profile || process.env.DTA_DWS_PROFILE);
235
+ const expectedUserId = clean(target.expectedUserId || process.env.DTA_EXPECTED_USER_ID);
236
+ if (!profile || profile.includes(',') || !expectedUserId) {
237
+ throw new Error('dingtalk-doc 发布必须固定单一 profile 和 expectedUserId');
238
+ }
239
+ const identity = dws.getSelf(profile);
240
+ const actualUserId = String(findValue(identity, ['userId', 'user_id', 'userid']) || '');
241
+ if (!actualUserId || actualUserId !== expectedUserId) {
242
+ throw new Error(`DWS 执行身份不符:expected=${expectedUserId}, actual=${actualUserId || '-'}`);
243
+ }
244
+ const existing = countMarker(content, candidateId);
245
+ let sideEffect = false;
246
+ if (!existing) {
247
+ const directory = mkdtempSync(join(tmpdir(), 'dta-memory-publish-'));
248
+ const file = join(directory, 'candidate.md');
249
+ try {
250
+ writeFileSync(file, block);
251
+ dws.appendDoc(target.uri.slice('dingtalk-doc:'.length), file, profile);
252
+ sideEffect = true;
253
+ }
254
+ finally {
255
+ rmSync(directory, { recursive: true, force: true });
256
+ }
257
+ }
258
+ const readback = String(dws.readDoc(target.uri.slice('dingtalk-doc:'.length), profile));
259
+ const markerCount = countMarker(readback, candidateId);
260
+ const verified = markerCount === 1 && dws.words(readback).includes(dws.words(block));
261
+ return {
262
+ verified,
263
+ sideEffect,
264
+ duplicate: existing === 1,
265
+ hash: digest(readback),
266
+ markerCount,
267
+ verification: verified
268
+ ? 'dingtalk-doc-append-full-readback' : 'dingtalk-doc-readback-mismatch',
269
+ };
270
+ }
271
+ function readPublishTarget(root, target) {
272
+ if (target.provider === 'local-md') {
273
+ const ref = target.uri.slice('local-md:'.length);
274
+ const rootReal = realpathSync(resolve(root));
275
+ const path = realpathSync(resolve(rootReal, ref));
276
+ assertInside(rootReal, path, 'local-md 发布目标');
277
+ const content = readFileSync(path, 'utf8');
278
+ return { path, content, hash: digest(content) };
279
+ }
280
+ const ref = target.uri.slice('dingtalk-doc:'.length);
281
+ const profile = clean(target.profile || process.env.DTA_DWS_PROFILE);
282
+ if (!ref)
283
+ throw new Error('dingtalk-doc 发布目标缺少 node/url');
284
+ const info = dws.docInfo(ref, profile);
285
+ if (String(info?.contentType || '').toUpperCase() !== 'ALIDOC' ||
286
+ String(info?.extension || '').toLowerCase() !== 'adoc') {
287
+ throw new Error('dingtalk-doc 发布目标必须是在线文档 adoc');
288
+ }
289
+ const content = String(dws.readDoc(ref, profile));
290
+ return { path: '', content, hash: digest(content) };
291
+ }
292
+ function renderCandidate(candidate) {
293
+ return `\n> DTA Candidate: \`${candidate.id}\`\n\n` +
294
+ `## ${candidate.title}\n\n` +
295
+ `- Kind: ${candidate.kind}\n` +
296
+ `- Scope: ${candidate.scopeId}\n` +
297
+ `- Confidence: ${candidate.confidence}\n` +
298
+ `- Sources: ${candidate.sourceRefs.join(', ')}\n` +
299
+ `- Supersedes: ${candidate.supersedes.join(', ') || '-'}\n\n` +
300
+ `${candidate.content.trim()}\n`;
301
+ }
302
+ function appendBlock(content, block) {
303
+ return `${content.trimEnd()}\n${block.startsWith('\n') ? block : `\n${block}`}`;
304
+ }
305
+ function countMarker(content, candidateId) {
306
+ return content.split(candidateId).length - 1;
307
+ }
308
+ function validateProposal(value) {
309
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
310
+ throw new Error('Memory Candidate proposal 必须是 JSON object');
311
+ }
312
+ const input = value;
313
+ const allowed = new Set([
314
+ '$schema', 'kind', 'scopeId', 'title', 'content', 'sourceRefs', 'confidence', 'supersedes',
315
+ ]);
316
+ const extra = Object.keys(input).filter((key) => !allowed.has(key));
317
+ if (extra.length)
318
+ throw new Error(`Memory Candidate proposal 含未知字段: ${extra.join(', ')}`);
319
+ if (input.$schema !== 'dingtalk-agent/memory-candidate-proposal@1' ||
320
+ !['semantic', 'procedural'].includes(input.kind)) {
321
+ throw new Error('Memory Candidate proposal schema/kind 非法');
322
+ }
323
+ for (const key of ['scopeId', 'title', 'content']) {
324
+ if (!clean(input[key]))
325
+ throw new Error(`Memory Candidate proposal 缺少 ${key}`);
326
+ }
327
+ if (Buffer.byteLength(input.content, 'utf8') > 32 * 1024) {
328
+ throw new Error('Memory Candidate content 超过 32 KiB');
329
+ }
330
+ for (const key of ['sourceRefs', 'supersedes']) {
331
+ if (!Array.isArray(input[key]) || input[key].some((item) => !clean(item))) {
332
+ throw new Error(`Memory Candidate ${key} 必须是非空字符串数组`);
333
+ }
334
+ }
335
+ if (!input.sourceRefs.length)
336
+ throw new Error('Memory Candidate 至少需要一条 sourceRef');
337
+ if (typeof input.confidence !== 'number' || input.confidence < 0 || input.confidence > 1) {
338
+ throw new Error('Memory Candidate confidence 必须在 0..1');
339
+ }
340
+ return JSON.parse(JSON.stringify(input));
341
+ }
342
+ function validateTarget(value) {
343
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
344
+ throw new Error('Memory publish target 必须是 JSON object');
345
+ }
346
+ const input = value;
347
+ const allowed = new Set(['$schema', 'provider', 'uri', 'profile', 'expectedUserId']);
348
+ const extra = Object.keys(input).filter((key) => !allowed.has(key));
349
+ if (extra.length)
350
+ throw new Error(`Memory publish target 含未知字段: ${extra.join(', ')}`);
351
+ if (input.$schema !== 'dingtalk-agent/memory-publish-target@1' ||
352
+ !['local-md', 'dingtalk-doc'].includes(input.provider)) {
353
+ throw new Error('Memory publish target schema/provider 非法');
354
+ }
355
+ if (!clean(input.uri) || !input.uri.startsWith(`${input.provider}:`)) {
356
+ throw new Error(`Memory publish target uri 必须以 ${input.provider}: 开头`);
357
+ }
358
+ return JSON.parse(JSON.stringify(input));
359
+ }
360
+ function candidateRoot(root, stateDir = '', prepared = false) {
361
+ const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent');
362
+ if (prepared)
363
+ assertInside(resolve(root, '.dingtalk-agent'), base, 'Prepared candidate stateDir');
364
+ const path = join(base, 'memory', 'candidates');
365
+ mkdirSync(path, { recursive: true });
366
+ return path;
367
+ }
368
+ function candidatePath(root, id, stateDir = '') {
369
+ if (!/^memcand_[a-f0-9]{24}$/.test(id))
370
+ throw new Error(`Memory Candidate ID 非法: ${id}`);
371
+ return join(candidateRoot(root, stateDir, false), `${id}.json`);
372
+ }
373
+ function proposerContext(root, runInput = '') {
374
+ const value = clean(runInput || process.env.DTA_RUN);
375
+ if (!value)
376
+ return null;
377
+ const rootReal = realpathSync(resolve(root));
378
+ const runPath = realpathSync(resolve(value));
379
+ assertInside(rootReal, runPath, 'Prepared Run');
380
+ const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'));
381
+ if (!run.id || !run.contextId || !run.definition?.hash) {
382
+ throw new Error('Prepared Run 缺少 id/contextId/definition hash');
383
+ }
384
+ return run;
385
+ }
386
+ function readCandidate(path) {
387
+ if (!existsSync(path))
388
+ throw new Error(`找不到 Memory Candidate: ${path}`);
389
+ const value = JSON.parse(readFileSync(path, 'utf8'));
390
+ const { hash, ...unsigned } = value;
391
+ if (!hash || hash !== digest(stableStringify(unsigned))) {
392
+ throw new Error(`Memory Candidate hash 不一致: ${value.id || path}`);
393
+ }
394
+ return value;
395
+ }
396
+ function signCandidate(unsigned) {
397
+ return { ...unsigned, hash: digest(stableStringify(unsigned)) };
398
+ }
399
+ function withoutHash(candidate) {
400
+ const { hash: _hash, ...unsigned } = candidate;
401
+ return unsigned;
402
+ }
403
+ function assertCandidateRevision(candidate, expected) {
404
+ if (!Number.isInteger(expected) || expected < 1 || candidate.revision !== expected) {
405
+ throw new Error(`Memory Candidate revision 冲突:expected=${expected}, actual=${candidate.revision}`);
406
+ }
407
+ }
408
+ function assertOffline(action, runPath = '') {
409
+ if (process.env.DTA_RUN || runPath) {
410
+ throw new Error(`在线 Prepared Run 只能 propose,不能 ${action} Memory Candidate`);
411
+ }
412
+ }
413
+ function assertInside(root, path, label) {
414
+ const rel = relative(resolve(root), resolve(path));
415
+ if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`)) {
416
+ throw new Error(`${label} 必须位于允许的 root 内`);
417
+ }
418
+ }
419
+ function readGitHead(root) {
420
+ const run = spawnSync('git', ['-C', root, 'rev-parse', 'HEAD'], {
421
+ encoding: 'utf8', timeout: 2_000,
422
+ });
423
+ return run.status === 0 ? String(run.stdout || '').trim() : '';
424
+ }
425
+ function findValue(value, keys) {
426
+ if (!value || typeof value !== 'object')
427
+ return null;
428
+ for (const [key, child] of Object.entries(value)) {
429
+ if (keys.includes(key) && child !== undefined && child !== null && child !== '')
430
+ return child;
431
+ }
432
+ for (const child of Object.values(value)) {
433
+ const found = findValue(child, keys);
434
+ if (found !== null)
435
+ return found;
436
+ }
437
+ return null;
438
+ }
439
+ function writeJsonAtomic(path, value) {
440
+ mkdirSync(dirname(path), { recursive: true });
441
+ writeTextAtomic(path, JSON.stringify(value, null, 2) + '\n');
442
+ }
443
+ function writeTextAtomic(path, value) {
444
+ const temp = `${path}.${process.pid}.${Date.now()}.tmp`;
445
+ writeFileSync(temp, value, { flag: 'wx' });
446
+ renameSync(temp, path);
447
+ }
448
+ function clean(value) {
449
+ return typeof value === 'string' ? value.trim() : '';
450
+ }
451
+ //# sourceMappingURL=candidates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"candidates.js","sourceRoot":"","sources":["../../../src/memory/candidates.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, renameSync, rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { dirname, join, relative, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\nimport { digest, stableStringify } from '../events.js'\nimport { acquireLease } from '../lease.js'\nimport * as dws from '../dws.js'\n\nexport interface MemoryCandidateProposal {\n $schema: 'dingtalk-agent/memory-candidate-proposal@1'\n kind: 'semantic' | 'procedural'\n scopeId: string\n title: string\n content: string\n sourceRefs: string[]\n confidence: number\n supersedes: string[]\n}\n\nexport interface MemoryCandidate {\n $schema: 'dingtalk-agent/memory-candidate@1'\n id: string\n revision: number\n kind: 'semantic' | 'procedural'\n scopeId: string\n title: string\n content: string\n sourceRefs: string[]\n confidence: number\n supersedes: string[]\n status: 'proposed' | 'approved' | 'rejected' | 'published'\n proposedAt: string\n proposer: {\n mode: 'prepared' | 'direct'\n runId: string\n eventId: string\n definitionHash: string\n }\n review: null | {\n decision: 'approve' | 'reject'\n reviewer: string\n reason: string\n reviewedAt: string\n }\n publication: null | {\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n targetHashBefore: string\n targetHashAfter: string\n verification: string\n concurrency: 'atomic-local-cas' | 'best-effort-read-check-append'\n publishedAt: string\n gitHead: string\n }\n hash: string\n}\n\nexport interface MemoryPublishTarget {\n $schema: 'dingtalk-agent/memory-publish-target@1'\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n profile?: string\n expectedUserId?: string\n}\n\nexport interface CandidateOptions {\n stateDir?: string\n runPath?: string\n}\n\nexport interface CandidateResult {\n $schema: 'dingtalk-agent/memory-candidate-result@1'\n duplicate: boolean\n path: string\n candidate: MemoryCandidate\n}\n\nexport interface CandidatePublishResult {\n $schema: 'dingtalk-agent/memory-publish-result@1'\n mode: 'dry-run' | 'published' | 'uncertain'\n sideEffect: boolean\n verified: boolean\n duplicate: boolean\n candidateId: string\n candidateRevision: number\n provider: 'local-md' | 'dingtalk-doc'\n uri: string\n currentTargetHash: string\n targetHashAfter: string\n markerCount: number\n verification: string\n concurrency: 'atomic-local-cas' | 'best-effort-read-check-append'\n candidate: MemoryCandidate\n}\n\nexport function proposeMemoryCandidate(\n root: string,\n value: unknown,\n options: CandidateOptions = {},\n): CandidateResult {\n const proposal = validateProposal(value)\n const run = proposerContext(root, options.runPath)\n if (run && proposal.scopeId !== run.contextId) {\n throw new Error(\n `Memory Candidate scopeId=${proposal.scopeId} 与 Prepared Run contextId=${run.contextId} 不一致`,\n )\n }\n const id = `memcand_${digest(stableStringify(proposal)).slice(0, 24)}`\n const rootPath = candidateRoot(root, options.stateDir, Boolean(run))\n const path = join(rootPath, `${id}.json`)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在创建`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n if (existsSync(path)) {\n const existing = readCandidate(path)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: true,\n path, candidate: existing }\n }\n const now = new Date().toISOString()\n const unsigned: Omit<MemoryCandidate, 'hash'> = {\n $schema: 'dingtalk-agent/memory-candidate@1',\n id,\n revision: 1,\n kind: proposal.kind,\n scopeId: proposal.scopeId,\n title: proposal.title,\n content: proposal.content,\n sourceRefs: proposal.sourceRefs,\n confidence: proposal.confidence,\n supersedes: proposal.supersedes,\n status: 'proposed',\n proposedAt: now,\n proposer: run ? {\n mode: 'prepared', runId: run.id, eventId: run.eventId,\n definitionHash: run.definition?.hash || '',\n } : { mode: 'direct', runId: '', eventId: '', definitionHash: '' },\n review: null,\n publication: null,\n }\n const candidate = signCandidate(unsigned)\n writeJsonAtomic(path, candidate)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n } finally {\n release()\n }\n}\n\nexport function showMemoryCandidate(\n root: string,\n id: string,\n options: CandidateOptions = {},\n): CandidateResult {\n const path = candidatePath(root, id, options.stateDir)\n if (!existsSync(path)) throw new Error(`找不到 Memory Candidate: ${id}`)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n}\n\nexport function reviewMemoryCandidate(\n root: string,\n id: string,\n decision: 'approve' | 'reject',\n reviewer: string,\n reason: string,\n expectedRevision: number,\n options: CandidateOptions = {},\n): CandidateResult {\n assertOffline('review', options.runPath)\n if (!['approve', 'reject'].includes(decision)) throw new Error('review decision 只能是 approve/reject')\n if (!clean(reviewer) || !clean(reason)) throw new Error('review 需要 reviewer 和 reason')\n const path = candidatePath(root, id, options.stateDir)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在评审`, {\n waitMs: 3_000, staleAfterMs: 2 * 60_000,\n })\n try {\n const current = readCandidate(path)\n assertCandidateRevision(current, expectedRevision)\n if (current.status !== 'proposed') {\n throw new Error(`Memory Candidate ${id} 当前状态是 ${current.status},不能再次评审`)\n }\n const unsigned: Omit<MemoryCandidate, 'hash'> = {\n ...withoutHash(current),\n revision: current.revision + 1,\n status: decision === 'approve' ? 'approved' : 'rejected',\n review: {\n decision,\n reviewer: clean(reviewer),\n reason: clean(reason),\n reviewedAt: new Date().toISOString(),\n },\n }\n const candidate = signCandidate(unsigned)\n writeJsonAtomic(path, candidate)\n return { $schema: 'dingtalk-agent/memory-candidate-result@1', duplicate: false,\n path, candidate: readCandidate(path) }\n } finally {\n release()\n }\n}\n\nexport function publishMemoryCandidate(\n root: string,\n id: string,\n targetValue: unknown,\n expectedRevision: number,\n expectedTargetHash = '',\n options: CandidateOptions & { execute?: boolean; yes?: boolean; live?: boolean } = {},\n): CandidatePublishResult {\n if (options.execute) assertOffline('publish', options.runPath)\n const target = validateTarget(targetValue)\n const path = candidatePath(root, id, options.stateDir)\n const release = acquireLease(`${path}.lock`, `Memory Candidate ${id} 正在发布`, {\n waitMs: 3_000, staleAfterMs: 10 * 60_000,\n })\n try {\n const current = readCandidate(path)\n assertCandidateRevision(current, expectedRevision)\n if (!['approved', 'published'].includes(current.status)) {\n throw new Error(`Memory Candidate ${id} 状态为 ${current.status},必须先 approve`)\n }\n if (current.status === 'published' && current.publication?.uri !== target.uri) {\n throw new Error(\n `Memory Candidate ${id} 已发布到 ${current.publication?.uri || '-'},不能静默换目标`,\n )\n }\n const targetContext = readPublishTarget(root, target)\n const block = renderCandidate(current)\n const markerCount = countMarker(targetContext.content, current.id)\n const concurrency = target.provider === 'local-md'\n ? 'atomic-local-cas' as const : 'best-effort-read-check-append' as const\n const base = {\n $schema: 'dingtalk-agent/memory-publish-result@1' as const,\n sideEffect: false,\n verified: false,\n duplicate: false,\n candidateId: current.id,\n candidateRevision: current.revision,\n provider: target.provider,\n uri: target.uri,\n currentTargetHash: targetContext.hash,\n targetHashAfter: '',\n markerCount,\n verification: 'dry-run-target-inspected',\n concurrency,\n candidate: current,\n }\n if (!options.execute) return { ...base, mode: 'dry-run' }\n if (!options.yes) throw new Error('Memory Candidate 发布必须显式 --yes')\n if (!expectedTargetHash || expectedTargetHash !== targetContext.hash) {\n throw new Error(\n `发布目标 hash 冲突:expected=${expectedTargetHash || '-'}, actual=${targetContext.hash};` +\n '请重新 dry-run 并人工检查差异',\n )\n }\n if (markerCount > 1) {\n return { ...base, mode: 'uncertain', verification: 'duplicate-candidate-markers' }\n }\n let published\n if (target.provider === 'local-md') {\n published = publishLocal(targetContext.path, targetContext.content, block, current.id)\n } else {\n if (!options.live) throw new Error('钉钉文档发布必须显式 --live --yes')\n published = publishDingTalkDoc(target, targetContext.content, block, current.id)\n }\n if (!published.verified) {\n return {\n ...base,\n mode: 'uncertain',\n sideEffect: published.sideEffect,\n duplicate: published.duplicate,\n targetHashAfter: published.hash,\n markerCount: published.markerCount,\n verification: published.verification,\n }\n }\n const publication = {\n provider: target.provider,\n uri: target.uri,\n targetHashBefore: targetContext.hash,\n targetHashAfter: published.hash,\n verification: published.verification,\n concurrency,\n publishedAt: new Date().toISOString(),\n gitHead: target.provider === 'local-md' ? readGitHead(root) : '',\n }\n const candidate = current.status === 'published'\n ? current\n : signCandidate({\n ...withoutHash(current),\n revision: current.revision + 1,\n status: 'published',\n publication,\n })\n if (current.status !== 'published') writeJsonAtomic(path, candidate)\n return {\n ...base,\n mode: 'published',\n sideEffect: published.sideEffect,\n verified: true,\n duplicate: published.duplicate,\n candidateRevision: candidate.revision,\n targetHashAfter: published.hash,\n markerCount: published.markerCount,\n verification: published.verification,\n candidate: readCandidate(path),\n }\n } finally {\n release()\n }\n}\n\nfunction publishLocal(\n path: string,\n content: string,\n block: string,\n candidateId: string,\n): { verified: boolean; sideEffect: boolean; duplicate: boolean; hash: string;\n markerCount: number; verification: string } {\n const release = acquireLease(`${path}.dta-publish.lock`, `发布目标 ${path} 正在更新`, {\n waitMs: 3_000, staleAfterMs: 10 * 60_000,\n })\n try {\n const latest = readFileSync(path, 'utf8')\n if (latest !== content) throw new Error('本地发布目标在加锁前发生漂移,请重新 dry-run')\n const existing = countMarker(latest, candidateId)\n const next = existing === 1 ? latest : appendBlock(latest, block)\n if (!existing) writeTextAtomic(path, next)\n const readback = readFileSync(path, 'utf8')\n const markerCount = countMarker(readback, candidateId)\n const verified = markerCount === 1 && readback.includes(block.trim())\n return {\n verified,\n sideEffect: !existing,\n duplicate: existing === 1,\n hash: digest(readback),\n markerCount,\n verification: verified ? 'local-atomic-write-readback' : 'local-readback-mismatch',\n }\n } finally {\n release()\n }\n}\n\nfunction publishDingTalkDoc(\n target: MemoryPublishTarget,\n content: string,\n block: string,\n candidateId: string,\n): { verified: boolean; sideEffect: boolean; duplicate: boolean; hash: string;\n markerCount: number; verification: string } {\n const profile = clean(target.profile || process.env.DTA_DWS_PROFILE)\n const expectedUserId = clean(target.expectedUserId || process.env.DTA_EXPECTED_USER_ID)\n if (!profile || profile.includes(',') || !expectedUserId) {\n throw new Error('dingtalk-doc 发布必须固定单一 profile 和 expectedUserId')\n }\n const identity = dws.getSelf(profile)\n const actualUserId = String(findValue(identity, ['userId', 'user_id', 'userid']) || '')\n if (!actualUserId || actualUserId !== expectedUserId) {\n throw new Error(`DWS 执行身份不符:expected=${expectedUserId}, actual=${actualUserId || '-'}`)\n }\n const existing = countMarker(content, candidateId)\n let sideEffect = false\n if (!existing) {\n const directory = mkdtempSync(join(tmpdir(), 'dta-memory-publish-'))\n const file = join(directory, 'candidate.md')\n try {\n writeFileSync(file, block)\n dws.appendDoc(target.uri.slice('dingtalk-doc:'.length), file, profile)\n sideEffect = true\n } finally {\n rmSync(directory, { recursive: true, force: true })\n }\n }\n const readback = String(dws.readDoc(target.uri.slice('dingtalk-doc:'.length), profile))\n const markerCount = countMarker(readback, candidateId)\n const verified = markerCount === 1 && dws.words(readback).includes(dws.words(block))\n return {\n verified,\n sideEffect,\n duplicate: existing === 1,\n hash: digest(readback),\n markerCount,\n verification: verified\n ? 'dingtalk-doc-append-full-readback' : 'dingtalk-doc-readback-mismatch',\n }\n}\n\nfunction readPublishTarget(\n root: string,\n target: MemoryPublishTarget,\n): { path: string; content: string; hash: string } {\n if (target.provider === 'local-md') {\n const ref = target.uri.slice('local-md:'.length)\n const rootReal = realpathSync(resolve(root))\n const path = realpathSync(resolve(rootReal, ref))\n assertInside(rootReal, path, 'local-md 发布目标')\n const content = readFileSync(path, 'utf8')\n return { path, content, hash: digest(content) }\n }\n const ref = target.uri.slice('dingtalk-doc:'.length)\n const profile = clean(target.profile || process.env.DTA_DWS_PROFILE)\n if (!ref) throw new Error('dingtalk-doc 发布目标缺少 node/url')\n const info = dws.docInfo(ref, profile)\n if (String(info?.contentType || '').toUpperCase() !== 'ALIDOC' ||\n String(info?.extension || '').toLowerCase() !== 'adoc') {\n throw new Error('dingtalk-doc 发布目标必须是在线文档 adoc')\n }\n const content = String(dws.readDoc(ref, profile))\n return { path: '', content, hash: digest(content) }\n}\n\nfunction renderCandidate(candidate: MemoryCandidate): string {\n return `\\n> DTA Candidate: \\`${candidate.id}\\`\\n\\n` +\n `## ${candidate.title}\\n\\n` +\n `- Kind: ${candidate.kind}\\n` +\n `- Scope: ${candidate.scopeId}\\n` +\n `- Confidence: ${candidate.confidence}\\n` +\n `- Sources: ${candidate.sourceRefs.join(', ')}\\n` +\n `- Supersedes: ${candidate.supersedes.join(', ') || '-'}\\n\\n` +\n `${candidate.content.trim()}\\n`\n}\n\nfunction appendBlock(content: string, block: string): string {\n return `${content.trimEnd()}\\n${block.startsWith('\\n') ? block : `\\n${block}`}`\n}\n\nfunction countMarker(content: string, candidateId: string): number {\n return content.split(candidateId).length - 1\n}\n\nfunction validateProposal(value: unknown): MemoryCandidateProposal {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory Candidate proposal 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set([\n '$schema', 'kind', 'scopeId', 'title', 'content', 'sourceRefs', 'confidence', 'supersedes',\n ])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Memory Candidate proposal 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/memory-candidate-proposal@1' ||\n !['semantic', 'procedural'].includes(input.kind)) {\n throw new Error('Memory Candidate proposal schema/kind 非法')\n }\n for (const key of ['scopeId', 'title', 'content']) {\n if (!clean(input[key])) throw new Error(`Memory Candidate proposal 缺少 ${key}`)\n }\n if (Buffer.byteLength(input.content, 'utf8') > 32 * 1024) {\n throw new Error('Memory Candidate content 超过 32 KiB')\n }\n for (const key of ['sourceRefs', 'supersedes']) {\n if (!Array.isArray(input[key]) || input[key].some((item: unknown) => !clean(item))) {\n throw new Error(`Memory Candidate ${key} 必须是非空字符串数组`)\n }\n }\n if (!input.sourceRefs.length) throw new Error('Memory Candidate 至少需要一条 sourceRef')\n if (typeof input.confidence !== 'number' || input.confidence < 0 || input.confidence > 1) {\n throw new Error('Memory Candidate confidence 必须在 0..1')\n }\n return JSON.parse(JSON.stringify(input)) as MemoryCandidateProposal\n}\n\nfunction validateTarget(value: unknown): MemoryPublishTarget {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new Error('Memory publish target 必须是 JSON object')\n }\n const input = value as Record<string, any>\n const allowed = new Set(['$schema', 'provider', 'uri', 'profile', 'expectedUserId'])\n const extra = Object.keys(input).filter((key) => !allowed.has(key))\n if (extra.length) throw new Error(`Memory publish target 含未知字段: ${extra.join(', ')}`)\n if (input.$schema !== 'dingtalk-agent/memory-publish-target@1' ||\n !['local-md', 'dingtalk-doc'].includes(input.provider)) {\n throw new Error('Memory publish target schema/provider 非法')\n }\n if (!clean(input.uri) || !input.uri.startsWith(`${input.provider}:`)) {\n throw new Error(`Memory publish target uri 必须以 ${input.provider}: 开头`)\n }\n return JSON.parse(JSON.stringify(input)) as MemoryPublishTarget\n}\n\nfunction candidateRoot(root: string, stateDir = '', prepared = false): string {\n const base = resolve(root, stateDir || process.env.DTA_STATE_DIR || '.dingtalk-agent')\n if (prepared) assertInside(resolve(root, '.dingtalk-agent'), base, 'Prepared candidate stateDir')\n const path = join(base, 'memory', 'candidates')\n mkdirSync(path, { recursive: true })\n return path\n}\n\nfunction candidatePath(root: string, id: string, stateDir = ''): string {\n if (!/^memcand_[a-f0-9]{24}$/.test(id)) throw new Error(`Memory Candidate ID 非法: ${id}`)\n return join(candidateRoot(root, stateDir, false), `${id}.json`)\n}\n\nfunction proposerContext(root: string, runInput = ''): Record<string, any> | null {\n const value = clean(runInput || process.env.DTA_RUN)\n if (!value) return null\n const rootReal = realpathSync(resolve(root))\n const runPath = realpathSync(resolve(value))\n assertInside(rootReal, runPath, 'Prepared Run')\n const run = JSON.parse(readFileSync(join(runPath, 'run.json'), 'utf8'))\n if (!run.id || !run.contextId || !run.definition?.hash) {\n throw new Error('Prepared Run 缺少 id/contextId/definition hash')\n }\n return run\n}\n\nfunction readCandidate(path: string): MemoryCandidate {\n if (!existsSync(path)) throw new Error(`找不到 Memory Candidate: ${path}`)\n const value = JSON.parse(readFileSync(path, 'utf8')) as MemoryCandidate\n const { hash, ...unsigned } = value\n if (!hash || hash !== digest(stableStringify(unsigned))) {\n throw new Error(`Memory Candidate hash 不一致: ${value.id || path}`)\n }\n return value\n}\n\nfunction signCandidate(unsigned: Omit<MemoryCandidate, 'hash'>): MemoryCandidate {\n return { ...unsigned, hash: digest(stableStringify(unsigned)) }\n}\n\nfunction withoutHash(candidate: MemoryCandidate): Omit<MemoryCandidate, 'hash'> {\n const { hash: _hash, ...unsigned } = candidate\n return unsigned\n}\n\nfunction assertCandidateRevision(candidate: MemoryCandidate, expected: number): void {\n if (!Number.isInteger(expected) || expected < 1 || candidate.revision !== expected) {\n throw new Error(\n `Memory Candidate revision 冲突:expected=${expected}, actual=${candidate.revision}`,\n )\n }\n}\n\nfunction assertOffline(action: string, runPath = ''): void {\n if (process.env.DTA_RUN || runPath) {\n throw new Error(`在线 Prepared Run 只能 propose,不能 ${action} Memory Candidate`)\n }\n}\n\nfunction assertInside(root: string, path: string, label: string): void {\n const rel = relative(resolve(root), resolve(path))\n if (rel === '..' || rel.startsWith(`..${process.platform === 'win32' ? '\\\\' : '/'}`)) {\n throw new Error(`${label} 必须位于允许的 root 内`)\n }\n}\n\nfunction readGitHead(root: string): string {\n const run = spawnSync('git', ['-C', root, 'rev-parse', 'HEAD'], {\n encoding: 'utf8', timeout: 2_000,\n })\n return run.status === 0 ? String(run.stdout || '').trim() : ''\n}\n\nfunction findValue(value: unknown, keys: string[]): unknown {\n if (!value || typeof value !== 'object') return null\n for (const [key, child] of Object.entries(value)) {\n if (keys.includes(key) && child !== undefined && child !== null && child !== '') return child\n }\n for (const child of Object.values(value)) {\n const found = findValue(child, keys)\n if (found !== null) return found\n }\n return null\n}\n\nfunction writeJsonAtomic(path: string, value: unknown): void {\n mkdirSync(dirname(path), { recursive: true })\n writeTextAtomic(path, JSON.stringify(value, null, 2) + '\\n')\n}\n\nfunction writeTextAtomic(path: string, value: string): void {\n const temp = `${path}.${process.pid}.${Date.now()}.tmp`\n writeFileSync(temp, value, { flag: 'wx' })\n renameSync(temp, path)\n}\n\nfunction clean(value: unknown): string {\n return typeof value === 'string' ? value.trim() : ''\n}\n"]}