evolcore 0.0.35 → 0.0.37
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 +42 -0
- package/README.md +6 -0
- package/bin/install-codex-managed-hooks.mjs +20 -3
- package/dist/agents/baseagent-availability.js +1 -1
- package/dist/agents/baseagent.js +88 -0
- package/dist/agents/claude-runner.js +59 -12
- package/dist/agents/codex/app-server-client.js +18 -1
- package/dist/agents/codex-runner.js +262 -21
- package/dist/agents/ecagent-runner.js +47 -11
- package/dist/agents/gemini-runner.js +36 -12
- package/dist/aun/aid/client.js +4 -3
- package/dist/aun/aid/control-aid.js +270 -8
- package/dist/aun/aid/identity.js +6 -3
- package/dist/aun/aid/ownership-operation.js +58 -0
- package/dist/aun/aid/store.js +1 -0
- package/dist/aun/group/fs-download.js +67 -2
- package/dist/aun/group/history.js +20 -5
- package/dist/aun/group/operations.js +8 -2
- package/dist/aun/menu/client.js +39 -2
- package/dist/aun/menu/transport.js +1 -1
- package/dist/aun/msg/history.js +43 -4
- package/dist/aun/msg/managed-operation.js +30 -53
- package/dist/aun/msg/p2p.js +51 -15
- package/dist/aun/outbox.js +4 -0
- package/dist/channels/aun.js +260 -73
- package/dist/channels/daemon.js +6 -4
- package/dist/channels/feishu.js +3 -0
- package/dist/cli/agent-command.js +161 -223
- package/dist/cli/agent-create.js +190 -223
- package/dist/cli/agent.js +3 -1
- package/dist/cli/aid-bind-command.js +53 -0
- package/dist/cli/aun-commands.js +384 -91
- package/dist/cli/bench.js +1 -1
- package/dist/cli/cli-argv.js +74 -0
- package/dist/cli/daemon-commands.js +105 -74
- package/dist/cli/diag.js +1 -1
- package/dist/cli/fs-command.js +18 -19
- package/dist/cli/getmeta-command.js +159 -6
- package/dist/cli/index.js +6 -12
- package/dist/cli/init-channel.js +8 -55
- package/dist/cli/init.js +125 -218
- package/dist/cli/queue-command.js +11 -8
- package/dist/cli/restart-monitor.js +177 -85
- package/dist/cli/session-command.js +1 -1
- package/dist/cli/stats.js +7 -5
- package/dist/cli/thread-command.js +103 -30
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg-diag.js +1 -0
- package/dist/config/access-policy.js +2 -2
- package/dist/config/boot-log.js +14 -11
- package/dist/config/config-field-policy.js +9 -1
- package/dist/config/config-manager.js +176 -90
- package/dist/config/config-operation-service.js +7 -14
- package/dist/config/contact-book-store.js +142 -26
- package/dist/config/contact-book.js +4 -2
- package/dist/config/lifecycle.js +1 -1
- package/dist/config/owner-config.js +96 -0
- package/dist/config/peer-role-resolver.js +12 -18
- package/dist/config/providers-config.js +382 -0
- package/dist/config/providers-import.js +74 -0
- package/dist/config/providers-management.js +328 -0
- package/dist/config/providers.js +22 -0
- package/dist/config/resolved-config-op.js +17 -14
- package/dist/config/snapshot.js +28 -16
- package/dist/config-store.js +18 -14
- package/dist/core/agent-ipc-registration.js +21 -63
- package/dist/core/agent-runtime.js +16 -5
- package/dist/core/auth/agent-delegation.js +199 -25
- package/dist/core/auth/auth-gateway.js +44 -2
- package/dist/core/auth/authorization-denial.js +1 -1
- package/dist/core/auth/debug-context.js +2 -1
- package/dist/core/auth/delegation-authorization.js +2 -2
- package/dist/core/auth/delegation-diagnostics.js +4 -1
- package/dist/core/auth/operation-authorizer.js +10 -1
- package/dist/core/auth/operation-catalog.js +19 -1
- package/dist/core/bootstrap-service.js +43 -20
- package/dist/core/channel-loader.js +0 -1
- package/dist/core/channel-runtime.js +30 -4
- package/dist/core/command/agent-control.js +196 -37
- package/dist/core/command/cli-intent-parser.js +60 -4
- package/dist/core/command/command-handler.js +212 -60
- package/dist/core/command/connect-menu.js +1 -0
- package/dist/core/command/diag-service.js +5 -4
- package/dist/core/command/file-search.js +368 -0
- package/dist/core/command/menu-catalog.js +2 -1
- package/dist/core/command/menu-handler.js +292 -107
- package/dist/core/command/menu-protocol.js +23 -0
- package/dist/core/command/role-menu.js +7 -19
- package/dist/core/command/skill-slash.js +130 -25
- package/dist/core/command/slash-handler.js +101 -53
- package/dist/core/command/topic-slash.js +16 -5
- package/dist/core/daemon-bootstrap.js +7 -1
- package/dist/core/daemon-control.js +19 -1
- package/dist/core/daemon-lifecycle.js +2 -1
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/evolagent-registry.js +13 -2
- package/dist/core/evolagent.js +3 -6
- package/dist/core/handoff/ipc-registration.js +2 -2
- package/dist/core/handoff/runtime.js +40 -6
- package/dist/core/handoff/store.js +1 -0
- package/dist/core/inference/text-inference.js +95 -6
- package/dist/core/ipc-registration.js +43 -24
- package/dist/core/memory/consolidation-context.js +4 -1
- package/dist/core/memory/consolidation.js +25 -14
- package/dist/core/message/aun-ipc-sender.js +296 -88
- package/dist/core/message/aun-request-registry.js +226 -0
- package/dist/core/message/create-status.js +33 -4
- package/dist/core/message/message-bridge.js +62 -13
- package/dist/core/message/message-log.js +0 -1
- package/dist/core/message/message-queue.js +4 -1
- package/dist/core/message/message-utils.js +8 -1
- package/dist/core/message/peer-mode.js +17 -9
- package/dist/core/message/response-engine.js +266 -124
- package/dist/core/message/retry-scheduler.js +11 -8
- package/dist/core/model/catalog-service.js +60 -18
- package/dist/core/model/model-catalog.js +112 -9
- package/dist/core/model/model-fallback.js +94 -26
- package/dist/core/ownership/owner-resolver.js +687 -0
- package/dist/core/permission/approval-gateway.js +196 -62
- package/dist/core/permission/ec-command-parser.js +138 -25
- package/dist/core/permission/filesystem-approval-scope.js +141 -0
- package/dist/core/permission/protected-paths.js +14 -1
- package/dist/core/permission/sandbox-runtime.js +171 -18
- package/dist/core/permission/tool-policy.js +13 -2
- package/dist/core/role/runtime-policy.js +3 -4
- package/dist/core/session/session-idle-monitor.js +10 -8
- package/dist/core/session/session-manager.js +72 -45
- package/dist/core/session/session-mapper.js +18 -7
- package/dist/core/session/session-renew.js +5 -4
- package/dist/core/session/session-title.js +2 -1
- package/dist/core/session/session-turn-coordinator.js +4 -2
- package/dist/core/skill/index-generator.js +2 -16
- package/dist/core/task/task-recovery-service.js +15 -2
- package/dist/core/thread/command-parser.js +28 -13
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +11 -8
- package/dist/core/thread/thread-operation.js +79 -44
- package/dist/core/thread/thread-route.js +54 -6
- package/dist/core/thread/thread-service.js +236 -45
- package/dist/core/thread/topic-id.js +248 -0
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/eck/message-renderer.js +12 -2
- package/dist/index.js +50 -27
- package/dist/ipc.js +59 -6
- package/dist/paths.js +1 -0
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +10 -3
- package/dist/stats/db.js +8 -0
- package/dist/stats/writer.js +26 -4
- package/dist/trigger/authorization.js +48 -3
- package/dist/trigger/feedback.js +28 -10
- package/dist/trigger/ipc-service.js +86 -10
- package/dist/trigger/local-files.js +55 -23
- package/dist/trigger/scheduler.js +57 -11
- package/dist/trigger/system-definitions.js +1 -0
- package/dist/trigger/validation.js +44 -15
- package/dist/utils/aid-bind.js +17 -297
- package/dist/utils/avatar-upload.js +16 -4
- package/dist/utils/cross-platform.js +115 -36
- package/dist/utils/ecweb-supervisor.js +1 -1
- package/dist/utils/ecweb-utils.js +8 -1
- package/dist/utils/error-utils.js +44 -6
- package/dist/utils/instance-registry.js +12 -2
- package/dist/utils/npm-ops.js +102 -27
- package/dist/utils/package-version-info.js +72 -27
- package/dist/utils/restart-safety.js +50 -0
- package/dist/utils/upgrade-jobs.js +304 -0
- package/dist/utils/windows-autostart.js +17 -10
- package/kits/docs/INDEX.md +5 -0
- package/kits/docs/aun/ABILITY_CALLING.md +239 -0
- package/kits/docs/evolcore/INDEX.md +14 -3
- package/kits/docs/evolcore/agent-create.md +55 -141
- package/kits/docs/evolcore/agent.md +38 -16
- package/kits/docs/evolcore/aid.md +34 -0
- package/kits/docs/evolcore/config.md +20 -1
- package/kits/docs/evolcore/event.md +2 -2
- package/kits/docs/evolcore/fs.md +18 -2
- package/kits/docs/evolcore/group-collaboration.md +13 -246
- package/kits/docs/evolcore/group.md +2 -1
- package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +65 -1
- package/kits/docs/evolcore/msg.md +64 -2
- package/kits/docs/evolcore/skill.md +86 -0
- package/kits/docs/evolcore/stats.md +6 -0
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +145 -51
- package/kits/docs/evolcore/trigger.md +48 -3
- package/kits/eck_manifest.json +21 -0
- package/kits/eck_message_manifest.json +4 -4
- package/kits/migrations/migrate-role-config-v5.mjs +20 -7
- package/kits/rules/01-overview.md +2 -1
- package/kits/rules/03-identity.md +3 -1
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/07-memory-and-thread.md +1 -1
- package/kits/schemas/_meta.json +16 -1
- package/kits/schemas/agent-config.schema.13.json +44 -2
- package/kits/schemas/contact-book.schema.3.json +5 -0
- package/kits/schemas/daemon.schema.6.json +3 -1
- package/kits/schemas/daemon.schema.8.json +329 -0
- package/kits/schemas/defaults.schema.5.json +39 -3
- package/kits/schemas/providers.schema.1.json +76 -0
- package/kits/schemas/relation-config.schema.9.json +5 -1
- package/kits/skills/.switches.json +28 -0
- package/kits/skills/aid-ability/SKILL.md +214 -0
- package/kits/skills/ec-agent-create/SKILL.md +162 -0
- package/kits/skills/ec-group/SKILL.md +2 -1
- package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
- package/kits/skills/ec-identity/SKILL.md +143 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
- package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
- package/kits/skills/ec-trigger/SKILL.md +167 -0
- package/kits/skills/ec-trigger/references/examples.md +153 -0
- package/kits/skills/thread-ops/SKILL.md +108 -420
- package/kits/templates/message-fragments/thread-context.md +1 -2
- package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
- package/kits/templates/roles/member.json +1 -1
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +1 -0
- package/kits/templates/system-fragments/channel.md +2 -1
- package/kits/templates/system-fragments/commands.md +5 -4
- package/kits/templates/system-fragments/identity.md +2 -0
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -3
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
3
4
|
import { resolveCommandPath } from '../../utils/cross-platform.js';
|
|
4
5
|
import { getExistingHClassMaskTargets, getExistingRelationAttachmentDirs, getExistingLClassReadOnlyTargets, isSameOrDescendant, } from './protected-paths.js';
|
|
5
6
|
import { resolveInstanceSocketPath, resolveRoot } from '../../paths.js';
|
|
6
|
-
|
|
7
|
+
import { MAIN_CLI_BIN } from '../../product.js';
|
|
7
8
|
let sandboxInitializationCircuit;
|
|
8
9
|
const sessionSandboxInitializationCircuits = new Map();
|
|
9
10
|
let sandboxCircuitNoticeAt = 0;
|
|
10
11
|
let sandboxInitializationFailureCounters = emptySandboxInitializationFailureCounters();
|
|
11
12
|
export const SANDBOX_INITIALIZATION_FAILED = 'sandbox_initialization_failed';
|
|
13
|
+
export const SANDBOX_DEPENDENCIES_MISSING = 'sandbox_dependencies_missing';
|
|
14
|
+
export const CODEX_SANDBOX_USER_NAMESPACE_UNAVAILABLE = 'codex_sandbox_userns_unavailable';
|
|
15
|
+
export const CODEX_SANDBOX_USER_NAMESPACE_DISABLED_BY_APPARMOR = 'codex_sandbox_userns_disabled_by_apparmor';
|
|
12
16
|
export const SANDBOX_INITIALIZATION_COOLDOWN_MS = 5 * 60 * 1000;
|
|
13
17
|
export const SANDBOX_CIRCUIT_NOTICE_INTERVAL_MS = 60 * 1000;
|
|
14
18
|
function emptySandboxInitializationFailureCounters() {
|
|
@@ -26,7 +30,7 @@ function sandboxInitializationFailureKind(text) {
|
|
|
26
30
|
return 'gid_map';
|
|
27
31
|
if (/\bseccomp\b/i.test(text))
|
|
28
32
|
return 'seccomp';
|
|
29
|
-
if (
|
|
33
|
+
if (isCodexSandboxUserNamespaceFailure(text))
|
|
30
34
|
return 'user_namespace';
|
|
31
35
|
if (/\b(?:bwrap|bubblewrap)\b/i.test(text))
|
|
32
36
|
return 'bubblewrap';
|
|
@@ -101,13 +105,34 @@ export function isSandboxInitializationFailure(error, stderr = []) {
|
|
|
101
105
|
.join('\n')
|
|
102
106
|
.toLowerCase();
|
|
103
107
|
return text.includes(SANDBOX_INITIALIZATION_FAILED)
|
|
108
|
+
|| (text.includes('sandbox required but unavailable') && !isClaudeSandboxDependencyFailure(text))
|
|
104
109
|
|| /fs sandbox helper failed(?: with status)?\b/.test(text)
|
|
105
110
|
|| /(?:apply-seccomp|seccomp)[\s\S]*(?:uid_map|gid_map|operation not permitted)/.test(text)
|
|
106
111
|
|| /(?:uid_map|gid_map)[\s\S]*(?:operation not permitted|permission denied)/.test(text)
|
|
107
|
-
||
|
|
112
|
+
|| isCodexSandboxUserNamespaceFailure(text)
|
|
108
113
|
|| /bubblewrap[\s\S]*namespace[\s\S]*(?:failed|not permitted|permission denied)/.test(text)
|
|
109
114
|
|| /(?:^|\n)\s*bwrap:\s*(?:can't|cannot|unable to)[\s\S]*(?:bind|mount|mount table)/.test(text)
|
|
110
|
-
|| /(?:^|\n)\s*bwrap:\s*(?:can't|cannot) create (?:file|directory) at [^\n]+: read-only file system/.test(text)
|
|
115
|
+
|| /(?:^|\n)\s*bwrap:\s*(?:can't|cannot) create (?:file|directory) at [^\n]+: read-only file system/.test(text)
|
|
116
|
+
|| /(?:^|\n)\s*bwrap:\s*(?:can't|cannot) mkdir parents for [^\n]+: read-only file system/.test(text);
|
|
117
|
+
}
|
|
118
|
+
export function isCodexSandboxUserNamespaceFailure(error) {
|
|
119
|
+
const record = error && typeof error === 'object'
|
|
120
|
+
? error
|
|
121
|
+
: undefined;
|
|
122
|
+
const stderr = Array.isArray(record?.stderr)
|
|
123
|
+
? record.stderr.filter((line) => typeof line === 'string').join('\n')
|
|
124
|
+
: typeof record?.stderr === 'string' ? record.stderr : '';
|
|
125
|
+
const text = record
|
|
126
|
+
? `${String(record.code ?? '')}\n${String(record.message ?? '')}\n${stderr}`
|
|
127
|
+
: String(error ?? '');
|
|
128
|
+
const lower = text.toLowerCase();
|
|
129
|
+
return lower.includes(CODEX_SANDBOX_USER_NAMESPACE_UNAVAILABLE)
|
|
130
|
+
|| lower.includes(CODEX_SANDBOX_USER_NAMESPACE_DISABLED_BY_APPARMOR)
|
|
131
|
+
|| /apparmor_restrict_unprivileged_userns\s*=\s*1/i.test(text)
|
|
132
|
+
|| /no permissions to create new namespace/i.test(text)
|
|
133
|
+
|| /(?:new )?namespace[^\n]*(?:operation not permitted|permission denied)/i.test(text)
|
|
134
|
+
|| /non-privileged user namespaces?/i.test(text)
|
|
135
|
+
|| /user namespace[\s\S]*(?:not permitted|unavailable|failed|permission denied)/i.test(text);
|
|
111
136
|
}
|
|
112
137
|
export function createSandboxInitializationError(error, stderr = []) {
|
|
113
138
|
if (error instanceof Error
|
|
@@ -177,10 +202,10 @@ function isExecutableFile(candidate) {
|
|
|
177
202
|
return false;
|
|
178
203
|
}
|
|
179
204
|
}
|
|
180
|
-
function codexBundledBubblewrap() {
|
|
205
|
+
function codexBundledBubblewrap(env) {
|
|
181
206
|
if (process.platform !== 'linux')
|
|
182
207
|
return undefined;
|
|
183
|
-
const codexPath = resolveCommandPath('codex');
|
|
208
|
+
const codexPath = resolveCommandPath('codex', env);
|
|
184
209
|
if (!codexPath)
|
|
185
210
|
return undefined;
|
|
186
211
|
let resolvedCodexPath = codexPath;
|
|
@@ -199,21 +224,150 @@ function codexBundledBubblewrap() {
|
|
|
199
224
|
const platformPackage = process.arch === 'arm64' ? 'codex-linux-arm64' : 'codex-linux-x64';
|
|
200
225
|
return path.join(packageRoot, 'node_modules', '@openai', platformPackage, 'vendor', target, 'codex-resources', 'bwrap');
|
|
201
226
|
}
|
|
202
|
-
export function resolveBubblewrapPath() {
|
|
203
|
-
if (
|
|
204
|
-
return cachedBubblewrapPath ?? undefined;
|
|
205
|
-
if (process.platform !== 'linux') {
|
|
206
|
-
cachedBubblewrapPath = null;
|
|
227
|
+
export function resolveBubblewrapPath(env = process.env) {
|
|
228
|
+
if (process.platform !== 'linux')
|
|
207
229
|
return undefined;
|
|
208
|
-
}
|
|
209
230
|
const candidates = [
|
|
210
|
-
|
|
211
|
-
resolveCommandPath('bwrap') ?? undefined,
|
|
212
|
-
codexBundledBubblewrap(),
|
|
231
|
+
env.EVOLCORE_BWRAP_PATH,
|
|
232
|
+
resolveCommandPath('bwrap', env) ?? undefined,
|
|
233
|
+
codexBundledBubblewrap(env),
|
|
213
234
|
];
|
|
214
235
|
const resolved = candidates.find(isExecutableFile);
|
|
215
|
-
|
|
216
|
-
|
|
236
|
+
return resolved ? path.resolve(resolved) : undefined;
|
|
237
|
+
}
|
|
238
|
+
export function inspectClaudeSandboxDependencies(env = process.env, platform = process.platform) {
|
|
239
|
+
if (platform !== 'linux')
|
|
240
|
+
return { platform, status: 'not_applicable', missing: [] };
|
|
241
|
+
const bwrapPath = resolveBubblewrapPath(env);
|
|
242
|
+
const socatCandidate = resolveCommandPath('socat', env) ?? undefined;
|
|
243
|
+
const socatPath = isExecutableFile(socatCandidate) ? socatCandidate : undefined;
|
|
244
|
+
const missing = [...(bwrapPath ? [] : ['bubblewrap (bwrap)']), ...(socatPath ? [] : ['socat'])];
|
|
245
|
+
return { platform, status: missing.length ? 'missing' : 'ready', bwrapPath, socatPath, missing };
|
|
246
|
+
}
|
|
247
|
+
export function formatClaudeSandboxDependencies(check) {
|
|
248
|
+
if (check.status === 'not_applicable')
|
|
249
|
+
return `Claude Linux sandbox dependency check not applicable on ${check.platform}`;
|
|
250
|
+
if (check.status === 'ready')
|
|
251
|
+
return `Claude sandbox dependencies found: bwrap=${check.bwrapPath}; socat=${check.socatPath} (execution not verified)`;
|
|
252
|
+
return `Claude sandbox dependencies missing: ${check.missing.join(', ')}. `
|
|
253
|
+
+ 'Sandbox-required sessions cannot execute; owner bypass may still work. '
|
|
254
|
+
+ 'Install with your system package manager (Debian/Ubuntu: apt install bubblewrap socat; Fedora: dnf install bubblewrap socat), '
|
|
255
|
+
+ `then run ${MAIN_CLI_BIN} diagnose in the service environment. EvolCore does not install OS packages or disable the sandbox automatically.`;
|
|
256
|
+
}
|
|
257
|
+
export function createClaudeSandboxDependencyError(check) {
|
|
258
|
+
return Object.assign(new Error(`${SANDBOX_DEPENDENCIES_MISSING}: ${formatClaudeSandboxDependencies(check)}`), {
|
|
259
|
+
code: SANDBOX_DEPENDENCIES_MISSING,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
export function isClaudeSandboxDependencyFailure(error) {
|
|
263
|
+
const text = error && typeof error === 'object' && 'message' in error
|
|
264
|
+
? String(error.message ?? '')
|
|
265
|
+
: String(error ?? '');
|
|
266
|
+
return text.includes(SANDBOX_DEPENDENCIES_MISSING)
|
|
267
|
+
|| /sandbox[\s\S]*(?:dependencies are missing|dependencies missing|(?:socat|bwrap|bubblewrap) not installed)/i.test(text);
|
|
268
|
+
}
|
|
269
|
+
export function probeClaudeSandboxDependencies(check) {
|
|
270
|
+
if (check.status !== 'ready' || !check.bwrapPath)
|
|
271
|
+
return { ok: false, detail: formatClaudeSandboxDependencies(check) };
|
|
272
|
+
try {
|
|
273
|
+
execFileSync(check.bwrapPath, [
|
|
274
|
+
'--die-with-parent', '--new-session', '--unshare-pid', '--ro-bind', '/', '/',
|
|
275
|
+
'--proc', '/proc', '--dev', '/dev', '--', '/bin/true',
|
|
276
|
+
], { timeout: 5_000, stdio: 'pipe' });
|
|
277
|
+
execFileSync(check.socatPath, ['-V'], { timeout: 5_000, stdio: 'pipe' });
|
|
278
|
+
return { ok: true, detail: 'Basic bwrap namespace and socat launch probes passed; full Claude sandbox policy is verified at execution.' };
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
const failure = error;
|
|
282
|
+
return { ok: false, detail: `${SANDBOX_INITIALIZATION_FAILED}: ${failure.message}\n${failure.stderr?.toString() ?? ''}`.trim() };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function codexAppArmorRestrictsUnprivilegedUserns(platform) {
|
|
286
|
+
if (platform !== 'linux')
|
|
287
|
+
return undefined;
|
|
288
|
+
try {
|
|
289
|
+
return fs.readFileSync('/proc/sys/kernel/apparmor_restrict_unprivileged_userns', 'utf8').trim() === '1';
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/** Resolve the bwrap binary Codex is most likely to use for its inner sandbox. */
|
|
296
|
+
export function resolveCodexSandboxBubblewrapPath(env = process.env) {
|
|
297
|
+
if (process.platform !== 'linux')
|
|
298
|
+
return undefined;
|
|
299
|
+
const bundled = codexBundledBubblewrap(env);
|
|
300
|
+
if (bundled && isExecutableFile(bundled))
|
|
301
|
+
return path.resolve(bundled);
|
|
302
|
+
return resolveBubblewrapPath(env);
|
|
303
|
+
}
|
|
304
|
+
export function inspectCodexSandboxAvailability(env = process.env, platform = process.platform) {
|
|
305
|
+
if (platform !== 'linux')
|
|
306
|
+
return { platform, status: 'not_applicable', missing: [] };
|
|
307
|
+
const bwrapPath = resolveCodexSandboxBubblewrapPath(env);
|
|
308
|
+
return {
|
|
309
|
+
platform,
|
|
310
|
+
status: bwrapPath ? 'ready' : 'missing',
|
|
311
|
+
bwrapPath,
|
|
312
|
+
apparmorRestrictsUnprivilegedUserns: codexAppArmorRestrictsUnprivilegedUserns(platform),
|
|
313
|
+
missing: bwrapPath ? [] : ['bubblewrap (bwrap)'],
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
export function formatCodexSandboxAvailability(check) {
|
|
317
|
+
if (check.status === 'not_applicable')
|
|
318
|
+
return `Codex Linux sandbox check not applicable on ${check.platform}`;
|
|
319
|
+
if (check.status === 'missing') {
|
|
320
|
+
return 'Codex Linux sandbox is unavailable: bubblewrap (bwrap) was not found; '
|
|
321
|
+
+ 'install or provision the Codex sandbox runtime. EvolCore will not disable the sandbox automatically.';
|
|
322
|
+
}
|
|
323
|
+
const apparmor = check.apparmorRestrictsUnprivilegedUserns === true
|
|
324
|
+
? ' AppArmor restricts unprivileged user namespaces on this host; the probe below confirms whether the active profile permits Codex.'
|
|
325
|
+
: '';
|
|
326
|
+
return `Codex Linux sandbox runtime found: bwrap=${check.bwrapPath}.${apparmor}`;
|
|
327
|
+
}
|
|
328
|
+
export function probeCodexSandboxAvailability(check) {
|
|
329
|
+
if (check.status !== 'ready' || !check.bwrapPath) {
|
|
330
|
+
return { ok: false, detail: formatCodexSandboxAvailability(check) };
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
execFileSync(check.bwrapPath, [
|
|
334
|
+
'--die-with-parent', '--new-session', '--unshare-pid', '--ro-bind', '/', '/',
|
|
335
|
+
'--proc', '/proc', '--dev-bind', '/dev', '/dev', '--tmpfs', '/tmp',
|
|
336
|
+
'--', '/bin/true',
|
|
337
|
+
], { timeout: 5_000, stdio: 'pipe' });
|
|
338
|
+
return { ok: true, detail: `Codex Linux sandbox user-namespace probe passed: bwrap=${check.bwrapPath}` };
|
|
339
|
+
}
|
|
340
|
+
catch (error) {
|
|
341
|
+
const failure = error;
|
|
342
|
+
const stderr = failure.stderr?.toString().trim();
|
|
343
|
+
const stdout = failure.stdout?.toString().trim();
|
|
344
|
+
const raw = stderr || stdout || failure.message.trim();
|
|
345
|
+
const apparmor = check.apparmorRestrictsUnprivilegedUserns === true
|
|
346
|
+
|| /apparmor_restrict_unprivileged_userns\s*=\s*1|apparmor/i.test(raw);
|
|
347
|
+
if (isCodexSandboxUserNamespaceFailure(raw)) {
|
|
348
|
+
const code = apparmor
|
|
349
|
+
? CODEX_SANDBOX_USER_NAMESPACE_DISABLED_BY_APPARMOR
|
|
350
|
+
: CODEX_SANDBOX_USER_NAMESPACE_UNAVAILABLE;
|
|
351
|
+
return {
|
|
352
|
+
ok: false,
|
|
353
|
+
kind: apparmor ? 'apparmor' : 'user_namespace',
|
|
354
|
+
detail: `${code}: ${raw}`,
|
|
355
|
+
raw,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return { ok: false, kind: 'bubblewrap', detail: `${SANDBOX_INITIALIZATION_FAILED}: ${raw}`, raw };
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
export function createCodexSandboxAvailabilityError(probe) {
|
|
362
|
+
const code = probe.kind === 'apparmor'
|
|
363
|
+
? CODEX_SANDBOX_USER_NAMESPACE_DISABLED_BY_APPARMOR
|
|
364
|
+
: probe.kind === 'user_namespace'
|
|
365
|
+
? CODEX_SANDBOX_USER_NAMESPACE_UNAVAILABLE
|
|
366
|
+
: SANDBOX_INITIALIZATION_FAILED;
|
|
367
|
+
return Object.assign(new Error(`${code}: ${probe.raw ?? probe.detail}`), {
|
|
368
|
+
code,
|
|
369
|
+
...(probe.raw ? { raw: probe.raw } : {}),
|
|
370
|
+
});
|
|
217
371
|
}
|
|
218
372
|
export function prependExecutableDirectory(env, executablePath) {
|
|
219
373
|
const currentPath = env.PATH ?? process.env.PATH ?? '';
|
|
@@ -713,7 +867,6 @@ export function buildBubblewrapCommand(executable, executableArgs, options) {
|
|
|
713
867
|
}
|
|
714
868
|
export function _resetSandboxRuntimeCache() {
|
|
715
869
|
sessionSandboxInitializationCircuits.clear();
|
|
716
|
-
cachedBubblewrapPath = undefined;
|
|
717
870
|
sandboxInitializationCircuit = undefined;
|
|
718
871
|
sandboxCircuitNoticeAt = 0;
|
|
719
872
|
sandboxInitializationFailureCounters = emptySandboxInitializationFailureCounters();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import { parseOwnershipCommand } from '../../aun/aid/ownership-operation.js';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import os from 'os';
|
|
4
5
|
import { randomUUID } from 'crypto';
|
|
@@ -42,7 +43,7 @@ export function expandManagedTempPath(value, options = {}) {
|
|
|
42
43
|
return substituteTmpDir(value, resolveManagedTempDir(options.env));
|
|
43
44
|
}
|
|
44
45
|
const WRITE_INTENT_RE = /(?:^|[\s;&|])(?:mkdir|mktemp|touch|tee|cp|mv|install|chmod|chown|ln|rm)(?:[\s;&|]|$)|(?:^|[\s])(?:\d>>?|>>?)\s*/i;
|
|
45
|
-
const TEMP_TOKEN_RE = /(?:\$TMPDIR|\$\{TMPDIR\}|\/
|
|
46
|
+
const TEMP_TOKEN_RE = /(?:\$TMPDIR|\$\{TMPDIR\}|\/(?:[^\s'";&|<>)]*\/)?(?:tmp|var\/tmp|dev\/shm)(?:\/|$))[^\s'";&|<>)]*/g;
|
|
46
47
|
function windowsTempRoots(options) {
|
|
47
48
|
if (process.platform !== 'win32')
|
|
48
49
|
return [];
|
|
@@ -2394,7 +2395,7 @@ export function evaluateToolPreflight(toolName, input, context) {
|
|
|
2394
2395
|
: undefined;
|
|
2395
2396
|
const stringShellCarrier = shellCarrier
|
|
2396
2397
|
?? (explicitCommandArgv ? undefined : resolveCodexShellCarrierString(command));
|
|
2397
|
-
const wrappedCommand = stringShellCarrier?.command;
|
|
2398
|
+
const wrappedCommand = stringShellCarrier?.parseFailure ? undefined : stringShellCarrier?.command;
|
|
2398
2399
|
const policyCommand = wrappedCommand ?? commandForPolicy;
|
|
2399
2400
|
if (context.sessionId && /^\s*(?:command\s+-v|which|type)\s+ec\s*$/i.test(policyCommand)) {
|
|
2400
2401
|
return {
|
|
@@ -2553,7 +2554,17 @@ export function evaluateToolPreflight(toolName, input, context) {
|
|
|
2553
2554
|
&& ['request', 'bypass'].includes(context.permissionMode ?? '');
|
|
2554
2555
|
const canUploadSelfAvatar = isSelfAvatarUpload
|
|
2555
2556
|
&& ['request', 'bypass'].includes(context.permissionMode ?? '');
|
|
2557
|
+
let isManagedOwnership = false;
|
|
2558
|
+
if (managedAidArgs?.[0] === 'bind') {
|
|
2559
|
+
try {
|
|
2560
|
+
const ownership = parseOwnershipCommand(managedAidArgs);
|
|
2561
|
+
isManagedOwnership = ownership.action === 'status'
|
|
2562
|
+
|| ['request', 'bypass'].includes(context.permissionMode ?? '');
|
|
2563
|
+
}
|
|
2564
|
+
catch { }
|
|
2565
|
+
}
|
|
2556
2566
|
const isAllowedManagedAidCommand = isManagedAidPublicRead
|
|
2567
|
+
|| isManagedOwnership
|
|
2557
2568
|
|| isSelfManagedAidShow
|
|
2558
2569
|
|| canPublishSelfAgentMd
|
|
2559
2570
|
|| canSetSelfAgentMd
|
|
@@ -2,7 +2,7 @@ import { getRoleDefinition } from '../../config/roles.js';
|
|
|
2
2
|
import { PUBLIC_PERMISSION_MODES } from '../permission/mode.js';
|
|
3
3
|
import { ConfigTarget, read } from '../../config/config-manager.js';
|
|
4
4
|
import { resolvePrincipal } from '../../config/contact-book.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getDaemonOwners, ownerResolver } from '../ownership/owner-resolver.js';
|
|
6
6
|
import { hasTrustedPrincipal } from '../auth/authenticated-actor.js';
|
|
7
7
|
const PERMISSION_MODE_AUTHORITY = {
|
|
8
8
|
readonly: 0,
|
|
@@ -150,9 +150,8 @@ export function validateRuntimeStringFieldOverride(input) {
|
|
|
150
150
|
export function isAgentFullAccessOwner(agentAid, principalId) {
|
|
151
151
|
if (!principalId)
|
|
152
152
|
return false;
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
&& loadDaemonConfig().owners?.includes(principalId) === true;
|
|
153
|
+
return ownerResolver.isOwner(agentAid, principalId)
|
|
154
|
+
&& getDaemonOwners().includes(principalId);
|
|
156
155
|
}
|
|
157
156
|
export function agentFullAccessStatus(agentAid, principalId) {
|
|
158
157
|
const config = read(ConfigTarget.Agent, { self: agentAid }, { cache: false });
|
|
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { ConfigTarget, mutateConfig, read as readConfig } from '../../config/config-manager.js';
|
|
4
4
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
5
|
+
import { isMainSession, isTopicSession, sessionTopicThreadId } from '../thread/topic-id.js';
|
|
5
6
|
import { isSystemControlChannel } from '../system-channels.js';
|
|
6
7
|
import { logger } from '../../utils/logger.js';
|
|
7
8
|
import { atomicWriteJson } from './session-fs-store.js';
|
|
@@ -35,7 +36,7 @@ export function resolveSessionLoopTarget(session) {
|
|
|
35
36
|
if (!session.selfAID || !peerId)
|
|
36
37
|
return undefined;
|
|
37
38
|
const peerKey = formatPeerKey(session.channelType || session.channel, peerId);
|
|
38
|
-
return { level: session
|
|
39
|
+
return { level: isTopicSession(session) ? 'topic-session' : 'relation-main', session, peerKey };
|
|
39
40
|
}
|
|
40
41
|
export function readSessionLoopConfig(target) {
|
|
41
42
|
let value;
|
|
@@ -90,7 +91,7 @@ export async function resolveCurrentSessionLoopTarget(store, route) {
|
|
|
90
91
|
const target = resolveSessionLoopTarget(session);
|
|
91
92
|
if (!target || !route.selfAid || session.selfAID !== route.selfAid
|
|
92
93
|
|| session.channel !== route.channel || session.channelId !== route.channelId
|
|
93
|
-
|| (session
|
|
94
|
+
|| (sessionTopicThreadId(session) ?? '') !== (route.threadId || '')) {
|
|
94
95
|
throw sessionLoopError('INVALID_CONTEXT', '当前会话路由或归属不匹配');
|
|
95
96
|
}
|
|
96
97
|
return target;
|
|
@@ -108,7 +109,7 @@ export function writeSessionLoopConfig(store, target, config) {
|
|
|
108
109
|
return { ...target, session };
|
|
109
110
|
}
|
|
110
111
|
const active = store.getActiveSessionSync(target.session.channel, target.session.channelId);
|
|
111
|
-
if (!active || active.deletedAt || active.id !== target.session.id || active
|
|
112
|
+
if (!active || active.deletedAt || active.id !== target.session.id || isTopicSession(active)) {
|
|
112
113
|
throw sessionLoopError('CONFLICT', '当前主会话已发生变化,请重新查询');
|
|
113
114
|
}
|
|
114
115
|
updateRelationSessionLoop(active, config);
|
|
@@ -430,6 +431,7 @@ export class SessionIdleMonitor {
|
|
|
430
431
|
state.emitted = true;
|
|
431
432
|
if (!this.persistState())
|
|
432
433
|
return;
|
|
434
|
+
const topicThreadId = sessionTopicThreadId(session);
|
|
433
435
|
this.options.eventBus.publish({
|
|
434
436
|
type: 'session:idle',
|
|
435
437
|
sessionId,
|
|
@@ -438,7 +440,7 @@ export class SessionIdleMonitor {
|
|
|
438
440
|
channelName: session.channel,
|
|
439
441
|
channelId: session.channelId,
|
|
440
442
|
chatType: session.chatType,
|
|
441
|
-
...(
|
|
443
|
+
...(topicThreadId ? { threadId: topicThreadId } : {}),
|
|
442
444
|
...(session.metadata?.peerId || session.channelId ? { peerId: session.metadata?.peerId || session.channelId } : {}),
|
|
443
445
|
...(typeof state.encrypted === 'boolean'
|
|
444
446
|
? { encrypted: state.encrypted }
|
|
@@ -491,12 +493,12 @@ export class SessionIdleMonitor {
|
|
|
491
493
|
}
|
|
492
494
|
isEligibleSession(session) {
|
|
493
495
|
return !!resolveSessionLoopTarget(session)
|
|
494
|
-
&& (
|
|
496
|
+
&& (isTopicSession(session) || !this.options.isCurrentMainSession || this.options.isCurrentMainSession(session));
|
|
495
497
|
}
|
|
496
498
|
async disarmMainSession(sessionId) {
|
|
497
499
|
try {
|
|
498
500
|
const session = await this.options.getSessionById(sessionId);
|
|
499
|
-
if (!session || session
|
|
501
|
+
if (!session || isTopicSession(session))
|
|
500
502
|
return;
|
|
501
503
|
this.clearTimers(sessionId);
|
|
502
504
|
this.generations.set(sessionId, (this.generations.get(sessionId) ?? 0) + 1);
|
|
@@ -509,7 +511,7 @@ export class SessionIdleMonitor {
|
|
|
509
511
|
try {
|
|
510
512
|
const session = await this.options.getSessionById(sessionId);
|
|
511
513
|
const state = this.sessions.get(sessionId);
|
|
512
|
-
if (!session || session
|
|
514
|
+
if (!session || isTopicSession(session) || !state || !this.isEligibleSession(session))
|
|
513
515
|
return;
|
|
514
516
|
this.clearTimers(sessionId);
|
|
515
517
|
this.generations.set(sessionId, (this.generations.get(sessionId) ?? 0) + 1);
|
|
@@ -525,7 +527,7 @@ export class SessionIdleMonitor {
|
|
|
525
527
|
async pruneInactiveMainSession(sessionId) {
|
|
526
528
|
try {
|
|
527
529
|
const session = await this.options.getSessionById(sessionId);
|
|
528
|
-
if (session &&
|
|
530
|
+
if (session && isMainSession(session) && !this.isEligibleSession(session))
|
|
529
531
|
await this.disarmMainSession(sessionId);
|
|
530
532
|
}
|
|
531
533
|
catch (error) {
|