evolcore 0.0.11 → 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.
- package/CHANGELOG.md +22 -0
- package/bin/codex-managed-hook.mjs +80 -0
- package/dist/agents/claude-runner.js +35 -2
- package/dist/agents/codex-app-server-client.js +120 -14
- package/dist/agents/codex-runner.js +273 -35
- package/dist/agents/ecagent-runner.js +36 -4
- package/dist/agents/gemini-runner.js +1 -0
- package/dist/aun/aid/client.js +11 -21
- package/dist/aun/aid/managed-operation.js +107 -0
- package/dist/aun/msg/group.js +81 -12
- package/dist/aun/msg/managed-operation.js +804 -0
- package/dist/aun/msg/mention-schema.js +20 -0
- package/dist/aun/msg/p2p.js +7 -0
- package/dist/channels/aun.js +288 -108
- package/dist/channels/daemon.js +13 -0
- package/dist/cli/agent-command.js +56 -8
- package/dist/cli/agent.js +170 -6
- package/dist/cli/aun-commands.js +270 -69
- package/dist/cli/bench.js +12 -3
- package/dist/cli/daemon-commands.js +31 -31
- package/dist/cli/fs-command.js +60 -0
- package/dist/cli/handoff-command.js +3 -0
- package/dist/cli/index.js +30 -2
- package/dist/cli/managed-command-guard.js +41 -0
- package/dist/cli/model.js +11 -4
- package/dist/cli/queue-command.js +11 -1
- package/dist/cli/response.js +71 -0
- package/dist/cli/restart-monitor.js +4 -18
- package/dist/cli/trigger-command.js +4 -0
- package/dist/config/builtin-roles.js +4 -0
- package/dist/config/contact-book-store.js +11 -3
- package/dist/config/contact-request-service.js +161 -15
- package/dist/config/mention-mode.js +8 -24
- package/dist/core/auth/agent-delegation.js +0 -1
- package/dist/core/auth/operation-authorizer.js +30 -7
- package/dist/core/auth/operation-catalog.js +187 -25
- package/dist/core/bootstrap-messages.js +18 -0
- package/dist/core/bootstrap-service.js +63 -4
- package/dist/core/capability/providers/claude-capability-provider.js +9 -31
- package/dist/core/capability/providers/codex-capability-provider.js +4 -15
- package/dist/core/capability/skill-discovery.js +55 -0
- package/dist/core/channel-loader.js +1 -1
- package/dist/core/command/cli-intent-parser.js +9 -0
- package/dist/core/command/command-handler.js +467 -6
- package/dist/core/command/connect-menu.js +15 -0
- package/dist/core/command/group-menu.js +4 -4
- package/dist/core/command/menu-catalog.js +366 -0
- package/dist/core/command/menu-handler.js +147 -35
- package/dist/core/command/menu-protocol.js +71 -0
- package/dist/core/command/slash-gate.js +5 -2
- package/dist/core/command/slash-handler.js +41 -21
- package/dist/core/daemon-file-cache.js +2 -1
- package/dist/core/data-migration.js +9 -2
- package/dist/core/evolagent.js +4 -2
- package/dist/core/handoff/dispatcher.js +5 -2
- package/dist/core/handoff/runtime.js +145 -21
- package/dist/core/handoff/store.js +24 -0
- package/dist/core/handoff/types.js +1 -0
- package/dist/core/message/logical-queue-bridge.js +1 -0
- package/dist/core/message/mention-schema.js +126 -0
- package/dist/core/message/message-bridge.js +236 -78
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +1 -0
- package/dist/core/message/response-engine.js +54 -36
- package/dist/core/permission/ec-command-parser.js +156 -10
- package/dist/core/permission/sandbox-runtime.js +22 -1
- package/dist/core/permission/tool-policy.js +73 -30
- package/dist/core/protected-paths.js +7 -2
- package/dist/core/session/session-manager.js +21 -2
- package/dist/eck/manifest-engine.js +39 -13
- package/dist/index.js +384 -98
- package/dist/ipc.js +218 -9
- package/dist/response-system/coordinator.js +6 -4
- package/dist/response-system/engines/v1/proactive-flow.js +26 -8
- package/dist/response-system/modes/single-session/index.js +14 -1
- package/dist/response-system/selector.js +6 -5
- package/dist/trigger/anomaly-store.js +4 -0
- package/dist/trigger/script-executor.js +1 -0
- package/dist/utils/codex-app-server-registry.js +90 -0
- package/dist/utils/codex-cli.js +5 -1
- package/dist/utils/cross-platform.js +15 -0
- package/dist/utils/npm-ops.js +5 -12
- package/dist/utils/tool-summary.js +11 -0
- package/kits/docs/channels/aun.md +1 -1
- package/kits/docs/context-assembly.md +2 -2
- package/kits/docs/evolcore/agent.md +11 -6
- package/kits/docs/evolcore/aid.md +14 -0
- package/kits/docs/prompt-loading-architecture.md +1 -2
- package/kits/docs/venues/group.md +1 -1
- package/kits/eck_manifest.json +0 -12
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/05-venue.md +2 -2
- package/kits/schemas/single-session.schema.1.json +3 -3
- package/kits/schemas/single-session.schema.2.json +3 -3
- package/kits/templates/roles/admin.json +22 -0
- package/kits/templates/roles/member.json +27 -0
- package/kits/templates/roles/visitor.json +33 -3
- package/kits/templates/system-fragments/bootstrap.md +1 -1
- package/kits/templates/system-fragments/channel.md +1 -1
- package/kits/templates/system-fragments/session.md +1 -1
- package/package.json +2 -2
- package/dist/core/command/evol-menu-version-gate.js +0 -39
|
@@ -1,27 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* - disabled(关闭 mention 过滤) ≡ broadcast(全部响应)
|
|
8
|
-
*
|
|
9
|
-
* 仅在协议边界(AUN resolver、render fallback)翻译;配置层、命令层一律用
|
|
10
|
-
* mentionMode 词汇。
|
|
11
|
-
*/
|
|
12
|
-
/** config → AUN 协议词汇;未知/未设值返回 undefined(回退服务端 dispatch_mode)。 */
|
|
13
|
-
export function mentionModeToDispatch(mode) {
|
|
14
|
-
if (mode === 'mention-only')
|
|
15
|
-
return 'mention';
|
|
16
|
-
if (mode === 'disabled')
|
|
17
|
-
return 'broadcast';
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
/** AUN 协议词汇 → config;未知返回 undefined。 */
|
|
21
|
-
export function dispatchToMentionMode(dispatch) {
|
|
22
|
-
if (dispatch === 'mention')
|
|
23
|
-
return 'mention-only';
|
|
24
|
-
if (dispatch === 'broadcast')
|
|
1
|
+
/** AUN `mention_mode` and EvolCore `mentionMode` share these wire values. */
|
|
2
|
+
export function normalizeMentionMode(mode) {
|
|
3
|
+
if (typeof mode !== 'string')
|
|
4
|
+
return undefined;
|
|
5
|
+
const normalized = mode.trim().toLowerCase();
|
|
6
|
+
if (normalized === 'disabled')
|
|
25
7
|
return 'disabled';
|
|
8
|
+
if (normalized === 'mention-only' || normalized === 'mention_only')
|
|
9
|
+
return 'mention-only';
|
|
26
10
|
return undefined;
|
|
27
11
|
}
|
|
@@ -155,7 +155,6 @@ export function authorizeDelegatedAunMsgSend(registry, input) {
|
|
|
155
155
|
channelId,
|
|
156
156
|
chatType: grant.chatType,
|
|
157
157
|
conversationId: channelId,
|
|
158
|
-
identity: { role: grant.issuedRole, mode: 'interactive' },
|
|
159
158
|
processOwners: [],
|
|
160
159
|
fromControlChannel: false,
|
|
161
160
|
});
|
|
@@ -173,10 +173,9 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
function matchCommandPermission(operation, category, commandPerms, isDangerous) {
|
|
176
|
-
const namespace = operation.split('.')[0];
|
|
177
176
|
const matches = [];
|
|
178
177
|
for (const [rule, permission] of Object.entries(commandPerms)) {
|
|
179
|
-
const rank = getRuleRank(rule, permission, operation,
|
|
178
|
+
const rank = getRuleRank(rule, permission, operation, category, isDangerous);
|
|
180
179
|
if (rank > 0) {
|
|
181
180
|
matches.push({ permission, matchedRule: rule, rank });
|
|
182
181
|
}
|
|
@@ -186,12 +185,17 @@ function matchCommandPermission(operation, category, commandPerms, isDangerous)
|
|
|
186
185
|
matches.sort((a, b) => b.rank - a.rank);
|
|
187
186
|
return matches[0];
|
|
188
187
|
}
|
|
189
|
-
function getRuleRank(rule, permission, operation,
|
|
188
|
+
function getRuleRank(rule, permission, operation, category, isDangerous) {
|
|
190
189
|
const denyOffset = permission.allow ? 0 : 1;
|
|
191
190
|
if (rule === operation)
|
|
192
191
|
return 1000 + denyOffset;
|
|
193
|
-
if (rule
|
|
194
|
-
|
|
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
|
+
}
|
|
195
199
|
if (rule.startsWith('category:') && rule.slice('category:'.length) === category)
|
|
196
200
|
return 600 + denyOffset;
|
|
197
201
|
if (rule === 'dangerous:*' && isDangerous)
|
|
@@ -230,7 +234,7 @@ function checkConstraints(ctx, constraints, resolvedConfigCommand) {
|
|
|
230
234
|
const sameGroup = constraints.currentRelationOnly ? ' and may only target that same group' : '';
|
|
231
235
|
return {
|
|
232
236
|
ok: false,
|
|
233
|
-
reason: `Denied ${ctx.intent.operation}: role=${ctx.role}, source_chat=${ctx.chatType ?? 'unknown'}, target_group=${target}. This role may
|
|
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.`,
|
|
234
238
|
};
|
|
235
239
|
}
|
|
236
240
|
if (constraints.requireDaemonOwner && !ctx.isDaemonOwner) {
|
|
@@ -401,7 +405,7 @@ function checkCurrentRelation(ctx, resolvedConfigCommand) {
|
|
|
401
405
|
const targetGroup = stringArg(ctx.intent.args.targetId) ?? peerIdFromArg(requestedPeer);
|
|
402
406
|
return {
|
|
403
407
|
ok: false,
|
|
404
|
-
reason: `Denied ${ctx.intent.operation}: role=${ctx.role}, current_group=${currentGroup}, target_group=${targetGroup}. This role may
|
|
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.`,
|
|
405
409
|
};
|
|
406
410
|
}
|
|
407
411
|
return { ok: false, reason: 'Only the current relation can be targeted' };
|
|
@@ -498,6 +502,25 @@ function checkOwnPeer(ctx) {
|
|
|
498
502
|
return { ok: true };
|
|
499
503
|
const requestedPeerId = argPeer ? peerIdFromArg(argPeer) : undefined;
|
|
500
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
|
+
}
|
|
501
524
|
if (ctx.actorId) {
|
|
502
525
|
if (requestedPeerId && requestedPeerId !== ctx.actorId) {
|
|
503
526
|
return { ok: false, reason: 'Only the actor peer can be targeted' };
|
|
@@ -21,6 +21,82 @@ const CONFIG_MANAGEMENT_OPERATIONS = [
|
|
|
21
21
|
description,
|
|
22
22
|
sources: ['menu.cli', 'agent-tool', 'control'],
|
|
23
23
|
}));
|
|
24
|
+
const GROUP_MANAGEMENT_OPERATIONS = [
|
|
25
|
+
['ec.group.list', 'read', ['agent'], 'List groups joined by the current Agent'],
|
|
26
|
+
['ec.group.info', 'read', ['relation', 'agent'], 'Read group information'],
|
|
27
|
+
['ec.group.pull', 'read', ['relation', 'agent'], 'Pull group messages'],
|
|
28
|
+
['ec.group.members', 'read', ['relation', 'agent'], 'List group members'],
|
|
29
|
+
['ec.group.online', 'read', ['relation', 'agent'], 'List online group members'],
|
|
30
|
+
['ec.group.rules.get', 'read', ['relation', 'agent'], 'Read the published group rules file'],
|
|
31
|
+
['ec.group.rules.read', 'read', ['relation', 'agent'], 'Read legacy group join rules'],
|
|
32
|
+
['ec.group.create', 'write-agent', ['agent'], 'Create a group as the current Agent'],
|
|
33
|
+
['ec.group.ack', 'write-agent', ['agent'], 'Advance the current Agent group cursor'],
|
|
34
|
+
['ec.group.update', 'write-agent', ['agent'], 'Update group metadata'],
|
|
35
|
+
['ec.group.dissolve', 'write-agent', ['agent'], 'Dissolve a group'],
|
|
36
|
+
['ec.group.suspend', 'write-agent', ['agent'], 'Suspend a group'],
|
|
37
|
+
['ec.group.resume', 'write-agent', ['agent'], 'Resume a group'],
|
|
38
|
+
['ec.group.join', 'write-agent', ['agent'], 'Request to join a group'],
|
|
39
|
+
['ec.group.leave', 'write-agent', ['agent'], 'Leave a group'],
|
|
40
|
+
['ec.group.invite', 'write-agent', ['agent'], 'Invite group members'],
|
|
41
|
+
['ec.group.kick', 'write-agent', ['agent'], 'Remove a group member'],
|
|
42
|
+
['ec.group.role', 'write-agent', ['agent'], 'Change a group member role'],
|
|
43
|
+
['ec.group.owner', 'write-agent', ['agent'], 'Transfer group ownership'],
|
|
44
|
+
['ec.group.ban', 'write-agent', ['agent'], 'Read or update the group ban list'],
|
|
45
|
+
['ec.group.unban', 'write-agent', ['agent'], 'Remove a group ban'],
|
|
46
|
+
['ec.group.rules.set', 'write-agent', ['agent'], 'Upload and publish group rules content'],
|
|
47
|
+
['ec.group.rules.publish', 'write-agent', ['agent'], 'Publish the current group rules file'],
|
|
48
|
+
['ec.group.rules.update', 'write-agent', ['agent'], 'Update group join rules'],
|
|
49
|
+
].map(([id, category, defaultScopes, description]) => ({
|
|
50
|
+
id,
|
|
51
|
+
category,
|
|
52
|
+
dangerous: false,
|
|
53
|
+
defaultScopes,
|
|
54
|
+
description,
|
|
55
|
+
sources: ['agent-tool'],
|
|
56
|
+
}));
|
|
57
|
+
const MSG_READ_OPERATIONS = [
|
|
58
|
+
['ec.msg.history', 'Read message history for an AUN private relation'],
|
|
59
|
+
['ec.msg.online', 'Read online status for an AUN private relation'],
|
|
60
|
+
].map(([id, description]) => ({
|
|
61
|
+
id,
|
|
62
|
+
category: 'read',
|
|
63
|
+
dangerous: false,
|
|
64
|
+
defaultScopes: ['relation', 'agent'],
|
|
65
|
+
description,
|
|
66
|
+
sources: ['agent-tool'],
|
|
67
|
+
}));
|
|
68
|
+
const GROUP_FS_READ_OPERATIONS = ['ls', 'stat', 'lstat', 'cat', 'find', 'df'].map(kind => ({
|
|
69
|
+
id: `ec.fs.${kind}`,
|
|
70
|
+
category: 'read',
|
|
71
|
+
dangerous: false,
|
|
72
|
+
defaultScopes: ['relation', 'agent'],
|
|
73
|
+
description: `Read current group filesystem (${kind})`,
|
|
74
|
+
sources: ['agent-tool'],
|
|
75
|
+
}));
|
|
76
|
+
const HANDOFF_READ_OPERATIONS = ['status', 'list', 'trace'].map(kind => ({
|
|
77
|
+
id: `ec.handoff.${kind}`,
|
|
78
|
+
category: 'read',
|
|
79
|
+
dangerous: false,
|
|
80
|
+
defaultScopes: ['relation', 'agent'],
|
|
81
|
+
description: `Read handoff ${kind}`,
|
|
82
|
+
sources: ['agent-tool'],
|
|
83
|
+
}));
|
|
84
|
+
const HANDOFF_WRITE_OPERATIONS = [{
|
|
85
|
+
id: 'ec.handoff.return',
|
|
86
|
+
category: 'write-own',
|
|
87
|
+
dangerous: false,
|
|
88
|
+
defaultScopes: ['relation', 'agent'],
|
|
89
|
+
description: 'Return the current handoff result',
|
|
90
|
+
sources: ['agent-tool'],
|
|
91
|
+
}];
|
|
92
|
+
const QUEUE_OPERATIONS = [['read', 'Read the current Agent message queue'], ['clear', 'Clear the current Agent message queue'], ['cancel', 'Cancel a current Agent queued message'], ['interrupt', 'Interrupt a current Agent session']].map(([kind, description]) => ({
|
|
93
|
+
id: `ec.queue.${kind}`,
|
|
94
|
+
category: kind === 'read' ? 'read' : 'write-agent',
|
|
95
|
+
dangerous: false,
|
|
96
|
+
defaultScopes: ['agent'],
|
|
97
|
+
description,
|
|
98
|
+
sources: ['agent-tool'],
|
|
99
|
+
}));
|
|
24
100
|
/**
|
|
25
101
|
* Operation Catalog - 所有命令操作的元数据定义
|
|
26
102
|
*
|
|
@@ -34,7 +110,7 @@ const OPERATIONS = [
|
|
|
34
110
|
dangerous: false,
|
|
35
111
|
defaultScopes: ['relation', 'role', 'agent'],
|
|
36
112
|
description: '列出可用模型',
|
|
37
|
-
sources: ['slash', 'menu', 'menu.cli'],
|
|
113
|
+
sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
|
|
38
114
|
},
|
|
39
115
|
{
|
|
40
116
|
id: 'model.current',
|
|
@@ -42,7 +118,7 @@ const OPERATIONS = [
|
|
|
42
118
|
dangerous: false,
|
|
43
119
|
defaultScopes: ['relation', 'role', 'agent'],
|
|
44
120
|
description: '查询当前使用的模型',
|
|
45
|
-
sources: ['slash', 'menu', 'menu.cli'],
|
|
121
|
+
sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
|
|
46
122
|
},
|
|
47
123
|
{
|
|
48
124
|
id: 'model.effort.current',
|
|
@@ -50,7 +126,7 @@ const OPERATIONS = [
|
|
|
50
126
|
dangerous: false,
|
|
51
127
|
defaultScopes: ['relation', 'role', 'agent'],
|
|
52
128
|
description: '查询当前推理努力度',
|
|
53
|
-
sources: ['slash', 'menu', 'menu.cli'],
|
|
129
|
+
sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
|
|
54
130
|
},
|
|
55
131
|
{
|
|
56
132
|
id: 'model.info',
|
|
@@ -74,7 +150,7 @@ const OPERATIONS = [
|
|
|
74
150
|
dangerous: false,
|
|
75
151
|
defaultScopes: ['relation', 'role', 'agent'],
|
|
76
152
|
description: '切换使用的模型',
|
|
77
|
-
sources: ['slash', 'menu', 'menu.cli'],
|
|
153
|
+
sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
|
|
78
154
|
},
|
|
79
155
|
{
|
|
80
156
|
id: 'model.effort',
|
|
@@ -82,7 +158,7 @@ const OPERATIONS = [
|
|
|
82
158
|
dangerous: false,
|
|
83
159
|
defaultScopes: ['relation', 'role', 'agent'],
|
|
84
160
|
description: '设置推理努力度',
|
|
85
|
-
sources: ['slash', 'menu', 'menu.cli'],
|
|
161
|
+
sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
|
|
86
162
|
},
|
|
87
163
|
{
|
|
88
164
|
id: 'model.reset',
|
|
@@ -195,7 +271,7 @@ const OPERATIONS = [
|
|
|
195
271
|
dangerous: false,
|
|
196
272
|
defaultScopes: ['relation'],
|
|
197
273
|
description: '查看当前会话状态',
|
|
198
|
-
sources: ['slash', 'menu'],
|
|
274
|
+
sources: ['slash', 'menu', 'agent-tool'],
|
|
199
275
|
},
|
|
200
276
|
{
|
|
201
277
|
id: 'session.topic.current',
|
|
@@ -227,7 +303,7 @@ const OPERATIONS = [
|
|
|
227
303
|
dangerous: false,
|
|
228
304
|
defaultScopes: ['relation'],
|
|
229
305
|
description: '重命名会话',
|
|
230
|
-
sources: ['slash', 'menu'],
|
|
306
|
+
sources: ['slash', 'menu', 'agent-tool'],
|
|
231
307
|
},
|
|
232
308
|
{
|
|
233
309
|
id: 'session.delete',
|
|
@@ -244,7 +320,7 @@ const OPERATIONS = [
|
|
|
244
320
|
dangerous: false,
|
|
245
321
|
defaultScopes: ['relation', 'agent'],
|
|
246
322
|
description: '查看当前项目摘要',
|
|
247
|
-
sources: ['menu'],
|
|
323
|
+
sources: ['menu', 'agent-tool'],
|
|
248
324
|
},
|
|
249
325
|
{
|
|
250
326
|
id: 'file.list',
|
|
@@ -481,6 +557,14 @@ const OPERATIONS = [
|
|
|
481
557
|
description: '列出当前 Agent 可用的 BaseAgent',
|
|
482
558
|
sources: ['menu', 'control'],
|
|
483
559
|
},
|
|
560
|
+
{
|
|
561
|
+
id: 'agent.baseagent.update',
|
|
562
|
+
category: 'write-agent',
|
|
563
|
+
dangerous: false,
|
|
564
|
+
defaultScopes: ['agent'],
|
|
565
|
+
description: '切换当前 Agent 使用的 BaseAgent',
|
|
566
|
+
sources: ['menu'],
|
|
567
|
+
},
|
|
484
568
|
{
|
|
485
569
|
id: 'agent.getConfig',
|
|
486
570
|
category: 'read',
|
|
@@ -505,6 +589,14 @@ const OPERATIONS = [
|
|
|
505
589
|
description: '重载 agent 配置',
|
|
506
590
|
sources: ['slash', 'menu', 'control'],
|
|
507
591
|
},
|
|
592
|
+
{
|
|
593
|
+
id: 'agent.bootstrapComplete',
|
|
594
|
+
category: 'write-agent',
|
|
595
|
+
dangerous: false,
|
|
596
|
+
defaultScopes: ['agent'],
|
|
597
|
+
description: 'Complete bootstrap for the current Agent',
|
|
598
|
+
sources: ['agent-tool'],
|
|
599
|
+
},
|
|
508
600
|
{
|
|
509
601
|
id: 'agent.delete',
|
|
510
602
|
category: 'dangerous',
|
|
@@ -520,7 +612,7 @@ const OPERATIONS = [
|
|
|
520
612
|
dangerous: false,
|
|
521
613
|
defaultScopes: ['process'],
|
|
522
614
|
description: '查看系统状态(敏感信息)',
|
|
523
|
-
sources: ['slash', 'menu', 'menu.cli'],
|
|
615
|
+
sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
|
|
524
616
|
},
|
|
525
617
|
{
|
|
526
618
|
id: 'activity.current',
|
|
@@ -530,6 +622,14 @@ const OPERATIONS = [
|
|
|
530
622
|
description: '查看当前中间活动显示策略',
|
|
531
623
|
sources: ['menu'],
|
|
532
624
|
},
|
|
625
|
+
{
|
|
626
|
+
id: 'activity.update',
|
|
627
|
+
category: 'write-agent',
|
|
628
|
+
dangerous: false,
|
|
629
|
+
defaultScopes: ['relation', 'agent'],
|
|
630
|
+
description: '更新中间活动显示策略',
|
|
631
|
+
sources: ['menu'],
|
|
632
|
+
},
|
|
533
633
|
{
|
|
534
634
|
id: 'observable.current',
|
|
535
635
|
category: 'read',
|
|
@@ -538,6 +638,14 @@ const OPERATIONS = [
|
|
|
538
638
|
description: '查看当前 Agent 观察者模式',
|
|
539
639
|
sources: ['menu', 'control'],
|
|
540
640
|
},
|
|
641
|
+
{
|
|
642
|
+
id: 'observable.update',
|
|
643
|
+
category: 'write-agent',
|
|
644
|
+
dangerous: false,
|
|
645
|
+
defaultScopes: ['agent'],
|
|
646
|
+
description: '更新当前 Agent 观察者模式',
|
|
647
|
+
sources: ['menu'],
|
|
648
|
+
},
|
|
541
649
|
{
|
|
542
650
|
id: 'capability.read',
|
|
543
651
|
category: 'read',
|
|
@@ -649,41 +757,41 @@ const OPERATIONS = [
|
|
|
649
757
|
id: 'storage.list',
|
|
650
758
|
category: 'read',
|
|
651
759
|
dangerous: false,
|
|
652
|
-
defaultScopes: ['control'],
|
|
760
|
+
defaultScopes: ['agent', 'control'],
|
|
653
761
|
description: '列出存储对象(敏感信息)',
|
|
654
|
-
sources: ['menu.cli', 'control'],
|
|
762
|
+
sources: ['menu.cli', 'agent-tool', 'control'],
|
|
655
763
|
},
|
|
656
764
|
{
|
|
657
765
|
id: 'storage.quota',
|
|
658
766
|
category: 'read',
|
|
659
767
|
dangerous: false,
|
|
660
|
-
defaultScopes: ['control'],
|
|
768
|
+
defaultScopes: ['agent', 'control'],
|
|
661
769
|
description: '查看存储配额(敏感信息)',
|
|
662
|
-
sources: ['menu.cli', 'control'],
|
|
770
|
+
sources: ['menu.cli', 'agent-tool', 'control'],
|
|
663
771
|
},
|
|
664
772
|
{
|
|
665
773
|
id: 'storage.upload',
|
|
666
774
|
category: 'write-agent',
|
|
667
775
|
dangerous: true,
|
|
668
|
-
defaultScopes: ['control'],
|
|
776
|
+
defaultScopes: ['agent', 'control'],
|
|
669
777
|
description: '上传文件到云存储',
|
|
670
|
-
sources: ['menu.cli', 'control'],
|
|
778
|
+
sources: ['menu.cli', 'agent-tool', 'control'],
|
|
671
779
|
},
|
|
672
780
|
{
|
|
673
781
|
id: 'storage.download',
|
|
674
782
|
category: 'write-agent',
|
|
675
783
|
dangerous: true,
|
|
676
|
-
defaultScopes: ['control'],
|
|
784
|
+
defaultScopes: ['agent', 'control'],
|
|
677
785
|
description: '从云存储下载文件',
|
|
678
|
-
sources: ['menu.cli', 'control'],
|
|
786
|
+
sources: ['menu.cli', 'agent-tool', 'control'],
|
|
679
787
|
},
|
|
680
788
|
{
|
|
681
789
|
id: 'storage.delete',
|
|
682
790
|
category: 'dangerous',
|
|
683
791
|
dangerous: true,
|
|
684
|
-
defaultScopes: ['control'],
|
|
792
|
+
defaultScopes: ['agent', 'control'],
|
|
685
793
|
description: '删除云存储对象',
|
|
686
|
-
sources: ['menu.cli', 'control'],
|
|
794
|
+
sources: ['menu.cli', 'agent-tool', 'control'],
|
|
687
795
|
},
|
|
688
796
|
// ── Gateway & Config Operations ──
|
|
689
797
|
{
|
|
@@ -745,6 +853,52 @@ const OPERATIONS = [
|
|
|
745
853
|
// ── EC Command Operations ──
|
|
746
854
|
// EC daemon 入口根据结构化 IPC 请求构造 operation;Runner 不解析 EC 子命令。
|
|
747
855
|
...CONFIG_MANAGEMENT_OPERATIONS,
|
|
856
|
+
...GROUP_MANAGEMENT_OPERATIONS,
|
|
857
|
+
...MSG_READ_OPERATIONS,
|
|
858
|
+
...GROUP_FS_READ_OPERATIONS,
|
|
859
|
+
...HANDOFF_READ_OPERATIONS,
|
|
860
|
+
...HANDOFF_WRITE_OPERATIONS,
|
|
861
|
+
...QUEUE_OPERATIONS,
|
|
862
|
+
{
|
|
863
|
+
id: 'ec.version',
|
|
864
|
+
category: 'read',
|
|
865
|
+
dangerous: false,
|
|
866
|
+
defaultScopes: ['relation', 'agent', 'process'],
|
|
867
|
+
description: 'Read local EvolCore component versions',
|
|
868
|
+
sources: ['menu.cli', 'agent-tool'],
|
|
869
|
+
},
|
|
870
|
+
{
|
|
871
|
+
id: 'ec.aid.show',
|
|
872
|
+
category: 'read',
|
|
873
|
+
dangerous: true,
|
|
874
|
+
defaultScopes: ['relation', 'agent'],
|
|
875
|
+
description: 'Inspect the current Agent local AID identity and signing state',
|
|
876
|
+
sources: ['agent-tool'],
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
id: 'ec.aid.lookup',
|
|
880
|
+
category: 'read',
|
|
881
|
+
dangerous: false,
|
|
882
|
+
defaultScopes: ['relation', 'agent'],
|
|
883
|
+
description: 'Look up the current Agent public AID record',
|
|
884
|
+
sources: ['agent-tool'],
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
id: 'ec.aid.agentmd.get',
|
|
888
|
+
category: 'read',
|
|
889
|
+
dangerous: false,
|
|
890
|
+
defaultScopes: ['relation', 'agent'],
|
|
891
|
+
description: 'Read and verify the current Agent public agent.md',
|
|
892
|
+
sources: ['agent-tool'],
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
id: 'ec.aid.agentmd.put',
|
|
896
|
+
category: 'write-agent',
|
|
897
|
+
dangerous: true,
|
|
898
|
+
defaultScopes: ['agent'],
|
|
899
|
+
description: 'Sign and publish the current Agent local agent.md',
|
|
900
|
+
sources: ['agent-tool'],
|
|
901
|
+
},
|
|
748
902
|
{
|
|
749
903
|
id: 'ec.msg.send',
|
|
750
904
|
category: 'write-own',
|
|
@@ -779,20 +933,28 @@ const OPERATIONS = [
|
|
|
779
933
|
},
|
|
780
934
|
{
|
|
781
935
|
id: 'ec.ctl.send',
|
|
782
|
-
category: 'write-
|
|
936
|
+
category: 'write-own',
|
|
783
937
|
dangerous: false,
|
|
784
|
-
defaultScopes: ['
|
|
785
|
-
description: '通过 ec ctl send
|
|
938
|
+
defaultScopes: ['relation'],
|
|
939
|
+
description: '通过 ec ctl send 向当前会话发送消息',
|
|
786
940
|
sources: ['agent-tool'],
|
|
787
941
|
},
|
|
788
942
|
{
|
|
789
943
|
id: 'ec.ctl.file',
|
|
790
|
-
category: 'write-
|
|
944
|
+
category: 'write-own',
|
|
791
945
|
dangerous: false,
|
|
792
|
-
defaultScopes: ['
|
|
793
|
-
description: '通过 ec ctl file
|
|
946
|
+
defaultScopes: ['relation'],
|
|
947
|
+
description: '通过 ec ctl file 向当前会话发送项目文件',
|
|
794
948
|
sources: ['agent-tool'],
|
|
795
949
|
},
|
|
950
|
+
...['read', 'clear', 'cancel', 'interrupt'].map(action => ({
|
|
951
|
+
id: `ec.ctl.queue.${action}`,
|
|
952
|
+
category: action === 'read' ? 'read' : 'write-own',
|
|
953
|
+
dangerous: false,
|
|
954
|
+
defaultScopes: ['relation'],
|
|
955
|
+
description: `${action} the current managed session queue`,
|
|
956
|
+
sources: ['agent-tool'],
|
|
957
|
+
})),
|
|
796
958
|
// ── Raw CLI & Shell Execution ──
|
|
797
959
|
{
|
|
798
960
|
id: 'cli.exec.raw',
|
|
@@ -48,3 +48,21 @@ export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName) {
|
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
+
export function hasPendingPostBootstrapWelcomeOutbox(aid) {
|
|
52
|
+
return !!outbox.findByDedupeKey(aid, postBootstrapWelcomeOperationId(aid));
|
|
53
|
+
}
|
|
54
|
+
/** Bind the durable completion welcome to the fresh post-bootstrap session. */
|
|
55
|
+
export function bindPostBootstrapWelcomeOutboxSession(aid, sessionId) {
|
|
56
|
+
const entry = outbox.findByDedupeKey(aid, postBootstrapWelcomeOperationId(aid));
|
|
57
|
+
if (!entry)
|
|
58
|
+
return false;
|
|
59
|
+
if (entry.context?.sessionId === sessionId)
|
|
60
|
+
return true;
|
|
61
|
+
return outbox.replace(aid, {
|
|
62
|
+
...entry,
|
|
63
|
+
context: {
|
|
64
|
+
...(entry.context ?? {}),
|
|
65
|
+
sessionId,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -11,8 +11,12 @@ import { activeBaseagent } from './model/config-scope.js';
|
|
|
11
11
|
import { buildEnvelope } from './message/message-utils.js';
|
|
12
12
|
import { BOOTSTRAP_MESSAGE_TTL_MS, bootstrapInitialMessageOperationId } from './bootstrap-messages.js';
|
|
13
13
|
/** Coordinate the write-ahead completion welcome with the lifecycle commit. */
|
|
14
|
-
export async function completeBootstrapWithWelcome(service, aid, welcome) {
|
|
14
|
+
export async function completeBootstrapWithWelcome(service, aid, welcome, sessions) {
|
|
15
15
|
const lifecycle = service.lifecycleOf(aid);
|
|
16
|
+
if (lifecycle !== 'bootstrapping' && lifecycle !== 'active') {
|
|
17
|
+
const result = service.completeBootstrap(aid);
|
|
18
|
+
return { ...result, reloaded: false };
|
|
19
|
+
}
|
|
16
20
|
if (lifecycle === 'bootstrapping') {
|
|
17
21
|
if (!welcome) {
|
|
18
22
|
return {
|
|
@@ -31,13 +35,68 @@ export async function completeBootstrapWithWelcome(service, aid, welcome) {
|
|
|
31
35
|
};
|
|
32
36
|
}
|
|
33
37
|
}
|
|
38
|
+
const welcomePending = welcome
|
|
39
|
+
? await welcome.hasPendingPostBootstrapWelcome()
|
|
40
|
+
: false;
|
|
41
|
+
const needsMainSessionBoundary = lifecycle === 'bootstrapping' || welcomePending;
|
|
42
|
+
let mainSession;
|
|
43
|
+
if (needsMainSessionBoundary) {
|
|
44
|
+
if (!sessions) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
code: 'MAIN_SESSION_UNAVAILABLE',
|
|
48
|
+
error: `No session coordinator available to create the post-bootstrap main session for ${aid}`,
|
|
49
|
+
reloaded: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
mainSession = await sessions.ensurePostBootstrapMainSession();
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
return {
|
|
57
|
+
ok: false,
|
|
58
|
+
code: 'MAIN_SESSION_CREATE_FAILED',
|
|
59
|
+
error: e instanceof Error ? e.message : `Failed to create the post-bootstrap main session for ${aid}`,
|
|
60
|
+
reloaded: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (!mainSession.sessionId) {
|
|
64
|
+
return {
|
|
65
|
+
ok: false,
|
|
66
|
+
code: 'MAIN_SESSION_CREATE_FAILED',
|
|
67
|
+
error: `Failed to create the post-bootstrap main session for ${aid}`,
|
|
68
|
+
reloaded: false,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (welcomePending && welcome && !await welcome.bindPostBootstrapWelcomeToSession(mainSession.sessionId)) {
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
code: 'WELCOME_SESSION_BIND_FAILED',
|
|
75
|
+
error: `Failed to bind the post-bootstrap welcome to session ${mainSession.sessionId}`,
|
|
76
|
+
reloaded: false,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
34
80
|
const result = service.completeBootstrap(aid);
|
|
35
81
|
if (!result.ok)
|
|
36
82
|
return { ...result, reloaded: false };
|
|
37
|
-
if (!welcome)
|
|
38
|
-
return {
|
|
83
|
+
if (!welcome) {
|
|
84
|
+
return {
|
|
85
|
+
...result,
|
|
86
|
+
reloaded: true,
|
|
87
|
+
welcomeQueued: false,
|
|
88
|
+
mainSessionId: mainSession?.sessionId,
|
|
89
|
+
mainSessionCreated: mainSession?.created,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
39
92
|
const welcomeQueued = await welcome.reconcilePostBootstrapWelcome();
|
|
40
|
-
return {
|
|
93
|
+
return {
|
|
94
|
+
...result,
|
|
95
|
+
reloaded: true,
|
|
96
|
+
welcomeQueued,
|
|
97
|
+
mainSessionId: mainSession?.sessionId,
|
|
98
|
+
mainSessionCreated: mainSession?.created,
|
|
99
|
+
};
|
|
41
100
|
}
|
|
42
101
|
export class BootstrapService {
|
|
43
102
|
agentRegistry;
|
|
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import os from 'os';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { execFileSync } from 'child_process';
|
|
5
|
+
import { discoverSkillDirectories } from '../skill-discovery.js';
|
|
5
6
|
function readJson(file) {
|
|
6
7
|
try {
|
|
7
8
|
if (!fs.existsSync(file))
|
|
@@ -12,31 +13,6 @@ function readJson(file) {
|
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
14
15
|
}
|
|
15
|
-
function listDirectories(dir) {
|
|
16
|
-
try {
|
|
17
|
-
if (!fs.existsSync(dir))
|
|
18
|
-
return [];
|
|
19
|
-
return fs.readdirSync(dir, { withFileTypes: true })
|
|
20
|
-
.filter(entry => entry.isDirectory())
|
|
21
|
-
.map(entry => entry.name);
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
return [];
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function readSkillDescription(skillDir) {
|
|
28
|
-
const file = path.join(skillDir, 'SKILL.md');
|
|
29
|
-
try {
|
|
30
|
-
const text = fs.readFileSync(file, 'utf-8');
|
|
31
|
-
const firstBodyLine = text.split(/\r?\n/)
|
|
32
|
-
.map(line => line.trim())
|
|
33
|
-
.find(line => line && !line.startsWith('#') && !line.startsWith('---') && !line.includes(':'));
|
|
34
|
-
return firstBodyLine ? firstBodyLine.slice(0, 180) : undefined;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return undefined;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
16
|
function describeMcpSpec(spec) {
|
|
41
17
|
const command = typeof spec?.command === 'string' ? spec.command : undefined;
|
|
42
18
|
if (command)
|
|
@@ -60,14 +36,15 @@ function discoverSkills(projectPath) {
|
|
|
60
36
|
const seen = new Set();
|
|
61
37
|
const items = [];
|
|
62
38
|
for (const root of roots) {
|
|
63
|
-
for (const
|
|
64
|
-
|
|
39
|
+
for (const skill of discoverSkillDirectories(root.dir)) {
|
|
40
|
+
const { id } = skill;
|
|
41
|
+
if (seen.has(id))
|
|
65
42
|
continue;
|
|
66
|
-
seen.add(
|
|
43
|
+
seen.add(id);
|
|
67
44
|
items.push({
|
|
68
|
-
id
|
|
69
|
-
label:
|
|
70
|
-
desc:
|
|
45
|
+
id,
|
|
46
|
+
label: id,
|
|
47
|
+
desc: skill.description,
|
|
71
48
|
source: root.source,
|
|
72
49
|
});
|
|
73
50
|
}
|
|
@@ -138,6 +115,7 @@ async function discoverPluginsFromCli() {
|
|
|
138
115
|
encoding: 'utf-8',
|
|
139
116
|
timeout: 3000,
|
|
140
117
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
118
|
+
windowsHide: process.platform === 'win32',
|
|
141
119
|
});
|
|
142
120
|
const parsed = JSON.parse(output);
|
|
143
121
|
const list = Array.isArray(parsed) ? parsed : Array.isArray(parsed?.installed) ? parsed.installed : [];
|