evolcore 0.0.25 → 0.0.27

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 (304) hide show
  1. package/CHANGELOG.md +632 -565
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +203 -160
  5. package/bin/codex-managed-hook.mjs +208 -208
  6. package/bin/ec-safe-output.js +327 -327
  7. package/bin/ec.js +40 -29
  8. package/bin/install-codex-managed-hooks.mjs +582 -555
  9. package/dist/agents/baseagent-availability.js +68 -0
  10. package/dist/agents/baseagent.js +96 -46
  11. package/dist/agents/claude-runner.js +172 -33
  12. package/dist/agents/codex/app-server-client.js +76 -31
  13. package/dist/agents/codex/catalog.js +1 -1
  14. package/dist/agents/codex/diagnostics.js +34 -1
  15. package/dist/agents/codex-runner.js +434 -446
  16. package/dist/agents/ecagent-runner.js +174 -34
  17. package/dist/agents/gemini-runner.js +8 -7
  18. package/dist/agents/runner-types.js +75 -19
  19. package/dist/aun/aid/agentmd.js +151 -36
  20. package/dist/aun/aid/client.js +1 -1
  21. package/dist/aun/aid/control-aid.js +180 -1
  22. package/dist/aun/aid/identity.js +4 -4
  23. package/dist/aun/aid/index.js +1 -1
  24. package/dist/aun/aid/store.js +17 -13
  25. package/dist/aun/group/history.js +303 -0
  26. package/dist/aun/group/identity.js +43 -0
  27. package/dist/aun/group/index.js +5 -0
  28. package/dist/aun/{msg/group.js → group/operations.js} +162 -39
  29. package/dist/aun/{menu-client.js → menu/client.js} +85 -6
  30. package/dist/aun/menu/index.js +2 -0
  31. package/dist/aun/menu/transport.js +49 -0
  32. package/dist/aun/msg/index.js +2 -1
  33. package/dist/aun/msg/managed-operation.js +85 -19
  34. package/dist/aun/msg/mention-schema.js +51 -0
  35. package/dist/aun/msg/p2p.js +19 -9
  36. package/dist/aun/msg/upload.js +43 -80
  37. package/dist/aun/outbox.js +29 -7
  38. package/dist/aun/rpc/client.js +1 -0
  39. package/dist/aun/storage/client.js +39 -50
  40. package/dist/channels/aun.js +842 -318
  41. package/dist/channels/daemon.js +10 -6
  42. package/dist/cli/agent-command.js +212 -89
  43. package/dist/cli/agent-create.js +626 -11
  44. package/dist/cli/agent.js +125 -13
  45. package/dist/cli/aun-commands.js +487 -337
  46. package/dist/cli/bench.js +20 -20
  47. package/dist/cli/config.js +55 -33
  48. package/dist/cli/contact.js +72 -15
  49. package/dist/cli/ctl-command.js +24 -24
  50. package/dist/cli/daemon-commands.js +140 -63
  51. package/dist/cli/diag.js +31 -0
  52. package/dist/cli/fs-command.js +70 -70
  53. package/dist/cli/handoff-command.js +46 -14
  54. package/dist/cli/index.js +91 -79
  55. package/dist/cli/init.js +34 -1
  56. package/dist/cli/link-rules.js +21 -21
  57. package/dist/cli/managed-command-guard.js +5 -1
  58. package/dist/cli/menu-client.js +51 -32
  59. package/dist/cli/model.js +3 -3
  60. package/dist/cli/net-check.js +22 -22
  61. package/dist/cli/queue-command.js +31 -31
  62. package/dist/cli/response.js +32 -32
  63. package/dist/cli/restart-monitor.js +103 -42
  64. package/dist/cli/stats.js +51 -51
  65. package/dist/cli/task-command.js +59 -0
  66. package/dist/cli/task-context.js +97 -49
  67. package/dist/cli/trigger-command.js +74 -64
  68. package/dist/config/builtin-roles.js +11 -0
  69. package/dist/config/config-field-policy.js +11 -0
  70. package/dist/config/config-manager.js +32 -4
  71. package/dist/config/config-operation-service.js +160 -0
  72. package/dist/config/contact-book-store.js +1 -1
  73. package/dist/config/contact-book.js +1 -1
  74. package/dist/config/contact-operation-service.js +97 -8
  75. package/dist/config/peer-role-resolver.js +1 -1
  76. package/dist/config/resolved-config-op.js +30 -7
  77. package/dist/config-store.js +1 -1
  78. package/dist/core/agent-application-service.js +7 -1
  79. package/dist/core/audit/event-key.js +17 -2
  80. package/dist/core/audit/log-integrity.js +34 -8
  81. package/dist/core/auth/agent-delegation.js +48 -14
  82. package/dist/core/auth/auth-gateway.js +2 -0
  83. package/dist/core/auth/authorization-audit.js +53 -49
  84. package/dist/core/auth/operation-authorizer.js +90 -7
  85. package/dist/core/auth/operation-catalog.js +145 -4
  86. package/dist/core/auth/remote-access-store.js +155 -10
  87. package/dist/core/bootstrap-messages.js +66 -7
  88. package/dist/core/bootstrap-service.js +111 -20
  89. package/dist/core/command/agent-control.js +88 -7
  90. package/dist/core/command/agent-storage-menu.js +443 -0
  91. package/dist/core/command/cli-intent-parser.js +19 -0
  92. package/dist/core/command/command-handler.js +159 -65
  93. package/dist/core/command/data-root-resolver.js +273 -0
  94. package/dist/core/command/diag-service.js +118 -0
  95. package/dist/core/command/group-menu.js +7 -2
  96. package/dist/core/command/menu-catalog.js +46 -7
  97. package/dist/core/command/menu-handler.js +392 -100
  98. package/dist/core/command/menu-protocol.js +45 -6
  99. package/dist/core/command/menu-token-store.js +41 -8
  100. package/dist/core/command/role-menu.js +2 -2
  101. package/dist/core/command/slash-gate.js +34 -4
  102. package/dist/core/command/slash-handler.js +123 -43
  103. package/dist/core/event-catalog.js +4 -0
  104. package/dist/core/evolagent-registry.js +28 -2
  105. package/dist/core/group/invite-service.js +924 -0
  106. package/dist/core/handoff/runtime.js +205 -27
  107. package/dist/core/handoff/store.js +193 -4
  108. package/dist/core/interaction-router.js +22 -8
  109. package/dist/core/message/im-renderer.js +146 -34
  110. package/dist/core/message/message-bridge.js +163 -20
  111. package/dist/core/message/message-log.js +5 -3
  112. package/dist/core/message/message-queue.js +99 -41
  113. package/dist/core/message/message-utils.js +1 -0
  114. package/dist/core/message/response-engine.js +755 -144
  115. package/dist/core/model/catalog-service.js +79 -49
  116. package/dist/core/model/context-window-suffix.js +33 -0
  117. package/dist/core/model/model-catalog.js +1 -1
  118. package/dist/core/model/model-permission.js +12 -3
  119. package/dist/core/permission/approval-gateway.js +36 -3
  120. package/dist/core/permission/ec-command-parser.js +112 -41
  121. package/dist/core/permission/protected-paths.js +134 -16
  122. package/dist/core/permission/sandbox-runtime.js +108 -17
  123. package/dist/core/permission/tool-error-code.js +15 -0
  124. package/dist/core/permission/tool-policy.js +9 -8
  125. package/dist/core/relation/peer-identity.js +57 -6
  126. package/dist/core/relation/shared-data.js +106 -0
  127. package/dist/core/role/runtime-policy.js +64 -0
  128. package/dist/core/runtime-lock.js +10 -26
  129. package/dist/core/session/runner-task-history.js +170 -0
  130. package/dist/core/session/session-manager.js +34 -6
  131. package/dist/core/session/session-mapper.js +41 -0
  132. package/dist/core/session/session-turn-coordinator.js +37 -7
  133. package/dist/core/session/session-turns.js +48 -7
  134. package/dist/core/task/task-recovery-service.js +176 -0
  135. package/dist/core/task/task-resume-operation.js +32 -0
  136. package/dist/eck/group-rules-sync.js +5 -3
  137. package/dist/eck/kit-renderer.js +1 -0
  138. package/dist/index.js +588 -217
  139. package/dist/ipc.js +193 -15
  140. package/dist/paths.js +17 -4
  141. package/dist/product.js +2 -0
  142. package/dist/response-system/engines/v1/proactive-flow.js +59 -2
  143. package/dist/stats/billing.js +41 -15
  144. package/dist/stats/db.js +159 -159
  145. package/dist/stats/eck-vars.js +9 -9
  146. package/dist/stats/price-resolver.js +28 -10
  147. package/dist/stats/query.js +139 -139
  148. package/dist/stats/role-budget.js +6 -6
  149. package/dist/stats/writer.js +51 -51
  150. package/dist/trigger/event-source.js +19 -0
  151. package/dist/trigger/feedback.js +233 -40
  152. package/dist/trigger/parser.js +55 -5
  153. package/dist/trigger/patch.js +9 -0
  154. package/dist/trigger/scheduler.js +30 -4
  155. package/dist/trigger/validation.js +20 -3
  156. package/dist/utils/cross-platform.js +30 -1
  157. package/dist/utils/ecweb-utils.js +1 -0
  158. package/dist/utils/error-dict.json +160 -160
  159. package/dist/utils/error-utils.js +61 -2
  160. package/dist/utils/evolcore-version.js +129 -0
  161. package/dist/utils/logger.js +26 -14
  162. package/dist/utils/macos-autostart.js +22 -22
  163. package/dist/utils/model-prices.jsonl +23 -23
  164. package/dist/utils/npm-ops.js +176 -35
  165. package/dist/utils/tool-summary.js +59 -3
  166. package/dist/utils/welcome.js +196 -23
  167. package/ecagent/LICENSE +21 -21
  168. package/ecagent/NOTICE +11 -11
  169. package/ecagent/README.md +61 -61
  170. package/ecagent/dist/harness/agent-harness.js +3 -0
  171. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  172. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  173. package/ecagent/dist/harness/messages.js +7 -7
  174. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  175. package/kits/docs/GUIDE.md +20 -20
  176. package/kits/docs/INDEX.md +60 -66
  177. package/kits/docs/aun/CHEATSHEET.md +19 -19
  178. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  179. package/kits/docs/channels/aun.md +69 -56
  180. package/kits/docs/channels/feishu.md +56 -56
  181. package/kits/docs/context-assembly.md +379 -367
  182. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  183. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  184. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  185. package/kits/docs/eck_templates/runtime.template.md +19 -19
  186. package/kits/docs/evolcore/INDEX.md +76 -71
  187. package/kits/docs/evolcore/agent-create.md +202 -165
  188. package/kits/docs/evolcore/agent.md +99 -67
  189. package/kits/docs/evolcore/aid.md +68 -60
  190. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
  191. package/kits/docs/evolcore/config.md +241 -195
  192. package/kits/docs/evolcore/contact.md +75 -68
  193. package/kits/docs/evolcore/ctl.md +46 -46
  194. package/kits/docs/evolcore/event.md +216 -216
  195. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  196. package/kits/docs/evolcore/fs.md +110 -110
  197. package/kits/docs/evolcore/group-collaboration.md +244 -244
  198. package/kits/docs/evolcore/group-fs.md +17 -17
  199. package/kits/docs/evolcore/group-rules.md +251 -251
  200. package/kits/docs/evolcore/group.md +267 -152
  201. package/kits/docs/evolcore/menu-client.md +58 -34
  202. package/kits/docs/evolcore/model.md +50 -50
  203. package/kits/docs/evolcore/msg.md +169 -165
  204. package/kits/docs/evolcore/response.md +75 -75
  205. package/kits/docs/evolcore/rpc.md +37 -37
  206. package/kits/docs/evolcore/self-summary.md +29 -29
  207. package/kits/docs/evolcore/stats.md +83 -83
  208. package/kits/docs/evolcore/storage.md +53 -50
  209. package/kits/docs/evolcore/task.md +14 -0
  210. package/kits/docs/evolcore/trigger.md +623 -575
  211. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  212. package/kits/docs/identity/PATH_OPS.md +16 -16
  213. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  214. package/kits/docs/identity/identity-tools.md +26 -26
  215. package/kits/docs/path-registry.md +62 -62
  216. package/kits/docs/prompt-loading-architecture.md +269 -269
  217. package/kits/docs/venues/aun-group.md +45 -45
  218. package/kits/docs/venues/aun-private.md +10 -10
  219. package/kits/docs/venues/client-desktop.md +10 -10
  220. package/kits/docs/venues/client-mobile.md +10 -10
  221. package/kits/docs/venues/feishu-group.md +13 -13
  222. package/kits/docs/venues/feishu-private.md +9 -9
  223. package/kits/docs/venues/group.md +42 -25
  224. package/kits/docs/venues/private.md +10 -10
  225. package/kits/eck_manifest.auxiliary.json +43 -43
  226. package/kits/eck_manifest.json +217 -190
  227. package/kits/eck_message_manifest.json +74 -74
  228. package/kits/migrations/README-role-config-v4.md +32 -32
  229. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  230. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  231. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  232. package/kits/migrations/rename-config-file.mjs +99 -99
  233. package/kits/rules/01-overview.md +166 -162
  234. package/kits/rules/02-navigation.md +96 -96
  235. package/kits/rules/03-identity.md +36 -36
  236. package/kits/rules/04-relation.md +76 -75
  237. package/kits/rules/05-venue.md +60 -60
  238. package/kits/rules/06-channel.md +65 -63
  239. package/kits/schemas/_meta.json +53 -53
  240. package/kits/schemas/agent-config.schema.1.json +177 -177
  241. package/kits/schemas/agent-config.schema.10.json +395 -395
  242. package/kits/schemas/agent-config.schema.11.json +421 -421
  243. package/kits/schemas/agent-config.schema.12.json +451 -427
  244. package/kits/schemas/agent-config.schema.2.json +239 -239
  245. package/kits/schemas/agent-config.schema.3.json +119 -119
  246. package/kits/schemas/agent-config.schema.4.json +208 -208
  247. package/kits/schemas/agent-config.schema.5.json +326 -326
  248. package/kits/schemas/agent-config.schema.6.json +322 -322
  249. package/kits/schemas/agent-config.schema.7.json +303 -303
  250. package/kits/schemas/agent-config.schema.8.json +304 -304
  251. package/kits/schemas/agent-config.schema.9.json +364 -364
  252. package/kits/schemas/contact-book.schema.1.json +36 -36
  253. package/kits/schemas/contact-book.schema.2.json +43 -43
  254. package/kits/schemas/contact-book.schema.3.json +67 -67
  255. package/kits/schemas/daemon.schema.1.json +91 -91
  256. package/kits/schemas/daemon.schema.2.json +101 -101
  257. package/kits/schemas/daemon.schema.3.json +123 -123
  258. package/kits/schemas/daemon.schema.4.json +136 -136
  259. package/kits/schemas/daemon.schema.5.json +135 -135
  260. package/kits/schemas/daemon.schema.6.json +131 -131
  261. package/kits/schemas/defaults.schema.1.json +81 -81
  262. package/kits/schemas/defaults.schema.2.json +85 -85
  263. package/kits/schemas/defaults.schema.3.json +73 -73
  264. package/kits/schemas/defaults.schema.4.json +107 -107
  265. package/kits/schemas/defaults.schema.5.json +119 -119
  266. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  267. package/kits/schemas/migrations/README.md +30 -30
  268. package/kits/schemas/relation-config.schema.1.json +158 -158
  269. package/kits/schemas/relation-config.schema.2.json +73 -73
  270. package/kits/schemas/relation-config.schema.3.json +50 -50
  271. package/kits/schemas/relation-config.schema.4.json +47 -47
  272. package/kits/schemas/relation-config.schema.5.json +47 -47
  273. package/kits/schemas/relation-config.schema.6.json +46 -46
  274. package/kits/schemas/relation-config.schema.7.json +59 -59
  275. package/kits/schemas/relation-config.schema.8.json +103 -103
  276. package/kits/schemas/role-config.schema.1.json +215 -201
  277. package/kits/schemas/role-registry.schema.1.json +35 -35
  278. package/kits/schemas/single-session.schema.1.json +31 -31
  279. package/kits/schemas/single-session.schema.2.json +57 -57
  280. package/kits/schemas/single-session.schema.3.json +32 -32
  281. package/kits/templates/bootstrap-welcome.md +17 -17
  282. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  283. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  284. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  285. package/kits/templates/message-fragments/inject-default.md +2 -2
  286. package/kits/templates/message-fragments/item.md +2 -2
  287. package/kits/templates/roles/admin.json +92 -92
  288. package/kits/templates/roles/member.json +101 -96
  289. package/kits/templates/roles/owner.json +9 -9
  290. package/kits/templates/roles/visitor.json +90 -85
  291. package/kits/templates/system-fragments/baseagent.md +14 -14
  292. package/kits/templates/system-fragments/bootstrap.md +53 -34
  293. package/kits/templates/system-fragments/channel.md +28 -64
  294. package/kits/templates/system-fragments/commands.md +36 -28
  295. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  296. package/kits/templates/system-fragments/identity.md +13 -13
  297. package/kits/templates/system-fragments/relation.md +19 -19
  298. package/kits/templates/system-fragments/reply.md +56 -0
  299. package/kits/templates/system-fragments/session.md +59 -59
  300. package/kits/templates/system-fragments/venue.md +31 -31
  301. package/package.json +104 -98
  302. package/dist/aun/group-identity.js +0 -9
  303. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  304. /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
