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,160 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import crypto from 'crypto';
4
+ import { resolvePaths } from '../paths.js';
5
+ const MAX_ENTRIES_PER_AID = 20;
6
+ const DEFAULT_TTL = 300_000; // 5 minutes
7
+ function outboxDir() {
8
+ return resolvePaths().outboxDir;
9
+ }
10
+ function outboxFile(aid) {
11
+ return path.join(outboxDir(), `${aid}.jsonl`);
12
+ }
13
+ function generateId() {
14
+ const ts = Date.now();
15
+ const rand = crypto.randomBytes(2).toString('hex');
16
+ return `out-${ts}-${rand}`;
17
+ }
18
+ function isExpired(entry) {
19
+ return Date.now() - entry.ts > entry.ttl;
20
+ }
21
+ function readEntries(aid) {
22
+ const file = outboxFile(aid);
23
+ if (!fs.existsSync(file))
24
+ return [];
25
+ try {
26
+ const content = fs.readFileSync(file, 'utf-8').trim();
27
+ if (!content)
28
+ return [];
29
+ return content.split('\n').map(line => {
30
+ try {
31
+ return JSON.parse(line);
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }).filter((e) => e !== null);
37
+ }
38
+ catch {
39
+ return [];
40
+ }
41
+ }
42
+ function writeEntries(aid, entries) {
43
+ const file = outboxFile(aid);
44
+ if (entries.length === 0) {
45
+ try {
46
+ fs.unlinkSync(file);
47
+ }
48
+ catch { }
49
+ return;
50
+ }
51
+ const dir = outboxDir();
52
+ fs.mkdirSync(dir, { recursive: true });
53
+ fs.writeFileSync(file, entries.map(e => JSON.stringify(e)).join('\n') + '\n');
54
+ }
55
+ export function enqueue(aid, opts) {
56
+ const entry = {
57
+ id: generateId(),
58
+ ts: Date.now(),
59
+ aid,
60
+ channelId: opts.channelId,
61
+ type: opts.type,
62
+ contentKind: opts.contentKind,
63
+ payload: opts.payload,
64
+ text: opts.text,
65
+ filePath: opts.filePath,
66
+ logText: opts.logText,
67
+ context: opts.context,
68
+ ttl: opts.ttl ?? DEFAULT_TTL,
69
+ postSend: opts.postSend,
70
+ };
71
+ const dir = outboxDir();
72
+ fs.mkdirSync(dir, { recursive: true });
73
+ const file = outboxFile(aid);
74
+ // Enforce cap: read existing, drop oldest if over limit
75
+ let entries = readEntries(aid);
76
+ if (entries.length >= MAX_ENTRIES_PER_AID) {
77
+ entries = entries.slice(entries.length - MAX_ENTRIES_PER_AID + 1);
78
+ writeEntries(aid, [...entries, entry]);
79
+ }
80
+ else {
81
+ fs.appendFileSync(file, JSON.stringify(entry) + '\n');
82
+ }
83
+ return entry;
84
+ }
85
+ export function remove(aid, id) {
86
+ const entries = readEntries(aid).filter(e => e.id !== id);
87
+ writeEntries(aid, entries);
88
+ }
89
+ /** Remove durable interaction cards that were cancelled before delivery. */
90
+ export function removeInteractionCards(aid, requestId) {
91
+ const entries = readEntries(aid);
92
+ const retained = entries.filter(entry => !(entry.postSend?.type === 'register_interaction_card'
93
+ && entry.postSend.requestId === requestId));
94
+ const removed = entries.length - retained.length;
95
+ if (removed > 0)
96
+ writeEntries(aid, retained);
97
+ return removed;
98
+ }
99
+ export function load(aid) {
100
+ return readEntries(aid).filter(e => !isExpired(e));
101
+ }
102
+ export function cleanup(aid) {
103
+ const all = readEntries(aid);
104
+ const valid = all.filter(e => !isExpired(e));
105
+ const removed = all.length - valid.length;
106
+ if (removed > 0)
107
+ writeEntries(aid, valid);
108
+ return removed;
109
+ }
110
+ export async function drain(aid, sender) {
111
+ const entries = readEntries(aid);
112
+ if (entries.length === 0)
113
+ return { sent: 0, expired: 0, failed: 0 };
114
+ const drainedIds = new Set(entries.map(e => e.id));
115
+ let sent = 0;
116
+ let expired = 0;
117
+ let failed = 0;
118
+ const remaining = [];
119
+ for (const entry of entries) {
120
+ if (isExpired(entry)) {
121
+ expired++;
122
+ continue;
123
+ }
124
+ try {
125
+ entry.attempts = (entry.attempts ?? 0) + 1;
126
+ const ok = await sender(entry);
127
+ if (ok) {
128
+ sent++;
129
+ }
130
+ else {
131
+ failed++;
132
+ entry.lastError = 'sender returned false';
133
+ remaining.push(entry);
134
+ }
135
+ }
136
+ catch (e) {
137
+ failed++;
138
+ entry.lastError = e instanceof Error ? e.message : String(e);
139
+ remaining.push(entry);
140
+ }
141
+ }
142
+ const current = readEntries(aid);
143
+ const currentIds = new Set(current.map(e => e.id));
144
+ const retainedNewEntries = current.filter(e => !drainedIds.has(e.id));
145
+ const retainedFailedEntries = remaining.filter(e => currentIds.has(e.id));
146
+ writeEntries(aid, [...retainedFailedEntries, ...retainedNewEntries]);
147
+ return { sent, expired, failed };
148
+ }
149
+ export function hasPending(aid) {
150
+ const file = outboxFile(aid);
151
+ if (!fs.existsSync(file))
152
+ return false;
153
+ try {
154
+ const stat = fs.statSync(file);
155
+ return stat.size > 0;
156
+ }
157
+ catch {
158
+ return false;
159
+ }
160
+ }
@@ -0,0 +1,42 @@
1
+ import { createShortConnection } from './connection.js';
2
+ export async function rpcCall(aid, method, params, opts) {
3
+ const conn = await createShortConnection(aid, opts);
4
+ try {
5
+ const result = await conn.call(method, params);
6
+ return { ok: true, result };
7
+ }
8
+ catch (e) {
9
+ if (e.code !== undefined && e.message !== undefined) {
10
+ return { ok: false, error: { code: e.code, message: e.message, data: e.data } };
11
+ }
12
+ return { ok: false, error: { code: -1, message: String(e.message || e) } };
13
+ }
14
+ finally {
15
+ await conn.close();
16
+ }
17
+ }
18
+ export async function rpcBatch(aid, calls, opts) {
19
+ const conn = await createShortConnection(aid, opts);
20
+ const results = [];
21
+ try {
22
+ for (const { method, params } of calls) {
23
+ try {
24
+ const result = await conn.call(method, params);
25
+ results.push({ ok: true, result });
26
+ }
27
+ catch (e) {
28
+ if (e.code !== undefined && e.message !== undefined) {
29
+ results.push({ ok: false, error: { code: e.code, message: e.message, data: e.data } });
30
+ }
31
+ else {
32
+ results.push({ ok: false, error: { code: -1, message: String(e.message || e) } });
33
+ }
34
+ break; // stop on first failure
35
+ }
36
+ }
37
+ }
38
+ finally {
39
+ await conn.close();
40
+ }
41
+ return results;
42
+ }
@@ -0,0 +1,25 @@
1
+ import { getAidStore, loadClient, SLOT } from '../aid/store.js';
2
+ export async function createShortConnection(aid, opts) {
3
+ const store = await getAidStore({ slotId: opts?.slotId ?? SLOT.cli, aunPath: opts?.aunPath });
4
+ try {
5
+ const client = await loadClient(store, aid);
6
+ await client.connect({ connection_kind: 'short', short_ttl_ms: 30000, auto_reconnect: false });
7
+ return {
8
+ async call(method, params) {
9
+ return client.call(method, params);
10
+ },
11
+ async close() {
12
+ try {
13
+ await client.close();
14
+ }
15
+ finally {
16
+ store.close();
17
+ }
18
+ },
19
+ };
20
+ }
21
+ catch (e) {
22
+ store.close();
23
+ throw e;
24
+ }
25
+ }
@@ -0,0 +1,2 @@
1
+ export { rpcCall, rpcBatch } from './caller.js';
2
+ export { createShortConnection } from './connection.js';
@@ -0,0 +1,225 @@
1
+ /**
2
+ * AUN Service Proxy 集成 — 把本地 HTTP/WS 服务通过控制 AID 暴露到 AUN 网络。
3
+ *
4
+ * 访问入口:https://{控制AID}/{serviceName}/...
5
+ * proxy-server 剥掉 {serviceName} 前缀后,把剩余 path 经隧道转发,
6
+ * ServiceProxyClient 真实 HTTP/WS 回连本地 endpoint(反向代理)。
7
+ *
8
+ * 关键设计:
9
+ * - providerAid = 控制 AID(daemon 进程身份,pureIdentity 常驻 AUN)
10
+ * - aunClient 生命周期陷阱:AUNChannel 重连会销毁重建底层 client,
11
+ * 所以不能把 client 引用直接交给 ServiceProxyClient;传一个动态解引用的
12
+ * facade,每次 .call()/.authenticate()/._tokenStore 都读 channel 当前 client。
13
+ * serveForever(persistent) 的指数退避会在 client 缺失时自动等待恢复。
14
+ * - endpoint 发现:source='ecweb' 时读 data/instance/ecweb-*.json 的 port。
15
+ * - 失败降级:任何异常只 warn,绝不影响 daemon 主流程。
16
+ */
17
+ import fs from 'fs';
18
+ import path from 'path';
19
+ import { ServiceProxyClient, EndpointPolicy } from '@agentunion/fastaun';
20
+ import { resolvePaths } from '../paths.js';
21
+ import { logger } from '../utils/logger.js';
22
+ const LOG = '[ServiceProxy]';
23
+ const ECWEB_DISCOVERY_TIMEOUT_MS = 10_000;
24
+ const ECWEB_DISCOVERY_INTERVAL_MS = 250;
25
+ function sleep(ms) {
26
+ return new Promise(resolve => setTimeout(resolve, ms));
27
+ }
28
+ /**
29
+ * 读 data/instance/ 下存活的 ecweb 实例端口。
30
+ * 取 startedAt 最新的一条(多实例保护下通常只有一条存活)。
31
+ */
32
+ function discoverEcwebPort() {
33
+ const dir = resolvePaths().instanceDir;
34
+ let files;
35
+ try {
36
+ files = fs.readdirSync(dir);
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ const records = [];
42
+ for (const file of files) {
43
+ if (!/^(ecweb|watch-web)-\d+\.json$/.test(file))
44
+ continue;
45
+ try {
46
+ const rec = JSON.parse(fs.readFileSync(path.join(dir, file), 'utf-8'));
47
+ if (rec && typeof rec.pid === 'number' && isProcessAlive(rec.pid) && typeof rec.port === 'number') {
48
+ records.push(rec);
49
+ }
50
+ }
51
+ catch {
52
+ /* 跳过损坏文件 */
53
+ }
54
+ }
55
+ if (records.length === 0)
56
+ return null;
57
+ records.sort((a, b) => (b.startedAt ?? 0) - (a.startedAt ?? 0));
58
+ return records[0].port;
59
+ }
60
+ function isProcessAlive(pid) {
61
+ try {
62
+ process.kill(pid, 0);
63
+ return true;
64
+ }
65
+ catch (e) {
66
+ // EPERM = 进程存在但无权限(仍算存活);ESRCH = 不存在
67
+ return e?.code === 'EPERM';
68
+ }
69
+ }
70
+ async function waitForEcwebPort(serviceName) {
71
+ const deadline = Date.now() + ECWEB_DISCOVERY_TIMEOUT_MS;
72
+ let loggedWait = false;
73
+ while (Date.now() <= deadline) {
74
+ const port = discoverEcwebPort();
75
+ if (port)
76
+ return port;
77
+ if (!loggedWait) {
78
+ logger.info(`${LOG} 服务 "${serviceName}" source=ecweb,等待 ecweb 实例就绪`);
79
+ loggedWait = true;
80
+ }
81
+ await sleep(ECWEB_DISCOVERY_INTERVAL_MS);
82
+ }
83
+ return null;
84
+ }
85
+ /**
86
+ * 把单个服务配置解析为本地回连 endpoint。无法解析返回 null。
87
+ */
88
+ async function resolveEndpoint(svc) {
89
+ if (svc.source === 'ecweb') {
90
+ const port = await waitForEcwebPort(svc.name);
91
+ if (!port) {
92
+ logger.warn(`${LOG} 服务 "${svc.name}" source=ecweb 等待 ${ECWEB_DISCOVERY_TIMEOUT_MS}ms 后仍未发现存活的 ecweb 实例,跳过`);
93
+ return null;
94
+ }
95
+ return `http://127.0.0.1:${port}`;
96
+ }
97
+ // static
98
+ if (svc.endpoint && svc.endpoint.trim())
99
+ return svc.endpoint.trim();
100
+ logger.warn(`${LOG} 服务 "${svc.name}" source=static 但未配置 endpoint,跳过`);
101
+ return null;
102
+ }
103
+ /**
104
+ * 启动 Service Proxy。挂在控制 AUNChannel 上,常驻反向代理隧道。
105
+ * 返回 handle 供关停;没有启用服务时返回 null。endpoint 发现和隧道启动在后台执行,
106
+ * 失败只 warn,不抛异常,不阻塞 daemon 主流程。
107
+ */
108
+ export function startServiceProxy(controlChannel, providerAid, config) {
109
+ const services = (config.services ?? []).filter((s) => s.enabled !== false);
110
+ if (services.length === 0) {
111
+ logger.info(`${LOG} 无启用的服务,跳过`);
112
+ return null;
113
+ }
114
+ let stopped = false;
115
+ let proxyClient = null;
116
+ const run = async () => {
117
+ try {
118
+ // 动态解引用 facade:每次访问都读 channel 当前 client,规避重连换 client 的死引用问题。
119
+ const aunFacade = {
120
+ call: (method, params) => {
121
+ const client = controlChannel.getClient();
122
+ if (!client)
123
+ return Promise.reject(new Error('AUN control client not connected'));
124
+ return client.call(method, params ?? {});
125
+ },
126
+ authenticate: () => {
127
+ const client = controlChannel.getClient();
128
+ if (!client || typeof client.authenticate !== 'function') {
129
+ return Promise.reject(new Error('AUN control client not connected'));
130
+ }
131
+ return client.authenticate();
132
+ },
133
+ on: (event, handler) => {
134
+ const client = controlChannel.getClient();
135
+ return client?.on?.(event, handler);
136
+ },
137
+ get _tokenStore() {
138
+ return controlChannel.getClient()?._tokenStore;
139
+ },
140
+ // ServiceProxyClient._resolveCachedAccessToken 依次读取 _identity / _auth /
141
+ // _tokenStore + deviceId 来复用 AUNChannel 已签发的 access_token。控制 AID 在
142
+ // connect 时已 authenticate(client 处于 ready 态),若这些字段不透出,
143
+ // _ensureAccessToken 会回退到 authenticate() 并抛 "authenticate not allowed
144
+ // in state ready",导致隧道永远连不上 proxy-server。动态解引用,规避重连换 client。
145
+ get _identity() {
146
+ return controlChannel.getClient()?._identity;
147
+ },
148
+ get _auth() {
149
+ return controlChannel.getClient()?._auth;
150
+ },
151
+ get _deviceId() {
152
+ return controlChannel.getClient()?._deviceId;
153
+ },
154
+ };
155
+ // endpoint 白名单:只允许回连本机回环(127.0.0.1 / localhost 默认放行)。
156
+ // logger:把 SDK 内部 _logWarn/_logError 接到 evolcore logger,
157
+ // 否则 serveForever() 的隧道失败被静默吞掉(无任何日志),无法排障。
158
+ proxyClient = new ServiceProxyClient({
159
+ providerAid,
160
+ aunClient: aunFacade,
161
+ endpointPolicy: new EndpointPolicy(),
162
+ logger: {
163
+ error: (msg, err) => logger.error(`${LOG} ${msg}${err ? ` ${err.stack || err.message}` : ''}`),
164
+ warn: (msg) => logger.warn(`${LOG} ${msg}`),
165
+ info: (msg) => logger.info(`${LOG} ${msg}`),
166
+ debug: (msg) => logger.debug(`${LOG} ${msg}`),
167
+ },
168
+ });
169
+ let registered = 0;
170
+ for (const svc of services) {
171
+ if (stopped)
172
+ return;
173
+ const endpoint = await resolveEndpoint(svc);
174
+ if (stopped)
175
+ return;
176
+ if (!endpoint)
177
+ continue;
178
+ try {
179
+ proxyClient.registerService(svc.name, endpoint, {
180
+ serviceType: svc.serviceType ?? 'http',
181
+ visibility: svc.visibility ?? 'private',
182
+ metadata: svc.metadata ?? {},
183
+ });
184
+ registered += 1;
185
+ logger.info(`${LOG} 注册服务 "${svc.name}" → ${endpoint} (visibility=${svc.visibility ?? 'private'})`);
186
+ }
187
+ catch (e) {
188
+ logger.warn(`${LOG} 注册服务 "${svc.name}" 失败: ${e?.message || e}`);
189
+ }
190
+ }
191
+ if (registered === 0) {
192
+ logger.warn(`${LOG} 没有成功注册任何服务,不启动隧道`);
193
+ return;
194
+ }
195
+ if (stopped)
196
+ return;
197
+ // 常驻持久隧道(内部自带指数退避重连 + client 缺失时自动等待)。
198
+ // 不 await:后台运行,不阻塞 daemon 启动。
199
+ proxyClient
200
+ .serveForever({ connectionMode: 'persistent' })
201
+ .then((stats) => {
202
+ logger.info(`${LOG} serveForever 退出: ${JSON.stringify(stats)}`);
203
+ })
204
+ .catch((e) => {
205
+ logger.error(`${LOG} serveForever 异常退出: ${e?.message || e}`);
206
+ });
207
+ logger.info(`${LOG} ✓ 已启动,provider=${providerAid},注册 ${registered} 个服务`);
208
+ }
209
+ catch (e) {
210
+ logger.warn(`${LOG} 启动失败(不影响 daemon 主流程): ${e?.message || e}`);
211
+ }
212
+ };
213
+ void run();
214
+ return {
215
+ stop: () => {
216
+ stopped = true;
217
+ try {
218
+ proxyClient?.stop();
219
+ }
220
+ catch {
221
+ /* noop */
222
+ }
223
+ },
224
+ };
225
+ }
@@ -0,0 +1,29 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { rpcCall } from '../rpc/index.js';
4
+ export async function storageDownload(aid, url, localPath, opts) {
5
+ // Parse URL: strip https:// prefix, split into owner + path
6
+ const cleaned = url.replace(/^https?:\/\//, '');
7
+ const slashIdx = cleaned.indexOf('/');
8
+ if (slashIdx === -1) {
9
+ return { ok: false, localPath: '', size: 0, error: 'URL 格式错误,需要 <owner-aid>/<path>' };
10
+ }
11
+ const ownerAid = cleaned.slice(0, slashIdx);
12
+ const objectKey = cleaned.slice(slashIdx + 1);
13
+ const ticketResult = await rpcCall(aid, 'storage.create_download_ticket', {
14
+ owner_aid: ownerAid,
15
+ object_key: objectKey,
16
+ }, { aunPath: opts?.aunPath });
17
+ if (!ticketResult.ok) {
18
+ return { ok: false, localPath: '', size: 0, error: JSON.stringify(ticketResult.error) };
19
+ }
20
+ const downloadUrl = ticketResult.result.download_url;
21
+ const resp = await fetch(downloadUrl);
22
+ if (!resp.ok) {
23
+ return { ok: false, localPath: '', size: 0, error: `HTTP GET failed: ${resp.status}` };
24
+ }
25
+ const buffer = Buffer.from(await resp.arrayBuffer());
26
+ const outPath = localPath ?? path.basename(objectKey);
27
+ fs.writeFileSync(outPath, buffer);
28
+ return { ok: true, localPath: outPath, size: buffer.length };
29
+ }
@@ -0,0 +1,3 @@
1
+ export { storageUpload } from './upload.js';
2
+ export { storageDownload } from './download.js';
3
+ export { storageLs, storageRm, storageQuota } from './manage.js';
@@ -0,0 +1,10 @@
1
+ import { rpcCall } from '../rpc/caller.js';
2
+ export async function storageLs(aid, prefix, opts) {
3
+ return rpcCall(aid, 'storage.list_objects', { prefix: prefix || '' }, { aunPath: opts?.aunPath });
4
+ }
5
+ export async function storageRm(aid, remotePath, opts) {
6
+ return rpcCall(aid, 'storage.delete_object', { object_key: remotePath }, { aunPath: opts?.aunPath });
7
+ }
8
+ export async function storageQuota(aid, opts) {
9
+ return rpcCall(aid, 'storage.get_quota', {}, { aunPath: opts?.aunPath });
10
+ }
@@ -0,0 +1,68 @@
1
+ import fs from 'fs';
2
+ import crypto from 'crypto';
3
+ import { rpcCall } from '../rpc/index.js';
4
+ function rpcErrorToString(error) {
5
+ if (!error)
6
+ return 'unknown error';
7
+ if (typeof error === 'string')
8
+ return error;
9
+ try {
10
+ return JSON.stringify(error);
11
+ }
12
+ catch {
13
+ return String(error);
14
+ }
15
+ }
16
+ function pickUrl(value) {
17
+ return typeof value === 'string' && value.trim() ? value : undefined;
18
+ }
19
+ export async function storageUpload(aid, localFile, remotePath, opts) {
20
+ const fileBuffer = fs.readFileSync(localFile);
21
+ const contentType = opts?.contentType ?? 'application/octet-stream';
22
+ const sha256 = crypto.createHash('sha256').update(fileBuffer).digest('hex');
23
+ const createResult = await rpcCall(aid, 'storage.create_upload_session', {
24
+ object_key: remotePath,
25
+ content_type: contentType,
26
+ size_bytes: fileBuffer.length,
27
+ }, { aunPath: opts?.aunPath });
28
+ if (!createResult.ok) {
29
+ return { ok: false, objectKey: remotePath, error: rpcErrorToString(createResult.error) };
30
+ }
31
+ const uploadUrl = createResult.result.upload_url;
32
+ if (!uploadUrl) {
33
+ return { ok: false, objectKey: remotePath, error: 'storage.create_upload_session did not return upload_url' };
34
+ }
35
+ const putResp = await fetch(uploadUrl, {
36
+ method: 'PUT',
37
+ headers: { 'Content-Type': contentType },
38
+ body: new Blob([new Uint8Array(fileBuffer)], { type: contentType }),
39
+ redirect: 'follow',
40
+ });
41
+ if (!putResp.ok) {
42
+ return { ok: false, objectKey: remotePath, error: `HTTP PUT failed: ${putResp.status}` };
43
+ }
44
+ const completeResult = await rpcCall(aid, 'storage.complete_upload', {
45
+ object_key: remotePath,
46
+ sha256,
47
+ content_type: contentType,
48
+ size_bytes: fileBuffer.length,
49
+ is_private: !(opts?.isPublic),
50
+ }, { aunPath: opts?.aunPath });
51
+ if (!completeResult.ok) {
52
+ return { ok: false, objectKey: remotePath, error: rpcErrorToString(completeResult.error) };
53
+ }
54
+ let publicUrl = pickUrl(completeResult.result?.url);
55
+ if (opts?.isPublic) {
56
+ if (!publicUrl) {
57
+ const ticketResult = await rpcCall(aid, 'storage.create_download_ticket', {
58
+ object_key: remotePath,
59
+ expire_in_seconds: 86400 * 30, // 30天
60
+ }, { aunPath: opts?.aunPath });
61
+ if (ticketResult.ok) {
62
+ publicUrl = pickUrl(ticketResult.result?.url) ?? pickUrl(ticketResult.result?.download_url);
63
+ }
64
+ }
65
+ publicUrl ??= `https://${aid}/${remotePath}`;
66
+ }
67
+ return { ok: true, objectKey: remotePath, publicUrl };
68
+ }