evolcore 0.0.26 → 0.0.28
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 +36 -0
- package/bin/codex-managed-acl.ps1 +43 -0
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +10 -5
- package/dist/agents/claude-runner.js +123 -22
- package/dist/agents/codex/app-server-client.js +70 -26
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex-runner.js +363 -421
- package/dist/agents/ecagent-runner.js +170 -25
- package/dist/agents/gemini-runner.js +6 -0
- package/dist/agents/runner-types.js +50 -2
- package/dist/aun/aid/agentmd.js +73 -31
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +3 -3
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +161 -38
- package/dist/aun/{menu-client.js → menu/client.js} +13 -7
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +84 -18
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +13 -8
- package/dist/aun/msg/upload.js +43 -88
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +544 -239
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +108 -6
- package/dist/cli/agent-create.js +515 -2
- package/dist/cli/agent.js +109 -8
- package/dist/cli/aun-commands.js +191 -42
- package/dist/cli/config.js +8 -5
- package/dist/cli/contact.js +2 -2
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +111 -162
- package/dist/cli/diag.js +3 -3
- package/dist/cli/fs-command.js +3 -3
- package/dist/cli/handoff-command.js +6 -6
- package/dist/cli/index.js +8 -2
- package/dist/cli/init.js +34 -1
- package/dist/cli/managed-command-guard.js +2 -1
- package/dist/cli/menu-client.js +13 -5
- package/dist/cli/model.js +3 -3
- package/dist/cli/queue-command.js +2 -2
- package/dist/cli/response.js +2 -2
- package/dist/cli/restart-monitor.js +81 -19
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +20 -10
- package/dist/config/builtin-roles.js +10 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +20 -5
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +1 -1
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +5 -0
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +34 -38
- package/dist/core/auth/operation-authorizer.js +67 -5
- package/dist/core/auth/operation-catalog.js +110 -0
- package/dist/core/auth/remote-access-store.js +115 -9
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +110 -19
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +105 -40
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +34 -4
- package/dist/core/command/menu-handler.js +364 -96
- package/dist/core/command/menu-protocol.js +43 -6
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-handler.js +61 -37
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +94 -16
- package/dist/core/message/message-bridge.js +140 -13
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +73 -41
- package/dist/core/message/response-engine.js +729 -118
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +76 -36
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +72 -3
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +8 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +38 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +322 -207
- package/dist/ipc.js +141 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +3 -0
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-utils.js +40 -2
- package/dist/utils/logger.js +23 -13
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +174 -1
- package/dist/utils/windows-shell-trust.js +37 -0
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/INDEX.md +0 -6
- package/kits/docs/channels/aun.md +23 -2
- package/kits/docs/channels/feishu.md +1 -1
- package/kits/docs/context-assembly.md +29 -17
- package/kits/docs/evolcore/INDEX.md +8 -3
- package/kits/docs/evolcore/agent-create.md +39 -7
- package/kits/docs/evolcore/agent.md +33 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/config.md +40 -1
- package/kits/docs/evolcore/group-collaboration.md +1 -1
- package/kits/docs/evolcore/group.md +117 -2
- package/kits/docs/evolcore/menu-client.md +16 -0
- package/kits/docs/evolcore/msg.md +3 -0
- package/kits/docs/evolcore/storage.md +3 -0
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +51 -3
- package/kits/docs/venues/group.md +5 -0
- package/kits/eck_manifest.json +27 -0
- package/kits/rules/01-overview.md +11 -7
- package/kits/rules/04-relation.md +2 -1
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +6 -4
- package/kits/schemas/agent-config.schema.12.json +25 -1
- package/kits/schemas/daemon.schema.6.json +2 -2
- package/kits/schemas/defaults.schema.5.json +1 -1
- package/kits/schemas/relation-config.schema.1.json +1 -1
- package/kits/schemas/relation-config.schema.5.json +1 -1
- package/kits/schemas/role-config.schema.1.json +14 -0
- package/kits/templates/roles/member.json +5 -0
- package/kits/templates/roles/visitor.json +5 -0
- package/kits/templates/system-fragments/baseagent.md +1 -1
- package/kits/templates/system-fragments/bootstrap.md +26 -9
- package/kits/templates/system-fragments/channel.md +8 -44
- package/kits/templates/system-fragments/commands.md +10 -2
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/reply.md +56 -0
- package/package.json +7 -3
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import { loadAgent } from '../config-store.js';
|
|
3
|
+
import { resolveAgentLifecycle } from '../config/lifecycle.js';
|
|
2
4
|
import { agentMdPath, resolvePaths } from '../paths.js';
|
|
3
5
|
import { parseAgentDisplayName, resolveAgentDisplayName } from '../aun/aid/agentmd.js';
|
|
4
|
-
import { generateWelcomeMessage } from '../utils/welcome.js';
|
|
6
|
+
import { generateWelcomeMessage, parseAgentWelcomeMetadata, readAgentWelcomeTemplate, renderPostBootstrapWelcomeMessage, } from '../utils/welcome.js';
|
|
5
7
|
import * as outbox from '../aun/outbox.js';
|
|
6
8
|
import { chatDirPath } from './session/session-fs-store.js';
|
|
7
|
-
import { hasMessageLogOperation } from './message/message-log.js';
|
|
9
|
+
import { hasMessageLogOperation, findMessageLogOperationMessageId } from './message/message-log.js';
|
|
8
10
|
import { isDeliveryTarget, sameDeliveryTarget } from './message/message-utils.js';
|
|
9
11
|
export const BOOTSTRAP_MESSAGE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
10
12
|
export const BOOTSTRAP_NOTIFICATION_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
@@ -32,10 +34,27 @@ export function isPostBootstrapWelcomeOperationId(operationId, aid) {
|
|
|
32
34
|
export function renderPostBootstrapWelcome(aid, owner, ownerName) {
|
|
33
35
|
const mdPath = agentMdPath(aid);
|
|
34
36
|
const agentMd = fs.existsSync(mdPath) ? fs.readFileSync(mdPath, 'utf-8') : '';
|
|
35
|
-
const
|
|
37
|
+
const metadata = parseAgentWelcomeMetadata(agentMd);
|
|
38
|
+
const agentName = metadata.name || parseAgentDisplayName(agentMd)
|
|
36
39
|
|| resolveAgentDisplayName(aid)
|
|
37
40
|
|| aid.split('.')[0];
|
|
38
41
|
const fallbackOwnerName = owner.replace(/^@/, '').split('.')[0];
|
|
42
|
+
const template = readAgentWelcomeTemplate(aid);
|
|
43
|
+
if (template) {
|
|
44
|
+
return renderPostBootstrapWelcomeMessage({
|
|
45
|
+
template,
|
|
46
|
+
agentName,
|
|
47
|
+
agentDescription: metadata.description,
|
|
48
|
+
agentAid: aid,
|
|
49
|
+
agentTags: metadata.tags,
|
|
50
|
+
ownerName: ownerName || fallbackOwnerName,
|
|
51
|
+
ownerAid: owner,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
const config = loadAgent(aid);
|
|
55
|
+
if (config && resolveAgentLifecycle(config) === 'bootstrapping' && config.initialization?.mode !== 'supplied') {
|
|
56
|
+
throw new Error('WELCOME_REQUIRED: Owner-confirmed welcome.md is required before activation');
|
|
57
|
+
}
|
|
39
58
|
return generateWelcomeMessage({
|
|
40
59
|
channelType: 'aun',
|
|
41
60
|
agentName,
|
|
@@ -49,15 +68,18 @@ export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName, deliver
|
|
|
49
68
|
const legacyOperationId = postBootstrapWelcomeOperationId(aid);
|
|
50
69
|
if (hasMessageLogOperation(chatDir, operationId) || hasMessageLogOperation(chatDir, legacyOperationId))
|
|
51
70
|
return;
|
|
52
|
-
const legacy = outbox.findByDedupeKey(aid, legacyOperationId);
|
|
71
|
+
const legacy = outbox.findByDedupeKey(aid, legacyOperationId, { includeTerminal: true });
|
|
53
72
|
if (legacy?.channelId === owner)
|
|
54
73
|
return;
|
|
55
|
-
const existing = outbox.findByDedupeKey(aid, operationId);
|
|
74
|
+
const existing = outbox.findByDedupeKey(aid, operationId, { includeTerminal: true });
|
|
56
75
|
if (existing
|
|
57
76
|
&& existing.channelId === owner
|
|
58
77
|
&& isDeliveryTarget(existing.delivery)
|
|
59
78
|
&& sameDeliveryTarget(existing.delivery, delivery))
|
|
60
79
|
return;
|
|
80
|
+
// Render before touching an existing route record: malformed content must not
|
|
81
|
+
// remove the only durable record of an earlier attempt.
|
|
82
|
+
const text = renderPostBootstrapWelcome(aid, owner, ownerName);
|
|
61
83
|
if (existing)
|
|
62
84
|
outbox.remove(aid, existing.id);
|
|
63
85
|
outbox.enqueue(aid, {
|
|
@@ -66,7 +88,7 @@ export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName, deliver
|
|
|
66
88
|
dedupeKey: operationId,
|
|
67
89
|
critical: true,
|
|
68
90
|
type: 'text',
|
|
69
|
-
text
|
|
91
|
+
text,
|
|
70
92
|
ttl: BOOTSTRAP_MESSAGE_TTL_MS,
|
|
71
93
|
context: {
|
|
72
94
|
delivery,
|
|
@@ -79,6 +101,43 @@ export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName, deliver
|
|
|
79
101
|
},
|
|
80
102
|
});
|
|
81
103
|
}
|
|
104
|
+
/** Read durable evidence, including failures and already accepted operations. */
|
|
105
|
+
export function postBootstrapWelcomeStatus(aid, owners) {
|
|
106
|
+
const entries = findPostBootstrapWelcomeOutbox(aid, { includeTerminal: true });
|
|
107
|
+
return {
|
|
108
|
+
deliveries: Array.from(new Set(owners)).map(owner => {
|
|
109
|
+
const operationId = postBootstrapWelcomeOperationId(aid, owner);
|
|
110
|
+
const chatDir = chatDirPath(resolvePaths().sessionsDir, 'aun', owner, aid);
|
|
111
|
+
const loggedId = findMessageLogOperationMessageId(chatDir, operationId)
|
|
112
|
+
?? findMessageLogOperationMessageId(chatDir, postBootstrapWelcomeOperationId(aid));
|
|
113
|
+
const entry = entries.find(candidate => candidate.channelId === owner
|
|
114
|
+
&& candidate.delivery?.chatType === 'private'
|
|
115
|
+
&& (candidate.dedupeKey === operationId || candidate.dedupeKey === postBootstrapWelcomeOperationId(aid)));
|
|
116
|
+
const base = { owner, operationId, ...(entry ? { outboxId: entry.id } : {}) };
|
|
117
|
+
if (loggedId)
|
|
118
|
+
return { ...base, status: 'sent', messageId: loggedId };
|
|
119
|
+
if (!entry)
|
|
120
|
+
return { ...base, status: 'not_prepared' };
|
|
121
|
+
const state = outbox.deliveryState(aid, entry.id);
|
|
122
|
+
if (state.status === 'sent' || state.status === 'failed')
|
|
123
|
+
return { ...base, ...state };
|
|
124
|
+
if (state.status === 'missing')
|
|
125
|
+
return { ...base, status: 'not_prepared' };
|
|
126
|
+
return { ...base, status: 'queued', error: entry.lastError, code: entry.lastErrorCode };
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Supersede unsent setup prompts when the agent becomes active. Keep diagnostic evidence. */
|
|
131
|
+
export function cancelPendingBootstrapPrompts(aid) {
|
|
132
|
+
for (const entry of outbox.findByDedupePrefix(aid, bootstrapInitialMessageOperationPrefix(aid))) {
|
|
133
|
+
if (entry.deliveryReceipt)
|
|
134
|
+
continue;
|
|
135
|
+
outbox.markTerminal(aid, entry.id, {
|
|
136
|
+
code: 'BOOTSTRAP_SUPERSEDED',
|
|
137
|
+
error: 'Bootstrap is complete; the initial prompt is no longer needed',
|
|
138
|
+
}, entry);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
82
141
|
export function hasPendingPostBootstrapWelcomeOutbox(aid) {
|
|
83
142
|
return findPostBootstrapWelcomeOutbox(aid)
|
|
84
143
|
.some(entry => outbox.isDeliveryForChannel(entry.delivery, entry.channelId));
|
|
@@ -92,7 +151,7 @@ export function findPostBootstrapWelcomeOutbox(aid, opts = {}) {
|
|
|
92
151
|
}
|
|
93
152
|
export function pendingPostBootstrapWelcomeOwners(aid) {
|
|
94
153
|
return findPostBootstrapWelcomeOutbox(aid)
|
|
95
|
-
.filter(entry => outbox.isDeliveryForChannel(entry.delivery, entry.channelId))
|
|
154
|
+
.filter(entry => !entry.context?.sessionId && outbox.isDeliveryForChannel(entry.delivery, entry.channelId))
|
|
96
155
|
.map(entry => entry.channelId)
|
|
97
156
|
.filter((owner, index, all) => all.indexOf(owner) === index);
|
|
98
157
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { hasSuppliedInitialization } from '../cli/agent-create.js';
|
|
1
2
|
import fs from 'fs';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { randomBytes } from 'crypto';
|
|
4
5
|
import { kitsTemplatesDir, agentMdPath, resolvePaths } from '../paths.js';
|
|
5
6
|
import { buildInitialAgentMd, resolveAgentDisplayName } from '../aun/aid/agentmd.js';
|
|
6
7
|
import { logger } from '../utils/logger.js';
|
|
8
|
+
import { readAgentWelcomeTemplate } from '../utils/welcome.js';
|
|
7
9
|
import { loadAgent, saveAgent } from '../config-store.js';
|
|
8
10
|
import { resolveAgentLifecycle, withLifecycleForWrite } from '../config/lifecycle.js';
|
|
9
11
|
import { renderTemplate } from '../eck/manifest-engine.js';
|
|
10
12
|
import { activeBaseagent } from './model/config-scope.js';
|
|
11
13
|
import { buildEnvelope } from './message/message-utils.js';
|
|
12
|
-
import { BOOTSTRAP_MESSAGE_TTL_MS, BOOTSTRAP_NOTIFICATION_WINDOW_MS, bootstrapInitialMessageOperationId, bootstrapInitialMessageOperationPrefix, bootstrapInitialRetryOperationId, } from './bootstrap-messages.js';
|
|
14
|
+
import { BOOTSTRAP_MESSAGE_TTL_MS, BOOTSTRAP_NOTIFICATION_WINDOW_MS, bootstrapInitialMessageOperationId, bootstrapInitialMessageOperationPrefix, bootstrapInitialRetryOperationId, cancelPendingBootstrapPrompts, postBootstrapWelcomeStatus, } from './bootstrap-messages.js';
|
|
13
15
|
import { findLatestMessageLogOperation } from './message/message-log.js';
|
|
14
16
|
import * as outbox from '../aun/outbox.js';
|
|
15
17
|
import { chatDirPath } from './session/session-fs-store.js';
|
|
@@ -21,6 +23,21 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
21
23
|
return { ...result, reloaded: false };
|
|
22
24
|
}
|
|
23
25
|
if (lifecycle === 'bootstrapping') {
|
|
26
|
+
// Existing per-Owner records are immutable retry snapshots. New interactive
|
|
27
|
+
// Bootstrap completions require the text saved after Owner confirmation.
|
|
28
|
+
const config = loadAgent(aid);
|
|
29
|
+
const deliveries = config?.owners?.length ? postBootstrapWelcomeStatus(aid, config.owners).deliveries : [];
|
|
30
|
+
const alreadyPrepared = deliveries.length > 0 && deliveries.every(delivery => delivery.status !== 'not_prepared');
|
|
31
|
+
if (config?.initialization?.mode !== 'supplied' && !alreadyPrepared) {
|
|
32
|
+
try {
|
|
33
|
+
if (readAgentWelcomeTemplate(aid) === null) {
|
|
34
|
+
return { ok: false, code: 'WELCOME_REQUIRED', error: '请先在 Bootstrap 对话中生成欢迎文案,经 Owner 确认后保存 welcome.md', reloaded: false };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return { ok: false, code: 'WELCOME_INVALID', error: error instanceof Error ? error.message : String(error), reloaded: false };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
24
41
|
if (!welcome) {
|
|
25
42
|
return {
|
|
26
43
|
ok: false,
|
|
@@ -41,7 +58,9 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
41
58
|
const welcomePending = welcome
|
|
42
59
|
? await welcome.hasPendingPostBootstrapWelcome()
|
|
43
60
|
: false;
|
|
44
|
-
const
|
|
61
|
+
const pendingOwners = welcome?.pendingPostBootstrapWelcomeOwners?.();
|
|
62
|
+
const needsMainSessionBoundary = lifecycle === 'bootstrapping'
|
|
63
|
+
|| (welcomePending && (pendingOwners === undefined || pendingOwners.length > 0));
|
|
45
64
|
let mainSession;
|
|
46
65
|
if (needsMainSessionBoundary) {
|
|
47
66
|
if (!sessions) {
|
|
@@ -52,7 +71,6 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
52
71
|
reloaded: false,
|
|
53
72
|
};
|
|
54
73
|
}
|
|
55
|
-
const pendingOwners = welcome?.pendingPostBootstrapWelcomeOwners?.();
|
|
56
74
|
const sessionOwners = pendingOwners?.length ? pendingOwners : [undefined];
|
|
57
75
|
for (const owner of sessionOwners) {
|
|
58
76
|
let ownerSession;
|
|
@@ -98,11 +116,27 @@ export async function completeBootstrapWithWelcome(service, aid, welcome, sessio
|
|
|
98
116
|
mainSessionCreated: mainSession?.created,
|
|
99
117
|
};
|
|
100
118
|
}
|
|
101
|
-
|
|
119
|
+
let welcomeResult;
|
|
120
|
+
try {
|
|
121
|
+
welcomeResult = await welcome.reconcilePostBootstrapWelcome();
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
125
|
+
logger.warn(`[Bootstrap] Completion committed; welcome reconciliation failed for ${aid}: ${message}`);
|
|
126
|
+
welcomeResult = { deliveries: [], error: message };
|
|
127
|
+
try {
|
|
128
|
+
welcomeResult = { ...postBootstrapWelcomeStatus(aid, loadAgent(aid)?.owners ?? []), error: message };
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// A local store failure must not turn an already committed lifecycle
|
|
132
|
+
// transition into a reported activation failure.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
102
135
|
return {
|
|
103
136
|
...result,
|
|
104
137
|
reloaded: true,
|
|
105
|
-
welcomeQueued,
|
|
138
|
+
welcomeQueued: welcomeResult.deliveries.some(delivery => delivery.status === 'queued'),
|
|
139
|
+
welcome: welcomeResult,
|
|
106
140
|
mainSessionId: mainSession?.sessionId,
|
|
107
141
|
mainSessionCreated: mainSession?.created,
|
|
108
142
|
};
|
|
@@ -123,11 +157,15 @@ export class BootstrapService {
|
|
|
123
157
|
const aid = agent?.aid || ctx.agentAid;
|
|
124
158
|
if (!aid)
|
|
125
159
|
return false;
|
|
160
|
+
if (hasSuppliedInitialization(aid) || loadAgent(aid)?.initialization)
|
|
161
|
+
return false;
|
|
126
162
|
const key = aid;
|
|
127
163
|
if (this.inFlight.has(key))
|
|
128
164
|
return false;
|
|
129
165
|
this.inFlight.add(key);
|
|
130
166
|
let lifecycleStarted = false;
|
|
167
|
+
let notificationPersisted = false;
|
|
168
|
+
let attemptedOperationId;
|
|
131
169
|
const loadedConfig = loadAgent(aid) || agent?.config;
|
|
132
170
|
if (!loadedConfig) {
|
|
133
171
|
this.inFlight.delete(key);
|
|
@@ -180,13 +218,18 @@ export class BootstrapService {
|
|
|
180
218
|
const operationId = starting && !notificationState.hasCompletedHistory
|
|
181
219
|
? bootstrapInitialMessageOperationId(aid)
|
|
182
220
|
: bootstrapInitialRetryOperationId(aid);
|
|
183
|
-
const shouldSend = !notificationState.recentlyNotified;
|
|
221
|
+
const shouldSend = !notificationState.recentlyNotified && !notificationState.pending;
|
|
222
|
+
if (notificationState.failure) {
|
|
223
|
+
logger.warn(`[Bootstrap] Initial notification terminated: ${notificationState.failure}; failure retained`);
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
184
226
|
if (starting) {
|
|
185
227
|
await this.publishAgentMdIfSupported(ctx.adapter, aid, agentName);
|
|
186
228
|
this.setLifecycle(agent, aid, 'bootstrapping');
|
|
187
229
|
lifecycleStarted = true;
|
|
188
230
|
}
|
|
189
231
|
if (shouldSend) {
|
|
232
|
+
attemptedOperationId = operationId;
|
|
190
233
|
const text = this.renderWelcome({
|
|
191
234
|
agentAid: aid,
|
|
192
235
|
agentName,
|
|
@@ -194,7 +237,7 @@ export class BootstrapService {
|
|
|
194
237
|
channel: channelType || ctx.channelKey,
|
|
195
238
|
baseagent,
|
|
196
239
|
});
|
|
197
|
-
await ctx.adapter.send(buildEnvelope({
|
|
240
|
+
const receipt = await ctx.adapter.send(buildEnvelope({
|
|
198
241
|
taskId: `bootstrap-${randomBytes(5).toString('hex')}`,
|
|
199
242
|
operationId,
|
|
200
243
|
channel: ctx.adapter.channelKey || ctx.adapter.channelName,
|
|
@@ -211,7 +254,26 @@ export class BootstrapService {
|
|
|
211
254
|
},
|
|
212
255
|
},
|
|
213
256
|
}), { kind: 'result.text', text, isFinal: true });
|
|
214
|
-
|
|
257
|
+
const persisted = channelType === 'aun'
|
|
258
|
+
? outbox.findByDedupeKey(aid, operationId, { includeTerminal: true }) : undefined;
|
|
259
|
+
notificationPersisted = !!persisted;
|
|
260
|
+
if (receipt?.status === 'sent' && receipt.messageId?.trim()) {
|
|
261
|
+
this.notifiedInProcess.set(aid, Date.now());
|
|
262
|
+
}
|
|
263
|
+
else if (receipt?.status === 'queued' && receipt.outboxId
|
|
264
|
+
&& (channelType !== 'aun' || (persisted?.id === receipt.outboxId && !persisted.terminal))) {
|
|
265
|
+
logger.info(`[Bootstrap] Initial notification queued: aid=${aid} outbox=${receipt.outboxId}`);
|
|
266
|
+
}
|
|
267
|
+
else if (!receipt && channelType !== 'aun') {
|
|
268
|
+
// Legacy non-AUN adapters have not all migrated to SendReceipt.
|
|
269
|
+
logger.info(`[Bootstrap] Legacy adapter accepted notification for ${aid} without a receipt`);
|
|
270
|
+
this.notifiedInProcess.set(aid, Date.now());
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
const error = receipt?.status === 'failed' ? receipt.error
|
|
274
|
+
: receipt?.status === 'suppressed' ? receipt.reason : 'missing valid send receipt';
|
|
275
|
+
throw new Error(error);
|
|
276
|
+
}
|
|
215
277
|
}
|
|
216
278
|
if (starting) {
|
|
217
279
|
this.eventBus.publish({ type: 'agent:bootstrap-started', aid, channel: channelType || ctx.channelKey, timestamp: Date.now() });
|
|
@@ -221,12 +283,24 @@ export class BootstrapService {
|
|
|
221
283
|
logger.info(`[Bootstrap] Reconciled initial message for ${aid} via ${ctx.channelKey} (${ctx.source})`);
|
|
222
284
|
}
|
|
223
285
|
else {
|
|
224
|
-
logger.debug(`[Bootstrap] Initial message already
|
|
286
|
+
logger.debug(`[Bootstrap] Initial message already accepted or pending for ${aid}`);
|
|
225
287
|
}
|
|
226
288
|
return true;
|
|
227
289
|
}
|
|
228
290
|
catch (e) {
|
|
229
|
-
if (
|
|
291
|
+
if (channelType === 'aun' && attemptedOperationId) {
|
|
292
|
+
try {
|
|
293
|
+
notificationPersisted ||= !!outbox.findByDedupeKey(aid, attemptedOperationId, { includeTerminal: true });
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
logger.warn(`[Bootstrap] Cannot inspect persisted notification for ${aid}: ${error}`);
|
|
297
|
+
// Its absence is not proven. Preserve the started lifecycle.
|
|
298
|
+
notificationPersisted = true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// A persisted operation owns delivery recovery. Do not reset the setup
|
|
302
|
+
// lifecycle merely because its network attempt or receipt failed.
|
|
303
|
+
if (lifecycleStarted && !notificationPersisted) {
|
|
230
304
|
try {
|
|
231
305
|
this.setLifecycle(agent, aid, 'created');
|
|
232
306
|
}
|
|
@@ -257,6 +331,13 @@ export class BootstrapService {
|
|
|
257
331
|
};
|
|
258
332
|
}
|
|
259
333
|
this.setLifecycle(agent, aid, 'active');
|
|
334
|
+
try {
|
|
335
|
+
cancelPendingBootstrapPrompts(aid);
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
// Delivery also checks lifecycle immediately before sending a prompt.
|
|
339
|
+
logger.warn(`[Bootstrap] Failed to cancel stale prompts for ${aid}: ${error}`);
|
|
340
|
+
}
|
|
260
341
|
this.eventBus.publish({ type: 'agent:bootstrap-complete', aid, timestamp: Date.now() });
|
|
261
342
|
logger.info(`[Bootstrap] Completed for ${aid} (previous lifecycle=${lifecycle})`);
|
|
262
343
|
return { ok: true, aid, transitioned: true };
|
|
@@ -341,26 +422,36 @@ export class BootstrapService {
|
|
|
341
422
|
catch {
|
|
342
423
|
// A missing or malformed session path must not prevent bootstrap.
|
|
343
424
|
}
|
|
425
|
+
let pending = false;
|
|
426
|
+
let failure;
|
|
427
|
+
let hasCompletedHistory = !!latestLoggedOperationId;
|
|
344
428
|
for (const entry of outbox.findByDedupePrefix(input.aid, prefix, { includeTerminal: true })) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
outbox.remove(input.aid, entry.id);
|
|
429
|
+
if (entry.dedupeKey === latestLoggedOperationId) {
|
|
430
|
+
// The log proves gateway acceptance, including pre-migration records.
|
|
431
|
+
if (!entry.deliveryResult && !entry.deliveryReceipt)
|
|
432
|
+
outbox.remove(input.aid, entry.id);
|
|
350
433
|
continue;
|
|
351
434
|
}
|
|
352
|
-
if (entry.
|
|
353
|
-
outbox.remove(input.aid, entry.id);
|
|
435
|
+
if (entry.channelId !== input.channelId || entry.delivery?.chatType !== 'private')
|
|
354
436
|
continue;
|
|
437
|
+
if (entry.deliveryResult || entry.deliveryReceipt) {
|
|
438
|
+
hasCompletedHistory = true;
|
|
439
|
+
latestTs = Math.max(latestTs, entry.deliveryResult?.at ?? entry.deliveryReceipt?.acceptedAt ?? entry.ts);
|
|
440
|
+
}
|
|
441
|
+
else if (entry.terminal) {
|
|
442
|
+
failure = entry.terminal.error;
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
// Pending operations do not expire at the reminder window boundary.
|
|
446
|
+
pending = true;
|
|
355
447
|
}
|
|
356
|
-
latestTs = Math.max(latestTs, entry.ts || 0);
|
|
357
448
|
}
|
|
358
449
|
const recentlyNotified = latestTs >= cutoff;
|
|
359
450
|
if (recentlyNotified)
|
|
360
451
|
this.notifiedInProcess.set(input.aid, latestTs);
|
|
361
452
|
else
|
|
362
453
|
this.notifiedInProcess.delete(input.aid);
|
|
363
|
-
return { recentlyNotified, hasCompletedHistory
|
|
454
|
+
return { recentlyNotified, hasCompletedHistory, pending, failure };
|
|
364
455
|
}
|
|
365
456
|
async publishAgentMdIfSupported(adapter, aid, fallbackName) {
|
|
366
457
|
if (typeof adapter.uploadAgentMd !== 'function')
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { agentFullAccessStatus, agentFullAccessWriteError } from '../role/runtime-policy.js';
|
|
2
|
+
import { initializationSummary } from '../../cli/agent-create.js';
|
|
1
3
|
import { agentDelete, agentEnable, agentDisable, agentList, agentShow, agentSet, agentReload, } from '../../cli/agent.js';
|
|
2
4
|
import { agentCreateNonInteractive } from '../../cli/agent-create.js';
|
|
3
5
|
import { logger } from '../../utils/logger.js';
|
|
@@ -10,7 +12,7 @@ import { uploadAvatar, uploadAvatarUrl } from '../../utils/avatar-upload.js';
|
|
|
10
12
|
import { agentmdGet, agentmdPut, updateAgentMdFrontmatterName } from '../../aun/aid/agentmd.js';
|
|
11
13
|
import { isValidAid } from '../../aun/aid/validation.js';
|
|
12
14
|
import { isSupportedBaseagent } from '../../agents/baseagent.js';
|
|
13
|
-
const SUPPORTED_AGENT_PATCH_FIELDS = new Set(['aid', 'name', 'active_baseagent', 'baseagents', 'projects', 'owners', 'chatmode', 'channels', 'channelOwners']);
|
|
15
|
+
const SUPPORTED_AGENT_PATCH_FIELDS = new Set(['aid', 'name', 'avatar', 'active_baseagent', 'baseagents', 'projects', 'owners', 'fullaccess', 'chatmode', 'channels', 'channelOwners']);
|
|
14
16
|
const HIDDEN_VALUE = '[hidden]';
|
|
15
17
|
const SENSITIVE_CONFIG_KEYS = new Set([
|
|
16
18
|
'apikey',
|
|
@@ -413,8 +415,29 @@ async function runCreateInBackground(opts, w, service) {
|
|
|
413
415
|
/** name=agent 的 menu.action 执行。create 使用显式 owner AID;peerId 仅作为控制面鉴权主体。
|
|
414
416
|
* create 受理即返回(D3);delete/enable/disable 同步等结果。
|
|
415
417
|
* 调用方负责传入已兜底的 args.project(见 command-handler 装配)。 */
|
|
416
|
-
export async function execAgentAction(action, args, peerId, eventBus, service) {
|
|
418
|
+
export async function execAgentAction(action, args, peerId, eventBus, service, subject) {
|
|
417
419
|
const a = args ?? {};
|
|
420
|
+
if (action === 'initialize') {
|
|
421
|
+
if (!service?.initialization)
|
|
422
|
+
return { error: '初始化服务不可用', code: 'NOT_CONFIGURED' };
|
|
423
|
+
const plan = a.plan && typeof a.plan === 'object' ? a.plan : {
|
|
424
|
+
aid: a.aid,
|
|
425
|
+
project: typeof a.project === 'string' ? a.project : '',
|
|
426
|
+
baseagent: a.baseagent,
|
|
427
|
+
owners: Array.isArray(a.owners) ? a.owners : (a.owner ? [a.owner] : []),
|
|
428
|
+
name: a.name,
|
|
429
|
+
description: a.description,
|
|
430
|
+
type: a.type || 'agent',
|
|
431
|
+
tags: a.tags,
|
|
432
|
+
...(typeof a.persona === 'string' ? { persona: a.persona } : {}),
|
|
433
|
+
};
|
|
434
|
+
try {
|
|
435
|
+
return { data: service.initialization.start(plan, peerId, a.dryRun === true) };
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
return { error: error instanceof Error ? error.message : String(error), code: error.code || 'INITIALIZE_FAILED' };
|
|
439
|
+
}
|
|
440
|
+
}
|
|
418
441
|
if (action === 'create') {
|
|
419
442
|
if (!peerId)
|
|
420
443
|
return { error: '缺少发起者 AID(无法校验控制权限)', code: 'INVALID_ARGS' };
|
|
@@ -497,8 +520,22 @@ export async function execAgentAction(action, args, peerId, eventBus, service) {
|
|
|
497
520
|
return { data: { aid: a.aid, reloaded: true } };
|
|
498
521
|
}
|
|
499
522
|
if (action === 'update') {
|
|
500
|
-
const result = await execAgentUpdate(a);
|
|
523
|
+
const result = await execAgentUpdate(a, subject);
|
|
501
524
|
if (!('error' in result)) {
|
|
525
|
+
const data = result.data;
|
|
526
|
+
if (data.avatar) {
|
|
527
|
+
eventBus?.publish({
|
|
528
|
+
type: 'agent:avatar_updated',
|
|
529
|
+
aid: data.aid,
|
|
530
|
+
avatar: data.avatar,
|
|
531
|
+
sha256: data.sha256,
|
|
532
|
+
mime: data.mime,
|
|
533
|
+
width: data.width,
|
|
534
|
+
height: data.height,
|
|
535
|
+
aspectRatio: data.aspectRatio,
|
|
536
|
+
timestamp: Date.now(),
|
|
537
|
+
});
|
|
538
|
+
}
|
|
502
539
|
eventBus?.publish({
|
|
503
540
|
type: 'agent:updated',
|
|
504
541
|
aid: a.aid,
|
|
@@ -514,9 +551,9 @@ export async function execAgentAction(action, args, peerId, eventBus, service) {
|
|
|
514
551
|
* 直接通过 ConfigManager 读写 agent config(不走 agentSet,避免其内部自动 evolagent.reload)——
|
|
515
552
|
* 重载由用户在 Agents 页操作列手动触发(带任务执行检查)。
|
|
516
553
|
* AUN 渠道绑定 agent 顶层 aid,不可通过 patch 编辑:拒绝改 aid、拒绝 channels 数组里出现 aun 条目。
|
|
517
|
-
* 可写字段:name / active_baseagent / baseagents / projects / owners / chatmode / channels(非 aun)/
|
|
554
|
+
* 可写字段:name / avatar(旧版 App 兼容,单独提交 data URL)/ active_baseagent / baseagents / projects / owners / fullaccess / chatmode / channels(非 aun)/
|
|
518
555
|
* channelOwners(按 type/name 局部更新非 AUN channel owners,避免前端回写脱敏 credentials)。 */
|
|
519
|
-
export async function execAgentUpdate(args) {
|
|
556
|
+
export async function execAgentUpdate(args, subject) {
|
|
520
557
|
const a = args ?? {};
|
|
521
558
|
if (!a.aid)
|
|
522
559
|
return { error: '缺少 aid', code: 'INVALID_ARGS' };
|
|
@@ -531,6 +568,9 @@ export async function execAgentUpdate(args) {
|
|
|
531
568
|
if (p.aid !== undefined) {
|
|
532
569
|
return { error: 'aid 不可修改(AUN 身份绑定,如需换 AID 请删除后重建)', code: 'INVALID_ARGS' };
|
|
533
570
|
}
|
|
571
|
+
if (Object.hasOwn(p, 'avatar') && Object.keys(p).length !== 1) {
|
|
572
|
+
return { error: 'avatar 不能与其他 patch 字段同时提交,请拆分为两次 update', code: 'INVALID_ARGS' };
|
|
573
|
+
}
|
|
534
574
|
if (p.name !== undefined) {
|
|
535
575
|
const otherKeys = Object.keys(p).filter(k => k !== 'name');
|
|
536
576
|
if (otherKeys.length > 0) {
|
|
@@ -546,9 +586,12 @@ export async function execAgentUpdate(args) {
|
|
|
546
586
|
const config = cfgRead(ConfigTarget.Agent, { self: a.aid });
|
|
547
587
|
if (!config)
|
|
548
588
|
return { error: `Agent "${a.aid}" not found`, code: 'NOT_FOUND' };
|
|
589
|
+
// Legacy App requests share the canonical validation, storage and agent.md publication flow.
|
|
590
|
+
if (Object.hasOwn(p, 'avatar'))
|
|
591
|
+
return execAidAvatar({ aid: a.aid, data: p.avatar });
|
|
549
592
|
let touched = false;
|
|
550
593
|
const data = { aid: a.aid };
|
|
551
|
-
const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owners !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
|
|
594
|
+
const hasConfigPatch = p.active_baseagent !== undefined || p.baseagents !== undefined || p.projects !== undefined || p.owners !== undefined || p.fullaccess !== undefined || p.chatmode !== undefined || p.channels !== undefined || p.channelOwners !== undefined;
|
|
552
595
|
if (p.active_baseagent !== undefined) {
|
|
553
596
|
if (typeof p.active_baseagent !== 'string' || !p.active_baseagent.trim()) {
|
|
554
597
|
return { error: `无效 active_baseagent: ${JSON.stringify(p.active_baseagent)}(必须是非空字符串)`, code: 'INVALID_ARGS' };
|
|
@@ -596,6 +639,30 @@ export async function execAgentUpdate(args) {
|
|
|
596
639
|
config.owners = owners;
|
|
597
640
|
touched = true;
|
|
598
641
|
}
|
|
642
|
+
if (p.fullaccess !== undefined) {
|
|
643
|
+
if (!p.fullaccess || typeof p.fullaccess !== 'object' || Array.isArray(p.fullaccess)) {
|
|
644
|
+
return { error: 'fullaccess 必须是对象', code: 'INVALID_ARGS' };
|
|
645
|
+
}
|
|
646
|
+
const fullaccess = p.fullaccess;
|
|
647
|
+
if (Object.keys(fullaccess).some(key => key !== 'enabled')) {
|
|
648
|
+
return { error: 'fullaccess 只支持 enabled 字段', code: 'INVALID_ARGS' };
|
|
649
|
+
}
|
|
650
|
+
if (fullaccess.enabled !== undefined && typeof fullaccess.enabled !== 'boolean') {
|
|
651
|
+
return { error: 'fullaccess.enabled 必须是布尔值', code: 'INVALID_ARGS' };
|
|
652
|
+
}
|
|
653
|
+
if (typeof fullaccess.enabled !== 'boolean')
|
|
654
|
+
return { error: 'fullaccess.enabled is required', code: 'INVALID_ARGS' };
|
|
655
|
+
const denied = agentFullAccessWriteError({
|
|
656
|
+
daemonOwner: subject?.isDaemonOwner === true,
|
|
657
|
+
ecwebManagement: subject?.ecwebManagement === true,
|
|
658
|
+
delegated: subject?.canApprovePersistentFullAccess === false || subject?.chatType === 'group',
|
|
659
|
+
enabled: fullaccess.enabled,
|
|
660
|
+
});
|
|
661
|
+
if (denied)
|
|
662
|
+
return { error: denied, code: 'FORBIDDEN' };
|
|
663
|
+
config.fullaccess = { enabled: fullaccess.enabled };
|
|
664
|
+
touched = true;
|
|
665
|
+
}
|
|
599
666
|
if (p.chatmode !== undefined) {
|
|
600
667
|
config.chatmode = p.chatmode;
|
|
601
668
|
touched = true;
|
|
@@ -645,17 +712,20 @@ export function resolveProjectPath(explicit, aid, defaults) {
|
|
|
645
712
|
return deriveAgentProjectPath(root, aid);
|
|
646
713
|
}
|
|
647
714
|
/** name=agent 的 menu.query:查单个 agent 详情,附构建进度(D3)。 */
|
|
648
|
-
export async function execAgentQuery(args, service) {
|
|
715
|
+
export async function execAgentQuery(args, service, subject) {
|
|
649
716
|
const aid = args?.aid;
|
|
650
717
|
if (!aid)
|
|
651
718
|
return { error: '缺少 aid', code: 'INVALID_ARGS' };
|
|
652
719
|
const agentDir = path.join(resolvePaths().agentsDir, aid);
|
|
653
720
|
const progress = readCreateStatus(agentDir);
|
|
721
|
+
const initialization = initializationSummary(aid);
|
|
654
722
|
const res = service
|
|
655
723
|
? await service.show(aid)
|
|
656
724
|
: await agentShow(aid);
|
|
657
725
|
if (!('ok' in res) || res.ok !== true) {
|
|
658
726
|
const code = classifyError(res.error);
|
|
727
|
+
if (code === 'NOT_FOUND' && initialization)
|
|
728
|
+
return { data: { aid, lifecycle: service?.readConfig(aid)?.lifecycle ?? null, initialization } };
|
|
659
729
|
if (code === 'NOT_FOUND' && progress)
|
|
660
730
|
return { data: buildCreateProgressOnlyAgent(aid, progress) };
|
|
661
731
|
return { error: res.error, code };
|
|
@@ -663,8 +733,10 @@ export async function execAgentQuery(args, service) {
|
|
|
663
733
|
const config = cfgRead(ConfigTarget.Agent, { self: aid });
|
|
664
734
|
const safeConfig = buildSafeAgentConfig(config);
|
|
665
735
|
const safeAgentConfig = safeConfig ?? {};
|
|
736
|
+
const fullaccessStatus = agentFullAccessStatus(aid, subject?.principalId ?? subject?.actorId);
|
|
666
737
|
const data = {
|
|
667
738
|
...res,
|
|
739
|
+
...(initialization ? { initialization } : {}),
|
|
668
740
|
config: {
|
|
669
741
|
...(res.config ?? {}),
|
|
670
742
|
active_baseagent: safeAgentConfig.active_baseagent ?? res.config?.baseagent ?? null,
|
|
@@ -673,6 +745,14 @@ export async function execAgentQuery(args, service) {
|
|
|
673
745
|
owners: safeAgentConfig.owners ?? res.config?.owners ?? [],
|
|
674
746
|
},
|
|
675
747
|
safeConfig,
|
|
748
|
+
fullaccessStatus: {
|
|
749
|
+
...fullaccessStatus,
|
|
750
|
+
canConfigure: subject?.ecwebManagement === true
|
|
751
|
+
&& subject?.isDaemonOwner === true
|
|
752
|
+
&& subject.canApprovePersistentFullAccess !== false
|
|
753
|
+
&& subject.chatType !== 'group'
|
|
754
|
+
&& fullaccessStatus.hostEnabled,
|
|
755
|
+
},
|
|
676
756
|
};
|
|
677
757
|
// 叠加构建进度(create 受理后、ready 前可见;ready 后文件仍在,可反映软失败 warn)
|
|
678
758
|
return { data: progress ? { ...data, createProgress: progress } : data };
|
|
@@ -686,6 +766,7 @@ export async function execAgentOptions(args, service) {
|
|
|
686
766
|
name: info.name,
|
|
687
767
|
personalName: info.personalName || null,
|
|
688
768
|
status: info.status || 'stopped',
|
|
769
|
+
lifecycle: info.lifecycle ?? null,
|
|
689
770
|
channels: info.channels || [],
|
|
690
771
|
projectPath: info.projectPath ? toPosix(info.projectPath) : null,
|
|
691
772
|
baseagent: info.baseagent || null,
|