evolcore 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/CHANGELOG.md +813 -0
  2. package/LICENSE +21 -0
  3. package/MIGRATION-0.5.0.md +378 -0
  4. package/README.md +318 -14
  5. package/ROLE_ACCESS_CONTROL.md +174 -0
  6. package/assets/.env.template +4 -0
  7. package/assets/brand/evolcore/README.md +19 -0
  8. package/assets/brand/evolcore/evolcore-app-icon.png +0 -0
  9. package/assets/brand/evolcore/evolcore-app-icon.svg +13 -0
  10. package/assets/brand/evolcore/evolcore-brand-board.png +0 -0
  11. package/assets/brand/evolcore/evolcore-brand-board.svg +126 -0
  12. package/assets/brand/evolcore/evolcore-logo-kit.zip +0 -0
  13. package/assets/brand/evolcore/evolcore-logo-reverse.png +0 -0
  14. package/assets/brand/evolcore/evolcore-logo-reverse.svg +14 -0
  15. package/assets/brand/evolcore/evolcore-logo.png +0 -0
  16. package/assets/brand/evolcore/evolcore-logo.svg +14 -0
  17. package/assets/brand/evolcore/evolcore-mark.png +0 -0
  18. package/assets/brand/evolcore/evolcore-mark.svg +10 -0
  19. package/bin/ec-safe-output.js +161 -0
  20. package/bin/ec.js +29 -0
  21. package/dist/agents/baseagent.js +163 -0
  22. package/dist/agents/claude-runner.js +2385 -0
  23. package/dist/agents/codex-app-server-client.js +448 -0
  24. package/dist/agents/codex-runner.js +2639 -0
  25. package/dist/agents/gemini-runner.js +666 -0
  26. package/dist/agents/runner-types.js +75 -0
  27. package/dist/aun/aid/agentmd.js +216 -0
  28. package/dist/aun/aid/client.js +132 -0
  29. package/dist/aun/aid/control-aid.js +91 -0
  30. package/dist/aun/aid/identity.js +518 -0
  31. package/dist/aun/aid/index.js +4 -0
  32. package/dist/aun/aid/store.js +74 -0
  33. package/dist/aun/aid/types.js +1 -0
  34. package/dist/aun/aid/validation.js +21 -0
  35. package/dist/aun/group-identity.js +10 -0
  36. package/dist/aun/msg/group-index.js +6 -0
  37. package/dist/aun/msg/group.js +1231 -0
  38. package/dist/aun/msg/history.js +123 -0
  39. package/dist/aun/msg/index.js +5 -0
  40. package/dist/aun/msg/p2p.js +393 -0
  41. package/dist/aun/msg/payload-type.js +27 -0
  42. package/dist/aun/msg/upload.js +137 -0
  43. package/dist/aun/outbox.js +160 -0
  44. package/dist/aun/rpc/caller.js +42 -0
  45. package/dist/aun/rpc/connection.js +25 -0
  46. package/dist/aun/rpc/index.js +2 -0
  47. package/dist/aun/service-proxy.js +225 -0
  48. package/dist/aun/storage/download.js +29 -0
  49. package/dist/aun/storage/index.js +3 -0
  50. package/dist/aun/storage/manage.js +10 -0
  51. package/dist/aun/storage/upload.js +68 -0
  52. package/dist/channels/aun.js +4147 -0
  53. package/dist/channels/daemon.js +422 -0
  54. package/dist/channels/dingtalk.js +649 -0
  55. package/dist/channels/feishu.js +1789 -0
  56. package/dist/channels/qqbot.js +409 -0
  57. package/dist/channels/wechat.js +817 -0
  58. package/dist/channels/wecom.js +565 -0
  59. package/dist/cli/agent-command.js +641 -0
  60. package/dist/cli/agent.js +1059 -0
  61. package/dist/cli/aun-commands.js +1948 -0
  62. package/dist/cli/bench.js +1228 -0
  63. package/dist/cli/cli-argv.js +66 -0
  64. package/dist/cli/code-stats.js +329 -0
  65. package/dist/cli/command-log.js +82 -0
  66. package/dist/cli/config-selector.js +69 -0
  67. package/dist/cli/config.js +261 -0
  68. package/dist/cli/ctl-command.js +62 -0
  69. package/dist/cli/daemon-commands.js +2887 -0
  70. package/dist/cli/fs-command.js +1447 -0
  71. package/dist/cli/handoff-command.js +302 -0
  72. package/dist/cli/help.js +31 -0
  73. package/dist/cli/index.js +358 -0
  74. package/dist/cli/init-channel.js +1377 -0
  75. package/dist/cli/init.js +553 -0
  76. package/dist/cli/link-rules.js +240 -0
  77. package/dist/cli/model.js +590 -0
  78. package/dist/cli/net-check.js +723 -0
  79. package/dist/cli/queue-command.js +126 -0
  80. package/dist/cli/response.js +345 -0
  81. package/dist/cli/restart-monitor.js +456 -0
  82. package/dist/cli/stats.js +607 -0
  83. package/dist/cli/task-context.js +80 -0
  84. package/dist/cli/trigger-command.js +505 -0
  85. package/dist/cli/version.js +88 -0
  86. package/dist/cli/watch-logs.js +33 -0
  87. package/dist/cli/watch-msg.js +673 -0
  88. package/dist/config/boot-log.js +266 -0
  89. package/dist/config/builtin-role-templates.js +30 -0
  90. package/dist/config/builtin-roles.js +85 -0
  91. package/dist/config/config-batch-get.js +11 -0
  92. package/dist/config/config-field-policy.js +261 -0
  93. package/dist/config/config-manager.js +916 -0
  94. package/dist/config/config-operation-service.js +384 -0
  95. package/dist/config/contact-book.js +371 -0
  96. package/dist/config/gateway-config.js +858 -0
  97. package/dist/config/lifecycle.js +17 -0
  98. package/dist/config/mention-mode.js +27 -0
  99. package/dist/config/merge.js +161 -0
  100. package/dist/config/owner-policy.js +4 -0
  101. package/dist/config/peer-role-resolver.js +139 -0
  102. package/dist/config/resolved-config-op.js +483 -0
  103. package/dist/config/role-config-v4-startup.js +32 -0
  104. package/dist/config/role-config-v5-startup.js +27 -0
  105. package/dist/config/role-schema.js +105 -0
  106. package/dist/config/role-service.js +159 -0
  107. package/dist/config/role-store.js +204 -0
  108. package/dist/config/roles.js +55 -0
  109. package/dist/config/schema-registry.js +154 -0
  110. package/dist/config/snapshot.js +598 -0
  111. package/dist/config-store.js +503 -0
  112. package/dist/core/auth/agent-delegation.js +111 -0
  113. package/dist/core/auth/auth-gateway.js +166 -0
  114. package/dist/core/auth/authenticated-actor.js +6 -0
  115. package/dist/core/auth/authorization-audit.js +110 -0
  116. package/dist/core/auth/operation-authorizer.js +718 -0
  117. package/dist/core/auth/operation-catalog.js +675 -0
  118. package/dist/core/baseagent-loader.js +54 -0
  119. package/dist/core/bootstrap-service.js +175 -0
  120. package/dist/core/capability/capability-manager.js +316 -0
  121. package/dist/core/capability/providers/claude-capability-provider.js +176 -0
  122. package/dist/core/capability/providers/codex-capability-provider.js +148 -0
  123. package/dist/core/capability/providers/gemini-capability-provider.js +10 -0
  124. package/dist/core/capability/types.js +27 -0
  125. package/dist/core/causation/audit.js +103 -0
  126. package/dist/core/causation/aun-association.js +111 -0
  127. package/dist/core/causation/context.js +93 -0
  128. package/dist/core/causation/index.js +4 -0
  129. package/dist/core/causation/types.js +2 -0
  130. package/dist/core/channel-loader.js +277 -0
  131. package/dist/core/command/agent-control.js +616 -0
  132. package/dist/core/command/cli-intent-parser.js +225 -0
  133. package/dist/core/command/command-handler.js +1638 -0
  134. package/dist/core/command/menu-handler.js +3354 -0
  135. package/dist/core/command/menu-protocol.js +247 -0
  136. package/dist/core/command/role-menu.js +1524 -0
  137. package/dist/core/command/slash-gate.js +148 -0
  138. package/dist/core/command/slash-handler.js +3056 -0
  139. package/dist/core/daemon-file-cache.js +216 -0
  140. package/dist/core/event-bus.js +32 -0
  141. package/dist/core/event-catalog.js +740 -0
  142. package/dist/core/evolagent-registry.js +546 -0
  143. package/dist/core/evolagent.js +331 -0
  144. package/dist/core/handoff/dispatcher.js +229 -0
  145. package/dist/core/handoff/mutex.js +46 -0
  146. package/dist/core/handoff/runtime.js +324 -0
  147. package/dist/core/handoff/store.js +537 -0
  148. package/dist/core/handoff/types.js +12 -0
  149. package/dist/core/inference/text-inference.js +173 -0
  150. package/dist/core/interaction-registration.js +10 -0
  151. package/dist/core/interaction-router.js +278 -0
  152. package/dist/core/message/create-status.js +67 -0
  153. package/dist/core/message/im-renderer.js +657 -0
  154. package/dist/core/message/items-formatter.js +76 -0
  155. package/dist/core/message/logical-queue-bridge.js +123 -0
  156. package/dist/core/message/message-bridge.js +803 -0
  157. package/dist/core/message/message-cache.js +56 -0
  158. package/dist/core/message/message-log.js +339 -0
  159. package/dist/core/message/message-processor.js +4 -0
  160. package/dist/core/message/message-queue.js +1436 -0
  161. package/dist/core/message/message-utils.js +70 -0
  162. package/dist/core/message/peer-mode.js +105 -0
  163. package/dist/core/message/pending-hints.js +232 -0
  164. package/dist/core/message/response-depth.js +33 -0
  165. package/dist/core/message/response-engine.js +3776 -0
  166. package/dist/core/message/response-snapshot.js +83 -0
  167. package/dist/core/message/stream-debouncer.js +130 -0
  168. package/dist/core/message/stream-idle-monitor.js +124 -0
  169. package/dist/core/model/config-scope.js +162 -0
  170. package/dist/core/model/field-scope.js +78 -0
  171. package/dist/core/model/model-catalog.js +227 -0
  172. package/dist/core/model/model-diagnostics.js +182 -0
  173. package/dist/core/model/model-permission.js +90 -0
  174. package/dist/core/permission/approval-gateway.js +1017 -0
  175. package/dist/core/permission/ec-command-parser.js +347 -0
  176. package/dist/core/permission/execution-sandbox.js +16 -0
  177. package/dist/core/permission/index.js +6 -0
  178. package/dist/core/permission/mode.js +24 -0
  179. package/dist/core/permission/sandbox-runtime.js +265 -0
  180. package/dist/core/permission/tool-policy.js +987 -0
  181. package/dist/core/permission/unix-socket-policy.js +99 -0
  182. package/dist/core/protected-paths.js +330 -0
  183. package/dist/core/relation/peer-identity.js +222 -0
  184. package/dist/core/relation/peer-key.js +1 -0
  185. package/dist/core/role/runtime-policy.js +141 -0
  186. package/dist/core/session/adapters/claude-session-file-adapter.js +218 -0
  187. package/dist/core/session/adapters/codex-session-file-adapter.js +333 -0
  188. package/dist/core/session/adapters/gemini-session-file-adapter.js +181 -0
  189. package/dist/core/session/session-file-adapter.js +7 -0
  190. package/dist/core/session/session-file-health.js +45 -0
  191. package/dist/core/session/session-fs-store.js +232 -0
  192. package/dist/core/session/session-key.js +24 -0
  193. package/dist/core/session/session-manager.js +1587 -0
  194. package/dist/core/session/session-mapper.js +100 -0
  195. package/dist/core/session/session-renew.js +314 -0
  196. package/dist/core/session/session-title.js +128 -0
  197. package/dist/core/session/session-turn-coordinator.js +205 -0
  198. package/dist/core/session/session-turns.js +67 -0
  199. package/dist/core/system-channels.js +29 -0
  200. package/dist/eck/baseagent-caps.js +18 -0
  201. package/dist/eck/detect.js +47 -0
  202. package/dist/eck/group-rules-sync.js +345 -0
  203. package/dist/eck/init.js +77 -0
  204. package/dist/eck/kit-renderer.js +359 -0
  205. package/dist/eck/manifest-engine.js +446 -0
  206. package/dist/eck/message-renderer.js +199 -0
  207. package/dist/eck/rules-loader.js +28 -0
  208. package/dist/index.js +2870 -4
  209. package/dist/ipc.js +748 -0
  210. package/dist/paths.js +262 -0
  211. package/dist/product.js +18 -0
  212. package/dist/response-system/context-builder.js +71 -0
  213. package/dist/response-system/coordinator.js +117 -0
  214. package/dist/response-system/decision-executor.js +86 -0
  215. package/dist/response-system/engines/v1/index.js +21 -0
  216. package/dist/response-system/engines/v1/interactive-flow.js +27 -0
  217. package/dist/response-system/engines/v1/proactive-flow.js +137 -0
  218. package/dist/response-system/engines/v1/types.js +1 -0
  219. package/dist/response-system/extensions.js +41 -0
  220. package/dist/response-system/index.js +6 -0
  221. package/dist/response-system/modes/index.js +7 -0
  222. package/dist/response-system/modes/single-session/index.js +72 -0
  223. package/dist/response-system/queues/fifo-queue.js +44 -0
  224. package/dist/response-system/queues/index.js +6 -0
  225. package/dist/response-system/queues/lifo-queue.js +42 -0
  226. package/dist/response-system/queues/priority-queue.js +63 -0
  227. package/dist/response-system/registry.js +97 -0
  228. package/dist/response-system/resolver.js +37 -0
  229. package/dist/response-system/selector.js +23 -0
  230. package/dist/response-system/types.js +7 -0
  231. package/dist/stats/billing.js +151 -0
  232. package/dist/stats/budget.js +93 -0
  233. package/dist/stats/db.js +403 -0
  234. package/dist/stats/eck-vars.js +89 -0
  235. package/dist/stats/index.js +11 -0
  236. package/dist/stats/normalizer.js +80 -0
  237. package/dist/stats/price-resolver.js +138 -0
  238. package/dist/stats/query.js +763 -0
  239. package/dist/stats/role-budget.js +168 -0
  240. package/dist/stats/writer.js +151 -0
  241. package/dist/trigger/anomaly-store.js +258 -0
  242. package/dist/trigger/audit.js +152 -0
  243. package/dist/trigger/event-source.js +119 -0
  244. package/dist/trigger/feedback.js +685 -0
  245. package/dist/trigger/history.js +290 -0
  246. package/dist/trigger/manager.js +291 -0
  247. package/dist/trigger/parser.js +520 -0
  248. package/dist/trigger/patch.js +148 -0
  249. package/dist/trigger/scheduler.js +1600 -0
  250. package/dist/trigger/script-executor.js +155 -0
  251. package/dist/trigger/state.js +145 -0
  252. package/dist/trigger/types.js +1 -0
  253. package/dist/trigger/validation.js +621 -0
  254. package/dist/types.js +12 -0
  255. package/dist/utils/aid-bind.js +299 -0
  256. package/dist/utils/atomic-write.js +95 -0
  257. package/dist/utils/avatar-upload.js +123 -0
  258. package/dist/utils/cross-platform.js +297 -0
  259. package/dist/utils/ecweb-utils.js +73 -0
  260. package/dist/utils/error-dict.json +153 -0
  261. package/dist/utils/error-utils.js +349 -0
  262. package/dist/utils/instance-registry.js +437 -0
  263. package/dist/utils/locale.js +21 -0
  264. package/dist/utils/log-writer.js +224 -0
  265. package/dist/utils/logger.js +89 -0
  266. package/dist/utils/markdown-to-plain-text.js +20 -0
  267. package/dist/utils/media-cache.js +271 -0
  268. package/dist/utils/model-prices.jsonl +17 -0
  269. package/dist/utils/npm-ops.js +210 -0
  270. package/dist/utils/process-introspect.js +133 -0
  271. package/dist/utils/process-tree-stats.js +271 -0
  272. package/dist/utils/project-path.js +74 -0
  273. package/dist/utils/stats.js +410 -0
  274. package/dist/utils/tool-summary.js +284 -0
  275. package/dist/utils/welcome.js +268 -0
  276. package/kits/docs/GUIDE.md +20 -0
  277. package/kits/docs/INDEX.md +65 -0
  278. package/kits/docs/aun/CHEATSHEET.md +19 -0
  279. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -0
  280. package/kits/docs/channels/aun.md +65 -0
  281. package/kits/docs/channels/feishu.md +56 -0
  282. package/kits/docs/context-assembly.md +366 -0
  283. package/kits/docs/eck_templates/GUIDE.template.md +22 -0
  284. package/kits/docs/eck_templates/INDEX.template.md +28 -0
  285. package/kits/docs/eck_templates/path-registry.template.md +33 -0
  286. package/kits/docs/eck_templates/runtime.template.md +19 -0
  287. package/kits/docs/evolcore/INDEX.md +66 -0
  288. package/kits/docs/evolcore/agent.md +69 -0
  289. package/kits/docs/evolcore/aid.md +49 -0
  290. package/kits/docs/evolcore/config.md +149 -0
  291. package/kits/docs/evolcore/ctl.md +46 -0
  292. package/kits/docs/evolcore/event.md +216 -0
  293. package/kits/docs/evolcore/fs-architecture.md +1215 -0
  294. package/kits/docs/evolcore/fs.md +101 -0
  295. package/kits/docs/evolcore/group-fs.md +17 -0
  296. package/kits/docs/evolcore/group-rules.md +226 -0
  297. package/kits/docs/evolcore/group.md +141 -0
  298. package/kits/docs/evolcore/model.md +47 -0
  299. package/kits/docs/evolcore/msg.md +130 -0
  300. package/kits/docs/evolcore/response.md +80 -0
  301. package/kits/docs/evolcore/rpc.md +35 -0
  302. package/kits/docs/evolcore/self-summary.md +29 -0
  303. package/kits/docs/evolcore/stats.md +70 -0
  304. package/kits/docs/evolcore/storage.md +49 -0
  305. package/kits/docs/evolcore/trigger.md +524 -0
  306. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -0
  307. package/kits/docs/identity/PATH_OPS.md +16 -0
  308. package/kits/docs/identity/ROLE_DETAIL.md +23 -0
  309. package/kits/docs/identity/identity-tools.md +26 -0
  310. package/kits/docs/path-registry.md +43 -0
  311. package/kits/docs/prompt-loading-architecture.md +266 -0
  312. package/kits/docs/venues/aun-group.md +45 -0
  313. package/kits/docs/venues/aun-private.md +10 -0
  314. package/kits/docs/venues/client-desktop.md +10 -0
  315. package/kits/docs/venues/client-mobile.md +10 -0
  316. package/kits/docs/venues/feishu-group.md +13 -0
  317. package/kits/docs/venues/feishu-private.md +9 -0
  318. package/kits/docs/venues/group.md +25 -0
  319. package/kits/docs/venues/private.md +10 -0
  320. package/kits/eck_manifest.auxiliary.json +43 -0
  321. package/kits/eck_manifest.json +191 -0
  322. package/kits/eck_message_manifest.json +63 -0
  323. package/kits/migrations/README-role-config-v4.md +32 -0
  324. package/kits/migrations/migrate-role-config-v4.mjs +623 -0
  325. package/kits/migrations/migrate-role-config-v5.mjs +346 -0
  326. package/kits/migrations/rename-config-file.mjs +99 -0
  327. package/kits/rules/01-overview.md +142 -0
  328. package/kits/rules/02-navigation.md +76 -0
  329. package/kits/rules/03-identity.md +34 -0
  330. package/kits/rules/04-relation.md +59 -0
  331. package/kits/rules/05-venue.md +44 -0
  332. package/kits/rules/06-channel.md +59 -0
  333. package/kits/schemas/_meta.json +29 -0
  334. package/kits/schemas/agent-config.schema.1.json +177 -0
  335. package/kits/schemas/agent-config.schema.2.json +239 -0
  336. package/kits/schemas/agent-config.schema.3.json +119 -0
  337. package/kits/schemas/agent-config.schema.4.json +208 -0
  338. package/kits/schemas/agent-config.schema.5.json +326 -0
  339. package/kits/schemas/contact-book.schema.1.json +36 -0
  340. package/kits/schemas/daemon.schema.1.json +90 -0
  341. package/kits/schemas/defaults.schema.1.json +81 -0
  342. package/kits/schemas/menu-exec-schema-commands.md +208 -0
  343. package/kits/schemas/migrations/README.md +28 -0
  344. package/kits/schemas/relation-config.schema.1.json +158 -0
  345. package/kits/schemas/relation-config.schema.2.json +73 -0
  346. package/kits/schemas/relation-config.schema.3.json +50 -0
  347. package/kits/schemas/relation-config.schema.4.json +47 -0
  348. package/kits/schemas/role-config.schema.1.json +200 -0
  349. package/kits/schemas/role-registry.schema.1.json +35 -0
  350. package/kits/schemas/single-session.schema.1.json +31 -0
  351. package/kits/templates/bootstrap-welcome.md +15 -0
  352. package/kits/templates/message-fragments/handoff-request-to-target.md +13 -0
  353. package/kits/templates/message-fragments/handoff-response-to-origin.md +10 -0
  354. package/kits/templates/message-fragments/inject-default.md +2 -0
  355. package/kits/templates/message-fragments/item.md +2 -0
  356. package/kits/templates/roles/admin.json +8 -0
  357. package/kits/templates/roles/member.json +40 -0
  358. package/kits/templates/roles/owner.json +8 -0
  359. package/kits/templates/roles/visitor.json +39 -0
  360. package/kits/templates/system-fragments/baseagent.md +14 -0
  361. package/kits/templates/system-fragments/bootstrap.md +16 -0
  362. package/kits/templates/system-fragments/channel.md +48 -0
  363. package/kits/templates/system-fragments/commands.md +26 -0
  364. package/kits/templates/system-fragments/identity.md +11 -0
  365. package/kits/templates/system-fragments/relation.md +19 -0
  366. package/kits/templates/system-fragments/session.md +53 -0
  367. package/kits/templates/system-fragments/venue.md +31 -0
  368. package/package.json +50 -15
  369. package/dist/index.d.ts +0 -7
  370. package/dist/index.d.ts.map +0 -1
  371. package/dist/index.js.map +0 -1
