evolcore 0.0.22 → 0.0.24

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 (117) hide show
  1. package/CHANGELOG.md +74 -14
  2. package/README.md +4 -0
  3. package/bin/codex-managed-acl.ps1 +160 -0
  4. package/bin/codex-managed-hook.mjs +127 -10
  5. package/bin/ec-safe-output.js +85 -3
  6. package/bin/install-codex-managed-hooks.mjs +384 -95
  7. package/dist/agents/baseagent-availability.js +48 -0
  8. package/dist/agents/baseagent.js +30 -2
  9. package/dist/agents/claude-runner.js +179 -240
  10. package/dist/agents/{codex-app-server-client.js → codex/app-server-client.js} +90 -20
  11. package/dist/{utils/codex-app-server-registry.js → agents/codex/app-server-registry.js} +2 -2
  12. package/dist/agents/codex/catalog.js +70 -0
  13. package/dist/agents/codex/diagnostics.js +369 -0
  14. package/dist/agents/codex-runner.js +839 -192
  15. package/dist/agents/ecagent-runner.js +27 -34
  16. package/dist/agents/gemini-runner.js +62 -8
  17. package/dist/agents/runner-types.js +1 -1
  18. package/dist/aun/aid/managed-operation.js +28 -6
  19. package/dist/aun/aid/store.js +43 -0
  20. package/dist/aun/menu-client.js +272 -0
  21. package/dist/aun/msg/group.js +65 -4
  22. package/dist/aun/msg/index.js +1 -1
  23. package/dist/aun/msg/managed-operation.js +57 -5
  24. package/dist/aun/outbox.js +56 -18
  25. package/dist/aun/rpc/client.js +7 -1
  26. package/dist/channels/aun.js +178 -77
  27. package/dist/channels/daemon.js +7 -1
  28. package/dist/channels/dingtalk.js +1 -0
  29. package/dist/channels/feishu.js +10 -4
  30. package/dist/channels/wechat.js +81 -10
  31. package/dist/channels/wecom.js +2 -1
  32. package/dist/cli/agent-command.js +29 -3
  33. package/dist/cli/agent-create.js +538 -0
  34. package/dist/cli/agent.js +26 -675
  35. package/dist/cli/aun-commands.js +108 -24
  36. package/dist/cli/command-log.js +21 -2
  37. package/dist/cli/ctl-command.js +2 -0
  38. package/dist/cli/daemon-commands.js +289 -61
  39. package/dist/cli/index.js +22 -2
  40. package/dist/cli/init.js +2 -10
  41. package/dist/cli/managed-command-guard.js +3 -0
  42. package/dist/cli/menu-client.js +95 -0
  43. package/dist/cli/model.js +23 -8
  44. package/dist/cli/restart-monitor.js +432 -8
  45. package/dist/cli/stats.js +110 -0
  46. package/dist/cli/task-context.js +12 -2
  47. package/dist/cli/trigger-command.js +9 -1
  48. package/dist/config/builtin-roles.js +2 -0
  49. package/dist/config/schema-migration.js +14 -2
  50. package/dist/core/auth/agent-delegation.js +10 -7
  51. package/dist/core/auth/auth-gateway.js +3 -2
  52. package/dist/core/auth/authorization-audit.js +75 -18
  53. package/dist/core/auth/operation-authorizer.js +63 -3
  54. package/dist/core/auth/operation-catalog.js +14 -2
  55. package/dist/core/auth/remote-access-store.js +136 -0
  56. package/dist/core/baseagent-loader.js +4 -4
  57. package/dist/core/bootstrap-messages.js +39 -18
  58. package/dist/core/bootstrap-service.js +32 -26
  59. package/dist/core/capability/capability-manager.js +8 -4
  60. package/dist/core/capability/providers/codex-capability-provider.js +1 -1
  61. package/dist/core/command/agent-control.js +7 -2
  62. package/dist/core/command/command-handler.js +128 -30
  63. package/dist/core/command/daemon-diagnostics.js +448 -0
  64. package/dist/core/command/menu-catalog.js +6 -1
  65. package/dist/core/command/menu-handler.js +410 -98
  66. package/dist/core/command/menu-protocol.js +123 -0
  67. package/dist/core/command/slash-gate.js +4 -6
  68. package/dist/core/command/slash-handler.js +199 -70
  69. package/dist/core/data-migration.js +5 -15
  70. package/dist/core/event-catalog.js +3 -0
  71. package/dist/core/handoff/runtime.js +3 -1
  72. package/dist/core/handoff/store.js +7 -1
  73. package/dist/core/message/im-renderer.js +13 -6
  74. package/dist/core/message/message-bridge.js +5 -36
  75. package/dist/core/message/message-queue.js +20 -15
  76. package/dist/core/message/message-utils.js +6 -3
  77. package/dist/core/message/response-engine.js +147 -94
  78. package/dist/core/model/catalog-service.js +310 -0
  79. package/dist/core/model/model-catalog.js +134 -334
  80. package/dist/core/model/model-diagnostics.js +4 -5
  81. package/dist/core/model/model-fallback.js +9 -16
  82. package/dist/core/model/model-permission.js +5 -2
  83. package/dist/core/permission/approval-gateway.js +183 -32
  84. package/dist/core/permission/protected-paths.js +63 -4
  85. package/dist/core/permission/sandbox-runtime.js +4 -2
  86. package/dist/core/permission/tool-policy.js +257 -31
  87. package/dist/core/runtime-lock.js +13 -8
  88. package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
  89. package/dist/core/session/session-manager.js +49 -13
  90. package/dist/core/session/session-renew.js +1 -0
  91. package/dist/index.js +214 -57
  92. package/dist/ipc.js +191 -102
  93. package/dist/paths.js +23 -1
  94. package/dist/stats/billing.js +18 -4
  95. package/dist/trigger/manager.js +3 -1
  96. package/dist/trigger/parser.js +77 -13
  97. package/dist/trigger/patch.js +104 -1
  98. package/dist/utils/atomic-write.js +26 -2
  99. package/dist/utils/cross-platform.js +436 -1
  100. package/dist/utils/ecweb-supervisor.js +11 -2
  101. package/dist/utils/ecweb-utils.js +8 -26
  102. package/dist/utils/error-utils.js +16 -2
  103. package/dist/utils/model-prices.jsonl +23 -20
  104. package/dist/utils/npm-ops.js +70 -15
  105. package/dist/utils/windows-autostart.js +1 -1
  106. package/kits/docs/evolcore/INDEX.md +1 -0
  107. package/kits/docs/evolcore/agent-create.md +13 -0
  108. package/kits/docs/evolcore/group-collaboration.md +7 -2
  109. package/kits/docs/evolcore/menu-client.md +34 -0
  110. package/kits/migrations/migrate-contact-book-v2.mjs +9 -1
  111. package/kits/migrations/migrate-role-config-v4.mjs +11 -5
  112. package/kits/migrations/migrate-role-config-v5.mjs +8 -2
  113. package/kits/templates/roles/admin.json +2 -0
  114. package/kits/templates/roles/visitor.json +1 -0
  115. package/kits/templates/system-fragments/bootstrap.md +8 -1
  116. package/package.json +16 -4
  117. package/dist/utils/codex-cli.js +0 -43
