evolcore 0.0.35 → 0.0.37

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 +42 -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 +177 -85
  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 +115 -36
  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
@@ -4,14 +4,12 @@ import path from 'path';
4
4
  import readline from 'readline';
5
5
  import { parse } from 'yaml';
6
6
  import { resolvePaths, aunPath as defaultAunPath, agentConfig, agentDataDir, agentPersonalDir, aidLocalDir, agentMdPath } from '../paths.js';
7
- import { loadDefaults, loadAgent, saveAgent, ensureAgentDirSkeleton, loadDaemonConfig } from '../config-store.js';
7
+ import { loadDefaults, loadAgent, saveAgent, ensureAgentDirSkeleton } from '../config-store.js';
8
8
  import { ConfigTarget, write as cfgWrite, ensureFile as cfgEnsure, read as cfgRead } from '../config/config-manager.js';
9
9
  import { ipcQuery } from '../ipc.js';
10
10
  import { CONFIG_SCHEMA_VERSION } from '../types.js';
11
11
  import { ensureInitialRoleRegistry } from '../config/role-service.js';
12
- import { addContact } from '../config/contact-request-service.js';
13
12
  import { getCodexAppServerAvailability } from '../agents/codex-runner.js';
14
- import { resolveEcagentConfig } from '../agents/baseagent.js';
15
13
  import { AUTO_BASEAGENT_CANDIDATES, BASEAGENT_CANDIDATES, detectAvailableBaseagents, } from '../agents/baseagent-availability.js';
16
14
  import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/project-path.js';
17
15
  import { isValidAid } from '../aun/aid/validation.js';
@@ -21,6 +19,19 @@ import { isHClassPath, isLClassPath, isSameOrDescendant } from '../core/permissi
21
19
  import { MAIN_CLI_BIN } from '../product.js';
22
20
  import { uploadAvatarFile, uploadAvatarUrl } from '../utils/avatar-upload.js';
23
21
  import { readTaskRuntimeContextFromEnv } from './task-context.js';
22
+ import { logger } from '../utils/logger.js';
23
+ import { creationOwnershipBinding } from '../core/ownership/owner-resolver.js';
24
+ /** Select the creation lifecycle independently of --non-interactive. */
25
+ export function resolveAgentCreateMode(args) {
26
+ if (args.includes('--initialize') && args.includes('--bootstrap')) {
27
+ throw new Error('--initialize and --bootstrap are mutually exclusive');
28
+ }
29
+ for (const flag of ['--initialize', '--bootstrap']) {
30
+ if (args.filter(arg => arg === flag).length > 1)
31
+ throw new Error(`${flag} must be supplied once`);
32
+ }
33
+ return args.includes('--bootstrap') ? 'bootstrap' : 'initialize';
34
+ }
24
35
  /** Parse the current Agent's Bootstrap welcome subcommand. */
