evolcore 0.0.23 → 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 +583 -516
- package/LICENSE +21 -21
- package/README.md +455 -453
- package/bin/codex-managed-acl.ps1 +160 -155
- package/bin/codex-managed-hook.mjs +209 -92
- package/bin/ec-safe-output.js +327 -245
- package/bin/ec.js +29 -29
- package/bin/install-codex-managed-hooks.mjs +555 -544
- package/dist/agents/baseagent-availability.js +4 -4
- package/dist/agents/baseagent.js +29 -1
- package/dist/agents/claude-runner.js +152 -14
- package/dist/agents/codex/app-server-client.js +18 -8
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +215 -0
- package/dist/agents/codex-runner.js +445 -63
- package/dist/agents/ecagent-runner.js +31 -16
- package/dist/agents/gemini-runner.js +82 -4
- package/dist/agents/runner-types.js +1 -1
- package/dist/aun/aid/agentmd.js +56 -4
- package/dist/aun/aid/index.js +1 -0
- package/dist/aun/aid/managed-operation.js +80 -6
- package/dist/aun/aid/store.js +41 -0
- package/dist/aun/msg/managed-operation.js +6 -1
- package/dist/aun/outbox.js +56 -18
- package/dist/aun/rpc/client.js +4 -5
- package/dist/aun/storage/client.js +4 -1
- package/dist/aun/storage/index.js +1 -1
- package/dist/channels/aun.js +147 -76
- package/dist/channels/daemon.js +7 -1
- package/dist/channels/dingtalk.js +1 -0
- package/dist/channels/feishu.js +10 -4
- package/dist/channels/wecom.js +2 -1
- package/dist/cli/agent-command.js +214 -89
- package/dist/cli/agent-create.js +576 -0
- package/dist/cli/agent.js +129 -676
- package/dist/cli/aun-commands.js +419 -313
- 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 -20
- package/dist/cli/daemon-commands.js +163 -32
- package/dist/cli/fs-command.js +67 -67
- package/dist/cli/handoff-command.js +7 -7
- package/dist/cli/index.js +79 -79
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +3 -0
- 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 +462 -38
- package/dist/cli/stats.js +161 -51
- package/dist/cli/trigger-command.js +56 -56
- package/dist/config/builtin-roles.js +3 -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/auth-gateway.js +3 -2
- package/dist/core/auth/authorization-audit.js +72 -19
- package/dist/core/auth/operation-authorizer.js +125 -7
- package/dist/core/auth/operation-catalog.js +26 -2
- package/dist/core/auth/remote-access-store.js +3 -2
- package/dist/core/baseagent-loader.js +4 -4
- package/dist/core/bootstrap-messages.js +39 -18
- package/dist/core/bootstrap-service.js +32 -26
- package/dist/core/capability/capability-manager.js +8 -4
- package/dist/core/capability/providers/codex-capability-provider.js +1 -1
- package/dist/core/command/agent-control.js +60 -26
- package/dist/core/command/cli-intent-parser.js +18 -0
- package/dist/core/command/command-handler.js +173 -36
- package/dist/core/command/menu-catalog.js +4 -1
- package/dist/core/command/menu-handler.js +315 -75
- package/dist/core/command/menu-protocol.js +7 -2
- package/dist/core/command/slash-gate.js +1 -3
- package/dist/core/command/slash-handler.js +166 -57
- package/dist/core/data-migration.js +5 -15
- package/dist/core/event-catalog.js +8 -0
- package/dist/core/evolagent.js +3 -3
- package/dist/core/handoff/runtime.js +3 -1
- package/dist/core/handoff/store.js +7 -1
- package/dist/core/message/im-renderer.js +13 -6
- package/dist/core/message/message-bridge.js +5 -36
- package/dist/core/message/message-utils.js +6 -3
- package/dist/core/message/response-engine.js +85 -27
- package/dist/core/model/catalog-service.js +3 -1
- package/dist/core/model/model-catalog.js +10 -0
- package/dist/core/model/model-permission.js +4 -1
- package/dist/core/permission/approval-gateway.js +169 -33
- package/dist/core/permission/tool-policy.js +56 -10
- package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
- package/dist/core/session/session-manager.js +49 -13
- package/dist/core/session/session-renew.js +1 -0
- package/dist/index.js +327 -134
- package/dist/ipc.js +68 -21
- package/dist/paths.js +23 -1
- package/dist/stats/billing.js +18 -4
- 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/atomic-write.js +26 -2
- package/dist/utils/avatar-upload.js +282 -23
- package/dist/utils/cross-platform.js +436 -1
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +11 -4
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -20
- package/dist/utils/npm-ops.js +24 -1
- package/dist/utils/welcome.js +22 -22
- package/dist/utils/windows-autostart.js +1 -1
- 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 -82
- 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 -94
- package/AGENTS.md +0 -62
- package/dist/utils/codex-cli.js +0 -43
- package/skills/eclink/SKILL.md +0 -84
- package/skills/eclink/agents/openai.yaml +0 -4
|
@@ -10,6 +10,8 @@ export function auditCommandAuthorization(event) {
|
|
|
10
10
|
(event.decision === 'allow' && event.dangerous) ||
|
|
11
11
|
(event.source === 'agent-tool' && event.operation.startsWith('config.')) ||
|
|
12
12
|
event.operation === 'codex.approval' ||
|
|
13
|
+
event.operation === 'permission.approval' ||
|
|
14
|
+
event.operation === 'permission.runtime' ||
|
|
13
15
|
event.operation.startsWith('fullaccess.') ||
|
|
14
16
|
event.operation.startsWith('role.') ||
|
|
15
17
|
event.operation === 'cli.exec.raw';
|
|
@@ -198,33 +200,78 @@ export function auditCodexApprovalDecision(input) {
|
|
|
198
200
|
* infrastructure denials without parsing localized log text.
|
|
199
201
|
*/
|
|
200
202
|
export function auditPermissionDecision(input) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
requestId: input.requestId,
|
|
203
|
+
const requestId = input.requestId ?? `perm-audit-${crypto.randomUUID()}`;
|
|
204
|
+
auditPermissionLifecycle({
|
|
205
|
+
phase: 'final',
|
|
206
|
+
requestId,
|
|
206
207
|
sessionId: input.sessionId,
|
|
207
208
|
agentAid: input.agentAid,
|
|
208
209
|
agentName: input.agentName,
|
|
209
210
|
permissionMode: input.permissionMode,
|
|
210
211
|
toolName: input.toolName,
|
|
212
|
+
decision: 'deny',
|
|
213
|
+
decisionSource: input.decisionSource,
|
|
214
|
+
policyCode: input.policyCode,
|
|
215
|
+
reason: input.reason,
|
|
216
|
+
role: input.role,
|
|
217
|
+
taskId: input.taskId,
|
|
218
|
+
summary: input.summary,
|
|
219
|
+
operation: 'permission.runtime',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Emit a canonical request/response/final lifecycle for runtime approvals.
|
|
224
|
+
* All three phases share one eventKey and complete correlation fields so
|
|
225
|
+
* daily analysis can group them without parsing runner-specific log text.
|
|
226
|
+
*/
|
|
227
|
+
export function auditPermissionLifecycle(input) {
|
|
228
|
+
const sessionId = input.sessionId ?? 'unknown';
|
|
229
|
+
auditCommandAuthorization({
|
|
230
|
+
ts: Date.now(),
|
|
231
|
+
eventKey: buildToolLifecycleEventKey({
|
|
232
|
+
sessionId,
|
|
233
|
+
callId: input.callId,
|
|
234
|
+
correlationId: input.correlationId,
|
|
235
|
+
requestId: input.requestId,
|
|
236
|
+
}),
|
|
237
|
+
eventPhase: input.phase,
|
|
238
|
+
callId: input.callId ?? input.requestId,
|
|
239
|
+
correlationId: input.correlationId ?? input.callId ?? input.requestId,
|
|
240
|
+
requestId: input.requestId,
|
|
241
|
+
sessionId,
|
|
242
|
+
agentAid: input.agentAid ?? 'unknown',
|
|
243
|
+
agentName: input.agentName,
|
|
244
|
+
permissionMode: input.permissionMode ?? 'unknown',
|
|
245
|
+
toolName: input.toolName,
|
|
246
|
+
approvalMethod: input.approvalMethod,
|
|
211
247
|
policyCode: input.policyCode,
|
|
212
248
|
decisionSource: input.decisionSource,
|
|
213
|
-
errorCode: input.
|
|
214
|
-
? '
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
249
|
+
errorCode: input.decision === 'deny'
|
|
250
|
+
? input.decisionSource === 'approval'
|
|
251
|
+
? 'USER_DENIED'
|
|
252
|
+
: input.decisionSource === 'policy'
|
|
253
|
+
? 'POLICY_DENIED'
|
|
254
|
+
: infrastructureErrorCode(input.policyCode)
|
|
255
|
+
: undefined,
|
|
218
256
|
source: 'agent-tool',
|
|
219
|
-
operation: 'permission.
|
|
257
|
+
operation: input.operation ?? 'permission.approval',
|
|
220
258
|
scope: 'filesystem',
|
|
221
259
|
dangerous: false,
|
|
222
260
|
role: input.role ?? 'unknown',
|
|
223
261
|
taskId: input.taskId,
|
|
224
|
-
argsSummary: input.summary
|
|
225
|
-
|
|
262
|
+
argsSummary: input.summary || input.response
|
|
263
|
+
? {
|
|
264
|
+
...(input.summary ? { summary: input.summary } : {}),
|
|
265
|
+
...(input.response ? { response: input.response } : {}),
|
|
266
|
+
}
|
|
267
|
+
: undefined,
|
|
268
|
+
decision: input.decision,
|
|
226
269
|
executed: false,
|
|
227
|
-
executionState: '
|
|
270
|
+
executionState: input.phase === 'request'
|
|
271
|
+
? 'requested'
|
|
272
|
+
: input.phase === 'response'
|
|
273
|
+
? 'responded'
|
|
274
|
+
: input.decision === 'deny' ? 'blocked' : 'authorized',
|
|
228
275
|
reason: input.reason,
|
|
229
276
|
});
|
|
230
277
|
}
|
|
@@ -270,7 +317,7 @@ function infrastructureErrorCode(policyCode) {
|
|
|
270
317
|
}
|
|
271
318
|
function buildAuditRecord(event) {
|
|
272
319
|
const executed = event.executed ?? false;
|
|
273
|
-
const decisionSource = event.decisionSource ?? (event.decision === 'deny' ? 'policy' : 'command');
|
|
320
|
+
const decisionSource = event.decisionSource ?? (event.decision === 'deny' ? 'policy' : event.decision === 'pending' ? 'approval' : 'command');
|
|
274
321
|
const errorCode = event.errorCode ?? (event.decision === 'deny'
|
|
275
322
|
? decisionSource === 'approval'
|
|
276
323
|
? 'USER_DENIED'
|
|
@@ -281,9 +328,11 @@ function buildAuditRecord(event) {
|
|
|
281
328
|
const executionState = event.executionState
|
|
282
329
|
?? (event.decision === 'deny'
|
|
283
330
|
? 'blocked'
|
|
284
|
-
:
|
|
285
|
-
?
|
|
286
|
-
:
|
|
331
|
+
: event.decision === 'pending'
|
|
332
|
+
? 'requested'
|
|
333
|
+
: executed
|
|
334
|
+
? (event.exitCode === undefined || event.exitCode === 0 ? 'completed' : 'failed')
|
|
335
|
+
: 'authorized');
|
|
287
336
|
const lifecycleId = event.callId ?? event.correlationId ?? event.requestId;
|
|
288
337
|
return {
|
|
289
338
|
ts: event.ts,
|
|
@@ -386,7 +435,11 @@ function logAuditEvent(record) {
|
|
|
386
435
|
: routineEcwebRoleRead
|
|
387
436
|
? 'debug'
|
|
388
437
|
: 'info';
|
|
389
|
-
const marker = record.decision === 'deny'
|
|
438
|
+
const marker = record.decision === 'deny'
|
|
439
|
+
? 'DENY'
|
|
440
|
+
: record.decision === 'pending'
|
|
441
|
+
? 'PENDING'
|
|
442
|
+
: record.dangerous ? 'DANGEROUS_ALLOW' : 'ALLOW';
|
|
390
443
|
const message = [
|
|
391
444
|
`[CommandAudit:${marker}]`,
|
|
392
445
|
`operation=${record.operation}`,
|
|
@@ -34,6 +34,9 @@ const DAEMON_SERVICE_OPERATIONS = new Set([
|
|
|
34
34
|
'trigger.cancel',
|
|
35
35
|
'trigger.delete',
|
|
36
36
|
'trigger.run',
|
|
37
|
+
'agent.reload',
|
|
38
|
+
'system.restart',
|
|
39
|
+
'system.upgrade',
|
|
37
40
|
]);
|
|
38
41
|
export function authorizeCommand(ctx) {
|
|
39
42
|
return authorizeCommandInternal(ctx);
|
|
@@ -121,6 +124,47 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
121
124
|
return denyDecision(ctx, 'NOT_ALLOWED', `Operation ${operation} is not available from source ${ctx.source}`, operation, intent.scope, opMeta.dangerous);
|
|
122
125
|
}
|
|
123
126
|
if (ctx.processRole === 'daemon-service') {
|
|
127
|
+
// ECWeb uses the authenticated daemon service for its read-only menu
|
|
128
|
+
// bootstrap (model/effort, agent metadata, trigger views, etc.). These
|
|
129
|
+
// queries are safe to authorize by catalog category; mutating operations
|
|
130
|
+
// remain restricted to the explicit daemon-service allowlist below.
|
|
131
|
+
const ECWEB_SERVICE_READ_OPERATIONS = new Set([
|
|
132
|
+
'system.status', 'model.current', 'model.list', 'baseagent.models.list',
|
|
133
|
+
'model.effort.current', 'agent.baseagent.current', 'agent.baseagent.list',
|
|
134
|
+
'agent.show',
|
|
135
|
+
'agent.list',
|
|
136
|
+
'capability.read',
|
|
137
|
+
'gateway.read', 'stats.summary', 'stats.session', 'stats.context',
|
|
138
|
+
'role.policy.read', 'role.relation.read', 'config.read',
|
|
139
|
+
'model.info', 'model.check',
|
|
140
|
+
'trigger.list', 'trigger.show', 'trigger.history', 'trigger.eventCatalog',
|
|
141
|
+
]);
|
|
142
|
+
if (ECWEB_SERVICE_READ_OPERATIONS.has(operation)) {
|
|
143
|
+
return {
|
|
144
|
+
allow: true,
|
|
145
|
+
operation,
|
|
146
|
+
scope: intent.scope,
|
|
147
|
+
role: 'daemon-service',
|
|
148
|
+
dangerous: opMeta.dangerous,
|
|
149
|
+
matchedRule: 'daemon-service-read',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// The in-process service may perform system lifecycle actions only when
|
|
153
|
+
// the request came through the authenticated ECWeb management surface.
|
|
154
|
+
// A raw daemon-service subject on the control source is not a human owner.
|
|
155
|
+
if ((operation === 'system.restart' || operation === 'system.upgrade') && ctx.source === 'control') {
|
|
156
|
+
return denyDecision(ctx, 'NOT_ALLOWED', `Daemon service is not authorized for ${operation}`, operation, intent.scope, opMeta.dangerous, 'daemon-service');
|
|
157
|
+
}
|
|
158
|
+
if (ctx.source !== 'control' && (operation === 'observable.current' || operation === 'observable.update')) {
|
|
159
|
+
return {
|
|
160
|
+
allow: true,
|
|
161
|
+
operation,
|
|
162
|
+
scope: intent.scope,
|
|
163
|
+
role: 'daemon-service',
|
|
164
|
+
dangerous: opMeta.dangerous,
|
|
165
|
+
matchedRule: 'ecweb-daemon-service-agent-management',
|
|
166
|
+
};
|
|
167
|
+
}
|
|
124
168
|
if (!DAEMON_SERVICE_OPERATIONS.has(operation)) {
|
|
125
169
|
return denyDecision(ctx, 'NOT_ALLOWED', `Daemon service is not authorized for ${operation}`, operation, intent.scope, opMeta.dangerous, 'daemon-service');
|
|
126
170
|
}
|
|
@@ -148,7 +192,8 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
148
192
|
};
|
|
149
193
|
}
|
|
150
194
|
// Any authenticated role may inspect the current Agent through the daemon's
|
|
151
|
-
// redacted view.
|
|
195
|
+
// redacted view. Management roles may inspect another Agent's redacted view;
|
|
196
|
+
// mutation and reload remain target-scoped below.
|
|
152
197
|
if (operation === 'agent.show' && isCurrentAgentTarget(ctx)) {
|
|
153
198
|
return {
|
|
154
199
|
allow: true,
|
|
@@ -159,6 +204,17 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
159
204
|
matchedRule: 'self-agent-read',
|
|
160
205
|
};
|
|
161
206
|
}
|
|
207
|
+
if (operation === 'agent.persona' && isCurrentAgentTarget(ctx)
|
|
208
|
+
&& (role === 'owner' || hasDaemonOwnerRole(ctx))) {
|
|
209
|
+
return {
|
|
210
|
+
allow: true,
|
|
211
|
+
operation,
|
|
212
|
+
scope: intent.scope,
|
|
213
|
+
role,
|
|
214
|
+
dangerous: opMeta.dangerous,
|
|
215
|
+
matchedRule: role === 'owner' ? 'agent-owner-persona' : 'daemon-owner-persona',
|
|
216
|
+
};
|
|
217
|
+
}
|
|
162
218
|
if (resolvedConfigCommand) {
|
|
163
219
|
const targetCheck = checkResolvedConfigTarget(ctx, resolvedConfigCommand);
|
|
164
220
|
if (!targetCheck.ok) {
|
|
@@ -171,7 +227,7 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
171
227
|
if (!isManagementRole(role) && intent.scope !== 'relation') {
|
|
172
228
|
return denyDecision(ctx, 'SCOPE_MISMATCH', `Role ${role} may only access relation-scoped config`, operation, intent.scope, opMeta.dangerous);
|
|
173
229
|
}
|
|
174
|
-
if (role === 'owner') {
|
|
230
|
+
if (role === 'owner' && isCurrentAgentTarget(ctx)) {
|
|
175
231
|
return {
|
|
176
232
|
allow: true,
|
|
177
233
|
operation,
|
|
@@ -181,6 +237,22 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
181
237
|
matchedRule: 'agent-owner',
|
|
182
238
|
};
|
|
183
239
|
}
|
|
240
|
+
// The daemon control identity is allowed to inspect any Agent config,
|
|
241
|
+
// including sensitive fields. This is intentionally handled before
|
|
242
|
+
// role-definition matching because daemon-owner subjects do not need an
|
|
243
|
+
// Agent relation role to read the daemon's local configuration store.
|
|
244
|
+
if (resolvedConfigCommand.kind === 'field'
|
|
245
|
+
&& resolvedConfigCommand.subcommand === 'get'
|
|
246
|
+
&& hasDaemonOwnerRole(ctx)) {
|
|
247
|
+
return {
|
|
248
|
+
allow: true,
|
|
249
|
+
operation,
|
|
250
|
+
scope: intent.scope,
|
|
251
|
+
role: 'daemon-owner',
|
|
252
|
+
dangerous: opMeta.dangerous,
|
|
253
|
+
matchedRule: 'daemon-owner-config-read',
|
|
254
|
+
};
|
|
255
|
+
}
|
|
184
256
|
}
|
|
185
257
|
const roleDef = getRoleDefinition(role, ctx.selfAid);
|
|
186
258
|
if (!roleDef) {
|
|
@@ -189,6 +261,20 @@ function authorizeCommandInternal(ctx, resolvedConfigCommand) {
|
|
|
189
261
|
if (roleDef.allowAccess === false) {
|
|
190
262
|
return denyDecision(ctx, 'ROLE_ACCESS_DENIED', `Role ${role} is not allowed to access commands`, operation, intent.scope, opMeta.dangerous);
|
|
191
263
|
}
|
|
264
|
+
// AID lookup and public agent.md reads are available to every accessible
|
|
265
|
+
// role and may target any AID that passed managed-command validation. The
|
|
266
|
+
// operation source is restricted to agent-tool by the catalog.
|
|
267
|
+
if ((operation === 'ec.aid.lookup' || operation === 'ec.aid.agentmd.get')
|
|
268
|
+
&& (intent.scope === 'relation' || intent.scope === 'agent')) {
|
|
269
|
+
return {
|
|
270
|
+
allow: true,
|
|
271
|
+
operation,
|
|
272
|
+
scope: intent.scope,
|
|
273
|
+
role,
|
|
274
|
+
dangerous: opMeta.dangerous,
|
|
275
|
+
matchedRule: 'public-aid-read',
|
|
276
|
+
};
|
|
277
|
+
}
|
|
192
278
|
let matchResult = matchCommandPermission(operation, opMeta.category, roleDef.commandPermissions || {}, opMeta.dangerous);
|
|
193
279
|
// Agent self-service contact add deliberately reuses the same low-trust
|
|
194
280
|
// relation boundary as ec.msg.send. Older per-Agent role files may still
|
|
@@ -299,10 +385,25 @@ function requiresDaemonOwner(ctx, resolvedConfigCommand) {
|
|
|
299
385
|
|| resolvedConfigCommand.configScope === 'process'
|
|
300
386
|
|| resolvedConfigCommand.configScope === 'defaults'))
|
|
301
387
|
return true;
|
|
388
|
+
// Sensitive reads of another Agent's config are daemon-scoped. Agent
|
|
389
|
+
// owner/admin roles may inspect safe fields cross-Agent, but only the
|
|
390
|
+
// daemon control identity may access config.read targets that are not the
|
|
391
|
+
// current Agent.
|
|
392
|
+
if (operation === 'config.read'
|
|
393
|
+
&& resolvedConfigCommand?.kind === 'field'
|
|
394
|
+
&& resolvedConfigCommand.configScope === 'agent'
|
|
395
|
+
&& !isCurrentAgentTarget(ctx)) {
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
302
398
|
if (operation === 'agent.reload' && hasDaemonOwnerRole(ctx)) {
|
|
303
399
|
return true;
|
|
304
400
|
}
|
|
305
|
-
|
|
401
|
+
// Avatar publication is an Agent-scoped mutation for Agent channels, but
|
|
402
|
+
// the trusted control plane may publish it for a selected Agent target.
|
|
403
|
+
if (operation === 'ec.aid.avatar' && hasDaemonOwnerRole(ctx)) {
|
|
404
|
+
return true;
|
|
405
|
+
}
|
|
406
|
+
if (operation === 'agent.reload') {
|
|
306
407
|
return !isCurrentAgentTarget(ctx);
|
|
307
408
|
}
|
|
308
409
|
if (operation.startsWith('trigger.')) {
|
|
@@ -317,7 +418,9 @@ function requiresDaemonOwner(ctx, resolvedConfigCommand) {
|
|
|
317
418
|
return false;
|
|
318
419
|
}
|
|
319
420
|
function hasDaemonOwnerRole(ctx) {
|
|
320
|
-
return ctx.isDaemonOwner === true
|
|
421
|
+
return ctx.isDaemonOwner === true
|
|
422
|
+
|| ctx.processRole === 'daemon-owner'
|
|
423
|
+
|| ctx.processRole === 'daemon-service';
|
|
321
424
|
}
|
|
322
425
|
function daemonOwnerDenialReasonCode(ctx) {
|
|
323
426
|
if ((ctx.intent.operation === 'agent.show' || ctx.intent.operation === 'agent.reload')
|
|
@@ -340,8 +443,8 @@ function isCurrentAgentTarget(ctx) {
|
|
|
340
443
|
return !!ctx.selfAid && !!targetAid && targetAid === ctx.selfAid;
|
|
341
444
|
}
|
|
342
445
|
function daemonOwnerRequiredMessage(operation) {
|
|
343
|
-
return
|
|
344
|
-
+ 'Agent owner/admin
|
|
446
|
+
return `无权限:${operation} 是 daemon 级操作,需要 DaemonOwner。`
|
|
447
|
+
+ 'Agent owner/admin 和 permissionMode=bypass 均不能授予此权限。';
|
|
345
448
|
}
|
|
346
449
|
function getRuleRank(rule, permission, operation, category, isDangerous) {
|
|
347
450
|
const denyOffset = permission.allow ? 0 : 1;
|
|
@@ -469,6 +572,12 @@ function checkConfigFieldPolicy(ctx, policy, resolvedConfigOp) {
|
|
|
469
572
|
return { ok: false, reason: 'Resolved config operation is required' };
|
|
470
573
|
const field = resolvedConfigOp.field;
|
|
471
574
|
if (!resolvedConfigOp.route || (resolvedConfigOp.fieldRule.class !== 'safe-scalar' && resolvedConfigOp.fieldRule.class !== 'safe-readonly-object')) {
|
|
575
|
+
if (policy === 'behavior-read'
|
|
576
|
+
&& !isCurrentAgentTarget(ctx)
|
|
577
|
+
&& hasDaemonOwnerRole(ctx)
|
|
578
|
+
&& resolvedConfigOp.route) {
|
|
579
|
+
return { ok: true };
|
|
580
|
+
}
|
|
472
581
|
return { ok: false, reason: `Config field ${field} is not available to user roles` };
|
|
473
582
|
}
|
|
474
583
|
if (policy === 'role-overridable-write'
|
|
@@ -481,8 +590,12 @@ function checkConfigFieldPolicy(ctx, policy, resolvedConfigOp) {
|
|
|
481
590
|
const fieldPermission = roleDef
|
|
482
591
|
? resolveRoleFieldPermission(roleDef.permissions || {}, field)
|
|
483
592
|
: undefined;
|
|
484
|
-
if (policy === 'behavior-read')
|
|
593
|
+
if (policy === 'behavior-read') {
|
|
594
|
+
// Only the daemon control identity may read sensitive config fields from
|
|
595
|
+
// another Agent. Agent owners retain unrestricted reads for their own
|
|
596
|
+
// target via the self-target fast path above.
|
|
485
597
|
return { ok: true };
|
|
598
|
+
}
|
|
486
599
|
if (fieldPermission && !fieldPermission.allowOverride) {
|
|
487
600
|
return { ok: false, reason: `Role ${ctx.role} cannot override ${field}` };
|
|
488
601
|
}
|
|
@@ -519,6 +632,11 @@ function checkResolvedConfigTarget(ctx, command) {
|
|
|
519
632
|
return { ok: true };
|
|
520
633
|
}
|
|
521
634
|
if (command.configScope === 'agent') {
|
|
635
|
+
// Management roles may read another Agent's non-sensitive config fields;
|
|
636
|
+
// sensitive fields are rejected by the field policy. Writes stay self-only.
|
|
637
|
+
if (command.subcommand === 'get' && (isManagementRole(ctx.role) || hasDaemonOwnerRole(ctx))) {
|
|
638
|
+
return { ok: true };
|
|
639
|
+
}
|
|
522
640
|
if (!ctx.selfAid || !command.self || command.self !== ctx.selfAid) {
|
|
523
641
|
return { ok: false, reason: 'Only the current agent can be targeted' };
|
|
524
642
|
}
|
|
@@ -116,6 +116,14 @@ const QUEUE_OPERATIONS = [['read', 'Read the current Agent message queue'], ['cl
|
|
|
116
116
|
*/
|
|
117
117
|
const OPERATIONS = [
|
|
118
118
|
// ── Model Operations ──
|
|
119
|
+
{
|
|
120
|
+
id: 'baseagent.models.list',
|
|
121
|
+
category: 'read',
|
|
122
|
+
dangerous: false,
|
|
123
|
+
defaultScopes: ['process'],
|
|
124
|
+
description: '查询主机默认 Baseagent 模型目录',
|
|
125
|
+
sources: ['menu', 'ecweb', 'control'],
|
|
126
|
+
},
|
|
119
127
|
{
|
|
120
128
|
id: 'model.list',
|
|
121
129
|
category: 'read',
|
|
@@ -593,6 +601,14 @@ const OPERATIONS = [
|
|
|
593
601
|
description: '获取 agent 配置(含凭证)',
|
|
594
602
|
sources: ['menu', 'menu.cli', 'control'],
|
|
595
603
|
},
|
|
604
|
+
{
|
|
605
|
+
id: 'agent.persona',
|
|
606
|
+
category: 'write-agent',
|
|
607
|
+
dangerous: false,
|
|
608
|
+
defaultScopes: ['agent'],
|
|
609
|
+
description: '读取或更新当前 Agent 的 persona.md',
|
|
610
|
+
sources: ['agent-tool', 'control'],
|
|
611
|
+
},
|
|
596
612
|
{
|
|
597
613
|
id: 'agent.create',
|
|
598
614
|
category: 'process',
|
|
@@ -917,7 +933,7 @@ const OPERATIONS = [
|
|
|
917
933
|
category: 'read',
|
|
918
934
|
dangerous: false,
|
|
919
935
|
defaultScopes: ['relation', 'agent'],
|
|
920
|
-
description: 'Look up
|
|
936
|
+
description: 'Look up a public AID record',
|
|
921
937
|
sources: ['agent-tool'],
|
|
922
938
|
},
|
|
923
939
|
{
|
|
@@ -925,7 +941,7 @@ const OPERATIONS = [
|
|
|
925
941
|
category: 'read',
|
|
926
942
|
dangerous: false,
|
|
927
943
|
defaultScopes: ['relation', 'agent'],
|
|
928
|
-
description: 'Read and verify
|
|
944
|
+
description: 'Read and verify a public Agent agent.md',
|
|
929
945
|
sources: ['agent-tool'],
|
|
930
946
|
},
|
|
931
947
|
{
|
|
@@ -936,6 +952,14 @@ const OPERATIONS = [
|
|
|
936
952
|
description: 'Sign and publish the current Agent local agent.md',
|
|
937
953
|
sources: ['agent-tool'],
|
|
938
954
|
},
|
|
955
|
+
{
|
|
956
|
+
id: 'ec.aid.avatar',
|
|
957
|
+
category: 'write-agent',
|
|
958
|
+
dangerous: true,
|
|
959
|
+
defaultScopes: ['agent'],
|
|
960
|
+
description: 'Upload and publish the current Agent avatar',
|
|
961
|
+
sources: ['agent-tool', 'menu', 'menu.cli'],
|
|
962
|
+
},
|
|
939
963
|
{
|
|
940
964
|
id: 'ec.msg.send',
|
|
941
965
|
category: 'write-own',
|
|
@@ -2,8 +2,9 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { resolvePaths } from '../../paths.js';
|
|
5
|
-
export const REMOTE_ACCESS_TOKEN_TTL_MS =
|
|
6
|
-
|
|
5
|
+
export const REMOTE_ACCESS_TOKEN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
6
|
+
// 与 owner 绑定二维码(BindService)的默认有效期保持一致:10 分钟。
|
|
7
|
+
export const REMOTE_ACCESS_PAIRING_TTL_MS = 10 * 60 * 1000;
|
|
7
8
|
export function remoteAccessTokenStorePath() {
|
|
8
9
|
return path.join(resolvePaths().instanceDir, 'control-access-tokens.json');
|
|
9
10
|
}
|
|
@@ -20,16 +20,16 @@ export class AgentLoader {
|
|
|
20
20
|
* Iterate over all EvolAgents in the registry × all registered plugins.
|
|
21
21
|
* Each successful (agent, plugin) pair yields one runner instance.
|
|
22
22
|
*/
|
|
23
|
-
createAll(registry, callbacks, creationErrors) {
|
|
23
|
+
async createAll(registry, callbacks, creationErrors) {
|
|
24
24
|
const instances = [];
|
|
25
25
|
const allAgents = registry.runnableAgents();
|
|
26
26
|
for (const agent of allAgents) {
|
|
27
|
-
instances.push(...this.createForAgent(agent, callbacks, creationErrors));
|
|
27
|
+
instances.push(...await this.createForAgent(agent, callbacks, creationErrors));
|
|
28
28
|
}
|
|
29
29
|
return instances;
|
|
30
30
|
}
|
|
31
31
|
/** Create runners for one EvolAgent, used by runtime hot-load. */
|
|
32
|
-
createForAgent(agent, callbacks, creationErrors) {
|
|
32
|
+
async createForAgent(agent, callbacks, creationErrors) {
|
|
33
33
|
const instances = [];
|
|
34
34
|
for (const [pluginName, plugin] of this.plugins) {
|
|
35
35
|
if (!plugin.isEnabled(agent)) {
|
|
@@ -37,7 +37,7 @@ export class AgentLoader {
|
|
|
37
37
|
continue;
|
|
38
38
|
}
|
|
39
39
|
try {
|
|
40
|
-
const instance = plugin.createAgent(agent, callbacks);
|
|
40
|
+
const instance = await plugin.createAgent(agent, callbacks);
|
|
41
41
|
if (!instance) {
|
|
42
42
|
logger.debug(`Plugin '${pluginName}' returned null for agent '${agent.name}', skipping`);
|
|
43
43
|
continue;
|
|
@@ -18,8 +18,16 @@ export function bootstrapInitialMessageOperationPrefix(aid) {
|
|
|
18
18
|
export function bootstrapInitialRetryOperationId(aid, at = Date.now()) {
|
|
19
19
|
return `${bootstrapInitialMessageOperationPrefix(aid)}:${at}`;
|
|
20
20
|
}
|
|
21
|
-
export function postBootstrapWelcomeOperationId(aid) {
|
|
22
|
-
|
|
21
|
+
export function postBootstrapWelcomeOperationId(aid, owner) {
|
|
22
|
+
const normalizedAid = aid.replace(/^@/, '');
|
|
23
|
+
return owner ? `bootstrap-complete:v2:${normalizedAid}:${owner}` : `bootstrap-complete:v1:${normalizedAid}`;
|
|
24
|
+
}
|
|
25
|
+
export function isPostBootstrapWelcomeOperationId(operationId, aid) {
|
|
26
|
+
if (!operationId)
|
|
27
|
+
return false;
|
|
28
|
+
const normalizedAid = aid.replace(/^@/, '');
|
|
29
|
+
return operationId === postBootstrapWelcomeOperationId(normalizedAid)
|
|
30
|
+
|| operationId.startsWith(`bootstrap-complete:v2:${normalizedAid}:`);
|
|
23
31
|
}
|
|
24
32
|
export function renderPostBootstrapWelcome(aid, owner, ownerName) {
|
|
25
33
|
const mdPath = agentMdPath(aid);
|
|
@@ -36,9 +44,13 @@ export function renderPostBootstrapWelcome(aid, owner, ownerName) {
|
|
|
36
44
|
});
|
|
37
45
|
}
|
|
38
46
|
export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName, delivery = { chatType: 'private' }) {
|
|
39
|
-
const operationId = postBootstrapWelcomeOperationId(aid);
|
|
47
|
+
const operationId = postBootstrapWelcomeOperationId(aid, owner);
|
|
40
48
|
const chatDir = chatDirPath(resolvePaths().sessionsDir, 'aun', owner, aid);
|
|
41
|
-
|
|
49
|
+
const legacyOperationId = postBootstrapWelcomeOperationId(aid);
|
|
50
|
+
if (hasMessageLogOperation(chatDir, operationId) || hasMessageLogOperation(chatDir, legacyOperationId))
|
|
51
|
+
return;
|
|
52
|
+
const legacy = outbox.findByDedupeKey(aid, legacyOperationId);
|
|
53
|
+
if (legacy?.channelId === owner)
|
|
42
54
|
return;
|
|
43
55
|
const existing = outbox.findByDedupeKey(aid, operationId);
|
|
44
56
|
if (existing
|
|
@@ -68,21 +80,30 @@ export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName, deliver
|
|
|
68
80
|
});
|
|
69
81
|
}
|
|
70
82
|
export function hasPendingPostBootstrapWelcomeOutbox(aid) {
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
return findPostBootstrapWelcomeOutbox(aid)
|
|
84
|
+
.some(entry => outbox.isDeliveryForChannel(entry.delivery, entry.channelId));
|
|
85
|
+
}
|
|
86
|
+
/** Keep pending welcomes from the single-owner v1 format retryable after upgrades. */
|
|
87
|
+
export function findPostBootstrapWelcomeOutbox(aid, opts = {}) {
|
|
88
|
+
const normalizedAid = aid.replace(/^@/, '');
|
|
89
|
+
const entries = outbox.findByDedupePrefix(normalizedAid, `bootstrap-complete:v2:${normalizedAid}:`, opts);
|
|
90
|
+
const legacy = outbox.findByDedupeKey(normalizedAid, postBootstrapWelcomeOperationId(normalizedAid), opts);
|
|
91
|
+
return [...entries, ...(legacy ? [legacy] : [])];
|
|
92
|
+
}
|
|
93
|
+
export function pendingPostBootstrapWelcomeOwners(aid) {
|
|
94
|
+
return findPostBootstrapWelcomeOutbox(aid)
|
|
95
|
+
.filter(entry => outbox.isDeliveryForChannel(entry.delivery, entry.channelId))
|
|
96
|
+
.map(entry => entry.channelId)
|
|
97
|
+
.filter((owner, index, all) => all.indexOf(owner) === index);
|
|
73
98
|
}
|
|
74
99
|
/** Bind the durable completion welcome to the fresh post-bootstrap session. */
|
|
75
|
-
export function bindPostBootstrapWelcomeOutboxSession(aid, sessionId) {
|
|
76
|
-
const
|
|
77
|
-
|
|
100
|
+
export function bindPostBootstrapWelcomeOutboxSession(aid, sessionId, owner) {
|
|
101
|
+
const normalizedAid = aid.replace(/^@/, '');
|
|
102
|
+
const entries = findPostBootstrapWelcomeOutbox(normalizedAid)
|
|
103
|
+
.filter(entry => (!owner || entry.channelId === owner) && outbox.isDeliveryForChannel(entry.delivery, entry.channelId));
|
|
104
|
+
// A session is scoped to one peer: never silently pick an arbitrary Owner.
|
|
105
|
+
if (!entries.length || (!owner && new Set(entries.map(entry => entry.channelId)).size !== 1))
|
|
78
106
|
return false;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return outbox.replaceIfRouteMatches(aid, entry, {
|
|
82
|
-
...entry,
|
|
83
|
-
context: {
|
|
84
|
-
...(entry.context ?? {}),
|
|
85
|
-
sessionId,
|
|
86
|
-
},
|
|
87
|
-
}) === 'replaced';
|
|
107
|
+
return entries.every(entry => entry.context?.sessionId === sessionId
|
|
108
|
+
|| outbox.replaceIfRouteMatches(normalizedAid, entry, { ...entry, context: { ...(entry.context ?? {}), sessionId } }) === 'replaced');
|
|
88
109
|
}
|
|
@@ -52,32 +52,38 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
52
52
|
reloaded: false,
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
55
|
+
const pendingOwners = welcome?.pendingPostBootstrapWelcomeOwners?.();
|
|
56
|
+
const sessionOwners = pendingOwners?.length ? pendingOwners : [undefined];
|
|
57
|
+
for (const owner of sessionOwners) {
|
|
58
|
+
let ownerSession;
|
|
59
|
+
try {
|
|
60
|
+
ownerSession = await sessions.ensurePostBootstrapMainSession(owner);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
return {
|
|
64
|
+
ok: false,
|
|
65
|
+
code: 'MAIN_SESSION_CREATE_FAILED',
|
|
66
|
+
error: e instanceof Error ? e.message : `Failed to create the post-bootstrap main session for ${aid}`,
|
|
67
|
+
reloaded: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (!ownerSession.sessionId) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
code: 'MAIN_SESSION_CREATE_FAILED',
|
|
74
|
+
error: `Failed to create the post-bootstrap main session for ${aid}`,
|
|
75
|
+
reloaded: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if (welcomePending && welcome && !await welcome.bindPostBootstrapWelcomeToSession(ownerSession.sessionId, owner)) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
code: 'WELCOME_SESSION_BIND_FAILED',
|
|
82
|
+
error: `Failed to bind the post-bootstrap welcome to session ${ownerSession.sessionId}`,
|
|
83
|
+
reloaded: false,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
mainSession ??= ownerSession;
|
|
81
87
|
}
|
|
82
88
|
}
|
|
83
89
|
const result = service.completeBootstrap(aid);
|
|
@@ -13,10 +13,11 @@ function defaultTypeConfig() {
|
|
|
13
13
|
return { mode: 'inherit', overrides: {} };
|
|
14
14
|
}
|
|
15
15
|
function resolveBaseagent(input) {
|
|
16
|
-
|
|
16
|
+
const value = input.baseagent
|
|
17
17
|
|| input.sessionBaseagent
|
|
18
|
-
|| input.config?.active_baseagent
|
|
19
|
-
|
|
18
|
+
|| input.config?.active_baseagent;
|
|
19
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
20
|
+
return normalized || undefined;
|
|
20
21
|
}
|
|
21
22
|
export function resolveCapabilityContext(input) {
|
|
22
23
|
const aid = input.aid || input.config?.aid;
|
|
@@ -25,9 +26,12 @@ export function resolveCapabilityContext(input) {
|
|
|
25
26
|
const projectPath = input.config?.projects?.defaultPath || input.projectPath || input.sessionProjectPath || null;
|
|
26
27
|
if (!projectPath)
|
|
27
28
|
return { error: '无法解析当前 agent projectPath', code: 'NO_PROJECT' };
|
|
29
|
+
const baseagent = resolveBaseagent(input);
|
|
30
|
+
if (!baseagent)
|
|
31
|
+
return { error: '无法解析当前 agent 的 baseagent', code: 'BASEAGENT_REQUIRED' };
|
|
28
32
|
return {
|
|
29
33
|
aid,
|
|
30
|
-
baseagent
|
|
34
|
+
baseagent,
|
|
31
35
|
projectPath,
|
|
32
36
|
};
|
|
33
37
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os from 'os';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { execCodexCliSync } from '../../../
|
|
3
|
+
import { execCodexCliSync } from '../../../agents/baseagent.js';
|
|
4
4
|
import { discoverSkillDirectories } from '../skill-discovery.js';
|
|
5
5
|
function discoverSkills(ctx) {
|
|
6
6
|
const roots = [
|