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
@@ -12,11 +12,102 @@ export const MENU_REQUEST_TYPES = new Set([
12
12
  'menu.update',
13
13
  'menu.action',
14
14
  ]);
15
+ export function buildMenuClientProtectedHeaders(input) {
16
+ const clientName = input.clientName ?? 'evol';
17
+ if (clientName === 'ec-menu-client') {
18
+ const clientVersion = input.clientVersion?.trim();
19
+ if (!parseStableSemver(clientVersion)) {
20
+ throw Object.assign(new Error('ec-menu-client requires a stable X.Y.Z client version'), { code: 'INVALID_CLIENT' });
21
+ }
22
+ return {
23
+ client_name: clientName,
24
+ client_version: clientVersion,
25
+ ...(input.remoteAccessToken || input.ecwebToken ? { auth_method: 'remote-access-token', remote_access_token: input.remoteAccessToken ?? input.ecwebToken } : {}),
26
+ };
27
+ }
28
+ const appClientVersion = input.clientVersion?.trim();
29
+ return {
30
+ ...(clientName === 'Evol App' ? { client_name: clientName } : {}),
31
+ ...(input.evolVersion ? { evol_version: input.evolVersion } : {}),
32
+ ...(clientName === 'Evol App' && appClientVersion ? { client_version: appClientVersion } : {}),
33
+ ...(input.remoteAccessToken || input.ecwebToken ? { auth_method: 'remote-access-token', remote_access_token: input.remoteAccessToken ?? input.ecwebToken } : {}),
34
+ };
35
+ }
36
+ export function parseMenuClientProtectedHeaders(value) {
37
+ if (!value)
38
+ return {};
39
+ const normalized = {};
40
+ for (const [key, raw] of Object.entries(value)) {
41
+ if (typeof raw !== 'string')
42
+ continue;
43
+ normalized[key.trim().toLowerCase()] = raw;
44
+ }
45
+ const result = {};
46
+ if (normalized.client_name === 'evol' || normalized.client_name === 'Evol App' || normalized.client_name === 'ec-menu-client')
47
+ result.client_name = normalized.client_name;
48
+ else if (normalized.client_name !== undefined)
49
+ result.client_name = normalized.client_name;
50
+ if (normalized.client_version !== undefined)
51
+ result.client_version = normalized.client_version;
52
+ if (normalized.evol_version !== undefined)
53
+ result.evol_version = normalized.evol_version;
54
+ if (normalized.auth_method === 'daemon-owner' || normalized.auth_method === 'remote-access-token' || normalized.auth_method === 'ecweb-token')
55
+ result.auth_method = normalized.auth_method;
56
+ else if (normalized.auth_method !== undefined)
57
+ result.auth_method = normalized.auth_method;
58
+ if (normalized.remote_access_token !== undefined)
59
+ result.remote_access_token = normalized.remote_access_token;
60
+ if (normalized.ecweb_token !== undefined)
61
+ result.ecweb_token = normalized.ecweb_token;
62
+ return result;
63
+ }
64
+ /** Validate client identity separately from authorization. These fields never grant access. */
65
+ export function evaluateMenuClientCompatibility(input) {
66
+ const headers = parseMenuClientProtectedHeaders(input.protectedHeaders);
67
+ const clientName = headers.client_name ?? 'evol';
68
+ if (clientName === 'ec-menu-client') {
69
+ if (!input.encrypted || !parseStableSemver(headers.client_version)) {
70
+ return {
71
+ code: 'INVALID_CLIENT',
72
+ message: 'ec-menu-client requires encrypted protected headers and a stable X.Y.Z client_version',
73
+ };
74
+ }
75
+ return null;
76
+ }
77
+ if (clientName !== 'evol' && clientName !== 'Evol App') {
78
+ return { code: 'INVALID_CLIENT', message: `Unsupported Menu client: ${String(clientName)}` };
79
+ }
80
+ return evaluateEvolMenuVersionGate(input);
81
+ }
82
+ export function parseMenuResponse(value) {
83
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
84
+ throw Object.assign(new Error('Menu response must be an object'), { code: 'INVALID_RESPONSE' });
85
+ }
86
+ const response = value;
87
+ if (response.type !== 'menu.response' || typeof response.id !== 'string' || !response.id.trim()) {
88
+ throw Object.assign(new Error('Invalid Menu response type or id'), { code: 'INVALID_RESPONSE' });
89
+ }
90
+ const hasData = Object.prototype.hasOwnProperty.call(response, 'data');
91
+ const hasError = Object.prototype.hasOwnProperty.call(response, 'error');
92
+ if (hasData === hasError) {
93
+ throw Object.assign(new Error('Menu response must contain exactly one of data or error'), { code: 'INVALID_RESPONSE' });
94
+ }
95
+ if (hasError) {
96
+ const error = response.error;
97
+ if (!error || typeof error !== 'object' || Array.isArray(error)
98
+ || typeof error.code !== 'string'
99
+ || typeof error.message !== 'string') {
100
+ throw Object.assign(new Error('Invalid Menu response error'), { code: 'INVALID_RESPONSE' });
101
+ }
102
+ }
103
+ return value;
104
+ }
15
105
  export const MENU_NAME_COMMANDS = Object.freeze({
16
106
  pwd: '/pwd',
17
107
  session: '/session',
18
108
  topic: '/topic',
19
109
  baseagent: '/baseagent',
110
+ 'baseagent-models': '/baseagent-models',
20
111
  model: '/model',
21
112
  effort: '/effort',
22
113
  chatmode: '/chatmode',
@@ -259,6 +350,25 @@ export function menuFailure(header, error) {
259
350
  },
260
351
  };
261
352
  }
