evolcore 0.0.1 → 0.0.3

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 (379) hide show
  1. package/CHANGELOG.md +64 -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/bin/ec-safe-output.js +161 -0
  8. package/bin/ec.js +29 -0
  9. package/dist/agents/baseagent.js +163 -0
  10. package/dist/agents/claude-runner.js +2565 -0
  11. package/dist/agents/codex-app-server-client.js +448 -0
  12. package/dist/agents/codex-runner.js +2682 -0
  13. package/dist/agents/gemini-runner.js +666 -0
  14. package/dist/agents/runner-types.js +75 -0
  15. package/dist/aun/aid/agentmd.js +216 -0
  16. package/dist/aun/aid/client.js +132 -0
  17. package/dist/aun/aid/control-aid.js +91 -0
  18. package/dist/aun/aid/identity.js +518 -0
  19. package/dist/aun/aid/index.js +4 -0
  20. package/dist/aun/aid/store.js +74 -0
  21. package/dist/aun/aid/types.js +1 -0
  22. package/dist/aun/aid/validation.js +21 -0
  23. package/dist/aun/group-identity.js +10 -0
  24. package/dist/aun/msg/group-index.js +6 -0
  25. package/dist/aun/msg/group.js +1231 -0
  26. package/dist/aun/msg/history.js +123 -0
  27. package/dist/aun/msg/index.js +5 -0
  28. package/dist/aun/msg/p2p.js +393 -0
  29. package/dist/aun/msg/payload-type.js +27 -0
  30. package/dist/aun/msg/upload.js +137 -0
  31. package/dist/aun/outbox.js +168 -0
  32. package/dist/aun/rpc/caller.js +42 -0
  33. package/dist/aun/rpc/connection.js +25 -0
  34. package/dist/aun/rpc/index.js +2 -0
  35. package/dist/aun/service-proxy.js +225 -0
  36. package/dist/aun/storage/download.js +29 -0
  37. package/dist/aun/storage/index.js +3 -0
  38. package/dist/aun/storage/manage.js +10 -0
  39. package/dist/aun/storage/upload.js +68 -0
  40. package/dist/channels/aun.js +4164 -0
  41. package/dist/channels/contact-bind-code.js +134 -0
  42. package/dist/channels/daemon.js +422 -0
  43. package/dist/channels/dingtalk.js +1479 -0
  44. package/dist/channels/feishu.js +1865 -0
  45. package/dist/channels/qqbot.js +409 -0
  46. package/dist/channels/wechat.js +817 -0
  47. package/dist/channels/wecom-card.js +101 -0
  48. package/dist/channels/wecom-onboarding.js +82 -0
  49. package/dist/channels/wecom-state.js +191 -0
  50. package/dist/channels/wecom.js +1157 -0
  51. package/dist/cli/agent-command.js +642 -0
  52. package/dist/cli/agent.js +1059 -0
  53. package/dist/cli/aun-commands.js +2003 -0
  54. package/dist/cli/bench.js +1228 -0
  55. package/dist/cli/cli-argv.js +66 -0
  56. package/dist/cli/code-stats.js +329 -0
  57. package/dist/cli/command-log.js +82 -0
  58. package/dist/cli/config-selector.js +69 -0
  59. package/dist/cli/config.js +261 -0
  60. package/dist/cli/contact.js +71 -0
  61. package/dist/cli/ctl-command.js +62 -0
  62. package/dist/cli/daemon-commands.js +2750 -0
  63. package/dist/cli/fs-command.js +1447 -0
  64. package/dist/cli/handoff-command.js +302 -0
  65. package/dist/cli/help.js +35 -0
  66. package/dist/cli/index.js +374 -0
  67. package/dist/cli/init-channel.js +1372 -0
  68. package/dist/cli/init.js +590 -0
  69. package/dist/cli/link-rules.js +240 -0
  70. package/dist/cli/model.js +591 -0
  71. package/dist/cli/net-check.js +723 -0
  72. package/dist/cli/queue-command.js +150 -0
  73. package/dist/cli/raw-key-input.js +25 -0
  74. package/dist/cli/response.js +344 -0
  75. package/dist/cli/restart-monitor.js +480 -0
  76. package/dist/cli/stats.js +609 -0
  77. package/dist/cli/task-context.js +80 -0
  78. package/dist/cli/trigger-command.js +545 -0
  79. package/dist/cli/version.js +93 -0
  80. package/dist/cli/watch-logs.js +33 -0
  81. package/dist/cli/watch-msg.js +673 -0
  82. package/dist/config/boot-log.js +266 -0
  83. package/dist/config/builtin-role-templates.js +42 -0
  84. package/dist/config/builtin-roles.js +91 -0
  85. package/dist/config/config-batch-get.js +11 -0
  86. package/dist/config/config-field-policy.js +261 -0
  87. package/dist/config/config-manager.js +1120 -0
  88. package/dist/config/config-operation-service.js +384 -0
  89. package/dist/config/contact-alias.js +68 -0
  90. package/dist/config/contact-book-store.js +454 -0
  91. package/dist/config/contact-book-v2-startup.js +35 -0
  92. package/dist/config/contact-book.js +224 -0
  93. package/dist/config/contact-operation-service.js +110 -0
  94. package/dist/config/gateway-config.js +858 -0
  95. package/dist/config/lifecycle.js +17 -0
  96. package/dist/config/mention-mode.js +27 -0
  97. package/dist/config/merge.js +161 -0
  98. package/dist/config/owner-policy.js +4 -0
  99. package/dist/config/peer-role-resolver.js +218 -0
  100. package/dist/config/resolved-config-op.js +483 -0
  101. package/dist/config/role-config-v4-startup.js +32 -0
  102. package/dist/config/role-config-v5-startup.js +27 -0
  103. package/dist/config/role-ranks.js +18 -0
  104. package/dist/config/role-schema.js +105 -0
  105. package/dist/config/role-service.js +156 -0
  106. package/dist/config/role-store.js +215 -0
  107. package/dist/config/roles.js +64 -0
  108. package/dist/config/schema-registry.js +154 -0
  109. package/dist/config/snapshot.js +598 -0
  110. package/dist/config-store.js +501 -0
  111. package/dist/core/auth/agent-delegation.js +111 -0
  112. package/dist/core/auth/auth-gateway.js +166 -0
  113. package/dist/core/auth/authenticated-actor.js +6 -0
  114. package/dist/core/auth/authorization-audit.js +119 -0
  115. package/dist/core/auth/operation-authorizer.js +720 -0
  116. package/dist/core/auth/operation-catalog.js +731 -0
  117. package/dist/core/baseagent-loader.js +54 -0
  118. package/dist/core/bootstrap-service.js +175 -0
  119. package/dist/core/capability/capability-manager.js +316 -0
  120. package/dist/core/capability/providers/claude-capability-provider.js +176 -0
  121. package/dist/core/capability/providers/codex-capability-provider.js +148 -0
  122. package/dist/core/capability/providers/gemini-capability-provider.js +10 -0
  123. package/dist/core/capability/types.js +27 -0
  124. package/dist/core/causation/audit.js +103 -0
  125. package/dist/core/causation/aun-association.js +111 -0
  126. package/dist/core/causation/context.js +93 -0
  127. package/dist/core/causation/index.js +4 -0
  128. package/dist/core/causation/types.js +2 -0
  129. package/dist/core/channel-loader.js +277 -0
  130. package/dist/core/command/agent-control.js +616 -0
  131. package/dist/core/command/cli-intent-parser.js +225 -0
  132. package/dist/core/command/command-handler.js +1733 -0
  133. package/dist/core/command/connect-menu.js +374 -0
  134. package/dist/core/command/menu-handler.js +3452 -0
  135. package/dist/core/command/menu-protocol.js +247 -0
  136. package/dist/core/command/role-menu.js +1623 -0
  137. package/dist/core/command/slash-gate.js +148 -0
  138. package/dist/core/command/slash-handler.js +3066 -0
  139. package/dist/core/daemon-file-cache.js +222 -0
  140. package/dist/core/event-bus.js +32 -0
  141. package/dist/core/event-catalog.js +810 -0
  142. package/dist/core/evolagent-registry.js +545 -0
  143. package/dist/core/evolagent.js +342 -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 +659 -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 +874 -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 +1446 -0
  161. package/dist/core/message/message-utils.js +76 -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 +4020 -0
  166. package/dist/core/message/response-snapshot.js +83 -0
  167. package/dist/core/message/send-receipt.js +24 -0
  168. package/dist/core/message/stream-debouncer.js +139 -0
  169. package/dist/core/message/stream-idle-monitor.js +124 -0
  170. package/dist/core/model/config-scope.js +162 -0
  171. package/dist/core/model/field-scope.js +78 -0
  172. package/dist/core/model/model-catalog.js +227 -0
  173. package/dist/core/model/model-diagnostics.js +182 -0
  174. package/dist/core/model/model-permission.js +90 -0
  175. package/dist/core/permission/approval-gateway.js +1017 -0
  176. package/dist/core/permission/ec-command-parser.js +347 -0
  177. package/dist/core/permission/execution-sandbox.js +16 -0
  178. package/dist/core/permission/index.js +6 -0
  179. package/dist/core/permission/mode.js +24 -0
  180. package/dist/core/permission/sandbox-runtime.js +265 -0
  181. package/dist/core/permission/tool-policy.js +1019 -0
  182. package/dist/core/permission/unix-socket-policy.js +99 -0
  183. package/dist/core/protected-paths.js +332 -0
  184. package/dist/core/relation/peer-identity.js +222 -0
  185. package/dist/core/relation/peer-key.js +1 -0
  186. package/dist/core/role/runtime-policy.js +141 -0
  187. package/dist/core/session/adapters/claude-session-file-adapter.js +218 -0
  188. package/dist/core/session/adapters/codex-session-file-adapter.js +333 -0
  189. package/dist/core/session/adapters/gemini-session-file-adapter.js +181 -0
  190. package/dist/core/session/session-file-adapter.js +7 -0
  191. package/dist/core/session/session-file-health.js +45 -0
  192. package/dist/core/session/session-fs-store.js +273 -0
  193. package/dist/core/session/session-key.js +24 -0
  194. package/dist/core/session/session-manager.js +1643 -0
  195. package/dist/core/session/session-mapper.js +100 -0
  196. package/dist/core/session/session-renew.js +314 -0
  197. package/dist/core/session/session-title.js +128 -0
  198. package/dist/core/session/session-turn-coordinator.js +205 -0
  199. package/dist/core/session/session-turns.js +67 -0
  200. package/dist/core/system-channels.js +29 -0
  201. package/dist/eck/baseagent-caps.js +18 -0
  202. package/dist/eck/detect.js +47 -0
  203. package/dist/eck/group-rules-sync.js +345 -0
  204. package/dist/eck/init.js +77 -0
  205. package/dist/eck/kit-renderer.js +359 -0
  206. package/dist/eck/manifest-engine.js +446 -0
  207. package/dist/eck/message-renderer.js +199 -0
  208. package/dist/eck/rules-loader.js +28 -0
  209. package/dist/index.js +2926 -4
  210. package/dist/ipc.js +777 -0
  211. package/dist/paths.js +262 -0
  212. package/dist/product.js +18 -0
  213. package/dist/response-system/context-builder.js +71 -0
  214. package/dist/response-system/coordinator.js +117 -0
  215. package/dist/response-system/decision-executor.js +86 -0
  216. package/dist/response-system/engines/v1/index.js +21 -0
  217. package/dist/response-system/engines/v1/interactive-flow.js +27 -0
  218. package/dist/response-system/engines/v1/proactive-flow.js +137 -0
  219. package/dist/response-system/engines/v1/types.js +1 -0
  220. package/dist/response-system/extensions.js +41 -0
  221. package/dist/response-system/index.js +6 -0
  222. package/dist/response-system/modes/index.js +7 -0
  223. package/dist/response-system/modes/single-session/index.js +72 -0
  224. package/dist/response-system/queues/fifo-queue.js +44 -0
  225. package/dist/response-system/queues/index.js +6 -0
  226. package/dist/response-system/queues/lifo-queue.js +42 -0
  227. package/dist/response-system/queues/priority-queue.js +63 -0
  228. package/dist/response-system/registry.js +97 -0
  229. package/dist/response-system/resolver.js +37 -0
  230. package/dist/response-system/selector.js +23 -0
  231. package/dist/response-system/types.js +7 -0
  232. package/dist/stats/billing.js +163 -0
  233. package/dist/stats/budget.js +93 -0
  234. package/dist/stats/db.js +403 -0
  235. package/dist/stats/eck-vars.js +89 -0
  236. package/dist/stats/index.js +11 -0
  237. package/dist/stats/normalizer.js +80 -0
  238. package/dist/stats/price-resolver.js +138 -0
  239. package/dist/stats/query.js +763 -0
  240. package/dist/stats/role-budget.js +168 -0
  241. package/dist/stats/writer.js +151 -0
  242. package/dist/trigger/anomaly-store.js +258 -0
  243. package/dist/trigger/audit.js +152 -0
  244. package/dist/trigger/event-source.js +119 -0
  245. package/dist/trigger/feedback.js +685 -0
  246. package/dist/trigger/history.js +290 -0
  247. package/dist/trigger/manager.js +294 -0
  248. package/dist/trigger/parser.js +595 -0
  249. package/dist/trigger/patch.js +155 -0
  250. package/dist/trigger/scheduler.js +1602 -0
  251. package/dist/trigger/script-executor.js +155 -0
  252. package/dist/trigger/state.js +145 -0
  253. package/dist/trigger/types.js +1 -0
  254. package/dist/trigger/validation.js +634 -0
  255. package/dist/types.js +12 -0
  256. package/dist/utils/aid-bind.js +313 -0
  257. package/dist/utils/atomic-write.js +95 -0
  258. package/dist/utils/avatar-upload.js +123 -0
  259. package/dist/utils/cross-platform.js +297 -0
  260. package/dist/utils/ecweb-utils.js +73 -0
  261. package/dist/utils/error-dict.json +153 -0
  262. package/dist/utils/error-utils.js +349 -0
  263. package/dist/utils/instance-registry.js +444 -0
  264. package/dist/utils/locale.js +21 -0
  265. package/dist/utils/log-writer.js +270 -0
  266. package/dist/utils/logger.js +89 -0
  267. package/dist/utils/markdown-to-plain-text.js +20 -0
  268. package/dist/utils/media-cache.js +274 -0
  269. package/dist/utils/model-prices.jsonl +20 -0
  270. package/dist/utils/npm-ops.js +210 -0
  271. package/dist/utils/process-introspect.js +133 -0
  272. package/dist/utils/process-tree-stats.js +271 -0
  273. package/dist/utils/project-path.js +74 -0
  274. package/dist/utils/restart-safety.js +31 -0
  275. package/dist/utils/stats.js +410 -0
  276. package/dist/utils/system-memory.js +62 -0
  277. package/dist/utils/tool-summary.js +284 -0
  278. package/dist/utils/welcome.js +268 -0
  279. package/kits/docs/GUIDE.md +20 -0
  280. package/kits/docs/INDEX.md +66 -0
  281. package/kits/docs/aun/CHEATSHEET.md +19 -0
  282. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  283. package/kits/docs/channels/aun.md +65 -0
  284. package/kits/docs/channels/feishu.md +56 -0
  285. package/kits/docs/context-assembly.md +366 -0
  286. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  287. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  288. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  289. package/kits/docs/eck_templates/runtime.template.md +19 -0
  290. package/kits/docs/evolcore/INDEX.md +68 -0
  291. package/kits/docs/evolcore/agent.md +77 -0
  292. package/kits/docs/evolcore/aid.md +52 -0
  293. package/kits/docs/evolcore/config.md +149 -0
  294. package/kits/docs/evolcore/contact.md +57 -0
  295. package/kits/docs/evolcore/ctl.md +46 -0
  296. package/kits/docs/evolcore/event.md +216 -0
  297. package/kits/docs/evolcore/fs-architecture.md +1215 -0
  298. package/kits/docs/evolcore/fs.md +110 -0
  299. package/kits/docs/evolcore/group-fs.md +17 -0
  300. package/kits/docs/evolcore/group-rules.md +226 -0
  301. package/kits/docs/evolcore/group.md +150 -0
  302. package/kits/docs/evolcore/model.md +50 -0
  303. package/kits/docs/evolcore/msg.md +136 -0
  304. package/kits/docs/evolcore/response.md +75 -0
  305. package/kits/docs/evolcore/rpc.md +37 -0
  306. package/kits/docs/evolcore/self-summary.md +29 -0
  307. package/kits/docs/evolcore/stats.md +83 -0
  308. package/kits/docs/evolcore/storage.md +50 -0
  309. package/kits/docs/evolcore/trigger.md +539 -0
  310. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -0
  311. package/kits/docs/identity/PATH_OPS.md +16 -0
  312. package/kits/docs/identity/ROLE_DETAIL.md +23 -0
  313. package/kits/docs/identity/identity-tools.md +26 -0
  314. package/kits/docs/path-registry.md +43 -0
  315. package/kits/docs/prompt-loading-architecture.md +266 -0
  316. package/kits/docs/venues/aun-group.md +45 -0
  317. package/kits/docs/venues/aun-private.md +10 -0
  318. package/kits/docs/venues/client-desktop.md +10 -0
  319. package/kits/docs/venues/client-mobile.md +10 -0
  320. package/kits/docs/venues/feishu-group.md +13 -0
  321. package/kits/docs/venues/feishu-private.md +9 -0
  322. package/kits/docs/venues/group.md +25 -0
  323. package/kits/docs/venues/private.md +10 -0
  324. package/kits/eck_manifest.auxiliary.json +43 -0
  325. package/kits/eck_manifest.json +203 -0
  326. package/kits/eck_message_manifest.json +63 -0
  327. package/kits/migrations/README-role-config-v4.md +32 -0
  328. package/kits/migrations/migrate-contact-book-v2.mjs +747 -0
  329. package/kits/migrations/migrate-role-config-v4.mjs +623 -0
  330. package/kits/migrations/migrate-role-config-v5.mjs +346 -0
  331. package/kits/migrations/rename-config-file.mjs +99 -0
  332. package/kits/rules/01-overview.md +142 -0
  333. package/kits/rules/02-navigation.md +76 -0
  334. package/kits/rules/03-identity.md +34 -0
  335. package/kits/rules/04-relation.md +59 -0
  336. package/kits/rules/05-venue.md +44 -0
  337. package/kits/rules/06-channel.md +59 -0
  338. package/kits/schemas/_meta.json +32 -0
  339. package/kits/schemas/agent-config.schema.1.json +177 -0
  340. package/kits/schemas/agent-config.schema.2.json +239 -0
  341. package/kits/schemas/agent-config.schema.3.json +119 -0
  342. package/kits/schemas/agent-config.schema.4.json +208 -0
  343. package/kits/schemas/agent-config.schema.5.json +326 -0
  344. package/kits/schemas/agent-config.schema.6.json +322 -0
  345. package/kits/schemas/contact-book.schema.1.json +36 -0
  346. package/kits/schemas/contact-book.schema.2.json +43 -0
  347. package/kits/schemas/daemon.schema.1.json +90 -0
  348. package/kits/schemas/defaults.schema.1.json +81 -0
  349. package/kits/schemas/menu-exec-schema-commands.md +208 -0
  350. package/kits/schemas/migrations/README.md +28 -0
  351. package/kits/schemas/relation-config.schema.1.json +158 -0
  352. package/kits/schemas/relation-config.schema.2.json +73 -0
  353. package/kits/schemas/relation-config.schema.3.json +50 -0
  354. package/kits/schemas/relation-config.schema.4.json +47 -0
  355. package/kits/schemas/relation-config.schema.5.json +47 -0
  356. package/kits/schemas/role-config.schema.1.json +201 -0
  357. package/kits/schemas/role-registry.schema.1.json +35 -0
  358. package/kits/schemas/single-session.schema.1.json +31 -0
  359. package/kits/templates/bootstrap-welcome.md +15 -0
  360. package/kits/templates/message-fragments/handoff-request-to-target.md +13 -0
  361. package/kits/templates/message-fragments/handoff-response-to-origin.md +10 -0
  362. package/kits/templates/message-fragments/inject-default.md +2 -0
  363. package/kits/templates/message-fragments/item.md +2 -0
  364. package/kits/templates/roles/admin.json +9 -0
  365. package/kits/templates/roles/member.json +41 -0
  366. package/kits/templates/roles/owner.json +9 -0
  367. package/kits/templates/roles/visitor.json +40 -0
  368. package/kits/templates/system-fragments/baseagent.md +14 -0
  369. package/kits/templates/system-fragments/bootstrap.md +16 -0
  370. package/kits/templates/system-fragments/channel.md +48 -0
  371. package/kits/templates/system-fragments/commands.md +28 -0
  372. package/kits/templates/system-fragments/identity.md +11 -0
  373. package/kits/templates/system-fragments/relation.md +19 -0
  374. package/kits/templates/system-fragments/session.md +53 -0
  375. package/kits/templates/system-fragments/venue.md +31 -0
  376. package/package.json +50 -15
  377. package/dist/index.d.ts +0 -7
  378. package/dist/index.d.ts.map +0 -1
  379. package/dist/index.js.map +0 -1