@@ -0,0 +1,553 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import readline from 'readline';
4
+ import { resolvePaths, ensureDataDirs } from '../paths.js';
5
+ import { commandExists } from '../utils/cross-platform.js';
6
+ import { scanInstances } from '../utils/instance-registry.js';
7
+ import { saveDefaultsSafe, loadAllAgents, loadDaemonConfig, saveDaemonConfig } from '../config-store.js';
8
+ import { generateControlAid, resolveControlIssuer } from '../aun/aid/control-aid.js';
9
+ import { getCodexAppServerAvailability, isCodexAppServerAvailable } from '../agents/codex-runner.js';
10
+ import { defaultProjectsRoot } from '../utils/project-path.js';
11
+ import { WEB_CLI_BIN, WEB_PACKAGE_LATEST } from '../product.js';
12
+ // ==================== Helpers ====================
13
+ function ask(rl, question) {
14
+ return new Promise(resolve => rl.question(question, resolve));
15
+ }
16
+ const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
17
+ function isBaseagentAvailable(baseagent) {
18
+ if (baseagent === 'codex')
19
+ return isCodexAppServerAvailable();
20
+ return commandExists(baseagent);
21
+ }
22
+ function detectAvailable() {
23
+ return BASEAGENT_CANDIDATES.filter(isBaseagentAvailable);
24
+ }
25
+ function pickDefault(available) {
26
+ return (available.includes('claude') ? 'claude' : available[0]);
27
+ }
28
+ function buildDefaults(chosen, available, projectsDefaultPath) {
29
+ const baseagents = {};
30
+ for (const b of available)
31
+ baseagents[b] = {};
32
+ return {
33
+ $schema_version: 1,
34
+ active_baseagent: chosen,
35
+ baseagents,
36
+ ...(projectsDefaultPath ? { projects: { defaultPath: projectsDefaultPath } } : {}),
37
+ };
38
+ }
39
+ function writeDefaults(chosen, available, projectsDefaultPath) {
40
+ saveDefaultsSafe(buildDefaults(chosen, available, projectsDefaultPath));
41
+ }
42
+ /** 启动门禁判定:缺控制 AID 且处于交互式终端时,应进 init 向导补全。
43
+ * 非 TTY(restart-monitor/systemd/管道)即使缺 aid 也不进 init(无法交互),由 daemon 侧 warn 兜底。 */
44
+ export function needsControlAidInit(aid, isTty) {
45
+ return !aid && isTty;
46
+ }
47
+ /** 解析用户输入的 owner AID 列表:按空白/逗号分隔,去空、去重、按 isValid 分流。
48
+ * 空输入 → valid:[](视为跳过)。 */
49
+ export function parseOwnerAids(raw, isValid) {
50
+ const tokens = raw.split(/[\s,]+/).map(t => t.trim()).filter(Boolean);
51
+ const valid = [];
52
+ const invalid = [];
53
+ for (const t of tokens) {
54
+ if (isValid(t)) {
55
+ if (!valid.includes(t))
56
+ valid.push(t);
57
+ }
58
+ else {
59
+ invalid.push(t);
60
+ }
61
+ }
62
+ return { valid, invalid };
63
+ }
64
+ function installErrorMessage(e) {
65
+ return String(e?.stderr || e?.message || e).trim();
66
+ }
67
+ async function ensureEcwebInstalledForInit() {
68
+ if (commandExists(WEB_CLI_BIN))
69
+ return true;
70
+ console.log(` 📦 EC Web 组件未安装,正在安装 ${WEB_PACKAGE_LATEST}...`);
71
+ try {
72
+ const { npmInstallGlobal } = await import('../utils/npm-ops.js');
73
+ await npmInstallGlobal(WEB_PACKAGE_LATEST);
74
+ console.log(' ✓ EC Web 组件安装完成');
75
+ return true;
76
+ }
77
+ catch (e) {
78
+ console.log(` ⚠ EC Web 组件安装失败: ${installErrorMessage(e)}`);
79
+ console.log(` 可稍后运行 ec watch web 自动安装并启动,或手动运行 npm install -g ${WEB_PACKAGE_LATEST}`);
80
+ return false;
81
+ }
82
+ }
83
+ // ==================== Main ====================
84
+ export async function cmdInit(options) {
85
+ // 云部署非交互式路径:当带 --owner 或 --format json 时走结构化分支,与交互式 tail 完全隔离。
86
+ // 预留方案 B:当 daemon 支持 Control Plane 无 agent 启动时,可在此分支跳过 agent new 预创建。
87
+ if (options?.nonInteractive && (options.owner || options.format === 'json')) {
88
+ return cmdInitNonInteractive({
89
+ owner: options.owner,
90
+ baseagent: options.baseagent,
91
+ projectpath: options.projectpath,
92
+ ecweb: options.ecweb,
93
+ force: options.force,
94
+ format: options.format,
95
+ });
96
+ }
97
+ const p = resolvePaths();
98
+ ensureDataDirs();
99
+ // ── 1. 单进程互斥 ──
100
+ const aliveMains = scanInstances().mains.filter(m => m.alive);
101
+ if (aliveMains.length > 0) {
102
+ const pids = aliveMains.map(m => m.record.pid).join(', ');
103
+ console.log(`❌ EvolCore 正在运行 (PID: ${pids}),请先执行 ec stop`);
104
+ return;
105
+ }
106
+ // ── 2. 探测 baseagent ──
107
+ const available = detectAvailable();
108
+ if (available.length === 0) {
109
+ console.log('❌ 未检测到可用 baseagent。请安装至少一款:');
110
+ console.log(' - claude CLI');
111
+ console.log(' - gemini CLI');
112
+ console.log(' - codex CLI with app-server');
113
+ console.log('\n安装后重新运行 ec init');
114
+ return;
115
+ }
116
+ console.log('检测到可用的 baseagent:');
117
+ for (const b of available)
118
+ console.log(` ● ${b}`);
119
+ console.log('');
120
+ const defaultsPath = p.defaultsConfig;
121
+ const defaultsExisted = fs.existsSync(defaultsPath);
122
+ // “已初始化”以 daemon.json 为准:文件存在且控制 AID 已生成。
123
+ // 删除 daemon.json(aid 丢失)即视为未初始化,向导会重新补全 aid + owners。
124
+ const initialized = fs.existsSync(p.daemonConfig) && !!loadDaemonConfig().aid;
125
+ // ── 3. 非交互式分支 ──
126
+ if (options?.nonInteractive) {
127
+ if (defaultsExisted && !options.force) {
128
+ // defaults 已存在且未 --force:不重写 defaults,但仍落到共享 tail(幂等补全控制 AID/owners)。
129
+ console.log(`配置已存在: ${defaultsPath}(加 --force 可覆盖)`);
130
+ }
131
+ else {
132
+ let chosen;
133
+ if (options.baseagent) {
134
+ if (!BASEAGENT_CANDIDATES.includes(options.baseagent)) {
135
+ console.log(`❌ 无效 baseagent: ${options.baseagent}(可选: ${BASEAGENT_CANDIDATES.join('/')})`);
136
+ return; // 硬错误:不落 tail
137
+ }
138
+ if (!available.includes(options.baseagent)) {
139
+ const reason = options.baseagent === 'codex'
140
+ ? getCodexAppServerAvailability().reason
141
+ : undefined;
142
+ console.log(`❌ ${options.baseagent} 当前环境不可用${reason ? `:${reason}` : `(可用: ${available.join('/')})`}`);
143
+ return; // 硬错误:不落 tail
144
+ }
145
+ chosen = options.baseagent;
146
+ }
147
+ else {
148
+ chosen = pickDefault(available);
149
+ }
150
+ writeDefaults(chosen, available);
151
+ console.log(`✓ 已${defaultsExisted ? '覆盖' : '创建'}: ${defaultsPath}`);
152
+ console.log(` active_baseagent: ${chosen}`);
153
+ }
154
+ // 落到共享 tail(不 return)
155
+ }
156
+ else {
157
+ // ── 4. 交互式分支(rl 生命周期封装在内部函数,tail 不引用 rl)──
158
+ await runInteractive();
159
+ }
160
+ // ── 共享 tail(单一出口):提示创建 agent + 生成控制 AID ──
161
+ await initTail();
162
+ // ── 内部函数 ──
163
+ async function runInteractive() {
164
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
165
+ async function askBaseagent() {
166
+ const defaultBa = pickDefault(available);
167
+ if (available.length === 1) {
168
+ console.log(` baseagent: ${defaultBa}`);
169
+ return defaultBa;
170
+ }
171
+ let chosen = null;
172
+ while (chosen === null) {
173
+ const input = (await ask(rl, `默认 baseagent (${available.join('/')}) [${defaultBa}]: `)).trim() || defaultBa;
174
+ if (!BASEAGENT_CANDIDATES.includes(input)) {
175
+ console.log(` 无效选择,可选: ${BASEAGENT_CANDIDATES.join('/')}`);
176
+ continue;
177
+ }
178
+ if (!available.includes(input)) {
179
+ console.log(` ${input} 当前环境不可用(可用: ${available.join('/')})`);
180
+ continue;
181
+ }
182
+ chosen = input;
183
+ }
184
+ return chosen;
185
+ }
186
+ async function askProjectsDefaultPath() {
187
+ const defaultDir = path.join(defaultProjectsRoot(p.root), 'default');
188
+ const input = (await ask(rl, `项目默认目录 [${defaultDir}]: `)).trim();
189
+ const resolved = input || defaultDir;
190
+ if (!path.isAbsolute(resolved)) {
191
+ console.log(' ⚠ 需要绝对路径,已跳过');
192
+ return undefined;
193
+ }
194
+ if (!fs.existsSync(resolved)) {
195
+ const create = (await ask(rl, ` 目录不存在,是否创建?[Y/n]: `)).trim().toLowerCase();
196
+ if (create === '' || create === 'y' || create === 'yes') {
197
+ try {
198
+ fs.mkdirSync(resolved, { recursive: true });
199
+ }
200
+ catch (e) {
201
+ console.log(` ⚠ 创建目录失败: ${e?.message || e}`);
202
+ return undefined;
203
+ }
204
+ console.log(` ✓ 已创建 ${resolved}`);
205
+ }
206
+ else {
207
+ return undefined;
208
+ }
209
+ }
210
+ return resolved;
211
+ }
212
+ try {
213
+ if (defaultsExisted) {
214
+ const ans = (await ask(rl, `配置文件已存在: ${defaultsPath}\n 是否覆盖?[y/N] `)).trim().toLowerCase();
215
+ if (ans === 'y' || ans === 'yes') {
216
+ const chosen = await askBaseagent();
217
+ const projectsDefaultPath = await askProjectsDefaultPath();
218
+ writeDefaults(chosen, available, projectsDefaultPath);
219
+ console.log(`\n✓ 已覆盖: ${defaultsPath}`);
220
+ console.log(` active_baseagent: ${chosen}\n`);
221
+ }
222
+ else {
223
+ console.log(' 已跳过(保留现有配置)\n');
224
+ }
225
+ }
226
+ else {
227
+ const chosen = await askBaseagent();
228
+ const projectsDefaultPath = await askProjectsDefaultPath();
229
+ writeDefaults(chosen, available, projectsDefaultPath);
230
+ console.log(`\n✓ 已创建: ${defaultsPath}`);
231
+ console.log(` active_baseagent: ${chosen}\n`);
232
+ }
233
+ }
234
+ finally {
235
+ try {
236
+ rl.close();
237
+ }
238
+ catch { /* ignore */ }
239
+ }
240
+ }
241
+ }
242
+ /** 补全控制 AID + owners(可单独调用,不走 baseagent 向导)。 */
243
+ export async function initTail() {
244
+ // 提示创建 agent(两分支汇合后执行一次)
245
+ const { agents } = loadAllAgents();
246
+ if (agents.length === 0) {
247
+ console.log('\n提示:尚无 agent,运行以下命令创建:');
248
+ console.log(' ec agent new <aid>.agentid.pub');
249
+ }
250
+ // 控制 AID:daemon 进程身份。缺失则生成并写回 daemon.json(幂等:已存在则跳过)。
251
+ const daemonConfig = loadDaemonConfig();
252
+ if (daemonConfig.aid) {
253
+ const targetIssuer = resolveControlIssuer();
254
+ const currentIssuer = daemonConfig.aid.split('.').slice(1).join('.');
255
+ if (currentIssuer !== targetIssuer) {
256
+ console.log(`⚠️ 控制 AID issuer (${currentIssuer}) 与目标 issuer (${targetIssuer}) 不一致`);
257
+ console.log(` 如需切换,请删除 daemon.json 中的 aid 字段后重新运行 init`);
258
+ }
259
+ console.log(`✓ 控制 AID 已存在: ${daemonConfig.aid}`);
260
+ }
261
+ else {
262
+ try {
263
+ const { aid } = await generateControlAid();
264
+ saveDaemonConfig({ ...daemonConfig, $schema_version: daemonConfig.$schema_version ?? 1, aid });
265
+ console.log(`✓ 已生成控制 AID: ${aid}`);
266
+ }
267
+ catch (e) {
268
+ console.error(`⚠️ 控制 AID 生成失败(Gateway 不可达?联网后重跑 ec init 补全): ${e?.message || e}`);
269
+ }
270
+ }
271
+ // 交互式询问:使用单一 readline 实例避免 stdin 状态混乱
272
+ if (process.stdin.isTTY) {
273
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
274
+ try {
275
+ await handleOwnersPrompt(rl);
276
+ await handleEcwebPrompt(rl);
277
+ }
278
+ finally {
279
+ try {
280
+ rl.close();
281
+ }
282
+ catch { /* ignore */ }
283
+ }
284
+ }
285
+ async function handleOwnersPrompt(rl) {
286
+ const daemonConfigForOwners = loadDaemonConfig();
287
+ if (daemonConfigForOwners.aid && (!daemonConfigForOwners.owners || daemonConfigForOwners.owners.length === 0)) {
288
+ const needOwner = (await ask(rl, '\n是否配置进程级管理者(Owner AID)?[y/N] ')).trim().toLowerCase();
289
+ if (needOwner === 'y' || needOwner === 'yes') {
290
+ console.log('\n📡 进程级管理者绑定 — 请用 evol app 扫描二维码\n');
291
+ // QR 绑定流程需要暂时关闭 rl,因为它会创建自己的输入监听
292
+ rl.pause();
293
+ try {
294
+ const { runDaemonOwnerQrBindFlow } = await import('./init-channel.js');
295
+ const result = await runDaemonOwnerQrBindFlow('append');
296
+ if (result?.boundAid) {
297
+ console.log(` ✓ 已配置管理者: ${result.boundAid}`);
298
+ }
299
+ else {
300
+ // QR 流程失败,恢复 rl 并提示手动输入
301
+ rl.resume();
302
+ await promptOwnersManually(rl);
303
+ }
304
+ }
305
+ catch (e) {
306
+ console.log(` ⚠ 扫码绑定不可用: ${e?.message || e}`);
307
+ rl.resume();
308
+ await promptOwnersManually(rl);
309
+ }
310
+ // QR 流程成功完成后恢复 rl
311
+ rl.resume();
312
+ }
313
+ else {
314
+ console.log(' 已跳过 owners 配置(可日后编辑 daemon.json 或重跑 ec init)');
315
+ }
316
+ }
317
+ }
318
+ async function promptOwnersManually(rl) {
319
+ const { isValidAid } = await import('../aun/aid/index.js');
320
+ const raw = (await ask(rl, '\n请输入 EvolCore 管理者 AID: ')).trim();
321
+ if (raw) {
322
+ const { valid, invalid } = parseOwnerAids(raw, isValidAid);
323
+ if (invalid.length > 0)
324
+ console.log(` ⚠ 跳过非法 AID: ${invalid.join(', ')}`);
325
+ if (valid.length > 0) {
326
+ saveDaemonConfig({ ...loadDaemonConfig(), owners: valid });
327
+ console.log(` ✓ 已配置管理者: ${valid.join(', ')}`);
328
+ }
329
+ else {
330
+ console.log(' 未输入合法 AID,已跳过 owners 配置');
331
+ }
332
+ }
333
+ else {
334
+ console.log(' 已跳过 owners 配置(可日后编辑 daemon.json 或重跑 ec init)');
335
+ }
336
+ }
337
+ async function handleEcwebPrompt(rl) {
338
+ const daemonConfigForEcweb = loadDaemonConfig();
339
+ if (daemonConfigForEcweb.ecweb?.enabled === undefined) {
340
+ const ans = (await ask(rl, '\n是否在 ec start 时自动启动 ECWeb 控制台?[y/N] ')).trim().toLowerCase();
341
+ if (ans === 'y' || ans === 'yes') {
342
+ const cfg = loadDaemonConfig();
343
+ saveDaemonConfig({ ...cfg, ecweb: { ...(cfg.ecweb ?? {}), enabled: true } });
344
+ console.log(' ✓ 已启用 ECWeb(ec start 将自动在后台启动)');
345
+ const installed = await ensureEcwebInstalledForInit();
346
+ console.log(installed
347
+ ? ' 提示:首次访问运行 ec watch web 查看配对码和 URL'
348
+ : ' 提示:安装完成后运行 ec start;如需立即打开控制台,运行 ec watch web');
349
+ }
350
+ else {
351
+ saveDaemonConfig({ ...loadDaemonConfig(), ecweb: { enabled: false } });
352
+ console.log(' 已跳过(可日后运行 ec watch web 手动启动,或编辑 daemon.json)');
353
+ }
354
+ }
355
+ }
356
+ // 初始化完成总结
357
+ console.log('\n✓ EvolCore 初始化完成');
358
+ const finalCfg = loadDaemonConfig();
359
+ console.log(` 控制 AID: ${finalCfg.aid || '(未配置)'}`);
360
+ console.log(` 管理者: ${finalCfg.owners?.join(', ') || '(未配置)'}`);
361
+ console.log(` ECWeb 自启动: ${finalCfg.ecweb?.enabled ? '已启用' : '已禁用'}`);
362
+ const { agents: finalAgents } = loadAllAgents();
363
+ if (finalAgents.length === 0) {
364
+ console.log('\n📌 下一步:创建 agent');
365
+ console.log(' ec agent new <your-aid>.agentid.pub');
366
+ console.log(' ec init feishu # 绑定飞书');
367
+ console.log(' ec start # 启动服务');
368
+ }
369
+ else {
370
+ console.log(`\n✓ 已有 ${finalAgents.length} 个 agent,可直接运行:`);
371
+ console.log(' ec start');
372
+ }
373
+ }
374
+ /**
375
+ * Present instance selection menu when existing instances are found.
376
+ * Returns the user's choice, or null if cancelled.
377
+ */
378
+ export async function selectInstance(rl, channelType, instances) {
379
+ const typeLabel = channelType === 'feishu' ? '飞书' : channelType === 'wechat' ? '微信' : channelType === 'dingtalk' ? '钉钉' : channelType === 'qqbot' ? 'QQ机器人' : channelType === 'wecom' ? '企业微信' : channelType.toUpperCase();
380
+ console.log(`\n发现已有 ${typeLabel} 配置:`);
381
+ const letters = 'abcdefghijklmnopqrstuvwxyz';
382
+ for (let i = 0; i < instances.length; i++) {
383
+ const inst = instances[i];
384
+ const id = inst.aid || inst.appId || inst.botId || inst.clientId || inst.token?.slice(0, 16) || '';
385
+ const suffix = id ? ` (${id})` : '';
386
+ console.log(` ${letters[i]}. ${inst.name}${suffix}`);
387
+ }
388
+ const addLetter = letters[instances.length];
389
+ console.log(` ${addLetter}. 添加新配置`);
390
+ console.log('');
391
+ const validOptions = letters.slice(0, instances.length + 1).split('');
392
+ let choice = '';
393
+ while (!validOptions.includes(choice)) {
394
+ choice = (await new Promise(r => rl.question('请选择: ', r))).trim().toLowerCase();
395
+ if (!validOptions.includes(choice)) {
396
+ console.log(`无效选择,请输入 ${validOptions.join('/')}`);
397
+ }
398
+ }
399
+ const choiceIndex = letters.indexOf(choice);
400
+ if (choiceIndex === instances.length) {
401
+ let name = '';
402
+ while (!name) {
403
+ name = (await new Promise(r => rl.question('请输入新配置名称: ', r))).trim();
404
+ if (!name)
405
+ console.log(' 名称不能为空');
406
+ if (instances.some(i => i.name === name)) {
407
+ console.log(` 名称 "${name}" 已存在,请换一个`);
408
+ name = '';
409
+ }
410
+ }
411
+ return { action: 'add', name };
412
+ }
413
+ const target = instances[choiceIndex];
414
+ console.log(`\n已选择:${target.name}`);
415
+ const confirm = (await new Promise(r => rl.question(`⚠️ 即将覆盖该配置,确认?(y/N) `, r))).trim().toLowerCase();
416
+ if (confirm !== 'y' && confirm !== 'yes') {
417
+ console.log('已取消');
418
+ return null;
419
+ }
420
+ return { action: 'overwrite', index: choiceIndex, name: target.name };
421
+ }
422
+ const EXIT_USAGE = 1;
423
+ const EXIT_RUNTIME = 2;
424
+ function emitResult(result, format) {
425
+ if (format === 'json') {
426
+ process.stdout.write(JSON.stringify(result) + '\n');
427
+ }
428
+ else if (result.success) {
429
+ console.log(`✓ 初始化成功: controlAid=${result.controlAid} ownerAid=${result.ownerAid}`);
430
+ }
431
+ else {
432
+ console.error(`❌ ${result.error.code}: ${result.error.message}`);
433
+ }
434
+ }
435
+ function fail(code, message, exitCode, format) {
436
+ emitResult({ type: 'init.result', success: false, error: { code, message } }, format);
437
+ process.exit(exitCode);
438
+ }
439
+ export async function cmdInitNonInteractive(opts) {
440
+ const format = opts.format;
441
+ const p = resolvePaths();
442
+ ensureDataDirs();
443
+ // ── 1. owner 校验 ──
444
+ if (!opts.owner) {
445
+ fail('MISSING_OWNER', '--owner is required in non-interactive mode', EXIT_USAGE, format);
446
+ }
447
+ if (/[\s,]/.test(opts.owner)) {
448
+ fail('INVALID_OWNER', '--owner accepts only a single AID (no comma/space lists)', EXIT_USAGE, format);
449
+ }
450
+ const { isValidAid } = await import('../aun/aid/index.js');
451
+ if (!isValidAid(opts.owner)) {
452
+ fail('INVALID_OWNER', `invalid owner AID: ${opts.owner}`, EXIT_USAGE, format);
453
+ }
454
+ const ownerAid = opts.owner;
455
+ // ── 2. 单进程互斥 ──
456
+ const aliveMains = scanInstances().mains.filter(m => m.alive);
457
+ if (aliveMains.length > 0) {
458
+ const pids = aliveMains.map(m => m.record.pid).join(', ');
459
+ fail('DAEMON_RUNNING', `EvolCore daemon is running (PID: ${pids}); run 'ec stop' first`, EXIT_USAGE, format);
460
+ }
461
+ // ── 3. baseagent 探测 + 校验 ──
462
+ const available = detectAvailable();
463
+ if (available.length === 0) {
464
+ fail('BASEAGENT_UNAVAILABLE', 'no baseagent CLI detected (install claude/codex/gemini)', EXIT_USAGE, format);
465
+ }
466
+ let chosenBaseagent;
467
+ if (opts.baseagent) {
468
+ if (!BASEAGENT_CANDIDATES.includes(opts.baseagent)) {
469
+ fail('INVALID_BASEAGENT', `invalid baseagent: ${opts.baseagent} (choose: ${BASEAGENT_CANDIDATES.join('/')})`, EXIT_USAGE, format);
470
+ }
471
+ if (!available.includes(opts.baseagent)) {
472
+ const reason = opts.baseagent === 'codex' ? getCodexAppServerAvailability().reason : undefined;
473
+ fail('BASEAGENT_UNAVAILABLE', `${opts.baseagent} not available${reason ? `: ${reason}` : ''}`, EXIT_USAGE, format);
474
+ }
475
+ chosenBaseagent = opts.baseagent;
476
+ }
477
+ else {
478
+ chosenBaseagent = pickDefault(available);
479
+ }
480
+ // ── 4. projectpath 校验 + 创建 ──
481
+ let projectsDefaultPath;
482
+ if (opts.projectpath !== undefined) {
483
+ if (!path.isAbsolute(opts.projectpath)) {
484
+ fail('INVALID_PROJECT_PATH', `--projectpath must be absolute: ${opts.projectpath}`, EXIT_USAGE, format);
485
+ }
486
+ if (!fs.existsSync(opts.projectpath)) {
487
+ try {
488
+ fs.mkdirSync(opts.projectpath, { recursive: true });
489
+ }
490
+ catch (e) {
491
+ fail('PROJECT_PATH_CREATE_FAILED', `failed to create ${opts.projectpath}: ${e?.message || e}`, EXIT_RUNTIME, format);
492
+ }
493
+ }
494
+ projectsDefaultPath = opts.projectpath;
495
+ }
496
+ // ── 5. owner 冲突检测 ──
497
+ const existingCfg = loadDaemonConfig();
498
+ const existingOwners = existingCfg.owners ?? [];
499
+ const sameOwner = existingOwners.length === 1 && existingOwners[0] === ownerAid;
500
+ const differentOwner = existingOwners.length > 0 && !sameOwner;
501
+ if (differentOwner && !opts.force) {
502
+ fail('OWNER_EXISTS', `owners already set to [${existingOwners.join(', ')}]; use --force to override`, EXIT_USAGE, format);
503
+ }
504
+ const forced = differentOwner && !!opts.force;
505
+ const previousOwners = forced ? [...existingOwners] : undefined;
506
+ // ── 6. 写 defaults.json ──
507
+ try {
508
+ saveDefaultsSafe(buildDefaults(chosenBaseagent, available, projectsDefaultPath));
509
+ }
510
+ catch (e) {
511
+ fail('IO_ERROR', `failed to write defaults.json: ${e?.message || e}`, EXIT_RUNTIME, format);
512
+ }
513
+ // ── 7. 控制 AID:缺失则生成 ──
514
+ let controlAid = existingCfg.aid;
515
+ if (!controlAid) {
516
+ try {
517
+ const { aid } = await generateControlAid();
518
+ controlAid = aid;
519
+ }
520
+ catch (e) {
521
+ fail('CONTROL_AID_CREATE_FAILED', `gateway unreachable: ${e?.message || e}`, EXIT_RUNTIME, format);
522
+ }
523
+ }
524
+ // ── 8. 写 daemon.json(aid + owners + ecweb)──
525
+ try {
526
+ const next = {
527
+ ...existingCfg,
528
+ $schema_version: existingCfg.$schema_version ?? 1,
529
+ aid: controlAid,
530
+ owners: [ownerAid],
531
+ ...(opts.ecweb === true ? { ecweb: { ...(existingCfg.ecweb ?? {}), enabled: true } } : {}),
532
+ };
533
+ saveDaemonConfig(next);
534
+ }
535
+ catch (e) {
536
+ fail('IO_ERROR', `failed to write daemon.json: ${e?.message || e}`, EXIT_RUNTIME, format);
537
+ }
538
+ // ── 9. 输出 init.result ──
539
+ const result = {
540
+ type: 'init.result',
541
+ success: true,
542
+ controlAid: controlAid,
543
+ ownerAid,
544
+ owners: [ownerAid],
545
+ ecwebEnabled: opts.ecweb === true,
546
+ baseagent: chosenBaseagent,
547
+ projectsDefaultPath: projectsDefaultPath ?? null,
548
+ defaultsPath: p.defaultsConfig,
549
+ daemonConfigPath: p.daemonConfig,
550
+ ...(forced ? { forced: true, previousOwners } : {}),
551
+ };
552
+ emitResult(result, format);
553
+ }