evolcore 0.0.24 → 0.0.25
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 +578 -561
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +160 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +29 -29
- package/bin/install-codex-managed-hooks.mjs +555 -555
- package/dist/agents/claude-runner.js +4 -1
- package/dist/agents/codex-runner.js +7 -4
- package/dist/agents/ecagent-runner.js +14 -13
- package/dist/agents/gemini-runner.js +22 -2
- package/dist/aun/aid/agentmd.js +56 -4
- package/dist/aun/aid/index.js +1 -0
- package/dist/aun/aid/managed-operation.js +53 -1
- package/dist/aun/storage/client.js +4 -1
- package/dist/aun/storage/index.js +1 -1
- package/dist/cli/agent-command.js +186 -87
- package/dist/cli/agent-create.js +42 -4
- package/dist/cli/agent.js +103 -1
- package/dist/cli/aun-commands.js +360 -294
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +20 -20
- package/dist/cli/contact.js +10 -10
- package/dist/cli/ctl-command.js +22 -22
- package/dist/cli/daemon-commands.js +15 -15
- package/dist/cli/fs-command.js +67 -67
- package/dist/cli/handoff-command.js +7 -7
- package/dist/cli/index.js +77 -77
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/menu-client.js +11 -11
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +29 -29
- package/dist/cli/response.js +30 -30
- package/dist/cli/restart-monitor.js +30 -30
- package/dist/cli/stats.js +51 -51
- package/dist/cli/trigger-command.js +56 -56
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-manager.js +15 -0
- package/dist/config/config-operation-service.js +20 -3
- package/dist/config/resolved-config-op.js +39 -1
- package/dist/core/auth/operation-authorizer.js +62 -4
- package/dist/core/auth/operation-catalog.js +16 -0
- package/dist/core/command/agent-control.js +54 -25
- package/dist/core/command/cli-intent-parser.js +18 -0
- package/dist/core/command/command-handler.js +91 -16
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +41 -5
- package/dist/core/command/menu-protocol.js +1 -0
- package/dist/core/command/slash-handler.js +9 -9
- package/dist/core/event-catalog.js +5 -0
- package/dist/core/evolagent.js +3 -3
- package/dist/core/message/response-engine.js +12 -6
- package/dist/core/permission/tool-policy.js +45 -6
- package/dist/index.js +209 -162
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/utils/avatar-upload.js +282 -23
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/welcome.js +22 -22
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +66 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +56 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +365 -364
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +71 -69
- package/kits/docs/evolcore/agent-create.md +170 -156
- package/kits/docs/evolcore/agent.md +83 -73
- package/kits/docs/evolcore/aid.md +64 -62
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -0
- package/kits/docs/evolcore/config.md +195 -195
- package/kits/docs/evolcore/contact.md +68 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +243 -243
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +152 -152
- package/kits/docs/evolcore/menu-client.md +34 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +165 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +50 -50
- package/kits/docs/evolcore/trigger.md +575 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +270 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +25 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +195 -183
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +162 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +39 -37
- package/kits/rules/04-relation.md +75 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +63 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +427 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +201 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +96 -84
- package/kits/templates/roles/member.json +97 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +86 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +38 -29
- package/kits/templates/system-fragments/channel.md +64 -64
- package/kits/templates/system-fragments/commands.md +28 -28
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +98 -98
- package/skills/eclink/SKILL.md +0 -84
- package/skills/eclink/agents/openai.yaml +0 -4
|
@@ -2489,7 +2489,10 @@ export class AgentRunner {
|
|
|
2489
2489
|
const bootstrapWritePaths = modelOverride?.bootstrapAgentMdPath
|
|
2490
2490
|
? [path.resolve(modelOverride.bootstrapAgentMdPath)]
|
|
2491
2491
|
: [];
|
|
2492
|
-
const
|
|
2492
|
+
const personalWritePaths = modelOverride?.personalMdPath
|
|
2493
|
+
? [path.resolve(modelOverride.personalMdPath)]
|
|
2494
|
+
: [];
|
|
2495
|
+
const allowedWritePaths = [...new Set([...runtimeWritePaths, ...bootstrapWritePaths, ...personalWritePaths])];
|
|
2493
2496
|
await assertClaudeSettingSourcesHaveLiteralSandboxPaths(projectPath, [...settingSources], managedSettings);
|
|
2494
2497
|
const sandboxProjectionDurationMs = Date.now() - sandboxProjectionStartedAt;
|
|
2495
2498
|
if (sandboxProjectionDurationMs > 2_000) {
|
|
@@ -1298,7 +1298,7 @@ export class CodexRunner {
|
|
|
1298
1298
|
}
|
|
1299
1299
|
return Object.fromEntries([...paths].map(candidate => [candidate, 'write']));
|
|
1300
1300
|
}
|
|
1301
|
-
buildPermissionProfileConfig(sessionId, mode, projectPath, bootstrapAgentMdPath) {
|
|
1301
|
+
buildPermissionProfileConfig(sessionId, mode, projectPath, bootstrapAgentMdPath, personalMdPath) {
|
|
1302
1302
|
const profileName = this.permissionProfileName(sessionId);
|
|
1303
1303
|
const managedTempDir = this.ensureSessionTempDir(sessionId);
|
|
1304
1304
|
const network = {
|
|
@@ -1324,6 +1324,9 @@ export class CodexRunner {
|
|
|
1324
1324
|
...(bootstrapAgentMdPath ? {
|
|
1325
1325
|
[path.resolve(bootstrapAgentMdPath)]: mode === 'readonly' ? 'read' : 'write',
|
|
1326
1326
|
} : {}),
|
|
1327
|
+
...(personalMdPath ? {
|
|
1328
|
+
[path.resolve(personalMdPath)]: mode === 'readonly' ? 'read' : 'write',
|
|
1329
|
+
} : {}),
|
|
1327
1330
|
...(mode !== 'readonly' && managedTempDir ? {
|
|
1328
1331
|
[managedTempDir]: 'write',
|
|
1329
1332
|
[managedTempDir + '/**']: 'write',
|
|
@@ -1336,12 +1339,12 @@ export class CodexRunner {
|
|
|
1336
1339
|
},
|
|
1337
1340
|
};
|
|
1338
1341
|
}
|
|
1339
|
-
buildExecutionSandboxOptions(sessionId, mode, projectPath, bootstrapAgentMdPath) {
|
|
1342
|
+
buildExecutionSandboxOptions(sessionId, mode, projectPath, bootstrapAgentMdPath, personalMdPath) {
|
|
1340
1343
|
const decision = resolvePhaseOneExecutionSandbox(mode, this.permissionContexts.get(sessionId)?.role);
|
|
1341
1344
|
return {
|
|
1342
1345
|
decision,
|
|
1343
1346
|
permissionProfileConfig: decision.state === 'active'
|
|
1344
|
-
? this.buildPermissionProfileConfig(sessionId, decision.permissionMode, projectPath, bootstrapAgentMdPath)
|
|
1347
|
+
? this.buildPermissionProfileConfig(sessionId, decision.permissionMode, projectPath, bootstrapAgentMdPath, personalMdPath)
|
|
1345
1348
|
: undefined,
|
|
1346
1349
|
sandbox: decision.state === 'off' ? 'danger-full-access' : undefined,
|
|
1347
1350
|
};
|
|
@@ -1758,7 +1761,7 @@ export class CodexRunner {
|
|
|
1758
1761
|
}
|
|
1759
1762
|
this.chatModes.set(sessionId, callMode);
|
|
1760
1763
|
const callApprovalPolicy = this.toApprovalPolicy(callMode);
|
|
1761
|
-
const executionSandbox = this.buildExecutionSandboxOptions(sessionId, callMode, projectPath, modelOverride?.bootstrapAgentMdPath);
|
|
1764
|
+
const executionSandbox = this.buildExecutionSandboxOptions(sessionId, callMode, projectPath, modelOverride?.bootstrapAgentMdPath, modelOverride?.personalMdPath);
|
|
1762
1765
|
const appServer = this.getAppServerClient(callMode === 'fullaccess');
|
|
1763
1766
|
this.dropExpiredPendingInterrupt(sessionId);
|
|
1764
1767
|
const effectiveApprovalPolicy = callApprovalPolicy;
|
|
@@ -18,8 +18,8 @@ import { appendRequestPath } from './request-identity.js';
|
|
|
18
18
|
import { getManagedTaskTempDir } from '../cli/task-context.js';
|
|
19
19
|
import { hasTrustedFullAccessContext } from './runner-types.js';
|
|
20
20
|
const PROVIDER_ID = 'evolcore-gateway';
|
|
21
|
-
const DEFAULT_SYSTEM_PROMPT = `You are ecagent, the coding agent built into EvolCore.
|
|
22
|
-
Work directly in the current project. Inspect relevant files before changing them, keep edits scoped, and verify the result.
|
|
21
|
+
const DEFAULT_SYSTEM_PROMPT = `You are ecagent, the coding agent built into EvolCore.
|
|
22
|
+
Work directly in the current project. Inspect relevant files before changing them, keep edits scoped, and verify the result.
|
|
23
23
|
Use the provided tools for filesystem and shell work. Never claim a tool action succeeded unless its result confirms success.`;
|
|
24
24
|
const MAX_READ_BYTES = 1024 * 1024;
|
|
25
25
|
const MAX_TOOL_OUTPUT = 200_000;
|
|
@@ -468,26 +468,27 @@ function isWithin(root, candidate) {
|
|
|
468
468
|
const relative = path.relative(root, candidate);
|
|
469
469
|
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
470
470
|
}
|
|
471
|
-
export function resolveEcagentToolPath(projectPath, candidate, forWrite = false, bootstrapAgentMdPath, fullaccess = false) {
|
|
471
|
+
export function resolveEcagentToolPath(projectPath, candidate, forWrite = false, bootstrapAgentMdPath, fullaccess = false, personalMdPath) {
|
|
472
472
|
const root = fs.realpathSync(projectPath);
|
|
473
473
|
const resolved = path.resolve(root, candidate || '.');
|
|
474
474
|
const allowedBootstrapFile = bootstrapAgentMdPath
|
|
475
475
|
? path.resolve(bootstrapAgentMdPath)
|
|
476
476
|
: undefined;
|
|
477
|
-
const
|
|
478
|
-
|
|
477
|
+
const allowedPersonalFile = personalMdPath ? path.resolve(personalMdPath) : undefined;
|
|
478
|
+
const isManagedIdentityFile = resolved === allowedBootstrapFile || resolved === allowedPersonalFile;
|
|
479
|
+
if (!fullaccess && !isWithin(root, resolved) && !isManagedIdentityFile) {
|
|
479
480
|
throw new Error(`Path is outside the project: ${candidate}`);
|
|
480
481
|
}
|
|
481
|
-
if (
|
|
482
|
+
if (isManagedIdentityFile) {
|
|
482
483
|
const parent = path.dirname(resolved);
|
|
483
484
|
const canonicalParent = fs.realpathSync(parent);
|
|
484
485
|
if (!isWithin(parent, canonicalParent) || !isWithin(canonicalParent, parent)) {
|
|
485
|
-
throw new Error(`
|
|
486
|
+
throw new Error(`Managed identity file parent resolves outside its declared path: ${candidate}`);
|
|
486
487
|
}
|
|
487
488
|
if (fs.existsSync(resolved)) {
|
|
488
489
|
const canonicalFile = fs.realpathSync(resolved);
|
|
489
490
|
if (!isWithin(resolved, canonicalFile) || !isWithin(canonicalFile, resolved)) {
|
|
490
|
-
throw new Error(`
|
|
491
|
+
throw new Error(`Managed identity file resolves outside its declared path: ${candidate}`);
|
|
491
492
|
}
|
|
492
493
|
}
|
|
493
494
|
return resolved;
|
|
@@ -550,7 +551,7 @@ async function walkFiles(root, signal) {
|
|
|
550
551
|
function textResult(text, details = {}) {
|
|
551
552
|
return { content: [{ type: 'text', text: truncate(text) }], details };
|
|
552
553
|
}
|
|
553
|
-
function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullaccess = false) {
|
|
554
|
+
function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullaccess = false, personalMdPath) {
|
|
554
555
|
const read = {
|
|
555
556
|
name: 'Read', label: 'Read', description: 'Read a UTF-8 text file from the project.',
|
|
556
557
|
parameters: Type.Object({
|
|
@@ -559,7 +560,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
559
560
|
limit: Type.Optional(Type.Number({ minimum: 1 })),
|
|
560
561
|
}),
|
|
561
562
|
async execute(_id, params, signal) {
|
|
562
|
-
const file = resolveEcagentToolPath(projectPath, params.file_path, false, bootstrapAgentMdPath, fullaccess);
|
|
563
|
+
const file = resolveEcagentToolPath(projectPath, params.file_path, false, bootstrapAgentMdPath, fullaccess, personalMdPath);
|
|
563
564
|
const stat = await fs.promises.stat(file);
|
|
564
565
|
if (stat.size > MAX_READ_BYTES)
|
|
565
566
|
throw new Error(`File exceeds ${MAX_READ_BYTES} byte read limit`);
|
|
@@ -625,7 +626,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
625
626
|
name: 'Write', label: 'Write', description: 'Create or completely overwrite a project file.',
|
|
626
627
|
parameters: Type.Object({ file_path: Type.String(), content: Type.String() }), executionMode: 'sequential',
|
|
627
628
|
async execute(_id, params, signal) {
|
|
628
|
-
const file = resolveEcagentToolPath(projectPath, params.file_path, true, bootstrapAgentMdPath, fullaccess);
|
|
629
|
+
const file = resolveEcagentToolPath(projectPath, params.file_path, true, bootstrapAgentMdPath, fullaccess, personalMdPath);
|
|
629
630
|
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
630
631
|
await fs.promises.writeFile(file, params.content, { encoding: 'utf8', signal });
|
|
631
632
|
return textResult(`Wrote ${Buffer.byteLength(params.content)} bytes to ${path.relative(projectPath, file)}`, { file });
|
|
@@ -638,7 +639,7 @@ function createTools(env, projectPath, runtimeEnv, bootstrapAgentMdPath, fullacc
|
|
|
638
639
|
replace_all: Type.Optional(Type.Boolean()),
|
|
639
640
|
}), executionMode: 'sequential',
|
|
640
641
|
async execute(_id, params, signal) {
|
|
641
|
-
const file = resolveEcagentToolPath(projectPath, params.file_path, false, bootstrapAgentMdPath, fullaccess);
|
|
642
|
+
const file = resolveEcagentToolPath(projectPath, params.file_path, false, bootstrapAgentMdPath, fullaccess, personalMdPath);
|
|
642
643
|
const value = await fs.promises.readFile(file, { encoding: 'utf8', signal });
|
|
643
644
|
if (!params.old_string)
|
|
644
645
|
throw new Error('old_string must not be empty');
|
|
@@ -858,7 +859,7 @@ export class EcagentRunner {
|
|
|
858
859
|
models,
|
|
859
860
|
model,
|
|
860
861
|
thinkingLevel: normalizeThinkingLevel(effort),
|
|
861
|
-
tools: createTools(nodeEnv, request.projectPath, request.runtimeEnv, request.modelOverride?.bootstrapAgentMdPath, fullaccess),
|
|
862
|
+
tools: createTools(nodeEnv, request.projectPath, request.runtimeEnv, request.modelOverride?.bootstrapAgentMdPath, fullaccess, request.modelOverride?.personalMdPath),
|
|
862
863
|
systemPrompt: [DEFAULT_SYSTEM_PROMPT, request.systemPromptAppend].filter(Boolean).join('\n\n'),
|
|
863
864
|
streamOptions: {
|
|
864
865
|
timeoutMs: this.config.timeoutMs,
|
|
@@ -147,6 +147,7 @@ const GEMINI_EC_COMMAND_PATTERNS = [
|
|
|
147
147
|
// quoted arguments.
|
|
148
148
|
String.raw `\x00"command":"[ ]*ec[ ]+(?:[^"\x00;&|$()<>\x60\r\n\\]|\\(?:\\|"))*"\x00`,
|
|
149
149
|
];
|
|
150
|
+
const GEMINI_BOOTSTRAP_PERSONA_COMMAND_PATTERN = String.raw `^\{\x00"command":"[ ]*ec[ ]+agent[ ]+persona(?:[ ]+show|[ ]+--(?:text|file)[ ]+(?:[^"\x00;&|$()<>\x60\r\n\\]|\\(?:\\|"))+)[ ]*"\x00\}$`;
|
|
150
151
|
export function resolveGeminiPermissionProfile(value, bootstrap = false) {
|
|
151
152
|
if (value === 'fullaccess')
|
|
152
153
|
return { mode: 'fullaccess', approvalMode: 'yolo' };
|
|
@@ -186,6 +187,9 @@ function geminiExactShellCommandPattern(command) {
|
|
|
186
187
|
// is_background or additional_permissions during bootstrap.
|
|
187
188
|
return `^\\{\\x00"command":"[ ]*${escapeGeminiArgsRegex(command)}[ ]*"\\x00\\}$`;
|
|
188
189
|
}
|
|
190
|
+
function geminiManagedIdentityPathPattern(filePath) {
|
|
191
|
+
return geminiJsonFieldEqualsPattern(['file_path'], path.resolve(filePath));
|
|
192
|
+
}
|
|
189
193
|
function appendGeminiPolicyRule(lines, toolName, decision, priority, argsPattern) {
|
|
190
194
|
lines.push('[[rule]]');
|
|
191
195
|
lines.push(`toolName = ${Array.isArray(toolName) ? JSON.stringify(toolName) : JSON.stringify(toolName)}`);
|
|
@@ -194,7 +198,7 @@ function appendGeminiPolicyRule(lines, toolName, decision, priority, argsPattern
|
|
|
194
198
|
lines.push(`decision = "${decision}"`);
|
|
195
199
|
lines.push(`priority = ${priority}`, '');
|
|
196
200
|
}
|
|
197
|
-
export function buildGeminiAdminPolicy(profile, bootstrapAgentMdPath) {
|
|
201
|
+
export function buildGeminiAdminPolicy(profile, bootstrapAgentMdPath, personalMdPath) {
|
|
198
202
|
const lines = [];
|
|
199
203
|
if (bootstrapAgentMdPath) {
|
|
200
204
|
const bootstrap = normalizeGeminiBootstrapAgentMdPath(bootstrapAgentMdPath);
|
|
@@ -212,6 +216,12 @@ export function buildGeminiAdminPolicy(profile, bootstrapAgentMdPath) {
|
|
|
212
216
|
appendGeminiPolicyRule(lines, GEMINI_BOOTSTRAP_FILE_TOOLS, 'allow', 990, writePathPattern);
|
|
213
217
|
appendGeminiPolicyRule(lines, 'run_shell_command', 'allow', 990, geminiExactShellCommandPattern(`ec aid agentmd put ${bootstrap.aid}`));
|
|
214
218
|
appendGeminiPolicyRule(lines, 'run_shell_command', 'allow', 990, geminiExactShellCommandPattern(`ec agent ready ${bootstrap.aid}`));
|
|
219
|
+
appendGeminiPolicyRule(lines, 'run_shell_command', 'allow', 990, GEMINI_BOOTSTRAP_PERSONA_COMMAND_PATTERN);
|
|
220
|
+
if (personalMdPath) {
|
|
221
|
+
const personalPathPattern = geminiManagedIdentityPathPattern(personalMdPath);
|
|
222
|
+
appendGeminiPolicyRule(lines, 'read_file', 'allow', 989, personalPathPattern);
|
|
223
|
+
appendGeminiPolicyRule(lines, GEMINI_BOOTSTRAP_FILE_TOOLS, 'allow', 989, personalPathPattern);
|
|
224
|
+
}
|
|
215
225
|
// These are Gemini's non-I/O task bookkeeping tools. They do not expose
|
|
216
226
|
// project files, shell, network, MCP, or user-interaction capabilities.
|
|
217
227
|
appendGeminiPolicyRule(lines, GEMINI_BOOTSTRAP_LIFECYCLE_TOOLS, 'allow', 950);
|
|
@@ -231,6 +241,11 @@ export function buildGeminiAdminPolicy(profile, bootstrapAgentMdPath) {
|
|
|
231
241
|
for (const pattern of GEMINI_L_CLASS_PATTERNS) {
|
|
232
242
|
appendGeminiPolicyRule(lines, GEMINI_L_CLASS_WRITE_TOOLS, 'deny', 997, pattern);
|
|
233
243
|
}
|
|
244
|
+
if (personalMdPath) {
|
|
245
|
+
const personalPathPattern = geminiManagedIdentityPathPattern(personalMdPath);
|
|
246
|
+
appendGeminiPolicyRule(lines, 'read_file', 'allow', 989, personalPathPattern);
|
|
247
|
+
appendGeminiPolicyRule(lines, GEMINI_BOOTSTRAP_FILE_TOOLS, 'allow', 989, personalPathPattern);
|
|
248
|
+
}
|
|
234
249
|
if (profile.mode === 'readonly') {
|
|
235
250
|
appendGeminiPolicyRule(lines, GEMINI_READONLY_TOOLS, 'allow', 950);
|
|
236
251
|
appendGeminiPolicyRule(lines, '*', 'deny', 900);
|
|
@@ -365,6 +380,9 @@ export class GeminiRunner {
|
|
|
365
380
|
const bootstrapAgentMdPath = modelOverride?.bootstrapAgentMdPath
|
|
366
381
|
? normalizeGeminiBootstrapAgentMdPath(modelOverride.bootstrapAgentMdPath).filePath
|
|
367
382
|
: undefined;
|
|
383
|
+
const personalMdPath = modelOverride?.personalMdPath
|
|
384
|
+
? path.resolve(modelOverride.personalMdPath)
|
|
385
|
+
: undefined;
|
|
368
386
|
const permissionProfile = resolveGeminiPermissionProfile(requestedPermissionMode, !!bootstrapAgentMdPath);
|
|
369
387
|
const callModel = modelOverride?.model || this.model;
|
|
370
388
|
const managedTaskTmpDir = getManagedTaskTempDir(runtimeEnv);
|
|
@@ -382,6 +400,7 @@ export class GeminiRunner {
|
|
|
382
400
|
...(runtimeDir ? [runtimeDir] : []),
|
|
383
401
|
...(runtimeLockDir ? [runtimeLockDir] : []),
|
|
384
402
|
...(bootstrapAgentMdPath ? [bootstrapAgentMdPath] : []),
|
|
403
|
+
...(personalMdPath ? [personalMdPath] : []),
|
|
385
404
|
],
|
|
386
405
|
});
|
|
387
406
|
if (executionPermissionMode !== 'fullaccess' && !sandboxProbe && workspaceContainsHClassPaths(projectPath)) {
|
|
@@ -410,7 +429,7 @@ export class GeminiRunner {
|
|
|
410
429
|
}
|
|
411
430
|
else {
|
|
412
431
|
const policyPath = path.join(managedTmpDir, `evolcore-gemini-permission-${crypto.randomUUID()}.toml`);
|
|
413
|
-
fs.writeFileSync(policyPath, buildGeminiAdminPolicy(permissionProfile, bootstrapAgentMdPath), { mode: 0o600, flag: 'wx' });
|
|
432
|
+
fs.writeFileSync(policyPath, buildGeminiAdminPolicy(permissionProfile, bootstrapAgentMdPath, personalMdPath), { mode: 0o600, flag: 'wx' });
|
|
414
433
|
tempFiles.push(policyPath);
|
|
415
434
|
args.push(...buildGeminiPermissionArgs(permissionProfile, policyPath, !!sandboxProbe));
|
|
416
435
|
}
|
|
@@ -452,6 +471,7 @@ export class GeminiRunner {
|
|
|
452
471
|
...(runtimeDir ? [runtimeDir] : []),
|
|
453
472
|
...(runtimeLockDir ? [runtimeLockDir] : []),
|
|
454
473
|
...(bootstrapAgentMdPath ? [bootstrapAgentMdPath] : []),
|
|
474
|
+
...(personalMdPath ? [personalMdPath] : []),
|
|
455
475
|
],
|
|
456
476
|
readonlyPaths: tempFiles,
|
|
457
477
|
});
|
package/dist/aun/aid/agentmd.js
CHANGED
|
@@ -4,6 +4,51 @@ import { parseDocument } from 'yaml';
|
|
|
4
4
|
import { getAidStore, loadAid, SLOT } from './store.js';
|
|
5
5
|
import { agentMdPath, aidLocalDir, resolveRoot } from '../../paths.js';
|
|
6
6
|
export const DEFAULT_AGENT_DESCRIPTION = 'EvolCore AI agent.';
|
|
7
|
+
export const AGENT_TAG_MIN_COUNT = 3;
|
|
8
|
+
export const AGENT_TAG_MAX_COUNT = 6;
|
|
9
|
+
export const AGENT_TAG_MAX_LENGTH = 50;
|
|
10
|
+
const AGENT_TAG_PATTERN = /^[\p{L}\p{N}]+$/u;
|
|
11
|
+
/** Return a human-readable validation error for one tag, or null when valid. */
|
|
12
|
+
export function validateAgentTag(tag) {
|
|
13
|
+
if (typeof tag !== 'string' || !tag.trim())
|
|
14
|
+
return 'must be a non-empty string';
|
|
15
|
+
const normalized = tag.trim();
|
|
16
|
+
if (Array.from(normalized).length > AGENT_TAG_MAX_LENGTH) {
|
|
17
|
+
return `must be at most ${AGENT_TAG_MAX_LENGTH} characters`;
|
|
18
|
+
}
|
|
19
|
+
if (!AGENT_TAG_PATTERN.test(normalized)) {
|
|
20
|
+
return 'must contain only Unicode letters and numbers';
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate an agent.md tags value. Count constraints are optional because
|
|
26
|
+
* existing published agent.md files may contain fewer than three tags.
|
|
27
|
+
*/
|
|
28
|
+
export function validateAgentTags(tags, options = {}) {
|
|
29
|
+
if (!Array.isArray(tags))
|
|
30
|
+
return ['must be an array of strings'];
|
|
31
|
+
const errors = [];
|
|
32
|
+
const normalized = new Set();
|
|
33
|
+
tags.forEach((tag, index) => {
|
|
34
|
+
const error = validateAgentTag(tag);
|
|
35
|
+
if (error) {
|
|
36
|
+
errors.push(`tag ${index + 1} ${error}`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const value = tag.trim();
|
|
40
|
+
normalized.add(value);
|
|
41
|
+
});
|
|
42
|
+
const minCount = options.minCount;
|
|
43
|
+
const maxCount = options.maxCount;
|
|
44
|
+
if (minCount !== undefined && normalized.size < minCount) {
|
|
45
|
+
errors.push(`must contain at least ${minCount} unique tags`);
|
|
46
|
+
}
|
|
47
|
+
if (maxCount !== undefined && normalized.size > maxCount) {
|
|
48
|
+
errors.push(`must contain at most ${maxCount} unique tags`);
|
|
49
|
+
}
|
|
50
|
+
return errors;
|
|
51
|
+
}
|
|
7
52
|
const displayNameCache = new Map();
|
|
8
53
|
const displayNamePending = new Map();
|
|
9
54
|
const displayNameRevision = new Map();
|
|
@@ -87,7 +132,12 @@ export function buildInitialAgentMd(opts) {
|
|
|
87
132
|
const agentName = opts.name?.trim() || opts.aid.split('.')[0];
|
|
88
133
|
const agentType = opts.type || 'ai';
|
|
89
134
|
const description = opts.description?.trim() || DEFAULT_AGENT_DESCRIPTION;
|
|
90
|
-
|
|
135
|
+
const rawTags = opts.tags?.length ? opts.tags : ['evolcore'];
|
|
136
|
+
const tagErrors = validateAgentTags(rawTags);
|
|
137
|
+
if (tagErrors.length > 0)
|
|
138
|
+
throw new Error(`Invalid agent.md tags: ${tagErrors.join('; ')}`);
|
|
139
|
+
const tags = [...new Set(rawTags.map(tag => tag.trim()))];
|
|
140
|
+
return `---\naid: ${yamlDoubleQuote(opts.aid)}\nname: ${yamlDoubleQuote(agentName)}\ntype: ${yamlDoubleQuote(agentType)}\nversion: "1.0.0"\ndescription: ${yamlDoubleQuote(description)}\ntags:\n${tags.map(tag => ` - ${yamlDoubleQuote(tag)}\n`).join('')}---\n`;
|
|
91
141
|
}
|
|
92
142
|
function ensureTrailingNewline(content) {
|
|
93
143
|
return content.endsWith('\n') ? content : `${content}\n`;
|
|
@@ -145,9 +195,11 @@ export function validateAgentMdFrontmatter(content, expectedAid) {
|
|
|
145
195
|
if (description && description.length > 100) {
|
|
146
196
|
errors.push('agent.md frontmatter description must be at most 100 characters');
|
|
147
197
|
}
|
|
148
|
-
if (values.tags !== undefined
|
|
149
|
-
|
|
150
|
-
|
|
198
|
+
if (values.tags !== undefined) {
|
|
199
|
+
const tagErrors = validateAgentTags(values.tags);
|
|
200
|
+
if (tagErrors.length > 0) {
|
|
201
|
+
errors.push(`agent.md frontmatter tags ${tagErrors.join('; ')}`);
|
|
202
|
+
}
|
|
151
203
|
}
|
|
152
204
|
return { valid: errors.length === 0, errors };
|
|
153
205
|
}
|
package/dist/aun/aid/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { AGENT_TAG_MIN_COUNT, AGENT_TAG_MAX_COUNT, AGENT_TAG_MAX_LENGTH, validateAgentTag, validateAgentTags, } from './agentmd.js';
|
|
1
2
|
export { isValidAid, aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, verifySignAbility, probePkiRecoverability, appendAidLifecycle, readAidLifecycle } from './identity.js';
|
|
2
3
|
export { DEFAULT_AGENT_DESCRIPTION, buildInitialAgentMd, validateAgentMdFrontmatter, agentmdGet, agentmdPut, agentmdSync, invalidateAgentDisplayName, parseAgentDisplayName, refreshAgentDisplayName, resolveAgentDisplayName, stripAgentMdSignature, updateAgentMdFrontmatterAvatar, updateAgentMdFrontmatterName, } from './agentmd.js';
|
|
3
4
|
export { MIN_AUN_CORE_SDK, AUN_CORE_SDK_PKG, isAunSdkVersionOk, resolveAunCoreSdkPkg, ensureAunSdk, isAunSdkReady, downloadCaRoot, suppressSdkLogs, } from './client.js';
|
|
@@ -2,6 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolveRoot } from '../../paths.js';
|
|
4
4
|
import { agentmdGet, agentmdPut } from './agentmd.js';
|
|
5
|
+
import { uploadAvatarBuffer, uploadAvatarUrl } from '../../utils/avatar-upload.js';
|
|
5
6
|
import { aidLookup, aidShow } from './identity.js';
|
|
6
7
|
import { isValidAid } from './validation.js';
|
|
7
8
|
export class ManagedAidOperationError extends Error {
|
|
@@ -28,6 +29,32 @@ function parseAid(value) {
|
|
|
28
29
|
return { ok: false, code: 'INVALID_AID', reason: `invalid AID: ${aid}` };
|
|
29
30
|
return { ok: true, aid };
|
|
30
31
|
}
|
|
32
|
+
function parseAvatar(args) {
|
|
33
|
+
const aidResult = parseAid(args[1]);
|
|
34
|
+
if (!aidResult.ok)
|
|
35
|
+
return aidResult;
|
|
36
|
+
const sourceFlag = args[2];
|
|
37
|
+
const sourceValue = args[3];
|
|
38
|
+
if (sourceFlag !== '--file' && sourceFlag !== '--url') {
|
|
39
|
+
return { ok: false, code: 'INVALID_ARGUMENT', reason: 'avatar requires exactly one of --file <path> or --url <https-url>' };
|
|
40
|
+
}
|
|
41
|
+
if (!sourceValue || sourceValue.startsWith('-')) {
|
|
42
|
+
return { ok: false, code: 'INVALID_ARGUMENT', reason: `${sourceFlag} requires a non-empty value` };
|
|
43
|
+
}
|
|
44
|
+
if (args.length !== 4 && !(args.length === 6 && args[4] === '--format' && args[5] === 'json')) {
|
|
45
|
+
return { ok: false, code: 'NOT_ALLOWED', reason: 'avatar only supports an optional --format json suffix' };
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
ok: true,
|
|
49
|
+
command: {
|
|
50
|
+
kind: 'avatar',
|
|
51
|
+
aid: aidResult.aid,
|
|
52
|
+
...(sourceFlag === '--file' ? { filePath: sourceValue } : { url: sourceValue }),
|
|
53
|
+
operationId: 'ec.aid.avatar',
|
|
54
|
+
canonicalArgv: ['aid', 'avatar', aidResult.aid, sourceFlag, sourceValue],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
31
58
|
/**
|
|
32
59
|
* The daemon accepts only the narrowly scoped AID commands exposed to managed
|
|
33
60
|
* tasks. Public lookup/get may name any valid AID; local show/publish remain
|
|
@@ -36,6 +63,8 @@ function parseAid(value) {
|
|
|
36
63
|
export function resolveManagedAidOperation(argv) {
|
|
37
64
|
const args = argv[0] === 'aid' ? argv.slice(1) : argv;
|
|
38
65
|
const subcommand = args[0];
|
|
66
|
+
if (subcommand === 'avatar')
|
|
67
|
+
return parseAvatar(args);
|
|
39
68
|
if ((subcommand === 'show' || subcommand === 'lookup') && hasOnlyOptionalJsonFormat(args, 1)) {
|
|
40
69
|
const parsedAid = parseAid(args[1]);
|
|
41
70
|
if (!parsedAid.ok)
|
|
@@ -68,7 +97,7 @@ export function resolveManagedAidOperation(argv) {
|
|
|
68
97
|
return {
|
|
69
98
|
ok: false,
|
|
70
99
|
code: 'NOT_ALLOWED',
|
|
71
|
-
reason: 'Managed AID operations only allow exact show, lookup, agentmd get,
|
|
100
|
+
reason: 'Managed AID operations only allow exact show, lookup, agentmd get, agentmd put, or avatar commands with supported options',
|
|
72
101
|
};
|
|
73
102
|
}
|
|
74
103
|
export function managedAidShowViewForRole(role) {
|
|
@@ -93,6 +122,8 @@ const defaultDependencies = () => ({
|
|
|
93
122
|
agentmdPut,
|
|
94
123
|
existsSync: fs.existsSync,
|
|
95
124
|
readFileSync: fs.readFileSync,
|
|
125
|
+
uploadAvatarBuffer,
|
|
126
|
+
uploadAvatarUrl,
|
|
96
127
|
});
|
|
97
128
|
/** Execute a validated AID operation from the daemon-owned host filesystem. */
|
|
98
129
|
export async function executeManagedAidOperation(command, options = {}) {
|
|
@@ -125,5 +156,26 @@ export async function executeManagedAidOperation(command, options = {}) {
|
|
|
125
156
|
await deps.agentmdPut(content, { aid: command.aid, aunPath });
|
|
126
157
|
return { kind: command.kind, aid: command.aid, path: localPath };
|
|
127
158
|
}
|
|
159
|
+
case 'avatar': {
|
|
160
|
+
const result = command.url
|
|
161
|
+
? await deps.uploadAvatarUrl(command.aid, command.url, { aunPath })
|
|
162
|
+
: await deps.uploadAvatarBuffer(command.aid, options.avatarBuffer ?? deps.readFileSync(command.filePath), { aunPath });
|
|
163
|
+
if (!result.ok) {
|
|
164
|
+
throw new ManagedAidOperationError(result.code ?? 'UPLOAD_FAILED', result.error ?? 'avatar upload failed');
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
kind: 'avatar',
|
|
168
|
+
aid: command.aid,
|
|
169
|
+
avatar: result.publicUrl,
|
|
170
|
+
objectKey: result.objectKey,
|
|
171
|
+
sha256: result.sha256,
|
|
172
|
+
mime: result.mime,
|
|
173
|
+
width: result.width,
|
|
174
|
+
height: result.height,
|
|
175
|
+
aspectRatio: result.aspectRatio,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
default:
|
|
179
|
+
throw new ManagedAidOperationError('NOT_ALLOWED', `Unsupported managed AID operation: ${command.kind}`);
|
|
128
180
|
}
|
|
129
181
|
}
|
|
@@ -17,7 +17,10 @@ function pickUrl(value) {
|
|
|
17
17
|
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
18
18
|
}
|
|
19
19
|
export async function storageUpload(aid, localFile, remotePath, opts) {
|
|
20
|
-
const fileBuffer = fs.readFileSync(localFile);
|
|
20
|
+
const fileBuffer = Buffer.isBuffer(localFile) ? localFile : fs.readFileSync(localFile);
|
|
21
|
+
return storageUploadBuffer(aid, fileBuffer, remotePath, opts);
|
|
22
|
+
}
|
|
23
|
+
export async function storageUploadBuffer(aid, fileBuffer, remotePath, opts) {
|
|
21
24
|
const contentType = opts?.contentType ?? 'application/octet-stream';
|
|
22
25
|
const sha256 = crypto.createHash('sha256').update(fileBuffer).digest('hex');
|
|
23
26
|
const createResult = await rpcCall(aid, 'storage.create_upload_session', {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { storageUpload, storageLs, storageRm, storageQuota } from './client.js';
|
|
1
|
+
export { storageUpload, storageUploadBuffer, storageLs, storageRm, storageQuota } from './client.js';
|
|
2
2
|
export { storageDownload } from './download.js';
|