353
+ export function enforceMenuResponseSize(response, maxBytes = 128 * 1024) {
354
+ let bytes;
355
+ try {
356
+ bytes = Buffer.byteLength(JSON.stringify(response), 'utf8');
357
+ }
358
+ catch {
359
+ return menuFailure({ id: response.id, ...(response.name ? { name: response.name } : {}) }, {
360
+ code: 'INTERNAL_ERROR',
361
+ message: 'Menu response is not serializable',
362
+ });
363
+ }
364
+ if (bytes <= maxBytes)
365
+ return response;
366
+ return menuFailure({ id: response.id, ...(response.name ? { name: response.name } : {}) }, {
367
+ code: 'RESPONSE_TOO_LARGE',
368
+ message: `Menu response exceeds the ${maxBytes}-byte limit`,
369
+ data: { bytes, maxBytes },
370
+ });
371
+ }
262
372
  const INVALID_ARGUMENT_CODES = new Set([
263
373
  'ARGUMENT_MISMATCH', 'FILE_TOO_LARGE', 'INVALID_ARGS', 'INVALID_DELEGATION',
264
374
  'INVALID_FIELD', 'INVALID_REVISION', 'INVALID_SCOPE', 'INVALID_TYPE', 'INVALID_VALUE', 'MISSING_AID',
@@ -273,6 +383,8 @@ const STABLE_CODES = new Set([
273
383
  'MENU_TOKEN_REQUIRED', 'MENU_TOKEN_REJECTED', 'MENU_TOKEN_ENCRYPTION_REQUIRED',
274
384
  'INVALID_CONTEXT', 'SCHEMA_VERSION_UNSUPPORTED', 'DEPENDENCY_UNAVAILABLE',
275
385
  'RATE_LIMITED', 'CATALOG_STALE', 'DATA_MIGRATION_REQUIRED',
386
+ 'INVALID_CLIENT', 'REMOTE_ACCESS_TOKEN_INVALID', 'ECWEB_TOKEN_INVALID', 'CLIENT_BUSY', 'INVALID_RESPONSE', 'TIMEOUT',
387
+ 'RESPONSE_TOO_LARGE',
276
388
  ]);
277
389
  export function normalizeMenuError(error) {
278
390
  const source = error && typeof error === 'object' ? error : {};
@@ -493,6 +605,9 @@ function menuFlowBaseRecord(request, context) {
493
605
  requestId: menuRequestId(request),
494
606
  messageId: context.messageId,
495
607
  selfAid: context.selfAid,
608
+ requesterAid: context.requesterAid,
609
+ authMethod: context.authMethod,
610
+ clientName: context.clientName,
496
611
  };
497
612
  }
498
613
  function menuRequestBusinessFields(request) {
@@ -531,11 +646,19 @@ export function logMenuRequestCompleted(request, response, context, options) {
531
646
  const processingMs = response && typeof response.processing_ms === 'number'
532
647
  ? response.processing_ms
533
648
  : undefined;
649
+ let responseBytes;
650
+ if (response) {
651
+ try {
652
+ responseBytes = Buffer.byteLength(JSON.stringify(response), 'utf8');
653
+ }
654
+ catch { }
655
+ }
534
656
  writeMenuFlowRecord({
535
657
  ...menuFlowBaseRecord(request, context),
536
658
  event: options.delivery === 'failed' ? 'menu.request.failed' : 'menu.request.completed',
537
659
  delivery: options.delivery,
538
660
  processingMs,
661
+ responseBytes,
539
662
  reason: options.reason,
540
663
  result: response && 'data' in response ? sanitizeMenuLogValue(response.data) : undefined,
541
664
  warning: response && 'warning' in response ? sanitizeMenuLogValue(response.warning) : undefined,
@@ -43,9 +43,9 @@ export function probeSessionActivity(evidence, probes) {
43
43
  return evaluateSessionActivity(collected);
44
44
  }
45
45
  // 支持的命令列表
46
- const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mentionmode', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade'];
46
+ const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mentionmode', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair'];
47
47
  const deprecatedCommands = ['/clear'];
48
- const exactBoundaryCommands = new Set(['/pause', '/resume', '/stop']);
48
+ const exactBoundaryCommands = new Set(['/pause', '/resume', '/stop', '/pair']);
49
49
  /** Parse the execution command without treating it as a quick/result command. */
50
50
  export function parseFullAccessCommand(content) {
51
51
  const match = content.match(/^\s*(\/fa|\/fullaccess)(?=\s|$)([\s\S]*)$/);
@@ -65,7 +65,7 @@ const aliases = {
65
65
  '/base': '/baseagent',
66
66
  };
67
67
  // 命令快速路径前缀(所有命令都不进入消息队列)
68
- const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mentionmode', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade'];
68
+ const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mentionmode', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair'];
69
69
  /**
70
70
  * 计算两个字符串的 Levenshtein 距离(编辑距离)
71
71
  */
@@ -119,10 +119,8 @@ export function guardThreadCommand(content, threadId) {
119
119
  const threadBlocked = ['/new', '/slist', '/s', '/session', '/fork', '/del', '/repair'];
120
120
  const hasCommandArgument = (command) => new RegExp(`^${command.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?:\\s|$)`).test(content);
121
121
  const isBlocked = threadBlocked.some(hasCommandArgument);
122
- const isBaseagentSwitch = /^\/baseagent\s/.test(content);
123
- const isBaseAliasSwitch = /^\/base\s/.test(content);
124
122
  const isRewindMutation = /^\/rewind\s/.test(content);
125
- if (!isBlocked && !isBaseagentSwitch && !isBaseAliasSwitch && !isRewindMutation)
123
+ if (!isBlocked && !isRewindMutation)
126
124
  return undefined;
127
125
  return { kind: 'command.error', text: '⚠️ 话题中不支持此命令' };
128
126
  }