package/dist/ipc.js ADDED
@@ -0,0 +1,777 @@
1
+ import net from 'net';
2
+ import fs from 'fs';
3
+ import os from 'os';
4
+ import path from 'path';
5
+ import { logger } from './utils/logger.js';
6
+ import { fileCache } from './core/daemon-file-cache.js';
7
+ import { HANDOFF_QUERY_MAX_LIMIT, HANDOFF_STATES } from './core/handoff/types.js';
8
+ import { resolvePaths } from './paths.js';
9
+ import { getProcessStartTime, isSameOrOlderProcess } from './utils/process-introspect.js';
10
+ import { classifyProcessTree, ProcessTreeSampler } from './utils/process-tree-stats.js';
11
+ import { readSystemMemoryUsage } from './utils/system-memory.js';
12
+ const isWindows = process.platform === 'win32';
13
+ const isNamedPipe = (p) => isWindows && p.startsWith('\\\\.\\pipe\\');
14
+ export function summarizeMonitorAgents(agents, aids) {
15
+ const connectedAgents = new Set(aids.filter(aid => aid.status === 'connected').map(aid => aid.agentName || aid.aid));
16
+ const enabledAgents = agents.filter(agent => agent.status !== 'disabled');
17
+ return {
18
+ total: agents.length,
19
+ enabled: enabledAgents.length,
20
+ running: agents.filter(agent => agent.status === 'running').length,
21
+ connected: enabledAgents.filter(agent => connectedAgents.has(agent.aid)).length,
22
+ disabled: agents.filter(agent => agent.status === 'disabled').length,
23
+ errors: agents.filter(agent => agent.status === 'error').length,
24
+ };
25
+ }
26
+ export class IpcServer {
27
+ socketPath;
28
+ getStatus;
29
+ commandExecutor;
30
+ server = null;
31
+ agentRegistry;
32
+ aunAidProvider;
33
+ aunAidStatsProvider;
34
+ aunAidStatsRecorder;
35
+ menuExecutor;
36
+ statsProvider;
37
+ agentStatsProvider;
38
+ queueSnapshotProvider;
39
+ queueActionExecutor;
40
+ triggerExecutor;
41
+ taskRuntimeContextProvider;
42
+ aunMsgSender;
43
+ handoffReturnExecutor;
44
+ handoffStatusExecutor;
45
+ handoffListExecutor;
46
+ handoffTraceExecutor;
47
+ bindExecutor;
48
+ configOperationExecutor;
49
+ contactOperationExecutor;
50
+ dingtalkContactBindExecutor;
51
+ wecomContactBindExecutor;
52
+ // CPU 占用追踪:IPC handler 是一次性同步调用,无法在响应里做 200ms 异步采样,
53
+ // 故用后台 1s interval 累积 process.cpuUsage() 增量,handler 直接读最近值。
54
+ // procCpuPercent = 本 daemon 进程占单核的百分比(可 >100% 仅当多核,已 clamp 到 100);
55
+ // sysCpuPercent = 整机所有核平均忙碌百分比(由 os.cpus() times 增量算出)。
56
+ lastCpuUsage = process.cpuUsage();
57
+ lastCpuTs = Date.now();
58
+ cpuPercent = 0; // 进程级
59
+ sysCpuPercent = 0; // 系统级
60
+ lastCpuTimes = null;
61
+ cpuTimer = null;
62
+ processTreeSampler = new ProcessTreeSampler(process.pid);
63
+ processTreeSnapshot = null;
64
+ associatedProcessKinds = new Map();
65
+ constructor(socketPath, getStatus, commandExecutor) {
66
+ this.socketPath = socketPath;
67
+ this.getStatus = getStatus;
68
+ this.commandExecutor = commandExecutor;
69
+ }
70
+ /** Inject EvolAgentRegistry for evolagent.* IPC handlers */
71
+ setAgentRegistry(registry) {
72
+ this.agentRegistry = registry;
73
+ }
74
+ /** Inject menu.* executor (ECWeb Control proxies menu requests through this) */
75
+ setMenuExecutor(executor) {
76
+ this.menuExecutor = executor;
77
+ }
78
+ setConfigOperationExecutor(executor) {
79
+ this.configOperationExecutor = executor;
80
+ }
81
+ setContactOperationExecutor(executor) {
82
+ this.contactOperationExecutor = executor;
83
+ }
84
+ /** Inject AUN AID state aggregator for aun-aids IPC handler */
85
+ setAunAidProvider(provider) {
86
+ this.aunAidProvider = provider;
87
+ }
88
+ /** Inject AUN AID stats provider for aun-aid-stats IPC handler */
89
+ setAunAidStatsProvider(provider) {
90
+ this.aunAidStatsProvider = provider;
91
+ }
92
+ /** Inject AUN AID stats recorder for aun-aid-stats-record-outbound IPC handler */
93
+ setAunAidStatsRecorder(recorder) {
94
+ this.aunAidStatsRecorder = recorder;
95
+ }
96
+ /** Inject global StatsSnapshot provider for monitor-snapshot IPC handler */
97
+ setStatsProvider(provider) {
98
+ this.statsProvider = provider;
99
+ }
100
+ /** Inject per-agent rolling stats provider for ECWeb Agents page. */
101
+ setAgentStatsProvider(provider) {
102
+ this.agentStatsProvider = provider;
103
+ }
104
+ /** Inject queue snapshot provider for queue-snapshot IPC handler (query mode) */
105
+ setQueueSnapshotProvider(provider) {
106
+ this.queueSnapshotProvider = provider;
107
+ }
108
+ /** Inject queue action executor for queue-snapshot IPC handler (action mode) */
109
+ setQueueActionExecutor(executor) {
110
+ this.queueActionExecutor = executor;
111
+ }
112
+ /** Inject daemon-level trigger executor for ec trigger. */
113
+ setTriggerExecutor(executor) {
114
+ this.triggerExecutor = executor;
115
+ }
116
+ /** Inject active task runtime-context provider for in-task CLI routing. */
117
+ setTaskRuntimeContextProvider(provider) {
118
+ this.taskRuntimeContextProvider = provider;
119
+ }
120
+ /** Inject daemon-backed AUN private message sender for in-task `ec msg send`. */
121
+ setAunMsgSender(sender) {
122
+ this.aunMsgSender = sender;
123
+ }
124
+ /** Inject internal handoff result return executor for `ec handoff return`. */
125
+ setHandoffReturnExecutor(executor) {
126
+ this.handoffReturnExecutor = executor;
127
+ }
128
+ setHandoffStatusExecutor(executor) {
129
+ this.handoffStatusExecutor = executor;
130
+ }
131
+ setHandoffListExecutor(executor) {
132
+ this.handoffListExecutor = executor;
133
+ }
134
+ setHandoffTraceExecutor(executor) {
135
+ this.handoffTraceExecutor = executor;
136
+ }
137
+ /** Inject bootstrap QR bind executor for init/init aun. */
138
+ setBindExecutor(executor) {
139
+ this.bindExecutor = executor;
140
+ }
141
+ /** Inject DingTalk contact binding-code executor. */
142
+ setDingtalkContactBindExecutor(executor) {
143
+ this.dingtalkContactBindExecutor = executor;
144
+ }
145
+ /** Inject WeCom contact binding-code executor. */
146
+ setWecomContactBindExecutor(executor) {
147
+ this.wecomContactBindExecutor = executor;
148
+ }
149
+ /** Start the 1s background CPU sampling loop (for monitor-snapshot). Call after start(). */
150
+ startCpuTracking() {
151
+ if (this.cpuTimer)
152
+ return;
153
+ this.sampleProcessTree();
154
+ this.cpuTimer = setInterval(() => {
155
+ const now = Date.now();
156
+ const elapsedUs = (now - this.lastCpuTs) * 1000; // wall time in microseconds
157
+ if (elapsedUs > 0) {
158
+ const usage = process.cpuUsage(this.lastCpuUsage); // delta since last sample
159
+ this.cpuPercent = Math.min(100, ((usage.user + usage.system) / elapsedUs) * 100);
160
+ }
161
+ this.lastCpuUsage = process.cpuUsage();
162
+ this.lastCpuTs = now;
163
+ // 系统级 CPU:os.cpus() 累计 times 的增量 → 整机平均忙碌率
164
+ try {
165
+ const cpus = os.cpus();
166
+ let idle = 0, total = 0;
167
+ for (const c of cpus) {
168
+ idle += c.times.idle;
169
+ total += c.times.user + c.times.nice + c.times.sys + c.times.idle + c.times.irq;
170
+ }
171
+ if (this.lastCpuTimes) {
172
+ const idleDelta = idle - this.lastCpuTimes.idle;
173
+ const totalDelta = total - this.lastCpuTimes.total;
174
+ if (totalDelta > 0) {
175
+ this.sysCpuPercent = Math.max(0, Math.min(100, (1 - idleDelta / totalDelta) * 100));
176
+ }
177
+ }
178
+ this.lastCpuTimes = { idle, total };
179
+ }
180
+ catch { /* os.cpus() 理论上不抛 */ }
181
+ this.sampleProcessTree();
182
+ }, 1000);
183
+ // Don't keep the event loop alive for sampling alone.
184
+ this.cpuTimer.unref?.();
185
+ }
186
+ /** Stop the CPU sampling loop. */
187
+ stopCpuTracking() {
188
+ if (this.cpuTimer) {
189
+ clearInterval(this.cpuTimer);
190
+ this.cpuTimer = null;
191
+ }
192
+ }
193
+ sampleProcessTree() {
194
+ try {
195
+ const roots = this.readAssociatedProcessRoots();
196
+ this.associatedProcessKinds = new Map(roots.map(root => [root.pid, root.kind]));
197
+ this.processTreeSnapshot = this.processTreeSampler.sample(roots.map(root => root.pid));
198
+ }
199
+ catch {
200
+ this.processTreeSnapshot = null;
201
+ this.associatedProcessKinds.clear();
202
+ }
203
+ }
204
+ readAssociatedProcessRoots() {
205
+ const roots = [];
206
+ let files;
207
+ try {
208
+ files = fs.readdirSync(resolvePaths().instanceDir);
209
+ }
210
+ catch {
211
+ return roots;
212
+ }
213
+ for (const file of files) {
214
+ const match = file.match(/^(ecweb|watch-web|restart-monitor|watch-aid|watch)-(\d+)\.json$/);
215
+ if (!match)
216
+ continue;
217
+ try {
218
+ const record = JSON.parse(fs.readFileSync(path.join(resolvePaths().instanceDir, file), 'utf8'));
219
+ const pid = Number(record.pid || match[2]);
220
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid)
221
+ continue;
222
+ if (record.startedAt) {
223
+ const actual = getProcessStartTime(pid);
224
+ if (!isSameOrOlderProcess(Number(record.startedAt), actual))
225
+ continue;
226
+ }
227
+ roots.push({ pid, kind: match[1] });
228
+ }
229
+ catch { }
230
+ }
231
+ return roots;
232
+ }
233
+ start() {
234
+ // Remove stale socket file (Unix only — named pipes auto-cleanup on process exit)
235
+ if (!isNamedPipe(this.socketPath)) {
236
+ try {
237
+ fs.unlinkSync(this.socketPath);
238
+ }
239
+ catch { }
240
+ }
241
+ return new Promise((resolve, reject) => {
242
+ this.server = net.createServer((conn) => {
243
+ let buf = '';
244
+ conn.on('data', async (data) => {
245
+ buf += data.toString();
246
+ // Simple newline-delimited JSON protocol
247
+ const idx = buf.indexOf('\n');
248
+ if (idx === -1)
249
+ return;
250
+ const line = buf.slice(0, idx);
251
+ buf = buf.slice(idx + 1);
252
+ try {
253
+ const cmd = JSON.parse(line);
254
+ const response = await this.handleCommand(cmd);
255
+ conn.end(JSON.stringify(response) + '\n');
256
+ }
257
+ catch {
258
+ conn.end(JSON.stringify({ error: 'invalid request' }) + '\n');
259
+ }
260
+ });
261
+ conn.on('error', () => { }); // ignore client errors
262
+ });
263
+ const onListenError = (err) => {
264
+ logger.error('[IPC] Server error:', err);
265
+ reject(err);
266
+ };
267
+ this.server.once('error', onListenError);
268
+ this.server.listen(this.socketPath, () => {
269
+ this.server?.off('error', onListenError);
270
+ this.server?.on('error', (err) => {
271
+ logger.error('[IPC] Server error:', err);
272
+ });
273
+ // Restrict to current user (Unix only — named pipes use Windows ACLs)
274
+ if (!isNamedPipe(this.socketPath)) {
275
+ try {
276
+ fs.chmodSync(this.socketPath, 0o600);
277
+ }
278
+ catch { }
279
+ }
280
+ logger.info(`[IPC] Listening on ${this.socketPath}`);
281
+ resolve();
282
+ });
283
+ });
284
+ }
285
+ stop() {
286
+ if (this.server) {
287
+ this.server.close();
288
+ this.server = null;
289
+ }
290
+ if (!isNamedPipe(this.socketPath)) {
291
+ try {
292
+ fs.unlinkSync(this.socketPath);
293
+ }
294
+ catch { }
295
+ }
296
+ }
297
+ async handleCommand(cmd) {
298
+ switch (cmd.type) {
299
+ case 'status':
300
+ return this.getStatus();
301
+ case 'ping':
302
+ return { pong: true, pid: process.pid, protocolVersion: 1 };
303
+ case 'bind.begin': {
304
+ if (!this.bindExecutor)
305
+ return { ok: false, error: 'bind executor not configured' };
306
+ return this.bindExecutor.begin({
307
+ bindType: cmd.bindType,
308
+ targetAid: cmd.targetAid,
309
+ agentName: cmd.agentName,
310
+ ownerMode: cmd.ownerMode,
311
+ ttlMs: cmd.ttlMs,
312
+ });
313
+ }
314
+ case 'bind.status': {
315
+ if (!this.bindExecutor)
316
+ return { ok: false, error: 'bind executor not configured' };
317
+ return this.bindExecutor.status(cmd.taskId);
318
+ }
319
+ case 'bind.cancel': {
320
+ if (!this.bindExecutor)
321
+ return { ok: false, error: 'bind executor not configured' };
322
+ return this.bindExecutor.cancel(cmd.taskId);
323
+ }
324
+ case 'dingtalk.contact-bind.register': {
325
+ if (!this.dingtalkContactBindExecutor) {
326
+ return { ok: false, error: 'dingtalk contact bind executor not configured' };
327
+ }
328
+ return this.dingtalkContactBindExecutor.register({
329
+ selfAid: cmd.selfAid,
330
+ channelName: cmd.channelName,
331
+ primaryId: cmd.primaryId,
332
+ });
333
+ }
334
+ case 'wecom.contact-bind.register': {
335
+ if (!this.wecomContactBindExecutor) {
336
+ return { ok: false, error: 'wecom contact bind executor not configured' };
337
+ }
338
+ return this.wecomContactBindExecutor.register({
339
+ selfAid: cmd.selfAid,
340
+ channelName: cmd.channelName,
341
+ primaryId: cmd.primaryId,
342
+ });
343
+ }
344
+ case 'aun-aids': {
345
+ const aids = this.aunAidProvider ? this.aunAidProvider() : [];
346
+ return { ok: true, aids };
347
+ }
348
+ case 'aun-aid-stats': {
349
+ const stats = this.aunAidStatsProvider ? this.aunAidStatsProvider() : [];
350
+ return { ok: true, stats };
351
+ }
352
+ case 'agent-stats': {
353
+ const stats = this.agentStatsProvider ? this.agentStatsProvider() : [];
354
+ return { ok: true, stats };
355
+ }
356
+ case 'cache-stats': {
357
+ // daemon 统一 FileCache 的只读运行统计(watch web Cache 页用)。
358
+ // 直接读单例,无需 provider 注入(与 manifest-engine 等 import 单例同款)。
359
+ return { ok: true, stats: fileCache.stats() };
360
+ }
361
+ case 'queue-snapshot': {
362
+ if (!cmd.agent)
363
+ return { ok: false, error: 'missing agent' };
364
+ if (!cmd.action) {
365
+ // 纯查询
366
+ if (!this.queueSnapshotProvider)
367
+ return { ok: false, error: 'queue-snapshot not configured' };
368
+ return { ok: true, items: this.queueSnapshotProvider({ agent: cmd.agent }) };
369
+ }
370
+ // 操作:clear / cancel / interrupt
371
+ if (!this.queueActionExecutor)
372
+ return { ok: false, error: 'queue actions not configured' };
373
+ return await this.queueActionExecutor({
374
+ agent: cmd.agent,
375
+ action: cmd.action,
376
+ messageId: cmd.messageId,
377
+ sessionKey: cmd.sessionKey,
378
+ });
379
+ }
380
+ case 'aun-aid-stats-record-outbound': {
381
+ if (!this.aunAidStatsRecorder)
382
+ return { ok: false, error: 'recorder not configured' };
383
+ try {
384
+ this.aunAidStatsRecorder({
385
+ aid: cmd.aid,
386
+ toPeer: cmd.toPeer,
387
+ text: cmd.text ?? '',
388
+ encrypt: cmd.encrypt,
389
+ chatmode: cmd.chatmode,
390
+ });
391
+ return { ok: true };
392
+ }
393
+ catch (e) {
394
+ return { ok: false, error: String(e?.message || e) };
395
+ }
396
+ }
397
+ case 'task-runtime-context': {
398
+ if (!this.taskRuntimeContextProvider)
399
+ return { ok: false, error: 'task runtime context not configured' };
400
+ if (!cmd.sessionId || typeof cmd.sessionId !== 'string')
401
+ return { ok: false, error: 'missing sessionId' };
402
+ const context = this.taskRuntimeContextProvider({ sessionId: cmd.sessionId }) ?? null;
403
+ return { ok: true, context };
404
+ }
405
+ case 'aun-msg-send': {
406
+ if (!this.aunMsgSender)
407
+ return { ok: false, error: 'aun msg sender not configured' };
408
+ if (!cmd.aid || typeof cmd.aid !== 'string')
409
+ return { ok: false, error: 'missing aid' };
410
+ if (!cmd.to || typeof cmd.to !== 'string')
411
+ return { ok: false, error: 'missing to' };
412
+ const payload = cmd.payload && typeof cmd.payload === 'object' && !Array.isArray(cmd.payload)
413
+ ? cmd.payload
414
+ : undefined;
415
+ const rawFile = cmd.file && typeof cmd.file === 'object' && !Array.isArray(cmd.file)
416
+ ? cmd.file
417
+ : undefined;
418
+ const file = typeof rawFile?.filePath === 'string'
419
+ ? {
420
+ filePath: rawFile.filePath,
421
+ as: typeof rawFile.as === 'string' ? rawFile.as : undefined,
422
+ contentType: typeof rawFile.contentType === 'string' ? rawFile.contentType : undefined,
423
+ text: typeof rawFile.text === 'string' ? rawFile.text : undefined,
424
+ transcript: typeof rawFile.transcript === 'string' ? rawFile.transcript : undefined,
425
+ }
426
+ : undefined;
427
+ if ((!payload && !file) || (payload && file)) {
428
+ return { ok: false, error: 'exactly one of payload or file is required' };
429
+ }
430
+ const rawLog = cmd.log && typeof cmd.log === 'object' && !Array.isArray(cmd.log)
431
+ ? cmd.log
432
+ : undefined;
433
+ const log = typeof rawLog?.content === 'string'
434
+ ? {
435
+ content: rawLog.content,
436
+ sessionId: typeof rawLog.sessionId === 'string' ? rawLog.sessionId : undefined,
437
+ threadId: typeof rawLog.threadId === 'string' ? rawLog.threadId : rawLog.threadId === null ? null : undefined,
438
+ msgType: rawLog.msgType,
439
+ payloadType: typeof rawLog.payloadType === 'string' ? rawLog.payloadType : undefined,
440
+ payloadSummary: rawLog.payloadSummary,
441
+ source: rawLog.source,
442
+ }
443
+ : undefined;
444
+ try {
445
+ return await this.aunMsgSender({
446
+ aid: cmd.aid,
447
+ to: cmd.to,
448
+ scope: cmd.scope === 'group' ? 'group' : 'msg',
449
+ payload,
450
+ file,
451
+ mentions: Array.isArray(cmd.mentions)
452
+ ? cmd.mentions.filter((entry) => !!entry && typeof entry === 'object' && !Array.isArray(entry))
453
+ : undefined,
454
+ encrypt: cmd.encrypt === true,
455
+ thread: typeof cmd.thread === 'string' ? cmd.thread : undefined,
456
+ returnPolicy: cmd.returnPolicy === 'required' || cmd.returnPolicy === 'none' ? cmd.returnPolicy : undefined,
457
+ originSessionId: typeof cmd.originSessionId === 'string' ? cmd.originSessionId : undefined,
458
+ originMessageId: typeof cmd.originMessageId === 'string' ? cmd.originMessageId : undefined,
459
+ delegationToken: typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined,
460
+ log,
461
+ });
462
+ }
463
+ catch (e) {
464
+ return { ok: false, error: e?.message || String(e) };
465
+ }
466
+ }
467
+ case 'handoff-return': {
468
+ if (!this.handoffReturnExecutor)
469
+ return { ok: false, error: 'handoff return not configured' };
470
+ if (typeof cmd.content !== 'string')
471
+ return { ok: false, code: 'HANDOFF_RETURN_CONTENT_REQUIRED', error: 'missing content' };
472
+ try {
473
+ return await this.handoffReturnExecutor({
474
+ sessionId: typeof cmd.sessionId === 'string' ? cmd.sessionId : undefined,
475
+ handoffId: typeof cmd.handoffId === 'string' ? cmd.handoffId : undefined,
476
+ content: cmd.content,
477
+ delegationToken: typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined,
478
+ });
479
+ }
480
+ catch (e) {
481
+ return { ok: false, error: e?.message || String(e) };
482
+ }
483
+ }
484
+ case 'handoff-status': {
485
+ if (!this.handoffStatusExecutor)
486
+ return { ok: false, code: 'HANDOFF_STATUS_UNAVAILABLE', error: 'handoff status not configured' };
487
+ if (!cmd.handoffId || typeof cmd.handoffId !== 'string')
488
+ return { ok: false, code: 'INVALID_HANDOFF_ID', error: 'missing handoff_id' };
489
+ return this.handoffStatusExecutor({
490
+ sessionId: typeof cmd.sessionId === 'string' ? cmd.sessionId : undefined,
491
+ handoffId: cmd.handoffId,
492
+ });
493
+ }
494
+ case 'handoff-list': {
495
+ if (!this.handoffListExecutor)
496
+ return { ok: false, code: 'HANDOFF_LIST_UNAVAILABLE', error: 'handoff list not configured' };
497
+ const state = typeof cmd.state === 'string' ? cmd.state : undefined;
498
+ if (state && !HANDOFF_STATES.includes(state)) {
499
+ return { ok: false, code: 'INVALID_HANDOFF_STATE', error: `invalid handoff state: ${state}` };
500
+ }
501
+ const limit = cmd.limit === undefined ? undefined : Number(cmd.limit);
502
+ if (limit !== undefined && (!Number.isInteger(limit) || limit < 1 || limit > HANDOFF_QUERY_MAX_LIMIT)) {
503
+ return { ok: false, code: 'INVALID_HANDOFF_LIMIT', error: `handoff limit must be an integer from 1 to ${HANDOFF_QUERY_MAX_LIMIT}` };
504
+ }
505
+ return this.handoffListExecutor({
506
+ sessionId: typeof cmd.sessionId === 'string' ? cmd.sessionId : undefined,
507
+ agent: typeof cmd.agent === 'string' ? cmd.agent : undefined,
508
+ state: state,
509
+ filterSessionId: typeof cmd.filterSessionId === 'string' ? cmd.filterSessionId : undefined,
510
+ limit,
511
+ });
512
+ }
513
+ case 'handoff-trace': {
514
+ if (!this.handoffTraceExecutor)
515
+ return { ok: false, code: 'HANDOFF_TRACE_UNAVAILABLE', error: 'handoff trace not configured' };
516
+ if (!cmd.handoffId || typeof cmd.handoffId !== 'string') {
517
+ return { ok: false, code: 'INVALID_HANDOFF_ID', error: 'missing handoff_id' };
518
+ }
519
+ const limit = cmd.limit === undefined ? undefined : Number(cmd.limit);
520
+ if (limit !== undefined && (!Number.isInteger(limit) || limit < 1 || limit > HANDOFF_QUERY_MAX_LIMIT)) {
521
+ return { ok: false, code: 'INVALID_HANDOFF_LIMIT', error: `handoff limit must be an integer from 1 to ${HANDOFF_QUERY_MAX_LIMIT}` };
522
+ }
523
+ return this.handoffTraceExecutor({
524
+ sessionId: typeof cmd.sessionId === 'string' ? cmd.sessionId : undefined,
525
+ agent: typeof cmd.agent === 'string' ? cmd.agent : undefined,
526
+ handoffId: cmd.handoffId,
527
+ limit,
528
+ });
529
+ }
530
+ case 'ctl': {
531
+ if (!this.commandExecutor)
532
+ return { ok: false, error: 'ctl not configured' };
533
+ const { cmd: slashCmd, sessionId } = cmd;
534
+ if (!slashCmd || !sessionId)
535
+ return { ok: false, error: 'missing cmd or sessionId' };
536
+ return await this.commandExecutor(slashCmd, sessionId, typeof cmd.delegationToken === 'string' ? cmd.delegationToken : undefined);
537
+ }
538
+ case 'config.op': {
539
+ if (!this.configOperationExecutor)
540
+ return { ok: false, code: 'NOT_CONFIGURED', error: 'config.op not configured' };
541
+ const { argv, sessionId, delegationToken } = cmd;
542
+ if (!Array.isArray(argv) || argv.some(value => typeof value !== 'string') || !sessionId) {
543
+ return { ok: false, code: 'INVALID_REQUEST', error: 'missing argv or sessionId' };
544
+ }
545
+ if (delegationToken !== undefined && typeof delegationToken !== 'string') {
546
+ return { ok: false, code: 'INVALID_DELEGATION', error: 'delegationToken must be a string' };
547
+ }
548
+ return await this.configOperationExecutor(argv, sessionId, delegationToken);
549
+ }
550
+ case 'contact.op': {
551
+ if (!this.contactOperationExecutor)
552
+ return { ok: false, code: 'NOT_CONFIGURED', error: 'contact.op not configured' };
553
+ const { argv, sessionId, delegationToken } = cmd;
554
+ if (!Array.isArray(argv) || argv.some(value => typeof value !== 'string') || !sessionId) {
555
+ return { ok: false, code: 'INVALID_REQUEST', error: 'missing argv or sessionId' };
556
+ }
557
+ if (delegationToken !== undefined && typeof delegationToken !== 'string') {
558
+ return { ok: false, code: 'INVALID_DELEGATION', error: 'delegationToken must be a string' };
559
+ }
560
+ return await this.contactOperationExecutor(argv, sessionId, delegationToken);
561
+ }
562
+ case 'trigger.list':
563
+ case 'trigger.show':
564
+ case 'trigger.history':
565
+ case 'trigger.eventCatalog':
566
+ case 'trigger.create':
567
+ case 'trigger.update':
568
+ case 'trigger.setEnabled':
569
+ case 'trigger.cancel':
570
+ case 'trigger.delete':
571
+ case 'trigger.run': {
572
+ if (!this.triggerExecutor)
573
+ return { ok: false, error: 'trigger executor not configured' };
574
+ try {
575
+ return await this.triggerExecutor(cmd);
576
+ }
577
+ catch (e) {
578
+ return { ok: false, error: e?.message || String(e) };
579
+ }
580
+ }
581
+ case 'evolagent.list': {
582
+ if (!this.agentRegistry)
583
+ return { ok: false, error: 'EvolAgentRegistry not available' };
584
+ return { ok: true, agents: this.agentRegistry.list() };
585
+ }
586
+ case 'evolagent.show': {
587
+ if (!this.agentRegistry)
588
+ return { ok: false, error: 'EvolAgentRegistry not available' };
589
+ const name = cmd.name;
590
+ if (!name || typeof name !== 'string')
591
+ return { ok: false, error: 'missing name' };
592
+ const agent = this.agentRegistry.get(name);
593
+ if (!agent)
594
+ return { ok: false, error: `Agent "${name}" not found` };
595
+ const info = this.agentRegistry.list().find((i) => i.aid === name);
596
+ // I7: null-guard list().find() result
597
+ if (!info)
598
+ return { ok: false, error: `Agent "${name}" found but info missing (race?)` };
599
+ return { ok: true, agent: info };
600
+ }
601
+ case 'evolagent.reload': {
602
+ if (!this.agentRegistry)
603
+ return { ok: false, error: 'EvolAgentRegistry not available' };
604
+ const name = cmd.name;
605
+ if (!name || typeof name !== 'string')
606
+ return { ok: false, error: 'missing name' };
607
+ const hooks = globalThis.__evolcore_reloadHooks;
608
+ if (!hooks)
609
+ return { ok: false, error: 'Reload hooks not initialized' };
610
+ try {
611
+ const a = this.agentRegistry.get(name);
612
+ if (!a)
613
+ return { ok: false, error: `Agent "${name}" not found` };
614
+ if (!this.agentRegistry.reload)
615
+ return { ok: false, error: 'EvolAgentRegistry.reload not available' };
616
+ await this.agentRegistry.reload(name, hooks);
617
+ return { ok: true, result: `Agent "${name}" reloaded` };
618
+ }
619
+ catch (e) {
620
+ return { ok: false, error: e?.message || String(e) };
621
+ }
622
+ }
623
+ case 'evolagent.load': {
624
+ if (!this.agentRegistry)
625
+ return { ok: false, error: 'EvolAgentRegistry not available' };
626
+ const aid = cmd.aid;
627
+ if (!aid || typeof aid !== 'string')
628
+ return { ok: false, error: 'missing aid' };
629
+ const hotLoad = globalThis.__evolcore_hotLoadAgent;
630
+ if (!hotLoad)
631
+ return { ok: false, error: 'Hot-load handler not initialized' };
632
+ try {
633
+ await hotLoad(aid);
634
+ return { ok: true, result: `Agent "${aid}" loaded and online` };
635
+ }
636
+ catch (e) {
637
+ return { ok: false, error: e?.message || String(e) };
638
+ }
639
+ }
640
+ case 'evolagent.resync': {
641
+ if (!this.agentRegistry)
642
+ return { ok: false, error: 'EvolAgentRegistry not available' };
643
+ const resync = globalThis.__evolcore_resyncAgents;
644
+ if (!resync)
645
+ return { ok: false, error: 'Resync handler not initialized' };
646
+ try {
647
+ const results = await resync();
648
+ return { ok: true, results };
649
+ }
650
+ catch (e) {
651
+ return { ok: false, error: e?.message || String(e) };
652
+ }
653
+ }
654
+ case 'menu.exec': {
655
+ if (!this.menuExecutor)
656
+ return { ok: false, error: 'menu.exec not configured' };
657
+ try {
658
+ const response = await this.menuExecutor(cmd.payload, cmd.auth);
659
+ return { ok: true, response };
660
+ }
661
+ catch (e) {
662
+ return { ok: false, error: e?.message ?? String(e) };
663
+ }
664
+ }
665
+ case 'monitor-snapshot': {
666
+ // watch web Monitor 页用:进程级 + 系统级运行指标 + 全局 stats + per-agent 汇总。
667
+ const mem = process.memoryUsage();
668
+ const systemMemory = readSystemMemoryUsage();
669
+ const aids = this.aunAidProvider ? this.aunAidProvider() : [];
670
+ const aidStats = this.aunAidStatsProvider ? this.aunAidStatsProvider() : [];
671
+ const statsMap = new Map(aidStats.map((s) => [s.aid, s]));
672
+ const agentInfos = this.agentRegistry ? this.agentRegistry.list() : [];
673
+ const agentRuntimeStats = this.agentStatsProvider ? this.agentStatsProvider() : [];
674
+ const agentRuntimeStatsMap = new Map(agentRuntimeStats.map((s) => [s.aid, s]));
675
+ const aidStateMap = new Map(aids.map((state) => [state.agentName || state.aid, state]));
676
+ const agentSummary = summarizeMonitorAgents(agentInfos, aids);
677
+ const processTree = this.processTreeSnapshot;
678
+ const processTreeCpu = processTree?.processCount ? processTree.cpuPercent : this.cpuPercent;
679
+ const processTreeRss = processTree?.processCount ? processTree.rss : mem.rss;
680
+ const processTreeDetails = processTree ? {
681
+ ...processTree,
682
+ processes: classifyProcessTree(processTree.processes, process.pid, this.associatedProcessKinds),
683
+ } : {
684
+ rootPid: process.pid,
685
+ rootPids: [process.pid],
686
+ processCount: 1,
687
+ cpuPercent: Math.round(this.cpuPercent * 10) / 10,
688
+ rss: mem.rss,
689
+ processes: [{
690
+ pid: process.pid,
691
+ ppid: process.ppid,
692
+ name: 'evolcore',
693
+ cpuPercent: Math.round(this.cpuPercent * 10) / 10,
694
+ rss: mem.rss,
695
+ kind: 'daemon',
696
+ }],
697
+ };
698
+ return {
699
+ ok: true,
700
+ snapshot: {
701
+ ts: Date.now(),
702
+ uptimeMs: Math.round(process.uptime() * 1000),
703
+ cpuCount: os.cpus().length,
704
+ // 进程级:daemon + 子进程 + 登记在册的关联进程树
705
+ memory: {
706
+ rss: processTreeRss,
707
+ heapUsed: mem.heapUsed,
708
+ heapTotal: mem.heapTotal,
709
+ external: mem.external,
710
+ },
711
+ cpuPercent: processTreeCpu,
712
+ mainProcess: {
713
+ pid: process.pid,
714
+ cpuPercent: Math.round(this.cpuPercent * 10) / 10,
715
+ memory: mem,
716
+ },
717
+ processTree: processTreeDetails,
718
+ // 系统级:整机
719
+ system: {
720
+ ...systemMemory,
721
+ cpuPercent: Math.round(this.sysCpuPercent * 10) / 10,
722
+ loadAvg: os.loadavg(), // [1m, 5m, 15m](Windows 恒 0)
723
+ },
724
+ stats: this.statsProvider ? this.statsProvider() : null,
725
+ agentSummary,
726
+ agents: agentInfos.map((a) => ({
727
+ aid: a.aid,
728
+ agentName: a.name,
729
+ status: a.status,
730
+ connectionStatus: aidStateMap.get(a.aid)?.status ?? (a.status === 'disabled' ? 'disabled' : 'unavailable'),
731
+ online: a.status !== 'disabled' && aidStateMap.get(a.aid)?.status === 'connected',
732
+ stats: statsMap.get(a.aid) ?? null,
733
+ runtimeStats: agentRuntimeStatsMap.get(a.aid) ?? null,
734
+ })),
735
+ },
736
+ };
737
+ }
738
+ default:
739
+ return { error: `unknown command: ${cmd.type}` };
740
+ }
741
+ }
742
+ }
743
+ /**
744
+ * Query the running EvolCore daemon via Unix socket.
745
+ * Returns null if the service is not running or the socket is unreachable.
746
+ */
747
+ export function ipcQuery(socketPath, cmd, timeoutMs = 3000) {
748
+ return new Promise((resolve) => {
749
+ const conn = net.connect(socketPath);
750
+ let buf = '';
751
+ const timer = setTimeout(() => {
752
+ conn.destroy();
753
+ resolve(null);
754
+ }, timeoutMs);
755
+ conn.on('connect', () => {
756
+ conn.write(JSON.stringify(cmd) + '\n');
757
+ });
758
+ conn.on('data', (data) => {
759
+ buf += data.toString();
760
+ const idx = buf.indexOf('\n');
761
+ if (idx !== -1) {
762
+ clearTimeout(timer);
763
+ try {
764
+ resolve(JSON.parse(buf.slice(0, idx)));
765
+ }
766
+ catch {
767
+ resolve(null);
768
+ }
769
+ conn.destroy();
770
+ }
771
+ });
772
+ conn.on('error', () => {
773
+ clearTimeout(timer);
774
+ resolve(null);
775
+ });
776
+ });
777
+ }