evolcore 0.0.35 → 0.0.36

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 (224) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +6 -0
  3. package/bin/install-codex-managed-hooks.mjs +20 -3
  4. package/dist/agents/baseagent-availability.js +1 -1
  5. package/dist/agents/baseagent.js +88 -0
  6. package/dist/agents/claude-runner.js +59 -12
  7. package/dist/agents/codex/app-server-client.js +18 -1
  8. package/dist/agents/codex-runner.js +262 -21
  9. package/dist/agents/ecagent-runner.js +47 -11
  10. package/dist/agents/gemini-runner.js +36 -12
  11. package/dist/aun/aid/client.js +4 -3
  12. package/dist/aun/aid/control-aid.js +270 -8
  13. package/dist/aun/aid/identity.js +6 -3
  14. package/dist/aun/aid/ownership-operation.js +58 -0
  15. package/dist/aun/aid/store.js +1 -0
  16. package/dist/aun/group/fs-download.js +67 -2
  17. package/dist/aun/group/history.js +20 -5
  18. package/dist/aun/group/operations.js +8 -2
  19. package/dist/aun/menu/client.js +39 -2
  20. package/dist/aun/menu/transport.js +1 -1
  21. package/dist/aun/msg/history.js +43 -4
  22. package/dist/aun/msg/managed-operation.js +30 -53
  23. package/dist/aun/msg/p2p.js +51 -15
  24. package/dist/aun/outbox.js +4 -0
  25. package/dist/channels/aun.js +260 -73
  26. package/dist/channels/daemon.js +6 -4
  27. package/dist/channels/feishu.js +3 -0
  28. package/dist/cli/agent-command.js +161 -223
  29. package/dist/cli/agent-create.js +190 -223
  30. package/dist/cli/agent.js +3 -1
  31. package/dist/cli/aid-bind-command.js +53 -0
  32. package/dist/cli/aun-commands.js +384 -91
  33. package/dist/cli/bench.js +1 -1
  34. package/dist/cli/cli-argv.js +74 -0
  35. package/dist/cli/daemon-commands.js +105 -74
  36. package/dist/cli/diag.js +1 -1
  37. package/dist/cli/fs-command.js +18 -19
  38. package/dist/cli/getmeta-command.js +159 -6
  39. package/dist/cli/index.js +6 -12
  40. package/dist/cli/init-channel.js +8 -55
  41. package/dist/cli/init.js +125 -218
  42. package/dist/cli/queue-command.js +11 -8
  43. package/dist/cli/restart-monitor.js +134 -48
  44. package/dist/cli/session-command.js +1 -1
  45. package/dist/cli/stats.js +7 -5
  46. package/dist/cli/thread-command.js +103 -30
  47. package/dist/cli/trigger-command.js +1 -1
  48. package/dist/cli/watch-msg-diag.js +1 -0
  49. package/dist/config/access-policy.js +2 -2
  50. package/dist/config/boot-log.js +14 -11
  51. package/dist/config/config-field-policy.js +9 -1
  52. package/dist/config/config-manager.js +176 -90
  53. package/dist/config/config-operation-service.js +7 -14
  54. package/dist/config/contact-book-store.js +142 -26
  55. package/dist/config/contact-book.js +4 -2
  56. package/dist/config/lifecycle.js +1 -1
  57. package/dist/config/owner-config.js +96 -0
  58. package/dist/config/peer-role-resolver.js +12 -18
  59. package/dist/config/providers-config.js +382 -0
  60. package/dist/config/providers-import.js +74 -0
  61. package/dist/config/providers-management.js +328 -0
  62. package/dist/config/providers.js +22 -0
  63. package/dist/config/resolved-config-op.js +17 -14
  64. package/dist/config/snapshot.js +28 -16
  65. package/dist/config-store.js +18 -14
  66. package/dist/core/agent-ipc-registration.js +21 -63
  67. package/dist/core/agent-runtime.js +16 -5
  68. package/dist/core/auth/agent-delegation.js +199 -25
  69. package/dist/core/auth/auth-gateway.js +44 -2
  70. package/dist/core/auth/authorization-denial.js +1 -1
  71. package/dist/core/auth/debug-context.js +2 -1
  72. package/dist/core/auth/delegation-authorization.js +2 -2
  73. package/dist/core/auth/delegation-diagnostics.js +4 -1
  74. package/dist/core/auth/operation-authorizer.js +10 -1
  75. package/dist/core/auth/operation-catalog.js +19 -1
  76. package/dist/core/bootstrap-service.js +43 -20
  77. package/dist/core/channel-loader.js +0 -1
  78. package/dist/core/channel-runtime.js +30 -4
  79. package/dist/core/command/agent-control.js +196 -37
  80. package/dist/core/command/cli-intent-parser.js +60 -4
  81. package/dist/core/command/command-handler.js +212 -60
  82. package/dist/core/command/connect-menu.js +1 -0
  83. package/dist/core/command/diag-service.js +5 -4
  84. package/dist/core/command/file-search.js +368 -0
  85. package/dist/core/command/menu-catalog.js +2 -1
  86. package/dist/core/command/menu-handler.js +292 -107
  87. package/dist/core/command/menu-protocol.js +23 -0
  88. package/dist/core/command/role-menu.js +7 -19
  89. package/dist/core/command/skill-slash.js +130 -25
  90. package/dist/core/command/slash-handler.js +101 -53
  91. package/dist/core/command/topic-slash.js +16 -5
  92. package/dist/core/daemon-bootstrap.js +7 -1
  93. package/dist/core/daemon-control.js +19 -1
  94. package/dist/core/daemon-lifecycle.js +2 -1
  95. package/dist/core/event-catalog.js +2 -0
  96. package/dist/core/evolagent-registry.js +13 -2
  97. package/dist/core/evolagent.js +3 -6
  98. package/dist/core/handoff/ipc-registration.js +2 -2
  99. package/dist/core/handoff/runtime.js +40 -6
  100. package/dist/core/handoff/store.js +1 -0
  101. package/dist/core/inference/text-inference.js +95 -6
  102. package/dist/core/ipc-registration.js +43 -24
  103. package/dist/core/memory/consolidation-context.js +4 -1
  104. package/dist/core/memory/consolidation.js +25 -14
  105. package/dist/core/message/aun-ipc-sender.js +296 -88
  106. package/dist/core/message/aun-request-registry.js +226 -0
  107. package/dist/core/message/create-status.js +33 -4
  108. package/dist/core/message/message-bridge.js +62 -13
  109. package/dist/core/message/message-log.js +0 -1
  110. package/dist/core/message/message-queue.js +4 -1
  111. package/dist/core/message/message-utils.js +8 -1
  112. package/dist/core/message/peer-mode.js +17 -9
  113. package/dist/core/message/response-engine.js +266 -124
  114. package/dist/core/message/retry-scheduler.js +11 -8
  115. package/dist/core/model/catalog-service.js +60 -18
  116. package/dist/core/model/model-catalog.js +112 -9
  117. package/dist/core/model/model-fallback.js +94 -26
  118. package/dist/core/ownership/owner-resolver.js +687 -0
  119. package/dist/core/permission/approval-gateway.js +196 -62
  120. package/dist/core/permission/ec-command-parser.js +138 -25
  121. package/dist/core/permission/filesystem-approval-scope.js +141 -0
  122. package/dist/core/permission/protected-paths.js +14 -1
  123. package/dist/core/permission/sandbox-runtime.js +171 -18
  124. package/dist/core/permission/tool-policy.js +13 -2
  125. package/dist/core/role/runtime-policy.js +3 -4
  126. package/dist/core/session/session-idle-monitor.js +10 -8
  127. package/dist/core/session/session-manager.js +72 -45
  128. package/dist/core/session/session-mapper.js +18 -7
  129. package/dist/core/session/session-renew.js +5 -4
  130. package/dist/core/session/session-title.js +2 -1
  131. package/dist/core/session/session-turn-coordinator.js +4 -2
  132. package/dist/core/skill/index-generator.js +2 -16
  133. package/dist/core/task/task-recovery-service.js +15 -2
  134. package/dist/core/thread/command-parser.js +28 -13
  135. package/dist/core/thread/index.js +1 -0
  136. package/dist/core/thread/ipc-operation.js +11 -8
  137. package/dist/core/thread/thread-operation.js +79 -44
  138. package/dist/core/thread/thread-route.js +54 -6
  139. package/dist/core/thread/thread-service.js +236 -45
  140. package/dist/core/thread/topic-id.js +248 -0
  141. package/dist/eck/kit-renderer.js +1 -1
  142. package/dist/eck/message-renderer.js +12 -2
  143. package/dist/index.js +50 -27
  144. package/dist/ipc.js +59 -6
  145. package/dist/paths.js +1 -0
  146. package/dist/product.js +1 -0
  147. package/dist/response-system/engines/v1/proactive-flow.js +10 -3
  148. package/dist/stats/db.js +8 -0
  149. package/dist/stats/writer.js +26 -4
  150. package/dist/trigger/authorization.js +48 -3
  151. package/dist/trigger/feedback.js +28 -10
  152. package/dist/trigger/ipc-service.js +86 -10
  153. package/dist/trigger/local-files.js +55 -23
  154. package/dist/trigger/scheduler.js +57 -11
  155. package/dist/trigger/system-definitions.js +1 -0
  156. package/dist/trigger/validation.js +44 -15
  157. package/dist/utils/aid-bind.js +17 -297
  158. package/dist/utils/avatar-upload.js +16 -4
  159. package/dist/utils/cross-platform.js +109 -34
  160. package/dist/utils/ecweb-supervisor.js +1 -1
  161. package/dist/utils/ecweb-utils.js +8 -1
  162. package/dist/utils/error-utils.js +44 -6
  163. package/dist/utils/instance-registry.js +12 -2
  164. package/dist/utils/npm-ops.js +102 -27
  165. package/dist/utils/package-version-info.js +72 -27
  166. package/dist/utils/restart-safety.js +50 -0
  167. package/dist/utils/upgrade-jobs.js +304 -0
  168. package/dist/utils/windows-autostart.js +17 -10
  169. package/kits/docs/INDEX.md +5 -0
  170. package/kits/docs/aun/ABILITY_CALLING.md +239 -0
  171. package/kits/docs/evolcore/INDEX.md +14 -3
  172. package/kits/docs/evolcore/agent-create.md +55 -141
  173. package/kits/docs/evolcore/agent.md +38 -16
  174. package/kits/docs/evolcore/aid.md +34 -0
  175. package/kits/docs/evolcore/config.md +20 -1
  176. package/kits/docs/evolcore/event.md +2 -2
  177. package/kits/docs/evolcore/fs.md +18 -2
  178. package/kits/docs/evolcore/group-collaboration.md +13 -246
  179. package/kits/docs/evolcore/group.md +2 -1
  180. package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
  181. package/kits/docs/evolcore/menu-protocol.md +65 -1
  182. package/kits/docs/evolcore/msg.md +64 -2
  183. package/kits/docs/evolcore/skill.md +86 -0
  184. package/kits/docs/evolcore/stats.md +6 -0
  185. package/kits/docs/evolcore/task.md +2 -0
  186. package/kits/docs/evolcore/thread-chain.md +145 -51
  187. package/kits/docs/evolcore/trigger.md +48 -3
  188. package/kits/eck_manifest.json +21 -0
  189. package/kits/eck_message_manifest.json +4 -4
  190. package/kits/migrations/migrate-role-config-v5.mjs +20 -7
  191. package/kits/rules/01-overview.md +2 -1
  192. package/kits/rules/03-identity.md +3 -1
  193. package/kits/rules/04-relation.md +1 -1
  194. package/kits/rules/07-memory-and-thread.md +1 -1
  195. package/kits/schemas/_meta.json +16 -1
  196. package/kits/schemas/agent-config.schema.13.json +44 -2
  197. package/kits/schemas/contact-book.schema.3.json +5 -0
  198. package/kits/schemas/daemon.schema.6.json +3 -1
  199. package/kits/schemas/daemon.schema.8.json +329 -0
  200. package/kits/schemas/defaults.schema.5.json +39 -3
  201. package/kits/schemas/providers.schema.1.json +76 -0
  202. package/kits/schemas/relation-config.schema.9.json +5 -1
  203. package/kits/skills/.switches.json +28 -0
  204. package/kits/skills/aid-ability/SKILL.md +214 -0
  205. package/kits/skills/ec-agent-create/SKILL.md +162 -0
  206. package/kits/skills/ec-group/SKILL.md +2 -1
  207. package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
  208. package/kits/skills/ec-identity/SKILL.md +143 -0
  209. package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
  210. package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
  211. package/kits/skills/ec-trigger/SKILL.md +167 -0
  212. package/kits/skills/ec-trigger/references/examples.md +153 -0
  213. package/kits/skills/thread-ops/SKILL.md +108 -420
  214. package/kits/templates/message-fragments/thread-context.md +1 -2
  215. package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
  216. package/kits/templates/roles/member.json +1 -1
  217. package/kits/templates/roles/visitor.json +1 -0
  218. package/kits/templates/system-fragments/bootstrap.md +1 -0
  219. package/kits/templates/system-fragments/channel.md +2 -1
  220. package/kits/templates/system-fragments/commands.md +5 -4
  221. package/kits/templates/system-fragments/identity.md +2 -0
  222. package/kits/templates/system-fragments/session.md +1 -1
  223. package/kits/templates/system-fragments/venue.md +1 -1
  224. package/package.json +4 -3
