evolcore 0.0.10 → 0.0.12

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 (131) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +3 -3
  3. package/bin/codex-managed-hook.mjs +80 -0
  4. package/dist/agents/baseagent.js +4 -0
  5. package/dist/agents/claude-runner.js +158 -44
  6. package/dist/agents/codex-app-server-client.js +153 -23
  7. package/dist/agents/codex-runner.js +331 -43
  8. package/dist/agents/ecagent-runner.js +53 -6
  9. package/dist/agents/gemini-runner.js +1 -0
  10. package/dist/agents/request-identity.js +55 -0
  11. package/dist/aun/aid/client.js +11 -21
  12. package/dist/aun/aid/managed-operation.js +107 -0
  13. package/dist/aun/msg/group.js +81 -12
  14. package/dist/aun/msg/managed-operation.js +804 -0
  15. package/dist/aun/msg/mention-schema.js +20 -0
  16. package/dist/aun/msg/p2p.js +7 -0
  17. package/dist/aun/outbox.js +28 -31
  18. package/dist/channels/aun.js +418 -235
  19. package/dist/channels/daemon.js +13 -0
  20. package/dist/cli/agent-command.js +72 -17
  21. package/dist/cli/agent.js +249 -22
  22. package/dist/cli/aun-commands.js +270 -69
  23. package/dist/cli/bench.js +12 -3
  24. package/dist/cli/daemon-commands.js +52 -33
  25. package/dist/cli/fs-command.js +60 -0
  26. package/dist/cli/handoff-command.js +3 -0
  27. package/dist/cli/index.js +106 -63
  28. package/dist/cli/init-cancel.js +208 -0
  29. package/dist/cli/init-channel.js +343 -195
  30. package/dist/cli/init.js +21 -9
  31. package/dist/cli/managed-command-guard.js +41 -0
  32. package/dist/cli/model.js +11 -4
  33. package/dist/cli/queue-command.js +11 -1
  34. package/dist/cli/response.js +71 -0
  35. package/dist/cli/restart-monitor.js +4 -18
  36. package/dist/cli/trigger-command.js +4 -0
  37. package/dist/config/builtin-roles.js +5 -0
  38. package/dist/config/contact-book-store.js +11 -3
  39. package/dist/config/contact-request-service.js +161 -15
  40. package/dist/config/gateway-config.js +26 -10
  41. package/dist/config/mention-mode.js +8 -24
  42. package/dist/core/agent-reload-coordinator.js +53 -0
  43. package/dist/core/auth/agent-delegation.js +0 -1
  44. package/dist/core/auth/operation-authorizer.js +62 -154
  45. package/dist/core/auth/operation-catalog.js +264 -22
  46. package/dist/core/bootstrap-messages.js +68 -0
  47. package/dist/core/bootstrap-service.js +144 -10
  48. package/dist/core/capability/providers/claude-capability-provider.js +9 -31
  49. package/dist/core/capability/providers/codex-capability-provider.js +4 -15
  50. package/dist/core/capability/skill-discovery.js +55 -0
  51. package/dist/core/channel-loader.js +24 -7
  52. package/dist/core/command/agent-control.js +14 -11
  53. package/dist/core/command/cli-intent-parser.js +9 -0
  54. package/dist/core/command/command-handler.js +467 -6
  55. package/dist/core/command/connect-menu.js +15 -0
  56. package/dist/core/command/group-menu.js +4 -4
  57. package/dist/core/command/menu-catalog.js +366 -0
  58. package/dist/core/command/menu-handler.js +213 -110
  59. package/dist/core/command/menu-protocol.js +71 -0
  60. package/dist/core/command/slash-gate.js +5 -2
  61. package/dist/core/command/slash-handler.js +45 -25
  62. package/dist/core/daemon-file-cache.js +2 -1
  63. package/dist/core/data-migration.js +9 -2
  64. package/dist/core/evolagent-registry.js +125 -35
  65. package/dist/core/evolagent.js +12 -5
  66. package/dist/core/handoff/dispatcher.js +5 -2
  67. package/dist/core/handoff/runtime.js +145 -21
  68. package/dist/core/handoff/store.js +24 -0
  69. package/dist/core/handoff/types.js +1 -0
  70. package/dist/core/inference/text-inference.js +38 -4
  71. package/dist/core/message/logical-queue-bridge.js +1 -0
  72. package/dist/core/message/mention-schema.js +126 -0
  73. package/dist/core/message/message-bridge.js +237 -79
  74. package/dist/core/message/message-log.js +23 -0
  75. package/dist/core/message/message-queue.js +20 -4
  76. package/dist/core/message/response-engine.js +54 -36
  77. package/dist/core/model/model-catalog.js +143 -24
  78. package/dist/core/model/model-diagnostics.js +28 -10
  79. package/dist/core/permission/ec-command-parser.js +156 -10
  80. package/dist/core/permission/index.js +1 -0
  81. package/dist/core/permission/readonly-shell-query.js +532 -0
  82. package/dist/core/permission/sandbox-runtime.js +22 -1
  83. package/dist/core/permission/shell-environment.js +46 -0
  84. package/dist/core/permission/tool-policy.js +292 -111
  85. package/dist/core/protected-paths.js +17 -9
  86. package/dist/core/runner-reload-transaction.js +57 -0
  87. package/dist/core/session/session-manager.js +21 -2
  88. package/dist/eck/manifest-engine.js +39 -13
  89. package/dist/index.js +644 -180
  90. package/dist/ipc.js +246 -19
  91. package/dist/response-system/coordinator.js +6 -4
  92. package/dist/response-system/engines/v1/proactive-flow.js +26 -8
  93. package/dist/response-system/modes/single-session/index.js +14 -1
  94. package/dist/response-system/selector.js +6 -5
  95. package/dist/trigger/anomaly-store.js +4 -0
  96. package/dist/trigger/script-executor.js +1 -0
  97. package/dist/utils/aid-bind.js +3 -8
  98. package/dist/utils/codex-app-server-registry.js +90 -0
  99. package/dist/utils/codex-cli.js +5 -1
  100. package/dist/utils/cross-platform.js +15 -0
  101. package/dist/utils/log-writer.js +6 -10
  102. package/dist/utils/logger.js +5 -5
  103. package/dist/utils/npm-ops.js +5 -12
  104. package/dist/utils/tool-summary.js +11 -0
  105. package/kits/docs/channels/aun.md +1 -1
  106. package/kits/docs/context-assembly.md +2 -2
  107. package/kits/docs/evolcore/agent.md +11 -6
  108. package/kits/docs/evolcore/aid.md +14 -0
  109. package/kits/docs/evolcore/msg.md +13 -0
  110. package/kits/docs/prompt-loading-architecture.md +1 -2
  111. package/kits/docs/venues/group.md +1 -1
  112. package/kits/eck_manifest.json +0 -12
  113. package/kits/rules/01-overview.md +9 -0
  114. package/kits/rules/04-relation.md +1 -1
  115. package/kits/rules/05-venue.md +2 -2
  116. package/kits/schemas/agent-config.schema.3.json +1 -1
  117. package/kits/schemas/agent-config.schema.4.json +1 -1
  118. package/kits/schemas/relation-config.schema.2.json +1 -1
  119. package/kits/schemas/role-config.schema.1.json +1 -1
  120. package/kits/schemas/single-session.schema.1.json +3 -3
  121. package/kits/schemas/single-session.schema.2.json +3 -3
  122. package/kits/templates/roles/admin.json +27 -0
  123. package/kits/templates/roles/member.json +44 -0
  124. package/kits/templates/roles/visitor.json +40 -2
  125. package/kits/templates/system-fragments/bootstrap.md +12 -6
  126. package/kits/templates/system-fragments/channel.md +6 -0
  127. package/kits/templates/system-fragments/session.md +2 -0
  128. package/package.json +3 -2
  129. package/skills/eclink/SKILL.md +15 -3
  130. package/skills/eclink/agents/openai.yaml +3 -3
  131. package/dist/core/command/evol-menu-version-gate.js +0 -39
