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,616 @@
1
+ import { agentCreateNonInteractive, agentDelete, agentEnable, agentDisable, agentList, agentShow, agentSet, agentReload, } from '../../cli/agent.js';
2
+ import { logger } from '../../utils/logger.js';
3
+ import { resolvePaths, resolveRoot } from '../../paths.js';
4
+ import path from 'path';
5
+ import { ConfigTarget, ensureFile as cfgEnsure, read as cfgRead, write as cfgWrite, } from '../../config/config-manager.js';
6
+ import { CreateStatusWriter, readCreateStatus } from '../message/create-status.js';
7
+ import { deriveAgentProjectPath } from '../../utils/project-path.js';
8
+ import { uploadAvatar } from '../../utils/avatar-upload.js';
9
+ import { agentmdGet, agentmdPut, updateAgentMdFrontmatterName } from '../../aun/aid/agentmd.js';
10
+ import { isValidAid } from '../../aun/aid/validation.js';
11
+ const SUPPORTED_AGENT_PATCH_FIELDS = new Set(['aid', 'name', 'avatar', 'active_baseagent', 'baseagents', 'projects', 'owners', 'chatmode', 'channels', 'channelOwners']);
12
+ const HIDDEN_VALUE = '[hidden]';
13
+ const SENSITIVE_CONFIG_KEYS = new Set([
14
+ 'apiKey',
15
+ 'apikey',
16
+ 'appId',
17
+ 'appSecret',
18
+ 'botId',
19
+ 'clientId',
20
+ 'clientSecret',
21
+ 'secret',
22
+ 'token',
23
+ 'accessToken',
24
+ 'authorization',
25
+ 'credential',
26
+ 'credentials',
27
+ 'password',
28
+ 'privateKey',
29
+ 'encryptionSeed',
30
+ ]);
31
+ const HIDDEN_SETTINGS_KEYS = new Set([
32
+ 'pathToClaudeCodeExecutable',
33
+ 'enableRequestUserInput',
34
+ 'approvalsReviewer',
35
+ ]);
36
+ /** 把 cli/agent.ts 的 error 字符串映射为结构化错误码 */
37
+ function classifyError(error) {
38
+ if (/already exists/i.test(error))
39
+ return 'CONFLICT';
40
+ if (/not found/i.test(error))
41
+ return 'NOT_FOUND';
42
+ if (/invalid|must be|required|缺少/i.test(error))
43
+ return 'INVALID_ARGS';
44
+ return 'INTERNAL';
45
+ }
46
+ function classifyAgentMdError(error) {
47
+ if (/not found|404|不存在/i.test(error))
48
+ return 'NOT_FOUND';
49
+ if (/invalid|must be|required|缺少|frontmatter|empty|为空/i.test(error))
50
+ return 'INVALID_ARGS';
51
+ return 'UPLOAD_FAILED';
52
+ }
53
+ async function updateAgentMdName(aid, value) {
54
+ const name = typeof value === 'string' ? value.trim() : '';
55
+ if (!name)
56
+ return { ok: false, error: 'name 不能为空', code: 'INVALID_ARGS' };
57
+ try {
58
+ const content = await agentmdGet(aid, { aunPath: resolveRoot() });
59
+ const updated = updateAgentMdFrontmatterName(content, name);
60
+ await agentmdPut(updated.content, { aid, aunPath: resolveRoot() });
61
+ return { ok: true, name };
62
+ }
63
+ catch (e) {
64
+ const message = e?.message || String(e);
65
+ return { ok: false, error: `更新 agent.md name 失败: ${message}`, code: classifyAgentMdError(message) };
66
+ }
67
+ }
68
+ function toPosix(p) {
69
+ return p.replace(/\\/g, '/');
70
+ }
71
+ function stripUnsupportedProjectFields(projects) {
72
+ if (!projects || typeof projects !== 'object')
73
+ return undefined;
74
+ const out = {};
75
+ if (typeof projects.defaultPath === 'string')
76
+ out.defaultPath = projects.defaultPath;
77
+ return Object.keys(out).length ? out : undefined;
78
+ }
79
+ function normalizeProjectsPatch(value) {
80
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
81
+ return { ok: false, error: 'projects 必须是对象' };
82
+ }
83
+ const p = value;
84
+ const unsupported = Object.keys(p).filter(k => k !== 'defaultPath');
85
+ if (unsupported.length > 0) {
86
+ return { ok: false, error: `projects.${unsupported.join(' / projects.')} 不可写;agent 仅支持 projects.defaultPath` };
87
+ }
88
+ const out = {};
89
+ if (p.defaultPath !== undefined) {
90
+ if (typeof p.defaultPath !== 'string')
91
+ return { ok: false, error: 'projects.defaultPath 必须是字符串' };
92
+ out.defaultPath = p.defaultPath;
93
+ }
94
+ return { ok: true, value: out };
95
+ }
96
+ function normalizeBaseagentsPatch(value) {
97
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
98
+ return { ok: false, error: 'baseagents 必须是对象' };
99
+ }
100
+ const out = {};
101
+ for (const [name, raw] of Object.entries(value)) {
102
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
103
+ return { ok: false, error: `baseagents.${name} 必须是对象` };
104
+ }
105
+ const block = { ...raw };
106
+ if (Object.prototype.hasOwnProperty.call(block, 'reasoning')) {
107
+ if (block.effort === undefined)
108
+ block.effort = block.reasoning;
109
+ delete block.reasoning;
110
+ }
111
+ out[name] = block;
112
+ }
113
+ return { ok: true, value: out };
114
+ }
115
+ function mergeBaseagentsPatch(existing, patch) {
116
+ const current = existing && typeof existing === 'object' && !Array.isArray(existing)
117
+ ? { ...existing }
118
+ : {};
119
+ for (const [name, patchBlock] of Object.entries(patch)) {
120
+ const rawExisting = current[name];
121
+ const nextBlock = rawExisting && typeof rawExisting === 'object' && !Array.isArray(rawExisting)
122
+ ? { ...rawExisting }
123
+ : {};
124
+ for (const [key, value] of Object.entries(patchBlock)) {
125
+ if (value === null)
126
+ delete nextBlock[key];
127
+ else
128
+ nextBlock[key] = value;
129
+ }
130
+ if (Object.keys(nextBlock).length > 0)
131
+ current[name] = nextBlock;
132
+ else
133
+ delete current[name];
134
+ }
135
+ return current;
136
+ }
137
+ function normalizeStringList(value, label) {
138
+ const rawItems = Array.isArray(value)
139
+ ? value
140
+ : (typeof value === 'string' ? value.split(/[\s,,]+/) : null);
141
+ if (!rawItems)
142
+ return { ok: false, error: `${label} 必须是字符串数组或分隔字符串` };
143
+ const seen = new Set();
144
+ const out = [];
145
+ for (const raw of rawItems) {
146
+ if (typeof raw !== 'string')
147
+ return { ok: false, error: `${label} 只能包含字符串` };
148
+ const item = raw.trim();
149
+ if (!item || seen.has(item))
150
+ continue;
151
+ seen.add(item);
152
+ out.push(item);
153
+ }
154
+ return { ok: true, value: out };
155
+ }
156
+ function normalizeChannelOwnersPatch(value) {
157
+ if (!Array.isArray(value))
158
+ return { ok: false, error: 'channelOwners 必须是数组' };
159
+ const out = [];
160
+ const seen = new Set();
161
+ for (const [idx, raw] of value.entries()) {
162
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
163
+ return { ok: false, error: `channelOwners[${idx}] 必须是对象` };
164
+ }
165
+ const item = raw;
166
+ const type = typeof item.type === 'string' ? item.type.trim() : '';
167
+ const name = typeof item.name === 'string' ? item.name.trim() : '';
168
+ if (!type || !name)
169
+ return { ok: false, error: `channelOwners[${idx}] 缺少 type/name` };
170
+ if (type === 'aun')
171
+ return { ok: false, error: 'AUN 渠道 owner 由 agent 顶层 owners 管理,不支持 channelOwners 编辑' };
172
+ const owners = normalizeStringList(item.owners, `channelOwners[${idx}].owners`);
173
+ if (!owners.ok)
174
+ return owners;
175
+ const key = `${type}\0${name}`;
176
+ if (seen.has(key))
177
+ return { ok: false, error: `channelOwners 重复渠道: ${type}/${name}` };
178
+ seen.add(key);
179
+ out.push({ type, name, owners: owners.value });
180
+ }
181
+ return { ok: true, value: out };
182
+ }
183
+ function applyChannelOwnersPatch(config, patch) {
184
+ const channels = Array.isArray(config.channels) ? config.channels : [];
185
+ let changed = false;
186
+ for (const item of patch) {
187
+ const channel = channels.find((c) => c && typeof c === 'object' && !Array.isArray(c) &&
188
+ String(c.type || '').trim() === item.type &&
189
+ String(c.name || '').trim() === item.name);
190
+ if (!channel)
191
+ return { ok: false, error: `未找到渠道: ${item.type}/${item.name}` };
192
+ const before = JSON.stringify({
193
+ owners: channel.owners,
194
+ owner: channel.owner,
195
+ ownerId: channel.ownerId,
196
+ ownerAid: channel.ownerAid,
197
+ ownerIds: channel.ownerIds,
198
+ ownerAids: channel.ownerAids,
199
+ admins: channel.admins,
200
+ });
201
+ channel.owners = item.owners;
202
+ delete channel.owner;
203
+ delete channel.ownerId;
204
+ delete channel.ownerAid;
205
+ delete channel.ownerIds;
206
+ delete channel.ownerAids;
207
+ delete channel.admins;
208
+ const after = JSON.stringify({ owners: channel.owners });
209
+ if (before !== after)
210
+ changed = true;
211
+ }
212
+ return { ok: true, changed };
213
+ }
214
+ function sanitizeConfigValue(value) {
215
+ if (Array.isArray(value))
216
+ return value.map(sanitizeConfigValue);
217
+ if (!value || typeof value !== 'object')
218
+ return value;
219
+ const out = {};
220
+ for (const [key, raw] of Object.entries(value)) {
221
+ if (HIDDEN_SETTINGS_KEYS.has(key)) {
222
+ continue;
223
+ }
224
+ if (key === 'reasoning') {
225
+ if (out.effort === undefined)
226
+ out.effort = sanitizeConfigValue(raw);
227
+ }
228
+ else if (SENSITIVE_CONFIG_KEYS.has(key)) {
229
+ out[key] = raw == null || raw === '' ? raw : HIDDEN_VALUE;
230
+ }
231
+ else if (key === 'projects') {
232
+ out[key] = stripUnsupportedProjectFields(raw) ?? {};
233
+ }
234
+ else {
235
+ out[key] = sanitizeConfigValue(raw);
236
+ }
237
+ }
238
+ return out;
239
+ }
240
+ function buildSafeAgentConfig(config) {
241
+ if (!config)
242
+ return null;
243
+ return sanitizeConfigValue({
244
+ ...config,
245
+ active_baseagent: config.active_baseagent ?? null,
246
+ owners: config.owners ?? [],
247
+ channels: config.channels ?? [],
248
+ baseagents: config.baseagents ?? {},
249
+ projects: stripUnsupportedProjectFields(config.projects) ?? {},
250
+ });
251
+ }
252
+ function buildCreateProgressOnlyAgent(aid, progress) {
253
+ const agentDir = path.join(resolvePaths().agentsDir, aid);
254
+ return {
255
+ aid,
256
+ status: progress?.status === 'failed' ? 'error' : 'stopped',
257
+ identity: { name: null, description: null },
258
+ config: {
259
+ baseagent: null,
260
+ model: null,
261
+ effort: null,
262
+ chatmode: null,
263
+ owners: [],
264
+ channels: [],
265
+ },
266
+ connection: null,
267
+ sessions: { active: 0, last_activity: null },
268
+ paths: {
269
+ config: toPosix(path.join(agentDir, 'config.json')),
270
+ agent_md: null,
271
+ project: null,
272
+ data: toPosix(path.join(agentDir, 'data')),
273
+ },
274
+ createProgress: progress,
275
+ };
276
+ }
277
+ /** 后台异步:实际创建 agent + 落 model/effort/chatmode,全程写构建进度(D3)。
278
+ * 失败仅写日志 + create-status,不回传(受理即返回)。
279
+ * agentSet key 对照 cli/agent.ts 的 setNestedValue:
280
+ * model/effort → 'baseagents.<baseagent>.*';chatmode → 'chatmode'(ChatmodeBlock 对象)。 */
281
+ async function runCreateInBackground(opts, w) {
282
+ let curPhase = 'validating'; // 跟踪当前环节,供 catch 兜底时标注正确 phase
283
+ try {
284
+ // onPhase 把 agentCreateNonInteractive 内部环节(0-3、5)映射到进度文件
285
+ const res = await agentCreateNonInteractive({
286
+ aid: opts.aid, name: opts.name, baseagent: opts.baseagent,
287
+ project: opts.project, owner: opts.owner,
288
+ onPhase: (phase, state, detail) => {
289
+ if (state === 'begin') {
290
+ curPhase = phase;
291
+ w.begin(phase);
292
+ }
293
+ else if (state === 'done')
294
+ w.done(phase, detail);
295
+ else if (state === 'warn')
296
+ w.warn(phase, detail);
297
+ else if (state === 'failed')
298
+ w.finishFailed(phase, detail ?? 'failed');
299
+ },
300
+ });
301
+ if (!('ok' in res) || res.ok !== true) {
302
+ // 硬失败:onPhase('failed') 已写终态;这里仅兜底日志(防回调未覆盖的 return 路径)
303
+ const err = res.error;
304
+ logger.warn(`[agent-control] create ${opts.aid} failed: ${err}`);
305
+ return;
306
+ }
307
+ // 环节 4:applying_config(model/effort/chatmode,agentCreateNonInteractive 之外)
308
+ if (opts.model || opts.effort || opts.chatmode) {
309
+ curPhase = 'applying_config';
310
+ w.begin('applying_config');
311
+ let warned;
312
+ if (opts.model) {
313
+ const r = await agentSet(opts.aid, `baseagents.${opts.baseagent}.model`, opts.model);
314
+ if (!('ok' in r) || !r.ok)
315
+ warned = `model: ${r.error}`;
316
+ }
317
+ if (opts.effort) {
318
+ const r = await agentSet(opts.aid, `baseagents.${opts.baseagent}.effort`, opts.effort);
319
+ if (!('ok' in r) || !r.ok)
320
+ warned = `${warned ? warned + '; ' : ''}effort: ${r.error}`;
321
+ }
322
+ if (opts.chatmode) {
323
+ const r = await agentSet(opts.aid, 'chatmode', JSON.stringify(opts.chatmode));
324
+ if (!('ok' in r) || !r.ok)
325
+ warned = `${warned ? warned + '; ' : ''}chatmode: ${r.error}`;
326
+ }
327
+ if (warned) {
328
+ logger.warn(`[agent-control] applying_config ${opts.aid}: ${warned}`);
329
+ w.warn('applying_config', warned);
330
+ }
331
+ else
332
+ w.done('applying_config');
333
+ }
334
+ w.finishReady();
335
+ opts.eventBus?.publish({
336
+ type: 'agent:created',
337
+ aid: opts.aid,
338
+ name: opts.name,
339
+ baseagent: opts.baseagent,
340
+ projectPath: opts.project,
341
+ owner: opts.owner,
342
+ timestamp: Date.now(),
343
+ });
344
+ logger.info(`[agent-control] create ${opts.aid} ready`);
345
+ }
346
+ catch (e) {
347
+ const msg = e?.message || String(e);
348
+ logger.warn(`[agent-control] create ${opts.aid} threw at ${curPhase}: ${msg}`);
349
+ w.finishFailed(curPhase, msg); // 兜底终态,标注真实失败环节
350
+ opts.eventBus?.publish({ type: 'agent:error', aid: opts.aid, action: 'create', error: msg, timestamp: Date.now() });
351
+ }
352
+ }
353
+ /** name=agent 的 menu.action 执行。create 使用显式 owner AID;peerId 仅作为控制面鉴权主体。
354
+ * create 受理即返回(D3);delete/enable/disable 同步等结果。
355
+ * 调用方负责传入已兜底的 args.project(见 command-handler 装配)。 */
356
+ export async function execAgentAction(action, args, peerId, eventBus) {
357
+ const a = args ?? {};
358
+ if (action === 'create') {
359
+ if (!peerId)
360
+ return { error: '缺少发起者 AID(无法校验控制权限)', code: 'INVALID_ARGS' };
361
+ if (!a.aid || !a.name || !a.baseagent) {
362
+ return { error: '缺少必填参数:aid / name / baseagent', code: 'INVALID_ARGS' };
363
+ }
364
+ const owner = typeof a.owner === 'string' && a.owner.trim() ? a.owner.trim() : peerId.trim();
365
+ if (!owner)
366
+ return { error: '缺少 owner AID', code: 'INVALID_ARGS' };
367
+ if (!isValidAid(owner))
368
+ return { error: `无效 owner AID: ${owner}`, code: 'INVALID_ARGS' };
369
+ if (!a.project || typeof a.project !== 'string') {
370
+ return { error: 'project 缺失且无法兜底(需 defaults.projects.rootPath/defaultPath)', code: 'INVALID_ARGS' };
371
+ }
372
+ const model = typeof a.model === 'string' && a.model.trim() ? a.model.trim() : undefined;
373
+ const rawEffort = typeof a.effort === 'string' && a.effort.trim() ? a.effort.trim() : undefined;
374
+ const effort = rawEffort && rawEffort !== 'auto' ? rawEffort : undefined;
375
+ // D3: accepted=true 必须意味着后续 query 能查到该 AID 的创建状态。
376
+ let progressWriter;
377
+ try {
378
+ progressWriter = new CreateStatusWriter(path.join(resolvePaths().agentsDir, a.aid), a.aid);
379
+ }
380
+ catch (e) {
381
+ return { error: `创建进度状态初始化失败: ${e?.message || e}`, code: 'INTERNAL' };
382
+ }
383
+ // 重副作用转后台,后台内部有 try/catch;这里 catch 只兜底未预期拒绝。
384
+ void runCreateInBackground({
385
+ aid: a.aid, name: a.name, baseagent: a.baseagent,
386
+ project: a.project, owner,
387
+ model, effort, chatmode: a.chatmode,
388
+ eventBus,
389
+ }, progressWriter).catch(e => logger.error(`[agent-control] runCreateInBackground unhandled ${a.aid}: ${e?.message || e}`));
390
+ return { data: { accepted: true, aid: a.aid } };
391
+ }
392
+ if (action === 'delete') {
393
+ if (!a.aid)
394
+ return { error: '缺少 aid', code: 'INVALID_ARGS' };
395
+ const res = await agentDelete(a.aid, false);
396
+ if (!('ok' in res) || res.ok !== true)
397
+ return { error: res.error, code: classifyError(res.error) };
398
+ eventBus?.publish({ type: 'agent:deleted', aid: res.aid, purged: res.purged, timestamp: Date.now() });
399
+ return { data: { aid: res.aid, purged: res.purged } };
400
+ }
401
+ if (action === 'enable' || action === 'disable') {
402
+ if (!a.aid)
403
+ return { error: '缺少 aid', code: 'INVALID_ARGS' };
404
+ const res = action === 'enable' ? await agentEnable(a.aid) : await agentDisable(a.aid);
405
+ if (!('ok' in res) || res.ok !== true)
406
+ return { error: res.error, code: classifyError(res.error) };
407
+ eventBus?.publish({
408
+ type: action === 'enable' ? 'agent:enabled' : 'agent:disabled',
409
+ aid: res.aid,
410
+ reloaded: res.reloaded,
411
+ timestamp: Date.now(),
412
+ });
413
+ return { data: { aid: res.aid, enabled: res.enabled, reloaded: res.reloaded } };
414
+ }
415
+ if (action === 'reload') {
416
+ if (!a.aid)
417
+ return { error: '缺少 aid', code: 'INVALID_ARGS' };
418
+ const res = await agentReload(a.aid);
419
+ if (!('ok' in res) || res.ok !== true)
420
+ return { error: res.error, code: classifyError(res.error) };
421
+ eventBus?.publish({ type: 'agent:reloaded', aid: a.aid, timestamp: Date.now() });
422
+ return { data: { aid: a.aid, reloaded: true } };
423
+ }
424
+ if (action === 'update') {
425
+ const result = await execAgentUpdate(a);
426
+ if (!('error' in result)) {
427
+ if (result.data?.avatar) {
428
+ eventBus?.publish({
429
+ type: 'agent:avatar_updated',
430
+ aid: a.aid,
431
+ avatar: result.data.avatar,
432
+ timestamp: Date.now(),
433
+ });
434
+ }
435
+ eventBus?.publish({
436
+ type: 'agent:updated',
437
+ aid: a.aid,
438
+ nameChanged: Boolean(result.data?.name),
439
+ timestamp: Date.now(),
440
+ });
441
+ }
442
+ return result;
443
+ }
444
+ return { error: `不支持的 action: ${action}`, code: 'INVALID_ARGS' };
445
+ }
446
+ /** name=agent 的 menu.action=update:落盘 config patch / agent.md patch,不触发 reload。
447
+ * 直接通过 ConfigManager 读写 agent config(不走 agentSet,避免其内部自动 evolagent.reload)——
448
+ * 重载由用户在 Agents 页操作列手动触发(带任务执行检查)。
449
+ * AUN 渠道绑定 agent 顶层 aid,不可通过 patch 编辑:拒绝改 aid、拒绝 channels 数组里出现 aun 条目。
450
+ * 可写字段:name / active_baseagent / baseagents / projects / owners / chatmode / channels(非 aun)/
451
+ * channelOwners(按 type/name 局部更新非 AUN channel owners,避免前端回写脱敏 credentials)。 */
452
+ export async function execAgentUpdate(args) {
453
+ const a = args ?? {};
454
+ if (!a.aid)
455
+ return { error: '缺少 aid', code: 'INVALID_ARGS' };
456
+ const p = a.patch ?? {};
457
+ if (!p || typeof p !== 'object' || Array.isArray(p)) {
458
+ return { error: 'patch 必须是对象', code: 'INVALID_ARGS' };
459
+ }
460
+ const unsupported = Object.keys(p).filter(k => !SUPPORTED_AGENT_PATCH_FIELDS.has(k));
461
+ if (unsupported.length > 0) {
462
+ return { error: `不支持的 patch 字段: ${unsupported.join(', ')}`, code: 'UNSUPPORTED_FIELD' };
463
+ }
464
+ if (p.aid !== undefined) {
465
+ return { error: 'aid 不可修改(AUN 身份绑定,如需换 AID 请删除后重建)', code: 'INVALID_ARGS' };
466
+ }
467
+ if (p.avatar !== undefined) {
468
+ const otherKeys = Object.keys(p).filter(k => k !== 'avatar');
469
+ if (otherKeys.length > 0) {
470
+ return { error: 'avatar 不能与其他 patch 字段同时提交,请拆分为两次 update', code: 'INVALID_ARGS' };
471
+ }
472
+ }
473
+ if (p.name !== undefined) {
474
+ const otherKeys = Object.keys(p).filter(k => k !== 'name');
475
+ if (otherKeys.length > 0) {
476
+ return { error: 'name 不能与其他 patch 字段同时提交,请拆分为两次 update', code: 'INVALID_ARGS' };
477
+ }
478
+ }
479
+ if (Array.isArray(p.channels) && p.channels.some((c) => c?.type === 'aun')) {
480
+ return { error: 'AUN 渠道不可通过 patch 编辑(由 agent aid 隐式管理)', code: 'INVALID_ARGS' };
481
+ }
482
+ if (p.channels !== undefined && p.channelOwners !== undefined) {
483
+ return { error: 'channels 与 channelOwners 不能同时提交', code: 'INVALID_ARGS' };
484
+ }
485
+ const config = cfgRead(ConfigTarget.Agent, { self: a.aid });
486
+ if (!config)
487
+ return { error: `Agent "${a.aid}" not found`, code: 'NOT_FOUND' };
488
+ if (p.avatar !== undefined) {
489
+ const result = await uploadAvatar(a.aid, p.avatar, { aunPath: resolveRoot() });
490
+ if (!result.ok) {
491
+ return { error: `头像上传失败: ${result.error}`, code: result.code ?? 'UPLOAD_FAILED' };
492
+ }
493
+ return { data: { aid: a.aid, avatar: result.publicUrl, saved: true } };
494
+ }
495
+ let touched = false;
496
+ const data = { aid: a.aid };
497
+ const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owners !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
498
+ if (p.active_baseagent !== undefined) {
499
+ if (typeof p.active_baseagent !== 'string' || !p.active_baseagent.trim()) {
500
+ return { error: `无效 active_baseagent: ${JSON.stringify(p.active_baseagent)}(必须是非空字符串)`, code: 'INVALID_ARGS' };
501
+ }
502
+ config.active_baseagent = p.active_baseagent.trim();
503
+ touched = true;
504
+ }
505
+ if (p.baseagents !== undefined) {
506
+ const normalized = normalizeBaseagentsPatch(p.baseagents);
507
+ if (!normalized.ok)
508
+ return { error: normalized.error, code: 'INVALID_ARGS' };
509
+ config.baseagents = mergeBaseagentsPatch(config.baseagents, normalized.value);
510
+ touched = true;
511
+ }
512
+ if (p.projects !== undefined) {
513
+ const normalized = normalizeProjectsPatch(p.projects);
514
+ if (!normalized.ok)
515
+ return { error: normalized.error, code: 'INVALID_ARGS' };
516
+ config.projects = normalized.value;
517
+ touched = true;
518
+ }
519
+ else {
520
+ const normalizedExisting = stripUnsupportedProjectFields(config.projects);
521
+ if (normalizedExisting)
522
+ config.projects = normalizedExisting;
523
+ else
524
+ delete config.projects;
525
+ }
526
+ if (p.owners !== undefined) {
527
+ config.owners = p.owners;
528
+ touched = true;
529
+ }
530
+ if (p.chatmode !== undefined) {
531
+ config.chatmode = p.chatmode;
532
+ touched = true;
533
+ }
534
+ if (p.channels !== undefined) {
535
+ config.channels = p.channels;
536
+ touched = true;
537
+ }
538
+ if (p.channelOwners !== undefined) {
539
+ const normalized = normalizeChannelOwnersPatch(p.channelOwners);
540
+ if (!normalized.ok)
541
+ return { error: normalized.error, code: 'INVALID_ARGS' };
542
+ const applied = applyChannelOwnersPatch(config, normalized.value);
543
+ if (!applied.ok)
544
+ return { error: applied.error, code: 'INVALID_ARGS' };
545
+ touched = true;
546
+ }
547
+ if (p.name !== undefined) {
548
+ const result = await updateAgentMdName(a.aid, p.name);
549
+ if (!result.ok)
550
+ return { error: result.error, code: result.code };
551
+ data.name = result.name;
552
+ touched = true;
553
+ }
554
+ if (!touched)
555
+ return { error: 'patch 为空,无可写字段', code: 'INVALID_ARGS' };
556
+ if (hasConfigPatch) {
557
+ try {
558
+ cfgEnsure(ConfigTarget.Agent, { self: a.aid });
559
+ cfgWrite(ConfigTarget.Agent, config, { self: a.aid });
560
+ }
561
+ catch (e) {
562
+ return { error: e?.message || String(e), code: classifyError(e?.message || String(e)) };
563
+ }
564
+ }
565
+ return { data: { ...data, saved: true, ...(hasConfigPatch ? { requiresReload: true } : {}) } };
566
+ }
567
+ /** project 兜底:显式值 > rootPath 合成 > defaultPath > undefined */
568
+ export function resolveProjectPath(explicit, aid, defaults) {
569
+ if (explicit && explicit.trim())
570
+ return explicit;
571
+ const root = defaults?.projects?.rootPath;
572
+ if (root)
573
+ return deriveAgentProjectPath(root, aid);
574
+ return defaults?.projects?.defaultPath;
575
+ }
576
+ /** name=agent 的 menu.query:查单个 agent 详情,附构建进度(D3)。 */
577
+ export async function execAgentQuery(args) {
578
+ const aid = args?.aid;
579
+ if (!aid)
580
+ return { error: '缺少 aid', code: 'INVALID_ARGS' };
581
+ const agentDir = path.join(resolvePaths().agentsDir, aid);
582
+ const progress = readCreateStatus(agentDir);
583
+ const res = await agentShow(aid);
584
+ if (!('ok' in res) || res.ok !== true) {
585
+ const code = classifyError(res.error);
586
+ if (code === 'NOT_FOUND' && progress)
587
+ return { data: buildCreateProgressOnlyAgent(aid, progress) };
588
+ return { error: res.error, code };
589
+ }
590
+ const config = cfgRead(ConfigTarget.Agent, { self: aid });
591
+ const safeConfig = buildSafeAgentConfig(config);
592
+ const data = {
593
+ ...res,
594
+ config: {
595
+ ...(res.config ?? {}),
596
+ active_baseagent: config?.active_baseagent ?? res.config?.baseagent ?? null,
597
+ projects: stripUnsupportedProjectFields(config?.projects) ?? {},
598
+ baseagents: config?.baseagents ?? {},
599
+ owners: config?.owners ?? res.config?.owners ?? [],
600
+ },
601
+ safeConfig,
602
+ };
603
+ // 叠加构建进度(create 受理后、ready 前可见;ready 后文件仍在,可反映软失败 warn)
604
+ return { data: progress ? { ...data, createProgress: progress } : data };
605
+ }
606
+ /** name=agent 的 menu.options:列出 agent(enabled 默认 / all) */
607
+ export async function execAgentOptions(args) {
608
+ const scope = args?.options === 'all' ? 'all' : 'enabled';
609
+ const res = await agentList();
610
+ if (!('ok' in res) || res.ok !== true)
611
+ return { error: res.error, code: classifyError(res.error) };
612
+ const agents = scope === 'all'
613
+ ? res.agents
614
+ : res.agents.filter((x) => x.status !== 'disabled');
615
+ return { data: { agents, scope } };
616
+ }