@@ -1,3 +1,5 @@
1
+ import fs from 'node:fs';
2
+ import { ownerResolver } from '../ownership/owner-resolver.js';
1
3
  import { agentFullAccessStatus, agentFullAccessWriteError } from '../role/runtime-policy.js';
2
4
  import { initializationSummary } from '../../cli/agent-create.js';
3
5
  import { agentDelete, agentEnable, agentDisable, agentList, agentShow, agentSet, agentReload, } from '../../cli/agent.js';
@@ -12,7 +14,8 @@ import { uploadAvatar, uploadAvatarUrl } from '../../utils/avatar-upload.js';
12
14
  import { agentmdGet, agentmdPut, updateAgentMdFrontmatterName } from '../../aun/aid/agentmd.js';
13
15
  import { isValidAid } from '../../aun/aid/validation.js';
14
16
  import { isSupportedBaseagent } from '../../agents/baseagent.js';
15
- const SUPPORTED_AGENT_PATCH_FIELDS = new Set(['aid', 'name', 'avatar', 'active_baseagent', 'baseagents', 'projects', 'owners', 'fullaccess', 'chatmode', 'channels', 'channelOwners']);
17
+ import { resolveProviderServiceForBaseagent } from '../../config/providers.js';
18
+ const SUPPORTED_AGENT_PATCH_FIELDS = new Set(['aid', 'name', 'avatar', 'active_baseagent', 'baseagents', 'projects', 'owner', 'owners', 'fullaccess', 'chatmode', 'channels', 'channelOwners']);
16
19
  const HIDDEN_VALUE = '[hidden]';
