evolcore 0.0.4 → 0.0.6

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 (332) hide show
  1. package/CHANGELOG.md +65 -3
  2. package/README.md +4 -12
  3. package/dist/agents/baseagent.js +39 -0
  4. package/dist/agents/claude-runner.js +10 -2
  5. package/dist/agents/codex-runner.js +37 -8
  6. package/dist/agents/ecagent-runner.js +1159 -0
  7. package/dist/agents/gemini-runner.js +4 -1
  8. package/dist/agents/runner-types.js +20 -4
  9. package/dist/aun/msg/history.js +32 -9
  10. package/dist/aun/outbox.js +4 -9
  11. package/dist/channels/aun.js +32 -6
  12. package/dist/channels/daemon.js +7 -4
  13. package/dist/channels/dingtalk.js +3 -5
  14. package/dist/channels/feishu.js +16 -108
  15. package/dist/channels/wechat.js +4 -4
  16. package/dist/channels/wecom.js +4 -6
  17. package/dist/cli/agent-command.js +1 -1
  18. package/dist/cli/agent.js +42 -11
  19. package/dist/cli/aun-commands.js +50 -3
  20. package/dist/cli/daemon-commands.js +127 -21
  21. package/dist/cli/data-command.js +132 -0
  22. package/dist/cli/index.js +11 -3
  23. package/dist/cli/init.js +116 -37
  24. package/dist/cli/net-check.js +9 -20
  25. package/dist/cli/restart-monitor.js +11 -2
  26. package/dist/cli/trigger-command.js +1 -1
  27. package/dist/cli/watch-msg.js +12 -25
  28. package/dist/config/access-policy-domain.js +0 -20
  29. package/dist/config/access-policy.js +5 -29
  30. package/dist/config/builtin-roles.js +3 -1
  31. package/dist/config/config-field-policy.js +1 -1
  32. package/dist/config/gateway-config.js +21 -4
  33. package/dist/config/resolved-config-op.js +10 -0
  34. package/dist/core/auth/operation-catalog.js +1 -1
  35. package/dist/core/command/command-handler.js +2 -2
  36. package/dist/core/command/connect-menu.js +20 -42
  37. package/dist/core/command/menu-handler.js +11 -9
  38. package/dist/core/command/role-menu.js +27 -0
  39. package/dist/core/command/slash-handler.js +18 -14
  40. package/dist/core/data-migration.js +1434 -0
  41. package/dist/core/handoff/store.js +14 -4
  42. package/dist/core/inference/text-inference.js +42 -1
  43. package/dist/core/message/inbound-admission.js +23 -13
  44. package/dist/core/message/pending-hints.js +1 -1
  45. package/dist/core/message/response-engine.js +406 -167
  46. package/dist/core/message/retry-scheduler.js +71 -0
  47. package/dist/core/model/model-catalog.js +7 -2
  48. package/dist/core/model/model-fallback.js +81 -0
  49. package/dist/core/protected-paths.js +41 -8
  50. package/dist/core/session/adapters/ecagent-session-file-adapter.js +112 -0
  51. package/dist/core/session/session-fs-store.js +300 -61
  52. package/dist/core/session/session-manager.js +225 -21
  53. package/dist/core/session/session-title.js +1 -0
  54. package/dist/core/session/session-turn-coordinator.js +8 -1
  55. package/dist/core/system-channels.js +1 -0
  56. package/dist/index.js +10 -9
  57. package/dist/paths.js +35 -27
  58. package/dist/trigger/feedback.js +16 -0
  59. package/dist/trigger/legacy-session-history.js +19 -0
  60. package/dist/trigger/manager.js +12 -1
  61. package/dist/trigger/parser.js +4 -2
  62. package/dist/trigger/scheduler.js +185 -15
  63. package/dist/trigger/session-lock.js +62 -0
  64. package/dist/trigger/state.js +64 -0
  65. package/dist/trigger/validation.js +32 -2
  66. package/dist/utils/aid-bind.js +1 -1
  67. package/dist/utils/cross-platform.js +8 -2
  68. package/dist/utils/error-utils.js +9 -0
  69. package/dist/utils/process-introspect.js +19 -3
  70. package/dist/utils/welcome.js +2 -3
  71. package/ecagent/LICENSE +21 -0
  72. package/ecagent/NOTICE +11 -0
  73. package/ecagent/README.md +61 -0
  74. package/ecagent/dist/agent-loop.d.ts +24 -0
  75. package/ecagent/dist/agent-loop.d.ts.map +1 -0
  76. package/ecagent/dist/agent-loop.js +547 -0
  77. package/ecagent/dist/agent-loop.js.map +1 -0
  78. package/ecagent/dist/agent.d.ts +127 -0
  79. package/ecagent/dist/agent.d.ts.map +1 -0
  80. package/ecagent/dist/agent.js +386 -0
  81. package/ecagent/dist/agent.js.map +1 -0
  82. package/ecagent/dist/harness/agent-harness.d.ts +95 -0
  83. package/ecagent/dist/harness/agent-harness.d.ts.map +1 -0
  84. package/ecagent/dist/harness/agent-harness.js +926 -0
  85. package/ecagent/dist/harness/agent-harness.js.map +1 -0
  86. package/ecagent/dist/harness/compaction/branch-summarization.d.ts +51 -0
  87. package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +1 -0
  88. package/ecagent/dist/harness/compaction/branch-summarization.js +174 -0
  89. package/ecagent/dist/harness/compaction/branch-summarization.js.map +1 -0
  90. package/ecagent/dist/harness/compaction/compaction.d.ts +95 -0
  91. package/ecagent/dist/harness/compaction/compaction.d.ts.map +1 -0
  92. package/ecagent/dist/harness/compaction/compaction.js +528 -0
  93. package/ecagent/dist/harness/compaction/compaction.js.map +1 -0
  94. package/ecagent/dist/harness/compaction/utils.d.ts +25 -0
  95. package/ecagent/dist/harness/compaction/utils.d.ts.map +1 -0
  96. package/ecagent/dist/harness/compaction/utils.js +131 -0
  97. package/ecagent/dist/harness/compaction/utils.js.map +1 -0
  98. package/ecagent/dist/harness/env/nodejs.d.ts +51 -0
  99. package/ecagent/dist/harness/env/nodejs.d.ts.map +1 -0
  100. package/ecagent/dist/harness/env/nodejs.js +513 -0
  101. package/ecagent/dist/harness/env/nodejs.js.map +1 -0
  102. package/ecagent/dist/harness/messages.d.ts +51 -0
  103. package/ecagent/dist/harness/messages.d.ts.map +1 -0
  104. package/ecagent/dist/harness/messages.js +102 -0
  105. package/ecagent/dist/harness/messages.js.map +1 -0
  106. package/ecagent/dist/harness/prompt-templates.d.ts +48 -0
  107. package/ecagent/dist/harness/prompt-templates.d.ts.map +1 -0
  108. package/ecagent/dist/harness/prompt-templates.js +230 -0
  109. package/ecagent/dist/harness/prompt-templates.js.map +1 -0
  110. package/ecagent/dist/harness/session/jsonl-repo.d.ts +26 -0
  111. package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +1 -0
  112. package/ecagent/dist/harness/session/jsonl-repo.js +100 -0
  113. package/ecagent/dist/harness/session/jsonl-repo.js.map +1 -0
  114. package/ecagent/dist/harness/session/jsonl-storage.d.ts +34 -0
  115. package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +1 -0
  116. package/ecagent/dist/harness/session/jsonl-storage.js +234 -0
  117. package/ecagent/dist/harness/session/jsonl-storage.js.map +1 -0
  118. package/ecagent/dist/harness/session/memory-repo.d.ts +18 -0
  119. package/ecagent/dist/harness/session/memory-repo.d.ts.map +1 -0
  120. package/ecagent/dist/harness/session/memory-repo.js +44 -0
  121. package/ecagent/dist/harness/session/memory-repo.js.map +1 -0
  122. package/ecagent/dist/harness/session/memory-storage.d.ts +25 -0
  123. package/ecagent/dist/harness/session/memory-storage.d.ts.map +1 -0
  124. package/ecagent/dist/harness/session/memory-storage.js +111 -0
  125. package/ecagent/dist/harness/session/memory-storage.js.map +1 -0
  126. package/ecagent/dist/harness/session/repo-utils.d.ts +11 -0
  127. package/ecagent/dist/harness/session/repo-utils.d.ts.map +1 -0
  128. package/ecagent/dist/harness/session/repo-utils.js +39 -0
  129. package/ecagent/dist/harness/session/repo-utils.js.map +1 -0
  130. package/ecagent/dist/harness/session/session.d.ts +47 -0
  131. package/ecagent/dist/harness/session/session.d.ts.map +1 -0
  132. package/ecagent/dist/harness/session/session.js +245 -0
  133. package/ecagent/dist/harness/session/session.js.map +1 -0
  134. package/ecagent/dist/harness/session/uuid.d.ts +2 -0
  135. package/ecagent/dist/harness/session/uuid.d.ts.map +1 -0
  136. package/ecagent/dist/harness/session/uuid.js +50 -0
  137. package/ecagent/dist/harness/session/uuid.js.map +1 -0
  138. package/ecagent/dist/harness/skills.d.ts +44 -0
  139. package/ecagent/dist/harness/skills.d.ts.map +1 -0
  140. package/ecagent/dist/harness/skills.js +311 -0
  141. package/ecagent/dist/harness/skills.js.map +1 -0
  142. package/ecagent/dist/harness/system-prompt.d.ts +3 -0
  143. package/ecagent/dist/harness/system-prompt.d.ts.map +1 -0
  144. package/ecagent/dist/harness/system-prompt.js +30 -0
  145. package/ecagent/dist/harness/system-prompt.js.map +1 -0
  146. package/ecagent/dist/harness/types.d.ts +619 -0
  147. package/ecagent/dist/harness/types.d.ts.map +1 -0
  148. package/ecagent/dist/harness/types.js +81 -0
  149. package/ecagent/dist/harness/types.js.map +1 -0
  150. package/ecagent/dist/harness/utils/shell-output.d.ts +14 -0
  151. package/ecagent/dist/harness/utils/shell-output.d.ts.map +1 -0
  152. package/ecagent/dist/harness/utils/shell-output.js +126 -0
  153. package/ecagent/dist/harness/utils/shell-output.js.map +1 -0
  154. package/ecagent/dist/harness/utils/truncate.d.ts +70 -0
  155. package/ecagent/dist/harness/utils/truncate.d.ts.map +1 -0
  156. package/ecagent/dist/harness/utils/truncate.js +290 -0
  157. package/ecagent/dist/harness/utils/truncate.js.map +1 -0
  158. package/ecagent/dist/index.d.ts +22 -0
  159. package/ecagent/dist/index.d.ts.map +1 -0
  160. package/ecagent/dist/index.js +27 -0
  161. package/ecagent/dist/index.js.map +1 -0
  162. package/ecagent/dist/node.d.ts +3 -0
  163. package/ecagent/dist/node.d.ts.map +1 -0
  164. package/ecagent/dist/node.js +3 -0
  165. package/ecagent/dist/node.js.map +1 -0
  166. package/ecagent/dist/proxy.d.ts +69 -0
  167. package/ecagent/dist/proxy.d.ts.map +1 -0
  168. package/ecagent/dist/proxy.js +278 -0
  169. package/ecagent/dist/proxy.js.map +1 -0
  170. package/ecagent/dist/runtime/api/lazy.d.ts +15 -0
  171. package/ecagent/dist/runtime/api/lazy.d.ts.map +1 -0
  172. package/ecagent/dist/runtime/api/lazy.js +59 -0
  173. package/ecagent/dist/runtime/api/lazy.js.map +1 -0
  174. package/ecagent/dist/runtime/api/pi-messages.d.ts +97 -0
  175. package/ecagent/dist/runtime/api/pi-messages.d.ts.map +1 -0
  176. package/ecagent/dist/runtime/api/pi-messages.js +307 -0
  177. package/ecagent/dist/runtime/api/pi-messages.js.map +1 -0
  178. package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts +3 -0
  179. package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +1 -0
  180. package/ecagent/dist/runtime/api/pi-messages.lazy.js +3 -0
  181. package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +1 -0
  182. package/ecagent/dist/runtime/auth/context.d.ts +7 -0
  183. package/ecagent/dist/runtime/auth/context.d.ts.map +1 -0
  184. package/ecagent/dist/runtime/auth/context.js +42 -0
  185. package/ecagent/dist/runtime/auth/context.js.map +1 -0
  186. package/ecagent/dist/runtime/auth/credential-store.d.ts +16 -0
  187. package/ecagent/dist/runtime/auth/credential-store.d.ts.map +1 -0
  188. package/ecagent/dist/runtime/auth/credential-store.js +39 -0
  189. package/ecagent/dist/runtime/auth/credential-store.js.map +1 -0
  190. package/ecagent/dist/runtime/auth/helpers.d.ts +20 -0
  191. package/ecagent/dist/runtime/auth/helpers.d.ts.map +1 -0
  192. package/ecagent/dist/runtime/auth/helpers.js +46 -0
  193. package/ecagent/dist/runtime/auth/helpers.js.map +1 -0
  194. package/ecagent/dist/runtime/auth/resolve.d.ts +26 -0
  195. package/ecagent/dist/runtime/auth/resolve.d.ts.map +1 -0
  196. package/ecagent/dist/runtime/auth/resolve.js +100 -0
  197. package/ecagent/dist/runtime/auth/resolve.js.map +1 -0
  198. package/ecagent/dist/runtime/auth/types.d.ts +180 -0
  199. package/ecagent/dist/runtime/auth/types.d.ts.map +1 -0
  200. package/ecagent/dist/runtime/auth/types.js +2 -0
  201. package/ecagent/dist/runtime/auth/types.js.map +1 -0
  202. package/ecagent/dist/runtime/compat.d.ts +28 -0
  203. package/ecagent/dist/runtime/compat.d.ts.map +1 -0
  204. package/ecagent/dist/runtime/compat.js +86 -0
  205. package/ecagent/dist/runtime/compat.js.map +1 -0
  206. package/ecagent/dist/runtime/index.d.ts +20 -0
  207. package/ecagent/dist/runtime/index.d.ts.map +1 -0
  208. package/ecagent/dist/runtime/index.js +17 -0
  209. package/ecagent/dist/runtime/index.js.map +1 -0
  210. package/ecagent/dist/runtime/models.d.ts +142 -0
  211. package/ecagent/dist/runtime/models.d.ts.map +1 -0
  212. package/ecagent/dist/runtime/models.js +245 -0
  213. package/ecagent/dist/runtime/models.js.map +1 -0
  214. package/ecagent/dist/runtime/oauth.d.ts +2 -0
  215. package/ecagent/dist/runtime/oauth.d.ts.map +1 -0
  216. package/ecagent/dist/runtime/oauth.js +2 -0
  217. package/ecagent/dist/runtime/oauth.js.map +1 -0
  218. package/ecagent/dist/runtime/providers/faux.d.ts +97 -0
  219. package/ecagent/dist/runtime/providers/faux.d.ts.map +1 -0
  220. package/ecagent/dist/runtime/providers/faux.js +395 -0
  221. package/ecagent/dist/runtime/providers/faux.js.map +1 -0
  222. package/ecagent/dist/runtime/types.d.ts +607 -0
  223. package/ecagent/dist/runtime/types.d.ts.map +1 -0
  224. package/ecagent/dist/runtime/types.js +2 -0
  225. package/ecagent/dist/runtime/types.js.map +1 -0
  226. package/ecagent/dist/runtime/utils/diagnostics.d.ts +19 -0
  227. package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +1 -0
  228. package/ecagent/dist/runtime/utils/diagnostics.js +25 -0
  229. package/ecagent/dist/runtime/utils/diagnostics.js.map +1 -0
  230. package/ecagent/dist/runtime/utils/event-stream.d.ts +21 -0
  231. package/ecagent/dist/runtime/utils/event-stream.d.ts.map +1 -0
  232. package/ecagent/dist/runtime/utils/event-stream.js +77 -0
  233. package/ecagent/dist/runtime/utils/event-stream.js.map +1 -0
  234. package/ecagent/dist/runtime/utils/headers.d.ts +4 -0
  235. package/ecagent/dist/runtime/utils/headers.d.ts.map +1 -0
  236. package/ecagent/dist/runtime/utils/headers.js +18 -0
  237. package/ecagent/dist/runtime/utils/headers.js.map +1 -0
  238. package/ecagent/dist/runtime/utils/json-parse.d.ts +16 -0
  239. package/ecagent/dist/runtime/utils/json-parse.d.ts.map +1 -0
  240. package/ecagent/dist/runtime/utils/json-parse.js +113 -0
  241. package/ecagent/dist/runtime/utils/json-parse.js.map +1 -0
  242. package/ecagent/dist/runtime/utils/oauth/types.d.ts +64 -0
  243. package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +1 -0
  244. package/ecagent/dist/runtime/utils/oauth/types.js +2 -0
  245. package/ecagent/dist/runtime/utils/oauth/types.js.map +1 -0
  246. package/ecagent/dist/runtime/utils/overflow.d.ts +58 -0
  247. package/ecagent/dist/runtime/utils/overflow.d.ts.map +1 -0
  248. package/ecagent/dist/runtime/utils/overflow.js +158 -0
  249. package/ecagent/dist/runtime/utils/overflow.js.map +1 -0
  250. package/ecagent/dist/runtime/utils/provider-env.d.ts +7 -0
  251. package/ecagent/dist/runtime/utils/provider-env.d.ts.map +1 -0
  252. package/ecagent/dist/runtime/utils/provider-env.js +44 -0
  253. package/ecagent/dist/runtime/utils/provider-env.js.map +1 -0
  254. package/ecagent/dist/runtime/utils/retry.d.ts +12 -0
  255. package/ecagent/dist/runtime/utils/retry.d.ts.map +1 -0
  256. package/ecagent/dist/runtime/utils/retry.js +90 -0
  257. package/ecagent/dist/runtime/utils/retry.js.map +1 -0
  258. package/ecagent/dist/runtime/utils/typebox-helpers.d.ts +17 -0
  259. package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +1 -0
  260. package/ecagent/dist/runtime/utils/typebox-helpers.js +21 -0
  261. package/ecagent/dist/runtime/utils/typebox-helpers.js.map +1 -0
  262. package/ecagent/dist/runtime/utils/validation.d.ts +18 -0
  263. package/ecagent/dist/runtime/utils/validation.d.ts.map +1 -0
  264. package/ecagent/dist/runtime/utils/validation.js +269 -0
  265. package/ecagent/dist/runtime/utils/validation.js.map +1 -0
  266. package/ecagent/dist/types.d.ts +401 -0
  267. package/ecagent/dist/types.d.ts.map +1 -0
  268. package/ecagent/dist/types.js +2 -0
  269. package/ecagent/dist/types.js.map +1 -0
  270. package/ecagent/package.json +93 -0
  271. package/ecagent/src/agent-loop.ts +792 -0
  272. package/ecagent/src/agent.ts +575 -0
  273. package/ecagent/src/harness/agent-harness.ts +1029 -0
  274. package/ecagent/src/harness/compaction/branch-summarization.ts +261 -0
  275. package/ecagent/src/harness/compaction/compaction.ts +753 -0
  276. package/ecagent/src/harness/compaction/utils.ts +144 -0
  277. package/ecagent/src/harness/env/nodejs.ts +569 -0
  278. package/ecagent/src/harness/messages.ts +164 -0
  279. package/ecagent/src/harness/prompt-templates.ts +267 -0
  280. package/ecagent/src/harness/session/jsonl-repo.ts +179 -0
  281. package/ecagent/src/harness/session/jsonl-storage.ts +314 -0
  282. package/ecagent/src/harness/session/memory-repo.ts +50 -0
  283. package/ecagent/src/harness/session/memory-storage.ts +133 -0
  284. package/ecagent/src/harness/session/repo-utils.ts +51 -0
  285. package/ecagent/src/harness/session/session.ts +338 -0
  286. package/ecagent/src/harness/session/uuid.ts +54 -0
  287. package/ecagent/src/harness/skills.ts +375 -0
  288. package/ecagent/src/harness/system-prompt.ts +34 -0
  289. package/ecagent/src/harness/types.ts +838 -0
  290. package/ecagent/src/harness/utils/shell-output.ts +135 -0
  291. package/ecagent/src/harness/utils/truncate.ts +344 -0
  292. package/ecagent/src/index.ts +46 -0
  293. package/ecagent/src/node.ts +2 -0
  294. package/ecagent/src/proxy.ts +367 -0
  295. package/ecagent/src/runtime/api/lazy.ts +70 -0
  296. package/ecagent/src/runtime/api/pi-messages.lazy.ts +4 -0
  297. package/ecagent/src/runtime/api/pi-messages.ts +436 -0
  298. package/ecagent/src/runtime/auth/context.ts +45 -0
  299. package/ecagent/src/runtime/auth/credential-store.ts +47 -0
  300. package/ecagent/src/runtime/auth/helpers.ts +46 -0
  301. package/ecagent/src/runtime/auth/resolve.ts +141 -0
  302. package/ecagent/src/runtime/auth/types.ts +182 -0
  303. package/ecagent/src/runtime/compat.ts +158 -0
  304. package/ecagent/src/runtime/index.ts +31 -0
  305. package/ecagent/src/runtime/models.ts +452 -0
  306. package/ecagent/src/runtime/oauth.ts +1 -0
  307. package/ecagent/src/runtime/providers/faux.ts +538 -0
  308. package/ecagent/src/runtime/types.ts +718 -0
  309. package/ecagent/src/runtime/utils/diagnostics.ts +45 -0
  310. package/ecagent/src/runtime/utils/event-stream.ts +88 -0
  311. package/ecagent/src/runtime/utils/headers.ts +18 -0
  312. package/ecagent/src/runtime/utils/json-parse.ts +124 -0
  313. package/ecagent/src/runtime/utils/oauth/types.ts +79 -0
  314. package/ecagent/src/runtime/utils/overflow.ts +165 -0
  315. package/ecagent/src/runtime/utils/provider-env.ts +52 -0
  316. package/ecagent/src/runtime/utils/retry.ts +101 -0
  317. package/ecagent/src/runtime/utils/typebox-helpers.ts +24 -0
  318. package/ecagent/src/runtime/utils/validation.ts +310 -0
  319. package/ecagent/src/types.ts +430 -0
  320. package/ecagent/tsconfig.build.json +32 -0
  321. package/kits/docs/evolcore/config.md +4 -4
  322. package/kits/docs/evolcore/contact.md +2 -1
  323. package/kits/schemas/_meta.json +7 -4
  324. package/kits/schemas/agent-config.schema.10.json +370 -0
  325. package/kits/schemas/agent-config.schema.9.json +2 -12
  326. package/kits/schemas/defaults.schema.4.json +93 -0
  327. package/kits/schemas/relation-config.schema.8.json +69 -0
  328. package/kits/templates/roles/admin.json +1 -1
  329. package/package.json +22 -6
  330. package/skills/eclink/SKILL.md +70 -0
  331. package/skills/eclink/agents/openai.yaml +4 -0
  332. package/assets/.env.template +0 -4
