evolcore 0.0.12 → 0.0.14
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 +37 -0
- package/bin/codex-managed-hook.mjs +4 -1
- package/bin/ec-safe-output.js +26 -7
- package/bin/install-codex-managed-hooks.mjs +201 -0
- package/dist/agents/claude-runner.js +105 -11
- package/dist/agents/codex-app-server-client.js +176 -7
- package/dist/agents/codex-runner.js +248 -84
- package/dist/agents/ecagent-runner.js +21 -2
- package/dist/agents/gemini-runner.js +9 -4
- package/dist/aun/aid/control-aid.js +36 -13
- package/dist/aun/aid/store.js +13 -7
- package/dist/aun/group-fs-download.js +56 -0
- package/dist/aun/group-identity.js +1 -2
- package/dist/aun/msg/group.js +11 -33
- package/dist/aun/msg/index.js +1 -2
- package/dist/aun/msg/managed-operation.js +176 -55
- package/dist/aun/msg/upload.js +16 -1
- package/dist/aun/outbox.js +31 -2
- package/dist/aun/rpc/client.js +66 -0
- package/dist/aun/rpc/index.js +1 -2
- package/dist/aun/storage/{upload.js → client.js} +11 -2
- package/dist/aun/storage/index.js +1 -2
- package/dist/channels/aun.js +514 -150
- package/dist/channels/daemon.js +2 -0
- package/dist/cli/agent.js +9 -96
- package/dist/cli/aun-commands.js +1 -1
- package/dist/cli/cli-argv.js +10 -0
- package/dist/cli/config.js +9 -17
- package/dist/cli/ctl-command.js +1 -1
- package/dist/cli/daemon-commands.js +39 -24
- package/dist/cli/fs-command.js +65 -19
- package/dist/cli/init.js +77 -8
- package/dist/cli/queue-command.js +42 -0
- package/dist/cli/restart-monitor.js +3 -14
- package/dist/cli/task-context.js +172 -0
- package/dist/cli/trigger-command.js +7 -0
- package/dist/config/access-policy.js +1 -2
- package/dist/config/builtin-roles.js +7 -0
- package/dist/config/config-manager.js +27 -3
- package/dist/config/contact-book-store.js +7 -2
- package/dist/config/peer-role-resolver.js +6 -2
- package/dist/config/role-migration-startup.js +53 -0
- package/dist/config/role-store.js +1 -1
- package/dist/core/auth/agent-delegation.js +1 -1
- package/dist/core/auth/auth-gateway.js +30 -1
- package/dist/core/auth/authorization-audit.js +47 -0
- package/dist/core/auth/operation-authorizer.js +1 -0
- package/dist/core/auth/operation-catalog.js +10 -1
- package/dist/core/bootstrap-messages.js +9 -2
- package/dist/core/bootstrap-service.js +8 -1
- package/dist/core/command/command-handler.js +201 -51
- package/dist/core/command/menu-catalog.js +4 -0
- package/dist/core/command/menu-handler.js +85 -18
- package/dist/core/command/menu-protocol.js +23 -2
- package/dist/core/command/slash-handler.js +58 -10
- package/dist/core/event-catalog.js +8 -0
- package/dist/core/handoff/runtime.js +12 -1
- package/dist/core/handoff/store.js +5 -1
- package/dist/core/interaction-router.js +10 -0
- package/dist/core/message/im-renderer.js +34 -1
- package/dist/core/message/message-bridge.js +68 -13
- package/dist/core/message/message-log.js +2 -0
- package/dist/core/message/message-queue.js +267 -39
- package/dist/core/message/message-utils.js +81 -4
- package/dist/core/message/response-engine.js +242 -48
- package/dist/core/message/stream-debouncer.js +10 -2
- package/dist/core/permission/approval-gateway.js +1 -0
- package/dist/core/permission/ec-command-parser.js +649 -18
- package/dist/core/permission/index.js +1 -1
- package/dist/core/permission/mode.js +15 -0
- package/dist/core/permission/readonly-shell-query.js +148 -8
- package/dist/core/permission/sandbox-runtime.js +21 -0
- package/dist/core/permission/tool-policy.js +266 -56
- package/dist/core/protected-paths.js +107 -2
- package/dist/core/runtime-lock.js +101 -0
- package/dist/core/session/session-manager.js +21 -2
- package/dist/core/session/session-mapper.js +20 -1
- package/dist/eck/detect.js +18 -1
- package/dist/eck/group-rules-sync.js +15 -44
- package/dist/index.js +191 -89
- package/dist/ipc.js +16 -3
- package/dist/paths.js +3 -0
- package/dist/response-system/engines/v1/proactive-flow.js +92 -8
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +64 -11
- package/dist/trigger/history.js +42 -7
- package/dist/trigger/manager.js +21 -1
- package/dist/trigger/parser.js +14 -2
- package/dist/trigger/scheduler.js +1 -0
- package/dist/trigger/validation.js +67 -6
- package/dist/utils/ecweb-supervisor.js +332 -0
- package/dist/utils/error-utils.js +17 -0
- package/dist/utils/logger.js +37 -4
- package/kits/docs/evolcore/trigger.md +17 -1
- package/kits/migrations/migrate-contact-book-v2.mjs +1 -2
- package/kits/schemas/role-config.schema.1.json +1 -0
- package/kits/templates/roles/admin.json +7 -0
- package/kits/templates/roles/member.json +8 -1
- package/kits/templates/roles/visitor.json +2 -0
- package/package.json +1 -1
- package/dist/aun/msg/payload-type.js +0 -27
- package/dist/aun/rpc/caller.js +0 -42
- package/dist/aun/rpc/connection.js +0 -25
- package/dist/aun/storage/manage.js +0 -10
- package/dist/config/access-policy-domain.js +0 -18
- package/dist/config/config-batch-get.js +0 -11
- package/dist/config/owner-policy.js +0 -4
- package/dist/config/role-config-v4-startup.js +0 -32
- package/dist/config/role-config-v5-startup.js +0 -27
- package/dist/core/auth/trigger-authorization.js +0 -15
- package/dist/core/interaction-registration.js +0 -10
- package/dist/core/permission/execution-sandbox.js +0 -16
- package/dist/core/relation/peer-key.js +0 -1
- package/dist/core/session/session-key.js +0 -24
- package/dist/eck/baseagent-caps.js +0 -18
- package/dist/eck/rules-loader.js +0 -28
|
@@ -2,6 +2,6 @@ export * from './tool-policy.js';
|
|
|
2
2
|
export * from './ec-command-parser.js';
|
|
3
3
|
export * from './readonly-shell-query.js';
|
|
4
4
|
export * from './approval-gateway.js';
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './mode.js';
|
|
6
6
|
// Tool summaries live in utils; keep the historical permission import path compatible.
|
|
7
7
|
export { summarizeToolInput } from '../../utils/tool-summary.js';
|
|
@@ -22,3 +22,18 @@ export function normalizePermissionMode(value) {
|
|
|
22
22
|
return { mode: 'readonly', workflow: 'plan', migratedFrom: 'plan' };
|
|
23
23
|
return { mode: 'readonly' };
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Phase one only disables the task execution sandbox for an authenticated
|
|
27
|
+
* owner running in bypass mode. Every other combination remains fail-closed.
|
|
28
|
+
*/
|
|
29
|
+
export function resolvePhaseOneExecutionSandbox(permissionMode, role) {
|
|
30
|
+
const normalizedMode = normalizePermissionMode(permissionMode).mode;
|
|
31
|
+
const normalizedRole = role ?? undefined;
|
|
32
|
+
const sandboxOff = normalizedMode === 'bypass' && normalizedRole === 'owner';
|
|
33
|
+
return {
|
|
34
|
+
permissionMode: normalizedMode,
|
|
35
|
+
role: normalizedRole,
|
|
36
|
+
state: sandboxOff ? 'off' : 'active',
|
|
37
|
+
reason: sandboxOff ? 'owner-bypass' : 'phase-one-required',
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -3,7 +3,7 @@ import { parseLiteralShellArgv } from './ec-command-parser.js';
|
|
|
3
3
|
const MAX_QUERY_LISTS = 8;
|
|
4
4
|
const MAX_PIPELINE_STAGES = 3;
|
|
5
5
|
const SUPPORTED_EXECUTABLES = new Set([
|
|
6
|
-
'echo', 'pwd', 'ls', 'cat', 'grep', 'rg', 'find', 'sed', 'head', 'sort',
|
|
6
|
+
'echo', 'pwd', 'ls', 'cat', 'grep', 'rg', 'find', 'sed', 'head', 'sort', 'git', 'wc', 'stat', 'lstat',
|
|
7
7
|
]);
|
|
8
8
|
const FIND_MUTATING_PRIMARY_RE = /^-(?:delete|exec|execdir|ok|okdir|fprint|fprint0|fprintf|fls)$/;
|
|
9
9
|
const RG_PROCESS_SPAWNING_OPTION_RE = /^(?:--pre|--hostname-bin|--pre-glob|--search-zip)(?:=|$)/;
|
|
@@ -71,8 +71,17 @@ function splitQueryStructure(command) {
|
|
|
71
71
|
segment += char;
|
|
72
72
|
continue;
|
|
73
73
|
}
|
|
74
|
-
if (char === '\0' || char === '\r' || char === '\n' || char === '
|
|
74
|
+
if (char === '\0' || char === '\r' || char === '\n' || char === '<')
|
|
75
75
|
return null;
|
|
76
|
+
if (char === '&') {
|
|
77
|
+
// A bounded sequence of independently proven read-only commands is
|
|
78
|
+
// safe to run in order. A single ampersand would background execution;
|
|
79
|
+
// `||` remains rejected because it introduces conditional control flow.
|
|
80
|
+
if (command[index + 1] !== '&' || !finishPipeline())
|
|
81
|
+
return null;
|
|
82
|
+
index++;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
76
85
|
if (char === '|') {
|
|
77
86
|
if (command[index + 1] === '|' || !finishStage())
|
|
78
87
|
return null;
|
|
@@ -89,12 +98,14 @@ function splitQueryStructure(command) {
|
|
|
89
98
|
return null;
|
|
90
99
|
return pipelines;
|
|
91
100
|
}
|
|
92
|
-
function parseStageArgv(segment) {
|
|
101
|
+
function parseStageArgv(segment, options) {
|
|
93
102
|
const redirectMatch = segment.match(STDERR_DEV_NULL_RE);
|
|
94
103
|
const withoutRedirect = redirectMatch?.[1] ?? segment;
|
|
95
104
|
if (withoutRedirect.includes('>'))
|
|
96
105
|
return null;
|
|
97
|
-
return parseLiteralShellArgv(withoutRedirect.trim()
|
|
106
|
+
return parseLiteralShellArgv(withoutRedirect.trim(), options.managedTempDir
|
|
107
|
+
? { allowManagedTmpDir: true, managedTempDir: options.managedTempDir }
|
|
108
|
+
: undefined);
|
|
98
109
|
}
|
|
99
110
|
function exact(value) {
|
|
100
111
|
return { value, access: 'exact' };
|
|
@@ -458,12 +469,118 @@ function analyzeSort(args) {
|
|
|
458
469
|
}
|
|
459
470
|
return paths;
|
|
460
471
|
}
|
|
472
|
+
/**
|
|
473
|
+
* Git metadata queries do not expose file contents and their output paths are
|
|
474
|
+
* controlled by the repository, not by arbitrary shell operands. Keep this
|
|
475
|
+
* deliberately small: status and read-only diff summaries are the patterns
|
|
476
|
+
* used for workspace diagnostics. Mutating subcommands and pathspecs remain
|
|
477
|
+
* unproven so the normal H-class checks still apply.
|
|
478
|
+
*/
|
|
479
|
+
function analyzeGit(args) {
|
|
480
|
+
if (args.length === 0)
|
|
481
|
+
return null;
|
|
482
|
+
const subcommand = args[0];
|
|
483
|
+
if (subcommand === 'status') {
|
|
484
|
+
// Keep the allow-list explicit; callers should request a bounded metadata
|
|
485
|
+
// view such as `--short` or `--branch`, rather than inheriting Git's full
|
|
486
|
+
// default output and any future options.
|
|
487
|
+
if (args.length === 1)
|
|
488
|
+
return null;
|
|
489
|
+
const allowed = new Set([
|
|
490
|
+
'--short', '--porcelain', '--porcelain=v1', '--porcelain=v2', '--branch',
|
|
491
|
+
'--untracked-files=no', '--untracked-files=normal', '--ignored=no',
|
|
492
|
+
'--ignore-submodules', '--renames', '--no-renames', '--ahead-behind',
|
|
493
|
+
'--no-ahead-behind', '--show-stash', '--no-optional-locks',
|
|
494
|
+
]);
|
|
495
|
+
for (const arg of args.slice(1)) {
|
|
496
|
+
if (arg === '--')
|
|
497
|
+
return null;
|
|
498
|
+
if (!allowed.has(arg))
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
return [];
|
|
502
|
+
}
|
|
503
|
+
if (subcommand === 'diff') {
|
|
504
|
+
let sawSummary = false;
|
|
505
|
+
let optionsEnded = false;
|
|
506
|
+
const paths = [];
|
|
507
|
+
const allowedFlags = new Set([
|
|
508
|
+
'--stat', '--shortstat', '--numstat', '--name-only', '--name-status',
|
|
509
|
+
'--no-ext-diff', '--no-renames', '--no-textconv', '--no-index',
|
|
510
|
+
'--cached', '--staged', '--merge-base', '--no-color', '--color=never',
|
|
511
|
+
]);
|
|
512
|
+
for (const arg of args.slice(1)) {
|
|
513
|
+
if (!optionsEnded && arg === '--') {
|
|
514
|
+
optionsEnded = true;
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
if (!optionsEnded && arg.startsWith('-')) {
|
|
518
|
+
if (arg === '--stat' || arg === '--shortstat' || arg === '--numstat'
|
|
519
|
+
|| arg === '--name-only' || arg === '--name-status')
|
|
520
|
+
sawSummary = true;
|
|
521
|
+
if (!allowedFlags.has(arg) && !/^[0-9a-f]{7,64}$/.test(arg))
|
|
522
|
+
return null;
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
// Revisions are safe literals; pathspecs after -- are bounded exact reads.
|
|
526
|
+
if (optionsEnded)
|
|
527
|
+
paths.push({ value: arg, access: 'exact' });
|
|
528
|
+
else if (!/^[0-9A-Za-z._~^/:-]+$/.test(arg))
|
|
529
|
+
return null;
|
|
530
|
+
}
|
|
531
|
+
return sawSummary ? paths : null;
|
|
532
|
+
}
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
function analyzeWc(args) {
|
|
536
|
+
const allowed = new Set(['-l', '-w', '-c', '-m', '-L', '--lines', '--words', '--bytes', '--chars', '--max-line-length']);
|
|
537
|
+
const paths = [];
|
|
538
|
+
for (const arg of args) {
|
|
539
|
+
if (arg.startsWith('-')) {
|
|
540
|
+
if (!allowed.has(arg))
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
else if (arg !== '-') {
|
|
544
|
+
paths.push(exact(arg));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return paths;
|
|
548
|
+
}
|
|
549
|
+
function analyzeStat(args) {
|
|
550
|
+
// GNU stat defaults to lstat semantics. Following a final symlink would
|
|
551
|
+
// let a metadata-only query reach a protected target through an alias.
|
|
552
|
+
if (args.some(argument => argument === '-L' || argument === '--dereference'))
|
|
553
|
+
return null;
|
|
554
|
+
const valueOptions = new Set(['-c', '--format', '--printf']);
|
|
555
|
+
const paths = [];
|
|
556
|
+
let optionsEnded = false;
|
|
557
|
+
for (let index = 0; index < args.length; index++) {
|
|
558
|
+
const argument = args[index];
|
|
559
|
+
if (!optionsEnded && argument === '--') {
|
|
560
|
+
optionsEnded = true;
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
if (!optionsEnded && argument.startsWith('-') && argument !== '-') {
|
|
564
|
+
const option = argument.split('=', 1)[0];
|
|
565
|
+
if (valueOptions.has(option) && !argument.includes('=') && ++index >= args.length)
|
|
566
|
+
return null;
|
|
567
|
+
if (!valueOptions.has(option) && !new Set(['-f', '--file-system', '-t', '--terse', '--cached']).has(option)) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (argument !== '-')
|
|
573
|
+
paths.push(exact(argument));
|
|
574
|
+
}
|
|
575
|
+
return paths.length > 0 ? paths : null;
|
|
576
|
+
}
|
|
461
577
|
function analyzeCommand(argv) {
|
|
462
578
|
const executable = normalizeExecutable(argv[0]);
|
|
463
579
|
if (!executable)
|
|
464
580
|
return null;
|
|
465
581
|
const args = argv.slice(1);
|
|
466
582
|
let pathOperands = null;
|
|
583
|
+
let accessKind = 'content';
|
|
467
584
|
switch (executable) {
|
|
468
585
|
case 'echo':
|
|
469
586
|
pathOperands = [];
|
|
@@ -495,12 +612,35 @@ function analyzeCommand(argv) {
|
|
|
495
612
|
case 'sort':
|
|
496
613
|
pathOperands = analyzeSort(args);
|
|
497
614
|
break;
|
|
615
|
+
case 'git':
|
|
616
|
+
pathOperands = analyzeGit(args);
|
|
617
|
+
break;
|
|
618
|
+
case 'wc':
|
|
619
|
+
pathOperands = analyzeWc(args);
|
|
620
|
+
break;
|
|
621
|
+
case 'stat':
|
|
622
|
+
case 'lstat':
|
|
623
|
+
pathOperands = analyzeStat(args);
|
|
624
|
+
accessKind = 'metadata';
|
|
625
|
+
break;
|
|
498
626
|
}
|
|
499
627
|
if (!pathOperands)
|
|
500
628
|
return null;
|
|
501
|
-
|
|
629
|
+
if (['ls', 'find'].includes(executable))
|
|
630
|
+
accessKind = 'enumerate';
|
|
631
|
+
return {
|
|
632
|
+
command: {
|
|
633
|
+
executable,
|
|
634
|
+
argv,
|
|
635
|
+
pathOperands,
|
|
636
|
+
// Keep the established IR shape for ordinary queries. Only metadata
|
|
637
|
+
// commands need an explicit action marker; content/enumeration are
|
|
638
|
+
// derived from their operands by policy consumers.
|
|
639
|
+
...(accessKind === 'metadata' ? { accessKind } : {}),
|
|
640
|
+
},
|
|
641
|
+
};
|
|
502
642
|
}
|
|
503
|
-
export function analyzeReadonlyShellQuery(command) {
|
|
643
|
+
export function analyzeReadonlyShellQuery(command, options = {}) {
|
|
504
644
|
const structure = splitQueryStructure(command);
|
|
505
645
|
if (!structure)
|
|
506
646
|
return { kind: 'unproven', reason: 'unsupported-shell-structure' };
|
|
@@ -509,14 +649,14 @@ export function analyzeReadonlyShellQuery(command) {
|
|
|
509
649
|
for (const stages of structure) {
|
|
510
650
|
const pipeline = [];
|
|
511
651
|
for (let index = 0; index < stages.length; index++) {
|
|
512
|
-
const argv = parseStageArgv(stages[index]);
|
|
652
|
+
const argv = parseStageArgv(stages[index], options);
|
|
513
653
|
if (!argv)
|
|
514
654
|
return { kind: 'unproven', reason: 'non-literal-command' };
|
|
515
655
|
const analyzed = analyzeCommand(argv);
|
|
516
656
|
if (!analyzed)
|
|
517
657
|
return { kind: 'unproven', reason: 'unsupported-command-or-option' };
|
|
518
658
|
if (index > 0) {
|
|
519
|
-
if (!['head', 'sort'].includes(analyzed.command.executable)) {
|
|
659
|
+
if (!['head', 'sort', 'grep', 'wc'].includes(analyzed.command.executable)) {
|
|
520
660
|
return { kind: 'unproven', reason: 'unsupported-pipeline-filter' };
|
|
521
661
|
}
|
|
522
662
|
if (analyzed.command.pathOperands.length > 0) {
|
|
@@ -4,6 +4,27 @@ import { resolveCommandPath } from '../../utils/cross-platform.js';
|
|
|
4
4
|
import { getExistingHClassMaskTargets, getExistingLClassReadOnlyTargets, isSameOrDescendant, } from '../protected-paths.js';
|
|
5
5
|
import { resolveRoot } from '../../paths.js';
|
|
6
6
|
let cachedBubblewrapPath;
|
|
7
|
+
export const SANDBOX_INITIALIZATION_FAILED = 'sandbox_initialization_failed';
|
|
8
|
+
/** Recognize sandbox bootstrap failures independently of localized stderr. */
|
|
9
|
+
export function isSandboxInitializationFailure(error, stderr = []) {
|
|
10
|
+
const text = [error instanceof Error ? error.message : String(error ?? ''), ...stderr]
|
|
11
|
+
.join('\n')
|
|
12
|
+
.toLowerCase();
|
|
13
|
+
return text.includes(SANDBOX_INITIALIZATION_FAILED)
|
|
14
|
+
|| /(?:apply-seccomp|seccomp)[\s\S]*(?:uid_map|gid_map|operation not permitted)/.test(text)
|
|
15
|
+
|| /(?:uid_map|gid_map)[\s\S]*(?:operation not permitted|permission denied)/.test(text)
|
|
16
|
+
|| /user namespace[\s\S]*(?:not permitted|unavailable|failed)/.test(text)
|
|
17
|
+
|| /bubblewrap[\s\S]*namespace[\s\S]*(?:failed|not permitted|permission denied)/.test(text);
|
|
18
|
+
}
|
|
19
|
+
export function createSandboxInitializationError(error, stderr = []) {
|
|
20
|
+
const detail = error instanceof Error ? error.message : String(error ?? 'sandbox bootstrap failed');
|
|
21
|
+
const wrapped = new Error(`${SANDBOX_INITIALIZATION_FAILED}: ${detail}`);
|
|
22
|
+
wrapped.name = 'SandboxInitializationError';
|
|
23
|
+
wrapped.code = SANDBOX_INITIALIZATION_FAILED;
|
|
24
|
+
if (stderr.length > 0)
|
|
25
|
+
wrapped.stderr = [...stderr].slice(-20);
|
|
26
|
+
return wrapped;
|
|
27
|
+
}
|
|
7
28
|
/**
|
|
8
29
|
* Claude Agent SDK's native sandbox is unavailable on Windows. WSL2 reports
|
|
9
30
|
* itself as Linux, so it remains fail-closed there together with macOS/Linux.
|