evolcore 0.0.28 → 0.0.29
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 +12 -0
- package/bin/ec-safe-output.js +270 -54
- package/dist/agents/baseagent-availability.js +37 -1
- package/dist/agents/baseagent.js +19 -9
- package/dist/agents/claude-runner.js +171 -13
- package/dist/agents/codex/app-server-client.js +6 -2
- package/dist/agents/codex/diagnostics.js +4 -3
- package/dist/agents/codex-runner.js +396 -95
- package/dist/agents/gemini-runner.js +35 -17
- package/dist/aun/group/history.js +130 -90
- package/dist/aun/group/operations.js +1 -3
- package/dist/aun/menu/transport.js +5 -3
- package/dist/aun/msg/managed-operation.js +70 -0
- package/dist/aun/msg/p2p.js +1 -3
- package/dist/aun/msg/upload.js +2 -2
- package/dist/aun/outbox.js +1 -37
- package/dist/channels/aun.js +249 -89
- package/dist/channels/daemon.js +18 -1
- package/dist/channels/feishu.js +1 -2
- package/dist/cli/agent-command.js +23 -3
- package/dist/cli/agent-create.js +68 -2
- package/dist/cli/agent.js +12 -2
- package/dist/cli/aun-commands.js +87 -13
- package/dist/cli/cli-argv.js +26 -0
- package/dist/cli/daemon-commands.js +40 -10
- package/dist/cli/data-command.js +4 -4
- package/dist/cli/handoff-command.js +2 -0
- package/dist/cli/index.js +18 -1
- package/dist/cli/managed-command-guard.js +10 -0
- package/dist/cli/memory-command.js +441 -0
- package/dist/cli/restart-monitor.js +62 -6
- package/dist/cli/skill-command.js +41 -0
- package/dist/cli/task-context.js +2 -23
- package/dist/cli/trigger-command.js +9 -1
- package/dist/cli/watch-msg-diag.js +209 -0
- package/dist/config/config-field-policy.js +52 -3
- package/dist/config/config-manager.js +17 -4
- package/dist/config/contact-book-store.js +2 -2
- package/dist/config/mention-mode.js +7 -2
- package/dist/config/merge.js +28 -9
- package/dist/config/resolved-config-op.js +1 -1
- package/dist/config/runtime-env.js +137 -0
- package/dist/config/schema-registry.js +11 -1
- package/dist/config-store.js +10 -10
- package/dist/core/audit/event-key.js +3 -1
- package/dist/core/audit/log-integrity.js +4 -0
- package/dist/core/auth/agent-delegation.js +2 -1
- package/dist/core/auth/auth-gateway.js +13 -6
- package/dist/core/auth/authorization-audit.js +54 -19
- package/dist/core/auth/operation-authorizer.js +17 -0
- package/dist/core/auth/operation-catalog.js +9 -0
- package/dist/core/causation/context.js +5 -1
- package/dist/core/command/agent-control.js +1 -2
- package/dist/core/command/command-handler.js +51 -23
- package/dist/core/command/memory-slash.js +270 -0
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +315 -60
- package/dist/core/command/menu-protocol.js +42 -4
- package/dist/core/command/slash-gate.js +10 -10
- package/dist/core/command/slash-handler.js +206 -64
- package/dist/core/data-migration.js +282 -505
- package/dist/core/event-catalog.js +26 -0
- package/dist/core/evolagent-registry.js +6 -0
- package/dist/core/evolagent.js +0 -10
- package/dist/core/handoff/store.js +1 -20
- package/dist/core/inference/text-inference.js +57 -1
- package/dist/core/memory/consolidation-context.js +505 -0
- package/dist/core/memory/consolidation-ops-records.js +124 -0
- package/dist/core/memory/consolidation-trigger.js +394 -0
- package/dist/core/memory/index-manager.js +308 -0
- package/dist/core/memory/launch-consolidation.js +395 -0
- package/dist/core/memory/memory-admin.js +234 -0
- package/dist/core/memory/memory-document.js +100 -0
- package/dist/core/memory/memory-session-policy.js +41 -0
- package/dist/core/memory/memory-signature.js +257 -0
- package/dist/core/memory/memory-writer.js +432 -0
- package/dist/core/memory/staleness.js +117 -0
- package/dist/core/message/auto-mention-gate.js +454 -0
- package/dist/core/message/im-renderer.js +69 -16
- package/dist/core/message/message-bridge.js +287 -21
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +114 -27
- package/dist/core/message/pending-hints.js +329 -161
- package/dist/core/message/response-engine.js +567 -80
- package/dist/core/permission/ec-command-parser.js +1029 -80
- package/dist/core/permission/protected-paths.js +376 -126
- package/dist/core/permission/sandbox-runtime.js +40 -12
- package/dist/core/permission/tool-error-code.js +96 -13
- package/dist/core/permission/tool-policy.js +276 -23
- package/dist/core/role/runtime-policy.js +3 -7
- package/dist/core/session/{runner-task-history.js → runner-event-summary.js} +1 -1
- package/dist/core/session/session-fs-store.js +0 -76
- package/dist/core/session/session-idle-monitor.js +355 -0
- package/dist/core/session/session-manager.js +478 -17
- package/dist/core/session/session-mapper.js +33 -16
- package/dist/core/session/session-renew.js +217 -155
- package/dist/core/session/{session-turns.js → session-transcript.js} +35 -6
- package/dist/core/skill/global-watcher.js +282 -0
- package/dist/core/skill/index-generator.js +84 -0
- package/dist/core/skill/startup.js +73 -0
- package/dist/core/skill/switch-resolver.js +115 -0
- package/dist/core/task/task-activity-store.js +219 -0
- package/dist/eck/kit-renderer.js +30 -3
- package/dist/eck/manifest-engine.js +26 -4
- package/dist/index.js +708 -18
- package/dist/ipc.js +564 -2
- package/dist/paths.js +30 -9
- package/dist/response-system/engines/v1/proactive-flow.js +116 -15
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +1 -0
- package/dist/trigger/manager.js +0 -10
- package/dist/trigger/scheduler.js +11 -0
- package/dist/trigger/validation.js +22 -0
- package/dist/utils/avatar-upload.js +59 -18
- package/dist/utils/error-dict.json +6 -3
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/logger.js +32 -10
- package/dist/utils/media-cache.js +84 -0
- package/dist/utils/msg-diag.js +97 -0
- package/dist/utils/welcome.js +37 -8
- package/kits/docs/AUTHORING.md +314 -0
- package/kits/docs/GUIDE.md +2 -0
- package/kits/docs/INDEX.md +2 -0
- package/kits/docs/aun/CHEATSHEET.md +4 -0
- package/kits/docs/aun/SDK.md +60 -0
- package/kits/docs/context-assembly.md +10 -6
- package/kits/docs/evolcore/INDEX.md +17 -3
- package/kits/docs/evolcore/agent-create.md +24 -0
- package/kits/docs/evolcore/agent.md +5 -2
- package/kits/docs/evolcore/config.md +1 -1
- package/kits/docs/evolcore/ec-capabilities.md +364 -0
- package/kits/docs/evolcore/group.md +34 -18
- package/kits/docs/evolcore/memory-architecture.md +78 -0
- package/kits/docs/evolcore/memory-consolidation-batches.md +133 -0
- package/kits/docs/evolcore/memory-consolidation.md +263 -0
- package/kits/docs/evolcore/memory-tags.md +63 -0
- package/kits/docs/evolcore/memory.md +110 -0
- package/kits/docs/evolcore/menu-client.md +27 -11
- package/kits/{schemas → docs/evolcore}/menu-exec-schema-commands.md +12 -6
- package/kits/docs/evolcore/menu-protocol.md +213 -0
- package/kits/docs/evolcore/msg.md +2 -0
- package/kits/docs/evolcore/trigger.md +7 -5
- package/kits/docs/path-registry.md +6 -8
- package/kits/docs/prompt-loading-architecture.md +5 -3
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +294 -88
- package/kits/eck_manifest.memory.json +257 -0
- package/kits/rules/03-identity.md +8 -8
- package/kits/rules/05-venue.md +4 -2
- package/kits/rules/06-channel.md +1 -1
- package/kits/schemas/_meta.json +276 -47
- package/kits/schemas/agent-config.schema.12.json +38 -2
- package/kits/schemas/agent-config.schema.13.json +591 -0
- package/kits/schemas/daemon.schema.6.json +9 -9
- package/kits/schemas/defaults.schema.5.json +29 -0
- package/kits/schemas/relation-config.schema.8.json +14 -1
- package/kits/schemas/relation-config.schema.9.json +129 -0
- package/kits/schemas/role-config.schema.1.json +3 -3
- package/kits/skills/.switches.json +3 -0
- package/kits/skills/ec-skill/SKILL.md +217 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +128 -0
- package/kits/skills/ec-skill/scripts/deps.mjs +107 -0
- package/kits/skills/ec-skill/scripts/frontmatter.mjs +104 -0
- package/kits/skills/ec-skill/scripts/skill.mjs +629 -0
- package/kits/skills/ec-skill/scripts/template/SKILL.md.tmpl +30 -0
- package/kits/templates/decision/auto-mention.md +25 -0
- package/kits/templates/decision/session-renew.md +22 -0
- package/kits/templates/memory-consolidation/forget.md +104 -0
- package/kits/templates/memory-consolidation/generalize.md +76 -0
- package/kits/templates/memory-consolidation/notes.md +133 -0
- package/kits/templates/memory-consolidation/profile.md +58 -0
- package/kits/templates/memory-consolidation/promote.md +72 -0
- package/kits/templates/memory-consolidation/workflow.md +75 -0
- package/kits/templates/system-fragments/bootstrap.md +14 -5
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/group-history.md +6 -0
- package/kits/templates/system-fragments/identity.md +0 -3
- package/kits/templates/system-fragments/memory.md +79 -0
- package/kits/templates/system-fragments/reply.md +1 -0
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -6
- package/dist/trigger/legacy-session-history.js +0 -19
- package/kits/templates/system-fragments/group-unread-history.md +0 -7
|
@@ -1,68 +1,55 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolveRoot } from '../../paths.js';
|
|
4
|
+
import { isValidAid } from '../../aun/aid/identity.js';
|
|
4
5
|
const H_CLASS_RELATIVE_PATTERNS = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/^
|
|
8
|
-
/^
|
|
9
|
-
/^agents\/[^/]+\/contact-operations\.jsonl$/,
|
|
10
|
-
/^agents\/[^/]+\/relations\/[^/]+\/config\.json$/,
|
|
11
|
-
/^backups\/config(?:\/|$)/,
|
|
6
|
+
// These are true secret or daemon-owned roots. Agent-owned content is not
|
|
7
|
+
// H-class merely because it is persisted under the EvolCore home.
|
|
8
|
+
/^data(?:\/|$)/,
|
|
9
|
+
/^(?:AIDs|aids)(?:\/|$)/,
|
|
12
10
|
/^\.snapshots(?:\/|$)/,
|
|
13
11
|
/^CA(?:\/|$)/,
|
|
14
|
-
/^(?:AIDs|aids)\/[^/]+\/(?:cert|keys|private)(?:\/|$)/,
|
|
15
12
|
/^\.device_id$/,
|
|
16
13
|
/^\.env$/,
|
|
17
14
|
/^\.seed(?:\.|$)/,
|
|
18
15
|
/^\.migrated-/,
|
|
19
|
-
/(?:^|\/)[^/]+\.json_$/,
|
|
20
|
-
/(?:^|\/)[^/]+\.json\.migrated$/,
|
|
21
|
-
/^agents\/defaults_\d+\.json$/,
|
|
22
16
|
/^\.lock$/,
|
|
23
17
|
/^daemon\.pid$/,
|
|
24
|
-
/^data\/
|
|
25
|
-
/^data\/
|
|
26
|
-
/^data\/(?:sessions(?:\/|$)|contact-book-audit\.jsonl$|feishu-seen-.*\.jsonl$|[a-z0-9_-]+-greeted-.*\.jsonl$|message-queue\.json(?:_|__|\.tmp-.*)?$|daemon\/(?:message-queue\.json(?:_|__|\.tmp-.*)?$|control(?:\/|$)|migrations(?:\/|$))|channel-state(?:\/|$))/,
|
|
27
|
-
/^data\/instance\/control\.token$/,
|
|
28
|
-
/^data\/outbox(?:\/|$)/,
|
|
29
|
-
/^data\/handoff(?:\/|$)/,
|
|
30
|
-
/^agents\/[^/]+\/sessions(?:\/|$)/,
|
|
31
|
-
/^agents\/[^/]+\/data\/async-questions(?:\/|$)/,
|
|
32
|
-
/^agents\/[^/]+\/data\/aun(?:\/|$)/,
|
|
33
|
-
/^agents\/[^/]+\/data\/(?:channels(?:\/|$)|handoff(?:\/|$)|(?:outbox|activity-outbox)\.jsonl(?:_|__|\.tmp-.*)?$|contact-audit\.jsonl$)/,
|
|
18
|
+
/^agents\/[^/]+\/data\/codex-tokens(?:\/|$)/,
|
|
19
|
+
/^agents\/[^/]+\/data\/(?:.*\/)?(?:context-tokens|menu-tokens)\.json(?:_|__|\.tmp-.*)?$/,
|
|
34
20
|
];
|
|
35
21
|
const H_CLASS_REFERENCE_PATTERNS = [
|
|
36
|
-
/(?:^|[/\\\s"'=<>])
|
|
37
|
-
/(?:^|[/\\\s"'=<>])
|
|
38
|
-
/(?:^|[^A-Za-z0-9_.-])daemon\.
|
|
39
|
-
/(?:^|[
|
|
40
|
-
/(?:^|[^A-Za-z0-9_.-])(?:backups[\\/]config|\.snapshots|CA|(?:AIDs|aids)[\\/][^/\\\s"']+[\\/](?:cert|keys|private))(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
41
|
-
/(?:^|[/\\\s"'=<>])(?:\.device_id|\.env|\.seed(?:\.[^/\\\s"']*)?|\.migrated-[^/\\\s"']*|\.lock|daemon\.pid|data[\\/](?:causation-aun\.json(?:_|__)?|sessions|contact-book-audit\.jsonl|feishu-seen-[^/\\\s"']+\.jsonl|[a-z0-9_-]+-greeted-[^/\\\s"']+\.jsonl|message-queue\.json(?:_|__|\.tmp-[^/\\\s"']*)?|daemon[\\/](?:message-queue\.json(?:_|__|\.tmp-[^/\\\s"']*)?|control|migrations)|channel-state|instance[\\/]control\.token|outbox|handoff)|agents[\\/][^/\\\s"']+[\\/](?:sessions|data[\\/](?:channels|handoff|(?:outbox|activity-outbox)\.jsonl|contact-audit\.jsonl)))(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
42
|
-
/(?:^|[/\\\s"'=<>])data[\\/]triggers(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
43
|
-
/(?:^|[/\\\s"'=<>])(?:[^/\\\s"']+\.json_|[^/\\\s"']+\.json\.migrated|defaults_\d+\.json)(?=$|[\s"';&|<>)},])/,
|
|
22
|
+
/(?:^|[/\\\s"'=<>])data[\\/]/,
|
|
23
|
+
/(?:^|[/\\\s"'=<>])(?:AIDs|aids)[\\/]/,
|
|
24
|
+
/(?:^|[^A-Za-z0-9_.-])(?:\.device_id|\.env|\.seed(?:\.[^/\\\s"']*)?|\.migrated-[^/\\\s"']*|\.lock|daemon\.pid)(?=$|[\s"';&|<>)},])/,
|
|
25
|
+
/(?:^|[/\\\s"'=<>])agents[\\/][^/\\\s"']+[\\/]data[\\/](?:codex-tokens|(?:.*[\\/])?(?:context-tokens|menu-tokens)\.json)(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
44
26
|
];
|
|
45
27
|
// H-class directory roots are kept separately from the full path matcher so
|
|
46
28
|
// an exact metadata query can distinguish a protected directory from a
|
|
47
29
|
// protected file. Descendants inherit the directory classification unless an
|
|
48
30
|
// existing regular file gives us a more precise answer.
|
|
49
31
|
const H_CLASS_DIRECTORY_RELATIVE_PATTERNS = [
|
|
50
|
-
/^
|
|
51
|
-
/^
|
|
52
|
-
/^backups\/config(?:\/|$)/,
|
|
32
|
+
/^data(?:\/|$)/,
|
|
33
|
+
/^(?:AIDs|aids)(?:\/|$)/,
|
|
53
34
|
/^\.snapshots(?:\/|$)/,
|
|
54
35
|
/^CA(?:\/|$)/,
|
|
55
|
-
/^
|
|
56
|
-
/^data\/(?:triggers|sessions|outbox|handoff|channel-state)(?:\/|$)/,
|
|
57
|
-
/^data\/daemon\/(?:control|migrations)(?:\/|$)/,
|
|
58
|
-
/^agents\/[^/]+\/sessions(?:\/|$)/,
|
|
59
|
-
/^agents\/[^/]+\/data\/(?:channels|handoff)(?:\/|$)/,
|
|
36
|
+
/^agents\/[^/]+\/data\/codex-tokens(?:\/|$)/,
|
|
60
37
|
];
|
|
61
38
|
const L_CLASS_RELATIVE_PATTERNS = [
|
|
39
|
+
/^daemon\.json$/,
|
|
40
|
+
/^agents\/defaults\.json$/,
|
|
41
|
+
/^agents\/[^/]+\/config\.json$/,
|
|
42
|
+
/^agents\/[^/]+\/contact\.json$/,
|
|
43
|
+
/^agents\/[^/]+\/contact-operations\.jsonl$/,
|
|
44
|
+
/^agents\/[^/]+\/relations\/[^/]+\/config\.json$/,
|
|
45
|
+
/^backups\/config(?:\/|$)/,
|
|
62
46
|
/^agents\/[^/]+\/triggers(?:\/|$)/,
|
|
63
47
|
/^agents\/[^/]+\/roles(?:\/|$)/,
|
|
64
48
|
];
|
|
65
49
|
const L_CLASS_REFERENCE_PATTERNS = [
|
|
50
|
+
/(?:^|[^A-Za-z0-9_.-])daemon\.json(?=$|[^A-Za-z0-9_.-])/,
|
|
51
|
+
/(?:^|[^A-Za-z0-9_.-])agents[\\/](?:defaults\.json|[^/\\\s"']+[\\/](?:(?:config|contact)\.json|contact-operations\.jsonl|relations[\\/][^/\\\s"']+[\\/]config\.json))(?=$|[\s"';&|<>)},])/,
|
|
52
|
+
/(?:^|[^A-Za-z0-9_.-])backups[\\/]config(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
66
53
|
/(?:^|[^A-Za-z0-9_.-])agents[\\/][^/\\\s"']+[\\/]triggers(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
67
54
|
/(?:^|[^A-Za-z0-9_.-])agents[\\/][^/\\\s"']+[\\/]roles(?:[\\/]|$|[\s"';&|<>)},])/,
|
|
68
55
|
];
|
|
@@ -88,6 +75,60 @@ function resolveThroughExistingAncestor(value) {
|
|
|
88
75
|
return absolute;
|
|
89
76
|
}
|
|
90
77
|
}
|
|
78
|
+
function hasExplicitSelfAid(options) {
|
|
79
|
+
// Several legacy helper callers construct an options object with the
|
|
80
|
+
// optional property spread from an absent runtime binding, which produces
|
|
81
|
+
// `selfAid: undefined`. Treat that the same as an omitted property so the
|
|
82
|
+
// compatibility projection remains available. An explicitly supplied
|
|
83
|
+
// empty/invalid string is still fail-closed below.
|
|
84
|
+
return !!options
|
|
85
|
+
&& Object.prototype.hasOwnProperty.call(options, 'selfAid')
|
|
86
|
+
&& options.selfAid !== undefined;
|
|
87
|
+
}
|
|
88
|
+
function normalizeAid(value) {
|
|
89
|
+
if (typeof value !== 'string')
|
|
90
|
+
return undefined;
|
|
91
|
+
const normalized = value.trim();
|
|
92
|
+
return normalized && isValidAid(normalized) ? normalized : undefined;
|
|
93
|
+
}
|
|
94
|
+
function assertValidSelfAid(options, operation) {
|
|
95
|
+
if (hasExplicitSelfAid(options) && !normalizeAid(options?.selfAid)) {
|
|
96
|
+
throw new Error(`[Permission] ${operation} requires a valid selfAid`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function hasInvalidExplicitSelfAid(options) {
|
|
100
|
+
return hasExplicitSelfAid(options) && !normalizeAid(options?.selfAid);
|
|
101
|
+
}
|
|
102
|
+
function agentScopeRelative(relative, selfAid) {
|
|
103
|
+
const parts = relative.split('/').filter(Boolean);
|
|
104
|
+
if (parts[0] !== 'agents' || !parts[1])
|
|
105
|
+
return false;
|
|
106
|
+
const own = normalizeAid(selfAid);
|
|
107
|
+
if (/^defaults(?:_\d+)?\.json$/i.test(parts[1]))
|
|
108
|
+
return false;
|
|
109
|
+
// With no identity context, the legacy H-class projection is used instead
|
|
110
|
+
// of guessing which Agent is self.
|
|
111
|
+
return !!own && parts[1].toLowerCase() !== own.toLowerCase();
|
|
112
|
+
}
|
|
113
|
+
function matchesAgentScopeRelative(relative, selfAid) {
|
|
114
|
+
return agentScopeRelative(relative, selfAid);
|
|
115
|
+
}
|
|
116
|
+
function agentScopeCandidate(value, options = {}) {
|
|
117
|
+
if (!normalizeAid(options.selfAid))
|
|
118
|
+
return undefined;
|
|
119
|
+
const root = resolveThroughExistingAncestor(options.root ?? resolveRoot());
|
|
120
|
+
const lexical = lexicalCandidate(value, options.cwd);
|
|
121
|
+
if (isSameOrDescendant(lexical, root)) {
|
|
122
|
+
const relative = path.relative(root, lexical).split(path.sep).join('/');
|
|
123
|
+
if (matchesAgentScopeRelative(relative, options.selfAid))
|
|
124
|
+
return lexical;
|
|
125
|
+
}
|
|
126
|
+
const candidate = resolveProtectedCandidate(value, options.cwd);
|
|
127
|
+
if (!isSameOrDescendant(candidate, root))
|
|
128
|
+
return undefined;
|
|
129
|
+
const relative = path.relative(root, candidate).split(path.sep).join('/');
|
|
130
|
+
return matchesAgentScopeRelative(relative, options.selfAid) ? candidate : undefined;
|
|
131
|
+
}
|
|
91
132
|
/**
|
|
92
133
|
* H-class file names are normally leaves, but treating their descendants as
|
|
93
134
|
* protected as well is important when a malformed or externally-created
|
|
@@ -104,6 +145,28 @@ function matchesHClassRelative(relative) {
|
|
|
104
145
|
}
|
|
105
146
|
return false;
|
|
106
147
|
}
|
|
148
|
+
const SELF_AWARE_H_CLASS_RELATIVE_PATTERNS = [
|
|
149
|
+
/^data(?:\/|$)/,
|
|
150
|
+
/^(?:AIDs|aids)(?:\/|$)/,
|
|
151
|
+
/^CA(?:\/|$)/,
|
|
152
|
+
/^\.device_id$/,
|
|
153
|
+
/^\.env$/,
|
|
154
|
+
/^\.seed(?:\.|$)/,
|
|
155
|
+
/^\.lock$/,
|
|
156
|
+
/^daemon\.pid$/,
|
|
157
|
+
];
|
|
158
|
+
function matchesSelfAwareHClassRelative(relative, selfAid) {
|
|
159
|
+
if (matchesAgentScopeRelative(relative, selfAid))
|
|
160
|
+
return true;
|
|
161
|
+
if (SELF_AWARE_H_CLASS_RELATIVE_PATTERNS.some(pattern => pattern.test(relative)))
|
|
162
|
+
return true;
|
|
163
|
+
const own = normalizeAid(selfAid);
|
|
164
|
+
if (!own)
|
|
165
|
+
return false;
|
|
166
|
+
const escaped = own.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
167
|
+
return new RegExp(`^agents/${escaped}/data/codex-tokens(?:/|$)`).test(relative)
|
|
168
|
+
|| new RegExp(`^agents/${escaped}/data/(?:.*\/)?(?:context-tokens|menu-tokens)\\.json(?:_|__|\\.tmp-.*)?$`).test(relative);
|
|
169
|
+
}
|
|
107
170
|
export function isSameOrDescendant(candidate, parent) {
|
|
108
171
|
const normalizedCandidate = normalizeForComparison(candidate);
|
|
109
172
|
const normalizedParent = normalizeForComparison(parent);
|
|
@@ -119,16 +182,22 @@ export function isHClassPath(value, options = {}) {
|
|
|
119
182
|
const lexicalCandidate = path.isAbsolute(value)
|
|
120
183
|
? path.resolve(value)
|
|
121
184
|
: path.resolve(options.cwd ?? process.cwd(), value);
|
|
185
|
+
if (hasInvalidExplicitSelfAid(options))
|
|
186
|
+
return isSameOrDescendant(lexicalCandidate, root);
|
|
187
|
+
if (agentScopeCandidate(value, options))
|
|
188
|
+
return true;
|
|
122
189
|
if (isSameOrDescendant(lexicalCandidate, root)) {
|
|
123
190
|
const lexicalRelative = path.relative(root, lexicalCandidate).split(path.sep).join('/');
|
|
124
|
-
if (matchesHClassRelative(lexicalRelative))
|
|
191
|
+
if ((options.selfAid ? matchesSelfAwareHClassRelative(lexicalRelative, options.selfAid) : matchesHClassRelative(lexicalRelative)))
|
|
125
192
|
return true;
|
|
126
193
|
}
|
|
127
194
|
const candidate = resolveProtectedCandidate(value, options.cwd);
|
|
128
195
|
if (!isSameOrDescendant(candidate, root))
|
|
129
196
|
return false;
|
|
130
197
|
const relative = path.relative(root, candidate).split(path.sep).join('/');
|
|
131
|
-
return
|
|
198
|
+
return options.selfAid
|
|
199
|
+
? matchesSelfAwareHClassRelative(relative, options.selfAid)
|
|
200
|
+
: matchesHClassRelative(relative);
|
|
132
201
|
}
|
|
133
202
|
function hasPathSyntax(value) {
|
|
134
203
|
return /[\0\r\n$`*?\[\]{}<>|;&]/.test(value);
|
|
@@ -166,7 +235,11 @@ export function classifyProtectedPath(value, options = {}) {
|
|
|
166
235
|
const relative = relativeWithinRoot(candidate, root);
|
|
167
236
|
if (relative === undefined)
|
|
168
237
|
return 'ordinary';
|
|
169
|
-
|
|
238
|
+
if (matchesAgentScopeRelative(relative, options.selfAid))
|
|
239
|
+
return 'h-directory';
|
|
240
|
+
const hMatch = options.selfAid
|
|
241
|
+
? matchesSelfAwareHClassRelative(relative, options.selfAid)
|
|
242
|
+
: matchesHClassRelative(relative);
|
|
170
243
|
if (hMatch) {
|
|
171
244
|
let directory = H_CLASS_DIRECTORY_RELATIVE_PATTERNS.some(pattern => pattern.test(relative));
|
|
172
245
|
try {
|
|
@@ -205,29 +278,77 @@ export function checkProtectedPathAccess(value, accessKind, options = {}) {
|
|
|
205
278
|
allowed: accessKind !== 'write' && accessKind !== 'grant',
|
|
206
279
|
};
|
|
207
280
|
}
|
|
208
|
-
export function
|
|
281
|
+
export function isAgentScopePath(value, options = {}) {
|
|
282
|
+
return !!agentScopeCandidate(value, options);
|
|
283
|
+
}
|
|
284
|
+
export function containsAgentScopeReference(value, options = {}) {
|
|
285
|
+
if (hasInvalidExplicitSelfAid(options))
|
|
286
|
+
return true;
|
|
287
|
+
if (!normalizeAid(options.selfAid))
|
|
288
|
+
return false;
|
|
289
|
+
const root = resolveThroughExistingAncestor(options.root ?? resolveRoot());
|
|
290
|
+
return extractLiteralPathCandidates(value).some(candidate => isAgentScopePath(candidate, { ...options, root }));
|
|
291
|
+
}
|
|
292
|
+
export function containsHClassReference(value, options = {}) {
|
|
293
|
+
if (hasInvalidExplicitSelfAid(options))
|
|
294
|
+
return true;
|
|
209
295
|
const normalized = value.replace(/\\/g, '/');
|
|
210
296
|
const unquoted = normalized.replace(/^["']|["']$/g, '').replace(/[;,) ]+$/, '');
|
|
297
|
+
// Resolve literal paths before applying textual rules. A self-Agent path
|
|
298
|
+
// such as agents/<self>/data/outbox/... contains the shared `data/` token,
|
|
299
|
+
// but it is ordinary Agent-owned data and must not inherit data/** H-class.
|
|
300
|
+
const literalCandidates = extractLiteralPathCandidates(value);
|
|
301
|
+
if (literalCandidates.length) {
|
|
302
|
+
const root = resolveThroughExistingAncestor(options.root ?? resolveRoot());
|
|
303
|
+
const inRoot = literalCandidates.filter(candidate => {
|
|
304
|
+
const resolved = resolveProtectedCandidate(candidate, options.cwd);
|
|
305
|
+
return isSameOrDescendant(resolved, root);
|
|
306
|
+
});
|
|
307
|
+
if (inRoot.length) {
|
|
308
|
+
return inRoot.some(candidate => isHClassPath(candidate, options) || isAgentScopePath(candidate, options));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
211
311
|
if (H_CLASS_RELATIVE_PATTERNS.some(pattern => pattern.test(unquoted)))
|
|
212
312
|
return true;
|
|
213
|
-
return H_CLASS_REFERENCE_PATTERNS.some(pattern => pattern.test(normalized))
|
|
313
|
+
return H_CLASS_REFERENCE_PATTERNS.some(pattern => pattern.test(normalized))
|
|
314
|
+
|| containsAgentScopeReference(value, options);
|
|
315
|
+
}
|
|
316
|
+
function extractLiteralPathCandidates(value) {
|
|
317
|
+
const normalized = value.replace(/\\/g, '/');
|
|
318
|
+
const candidates = new Set();
|
|
319
|
+
const absolute = normalized.match(/(?:[A-Za-z]:\/|\/)[^\s"'`;|&<>()[\]{}]+/g) ?? [];
|
|
320
|
+
for (const candidate of absolute)
|
|
321
|
+
candidates.add(candidate.replace(/[.,:]+$/, ''));
|
|
322
|
+
const relative = normalized.match(/(?:^|[\s"'=<>:(])((?:\.{0,2}\/)?(?:agents|data|AIDs|aids|backups|CA|\.snapshots)(?:\/[^\s"'`;|&<>()[\]{}]*)?)/gi) ?? [];
|
|
323
|
+
for (const candidate of relative)
|
|
324
|
+
candidates.add(candidate.replace(/^[\s"'=<>:(]+/, '').replace(/[.,:]+$/, ''));
|
|
325
|
+
for (const candidate of normalized.split(/[\s"'=<>:();|&]+/).filter(Boolean)) {
|
|
326
|
+
if (/^(?:daemon\.json|\.device_id|\.env|\.seed(?:\.[^/]+)?|\.lock|daemon\.pid)$/i.test(candidate)) {
|
|
327
|
+
candidates.add(candidate);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return [...candidates];
|
|
214
331
|
}
|
|
215
332
|
/** L-class paths are readable by agents but may only be mutated by trusted daemon paths. */
|
|
216
333
|
export function isLClassPath(value, options = {}) {
|
|
334
|
+
if (hasInvalidExplicitSelfAid(options))
|
|
335
|
+
return false;
|
|
217
336
|
const root = resolveThroughExistingAncestor(options.root ?? resolveRoot());
|
|
218
337
|
const lexicalCandidate = path.isAbsolute(value)
|
|
219
338
|
? path.resolve(value)
|
|
220
339
|
: path.resolve(options.cwd ?? process.cwd(), value);
|
|
221
340
|
if (isSameOrDescendant(lexicalCandidate, root)) {
|
|
222
341
|
const lexicalRelative = path.relative(root, lexicalCandidate).split(path.sep).join('/');
|
|
223
|
-
if (
|
|
342
|
+
if (!matchesAgentScopeRelative(lexicalRelative, options.selfAid)
|
|
343
|
+
&& L_CLASS_RELATIVE_PATTERNS.some(pattern => pattern.test(lexicalRelative)))
|
|
224
344
|
return true;
|
|
225
345
|
}
|
|
226
346
|
const candidate = resolveProtectedCandidate(value, options.cwd);
|
|
227
347
|
if (!isSameOrDescendant(candidate, root))
|
|
228
348
|
return false;
|
|
229
349
|
const relative = path.relative(root, candidate).split(path.sep).join('/');
|
|
230
|
-
return
|
|
350
|
+
return !matchesAgentScopeRelative(relative, options.selfAid)
|
|
351
|
+
&& L_CLASS_RELATIVE_PATTERNS.some(pattern => pattern.test(relative));
|
|
231
352
|
}
|
|
232
353
|
export function containsLClassReference(value) {
|
|
233
354
|
const normalized = value.replace(/\\/g, '/');
|
|
@@ -236,8 +357,7 @@ export function containsLClassReference(value) {
|
|
|
236
357
|
return true;
|
|
237
358
|
return L_CLASS_REFERENCE_PATTERNS.some(pattern => pattern.test(normalized));
|
|
238
359
|
}
|
|
239
|
-
|
|
240
|
-
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
360
|
+
function getLegacyHClassSandboxPatterns(root) {
|
|
241
361
|
const entries = [
|
|
242
362
|
'daemon.json',
|
|
243
363
|
path.join('agents', 'defaults.json'),
|
|
@@ -245,59 +365,60 @@ export function getHClassSandboxPatterns(root = resolveRoot()) {
|
|
|
245
365
|
path.join('agents', '*', 'contact.json'),
|
|
246
366
|
path.join('agents', '*', 'contact-operations.jsonl'),
|
|
247
367
|
path.join('agents', '*', 'relations', '*', 'config.json'),
|
|
248
|
-
path.join('backups', 'config'),
|
|
249
|
-
path.join('
|
|
250
|
-
'.
|
|
251
|
-
path.join('.
|
|
368
|
+
path.join('backups', 'config'), path.join('backups', 'config', '**'),
|
|
369
|
+
'.snapshots', path.join('.snapshots', '**'),
|
|
370
|
+
'CA', path.join('CA', '**'),
|
|
371
|
+
path.join('AIDs', '*', 'cert'), path.join('AIDs', '*', 'cert', '**'),
|
|
372
|
+
path.join('AIDs', '*', 'keys'), path.join('AIDs', '*', 'keys', '**'),
|
|
373
|
+
path.join('AIDs', '*', 'private'), path.join('AIDs', '*', 'private', '**'),
|
|
374
|
+
path.join('aids', '*', 'cert'), path.join('aids', '*', 'cert', '**'),
|
|
375
|
+
path.join('aids', '*', 'keys'), path.join('aids', '*', 'keys', '**'),
|
|
376
|
+
path.join('aids', '*', 'private'), path.join('aids', '*', 'private', '**'),
|
|
377
|
+
'.device_id', '.env', '.seed', '.seed.*', '.migrated-*',
|
|
378
|
+
path.join('**', '*.json_'), path.join('**', '*.json.migrated'),
|
|
379
|
+
path.join('agents', 'defaults_*.json'), '.lock', 'daemon.pid',
|
|
380
|
+
path.join('data', 'causation-aun.json*'), path.join('data', 'contact-book-audit.jsonl'),
|
|
381
|
+
path.join('data', 'feishu-seen-*.jsonl'), path.join('data', '*-greeted-*.jsonl'),
|
|
382
|
+
path.join('data', 'message-queue.json*'), path.join('data', 'daemon', 'message-queue.json*'),
|
|
383
|
+
path.join('data', 'daemon', 'control') + '/**', path.join('data', 'daemon', 'migrations') + '/**',
|
|
384
|
+
path.join('data', 'channel-state') + '/**', path.join('data', 'instance', 'control.token'),
|
|
385
|
+
path.join('data', 'outbox'), path.join('data', 'outbox') + '/**',
|
|
386
|
+
path.join('data', 'handoff'), path.join('data', 'handoff') + '/**',
|
|
387
|
+
path.join('agents', '*', 'sessions', '**'), path.join('agents', '*', 'data', 'channels', '**'),
|
|
388
|
+
path.join('agents', '*', 'data', 'handoff', '**'), path.join('agents', '*', 'data', 'async-questions', '**'),
|
|
389
|
+
path.join('agents', '*', 'data', 'task-activity', '**'), path.join('agents', '*', 'data', 'aun', '**'),
|
|
390
|
+
path.join('agents', '*', 'data', 'outbox.jsonl*'), path.join('agents', '*', 'data', 'activity-outbox.jsonl*'),
|
|
391
|
+
path.join('agents', '*', 'data', 'contact-audit.jsonl'),
|
|
392
|
+
];
|
|
393
|
+
return entries.map(entry => path.join(root, entry));
|
|
394
|
+
}
|
|
395
|
+
export function getHClassSandboxPatterns(root = resolveRoot(), options = {}) {
|
|
396
|
+
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
397
|
+
assertValidSelfAid(options, 'getHClassSandboxPatterns');
|
|
398
|
+
if (!normalizeAid(options.selfAid))
|
|
399
|
+
return getLegacyHClassSandboxPatterns(absoluteRoot);
|
|
400
|
+
const entries = [
|
|
401
|
+
'data', path.join('data', '**'),
|
|
402
|
+
'AIDs', path.join('AIDs', '**'),
|
|
403
|
+
'aids', path.join('aids', '**'),
|
|
252
404
|
'CA',
|
|
253
405
|
path.join('CA', '**'),
|
|
254
|
-
|
|
255
|
-
path.join('
|
|
256
|
-
path.join('
|
|
257
|
-
path.join('
|
|
258
|
-
path.join('
|
|
259
|
-
path.join('AIDs', '*', 'private', '**'),
|
|
260
|
-
path.join('aids', '*', 'cert'),
|
|
261
|
-
path.join('aids', '*', 'cert', '**'),
|
|
262
|
-
path.join('aids', '*', 'keys'),
|
|
263
|
-
path.join('aids', '*', 'keys', '**'),
|
|
264
|
-
path.join('aids', '*', 'private'),
|
|
265
|
-
path.join('aids', '*', 'private', '**'),
|
|
266
|
-
'.device_id',
|
|
267
|
-
'.env',
|
|
268
|
-
'.seed',
|
|
269
|
-
'.seed.*',
|
|
270
|
-
'.migrated-*',
|
|
271
|
-
path.join('**', '*.json_'),
|
|
272
|
-
path.join('**', '*.json.migrated'),
|
|
273
|
-
path.join('agents', 'defaults_*.json'),
|
|
274
|
-
'.lock',
|
|
275
|
-
'daemon.pid',
|
|
276
|
-
path.join('data', 'causation-aun.json*'),
|
|
277
|
-
path.join('data', 'triggers') + '/**',
|
|
278
|
-
path.join('data', 'sessions') + '/**',
|
|
279
|
-
path.join('data', 'contact-book-audit.jsonl'),
|
|
280
|
-
path.join('data', 'feishu-seen-*.jsonl'),
|
|
281
|
-
path.join('data', '*-greeted-*.jsonl'),
|
|
282
|
-
path.join('data', 'message-queue.json*'),
|
|
283
|
-
path.join('data', 'daemon', 'message-queue.json*'),
|
|
284
|
-
path.join('data', 'daemon', 'control') + '/**',
|
|
285
|
-
path.join('data', 'daemon', 'migrations') + '/**',
|
|
286
|
-
path.join('data', 'channel-state') + '/**',
|
|
287
|
-
path.join('data', 'instance', 'control.token'),
|
|
288
|
-
path.join('data', 'outbox'),
|
|
289
|
-
path.join('data', 'outbox') + '/**',
|
|
290
|
-
path.join('data', 'handoff'),
|
|
291
|
-
path.join('data', 'handoff') + '/**',
|
|
292
|
-
path.join('agents', '*', 'sessions', '**'),
|
|
293
|
-
path.join('agents', '*', 'data', 'channels', '**'),
|
|
294
|
-
path.join('agents', '*', 'data', 'handoff', '**'),
|
|
295
|
-
path.join('agents', '*', 'data', 'async-questions', '**'),
|
|
296
|
-
path.join('agents', '*', 'data', 'aun', '**'),
|
|
297
|
-
path.join('agents', '*', 'data', 'outbox.jsonl*'),
|
|
298
|
-
path.join('agents', '*', 'data', 'activity-outbox.jsonl*'),
|
|
299
|
-
path.join('agents', '*', 'data', 'contact-audit.jsonl'),
|
|
406
|
+
'.device_id', '.env', '.seed', '.seed.*', '.lock', 'daemon.pid',
|
|
407
|
+
path.join('agents', options.selfAid, 'data', 'codex-tokens'),
|
|
408
|
+
path.join('agents', options.selfAid, 'data', 'codex-tokens', '**'),
|
|
409
|
+
path.join('agents', options.selfAid, 'data', '**', 'context-tokens.json'),
|
|
410
|
+
path.join('agents', options.selfAid, 'data', '**', 'menu-tokens.json'),
|
|
300
411
|
];
|
|
412
|
+
// Exact roots are substantially smaller than `agents/*/**` on Windows and
|
|
413
|
+
// avoid relying on ACL override precedence to re-open self Agent content.
|
|
414
|
+
try {
|
|
415
|
+
for (const entry of fs.readdirSync(path.join(absoluteRoot, 'agents'), { withFileTypes: true })) {
|
|
416
|
+
if (entry.isDirectory() && entry.name.toLowerCase() !== options.selfAid.toLowerCase()) {
|
|
417
|
+
entries.push(path.join('agents', entry.name), path.join('agents', entry.name, '**'));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
catch { }
|
|
301
422
|
return entries.map(entry => path.join(absoluteRoot, entry));
|
|
302
423
|
}
|
|
303
424
|
export function getLClassWritePatterns(root = resolveRoot()) {
|
|
@@ -315,7 +436,7 @@ const CODEX_GLOB_MAGIC = /[*?[\]]/;
|
|
|
315
436
|
// passing it as one CreateProcess argument. Real Codex 0.154 payloads are
|
|
316
437
|
// roughly 3-5x larger than EvolCore's input map, so leave enough room below
|
|
317
438
|
// Windows' 32,767-character command-line ceiling for helper metadata.
|
|
318
|
-
const CODEX_WINDOWS_FILESYSTEM_RULE_BUDGET_BYTES =
|
|
439
|
+
const CODEX_WINDOWS_FILESYSTEM_RULE_BUDGET_BYTES = 10 * 1024;
|
|
319
440
|
const CODEX_WINDOWS_MATERIALIZED_FILE_GLOBS = [
|
|
320
441
|
'**/*.json_',
|
|
321
442
|
'**/*.json.migrated',
|
|
@@ -330,13 +451,61 @@ function addExistingTarget(targets, value) {
|
|
|
330
451
|
}
|
|
331
452
|
catch { }
|
|
332
453
|
}
|
|
333
|
-
|
|
454
|
+
function getAgentAwareHClassMaskTargets(root, selfAid) {
|
|
455
|
+
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
456
|
+
const targets = new Map();
|
|
457
|
+
for (const relative of [
|
|
458
|
+
'data', 'AIDs', 'aids', 'CA',
|
|
459
|
+
'.device_id', '.env', '.seed', '.lock', 'daemon.pid',
|
|
460
|
+
])
|
|
461
|
+
addExistingTarget(targets, path.join(absoluteRoot, relative));
|
|
462
|
+
const agentsDir = path.join(absoluteRoot, 'agents');
|
|
463
|
+
try {
|
|
464
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
465
|
+
if (!entry.isDirectory())
|
|
466
|
+
continue;
|
|
467
|
+
const agentRoot = path.join(agentsDir, entry.name);
|
|
468
|
+
if (entry.name.toLowerCase() !== selfAid.toLowerCase()) {
|
|
469
|
+
addExistingTarget(targets, agentRoot);
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
addExistingTarget(targets, path.join(agentRoot, 'data', 'codex-tokens'));
|
|
473
|
+
const walk = (directory, depth = 0) => {
|
|
474
|
+
if (depth > 8)
|
|
475
|
+
return;
|
|
476
|
+
let children;
|
|
477
|
+
try {
|
|
478
|
+
children = fs.readdirSync(directory, { withFileTypes: true });
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
for (const child of children) {
|
|
484
|
+
const childPath = path.join(directory, child.name);
|
|
485
|
+
if (child.isDirectory())
|
|
486
|
+
walk(childPath, depth + 1);
|
|
487
|
+
else if (/^(?:context-tokens|menu-tokens)\.json(?:_|__|\.tmp-.*)?$/i.test(child.name)) {
|
|
488
|
+
addExistingTarget(targets, childPath);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
walk(path.join(agentRoot, 'data'));
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch { }
|
|
496
|
+
return [...targets.values()];
|
|
497
|
+
}
|
|
498
|
+
export function getExistingHClassMaskTargets(root = resolveRoot(), options = {}) {
|
|
499
|
+
assertValidSelfAid(options, 'getExistingHClassMaskTargets');
|
|
500
|
+
const selfAid = normalizeAid(options.selfAid);
|
|
501
|
+
if (selfAid)
|
|
502
|
+
return getAgentAwareHClassMaskTargets(root, selfAid);
|
|
334
503
|
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
335
504
|
const targets = new Map();
|
|
336
505
|
for (const relative of [
|
|
337
506
|
'daemon.json', 'backups/config', '.snapshots', 'CA',
|
|
338
507
|
'.device_id', '.env', '.seed', '.lock', 'daemon.pid',
|
|
339
|
-
'data/causation-aun.json', 'data/
|
|
508
|
+
'data/causation-aun.json', 'data/contact-book-audit.jsonl',
|
|
340
509
|
'data/message-queue.json', 'data/message-queue.json_', 'data/message-queue.json__',
|
|
341
510
|
'data/daemon/message-queue.json', 'data/daemon/control', 'data/daemon/migrations', 'data/channel-state',
|
|
342
511
|
'data/instance/control.token',
|
|
@@ -388,6 +557,7 @@ export function getExistingHClassMaskTargets(root = resolveRoot()) {
|
|
|
388
557
|
addExistingTarget(targets, path.join(agentRoot, 'data', 'channels'));
|
|
389
558
|
addExistingTarget(targets, path.join(agentRoot, 'data', 'handoff'));
|
|
390
559
|
addExistingTarget(targets, path.join(agentRoot, 'data', 'async-questions'));
|
|
560
|
+
addExistingTarget(targets, path.join(agentRoot, 'data', 'task-activity'));
|
|
391
561
|
addExistingTarget(targets, path.join(agentRoot, 'data', 'aun'));
|
|
392
562
|
addExistingTarget(targets, path.join(agentRoot, 'data', 'outbox.jsonl'));
|
|
393
563
|
addExistingTarget(targets, path.join(agentRoot, 'data', 'activity-outbox.jsonl'));
|
|
@@ -410,10 +580,32 @@ export function getExistingHClassMaskTargets(root = resolveRoot()) {
|
|
|
410
580
|
}
|
|
411
581
|
return [...targets.values()];
|
|
412
582
|
}
|
|
413
|
-
export function getExistingLClassReadOnlyTargets(root = resolveRoot()) {
|
|
583
|
+
export function getExistingLClassReadOnlyTargets(root = resolveRoot(), options = {}) {
|
|
584
|
+
assertValidSelfAid(options, 'getExistingLClassReadOnlyTargets');
|
|
414
585
|
const targets = new Map();
|
|
415
586
|
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
416
587
|
const agentsDir = path.join(absoluteRoot, 'agents');
|
|
588
|
+
const selfAid = normalizeAid(options.selfAid);
|
|
589
|
+
if (selfAid) {
|
|
590
|
+
for (const relative of ['daemon.json', 'agents/defaults.json', 'backups/config']) {
|
|
591
|
+
addExistingTarget(targets, path.join(absoluteRoot, relative));
|
|
592
|
+
}
|
|
593
|
+
const ownRoot = path.join(agentsDir, selfAid);
|
|
594
|
+
for (const relative of [
|
|
595
|
+
'config.json', 'contact.json', 'contact-operations.jsonl', 'roles', 'triggers',
|
|
596
|
+
])
|
|
597
|
+
addExistingTarget(targets, path.join(ownRoot, relative));
|
|
598
|
+
try {
|
|
599
|
+
const relationsDir = path.join(ownRoot, 'relations');
|
|
600
|
+
for (const relation of fs.readdirSync(relationsDir, { withFileTypes: true })) {
|
|
601
|
+
if (!relation.isDirectory())
|
|
602
|
+
continue;
|
|
603
|
+
addExistingTarget(targets, path.join(relationsDir, relation.name, 'config.json'));
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
catch { }
|
|
607
|
+
return [...targets.values()];
|
|
608
|
+
}
|
|
417
609
|
try {
|
|
418
610
|
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
419
611
|
if (!entry.isDirectory())
|
|
@@ -425,11 +617,49 @@ export function getExistingLClassReadOnlyTargets(root = resolveRoot()) {
|
|
|
425
617
|
catch { }
|
|
426
618
|
return [...targets.values()];
|
|
427
619
|
}
|
|
620
|
+
export function getExistingRelationAttachmentDirs(root = resolveRoot(), options = {}) {
|
|
621
|
+
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
622
|
+
const agentsDir = path.join(absoluteRoot, 'agents');
|
|
623
|
+
const targets = new Set();
|
|
624
|
+
try {
|
|
625
|
+
for (const agent of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
626
|
+
if (!agent.isDirectory())
|
|
627
|
+
continue;
|
|
628
|
+
if (options.selfAid) {
|
|
629
|
+
const isSelf = agent.name.toLowerCase() === options.selfAid.toLowerCase();
|
|
630
|
+
if (options.onlyOtherAgents ? isSelf : !isSelf)
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
const relationsDir = path.join(agentsDir, agent.name, 'relations');
|
|
634
|
+
for (const relation of fs.readdirSync(relationsDir, { withFileTypes: true })) {
|
|
635
|
+
if (!relation.isDirectory())
|
|
636
|
+
continue;
|
|
637
|
+
const attachments = path.join(relationsDir, relation.name, 'attachments');
|
|
638
|
+
try {
|
|
639
|
+
if (fs.lstatSync(attachments).isDirectory())
|
|
640
|
+
targets.add(attachments);
|
|
641
|
+
}
|
|
642
|
+
catch { }
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
catch { }
|
|
647
|
+
return [...targets];
|
|
648
|
+
}
|
|
428
649
|
export function buildClaudeProtectedFilesystem(root = resolveRoot(), options = {}) {
|
|
429
|
-
const hClassPaths =
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const
|
|
650
|
+
const hClassPaths = [
|
|
651
|
+
...getExistingHClassMaskTargets(root, options).map(target => target.path),
|
|
652
|
+
];
|
|
653
|
+
const relationAttachmentPaths = getExistingRelationAttachmentDirs(root, options);
|
|
654
|
+
const lClassPaths = getExistingLClassReadOnlyTargets(root, options).map(target => target.path);
|
|
655
|
+
const allPaths = [...new Set([...hClassPaths, ...lClassPaths, ...relationAttachmentPaths])];
|
|
656
|
+
// Self-Agent relation attachments are ordinary readable content. They stay
|
|
657
|
+
// in denyWrite so the nested Claude sandbox cannot mutate an uploaded asset;
|
|
658
|
+
// callers without identity context retain the legacy deny-read behavior.
|
|
659
|
+
const legacyAttachmentRead = options.selfAid ? [] : relationAttachmentPaths;
|
|
660
|
+
const denyRead = options.denyLClassRead
|
|
661
|
+
? [...new Set([...hClassPaths, ...lClassPaths, ...legacyAttachmentRead])]
|
|
662
|
+
: [...new Set([...hClassPaths, ...legacyAttachmentRead])];
|
|
433
663
|
if (allPaths.length > CLAUDE_PROTECTED_TARGET_LIMIT) {
|
|
434
664
|
throw new Error(`[ClaudeSandbox] protected target limit exceeded: ${allPaths.length} > ${CLAUDE_PROTECTED_TARGET_LIMIT}`);
|
|
435
665
|
}
|
|
@@ -446,14 +676,16 @@ export function buildClaudeProtectedFilesystem(root = resolveRoot(), options = {
|
|
|
446
676
|
denyWrite: allPaths,
|
|
447
677
|
};
|
|
448
678
|
}
|
|
449
|
-
export function buildCodexHClassFilesystemRules(root = resolveRoot(),
|
|
679
|
+
export function buildCodexHClassFilesystemRules(root = resolveRoot(), platformOrOptions = process.platform) {
|
|
680
|
+
const options = typeof platformOrOptions === 'string' ? {} : platformOrOptions;
|
|
681
|
+
const platform = typeof platformOrOptions === 'string' ? platformOrOptions : (platformOrOptions.platform ?? process.platform);
|
|
450
682
|
const filesystem = {
|
|
451
683
|
// Codex pre-expands unbounded deny globs on Linux/WSL/Windows. Without a
|
|
452
684
|
// bound, patterns such as **/*.json_ are accepted but may not be enforced.
|
|
453
685
|
glob_scan_max_depth: 64,
|
|
454
|
-
...Object.fromEntries(filterWindowsCodexFilesystemTargets(getHClassSandboxPatterns(root), platform).map(pattern => [pattern, 'deny'])),
|
|
686
|
+
...Object.fromEntries(filterWindowsCodexFilesystemTargets(getHClassSandboxPatterns(root, options), platform).map(pattern => [pattern, 'deny'])),
|
|
455
687
|
};
|
|
456
|
-
return materializeWindowsCodexRecursiveFileDenies(compactWindowsCodexFilesystemRules(filesystem, platform), root, platform);
|
|
688
|
+
return materializeWindowsCodexRecursiveFileDenies(compactWindowsCodexFilesystemRules(filesystem, platform), root, platform, options);
|
|
457
689
|
}
|
|
458
690
|
/**
|
|
459
691
|
* Windows Codex sandbox setup materializes a path while applying its deny-read
|
|
@@ -565,12 +797,12 @@ export function compactWindowsCodexFilesystemRules(filesystem, platform = proces
|
|
|
565
797
|
* remain dynamic globs, preserving protection for newly created agent/config
|
|
566
798
|
* paths without recreating the unbounded recursive expansion.
|
|
567
799
|
*/
|
|
568
|
-
export function materializeWindowsCodexRecursiveFileDenies(filesystem, root = resolveRoot(), platform = process.platform) {
|
|
800
|
+
export function materializeWindowsCodexRecursiveFileDenies(filesystem, root = resolveRoot(), platform = process.platform, options = {}) {
|
|
569
801
|
if (platform !== 'win32')
|
|
570
802
|
return filesystem;
|
|
571
803
|
const absoluteRoot = resolveThroughExistingAncestor(root);
|
|
572
804
|
const materializedPatterns = new Set(CODEX_WINDOWS_MATERIALIZED_FILE_GLOBS.map(pattern => path.join(absoluteRoot, pattern)));
|
|
573
|
-
const deniedDirectories = getExistingHClassMaskTargets(absoluteRoot)
|
|
805
|
+
const deniedDirectories = getExistingHClassMaskTargets(absoluteRoot, options)
|
|
574
806
|
.filter(target => target.kind === 'directory')
|
|
575
807
|
.map(target => target.path);
|
|
576
808
|
const projected = {};
|
|
@@ -616,7 +848,7 @@ export function buildCodexProtectedFilesystemRules(root = resolveRoot(), options
|
|
|
616
848
|
// nested bwrap per-file projection. Callers on platforms without that
|
|
617
849
|
// outer guard retain the historical expansion by default.
|
|
618
850
|
const expandLClassReadDeny = options.expandLClassReadDeny ?? true;
|
|
619
|
-
for (const target of getExistingLClassReadOnlyTargets(root)) {
|
|
851
|
+
for (const target of getExistingLClassReadOnlyTargets(root, options)) {
|
|
620
852
|
if (target.kind === 'directory') {
|
|
621
853
|
// :workspace/:read-only already grants L-class read access on Windows.
|
|
622
854
|
// Omitting redundant read ACLs keeps Codex's serialized helper payload
|
|
@@ -634,8 +866,11 @@ export function buildCodexProtectedFilesystemRules(root = resolveRoot(), options
|
|
|
634
866
|
lClassRules[target.path] = lClassAccess;
|
|
635
867
|
}
|
|
636
868
|
}
|
|
869
|
+
const hClassOptions = { platform };
|
|
870
|
+
if (Object.prototype.hasOwnProperty.call(options, 'selfAid'))
|
|
871
|
+
hClassOptions.selfAid = options.selfAid;
|
|
637
872
|
const filesystem = compactWindowsCodexFilesystemRules({
|
|
638
|
-
...buildCodexHClassFilesystemRules(root,
|
|
873
|
+
...buildCodexHClassFilesystemRules(root, hClassOptions),
|
|
639
874
|
...lClassRules,
|
|
640
875
|
}, platform);
|
|
641
876
|
assertWindowsCodexFilesystemRuleBudget(filesystem, platform);
|
|
@@ -643,7 +878,7 @@ export function buildCodexProtectedFilesystemRules(root = resolveRoot(), options
|
|
|
643
878
|
}
|
|
644
879
|
export function hClassGrantIncludesProtectedPath(value, options = {}) {
|
|
645
880
|
const root = resolveThroughExistingAncestor(options.root ?? resolveRoot());
|
|
646
|
-
if (containsHClassReference(value))
|
|
881
|
+
if (containsHClassReference(value, options) || containsAgentScopeReference(value, options))
|
|
647
882
|
return true;
|
|
648
883
|
const normalized = value.replace(/\\/g, '/');
|
|
649
884
|
const globIndex = normalized.search(/[*?[{]/);
|
|
@@ -651,12 +886,29 @@ export function hClassGrantIncludesProtectedPath(value, options = {}) {
|
|
|
651
886
|
? value
|
|
652
887
|
: normalized.slice(0, globIndex).replace(/\/+$/, '') || '.';
|
|
653
888
|
const candidate = resolveProtectedCandidate(literalGrantRoot, options.cwd);
|
|
654
|
-
if (isHClassPath(candidate, { root }))
|
|
889
|
+
if (isHClassPath(candidate, { root, selfAid: options.selfAid }))
|
|
655
890
|
return true;
|
|
656
891
|
if (isSameOrDescendant(root, candidate))
|
|
657
892
|
return true;
|
|
658
893
|
if (!isSameOrDescendant(candidate, root))
|
|
659
894
|
return false;
|
|
895
|
+
if (options.selfAid) {
|
|
896
|
+
const relative = path.relative(root, candidate).split(path.sep).filter(Boolean);
|
|
897
|
+
if (relative[0] === 'data' || relative[0] === 'AIDs' || relative[0] === 'aids')
|
|
898
|
+
return true;
|
|
899
|
+
if (relative[0] === 'agents' && relative[1]) {
|
|
900
|
+
if (relative[1].toLowerCase() !== options.selfAid.toLowerCase())
|
|
901
|
+
return true;
|
|
902
|
+
if (relative.length <= 2)
|
|
903
|
+
return true;
|
|
904
|
+
if (relative[2] === 'data' && (!relative[3] || ['codex-tokens', 'channels'].includes(relative[3])))
|
|
905
|
+
return true;
|
|
906
|
+
}
|
|
907
|
+
// A grant scoped to an ordinary self-Agent subtree does not automatically
|
|
908
|
+
// cover an H-class path; this is the distinction that lets sessions,
|
|
909
|
+
// handoff and outbox remain usable while token/data roots stay protected.
|
|
910
|
+
return false;
|
|
911
|
+
}
|
|
660
912
|
// A filesystem grant is a range, not a one-file allow. Every directory
|
|
661
913
|
// below the protected root can contain an H-class backup name (for example
|
|
662
914
|
// *.json_), so an overlay grant there could bypass the baseline deny rules.
|
|
@@ -666,7 +918,7 @@ export function lClassGrantIncludesProtectedPath(value, options = {}) {
|
|
|
666
918
|
if (!value.trim())
|
|
667
919
|
return false;
|
|
668
920
|
const root = resolveThroughExistingAncestor(options.root ?? resolveRoot());
|
|
669
|
-
if (isLClassPath(value, { cwd: options.cwd, root }))
|
|
921
|
+
if (isLClassPath(value, { cwd: options.cwd, root, selfAid: options.selfAid }))
|
|
670
922
|
return true;
|
|
671
923
|
const normalized = value.replace(/\\/g, '/');
|
|
672
924
|
const globIndex = normalized.search(/[*?[{]/);
|
|
@@ -674,31 +926,29 @@ export function lClassGrantIncludesProtectedPath(value, options = {}) {
|
|
|
674
926
|
? value
|
|
675
927
|
: normalized.slice(0, globIndex).replace(/\/+$/, '') || '.';
|
|
676
928
|
const candidate = resolveProtectedCandidate(literalGrantRoot, options.cwd);
|
|
677
|
-
if (isSameOrDescendant(root, candidate))
|
|
929
|
+
if (isSameOrDescendant(root, candidate) && candidate === root)
|
|
678
930
|
return true;
|
|
679
931
|
if (!isSameOrDescendant(candidate, root))
|
|
680
932
|
return false;
|
|
681
|
-
const relative = path.relative(root, candidate);
|
|
682
|
-
const segments = relative
|
|
683
|
-
if (segments[0] === '
|
|
684
|
-
|
|
685
|
-
return true;
|
|
686
|
-
return segments[1] === 'triggers';
|
|
687
|
-
}
|
|
933
|
+
const relative = path.relative(root, candidate).split(path.sep).filter(Boolean);
|
|
934
|
+
const segments = relative;
|
|
935
|
+
if (segments[0] === 'backups' && segments[1] === 'config')
|
|
936
|
+
return true;
|
|
688
937
|
if (segments[0] === 'agents') {
|
|
689
|
-
//
|
|
938
|
+
// A grant covering an Agent root also covers its L-class configuration.
|
|
690
939
|
if (segments.length <= 2)
|
|
691
940
|
return true;
|
|
692
|
-
return
|
|
941
|
+
return ['config.json', 'contact.json', 'contact-operations.jsonl', 'relations', 'roles', 'triggers']
|
|
942
|
+
.includes(segments[2]);
|
|
693
943
|
}
|
|
694
944
|
return false;
|
|
695
945
|
}
|
|
696
|
-
export function workspaceContainsHClassPaths(projectPath, root = resolveRoot()) {
|
|
946
|
+
export function workspaceContainsHClassPaths(projectPath, root = resolveRoot(), options = {}) {
|
|
697
947
|
const project = resolveThroughExistingAncestor(projectPath);
|
|
698
948
|
const protectedRoot = resolveThroughExistingAncestor(root);
|
|
699
949
|
if (isSameOrDescendant(protectedRoot, project))
|
|
700
950
|
return true;
|
|
701
951
|
if (!isSameOrDescendant(project, protectedRoot))
|
|
702
952
|
return false;
|
|
703
|
-
return hClassGrantIncludesProtectedPath(project, { root: protectedRoot });
|
|
953
|
+
return hClassGrantIncludesProtectedPath(project, { root: protectedRoot, selfAid: options.selfAid });
|
|
704
954
|
}
|