evolcore 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/CHANGELOG.md +813 -0
  2. package/LICENSE +21 -0
  3. package/MIGRATION-0.5.0.md +378 -0
  4. package/README.md +318 -14
  5. package/ROLE_ACCESS_CONTROL.md +174 -0
  6. package/assets/.env.template +4 -0
  7. package/assets/brand/evolcore/README.md +19 -0
  8. package/assets/brand/evolcore/evolcore-app-icon.png +0 -0
  9. package/assets/brand/evolcore/evolcore-app-icon.svg +13 -0
  10. package/assets/brand/evolcore/evolcore-brand-board.png +0 -0
  11. package/assets/brand/evolcore/evolcore-brand-board.svg +126 -0
  12. package/assets/brand/evolcore/evolcore-logo-kit.zip +0 -0
  13. package/assets/brand/evolcore/evolcore-logo-reverse.png +0 -0
  14. package/assets/brand/evolcore/evolcore-logo-reverse.svg +14 -0
  15. package/assets/brand/evolcore/evolcore-logo.png +0 -0
  16. package/assets/brand/evolcore/evolcore-logo.svg +14 -0
  17. package/assets/brand/evolcore/evolcore-mark.png +0 -0
  18. package/assets/brand/evolcore/evolcore-mark.svg +10 -0
  19. package/bin/ec-safe-output.js +161 -0
  20. package/bin/ec.js +29 -0
  21. package/dist/agents/baseagent.js +163 -0
  22. package/dist/agents/claude-runner.js +2385 -0
  23. package/dist/agents/codex-app-server-client.js +448 -0
  24. package/dist/agents/codex-runner.js +2639 -0
  25. package/dist/agents/gemini-runner.js +666 -0
  26. package/dist/agents/runner-types.js +75 -0
  27. package/dist/aun/aid/agentmd.js +216 -0
  28. package/dist/aun/aid/client.js +132 -0
  29. package/dist/aun/aid/control-aid.js +91 -0
  30. package/dist/aun/aid/identity.js +518 -0
  31. package/dist/aun/aid/index.js +4 -0
  32. package/dist/aun/aid/store.js +74 -0
  33. package/dist/aun/aid/types.js +1 -0
  34. package/dist/aun/aid/validation.js +21 -0
  35. package/dist/aun/group-identity.js +10 -0
  36. package/dist/aun/msg/group-index.js +6 -0
  37. package/dist/aun/msg/group.js +1231 -0
  38. package/dist/aun/msg/history.js +123 -0
  39. package/dist/aun/msg/index.js +5 -0
  40. package/dist/aun/msg/p2p.js +393 -0
  41. package/dist/aun/msg/payload-type.js +27 -0
  42. package/dist/aun/msg/upload.js +137 -0
  43. package/dist/aun/outbox.js +160 -0
  44. package/dist/aun/rpc/caller.js +42 -0
  45. package/dist/aun/rpc/connection.js +25 -0
  46. package/dist/aun/rpc/index.js +2 -0
  47. package/dist/aun/service-proxy.js +225 -0
  48. package/dist/aun/storage/download.js +29 -0
  49. package/dist/aun/storage/index.js +3 -0
  50. package/dist/aun/storage/manage.js +10 -0
  51. package/dist/aun/storage/upload.js +68 -0
  52. package/dist/channels/aun.js +4147 -0
  53. package/dist/channels/daemon.js +422 -0
  54. package/dist/channels/dingtalk.js +649 -0
  55. package/dist/channels/feishu.js +1789 -0
  56. package/dist/channels/qqbot.js +409 -0
  57. package/dist/channels/wechat.js +817 -0
  58. package/dist/channels/wecom.js +565 -0
  59. package/dist/cli/agent-command.js +641 -0
  60. package/dist/cli/agent.js +1059 -0
  61. package/dist/cli/aun-commands.js +1948 -0
  62. package/dist/cli/bench.js +1228 -0
  63. package/dist/cli/cli-argv.js +66 -0
  64. package/dist/cli/code-stats.js +329 -0
  65. package/dist/cli/command-log.js +82 -0
  66. package/dist/cli/config-selector.js +69 -0
  67. package/dist/cli/config.js +261 -0
  68. package/dist/cli/ctl-command.js +62 -0
  69. package/dist/cli/daemon-commands.js +2887 -0
  70. package/dist/cli/fs-command.js +1447 -0
  71. package/dist/cli/handoff-command.js +302 -0
  72. package/dist/cli/help.js +31 -0
  73. package/dist/cli/index.js +358 -0
  74. package/dist/cli/init-channel.js +1377 -0
  75. package/dist/cli/init.js +553 -0
  76. package/dist/cli/link-rules.js +240 -0
  77. package/dist/cli/model.js +590 -0
  78. package/dist/cli/net-check.js +723 -0
  79. package/dist/cli/queue-command.js +126 -0
  80. package/dist/cli/response.js +345 -0
  81. package/dist/cli/restart-monitor.js +456 -0
  82. package/dist/cli/stats.js +607 -0
  83. package/dist/cli/task-context.js +80 -0
  84. package/dist/cli/trigger-command.js +505 -0
  85. package/dist/cli/version.js +88 -0
  86. package/dist/cli/watch-logs.js +33 -0
  87. package/dist/cli/watch-msg.js +673 -0
  88. package/dist/config/boot-log.js +266 -0
  89. package/dist/config/builtin-role-templates.js +30 -0
  90. package/dist/config/builtin-roles.js +85 -0
  91. package/dist/config/config-batch-get.js +11 -0
  92. package/dist/config/config-field-policy.js +261 -0
  93. package/dist/config/config-manager.js +916 -0
  94. package/dist/config/config-operation-service.js +384 -0
  95. package/dist/config/contact-book.js +371 -0
  96. package/dist/config/gateway-config.js +858 -0
  97. package/dist/config/lifecycle.js +17 -0
  98. package/dist/config/mention-mode.js +27 -0
  99. package/dist/config/merge.js +161 -0
  100. package/dist/config/owner-policy.js +4 -0
  101. package/dist/config/peer-role-resolver.js +139 -0
  102. package/dist/config/resolved-config-op.js +483 -0
  103. package/dist/config/role-config-v4-startup.js +32 -0
  104. package/dist/config/role-config-v5-startup.js +27 -0
  105. package/dist/config/role-schema.js +105 -0
  106. package/dist/config/role-service.js +159 -0
  107. package/dist/config/role-store.js +204 -0
  108. package/dist/config/roles.js +55 -0
  109. package/dist/config/schema-registry.js +154 -0
  110. package/dist/config/snapshot.js +598 -0
  111. package/dist/config-store.js +503 -0
  112. package/dist/core/auth/agent-delegation.js +111 -0
  113. package/dist/core/auth/auth-gateway.js +166 -0
  114. package/dist/core/auth/authenticated-actor.js +6 -0
  115. package/dist/core/auth/authorization-audit.js +110 -0
  116. package/dist/core/auth/operation-authorizer.js +718 -0
  117. package/dist/core/auth/operation-catalog.js +675 -0
  118. package/dist/core/baseagent-loader.js +54 -0
  119. package/dist/core/bootstrap-service.js +175 -0
  120. package/dist/core/capability/capability-manager.js +316 -0
  121. package/dist/core/capability/providers/claude-capability-provider.js +176 -0
  122. package/dist/core/capability/providers/codex-capability-provider.js +148 -0
  123. package/dist/core/capability/providers/gemini-capability-provider.js +10 -0
  124. package/dist/core/capability/types.js +27 -0
  125. package/dist/core/causation/audit.js +103 -0
  126. package/dist/core/causation/aun-association.js +111 -0
  127. package/dist/core/causation/context.js +93 -0
  128. package/dist/core/causation/index.js +4 -0
  129. package/dist/core/causation/types.js +2 -0
  130. package/dist/core/channel-loader.js +277 -0
  131. package/dist/core/command/agent-control.js +616 -0
  132. package/dist/core/command/cli-intent-parser.js +225 -0
  133. package/dist/core/command/command-handler.js +1638 -0
  134. package/dist/core/command/menu-handler.js +3354 -0
  135. package/dist/core/command/menu-protocol.js +247 -0
  136. package/dist/core/command/role-menu.js +1524 -0
  137. package/dist/core/command/slash-gate.js +148 -0
  138. package/dist/core/command/slash-handler.js +3056 -0
  139. package/dist/core/daemon-file-cache.js +216 -0
  140. package/dist/core/event-bus.js +32 -0
  141. package/dist/core/event-catalog.js +740 -0
  142. package/dist/core/evolagent-registry.js +546 -0
  143. package/dist/core/evolagent.js +331 -0
  144. package/dist/core/handoff/dispatcher.js +229 -0
  145. package/dist/core/handoff/mutex.js +46 -0
  146. package/dist/core/handoff/runtime.js +324 -0
  147. package/dist/core/handoff/store.js +537 -0
  148. package/dist/core/handoff/types.js +12 -0
  149. package/dist/core/inference/text-inference.js +173 -0
  150. package/dist/core/interaction-registration.js +10 -0
  151. package/dist/core/interaction-router.js +278 -0
  152. package/dist/core/message/create-status.js +67 -0
  153. package/dist/core/message/im-renderer.js +657 -0
  154. package/dist/core/message/items-formatter.js +76 -0
  155. package/dist/core/message/logical-queue-bridge.js +123 -0
  156. package/dist/core/message/message-bridge.js +803 -0
  157. package/dist/core/message/message-cache.js +56 -0
  158. package/dist/core/message/message-log.js +339 -0
  159. package/dist/core/message/message-processor.js +4 -0
  160. package/dist/core/message/message-queue.js +1436 -0
  161. package/dist/core/message/message-utils.js +70 -0
  162. package/dist/core/message/peer-mode.js +105 -0
  163. package/dist/core/message/pending-hints.js +232 -0
  164. package/dist/core/message/response-depth.js +33 -0
  165. package/dist/core/message/response-engine.js +3776 -0
  166. package/dist/core/message/response-snapshot.js +83 -0
  167. package/dist/core/message/stream-debouncer.js +130 -0
  168. package/dist/core/message/stream-idle-monitor.js +124 -0
  169. package/dist/core/model/config-scope.js +162 -0
  170. package/dist/core/model/field-scope.js +78 -0
  171. package/dist/core/model/model-catalog.js +227 -0
  172. package/dist/core/model/model-diagnostics.js +182 -0
  173. package/dist/core/model/model-permission.js +90 -0
  174. package/dist/core/permission/approval-gateway.js +1017 -0
  175. package/dist/core/permission/ec-command-parser.js +347 -0
  176. package/dist/core/permission/execution-sandbox.js +16 -0
  177. package/dist/core/permission/index.js +6 -0
  178. package/dist/core/permission/mode.js +24 -0
  179. package/dist/core/permission/sandbox-runtime.js +265 -0
  180. package/dist/core/permission/tool-policy.js +987 -0
  181. package/dist/core/permission/unix-socket-policy.js +99 -0
  182. package/dist/core/protected-paths.js +330 -0
  183. package/dist/core/relation/peer-identity.js +222 -0
  184. package/dist/core/relation/peer-key.js +1 -0
  185. package/dist/core/role/runtime-policy.js +141 -0
  186. package/dist/core/session/adapters/claude-session-file-adapter.js +218 -0
  187. package/dist/core/session/adapters/codex-session-file-adapter.js +333 -0
  188. package/dist/core/session/adapters/gemini-session-file-adapter.js +181 -0
  189. package/dist/core/session/session-file-adapter.js +7 -0
  190. package/dist/core/session/session-file-health.js +45 -0
  191. package/dist/core/session/session-fs-store.js +232 -0
  192. package/dist/core/session/session-key.js +24 -0
  193. package/dist/core/session/session-manager.js +1587 -0
  194. package/dist/core/session/session-mapper.js +100 -0
  195. package/dist/core/session/session-renew.js +314 -0
  196. package/dist/core/session/session-title.js +128 -0
  197. package/dist/core/session/session-turn-coordinator.js +205 -0
  198. package/dist/core/session/session-turns.js +67 -0
  199. package/dist/core/system-channels.js +29 -0
  200. package/dist/eck/baseagent-caps.js +18 -0
  201. package/dist/eck/detect.js +47 -0
  202. package/dist/eck/group-rules-sync.js +345 -0
  203. package/dist/eck/init.js +77 -0
  204. package/dist/eck/kit-renderer.js +359 -0
  205. package/dist/eck/manifest-engine.js +446 -0
  206. package/dist/eck/message-renderer.js +199 -0
  207. package/dist/eck/rules-loader.js +28 -0
  208. package/dist/index.js +2870 -4
  209. package/dist/ipc.js +748 -0
  210. package/dist/paths.js +262 -0
  211. package/dist/product.js +18 -0
  212. package/dist/response-system/context-builder.js +71 -0
  213. package/dist/response-system/coordinator.js +117 -0
  214. package/dist/response-system/decision-executor.js +86 -0
  215. package/dist/response-system/engines/v1/index.js +21 -0
  216. package/dist/response-system/engines/v1/interactive-flow.js +27 -0
  217. package/dist/response-system/engines/v1/proactive-flow.js +137 -0
  218. package/dist/response-system/engines/v1/types.js +1 -0
  219. package/dist/response-system/extensions.js +41 -0
  220. package/dist/response-system/index.js +6 -0
  221. package/dist/response-system/modes/index.js +7 -0
  222. package/dist/response-system/modes/single-session/index.js +72 -0
  223. package/dist/response-system/queues/fifo-queue.js +44 -0
  224. package/dist/response-system/queues/index.js +6 -0
  225. package/dist/response-system/queues/lifo-queue.js +42 -0
  226. package/dist/response-system/queues/priority-queue.js +63 -0
  227. package/dist/response-system/registry.js +97 -0
  228. package/dist/response-system/resolver.js +37 -0
  229. package/dist/response-system/selector.js +23 -0
  230. package/dist/response-system/types.js +7 -0
  231. package/dist/stats/billing.js +151 -0
  232. package/dist/stats/budget.js +93 -0
  233. package/dist/stats/db.js +403 -0
  234. package/dist/stats/eck-vars.js +89 -0
  235. package/dist/stats/index.js +11 -0
  236. package/dist/stats/normalizer.js +80 -0
  237. package/dist/stats/price-resolver.js +138 -0
  238. package/dist/stats/query.js +763 -0
  239. package/dist/stats/role-budget.js +168 -0
  240. package/dist/stats/writer.js +151 -0
  241. package/dist/trigger/anomaly-store.js +258 -0
  242. package/dist/trigger/audit.js +152 -0
  243. package/dist/trigger/event-source.js +119 -0
  244. package/dist/trigger/feedback.js +685 -0
  245. package/dist/trigger/history.js +290 -0
  246. package/dist/trigger/manager.js +291 -0
  247. package/dist/trigger/parser.js +520 -0
  248. package/dist/trigger/patch.js +148 -0
  249. package/dist/trigger/scheduler.js +1600 -0
  250. package/dist/trigger/script-executor.js +155 -0
  251. package/dist/trigger/state.js +145 -0
  252. package/dist/trigger/types.js +1 -0
  253. package/dist/trigger/validation.js +621 -0
  254. package/dist/types.js +12 -0
  255. package/dist/utils/aid-bind.js +299 -0
  256. package/dist/utils/atomic-write.js +95 -0
  257. package/dist/utils/avatar-upload.js +123 -0
  258. package/dist/utils/cross-platform.js +297 -0
  259. package/dist/utils/ecweb-utils.js +73 -0
  260. package/dist/utils/error-dict.json +153 -0
  261. package/dist/utils/error-utils.js +349 -0
  262. package/dist/utils/instance-registry.js +437 -0
  263. package/dist/utils/locale.js +21 -0
  264. package/dist/utils/log-writer.js +224 -0
  265. package/dist/utils/logger.js +89 -0
  266. package/dist/utils/markdown-to-plain-text.js +20 -0
  267. package/dist/utils/media-cache.js +271 -0
  268. package/dist/utils/model-prices.jsonl +17 -0
  269. package/dist/utils/npm-ops.js +210 -0
  270. package/dist/utils/process-introspect.js +133 -0
  271. package/dist/utils/process-tree-stats.js +271 -0
  272. package/dist/utils/project-path.js +74 -0
  273. package/dist/utils/stats.js +410 -0
  274. package/dist/utils/tool-summary.js +284 -0
  275. package/dist/utils/welcome.js +268 -0
  276. package/kits/docs/GUIDE.md +20 -0
  277. package/kits/docs/INDEX.md +65 -0
  278. package/kits/docs/aun/CHEATSHEET.md +19 -0
  279. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  280. package/kits/docs/channels/aun.md +65 -0
  281. package/kits/docs/channels/feishu.md +56 -0
  282. package/kits/docs/context-assembly.md +366 -0
  283. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  284. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  285. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  286. package/kits/docs/eck_templates/runtime.template.md +19 -0
  287. package/kits/docs/evolcore/INDEX.md +66 -0
  288. package/kits/docs/evolcore/agent.md +69 -0
  289. package/kits/docs/evolcore/aid.md +49 -0
  290. package/kits/docs/evolcore/config.md +149 -0
  291. package/kits/docs/evolcore/ctl.md +46 -0
  292. package/kits/docs/evolcore/event.md +216 -0
  293. package/kits/docs/evolcore/fs-architecture.md +1215 -0
  294. package/kits/docs/evolcore/fs.md +101 -0
  295. package/kits/docs/evolcore/group-fs.md +17 -0
  296. package/kits/docs/evolcore/group-rules.md +226 -0
  297. package/kits/docs/evolcore/group.md +141 -0
  298. package/kits/docs/evolcore/model.md +47 -0
  299. package/kits/docs/evolcore/msg.md +130 -0
  300. package/kits/docs/evolcore/response.md +80 -0
  301. package/kits/docs/evolcore/rpc.md +35 -0
  302. package/kits/docs/evolcore/self-summary.md +29 -0
  303. package/kits/docs/evolcore/stats.md +70 -0
  304. package/kits/docs/evolcore/storage.md +49 -0
  305. package/kits/docs/evolcore/trigger.md +524 -0
  306. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -0
  307. package/kits/docs/identity/PATH_OPS.md +16 -0
  308. package/kits/docs/identity/ROLE_DETAIL.md +23 -0
  309. package/kits/docs/identity/identity-tools.md +26 -0
  310. package/kits/docs/path-registry.md +43 -0
  311. package/kits/docs/prompt-loading-architecture.md +266 -0
  312. package/kits/docs/venues/aun-group.md +45 -0
  313. package/kits/docs/venues/aun-private.md +10 -0
  314. package/kits/docs/venues/client-desktop.md +10 -0
  315. package/kits/docs/venues/client-mobile.md +10 -0
  316. package/kits/docs/venues/feishu-group.md +13 -0
  317. package/kits/docs/venues/feishu-private.md +9 -0
  318. package/kits/docs/venues/group.md +25 -0
  319. package/kits/docs/venues/private.md +10 -0
  320. package/kits/eck_manifest.auxiliary.json +43 -0
  321. package/kits/eck_manifest.json +191 -0
  322. package/kits/eck_message_manifest.json +63 -0
  323. package/kits/migrations/README-role-config-v4.md +32 -0
  324. package/kits/migrations/migrate-role-config-v4.mjs +623 -0
  325. package/kits/migrations/migrate-role-config-v5.mjs +346 -0
  326. package/kits/migrations/rename-config-file.mjs +99 -0
  327. package/kits/rules/01-overview.md +142 -0
  328. package/kits/rules/02-navigation.md +76 -0
  329. package/kits/rules/03-identity.md +34 -0
  330. package/kits/rules/04-relation.md +59 -0
  331. package/kits/rules/05-venue.md +44 -0
  332. package/kits/rules/06-channel.md +59 -0
  333. package/kits/schemas/_meta.json +29 -0
  334. package/kits/schemas/agent-config.schema.1.json +177 -0
  335. package/kits/schemas/agent-config.schema.2.json +239 -0
  336. package/kits/schemas/agent-config.schema.3.json +119 -0
  337. package/kits/schemas/agent-config.schema.4.json +208 -0
  338. package/kits/schemas/agent-config.schema.5.json +326 -0
  339. package/kits/schemas/contact-book.schema.1.json +36 -0
  340. package/kits/schemas/daemon.schema.1.json +90 -0
  341. package/kits/schemas/defaults.schema.1.json +81 -0
  342. package/kits/schemas/menu-exec-schema-commands.md +208 -0
  343. package/kits/schemas/migrations/README.md +28 -0
  344. package/kits/schemas/relation-config.schema.1.json +158 -0
  345. package/kits/schemas/relation-config.schema.2.json +73 -0
  346. package/kits/schemas/relation-config.schema.3.json +50 -0
  347. package/kits/schemas/relation-config.schema.4.json +47 -0
  348. package/kits/schemas/role-config.schema.1.json +200 -0
  349. package/kits/schemas/role-registry.schema.1.json +35 -0
  350. package/kits/schemas/single-session.schema.1.json +31 -0
  351. package/kits/templates/bootstrap-welcome.md +15 -0
  352. package/kits/templates/message-fragments/handoff-request-to-target.md +13 -0
  353. package/kits/templates/message-fragments/handoff-response-to-origin.md +10 -0
  354. package/kits/templates/message-fragments/inject-default.md +2 -0
  355. package/kits/templates/message-fragments/item.md +2 -0
  356. package/kits/templates/roles/admin.json +8 -0
  357. package/kits/templates/roles/member.json +40 -0
  358. package/kits/templates/roles/owner.json +8 -0
  359. package/kits/templates/roles/visitor.json +39 -0
  360. package/kits/templates/system-fragments/baseagent.md +14 -0
  361. package/kits/templates/system-fragments/bootstrap.md +16 -0
  362. package/kits/templates/system-fragments/channel.md +48 -0
  363. package/kits/templates/system-fragments/commands.md +26 -0
  364. package/kits/templates/system-fragments/identity.md +11 -0
  365. package/kits/templates/system-fragments/relation.md +19 -0
  366. package/kits/templates/system-fragments/session.md +53 -0
  367. package/kits/templates/system-fragments/venue.md +31 -0
  368. package/package.json +50 -15
  369. package/dist/index.d.ts +0 -7
  370. package/dist/index.d.ts.map +0 -1
  371. package/dist/index.js.map +0 -1
