evolcore 0.0.23 → 0.0.25

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 (245) hide show
  1. package/CHANGELOG.md +583 -516
  2. package/LICENSE +21 -21
  3. package/README.md +455 -453
  4. package/bin/codex-managed-acl.ps1 +160 -155
  5. package/bin/codex-managed-hook.mjs +209 -92
  6. package/bin/ec-safe-output.js +327 -245
  7. package/bin/ec.js +29 -29
  8. package/bin/install-codex-managed-hooks.mjs +555 -544
  9. package/dist/agents/baseagent-availability.js +4 -4
  10. package/dist/agents/baseagent.js +29 -1
  11. package/dist/agents/claude-runner.js +152 -14
  12. package/dist/agents/codex/app-server-client.js +18 -8
  13. package/dist/agents/codex/catalog.js +1 -1
  14. package/dist/agents/codex/diagnostics.js +215 -0
  15. package/dist/agents/codex-runner.js +445 -63
  16. package/dist/agents/ecagent-runner.js +31 -16
  17. package/dist/agents/gemini-runner.js +82 -4
  18. package/dist/agents/runner-types.js +1 -1
  19. package/dist/aun/aid/agentmd.js +56 -4
  20. package/dist/aun/aid/index.js +1 -0
  21. package/dist/aun/aid/managed-operation.js +80 -6
  22. package/dist/aun/aid/store.js +41 -0
  23. package/dist/aun/msg/managed-operation.js +6 -1
  24. package/dist/aun/outbox.js +56 -18
  25. package/dist/aun/rpc/client.js +4 -5
  26. package/dist/aun/storage/client.js +4 -1
  27. package/dist/aun/storage/index.js +1 -1
  28. package/dist/channels/aun.js +147 -76
  29. package/dist/channels/daemon.js +7 -1
  30. package/dist/channels/dingtalk.js +1 -0
  31. package/dist/channels/feishu.js +10 -4
  32. package/dist/channels/wecom.js +2 -1
  33. package/dist/cli/agent-command.js +214 -89
  34. package/dist/cli/agent-create.js +576 -0
  35. package/dist/cli/agent.js +129 -676
  36. package/dist/cli/aun-commands.js +419 -313
  37. package/dist/cli/bench.js +20 -20
  38. package/dist/cli/config.js +20 -20
  39. package/dist/cli/contact.js +10 -10
  40. package/dist/cli/ctl-command.js +22 -20
  41. package/dist/cli/daemon-commands.js +163 -32
  42. package/dist/cli/fs-command.js +67 -67
  43. package/dist/cli/handoff-command.js +7 -7
  44. package/dist/cli/index.js +79 -79
  45. package/dist/cli/link-rules.js +21 -21
  46. package/dist/cli/managed-command-guard.js +3 -0
  47. package/dist/cli/menu-client.js +11 -11
  48. package/dist/cli/net-check.js +22 -22
  49. package/dist/cli/queue-command.js +29 -29
  50. package/dist/cli/response.js +30 -30
  51. package/dist/cli/restart-monitor.js +462 -38
  52. package/dist/cli/stats.js +161 -51
  53. package/dist/cli/trigger-command.js +56 -56
  54. package/dist/config/builtin-roles.js +3 -0
  55. package/dist/config/config-manager.js +15 -0
  56. package/dist/config/config-operation-service.js +20 -3
  57. package/dist/config/resolved-config-op.js +39 -1
  58. package/dist/core/auth/auth-gateway.js +3 -2
  59. package/dist/core/auth/authorization-audit.js +72 -19
  60. package/dist/core/auth/operation-authorizer.js +125 -7
  61. package/dist/core/auth/operation-catalog.js +26 -2
  62. package/dist/core/auth/remote-access-store.js +3 -2
  63. package/dist/core/baseagent-loader.js +4 -4
  64. package/dist/core/bootstrap-messages.js +39 -18
  65. package/dist/core/bootstrap-service.js +32 -26
  66. package/dist/core/capability/capability-manager.js +8 -4
  67. package/dist/core/capability/providers/codex-capability-provider.js +1 -1
  68. package/dist/core/command/agent-control.js +60 -26
  69. package/dist/core/command/cli-intent-parser.js +18 -0
  70. package/dist/core/command/command-handler.js +173 -36
  71. package/dist/core/command/menu-catalog.js +4 -1
  72. package/dist/core/command/menu-handler.js +315 -75
  73. package/dist/core/command/menu-protocol.js +7 -2
  74. package/dist/core/command/slash-gate.js +1 -3
  75. package/dist/core/command/slash-handler.js +166 -57
  76. package/dist/core/data-migration.js +5 -15
  77. package/dist/core/event-catalog.js +8 -0
  78. package/dist/core/evolagent.js +3 -3
  79. package/dist/core/handoff/runtime.js +3 -1
  80. package/dist/core/handoff/store.js +7 -1
  81. package/dist/core/message/im-renderer.js +13 -6
  82. package/dist/core/message/message-bridge.js +5 -36
  83. package/dist/core/message/message-utils.js +6 -3
  84. package/dist/core/message/response-engine.js +85 -27
  85. package/dist/core/model/catalog-service.js +3 -1
  86. package/dist/core/model/model-catalog.js +10 -0
  87. package/dist/core/model/model-permission.js +4 -1
  88. package/dist/core/permission/approval-gateway.js +169 -33
  89. package/dist/core/permission/tool-policy.js +56 -10
  90. package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
  91. package/dist/core/session/session-manager.js +49 -13
  92. package/dist/core/session/session-renew.js +1 -0
  93. package/dist/index.js +327 -134
  94. package/dist/ipc.js +68 -21
  95. package/dist/paths.js +23 -1
  96. package/dist/stats/billing.js +18 -4
  97. package/dist/stats/db.js +159 -159
  98. package/dist/stats/eck-vars.js +9 -9
  99. package/dist/stats/query.js +139 -139
  100. package/dist/stats/role-budget.js +6 -6
  101. package/dist/stats/writer.js +51 -51
  102. package/dist/utils/atomic-write.js +26 -2
  103. package/dist/utils/avatar-upload.js +282 -23
  104. package/dist/utils/cross-platform.js +436 -1
  105. package/dist/utils/error-dict.json +160 -160
  106. package/dist/utils/error-utils.js +11 -4
  107. package/dist/utils/macos-autostart.js +22 -22
  108. package/dist/utils/model-prices.jsonl +23 -20
  109. package/dist/utils/npm-ops.js +24 -1
  110. package/dist/utils/welcome.js +22 -22
  111. package/dist/utils/windows-autostart.js +1 -1
  112. package/ecagent/LICENSE +21 -21
  113. package/ecagent/NOTICE +11 -11
  114. package/ecagent/README.md +61 -61
  115. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  116. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  117. package/ecagent/dist/harness/messages.js +7 -7
  118. package/kits/docs/GUIDE.md +20 -20
  119. package/kits/docs/INDEX.md +66 -66
  120. package/kits/docs/aun/CHEATSHEET.md +19 -19
  121. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  122. package/kits/docs/channels/aun.md +56 -56
  123. package/kits/docs/channels/feishu.md +56 -56
  124. package/kits/docs/context-assembly.md +365 -364
  125. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  126. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  127. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  128. package/kits/docs/eck_templates/runtime.template.md +19 -19
  129. package/kits/docs/evolcore/INDEX.md +71 -69
  130. package/kits/docs/evolcore/agent-create.md +170 -156
  131. package/kits/docs/evolcore/agent.md +83 -73
  132. package/kits/docs/evolcore/aid.md +64 -62
  133. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -0
  134. package/kits/docs/evolcore/config.md +195 -195
  135. package/kits/docs/evolcore/contact.md +68 -68
  136. package/kits/docs/evolcore/ctl.md +46 -46
  137. package/kits/docs/evolcore/event.md +216 -216
  138. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  139. package/kits/docs/evolcore/fs.md +110 -110
  140. package/kits/docs/evolcore/group-collaboration.md +243 -243
  141. package/kits/docs/evolcore/group-fs.md +17 -17
  142. package/kits/docs/evolcore/group-rules.md +251 -251
  143. package/kits/docs/evolcore/group.md +152 -152
  144. package/kits/docs/evolcore/menu-client.md +34 -34
  145. package/kits/docs/evolcore/model.md +50 -50
  146. package/kits/docs/evolcore/msg.md +165 -165
  147. package/kits/docs/evolcore/response.md +75 -75
  148. package/kits/docs/evolcore/rpc.md +37 -37
  149. package/kits/docs/evolcore/self-summary.md +29 -29
  150. package/kits/docs/evolcore/stats.md +83 -83
  151. package/kits/docs/evolcore/storage.md +50 -50
  152. package/kits/docs/evolcore/trigger.md +575 -575
  153. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  154. package/kits/docs/identity/PATH_OPS.md +16 -16
  155. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  156. package/kits/docs/identity/identity-tools.md +26 -26
  157. package/kits/docs/path-registry.md +62 -62
  158. package/kits/docs/prompt-loading-architecture.md +270 -269
  159. package/kits/docs/venues/aun-group.md +45 -45
  160. package/kits/docs/venues/aun-private.md +10 -10
  161. package/kits/docs/venues/client-desktop.md +10 -10
  162. package/kits/docs/venues/client-mobile.md +10 -10
  163. package/kits/docs/venues/feishu-group.md +13 -13
  164. package/kits/docs/venues/feishu-private.md +9 -9
  165. package/kits/docs/venues/group.md +25 -25
  166. package/kits/docs/venues/private.md +10 -10
  167. package/kits/eck_manifest.auxiliary.json +43 -43
  168. package/kits/eck_manifest.json +195 -183
  169. package/kits/eck_message_manifest.json +74 -74
  170. package/kits/migrations/README-role-config-v4.md +32 -32
  171. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  172. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  173. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  174. package/kits/migrations/rename-config-file.mjs +99 -99
  175. package/kits/rules/01-overview.md +162 -162
  176. package/kits/rules/02-navigation.md +96 -96
  177. package/kits/rules/03-identity.md +39 -37
  178. package/kits/rules/04-relation.md +75 -75
  179. package/kits/rules/05-venue.md +60 -60
  180. package/kits/rules/06-channel.md +63 -63
  181. package/kits/schemas/_meta.json +53 -53
  182. package/kits/schemas/agent-config.schema.1.json +177 -177
  183. package/kits/schemas/agent-config.schema.10.json +395 -395
  184. package/kits/schemas/agent-config.schema.11.json +421 -421
  185. package/kits/schemas/agent-config.schema.12.json +427 -427
  186. package/kits/schemas/agent-config.schema.2.json +239 -239
  187. package/kits/schemas/agent-config.schema.3.json +119 -119
  188. package/kits/schemas/agent-config.schema.4.json +208 -208
  189. package/kits/schemas/agent-config.schema.5.json +326 -326
  190. package/kits/schemas/agent-config.schema.6.json +322 -322
  191. package/kits/schemas/agent-config.schema.7.json +303 -303
  192. package/kits/schemas/agent-config.schema.8.json +304 -304
  193. package/kits/schemas/agent-config.schema.9.json +364 -364
  194. package/kits/schemas/contact-book.schema.1.json +36 -36
  195. package/kits/schemas/contact-book.schema.2.json +43 -43
  196. package/kits/schemas/contact-book.schema.3.json +67 -67
  197. package/kits/schemas/daemon.schema.1.json +91 -91
  198. package/kits/schemas/daemon.schema.2.json +101 -101
  199. package/kits/schemas/daemon.schema.3.json +123 -123
  200. package/kits/schemas/daemon.schema.4.json +136 -136
  201. package/kits/schemas/daemon.schema.5.json +135 -135
  202. package/kits/schemas/daemon.schema.6.json +131 -131
  203. package/kits/schemas/defaults.schema.1.json +81 -81
  204. package/kits/schemas/defaults.schema.2.json +85 -85
  205. package/kits/schemas/defaults.schema.3.json +73 -73
  206. package/kits/schemas/defaults.schema.4.json +107 -107
  207. package/kits/schemas/defaults.schema.5.json +119 -119
  208. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  209. package/kits/schemas/migrations/README.md +30 -30
  210. package/kits/schemas/relation-config.schema.1.json +158 -158
  211. package/kits/schemas/relation-config.schema.2.json +73 -73
  212. package/kits/schemas/relation-config.schema.3.json +50 -50
  213. package/kits/schemas/relation-config.schema.4.json +47 -47
  214. package/kits/schemas/relation-config.schema.5.json +47 -47
  215. package/kits/schemas/relation-config.schema.6.json +46 -46
  216. package/kits/schemas/relation-config.schema.7.json +59 -59
  217. package/kits/schemas/relation-config.schema.8.json +103 -103
  218. package/kits/schemas/role-config.schema.1.json +201 -201
  219. package/kits/schemas/role-registry.schema.1.json +35 -35
  220. package/kits/schemas/single-session.schema.1.json +31 -31
  221. package/kits/schemas/single-session.schema.2.json +57 -57
  222. package/kits/schemas/single-session.schema.3.json +32 -32
  223. package/kits/templates/bootstrap-welcome.md +17 -17
  224. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  225. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  226. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  227. package/kits/templates/message-fragments/inject-default.md +2 -2
  228. package/kits/templates/message-fragments/item.md +2 -2
  229. package/kits/templates/roles/admin.json +96 -82
  230. package/kits/templates/roles/member.json +97 -96
  231. package/kits/templates/roles/owner.json +9 -9
  232. package/kits/templates/roles/visitor.json +86 -85
  233. package/kits/templates/system-fragments/baseagent.md +14 -14
  234. package/kits/templates/system-fragments/bootstrap.md +38 -29
  235. package/kits/templates/system-fragments/channel.md +64 -64
  236. package/kits/templates/system-fragments/commands.md +28 -28
  237. package/kits/templates/system-fragments/identity.md +13 -13
  238. package/kits/templates/system-fragments/relation.md +19 -19
  239. package/kits/templates/system-fragments/session.md +59 -59
  240. package/kits/templates/system-fragments/venue.md +31 -31
  241. package/package.json +98 -94
  242. package/AGENTS.md +0 -62
  243. package/dist/utils/codex-cli.js +0 -43
  244. package/skills/eclink/SKILL.md +0 -84
  245. package/skills/eclink/agents/openai.yaml +0 -4
