evolcore 0.0.24 → 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 (197) hide show
  1. package/CHANGELOG.md +578 -561
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +160 -160
  5. package/bin/codex-managed-hook.mjs +208 -208
  6. package/bin/ec-safe-output.js +327 -327
  7. package/bin/ec.js +29 -29
  8. package/bin/install-codex-managed-hooks.mjs +555 -555
  9. package/dist/agents/claude-runner.js +4 -1
  10. package/dist/agents/codex-runner.js +7 -4
  11. package/dist/agents/ecagent-runner.js +14 -13
  12. package/dist/agents/gemini-runner.js +22 -2
  13. package/dist/aun/aid/agentmd.js +56 -4
  14. package/dist/aun/aid/index.js +1 -0
  15. package/dist/aun/aid/managed-operation.js +53 -1
  16. package/dist/aun/storage/client.js +4 -1
  17. package/dist/aun/storage/index.js +1 -1
  18. package/dist/cli/agent-command.js +186 -87
  19. package/dist/cli/agent-create.js +42 -4
  20. package/dist/cli/agent.js +103 -1
  21. package/dist/cli/aun-commands.js +360 -294
  22. package/dist/cli/bench.js +20 -20
  23. package/dist/cli/config.js +20 -20
  24. package/dist/cli/contact.js +10 -10
  25. package/dist/cli/ctl-command.js +22 -22
  26. package/dist/cli/daemon-commands.js +15 -15
  27. package/dist/cli/fs-command.js +67 -67
  28. package/dist/cli/handoff-command.js +7 -7
  29. package/dist/cli/index.js +77 -77
  30. package/dist/cli/link-rules.js +21 -21
  31. package/dist/cli/menu-client.js +11 -11
  32. package/dist/cli/net-check.js +22 -22
  33. package/dist/cli/queue-command.js +29 -29
  34. package/dist/cli/response.js +30 -30
  35. package/dist/cli/restart-monitor.js +30 -30
  36. package/dist/cli/stats.js +51 -51
  37. package/dist/cli/trigger-command.js +56 -56
  38. package/dist/config/builtin-roles.js +1 -0
  39. package/dist/config/config-manager.js +15 -0
  40. package/dist/config/config-operation-service.js +20 -3
  41. package/dist/config/resolved-config-op.js +39 -1
  42. package/dist/core/auth/operation-authorizer.js +62 -4
  43. package/dist/core/auth/operation-catalog.js +16 -0
  44. package/dist/core/command/agent-control.js +54 -25
  45. package/dist/core/command/cli-intent-parser.js +18 -0
  46. package/dist/core/command/command-handler.js +91 -16
  47. package/dist/core/command/menu-catalog.js +1 -0
  48. package/dist/core/command/menu-handler.js +41 -5
  49. package/dist/core/command/menu-protocol.js +1 -0
  50. package/dist/core/command/slash-handler.js +9 -9
  51. package/dist/core/event-catalog.js +5 -0
  52. package/dist/core/evolagent.js +3 -3
  53. package/dist/core/message/response-engine.js +12 -6
  54. package/dist/core/permission/tool-policy.js +45 -6
  55. package/dist/index.js +209 -162
  56. package/dist/stats/db.js +159 -159
  57. package/dist/stats/eck-vars.js +9 -9
  58. package/dist/stats/query.js +139 -139
  59. package/dist/stats/role-budget.js +6 -6
  60. package/dist/stats/writer.js +51 -51
  61. package/dist/utils/avatar-upload.js +282 -23
  62. package/dist/utils/error-dict.json +160 -160
  63. package/dist/utils/macos-autostart.js +22 -22
  64. package/dist/utils/model-prices.jsonl +23 -23
  65. package/dist/utils/welcome.js +22 -22
  66. package/ecagent/LICENSE +21 -21
  67. package/ecagent/NOTICE +11 -11
  68. package/ecagent/README.md +61 -61
  69. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  70. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  71. package/ecagent/dist/harness/messages.js +7 -7
  72. package/kits/docs/GUIDE.md +20 -20
  73. package/kits/docs/INDEX.md +66 -66
  74. package/kits/docs/aun/CHEATSHEET.md +19 -19
  75. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  76. package/kits/docs/channels/aun.md +56 -56
  77. package/kits/docs/channels/feishu.md +56 -56
  78. package/kits/docs/context-assembly.md +365 -364
  79. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  80. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  81. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  82. package/kits/docs/eck_templates/runtime.template.md +19 -19
  83. package/kits/docs/evolcore/INDEX.md +71 -69
  84. package/kits/docs/evolcore/agent-create.md +170 -156
  85. package/kits/docs/evolcore/agent.md +83 -73
  86. package/kits/docs/evolcore/aid.md +64 -62
  87. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -0
  88. package/kits/docs/evolcore/config.md +195 -195
  89. package/kits/docs/evolcore/contact.md +68 -68
  90. package/kits/docs/evolcore/ctl.md +46 -46
  91. package/kits/docs/evolcore/event.md +216 -216
  92. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  93. package/kits/docs/evolcore/fs.md +110 -110
  94. package/kits/docs/evolcore/group-collaboration.md +243 -243
  95. package/kits/docs/evolcore/group-fs.md +17 -17
  96. package/kits/docs/evolcore/group-rules.md +251 -251
  97. package/kits/docs/evolcore/group.md +152 -152
  98. package/kits/docs/evolcore/menu-client.md +34 -34
  99. package/kits/docs/evolcore/model.md +50 -50
  100. package/kits/docs/evolcore/msg.md +165 -165
  101. package/kits/docs/evolcore/response.md +75 -75
  102. package/kits/docs/evolcore/rpc.md +37 -37
  103. package/kits/docs/evolcore/self-summary.md +29 -29
  104. package/kits/docs/evolcore/stats.md +83 -83
  105. package/kits/docs/evolcore/storage.md +50 -50
  106. package/kits/docs/evolcore/trigger.md +575 -575
  107. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  108. package/kits/docs/identity/PATH_OPS.md +16 -16
  109. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  110. package/kits/docs/identity/identity-tools.md +26 -26
  111. package/kits/docs/path-registry.md +62 -62
  112. package/kits/docs/prompt-loading-architecture.md +270 -269
  113. package/kits/docs/venues/aun-group.md +45 -45
  114. package/kits/docs/venues/aun-private.md +10 -10
  115. package/kits/docs/venues/client-desktop.md +10 -10
  116. package/kits/docs/venues/client-mobile.md +10 -10
  117. package/kits/docs/venues/feishu-group.md +13 -13
  118. package/kits/docs/venues/feishu-private.md +9 -9
  119. package/kits/docs/venues/group.md +25 -25
  120. package/kits/docs/venues/private.md +10 -10
  121. package/kits/eck_manifest.auxiliary.json +43 -43
  122. package/kits/eck_manifest.json +195 -183
  123. package/kits/eck_message_manifest.json +74 -74
  124. package/kits/migrations/README-role-config-v4.md +32 -32
  125. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  126. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  127. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  128. package/kits/migrations/rename-config-file.mjs +99 -99
  129. package/kits/rules/01-overview.md +162 -162
  130. package/kits/rules/02-navigation.md +96 -96
  131. package/kits/rules/03-identity.md +39 -37
  132. package/kits/rules/04-relation.md +75 -75
  133. package/kits/rules/05-venue.md +60 -60
  134. package/kits/rules/06-channel.md +63 -63
  135. package/kits/schemas/_meta.json +53 -53
  136. package/kits/schemas/agent-config.schema.1.json +177 -177
  137. package/kits/schemas/agent-config.schema.10.json +395 -395
  138. package/kits/schemas/agent-config.schema.11.json +421 -421
  139. package/kits/schemas/agent-config.schema.12.json +427 -427
  140. package/kits/schemas/agent-config.schema.2.json +239 -239
  141. package/kits/schemas/agent-config.schema.3.json +119 -119
  142. package/kits/schemas/agent-config.schema.4.json +208 -208
  143. package/kits/schemas/agent-config.schema.5.json +326 -326
  144. package/kits/schemas/agent-config.schema.6.json +322 -322
  145. package/kits/schemas/agent-config.schema.7.json +303 -303
  146. package/kits/schemas/agent-config.schema.8.json +304 -304
  147. package/kits/schemas/agent-config.schema.9.json +364 -364
  148. package/kits/schemas/contact-book.schema.1.json +36 -36
  149. package/kits/schemas/contact-book.schema.2.json +43 -43
  150. package/kits/schemas/contact-book.schema.3.json +67 -67
  151. package/kits/schemas/daemon.schema.1.json +91 -91
  152. package/kits/schemas/daemon.schema.2.json +101 -101
  153. package/kits/schemas/daemon.schema.3.json +123 -123
  154. package/kits/schemas/daemon.schema.4.json +136 -136
  155. package/kits/schemas/daemon.schema.5.json +135 -135
  156. package/kits/schemas/daemon.schema.6.json +131 -131
  157. package/kits/schemas/defaults.schema.1.json +81 -81
  158. package/kits/schemas/defaults.schema.2.json +85 -85
  159. package/kits/schemas/defaults.schema.3.json +73 -73
  160. package/kits/schemas/defaults.schema.4.json +107 -107
  161. package/kits/schemas/defaults.schema.5.json +119 -119
  162. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  163. package/kits/schemas/migrations/README.md +30 -30
  164. package/kits/schemas/relation-config.schema.1.json +158 -158
  165. package/kits/schemas/relation-config.schema.2.json +73 -73
  166. package/kits/schemas/relation-config.schema.3.json +50 -50
  167. package/kits/schemas/relation-config.schema.4.json +47 -47
  168. package/kits/schemas/relation-config.schema.5.json +47 -47
  169. package/kits/schemas/relation-config.schema.6.json +46 -46
  170. package/kits/schemas/relation-config.schema.7.json +59 -59
  171. package/kits/schemas/relation-config.schema.8.json +103 -103
  172. package/kits/schemas/role-config.schema.1.json +201 -201
  173. package/kits/schemas/role-registry.schema.1.json +35 -35
  174. package/kits/schemas/single-session.schema.1.json +31 -31
  175. package/kits/schemas/single-session.schema.2.json +57 -57
  176. package/kits/schemas/single-session.schema.3.json +32 -32
  177. package/kits/templates/bootstrap-welcome.md +17 -17
  178. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  179. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  180. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  181. package/kits/templates/message-fragments/inject-default.md +2 -2
  182. package/kits/templates/message-fragments/item.md +2 -2
  183. package/kits/templates/roles/admin.json +96 -84
  184. package/kits/templates/roles/member.json +97 -96
  185. package/kits/templates/roles/owner.json +9 -9
  186. package/kits/templates/roles/visitor.json +86 -85
  187. package/kits/templates/system-fragments/baseagent.md +14 -14
  188. package/kits/templates/system-fragments/bootstrap.md +38 -29
  189. package/kits/templates/system-fragments/channel.md +64 -64
  190. package/kits/templates/system-fragments/commands.md +28 -28
  191. package/kits/templates/system-fragments/identity.md +13 -13
  192. package/kits/templates/system-fragments/relation.md +19 -19
  193. package/kits/templates/system-fragments/session.md +59 -59
  194. package/kits/templates/system-fragments/venue.md +31 -31
  195. package/package.json +98 -98
  196. package/skills/eclink/SKILL.md +0 -84
  197. package/skills/eclink/agents/openai.yaml +0 -4
