evolcore 0.0.11 → 0.0.13

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 (164) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/codex-managed-hook.mjs +80 -0
  3. package/bin/ec-safe-output.js +26 -7
  4. package/dist/agents/claude-runner.js +86 -7
  5. package/dist/agents/codex-app-server-client.js +174 -20
  6. package/dist/agents/codex-runner.js +375 -92
  7. package/dist/agents/ecagent-runner.js +39 -4
  8. package/dist/agents/gemini-runner.js +1 -0
  9. package/dist/aun/aid/client.js +11 -21
  10. package/dist/aun/aid/control-aid.js +36 -13
  11. package/dist/aun/aid/managed-operation.js +107 -0
  12. package/dist/aun/aid/store.js +13 -7
  13. package/dist/aun/group-fs-download.js +56 -0
  14. package/dist/aun/group-identity.js +1 -2
  15. package/dist/aun/msg/group.js +91 -44
  16. package/dist/aun/msg/index.js +1 -2
  17. package/dist/aun/msg/managed-operation.js +865 -0
  18. package/dist/aun/msg/mention-schema.js +20 -0
  19. package/dist/aun/msg/p2p.js +7 -0
  20. package/dist/aun/msg/upload.js +16 -1
  21. package/dist/aun/outbox.js +31 -2
  22. package/dist/aun/rpc/client.js +66 -0
  23. package/dist/aun/rpc/index.js +1 -2
  24. package/dist/aun/storage/{upload.js → client.js} +11 -2
  25. package/dist/aun/storage/index.js +1 -2
  26. package/dist/channels/aun.js +655 -240
  27. package/dist/channels/daemon.js +13 -0
  28. package/dist/cli/agent-command.js +56 -8
  29. package/dist/cli/agent.js +108 -31
  30. package/dist/cli/aun-commands.js +270 -69
  31. package/dist/cli/bench.js +12 -3
  32. package/dist/cli/cli-argv.js +10 -0
  33. package/dist/cli/config.js +9 -17
  34. package/dist/cli/ctl-command.js +1 -1
  35. package/dist/cli/daemon-commands.js +70 -55
  36. package/dist/cli/fs-command.js +79 -10
  37. package/dist/cli/handoff-command.js +3 -0
  38. package/dist/cli/index.js +30 -2
  39. package/dist/cli/init.js +77 -8
  40. package/dist/cli/managed-command-guard.js +41 -0
  41. package/dist/cli/model.js +11 -4
  42. package/dist/cli/queue-command.js +53 -1
  43. package/dist/cli/response.js +71 -0
  44. package/dist/cli/restart-monitor.js +7 -32
  45. package/dist/cli/trigger-command.js +11 -0
  46. package/dist/config/access-policy.js +1 -2
  47. package/dist/config/builtin-roles.js +9 -0
  48. package/dist/config/config-manager.js +21 -1
  49. package/dist/config/contact-book-store.js +11 -3
  50. package/dist/config/contact-request-service.js +161 -15
  51. package/dist/config/mention-mode.js +8 -24
  52. package/dist/config/peer-role-resolver.js +6 -2
  53. package/dist/config/role-migration-startup.js +53 -0
  54. package/dist/config/role-store.js +1 -1
  55. package/dist/core/auth/agent-delegation.js +1 -2
  56. package/dist/core/auth/auth-gateway.js +29 -1
  57. package/dist/core/auth/authorization-audit.js +15 -0
  58. package/dist/core/auth/operation-authorizer.js +31 -7
  59. package/dist/core/auth/operation-catalog.js +196 -25
  60. package/dist/core/bootstrap-messages.js +25 -0
  61. package/dist/core/bootstrap-service.js +64 -4
  62. package/dist/core/capability/providers/claude-capability-provider.js +9 -31
  63. package/dist/core/capability/providers/codex-capability-provider.js +4 -15
  64. package/dist/core/capability/skill-discovery.js +55 -0
  65. package/dist/core/channel-loader.js +1 -1
  66. package/dist/core/command/cli-intent-parser.js +9 -0
  67. package/dist/core/command/command-handler.js +650 -42
  68. package/dist/core/command/connect-menu.js +15 -0
  69. package/dist/core/command/group-menu.js +4 -4
  70. package/dist/core/command/menu-catalog.js +370 -0
  71. package/dist/core/command/menu-handler.js +230 -51
  72. package/dist/core/command/menu-protocol.js +94 -2
  73. package/dist/core/command/slash-gate.js +5 -2
  74. package/dist/core/command/slash-handler.js +99 -31
  75. package/dist/core/daemon-file-cache.js +2 -1
  76. package/dist/core/data-migration.js +9 -2
  77. package/dist/core/event-catalog.js +6 -0
  78. package/dist/core/evolagent.js +4 -2
  79. package/dist/core/handoff/dispatcher.js +5 -2
  80. package/dist/core/handoff/runtime.js +157 -22
  81. package/dist/core/handoff/store.js +29 -1
  82. package/dist/core/handoff/types.js +1 -0
  83. package/dist/core/interaction-router.js +10 -0
  84. package/dist/core/message/im-renderer.js +19 -0
  85. package/dist/core/message/logical-queue-bridge.js +1 -0
  86. package/dist/core/message/mention-schema.js +126 -0
  87. package/dist/core/message/message-bridge.js +298 -88
  88. package/dist/core/message/message-log.js +3 -0
  89. package/dist/core/message/message-queue.js +268 -39
  90. package/dist/core/message/message-utils.js +81 -4
  91. package/dist/core/message/response-engine.js +161 -77
  92. package/dist/core/message/stream-debouncer.js +10 -2
  93. package/dist/core/permission/approval-gateway.js +1 -0
  94. package/dist/core/permission/ec-command-parser.js +243 -18
  95. package/dist/core/permission/index.js +1 -1
  96. package/dist/core/permission/mode.js +15 -0
  97. package/dist/core/permission/readonly-shell-query.js +148 -8
  98. package/dist/core/permission/sandbox-runtime.js +43 -1
  99. package/dist/core/permission/tool-policy.js +322 -57
  100. package/dist/core/protected-paths.js +114 -4
  101. package/dist/core/session/session-manager.js +42 -4
  102. package/dist/core/session/session-mapper.js +20 -1
  103. package/dist/eck/detect.js +18 -1
  104. package/dist/eck/group-rules-sync.js +15 -44
  105. package/dist/eck/manifest-engine.js +39 -13
  106. package/dist/index.js +541 -180
  107. package/dist/ipc.js +232 -10
  108. package/dist/paths.js +3 -0
  109. package/dist/response-system/coordinator.js +6 -4
  110. package/dist/response-system/engines/v1/proactive-flow.js +26 -8
  111. package/dist/response-system/modes/single-session/index.js +14 -1
  112. package/dist/response-system/selector.js +6 -5
  113. package/dist/trigger/anomaly-store.js +4 -0
  114. package/dist/trigger/feedback.js +64 -11
  115. package/dist/trigger/manager.js +21 -1
  116. package/dist/trigger/parser.js +14 -2
  117. package/dist/trigger/scheduler.js +1 -0
  118. package/dist/trigger/script-executor.js +1 -0
  119. package/dist/trigger/validation.js +67 -6
  120. package/dist/utils/codex-app-server-registry.js +90 -0
  121. package/dist/utils/codex-cli.js +5 -1
  122. package/dist/utils/cross-platform.js +15 -0
  123. package/dist/utils/ecweb-supervisor.js +332 -0
  124. package/dist/utils/error-utils.js +10 -0
  125. package/dist/utils/npm-ops.js +5 -12
  126. package/dist/utils/tool-summary.js +11 -0
  127. package/kits/docs/channels/aun.md +1 -1
  128. package/kits/docs/context-assembly.md +2 -2
  129. package/kits/docs/evolcore/agent.md +11 -6
  130. package/kits/docs/evolcore/aid.md +14 -0
  131. package/kits/docs/evolcore/trigger.md +17 -1
  132. package/kits/docs/prompt-loading-architecture.md +1 -2
  133. package/kits/docs/venues/group.md +1 -1
  134. package/kits/eck_manifest.json +0 -12
  135. package/kits/migrations/migrate-contact-book-v2.mjs +1 -2
  136. package/kits/rules/04-relation.md +1 -1
  137. package/kits/rules/05-venue.md +2 -2
  138. package/kits/schemas/role-config.schema.1.json +1 -0
  139. package/kits/schemas/single-session.schema.1.json +3 -3
  140. package/kits/schemas/single-session.schema.2.json +3 -3
  141. package/kits/templates/roles/admin.json +27 -0
  142. package/kits/templates/roles/member.json +34 -1
  143. package/kits/templates/roles/visitor.json +35 -3
  144. package/kits/templates/system-fragments/bootstrap.md +1 -1
  145. package/kits/templates/system-fragments/channel.md +1 -1
  146. package/kits/templates/system-fragments/session.md +1 -1
  147. package/package.json +2 -2
  148. package/dist/aun/msg/payload-type.js +0 -27
  149. package/dist/aun/rpc/caller.js +0 -42
  150. package/dist/aun/rpc/connection.js +0 -25
  151. package/dist/aun/storage/manage.js +0 -10
  152. package/dist/config/access-policy-domain.js +0 -18
  153. package/dist/config/config-batch-get.js +0 -11
  154. package/dist/config/owner-policy.js +0 -4
  155. package/dist/config/role-config-v4-startup.js +0 -32
  156. package/dist/config/role-config-v5-startup.js +0 -27
  157. package/dist/core/auth/trigger-authorization.js +0 -15
  158. package/dist/core/command/evol-menu-version-gate.js +0 -39
  159. package/dist/core/interaction-registration.js +0 -10
  160. package/dist/core/permission/execution-sandbox.js +0 -16
  161. package/dist/core/relation/peer-key.js +0 -1
  162. package/dist/core/session/session-key.js +0 -24
  163. package/dist/eck/baseagent-caps.js +0 -18
  164. package/dist/eck/rules-loader.js +0 -28