@@ -1,10 +1,10 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { agentMdPath, resolvePaths, resolveRoot } from '../paths.js';
4
- import { isExplicitGroupId } from '../aun/group-identity.js';
4
+ import { isExplicitGroupId, normalizeGroupAid, sameGroupAid } from '../aun/group/index.js';
5
5
  import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
6
6
  import { ipcQuery } from '../ipc.js';
7
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
7
+ import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
8
8
  import { isManagementRole } from '../config/builtin-roles.js';
9
9
  import { readBestTaskRuntimeContext } from './task-context.js';
10
10
  // ==================== AID ====================
@@ -107,7 +107,7 @@ async function runManagedAid(args, formatJson) {
107
107
  const sessionId = process.env.EVOLCORE_SESSION_ID;
108
108
  if (!sessionId)
109
109
  failManagedAid(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID is not set');
110
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
110
+ const delegationToken = readDelegationCredential();
111
111
  if (!delegationToken) {
112
112
  failManagedAid(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task`);
113
113
  }
@@ -184,7 +184,7 @@ async function runManagedGroup(args, formatJson) {
184
184
  const sessionId = process.env.EVOLCORE_SESSION_ID;
185
185
  if (!sessionId)
186
186
  failManagedGroup(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID is not set');
187
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
187
+ const delegationToken = readDelegationCredential();
188
188
  if (!delegationToken) {
189
189
  failManagedGroup(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task`);
190
190
  }
@@ -214,7 +214,7 @@ async function runManagedMsg(args, formatJson) {
214
214
  const sessionId = process.env.EVOLCORE_SESSION_ID;
215
215
  if (!sessionId)
216
216
  failManagedGroup(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID is not set');
217
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
217
+ const delegationToken = readDelegationCredential();
218
218
  if (!delegationToken) {
219
219
  failManagedGroup(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task`);
220
220
  }
@@ -274,7 +274,7 @@ function validateManagedGroupScope(from, groupId, runtime, formatJson) {
274
274
  if (runtime.channel !== 'aun' || runtime.chatType !== 'group') {
275
275
  failManagedGroup(formatJson, 'ARGUMENT_MISMATCH', `当前角色 ${runtime.peerRole} 只能在 AUN 群聊任务中操作当前群`);
276
276
  }
277
- if (!runtime.channelId || groupId !== runtime.channelId) {
277
+ if (!runtime.channelId || !sameGroupAid(groupId, runtime.channelId)) {
278
278
  failManagedGroup(formatJson, 'ARGUMENT_MISMATCH', `当前角色 ${runtime.peerRole} 只能操作当前群 ${runtime.channelId ?? '<unknown>'},不能操作 ${groupId}`);
279
279
  }
280
280
  }
@@ -307,6 +307,27 @@ function renderManagedGroupResult(args, result, formatJson) {
307
307
  return;
308
308
  }
309
309
  const sub = args[0];
310
+ if (sub === 'history') {
311
+ if (result.mode === 'message')
312
+ console.log(result.content);
313
+ else {
314
+ console.log('本地群历史:' + result.count + ' 条');
315
+ for (const message of result.messages ?? []) {
316
+ console.log('[' + message.time + '] ' + message.from + ' → ' + message.to
317
+ + ' thread=' + (message.threadId || 'main') + '\n' + message.content);
318
+ if (message.content_truncated)
319
+ console.log('正文尚未读完');
320
+ if (message.content_truncated && message.msgId) {
321
+ console.log('--all --message ' + message.msgId + ' --offset ' + message.next_offset);
322
+ }
323
+ }
324
+ }
325
+ if (result.next_offset != null)
326
+ console.log('next_offset=' + result.next_offset);
327
+ if (result.has_more)
328
+ console.log('还有更多历史');
329
+ return;
330
+ }
310
331
  if (sub === 'list') {
311
332
  if (!result.items?.length)
312
333
  console.log('(没有加入任何群)');
@@ -317,8 +338,35 @@ function renderManagedGroupResult(args, result, formatJson) {
317
338
  }
318
339
  return;
319
340
  }
341
+ if (sub === 'blocklist') {
342
+ const items = result.items ?? [];
343
+ console.log(items.length ? `共 ${result.total ?? items.length} 条屏蔽:` : '(没有屏蔽成员)');
344
+ for (const item of items) {
345
+ console.log(` ${item.subject ?? item.aid ?? '-'} blocked_by=${item.blocked_by ?? '-'} reason=${item.reason ?? ''}`);
346
+ }
347
+ return;
348
+ }
349
+ if (sub === 'member-statuses') {
350
+ console.log(`成员上报状态(共 ${result.items?.length ?? 0} 名成员):`);
351
+ for (const item of result.items ?? []) {
352
+ console.log(` ${item.aid ?? '-'} online_status=${item.online_status || '(未上报)'} work_status=${item.work_status || '(未上报)'}`);
353
+ }
354
+ return;
355
+ }
356
+ if (sub === 'report-status') {
357
+ console.log('✓ 已上报当前成员状态');
358
+ console.log(JSON.stringify(result.data?.status ?? {}, null, 2));
359
+ return;
360
+ }
361
+ if (sub === 'block' || sub === 'unblock') {
362
+ const target = result.data?.block?.subject ?? result.data?.subject ?? args[3];
363
+ console.log(`✓ 已${sub === 'block' ? '屏蔽' : '取消屏蔽'} ${target} 接收群消息`);
364
+ return;
365
+ }
320
366
  if (sub === 'create') {
321
- console.log(`✓ 已创建群 ${result.group?.group_id ?? '-'}`);
367
+ console.log(`✓ 已创建群 ${result.group?.group_aid ?? result.group?.group_id ?? '-'}`);
368
+ if (result.warning)
369
+ console.warn(result.warning);
322
370
  return;
323
371
  }
324
372
  if (sub === 'rules' && args[3] === 'get' && result.status === 'ok') {
@@ -338,7 +386,7 @@ function renderManagedGroupResult(args, result, formatJson) {
338
386
  return;
339
387
  }
340
388
  if (sub === 'accept-invite' || sub === 'reject-invite' || sub === 'revoke-invite') {
341
- console.log(`✓ group ${sub} 完成`);
389
+ console.log(typeof result.message === 'string' ? result.message : `✓ group ${sub} 完成`);
342
390
  return;
343
391
  }
344
392
  console.log(`✓ group ${sub} 完成`);
@@ -348,37 +396,37 @@ export async function cmdAid(args) {
348
396
  const formatJson = getArgValue(args, '--format') === 'json';
349
397
  const aunPath = resolveAunPath(args);
350
398
  if (!sub || isHelpFlag(sub)) {
351
- console.log(`用法: ec aid <command>
352
-
353
- Commands:
354
- list 列出本地所有 AID(实测 sign+verify)
355
- show <aid> 查看本地 AID 详情(证书、私钥、签名能力)
356
- new <aid> 创建新 AID 身份
357
- delete <aid> 删除指定本地 AID(无网络注销)
358
- delete --orphan 批量清理无私钥的外部 AID 缓存
359
- delete --no-cert 批量清理无私钥也无公钥证书的孤儿目录
360
- delete --unrecoverable 批量清理云端公钥已变更、本地不可恢复的 AID
361
- 批量删除默认 dry-run,加 --yes 执行
362
- lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
399
+ console.log(`用法: ec aid <command>
400
+
401
+ Commands:
402
+ list 列出本地所有 AID(实测 sign+verify)
403
+ show <aid> 查看本地 AID 详情(证书、私钥、签名能力)
404
+ new <aid> 创建新 AID 身份
405
+ delete <aid> 删除指定本地 AID(无网络注销)
406
+ delete --orphan 批量清理无私钥的外部 AID 缓存
407
+ delete --no-cert 批量清理无私钥也无公钥证书的孤儿目录
408
+ delete --unrecoverable 批量清理云端公钥已变更、本地不可恢复的 AID
409
+ 批量删除默认 dry-run,加 --yes 执行
410
+ lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
363
411
  agentmd put <aid> 读本地 agent.md → 签名 → 上传
364
412
  agentmd get <aid> 下载 agent.md → 验签 → 本地持久化
365
413
  avatar <aid> --file <path> | --url <https-url> 上传头像并更新 agent.md
366
-
367
- Options:
368
- --format json 输出 JSON 格式
369
- --aun-path <path> 指定 AUN keystore 根(默认 EVOLCORE_HOME,可由 AUN_HOME 设置)
370
- --help, -h 各子命令均支持,查看详细用法
371
-
372
- 示例:
373
- ec aid list
374
- ec aid show toleiliang2.agentid.pub
375
- ec aid new reviewer.agentid.pub
376
- ec aid delete --help
377
- ec aid delete old.agentid.pub
378
- ec aid delete --orphan
379
- ec aid delete --unrecoverable --yes
380
- ec aid lookup someone.agentid.pub
381
- ec aid agentmd put mybot.agentid.pub
414
+
415
+ Options:
416
+ --format json 输出 JSON 格式
417
+ --aun-path <path> 指定 AUN keystore 根(默认 EVOLCORE_HOME,可由 AUN_HOME 设置)
418
+ --help, -h 各子命令均支持,查看详细用法
419
+
420
+ 示例:
421
+ ec aid list
422
+ ec aid show toleiliang2.agentid.pub
423
+ ec aid new reviewer.agentid.pub
424
+ ec aid delete --help
425
+ ec aid delete old.agentid.pub
426
+ ec aid delete --orphan
427
+ ec aid delete --unrecoverable --yes
428
+ ec aid lookup someone.agentid.pub
429
+ ec aid agentmd put mybot.agentid.pub
382
430
  ec aid agentmd get someone.agentid.pub`);
383
431
  return;
384
432
  }
@@ -389,33 +437,33 @@ Options:
389
437
  const { aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, agentmdPut, agentmdGet, buildInitialAgentMd, isValidAid } = await import('../aun/aid/index.js');
390
438
  if (sub === 'list') {
391
439
  if (wantsHelp(args)) {
392
- console.log(`用法: ec aid list [筛选选项] [--no-verify] [--format json]
393
-
394
- 列出本地 AID 并跑 sign+verify 自检。
395
-
396
- 筛选选项(可组合,不指定 = 列出 mine + broken + peer-cert):
397
- --mine 仅本地可用身份(实测可签名+验签通过)
398
- --broken 仅有私钥但不可用(公钥不匹配 / 证书过期 / sign 失败)
399
- --peer-cert 仅对端 AID(无私钥,有公钥证书)
400
- --no-cert 仅无私钥无证书的目录(默认隐藏,需用 aid delete --no-cert 清理)
401
-
402
- 选项:
403
- --no-verify 跳过 sign+verify 实测,仅静态扫描(更快,mine/broken 仅按静态判定近似)
404
- --format json JSON 格式输出
405
-
406
- 输出图标:
407
- 🔑 有私钥
408
- ✅ 实测可签名/验签
409
- ❌ 不可签名(公钥不匹配 / sign 失败 / verify 失败等)
410
- ⌛ 证书过期
411
- 📜 有公钥证书
412
- 📄 有 agent.md
413
-
414
- 示例:
415
- ec aid list 列出 mine + broken + peer-cert
416
- ec aid list --mine 仅可用身份
417
- ec aid list --mine --broken 所有有私钥的 AID
418
- ec aid list --no-cert 仅无私钥无证书的孤儿目录
440
+ console.log(`用法: ec aid list [筛选选项] [--no-verify] [--format json]
441
+
442
+ 列出本地 AID 并跑 sign+verify 自检。
443
+
444
+ 筛选选项(可组合,不指定 = 列出 mine + broken + peer-cert):
445
+ --mine 仅本地可用身份(实测可签名+验签通过)
446
+ --broken 仅有私钥但不可用(公钥不匹配 / 证书过期 / sign 失败)
447
+ --peer-cert 仅对端 AID(无私钥,有公钥证书)
448
+ --no-cert 仅无私钥无证书的目录(默认隐藏,需用 aid delete --no-cert 清理)
449
+
450
+ 选项:
451
+ --no-verify 跳过 sign+verify 实测,仅静态扫描(更快,mine/broken 仅按静态判定近似)
452
+ --format json JSON 格式输出
453
+
454
+ 输出图标:
455
+ 🔑 有私钥
456
+ ✅ 实测可签名/验签
457
+ ❌ 不可签名(公钥不匹配 / sign 失败 / verify 失败等)
458
+ ⌛ 证书过期
459
+ 📜 有公钥证书
460
+ 📄 有 agent.md
461
+
462
+ 示例:
463
+ ec aid list 列出 mine + broken + peer-cert
464
+ ec aid list --mine 仅可用身份
465
+ ec aid list --mine --broken 所有有私钥的 AID
466
+ ec aid list --no-cert 仅无私钥无证书的孤儿目录
419
467
  ec aid list --no-verify 跳过实测,快速静态扫描`);
420
468
  return;
421
469
  }
@@ -467,8 +515,8 @@ Options:
467
515
  }
468
516
  if (sub === 'show') {
469
517
  if (wantsHelp(args)) {
470
- console.log(`用法: ec aid show <aid> [--format json]
471
-
518
+ console.log(`用法: ec aid show <aid> [--format json]
519
+
472
520
  查看本地 AID 详情:私钥/证书/agent.md 状态、签名能力实测。`);
473
521
  return;
474
522
  }
@@ -483,16 +531,16 @@ Options:
483
531
  }
484
532
  if (sub === 'new') {
485
533
  if (wantsHelp(args)) {
486
- console.log(`用法: ec aid new <完整AID> [--force] [--format json]
487
-
488
- 创建新 AID 身份:生成 ECDSA 密钥对、向 Issuer 申请证书、构建并上传初始 agent.md。
489
-
490
- 选项:
491
- --force 强制重新注册,覆盖已存在的身份(即使签名验证失败)
492
- --format json 输出 JSON
493
- --aun-path <path> 指定 AUN keystore 根
494
-
495
- 例: ec aid new reviewer.agentid.pub
534
+ console.log(`用法: ec aid new <完整AID> [--force] [--format json]
535
+
536
+ 创建新 AID 身份:生成 ECDSA 密钥对、向 Issuer 申请证书、构建并上传初始 agent.md。
537
+
538
+ 选项:
539
+ --force 强制重新注册,覆盖已存在的身份(即使签名验证失败)
540
+ --format json 输出 JSON
541
+ --aun-path <path> 指定 AUN keystore 根
542
+
543
+ 例: ec aid new reviewer.agentid.pub
496
544
  ec aid new reviewer.agentid.pub --force`);
497
545
  return;
498
546
  }
@@ -575,34 +623,34 @@ Options:
575
623
  }
576
624
  if (sub === 'delete') {
577
625
  if (wantsHelp(args)) {
578
- console.log(`用法: ec aid delete <子命令>
579
-
580
- 单个删除:
581
- ec aid delete <aid> 删除指定 AID 的本地数据(无网络注销)
582
-
583
- 批量删除(默认 dry-run,加 --yes 才真删):
584
- ec aid delete --orphan 删除所有"无私钥"的本地缓存(外部 AID)
585
- ec aid delete --no-cert 删除所有"无私钥也无公钥证书"的目录
586
- 条件:!hasPrivateKey && !hasCert
587
- 这些目录最多只剩 agent.md 或 SQLite 残留,
588
- 对验签和加密通信都没用,删除安全。
589
- ec aid delete --unrecoverable 删除所有不可恢复的 AID
590
- 条件:本地 sign+verify 实测失败
591
- 且 PKI 探测确认云端公钥也不等本地 key.json
592
-
593
- 选项:
594
- --yes 跳过 dry-run,立即执行
595
- --skip-pki --unrecoverable 时跳过 PKI 探测,仅依据本地 sign+verify 失败判断(危险,可能误删可恢复 AID)
596
- --format json 输出 JSON 格式
597
- --aun-path <path> 指定 AUN keystore 根
598
-
599
- 示例:
600
- ec aid delete old.agentid.pub
601
- ec aid delete --orphan 列出会被清理的孤儿
602
- ec aid delete --orphan --yes 实际清理
603
- ec aid delete --no-cert 列出无证书孤儿目录
604
- ec aid delete --no-cert --yes 实际清理
605
- ec aid delete --unrecoverable 联网探测后列出无救 AID
626
+ console.log(`用法: ec aid delete <子命令>
627
+
628
+ 单个删除:
629
+ ec aid delete <aid> 删除指定 AID 的本地数据(无网络注销)
630
+
631
+ 批量删除(默认 dry-run,加 --yes 才真删):
632
+ ec aid delete --orphan 删除所有"无私钥"的本地缓存(外部 AID)
633
+ ec aid delete --no-cert 删除所有"无私钥也无公钥证书"的目录
634
+ 条件:!hasPrivateKey && !hasCert
635
+ 这些目录最多只剩 agent.md 或 SQLite 残留,
636
+ 对验签和加密通信都没用,删除安全。
637
+ ec aid delete --unrecoverable 删除所有不可恢复的 AID
638
+ 条件:本地 sign+verify 实测失败
639
+ 且 PKI 探测确认云端公钥也不等本地 key.json
640
+
641
+ 选项:
642
+ --yes 跳过 dry-run,立即执行
643
+ --skip-pki --unrecoverable 时跳过 PKI 探测,仅依据本地 sign+verify 失败判断(危险,可能误删可恢复 AID)
644
+ --format json 输出 JSON 格式
645
+ --aun-path <path> 指定 AUN keystore 根
646
+
647
+ 示例:
648
+ ec aid delete old.agentid.pub
649
+ ec aid delete --orphan 列出会被清理的孤儿
650
+ ec aid delete --orphan --yes 实际清理
651
+ ec aid delete --no-cert 列出无证书孤儿目录
652
+ ec aid delete --no-cert --yes 实际清理
653
+ ec aid delete --unrecoverable 联网探测后列出无救 AID
606
654
  ec aid delete --unrecoverable --yes`);
607
655
  return;
608
656
  }
@@ -732,8 +780,8 @@ Options:
732
780
  }
733
781
  if (sub === 'lookup') {
734
782
  if (wantsHelp(args)) {
735
- console.log(`用法: ec aid lookup <aid> [--format json]
736
-
783
+ console.log(`用法: ec aid lookup <aid> [--format json]
784
+
737
785
  远程探测 AID:是否注册、所在网关、是否有 agent.md(不验签,仅获取)。`);
738
786
  return;
739
787
  }
@@ -754,9 +802,9 @@ Options:
754
802
  const verb = args[1];
755
803
  const aid = args[2];
756
804
  if (!verb || isHelpFlag(verb) || wantsHelp(args)) {
757
- console.log(`用法: ec aid agentmd <put|get> <aid> [--format json]
758
-
759
- put <aid> 读本地 agent.md → 用本地私钥签名 → 上传到 PKI
805
+ console.log(`用法: ec aid agentmd <put|get> <aid> [--format json]
806
+
807
+ put <aid> 读本地 agent.md → 用本地私钥签名 → 上传到 PKI
760
808
  get <aid> 从 PKI 下载 agent.md → 验签 → 持久化到本地`);
761
809
  return;
762
810
  }
@@ -867,24 +915,24 @@ Options:
867
915
  // ==================== RPC ====================
868
916
  export async function cmdRpc(args) {
869
917
  if (args.length === 0 || wantsHelp(args)) {
870
- console.log(`用法: ec rpc --as <aid> --params <params>
871
-
872
- 通用 AUN RPC 调用。
873
-
874
- --params 自动判断输入形式:
875
- 单行 JSON (以 { 开头) → 单次调用
876
- 多行 JSONL → 逐行执行,失败即停
877
- 文件路径 (文件存在) → 读取文件内容作为 JSONL
878
-
879
- 每行 JSON 格式: {"method":"<namespace.method>","params":{...}}
880
-
881
- Options:
882
- --app <name> 指定应用 slot(独立消费通道)。仅对 message.pull / group.pull
883
- 等消费类方法有意义——隔离 seq 游标与消息过滤;默认与 daemon 共享通道。
884
- --aun-path <path> 指定 AUN keystore 根
885
-
886
- 示例:
887
- ec rpc --as alice.agentid.pub --params '{"method":"message.send","params":{"to":"bob.agentid.pub","payload":{"type":"text","text":"hello"}}}'
918
+ console.log(`用法: ec rpc --as <aid> --params <params>
919
+
920
+ 通用 AUN RPC 调用。
921
+
922
+ --params 自动判断输入形式:
923
+ 单行 JSON (以 { 开头) → 单次调用
924
+ 多行 JSONL → 逐行执行,失败即停
925
+ 文件路径 (文件存在) → 读取文件内容作为 JSONL
926
+
927
+ 每行 JSON 格式: {"method":"<namespace.method>","params":{...}}
928
+
929
+ Options:
930
+ --app <name> 指定应用 slot(独立消费通道)。仅对 message.pull / group.pull
931
+ 等消费类方法有意义——隔离 seq 游标与消息过滤;默认与 daemon 共享通道。
932
+ --aun-path <path> 指定 AUN keystore 根
933
+
934
+ 示例:
935
+ ec rpc --as alice.agentid.pub --params '{"method":"message.send","params":{"to":"bob.agentid.pub","payload":{"type":"text","text":"hello"}}}'
888
936
  ec rpc --as alice.agentid.pub --params calls.jsonl`);
889
937
  return;
890
938
  }
@@ -952,29 +1000,29 @@ export async function cmdStorage(args) {
952
1000
  const aunPath = resolveAunPath(args);
953
1001
  const formatJson = getArgValue(args, '--format') === 'json';
954
1002
  if (!sub || wantsHelp(args)) {
955
- console.log(`用法: ec storage <command> <aid> [options]
956
-
957
- Commands:
958
- upload <aid> <local-file> <remote-path> [--public] 上传文件(默认私有)
959
- download <aid> <url> [local-path] 下载文件
960
- ls <aid> [prefix] 列文件
961
- rm <aid> <remote-path> 删文件
962
- quota <aid> 查配额
963
-
964
- <url> 格式: [https://]<owner-aid>/<path>
965
-
966
- Options:
967
- --public 上传后公开可读(仅 upload)
968
- --format json 输出 JSON
969
- --aun-path <path> 指定 AUN keystore 根
970
-
971
- 示例:
972
- ec storage upload myaid.agentid.pub ./doc.txt notes/doc.txt
973
- ec storage upload myaid.agentid.pub ./pic.png images/pic.png --public
974
- ec storage download myaid.agentid.pub myaid.agentid.pub/notes/doc.txt ./doc.txt
975
- ec storage download myaid.agentid.pub bob.agentid.pub/public/file.pdf ./file.pdf
976
- ec storage ls myaid.agentid.pub notes/
977
- ec storage rm myaid.agentid.pub notes/doc.txt
1003
+ console.log(`用法: ec storage <command> <aid> [options]
1004
+
1005
+ Commands:
1006
+ upload <aid> <local-file> <remote-path> [--public] 上传文件(默认私有)
1007
+ download <aid> <url> [local-path] 下载文件
1008
+ ls <aid> [prefix] 列文件
1009
+ rm <aid> <remote-path> 删文件
1010
+ quota <aid> 查配额
1011
+
1012
+ <url> 格式: [https://]<owner-aid>/<path>
1013
+
1014
+ Options:
1015
+ --public 上传后公开可读(仅 upload)
1016
+ --format json 输出 JSON
1017
+ --aun-path <path> 指定 AUN keystore 根
1018
+
1019
+ 示例:
1020
+ ec storage upload myaid.agentid.pub ./doc.txt notes/doc.txt
1021
+ ec storage upload myaid.agentid.pub ./pic.png images/pic.png --public
1022
+ ec storage download myaid.agentid.pub myaid.agentid.pub/notes/doc.txt ./doc.txt
1023
+ ec storage download myaid.agentid.pub bob.agentid.pub/public/file.pdf ./file.pdf
1024
+ ec storage ls myaid.agentid.pub notes/
1025
+ ec storage rm myaid.agentid.pub notes/doc.txt
978
1026
  ec storage quota myaid.agentid.pub`);
979
1027
  return;
980
1028
  }
@@ -992,15 +1040,47 @@ Options:
992
1040
  const operation = { ls: 'storage.list', quota: 'storage.quota', upload: 'storage.upload', download: 'storage.download', rm: 'storage.delete' }[sub];
993
1041
  if (!operation)
994
1042
  failManagedGroup(formatJson, 'NOT_ALLOWED', `unsupported managed storage command: ${sub}`);
995
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
1043
+ const delegationToken = readDelegationCredential();
996
1044
  if (!delegationToken)
997
1045
  failManagedGroup(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task`);
1046
+ if (sub === 'upload') {
1047
+ const localFile = args[2];
1048
+ const remotePath = args[3];
1049
+ if (!localFile || !remotePath) {
1050
+ console.error('用法: ec storage upload <aid> <local-file> <remote-path> [--public]');
1051
+ process.exit(1);
1052
+ }
1053
+ if (!fs.existsSync(localFile)) {
1054
+ console.error(`❌ 文件不存在: ${localFile}`);
1055
+ process.exit(1);
1056
+ }
1057
+ const result = await ipcQuery(resolvePaths().socket, {
1058
+ type: 'storage.upload',
1059
+ aid,
1060
+ localFile,
1061
+ remotePath,
1062
+ isPublic: args.includes('--public'),
1063
+ sessionId: process.env.EVOLCORE_SESSION_ID,
1064
+ delegationToken,
1065
+ }, null);
1066
+ if (!result)
1067
+ failManagedGroup(formatJson, 'DAEMON_UNAVAILABLE', 'Unable to connect to the evolcore daemon');
1068
+ if (!result.ok)
1069
+ failManagedGroup(formatJson, result.code || 'STORAGE_UPLOAD_FAILED', result.error || 'Storage upload failed');
1070
+ if (formatJson)
1071
+ console.log(JSON.stringify({ ok: true, objectKey: remotePath, isPublic: args.includes('--public'), ref: `${aid}/${remotePath}`, publicUrl: result.publicUrl ?? null }));
1072
+ else {
1073
+ console.log(`✓ 已上传: ${remotePath}${args.includes('--public') ? ' (公开)' : ''}`);
1074
+ if (result.publicUrl)
1075
+ console.log(` 🔗 访问: ${result.publicUrl}`);
1076
+ else
1077
+ console.log(` 引用: ${aid}/${remotePath}`);
1078
+ console.log(` 下载: ec storage download ${aid} ${aid}/${remotePath}`);
1079
+ }
1080
+ return;
1081
+ }
998
1082
  const authorization = await ipcQuery(resolvePaths().socket, {
999
- type: 'storage.auth',
1000
- operation,
1001
- aid,
1002
- sessionId: process.env.EVOLCORE_SESSION_ID,
1003
- delegationToken,
1083
+ type: 'storage.auth', operation, aid, sessionId: process.env.EVOLCORE_SESSION_ID, delegationToken,
1004
1084
  }, 10_000);
1005
1085
  if (!authorization)
1006
1086
  failManagedGroup(formatJson, 'DAEMON_UNAVAILABLE', 'Unable to connect to the evolcore daemon');
@@ -1129,83 +1209,84 @@ export async function cmdMsg(args) {
1129
1209
  const formatJson = getArgValue(args, '--format') === 'json';
1130
1210
  const appSlot = getArgValue(args, '--app');
1131
1211
  if (!sub || isHelpFlag(sub) || (wantsHelp(args) && sub !== 'history')) {
1132
- console.log(`用法: ec msg <command> <from-aid> [args...] [options]
1133
-
1134
- Commands:
1135
- send <from> <to> <text> --return <none|required> 发送文本(跨会话时 --return 必填)
1136
- send <from> <to> --text-from-file <path> 从文件读取文本内容
1137
- send <from> <to> --file <path> [--as <type>] 发送文件(image|video|voice|file)
1138
- send <from> <to> --link <url> [--title T] 发送链接卡片
1139
- send <from> <to> --payload <json> 发送自定义 payload
1212
+ console.log(`用法: ec msg <command> <from-aid> [args...] [options]
1213
+
1214
+ Commands:
1215
+ send <from> <to> <text> --return <none|required> 发送文本(跨会话时 --return 必填)
1216
+ send <from> <to> --text-from-file <path> 从文件读取文本内容
1217
+ send <from> <to> --file <path> [--as <type>] 发送文件(image|video|voice|file)
1218
+ send <from> <to> --link <url> [--title T] 发送链接卡片
1219
+ send <from> <to> --payload <json> 发送自定义 payload
1140
1220
  pull <from> [--after-seq N] [--limit N] --app <name> 拉取收件箱(必须使用独立 slot)
1141
- ack <from> <seq> [--app <name>] 确认已读
1142
- recall <from> <message-id> [<message-id>...] 撤回消息
1143
- online <from> <target-aid> [<target-aid>...] 查询在线状态
1144
- history <from> [<target-aid>|selector] [筛选选项] 查询本地消息历史
1145
-
1146
- Options:
1147
- --text-from-file <path> 从文件读取文本(UTF-8),用于超长消息或避免 Shell 转义
1148
- --app <name> 指定应用 slot(独立消费通道,不影响 daemon)
1149
- --aun-path <path> 指定 AUN keystore 根
1150
- --format json 输出 JSON 格式
1151
- --encrypt 强制端到端加密(未指定时使用 daemon 默认值)
1152
- --no-encrypt 强制明文发送(优先于 --encrypt)
1153
- --thread <id> 指定话题 ID(用于多话题路由)
1154
- --session <latest|all|id> 按 EvolCore 逻辑会话过滤历史(默认 latest)
1155
- --before <time> 只返回该时间之前的历史
1156
- --after <time> 只返回该时间之后的历史
1157
- --direction <value> 历史方向:in|out|all
1158
- --channel <type> 历史渠道:aun|feishu|wechat|dingtalk|qqbot|wecom
1159
- --channel-name <name> 历史渠道实例名(非 AUN 渠道必须匹配 Agent 配置)
1160
- --channel-key <key> 非 AUN 已落盘渠道的完整实例键(与 --peer-id 成对)
1161
- --peer-id <id> 非 AUN 渠道的原生对端 ID(与 --channel-key 成对)
1162
- --return <none|required> 跨会话发送必填:none=仅补充目标上下文,required=回答回流来源
1163
- --content-type <mime> 显式覆盖 MIME(仅 --file 模式)
1164
- --as <type> 附件类型:image|video|voice|file(仅 --file 模式)
1165
- --text <说明> 附件说明文字(仅 --file 模式)
1166
- --transcript <text> 语音转写(仅 --as voice)
1167
- --title <text> 链接标题(仅 --link 模式)
1168
- --description <text> 链接描述(仅 --link 模式)
1169
- -- end-of-options:其后所有参数按正文处理
1170
- (用于发送恰好等于某 flag 的文本,如 send a b -- --encrypt)
1171
-
1172
- 示例:
1173
- ec msg send alice.agentid.pub bob.agentid.pub "hello" --return none
1174
- ec msg send alice.agentid.pub bob.agentid.pub --text-from-file long-message.txt --return none
1175
- ec msg send alice.agentid.pub bob.agentid.pub "讨论项目A" --thread "project-A" --return required
1176
- ec msg send alice.agentid.pub bob.agentid.pub --file ./pic.png --return none
1177
- ec msg send alice.agentid.pub bob.agentid.pub --file ./demo.mp4 --as video --return none
1178
- ec msg send alice.agentid.pub bob.agentid.pub --link https://example.com --title "AUN" --return none
1179
- ec msg pull alice.agentid.pub --app my-bot
1180
- ec msg ack alice.agentid.pub 42 --app my-bot
1181
- ec msg recall alice.agentid.pub msg-uuid-1 msg-uuid-2
1182
- ec msg online alice.agentid.pub bob.agentid.pub carol.agentid.pub
1183
- ec msg history alice.agentid.pub bob.agentid.pub --session latest --limit 50
1221
+ ack <from> <seq> [--app <name>] 确认已读
1222
+ recall <from> <message-id> [<message-id>...] 撤回消息
1223
+ online <from> <target-aid> [<target-aid>...] 查询在线状态
1224
+ history <from> [<target-aid>|selector] [筛选选项] 查询本地消息历史
1225
+
1226
+ Options:
1227
+ --text-from-file <path> 从文件读取文本(UTF-8),用于超长消息或避免 Shell 转义
1228
+ --handoff-context <text> 仅托管会话:为目标会话补充本地上下文,不发给对端
1229
+ --app <name> 指定应用 slot(独立消费通道,不影响 daemon)
1230
+ --aun-path <path> 指定 AUN keystore 根
1231
+ --format json 输出 JSON 格式
1232
+ --encrypt 强制端到端加密(未指定时使用 daemon 默认值)
1233
+ --no-encrypt 强制明文发送(优先于 --encrypt)
1234
+ --thread <id> 指定话题 ID(用于多话题路由)
1235
+ --session <latest|all|id> 按 EvolCore 逻辑会话过滤历史(默认 latest)
1236
+ --before <time> 只返回该时间之前的历史
1237
+ --after <time> 只返回该时间之后的历史
1238
+ --direction <value> 历史方向:in|out|all
1239
+ --channel <type> 历史渠道:aun|feishu|wechat|dingtalk|qqbot|wecom
1240
+ --channel-name <name> 历史渠道实例名(非 AUN 渠道必须匹配 Agent 配置)
1241
+ --channel-key <key> 非 AUN 已落盘渠道的完整实例键(与 --peer-id 成对)
1242
+ --peer-id <id> 非 AUN 渠道的原生对端 ID(与 --channel-key 成对)
1243
+ --return <none|required> 跨会话发送必填:none=仅补充目标上下文,required=回答回流来源
1244
+ --content-type <mime> 显式覆盖 MIME(仅 --file 模式)
1245
+ --as <type> 附件类型:image|video|voice|file(仅 --file 模式)
1246
+ --text <说明> 附件说明文字(仅 --file 模式)
1247
+ --transcript <text> 语音转写(仅 --as voice)
1248
+ --title <text> 链接标题(仅 --link 模式)
1249
+ --description <text> 链接描述(仅 --link 模式)
1250
+ -- end-of-options:其后所有参数按正文处理
1251
+ (用于发送恰好等于某 flag 的文本,如 send a b -- --encrypt)
1252
+
1253
+ 示例:
1254
+ ec msg send alice.agentid.pub bob.agentid.pub "hello" --return none
1255
+ ec msg send alice.agentid.pub bob.agentid.pub --text-from-file long-message.txt --return none
1256
+ ec msg send alice.agentid.pub bob.agentid.pub "讨论项目A" --thread "project-A" --return required
1257
+ ec msg send alice.agentid.pub bob.agentid.pub --file ./pic.png --return none
1258
+ ec msg send alice.agentid.pub bob.agentid.pub --file ./demo.mp4 --as video --return none
1259
+ ec msg send alice.agentid.pub bob.agentid.pub --link https://example.com --title "AUN" --return none
1260
+ ec msg pull alice.agentid.pub --app my-bot
1261
+ ec msg ack alice.agentid.pub 42 --app my-bot
1262
+ ec msg recall alice.agentid.pub msg-uuid-1 msg-uuid-2
1263
+ ec msg online alice.agentid.pub bob.agentid.pub carol.agentid.pub
1264
+ ec msg history alice.agentid.pub bob.agentid.pub --session latest --limit 50
1184
1265
  ec msg history alice.agentid.pub --channel-key feishu#alice.agentid.pub#main --peer-id ou_xxx --session all --format json`);
1185
1266
  return;
1186
1267
  }
1187
1268
  if (sub === 'history' && wantsHelp(args)) {
1188
- console.log(`用法: ec msg history <self-aid> [<target-aid> | --channel-key <key> --peer-id <id>] [options]
1189
-
1190
- 查询指定会话对的本地历史,不调用 message.pull,也不影响收件箱游标。非 AUN selector 按已落盘的 session metadata、完整 channelKey 与原生 peer ID 精确读取,不能传入文件路径。
1191
-
1192
- 托管会话限制:普通会话只能使用当前 self AID 和当前 AUN 私聊对端;可信 daemon Trigger 可用精确的 --channel-key/--peer-id selector 读取已落盘的非 AUN 私聊历史。托管任务不支持 --channel、--channel-name、--aun-path 或 --app。
1193
-
1194
- Options:
1195
- --session <latest|all|id> 默认 latest;all 查询全部;也可指定会话 ID
1196
- --limit <N> 返回最新 N 条(默认 50,最大 500)
1197
- --before <time> 开区间;epoch 毫秒或 ISO 时间
1198
- --after <time> 开区间;epoch 毫秒或 ISO 时间
1199
- --direction <value> in|out|all(默认 all)
1200
- --channel-key <key> 非 AUN 已落盘渠道完整键;必须与 --peer-id 同时给出
1201
- --peer-id <id> 原生私聊对端 ID;必须与 --channel-key 同时给出
1202
- --format <text|json> 输出格式(默认 text)
1203
-
1204
- 示例:
1205
- ec msg history alice.agentid.pub bob.agentid.pub
1206
- ec msg history alice.agentid.pub bob.agentid.pub --session latest
1207
- ec msg history alice.agentid.pub bob.agentid.pub --session all
1208
- ec msg history alice.agentid.pub bob.agentid.pub --session meta_20260713_1783920000000 --format json
1269
+ console.log(`用法: ec msg history <self-aid> [<target-aid> | --channel-key <key> --peer-id <id>] [options]
1270
+
1271
+ 查询指定会话对的本地历史,不调用 message.pull,也不影响收件箱游标。非 AUN selector 按已落盘的 session metadata、完整 channelKey 与原生 peer ID 精确读取,不能传入文件路径。
1272
+
1273
+ 托管会话限制:普通会话只能使用当前 self AID 和当前 AUN 私聊对端;可信 daemon Trigger 可用精确的 --channel-key/--peer-id selector 读取已落盘的非 AUN 私聊历史。托管任务不支持 --channel、--channel-name、--aun-path 或 --app。
1274
+
1275
+ Options:
1276
+ --session <latest|all|id> 默认 latest;all 查询全部;也可指定会话 ID
1277
+ --limit <N> 返回最新 N 条(默认 50,最大 500)
1278
+ --before <time> 开区间;epoch 毫秒或 ISO 时间
1279
+ --after <time> 开区间;epoch 毫秒或 ISO 时间
1280
+ --direction <value> in|out|all(默认 all)
1281
+ --channel-key <key> 非 AUN 已落盘渠道完整键;必须与 --peer-id 同时给出
1282
+ --peer-id <id> 原生私聊对端 ID;必须与 --channel-key 同时给出
1283
+ --format <text|json> 输出格式(默认 text)
1284
+
1285
+ 示例:
1286
+ ec msg history alice.agentid.pub bob.agentid.pub
1287
+ ec msg history alice.agentid.pub bob.agentid.pub --session latest
1288
+ ec msg history alice.agentid.pub bob.agentid.pub --session all
1289
+ ec msg history alice.agentid.pub bob.agentid.pub --session meta_20260713_1783920000000 --format json
1209
1290
  ec msg history alice.agentid.pub --channel-key feishu#alice.agentid.pub#main --peer-id ou_xxx --session all --format json`);
1210
1291
  return;
1211
1292
  }
@@ -1442,28 +1523,14 @@ Options:
1442
1523
  console.error(`❌ --return 仅支持 required|none: ${returnPolicyRaw}`);
1443
1524
  process.exit(1);
1444
1525
  }
1445
- // 文件上传进度展示(非 JSON 输出时)。仅在大文件降级到 HTTP PUT 阶段会逐块更新。
1446
- let lastPctShown = -1;
1526
+ // SDK 尚未提供字节进度回调,只展示上传开始和成功完成。
1447
1527
  const onUploadProgress = formatJson ? undefined : (info) => {
1448
- if (info.phase === 'inline')
1449
- return; // 内联阶段不分块,跳过
1450
- if (info.phase === 'http-put') {
1451
- const pct = info.total > 0 ? Math.floor((info.bytes / info.total) * 100) : 0;
1452
- if (pct === lastPctShown && info.bytes < info.total)
1453
- return;
1454
- lastPctShown = pct;
1455
- const mb = (n) => (n / 1024 / 1024).toFixed(2);
1456
- const eol = info.bytes >= info.total ? '\n' : '\r';
1457
- process.stderr.write(` ⏫ uploading: ${pct}% (${mb(info.bytes)}/${mb(info.total)} MB)${eol}`);
1458
- }
1459
- else if (info.phase === 'session-create') {
1460
- process.stderr.write(' ⏫ requesting upload session...\n');
1461
- }
1462
- else if (info.phase === 'session-complete') {
1463
- process.stderr.write(' ⏫ finalizing upload...\n');
1464
- }
1528
+ if (info.phase === 'upload')
1529
+ process.stderr.write(' ⏫ uploading...\n');
1530
+ else if (info.phase === 'done')
1531
+ process.stderr.write(' ✓ upload complete\n');
1465
1532
  };
1466
- const result = await msgSend({ from, to, body, encrypt, thread, returnPolicy: returnPolicyRaw, onUploadProgress, ...commonOpts });
1533
+ const result = await msgSend({ from, to, body, encrypt, thread, returnPolicy: returnPolicyRaw, handoffContext: getArgValue(args, '--handoff-context'), onUploadProgress, ...commonOpts });
1467
1534
  if (!result.ok) {
1468
1535
  if (formatJson) {
1469
1536
  console.log(JSON.stringify(result));
@@ -1632,77 +1699,104 @@ export async function cmdGroup(args) {
1632
1699
  const aunPath = resolveAunPath(args);
1633
1700
  const formatJson = getArgValue(args, '--format') === 'json';
1634
1701
  const appSlot = getArgValue(args, '--app');
1702
+ if (sub === 'history' && wantsHelp(args)) {
1703
+ console.log(`用法: ec group history <self-aid> <group-aid> --unread|--all [options]
1704
+ 本地 messages.jsonl 查询,不访问 Gateway,不推进 group pull/ack 游标。
1705
+ --unread 返回最早未读的未提及背景,并自动记录本页已读
1706
+ --all 浏览群会话历史(返回最近 N 条),不改变已读状态
1707
+ --limit <N> 默认 50,范围 1–500;另有 24 KiB 单页消息预算
1708
+ --thread <main|all|id> 当前群任务缺省继承当前话题;其他调用缺省 all
1709
+ --direction <in|out|all> 按方向筛选,默认 all
1710
+ --before/--after <time> 按接收时间筛选,开区间;epoch 毫秒或 ISO 时间
1711
+ --format <text|json> 默认 text
1712
+ --message <msg-id> 配合 --all 查看指定长消息正文
1713
+ --offset <bytes> 配合 --message 从 next_offset 继续读取,默认 0
1714
+ --unread 返回的消息会记为已读;--all(包括 --all --message)始终只读,之后仍可回看。
1715
+ visitor 不开放历史;群权限仍由托管会话校验。
1716
+ 旧日志通过 --all 查询,只有带本地未提及标记的新记录参与 --unread。`);
1717
+ return;
1718
+ }
1635
1719
  const rulesActionHelp = sub === 'rules' && isHelpFlag(args[3]);
1636
1720
  if (!sub || isHelpFlag(sub) || (wantsHelp(args) && !rulesActionHelp)) {
1637
- console.log(`用法: ec group <command> <from-aid> [args...] [options]
1638
-
1639
- 消息:
1640
- send <from> <group-id> <text> --return <none|required> 发送群文本(跨会话时 --return 必填)
1641
- send <from> <group-id> --file <path> [--as <type>] 发送群文件
1642
- send <from> <group-id> --payload <json> 发送自定义 payload
1721
+ console.log(`用法: ec group <command> <from-aid> [args...] [options]
1722
+
1723
+ 消息:
1724
+ send <from> <group-id> <text> --return <none|required> 发送群文本(跨会话时 --return 必填)
1725
+ send <from> <group-id> --file <path> [--as <type>] 发送群文件
1726
+ send <from> <group-id> --payload <json> 发送自定义 payload
1643
1727
  pull <from> <group-id> [--after-seq N] [--limit N] --app <name> 拉取群消息(必须使用独立 slot)
1644
- ack <from> <group-id> <seq> [--app <name>] 确认已读
1645
-
1646
- 群管理:
1647
- create <from> <name> [--visibility public|private] [--description D]
1648
- [--join-mode open|approval|invite_only|closed] 创建群
1649
- list <from> [--size N] 列出我加入的群
1650
- info <from> <group-id> 查看群详情
1651
- update <from> <group-id> [--name N] [--description D] 修改群信息
1652
- dissolve <from> <group-id> 解散群
1653
- suspend <from> <group-id> 暂停群
1654
- resume <from> <group-id> 恢复群
1655
- rules <from> <group-id> get 读取已发布群规则文件 /rules.md
1656
- rules <from> <group-id> set <file> 上传并发布群规则文件
1657
- rules <from> <group-id> publish 发布当前群空间 /rules.md
1658
- rules <from> <group-id> [--mode M] [--question Q] [--max-pending N] 查看/更新入群规则
1659
-
1660
- 成员:
1661
- join <from> <group-id> [--message M] [--answer A] 申请加入
1662
- leave <from> <group-id> 退出群
1663
- invite <from> <group-id> <member-aid> [<member-aid>...] 创建定向邀请
1664
- invites <from> [--page N] [--size N] 查看收到的邀请
1665
- accept-invite <from> <invite-id> 接受邀请
1666
- reject-invite <from> <invite-id> 拒绝邀请
1667
- revoke-invite <from> <invite-id> 撤回邀请
1668
- kick <from> <group-id> <member-aid> 踢出成员
1669
- members <from> <group-id> [--page N] [--size N] 列出群成员
1670
- online <from> <group-id> 查看在线成员
1671
- role <from> <group-id> <member-aid> <admin|member> 设置成员角色
1672
- owner <from> <group-id> <new-owner-aid> 转让群主
1673
- ban <from> <group-id> [<member-aid>] [--duration N] 封禁成员;不带 member-aid 时列出封禁
1674
- unban <from> <group-id> <member-aid> 解封成员
1675
-
1676
- Options:
1677
- --app <name> 指定应用 slot(独立消费通道,不影响 daemon)
1678
- --aun-path <path> 指定 AUN keystore 根
1679
- --format json 输出 JSON 格式
1680
- --encrypt 强制端到端加密(未指定时使用 daemon 默认值;仅 send)
1681
- --no-encrypt 强制明文发送(优先于 --encrypt;仅 send)
1682
- --thread <id> 指定话题 ID(仅 send)
1683
- --return <none|required> 跨会话发送必填(仅 send;Trigger 只能使用 none)
1684
- --mention <aid> 发送时 @ 某个成员(可多次,或用逗号分隔多个 aid)
1685
- --mention-all 发送时 @ 所有人
1686
- --content-type <mime> 显式覆盖 MIME(仅 --file 模式)
1687
- --as <type> 附件类型:image|video|voice|file(仅 --file 模式)
1688
- --text <说明> 附件说明文字(仅 --file 模式)
1689
- --transcript <text> 语音转写(仅 --as voice)
1690
- --group-id <aid> 指定自定义群 AID(仅 create)
1691
- --member-type <type> 定向邀请成员类型:human|ai(仅 invite)
1692
- -- end-of-options:其后所有参数按正文处理
1693
- (用于发送恰好等于某 flag 的文本,如 send a g -- --encrypt)
1694
-
1695
- 格式示例(.example.invalid 是保留的虚构域,以下 AID 均不是真实地址):
1696
- ec group create sender.example.invalid "Dev Team" --visibility private
1697
- ec group send sender.example.invalid 12345.example.invalid "hello team" --return none
1698
- ec group send sender.example.invalid 12345.example.invalid "@member 看下 PR" --mention member.example.invalid
1699
- ec group send sender.example.invalid 12345.example.invalid --file ./arch.png
1700
- ec group rules sender.example.invalid 12345.example.invalid set ./rules.md
1701
- ec group invite sender.example.invalid 12345.example.invalid member.example.invalid
1702
- ec group members sender.example.invalid 12345.example.invalid
1703
-
1704
- 查询真实群 AID:
1705
- ec group list <发送方AID>`);
1728
+ ack <from> <group-id> <seq> [--app <name>] 确认已读
1729
+ history <from> <group-id> [--unread|--all] 查询本地群消息历史
1730
+
1731
+ 群管理:
1732
+ create <from> <name> [--visibility public|private] [--description D]
1733
+ [--join-mode open|approval|invite_only|closed] 创建群
1734
+ list <from> [--size N] 列出我加入的群
1735
+ info <from> <group-id> 查看群详情
1736
+ update <from> <group-id> [--name N] [--description D] 修改群信息
1737
+ dissolve <from> <group-id> 解散群
1738
+ suspend <from> <group-id> 暂停群
1739
+ resume <from> <group-id> 恢复群
1740
+ rules <from> <group-id> get 读取已发布群规则文件 /rules.md
1741
+ rules <from> <group-id> set <file> 上传并发布群规则文件
1742
+ rules <from> <group-id> publish 发布当前群空间 /rules.md
1743
+ rules <from> <group-id> [--mode M] [--question Q] [--max-pending N] 查看/更新入群规则
1744
+
1745
+ 成员:
1746
+ join <from> <group-id> [--message M] [--answer A] 申请加入
1747
+ leave <from> <group-id> 退出群
1748
+ invite <from> <group-id> <member-aid> [<member-aid>...] 创建定向邀请
1749
+ invites <from> [--page N] [--size N] 查看收到的邀请
1750
+ accept-invite <from> <invite-id> 接受邀请
1751
+ reject-invite <from> <invite-id> 拒绝邀请
1752
+ revoke-invite <from> <invite-id> 撤回邀请
1753
+ kick <from> <group-id> <member-aid> 踢出成员
1754
+ members <from> <group-id> [--page N] [--size N] 列出群成员
1755
+ online <from> <group-id> 查看在线成员
1756
+ role <from> <group-id> <member-aid> <admin|member> 设置成员角色
1757
+ owner <from> <group-id> <new-owner-aid> 转让群主
1758
+ ban <from> <group-id> [<member-aid>] [--duration N] 封禁成员;不带 member-aid 时列出封禁
1759
+ unban <from> <group-id> <member-aid> 解封成员
1760
+ block <from> <group-id> <member-aid> [--reason R] 屏蔽成员接收群消息
1761
+ unblock <from> <group-id> <member-aid> 取消屏蔽
1762
+ blocklist <from> <group-id> 查看屏蔽列表(群管理员)
1763
+ report-status <from> <group-id> --online-status O --work-status W 上报自己的状态
1764
+ member-statuses <from> <group-id> 查看成员上报状态(独立于 online)
1765
+
1766
+ Options:
1767
+ --app <name> 指定应用 slot(独立消费通道,不影响 daemon)
1768
+ --aun-path <path> 指定 AUN keystore 根
1769
+ --format json 输出 JSON 格式
1770
+ --encrypt 强制端到端加密(未指定时使用 daemon 默认值;仅 send)
1771
+ --no-encrypt 强制明文发送(优先于 --encrypt;仅 send)
1772
+ --thread <id> 指定话题 ID(仅 send)
1773
+ --return <none|required> 跨会话发送必填(仅 send;Trigger 只能使用 none)
1774
+ --mention <aid> 发送时 @ 某个成员(可多次,或用逗号分隔多个 aid)
1775
+ --mention-all 发送时 @ 所有人
1776
+ --content-type <mime> 显式覆盖 MIME(仅 --file 模式)
1777
+ --as <type> 附件类型:image|video|voice|file(仅 --file 模式)
1778
+ --text <说明> 附件说明文字(仅 --file 模式)
1779
+ --transcript <text> 语音转写(仅 --as voice)
1780
+ --group-id <aid> 指定自定义群 AID(仅 create);省略时生成 g- 加五位随机数字
1781
+ --member-type <type> 定向邀请成员类型:human|agent(仅 invite)
1782
+ -- end-of-options:其后所有参数按正文处理
1783
+ (用于发送恰好等于某 flag 的文本,如 send a g -- --encrypt)
1784
+
1785
+ 格式示例(.example.invalid 是保留的虚构域,以下 AID 均不是真实地址):
1786
+ ec group create sender.example.invalid "Dev Team" --visibility private
1787
+ ec group send sender.example.invalid 12345.example.invalid "hello team" --return none
1788
+ ec group send sender.example.invalid 12345.example.invalid "@member 看下 PR" --mention member.example.invalid
1789
+ ec group send sender.example.invalid 12345.example.invalid --file ./arch.png
1790
+ ec group rules sender.example.invalid 12345.example.invalid set ./rules.md
1791
+ ec group invite sender.example.invalid 12345.example.invalid member.example.invalid
1792
+ ec group members sender.example.invalid 12345.example.invalid
1793
+
1794
+ 查询真实群 AID:
1795
+ ec group list <发送方AID>
1796
+
1797
+ 群 AID 使用 base.issuer(如 ontology.example.invalid、g-12345.example.invalid)。
1798
+ 群命令支持本域 base 简写;不再支持 group.issuer/base 或 base@issuer。
1799
+ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g-99999。`);
1706
1800
  return;
1707
1801
  }
1708
1802
  const from = args[1];
@@ -1719,13 +1813,55 @@ Options:
1719
1813
  printGroupSendAidHint();
1720
1814
  process.exit(1);
1721
1815
  }
1722
- if (process.env.EVOLCORE_SESSION_ID && sub !== 'send') {
1816
+ if ((process.env.EVOLCORE_SESSION_ID || (sub === 'history' && readDelegationCredential())) && sub !== 'send') {
1723
1817
  const result = await runManagedGroup(args, formatJson);
1724
1818
  renderManagedGroupResult(args, result, formatJson);
1725
1819
  return;
1726
1820
  }
1727
- const { groupSend, groupPull, groupAck, groupCreate, groupInfo, groupList, groupUpdate, groupDissolve, groupSuspend, groupResume, groupJoin, groupLeave, groupInvite, groupInvites, groupAcceptInvite, groupRejectInvite, groupRevokeInvite, groupKick, groupMembers, groupOnline, groupSetRole, groupTransferOwner, groupBan, groupUnban, groupBanlist, groupRules, groupUpdateRules, groupRulesFileGet, groupRulesFileSet, groupRulesFilePublish, } = await import('../aun/msg/index.js');
1821
+ const { groupSend, groupPull, groupAck, groupHistory, parseGroupHistoryArgs, groupCreate, groupInfo, groupList, groupUpdate, groupDissolve, groupSuspend, groupResume, groupJoin, groupLeave, groupInvite, groupInvites, groupAcceptInvite, groupRejectInvite, groupRevokeInvite, groupKick, groupMembers, groupOnline, groupSetRole, groupTransferOwner, groupBan, groupUnban, groupBanlist, groupBlock, groupUnblock, groupBlocklist, groupReportStatus, groupMemberStatuses, groupRules, groupUpdateRules, groupRulesFileGet, groupRulesFileSet, groupRulesFilePublish, } = await import('../aun/msg/index.js');
1728
1822
  const commonOpts = { aunPath, slotId: appSlot };
1823
+ if (['block', 'unblock', 'blocklist', 'report-status', 'member-statuses'].includes(sub)) {
1824
+ // Share validation with the daemon; standalone connection options stay local.
1825
+ const operationArgs = [];
1826
+ for (let i = 0; i < args.length; i++) {
1827
+ if (args[i] === '--aun-path' || args[i] === '--app') {
1828
+ if (args[i + 1] === undefined || args[i + 1].startsWith('--')) {
1829
+ failManagedGroup(formatJson, 'INVALID_ARGUMENT', `${args[i]} requires a value`);
1830
+ }
1831
+ i++;
1832
+ }
1833
+ else {
1834
+ operationArgs.push(args[i]);
1835
+ }
1836
+ }
1837
+ const { resolveManagedGroupOperation } = await import('../aun/msg/managed-operation.js');
1838
+ const parsed = resolveManagedGroupOperation(operationArgs);
1839
+ if (!parsed.ok)
1840
+ failManagedGroup(formatJson, parsed.code, parsed.reason);
1841
+ const command = parsed.command;
1842
+ const base = { from: command.from, groupId: command.groupId, ...commonOpts };
1843
+ let result;
1844
+ switch (sub) {
1845
+ case 'block':
1846
+ result = await groupBlock({ ...base, memberAid: command.memberAid, reason: command.reason });
1847
+ break;
1848
+ case 'unblock':
1849
+ result = await groupUnblock({ ...base, memberAid: command.memberAid });
1850
+ break;
1851
+ case 'blocklist':
1852
+ result = await groupBlocklist(base);
1853
+ break;
1854
+ case 'report-status':
1855
+ result = await groupReportStatus({ ...base, onlineStatus: command.onlineStatus, workStatus: command.workStatus });
1856
+ break;
1857
+ default:
1858
+ result = await groupMemberStatuses(base);
1859
+ }
1860
+ if (!result.ok)
1861
+ failManagedGroup(formatJson, result.code ?? 'GROUP_OPERATION_FAILED', result.error);
1862
+ renderManagedGroupResult(operationArgs, result, formatJson);
1863
+ return;
1864
+ }
1729
1865
  // 通用 group_id 提取(第三参数)
1730
1866
  const requireGroupId = () => {
1731
1867
  const gid = args[2];
@@ -1734,12 +1870,14 @@ Options:
1734
1870
  printGroupSendAidHint();
1735
1871
  process.exit(1);
1736
1872
  }
1737
- if (!isExplicitGroupId(gid)) {
1738
- console.error(`❌ 第 2 个位置参数 <group-aid> 不是有效群 AID: ${gid}`);
1873
+ try {
1874
+ return normalizeGroupAid(gid, from.slice(from.indexOf('.') + 1));
1875
+ }
1876
+ catch (error) {
1877
+ console.error(`❌ 第 2 个位置参数 <group-aid> 不是有效群 AID: ${gid}: ${error.message}`);
1739
1878
  printGroupSendAidHint();
1740
1879
  process.exit(1);
1741
1880
  }
1742
- return gid;
1743
1881
  };
1744
1882
  // 收集 --mention(可多次;每次的值支持逗号分隔多个 aid)
1745
1883
  const collectMentions = () => {
@@ -1852,6 +1990,16 @@ Options:
1852
1990
  return parts.join(' ');
1853
1991
  };
1854
1992
  // ---- 消息 ----
1993
+ if (sub === 'history') {
1994
+ try {
1995
+ const result = groupHistory(parseGroupHistoryArgs(args));
1996
+ renderManagedGroupResult(args, result, formatJson);
1997
+ }
1998
+ catch (error) {
1999
+ failManagedGroup(formatJson, error.code || 'HISTORY_READ_FAILED', error instanceof Error ? error.message : String(error));
2000
+ }
2001
+ return;
2002
+ }
1855
2003
  if (sub === 'send') {
1856
2004
  const groupId = requireGroupId();
1857
2005
  // Group sends use the dedicated AUN message daemon route rather than the
@@ -2049,9 +2197,11 @@ Options:
2049
2197
  });
2050
2198
  outputResult(result, () => {
2051
2199
  const r = result;
2052
- console.log(`✓ 已创建群 ${r.group?.group_id}`);
2200
+ console.log(`✓ 已创建群 ${r.group?.group_aid ?? r.group?.group_id}`);
2053
2201
  console.log(` 名称: ${r.group?.name}`);
2054
2202
  console.log(` 可见性: ${r.group?.visibility}`);
2203
+ if (r.warning)
2204
+ console.warn(r.warning);
2055
2205
  });
2056
2206
  return;
2057
2207
  }
@@ -2133,18 +2283,18 @@ Options:
2133
2283
  const groupId = requireGroupId();
2134
2284
  const action = args[3];
2135
2285
  const printRulesFileUsage = () => {
2136
- console.log(`用法:
2137
- ec group rules <from> <group-id> get
2138
- ec group rules <from> <group-id> set <file>
2139
- ec group rules <from> <group-id> publish
2140
- ec group rules <from> <group-id> [--mode open|approval|invite_only|closed] [--question Q] [--max-pending N]
2141
-
2142
- 说明:
2143
- get 读取当前已发布的群规则文件 /rules.md
2144
- set 上传本地文件到群空间 /rules.md,发布 rules.content 元数据,并发送 group.rules.updated 通知
2145
- publish 不上传文件,仅发布当前群空间 /rules.md 的元数据并发送通知
2146
-
2147
- 兼容:
2286
+ console.log(`用法:
2287
+ ec group rules <from> <group-id> get
2288
+ ec group rules <from> <group-id> set <file>
2289
+ ec group rules <from> <group-id> publish
2290
+ ec group rules <from> <group-id> [--mode open|approval|invite_only|closed] [--question Q] [--max-pending N]
2291
+
2292
+ 说明:
2293
+ get 读取当前已发布的群规则文件 /rules.md
2294
+ set 上传本地文件到群空间 /rules.md,发布 rules.content 元数据,并发送 group.rules.updated 通知
2295
+ publish 不上传文件,仅发布当前群空间 /rules.md 的元数据并发送通知
2296
+
2297
+ 兼容:
2148
2298
  不带 get/set/publish 时仍使用旧的入群规则接口。`);
2149
2299
  };
2150
2300
  const printRulesFileState = (result, verb) => {
@@ -2292,8 +2442,8 @@ Options:
2292
2442
  }
2293
2443
  }
2294
2444
  const memberType = getArgValue(args, '--member-type');
2295
- if (memberType !== undefined && memberType !== 'human' && memberType !== 'ai') {
2296
- console.error('❌ --member-type 必须是 human 或 ai');
2445
+ if (memberType !== undefined && memberType !== 'human' && memberType !== 'agent') {
2446
+ console.error('❌ --member-type 必须是 human 或 agent');
2297
2447
  process.exit(1);
2298
2448
  }
2299
2449
  const result = await groupInvite({ from, groupId, members, memberType: memberType, ...commonOpts });
@@ -2449,7 +2599,7 @@ Options:
2449
2599
  });
2450
2600
  return;
2451
2601
  }
2452
- console.error(`未知子命令: ${sub}\n用法: ec group [send|pull|ack|create|list|info|update|dissolve|suspend|resume|rules|join|leave|invite|invites|accept-invite|reject-invite|revoke-invite|kick|members|online|role|owner|ban|unban]`);
2602
+ console.error(`未知子命令: ${sub}\n用法: ec group [send|pull|ack|history|create|list|info|update|dissolve|suspend|resume|rules|join|leave|invite|invites|accept-invite|reject-invite|revoke-invite|kick|members|online|role|owner|ban|unban|block|unblock|blocklist|report-status|member-statuses]`);
2453
2603
  process.exit(1);
2454
2604
  }
2455
2605
  // ==================== Main ====================
@@ -2472,7 +2622,7 @@ const VALUE_FLAGS = new Set([
2472
2622
  '--as', '--content-type', '--mention', '--visibility', '--join-mode',
2473
2623
  '--group-id', '--name', '--message', '--answer', '--page', '--size',
2474
2624
  '--member-type',
2475
- '--aun-path', '--thread', '--return',
2625
+ '--aun-path', '--thread', '--return', '--handoff-context',
2476
2626
  ]);
2477
2627
  const BOOLEAN_FLAGS = new Set([
2478
2628
  '--encrypt', '--no-encrypt', '--mention-all',