@@ -5,68 +5,6 @@ import { isResolvedConfigMutation, } from '../../config/resolved-config-op.js';
5
5
  import { normalizePeer } from '../model/config-scope.js';
6
6
  import { getOperationMeta } from './operation-catalog.js';
7
7
  import { formatPeerKey, parsePeerKey } from '../relation/peer-identity.js';
8
- export const USER_PLANE_CAPABILITY_CEILING = {
9
- allowOperations: new Set([
10
- 'model.list',
11
- 'model.current',
12
- 'model.use',
13
- 'model.effort',
14
- 'model.reset',
15
- 'permission.current',
16
- 'permission.answer',
17
- 'chatmode.current',
18
- 'chatmode.update',
19
- 'mentionmode.current',
20
- 'mentionmode.update',
21
- 'group.mentionmode.current',
22
- 'group.rulespolicy.current',
23
- 'session.list',
24
- 'session.create',
25
- 'session.rename',
26
- 'trigger.list',
27
- 'trigger.show',
28
- 'trigger.history',
29
- 'trigger.eventCatalog',
30
- 'trigger.create',
31
- 'trigger.update',
32
- 'trigger.setEnabled',
33
- 'trigger.cancel',
34
- 'trigger.delete',
35
- 'trigger.run',
36
- 'stats.summary',
37
- 'stats.session',
38
- 'stats.context',
39
- 'file.list',
40
- 'file.fetch',
41
- 'ec.msg.send',
42
- 'ec.msg.file',
43
- 'ec.group.send',
44
- 'ec.group.file',
45
- 'config.get',
46
- 'config.set',
47
- 'config.unset',
48
- ]),
49
- denyOperations: new Set([
50
- 'role.assign',
51
- 'role.revoke',
52
- 'config.write',
53
- 'gateway.write',
54
- 'cli.exec.raw',
55
- 'shell.exec',
56
- 'rce.exec',
57
- ]),
58
- denyNamespaces: new Set([
59
- 'role',
60
- 'connect',
61
- 'contact',
62
- 'agent',
63
- 'system',
64
- 'storage',
65
- 'aid',
66
- ]),
67
- allowCategories: new Set(['read', 'write-own']),
68
- denyCategories: new Set(['write-agent', 'process', 'dangerous']),
69
- };
70
8
  export function authorizeCommand(ctx) {
71
9
  return authorizeCommandInternal(ctx);
72
10
  }