@@ -0,0 +1,20 @@
1
+ import { MentionSchemaError, normalizeMentionEntries, } from '../../core/message/mention-schema.js';
2
+ const AUN_MENTION_KEYS = new Set(['aid', 'scope', 'display', 'offset', 'length']);
3
+ /**
4
+ * Validate the AUN wire schema. `userId` is deliberately excluded here:
5
+ * it identifies users in platform-native adapters such as Feishu/DingTalk,
6
+ * while AUN addresses agents with `aid` and uses `scope: 'all'` for broadcast.
7
+ */
8
+ export function normalizeAunMentionEntries(raw) {
9
+ const entries = normalizeMentionEntries(raw);
10
+ for (const [index, entry] of entries.entries()) {
11
+ if ('userId' in entry) {
12
+ throw new MentionSchemaError('userId is not valid in AUN mentions; use {aid: "..."}', index);
13
+ }
14
+ const unsupported = Object.keys(entry).find(key => !AUN_MENTION_KEYS.has(key));
15
+ if (unsupported) {
16
+ throw new MentionSchemaError(`${unsupported} is not valid AUN mention metadata`, index);
17
+ }
18
+ }
19
+ return entries;
20
+ }
@@ -10,6 +10,7 @@ import { resolvePaths } from '../../paths.js';
10
10
  import { ipcQuery } from '../../ipc.js';