17
20
  const SENSITIVE_CONFIG_KEYS = new Set([
18
21
  'apikey',
@@ -192,6 +195,28 @@ function normalizeStringList(value, label) {
192
195
  }
193
196
  return { ok: true, value: out };
194
197
  }
198
+ function normalizeOwnerPatch(value, label, options) {
199
+ if (Object.hasOwn(value, 'owner')) {
200
+ if (value.owner === null && !options.required)
201
+ return { ok: true, value: undefined };
202
+ if (typeof value.owner !== 'string')
203
+ return { ok: false, error: `${label}.owner 必须是字符串` };
204
+ const owner = value.owner.trim();
205
+ if (!owner && options.required)
206
+ return { ok: false, error: `${label}.owner 不能为空` };
207
+ return { ok: true, value: owner || undefined };
208
+ }
209
+ if (Object.hasOwn(value, 'owners')) {
210
+ if (!Array.isArray(value.owners))
211
+ return { ok: false, error: `${label}.owners 必须是字符串数组` };
212
+ const first = value.owners.find(item => typeof item === 'string' && item.trim());
213
+ const owner = typeof first === 'string' ? first.trim() : undefined;
214
+ if (!owner && options.required)
215
+ return { ok: false, error: `${label}.owners 至少需要一个 owner` };
216
+ return { ok: true, value: owner };
217
+ }
218
+ return { ok: false, error: `${label} 缺少 owner` };
219
+ }
195
220
  function normalizeChannelOwnersPatch(value) {
196
221
  if (!Array.isArray(value))
197
222
  return { ok: false, error: 'channelOwners 必须是数组' };
@@ -207,15 +232,15 @@ function normalizeChannelOwnersPatch(value) {
207
232
  if (!type || !name)
208
233
  return { ok: false, error: `channelOwners[${idx}] 缺少 type/name` };
209
234
  if (type === 'aun')
210
- return { ok: false, error: 'AUN 渠道 owner 由 agent 顶层 owners 管理,不支持 channelOwners 编辑' };
211
- const owners = normalizeStringList(item.owners, `channelOwners[${idx}].owners`);
212
- if (!owners.ok)
213
- return owners;
235
+ return { ok: false, error: 'AUN 渠道 owner 由 agent 顶层 owner 管理,不支持 channelOwners 编辑' };
236
+ const owner = normalizeOwnerPatch(item, `channelOwners[${idx}]`, { required: false });
237
+ if (!owner.ok)
238
+ return owner;
214
239
  const key = `${type}\0${name}`;
215
240
  if (seen.has(key))
216
241
  return { ok: false, error: `channelOwners 重复渠道: ${type}/${name}` };
217
242
  seen.add(key);
218
- out.push({ type, name, owners: owners.value });
243
+ out.push({ type, name, owner: owner.value });
219
244
  }
220
245
  return { ok: true, value: out };
221
246
  }
@@ -237,14 +262,17 @@ function applyChannelOwnersPatch(config, patch) {
237
262
  ownerAids: channel.ownerAids,
238
263
  admins: channel.admins,
239
264
  });
