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,371 @@
1
+ import { agentContactConfig } from '../paths.js';
2
+ import { isValidAid } from '../aun/aid/validation.js';
3
+ import { ConfigTarget, read, validateConfig, write } from './config-manager.js';
4
+ export class ContactBookError extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(message);
8
+ this.code = code;
9
+ this.name = 'ContactBookError';
10
+ }
11
+ }
12
+ let aliasMapCache = new WeakMap();
13
+ const emptyAliasMap = {
14
+ scopedAliasToPrimary: new Map(),
15
+ conflictingScopedAliases: new Set(),
16
+ legacyAliasToPrimary: new Map(),
17
+ conflictingLegacyAliases: new Set(),
18
+ };
19
+ const SCOPED_ALIAS_PREFIX = 'channel-key:';
20
+ export function agentContactConfigPath(aid) {
21
+ return agentContactConfig(aid);
22
+ }
23
+ export function readContactBook(selfAid, opts = {}) {
24
+ if (!selfAid)
25
+ return null;
26
+ return read(ConfigTarget.Contact, { self: selfAid }, { cache: opts.cache ?? true });
27
+ }
28
+ export function resolvePrincipal(selfAid, channelType, actorId, channelKey) {
29
+ const normalizedActor = String(actorId || '').trim();
30
+ const normalizedChannel = String(channelType || '').trim().toLowerCase();
31
+ if (normalizedChannel === 'aun') {
32
+ return isValidAid(normalizedActor)
33
+ ? { principalId: normalizedActor, principalStatus: 'native_aid' }
34
+ : { principalStatus: normalizedActor ? 'unmapped' : 'error' };
35
+ }
36
+ const normalizedSelf = String(selfAid || '').trim();
37
+ const normalizedChannelKey = normalizeChannelKey(normalizedSelf, normalizedChannel, channelKey);
38
+ const legacyAlias = normalizeLegacyAlias(normalizedChannel, normalizedActor);
39
+ if (!isValidAid(normalizedSelf) || !normalizedChannelKey || !legacyAlias) {
40
+ return { principalStatus: 'error' };
41
+ }
42
+ const scopedAlias = scopedAliasLookupKey(normalizedChannelKey, normalizedActor);
43
+ try {
44
+ const aliases = loadAliasMap(normalizedSelf);
45
+ if (aliases.conflictingScopedAliases.has(scopedAlias)) {
46
+ return { principalStatus: 'conflict' };
47
+ }
48
+ const scopedPrincipalId = aliases.scopedAliasToPrimary.get(scopedAlias);
49
+ if (scopedPrincipalId) {
50
+ return { principalId: scopedPrincipalId, principalStatus: 'mapped' };
51
+ }
52
+ // Legacy aliases did not identify a channel instance. They remain trusted only
53
+ // while the configured channel type has exactly one matching instance.
54
+ if (!isUnambiguousLegacyChannel(normalizedSelf, normalizedChannel, normalizedChannelKey)) {
55
+ return { principalStatus: 'unmapped' };
56
+ }
57
+ if (aliases.conflictingLegacyAliases.has(legacyAlias)) {
58
+ return { principalStatus: 'conflict' };
59
+ }
60
+ const legacyPrincipalId = aliases.legacyAliasToPrimary.get(legacyAlias);
61
+ return legacyPrincipalId
62
+ ? { principalId: legacyPrincipalId, principalStatus: 'mapped' }
63
+ : { principalStatus: 'unmapped' };
64
+ }
65
+ catch {
66
+ return { principalStatus: 'error' };
67
+ }
68
+ }
69
+ export function resolvePrimaryId(selfAid, channelType, actorId, channelKey) {
70
+ const normalizedActor = String(actorId || '').trim();
71
+ return resolvePrincipal(selfAid, channelType, normalizedActor, channelKey).principalId ?? normalizedActor;
72
+ }
73
+ export function bindContactAlias(selfAid, primaryId, channelType, actorId, channelKey) {
74
+ const primary = normalizePrimaryId(primaryId);
75
+ const alias = requireScopedAlias(selfAid, channelType, actorId, channelKey);
76
+ const legacyAlias = requireLegacyAlias(channelType, actorId);
77
+ ensureNativeAidIsNotRemapped(primary, channelType, actorId);
78
+ const next = cloneContactBook(readContactBook(selfAid, { cache: true }));
79
+ ensureScopedAliasAvailable(next, selfAid, primary, alias.lookupKey);
80
+ const contacts = next.contacts ?? {};
81
+ let removedLegacyAlias = false;
82
+ // An explicit scoped bind supersedes every unscoped copy of the same alias.
83
+ // Otherwise unbinding the scoped entry could silently reactivate a legacy
84
+ // mapping owned by another principal.
85
+ for (const [contactId, value] of Object.entries(contacts)) {
86
+ const entry = normalizeContactEntry(value);
87
+ const filtered = entry.aliases.filter(item => normalizeLegacyAliasString(item) !== legacyAlias);
88
+ if (filtered.length !== entry.aliases.length) {
89
+ contacts[contactId] = { ...entry, aliases: filtered };
90
+ removedLegacyAlias = true;
91
+ }
92
+ }
93
+ const current = normalizeContactEntry(contacts[primary]);
94
+ const alreadyScoped = current.aliases.some(value => (normalizeScopedAliasString(value, selfAid)?.lookupKey === alias.lookupKey));
95
+ if (alreadyScoped && !removedLegacyAlias) {
96
+ return false;
97
+ }
98
+ contacts[primary] = {
99
+ ...current,
100
+ aliases: alreadyScoped
101
+ ? current.aliases
102
+ : [...current.aliases, alias.serialized],
103
+ };
104
+ next.contacts = contacts;
105
+ write(ConfigTarget.Contact, next, { self: selfAid });
106
+ return true;
107
+ }
108
+ export function unbindContactAlias(selfAid, primaryId, channelType, actorId, channelKey) {
109
+ const primary = normalizePrimaryId(primaryId);
110
+ const alias = requireScopedAlias(selfAid, channelType, actorId, channelKey);
111
+ const legacyAlias = requireLegacyAlias(channelType, actorId);
112
+ const next = cloneContactBook(readContactBook(selfAid, { cache: true }));
113
+ const contacts = next.contacts ?? {};
114
+ let changed = false;
115
+ // Remove the requested scoped binding from the target principal and purge
116
+ // every unscoped copy of the same raw alias. Legacy aliases do not carry a
117
+ // channel-instance identity, so retaining one on another contact would
118
+ // silently reactivate that principal after this scoped binding is revoked.
119
+ for (const [contactId, value] of Object.entries(contacts)) {
120
+ const entry = normalizeContactEntry(value);
121
+ const filtered = entry.aliases.filter(item => {
122
+ const isTargetScoped = contactId.trim() === primary
123
+ && normalizeScopedAliasString(item, selfAid)?.lookupKey === alias.lookupKey;
124
+ const isLegacyCopy = normalizeLegacyAliasString(item) === legacyAlias;
125
+ return !isTargetScoped && !isLegacyCopy;
126
+ });
127
+ if (filtered.length !== entry.aliases.length) {
128
+ contacts[contactId] = { ...entry, aliases: filtered };
129
+ changed = true;
130
+ }
131
+ }
132
+ if (!changed) {
133
+ return false;
134
+ }
135
+ next.contacts = contacts;
136
+ write(ConfigTarget.Contact, next, { self: selfAid });
137
+ return true;
138
+ }
139
+ export function clearContactBookCache() {
140
+ aliasMapCache = new WeakMap();
141
+ }
142
+ function loadAliasMap(selfAid) {
143
+ const book = readContactBook(selfAid, { cache: true });
144
+ if (!book)
145
+ return emptyAliasMap;
146
+ const cached = aliasMapCache.get(book);
147
+ if (cached)
148
+ return cached;
149
+ const validationErrors = validateConfig(ConfigTarget.Contact, book);
150
+ if (validationErrors.length > 0) {
151
+ throw new ContactBookError('INVALID_CONTACT_BOOK', `Invalid contact book for ${selfAid}: ${validationErrors.join('; ')}`);
152
+ }
153
+ const built = buildAliasMap(book, selfAid);
154
+ aliasMapCache.set(book, built);
155
+ return built;
156
+ }
157
+ function buildAliasMap(config, selfAid) {
158
+ const scopedAliasToPrimary = new Map();
159
+ const conflictingScopedAliases = new Set();
160
+ const legacyAliasToPrimary = new Map();
161
+ const conflictingLegacyAliases = new Set();
162
+ const contacts = config?.contacts;
163
+ if (!contacts || typeof contacts !== 'object' || Array.isArray(contacts)) {
164
+ return {
165
+ scopedAliasToPrimary,
166
+ conflictingScopedAliases,
167
+ legacyAliasToPrimary,
168
+ conflictingLegacyAliases,
169
+ };
170
+ }
171
+ for (const [rawPrimaryId, entry] of Object.entries(contacts)) {
172
+ const primaryId = rawPrimaryId.trim();
173
+ if (!isValidAid(primaryId) || !entry || typeof entry !== 'object' || Array.isArray(entry))
174
+ continue;
175
+ const aliases = Array.isArray(entry.aliases) ? entry.aliases : [];
176
+ for (const rawAlias of aliases) {
177
+ const scoped = normalizeScopedAliasString(rawAlias, selfAid);
178
+ if (scoped) {
179
+ addAliasMapping(scopedAliasToPrimary, conflictingScopedAliases, scoped.lookupKey, primaryId);
180
+ }
181
+ else {
182
+ const legacy = normalizeLegacyAliasString(rawAlias);
183
+ if (legacy) {
184
+ addAliasMapping(legacyAliasToPrimary, conflictingLegacyAliases, legacy, primaryId);
185
+ }
186
+ }
187
+ }
188
+ }
189
+ return {
190
+ scopedAliasToPrimary,
191
+ conflictingScopedAliases,
192
+ legacyAliasToPrimary,
193
+ conflictingLegacyAliases,
194
+ };
195
+ }
196
+ function addAliasMapping(aliases, conflicts, alias, primaryId) {
197
+ if (conflicts.has(alias))
198
+ return;
199
+ const existing = aliases.get(alias);
200
+ if (existing && existing !== primaryId) {
201
+ aliases.delete(alias);
202
+ conflicts.add(alias);
203
+ return;
204
+ }
205
+ aliases.set(alias, primaryId);
206
+ }
207
+ function cloneContactBook(config) {
208
+ const next = config ? { ...config } : {};
209
+ const contacts = {};
210
+ const rawContacts = config?.contacts;
211
+ if (rawContacts && typeof rawContacts === 'object' && !Array.isArray(rawContacts)) {
212
+ for (const [primaryId, entry] of Object.entries(rawContacts)) {
213
+ contacts[primaryId] = normalizeContactEntry(entry);
214
+ }
215
+ }
216
+ next.contacts = contacts;
217
+ return next;
218
+ }
219
+ function normalizeContactEntry(value) {
220
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
221
+ return { aliases: [] };
222
+ }
223
+ const entry = value;
224
+ return {
225
+ ...entry,
226
+ aliases: Array.isArray(entry.aliases)
227
+ ? entry.aliases.filter((item) => typeof item === 'string')
228
+ : [],
229
+ };
230
+ }
231
+ function ensureScopedAliasAvailable(config, selfAid, primaryId, alias) {
232
+ const owners = findScopedAliasOwners(config, selfAid, alias);
233
+ if (owners.size === 0)
234
+ return;
235
+ if (owners.size === 1 && owners.has(primaryId))
236
+ return;
237
+ throw new ContactBookError('ALIAS_CONFLICT', `Alias "${alias}" is already bound to ${[...owners].join(', ')}`);
238
+ }
239
+ function findScopedAliasOwners(config, selfAid, alias) {
240
+ const owners = new Set();
241
+ const contacts = config.contacts;
242
+ if (!contacts || typeof contacts !== 'object' || Array.isArray(contacts))
243
+ return owners;
244
+ for (const [rawPrimaryId, entry] of Object.entries(contacts)) {
245
+ const primaryId = rawPrimaryId.trim();
246
+ if (!primaryId || !entry || typeof entry !== 'object' || Array.isArray(entry))
247
+ continue;
248
+ const aliases = Array.isArray(entry.aliases) ? entry.aliases : [];
249
+ if (aliases.some(value => normalizeScopedAliasString(value, selfAid)?.lookupKey === alias)) {
250
+ owners.add(primaryId);
251
+ }
252
+ }
253
+ return owners;
254
+ }
255
+ function normalizePrimaryId(value) {
256
+ const primaryId = String(value || '').trim();
257
+ if (!isValidAid(primaryId)) {
258
+ throw new ContactBookError('INVALID_PRIMARY_ID', `Invalid contact primary AID: ${String(value)}`);
259
+ }
260
+ return primaryId;
261
+ }
262
+ function requireLegacyAlias(channelType, actorId) {
263
+ const alias = normalizeLegacyAlias(channelType, actorId);
264
+ if (!alias) {
265
+ throw new ContactBookError('INVALID_ALIAS', `Invalid contact alias: ${String(channelType)}:${String(actorId)}`);
266
+ }
267
+ return alias;
268
+ }
269
+ function normalizeLegacyAlias(channelType, actorId) {
270
+ const channel = String(channelType || '').trim().toLowerCase();
271
+ const id = String(actorId || '').trim();
272
+ if (!/^[a-z0-9_-]+$/.test(channel) || !id)
273
+ return null;
274
+ return `${channel}:${id}`;
275
+ }
276
+ function normalizeLegacyAliasString(value) {
277
+ if (typeof value !== 'string')
278
+ return null;
279
+ const trimmed = value.trim();
280
+ if (trimmed.startsWith(SCOPED_ALIAS_PREFIX))
281
+ return null;
282
+ const idx = trimmed.indexOf(':');
283
+ if (idx <= 0 || idx === trimmed.length - 1)
284
+ return null;
285
+ return normalizeLegacyAlias(trimmed.slice(0, idx), trimmed.slice(idx + 1));
286
+ }
287
+ function requireScopedAlias(selfAid, channelType, actorId, channelKey) {
288
+ const normalizedActor = String(actorId || '').trim();
289
+ const normalizedChannel = String(channelType || '').trim().toLowerCase();
290
+ const normalizedChannelKey = normalizeChannelKey(selfAid, normalizedChannel, channelKey);
291
+ if (!normalizedActor || !normalizedChannelKey) {
292
+ throw new ContactBookError('INVALID_CHANNEL_ALIAS', `Invalid scoped contact alias: ${String(channelKey)}:${String(actorId)}`);
293
+ }
294
+ return {
295
+ lookupKey: scopedAliasLookupKey(normalizedChannelKey, normalizedActor),
296
+ serialized: serializeScopedAlias(normalizedChannelKey, normalizedActor),
297
+ };
298
+ }
299
+ function normalizeScopedAliasString(value, selfAid) {
300
+ if (typeof value !== 'string')
301
+ return null;
302
+ const trimmed = value.trim();
303
+ if (!trimmed.startsWith(SCOPED_ALIAS_PREFIX))
304
+ return null;
305
+ const encoded = trimmed.slice(SCOPED_ALIAS_PREFIX.length);
306
+ const separator = encoded.indexOf(':');
307
+ if (separator <= 0 || separator === encoded.length - 1)
308
+ return null;
309
+ try {
310
+ const channelKey = decodeURIComponent(encoded.slice(0, separator));
311
+ const actorId = decodeURIComponent(encoded.slice(separator + 1)).trim();
312
+ const channelType = channelKey.split('#', 1)[0]?.toLowerCase() ?? '';
313
+ const normalizedChannelKey = normalizeChannelKey(selfAid, channelType, channelKey);
314
+ if (!normalizedChannelKey || !actorId)
315
+ return null;
316
+ return {
317
+ lookupKey: scopedAliasLookupKey(normalizedChannelKey, actorId),
318
+ serialized: serializeScopedAlias(normalizedChannelKey, actorId),
319
+ };
320
+ }
321
+ catch {
322
+ return null;
323
+ }
324
+ }
325
+ function serializeScopedAlias(channelKey, actorId) {
326
+ return `${SCOPED_ALIAS_PREFIX}${encodeURIComponent(channelKey)}:${encodeURIComponent(actorId)}`;
327
+ }
328
+ function scopedAliasLookupKey(channelKey, actorId) {
329
+ return JSON.stringify([channelKey, actorId]);
330
+ }
331
+ function normalizeChannelKey(selfAid, channelType, value) {
332
+ const key = typeof value === 'string' ? value.trim() : '';
333
+ const parts = key.split('#');
334
+ if (parts.length !== 3)
335
+ return null;
336
+ const [rawType, keySelfAid, name] = parts;
337
+ const normalizedType = rawType.toLowerCase();
338
+ if (!/^[a-z0-9_-]+$/.test(normalizedType)
339
+ || normalizedType !== channelType
340
+ || keySelfAid !== selfAid
341
+ || !name) {
342
+ return null;
343
+ }
344
+ return `${normalizedType}#${keySelfAid}#${name}`;
345
+ }
346
+ function isUnambiguousLegacyChannel(selfAid, channelType, channelKey) {
347
+ try {
348
+ const agent = read(ConfigTarget.Agent, { self: selfAid }, { cache: true });
349
+ const matches = new Set();
350
+ for (const candidate of agent?.channels ?? []) {
351
+ if (!candidate || typeof candidate !== 'object')
352
+ continue;
353
+ const candidateType = String(candidate.type || '').trim().toLowerCase();
354
+ const candidateName = String(candidate.name || '').trim();
355
+ if (candidateType !== channelType || !candidateName || candidateName.includes('#'))
356
+ continue;
357
+ matches.add(`${candidateType}#${selfAid}#${candidateName}`);
358
+ }
359
+ return matches.size === 1 && matches.has(channelKey);
360
+ }
361
+ catch {
362
+ return false;
363
+ }
364
+ }
365
+ function ensureNativeAidIsNotRemapped(primaryId, channelType, actorId) {
366
+ const channel = String(channelType || '').trim().toLowerCase();
367
+ const actor = String(actorId || '').trim();
368
+ if (channel === 'aun' && isValidAid(actor) && actor !== primaryId) {
369
+ throw new ContactBookError('NATIVE_AID_REMAP_FORBIDDEN', `Native AID "${actor}" cannot be remapped to "${primaryId}"`);
370
+ }
371
+ }