@@ -0,0 +1,503 @@
1
+ /**
2
+ * ConfigStore —— 新结构(evolcore-home-directory.md)的配置加载/合并/写入。
3
+ *
4
+ * agents/defaults.json ← DefaultsConfig
5
+ * agents/<aid>/config.json ← AgentConfig(per-agent)
6
+ *
7
+ * 合并规则:
8
+ * - 统一由 ConfigManager.resolveEffective() 处理
9
+ * - 覆盖链:defaults → agent/config → relation/config
10
+ * - 深合并:models / chatmode / aun / baseagents / projects 子字段
11
+ * - 标量覆盖:active_baseagent / show_activities / flush_delay / debounce
12
+ * - per-agent only:aid / enabled / channels(不进 defaults)
13
+ *
14
+ * 写入:通过 atomic-write 双 rename,避免崩溃损坏。
15
+ *
16
+ * 旧 data/daemon.json / agents/<name>.json 不识别、不兼容——视若不存在。
17
+ */
18
+ import fs from 'fs';
19
+ import path from 'path';
20
+ import { resolvePaths, agentDir, } from './paths.js';
21
+ import { atomicReadJson, atomicWriteJson } from './utils/atomic-write.js';
22
+ import { checkAgentDir, isValidAid } from './aun/aid/validation.js';
23
+ import { isValidChannelName } from './core/channel-loader.js';
24
+ import { CONFIG_SCHEMA_VERSION } from './types.js';
25
+ import { ConfigTarget, read as cfgRead, write as cfgWrite } from './config/config-manager.js';
26
+ import { expandVars, buildEnvResolver } from './config/merge.js';
27
+ import { logger } from './utils/logger.js';
28
+ /** 读 {root}/daemon.json。文件不存在返回 {},不报错。 */
29
+ export function loadDaemonConfig() {
30
+ const raw = atomicReadJson(resolvePaths().daemonConfig);
31
+ return raw ?? {};
32
+ }
33
+ let eckSnapshotsConfigCache;
34
+ /** Parse the process-level snapshot gate once for the current daemon lifecycle. */
35
+ export function initializeEckSnapshotsConfig(config = loadDaemonConfig()) {
36
+ const enabled = config.debug?.eckSnapshots === true;
37
+ eckSnapshotsConfigCache = {
38
+ configPath: resolvePaths().daemonConfig,
39
+ enabled,
40
+ };
41
+ return enabled;
42
+ }
43
+ export function isEckSnapshotsEnabled() {
44
+ const configPath = resolvePaths().daemonConfig;
45
+ if (!eckSnapshotsConfigCache || eckSnapshotsConfigCache.configPath !== configPath) {
46
+ return initializeEckSnapshotsConfig();
47
+ }
48
+ return eckSnapshotsConfigCache.enabled;
49
+ }
50
+ /** 原子写入 {root}/daemon.json。调用方负责传完整对象(含要保留的字段)。 */
51
+ export function saveDaemonConfig(value) {
52
+ atomicWriteJson(resolvePaths().daemonConfig, value);
53
+ }
54
+ const SUPPORTED_CHANNEL_TYPES = new Set([
55
+ 'aun', 'feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom',
56
+ ]);
57
+ // ── env 展开(${VAR},design §五)─────────────────────────────────────────
58
+ //
59
+ // 仅支持 ${VAR}(旧 $ENV:NAME 已废弃)。展开经 merge.ts 的 expandVars + 三级 .env 解析器
60
+ // (关系 > agent > 全局 > process.env)。loadAgent 传 agent 作用域;loadDefaults 用全局。
61
+ /** 全局作用域(仅 {root}/.env + process.env)展开 ${VAR}。 */
62
+ export function expandEnvRefs(value) {
63
+ const resolver = buildEnvResolver({ rootDir: resolvePaths().root });
64
+ return expandVars(value, resolver);
65
+ }
66
+ /** agent 作用域展开(agent/.env > 全局 .env > process.env)。 */
67
+ function expandEnvRefsForAgent(value, aid) {
68
+ const resolver = buildEnvResolver({ rootDir: resolvePaths().root, agentDir: agentDir(aid) });
69
+ return expandVars(value, resolver);
70
+ }
71
+ // ── 加载/写入 ──────────────────────────────────────────────────────────
72
+ export function loadDefaults() {
73
+ const p = resolvePaths().defaultsConfig;
74
+ const raw = atomicReadJson(p);
75
+ if (raw === null)
76
+ return null;
77
+ if (typeof raw.$schema_version !== 'number') {
78
+ logger.warn(`[config] ${p}: missing $schema_version, treating as ${CONFIG_SCHEMA_VERSION}`);
79
+ }
80
+ return expandEnvRefs(raw);
81
+ }
82
+ export function saveDefaults(value) {
83
+ backupDefaults(resolvePaths().defaultsConfig);
84
+ atomicWriteJson(resolvePaths().defaultsConfig, value);
85
+ }
86
+ /**
87
+ * 备份 defaults.json 为 defaults_YYYYMMDDhhmmss.json。文件不存在时为 no-op。
88
+ * 同秒重复调用会被覆盖(同一秒内的内容相同,可接受)。
89
+ */
90
+ function backupDefaults(filePath) {
91
+ if (!fs.existsSync(filePath))
92
+ return;
93
+ const now = new Date();
94
+ const ts = now.getFullYear().toString()
95
+ + String(now.getMonth() + 1).padStart(2, '0')
96
+ + String(now.getDate()).padStart(2, '0')
97
+ + String(now.getHours()).padStart(2, '0')
98
+ + String(now.getMinutes()).padStart(2, '0')
99
+ + String(now.getSeconds()).padStart(2, '0');
100
+ const backupPath = path.join(path.dirname(filePath), `defaults_${ts}.json`);
101
+ try {
102
+ fs.copyFileSync(filePath, backupPath);
103
+ }
104
+ catch (e) {
105
+ logger.warn(`[config] backup failed: ${backupPath}: ${e}`);
106
+ }
107
+ }
108
+ /**
109
+ * 安全写入 defaults.json:备份现有文件 → 深合并 patch → 原子写入。
110
+ *
111
+ * 与 saveDefaults() 不同,本函数保留现有字段,仅覆盖 patch 中显式指定的字段。
112
+ * 适用场景:ec init 仅修改 active_baseagent/baseagents 时,不应丢失 chatmode/projects 等其它字段。
113
+ */
114
+ export function saveDefaultsSafe(patch) {
115
+ const p = resolvePaths().defaultsConfig;
116
+ let existing = null;
117
+ try {
118
+ existing = atomicReadJson(p);
119
+ }
120
+ catch (e) {
121
+ logger.warn(`[config] existing defaults.json unparsable, will be backed up and replaced: ${e}`);
122
+ }
123
+ fs.mkdirSync(path.dirname(p), { recursive: true });
124
+ backupDefaults(p);
125
+ const merged = existing
126
+ ? deepMergeObject(existing, patch)
127
+ : { $schema_version: CONFIG_SCHEMA_VERSION, ...patch };
128
+ atomicWriteJson(p, merged);
129
+ }
130
+ /** 递归对象合并:overlay 覆盖 base;标量与数组按 overlay 替换;plain object 递归。
131
+ * saveDefaultsSafe 内部用(保留现有"补丁式写 defaults"语义,与覆盖链合并无关)。 */
132
+ function deepMergeObject(base, overlay) {
133
+ if (overlay === undefined)
134
+ return base;
135
+ if (base === undefined)
136
+ return overlay;
137
+ if (!isPlainObject(base) || !isPlainObject(overlay))
138
+ return overlay;
139
+ const out = { ...base };
140
+ for (const [k, v] of Object.entries(overlay))
141
+ out[k] = deepMergeObject(base[k], v);
142
+ return out;
143
+ }
144
+ function isPlainObject(v) {
145
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
146
+ }
147
+ // ── 自动迁移(已删除)─────────────────────────────────────────────────
148
+ //
149
+ // 旧 data/daemon.json / agents/<name>.json → 新结构的一次性迁移已随配置体系 v2 退场
150
+ // (fresh init,不做兼容过渡,见 docs/config-system-design-v2.md §七)。
151
+ // 保留空壳仅为调用点签名兼容——startup 不再调用。
152
+ export function autoMigrateIfNeeded() {
153
+ /* no-op: legacy migration removed (config-system v2 fresh init) */
154
+ }
155
+ /**
156
+ * @deprecated Use ConfigManager.read(ConfigTarget.Agent, { self: aid }, { expand: true, cache: true }) instead.
157
+ * This wrapper exists for backward compatibility. All logic (aid validation, path cleaning, env expansion)
158
+ * is now handled by ConfigManager.
159
+ */
160
+ export function loadAgent(aid) {
161
+ return cfgRead(ConfigTarget.Agent, { self: aid }, { expand: true, cache: true });
162
+ }
163
+ /**
164
+ * @deprecated Use ConfigManager.write(ConfigTarget.Agent, value, { self: value.aid }) instead.
165
+ * This wrapper exists for backward compatibility. All logic (aid validation, projects normalization)
166
+ * is now handled by ConfigManager.
167
+ */
168
+ export function saveAgent(value) {
169
+ cfgWrite(ConfigTarget.Agent, value, { self: value.aid });
170
+ }
171
+ function isGeneratedControlAid(aid) {
172
+ return /^ec\d{5}\.agentid\.pub$/.test(aid);
173
+ }
174
+ function hasLocalAidPrivateKey(aid) {
175
+ return fs.existsSync(path.join(resolvePaths().root, 'AIDs', aid, 'private', 'key.json'));
176
+ }
177
+ function isControlAidStateDir(dirName, controlAid) {
178
+ if (dirName === controlAid)
179
+ return true;
180
+ return isGeneratedControlAid(dirName) && hasLocalAidPrivateKey(dirName);
181
+ }
182
+ /**
183
+ * 扫描 agents/ 目录加载所有 self-agent 配置。
184
+ *
185
+ * 跳过条件(warn-and-skip):
186
+ * - 目录名不是合法 AID
187
+ * - 缺 config.json(控制 AID 状态目录除外)
188
+ * - config.json 解析或基础校验失败
189
+ *
190
+ * 不抛错——返回 skipped 列表交调用方决定是否继续。
191
+ */
192
+ export function loadAllAgents(opts = {}) {
193
+ const agentsDir = resolvePaths().agentsDir;
194
+ const result = { agents: [], skipped: [], invalidAgents: opts.includeInvalid ? [] : undefined };
195
+ const controlAid = loadDaemonConfig().aid;
196
+ if (!fs.existsSync(agentsDir))
197
+ return result;
198
+ const entries = fs.readdirSync(agentsDir, { withFileTypes: true });
199
+ for (const entry of entries) {
200
+ if (!entry.isDirectory())
201
+ continue;
202
+ const dirName = entry.name;
203
+ const cfgPath = path.join(agentsDir, dirName, 'config.json');
204
+ // Skip directories without config.json (could be utility dirs like response-modes, templates, etc.)
205
+ if (!fs.existsSync(cfgPath)) {
206
+ if (isControlAidStateDir(dirName, controlAid)) {
207
+ logger.debug(`[config] ignore control AID state dir agents/${dirName}`);
208
+ }
209
+ else {
210
+ logger.debug(`[config] ignore non-agent dir agents/${dirName} (no config.json)`);
211
+ }
212
+ continue;
213
+ }
214
+ // Now validate AID format since config.json exists
215
+ const why = checkAgentDir(agentsDir, dirName);
216
+ if (why) {
217
+ result.skipped.push({ dirName, reason: why });
218
+ logger.warn(`[config] skip agents/${dirName}: ${why}`);
219
+ continue;
220
+ }
221
+ try {
222
+ const cfg = loadAgent(dirName);
223
+ if (cfg === null) {
224
+ result.skipped.push({ dirName, reason: 'config.json missing after dir check' });
225
+ continue;
226
+ }
227
+ const errs = validateAgentConfig(cfg);
228
+ if (errs.length > 0) {
229
+ const reason = errs.join('; ');
230
+ if (opts.includeInvalid) {
231
+ result.invalidAgents.push({ agent: cfg, reason });
232
+ }
233
+ else {
234
+ result.skipped.push({ dirName, reason });
235
+ }
236
+ logger.warn(`[config] skip agents/${dirName}: ${reason}`);
237
+ continue;
238
+ }
239
+ result.agents.push(cfg);
240
+ }
241
+ catch (e) {
242
+ const reason = e instanceof Error ? e.message : String(e);
243
+ if (opts.includeInvalid) {
244
+ result.invalidAgents.push({
245
+ agent: {
246
+ $schema_version: CONFIG_SCHEMA_VERSION,
247
+ aid: dirName,
248
+ enabled: true,
249
+ channels: [],
250
+ },
251
+ reason,
252
+ });
253
+ }
254
+ result.skipped.push({ dirName, reason });
255
+ logger.warn(`[config] skip agents/${dirName}: ${reason}`);
256
+ }
257
+ }
258
+ return result;
259
+ }
260
+ // ── 校验 ───────────────────────────────────────────────────────────────
261
+ /**
262
+ * @deprecated 设计目标(config-system-design-v2 §七)是用 ConfigManager 的 ajv schema
263
+ * 校验替代本函数。但**当前 agent config.json 尚未完成完整 schema 定义**——现有文件仍
264
+ * 包含少量历史/实验字段。agent-config schema 是 `additionalProperties:false`,
265
+ * 此刻切到 schema 校验可能让现存 agent 加载失败。
266
+ *
267
+ * 因此本函数**暂保留纯业务规则校验**(不接 schema)。待 schema 补齐所有字段后,
268
+ * 再切换到 ConfigManager.validateConfig。
269
+ * 见 docs/config-v2-inconsistencies-analysis.md 问题 B / config-system-v2-implementation-status.md。
270
+ */
271
+ export function validateAgentConfig(cfg) {
272
+ const errs = [];
273
+ if (!cfg.aid || !isValidAid(cfg.aid))
274
+ errs.push(`invalid aid: ${cfg.aid}`);
275
+ if (!Array.isArray(cfg.channels)) {
276
+ errs.push('channels must be an array');
277
+ return errs;
278
+ }
279
+ if (cfg.owners !== undefined) {
280
+ if (!Array.isArray(cfg.owners)) {
281
+ errs.push('owners must be an array');
282
+ }
283
+ else {
284
+ const seenOwners = new Set();
285
+ cfg.owners.forEach((owner, i) => {
286
+ if (typeof owner !== 'string' || !isValidAid(owner)) {
287
+ errs.push(`owners[${i}] invalid aid: ${owner}`);
288
+ return;
289
+ }
290
+ if (seenOwners.has(owner)) {
291
+ errs.push(`owners[${i}] duplicate aid: ${owner}`);
292
+ return;
293
+ }
294
+ seenOwners.add(owner);
295
+ });
296
+ }
297
+ }
298
+ let aunCount = 0;
299
+ const seenNamesByType = new Map();
300
+ for (const [i, ch] of cfg.channels.entries()) {
301
+ if (!ch || typeof ch !== 'object') {
302
+ errs.push(`channels[${i}] must be an object`);
303
+ continue;
304
+ }
305
+ if (ch.type === 'aun') {
306
+ // AUN 是隐式的(从 agent.aid 派生),不应出现在 channels[] 里
307
+ // 容忍但 warn——不算 error,跳过校验
308
+ aunCount++;
309
+ continue;
310
+ }
311
+ if (!SUPPORTED_CHANNEL_TYPES.has(ch.type)) {
312
+ errs.push(`channels[${i}].type "${ch.type}" not supported`);
313
+ continue;
314
+ }
315
+ if (!isValidChannelName(ch.name)) {
316
+ errs.push(`channels[${i}].name invalid (empty or contains '#'): ${JSON.stringify(ch.name)}`);
317
+ continue;
318
+ }
319
+ const set = seenNamesByType.get(ch.type) ?? new Set();
320
+ if (set.has(ch.name)) {
321
+ errs.push(`channels[${i}]: duplicate name "${ch.name}" within type "${ch.type}"`);
322
+ }
323
+ else {
324
+ set.add(ch.name);
325
+ seenNamesByType.set(ch.type, set);
326
+ }
327
+ }
328
+ if (aunCount > 0) {
329
+ logger.warn(`[config] agent ${cfg.aid}: channels[] contains ${aunCount} AUN entry(s) — AUN is implicit, these will be ignored`);
330
+ }
331
+ return errs;
332
+ }
333
+ // ── 合并 ───────────────────────────────────────────────────────────────
334
+ // ── 目录骨架 ───────────────────────────────────────────────────────────
335
+ /**
336
+ * 为某个 self-agent 创建文档约定的子目录骨架(personal/、identities/、venues/ 等)。
337
+ * 已存在则跳过,幂等可重复调用。
338
+ *
339
+ * 注:本函数只建**目录骨架**,不碰 config.json——由 saveAgent(创建路径)
340
+ * 或 ConfigManager.ensureFile(设计目标)负责。
341
+ * 骨架那部分职责,目录骨架职责保留在此。
342
+ */
343
+ export function ensureAgentDirSkeleton(aid) {
344
+ const root = agentDir(aid);
345
+ const subs = [
346
+ 'personal',
347
+ 'personal/memory',
348
+ 'personal/skills',
349
+ 'relations/contacts',
350
+ 'relations/_observed',
351
+ 'relations/_observed/_index',
352
+ 'relations/_index',
353
+ 'relations/_trash',
354
+ 'venues',
355
+ 'venues/_index',
356
+ 'venues/_trash',
357
+ 'sessions',
358
+ 'data/cache',
359
+ 'index',
360
+ ];
361
+ for (const sub of subs) {
362
+ fs.mkdirSync(path.join(root, sub), { recursive: true });
363
+ }
364
+ }
365
+ // ── identities → relations 迁移 ──────────────────────────────────────
366
+ /**
367
+ * 启动时自动迁移:如果 agents/<aid>/identities/ 存在但 relations/ 不存在,
368
+ * 将 identities/ 重命名为 relations/。幂等。
369
+ */
370
+ export function migrateIdentitiesIfNeeded() {
371
+ const agentsDir = resolvePaths().agentsDir;
372
+ if (!fs.existsSync(agentsDir))
373
+ return;
374
+ for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
375
+ if (!entry.isDirectory())
376
+ continue;
377
+ const oldDir = path.join(agentsDir, entry.name, 'identities');
378
+ const newDir = path.join(agentsDir, entry.name, 'relations');
379
+ if (fs.existsSync(oldDir) && !fs.existsSync(newDir)) {
380
+ fs.renameSync(oldDir, newDir);
381
+ logger.info(`[migrate] Renamed agents/${entry.name}/identities/ → relations/`);
382
+ }
383
+ }
384
+ }
385
+ // ── Project Migration ────────────────────────────────────────────────────────
386
+ import os from 'os';
387
+ // 复用与 Claude SDK 对齐的统一编码(resolve→realpath→NFC→非字母数字替换为 -),
388
+ // 避免本地实现规则不一致导致中文/非 ASCII 路径迁移时找不到 SDK 会话目录。
389
+ import { encodePath } from './utils/cross-platform.js';
390
+ /** 查找最新的 ~/.codex/state_*.sqlite */
391
+ function findCodexDb() {
392
+ const codexHome = path.join(os.homedir(), '.codex');
393
+ if (!fs.existsSync(codexHome))
394
+ return null;
395
+ const files = fs.readdirSync(codexHome)
396
+ .filter(f => /^state_\d+\.sqlite$/.test(f))
397
+ .sort((a, b) => {
398
+ const va = parseInt(a.match(/state_(\d+)/)?.[1] || '0');
399
+ const vb = parseInt(b.match(/state_(\d+)/)?.[1] || '0');
400
+ return vb - va;
401
+ });
402
+ return files.length > 0 ? path.join(codexHome, files[0]) : null;
403
+ }
404
+ export async function migrateProject(oldPath, newPath) {
405
+ const result = {
406
+ claudeSessionsMoved: false,
407
+ claudeHistoryUpdated: false,
408
+ codexUpdated: 0,
409
+ evolcoreDbUpdated: 0,
410
+ directoryMoved: false,
411
+ };
412
+ const oldAbs = path.resolve(oldPath);
413
+ const newAbs = path.resolve(newPath);
414
+ if (!fs.existsSync(oldAbs))
415
+ throw new Error(`源目录不存在: ${oldAbs}`);
416
+ if (fs.existsSync(newAbs))
417
+ throw new Error(`目标目录已存在: ${newAbs}`);
418
+ const claudeProjects = path.join(os.homedir(), '.claude', 'projects');
419
+ const oldEncoded = encodePath(oldAbs);
420
+ const newEncoded = encodePath(newAbs);
421
+ // 1. 迁移 ~/.claude/projects/{encoded}/
422
+ const oldClaudeDir = path.join(claudeProjects, oldEncoded);
423
+ const newClaudeDir = path.join(claudeProjects, newEncoded);
424
+ if (fs.existsSync(oldClaudeDir)) {
425
+ fs.renameSync(oldClaudeDir, newClaudeDir);
426
+ result.claudeSessionsMoved = true;
427
+ }
428
+ // 2. .jsonl 内部路径不需要替换 — 它们是历史对话记录,
429
+ // resume 时模型会根据当前 cwd 工作,旧路径只是历史上下文
430
+ // 3. 更新 ~/.claude/history.jsonl
431
+ const historyFile = path.join(os.homedir(), '.claude', 'history.jsonl');
432
+ if (fs.existsSync(historyFile)) {
433
+ const lines = fs.readFileSync(historyFile, 'utf-8').split('\n');
434
+ const updated = lines.map(line => {
435
+ if (!line.trim())
436
+ return line;
437
+ try {
438
+ const obj = JSON.parse(line);
439
+ if (obj.project === oldAbs) {
440
+ obj.project = newAbs;
441
+ return JSON.stringify(obj);
442
+ }
443
+ }
444
+ catch { /* skip */ }
445
+ return line;
446
+ });
447
+ const newContent = updated.join('\n');
448
+ if (newContent !== fs.readFileSync(historyFile, 'utf-8')) {
449
+ fs.writeFileSync(historyFile, newContent, 'utf-8');
450
+ result.claudeHistoryUpdated = true;
451
+ }
452
+ }
453
+ // 4. 更新 Codex SQLite threads.cwd
454
+ const codexDbPath = findCodexDb();
455
+ if (codexDbPath) {
456
+ try {
457
+ const { DatabaseSync } = await import('node:sqlite');
458
+ const db = new DatabaseSync(codexDbPath);
459
+ const r = db.prepare('UPDATE threads SET cwd = ? WHERE cwd = ?').run(newAbs, oldAbs);
460
+ result.codexUpdated = r.changes ?? 0;
461
+ db.close();
462
+ }
463
+ catch { /* Codex not installed or DB locked */ }
464
+ }
465
+ // 5. 移动项目目录
466
+ fs.renameSync(oldAbs, newAbs);
467
+ result.directoryMoved = true;
468
+ // 6. 更新 EvolCore sessions(文件系统)
469
+ const p = resolvePaths();
470
+ if (fs.existsSync(p.sessionsDir)) {
471
+ try {
472
+ const { scanChatDirs, scanMetaFiles, readJsonFile, atomicWriteJson, appendJsonl } = await import('./core/session/session-fs-store.js');
473
+ let updated = 0;
474
+ const chatDirs = scanChatDirs(p.sessionsDir);
475
+ for (const { dirPath } of chatDirs) {
476
+ // 更新 active.json
477
+ const activePath = path.join(dirPath, 'active.json');
478
+ const active = readJsonFile(activePath);
479
+ if (active && active.projectPath === oldAbs) {
480
+ active.projectPath = newAbs;
481
+ active.updatedAt = Date.now();
482
+ atomicWriteJson(activePath, active);
483
+ updated++;
484
+ }
485
+ // 更新各 meta jsonl 的最后一行(append 一条新快照标记 projectPath 变化)
486
+ for (const metaFile of scanMetaFiles(dirPath)) {
487
+ const metaPath = path.join(dirPath, metaFile);
488
+ const { readLastJsonlLine } = await import('./core/session/session-fs-store.js');
489
+ const meta = readLastJsonlLine(metaPath);
490
+ if (meta && meta.projectPath === oldAbs) {
491
+ meta.projectPath = newAbs;
492
+ meta.updatedAt = Date.now();
493
+ appendJsonl(metaPath, meta);
494
+ updated++;
495
+ }
496
+ }
497
+ }
498
+ result.evolcoreDbUpdated = updated;
499
+ }
500
+ catch { /* fs not accessible */ }
501
+ }
502
+ return result;
503
+ }
@@ -0,0 +1,111 @@
1
+ import crypto from 'crypto';
2
+ import { authorizeOperation, buildAuthSubject } from './auth-gateway.js';
3
+ import { formatPeerKey, parsePeerKey } from '../relation/peer-identity.js';
4
+ export const AGENT_DELEGATION_TOKEN_ENV = 'EVOLCORE_DELEGATION_TOKEN';
5
+ export class AgentDelegationRegistry {
6
+ grantsByHash = new Map();
7
+ activeHashBySession = new Map();
8
+ issue(input) {
9
+ this.revokeSession(input.sessionId);
10
+ const token = crypto.randomBytes(32).toString('base64url');
11
+ const tokenHash = hashDelegationToken(token);
12
+ this.grantsByHash.set(tokenHash, { ...input, tokenHash });
13
+ this.activeHashBySession.set(input.sessionId, tokenHash);
14
+ return token;
15
+ }
16
+ validate(token, sessionId) {
17
+ if (!token) {
18
+ return {
19
+ ok: false,
20
+ code: 'DELEGATION_REQUIRED',
21
+ reason: 'An active task delegation token is required',
22
+ };
23
+ }
24
+ const tokenHash = hashDelegationToken(token);
25
+ const grant = this.grantsByHash.get(tokenHash);
26
+ if (!grant
27
+ || grant.sessionId !== sessionId
28
+ || this.activeHashBySession.get(sessionId) !== tokenHash) {
29
+ return {
30
+ ok: false,
31
+ code: 'INVALID_DELEGATION',
32
+ reason: 'The task delegation token is invalid, revoked, or belongs to another session',
33
+ };
34
+ }
35
+ return { ok: true, grant };
36
+ }
37
+ revokeTask(sessionId, taskId) {
38
+ const tokenHash = this.activeHashBySession.get(sessionId);
39
+ if (!tokenHash)
40
+ return;
41
+ const grant = this.grantsByHash.get(tokenHash);
42
+ if (!grant || grant.taskId !== taskId)
43
+ return;
44
+ this.grantsByHash.delete(tokenHash);
45
+ this.activeHashBySession.delete(sessionId);
46
+ }
47
+ revokeSession(sessionId) {
48
+ const tokenHash = this.activeHashBySession.get(sessionId);
49
+ if (tokenHash)
50
+ this.grantsByHash.delete(tokenHash);
51
+ this.activeHashBySession.delete(sessionId);
52
+ }
53
+ }
54
+ export function authorizeDelegatedAunMsgSend(registry, input) {
55
+ if (!input.sessionId) {
56
+ return { ok: false, code: 'DELEGATION_REQUIRED', reason: 'Origin session is required' };
57
+ }
58
+ const validation = registry.validate(input.delegationToken, input.sessionId);
59
+ if (!validation.ok)
60
+ return validation;
61
+ const grant = validation.grant;
62
+ if (grant.selfAid !== input.aid) {
63
+ return { ok: false, code: 'INVALID_DELEGATION', reason: 'Delegation self agent does not match sender' };
64
+ }
65
+ if (grant.messageId && grant.messageId !== input.messageId) {
66
+ return { ok: false, code: 'INVALID_DELEGATION', reason: 'Delegation message does not match origin message' };
67
+ }
68
+ let channelId;
69
+ try {
70
+ channelId = parsePeerKey(grant.peerKey).channelId;
71
+ }
72
+ catch {
73
+ return { ok: false, code: 'INVALID_DELEGATION', reason: 'Delegation relation key is invalid' };
74
+ }
75
+ const builtSubject = buildAuthSubject({
76
+ selfAid: grant.selfAid,
77
+ actorId: grant.actorId,
78
+ channel: grant.channel,
79
+ channelType: grant.channelType,
80
+ channelId,
81
+ chatType: grant.chatType,
82
+ conversationId: channelId,
83
+ identity: { role: grant.issuedRole, mode: 'interactive' },
84
+ processOwners: [],
85
+ fromControlChannel: false,
86
+ });
87
+ const subject = { ...builtSubject, peerKey: grant.peerKey };
88
+ const decision = authorizeOperation({
89
+ source: 'agent-tool',
90
+ intent: {
91
+ operation: `ec.${input.scope ?? 'msg'}.${input.action ?? 'send'}`,
92
+ scope: 'relation',
93
+ source: 'agent-tool',
94
+ args: {
95
+ self: grant.selfAid,
96
+ peer: input.to,
97
+ peerKey: formatPeerKey(grant.channelType, input.to),
98
+ targetId: input.to,
99
+ },
100
+ },
101
+ subject,
102
+ auditMetadata: { taskId: grant.taskId, messageId: grant.messageId },
103
+ });
104
+ if (!decision.allow) {
105
+ return { ok: false, code: 'NOT_ALLOWED', reason: decision.reason };
106
+ }
107
+ return { ok: true, grant };
108
+ }
109
+ function hashDelegationToken(token) {
110
+ return crypto.createHash('sha256').update(token).digest('hex');
111
+ }