@@ -1,7 +1,7 @@
1
1
  import { ensureDir } from '../../utils/atomic-write.js';
2
2
  import { logger } from '../../utils/logger.js';
3
3
  import { encodePath } from '../../utils/cross-platform.js';
4
- import { chatDirPath, generateSessionId, formatTimestamp, atomicWriteJson, appendJsonl, readJsonFile, readLastJsonlLine, readAllJsonlLines, scanChatDirs, scanMetaFiles, ensureChatDir, readThreadIndex, writeThreadIndex, } from './session-fs-store.js';
4
+ import { chatDirPath, generateSessionId, formatTimestamp, atomicWriteJson, atomicWriteText, appendJsonl, readJsonFile, readLastJsonlLine, readAllJsonlLines, scanChatDirs, scanMetaFiles, ensureChatDir, readThreadIndex, writeThreadIndex, } from './session-fs-store.js';
5
5
  import { sessionToFile, fileToSession } from './session-mapper.js';
6
6
  import { formatSessionKey, DEFAULT_THREAD_ID } from './session-key.js';
7
7
  import { tryParseChannelKey } from '../channel-loader.js';
@@ -38,8 +38,6 @@ export class SessionManager {
38
38
  this.sessionsDir = sessionsDir;
39
39
  this.eventBus = eventBus;
40
40
  this.identityResolver = identityResolver;
41
- this.migrateChannelKeyFormat();
42
- this.migrateWecomChannelDirs();
43
41
  }
