evolcore 0.0.31 → 0.0.33
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 +35 -0
- package/bin/install-codex-managed-hooks.mjs +124 -37
- package/dist/agents/claude-runner.js +29 -2
- package/dist/agents/codex/app-server-client.js +3 -0
- package/dist/agents/codex/diagnostics.js +76 -44
- package/dist/agents/codex-runner.js +51 -24
- package/dist/agents/ecagent-runner.js +9 -13
- package/dist/agents/gemini-runner.js +4 -0
- package/dist/aun/aid/store.js +0 -81
- package/dist/aun/group/fs-download.js +1 -10
- package/dist/aun/group/operations.js +0 -1
- package/dist/aun/msg/history.js +1 -0
- package/dist/aun/msg/managed-operation.js +130 -32
- package/dist/aun/msg/p2p.js +0 -1
- package/dist/aun/outbox.js +50 -1
- package/dist/aun/service-proxy.js +12 -18
- package/dist/aun/storage/index.js +29 -0
- package/dist/channels/aun.js +38 -137
- package/dist/channels/daemon.js +257 -2
- package/dist/cli/agent-command.js +64 -31
- package/dist/cli/agent-create.js +43 -24
- package/dist/cli/agent.js +16 -70
- package/dist/cli/aun-commands.js +512 -32
- package/dist/cli/contact.js +8 -2
- package/dist/cli/ctl-command.js +1 -2
- package/dist/cli/daemon-commands.js +82 -13
- package/dist/cli/debug-mode.js +154 -0
- package/dist/cli/diag.js +2 -2
- package/dist/cli/handoff-command.js +18 -5
- package/dist/cli/index.js +81 -64
- package/dist/cli/init.js +2 -2
- package/dist/cli/managed-command-guard.js +5 -0
- package/dist/cli/memory-command.js +93 -12
- package/dist/cli/model.js +14 -138
- package/dist/cli/queue-command.js +51 -0
- package/dist/cli/response.js +5 -54
- package/dist/cli/session-command.js +194 -0
- package/dist/cli/skill-command.js +85 -3
- package/dist/cli/stats.js +10 -4
- package/dist/cli/task-command.js +1 -0
- package/dist/cli/task-context.js +16 -0
- package/dist/cli/thread-command.js +620 -0
- package/dist/cli/trigger-command.js +76 -50
- package/dist/config/builtin-roles.js +9 -7
- package/dist/config/config-field-policy.js +2 -3
- package/dist/config/config-manager.js +7 -2
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +15 -0
- package/dist/core/agent-ipc-registration.js +65 -22
- package/dist/core/auth/agent-delegation.js +42 -2
- package/dist/core/auth/debug-context.js +139 -0
- package/dist/core/auth/delegation-authorization.js +1 -0
- package/dist/core/auth/operation-authorizer.js +24 -1
- package/dist/core/auth/operation-catalog.js +44 -3
- package/dist/core/background-session/session-cleanup.js +212 -0
- package/dist/core/background-session/types.js +10 -0
- package/dist/core/bootstrap-messages.js +1 -1
- package/dist/core/bootstrap-service.js +6 -3
- package/dist/core/command/command-handler.js +224 -45
- package/dist/core/command/diag-service.js +5 -1
- package/dist/core/command/memory-slash.js +6 -2
- package/dist/core/command/menu-catalog.js +48 -1
- package/dist/core/command/menu-handler.js +92 -16
- package/dist/core/command/menu-protocol.js +24 -1
- package/dist/core/command/skill-slash.js +322 -0
- package/dist/core/command/slash-gate.js +6 -4
- package/dist/core/command/slash-handler.js +193 -13
- package/dist/core/command/topic-slash.js +528 -0
- package/dist/core/evolagent-registry.js +20 -5
- package/dist/core/handoff/ipc-registration.js +38 -0
- package/dist/core/handoff/runtime.js +5 -11
- package/dist/core/handoff/store.js +5 -0
- package/dist/core/ipc-registration.js +210 -9
- package/dist/core/memory/consolidation-context.js +49 -16
- package/dist/core/memory/consolidation-ops-records.js +35 -0
- package/dist/core/memory/consolidation-queue-format.js +21 -0
- package/dist/core/memory/consolidation.js +174 -180
- package/dist/core/message/aun-ipc-sender.js +207 -8
- package/dist/core/message/im-renderer.js +149 -6
- package/dist/core/message/message-bridge.js +13 -3
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +131 -3
- package/dist/core/message/peer-mode.js +6 -1
- package/dist/core/message/response-engine.js +379 -69
- package/dist/core/message/subtask-tool-projection.js +140 -0
- package/dist/core/model/catalog-service.js +17 -12
- package/dist/core/permission/ec-command-parser.js +126 -7
- package/dist/core/permission/sandbox-runtime.js +14 -1
- package/dist/core/session/session-idle-monitor.js +249 -22
- package/dist/core/session/session-manager.js +54 -9
- package/dist/core/skill/command-parser.js +13 -0
- package/dist/core/skill/index-generator.js +4 -1
- package/dist/core/skill/startup.js +41 -0
- package/dist/core/skill/switch-resolver.js +55 -29
- package/dist/core/task/task-recovery-service.js +2 -0
- package/dist/core/task/task-resume-operation.js +11 -0
- package/dist/core/thread/command-parser.js +125 -0
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +95 -0
- package/dist/core/thread/thread-context-storage.js +131 -0
- package/dist/core/thread/thread-operation.js +258 -0
- package/dist/core/thread/thread-route.js +33 -0
- package/dist/core/thread/thread-service.js +777 -0
- package/dist/core/thread/types.js +1 -0
- package/dist/eck/message-renderer.js +35 -0
- package/dist/index.js +10 -7
- package/dist/ipc.js +234 -17
- package/dist/paths.js +23 -0
- package/dist/response-system/engines/v1/proactive-flow.js +169 -80
- package/dist/trigger/authorization.js +59 -29
- package/dist/trigger/feedback.js +7 -1
- package/dist/trigger/ipc-service.js +49 -35
- package/dist/trigger/parser.js +63 -1
- package/dist/trigger/script-sandbox.js +58 -77
- package/dist/trigger/validation.js +14 -0
- package/dist/utils/error-utils.js +22 -1
- package/kits/docs/AUTHORING.md +1 -1
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/context-assembly.md +1 -0
- package/kits/docs/evolcore/INDEX.md +3 -2
- package/kits/docs/evolcore/agent-create.md +39 -28
- package/kits/docs/evolcore/agent.md +19 -4
- package/kits/docs/evolcore/ec-capabilities.md +4 -0
- package/kits/docs/evolcore/group-collaboration.md +3 -5
- package/kits/docs/evolcore/group.md +3 -4
- package/kits/docs/evolcore/memory-consolidation.md +1 -1
- package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
- package/kits/docs/evolcore/menu-protocol.md +7 -0
- package/kits/docs/evolcore/msg.md +5 -8
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +267 -0
- package/kits/docs/evolcore/trigger.md +2 -2
- package/kits/docs/prompt-loading-architecture.md +1 -0
- package/kits/eck_manifest.json +61 -26
- package/kits/eck_message_manifest.json +169 -10
- package/kits/rules/01-overview.md +0 -9
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +7 -1
- package/kits/rules/07-memory-and-thread.md +202 -0
- package/kits/schemas/relation-config.schema.9.json +18 -3
- package/kits/schemas/role-config.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.2.json +6 -6
- package/kits/schemas/single-session.schema.3.json +6 -6
- package/kits/skills/.switches.json +12 -1
- package/kits/skills/ec-group/SKILL.md +234 -0
- package/kits/skills/ec-skill/SKILL.md +10 -1
- package/kits/skills/ec-skill/scripts/cli.mjs +15 -1
- package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
- package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
- package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
- package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
- package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
- package/kits/skills/thread-ops/SKILL.md +492 -0
- package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
- package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
- package/kits/skills/wechat-article-reader/SKILL.md +97 -0
- package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
- package/kits/templates/bootstrap-welcome.md +7 -7
- package/kits/templates/memory-consolidation/forget.md +5 -0
- package/kits/templates/memory-consolidation/generalize.md +5 -0
- package/kits/templates/memory-consolidation/profile.md +5 -0
- package/kits/templates/memory-consolidation/promote.md +5 -0
- package/kits/templates/message-fragments/item.md +2 -1
- package/kits/templates/message-fragments/thread-context.md +6 -0
- package/kits/templates/message-fragments/trigger-session.md +2 -0
- package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
- package/kits/templates/roles/member.json +2 -0
- package/kits/templates/roles/visitor.json +2 -0
- package/kits/templates/system-fragments/bootstrap.md +66 -72
- package/kits/templates/system-fragments/channel.md +3 -6
- package/kits/templates/system-fragments/commands.md +2 -1
- package/kits/templates/system-fragments/managed-runtime.md +15 -0
- package/kits/templates/system-fragments/reply.md +3 -2
- package/kits/templates/system-fragments/session.md +5 -14
- package/package.json +3 -1
- package/kits/docs/evolcore/group-fs.md +0 -17
- package/kits/docs/venues/aun-group.md +0 -45
- package/kits/docs/venues/group.md +0 -43
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
1
|
import { getEventCatalog } from '../core/event-catalog.js';
|
|
4
2
|
import { authorizeOperation, canApprovePersistentFullAccessTrigger, isCrossAgentTriggerOperationAllowed, } from '../core/auth/auth-gateway.js';
|
|
5
3
|
import { auditFullAccessEvent } from '../core/auth/authorization-audit.js';
|
|
6
4
|
import { assertTriggerLocalFileAuthority, daemonPrivilegedTriggerReason, } from './authorization.js';
|
|
7
|
-
import { decodeTriggerScriptFile
|
|
5
|
+
import { decodeTriggerScriptFile } from './local-files.js';
|
|
8
6
|
import { applyTriggerPatch } from './patch.js';
|
|
9
7
|
import { definitionRevision, normalizeTriggerDefinition, splitScriptCommand } from './validation.js';
|
|
10
8
|
export function createTriggerBaseagentResolver({ daemonTriggerOwnerAid, getAgentName, getDaemonAgentName, agentMap, }) {
|
|
@@ -51,6 +49,9 @@ export function materializeTriggerCreateBaseagent(input, agentAid, dependencies)
|
|
|
51
49
|
}
|
|
52
50
|
export function createTriggerIpcExecutor(dependencies) {
|
|
53
51
|
return async (cmd) => {
|
|
52
|
+
let approvedActor;
|
|
53
|
+
let approvedAgentAid;
|
|
54
|
+
let approvedOperation;
|
|
54
55
|
const schedulerFor = (agentAid) => {
|
|
55
56
|
const scheduler = dependencies.getScheduler(agentAid);
|
|
56
57
|
if (!scheduler)
|
|
@@ -102,7 +103,10 @@ export function createTriggerIpcExecutor(dependencies) {
|
|
|
102
103
|
return { ...definition, authorizedBy };
|
|
103
104
|
};
|
|
104
105
|
const authorizeTrigger = async (agentAid, operation, triggerId, contextOnly = false) => {
|
|
105
|
-
|
|
106
|
+
if (approvedActor && (agentAid !== approvedAgentAid || operation !== approvedOperation)) {
|
|
107
|
+
throw new Error('Trigger operation does not match its approved argv');
|
|
108
|
+
}
|
|
109
|
+
const actor = approvedActor ?? await dependencies.authenticateActor(agentAid, cmd.actorSessionId, cmd.delegationToken, cmd.delegationCommandHash, cmd.controlToken, contextOnly);
|
|
106
110
|
if (actor.permissionMode === 'readonly' && !actor.fullAccess
|
|
107
111
|
&& !['trigger.list', 'trigger.show', 'trigger.history', 'trigger.eventCatalog'].includes(operation)) {
|
|
108
112
|
throw new Error('readonly tasks cannot modify or run Triggers');
|
|
@@ -160,38 +164,48 @@ export function createTriggerIpcExecutor(dependencies) {
|
|
|
160
164
|
}
|
|
161
165
|
return actor;
|
|
162
166
|
};
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
167
|
+
if (cmd.type === 'trigger.op') {
|
|
168
|
+
if (!Array.isArray(cmd.argv) || cmd.argv.some((value) => typeof value !== 'string')
|
|
169
|
+
|| typeof cmd.actorSessionId !== 'string' || !cmd.actorSessionId) {
|
|
170
|
+
throw new Error('Managed Trigger requires argv and actorSessionId');
|
|
171
|
+
}
|
|
172
|
+
const session = await dependencies.getSessionById(cmd.actorSessionId);
|
|
173
|
+
if (!session?.selfAID)
|
|
174
|
+
throw new Error('Trigger actor session is unavailable');
|
|
175
|
+
const { resolveTriggerCommandArgv, buildTriggerCreateRequest, buildTriggerUpdateRequest } = await import('../cli/trigger-command.js');
|
|
176
|
+
const argv = cmd.argv;
|
|
177
|
+
const command = resolveTriggerCommandArgv(argv, session.selfAID);
|
|
178
|
+
cmd = { ...command, actorSessionId: cmd.actorSessionId, delegationToken: cmd.delegationToken,
|
|
179
|
+
delegationCommandHash: cmd.delegationCommandHash };
|
|
180
|
+
approvedAgentAid = requireAgent(command.agentAid);
|
|
181
|
+
approvedOperation = command.type;
|
|
182
|
+
approvedActor = await authorizeTrigger(approvedAgentAid, approvedOperation, command.triggerId);
|
|
183
|
+
const args = argv.slice(2);
|
|
184
|
+
const usesFiles = args.some(value => ['--file', '--prompt-file', '--script-path', '--script-file']
|
|
185
|
+
.some(flag => value === flag || value.startsWith(`${flag}=`)));
|
|
186
|
+
if (usesFiles)
|
|
187
|
+
assertTriggerLocalFileAuthority(approvedActor);
|
|
188
|
+
const fileScope = approvedActor.fullAccess ? undefined : {
|
|
189
|
+
selfAid: approvedAgentAid, projectPath: session.projectPath,
|
|
190
|
+
sessionRuntimeDir: approvedActor.sessionRuntimeDir, cwd: session.projectPath,
|
|
191
|
+
};
|
|
192
|
+
if (command.type === 'trigger.create') {
|
|
193
|
+
const parsed = await buildTriggerCreateRequest(args, fileScope, approvedAgentAid);
|
|
194
|
+
if (parsed.definition?.agentAid !== approvedAgentAid)
|
|
195
|
+
throw new Error('Imported Trigger does not match the authorized Agent');
|
|
196
|
+
cmd = { ...cmd, ...parsed };
|
|
197
|
+
}
|
|
198
|
+
else if (command.type === 'trigger.update') {
|
|
199
|
+
cmd = { ...cmd, ...await buildTriggerUpdateRequest(args, fileScope, approvedAgentAid) };
|
|
200
|
+
}
|
|
201
|
+
else if (usesFiles) {
|
|
202
|
+
throw new Error('File inputs are only valid for Trigger create/update');
|
|
194
203
|
}
|
|
204
|
+
}
|
|
205
|
+
else if (cmd.actorSessionId) {
|
|
206
|
+
throw new Error('Managed callers must use trigger.op with approved argv');
|
|
207
|
+
}
|
|
208
|
+
switch (cmd.type) {
|
|
195
209
|
case 'trigger.list': {
|
|
196
210
|
const agentAid = requireAgent(cmd.agentAid);
|
|
197
211
|
const actor = await authorizeTrigger(agentAid, 'trigger.list');
|
package/dist/trigger/parser.js
CHANGED
|
@@ -11,7 +11,7 @@ const TRIGGER_UPDATE_FLAGS = new Set([
|
|
|
11
11
|
]);
|
|
12
12
|
const TRIGGER_CREATE_FLAGS = new Set([
|
|
13
13
|
'once', 'delay', 'at', 'cron', 'every', 'event', 'event-filter', 'tz',
|
|
14
|
-
'exec', 'prompt', 'name', 'agent',
|
|
14
|
+
'exec', 'prompt', 'name', 'agent', 'label',
|
|
15
15
|
'script-path', 'script-runtime', 'script-args', 'script-timeout', 'execution-timeout',
|
|
16
16
|
'feedback', 'target-channel', 'target-channel-id', 'target-chat-type', 'target-session', 'target-thread-id',
|
|
17
17
|
'trigger-thread', 'baseagent',
|
|
@@ -68,6 +68,60 @@ export function parseDuration(s) {
|
|
|
68
68
|
const multiplier = unit === 'd' ? 86_400_000 : unit === 'h' ? 3_600_000 : unit === 'm' ? 60_000 : 1_000;
|
|
69
69
|
return amount * multiplier;
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* T10: 从原始 args 里提取 `--label key=value`(支持多次出现,值内可用逗号分隔多对)。
|
|
73
|
+
* 约定:labels 若存在则必须含 `kind`(渲染模板路由 key)。
|
|
74
|
+
*/
|
|
75
|
+
export function extractLabels(args) {
|
|
76
|
+
const tokens = [];
|
|
77
|
+
if (Array.isArray(args)) {
|
|
78
|
+
for (let i = 0; i < args.length; i++) {
|
|
79
|
+
const a = args[i];
|
|
80
|
+
if (a === '--label') {
|
|
81
|
+
const next = args[i + 1];
|
|
82
|
+
if (next === undefined || next.startsWith('--'))
|
|
83
|
+
return { error: '--label 不能为空(格式:--label key=value)' };
|
|
84
|
+
tokens.push(next);
|
|
85
|
+
i += 1;
|
|
86
|
+
}
|
|
87
|
+
else if (a.startsWith('--label=')) {
|
|
88
|
+
tokens.push(a.slice('--label='.length));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const re = /--label(?:=(\S+)|(?:\s+(?!--)(\S+)))?/g;
|
|
94
|
+
let m;
|
|
95
|
+
while ((m = re.exec(args)) !== null) {
|
|
96
|
+
const v = m[1] ?? m[2];
|
|
97
|
+
if (v === undefined)
|
|
98
|
+
return { error: '--label 不能为空(格式:--label key=value)' };
|
|
99
|
+
tokens.push(v.replace(/^["']|["']$/g, ''));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (tokens.length === 0)
|
|
103
|
+
return { labels: {} };
|
|
104
|
+
const labels = {};
|
|
105
|
+
for (const token of tokens) {
|
|
106
|
+
for (const pair of token.split(',')) {
|
|
107
|
+
const trimmed = pair.trim();
|
|
108
|
+
if (!trimmed)
|
|
109
|
+
continue;
|
|
110
|
+
const eq = trimmed.indexOf('=');
|
|
111
|
+
if (eq <= 0)
|
|
112
|
+
return { error: `--label 格式无效: "${trimmed}"(应为 key=value)` };
|
|
113
|
+
const key = trimmed.slice(0, eq).trim();
|
|
114
|
+
const value = trimmed.slice(eq + 1);
|
|
115
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
|
|
116
|
+
return { error: `--label key 名无效: "${key}"(只允许字母、数字、下划线,且不以数字开头)` };
|
|
117
|
+
}
|
|
118
|
+
labels[key] = value;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!('kind' in labels))
|
|
122
|
+
return { error: '--label 必须包含 kind(如 --label kind=default)' };
|
|
123
|
+
return { labels };
|
|
124
|
+
}
|
|
71
125
|
export function parseIsoDate(s) {
|
|
72
126
|
const d = new Date(s);
|
|
73
127
|
return isNaN(d.getTime()) ? null : d.getTime();
|
|
@@ -496,6 +550,9 @@ export function parseTriggerSet(args) {
|
|
|
496
550
|
if (!parsed.ok)
|
|
497
551
|
return { ok: false, error: withPromptFileHint(parsed.error, args) };
|
|
498
552
|
const value = parsed.value;
|
|
553
|
+
const labelsResult = extractLabels(args);
|
|
554
|
+
if ('error' in labelsResult)
|
|
555
|
+
return { ok: false, error: labelsResult.error };
|
|
499
556
|
return {
|
|
500
557
|
ok: true,
|
|
501
558
|
value: {
|
|
@@ -525,6 +582,7 @@ export function parseTriggerSet(args) {
|
|
|
525
582
|
model: value.model,
|
|
526
583
|
effort: value.effort,
|
|
527
584
|
permissionMode: value.permissionMode,
|
|
585
|
+
...(Object.keys(labelsResult.labels).length > 0 ? { labels: labelsResult.labels } : {}),
|
|
528
586
|
},
|
|
529
587
|
};
|
|
530
588
|
}
|
|
@@ -538,6 +596,9 @@ export function parseTriggerSetArgv(args, opts = {}) {
|
|
|
538
596
|
if (!parsed.ok)
|
|
539
597
|
return { ok: false, error: withPromptFileHint(parsed.error, args, opts) };
|
|
540
598
|
const value = parsed.value;
|
|
599
|
+
const labelsResult = extractLabels(args);
|
|
600
|
+
if ('error' in labelsResult)
|
|
601
|
+
return { ok: false, error: labelsResult.error };
|
|
541
602
|
return {
|
|
542
603
|
ok: true,
|
|
543
604
|
value: {
|
|
@@ -567,6 +628,7 @@ export function parseTriggerSetArgv(args, opts = {}) {
|
|
|
567
628
|
model: value.model,
|
|
568
629
|
effort: value.effort,
|
|
569
630
|
permissionMode: value.permissionMode,
|
|
631
|
+
...(Object.keys(labelsResult.labels).length > 0 ? { labels: labelsResult.labels } : {}),
|
|
570
632
|
},
|
|
571
633
|
};
|
|
572
634
|
}
|
|
@@ -6,28 +6,16 @@ import { pathToFileURL } from 'node:url';
|
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
import { resolveCodexCliPath } from '../agents/baseagent.js';
|
|
8
8
|
import { ensureSessionRuntimeDir } from '../cli/task-context.js';
|
|
9
|
-
import { resolveBubblewrapPath } from '../core/permission/sandbox-runtime.js';
|
|
10
|
-
import {
|
|
9
|
+
import { buildBubblewrapCommand, buildHClassGuardCommand, resolveBubblewrapPath, } from '../core/permission/sandbox-runtime.js';
|
|
10
|
+
import { resolvePhaseOneExecutionSandbox } from '../core/permission/mode.js';
|
|
11
|
+
import { sanitizeShellExecutionEnvironment } from '../core/permission/shell-environment.js';
|
|
12
|
+
import { buildCodexProtectedFilesystemRules, classifyProtectedPath, getExistingRelationAttachmentDirs, isSameOrDescendant, } from '../core/permission/protected-paths.js';
|
|
11
13
|
import { resolveRoot } from '../paths.js';
|
|
12
14
|
import { buildCliLaunchCommand, killProcess, resolveCommandPath } from '../utils/cross-platform.js';
|
|
13
15
|
import { TRIGGER_LOCAL_FILE_LIMIT } from './local-files.js';
|
|
14
|
-
const SAFE_ENVIRONMENT_KEYS = [
|
|
15
|
-
'ComSpec', 'COMSPEC', 'LANG', 'LC_ALL', 'OS', 'PATH', 'PATHEXT',
|
|
16
|
-
'ProgramData', 'ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432',
|
|
17
|
-
'SystemDrive', 'SystemRoot', 'WINDIR',
|
|
18
|
-
];
|
|
19
|
-
const SYSTEM_READ_ROOTS = ['/usr/bin', '/usr/lib', '/usr/lib64', '/usr/local/bin', '/usr/local/lib', '/usr/share/locale', '/usr/share/zoneinfo', '/bin', '/sbin', '/lib', '/lib64'];
|
|
20
|
-
const SYSTEM_READ_FILES = ['/etc/ld.so.cache', '/etc/localtime', '/etc/passwd', '/etc/group'];
|
|
21
|
-
const CONTROL_DIRECTORY_NAMES = ['agents', 'AIDs', 'aids', 'data', 'CA', '.snapshots', 'logs', 'backups'];
|
|
22
16
|
const WINDOWS_SANDBOX_SETUP_VERSION = 5;
|
|
23
|
-
const
|
|
17
|
+
const SCRIPT_ENVIRONMENT_EXCLUDES = [
|
|
24
18
|
'CODEX_HOME',
|
|
25
|
-
'EVOLCORE_DELEGATION_TOKEN',
|
|
26
|
-
'EVOLCORE_CODEX_SESSION_TOKEN',
|
|
27
|
-
'EVOLCORE_TASK_RUNTIME_CONTEXT',
|
|
28
|
-
'EVOLCORE_INSTANCE_SOCKET',
|
|
29
|
-
'EVOLCORE_DAEMON_SOCKET',
|
|
30
|
-
'EVOLCORE_IPC_SOCKET',
|
|
31
19
|
'OPENAI_API_KEY',
|
|
32
20
|
'CODEX_API_KEY',
|
|
33
21
|
'ANTHROPIC_API_KEY',
|
|
@@ -48,6 +36,8 @@ export function buildTriggerScriptLaunch(input) {
|
|
|
48
36
|
if (!authorization.permissionMode || authorization.permissionMode === 'fullaccess') {
|
|
49
37
|
throw new Error('scoped Trigger execution requires an effective non-fullaccess permission mode');
|
|
50
38
|
}
|
|
39
|
+
const sandboxDecision = resolvePhaseOneExecutionSandbox(authorization.permissionMode, authorization.role);
|
|
40
|
+
const readonly = sandboxDecision.permissionMode === 'readonly';
|
|
51
41
|
if (process.platform !== 'linux' && process.platform !== 'win32') {
|
|
52
42
|
throw new Error('scoped Trigger script isolation is unavailable on this host');
|
|
53
43
|
}
|
|
@@ -108,9 +98,12 @@ export function buildTriggerScriptLaunch(input) {
|
|
|
108
98
|
fs.writeFileSync(scriptPath, scriptBytes, { flag: 'wx', mode: 0o400 });
|
|
109
99
|
preserveNodeModuleType(runtime, input.scriptPath, snapshotDir);
|
|
110
100
|
const env = buildSandboxEnvironment(workDir);
|
|
111
|
-
const blockedPaths = protectedScriptPaths(root, input.trigger.agentAid);
|
|
112
101
|
const scriptArgs = [scriptPath, ...input.scriptArgs];
|
|
113
102
|
if (windowsBackend) {
|
|
103
|
+
const filesystem = buildCodexProtectedFilesystemRules(root, {
|
|
104
|
+
selfAid: input.trigger.agentAid,
|
|
105
|
+
denyLClassRead: readonly,
|
|
106
|
+
});
|
|
114
107
|
const systemRoot = process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows';
|
|
115
108
|
const readRoots = [
|
|
116
109
|
path.join(systemRoot, 'System32'),
|
|
@@ -122,25 +115,37 @@ export function buildTriggerScriptLaunch(input) {
|
|
|
122
115
|
snapshotDir,
|
|
123
116
|
].filter(value => fs.existsSync(value));
|
|
124
117
|
const entries = [
|
|
125
|
-
{ path: { type: 'special', value: { kind: 'root' } },
|
|
118
|
+
{ path: { type: 'special', value: { kind: 'root' } },
|
|
119
|
+
access: sandboxDecision.state === 'off' ? 'write' : 'read' },
|
|
126
120
|
...readRoots.map(value => filesystemEntry(value, 'read')),
|
|
127
|
-
filesystemEntry(projectPath,
|
|
121
|
+
filesystemEntry(projectPath, readonly ? 'read' : 'write'),
|
|
122
|
+
filesystemEntry(snapshotDir, 'read'),
|
|
128
123
|
filesystemEntry(workDir, 'write'),
|
|
129
|
-
|
|
124
|
+
filesystemEntry(windowsBackend.home, 'deny'),
|
|
125
|
+
...Object.entries(filesystem).flatMap(([value, access]) => typeof access === 'number' ? [] : [{
|
|
126
|
+
path: /[*?[\]]/.test(value)
|
|
127
|
+
? { type: 'glob_pattern', pattern: value }
|
|
128
|
+
: { type: 'path', path: value },
|
|
129
|
+
access,
|
|
130
|
+
}]),
|
|
131
|
+
...getExistingRelationAttachmentDirs(root, {
|
|
132
|
+
selfAid: input.trigger.agentAid,
|
|
133
|
+
onlyOtherAgents: true,
|
|
134
|
+
}).map(value => filesystemEntry(value, 'deny')),
|
|
130
135
|
];
|
|
131
136
|
const sandboxState = JSON.stringify({
|
|
132
137
|
permissionProfile: {
|
|
133
138
|
type: 'managed',
|
|
134
|
-
file_system: { type: 'restricted', entries },
|
|
135
|
-
network: '
|
|
139
|
+
file_system: { type: 'restricted', entries, glob_scan_max_depth: filesystem.glob_scan_max_depth },
|
|
140
|
+
network: 'enabled',
|
|
136
141
|
},
|
|
137
142
|
sandboxCwd: pathToFileURL(projectPath).href,
|
|
138
143
|
});
|
|
139
144
|
if (sandboxState.length > 20_000)
|
|
140
145
|
throw new Error('scoped Windows Trigger filesystem policy exceeds the command-line budget');
|
|
141
|
-
const shellEnvironmentPolicy = `shell_environment_policy={inherit="all",exclude=${JSON.stringify(
|
|
146
|
+
const shellEnvironmentPolicy = `shell_environment_policy={inherit="all",exclude=${JSON.stringify(getScriptEnvironmentExcludes())},include_only=[],set={}}`;
|
|
142
147
|
const sandboxArgs = [
|
|
143
|
-
'sandbox', '--sandbox-state-json', sandboxState,
|
|
148
|
+
'sandbox', '--sandbox-state-json', sandboxState,
|
|
144
149
|
'-c', 'windows.sandbox="elevated"',
|
|
145
150
|
'-c', shellEnvironmentPolicy,
|
|
146
151
|
];
|
|
@@ -154,40 +159,26 @@ export function buildTriggerScriptLaunch(input) {
|
|
|
154
159
|
launch.prepare = signal => verifyWindowsReadIsolation(launch, sandboxArgs, runDir, workDir, signal);
|
|
155
160
|
return launch;
|
|
156
161
|
}
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
args.push('--ro-bind', value, value);
|
|
178
|
-
args.push(authorization.permissionMode === 'readonly' ? '--ro-bind' : '--bind', projectPath, projectPath);
|
|
179
|
-
for (const value of blockedPaths) {
|
|
180
|
-
if (!visibleRoots.some(directory => isSameOrDescendant(value, directory)) || !fs.existsSync(value))
|
|
181
|
-
continue;
|
|
182
|
-
const stat = fs.lstatSync(value);
|
|
183
|
-
if (stat.isDirectory())
|
|
184
|
-
args.push('--tmpfs', value, '--remount-ro', value);
|
|
185
|
-
else
|
|
186
|
-
args.push('--ro-bind', '/dev/null', value);
|
|
187
|
-
}
|
|
188
|
-
args.push('--ro-bind', runDir, runDir, '--bind', workDir, workDir, '--remount-ro', '/');
|
|
189
|
-
args.push('--chdir', projectPath, '--', runtime, ...scriptArgs);
|
|
190
|
-
return { command: bubblewrap, args, cwd: projectPath, env, cleanup };
|
|
162
|
+
const launch = sandboxDecision.state === 'off'
|
|
163
|
+
? buildHClassGuardCommand(runtime, scriptArgs, root, { selfAid: input.trigger.agentAid })
|
|
164
|
+
: buildBubblewrapCommand(runtime, scriptArgs, {
|
|
165
|
+
projectPath,
|
|
166
|
+
projectWritable: !readonly,
|
|
167
|
+
root,
|
|
168
|
+
selfAid: input.trigger.agentAid,
|
|
169
|
+
exposeDaemonIpc: false,
|
|
170
|
+
denyLClassRead: readonly,
|
|
171
|
+
});
|
|
172
|
+
if (!launch)
|
|
173
|
+
throw new Error('bubblewrap is required for scoped Trigger script isolation');
|
|
174
|
+
const separator = launch.args.indexOf('--');
|
|
175
|
+
if (separator < 0)
|
|
176
|
+
throw new Error('bubblewrap launch is missing its command separator');
|
|
177
|
+
const runMountArgs = ['--ro-bind', runDir, runDir, '--bind', workDir, workDir];
|
|
178
|
+
if (!launch.args.slice(0, separator).includes('--chdir'))
|
|
179
|
+
runMountArgs.push('--chdir', projectPath);
|
|
180
|
+
launch.args.splice(separator, 0, ...runMountArgs);
|
|
181
|
+
return { ...launch, cwd: projectPath, env, cleanup };
|
|
191
182
|
}
|
|
192
183
|
catch (error) {
|
|
193
184
|
cleanup();
|
|
@@ -331,30 +322,20 @@ function preserveNodeModuleType(runtime, scriptPath, snapshotDir) {
|
|
|
331
322
|
}
|
|
332
323
|
function buildSandboxEnvironment(workDir) {
|
|
333
324
|
const env = {};
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (
|
|
325
|
+
const excluded = new Set(getScriptEnvironmentExcludes().map(key => key.toUpperCase()));
|
|
326
|
+
for (const [key, value] of Object.entries(sanitizeShellExecutionEnvironment(process.env))) {
|
|
327
|
+
if (!excluded.has(key.toUpperCase())
|
|
328
|
+
&& typeof value === 'string')
|
|
337
329
|
env[key] = value;
|
|
338
330
|
}
|
|
339
|
-
const homeDir = process.platform === 'win32' ? path.join(workDir, 'home') : workDir;
|
|
340
|
-
if (homeDir !== workDir)
|
|
341
|
-
fs.mkdirSync(homeDir, { mode: 0o700 });
|
|
342
331
|
return {
|
|
343
|
-
...env,
|
|
344
|
-
APPDATA: path.join(workDir, 'appdata'), LOCALAPPDATA: path.join(workDir, 'localappdata'),
|
|
332
|
+
...env,
|
|
345
333
|
TMPDIR: workDir, TEMP: workDir, TMP: workDir, EVOLCORE_TRIGGER_SANDBOX: '1',
|
|
346
334
|
};
|
|
347
335
|
}
|
|
348
|
-
function
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
...directoryRoots,
|
|
352
|
-
...getExistingHClassMaskTargets(root, { selfAid }).map(target => target.path),
|
|
353
|
-
...getExistingLClassReadOnlyTargets(root, { selfAid }).map(target => target.path),
|
|
354
|
-
path.join(root, 'daemon.json'), path.join(root, '.env'), path.join(root, '.device_id'),
|
|
355
|
-
path.join(root, '.lock'), path.join(root, 'daemon.pid'),
|
|
356
|
-
];
|
|
357
|
-
return [...new Set(targets)].filter(candidate => (directoryRoots.includes(candidate) || !directoryRoots.some(directory => isSameOrDescendant(candidate, directory))));
|
|
336
|
+
function getScriptEnvironmentExcludes() {
|
|
337
|
+
const dynamic = Object.keys(process.env).filter(key => key.toUpperCase().startsWith('EVOLCORE_'));
|
|
338
|
+
return [...new Set([...SCRIPT_ENVIRONMENT_EXCLUDES, ...dynamic])];
|
|
358
339
|
}
|
|
359
340
|
function filesystemEntry(value, access) {
|
|
360
341
|
return { path: { type: 'path', path: path.resolve(value) }, access };
|
|
@@ -252,6 +252,20 @@ function normalizeV3Phase2(raw, opts) {
|
|
|
252
252
|
reliability: normalizeReliability(raw.reliability),
|
|
253
253
|
limits: normalizeLimits(raw.limits),
|
|
254
254
|
};
|
|
255
|
+
// T10: labels 字典原样保留,只做类型校验(如果存在必须是 Record<string, string>)
|
|
256
|
+
const rawLabels = raw.labels;
|
|
257
|
+
if (rawLabels !== undefined && rawLabels !== null) {
|
|
258
|
+
if (typeof rawLabels !== 'object' || Array.isArray(rawLabels)) {
|
|
259
|
+
throw new Error('labels must be a plain object');
|
|
260
|
+
}
|
|
261
|
+
const labels = {};
|
|
262
|
+
for (const [k, v] of Object.entries(rawLabels)) {
|
|
263
|
+
if (typeof v !== 'string')
|
|
264
|
+
throw new Error(`labels.${k} must be a string`);
|
|
265
|
+
labels[k] = v;
|
|
266
|
+
}
|
|
267
|
+
definition.labels = labels;
|
|
268
|
+
}
|
|
255
269
|
validateTriggerSemantics(definition);
|
|
256
270
|
return definition;
|
|
257
271
|
}
|
|
@@ -466,7 +466,7 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
|
|
|
466
466
|
}
|
|
467
467
|
}
|
|
468
468
|
// 回退到原有的错误消息匹配逻辑
|
|
469
|
-
const msg =
|
|
469
|
+
const msg = resolveErrorMessage(error);
|
|
470
470
|
const warnPrefix = includeEmoji ? '⚠️ ' : '';
|
|
471
471
|
const errPrefix = includeEmoji ? '❌ ' : '';
|
|
472
472
|
if (/invalid (?:jsonl )?session file/i.test(msg)) {
|
|
@@ -512,5 +512,26 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
|
|
|
512
512
|
if (msg.includes('timeout')) {
|
|
513
513
|
return `${warnPrefix}请求超时,请重试`;
|
|
514
514
|
}
|
|
515
|
+
if (msg)
|
|
516
|
+
return `${errPrefix}暂无法判定错误原因:${msg}`;
|
|
515
517
|
return `${errPrefix}处理消息时出错,请稍后重试`;
|
|
516
518
|
}
|
|
519
|
+
function resolveErrorMessage(error) {
|
|
520
|
+
if (typeof error === 'string')
|
|
521
|
+
return error.trim();
|
|
522
|
+
if (error === null || error === undefined)
|
|
523
|
+
return '';
|
|
524
|
+
if (typeof error === 'object') {
|
|
525
|
+
const message = 'message' in error ? String(error.message ?? '').trim() : '';
|
|
526
|
+
if (message)
|
|
527
|
+
return message;
|
|
528
|
+
const code = 'code' in error ? String(error.code ?? '').trim() : '';
|
|
529
|
+
if (code)
|
|
530
|
+
return code;
|
|
531
|
+
if ('message' in error)
|
|
532
|
+
return '';
|
|
533
|
+
const stringified = String(error).trim();
|
|
534
|
+
return stringified === '[object Object]' || stringified === 'Error' ? '' : stringified;
|
|
535
|
+
}
|
|
536
|
+
return String(error).trim();
|
|
537
|
+
}
|
package/kits/docs/AUTHORING.md
CHANGED
|
@@ -111,7 +111,7 @@ ECK 的 manifest 机制决定了**不同位置的内容有不同的成本量级*
|
|
|
111
111
|
|
|
112
112
|
写入 `rules/` 前自问:**这条信息如果不注入,agent 会在多少比例的对话里做错事?**
|
|
113
113
|
|
|
114
|
-
- 每轮都需要(如"
|
|
114
|
+
- 每轮都需要(如"不得停止或重启承载当前会话的 EvolCore 实例")→ 进 `rules/`
|
|
115
115
|
- 偶发场景才需要(如"Menu 消息有哪些字段")→ 留 `docs/`,靠 `INDEX.md` 触发词按需命中
|
|
116
116
|
|
|
117
117
|
答不上来就别进 `rules/`。最常见的隐性浪费是把偶发查阅的内容塞进规则文件,之后每轮对话都在白烧 token。
|
|
@@ -42,6 +42,14 @@ AUN keystore seed 由 EvolCore 使用固定应用值管理,不再提供配置
|
|
|
42
42
|
|
|
43
43
|
> Gateway 不在配置里手填:连接时从 AID 自动发现(见下)。Keystore 默认落在 `$EVOLCORE_HOME`。
|
|
44
44
|
|
|
45
|
+
## SDK 同步边界
|
|
46
|
+
|
|
47
|
+
`@agentunion/fastaun` 管理消息/群消息的 A/T/H 水位、ACK、Push/Tail/Forward、Gap Fill、多页同步、重连恢复和 Pull Gate。EvolCore 只消费公开消息/撤回/同步事件,负责业务路由、持久化和 `(namespace, message_id)` 应用幂等;`seq` 只用于顺序、诊断和日志。菜单、普通文本、volatile 消息和应用去重记录均不能用来推导或回写 SDK 游标。
|
|
48
|
+
|
|
49
|
+
不得访问或 monkey patch SDK 私有成员,包括 `_seqTracker`、`_pullV2`、`_pullGroupV2`、`_publishAppEvent`、`_dispatcher`、`_identity`、`_auth`、`_tokenStore`、`_v2E2EE`。需要补同步、确认消息或调试时,应先检查 SDK 公开 API;缺少能力应向 SDK 增补公开契约,而不是在渠道适配层改写同步状态。显式查询使用公开 RPC/facade 与独立 slot,不得推进 daemon 消费游标。
|
|
50
|
+
|
|
51
|
+
`fastaun 0.5.18` 公开 `sender_device_id`,但隐藏发送方 slot。EvolCore 的菜单 token 当前仅按设备绑定,不声称具备同设备多 slot 隔离。
|
|
52
|
+
|
|
45
53
|
## 特有机制
|
|
46
54
|
|
|
47
55
|
- **隐式创建**:aun 渠道由顶层 `aid` 派生,无独立配置实例;这是它与飞书等渠道最大的不同。
|
|
@@ -311,6 +311,7 @@ coding 场景(无 channel/无身份)下,`chatType`、`channel`、`selfAid`
|
|
|
311
311
|
| 55 | commands | fragment | active 且 channel≠null | ✓ |
|
|
312
312
|
| 60 | session | fragment | active | ✓ |
|
|
313
313
|
| 70 | baseagent | fragment | active 且 baseAgent≠null | ✓ |
|
|
314
|
+
| 80 | managed-runtime-notice | fragment | active | ✓ |
|
|
314
315
|
|
|
315
316
|
Bootstrap 只加载引导与有渠道时的最小通信上下文 `[reply]`,不加载完整身份/关系/渠道能力、个人记忆或普通任务命令。
|
|
316
317
|
`[reply]` 展示 selfAid、peerId、peerType、channel、chatType、chatMode;未知身份显示 unknown,回复方式只取运行时已解析的 chatMode,不从身份或私聊场景重新推断。命令经当前会话 delegated sender / daemon IPC 发送,遵守现有身份、目标、话题与加密约束。
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
2. **不确定有没有命令**时,直接 `ec <猜测的子命令> --help` 试一下(如 `ec stats --help`)
|
|
15
15
|
3. **已知场景需求**(如"要给对端发消息")→ 看下方分类表 → 定位到对应命令集
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
生命周期保护仅针对承载当前会话的 EvolCore 实例;其他实例按用户授权和目标端权限处理,不限管理通道。完整规则见 `$KITS_RULES/06-channel.md`。
|
|
18
18
|
|
|
19
19
|
## 服务运维类(本地,无需 AUN)
|
|
20
20
|
|
|
21
21
|
| 命令 | 用途 | 触发词 |
|
|
22
22
|
|------|------|--------|
|
|
23
23
|
| `ec --version` / `-v` / `-V` | 查看版本号 | 版本 |
|
|
24
|
-
| `ec restart` |
|
|
24
|
+
| `ec restart` | 重启目标 daemon(承载当前托管会话的实例受生命周期保护) | 重启 |
|
|
25
25
|
| `ec status` | 查看运行状态、进程、会话、渠道连接 | 状态/查看状态 |
|
|
26
26
|
| `ec logs` | 查看日志(`--level` `--module` `--raw` `--no-color`) | 日志/查看日志 |
|
|
27
27
|
| `ec diagnose` | 诊断启动环境 | 诊断/环境诊断 |
|
|
@@ -33,6 +33,7 @@ Windows 上 Codex 托管任务出现 `helper_sandbox_lock_failed`、`SetNamedSec
|
|
|
33
33
|
| 命令集 | 用途 | 触发词 | 适用场景 | 文档 |
|
|
34
34
|
|--------|------|--------|----------|------|
|
|
35
35
|
| `ec msg` | 私聊收发消息 | 回复/发消息/拉取/撤回/查在线 | 有对端(peerId) | `msg.md` |
|
|
36
|
+
| `ec thread` | 话题管理与话题链 | 话题/thread/跨会话/委托/话题链/ThreadOrigin/summary/删除话题 | 有对端(私聊或群聊) | `thread-chain.md` |
|
|
36
37
|
| `ec group` | 群聊收发与群管理 | 群发/建群/本地群历史/邀请/踢人/退群/群成员/角色/封禁/屏蔽/成员状态/规则/@提及模式/协作 | 群聊(groupId) | `group.md`;完整协作流程见 `group-collaboration.md` |
|
|
37
38
|
| `/invites` / `ec group invites` | 收到群邀请、Owner 卡片审核与恢复 | 入群邀请/接受邀请/拒绝邀请/审核卡片/待处理邀请 | 当前 Agent Owner 的 AUN 私聊 | `group.md` |
|
|
38
39
|
| `ec group rules` | 群规则文件发布与上下文注入 | 群规则/工作流程/职责分工/rules.md/发布规则 | AUN 群聊(groupId) | `group-rules.md` |
|