25
36
  export function parseAgentWelcomeArgs(args) {
26
37
  const tail = args.at(-2) === '--format' && args.at(-1) === 'json' ? args.slice(0, -2) : args;
@@ -71,24 +82,17 @@ export function parseAgentTags(raw) {
71
82
  return [...new Set(tags)];
72
83
  }
73
84
  export function validateAgentOwnerOptions(options) {
74
- if (options.owner !== undefined && options.owners !== undefined) {
75
- return 'Options --owner and --owners are mutually exclusive';
76
- }
77
- if (options.owners !== undefined && (!Array.isArray(options.owners) || options.owners.length === 0)) {
78
- return '--owners must be a non-empty JSON array of AIDs';
79
- }
80
- const owners = options.owners ?? (options.owner !== undefined ? [options.owner] : []);
81
- if (owners.some(owner => typeof owner !== 'string' || !isValidAid(owner))) {
82
- return 'Every owner must be a valid AID';
85
+ const owner = options.owner?.trim();
86
+ if (owner !== undefined && !isValidAid(owner)) {
87
+ return 'Owner must be a valid AID';
83
88
  }
84
89
  return null;
85
90
  }
86
91
  /** Shared by the standalone CLI and the authenticated daemon command path. */
87
92
  export function parseAgentOwnerArgs(argv) {
93
+ if (argv.includes('--owners'))
94
+ throw new Error('--owners has been removed; use one --owner <aid>');
88
95
  const hasOwner = argv.includes('--owner');
89
- const hasOwners = argv.includes('--owners');
90
- if (hasOwner && hasOwners)
91
- throw new Error('Options --owner and --owners are mutually exclusive');
92
96
  const value = (flag) => {
93
97
  if (argv.filter(arg => arg === flag).length !== 1)
94
98
  throw new Error(`${flag} must be supplied once`);
@@ -100,71 +104,17 @@ export function parseAgentOwnerArgs(argv) {
100
104
  const options = {};
101
105
  if (hasOwner)
102
106
  options.owner = value('--owner');
103
- if (hasOwners) {
104
- const raw = value('--owners');
105
- try {
106
- options.owners = JSON.parse(raw);
107
- }
108
- catch {
109
- throw new Error('--owners must be a non-empty JSON array of AIDs');
110
- }
111
- }
112
107
  const error = validateAgentOwnerOptions(options);
113
108
  if (error)
114
109
  throw new Error(error);
115
- if (options.owners)
116
- options.owners = [...new Set(options.owners)];
117
110
  return options;
118
111
  }
119
- function withStaticOwners(config, ownersInput) {
120
- const values = (ownersInput ?? []).map(value => value.trim()).filter(Boolean);
121
- if (values.length === 0)
122
- return config;
123
- const owners = config.owners ?? [];
124
- return { ...config, owners: [...new Set([...owners, ...values])] };
125
- }
126
- function withStaticOwner(config, owner) {
127
- return withStaticOwners(config, owner ? [owner] : undefined);
128
- }
129
- /**
130
- * An Agent owner must be able to receive the new Agent's Bootstrap reply.
131
- * Contact admission is per local Agent, so materialize the new AID in each
132
- * locally managed owner's contact book immediately after creation. Human or
133
- * remote owners have no local contact book and are reported as skipped.
134
- */
135
- export async function syncOwnerContactsAfterCreate(createdAid, owners) {
136
- const synced = [];
137
- const skipped = [];
138
- const errors = [];
139
- for (const ownerAid of [...new Set((owners ?? []).map(value => value.trim()).filter(Boolean))]) {
140
- if (ownerAid === createdAid)
141
- continue;
142
- const ownerConfig = path.join(resolvePaths().agentsDir, ownerAid, 'config.json');
143
- if (!fs.existsSync(ownerConfig)) {
144
- skipped.push(ownerAid);
145
- continue;
146
- }
147
- try {
148
- await addContact({
149
- selfAid: ownerAid,
150
- primaryId: createdAid,
151
- actorId: 'agent-create-owner-sync',
152
- });
153
- synced.push(ownerAid);
154
- }
155
- catch (error) {
156
- errors.push(`${ownerAid}: ${error instanceof Error ? error.message : String(error)}`);
157
- }
158
- }
159
- return {
160
- ...(synced.length > 0 ? { ownerContactsSynced: synced } : {}),
161
- ...(skipped.length > 0 ? { ownerContactsSkipped: skipped } : {}),
162
- ...(errors.length > 0 ? { ownerContactSyncErrors: errors } : {}),
163
- };
164
- }
165
112
  function pickDefaultBaseagent(available) {
166
113
  return AUTO_BASEAGENT_CANDIDATES.find(candidate => available.includes(candidate)) ?? null;
167
114
  }
115
+ function pickInteractiveDefaultBaseagent(available) {
116
+ return available.includes('ecagent') ? 'ecagent' : pickDefaultBaseagent(available);
117
+ }
168
118
  function readProjectMetadata(project) {
169
119
  try {
170
120
  const packageJsonPath = path.join(project, 'package.json');
@@ -196,7 +146,6 @@ export function resolveAgentCreatePlan(options, projectCwd = process.cwd()) {
196
146
  const project = path.resolve(projectCwd, options.project || '.');
197
147
  const metadata = readProjectMetadata(project);
198
148
  const defaults = loadDefaults();
199
- const daemon = loadDaemonConfig();
200
149
  const configuredBaseagent = defaults?.active_baseagent;
201
150
  const available = detectAvailableBaseagents();
202
151
  const defaultBaseagent = configuredBaseagent && available.includes(configuredBaseagent)
@@ -206,9 +155,9 @@ export function resolveAgentCreatePlan(options, projectCwd = process.cwd()) {
206
155
  const baseagentSource = options.baseagent
207
156
  ? 'argument'
208
157
  : configuredBaseagent && baseagent === configuredBaseagent ? 'defaults' : 'detected';
209
- const owners = options.owners;
210
- const owner = options.owner?.trim() || (owners === undefined ? daemon.owners?.[0] : undefined);
211
- const ownerSource = owners !== undefined || options.owner?.trim() ? 'argument' : owner ? 'daemon' : 'none';
158
+ const hasExplicitOwner = options.owner !== undefined;
159
+ const owner = options.owner?.trim() || undefined;
160
+ const ownerSource = hasExplicitOwner ? 'argument' : 'none';
212
161
  const name = options.name?.trim() || metadata.name || projectSlug(project);
213
162
  // description 是可选字段:用户显式传入的必须合规(超长会在校验阶段被拒);
214
163
  // 从 package.json 推导出来的超长值直接弃用、回落默认短描述——用户没设过它,
@@ -224,7 +173,7 @@ export function resolveAgentCreatePlan(options, projectCwd = process.cwd()) {
224
173
  const type = requestedType ? (normalizeAgentType(requestedType) ?? requestedType) : DEFAULT_AGENT_TYPE;
225
174
  const configExists = isValidAid(aid) && fs.existsSync(path.join(resolvePaths().agentsDir, aid, 'config.json'));
226
175
  return {
227
- aid, project, baseagent, owner, owners, handoff: options.handoff, avatarFile: options.avatarFile, avatarUrl: options.avatarUrl,
176
+ aid, project, baseagent, owner, avatarFile: options.avatarFile, avatarUrl: options.avatarUrl,
228
177
  name, description, type, tags: options.tags,
229
178
  force: options.force === true, configExists, baseagentSource, ownerSource,
230
179
  nameSource: options.name?.trim() ? 'argument' : metadata.name ? 'package' : 'directory',
@@ -237,7 +186,7 @@ export function validateAgentCreatePlan(plan) {
237
186
  if (ownerError)
238
187
  return ownerError;
239
188
  if (!isValidAid(plan.aid))
240
- return `Invalid AID "${plan.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`;
189
+ return `Invalid AID "${plan.aid}": must be a valid multi-level domain (e.g. mybot.agentid.cn)`;
241
190
  if (plan.avatarFile !== undefined && plan.avatarUrl !== undefined)
242
191
  return '--avatar-file and --avatar-url are mutually exclusive';
243
192
  if (plan.configExists && !plan.force)
@@ -250,6 +199,9 @@ export function validateAgentCreatePlan(plan) {
250
199
  const typeError = validateAgentType(plan.type);
251
200
  if (typeError)
252
201
  return `Invalid --type: ${typeError}`;
202
+ if (normalizeAgentType(plan.type) === 'agent' && !plan.owner) {
203
+ return 'An owner AID is required when creating an agent';
204
+ }
253
205
  // 只有显式传入的 --description 才会超限(package.json 的超长值在 resolve 阶段
254
206
  // 已被弃用)。必须在这里就拒绝:否则 plan 通过、直到 agentmdPut 上传才失败,
255
207
  // 而那处是 warn 级不中断创建,最终留下一张 SDK 兜底名片(--type/--name 全部丢失)。
@@ -265,22 +217,8 @@ export function validateAgentCreatePlan(plan) {
265
217
  if (!detectAvailableBaseagents().includes(plan.baseagent)) {
266
218
  return `${plan.baseagent} is not available in the current environment`;
267
219
  }
268
- if (plan.baseagent === 'ecagent') {
269
- const reason = ecagentUnavailableReason();
270
- if (reason)
271
- return reason;
272
- }
273
220
  return null;
274
221
  }
275
- function ecagentUnavailableReason() {
276
- try {
277
- resolveEcagentConfig({ agents: { ecagent: {} } });
278
- return undefined;
279
- }
280
- catch (error) {
281
- return error instanceof Error ? error.message : String(error);
282
- }
283
- }
284
222
  function saveInitialBehavior(aid, baseagent) {
285
223
  const behavior = {
286
224
  active_baseagent: baseagent,
@@ -302,7 +240,7 @@ export async function agentCreateInteractive(opts = {}) {
302
240
  const ask = (q) => new Promise(r => rl.question(q, r));
303
241
  try {
304
242
  const { aidCreate, buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
305
- const aidPrompt = opts.suggestedName ? `AID [${opts.suggestedName}]: ` : 'AID (e.g. mybot.agentid.pub): ';
243
+ const aidPrompt = opts.suggestedName ? `AID [${opts.suggestedName}]: ` : 'AID (e.g. mybot.agentid.cn): ';
306
244
  let aid = '';
307
245
  while (!aid) {
308
246
  const aidInput = (await ask(aidPrompt)).trim();
@@ -312,7 +250,7 @@ export async function agentCreateInteractive(opts = {}) {
312
250
  continue;
313
251
  }
314
252
  if (!isValidAid(candidate)) {
315
- console.log(` ⚠ Invalid AID "${candidate}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
253
+ console.log(` ⚠ Invalid AID "${candidate}": must be a valid multi-level domain (e.g. mybot.agentid.cn)`);
316
254
  continue;
317
255
  }
318
256
  aid = candidate;
@@ -327,19 +265,6 @@ export async function agentCreateInteractive(opts = {}) {
327
265
  return { ok: false, error: 'Aborted.' };
328
266
  }
329
267
  console.log(`\nCreating agent: ${aid}\n`);
330
- let aidCreated = false;
331
- try {
332
- const result = await aidCreate(aid);
333
- try {
334
- await result.client.close();
335
- }
336
- catch { /* ignore */ }
337
- aidCreated = !result.alreadyExisted;
338
- console.log(` ✓ AID ${result.alreadyExisted ? 'reused' : 'created'}: ${aid}`);
339
- }
340
- catch (e) {
341
- return { ok: false, error: `AID creation failed: ${e?.message || e}` };
342
- }
343
268
  let suggestedProjectPath = '';
344
269
  try {
345
270
  suggestedProjectPath = deriveAgentProjectPath(agentProjectRootFromDefaults(loadDefaults(), p.root), aid);
@@ -366,16 +291,12 @@ export async function agentCreateInteractive(opts = {}) {
366
291
  return { ok: false, error: 'Aborted.' };
367
292
  }
368
293
  const available = detectAvailableBaseagents();
369
- if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
370
- return { ok: false, error: 'No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.' };
294
+ if (available.length === 0) {
295
+ return { ok: false, error: 'No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or use bundled ecagent.' };
371
296
  }
372
- const defaultBa = pickDefaultBaseagent(available);
297
+ const defaultBa = pickInteractiveDefaultBaseagent(available);
373
298
  let baseagent;
374
- if (available.length === 1 && defaultBa) {
375
- console.log(` Baseagent: ${defaultBa}`);
376
- baseagent = defaultBa;
377
- }
378
- else {
299
+ {
379
300
  let chosen = null;
380
301
  while (chosen === null) {
381
302
  const defaultHint = defaultBa ? ` [${defaultBa}]` : '';
@@ -392,40 +313,19 @@ export async function agentCreateInteractive(opts = {}) {
392
313
  console.log(` ${input} is not available in the current environment. Available: ${available.join('/')}`);
393
314
  continue;
394
315
  }
395
- if (input === 'ecagent') {
396
- const reason = ecagentUnavailableReason();
397
- if (reason) {
398
- console.log(` ecagent is unavailable: ${reason}`);
399
- continue;
400
- }
401
- }
402
316
  chosen = input;
403
317
  }
404
318
  baseagent = chosen;
405
319
  }
406
- const daemonCfg = loadDaemonConfig();
407
- const daemonHasOwner = !!daemonCfg.owners?.length;
408
320
  let owner;
409
- let skipQrBinding = false;
410
- if (daemonHasOwner) {
411
- const defaultOwner = daemonCfg.owners[0];
412
- while (true) {
413
- const ownerInput = (await ask(`Owner AID [${defaultOwner}]: `)).trim();
414
- if (!ownerInput) {
415
- owner = defaultOwner;
416
- break;
417
- }
418
- if (ownerInput.toLowerCase() === 'new' || ownerInput.toLowerCase() === 'qr') {
419
- break;
420
- }
421
- if (!isValidAid(ownerInput)) {
422
- console.log(` ⚠ Invalid Owner AID "${ownerInput}"`);
423
- continue;
424
- }
425
- owner = ownerInput;
426
- skipQrBinding = true;
427
- break;
321
+ while (true) {
322
+ const ownerInput = (await ask('Owner AID (required): ')).trim();
323
+ if (!isValidAid(ownerInput)) {
324
+ console.log(` ⚠ Invalid Owner AID "${ownerInput}"`);
325
+ continue;
428
326
  }
327
+ owner = ownerInput;
328
+ break;
429
329
  }
430
330
  const defaultName = aid.split('.')[0];
431
331
  const agentName = (await ask(`Display name [${defaultName}]: `)).trim() || defaultName;
@@ -438,14 +338,28 @@ export async function agentCreateInteractive(opts = {}) {
438
338
  if (tagErrors.length > 0)
439
339
  return { ok: false, error: `Invalid tags: ${tagErrors.join('; ')}` };
440
340
  }
341
+ let aidCreated = false;
342
+ try {
343
+ // Keep the registration connection independent from Ownership. Its
344
+ // authentication can be short-lived, so only submit binding after the
345
+ // complete agent.md has been published and the daemon has hot-loaded it.
346
+ const result = await aidCreate(aid, { type: 'agent' });
347
+ try {
348
+ await result.client.close();
349
+ }
350
+ catch { /* ignore */ }
351
+ aidCreated = !result.alreadyExisted;
352
+ console.log(` ✓ AID ${result.alreadyExisted ? 'reused' : 'created'}: ${aid}`);
353
+ }
354
+ catch (e) {
355
+ return { ok: false, error: `AID creation failed: ${e?.message || e}` };
356
+ }
441
357
  if (ownRl)
442
358
  rl.close();
443
- saveAgent(withStaticOwner({ $schema_version: CONFIG_SCHEMA_VERSION, aid, enabled: true, lifecycle: 'created', channels: [], projects: { defaultPath: projectPath } }, owner));
359
+ saveAgent({ $schema_version: CONFIG_SCHEMA_VERSION, aid, enabled: true, lifecycle: 'created', channels: [], projects: { defaultPath: projectPath } });
444
360
  ensureInitialRoleRegistry(aid);
445
361
  saveInitialBehavior(aid, baseagent);
446
362
  ensureAgentDirSkeleton(aid);
447
- if (owner)
448
- await syncOwnerContactsAfterCreate(aid, [owner]);
449
363
  let agentmdUploaded = false;
450
364
  try {
451
365
  const content = buildInitialAgentMd({ aid, name: agentName, description: agentDescription, tags: agentTags });
@@ -470,6 +384,13 @@ export async function agentCreateInteractive(opts = {}) {
470
384
  catch (e) {
471
385
  console.warn(` ⚠ agent.md generation failed: ${e?.message || e}`);
472
386
  }
387
+ if (owner && agentmdUploaded) {
388
+ const config = loadAgent(aid);
389
+ if (config) {
390
+ config.lifecycle = 'ownerpending';
391
+ saveAgent(config);
392
+ }
393
+ }
473
394
  let hotLoaded = false;
474
395
  let hotLoadError;
475
396
  try {
@@ -480,41 +401,39 @@ export async function agentCreateInteractive(opts = {}) {
480
401
  hotLoadError = ipcResult.error;
481
402
  }
482
403
  catch { /* daemon not running */ }
483
- let ownerBoundAid;
404
+ let ownerBindRequestedAid;
484
405
  let ownerBindSkipped = false;
485
406
  let ownerBindInterrupted = false;
486
- if (!owner && !skipQrBinding && process.stdin.isTTY && daemonHasOwner) {
407
+ if (owner && agentmdUploaded && hotLoaded) {
487
408
  try {
488
- const { runAgentOwnerQrBindFlow } = await import('./init-channel.js');
489
- const bound = await runAgentOwnerQrBindFlow(aid, agentName);
490
- if (bound.action === 'bound')
491
- ownerBoundAid = bound.boundAid;
492
- else if (bound.action === 'manual') {
493
- ownerBindSkipped = true;
494
- ownerBoundAid = await promptAgentOwnerManually(aid);
495
- }
496
- else
497
- ownerBindInterrupted = true;
409
+ const bindResult = await ipcQuery(p.socket, {
410
+ type: 'aid.ownership',
411
+ argv: ['aid', 'bind', owner, '--subject', aid],
412
+ }, 30_000);
413
+ if (!bindResult?.ok)
414
+ throw new Error(bindResult?.error || 'Ownership bind failed');
415
+ ownerBindRequestedAid = owner;
498
416
  }
499
- catch {
500
- ownerBindSkipped = true;
501
- ownerBoundAid = await promptAgentOwnerManually(aid);
417
+ catch (error) {
418
+ ownerBindInterrupted = true;
419
+ logger.warn(`[agent-create] Ownership bind interrupted for ${aid}: ${error instanceof Error ? error.message : String(error)}`);
502
420
  }
503
421
  }
504
- const finalOwnerAid = owner ?? ownerBoundAid;
505
- const ownerContactSync = await syncOwnerContactsAfterCreate(aid, finalOwnerAid ? [finalOwnerAid] : undefined);
422
+ else if (owner && agentmdUploaded) {
423
+ ownerBindSkipped = true;
424
+ }
506
425
  return {
507
426
  ok: true,
508
427
  aid,
428
+ ownerAid: owner,
509
429
  configPath: toPosix(path.join(agentDirPath, 'config.json')),
510
430
  aidCreated,
511
431
  agentmdUploaded,
512
432
  hotLoaded,
513
433
  hotLoadError,
514
- ownerBoundAid,
434
+ ownerBindRequestedAid,
515
435
  ownerBindSkipped,
516
436
  ownerBindInterrupted,
517
- ...ownerContactSync,
518
437
  };
519
438
  }
520
439
  finally {
@@ -526,32 +445,6 @@ export async function agentCreateInteractive(opts = {}) {
526
445
  }
527
446
  }
528
447
  }
529
- async function promptAgentOwnerManually(aid) {
530
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
531
- try {
532
- while (true) {
533
- const owner = (await new Promise(resolve => rl.question('\n扫码未完成。手动输入 agent owner AID(留空跳过): ', resolve))).trim();
534
- if (!owner)
535
- return undefined;
536
- if (!isValidAid(owner)) {
537
- console.log(' ⚠ Owner AID 格式无效');
538
- continue;
539
- }
540
- const agent = loadAgent(aid);
541
- if (!agent)
542
- return undefined;
543
- saveAgent(withStaticOwner(agent, owner));
544
- try {
545
- await ipcQuery(resolvePaths().socket, { type: 'evolagent.reload', name: aid }, 30_000);
546
- }
547
- catch { /* daemon not running */ }
548
- return owner;
549
- }
550
- }
551
- finally {
552
- rl.close();
553
- }
554
- }
555
448
  export async function agentCreateNonInteractive(opts, runtime = {}) {
556
449
  const p = resolvePaths();
557
450
  const { aidCreate, buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
@@ -560,6 +453,10 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
560
453
  const ownerError = validateAgentOwnerOptions(opts);
561
454
  if (ownerError)
562
455
  return failValidating(ownerError);
456
+ const ownerAid = opts.owner?.trim();
457
+ const agentType = normalizeAgentType(opts.type ?? DEFAULT_AGENT_TYPE) ?? opts.type ?? DEFAULT_AGENT_TYPE;
458
+ if (agentType === 'agent' && !ownerAid)
459
+ return failValidating('An owner AID is required when creating an agent');
563
460
  if (opts.tags !== undefined) {
564
461
  const tagErrors = validateAgentTags(opts.tags, { minCount: AGENT_TAG_MIN_COUNT, maxCount: AGENT_TAG_MAX_COUNT });
565
462
  if (tagErrors.length > 0)
@@ -577,7 +474,7 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
577
474
  }
578
475
  }
579
476
  if (!isValidAid(opts.aid))
580
- return failValidating(`Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
477
+ return failValidating(`Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.cn)`);
581
478
  if (hasSuppliedInitialization(opts.aid))
582
479
  return failValidating('Use agent initialize --resume for this target');
583
480
  const agentDirPath = path.join(p.agentsDir, opts.aid);
@@ -585,25 +482,20 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
585
482
  if (configExists && !opts.force)
586
483
  return failValidating(`Agent "${opts.aid}" already exists: ${agentDirPath}/config.json (use --force to overwrite)`);
587
484
  const available = detectAvailableBaseagents();
588
- if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason()))
589
- return failValidating('No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.');
485
+ if (available.length === 0)
486
+ return failValidating('No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or use bundled ecagent.');
590
487
  let baseagent;
591
488
  if (opts.baseagent) {
592
489
  if (!BASEAGENT_CANDIDATES.includes(opts.baseagent))
593
490
  return failValidating(`Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`);
594
491
  if (!available.includes(opts.baseagent))
595
492
  return failValidating(opts.baseagent === 'codex' ? getCodexAppServerAvailability().reason || `${opts.baseagent} is not available in the current environment` : `${opts.baseagent} is not available in the current environment (available: ${available.join('/')})`);
596
- if (opts.baseagent === 'ecagent') {
597
- const reason = ecagentUnavailableReason();
598
- if (reason)
599
- return failValidating(reason);
600
- }
601
493
  baseagent = opts.baseagent;
602
494
  }
603
495
  else {
604
496
  const defaultBaseagent = pickDefaultBaseagent(available);
605
497
  if (!defaultBaseagent)
606
- return failValidating('ecagent is optional; pass --baseagent ecagent after configuring its API key');
498
+ return failValidating('ecagent is optional; pass --baseagent ecagent to select it explicitly');
607
499
  baseagent = defaultBaseagent;
608
500
  }
609
501
  if (!path.isAbsolute(opts.project))
@@ -619,8 +511,13 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
619
511
  opts.onPhase?.('validating', 'done');
620
512
  opts.onPhase?.('registering_aid', 'begin');
621
513
  let aidCreated = false;
514
+ // Do not persist a pending registration ownership intent here. Avatar
515
+ // publication uses an AUN short connection, and the SDK may resume that
516
+ // intent as soon as the short connection is authenticated, before the final
517
+ // agent.md (including avatar) has been published. Submit the bind only after
518
+ // the final card is in place and the Agent has a long-lived channel.
622
519
  try {
623
- const result = await aidCreate(opts.aid);
520
+ const result = await aidCreate(opts.aid, { type: agentType });
624
521
  try {
625
522
  await result.client.close();
626
523
  }
@@ -643,17 +540,16 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
643
540
  catch { /* ignore */ }
644
541
  }
645
542
  opts.onPhase?.('config_saved', 'begin');
646
- saveAgent(withStaticOwners({ $schema_version: CONFIG_SCHEMA_VERSION, aid: opts.aid, enabled: true, lifecycle: preservedLifecycle, channels: [], projects: { defaultPath: opts.project } }, opts.owners ?? (opts.owner ? [opts.owner] : undefined)));
543
+ saveAgent({ $schema_version: CONFIG_SCHEMA_VERSION, aid: opts.aid, enabled: true, lifecycle: preservedLifecycle, channels: [], projects: { defaultPath: opts.project } });
647
544
  ensureInitialRoleRegistry(opts.aid);
648
545
  saveInitialBehavior(opts.aid, baseagent);
649
546
  ensureAgentDirSkeleton(opts.aid);
650
- const ownerContactSync = await syncOwnerContactsAfterCreate(opts.aid, opts.owners ?? (opts.owner ? [opts.owner] : undefined));
651
547
  opts.onPhase?.('config_saved', 'done');
652
548
  opts.onPhase?.('uploading_agentmd', 'begin');
653
549
  let agentmdUploaded = false;
654
550
  let agentmdError;
655
551
  try {
656
- const content = buildInitialAgentMd({ aid: opts.aid, name: opts.name, description: opts.description, type: opts.type, tags: opts.tags });
552
+ const content = buildInitialAgentMd({ aid: opts.aid, name: opts.name, description: opts.description, type: agentType, tags: opts.tags });
657
553
  const aunPath = process.env.AUN_HOME || defaultAunPath();
658
554
  let lastError;
659
555
  for (let attempt = 1; attempt <= 3; attempt++) {
@@ -679,6 +575,13 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
679
575
  agentmdError = `generation failed: ${e?.message || e}`;
680
576
  opts.onPhase?.('uploading_agentmd', 'warn', agentmdError);
681
577
  }
578
+ if (ownerAid && agentmdUploaded) {
579
+ const config = loadAgent(opts.aid);
580
+ if (config) {
581
+ config.lifecycle = 'ownerpending';
582
+ saveAgent(config);
583
+ }
584
+ }
682
585
  let avatarUploaded = false;
683
586
  if (opts.avatarFile || opts.avatarUrl) {
684
587
  opts.onPhase?.('uploading_avatar', 'begin');
@@ -726,18 +629,57 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
726
629
  hotLoadError = error instanceof Error ? error.message : String(error);
727
630
  opts.onPhase?.('hot_loading', 'warn', hotLoadError);
728
631
  }
632
+ let ownerBindRequestedAid;
633
+ let ownerBindSkipped = false;
634
+ let ownerBindInterrupted = false;
635
+ let ownershipBinding;
636
+ if (ownerAid && agentmdUploaded && hotLoaded) {
637
+ try {
638
+ let state;
639
+ if (runtime.bindOwnerAgent) {
640
+ state = await runtime.bindOwnerAgent(opts.aid, ownerAid);
641
+ }
642
+ else {
643
+ const bindResult = await ipcQuery(p.socket, {
644
+ type: 'aid.ownership',
645
+ argv: ['aid', 'bind', ownerAid, '--subject', opts.aid],
646
+ }, 30_000);
647
+ if (!bindResult?.ok)
648
+ throw new Error(bindResult?.error || 'Ownership bind failed');
649
+ state = bindResult.state;
650
+ }
651
+ ownerBindRequestedAid = ownerAid;
652
+ // Reusing an existing identity (including a failed-create retry) cannot
653
+ // prove that an SDK-reused task originated in this creation attempt.
654
+ const binding = aidCreated ? creationOwnershipBinding(state?.task, opts.aid, ownerAid) : undefined;
655
+ if (binding) {
656
+ opts.onOwnershipBinding?.(binding);
657
+ ownershipBinding = binding;
658
+ }
659
+ }
660
+ catch (error) {
661
+ ownerBindInterrupted = true;
662
+ logger.warn(`[agent-create] Ownership bind interrupted for ${opts.aid}: ${error instanceof Error ? error.message : String(error)}`);
663
+ }
664
+ }
665
+ else if (ownerAid && agentmdUploaded) {
666
+ ownerBindSkipped = true;
667
+ }
729
668
  return {
730
669
  ok: true,
731
670
  aid: opts.aid,
732
- ownerAid: (opts.owners ?? (opts.owner ? [opts.owner] : undefined))?.[0],
671
+ ownerAid,
733
672
  configPath: toPosix(path.join(agentDirPath, 'config.json')),
734
673
  aidCreated,
735
674
  agentmdUploaded,
736
675
  agentmdError,
737
676
  hotLoaded,
738
677
  hotLoadError,
678
+ ownerBindRequestedAid,
679
+ ownerBindSkipped,
680
+ ownerBindInterrupted,
681
+ ...(ownershipBinding ? { ownershipBinding } : {}),
739
682
  ...(opts.avatarFile || opts.avatarUrl ? { avatarUploaded } : {}),
740
- ...ownerContactSync,
741
683
  };
742
684
  }
743
685
  // ---- One-shot Agent initialization (kept with Agent creation) ----
@@ -755,7 +697,7 @@ export function initializationPath(aid) {
755
697
  }
756
698
  export function initializationFingerprint(plan) {
757
699
  return createHash('sha256').update(JSON.stringify([
758
- plan.aid, plan.project, plan.baseagent, plan.owners, plan.name,
700
+ plan.aid, plan.project, plan.baseagent, plan.ownerAid, plan.name,
759
701
  plan.description, plan.type, plan.tags, plan.persona ?? null,
760
702
  plan.avatarFile ?? null, plan.avatarUrl ?? null,
761
703
  ])).digest('hex');
@@ -824,15 +766,17 @@ function failure(code, error = code) {
824
766
  throw Object.assign(new Error(error), { code });
825
767
  }
826
768
  export function validateInitializationPlan(plan) {
827
- if (!plan.name?.trim() || !plan.description?.trim() || !Array.isArray(plan.tags) || !plan.owners?.length) {
828
- failure('INITIALIZE_FIELDS_REQUIRED', 'Explicit name, description, tags and owners are required');
769
+ if (!plan.name?.trim() || !plan.description?.trim() || !Array.isArray(plan.tags) || !plan.ownerAid?.trim()) {
770
+ failure('INITIALIZE_FIELDS_REQUIRED', 'Explicit name, description, tags and one Owner AID are required');
829
771
  }
772
+ if (!isValidAid(plan.ownerAid))
773
+ failure('INVALID_ARGS', 'Owner must be a valid AID');
830
774
  if (plan.type !== 'agent')
831
775
  failure('INVALID_ARGS', 'Initialized targets must have type=agent');
832
776
  if (plan.avatarFile !== undefined && plan.avatarUrl !== undefined)
833
777
  failure('INVALID_ARGS', 'avatar-file and avatar-url are mutually exclusive');
834
778
  const error = validateAgentCreatePlan({
835
- ...plan, force: false, configExists: false, baseagentSource: 'argument', ownerSource: 'argument',
779
+ ...plan, owner: plan.ownerAid, force: false, configExists: false, baseagentSource: 'argument', ownerSource: 'argument',
836
780
  nameSource: 'argument', descriptionSource: 'argument', typeSource: 'argument',
837
781
  });
838
782
  if (error)
@@ -931,6 +875,20 @@ export class AgentInitializationService {
931
875
  }
932
876
  return this.status(aid);
933
877
  }
878
+ resumeForOwner(aid, ownerAid) {
879
+ if (!ownerAid)
880
+ return;
881
+ try {
882
+ const record = readInitialization(aid);
883
+ if (!record || record.status !== 'in_progress' || record.phase !== 'ownerpending'
884
+ || this.running.has(aid))
885
+ return;
886
+ this.resume(aid, record.actor);
887
+ }
888
+ catch (error) {
889
+ logger.warn(`[Initialization] Owner-consensus recovery failed for ${aid}: ${error instanceof Error ? error.message : String(error)}`);
890
+ }
891
+ }
934
892
  async cancel(aid) {
935
893
  const r = readInitialization(aid);
936
894
  if (!r || r.status === 'complete')
@@ -987,7 +945,6 @@ export class AgentInitializationService {
987
945
  if (r.configSaved && (!config || config.enabled === false))
988
946
  failure('INITIALIZE_TARGET_CHANGED');
989
947
  if (config && (config.initialization?.operationId !== r.operationId
990
- || JSON.stringify(config.owners) !== JSON.stringify(r.plan.owners)
991
948
  || config.active_baseagent !== r.plan.baseagent || config.projects?.defaultPath !== r.plan.project)) {
992
949
  failure('INITIALIZE_TARGET_CHANGED');
993
950
  }
@@ -1000,13 +957,13 @@ export class AgentInitializationService {
1000
957
  async run(r) {
1001
958
  const p = r.plan;
1002
959
  this.phase(r, 'registering_aid');
1003
- await this.deps.register(p.aid);
960
+ await this.deps.register(p.aid, p.ownerAid);
1004
961
  this.phase(r, 'config_saved');
1005
962
  fs.mkdirSync(p.project, { recursive: true });
1006
963
  if (!loadAgent(p.aid)) {
1007
964
  saveAgent({
1008
965
  $schema_version: CONFIG_SCHEMA_VERSION, aid: p.aid, enabled: true, lifecycle: 'created',
1009
- initialization: { mode: 'supplied', operationId: r.operationId }, channels: [], owners: p.owners,
966
+ initialization: { mode: 'supplied', operationId: r.operationId }, channels: [],
1010
967
  projects: { defaultPath: p.project }, active_baseagent: p.baseagent,
1011
968
  baseagents: { [p.baseagent]: {} }, chatmode: { private: 'interactive', group: 'proactive', nothuman: 'proactive' },
1012
969
  });
@@ -1022,7 +979,6 @@ export class AgentInitializationService {
1022
979
  fs.writeFileSync(file, p.persona, { encoding: 'utf8', mode: 0o600 });
1023
980
  }
1024
981
  const resolvedAvatarFile = p.avatarFile;
1025
- await syncOwnerContactsAfterCreate(p.aid, p.owners);
1026
982
  this.phase(r, 'uploading_agentmd');
1027
983
  let remote;
1028
984
  if (r.publicationStarted) {
@@ -1088,13 +1044,22 @@ export class AgentInitializationService {
1088
1044
  }
1089
1045
  r.published = true;
1090
1046
  r.verified = true;
1091
- this.phase(r, 'hot_loading');
1092
- const config = loadAgent(p.aid);
1093
- if (config.lifecycle !== 'active') {
1094
- config.lifecycle = 'bootstrapping';
1095
- saveAgent(config);
1047
+ const currentConfig = loadAgent(p.aid);
1048
+ if (currentConfig.lifecycle !== 'ownerpending') {
1049
+ currentConfig.lifecycle = 'ownerpending';
1050
+ saveAgent(currentConfig);
1096
1051
  }
1052
+ this.phase(r, 'hot_loading');
1097
1053
  await this.deps.hotLoad(p.aid);
1054
+ if (this.deps.bindOwner)
1055
+ await this.deps.bindOwner(p.aid, p.ownerAid);
1056
+ this.phase(r, 'ownerpending');
1057
+ const ownership = await this.deps.checkOwner(p.aid, p.ownerAid);
1058
+ this.check(r);
1059
+ if (ownership === 'pending')
1060
+ return;
1061
+ if (ownership === 'conflict')
1062
+ failure('INITIALIZE_OWNER_CONFLICT', 'Fresh Ownership consensus does not confirm the requested Owner');
1098
1063
  this.phase(r, 'activating');
1099
1064
  if (p.persona !== undefined && fs.readFileSync(path.join(agentPersonalDir(p.aid), 'persona.md'), 'utf8') !== p.persona) {
1100
1065
  failure('INITIALIZE_PLAN_CONFLICT');
@@ -1145,9 +1110,11 @@ export function parseInitializationArgs(args) {
1145
1110
  const resume = args[0] === 'initialize';
1146
1111
  if ((!resume && args[0] !== 'new') || !isValidAid(args[1] ?? ''))
1147
1112
  throw new Error('Invalid initialization command or AID');
1113
+ if (!resume && resolveAgentCreateMode(args) !== 'initialize')
1114
+ throw new Error('--bootstrap cannot initialize an agent');
1148
1115
  const booleans = new Set(resume ? ['--resume'] : ['--initialize', '--non-interactive', '--dry-run']);
1149
1116
  const strings = new Set(resume ? ['--wait', '--format'] : [
1150
- '--project', '--baseagent', '--owner', '--owners', '--name', '--description', '--tags', '--type', '--avatar-file', '--avatar-url',
1117
+ '--project', '--baseagent', '--owner', '--name', '--description', '--tags', '--type', '--avatar-file', '--avatar-url',
1151
1118
  '--persona-file', '--persona-text', '--wait', '--format',
1152
1119
  ]);
1153
1120
  const seen = new Set();
@@ -1164,8 +1131,8 @@ export function parseInitializationArgs(args) {
1164
1131
  values[flag] = value;
1165
1132
  }
1166
1133
  }
1167
- if (!seen.has(resume ? '--resume' : '--initialize'))
1168
- throw new Error(resume ? '--resume required' : '--initialize required');
1134
+ if (resume && !seen.has('--resume'))
1135
+ throw new Error('--resume required');
1169
1136
  if (values['--format'] !== undefined && values['--format'] !== 'json')
1170
1137
  throw new Error('--format must be json');
1171
1138
  if (seen.has('--persona-file') && seen.has('--persona-text'))
@@ -1201,7 +1168,7 @@ export function resolveInitializationPlan(args, context) {
1201
1168
  name: v['--name'], description: v['--description'], tags: parseAgentTags(v['--tags']), type: v['--type'],
1202
1169
  }, context?.projectCwd);
1203
1170
  return {
1204
- aid: p.aid, project: p.project, baseagent: p.baseagent ?? '', owners: p.owners ?? (p.owner ? [p.owner] : []),
1171
+ aid: p.aid, project: p.project, baseagent: p.baseagent ?? '', ownerAid: p.owner ?? '',
1205
1172
  name: p.name, description: p.description, tags: p.tags, type: p.type,
1206
1173
  ...(persona !== undefined ? { persona } : {}),
1207
1174
  ...(v['--avatar-file'] !== undefined ? { avatarFile: v['--avatar-file'] } : {}),