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,345 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { createHash } from 'crypto';
4
+ import { TextDecoder } from 'util';
5
+ import { getAidStore, isValidAid, loadClient, SLOT } from '../aun/aid/index.js';
6
+ import { checkGroupIndex as checkGroupIndexRpc, getGroupIndex as getGroupIndexRpc } from '../aun/msg/group-index.js';
7
+ import { agentRelationsDir } from '../paths.js';
8
+ import { formatPeerKey } from '../core/relation/peer-identity.js';
9
+ import { atomicWriteBytes } from '../utils/atomic-write.js';
10
+ import { logger } from '../utils/logger.js';
11
+ import { invalidateKitCache } from './kit-renderer.js';
12
+ const RULES_REMOTE_PATH = '/rules.md';
13
+ const RULES_LOCAL_PATH = 'rules.md';
14
+ // Keep group rules aligned with AUN agent.md: an entry document, not a knowledge base.
15
+ const MAX_RULES_BYTES = 4 * 1024;
16
+ const MTIME_TOLERANCE_MS = 1;
17
+ export async function syncGroupRulesContext(opts) {
18
+ const { selfAid, groupId, channel } = opts;
19
+ if (!selfAid || !groupId || !isValidAid(selfAid))
20
+ return {};
21
+ const paths = relationPaths(selfAid, channel, groupId);
22
+ fs.mkdirSync(paths.dir, { recursive: true });
23
+ const group = lazyGroupClient(selfAid);
24
+ try {
25
+ const resolved = await resolveGroupRules(group.client, groupId, paths.localRulesPath);
26
+ if (resolved.changed)
27
+ invalidateKitCache();
28
+ return {
29
+ groupRulesPath: resolved.usable ? paths.localRulesPath : undefined,
30
+ groupRulesStatus: resolved.status,
31
+ groupRulesError: resolved.error,
32
+ };
33
+ }
34
+ catch (e) {
35
+ const status = classifyError(e);
36
+ const error = errorMessage(e);
37
+ logger.warn(`[GroupRulesSync] ${groupId} rules sync failed: ${error}`);
38
+ return {
39
+ groupRulesStatus: status,
40
+ groupRulesError: error,
41
+ };
42
+ }
43
+ finally {
44
+ await group.close();
45
+ }
46
+ }
47
+ async function resolveGroupRules(clientPromise, groupId, localPath) {
48
+ const client = await clientPromise();
49
+ const check = await safeCheckGroupIndex(client, groupId);
50
+ const shouldPull = check === null || check.needs_update === true || check.local_found !== true;
51
+ const rulesContent = await getRulesContent(client, groupId, shouldPull);
52
+ const rawContent = rulesContent.content;
53
+ if (rawContent === undefined || rawContent === null || rawContent === '') {
54
+ return { status: 'missing', usable: false, changed: false };
55
+ }
56
+ const metadata = parseRulesMetadata(rawContent);
57
+ if (metadata.size > MAX_RULES_BYTES) {
58
+ return { status: 'too_large', usable: false, changed: false, error: `群规则过大: ${metadata.size} bytes > ${MAX_RULES_BYTES}` };
59
+ }
60
+ const remoteRefValue = `${rulesContent.groupAid || groupId}:${RULES_REMOTE_PATH}`;
61
+ const remoteNode = normalizeRemoteRulesNode(await client.group.fs.stat(remoteRefValue));
62
+ if (!remoteNode.size || remoteNode.mtimeMs === undefined) {
63
+ return {
64
+ status: 'unreadable',
65
+ usable: false,
66
+ changed: false,
67
+ error: `远端规则文件缺少 size 或 mtimeMs: ${remoteRefValue}`,
68
+ };
69
+ }
70
+ if (!metadataMatchesNode(metadata, remoteNode)) {
71
+ return {
72
+ status: 'file_mismatch',
73
+ usable: false,
74
+ changed: false,
75
+ error: `远端 /rules.md 与 rules.content 不匹配: expected size=${metadata.size} mtimeMs=${metadata.mtimeMs}, actual size=${remoteNode.size} mtimeMs=${remoteNode.mtimeMs}`,
76
+ };
77
+ }
78
+ if (localMaterializationMatches(localPath, metadata)) {
79
+ return { status: rulesContent.pulled ? 'synced' : 'cached', usable: true, changed: false };
80
+ }
81
+ const bytes = await downloadGroupFileBytes(client, remoteRefValue);
82
+ if (bytes.byteLength > MAX_RULES_BYTES) {
83
+ return { status: 'too_large', usable: false, changed: false, error: `群规则过大: ${bytes.byteLength} bytes > ${MAX_RULES_BYTES}` };
84
+ }
85
+ if (bytes.byteLength !== metadata.size) {
86
+ return {
87
+ status: 'file_mismatch',
88
+ usable: false,
89
+ changed: false,
90
+ error: `下载后的 /rules.md 与 rules.content 大小不匹配: expected ${metadata.size}, actual ${bytes.byteLength}`,
91
+ };
92
+ }
93
+ try {
94
+ assertUtf8(bytes);
95
+ }
96
+ catch (e) {
97
+ return {
98
+ status: 'unreadable',
99
+ usable: false,
100
+ changed: false,
101
+ error: `远端 /rules.md 不是有效 UTF-8: ${errorMessage(e)}`,
102
+ };
103
+ }
104
+ const previousMatches = localMaterializationMatches(localPath, metadata);
105
+ atomicWriteBytes(localPath, bytes);
106
+ const mtimeSeconds = metadata.mtimeMs / 1000;
107
+ fs.utimesSync(localPath, mtimeSeconds, mtimeSeconds);
108
+ if (!localMaterializationMatches(localPath, metadata)) {
109
+ return {
110
+ status: 'error',
111
+ usable: false,
112
+ changed: false,
113
+ error: `本地物化文件 stat 与 rules.content 不匹配: ${localPath}`,
114
+ };
115
+ }
116
+ return { status: 'synced', usable: true, changed: !previousMatches };
117
+ }
118
+ async function safeCheckGroupIndex(client, groupId) {
119
+ try {
120
+ return await checkGroupIndexRpc(client, groupId);
121
+ }
122
+ catch (e) {
123
+ logger.debug(`[GroupRulesSync] checkGroupIndex ignored for ${groupId}: ${errorMessage(e)}`);
124
+ return null;
125
+ }
126
+ }
127
+ async function getGroupIndex(client, groupId) {
128
+ const result = await getGroupIndexRpc(client, groupId);
129
+ return {
130
+ group_aid: typeof result.group_aid === 'string' ? result.group_aid : groupId,
131
+ meta: isRecord(result.meta) ? result.meta : undefined,
132
+ settings: isRecord(result.settings) ? result.settings : {},
133
+ };
134
+ }
135
+ async function getRulesContent(client, groupId, forcePull) {
136
+ if (forcePull) {
137
+ const index = await getGroupIndex(client, groupId);
138
+ return {
139
+ groupAid: index.group_aid || groupId,
140
+ content: index.settings?.['rules.content'],
141
+ pulled: true,
142
+ };
143
+ }
144
+ try {
145
+ const result = await client.group.getRules({ group_id: groupId });
146
+ const rules = isRecord(result.rules) ? result.rules : {};
147
+ return {
148
+ groupAid: typeof result.group_id === 'string' ? result.group_id : groupId,
149
+ content: rules.content,
150
+ pulled: false,
151
+ };
152
+ }
153
+ catch (e) {
154
+ logger.debug(`[GroupRulesSync] getRules fallback to getGroupIndex for ${groupId}: ${errorMessage(e)}`);
155
+ const index = await getGroupIndex(client, groupId);
156
+ return {
157
+ groupAid: index.group_aid || groupId,
158
+ content: index.settings?.['rules.content'],
159
+ pulled: true,
160
+ };
161
+ }
162
+ }
163
+ function parseRulesMetadata(value) {
164
+ let parsed;
165
+ if (typeof value === 'string') {
166
+ try {
167
+ parsed = JSON.parse(value);
168
+ }
169
+ catch {
170
+ throw statusError('invalid_metadata', 'rules.content 不是合法 JSON');
171
+ }
172
+ }
173
+ else {
174
+ parsed = value;
175
+ }
176
+ if (!isRecord(parsed)) {
177
+ throw statusError('invalid_metadata', 'rules.content 必须是对象');
178
+ }
179
+ if (parsed.path !== RULES_REMOTE_PATH) {
180
+ throw statusError('invalid_metadata', `rules.content.path 必须是 ${RULES_REMOTE_PATH}`);
181
+ }
182
+ const size = numberField(parsed, ['size']);
183
+ const mtimeMs = mtimeMsField(parsed);
184
+ if (size === undefined || !Number.isInteger(size) || size <= 0) {
185
+ throw statusError('invalid_metadata', 'rules.content.size 必须是正整数');
186
+ }
187
+ if (mtimeMs === undefined || !Number.isFinite(mtimeMs) || mtimeMs <= 0) {
188
+ throw statusError('invalid_metadata', 'rules.content.mtimeMs 必须是有效毫秒时间戳');
189
+ }
190
+ return { path: RULES_REMOTE_PATH, size, mtimeMs };
191
+ }
192
+ function normalizeRemoteRulesNode(value) {
193
+ if (!isRecord(value))
194
+ return {};
195
+ return {
196
+ size: numberField(value, ['size', 'sizeBytes', 'size_bytes', 'bytes']),
197
+ mtimeMs: mtimeMsField(value),
198
+ };
199
+ }
200
+ function metadataMatchesNode(metadata, node) {
201
+ return node.size === metadata.size
202
+ && node.mtimeMs !== undefined
203
+ && Math.abs(node.mtimeMs - metadata.mtimeMs) <= MTIME_TOLERANCE_MS;
204
+ }
205
+ function localMaterializationMatches(localPath, metadata) {
206
+ try {
207
+ const st = fs.statSync(localPath);
208
+ return st.isFile()
209
+ && st.size === metadata.size
210
+ && Math.abs(st.mtimeMs - metadata.mtimeMs) <= MTIME_TOLERANCE_MS;
211
+ }
212
+ catch {
213
+ return false;
214
+ }
215
+ }
216
+ function lazyGroupClient(selfAid) {
217
+ let client;
218
+ let store;
219
+ return {
220
+ client: async () => {
221
+ if (client)
222
+ return client;
223
+ store = await getAidStore({ slotId: SLOT.daemon });
224
+ client = await loadClient(store, selfAid);
225
+ await client.connect({ connection_kind: 'short', short_ttl_ms: 30000, auto_reconnect: false });
226
+ return client;
227
+ },
228
+ close: async () => {
229
+ if (client) {
230
+ try {
231
+ await client.close();
232
+ }
233
+ catch { /* ignore */ }
234
+ }
235
+ if (store) {
236
+ try {
237
+ store.close();
238
+ }
239
+ catch { /* ignore */ }
240
+ }
241
+ },
242
+ };
243
+ }
244
+ async function downloadGroupFileBytes(client, remoteRef) {
245
+ const ticket = await client.call('group.fs.create_download_ticket', { path: remoteRef });
246
+ if (!isRecord(ticket)) {
247
+ throw statusError('unreadable', 'group.fs.create_download_ticket returned invalid response');
248
+ }
249
+ const downloadUrl = stringField(ticket, ['download_url', 'url']);
250
+ if (!downloadUrl) {
251
+ throw statusError('unreadable', 'group.fs.create_download_ticket did not return download_url');
252
+ }
253
+ const bytes = await client.group.fs.lowlevel.httpGet(downloadUrl, bearerHeaders(client));
254
+ const expectedSha = stringField(ticket, ['sha256']);
255
+ if (expectedSha && sha256Hex(bytes).toLowerCase() !== expectedSha.toLowerCase()) {
256
+ throw statusError('unreadable', 'download hash verification failed');
257
+ }
258
+ return bytes;
259
+ }
260
+ function sha256Hex(bytes) {
261
+ return createHash('sha256').update(bytes).digest('hex');
262
+ }
263
+ function bearerHeaders(client) {
264
+ const token = accessTokenFromClient(client);
265
+ return token ? { Authorization: `Bearer ${token}` } : undefined;
266
+ }
267
+ function accessTokenFromClient(client) {
268
+ const anyClient = client;
269
+ if (typeof anyClient.getAccessToken === 'function') {
270
+ const token = stringValue(anyClient.getAccessToken());
271
+ if (token)
272
+ return token;
273
+ }
274
+ return stringValue(anyClient.accessToken)
275
+ || stringValue(anyClient.access_token)
276
+ || stringValue(anyClient._identity?.access_token)
277
+ || stringValue(anyClient._sessionParams?.access_token);
278
+ }
279
+ function assertUtf8(bytes) {
280
+ new TextDecoder('utf-8', { fatal: true }).decode(bytes);
281
+ }
282
+ function relationPaths(selfAid, channel, groupId) {
283
+ const peerKey = formatPeerKey(channel, groupId);
284
+ const dir = path.join(agentRelationsDir(selfAid), peerKey);
285
+ return {
286
+ peerKey,
287
+ dir,
288
+ localRulesPath: path.join(dir, RULES_LOCAL_PATH),
289
+ };
290
+ }
291
+ class StatusError extends Error {
292
+ status;
293
+ constructor(status, message) {
294
+ super(message);
295
+ this.status = status;
296
+ }
297
+ }
298
+ function statusError(status, message) {
299
+ return new StatusError(status, message);
300
+ }
301
+ function classifyError(e) {
302
+ if (e instanceof StatusError)
303
+ return e.status;
304
+ const msg = errorMessage(e).toLowerCase();
305
+ if (msg.includes('forbidden') || msg.includes('unauthorized') || msg.includes('permission'))
306
+ return 'forbidden';
307
+ if (msg.includes('not found') || msg.includes('does not exist'))
308
+ return 'missing';
309
+ return 'error';
310
+ }
311
+ function errorMessage(e) {
312
+ return e instanceof Error ? e.message : String(e);
313
+ }
314
+ function isRecord(x) {
315
+ return typeof x === 'object' && x !== null && !Array.isArray(x);
316
+ }
317
+ function stringValue(x) {
318
+ return typeof x === 'string' ? x : '';
319
+ }
320
+ function stringField(obj, keys) {
321
+ for (const k of keys) {
322
+ const v = obj[k];
323
+ if (typeof v === 'string')
324
+ return v;
325
+ }
326
+ return undefined;
327
+ }
328
+ function numberField(obj, keys) {
329
+ for (const k of keys) {
330
+ const v = obj[k];
331
+ if (typeof v === 'number' && Number.isFinite(v))
332
+ return v;
333
+ }
334
+ return undefined;
335
+ }
336
+ function mtimeMsField(obj) {
337
+ const candidates = ['mtimeMs', 'mtime_ms', 'mtimeMillis', 'mtime'];
338
+ for (const k of candidates) {
339
+ const v = obj[k];
340
+ if (typeof v === 'number' && Number.isFinite(v)) {
341
+ return k === 'mtime' && v < 1e12 ? v * 1000 : v;
342
+ }
343
+ }
344
+ return undefined;
345
+ }
@@ -0,0 +1,77 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { resolvePaths, kitsDocsDir, agentDir, getPackageRoot } from '../paths.js';
4
+ import { atomicWriteText } from '../utils/atomic-write.js';
5
+ import { logger } from '../utils/logger.js';
6
+ export function initEck() {
7
+ const p = resolvePaths();
8
+ const eckDir = p.eckDir;
9
+ fs.mkdirSync(eckDir, { recursive: true });
10
+ initEckRuntime(eckDir);
11
+ initEckPathRegistry(eckDir);
12
+ }
13
+ export function initAgentIndex(aid) {
14
+ const indexDir = path.join(agentDir(aid), 'index');
15
+ fs.mkdirSync(indexDir, { recursive: true });
16
+ const indexFile = path.join(indexDir, 'INDEX.md');
17
+ const guideFile = path.join(indexDir, 'GUIDE.md');
18
+ if (!fs.existsSync(indexFile)) {
19
+ const template = loadTemplate('INDEX.template.md');
20
+ if (template) {
21
+ atomicWriteText(indexFile, renderTemplate(template, { AID: aid }));
22
+ logger.info(`[eck] Created ${indexFile}`);
23
+ }
24
+ }
25
+ if (!fs.existsSync(guideFile)) {
26
+ const template = loadTemplate('GUIDE.template.md');
27
+ if (template) {
28
+ atomicWriteText(guideFile, renderTemplate(template, { AID: aid }));
29
+ logger.info(`[eck] Created ${guideFile}`);
30
+ }
31
+ }
32
+ }
33
+ function initEckRuntime(eckDir) {
34
+ const runtimeFile = path.join(eckDir, 'runtime.md');
35
+ if (fs.existsSync(runtimeFile))
36
+ return;
37
+ const template = loadTemplate('runtime.template.md');
38
+ if (!template)
39
+ return;
40
+ const vars = {
41
+ EVOLCORE_HOME: resolvePaths().root,
42
+ PACKAGE_ROOT: getPackageRoot(),
43
+ };
44
+ atomicWriteText(runtimeFile, renderTemplate(template, vars));
45
+ logger.info(`[eck] Created ${runtimeFile}`);
46
+ }
47
+ function initEckPathRegistry(eckDir) {
48
+ const registryFile = path.join(eckDir, 'path-registry.md');
49
+ if (fs.existsSync(registryFile))
50
+ return;
51
+ const template = loadTemplate('path-registry.template.md');
52
+ if (!template)
53
+ return;
54
+ const vars = {
55
+ EVOLCORE_HOME: resolvePaths().root,
56
+ PACKAGE_ROOT: getPackageRoot(),
57
+ };
58
+ atomicWriteText(registryFile, renderTemplate(template, vars));
59
+ logger.info(`[eck] Created ${registryFile}`);
60
+ }
61
+ function loadTemplate(filename) {
62
+ const templatePath = path.join(kitsDocsDir(), 'eck_templates', filename);
63
+ try {
64
+ return fs.readFileSync(templatePath, 'utf-8');
65
+ }
66
+ catch {
67
+ logger.warn(`[eck] Template not found: ${templatePath}`);
68
+ return null;
69
+ }
70
+ }
71
+ function renderTemplate(template, vars) {
72
+ let result = template;
73
+ for (const [key, value] of Object.entries(vars)) {
74
+ result = result.replaceAll(`{{${key}}}`, value);
75
+ }
76
+ return result;
77
+ }