@@ -0,0 +1,576 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import readline from 'readline';
4
+ import { resolvePaths, aunPath as defaultAunPath } from '../paths.js';
5
+ import { loadDefaults, loadAgent, saveAgent, ensureAgentDirSkeleton, loadDaemonConfig } from '../config-store.js';
6
+ import { ConfigTarget, write as cfgWrite, ensureFile as cfgEnsure, read as cfgRead } from '../config/config-manager.js';
7
+ import { ipcQuery } from '../ipc.js';
8
+ import { CONFIG_SCHEMA_VERSION } from '../types.js';
9
+ import { ensureInitialRoleRegistry } from '../config/role-service.js';
10
+ import { getCodexAppServerAvailability } from '../agents/codex-runner.js';
11
+ import { resolveEcagentConfig } from '../agents/baseagent.js';
12
+ import { AUTO_BASEAGENT_CANDIDATES, BASEAGENT_CANDIDATES, detectAvailableBaseagents, } from '../agents/baseagent-availability.js';
13
+ import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/project-path.js';
14
+ import { isValidAid } from '../aun/aid/validation.js';
15
+ import { AGENT_TAG_MAX_COUNT, AGENT_TAG_MIN_COUNT, DEFAULT_AGENT_DESCRIPTION, validateAgentTags, } from '../aun/aid/agentmd.js';
16
+ export function parseAgentTags(raw) {
17
+ if (raw === undefined)
18
+ return undefined;
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(raw);
22
+ }
23
+ catch {
24
+ throw new Error('--tags must be a JSON array of 3 to 6 valid tags');
25
+ }
26
+ if (!Array.isArray(parsed))
27
+ throw new Error('--tags must be a JSON array of 3 to 6 valid tags');
28
+ const tags = parsed.map(value => typeof value === 'string' ? value.trim() : value);
29
+ const tagErrors = validateAgentTags(tags, { minCount: AGENT_TAG_MIN_COUNT, maxCount: AGENT_TAG_MAX_COUNT });
30
+ if (tagErrors.length > 0)
31
+ throw new Error(`--tags ${tagErrors.join('; ')}`);
32
+ // Duplicate labels are harmless at the wire level, but should not consume
33
+ // the advertised 3-6 tag budget or produce duplicate frontmatter entries.
34
+ return [...new Set(tags)];
35
+ }
36
+ export function validateAgentOwnerOptions(options) {
37
+ if (options.owner !== undefined && options.owners !== undefined) {
38
+ return 'Options --owner and --owners are mutually exclusive';
39
+ }
40
+ if (options.owners !== undefined && (!Array.isArray(options.owners) || options.owners.length === 0)) {
41
+ return '--owners must be a non-empty JSON array of AIDs';
42
+ }
43
+ const owners = options.owners ?? (options.owner !== undefined ? [options.owner] : []);
44
+ if (owners.some(owner => typeof owner !== 'string' || !isValidAid(owner))) {
45
+ return 'Every owner must be a valid AID';
46
+ }
47
+ return null;
48
+ }
49
+ /** Shared by the standalone CLI and the authenticated daemon command path. */
50
+ export function parseAgentOwnerArgs(argv) {
51
+ const hasOwner = argv.includes('--owner');
52
+ const hasOwners = argv.includes('--owners');
53
+ if (hasOwner && hasOwners)
54
+ throw new Error('Options --owner and --owners are mutually exclusive');
55
+ const value = (flag) => {
56
+ if (argv.filter(arg => arg === flag).length !== 1)
57
+ throw new Error(`${flag} must be supplied once`);
58
+ const argument = argv[argv.indexOf(flag) + 1];
59
+ if (!argument || argument.startsWith('--'))
60
+ throw new Error(`${flag} requires a value`);
61
+ return argument;
62
+ };
63
+ const options = {};
64
+ if (hasOwner)
65
+ options.owner = value('--owner');
66
+ if (hasOwners) {
67
+ const raw = value('--owners');
68
+ try {
69
+ options.owners = JSON.parse(raw);
70
+ }
71
+ catch {
72
+ throw new Error('--owners must be a non-empty JSON array of AIDs');
73
+ }
74
+ }
75
+ const error = validateAgentOwnerOptions(options);
76
+ if (error)
77
+ throw new Error(error);
78
+ if (options.owners)
79
+ options.owners = [...new Set(options.owners)];
80
+ return options;
81
+ }
82
+ function withStaticOwners(config, ownersInput) {
83
+ const values = (ownersInput ?? []).map(value => value.trim()).filter(Boolean);
84
+ if (values.length === 0)
85
+ return config;
86
+ const owners = config.owners ?? [];
87
+ return { ...config, owners: [...new Set([...owners, ...values])] };
88
+ }
89
+ function withStaticOwner(config, owner) {
90
+ return withStaticOwners(config, owner ? [owner] : undefined);
91
+ }
92
+ function pickDefaultBaseagent(available) {
93
+ return AUTO_BASEAGENT_CANDIDATES.find(candidate => available.includes(candidate)) ?? null;
94
+ }
95
+ function readProjectMetadata(project) {
96
+ try {
97
+ const packageJsonPath = path.join(project, 'package.json');
98
+ if (!fs.existsSync(packageJsonPath))
99
+ return {};
100
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
101
+ return {
102
+ name: typeof parsed.name === 'string' ? parsed.name.trim() : undefined,
103
+ description: typeof parsed.description === 'string' ? parsed.description.trim() : undefined,
104
+ };
105
+ }
106
+ catch {
107
+ return {};
108
+ }
109
+ }
110
+ function projectSlug(project) {
111
+ const basename = path.basename(project) || 'agent';
112
+ const slug = basename
113
+ .normalize('NFKD')
114
+ .replace(/[^a-zA-Z0-9-]+/g, '-')
115
+ .replace(/^-+|-+$/g, '')
116
+ .toLowerCase()
117
+ .slice(0, 63)
118
+ .replace(/-+$/g, '');
119
+ return slug || 'agent';
120
+ }
121
+ export function resolveAgentCreatePlan(options) {
122
+ const aid = options.aid.trim();
123
+ const project = path.resolve(options.project || process.cwd());
124
+ const metadata = readProjectMetadata(project);
125
+ const defaults = loadDefaults();
126
+ const daemon = loadDaemonConfig();
127
+ const configuredBaseagent = defaults?.active_baseagent;
128
+ const available = detectAvailableBaseagents();
129
+ const defaultBaseagent = configuredBaseagent && available.includes(configuredBaseagent)
130
+ ? configuredBaseagent
131
+ : pickDefaultBaseagent(available) ?? undefined;
132
+ const baseagent = options.baseagent || defaultBaseagent;
133
+ const baseagentSource = options.baseagent
134
+ ? 'argument'
135
+ : configuredBaseagent && baseagent === configuredBaseagent ? 'defaults' : 'detected';
136
+ const owners = options.owners;
137
+ const owner = options.owner?.trim() || (owners === undefined ? daemon.owners?.[0] : undefined);
138
+ const ownerSource = owners !== undefined || options.owner?.trim() ? 'argument' : owner ? 'daemon' : 'none';
139
+ const name = options.name?.trim() || metadata.name || projectSlug(project);
140
+ const description = options.description?.trim() || metadata.description || DEFAULT_AGENT_DESCRIPTION;
141
+ const configExists = isValidAid(aid) && fs.existsSync(path.join(resolvePaths().agentsDir, aid, 'config.json'));
142
+ return {
143
+ aid, project, baseagent, owner, owners, handoff: options.handoff, name, description, tags: options.tags,
144
+ force: options.force === true, configExists, baseagentSource, ownerSource,
145
+ nameSource: options.name?.trim() ? 'argument' : metadata.name ? 'package' : 'directory',
146
+ descriptionSource: options.description?.trim() ? 'argument' : metadata.description ? 'package' : 'default',
147
+ };
148
+ }
149
+ export function validateAgentCreatePlan(plan) {
150
+ const ownerError = validateAgentOwnerOptions(plan);
151
+ if (ownerError)
152
+ return ownerError;
153
+ if (!isValidAid(plan.aid))
154
+ return `Invalid AID "${plan.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`;
155
+ if (plan.configExists && !plan.force)
156
+ return `Agent "${plan.aid}" already exists (use --force to overwrite)`;
157
+ if (plan.tags !== undefined) {
158
+ const tagErrors = validateAgentTags(plan.tags, { minCount: AGENT_TAG_MIN_COUNT, maxCount: AGENT_TAG_MAX_COUNT });
159
+ if (tagErrors.length > 0)
160
+ return `Invalid tags: ${tagErrors.join('; ')}`;
161
+ }
162
+ if (!plan.baseagent)
163
+ return 'No usable baseagent detected. Pass --baseagent or configure a baseagent in agents/defaults.json.';
164
+ if (!BASEAGENT_CANDIDATES.includes(plan.baseagent)) {
165
+ return `Invalid baseagent: ${plan.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`;
166
+ }
167
+ if (!detectAvailableBaseagents().includes(plan.baseagent)) {
168
+ return `${plan.baseagent} is not available in the current environment`;
169
+ }
170
+ if (plan.baseagent === 'ecagent') {
171
+ const reason = ecagentUnavailableReason();
172
+ if (reason)
173
+ return reason;
174
+ }
175
+ return null;
176
+ }
177
+ function ecagentUnavailableReason() {
178
+ try {
179
+ resolveEcagentConfig({ agents: { ecagent: {} } });
180
+ return undefined;
181
+ }
182
+ catch (error) {
183
+ return error instanceof Error ? error.message : String(error);
184
+ }
185
+ }
186
+ function saveInitialBehavior(aid, baseagent) {
187
+ const behavior = {
188
+ active_baseagent: baseagent,
189
+ baseagents: { [baseagent]: {} },
190
+ chatmode: { private: 'interactive', group: 'proactive', nothuman: 'proactive' },
191
+ };
192
+ const sel = { self: aid };
193
+ const existingBehavior = cfgRead(ConfigTarget.Agent, sel) || {};
194
+ cfgEnsure(ConfigTarget.Agent, sel);
195
+ cfgWrite(ConfigTarget.Agent, { ...existingBehavior, ...behavior }, sel);
196
+ }
197
+ function toPosix(value) {
198
+ return value ? value.replace(/\\/g, '/') : null;
199
+ }
200
+ export async function agentCreateInteractive(opts = {}) {
201
+ const p = resolvePaths();
202
+ const ownRl = !opts.rl;
203
+ const rl = opts.rl ?? readline.createInterface({ input: opts.stdin || process.stdin, output: opts.stdout || process.stdout });
204
+ const ask = (q) => new Promise(r => rl.question(q, r));
205
+ try {
206
+ const { aidCreate, buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
207
+ const aidPrompt = opts.suggestedName ? `AID [${opts.suggestedName}]: ` : 'AID (e.g. mybot.agentid.pub): ';
208
+ let aid = '';
209
+ while (!aid) {
210
+ const aidInput = (await ask(aidPrompt)).trim();
211
+ const candidate = aidInput || opts.suggestedName;
212
+ if (!candidate) {
213
+ console.log(' ⚠ AID is required.');
214
+ continue;
215
+ }
216
+ if (!isValidAid(candidate)) {
217
+ console.log(` ⚠ Invalid AID "${candidate}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
218
+ continue;
219
+ }
220
+ aid = candidate;
221
+ }
222
+ const agentDirPath = path.join(p.agentsDir, aid);
223
+ const configExists = fs.existsSync(path.join(agentDirPath, 'config.json'));
224
+ if (configExists) {
225
+ const ans = (await ask(`Agent "${aid}" already exists. Overwrite config.json? (AID 与 agent.md 保留) [y/N]: `)).trim().toLowerCase();
226
+ if (ans !== 'y' && ans !== 'yes')
227
+ return { ok: false, error: 'Aborted.' };
228
+ }
229
+ console.log(`\nCreating agent: ${aid}\n`);
230
+ let aidCreated = false;
231
+ try {
232
+ const result = await aidCreate(aid);
233
+ try {
234
+ await result.client.close();
235
+ }
236
+ catch { /* ignore */ }
237
+ aidCreated = !result.alreadyExisted;
238
+ console.log(` ✓ AID ${result.alreadyExisted ? 'reused' : 'created'}: ${aid}`);
239
+ }
240
+ catch (e) {
241
+ return { ok: false, error: `AID creation failed: ${e?.message || e}` };
242
+ }
243
+ let suggestedProjectPath = '';
244
+ try {
245
+ suggestedProjectPath = deriveAgentProjectPath(agentProjectRootFromDefaults(loadDefaults(), p.root), aid);
246
+ }
247
+ catch {
248
+ suggestedProjectPath = deriveAgentProjectPath(agentProjectRootFromDefaults(null, p.root), aid);
249
+ }
250
+ const projectInput = (await ask(`Project path [${suggestedProjectPath}]: `)).trim();
251
+ const projectPath = projectInput || suggestedProjectPath;
252
+ if (!path.isAbsolute(projectPath))
253
+ return { ok: false, error: 'Project path must be an absolute path.' };
254
+ if (!fs.existsSync(projectPath)) {
255
+ const create = (await ask(`Project path does not exist. Create? [Y/n]: `)).trim().toLowerCase();
256
+ if (create === '' || create === 'y' || create === 'yes') {
257
+ try {
258
+ fs.mkdirSync(projectPath, { recursive: true });
259
+ }
260
+ catch (e) {
261
+ return { ok: false, error: `Failed to create project path "${projectPath}": ${e?.message || e}` };
262
+ }
263
+ console.log(` ✓ Created ${projectPath}`);
264
+ }
265
+ else
266
+ return { ok: false, error: 'Aborted.' };
267
+ }
268
+ const available = detectAvailableBaseagents();
269
+ if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
270
+ return { ok: false, error: 'No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.' };
271
+ }
272
+ const defaultBa = pickDefaultBaseagent(available);
273
+ let baseagent;
274
+ if (available.length === 1 && defaultBa) {
275
+ console.log(` Baseagent: ${defaultBa}`);
276
+ baseagent = defaultBa;
277
+ }
278
+ else {
279
+ let chosen = null;
280
+ while (chosen === null) {
281
+ const defaultHint = defaultBa ? ` [${defaultBa}]` : '';
282
+ const input = (await ask(`Baseagent (${available.join('/')})${defaultHint}: `)).trim() || defaultBa;
283
+ if (!input) {
284
+ console.log(' ecagent is optional; enter ecagent to select it explicitly.');
285
+ continue;
286
+ }
287
+ if (!BASEAGENT_CANDIDATES.includes(input)) {
288
+ console.log(` Invalid choice. Options: ${BASEAGENT_CANDIDATES.join('/')}`);
289
+ continue;
290
+ }
291
+ if (!available.includes(input)) {
292
+ console.log(` ${input} is not available in the current environment. Available: ${available.join('/')}`);
293
+ continue;
294
+ }
295
+ if (input === 'ecagent') {
296
+ const reason = ecagentUnavailableReason();
297
+ if (reason) {
298
+ console.log(` ecagent is unavailable: ${reason}`);
299
+ continue;
300
+ }
301
+ }
302
+ chosen = input;
303
+ }
304
+ baseagent = chosen;
305
+ }
306
+ const daemonCfg = loadDaemonConfig();
307
+ const daemonHasOwner = !!daemonCfg.owners?.length;
308
+ let owner;
309
+ let skipQrBinding = false;
310
+ if (daemonHasOwner) {
311
+ const defaultOwner = daemonCfg.owners[0];
312
+ while (true) {
313
+ const ownerInput = (await ask(`Owner AID [${defaultOwner}]: `)).trim();
314
+ if (!ownerInput) {
315
+ owner = defaultOwner;
316
+ break;
317
+ }
318
+ if (ownerInput.toLowerCase() === 'new' || ownerInput.toLowerCase() === 'qr') {
319
+ break;
320
+ }
321
+ if (!isValidAid(ownerInput)) {
322
+ console.log(` ⚠ Invalid Owner AID "${ownerInput}"`);
323
+ continue;
324
+ }
325
+ owner = ownerInput;
326
+ skipQrBinding = true;
327
+ break;
328
+ }
329
+ }
330
+ const defaultName = aid.split('.')[0];
331
+ const agentName = (await ask(`Display name [${defaultName}]: `)).trim() || defaultName;
332
+ const agentDescription = (await ask('Description (optional): ')).trim() || '';
333
+ const tagInput = (await ask('Tags (3-6, comma separated; optional): ')).trim();
334
+ let agentTags;
335
+ if (tagInput) {
336
+ agentTags = [...new Set(tagInput.split(/[,,\s]+/).map(tag => tag.trim()).filter(Boolean))];
337
+ const tagErrors = validateAgentTags(agentTags, { minCount: AGENT_TAG_MIN_COUNT, maxCount: AGENT_TAG_MAX_COUNT });
338
+ if (tagErrors.length > 0)
339
+ return { ok: false, error: `Invalid tags: ${tagErrors.join('; ')}` };
340
+ }
341
+ if (ownRl)
342
+ rl.close();
343
+ saveAgent(withStaticOwner({ $schema_version: CONFIG_SCHEMA_VERSION, aid, enabled: true, lifecycle: 'created', channels: [], projects: { defaultPath: projectPath } }, owner));
344
+ ensureInitialRoleRegistry(aid);
345
+ saveInitialBehavior(aid, baseagent);
346
+ ensureAgentDirSkeleton(aid);
347
+ let agentmdUploaded = false;
348
+ try {
349
+ const content = buildInitialAgentMd({ aid, name: agentName, description: agentDescription, tags: agentTags });
350
+ const aunPath = process.env.AUN_HOME || defaultAunPath();
351
+ let lastError;
352
+ for (let attempt = 1; attempt <= 3; attempt++) {
353
+ try {
354
+ if (attempt > 1)
355
+ await new Promise(r => setTimeout(r, 2000));
356
+ await agentmdPut(content, { aid, aunPath });
357
+ agentmdUploaded = true;
358
+ break;
359
+ }
360
+ catch (e) {
361
+ lastError = e;
362
+ }
363
+ }
364
+ if (!agentmdUploaded)
365
+ console.warn(` ⚠ agent.md upload failed: ${lastError?.message || lastError}`);
366
+ await new Promise(r => setTimeout(r, 0));
367
+ }
368
+ catch (e) {
369
+ console.warn(` ⚠ agent.md generation failed: ${e?.message || e}`);
370
+ }
371
+ let hotLoaded = false;
372
+ let hotLoadError;
373
+ try {
374
+ const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid }, 30_000);
375
+ if (ipcResult?.ok)
376
+ hotLoaded = true;
377
+ else if (ipcResult)
378
+ hotLoadError = ipcResult.error;
379
+ }
380
+ catch { /* daemon not running */ }
381
+ let ownerBoundAid;
382
+ let ownerBindSkipped = false;
383
+ let ownerBindInterrupted = false;
384
+ if (!owner && !skipQrBinding && process.stdin.isTTY && daemonHasOwner) {
385
+ try {
386
+ const { runAgentOwnerQrBindFlow } = await import('./init-channel.js');
387
+ const bound = await runAgentOwnerQrBindFlow(aid, agentName);
388
+ if (bound.action === 'bound')
389
+ ownerBoundAid = bound.boundAid;
390
+ else if (bound.action === 'manual') {
391
+ ownerBindSkipped = true;
392
+ ownerBoundAid = await promptAgentOwnerManually(aid);
393
+ }
394
+ else
395
+ ownerBindInterrupted = true;
396
+ }
397
+ catch {
398
+ ownerBindSkipped = true;
399
+ ownerBoundAid = await promptAgentOwnerManually(aid);
400
+ }
401
+ }
402
+ return { ok: true, aid, configPath: toPosix(path.join(agentDirPath, 'config.json')), aidCreated, agentmdUploaded, hotLoaded, hotLoadError, ownerBoundAid, ownerBindSkipped, ownerBindInterrupted };
403
+ }
404
+ finally {
405
+ if (ownRl) {
406
+ try {
407
+ rl.close();
408
+ }
409
+ catch { /* ignore */ }
410
+ }
411
+ }
412
+ }
413
+ async function promptAgentOwnerManually(aid) {
414
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
415
+ try {
416
+ while (true) {
417
+ const owner = (await new Promise(resolve => rl.question('\n扫码未完成。手动输入 agent owner AID(留空跳过): ', resolve))).trim();
418
+ if (!owner)
419
+ return undefined;
420
+ if (!isValidAid(owner)) {
421
+ console.log(' ⚠ Owner AID 格式无效');
422
+ continue;
423
+ }
424
+ const agent = loadAgent(aid);
425
+ if (!agent)
426
+ return undefined;
427
+ saveAgent(withStaticOwner(agent, owner));
428
+ try {
429
+ await ipcQuery(resolvePaths().socket, { type: 'evolagent.reload', name: aid }, 30_000);
430
+ }
431
+ catch { /* daemon not running */ }
432
+ return owner;
433
+ }
434
+ }
435
+ finally {
436
+ rl.close();
437
+ }
438
+ }
439
+ export async function agentCreateNonInteractive(opts, runtime = {}) {
440
+ const p = resolvePaths();
441
+ const { aidCreate, buildInitialAgentMd, agentmdPut } = await import('../aun/aid/index.js');
442
+ opts.onPhase?.('validating', 'begin');
443
+ const failValidating = (error) => { opts.onPhase?.('validating', 'failed', error); return { ok: false, error }; };
444
+ const ownerError = validateAgentOwnerOptions(opts);
445
+ if (ownerError)
446
+ return failValidating(ownerError);
447
+ if (opts.tags !== undefined) {
448
+ const tagErrors = validateAgentTags(opts.tags, { minCount: AGENT_TAG_MIN_COUNT, maxCount: AGENT_TAG_MAX_COUNT });
449
+ if (tagErrors.length > 0)
450
+ return failValidating(`Invalid tags: ${tagErrors.join('; ')}`);
451
+ }
452
+ if (!isValidAid(opts.aid))
453
+ return failValidating(`Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
454
+ const agentDirPath = path.join(p.agentsDir, opts.aid);
455
+ const configExists = fs.existsSync(path.join(agentDirPath, 'config.json'));
456
+ if (configExists && !opts.force)
457
+ return failValidating(`Agent "${opts.aid}" already exists: ${agentDirPath}/config.json (use --force to overwrite)`);
458
+ const available = detectAvailableBaseagents();
459
+ if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason()))
460
+ return failValidating('No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.');
461
+ let baseagent;
462
+ if (opts.baseagent) {
463
+ if (!BASEAGENT_CANDIDATES.includes(opts.baseagent))
464
+ return failValidating(`Invalid baseagent: ${opts.baseagent} (options: ${BASEAGENT_CANDIDATES.join('/')})`);
465
+ if (!available.includes(opts.baseagent))
466
+ 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('/')})`);
467
+ if (opts.baseagent === 'ecagent') {
468
+ const reason = ecagentUnavailableReason();
469
+ if (reason)
470
+ return failValidating(reason);
471
+ }
472
+ baseagent = opts.baseagent;
473
+ }
474
+ else {
475
+ const defaultBaseagent = pickDefaultBaseagent(available);
476
+ if (!defaultBaseagent)
477
+ return failValidating('ecagent is optional; pass --baseagent ecagent after configuring its API key');
478
+ baseagent = defaultBaseagent;
479
+ }
480
+ if (!path.isAbsolute(opts.project))
481
+ return failValidating(`--project must be absolute: ${opts.project}`);
482
+ if (!fs.existsSync(opts.project)) {
483
+ try {
484
+ fs.mkdirSync(opts.project, { recursive: true });
485
+ }
486
+ catch (e) {
487
+ return failValidating(`Failed to create ${opts.project}: ${e?.message || e}`);
488
+ }
489
+ }
490
+ opts.onPhase?.('validating', 'done');
491
+ opts.onPhase?.('registering_aid', 'begin');
492
+ let aidCreated = false;
493
+ try {
494
+ const result = await aidCreate(opts.aid);
495
+ try {
496
+ await result.client.close();
497
+ }
498
+ catch { /* ignore */ }
499
+ aidCreated = !result.alreadyExisted;
500
+ opts.onPhase?.('registering_aid', 'done', aidCreated ? 'created' : 'existed');
501
+ }
502
+ catch (e) {
503
+ const error = `AID creation failed: ${e?.message || e}`;
504
+ opts.onPhase?.('registering_aid', 'failed', error);
505
+ return { ok: false, error };
506
+ }
507
+ let preservedLifecycle = 'created';
508
+ if (configExists) {
509
+ try {
510
+ const existing = loadAgent(opts.aid);
511
+ if (existing?.lifecycle)
512
+ preservedLifecycle = existing.lifecycle;
513
+ }
514
+ catch { /* ignore */ }
515
+ }
516
+ opts.onPhase?.('config_saved', 'begin');
517
+ 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)));
518
+ ensureInitialRoleRegistry(opts.aid);
519
+ saveInitialBehavior(opts.aid, baseagent);
520
+ ensureAgentDirSkeleton(opts.aid);
521
+ opts.onPhase?.('config_saved', 'done');
522
+ opts.onPhase?.('uploading_agentmd', 'begin');
523
+ let agentmdUploaded = false;
524
+ try {
525
+ const content = buildInitialAgentMd({ aid: opts.aid, name: opts.name, description: opts.description, tags: opts.tags });
526
+ const aunPath = process.env.AUN_HOME || defaultAunPath();
527
+ let lastError;
528
+ for (let attempt = 1; attempt <= 3; attempt++) {
529
+ try {
530
+ if (attempt > 1)
531
+ await new Promise(r => setTimeout(r, 2000));
532
+ await agentmdPut(content, { aid: opts.aid, aunPath });
533
+ agentmdUploaded = true;
534
+ opts.onPhase?.('uploading_agentmd', 'done');
535
+ break;
536
+ }
537
+ catch (e) {
538
+ lastError = e;
539
+ }
540
+ }
541
+ if (!agentmdUploaded)
542
+ opts.onPhase?.('uploading_agentmd', 'warn', `upload failed: ${lastError?.message || lastError}`);
543
+ await new Promise(r => setTimeout(r, 0));
544
+ }
545
+ catch (e) {
546
+ opts.onPhase?.('uploading_agentmd', 'warn', `generation failed: ${e?.message || e}`);
547
+ }
548
+ let hotLoaded = false;
549
+ let hotLoadError;
550
+ opts.onPhase?.('hot_loading', 'begin');
551
+ try {
552
+ if (runtime.hotLoadAgent) {
553
+ await runtime.hotLoadAgent(opts.aid);
554
+ hotLoaded = true;
555
+ opts.onPhase?.('hot_loading', 'done');
556
+ }
557
+ else {
558
+ const ipcResult = await ipcQuery(p.socket, { type: 'evolagent.load', aid: opts.aid }, 30_000);
559
+ if (ipcResult?.ok) {
560
+ hotLoaded = true;
561
+ opts.onPhase?.('hot_loading', 'done');
562
+ }
563
+ else if (ipcResult) {
564
+ hotLoadError = ipcResult.error;
565
+ opts.onPhase?.('hot_loading', 'warn', hotLoadError);
566
+ }
567
+ else
568
+ opts.onPhase?.('hot_loading', 'warn', 'daemon not running');
569
+ }
570
+ }
571
+ catch (error) {
572
+ hotLoadError = error instanceof Error ? error.message : String(error);
573
+ opts.onPhase?.('hot_loading', 'warn', hotLoadError);
574
+ }
575
+ return { ok: true, aid: opts.aid, ownerAid: (opts.owners ?? (opts.owner ? [opts.owner] : undefined))?.[0], configPath: toPosix(path.join(agentDirPath, 'config.json')), aidCreated, agentmdUploaded, hotLoaded, hotLoadError };
576
+ }