@@ -1,6 +1,7 @@
1
1
  import path from 'path';
2
2
  import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
3
3
  import { isHostChinese } from '../utils/locale.js';
4
+ import { readTaskRuntimeContextFromEnv } from './task-context.js';
4
5
  function formatTimeAgo(ms) {
5
6
  const sec = Math.floor(ms / 1000);
6
7
  if (sec < 60)
@@ -25,7 +26,7 @@ function formatBytes(bytes) {
25
26
  export async function cmdAgent(args) {
26
27
  const sub = args[0];
27
28
  const formatJson = getArgValue(args, '--format') === 'json';
28
- const commands = new Set(['list', 'show', 'new', 'enable', 'disable', 'get', 'set', 'rename', 'ready', 'reload', 'delete']);
29
+ const commands = new Set(['list', 'show', 'new', 'enable', 'disable', 'get', 'set', 'persona', 'rename', 'ready', 'reload', 'delete']);
29
30
  if (sub === 'create') {
30
31
  const error = { ok: false, code: 'INVALID_COMMAND', error: '`ec agent create` is not a command; use `ec agent new`.' };
31
32
  if (formatJson)
@@ -36,41 +37,45 @@ export async function cmdAgent(args) {
36
37
  return;
37
38
  }
38
39
  if (!sub || isHelpFlag(sub) || (wantsHelp(args) && !commands.has(sub))) {
39
- console.log(`用法: ec agent <command>
40
-
41
- Commands:
42
- list 列出所有 agent
43
- show <aid> 查看 agent 详情(身份 + 配置 + 连接 + 会话 + 路径)
44
- new [aid] 交互式创建 agent
45
- new <aid> --non-interactive ... 非交互式创建
46
- enable <aid> 启用 agent
47
- disable <aid> 停用 agent
48
- get <aid> <key> 读取单个配置字段(支持点路径)
40
+ console.log(`用法: ec agent <command>
41
+
42
+ Commands:
43
+ list 列出所有 agent
44
+ show <aid> 查看 agent 详情(身份 + 配置 + 连接 + 会话 + 路径)
45
+ new [aid] 交互式创建 agent
46
+ new <aid> --non-interactive ... 非交互式创建
47
+ enable <aid> 启用 agent
48
+ disable <aid> 停用 agent
49
+ get <aid> <key> 读取单个配置字段(支持点路径)
49
50
  set <aid> <key> <val> 修改单个配置字段(支持点路径)
50
- rename <aid> <name> 修改 agent.md 中的显示名称
51
- ready <aid> 标记 bootstrap 完成,进入 active 状态
52
- reload [aid] 热重载配置(无参数=全量 resync)
53
- delete <aid> [--purge] 删除 agent
54
-
55
- Options:
56
- --format json 输出 JSON 格式
57
- --help, -h 各子命令均支持,查看详细用法
58
-
59
- 示例:
60
- ec agent list
61
- ec agent show mybot.agentid.pub
62
- ec agent new mybot.agentid.pub
63
- ec agent enable mybot.agentid.pub
64
- ec agent get mybot.agentid.pub active_baseagent
51
+ persona show 查看当前 Agent 的 persona.md
52
+ persona --text <text> 用文本设置当前 Agent 的 persona.md
53
+ persona --file <path> 用 .md/.txt 文件设置当前 Agent 的 persona.md
54
+ rename <aid> <name> 修改 agent.md 中的显示名称
55
+ ready <aid> 标记 bootstrap 完成,进入 active 状态
56
+ reload [aid] 热重载配置(无参数=全量 resync)
57
+ delete <aid> [--purge] 删除 agent
58
+
59
+ Options:
60
+ --format json 输出 JSON 格式
61
+ --help, -h 各子命令均支持,查看详细用法
62
+
63
+ 示例:
64
+ ec agent list
65
+ ec agent show mybot.agentid.pub
66
+ ec agent new mybot.agentid.pub
67
+ ec agent enable mybot.agentid.pub
68
+ ec agent get mybot.agentid.pub active_baseagent
65
69
  ec agent set mybot.agentid.pub active_baseagent codex
66
- ec agent rename mybot.agentid.pub "New Name"
67
- ec agent ready mybot.agentid.pub
70
+ ec agent persona --text "你是一名严谨的诊断工程师。"
71
+ ec agent rename mybot.agentid.pub "New Name"
72
+ ec agent ready mybot.agentid.pub
68
73
  ec agent delete mybot.agentid.pub --purge`);
69
74
  return;
70
75
  }
71
- const { agentList, agentShow, agentCreateInteractive, agentCreateNonInteractive, agentReload, agentEnable, agentDisable, agentGet, agentSet, agentRename, agentDelete, agentReady, runManagedAgentOperation, } = await import('./agent.js');
72
- const { parseAgentOwnerArgs, resolveAgentCreatePlan, validateAgentCreatePlan } = await import('./agent-create.js');
73
- if (process.env.EVOLCORE_SESSION_ID && !wantsHelp(args) && !new Set(['get', 'set', 'ready']).has(sub)) {
76
+ const { agentList, agentShow, agentCreateInteractive, agentCreateNonInteractive, agentReload, agentEnable, agentDisable, agentGet, agentSet, agentPersona, agentRename, agentDelete, agentReady, runManagedAgentOperation, } = await import('./agent.js');
77
+ const { parseAgentOwnerArgs, parseAgentTags, resolveAgentCreatePlan, validateAgentCreatePlan } = await import('./agent-create.js');
78
+ if (process.env.EVOLCORE_SESSION_ID && !wantsHelp(args) && !new Set(['get', 'set', 'persona', 'ready']).has(sub)) {
74
79
  if (sub === 'new' && !args.includes('--non-interactive')) {
75
80
  const error = {
76
81
  ok: false,
@@ -132,8 +137,8 @@ Options:
132
137
  // --- list ---
133
138
  if (sub === 'list') {
134
139
  if (wantsHelp(args)) {
135
- console.log(`用法: ec agent list [--format json]
136
-
140
+ console.log(`用法: ec agent list [--format json]
141
+
137
142
  列出所有 agent,显示名称、状态、渠道、项目、基座、最后活跃时间。`);
138
143
  return;
139
144
  }
@@ -203,26 +208,27 @@ Options:
203
208
  // --- new ---
204
209
  if (sub === 'new') {
205
210
  if (wantsHelp(args)) {
206
- console.log(`用法: ec agent new [aid] 交互式创建
207
- ec agent new <aid> --non-interactive [选项]
208
-
209
- 非交互模式选项:
210
- --project <path> 默认: 当前目录
211
- --baseagent <claude|codex|gemini|ecagent>
212
- 默认: defaults 配置,否则检测本机可用基座
211
+ console.log(`用法: ec agent new [aid] 交互式创建
212
+ ec agent new <aid> --non-interactive [选项]
213
+
214
+ 非交互模式选项:
215
+ --project <path> 默认: 当前目录
216
+ --baseagent <claude|codex|gemini|ecagent>
217
+ 默认: defaults 配置,否则检测本机可用基座
213
218
  --owner <aid> 默认: daemon.json 第一个 owner
214
219
  --owners <json-array> 多个 Owner;与 --owner 互斥
215
220
  --handoff <context> 当前任务的 Bootstrap 上下文
216
- --name <display-name> 默认: package.json name,否则目录名
221
+ --name <display-name> 默认: package.json name,否则目录名
217
222
  --description <text> 默认: package.json description,否则使用 EvolCore 默认描述
218
- --dry-run 只预览最终参数,不注册 AID、不写文件
219
- --force 覆盖已有 config.json
220
- --format json 输出 JSON
221
-
222
- 示例:
223
- ec agent new mybot.agentid.pub
224
- ec agent new mybot.agentid.pub --non-interactive
225
- ec agent new mybot.agentid.pub --non-interactive --dry-run --format json
223
+ --tags <json-array> 3 到 6 个标签,例如 '["coding","diagnostics","logs"]'
224
+ --dry-run 只预览最终参数,不注册 AID、不写文件
225
+ --force 覆盖已有 config.json
226
+ --format json 输出 JSON
227
+
228
+ 示例:
229
+ ec agent new mybot.agentid.pub
230
+ ec agent new mybot.agentid.pub --non-interactive
231
+ ec agent new mybot.agentid.pub --non-interactive --dry-run --format json
226
232
  ec agent new mybot.agentid.pub --non-interactive --project ../project --baseagent claude`);
227
233
  return;
228
234
  }
@@ -259,6 +265,19 @@ Options:
259
265
  process.exitCode = 1;
260
266
  return;
261
267
  }
268
+ let tags;
269
+ try {
270
+ tags = parseAgentTags(getArg('--tags'));
271
+ }
272
+ catch (error) {
273
+ const result = { ok: false, error: error instanceof Error ? error.message : String(error) };
274
+ if (formatJson)
275
+ console.log(JSON.stringify(result));
276
+ else
277
+ console.error(`❌ ${result.error}`);
278
+ process.exitCode = 1;
279
+ return;
280
+ }
262
281
  const plan = resolveAgentCreatePlan({
263
282
  aid: name,
264
283
  project: getArg('--project'),
@@ -267,6 +286,7 @@ Options:
267
286
  handoff: getArg('--handoff'),
268
287
  name: getArg('--name'),
269
288
  description: getArg('--description'),
289
+ tags,
270
290
  force: args.includes('--force'),
271
291
  });
272
292
  const validationError = validateAgentCreatePlan(plan);
@@ -304,6 +324,7 @@ Options:
304
324
  owners: plan.owners,
305
325
  name: plan.name,
306
326
  description: plan.description,
327
+ tags: plan.tags,
307
328
  force: args.includes('--force'),
308
329
  });
309
330
  if (!result.ok) {
@@ -399,11 +420,11 @@ Options:
399
420
  // --- reload ---
400
421
  if (sub === 'reload') {
401
422
  if (wantsHelp(args)) {
402
- console.log(`用法: ec agent reload [aid] [--force] [--format json]
403
-
404
- 热重载 agent 配置。
405
- 无参数 全量 resync(扫磁盘,新增上线、删除下线、修改热更新)
406
- <aid> 仅热重载指定 agent
423
+ console.log(`用法: ec agent reload [aid] [--force] [--format json]
424
+
425
+ 热重载 agent 配置。
426
+ 无参数 全量 resync(扫磁盘,新增上线、删除下线、修改热更新)
427
+ <aid> 仅热重载指定 agent
407
428
  --force 中断目标 Agent 的运行中任务并清空排队任务后重载(仅与 <aid> 同用)`);
408
429
  return;
409
430
  }
@@ -435,9 +456,9 @@ Options:
435
456
  // --- enable ---
436
457
  if (sub === 'enable') {
437
458
  if (wantsHelp(args)) {
438
- console.log(`用法: ec agent enable <aid> [--force] [--format json]
439
-
440
- 启用 agent。若服务运行中会热重载,否则下次 ec start 时生效。
459
+ console.log(`用法: ec agent enable <aid> [--force] [--format json]
460
+
461
+ 启用 agent。若服务运行中会热重载,否则下次 ec start 时生效。
441
462
  --force 中断目标 Agent 的运行中任务并清空排队任务后重载`);
442
463
  return;
443
464
  }
@@ -467,9 +488,9 @@ Options:
467
488
  // --- disable ---
468
489
  if (sub === 'disable') {
469
490
  if (wantsHelp(args)) {
470
- console.log(`用法: ec agent disable <aid> [--force] [--format json]
471
-
472
- 停用 agent。若服务运行中会热重载离线,否则在配置中标记为禁用。
491
+ console.log(`用法: ec agent disable <aid> [--force] [--format json]
492
+
493
+ 停用 agent。若服务运行中会热重载离线,否则在配置中标记为禁用。
473
494
  --force 中断目标 Agent 的运行中任务并清空排队任务后重载`);
474
495
  return;
475
496
  }
@@ -497,16 +518,94 @@ Options:
497
518
  return;
498
519
  }
499
520
  // --- get ---
500
- if (sub === 'get') {
521
+ if (sub === 'persona') {
501
522
  if (wantsHelp(args)) {
502
- console.log(`用法: ec agent get <aid> <key> [--format json]
523
+ console.log(`用法: ec agent persona show [--format json]
524
+ ec agent persona --text <text> [--format json]
525
+ ec agent persona --file <path> [--format json]
503
526
 
504
- 读取单个配置字段。key 支持点路径,如 "channels.aun.enabled"。
505
- 托管任务通过 daemon 统一鉴权;无会话的本机 CLI 走控制面。
506
-
507
- 示例:
508
- ec agent get mybot.agentid.pub active_baseagent
509
- ec agent get mybot.agentid.pub observable
527
+ 读取或设置当前 Agent 的 persona.md。--file 只接受 .md/.txt 文本文件。`);
528
+ return;
529
+ }
530
+ const formatSuffix = args.length >= 3
531
+ && args.at(-2) === '--format'
532
+ && args.at(-1) === 'json';
533
+ const commandArgs = formatSuffix ? args.slice(0, -2) : args;
534
+ const personaArgs = commandArgs.slice(1);
535
+ const invalid = (error) => {
536
+ const result = { ok: false, code: 'INVALID_ARGS', error };
537
+ if (formatJson)
538
+ console.log(JSON.stringify(result));
539
+ else
540
+ console.error(`❌ ${result.error}`);
541
+ process.exitCode = 1;
542
+ return;
543
+ };
544
+ if (!formatSuffix && args.includes('--format')) {
545
+ invalid('persona 仅支持末尾的 --format json');
546
+ return;
547
+ }
548
+ let text;
549
+ let file;
550
+ if (personaArgs.length === 1 && personaArgs[0] === 'show') {
551
+ // show is the only read form; no payload is accepted.
552
+ }
553
+ else if (personaArgs.length === 2 && personaArgs[0] === '--text') {
554
+ text = personaArgs[1];
555
+ if (text === undefined) {
556
+ invalid('persona --text 缺少参数');
557
+ return;
558
+ }
559
+ }
560
+ else if (personaArgs.length === 2 && personaArgs[0] === '--file') {
561
+ file = personaArgs[1];
562
+ if (!file || file.startsWith('-')) {
563
+ invalid('persona --file 缺少有效路径');
564
+ return;
565
+ }
566
+ }
567
+ else {
568
+ invalid('用法: ec agent persona show | --text <text> | --file <path>');
569
+ return;
570
+ }
571
+ const taskAid = process.env.EVOLCORE_SESSION_ID ? (readTaskRuntimeContextFromEnv()?.selfAid || '') : '';
572
+ const aid = taskAid || process.env.EVOLCORE_SELF_AID || '';
573
+ if (!aid) {
574
+ const result = { ok: false, code: 'INVALID_ARGS', error: '无法确定当前 Agent AID' };
575
+ if (formatJson)
576
+ console.log(JSON.stringify(result));
577
+ else
578
+ console.error(`❌ ${result.error}`);
579
+ process.exitCode = 1;
580
+ return;
581
+ }
582
+ const result = await agentPersona(aid, { text, file });
583
+ if (!result.ok) {
584
+ if (formatJson)
585
+ console.log(JSON.stringify(result));
586
+ else
587
+ console.error(`❌ ${result.error}`);
588
+ process.exitCode = 1;
589
+ return;
590
+ }
591
+ if (formatJson)
592
+ console.log(JSON.stringify(result, null, 2));
593
+ else if (result.saved)
594
+ console.log(`✓ ${aid} persona.md 已保存`);
595
+ else
596
+ console.log(result.content ?? '(persona.md 不存在)');
597
+ return;
598
+ }
599
+ if (sub === 'get') {
600
+ if (wantsHelp(args)) {
601
+ console.log(`用法: ec agent get <aid> <key> [--format json]
602
+
603
+ 读取单个配置字段。key 支持点路径,如 "channels.aun.enabled"。
604
+ 托管任务通过 daemon 统一鉴权;无会话的本机 CLI 走控制面。
605
+
606
+ 示例:
607
+ ec agent get mybot.agentid.pub active_baseagent
608
+ ec agent get mybot.agentid.pub observable
510
609
  ec agent get mybot.agentid.pub channels.aun.enabled`);
511
610
  return;
512
611
  }
@@ -538,15 +637,15 @@ Options:
538
637
  // --- set ---
539
638
  if (sub === 'set') {
540
639
  if (wantsHelp(args)) {
541
- console.log(`用法: ec agent set <aid> <key> <value> [--format json]
542
-
543
- 修改单个配置字段。key 支持点路径。本机控制面会尝试热重载;托管任务如需重载须另行执行 agent reload。
544
- 托管任务通过 daemon 统一鉴权;无会话的本机 CLI 走控制面。
545
-
546
- 示例:
547
- ec agent set mybot.agentid.pub active_baseagent codex
548
- ec agent set mybot.agentid.pub observable true
549
- ec agent set mybot.agentid.pub observable false
640
+ console.log(`用法: ec agent set <aid> <key> <value> [--format json]
641
+
642
+ 修改单个配置字段。key 支持点路径。本机控制面会尝试热重载;托管任务如需重载须另行执行 agent reload。
643
+ 托管任务通过 daemon 统一鉴权;无会话的本机 CLI 走控制面。
644
+
645
+ 示例:
646
+ ec agent set mybot.agentid.pub active_baseagent codex
647
+ ec agent set mybot.agentid.pub observable true
648
+ ec agent set mybot.agentid.pub observable false
550
649
  ec agent set mybot.agentid.pub channels.aun.enabled true`);
551
650
  return;
552
651
  }
@@ -578,8 +677,8 @@ Options:
578
677
  // --- ready ---
579
678
  if (sub === 'ready') {
580
679
  if (wantsHelp(args)) {
581
- console.log(`用法: ec agent ready <aid> [--format json]
582
-
680
+ console.log(`用法: ec agent ready <aid> [--format json]
681
+
583
682
  标记 agent bootstrap 已完成,将 lifecycle 切换为 active。该命令允许 agent 在工具调用中自报完成。`);
584
683
  return;
585
684
  }
@@ -609,10 +708,10 @@ Options:
609
708
  // --- delete ---
610
709
  if (sub === 'delete') {
611
710
  if (wantsHelp(args)) {
612
- console.log(`用法: ec agent delete <aid> [--purge] [--format json]
613
-
614
- 删除 agent 的配置。
615
- --purge 同时清除该 agent 的会话、消息、日志等运行时数据
711
+ console.log(`用法: ec agent delete <aid> [--purge] [--format json]
712
+
713
+ 删除 agent 的配置。
714
+ --purge 同时清除该 agent 的会话、消息、日志等运行时数据
616
715
  默认 仅删除 config.json,运行时数据保留`);
617
716
  return;
618
717
  }
@@ -643,8 +742,8 @@ Options:
643
742
  // --- show ---
644
743
  if (sub === 'show') {
645
744
  if (wantsHelp(args)) {
646
- console.log(`用法: ec agent show <aid> [--format json]
647
-
745
+ console.log(`用法: ec agent show <aid> [--format json]
746
+
648
747
  查看 agent 详情:身份、配置、连接状态、会话路径等。`);
649
748
  return;
650
749
  }
@@ -673,8 +772,8 @@ Options:
673
772
  // --- rename ---
674
773
  if (sub === 'rename') {
675
774
  if (wantsHelp(args)) {
676
- console.log(`用法: ec agent rename <aid> <name> [--format json]
677
-
775
+ console.log(`用法: ec agent rename <aid> <name> [--format json]
776
+
678
777
  修改本地 AIDs/<aid>/agent.md 中的 name 字段。`);
679
778
  return;
680
779
  }
@@ -12,7 +12,27 @@ import { resolveEcagentConfig } from '../agents/baseagent.js';
12
12
  import { AUTO_BASEAGENT_CANDIDATES, BASEAGENT_CANDIDATES, detectAvailableBaseagents, } from '../agents/baseagent-availability.js';
13
13
  import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/project-path.js';
14
14
  import { isValidAid } from '../aun/aid/validation.js';
15
- import { DEFAULT_AGENT_DESCRIPTION } from '../aun/aid/agentmd.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
+ }
16
36
  export function validateAgentOwnerOptions(options) {
17
37
  if (options.owner !== undefined && options.owners !== undefined) {
18
38
  return 'Options --owner and --owners are mutually exclusive';
@@ -120,7 +140,7 @@ export function resolveAgentCreatePlan(options) {
120
140
  const description = options.description?.trim() || metadata.description || DEFAULT_AGENT_DESCRIPTION;
121
141
  const configExists = isValidAid(aid) && fs.existsSync(path.join(resolvePaths().agentsDir, aid, 'config.json'));
122
142
  return {
123
- aid, project, baseagent, owner, owners, handoff: options.handoff, name, description,
143
+ aid, project, baseagent, owner, owners, handoff: options.handoff, name, description, tags: options.tags,
124
144
  force: options.force === true, configExists, baseagentSource, ownerSource,
125
145
  nameSource: options.name?.trim() ? 'argument' : metadata.name ? 'package' : 'directory',
126
146
  descriptionSource: options.description?.trim() ? 'argument' : metadata.description ? 'package' : 'default',
@@ -134,6 +154,11 @@ export function validateAgentCreatePlan(plan) {
134
154
  return `Invalid AID "${plan.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`;
135
155
  if (plan.configExists && !plan.force)
136
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
+ }
137
162
  if (!plan.baseagent)
138
163
  return 'No usable baseagent detected. Pass --baseagent or configure a baseagent in agents/defaults.json.';
139
164
  if (!BASEAGENT_CANDIDATES.includes(plan.baseagent)) {
@@ -305,6 +330,14 @@ export async function agentCreateInteractive(opts = {}) {
305
330
  const defaultName = aid.split('.')[0];
306
331
  const agentName = (await ask(`Display name [${defaultName}]: `)).trim() || defaultName;
307
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
+ }
308
341
  if (ownRl)
309
342
  rl.close();
310
343
  saveAgent(withStaticOwner({ $schema_version: CONFIG_SCHEMA_VERSION, aid, enabled: true, lifecycle: 'created', channels: [], projects: { defaultPath: projectPath } }, owner));
@@ -313,7 +346,7 @@ export async function agentCreateInteractive(opts = {}) {
313
346
  ensureAgentDirSkeleton(aid);
314
347
  let agentmdUploaded = false;
315
348
  try {
316
- const content = buildInitialAgentMd({ aid, name: agentName, description: agentDescription });
349
+ const content = buildInitialAgentMd({ aid, name: agentName, description: agentDescription, tags: agentTags });
317
350
  const aunPath = process.env.AUN_HOME || defaultAunPath();
318
351
  let lastError;
319
352
  for (let attempt = 1; attempt <= 3; attempt++) {
@@ -411,6 +444,11 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
411
444
  const ownerError = validateAgentOwnerOptions(opts);
412
445
  if (ownerError)
413
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
+ }
414
452
  if (!isValidAid(opts.aid))
415
453
  return failValidating(`Invalid AID "${opts.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`);
416
454
  const agentDirPath = path.join(p.agentsDir, opts.aid);
@@ -484,7 +522,7 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
484
522
  opts.onPhase?.('uploading_agentmd', 'begin');
485
523
  let agentmdUploaded = false;
486
524
  try {
487
- const content = buildInitialAgentMd({ aid: opts.aid, name: opts.name, description: opts.description });
525
+ const content = buildInitialAgentMd({ aid: opts.aid, name: opts.name, description: opts.description, tags: opts.tags });
488
526
  const aunPath = process.env.AUN_HOME || defaultAunPath();
489
527
  let lastError;
490
528
  for (let attempt = 1; attempt <= 3; attempt++) {
package/dist/cli/agent.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { resolvePaths, agentMdPath as getAgentMdPathFromPaths, aunPath as defaultAunPath } from '../paths.js';
3
+ import { resolvePaths, agentMdPath as getAgentMdPathFromPaths, agentPersonalDir, aunPath as defaultAunPath } from '../paths.js';
4
4
  import { loadDefaults, loadAllAgents, loadAgent, saveAgent, ensureAgentDirSkeleton } from '../config-store.js';
5
5
  import { initConfigManager } from '../config/config-manager.js';
6
6
  import { resolveConfigCommand } from '../config/resolved-config-op.js';
@@ -12,6 +12,7 @@ import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/p
12
12
  import { isValidChannelName } from '../core/channel-loader.js';
13
13
  import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
14
14
  import { readTaskRuntimeContextFromEnv } from './task-context.js';
15
+ import { isHClassPath, isLClassPath, isSameOrDescendant } from '../core/permission/protected-paths.js';
15
16
  export { agentCreateInteractive, agentCreateNonInteractive, parseAgentOwnerArgs, resolveAgentCreatePlan, validateAgentCreatePlan, validateAgentOwnerOptions, } from './agent-create.js';
16
17
  /** Route agent lifecycle commands from a managed task through daemon IPC. */
17
18
  export async function runManagedAgentOperation(argv) {
@@ -456,6 +457,107 @@ export async function agentSet(aid, key, rawValue, options = {}) {
456
457
  catch { }
457
458
  return { ok: true, aid, key, value, reloaded };
458
459
  }
460
+ export const AGENT_PERSONA_MAX_BYTES = 64 * 1024;
461
+ function validatePersonaContent(content) {
462
+ if (content.includes('\0'))
463
+ return 'persona 只能包含文本内容';
464
+ if (Buffer.byteLength(content, 'utf8') > AGENT_PERSONA_MAX_BYTES) {
465
+ return `persona 不能超过 ${AGENT_PERSONA_MAX_BYTES} bytes`;
466
+ }
467
+ return null;
468
+ }
469
+ function readPersonaSource(file) {
470
+ const resolved = path.resolve(file);
471
+ if (!/\.(?:md|txt)$/i.test(resolved)) {
472
+ return { ok: false, code: 'INVALID_ARGS', error: '--file 只接受 .md 或 .txt 文本文件' };
473
+ }
474
+ try {
475
+ const stat = fs.statSync(resolved);
476
+ if (!stat.isFile())
477
+ return { ok: false, code: 'INVALID_ARGS', error: `--file 必须指向普通文件: ${resolved}` };
478
+ const content = fs.readFileSync(resolved, 'utf8');
479
+ const error = validatePersonaContent(content);
480
+ return error ? { ok: false, code: 'INVALID_ARGS', error } : { ok: true, content };
481
+ }
482
+ catch (e) {
483
+ return { ok: false, code: 'READ_FAILED', error: `无法读取 --file: ${e?.message || e}` };
484
+ }
485
+ }
486
+ /** Read or replace the current Agent's personal/persona.md. */
487
+ export async function agentPersona(aid, options = {}) {
488
+ if (options.text !== undefined && options.file !== undefined)
489
+ return { ok: false, code: 'INVALID_ARGS', error: '--text 与 --file 不能同时使用' };
490
+ const managedSession = !!process.env.EVOLCORE_SESSION_ID && !options.trustedLocal;
491
+ let text = options.text;
492
+ if (options.file !== undefined) {
493
+ if (managedSession) {
494
+ const resolved = path.resolve(options.file);
495
+ const projectRoot = path.resolve(process.cwd());
496
+ const tempRoot = process.env.TMPDIR?.trim() && path.isAbsolute(process.env.TMPDIR)
497
+ ? path.resolve(process.env.TMPDIR)
498
+ : undefined;
499
+ const allowed = isSameOrDescendant(resolved, projectRoot)
500
+ || (!!tempRoot && isSameOrDescendant(resolved, tempRoot));
501
+ if (!allowed || isHClassPath(resolved) || isLClassPath(resolved)) {
502
+ return { ok: false, code: 'INVALID_ARGS', error: '--file 必须位于当前项目或会话 $TMPDIR,且不能读取 EvolCore 受保护路径' };
503
+ }
504
+ try {
505
+ const stat = fs.lstatSync(resolved);
506
+ if (stat.isSymbolicLink() || !stat.isFile()) {
507
+ return { ok: false, code: 'INVALID_ARGS', error: '--file 必须指向当前项目或会话 $TMPDIR 内的普通文件' };
508
+ }
509
+ const realPath = fs.realpathSync(resolved);
510
+ const realProjectRoot = fs.realpathSync(projectRoot);
511
+ const realTempRoot = tempRoot ? fs.realpathSync(tempRoot) : undefined;
512
+ const realAllowed = isSameOrDescendant(realPath, realProjectRoot)
513
+ || (!!realTempRoot && isSameOrDescendant(realPath, realTempRoot));
514
+ if (!realAllowed || isHClassPath(realPath) || isLClassPath(realPath)) {
515
+ return { ok: false, code: 'INVALID_ARGS', error: '--file 解析后越出允许目录或命中 EvolCore 受保护路径' };
516
+ }
517
+ }
518
+ catch (e) {
519
+ return { ok: false, code: 'READ_FAILED', error: `无法校验 --file: ${e?.message || e}` };
520
+ }
521
+ }
522
+ const source = readPersonaSource(options.file);
523
+ if (!source.ok)
524
+ return source;
525
+ text = source.content;
526
+ }
527
+ if (text !== undefined) {
528
+ const error = validatePersonaContent(text);
529
+ if (error)
530
+ return { ok: false, code: 'INVALID_ARGS', error };
531
+ }
532
+ const managedArgs = options.text !== undefined
533
+ ? ['persona', '--text', text]
534
+ : options.file !== undefined
535
+ ? ['persona', '--text', text]
536
+ : ['persona', 'show'];
537
+ if (managedSession) {
538
+ const managed = await runManagedAgentOperation(managedArgs);
539
+ if (!managed.ok)
540
+ return managed;
541
+ return { ok: true, aid, content: managed.content ?? null, ...(managed.path ? { path: managed.path } : {}), ...(managed.saved ? { saved: true } : {}) };
542
+ }
543
+ const personaPath = path.join(agentPersonalDir(aid), 'persona.md');
544
+ if (text === undefined) {
545
+ try {
546
+ return { ok: true, aid, content: fs.existsSync(personaPath) ? fs.readFileSync(personaPath, 'utf8') : null, path: personaPath };
547
+ }
548
+ catch (e) {
549
+ return { ok: false, code: 'READ_FAILED', error: e?.message || String(e) };
550
+ }
551
+ }
552
+ try {
553
+ fs.mkdirSync(path.dirname(personaPath), { recursive: true });
554
+ fs.writeFileSync(personaPath, text, 'utf8');
555
+ return { ok: true, aid, content: text, path: personaPath, saved: true };
556
+ }
557
+ catch (e) {
558
+ return { ok: false, code: 'WRITE_FAILED', error: e?.message || String(e) };
559
+ }
560
+ }
459
561
  /**
460
562
  * Add or overwrite a channel instance on a per-agent config.
461
563
  *