@@ -84,68 +22,33 @@ export function authorizeResolvedConfigCommand(command, context) {
84
22
  * enforced here.
85
23
  */
86
24
  export function evaluateRoleOperationCapability(params) {
87
- const opMeta = getOperationMeta(params.operation);
88
- if (!opMeta) {
89
- return {
90
- allow: false,
91
- operation: params.operation,
92
- reason: `Unknown operation: ${params.operation}`,
93
- };
94
- }
95
- const roleDef = getRoleDefinition(params.role, params.selfAid);
96
- if (!roleDef || roleDef.allowAccess === false) {
97
- return {
98
- allow: false,
99
- operation: params.operation,
100
- reason: `Role ${params.role} cannot access commands`,
101
- };
102
- }
103
- const matched = matchCommandPermission(params.operation, opMeta.category, roleDef.commandPermissions || {}, opMeta.dangerous);
104
- if (!matched) {
105
- return {
106
- allow: false,
107
- operation: params.operation,
108
- reason: `Role ${params.role} has no permission for ${params.operation}`,
109
- };
110
- }
111
- const { permission, matchedRule } = matched;
112
- if (!permission.allow) {
113
- return {
114
- allow: false,
115
- operation: params.operation,
116
- reason: permission.reason || `Role ${params.role} explicitly denies ${params.operation}`,
117
- matchedRule,
118
- };
119
- }
120
- const scopes = permission.scopes || opMeta.defaultScopes;
121
- if (!scopes.includes(params.scope)) {
122
- return {
123
- allow: false,
25
+ // Capability discovery has no concrete relation target. Use a synthetic
26
+ // self relation so target/current-relation constraints are evaluated as
27
+ // role capabilities without weakening the real authorization path.
28
+ const capabilitySelf = params.selfAid ?? 'capability.agentid.pub';
29
+ const capabilityPeer = formatPeerKey('aun', capabilitySelf);
30
+ const decision = authorizeCommand({
31
+ intent: {
124
32
  operation: params.operation,
125
- reason: `Scope ${params.scope} is not allowed for ${params.operation}`,
126
- matchedRule,
127
- };
128
- }
129
- const constraints = permission.constraints;
130
- if (constraints?.privateOnly && params.chatType !== 'private') {
131
- return { allow: false, operation: params.operation, reason: 'Operation is private-chat only', matchedRule };
132
- }
133
- if (constraints?.groupOnly && params.chatType !== 'group') {
134
- return { allow: false, operation: params.operation, reason: 'Operation is group-chat only', matchedRule };
135
- }
136
- if (constraints?.requireAgentOwner && params.role !== 'owner') {
137
- return { allow: false, operation: params.operation, reason: 'Operation requires Agent owner', matchedRule };
138
- }
139
- if (constraints?.requireAgentAdmin && params.role !== 'owner' && params.role !== 'admin') {
140
- return { allow: false, operation: params.operation, reason: 'Operation requires Agent admin', matchedRule };
141
- }
142
- if (constraints?.requireControlChannel && !params.fromControlChannel) {
143
- return { allow: false, operation: params.operation, reason: 'Operation requires the control channel', matchedRule };
144
- }
145
- if (opMeta.dangerous && !isExplicitDangerousGrant(matchedRule, permission)) {
146
- return { allow: false, operation: params.operation, reason: 'Dangerous operation is not explicitly granted', matchedRule };
147
- }
148
- return { allow: true, operation: params.operation, matchedRule };
33
+ scope: params.scope,
34
+ source: 'menu',
35
+ args: {
36
+ self: capabilitySelf,
37
+ peer: capabilityPeer,
38
+ peerKey: capabilityPeer,
39
+ },
40
+ },
41
+ selfAid: capabilitySelf,
42
+ peerKey: capabilityPeer,
43
+ role: params.role,
44
+ chatType: params.chatType,
45
+ isDaemonOwner: params.fromControlChannel && params.role === 'owner',
46
+ fromControlChannel: params.fromControlChannel,
47
+ source: 'menu',
48
+ });
49
+ return decision.allow
50
+ ? { allow: true, operation: params.operation, matchedRule: decision.matchedRule }
51
+ : { allow: false, operation: params.operation, reason: decision.reason, matchedRule: decision.matchedRule };
149
52
  }
150
53
  function authorizeCommandInternal(ctx, resolvedConfigCommand) {
151
54
  const { intent, role } = ctx;
@@ -208,11 +111,6 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
208
111
  if (roleDef.allowAccess === false) {
209
112
  return denyDecision(ctx, 'ROLE_ACCESS_DENIED', `Role ${role} is not allowed to access commands`, operation, intent.scope, opMeta.dangerous);
210
113
  }
211
- if (!isManagementRole(role)
212
- && !resolvedConfigCommand
213
- && !isUserPlaneOperationAllowed(operation, opMeta.category, opMeta.dangerous)) {
214
- return denyDecision(ctx, 'NOT_ALLOWED', `Operation ${operation} is outside the user permission plane`, operation, intent.scope, opMeta.dangerous);
215
- }
216
114
  const matchResult = matchCommandPermission(operation, opMeta.category, roleDef.commandPermissions || {}, opMeta.dangerous);
217
115
  if (!matchResult) {
218
116
  return denyDecision(ctx, 'NO_PERMISSION', `Role ${role} has no permission for ${operation}`, operation, intent.scope, opMeta.dangerous);
@@ -261,7 +159,7 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
261
159
  if (permission.constraints) {
262
160
  const constraintCheck = checkConstraints(ctx, permission.constraints, resolvedConfigCommand);
263
161
  if (!constraintCheck.ok) {
264
- return denyDecision(ctx, 'ARGUMENT_MISMATCH', constraintCheck.reason || 'Command arguments do not satisfy permission constraints', operation, intent.scope, opMeta.dangerous, matchedRule);
162
+ return denyDecision(ctx, constraintCheck.code ?? 'ARGUMENT_MISMATCH', constraintCheck.reason || 'Command arguments do not satisfy permission constraints', operation, intent.scope, opMeta.dangerous, matchedRule);
265
163
  }
266
164
  }
267
165
  return {
@@ -275,10 +173,9 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
275
173
  };
276
174
  }
277
175
  function matchCommandPermission(operation, category, commandPerms, isDangerous) {
278
- const namespace = operation.split('.')[0];
279
176
  const matches = [];
280
177
  for (const [rule, permission] of Object.entries(commandPerms)) {
281
- const rank = getRuleRank(rule, permission, operation, namespace, category, isDangerous);
178
+ const rank = getRuleRank(rule, permission, operation, category, isDangerous);
282
179
  if (rank > 0) {
283
180
  matches.push({ permission, matchedRule: rule, rank });
284
181
  }
@@ -288,12 +185,17 @@ function matchCommandPermission(operation, category, commandPerms, isDangerous)
288
185
  matches.sort((a, b) => b.rank - a.rank);
289
186
  return matches[0];
290
187
  }
291
- function getRuleRank(rule, permission, operation, namespace, category, isDangerous) {
188
+ function getRuleRank(rule, permission, operation, category, isDangerous) {
292
189
  const denyOffset = permission.allow ? 0 : 1;
293
190
  if (rule === operation)
294
191
  return 1000 + denyOffset;
295
- if (rule === `${namespace}.*`)
296
- return 800 + denyOffset;
192
+ if (rule.endsWith('.*')) {
193
+ const prefix = rule.slice(0, -1);
194
+ if (operation.startsWith(prefix)) {
195
+ const depth = rule.slice(0, -2).split('.').length;
196
+ return 800 + Math.min((depth - 1) * 20, 180) + denyOffset;
197
+ }
198
+ }
297
199
  if (rule.startsWith('category:') && rule.slice('category:'.length) === category)
298
200
  return 600 + denyOffset;
299
201
  if (rule === 'dangerous:*' && isDangerous)
@@ -305,20 +207,6 @@ function getRuleRank(rule, permission, operation, namespace, category, isDangero
305
207
  function isExplicitDangerousGrant(rule, permission) {
306
208
  return permission.allow === true && permission.dangerous === true && (rule === 'dangerous:*' || !rule.includes('*') && !rule.startsWith('category:'));
307
209
  }
308
- function isUserPlaneOperationAllowed(operation, category, dangerous) {
309
- const namespace = operation.split('.')[0];
310
- if (dangerous)
311
- return false;
312
- if (USER_PLANE_CAPABILITY_CEILING.denyCategories.has(category))
313
- return false;
314
- if (!USER_PLANE_CAPABILITY_CEILING.allowCategories.has(category))
315
- return false;
316
- if (USER_PLANE_CAPABILITY_CEILING.denyOperations.has(operation))
317
- return false;
318
- if (USER_PLANE_CAPABILITY_CEILING.denyNamespaces.has(namespace))
319
- return false;
320
- return USER_PLANE_CAPABILITY_CEILING.allowOperations.has(operation);
321
- }
322
210
  function checkConstraints(ctx, constraints, resolvedConfigCommand) {
323
211
  if (constraints.ownPeerOnly) {
324
212
  const peerCheck = checkOwnPeer(ctx);
@@ -326,16 +214,17 @@ function checkConstraints(ctx, constraints, resolvedConfigCommand) {
326
214
  return peerCheck;
327
215
  }
328
216
  if (constraints.ownAgentOnly || constraints.targetCurrentAgentOnly) {
329
- const argSelf = stringArg(ctx.intent.args.self);
330
- if (argSelf && argSelf !== ctx.selfAid) {
217
+ const controlOwnerOverride = ctx.fromControlChannel && ctx.isDaemonOwner;
218
+ const targetAid = stringArg(ctx.intent.args.self) ?? stringArg(ctx.intent.args.aid);
219
+ if (!controlOwnerOverride && (!ctx.selfAid || !targetAid || targetAid !== ctx.selfAid)) {
331
220
  return { ok: false, reason: 'Only the current agent can be targeted' };
332
221
  }
333
222
  }
334
223
  if (constraints.requireAgentOwner && ctx.role !== 'owner') {
335
- return { ok: false, reason: 'This command requires agent owner permission' };
224
+ return { ok: false, code: 'NO_PERMISSION', reason: 'This command requires agent owner permission' };
336
225
  }
337
226
  if (constraints.requireAgentAdmin && ctx.role !== 'owner' && ctx.role !== 'admin') {
338
- return { ok: false, reason: 'This command requires agent admin permission' };
227
+ return { ok: false, code: 'NO_PERMISSION', reason: 'This command requires agent admin permission' };
339
228
  }
340
229
  if (constraints.privateOnly && ctx.chatType !== 'private') {
341
230
  return { ok: false, reason: 'This command is only allowed in private chats' };
@@ -345,7 +234,7 @@ function checkConstraints(ctx, constraints, resolvedConfigCommand) {
345
234
  const sameGroup = constraints.currentRelationOnly ? ' and may only target that same group' : '';
346
235
  return {
347
236
  ok: false,
348
- reason: `Denied ${ctx.intent.operation}: role=${ctx.role}, source_chat=${ctx.chatType ?? 'unknown'}, target_group=${target}. This role may send group messages only from a group-chat task${sameGroup}; the target being a group is not sufficient.`,
237
+ reason: `Denied ${ctx.intent.operation}: role=${ctx.role}, source_chat=${ctx.chatType ?? 'unknown'}, target_group=${target}. This role may access group operations only from a group-chat task${sameGroup}; the target being a group is not sufficient.`,
349
238
  };
350
239
  }
351
240
  if (constraints.requireDaemonOwner && !ctx.isDaemonOwner) {
@@ -516,7 +405,7 @@ function checkCurrentRelation(ctx, resolvedConfigCommand) {
516
405
  const targetGroup = stringArg(ctx.intent.args.targetId) ?? peerIdFromArg(requestedPeer);
517
406
  return {
518
407
  ok: false,
519
- reason: `Denied ${ctx.intent.operation}: role=${ctx.role}, current_group=${currentGroup}, target_group=${targetGroup}. This role may send only to the current group; cross-group sends require admin or owner permission.`,
408
+ reason: `Denied ${ctx.intent.operation}: role=${ctx.role}, current_group=${currentGroup}, target_group=${targetGroup}. This role may access only the current group; cross-group access requires admin or owner permission.`,
520
409
  };
521
410
  }
522
411
  return { ok: false, reason: 'Only the current relation can be targeted' };
@@ -613,6 +502,25 @@ function checkOwnPeer(ctx) {
613
502
  return { ok: true };
614
503
  const requestedPeerId = argPeer ? peerIdFromArg(argPeer) : undefined;
615
504
  const requestedPeerKeyId = argPeerKey ? peerIdFromArg(argPeerKey) : undefined;
505
+ if (ctx.chatType === 'group') {
506
+ if (!expectedPeerKey)
507
+ return { ok: false, reason: 'Cannot verify peer ownership' };
508
+ const candidateKeys = new Set();
509
+ if (argPeerKey)
510
+ candidateKeys.add(argPeerKey);
511
+ if (argPeer) {
512
+ candidateKeys.add(argPeer);
513
+ const channelType = parseChannelType(expectedPeerKey);
514
+ if (channelType)
515
+ candidateKeys.add(formatPeerKey(channelType, argPeer));
516
+ const legacyChannelType = parseLegacyChannelType(expectedPeerKey);
517
+ if (legacyChannelType)
518
+ candidateKeys.add(`${legacyChannelType}::${argPeer}`);
519
+ }
520
+ return candidateKeys.has(expectedPeerKey)
521
+ ? { ok: true }
522
+ : { ok: false, reason: 'Only the current group relation can be targeted' };
523
+ }
616
524
  if (ctx.actorId) {
617
525
  if (requestedPeerId && requestedPeerId !== ctx.actorId) {
618
526
  return { ok: false, reason: 'Only the actor peer can be targeted' };