44
42
  setIdentityResolver(resolver) {
45
43
  this.identityResolver = resolver;
@@ -378,7 +376,7 @@ export class SessionManager {
378
376
  logger.error(`[SessionManager] validateSessionFile: no adapter for baseagent=${session.baseagent}, session=${session.id}`);
379
377
  return agentSessionId;
380
378
  }
381
- if (adapter.checkExists(session.projectPath, agentSessionId))
379
+ if (adapter.checkExists(session.projectPath, agentSessionId, session.selfAID))
382
380
  return agentSessionId;
383
381
  logger.warn(`Session file not found for ${session.baseagent}: ${agentSessionId}, clearing session ID`);
384
382
  session.agentSessionId = undefined;
@@ -1315,16 +1313,16 @@ export class SessionManager {
1315
1313
  });
1316
1314
  return session;
1317
1315
  }
1318
- async scanCliSessions(projectPath, baseagent, limit = 10) {
1316
+ async scanCliSessions(projectPath, baseagent, limit = 10, agentAid) {
1319
1317
  const adapter = this.getFileAdapter(baseagent);
1320
1318
  if (!adapter)
1321
1319
  return [];
1322
- return adapter.scanCliSessions(projectPath, limit);
1320
+ return adapter.scanCliSessions(projectPath, limit, agentAid);
1323
1321
  }
1324
- async listImportableCliSessions(projectPath, baseagent) {
1322
+ async listImportableCliSessions(projectPath, baseagent, agentAid) {
1325
1323
  const boundSessionIds = this.listBoundAgentSessionIds(projectPath, baseagent);
1326
1324
  const displayLimit = 10;
1327
- const cliSessions = await this.scanCliSessions(projectPath, baseagent, boundSessionIds.size + displayLimit);
1325
+ const cliSessions = await this.scanCliSessions(projectPath, baseagent, boundSessionIds.size + displayLimit, agentAid);
1328
1326
  return cliSessions
1329
1327
  .filter(session => !boundSessionIds.has(session.uuid))
1330
1328
  .slice(0, displayLimit);
@@ -1343,25 +1341,25 @@ export class SessionManager {
1343
1341
  }
1344
1342
  return sessionIds;
1345
1343
  }
1346
- checkSessionFileExists(projectPath, agentSessionId, baseagent) {
1344
+ checkSessionFileExists(projectPath, agentSessionId, baseagent, agentAid) {
1347
1345
  const adapter = this.getFileAdapter(baseagent);
1348
1346
  if (!adapter)
1349
1347
  return false;
1350
- return adapter.checkExists(projectPath, agentSessionId);
1348
+ return adapter.checkExists(projectPath, agentSessionId, agentAid);
1351
1349
  }
1352
- readSessionFirstMessage(projectPath, agentSessionId, baseagent) {
1350
+ readSessionFirstMessage(projectPath, agentSessionId, baseagent, agentAid) {
1353
1351
  const adapter = this.getFileAdapter(baseagent);
1354
1352
  if (!adapter)
1355
1353
  return null;
1356
- return adapter.readFirstMessage(projectPath, agentSessionId);
1354
+ return adapter.readFirstMessage(projectPath, agentSessionId, agentAid);
1357
1355
  }
1358
- readSessionLastUserMessage(projectPath, agentSessionId, baseagent) {
1356
+ readSessionLastUserMessage(projectPath, agentSessionId, baseagent, agentAid) {
1359
1357
  const adapter = this.getFileAdapter(baseagent);
1360
1358
  if (!adapter)
1361
1359
  return null;
1362
- return adapter.readLastUserMessage(projectPath, agentSessionId);
1360
+ return adapter.readLastUserMessage(projectPath, agentSessionId, agentAid);
1363
1361
  }
1364
- getSessionFileInfo(projectPath, agentSessionId, baseagent) {
1362
+ getSessionFileInfo(projectPath, agentSessionId, baseagent, agentAid) {
1365
1363
  if (!baseagent) {
1366
1364
  logger.error(`[SessionManager] getSessionFileInfo: baseagent is empty, returning turns=0. agentSessionId=${agentSessionId}`);
1367
1365
  return { turns: 0 };
@@ -1371,13 +1369,13 @@ export class SessionManager {
1371
1369
  logger.error(`[SessionManager] getSessionFileInfo: no adapter for baseagent=${baseagent}, returning turns=0`);
1372
1370
  return { turns: 0 };
1373
1371
  }
1374
- return adapter.getFileInfo(projectPath, agentSessionId);
1372
+ return adapter.getFileInfo(projectPath, agentSessionId, agentAid);
1375
1373
  }
1376
- async listSdkSessions(projectPath, baseagent) {
1374
+ async listSdkSessions(projectPath, baseagent, agentAid) {
1377
1375
  const adapter = this.getFileAdapter(baseagent);
1378
1376
  if (!adapter?.listSdkSessions)
1379
1377
  return [];
1380
- return adapter.listSdkSessions(projectPath);
1378
+ return adapter.listSdkSessions(projectPath, agentAid);
1381
1379
  }
1382
1380
  async getSessionByUuidPrefix(channel, channelId, uuidPrefix) {
1383
1381
  const chatDir = this.resolveChatDirSafe(channel, channelId);
@@ -1390,15 +1388,16 @@ export class SessionManager {
1390
1388
  }
1391
1389
  return matched[0];
1392
1390
  }
1393
- async importCliSession(channel, channelId, projectPath, agentSessionId, baseagent = 'claude') {
1391
+ async importCliSession(channel, channelId, projectPath, agentSessionId, baseagent = 'claude', agentAid) {
1394
1392
  const inheritedChatType = this.getActiveChatType(channel, channelId);
1395
- const fileInfo = this.getSessionFileInfo(projectPath, agentSessionId, baseagent);
1393
+ const resolvedAgentAid = agentAid || this.deriveChannelIdentity(channel, channelId).selfAID;
1394
+ const fileInfo = this.getSessionFileInfo(projectPath, agentSessionId, baseagent, resolvedAgentAid);
1396
1395
  const name = fileInfo.title || `CLI会话-${new Date().toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}`;
1397
1396
  // Derive selfAID and channelType from existing sessions
1398
1397
  const existingDir = this.findExistingChatDir(channel, channelId);
1399
1398
  const identity = this.deriveChannelIdentity(channel, channelId);
1400
1399
  let channelType = identity.channelType;
1401
- let selfAID = identity.selfAID;
1400
+ let selfAID = identity.selfAID || resolvedAgentAid || '';
1402
1401
  if (existingDir) {
1403
1402
  const active = readJsonFile(path.join(existingDir, 'active.json'));
1404
1403
  if (active) {
@@ -1662,4 +1661,209 @@ export class SessionManager {
1662
1661
  logger.info(`[SessionManager] Migrated ${migrated} WeCom session director${migrated === 1 ? 'y' : 'ies'} to channelKey isolation`);
1663
1662
  }
1664
1663
  }
1664
+ /**
1665
+ * Recover legacy AUN chats written beneath `_unknown` before selfAID was
1666
+ * persisted. A channel key or persisted selfAID is required to make the
1667
+ * migration unambiguous; all other directories remain untouched.
1668
+ */
1669
+ migrateUnknownAunDirs() {
1670
+ const legacyDirs = scanChatDirs(this.sessionsDir)
1671
+ .filter(entry => entry.channelType === 'aun' && entry.selfAID === '_unknown');
1672
+ let migrated = 0;
1673
+ for (const entry of legacyDirs) {
1674
+ const selfAIDs = this.findAunSelfAIDCandidates(entry.dirPath);
1675
+ if (selfAIDs.size !== 1) {
1676
+ if (selfAIDs.size > 1) {
1677
+ logger.error(`[SessionManager] Cannot auto-migrate mixed unknown AUN session directory: ${entry.dirPath}`);
1678
+ }
1679
+ continue;
1680
+ }
1681
+ const selfAID = [...selfAIDs][0];
1682
+ const target = chatDirPath(this.sessionsDir, 'aun', entry.channelId, selfAID);
1683
+ try {
1684
+ this.mergeUnknownAunDirectory(entry.dirPath, target, selfAID);
1685
+ migrated++;
1686
+ }
1687
+ catch (error) {
1688
+ logger.error(`[SessionManager] Failed to migrate unknown AUN session directory ${entry.dirPath}: ${String(error)}`);
1689
+ }
1690
+ }
1691
+ if (migrated > 0) {
1692
+ logger.info(`[SessionManager] Migrated ${migrated} unknown AUN session director${migrated === 1 ? 'y' : 'ies'} to selfAID isolation`);
1693
+ }
1694
+ }
1695
+ findAunSelfAIDCandidates(chatDir) {
1696
+ const candidates = new Set();
1697
+ const visitRecord = (record) => {
1698
+ if (!record || typeof record !== 'object')
1699
+ return;
1700
+ const session = record;
1701
+ const direct = typeof session.selfAID === 'string' ? session.selfAID.trim() : '';
1702
+ if (direct && direct !== '_unknown')
1703
+ candidates.add(direct);
1704
+ const channel = typeof session.channel === 'string' ? tryParseChannelKey(session.channel) : null;
1705
+ if (channel?.type === 'aun' && channel.selfAID !== '_unknown')
1706
+ candidates.add(channel.selfAID);
1707
+ };
1708
+ const visitJsonl = (filePath) => {
1709
+ for (const record of readAllJsonlLines(filePath))
1710
+ visitRecord(record);
1711
+ };
1712
+ visitRecord(readJsonFile(path.join(chatDir, 'active.json')));
1713
+ for (const metaFile of scanMetaFiles(chatDir))
1714
+ visitJsonl(path.join(chatDir, metaFile));
1715
+ const threadDir = path.join(chatDir, '_threads');
1716
+ for (const metaFile of scanMetaFiles(threadDir))
1717
+ visitJsonl(path.join(threadDir, metaFile));
1718
+ return candidates;
1719
+ }
1720
+ mergeUnknownAunDirectory(sourceDir, targetDir, selfAID) {
1721
+ if (sourceDir === targetDir)
1722
+ return;
1723
+ fs.mkdirSync(targetDir, { recursive: true });
1724
+ this.mergeUnknownAunDirectoryContents(sourceDir, targetDir, selfAID);
1725
+ fs.rmdirSync(sourceDir);
1726
+ }
1727
+ mergeUnknownAunDirectoryContents(sourceDir, targetDir, selfAID) {
1728
+ for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
1729
+ const sourcePath = path.join(sourceDir, entry.name);
1730
+ const targetPath = path.join(targetDir, entry.name);
1731
+ if (entry.isDirectory()) {
1732
+ fs.mkdirSync(targetPath, { recursive: true });
1733
+ this.mergeUnknownAunDirectoryContents(sourcePath, targetPath, selfAID);
1734
+ fs.rmdirSync(sourcePath);
1735
+ continue;
1736
+ }
1737
+ if (!entry.isFile())
1738
+ continue;
1739
+ if (entry.name === 'active.json') {
1740
+ this.mergeUnknownAunActiveFile(sourcePath, targetPath, selfAID);
1741
+ }
1742
+ else if (entry.name.endsWith('.jsonl')) {
1743
+ this.mergeUnknownAunJsonlFile(sourcePath, targetPath, selfAID);
1744
+ }
1745
+ else if (entry.name.endsWith('.json')) {
1746
+ this.mergeUnknownAunJsonFile(sourcePath, targetPath);
1747
+ }
1748
+ else if (!fs.existsSync(targetPath)) {
1749
+ fs.renameSync(sourcePath, targetPath);
1750
+ }
1751
+ else if (fs.readFileSync(sourcePath).equals(fs.readFileSync(targetPath))) {
1752
+ fs.unlinkSync(sourcePath);
1753
+ }
1754
+ else {
1755
+ fs.renameSync(sourcePath, this.uniqueLegacyFilePath(targetPath));
1756
+ }
1757
+ }
1758
+ }
1759
+ mergeUnknownAunActiveFile(sourcePath, targetPath, selfAID) {
1760
+ const source = this.normalizeAunSessionRecord(readJsonFile(sourcePath), selfAID);
1761
+ const target = this.normalizeAunSessionRecord(readJsonFile(targetPath), selfAID);
1762
+ const sourceUpdatedAt = typeof source?.updatedAt === 'number' ? source.updatedAt : 0;
1763
+ const targetUpdatedAt = typeof target?.updatedAt === 'number' ? target.updatedAt : 0;
1764
+ const selected = target && targetUpdatedAt >= sourceUpdatedAt ? target : source;
1765
+ if (selected)
1766
+ atomicWriteJson(targetPath, selected);
1767
+ fs.unlinkSync(sourcePath);
1768
+ }
1769
+ mergeUnknownAunJsonlFile(sourcePath, targetPath, selfAID) {
1770
+ const records = [
1771
+ ...this.readNormalizedAunJsonl(sourcePath, selfAID),
1772
+ ...this.readNormalizedAunJsonl(targetPath, selfAID),
1773
+ ];
1774
+ const seen = new Set();
1775
+ const unique = records.filter(record => {
1776
+ if (seen.has(record.key))
1777
+ return false;
1778
+ seen.add(record.key);
1779
+ return true;
1780
+ });
1781
+ unique.sort((left, right) => left.timestamp - right.timestamp || left.order - right.order);
1782
+ atomicWriteText(targetPath, unique.map(record => record.line).join('\n') + (unique.length ? '\n' : ''));
1783
+ fs.unlinkSync(sourcePath);
1784
+ }
1785
+ readNormalizedAunJsonl(filePath, selfAID) {
1786
+ let content;
1787
+ try {
1788
+ content = fs.readFileSync(filePath, 'utf-8');
1789
+ }
1790
+ catch (error) {
1791
+ if (error?.code === 'ENOENT')
1792
+ return [];
1793
+ throw error;
1794
+ }
1795
+ return content.split('\n').flatMap((rawLine, order) => {
1796
+ const line = rawLine.trim();
1797
+ if (!line)
1798
+ return [];
1799
+ try {
1800
+ const record = this.normalizeAunSessionRecord(JSON.parse(line), selfAID);
1801
+ const normalizedLine = JSON.stringify(record);
1802
+ return [{
1803
+ key: this.stableJson(record),
1804
+ line: normalizedLine,
1805
+ timestamp: this.recordTimestamp(record),
1806
+ order,
1807
+ }];
1808
+ }
1809
+ catch {
1810
+ return [{ key: `raw:${line}`, line, timestamp: Number.MAX_SAFE_INTEGER, order }];
1811
+ }
1812
+ });
1813
+ }
1814
+ normalizeAunSessionRecord(record, selfAID) {
1815
+ if (!record || typeof record !== 'object' || Array.isArray(record))
1816
+ return record;
1817
+ const result = { ...record };
1818
+ const isSessionRecord = 'channel' in result || 'channelType' in result || 'sessionKey' in result || 'selfAID' in result;
1819
+ if (!isSessionRecord)
1820
+ return result;
1821
+ if (!result.selfAID || result.selfAID === '_unknown')
1822
+ result.selfAID = selfAID;
1823
+ return result;
1824
+ }
1825
+ stableJson(value) {
1826
+ if (Array.isArray(value))
1827
+ return `[${value.map(item => this.stableJson(item)).join(',')}]`;
1828
+ if (value && typeof value === 'object') {
1829
+ return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${this.stableJson(value[key])}`).join(',')}}`;
1830
+ }
1831
+ return JSON.stringify(value);
1832
+ }
1833
+ recordTimestamp(record) {
1834
+ if (!record || typeof record !== 'object')
1835
+ return Number.MAX_SAFE_INTEGER;
1836
+ const value = record;
1837
+ for (const key of ['ts', 'at', 'updatedAt', 'createdAt']) {
1838
+ if (typeof value[key] === 'number' && Number.isFinite(value[key]))
1839
+ return value[key];
1840
+ }
1841
+ return Number.MAX_SAFE_INTEGER;
1842
+ }
1843
+ mergeUnknownAunJsonFile(sourcePath, targetPath) {
1844
+ if (!fs.existsSync(targetPath)) {
1845
+ fs.renameSync(sourcePath, targetPath);
1846
+ return;
1847
+ }
1848
+ const source = readJsonFile(sourcePath);
1849
+ const target = readJsonFile(targetPath);
1850
+ if (source && target && !Array.isArray(source) && !Array.isArray(target)) {
1851
+ atomicWriteJson(targetPath, { ...source, ...target });
1852
+ fs.unlinkSync(sourcePath);
1853
+ return;
1854
+ }
1855
+ if (fs.readFileSync(sourcePath).equals(fs.readFileSync(targetPath))) {
1856
+ fs.unlinkSync(sourcePath);
1857
+ return;
1858
+ }
1859
+ fs.renameSync(sourcePath, this.uniqueLegacyFilePath(targetPath));
1860
+ }
1861
+ uniqueLegacyFilePath(targetPath) {
1862
+ let index = 1;
1863
+ let candidate = `${targetPath}.legacy-unknown`;
1864
+ while (fs.existsSync(candidate)) {
1865
+ candidate = `${targetPath}.legacy-unknown-${index++}`;
1866
+ }
1867
+ return candidate;
1868
+ }
1665
1869
  }
@@ -30,6 +30,7 @@ const BACKEND_SYNTHETIC_CLI_PROMPT_PREFIXES = {
30
30
  ],
31
31
  codex: [],
32
32
  gemini: [],
33
+ ecagent: [],
33
34
  };
34
35
  // Claude Code 斜杠命令 / skill / hook 注入的脚手架,经真实会话数据核对,形态包括:
35
36
  // - <local-command-caveat> / <local-command-stdout> / <local-command-stderr> 等 local-command 标签族
@@ -142,9 +142,16 @@ export class SessionTurnCoordinator {
142
142
  if (evidence.openToolUseIds.length > 0)
143
143
  return { ok: false, reason: 'tool_open' };
144
144
  const madeProgress = evidence.textCount > 0 || evidence.toolUseCount > 0 || !!evidence.resultText?.trim();
145
- if (!evidence.inputAccepted && !madeProgress)
145
+ // Not every runner can emit input_accepted. Token usage is equally strong
146
+ // evidence that the upstream model consumed the input, even for a silent result.
147
+ const inputConsumed = evidence.inputAccepted
148
+ || evidence.hasTokenUsage === true
149
+ || evidence.inputTokens > 0
150
+ || evidence.outputTokens > 0;
151
+ if (!inputConsumed && !madeProgress)
146
152
  return { ok: false, reason: 'input_not_consumed' };
147
153
  const emptySuccess = !evidence.explicitNoop
154
+ && !evidence.hasTokenUsage
148
155
  && evidence.inputTokens === 0
149
156
  && evidence.outputTokens === 0
150
157
  && !madeProgress;
@@ -14,6 +14,7 @@ export function isSystemControlChannel(channel) {
14
14
  export function isNonAgentSessionChannel(channel) {
15
15
  return channel === 'daemon' || isSystemControlChannel(channel);
16
16
  }
17
+ /** Explicit maintenance helper; startup never invokes it. */
17
18
  export function cleanupLegacySystemControlSessions(sessionsDir) {
18
19
  const removed = [];
19
20
  for (const channel of LEGACY_SYSTEM_CONTROL_CHANNELS) {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // 【重要】最先加载环境变量,确保后续模块初始化时可用
2
2
  import dotenv from 'dotenv';
3
3
  import path from 'path';
4
- import { ensureDataDirs, resolvePaths, getPackageRoot, agentMdPath, eckDebugDir } from './paths.js';
4
+ import { ensureDataDirs, resolvePaths, getPackageRoot, agentMdPath, eckDebugDir, daemonControlDir, daemonQueuePath } from './paths.js';
5
5
  // 立即加载 .env 文件(在其他模块导入之前)
6
6
  try {
7
7
  dotenv.config({ path: path.join(resolvePaths().root, '.env') });
@@ -12,6 +12,7 @@ catch {
12
12
  import { ClaudeSessionFileAdapter } from './core/session/adapters/claude-session-file-adapter.js';
13
13
  import { CodexSessionFileAdapter } from './core/session/adapters/codex-session-file-adapter.js';
14
14
  import { GeminiSessionFileAdapter } from './core/session/adapters/gemini-session-file-adapter.js';
15
+ import { EcagentSessionFileAdapter } from './core/session/adapters/ecagent-session-file-adapter.js';
15
16
  import { loadDefaults, loadAllAgents, migrateIdentitiesIfNeeded, loadDaemonConfig, initializeEckSnapshotsConfig } from './config-store.js';
16
17
  import { ConfigTarget, initConfigManager, onConfigWrite } from './config/config-manager.js';
17
18
  import { ensureRoleConfigV4OnStartup } from './config/role-config-v4-startup.js';
@@ -30,6 +31,7 @@ import { SessionManager } from './core/session/session-manager.js';
30
31
  import { ClaudeAgentPlugin } from './agents/claude-runner.js';
31
32
  import { CodexAgentPlugin } from './agents/codex-runner.js';
32
33
  import { GeminiAgentPlugin } from './agents/gemini-runner.js';
34
+ import { EcagentAgentPlugin } from './agents/ecagent-runner.js';
33
35
  import { FeishuChannelPlugin, registerPendingFeishuContactBind } from './channels/feishu.js';
34
36
  import { WechatChannelPlugin, registerPendingWechatContactBind } from './channels/wechat.js';
35
37
  import { AUN_HANDOFF_MARKER_FIELD, AUNChannel, AUNChannelPlugin } from './channels/aun.js';
@@ -78,13 +80,13 @@ import { TriggerAuditLogger } from './trigger/audit.js';
78
80
  import { TriggerScriptExecutor } from './trigger/script-executor.js';
79
81
  import { TriggerFeedbackDispatcher } from './trigger/feedback.js';
80
82
  import { TriggerRuntimeScheduler } from './trigger/scheduler.js';
83
+ import { TargetSessionLockRegistry } from './trigger/session-lock.js';
81
84
  import { DaemonChannel } from './channels/daemon.js';
82
85
  import { definitionRevision, normalizeTriggerDefinition } from './trigger/validation.js';
83
86
  import { applyTriggerPatch } from './trigger/patch.js';
84
87
  import { validateModelSelectionForRole } from './core/model/model-permission.js';
85
88
  import { constrainRuntimePermissionMode, validateRuntimeStringFieldOverride, } from './core/role/runtime-policy.js';
86
89
  import { atomicWriteJson } from './core/session/session-fs-store.js';
87
- import { cleanupLegacySystemControlSessions } from './core/system-channels.js';
88
90
  import { appendMessageLog, buildOutboundEntry, classifyAunPayloadForLog } from './core/message/message-log.js';
89
91
  import fs from 'fs';
90
92
  import crypto from 'crypto';
@@ -844,21 +846,19 @@ async function main() {
844
846
  });
845
847
  return roleToSessionIdentity(detail.effectiveRole);
846
848
  };
847
- const removedLegacyControlSessions = cleanupLegacySystemControlSessions(paths.sessionsDir);
848
- if (removedLegacyControlSessions.length > 0) {
849
- logger.info(`[startup] Removed legacy synthetic control sessions: ${removedLegacyControlSessions.join(', ')}`);
850
- }
851
849
  const sessionManager = new SessionManager(paths.sessionsDir, eventBus, resolveSessionIdentity);
852
850
  logger.info('✓ Database initialized');
853
851
  // 注册会话文件适配器(Claude / Codex 各自的会话文件操作)
854
852
  sessionManager.registerFileAdapter(new ClaudeSessionFileAdapter());
855
853
  sessionManager.registerFileAdapter(new CodexSessionFileAdapter());
856
854
  sessionManager.registerFileAdapter(new GeminiSessionFileAdapter());
855
+ sessionManager.registerFileAdapter(new EcagentSessionFileAdapter());
857
856
  // Agent 插件系统:每个 EvolAgent × 每个 baseagent 一个独立 runner(H1/H2 修复)
858
857
  const agentLoader = new AgentLoader();
859
858
  agentLoader.register(new ClaudeAgentPlugin());
860
859
  agentLoader.register(new CodexAgentPlugin());
861
860
  agentLoader.register(new GeminiAgentPlugin());
861
+ agentLoader.register(new EcagentAgentPlugin());
862
862
  const agentInstances = agentLoader.createAll(agentRegistry, {
863
863
  onSessionIdUpdate: async (sessionId, agentSessionId) => {
864
864
  await sessionManager.updateAgentSessionIdBySessionId(sessionId, agentSessionId);
@@ -1010,7 +1010,7 @@ async function main() {
1010
1010
  const messageQueue = new MessageQueue(async (message) => {
1011
1011
  await processor.processMessage(message);
1012
1012
  }, {
1013
- persistencePath: path.join(resolvePaths().dataDir, 'message-queue.json'),
1013
+ persistencePath: daemonQueuePath(),
1014
1014
  });
1015
1015
  // 设置中断回调(精确中断正在处理的 agent)
1016
1016
  messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message') => {
@@ -1074,6 +1074,7 @@ async function main() {
1074
1074
  responseEngine.setHandoffRuntime(handoffRuntime);
1075
1075
  // Trigger runtime: daemon-level script + feedback scheduler.
1076
1076
  const triggerSchedulers = new Map();
1077
+ const targetSessionLocks = new TargetSessionLockRegistry();
1077
1078
  const triggerAudit = new TriggerAuditLogger();
1078
1079
  const triggerScriptExecutor = new TriggerScriptExecutor();
1079
1080
  const daemonChannel = new DaemonChannel(sessionManager, messageQueue, {
@@ -1446,7 +1447,7 @@ async function main() {
1446
1447
  baseagent: owner.baseagent,
1447
1448
  getBaseagent: () => agentRegistry.get(owner.aid)?.baseagent || owner.baseagent,
1448
1449
  authorizeExecution: authorizeTriggerExecution,
1449
- }, eventBus);
1450
+ }, eventBus, targetSessionLocks);
1450
1451
  triggerSchedulers.set(owner.aid, scheduler);
1451
1452
  try {
1452
1453
  await scheduler.init();
@@ -1710,7 +1711,7 @@ async function main() {
1710
1711
  }
1711
1712
  const connectedChannels = new Set();
1712
1713
  const onlineNoticeSent = new Set();
1713
- const pendingFile = path.join(resolvePaths().dataDir, 'restart-pending.json');
1714
+ const pendingFile = path.join(daemonControlDir(), 'restart-pending.json');
1714
1715
  let pendingRestartNoticeInFlight = null;
1715
1716
  let pendingRestartNoticeSent = false;
1716
1717
  const sendOnlineNoticeForChannel = (inst) => {
package/dist/paths.js CHANGED
@@ -25,15 +25,19 @@ export function _resetRoot() {
25
25
  }
26
26
  export function resolvePaths() {
27
27
  const root = resolveRoot();
28
+ const agentsDir = path.join(root, 'agents');
28
29
  return {
29
30
  root,
30
- sessionsDir: path.join(root, 'data', 'sessions'),
31
+ // Session storage is partitioned by owning Agent. Keep the historical
32
+ // location separately so the explicit data migration can inventory it.
33
+ sessionsDir: agentsDir,
34
+ legacySessionsDir: path.join(root, 'data', 'sessions'),
31
35
  instanceDir: path.join(root, 'data', 'instance'),
32
36
  outboxDir: path.join(root, 'data', 'outbox'),
33
37
  dataDir: path.join(root, 'data'),
34
38
  claudeModelCache: path.join(root, 'data', 'claude-model-cache.json'),
35
39
  logs: path.join(root, 'logs'),
36
- agentsDir: path.join(root, 'agents'),
40
+ agentsDir,
37
41
  lineStats: path.join(root, 'logs', 'line-stats.log'),
38
42
  readySignal: path.join(root, 'data', 'instance', 'ready.signal'),
39
43
  controlToken: path.join(root, 'data', 'instance', 'control.token'),
@@ -126,8 +130,36 @@ export function agentDataDir(aid) {
126
130
  export function agentDataCacheDir(aid) {
127
131
  return path.join(agentDataDir(aid), 'cache');
128
132
  }
133
+ export function agentHandoffDir(aid) {
134
+ return path.join(agentDataDir(aid), 'handoff');
135
+ }
136
+ export function agentOutboxPath(aid) {
137
+ return path.join(agentDataDir(aid), 'outbox.jsonl');
138
+ }
139
+ /** Directory-safe channel instance key used by connector runtime state. */
140
+ function encodePathKey(value) {
141
+ return encodeURIComponent(value);
142
+ }
143
+ export function daemonDataDir() {
144
+ return path.join(resolveRoot(), 'data', 'daemon');
145
+ }
146
+ export function daemonControlDir() {
147
+ return path.join(daemonDataDir(), 'control');
148
+ }
149
+ export function daemonQueuePath() {
150
+ return path.join(daemonDataDir(), 'message-queue.json');
151
+ }
152
+ export function channelStateDir(channelKey) {
153
+ if (!channelKey || channelKey === '.' || channelKey === '..') {
154
+ throw new Error('channelKey is required');
155
+ }
156
+ return path.join(resolveRoot(), 'data', 'channel-state', encodePathKey(channelKey));
157
+ }
158
+ export function channelStatePath(channelKey, ...parts) {
159
+ return path.join(channelStateDir(channelKey), ...parts);
160
+ }
129
161
  export function agentTriggersDir(aid) {
130
- return path.join(resolveRoot(), 'data', 'triggers', aid);
162
+ return path.join(agentDir(aid), 'triggers');
131
163
  }
132
164
  function resolveInstanceSocketPath(root) {
133
165
  if (isWindows) {
@@ -147,7 +179,6 @@ export function ensureDataDirs() {
147
179
  fs.mkdirSync(p.outboxDir, { recursive: true });
148
180
  fs.mkdirSync(p.eckDir, { recursive: true });
149
181
  fs.mkdirSync(aidsDir(), { recursive: true });
150
- seedConfigTemplates();
151
182
  migrateFromAun();
152
183
  }
153
184
  const MIGRATION_MARKER = '.migrated-from-aun';
@@ -211,29 +242,6 @@ function migrateFromAun() {
211
242
  }
212
243
  catch { }
213
244
  }
214
- /**
215
- * 首次运行时从 assets/ 模板拷贝 .env 到 $EVOLCORE_HOME。
216
- * 已存在则跳过,不覆盖用户修改。
217
- */
218
- function seedConfigTemplates() {
219
- const root = resolveRoot();
220
- const assetsDir = path.join(getPackageRoot(), 'assets');
221
- const templates = [
222
- { src: '.env.template', dst: '.env' },
223
- ];
224
- for (const { src, dst } of templates) {
225
- const dstPath = path.join(root, dst);
226
- if (fs.existsSync(dstPath))
227
- continue;
228
- const srcPath = path.join(assetsDir, src);
229
- if (!fs.existsSync(srcPath))
230
- continue;
231
- try {
232
- fs.copyFileSync(srcPath, dstPath);
233
- }
234
- catch { /* best-effort */ }
235
- }
236
- }
237
245
  // ── kits 路径(始终从包内读取,不复制到 EVOLCORE_HOME)──
238
246
  export function kitsDir() {
239
247
  return path.join(getPackageRoot(), 'kits');
@@ -69,6 +69,7 @@ export class TriggerFeedbackDispatcher {
69
69
  const deadlineTimer = setTimeout(() => abortDelivery('timeout', new Error(`target session timed out after ${TARGET_SESSION_DEADLINE_MS}ms`)), TARGET_SESSION_DEADLINE_MS);
70
70
  deadlineTimer.unref?.();
71
71
  let outcome;
72
+ let releaseSessionLock;
72
73
  try {
73
74
  if (delivery.signal.aborted) {
74
75
  const aborted = targetSessionCancellationError(abortKind, delivery.signal.reason, false);
@@ -128,6 +129,20 @@ export class TriggerFeedbackDispatcher {
128
129
  }
129
130
  return this.failed(feedback, [], 'session_error', err?.message || String(err));
130
131
  }
132
+ if (input.onSessionResolved) {
133
+ const access = await input.onSessionResolved(session);
134
+ if (access.kind === 'conflict') {
135
+ return {
136
+ status: 'skipped',
137
+ reason: 'concurrency_forbid',
138
+ conflictRunId: access.conflictRunId,
139
+ feedback,
140
+ effects: [],
141
+ error: null,
142
+ };
143
+ }
144
+ releaseSessionLock = access.release;
145
+ }
131
146
  const message = {
132
147
  channel: target.channelKey,
133
148
  channelType,
@@ -241,6 +256,7 @@ export class TriggerFeedbackDispatcher {
241
256
  }
242
257
  }
243
258
  finally {
259
+ releaseSessionLock?.();
244
260
  clearTimeout(deadlineTimer);
245
261
  input.signal?.removeEventListener('abort', onInputAbort);
246
262
  outcome?.cancel();
@@ -0,0 +1,19 @@
1
+ const HISTORY_CHANNELS = new Set(['aun', 'feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom']);
2
+ /**
3
+ * Turns legacy raw session-file references into the controlled history CLI.
4
+ * The replacement deliberately keeps the explicit peer/channel scope but
5
+ * never carries a filesystem location into a Trigger prompt.
6
+ */
7
+ export function rewriteLegacyTriggerSessionPaths(prompt, triggerAid) {
8
+ const legacyPath = /data\/sessions\/([A-Za-z0-9_-]+)\/([^/\s`"'<>]+)(?:\/([^/\s`"'<>]+))?\/messages\.jsonl/g;
9
+ return prompt.replace(legacyPath, (match, channel, first, second) => {
10
+ if (!HISTORY_CHANNELS.has(channel))
11
+ return match;
12
+ const isAun = channel === 'aun';
13
+ const target = isAun ? second : first;
14
+ const selfAid = triggerAid ?? (isAun ? first : undefined);
15
+ if (!selfAid || !target)
16
+ return match;
17
+ return `ec msg history ${selfAid} ${target} --channel ${channel} --session all --direction in --format json`;
18
+ });
19
+ }
@@ -4,6 +4,7 @@ import { agentTriggersDir } from '../paths.js';
4
4
  import { definitionRevision, normalizeTriggerDefinition, resolveScriptPath, safeRelativePath, } from './validation.js';
5
5
  import { atomicWriteJson } from '../core/session/session-fs-store.js';
6
6
  import { TriggerHistoryStore } from './history.js';
7
+ import { rewriteLegacyTriggerSessionPaths } from './legacy-session-history.js';
7
8
  export class TriggerDefinitionManager {
8
9
  agentAid;
9
10
  rootDir;
@@ -34,7 +35,17 @@ export class TriggerDefinitionManager {
34
35
  if (!fs.existsSync(file))
35
36
  return undefined;
36
37
  const raw = JSON.parse(fs.readFileSync(file, 'utf-8'));
37
- return normalizeTriggerDefinition(raw);
38
+ const definition = normalizeTriggerDefinition(raw);
39
+ if (typeof definition.execution.prompt === 'string') {
40
+ const rewritten = rewriteLegacyTriggerSessionPaths(definition.execution.prompt, definition.agentAid);
41
+ if (rewritten !== definition.execution.prompt) {
42
+ definition.execution = { ...definition.execution, prompt: rewritten };
43
+ definition.updatedAt = Date.now();
44
+ this.writeDefinition(definition);
45
+ this.history.recordDefinition('trigger.updated', definition, { reason: 'legacy-session-history-paths' });
46
+ }
47
+ }
48
+ return definition;
38
49
  }
39
50
  require(triggerId) {
40
51
  const def = this.get(triggerId);
@@ -210,11 +210,13 @@ function parseTriggerThread(flags) {
210
210
  return { ok: false, error: '--trigger-thread 不能为空' };
211
211
  if (raw === 'per-run')
212
212
  return { ok: true, value: 'per_run' };
213
+ if (raw === 'by-run')
214
+ return { ok: true, value: 'by_run' };
213
215
  if (raw === 'by-trigger')
214
216
  return { ok: true, value: 'by_trigger' };
215
- if (raw === 'per_run' || raw === 'by_trigger')
217
+ if (raw === 'per_run' || raw === 'by_run' || raw === 'by_trigger')
216
218
  return { ok: true, value: raw };
217
- return { ok: false, error: '--trigger-thread 只接受 per-run 或 by-trigger' };
219
+ return { ok: false, error: '--trigger-thread 只接受 by-run 或 by-trigger(兼容 per-run)' };
218
220
  }
219
221
  function parseTargetSession(flags) {
220
222
  if (!flags.has('target-session'))