240
- channel.owners = item.owners;
241
- delete channel.owner;
265
+ if (item.owner)
266
+ channel.owner = item.owner;
267
+ else
268
+ delete channel.owner;
269
+ delete channel.owners;
242
270
  delete channel.ownerId;
243
271
  delete channel.ownerAid;
244
272
  delete channel.ownerIds;
245
273
  delete channel.ownerAids;
246
274
  delete channel.admins;
247
- const after = JSON.stringify({ owners: channel.owners });
275
+ const after = JSON.stringify({ owner: channel.owner });
248
276
  if (before !== after)
249
277
  changed = true;
250
278
  }
@@ -294,7 +322,8 @@ function buildSafeAgentConfig(config) {
294
322
  return sanitizeConfigValue({
295
323
  ...config,
296
324
  active_baseagent: config.active_baseagent ?? null,
297
- owners: config.owners ?? [],
325
+ owner: ownerResolver.knownOwner(config.aid) ?? null,
326
+ owners: ownerResolver.knownOwners(config.aid),
298
327
  channels: config.channels ?? [],
299
328
  baseagents: config.baseagents ?? {},
300
329
  projects: stripUnsupportedProjectFields(config.projects) ?? {},
@@ -311,6 +340,7 @@ function buildCreateProgressOnlyAgent(aid, progress) {
311
340
  model: null,
312
341
  effort: null,
313
342
  chatmode: null,
343
+ owner: null,
314
344
  owners: [],
315
345
  channels: [],
316
346
  },
@@ -325,6 +355,71 @@ function buildCreateProgressOnlyAgent(aid, progress) {
325
355
  createProgress: progress,
326
356
  };
327
357
  }
358
+ function failedCreateRetryAllowed(aid, agentDir, service) {
359
+ const progress = readCreateStatus(agentDir);
360
+ if ((!progress && fs.existsSync(path.join(agentDir, 'create-status.json')))
361
+ || (progress && (!Array.isArray(progress.steps)
362
+ || progress.steps.some(step => !step || typeof step.phase !== 'string'
363
+ || !['in_progress', 'done', 'warn', 'failed'].includes(step.state))))) {
364
+ return { allowed: false, force: false, error: '已有创建进度无法读取,拒绝覆盖' };
365
+ }
366
+ if (progress && progress.aid !== aid) {
367
+ return { allowed: false, force: false, error: '创建进度状态与 AID 不匹配' };
368
+ }
369
+ if (progress?.status === 'in_progress') {
370
+ return { allowed: false, force: false, error: '该 Agent 正在创建中' };
371
+ }
372
+ if (progress?.status === 'failed' && (progress.currentPhase === 'hot_loading'
373
+ || progress.currentPhase === 'applying_config'
374
+ || progress.steps.some(step => step.phase === 'hot_loading' || step.phase === 'applying_config'))) {
375
+ return { allowed: false, force: false, error: '该 Agent 已进入加载流程,拒绝重建' };
376
+ }
377
+ const configPath = path.join(agentDir, 'config.json');
378
+ if (!fs.existsSync(configPath)) {
379
+ if (progress && progress.status !== 'failed') {
380
+ return { allowed: false, force: false, error: '已有创建记录不是可重试的失败状态' };
381
+ }
382
+ return { allowed: true, force: false };
383
+ }
384
+ if (progress?.status !== 'failed') {
385
+ return { allowed: false, force: false, error: `Agent "${aid}" already exists` };
386
+ }
387
+ let lifecycle;
388
+ try {
389
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
390
+ if (!config || typeof config !== 'object' || Array.isArray(config) || config.aid !== aid) {
391
+ return { allowed: false, force: false, error: '已有 Agent 配置与 AID 不匹配,拒绝覆盖' };
392
+ }
393
+ lifecycle = config && typeof config === 'object' && !Array.isArray(config)
394
+ ? config.lifecycle
395
+ : undefined;
396
+ }
397
+ catch {
398
+ return { allowed: false, force: false, error: '已有 Agent 配置无法读取,拒绝覆盖' };
399
+ }
400
+ if (lifecycle !== 'created' && lifecycle !== 'ownerpending') {
401
+ return { allowed: false, force: false, error: `Agent "${aid}" 已进入运行生命周期,拒绝重建` };
402
+ }
403
+ // A legacy retry may have overwritten the original progress. Check live state
404
+ // independently before allowing the creator's destructive --force path.
405
+ if (!service)
406
+ return { allowed: false, force: false, error: '无法确认 Agent 运行状态,拒绝重建' };
407
+ try {
408
+ if (service.info(aid))
409
+ return { allowed: false, force: false, error: '该 Agent 已加载,拒绝重建' };
410
+ const ownership = ownerResolver.snapshot(aid);
411
+ if (ownership.connected || ownership.consensusStatus === 'consensus' || ownership.task?.status === 'completed') {
412
+ return { allowed: false, force: false, error: '该 Agent 已连接或已确认 Ownership,拒绝重建' };
413
+ }
414
+ if (ownership.requestStatus === 'error') {
415
+ return { allowed: false, force: false, error: '无法确认 Agent Ownership 状态,拒绝重建' };
416
+ }
417
+ }
418
+ catch {
419
+ return { allowed: false, force: false, error: '无法确认 Agent 运行状态,拒绝重建' };
420
+ }
421
+ return { allowed: true, force: true };
422
+ }
328
423
  /** 后台异步:实际创建 agent + 落 model/effort/chatmode,全程写构建进度(D3)。
329
424
  * 失败仅写日志 + create-status,不回传(受理即返回)。
330
425
  * agentSet key 对照 cli/agent.ts 的 setNestedValue:
@@ -338,6 +433,10 @@ async function runCreateInBackground(opts, w, service) {
338
433
  project: opts.project, owner: opts.owner,
339
434
  description: opts.description,
340
435
  tags: opts.tags,
436
+ // Publish the avatar before hot-load starts Ownership with agent.md.
437
+ avatarUrl: opts.avatarUrl,
438
+ force: opts.retryFailedCreate === true,
439
+ onOwnershipBinding: binding => w.setOwnershipBinding(binding),
341
440
  onPhase: (phase, state, detail) => {
342
441
  if (state === 'begin') {
343
442
  curPhase = phase;
@@ -355,24 +454,51 @@ async function runCreateInBackground(opts, w, service) {
355
454
  ? await service.create(createOptions)
356
455
  : await agentCreateNonInteractive(createOptions);
357
456
  if (!('ok' in res) || res.ok !== true) {
358
- // 硬失败:onPhase('failed') 已写终态;这里仅兜底日志(防回调未覆盖的 return 路径)
359
- const err = res.error;
457
+ // Service adapters may return a failure without emitting an onPhase callback.
458
+ const err = String(res.error || 'Agent creation failed');
459
+ w.finishFailed(curPhase, err);
360
460
  logger.warn(`[agent-control] create ${opts.aid} failed: ${err}`);
361
461
  return;
362
462
  }
363
- // 环节 4:applying_config(model/effort/chatmode,agentCreateNonInteractive 之外)
364
- if (opts.model || opts.effort || opts.chatmode) {
463
+ if (res.aidCreated && res.ownershipBinding)
464
+ w.setOwnershipBinding(res.ownershipBinding);
465
+ // 环节 4:applying_config(provider/model/effort/chatmode,agentCreateNonInteractive 之外)
466
+ if (opts.provider || opts.providerServiceType || opts.model || opts.effort || opts.chatmode) {
365
467
  curPhase = 'applying_config';
366
468
  w.begin('applying_config');
367
469
  let warned;
368
- if (opts.model) {
470
+ if (opts.provider) {
471
+ const config = service?.readConfig(opts.aid) ?? cfgRead(ConfigTarget.Agent, { self: opts.aid });
472
+ if (!config)
473
+ throw new Error('Agent config is unavailable after creation');
474
+ const baseagents = config.baseagents && typeof config.baseagents === 'object' ? { ...config.baseagents } : {};
475
+ const current = baseagents[opts.baseagent] && typeof baseagents[opts.baseagent] === 'object'
476
+ ? { ...baseagents[opts.baseagent] }
477
+ : {};
478
+ baseagents[opts.baseagent] = {
479
+ ...current,
480
+ provider: opts.provider,
481
+ ...(opts.providerServiceType ? { providerServiceType: opts.providerServiceType } : {}),
482
+ ...(opts.model ? { model: opts.model } : {}),
483
+ ...(opts.effort ? { effort: opts.effort } : {}),
484
+ };
485
+ config.baseagents = baseagents;
486
+ if (service)
487
+ service.writeConfig(opts.aid, config);
488
+ else
489
+ cfgWrite(ConfigTarget.Agent, config, { self: opts.aid });
490
+ const reload = service ? await service.reload(opts.aid) : await agentReload(opts.aid);
491
+ if (!('ok' in reload) || !reload.ok)
492
+ warned = `provider saved but Agent reload failed: ${reload.error || 'unknown error'}`;
493
+ }
494
+ if (!opts.provider && opts.model) {
369
495
  const r = service
370
496
  ? await service.setConfig(opts.aid, `baseagents.${opts.baseagent}.model`, opts.model)
371
497
  : await agentSet(opts.aid, `baseagents.${opts.baseagent}.model`, opts.model);
372
498
  if (!('ok' in r) || !r.ok)
373
499
  warned = `model: ${r.error}`;
374
500
  }
375
- if (opts.effort) {
501
+ if (!opts.provider && opts.effort) {
376
502
  const r = service
377
503
  ? await service.setConfig(opts.aid, `baseagents.${opts.baseagent}.effort`, opts.effort)
378
504
  : await agentSet(opts.aid, `baseagents.${opts.baseagent}.effort`, opts.effort);
@@ -444,6 +570,8 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
444
570
  if (!a.aid || !a.name || !a.baseagent) {
445
571
  return { error: '缺少必填参数:aid / name / baseagent', code: 'INVALID_ARGS' };
446
572
  }
573
+ if (typeof a.aid !== 'string' || !isValidAid(a.aid))
574
+ return { error: '无效 Agent AID', code: 'INVALID_ARGS' };
447
575
  const owner = typeof a.owner === 'string' && a.owner.trim() ? a.owner.trim() : peerId.trim();
448
576
  if (!owner)
449
577
  return { error: '缺少 owner AID', code: 'INVALID_ARGS' };
@@ -453,16 +581,51 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
453
581
  return { error: 'project 缺失(调用方应先解析默认项目路径)', code: 'INVALID_ARGS' };
454
582
  }
455
583
  const model = typeof a.model === 'string' && a.model.trim() ? a.model.trim() : undefined;
584
+ if (a.provider !== undefined && typeof a.provider !== 'string')
585
+ return { error: 'provider 必须是字符串', code: 'INVALID_ARGS' };
586
+ const provider = typeof a.provider === 'string' && a.provider.trim() ? a.provider.trim() : undefined;
587
+ if (a.providerServiceType !== undefined && typeof a.providerServiceType !== 'string')
588
+ return { error: 'providerServiceType 必须是字符串', code: 'INVALID_ARGS' };
589
+ const providerServiceType = typeof a.providerServiceType === 'string' && a.providerServiceType.trim() ? a.providerServiceType.trim() : undefined;
590
+ if (provider) {
591
+ try {
592
+ const resolved = resolveProviderServiceForBaseagent(provider, a.baseagent, providerServiceType);
593
+ if (model && resolved.modelOverrides[model]?.enabled === false)
594
+ throw new Error(`Model ${model} is disabled for provider ${provider}`);
595
+ }
596
+ catch (error) {
597
+ return { error: error.message || String(error), code: 'INVALID_ARGS' };
598
+ }
599
+ }
456
600
  const rawEffort = typeof a.effort === 'string' && a.effort.trim() ? a.effort.trim() : undefined;
457
601
  const effort = rawEffort && rawEffort !== 'auto' ? rawEffort : undefined;
458
602
  const description = typeof a.description === 'string' && a.description.trim()
459
603
  ? a.description.trim()
460
604
  : undefined;
461
605
  const tags = Array.isArray(a.tags) ? a.tags : undefined;
606
+ let avatarUrl;
607
+ if (a.avatarUrl !== undefined) {
608
+ if (typeof a.avatarUrl !== 'string' || !a.avatarUrl.trim()) {
609
+ return { error: 'avatarUrl 必须是非空 HTTPS URL', code: 'INVALID_ARGS' };
610
+ }
611
+ try {
612
+ const url = new URL(a.avatarUrl.trim());
613
+ if (url.protocol !== 'https:' || url.username || url.password || (url.port && url.port !== '443'))
614
+ throw new Error('invalid avatar URL');
615
+ avatarUrl = url.toString();
616
+ }
617
+ catch {
618
+ return { error: 'avatarUrl 必须是不含认证信息的 HTTPS URL', code: 'INVALID_ARGS' };
619
+ }
620
+ }
621
+ const agentDir = path.join(resolvePaths().agentsDir, a.aid);
622
+ const retry = failedCreateRetryAllowed(a.aid, agentDir, service);
623
+ if (!retry.allowed)
624
+ return { error: retry.error || 'Agent 已存在', code: 'CONFLICT' };
462
625
  // D3: accepted=true 必须意味着后续 query 能查到该 AID 的创建状态。
463
626
  let progressWriter;
464
627
  try {
465
- progressWriter = new CreateStatusWriter(path.join(resolvePaths().agentsDir, a.aid), a.aid);
628
+ progressWriter = new CreateStatusWriter(agentDir, a.aid, { requesterAid: peerId, ownerAid: owner });
466
629
  }
467
630
  catch (e) {
468
631
  return { error: `创建进度状态初始化失败: ${e?.message || e}`, code: 'INTERNAL' };
@@ -471,10 +634,11 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
471
634
  void runCreateInBackground({
472
635
  aid: a.aid, name: a.name, baseagent: a.baseagent,
473
636
  project: a.project, owner,
474
- model, effort, description, tags, chatmode: a.chatmode,
637
+ provider, providerServiceType, model, effort, description, tags, chatmode: a.chatmode, avatarUrl,
638
+ retryFailedCreate: retry.force,
475
639
  eventBus,
476
640
  }, progressWriter, service).catch(e => logger.error(`[agent-control] runCreateInBackground unhandled ${a.aid}: ${e?.message || e}`));
477
- return { data: { accepted: true, aid: a.aid } };
641
+ return { data: { accepted: true, aid: a.aid, creationId: progressWriter.creationId, ...(avatarUrl ? { avatarAccepted: true } : {}) } };
478
642
  }
479
643
  if (action === 'delete') {
480
644
  if (!a.aid)
@@ -551,8 +715,8 @@ export async function execAgentAction(action, args, peerId, eventBus, service, s
551
715
  * 直接通过 ConfigManager 读写 agent config(不走 agentSet,避免其内部自动 evolagent.reload)——
552
716
  * 重载由用户在 Agents 页操作列手动触发(带任务执行检查)。
553
717
  * AUN 渠道绑定 agent 顶层 aid,不可通过 patch 编辑:拒绝改 aid、拒绝 channels 数组里出现 aun 条目。
554
- * 可写字段:name / avatar(旧版 App 兼容,单独提交 data URL)/ active_baseagent / baseagents / projects / owners / fullaccess / chatmode / channels(非 aun)/
555
- * channelOwners(按 type/name 局部更新非 AUN channel owners,避免前端回写脱敏 credentials)。 */
718
+ * 可写字段:name / avatar(旧版 App 兼容,单独提交 data URL)/ active_baseagent / baseagents / projects / owner(旧版 owners[] 兼容)/
719
+ * fullaccess / chatmode / channels(非 aun)/ channelOwners(按 type/name 局部更新非 AUN channel owner,避免前端回写脱敏 credentials)。 */
556
720
  export async function execAgentUpdate(args, subject) {
557
721
  const a = args ?? {};
558
722
  if (!a.aid)
@@ -606,7 +770,7 @@ export async function execAgentUpdate(args, subject) {
606
770
  return execAidAvatar({ aid: a.aid, data: p.avatar });
607
771
  let touched = false;
608
772
  const data = { aid: a.aid };
609
- const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owners !== undefined || p.fullaccess !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
773
+ const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owner !== undefined || p.owners !== undefined || p.fullaccess !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
610
774
  if (p.active_baseagent !== undefined) {
611
775
  if (typeof p.active_baseagent !== 'string' || !p.active_baseagent.trim()) {
612
776
  return { error: `无效 active_baseagent: ${JSON.stringify(p.active_baseagent)}(必须是非空字符串)`, code: 'INVALID_ARGS' };
@@ -638,21 +802,8 @@ export async function execAgentUpdate(args, subject) {
638
802
  else
639
803
  delete config.projects;
640
804
  }
641
- if (p.owners !== undefined) {
642
- if (!Array.isArray(p.owners) || p.owners.length === 0) {
643
- return { error: 'owners must contain at least one owner', code: 'LAST_OWNER_PROTECTED' };
644
- }
645
- const owners = [];
646
- for (const rawOwner of p.owners) {
647
- if (typeof rawOwner !== 'string' || !rawOwner.trim() || !isValidAid(rawOwner.trim())) {
648
- return { error: `Invalid owner AID: ${JSON.stringify(rawOwner)}`, code: 'INVALID_ARGS' };
649
- }
650
- const owner = rawOwner.trim();
651
- if (!owners.includes(owner))
652
- owners.push(owner);
653
- }
654
- config.owners = owners;
655
- touched = true;
805
+ if (p.owner !== undefined || p.owners !== undefined) {
806
+ return { error: 'Root owner/owners configuration is not supported; use ec aid bind', code: 'INVALID_ARGS' };
656
807
  }
657
808
  if (p.fullaccess !== undefined) {
658
809
  config.fullaccess = { enabled: p.fullaccess.enabled };
@@ -728,6 +879,7 @@ export async function execAgentQuery(args, service, subject) {
728
879
  const config = cfgRead(ConfigTarget.Agent, { self: aid });
729
880
  const safeConfig = buildSafeAgentConfig(config);
730
881
  const safeAgentConfig = safeConfig ?? {};
882
+ const ownership = ownerResolver.snapshot(aid);
731
883
  const fullaccessStatus = agentFullAccessStatus(aid, subject?.principalId ?? subject?.actorId);
732
884
  const data = {
733
885
  ...res,
@@ -737,9 +889,16 @@ export async function execAgentQuery(args, service, subject) {
737
889
  active_baseagent: safeAgentConfig.active_baseagent ?? res.config?.baseagent ?? null,
738
890
  projects: safeAgentConfig.projects ?? {},
739
891
  baseagents: safeAgentConfig.baseagents ?? {},
892
+ owner: safeConfig ? safeAgentConfig.owner : res.config?.owner ?? null,
740
893
  owners: safeAgentConfig.owners ?? res.config?.owners ?? [],
741
894
  },
742
895
  safeConfig,
896
+ ownership: {
897
+ relation: ownership.relation ?? null,
898
+ consensusStatus: ownership.consensusStatus,
899
+ checkedAt: ownership.checkedAt ?? null,
900
+ authorizationStatus: ownership.authorizationStatus,
901
+ },
743
902
  fullaccessStatus: {
744
903
  ...fullaccessStatus,
745
904
  canConfigure: agentFullAccessWriteError(aid, subject) === undefined,
@@ -1,4 +1,5 @@
1
- import { parseAgentWelcomeArgs, parseInitializationArgs } from '../../cli/agent-create.js';
1
+ import { parseAgentWelcomeArgs, parseInitializationArgs, resolveAgentCreateMode } from '../../cli/agent-create.js';
2
+ import { parseOwnershipCommand } from '../../aun/aid/ownership-operation.js';
2
3
  import { normalizeCliArgv } from '../../cli/cli-argv.js';
3
4
  import { resolveConfigCommand, } from '../../config/resolved-config-op.js';
4
5
  export { normalizeCliArgv, parseLegacyCliCommand, validateCliArgv } from '../../cli/cli-argv.js';
@@ -24,6 +25,8 @@ export function parseCliIntent(inputArgv, source = 'menu.cli', options = {}) {
24
25
  const cmd = argv[0];
25
26
  if (cmd === 'model')
26
27
  return parseModelCommand(argv, source);
28
+ if (cmd === 'thread')
29
+ return parseThreadCommand(argv, source);
27
30
  if (cmd === 'config')
28
31
  return parseConfigCommand(argv, source, options.defaultRelation);
29
32
  if (cmd === 'stats')
@@ -31,7 +34,7 @@ export function parseCliIntent(inputArgv, source = 'menu.cli', options = {}) {
31
34
  if (cmd === 'agent')
32
35
  return parseAgentCommand(argv, source);
33
36
  if (cmd === 'aid')
34
- return parseAidCommand(argv, source);
37
+ return parseAidCommand(argv, source, options.defaultRelation?.self);
35
38
  if (cmd === 'storage')
36
39
  return parseStorageCommand(argv, source);
37
40
  if (cmd === 'version') {
@@ -48,6 +51,36 @@ export function parseCliIntent(inputArgv, source = 'menu.cli', options = {}) {
48
51
  }
49
52
  return raw(source, argv, `Unknown command: ${cmd}`);
50
53
  }
54
+ function parseThreadCommand(argv, source) {
55
+ if (argv[1] !== 'summary' || !['show', 'log'].includes(argv[2] ?? '')) {
56
+ return raw(source, argv, 'Only thread summary show/log is available through remote CLI');
57
+ }
58
+ const action = argv[2];
59
+ const parsed = parseArgs(argv.slice(3));
60
+ const args = parsed.args;
61
+ if (Object.keys(args).some(key => !['self', 'format'].includes(key))) {
62
+ return raw(source, argv, 'Unsupported thread summary option');
63
+ }
64
+ if (parsed.positionals.length !== 1 || typeof args.self !== 'string' || !args.self.trim()) {
65
+ return raw(source, argv, 'thread summary show/log requires <peer>/<threadId> and --self');
66
+ }
67
+ if (args.format !== 'json') {
68
+ return raw(source, argv, 'Remote thread summary reads require --format json');
69
+ }
70
+ const pieces = parsed.positionals[0].split('/');
71
+ if (pieces.length !== 2 || !pieces[0] || !pieces[1]
72
+ || pieces[1] === 'main' || pieces[1] === 'current'
73
+ || !/^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(pieces[1])) {
74
+ return raw(source, argv, 'A concrete peer/threadId reference is required');
75
+ }
76
+ const operation = action === 'show' ? 'ec.thread.summary-show' : 'ec.thread.summary-log';
77
+ return recognized(operation, 'relation', source, {
78
+ self: args.self,
79
+ peer: pieces[0],
80
+ threadId: pieces[1],
81
+ action,
82
+ }, argv);
83
+ }
51
84
  export function rawCliIntent(argv, source = 'menu.cli') {
52
85
  return {
53
86
  operation: 'cli.exec.raw',
@@ -157,7 +190,16 @@ function parseStatsCommand(argv, source) {
157
190
  }
158
191
  function parseAgentCommand(argv, source) {
159
192
  const subcmd = argv[1];
160
- if ((subcmd === 'new' && argv.includes('--initialize')) || subcmd === 'initialize') {
193
+ let createMode;
194
+ if (subcmd === 'new') {
195
+ try {
196
+ createMode = resolveAgentCreateMode(argv.slice(1));
197
+ }
198
+ catch {
199
+ return raw(source, argv, 'Invalid creation mode');
200
+ }
201
+ }
202
+ if (createMode === 'initialize' || subcmd === 'initialize') {
161
203
  try {
162
204
  const parsed = parseInitializationArgs(argv.slice(1));
163
205
  return recognized('agent.initialize', 'control', source, { aid: parsed.aid }, argv, true);
@@ -195,8 +237,22 @@ function parseAgentCommand(argv, source) {
195
237
  return recognized('agent.getConfig', 'control', source, args, argv, true);
196
238
  return raw(source, argv, `Unknown agent subcommand: ${subcmd}`);
197
239
  }
198
- function parseAidCommand(argv, source) {
240
+ function parseAidCommand(argv, source, defaultSelfAid) {
199
241
  const subcmd = argv[1];
242
+ if (subcmd === 'bind') {
243
+ try {
244
+ const command = parseOwnershipCommand(argv.slice(1));
245
+ const subjectAid = command.subjectAid ?? defaultSelfAid;
246
+ return recognized(command.action === 'bind' ? 'ec.aid.bind' : 'ec.aid.bind.status', 'agent', source, {
247
+ ...(subjectAid ? { self: subjectAid } : {}),
248
+ ...(command.subjectAid ? { subjectAid: command.subjectAid } : {}),
249
+ ...(command.action === 'bind' ? { ownerAid: command.ownerAid } : {}),
250
+ }, argv, command.action === 'bind');
251
+ }
252
+ catch (error) {
253
+ return raw(source, argv, error instanceof Error ? error.message : 'Invalid aid bind command');
254
+ }
255
+ }
200
256
  if (subcmd === 'avatar') {
201
257
  const tail = argv.slice(2);
202
258
  const aid = tail[0];