11
11
  import { AGENT_DELEGATION_TOKEN_ENV } from '../../core/auth/agent-delegation.js';
12
12
  import { loadDaemonConfig } from '../../config-store.js';
13
+ import { normalizeAunMentionEntries } from './mention-schema.js';
13
14
  const DEFAULT_TASK_EXECUTION_MS = 60 * 60 * 1000;
14
15
  const DAEMON_SEND_TIMEOUT_GRACE_MS = 10_000;
15
16
  const MAX_TIMER_MS = 2_147_483_647;
@@ -206,6 +207,9 @@ export async function msgSend(args) {
206
207
  let payload;
207
208
  if (args.body.mode !== 'file') {
208
209
  payload = buildSimplePayload(args.body);
210
+ if (Object.prototype.hasOwnProperty.call(payload, 'mentions')) {
211
+ payload.mentions = normalizeAunMentionEntries(payload.mentions);
212
+ }
209
213
  applyRoutingPayloadFields(payload, args, runtimeContext, false);
210
214
  const daemonResult = await tryDaemonMsgSend(args, payload, runtimeContext);
211
215
  if (daemonResult)
@@ -265,6 +269,9 @@ export async function msgSend(args) {
265
269
  // 5. 写入 payload.thread_id/ref_message_id(如果指定)
266
270
  applyRoutingPayloadFields(payload, args, runtimeContext, false);
267
271
  applyRoutingPayloadFields(payload, args, runtimeContext);
272
+ if (Object.prototype.hasOwnProperty.call(payload, 'mentions')) {
273
+ payload.mentions = normalizeAunMentionEntries(payload.mentions);
274
+ }
268
275
  const encrypt = resolveAunMessageEncrypt(args.encrypt);
269
276
  const sendParams = { to: args.to, payload, encrypt };
270
277
  const result = await conn.call('message.send', sendParams);
@@ -2,7 +2,22 @@ import crypto from 'crypto';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
4
  import { guessMime, formatSize } from '../../utils/media-cache.js';
5
- import { inferPayloadType, isValidPayloadType } from './payload-type.js';
5
+ const EXT_TYPE_MAP = {
6
+ '.png': 'image', '.jpg': 'image', '.jpeg': 'image',
7
+ '.gif': 'image', '.webp': 'image', '.svg': 'image',
8
+ '.bmp': 'image', '.heic': 'image', '.heif': 'image',
9
+ '.mp4': 'video', '.mov': 'video', '.webm': 'video',
10
+ '.avi': 'video', '.mkv': 'video', '.m4v': 'video',
11
+ '.opus': 'voice', '.mp3': 'voice', '.aac': 'voice',
12
+ '.m4a': 'voice', '.wav': 'voice', '.flac': 'voice', '.ogg': 'voice',
13
+ };
14
+ export function inferPayloadType(filename) {
15
+ const ext = path.extname(filename).toLowerCase();
16
+ return EXT_TYPE_MAP[ext] ?? 'file';
17
+ }
18
+ export function isValidPayloadType(value) {
19
+ return value === 'image' || value === 'video' || value === 'voice' || value === 'file';
20
+ }
6
21
  /** 单次上传最大大小(与 daemon sendFile 一致)。 */
7
22
  export const MAX_AUN_ATTACHMENT_SIZE = 10 * 1024 * 1024;
8
23
  /** server 端 inline 上限错误的识别特征。优先匹配错误消息里的“inline 上限”字样。 */
@@ -1,6 +1,7 @@
1
1
  import crypto from 'crypto';
2
2
  import { agentOutboxPath } from '../paths.js';
3
3
  import { atomicRead, atomicWrite } from '../utils/atomic-write.js';
4
+ import { isDeliveryTarget, isDeliveryTargetForChannel, sameDeliveryTarget } from '../core/message/message-utils.js';
4
5
  const MAX_ENTRIES_PER_AID = 20;
5
6
  const DEFAULT_TTL = 300_000; // 5 minutes
6
7
  function outboxFile(aid) {
@@ -16,6 +17,9 @@ function isExpired(entry) {
16
17
  return false;
17
18
  return Date.now() - entry.ts > entry.ttl;
18
19
  }
20
+ export function isDeliveryForChannel(value, channelId) {
21
+ return isDeliveryTargetForChannel(value, channelId);
22
+ }
19
23
  function readEntries(aid) {
20
24
  const file = outboxFile(aid);
21
25
  try {
@@ -43,17 +47,32 @@ function writeEntries(aid, entries) {
43
47
  atomicWrite(file, content);
44
48
  }
45
49
  export function enqueue(aid, opts) {
46
- const existingEntries = readEntries(aid);
50
+ const delivery = opts.delivery;
51
+ if (!isDeliveryForChannel(delivery, opts.channelId)) {
52
+ const code = isDeliveryTarget(delivery) ? 'AUN_OUTBOUND_ROUTE_MISMATCH' : 'AUN_OUTBOUND_ROUTE_REQUIRED';
53
+ throw Object.assign(new Error(`invalid AUN outbox delivery route for channelId=${opts.channelId}`), { code });
54
+ }
55
+ let existingEntries = readEntries(aid);
47
56
  if (opts.dedupeKey) {
48
57
  const existing = existingEntries.find(entry => entry.dedupeKey === opts.dedupeKey && !isExpired(entry));
49
- if (existing)
58
+ if (existing
59
+ && existing.channelId === opts.channelId
60
+ && isDeliveryForChannel(existing.delivery, existing.channelId)
61
+ && sameDeliveryTarget(existing.delivery, delivery)) {
50
62
  return existing;
63
+ }
64
+ if (existing) {
65
+ // A pre-route entry must not block corrected code from persisting the
66
+ // same logical operation with an explicit delivery target.
67
+ existingEntries = existingEntries.filter(entry => entry.id !== existing.id);
68
+ }
51
69
  }
52
70
  const entry = {
53
71
  id: generateId(),
54
72
  ts: Date.now(),
55
73
  aid,
56
74
  channelId: opts.channelId,
75
+ delivery,
57
76
  dedupeKey: opts.dedupeKey,
58
77
  critical: opts.critical,
59
78
  type: opts.type,
@@ -123,6 +142,9 @@ export function cleanup(aid) {
123
142
  // duplicate sends while allowing a later drain trigger to pick up entries
124
143
  // enqueued during an active pass.
125
144
  const activeDrainTails = new Map();
145
+ function hasRouteForChannel(entry) {
146
+ return isDeliveryForChannel(entry.delivery, entry.channelId);
147
+ }
126
148
  async function drainOnce(aid, sender) {
127
149
  const entries = readEntries(aid);
128
150
  if (entries.length === 0)
@@ -137,6 +159,13 @@ async function drainOnce(aid, sender) {
137
159
  expired++;
138
160
  continue;
139
161
  }
162
+ if (!hasRouteForChannel(entry)) {
163
+ // A route is security-sensitive metadata. An entry whose groupId does
164
+ // not match its address cannot be repaired from channelId, so remove it
165
+ // instead of retrying the same malformed send forever.
166
+ expired++;
167
+ continue;
168
+ }
140
169
  try {
141
170
  entry.attempts = (entry.attempts ?? 0) + 1;
142
171
  const ok = await sender(entry);
@@ -0,0 +1,66 @@
1
+ import { getAidStore, loadClient, SLOT } from '../aid/store.js';
2
+ export async function createShortConnection(aid, opts) {
3
+ const store = await getAidStore({ slotId: opts?.slotId ?? SLOT.cli, aunPath: opts?.aunPath });
4
+ try {
5
+ const client = await loadClient(store, aid);
6
+ await client.connect({ connection_kind: 'short', short_ttl_ms: 30000, auto_reconnect: false });
7
+ return {
8
+ async call(method, params) {
9
+ return client.call(method, params);
10
+ },
11
+ async close() {
12
+ try {
13
+ await client.close();
14
+ }
15
+ finally {
16
+ store.close();
17
+ }
18
+ },
19
+ };
20
+ }
21
+ catch (error) {
22
+ store.close();
23
+ throw error;
24
+ }
25
+ }
26
+ export async function rpcCall(aid, method, params, opts) {
27
+ const conn = await createShortConnection(aid, opts);
28
+ try {
29
+ const result = await conn.call(method, params);
30
+ return { ok: true, result };
31
+ }
32
+ catch (error) {
33
+ if (error.code !== undefined && error.message !== undefined) {
34
+ return { ok: false, error: { code: error.code, message: error.message, data: error.data } };
35
+ }
36
+ return { ok: false, error: { code: -1, message: String(error.message || error) } };
37
+ }
38
+ finally {
39
+ await conn.close();
40
+ }
41
+ }
42
+ export async function rpcBatch(aid, calls, opts) {
43
+ const conn = await createShortConnection(aid, opts);
44
+ const results = [];
45
+ try {
46
+ for (const { method, params } of calls) {
47
+ try {
48
+ const result = await conn.call(method, params);
49
+ results.push({ ok: true, result });
50
+ }
51
+ catch (error) {
52
+ if (error.code !== undefined && error.message !== undefined) {
53
+ results.push({ ok: false, error: { code: error.code, message: error.message, data: error.data } });
54
+ }
55
+ else {
56
+ results.push({ ok: false, error: { code: -1, message: String(error.message || error) } });
57
+ }
58
+ break;
59
+ }
60
+ }
61
+ }
62
+ finally {
63
+ await conn.close();
64
+ }
65
+ return results;
66
+ }
@@ -1,2 +1 @@
1
- export { rpcCall, rpcBatch } from './caller.js';
2
- export { createShortConnection } from './connection.js';
1
+ export { rpcCall, rpcBatch, createShortConnection } from './client.js';
@@ -46,7 +46,7 @@ export async function storageUpload(aid, localFile, remotePath, opts) {
46
46
  sha256,
47
47
  content_type: contentType,
48
48
  size_bytes: fileBuffer.length,
49
- is_private: !(opts?.isPublic),
49
+ is_private: !opts?.isPublic,
50
50
  }, { aunPath: opts?.aunPath });
51
51
  if (!completeResult.ok) {
52
52
  return { ok: false, objectKey: remotePath, error: rpcErrorToString(completeResult.error) };
@@ -56,7 +56,7 @@ export async function storageUpload(aid, localFile, remotePath, opts) {
56
56
  if (!publicUrl) {
57
57
  const ticketResult = await rpcCall(aid, 'storage.create_download_ticket', {
58
58
  object_key: remotePath,
59
- expire_in_seconds: 86400 * 30, // 30天
59
+ expire_in_seconds: 86400 * 30,
60
60
  }, { aunPath: opts?.aunPath });
61
61
  if (ticketResult.ok) {
62
62
  publicUrl = pickUrl(ticketResult.result?.url) ?? pickUrl(ticketResult.result?.download_url);
@@ -66,3 +66,12 @@ export async function storageUpload(aid, localFile, remotePath, opts) {
66
66
  }
67
67
  return { ok: true, objectKey: remotePath, publicUrl };
68
68
  }
69
+ export async function storageLs(aid, prefix, opts) {
70
+ return rpcCall(aid, 'storage.list_objects', { prefix: prefix || '' }, { aunPath: opts?.aunPath });
71
+ }
72
+ export async function storageRm(aid, remotePath, opts) {
73
+ return rpcCall(aid, 'storage.delete_object', { object_key: remotePath }, { aunPath: opts?.aunPath });
74
+ }
75
+ export async function storageQuota(aid, opts) {
76
+ return rpcCall(aid, 'storage.get_quota', {}, { aunPath: opts?.aunPath });
77
+ }
@@ -1,3 +1,2 @@
1
- export { storageUpload } from './upload.js';
1
+ export { storageUpload, storageLs, storageRm, storageQuota } from './client.js';
2
2
  export { storageDownload } from './download.js';
3
- export { storageLs, storageRm, storageQuota } from './manage.js';