@@ -5,6 +5,7 @@ import { isExplicitGroupId } from '../aun/group-identity.js';
5
5
  import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
6
6
  import { ipcQuery } from '../ipc.js';
7
7
  import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
8
+ import { isManagementRole } from '../config/builtin-roles.js';
8
9
  import { readBestTaskRuntimeContext } from './task-context.js';
9
10
  // ==================== AID ====================
10
11
  function resolveAunPath(args) {
@@ -13,24 +14,35 @@ function resolveAunPath(args) {
13
14
  return args[idx + 1];
14
15
  return process.env.AUN_HOME || undefined;
15
16
  }
17
+ function isRedactedAidShowResult(info) {
18
+ return 'redacted' in info && info.redacted === true;
19
+ }
16
20
  function renderAidShow(info, formatJson) {
17
21
  if (formatJson) {
18
22
  console.log(JSON.stringify(info, null, 2));
19
23
  return;
20
24
  }
21
25
  console.log(`AID: ${info.aid}`);
22
- console.log(` 私钥: ${info.hasPrivateKey ? '有' : '无'}`);
26
+ const redacted = isRedactedAidShowResult(info);
27
+ if (!redacted) {
28
+ console.log(` 私钥: ${info.hasPrivateKey ? '有' : '无'}`);
29
+ }
23
30
  console.log(` agent.md: ${info.hasAgentMd ? '有' : '无'}`);
24
31
  if (info.hasAgentMd) {
32
+ const signatureReason = redacted ? undefined : info.agentMdSignatureReason;
25
33
  const sigLabel = info.agentMdSignature === 'verified' ? '✓ 已验签'
26
34
  : info.agentMdSignature === 'unsigned' ? '⚠ 未签名'
27
- : info.agentMdSignature === 'invalid' ? `✗ 签名无效${info.agentMdSignatureReason ? ': ' + info.agentMdSignatureReason : ''}`
35
+ : info.agentMdSignature === 'invalid' ? `✗ 签名无效${signatureReason ? ': ' + signatureReason : ''}`
28
36
  : '? 未知';
29
37
  console.log(` 签名状态: ${sigLabel}`);
30
38
  }
31
39
  console.log(` 证书到期: ${info.certExpiresAt ?? '无证书'}${info.certExpired ? ' (已过期!)' : ''}`);
32
40
  if (info.certSubject)
33
41
  console.log(` 证书主体: ${info.certSubject}`);
42
+ if (redacted) {
43
+ console.log(' 本地密钥状态: 已脱敏');
44
+ return;
45
+ }
34
46
  if (info.keyMatchesCert === false)
35
47
  console.log(' 密钥/证书: ✗ 公钥不匹配(cert.pem 与 key.json 公钥不一致)');
36
48
  else if (info.keyMatchesCert === true)
@@ -104,7 +116,8 @@ async function runManagedAid(args, formatJson) {
104
116
  if (!parsed.ok)
105
117
  failManagedAid(formatJson, parsed.code, parsed.reason);
106
118
  const runtime = await readBestTaskRuntimeContext();
107
- if (runtime?.selfAid && parsed.command.aid !== runtime.selfAid.replace(/^@/, '')) {
119
+ const requiresSelfAid = parsed.command.kind === 'show' || parsed.command.kind === 'agentmd.put';
120
+ if (requiresSelfAid && runtime?.selfAid && parsed.command.aid !== runtime.selfAid.replace(/^@/, '')) {
108
121
  failManagedAid(formatJson, 'SCOPE_MISMATCH', `托管任务只能操作当前 self AID:${runtime.selfAid}`);
109
122
  }
110
123
  const response = await ipcQuery(resolvePaths().socket, {
@@ -212,7 +225,12 @@ async function runManagedMsg(args, formatJson) {
212
225
  if (runtime && (runtime.channel !== 'aun' || runtime.chatType !== 'private')) {
213
226
  failManagedGroup(formatJson, 'SCOPE_MISMATCH', 'ec msg history/online 只能读取当前 AUN 私聊关系');
214
227
  }
215
- if (runtime?.channelId && parsed.command.target !== runtime.channelId.replace(/^@/, '')) {
228
+ // owner/admin 可以跨对端读历史(每次查询仍只针对一个对端)。这里只是快速
229
+ // 预检:角色未知时放行交给 daemon 判定,daemon 侧 handleMsgOperation 才是
230
+ // 权威关卡,member 由 currentRelationOnly 约束、visitor 直接拒绝。
231
+ const mayReadCrossPeer = parsed.command.kind === 'history'
232
+ && (runtime?.peerRole === undefined || isManagementRole(runtime.peerRole));
233
+ if (!mayReadCrossPeer && runtime?.channelId && parsed.command.target !== runtime.channelId.replace(/^@/, '')) {
216
234
  failManagedGroup(formatJson, 'SCOPE_MISMATCH', `只能读取当前 AUN 私聊对端:${runtime.channelId}`);
217
235
  }
218
236
  }
@@ -299,6 +317,14 @@ function renderManagedGroupResult(args, result, formatJson) {
299
317
  console.log(`✓ 成功 ${result.added?.length ?? 0},失败 ${result.failed?.length ?? 0}`);
300
318
  return;
301
319
  }
320
+ if (sub === 'invites') {
321
+ console.log(`✓ ${result.invites?.length ?? 0} 个待处理邀请`);
322
+ return;
323
+ }
324
+ if (sub === 'accept-invite' || sub === 'reject-invite' || sub === 'revoke-invite') {
325
+ console.log(`✓ group ${sub} 完成`);
326
+ return;
327
+ }
302
328
  console.log(`✓ group ${sub} 完成`);
303
329
  }
304
330
  export async function cmdAid(args) {
@@ -1045,7 +1071,7 @@ Commands:
1045
1071
  send <from> <to> --file <path> [--as <type>] 发送文件(image|video|voice|file)
1046
1072
  send <from> <to> --link <url> [--title T] 发送链接卡片
1047
1073
  send <from> <to> --payload <json> 发送自定义 payload
1048
- pull <from> [--after-seq N] [--limit N] 拉取收件箱
1074
+ pull <from> [--after-seq N] [--limit N] --app <name> 拉取收件箱(必须使用独立 slot)
1049
1075
  ack <from> <seq> [--app <name>] 确认已读
1050
1076
  recall <from> <message-id> [<message-id>...] 撤回消息
1051
1077
  online <from> <target-aid> [<target-aid>...] 查询在线状态
@@ -1134,6 +1160,20 @@ Options:
1134
1160
  }
1135
1161
  const { msgSend, msgPull, msgAck, msgRecall, msgOnline, msgHistory } = await import('../aun/msg/index.js');
1136
1162
  const commonOpts = { aunPath, slotId: appSlot };
1163
+ const requireConsumerSlot = (operation) => {
1164
+ if (appSlot)
1165
+ return appSlot;
1166
+ const error = {
1167
+ ok: false,
1168
+ code: 'APP_SLOT_REQUIRED',
1169
+ error: `${operation} requires an explicit --app <name> isolated consumer slot; refusing to access the daemon inbox`,
1170
+ };
1171
+ if (formatJson)
1172
+ console.log(JSON.stringify(error));
1173
+ else
1174
+ console.error(`❌ ${error.error}`);
1175
+ process.exit(1);
1176
+ };
1137
1177
  if (sub === 'history') {
1138
1178
  const target = args[2] && !args[2].startsWith('--') ? args[2] : undefined;
1139
1179
  const historyValueFlags = new Set([
@@ -1381,9 +1421,7 @@ Options:
1381
1421
  return;
1382
1422
  }
1383
1423
  if (sub === 'pull') {
1384
- if (!appSlot) {
1385
- console.warn('⚠ 警告: 未传 --app,当前与 daemon 共享 evolcore 消费通道。pull 会看到/影响 daemon 的消息消费;如需独立消费请用 --app <name>');
1386
- }
1424
+ const consumerSlot = requireConsumerSlot('ec msg pull');
1387
1425
  const afterSeqStr = getArgValue(args, '--after-seq');
1388
1426
  const limitStr = getArgValue(args, '--limit');
1389
1427
  const afterSeq = afterSeqStr !== undefined ? Number(afterSeqStr) : undefined;
@@ -1396,7 +1434,7 @@ Options:
1396
1434
  console.error(`❌ --limit 必须是数字: ${limitStr}`);
1397
1435
  process.exit(1);
1398
1436
  }
1399
- const result = await msgPull({ from, afterSeq, limit, ...commonOpts });
1437
+ const result = await msgPull({ from, afterSeq, limit, aunPath, slotId: consumerSlot });
1400
1438
  if (!result.ok) {
1401
1439
  if (formatJson) {
1402
1440
  console.log(JSON.stringify(result));
@@ -1432,10 +1470,8 @@ Options:
1432
1470
  console.error(`❌ seq 必须是数字: ${seqStr}`);
1433
1471
  process.exit(1);
1434
1472
  }
1435
- if (!appSlot) {
1436
- console.warn('⚠ 警告: 未传 --app,ack 将推进与 daemon 共享的 evolcore 消费游标,可能影响 daemon 收消息;如需独立请用 --app <name>');
1437
- }
1438
- const result = await msgAck({ from, seq, ...commonOpts });
1473
+ const consumerSlot = requireConsumerSlot('ec msg ack');
1474
+ const result = await msgAck({ from, seq, aunPath, slotId: consumerSlot });
1439
1475
  if (!result.ok) {
1440
1476
  if (formatJson) {
1441
1477
  console.log(JSON.stringify(result));
@@ -1538,7 +1574,7 @@ export async function cmdGroup(args) {
1538
1574
  send <from> <group-id> <text> --return <none|required> 发送群文本(跨会话时 --return 必填)
1539
1575
  send <from> <group-id> --file <path> [--as <type>] 发送群文件
1540
1576
  send <from> <group-id> --payload <json> 发送自定义 payload
1541
- pull <from> <group-id> [--after-seq N] [--limit N] 拉取群消息
1577
+ pull <from> <group-id> [--after-seq N] [--limit N] --app <name> 拉取群消息(必须使用独立 slot)
1542
1578
  ack <from> <group-id> <seq> [--app <name>] 确认已读
1543
1579
 
1544
1580
  群管理:
@@ -1558,7 +1594,11 @@ export async function cmdGroup(args) {
1558
1594
  成员:
1559
1595
  join <from> <group-id> [--message M] [--answer A] 申请加入
1560
1596
  leave <from> <group-id> 退出群
1561
- invite <from> <group-id> <member-aid> [<member-aid>...] 邀请成员
1597
+ invite <from> <group-id> <member-aid> [<member-aid>...] 创建定向邀请
1598
+ invites <from> [--page N] [--size N] 查看收到的邀请
1599
+ accept-invite <from> <invite-id> 接受邀请
1600
+ reject-invite <from> <invite-id> 拒绝邀请
1601
+ revoke-invite <from> <invite-id> 撤回邀请
1562
1602
  kick <from> <group-id> <member-aid> 踢出成员
1563
1603
  members <from> <group-id> [--page N] [--size N] 列出群成员
1564
1604
  online <from> <group-id> 查看在线成员
@@ -1582,6 +1622,7 @@ Options:
1582
1622
  --text <说明> 附件说明文字(仅 --file 模式)
1583
1623
  --transcript <text> 语音转写(仅 --as voice)
1584
1624
  --group-id <aid> 指定自定义群 AID(仅 create)
1625
+ --member-type <type> 定向邀请成员类型:human|ai(仅 invite)
1585
1626
  -- end-of-options:其后所有参数按正文处理
1586
1627
  (用于发送恰好等于某 flag 的文本,如 send a g -- --encrypt)
1587
1628
 
@@ -1617,7 +1658,7 @@ Options:
1617
1658
  renderManagedGroupResult(args, result, formatJson);
1618
1659
  return;
1619
1660
  }
1620
- const { groupSend, groupPull, groupAck, groupCreate, groupInfo, groupList, groupUpdate, groupDissolve, groupSuspend, groupResume, groupJoin, groupLeave, groupInvite, groupKick, groupMembers, groupOnline, groupSetRole, groupTransferOwner, groupBan, groupUnban, groupBanlist, groupRules, groupUpdateRules, groupRulesFileGet, groupRulesFileSet, groupRulesFilePublish, } = await import('../aun/msg/index.js');
1661
+ 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');
1621
1662
  const commonOpts = { aunPath, slotId: appSlot };
1622
1663
  // 通用 group_id 提取(第三参数)
1623
1664
  const requireGroupId = () => {
@@ -1693,6 +1734,31 @@ Options:
1693
1734
  }
1694
1735
  return parsed;
1695
1736
  };
1737
+ if (sub === 'invites') {
1738
+ const page = parseNumberFlag('--page', '--page');
1739
+ const size = parseNumberFlag('--size', '--size');
1740
+ const result = await groupInvites({ from, page, size, ...commonOpts });
1741
+ outputResult(result, () => {
1742
+ const r = result;
1743
+ console.log(`✓ ${r.invites.length} 个待处理邀请:`);
1744
+ for (const invite of r.invites) {
1745
+ console.log(` ${invite.invite_id ?? invite.id ?? '-'} ${invite.group_id ?? invite.group_aid ?? '-'} ${invite.inviter_aid ?? invite.from ?? '-'}`);
1746
+ }
1747
+ });
1748
+ return;
1749
+ }
1750
+ if (sub === 'accept-invite' || sub === 'reject-invite' || sub === 'revoke-invite') {
1751
+ const inviteId = args[2];
1752
+ if (!inviteId || inviteId.startsWith('--')) {
1753
+ console.error(`用法: ec group ${sub} <from> <invite-id>`);
1754
+ process.exit(1);
1755
+ }
1756
+ const action = sub === 'accept-invite' ? groupAcceptInvite
1757
+ : sub === 'reject-invite' ? groupRejectInvite : groupRevokeInvite;
1758
+ const result = await action({ from, inviteId, ...commonOpts });
1759
+ outputResult(result, () => console.log(`✓ 已${sub === 'accept-invite' ? '接受' : sub === 'reject-invite' ? '拒绝' : '撤回'}邀请 ${inviteId}`));
1760
+ return;
1761
+ }
1696
1762
  const requireFlagValue = (flag, label) => {
1697
1763
  const value = getArgValue(args, flag);
1698
1764
  if (value === undefined || value.startsWith('--')) {
@@ -1839,12 +1905,18 @@ Options:
1839
1905
  }
1840
1906
  if (sub === 'pull') {
1841
1907
  const groupId = requireGroupId();
1842
- if (!appSlot) {
1843
- console.warn('⚠ 警告: 未传 --app,当前与 daemon 共享 evolcore 消费通道。pull 会看到/影响 daemon 的消息消费;如需独立消费请用 --app <name>');
1908
+ const consumerSlot = appSlot;
1909
+ if (!consumerSlot) {
1910
+ const error = 'ec group pull requires an explicit --app <name> isolated consumer slot; refusing to access the daemon inbox';
1911
+ if (formatJson)
1912
+ console.log(JSON.stringify({ ok: false, code: 'APP_SLOT_REQUIRED', error }));
1913
+ else
1914
+ console.error(`❌ ${error}`);
1915
+ process.exit(1);
1844
1916
  }
1845
1917
  const afterSeq = parseNumberFlag('--after-seq', '--after-seq');
1846
1918
  const limit = parseNumberFlag('--limit', '--limit');
1847
- const result = await groupPull({ from, groupId, afterSeq, limit, ...commonOpts });
1919
+ const result = await groupPull({ from, groupId, afterSeq, limit, aunPath, slotId: consumerSlot });
1848
1920
  outputResult(result, () => {
1849
1921
  const r = result;
1850
1922
  console.log(`✓ ${r.messages.length} 条消息,latest_seq=${r.latest_message_seq}${r.has_more ? '(还有更多)' : ''}`);
@@ -1867,10 +1939,16 @@ Options:
1867
1939
  console.error(`❌ seq 必须是数字: ${seqStr}`);
1868
1940
  process.exit(1);
1869
1941
  }
1870
- if (!appSlot) {
1871
- console.warn('⚠ 警告: 未传 --app,ack 将推进与 daemon 共享的 evolcore 消费游标,可能影响 daemon 收消息;如需独立请用 --app <name>');
1942
+ const consumerSlot = appSlot;
1943
+ if (!consumerSlot) {
1944
+ const error = 'ec group ack requires an explicit --app <name> isolated consumer slot; refusing to access the daemon inbox';
1945
+ if (formatJson)
1946
+ console.log(JSON.stringify({ ok: false, code: 'APP_SLOT_REQUIRED', error }));
1947
+ else
1948
+ console.error(`❌ ${error}`);
1949
+ process.exit(1);
1872
1950
  }
1873
- const result = await groupAck({ from, groupId, seq, ...commonOpts });
1951
+ const result = await groupAck({ from, groupId, seq, aunPath, slotId: consumerSlot });
1874
1952
  outputResult(result, () => {
1875
1953
  const r = result;
1876
1954
  console.log(`✓ ack_seq=${r.ack_seq}`);
@@ -2147,7 +2225,12 @@ Options:
2147
2225
  process.exit(1);
2148
2226
  }
2149
2227
  }
2150
- const result = await groupInvite({ from, groupId, members, ...commonOpts });
2228
+ const memberType = getArgValue(args, '--member-type');
2229
+ if (memberType !== undefined && memberType !== 'human' && memberType !== 'ai') {
2230
+ console.error('❌ --member-type 必须是 human 或 ai');
2231
+ process.exit(1);
2232
+ }
2233
+ const result = await groupInvite({ from, groupId, members, memberType: memberType, ...commonOpts });
2151
2234
  outputResult(result, () => {
2152
2235
  const r = result;
2153
2236
  console.log(`✓ 成功 ${r.added.length},失败 ${r.failed.length}`);
@@ -2300,7 +2383,7 @@ Options:
2300
2383
  });
2301
2384
  return;
2302
2385
  }
2303
- console.error(`未知子命令: ${sub}\n用法: ec group [send|pull|ack|create|list|info|update|dissolve|suspend|resume|rules|join|leave|invite|kick|members|online|role|owner|ban|unban]`);
2386
+ 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]`);
2304
2387
  process.exit(1);
2305
2388
  }
2306
2389
  // ==================== Main ====================
@@ -2322,6 +2405,7 @@ const VALUE_FLAGS = new Set([
2322
2405
  '--payload', '--title', '--description', '--text', '--transcript',
2323
2406
  '--as', '--content-type', '--mention', '--visibility', '--join-mode',
2324
2407
  '--group-id', '--name', '--message', '--answer', '--page', '--size',
2408
+ '--member-type',
2325
2409
  '--aun-path', '--thread', '--return',
2326
2410
  ]);
2327
2411
  const BOOLEAN_FLAGS = new Set([
@@ -59,8 +59,8 @@ export function logCliCommand(cmd, args) {
59
59
  const line = JSON.stringify({
60
60
  ts: localTimestamp(),
61
61
  cmd,
62
- // 完整命令行,可直接拷贝执行(含 ec 前缀,含空格的参数自动加引号)
63
- command: `ec ${args.map(shellQuote).join(' ')}`,
62
+ // 可审计命令行(敏感参数掩码;含 ec 前缀,含空格参数自动加引号)
63
+ command: `ec ${loggableArgs(args).map(shellQuote).join(' ')}`,
64
64
  selfAid: selfAid || undefined,
65
65
  sessionId: process.env.EVOLCORE_SESSION_ID || undefined,
66
66
  }) + '\n';
@@ -82,6 +82,25 @@ function shellQuote(arg) {
82
82
  return arg;
83
83
  return `'${arg.replace(/'/g, `'\\''`)}'`;
84
84
  }
85
+ function loggableArgs(args) {
86
+ const output = [];
87
+ let redactNext = false;
88
+ for (const arg of args) {
89
+ if (redactNext) {
90
+ output.push('[REDACTED]');
91
+ redactNext = false;
92
+ continue;
93
+ }
94
+ const flag = arg.replace(/^--?/, '').replace(/=.*$/, '').toLowerCase();
95
+ if (/^(?:remote-token|ecweb-token|menu-token|token|password|secret)$/.test(flag)) {
96
+ output.push(arg.includes('=') ? `${arg.slice(0, arg.indexOf('=') + 1)}[REDACTED]` : arg);
97
+ redactNext = !arg.includes('=');
98
+ continue;
99
+ }
100
+ output.push(arg.replace(/((?:"|')?(?:ecweb[_-]?token|menu[_-]?token|access[_-]?token|refresh[_-]?token|password|secret)(?:"|')?\s*[:=]\s*)("(?:[^"\\]|\\.)*"|'[^']*'|[^,}\s]+)/gi, '$1"[REDACTED]"'));
101
+ }
102
+ return output;
103
+ }
85
104
  /** 本地日期 tag YYYYMMDD,用于日志文件按天切分(一天一个文件)。 */
86
105
  function dayTag() {
87
106
  const d = new Date();
@@ -7,6 +7,7 @@ const CTL_HELP = `用法: ec ctl <command> [args...]
7
7
 
8
8
  查询:
9
9
  status 查看会话状态
10
+ status --format json 查看当前任务的结构化运行上下文
10
11
  pwd 显示当前项目路径
11
12
  help 显示帮助
12
13
 
@@ -20,6 +21,7 @@ const CTL_HELP = `用法: ec ctl <command> [args...]
20
21
 
21
22
  示例:
22
23
  ec ctl status
24
+ ec ctl status --format json
23
25
  ec ctl name "新会话名称"
24
26
  ec ctl send "任务已完成"
25
27
  ec ctl file report.md