evolcore 0.0.25 → 0.0.27
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 +632 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +203 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +40 -29
- package/bin/install-codex-managed-hooks.mjs +582 -555
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +172 -33
- package/dist/agents/codex/app-server-client.js +76 -31
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +434 -446
- package/dist/agents/ecagent-runner.js +174 -34
- package/dist/agents/gemini-runner.js +8 -7
- package/dist/agents/runner-types.js +75 -19
- package/dist/aun/aid/agentmd.js +151 -36
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +4 -4
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- 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} +162 -39
- package/dist/aun/{menu-client.js → menu/client.js} +85 -6
- 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 +85 -19
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +19 -9
- package/dist/aun/msg/upload.js +43 -80
- 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 +842 -318
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +212 -89
- package/dist/cli/agent-create.js +626 -11
- package/dist/cli/agent.js +125 -13
- package/dist/cli/aun-commands.js +487 -337
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +55 -33
- package/dist/cli/contact.js +72 -15
- package/dist/cli/ctl-command.js +24 -24
- package/dist/cli/daemon-commands.js +140 -63
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +70 -70
- package/dist/cli/handoff-command.js +46 -14
- package/dist/cli/index.js +91 -79
- package/dist/cli/init.js +34 -1
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +5 -1
- package/dist/cli/menu-client.js +51 -32
- package/dist/cli/model.js +3 -3
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +31 -31
- package/dist/cli/response.js +32 -32
- package/dist/cli/restart-monitor.js +103 -42
- package/dist/cli/stats.js +51 -51
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +74 -64
- package/dist/config/builtin-roles.js +11 -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 +160 -0
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +97 -8
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +30 -7
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +7 -1
- 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 +53 -49
- package/dist/core/auth/operation-authorizer.js +90 -7
- package/dist/core/auth/operation-catalog.js +145 -4
- package/dist/core/auth/remote-access-store.js +155 -10
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +111 -20
- 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 +159 -65
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +46 -7
- package/dist/core/command/menu-handler.js +392 -100
- package/dist/core/command/menu-protocol.js +45 -6
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +123 -43
- 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/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +146 -34
- package/dist/core/message/message-bridge.js +163 -20
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +99 -41
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +755 -144
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +112 -41
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +108 -17
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +9 -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 +34 -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 +588 -217
- package/dist/ipc.js +193 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +2 -0
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/price-resolver.js +28 -10
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- 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/cross-platform.js +30 -1
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +61 -2
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +26 -14
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/npm-ops.js +176 -35
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +196 -23
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/agent-harness.js +3 -0
- 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/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +60 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +69 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +379 -367
- 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 +76 -71
- package/kits/docs/evolcore/agent-create.md +202 -165
- package/kits/docs/evolcore/agent.md +99 -67
- package/kits/docs/evolcore/aid.md +68 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +241 -195
- package/kits/docs/evolcore/contact.md +75 -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 +244 -244
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +267 -152
- package/kits/docs/evolcore/menu-client.md +58 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +169 -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 +53 -50
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +623 -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 +269 -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 +42 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +217 -190
- 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 +166 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +76 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +65 -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 +451 -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 +215 -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 +92 -92
- package/kits/templates/roles/member.json +101 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +90 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +53 -34
- package/kits/templates/system-fragments/channel.md +28 -64
- package/kits/templates/system-fragments/commands.md +36 -28
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/reply.md +56 -0
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +104 -98
- 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
|
@@ -28,7 +28,7 @@ import { isSystemControlChannel } from '../system-channels.js';
|
|
|
28
28
|
import { launchMonitorAndConfirm, resolveMonitorLaunch, cleanupMonitorStage } from '../../utils/cross-platform.js';
|
|
29
29
|
import { scanInstances } from '../../utils/instance-registry.js';
|
|
30
30
|
import { inspectDataMigrationRequirement } from '../data-migration.js';
|
|
31
|
-
import { guardIdleCommand, guardKnownCommand, guardRoleCommand, guardThreadCommand, isRecognizedSlashCommand, normalizeSlashContent, probeSessionActivity, } from './slash-gate.js';
|
|
31
|
+
import { guardIdleCommand, guardGroupSlashCommand, guardKnownCommand, guardRoleCommand, guardThreadCommand, isRecognizedSlashCommand, normalizeSlashContent, probeSessionActivity, } from './slash-gate.js';
|
|
32
32
|
const allEfforts = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
33
33
|
const PERMISSION_MODE_KEYS = PUBLIC_PERMISSION_MODES;
|
|
34
34
|
function defaultSlashChatmode(field) {
|
|
@@ -368,7 +368,7 @@ async function getGitWorkingDirInfo(projectPath) {
|
|
|
368
368
|
return null; // git 命令失败时静默返回 null
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
|
-
export async function handleSlashCommand(content, channel, channelId, sendMessage, userId, threadId, chatType, source, messageId, selfAID, overrideIdentity, overrideSubject, replyContext) {
|
|
371
|
+
export async function handleSlashCommand(content, channel, channelId, sendMessage, userId, threadId, chatType, source, messageId, selfAID, overrideIdentity, overrideSubject, replyContext, applyGroupSlashPolicy = false) {
|
|
372
372
|
// 卡片回调的 chatType 不可靠(飞书 bot 单聊 chatId 也是 oc_ 前缀),
|
|
373
373
|
// 不应覆盖 session 中已有的正确值
|
|
374
374
|
if (source === 'card-trigger')
|
|
@@ -434,9 +434,18 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
434
434
|
logger.warn(`[CommandHandler] topic session lookup failed: thread=${threadId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
435
435
|
}
|
|
436
436
|
}
|
|
437
|
-
const activeChatType =
|
|
437
|
+
const activeChatType = (applyGroupSlashPolicy
|
|
438
|
+
? replyContext?.delivery?.chatType || overrideSubject?.chatType || chatType
|
|
439
|
+
: undefined)
|
|
440
|
+
|| topicAuthSession?.chatType
|
|
438
441
|
|| activeSession?.chatType
|
|
439
442
|
|| (chatType === 'group' ? 'group' : 'private');
|
|
443
|
+
const groupSlash = applyGroupSlashPolicy && activeChatType === 'group';
|
|
444
|
+
if (applyGroupSlashPolicy) {
|
|
445
|
+
const groupGuard = guardGroupSlashCommand(normalizedContent, activeChatType);
|
|
446
|
+
if (groupGuard)
|
|
447
|
+
return groupGuard;
|
|
448
|
+
}
|
|
440
449
|
const getExistingSessionForCommand = async () => {
|
|
441
450
|
if (threadId) {
|
|
442
451
|
if (topicAuthSessionLookupFailed)
|
|
@@ -485,7 +494,8 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
485
494
|
|| normalizedContent === '/upgrade'
|
|
486
495
|
|| normalizedContent === '/reload'
|
|
487
496
|
|| normalizedContent.startsWith('/reload ')
|
|
488
|
-
|| normalizedContent === '/pair'
|
|
497
|
+
|| normalizedContent === '/pair'
|
|
498
|
+
|| /^\/diag(?:\s|$)/.test(normalizedContent);
|
|
489
499
|
const roleGuard = guardRoleCommand(normalizedContent, activeChatType, isAdmin || (isDaemonOwner && isProcessLevelSlash));
|
|
490
500
|
if (roleGuard)
|
|
491
501
|
return roleGuard;
|
|
@@ -617,6 +627,30 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
617
627
|
};
|
|
618
628
|
// /help 命令不需要会话
|
|
619
629
|
if (normalizedContent === '/help') {
|
|
630
|
+
if (groupSlash) {
|
|
631
|
+
const lines = [
|
|
632
|
+
'群聊可用命令:',
|
|
633
|
+
' /help - 显示帮助',
|
|
634
|
+
' /status - 显示会话状态',
|
|
635
|
+
' /check - 检查 Agent 健康',
|
|
636
|
+
' /model [current|list|check] - 查询模型或检查网关',
|
|
637
|
+
' /effort - 查看推理强度',
|
|
638
|
+
' /baseagent - 查看 Agent 后端',
|
|
639
|
+
' /perm - 查看权限模式',
|
|
640
|
+
' /mentionmode - 查看群聊 @ 处理模式',
|
|
641
|
+
' /ask <选项> - 回答待处理问题',
|
|
642
|
+
' /pause - 在下一次工具调用前暂停任务',
|
|
643
|
+
' /resume - 继续已暂停的任务',
|
|
644
|
+
' /stop - 中断当前任务',
|
|
645
|
+
...(isAdmin ? [
|
|
646
|
+
' /compact - 压缩会话上下文',
|
|
647
|
+
...(threadId ? [' /renew - 轮换当前话题的后端会话'] : []),
|
|
648
|
+
] : []),
|
|
649
|
+
'',
|
|
650
|
+
'模型、推理强度、后端、权限与 @ 模式在群聊中仅支持查询。',
|
|
651
|
+
];
|
|
652
|
+
return { kind: 'command.result', text: lines.join('\n') };
|
|
653
|
+
}
|
|
620
654
|
const canReadModel = canAccessSlashOperation('model.current', 'relation')
|
|
621
655
|
|| canAccessSlashOperation('model.list', 'relation');
|
|
622
656
|
const canUseModel = canAccessSlashOperation('model.use', 'relation');
|
|
@@ -633,7 +667,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
633
667
|
const appendProcessCommands = (lines) => {
|
|
634
668
|
if (!isDaemonOwner)
|
|
635
669
|
return;
|
|
636
|
-
lines.push('', '🛠️ 进程级运维:', ' /restart - 重启服务', ' /upgrade - 检查版本更新', ' /reload [aid] - 热重载 Agent 配置', ' /fa <提示词> - 单次使用宿主级 fullaccess 执行(别名: /fullaccess)', ' /pair - 获取远程控制配对码');
|
|
670
|
+
lines.push('', '🛠️ 进程级运维:', ' /restart - 重启服务', ' /upgrade - 检查版本更新', ' /reload [aid] - 热重载 Agent 配置', ' /fa <提示词> - 单次使用宿主级 fullaccess 执行(别名: /fullaccess)', ' /pair - 获取远程控制配对码', ' /diag <问题描述> - 邀请远程诊断;/diag stop 撤销授权');
|
|
637
671
|
};
|
|
638
672
|
if (!isAdmin && activeChatType === 'group') {
|
|
639
673
|
const lines = [
|
|
@@ -677,7 +711,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
677
711
|
' /del <名称> - 删除指定会话(仅解绑,不删除文件)',
|
|
678
712
|
...(threadId ? [' /renew - 在当前话题中轮换 backend'] : []),
|
|
679
713
|
' /pause - 在下一次工具调用前暂停当前任务',
|
|
680
|
-
' /resume -
|
|
714
|
+
' /resume - 继续暂停或异常中断的当前任务',
|
|
681
715
|
' /stop - 中断当前任务',
|
|
682
716
|
' /status - 显示会话状态',
|
|
683
717
|
' /check - 检查 EvolAgent 实例健康',
|
|
@@ -727,7 +761,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
727
761
|
' /compact - 压缩会话上下文(减少 token 用量)',
|
|
728
762
|
' /renew - 在话题中轮换 backend(下一条消息懒初始化)',
|
|
729
763
|
' /pause - 在下一次工具调用前暂停当前任务',
|
|
730
|
-
' /resume -
|
|
764
|
+
' /resume - 继续暂停或异常中断的当前任务',
|
|
731
765
|
' /stop - 中断当前任务',
|
|
732
766
|
'',
|
|
733
767
|
'🤖 Agent 与模型:',
|
|
@@ -748,7 +782,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
748
782
|
'🛠️ 运维:',
|
|
749
783
|
' /status - 显示会话状态',
|
|
750
784
|
' /pause - 在下一次工具调用前暂停当前任务',
|
|
751
|
-
' /resume -
|
|
785
|
+
' /resume - 继续暂停或异常中断的当前任务',
|
|
752
786
|
' /stop - 中断当前任务',
|
|
753
787
|
' /check - 检查 EvolAgent 实例健康',
|
|
754
788
|
...(isOwner ? [
|
|
@@ -773,6 +807,14 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
773
807
|
];
|
|
774
808
|
return { kind: 'command.result', text: lines.join('\n') };
|
|
775
809
|
}
|
|
810
|
+
if (/^\/diag(?:\s|$)/.test(normalizedContent)) {
|
|
811
|
+
if (!isDaemonOwner || !userId || !this.diagService)
|
|
812
|
+
return { kind: 'command.error', text: '❌ /diag 需要本机 DaemonOwner 和可用的诊断入口' };
|
|
813
|
+
const problem = content.trim().slice(5).trim();
|
|
814
|
+
const result = await this.diagService.execute(problem.toLowerCase() === 'stop'
|
|
815
|
+
? { action: 'stop' } : { action: 'start', problem }, userId);
|
|
816
|
+
return { kind: result.ok ? 'command.result' : 'command.error', text: result.message };
|
|
817
|
+
}
|
|
776
818
|
// /pair is also recognized on an Agent channel so it cannot fall through
|
|
777
819
|
// into model input. The daemon control channel has its own fast path; this
|
|
778
820
|
// branch preserves the same daemon-owner boundary for ordinary AUN chats.
|
|
@@ -783,15 +825,35 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
783
825
|
text: '❌ /pair 仅限 daemon-owner 使用;请向 daemon 控制 AID 发送 /pair。',
|
|
784
826
|
};
|
|
785
827
|
}
|
|
786
|
-
const pair = remoteAccessService.getPairingCode(userId);
|
|
828
|
+
const pair = remoteAccessService.getPairingCode(userId, Date.now(), 'pair');
|
|
787
829
|
const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
|
|
788
830
|
return {
|
|
789
831
|
kind: 'command.result',
|
|
790
|
-
text: `远程控制配对码:${pair.code}(约 ${mins}
|
|
832
|
+
text: `远程控制配对码:${pair.code}(约 ${mins} 分钟内有效,仅可配对一次)\n可用于 ECWeb 登录或远程 Menu 客户端授权`,
|
|
791
833
|
};
|
|
792
834
|
}
|
|
793
835
|
// /evolhelp 命令:返回 JSON 格式的命令列表(供程序解析)
|
|
794
836
|
if (normalizedContent === '/evolhelp') {
|
|
837
|
+
if (groupSlash) {
|
|
838
|
+
const commands = [
|
|
839
|
+
{ command: '/help', description: '显示帮助信息', category: '帮助', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
840
|
+
{ command: '/status', description: '显示会话状态', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
841
|
+
{ command: '/check', description: '检查 EvolAgent 实例健康', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
842
|
+
{ command: '/model', args: '[current|list|check]', description: '查询模型或检查模型网关', category: 'Agent 与模型', roles: [identity.role] },
|
|
843
|
+
{ command: '/effort', description: '查看推理强度', category: 'Agent 与模型', roles: [identity.role] },
|
|
844
|
+
{ command: '/baseagent', description: '查看 Agent 后端', category: 'Agent 与模型', roles: [identity.role] },
|
|
845
|
+
{ command: '/perm', description: '查看当前权限模式', category: '权限管理', roles: [identity.role] },
|
|
846
|
+
{ command: '/mentionmode', description: '查看群聊 @ 处理模式', category: '聊天设置', roles: [identity.role] },
|
|
847
|
+
{ command: '/ask', args: '<选项>', description: '回答 Agent 的交互式问题', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
848
|
+
{ command: '/pause', description: '在下一次工具调用前暂停当前任务', category: '运维', roles: ['admin', 'owner'] },
|
|
849
|
+
{ command: '/resume', description: '继续已暂停的当前任务', category: '运维', roles: ['admin', 'owner'] },
|
|
850
|
+
{ command: '/stop', description: '中断当前任务', category: '运维', roles: ['admin', 'owner'] },
|
|
851
|
+
];
|
|
852
|
+
if (isAdmin) {
|
|
853
|
+
commands.push({ command: '/compact', description: '压缩会话上下文', category: '会话管理', roles: ['admin', 'owner'] }, ...(threadId ? [{ command: '/renew', description: '轮换当前话题 backend', category: '会话管理', roles: ['admin', 'owner'] }] : []));
|
|
854
|
+
}
|
|
855
|
+
return { kind: 'command.result', text: JSON.stringify({ commands, categories: [...new Set(commands.map(c => c.category))] }) };
|
|
856
|
+
}
|
|
795
857
|
const cmds = [];
|
|
796
858
|
const canReadModel = canAccessSlashOperation('model.current', 'relation')
|
|
797
859
|
|| canAccessSlashOperation('model.list', 'relation');
|
|
@@ -836,7 +898,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
836
898
|
// 运维
|
|
837
899
|
cmds.push({ command: '/status', description: '显示会话状态', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] });
|
|
838
900
|
cmds.push({ command: '/pause', description: '在下一次工具调用前暂停当前任务', category: '运维', roles: ['admin', 'owner'] });
|
|
839
|
-
cmds.push({ command: '/resume', description: '
|
|
901
|
+
cmds.push({ command: '/resume', description: '继续暂停或异常中断的当前任务', category: '运维', roles: ['admin', 'owner'] });
|
|
840
902
|
cmds.push({ command: '/stop', description: '中断当前任务', category: '运维', roles: ['admin', 'owner'] });
|
|
841
903
|
cmds.push({ command: '/check', description: '检查 EvolAgent 实例健康', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] });
|
|
842
904
|
if (isAdmin) {
|
|
@@ -851,6 +913,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
851
913
|
cmds.push({ command: '/upgrade', description: '检查版本更新', category: '运维', roles: ['daemon-owner'] });
|
|
852
914
|
cmds.push({ command: '/reload', args: '[aid]', description: '热重载 Agent 配置', category: '运维', roles: ['daemon-owner'] });
|
|
853
915
|
cmds.push({ command: '/pair', description: '获取远程控制配对码', category: '运维', roles: ['daemon-owner'] });
|
|
916
|
+
cmds.push({ command: '/diag', args: '<问题描述>|stop', description: '邀请远程诊断或撤销授权', category: '运维', roles: ['daemon-owner'] });
|
|
854
917
|
}
|
|
855
918
|
if (!isDaemonOwner && isAdmin) {
|
|
856
919
|
cmds.push({ command: '/reload', description: '热重载当前 Agent 配置', category: '运维', roles: ['admin', 'owner'] });
|
|
@@ -1008,19 +1071,20 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1008
1071
|
if (!args) {
|
|
1009
1072
|
if (!askSession)
|
|
1010
1073
|
return { kind: 'command.result', text: '当前没有待回答的问题' };
|
|
1011
|
-
const pendingIds = this.interactionRouter?.getPending(askSession.id) || [];
|
|
1074
|
+
const pendingIds = this.interactionRouter?.getPending(askSession.id, 'ask') || [];
|
|
1012
1075
|
if (pendingIds.length === 0)
|
|
1013
1076
|
return { kind: 'command.result', text: '当前没有待回答的问题' };
|
|
1014
|
-
return { kind: 'command.result',
|
|
1077
|
+
return { kind: 'command.result',
|
|
1078
|
+
text: `当前有 ${pendingIds.length} 个待回答问题,请回复 /ask <问题ID> <回答>:\n${pendingIds.join('\n')}` };
|
|
1015
1079
|
}
|
|
1016
1080
|
if (!askSession)
|
|
1017
1081
|
return { kind: 'command.error', text: '❌ 当前没有待回答的问题' };
|
|
1018
|
-
const fb = await this.handleInteractionFallback('ask', args, askSession.id, userId);
|
|
1082
|
+
const fb = await this.handleInteractionFallback('ask', args, askSession.id, userId, this.getAdapter(channel)?.channelKey);
|
|
1019
1083
|
if (fb.matched)
|
|
1020
1084
|
return { kind: 'command.result', text: fb.result ?? '✓ 已回答' };
|
|
1021
1085
|
return { kind: 'command.error', text: '❌ 当前没有待回答的问题' };
|
|
1022
1086
|
}
|
|
1023
|
-
// /pause
|
|
1087
|
+
// /pause gates the next tool; /resume also recovers a failed backend turn.
|
|
1024
1088
|
if (normalizedContent.startsWith('/pause ')) {
|
|
1025
1089
|
return { kind: 'command.error', text: '用法: /pause' };
|
|
1026
1090
|
}
|
|
@@ -1048,8 +1112,16 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1048
1112
|
const resumeSession = await getExistingSessionForCommand();
|
|
1049
1113
|
if (!resumeSession)
|
|
1050
1114
|
return { kind: 'command.result', text: '当前没有活跃会话' };
|
|
1051
|
-
const resumed = this.processor.
|
|
1052
|
-
|
|
1115
|
+
const resumed = await this.processor.recoverTask({
|
|
1116
|
+
sessionId: resumeSession.id,
|
|
1117
|
+
agentAid: resumeSession.selfAID,
|
|
1118
|
+
peerId: userId,
|
|
1119
|
+
encrypted: replyContext?.metadata?.encrypted,
|
|
1120
|
+
});
|
|
1121
|
+
return {
|
|
1122
|
+
kind: resumed.ok ? 'command.result' : 'command.error',
|
|
1123
|
+
text: resumed.message ?? (resumed.ok ? '已继续当前任务' : '任务恢复失败'),
|
|
1124
|
+
};
|
|
1053
1125
|
}
|
|
1054
1126
|
// /baseagent 命令:查看或切换 Agent 后端
|
|
1055
1127
|
if (normalizedContent === '/baseagent' || normalizedContent.startsWith('/baseagent ')) {
|
|
@@ -1063,7 +1135,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1063
1135
|
if (!args) {
|
|
1064
1136
|
const activeBaseagent = owningAgent?.baseagent || this.parseDefaultBaseagent();
|
|
1065
1137
|
// 尝试发送 CommandCard 卡片
|
|
1066
|
-
if (this.interactionRouter && available.length > 1) {
|
|
1138
|
+
if (!groupSlash && this.interactionRouter && available.length > 1) {
|
|
1067
1139
|
const baseagentSession = await getExistingSessionForCommand();
|
|
1068
1140
|
const interaction = {
|
|
1069
1141
|
type: 'interaction',
|
|
@@ -1090,7 +1162,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1090
1162
|
}
|
|
1091
1163
|
// 降级:文本
|
|
1092
1164
|
const list = available.map((a) => `${a === activeBaseagent ? ' ✓' : ' '} ${a}`).join('\n');
|
|
1093
|
-
const canSwitchAgent = isOwner;
|
|
1165
|
+
const canSwitchAgent = isOwner && !groupSlash;
|
|
1094
1166
|
if (canSwitchAgent) {
|
|
1095
1167
|
return { kind: 'command.result', text: `当前 Baseagent: ${activeBaseagent}\n\n可用:\n${list}\n用法: /baseagent <name>` };
|
|
1096
1168
|
}
|
|
@@ -1348,7 +1420,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1348
1420
|
isDaemonOwner,
|
|
1349
1421
|
});
|
|
1350
1422
|
// 尝试发送 CommandCard 卡片
|
|
1351
|
-
if (!args && canReadModelList && this.interactionRouter && models.length > 0) {
|
|
1423
|
+
if (!groupSlash && !args && canReadModelList && this.interactionRouter && models.length > 0) {
|
|
1352
1424
|
const interaction = {
|
|
1353
1425
|
type: 'interaction',
|
|
1354
1426
|
id: `model-${Date.now()}-${crypto.randomBytes(4).toString('hex')}`,
|
|
@@ -1379,7 +1451,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1379
1451
|
const catalogHint = `[${catalog.source}/${catalog.freshness}] ${catalog.diagnostics.map(d => d.message).join('; ')}`;
|
|
1380
1452
|
const modelList = models.map((m) => ` ${modelMatches(modelAgent, m, currentModel) ? '✓' : ' '} ${modelDisplayLabel(modelAgent, m)}`).join('\n');
|
|
1381
1453
|
const effortHint = efforts.length > 0
|
|
1382
|
-
? `\n推理强度: ${currentEffort === 'auto' ? 'auto (SDK默认)' : currentEffort} (使用 /effort 调整)`
|
|
1454
|
+
? `\n推理强度: ${currentEffort === 'auto' ? 'auto (SDK默认)' : currentEffort}${groupSlash ? '' : ' (使用 /effort 调整)'}`
|
|
1383
1455
|
: '';
|
|
1384
1456
|
if (args === 'current') {
|
|
1385
1457
|
return {
|
|
@@ -1389,7 +1461,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1389
1461
|
};
|
|
1390
1462
|
}
|
|
1391
1463
|
if (canReadModelList) {
|
|
1392
|
-
const usage = !args && isAdmin ? '\n\n用法: /model <模型>' : '';
|
|
1464
|
+
const usage = !groupSlash && !args && isAdmin ? '\n\n用法: /model <模型>' : '';
|
|
1393
1465
|
return {
|
|
1394
1466
|
kind: 'command.result',
|
|
1395
1467
|
text: `当前模型: ${modelDisplayLabel(modelAgent, currentModel)}${effortHint}${rawModels.includes(currentModel) ? '' : ' [当前配置,未列入目录]'}\n${catalogHint}\n\n可用模型:\n${modelList}${usage}`,
|
|
@@ -1473,10 +1545,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1473
1545
|
}
|
|
1474
1546
|
else {
|
|
1475
1547
|
const resolvedArg = hasModelSwitcher(modelAgent) ? (modelAgent.resolveModelId?.(arg) ?? arg) : arg;
|
|
1476
|
-
if (models.includes(resolvedArg)) {
|
|
1477
|
-
newModel = resolvedArg;
|
|
1478
|
-
}
|
|
1479
|
-
else if (models.includes(arg)) {
|
|
1548
|
+
if (models.includes(resolvedArg) || models.includes(arg)) {
|
|
1480
1549
|
newModel = arg;
|
|
1481
1550
|
}
|
|
1482
1551
|
else {
|
|
@@ -1503,7 +1572,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1503
1572
|
const errorLabel = allEfforts.includes(effortArg) ? '⚠️' : '❌';
|
|
1504
1573
|
return { kind: 'command.result', text: `${errorLabel} ${modelArg} 不支持 ${effortArg} 推理强度\n可选: ${targetEfforts.join(' / ')}` };
|
|
1505
1574
|
}
|
|
1506
|
-
newModel =
|
|
1575
|
+
newModel = modelArgRaw;
|
|
1507
1576
|
newEffort = effortArg;
|
|
1508
1577
|
}
|
|
1509
1578
|
// 优先写关系级覆盖;只有无法定位关系且具备管理权限时才回退到 runner/agent 级。
|
|
@@ -1543,11 +1612,13 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1543
1612
|
requestedModel: newModel,
|
|
1544
1613
|
models,
|
|
1545
1614
|
resolveModelId: modelAgent.resolveModelId?.bind(modelAgent),
|
|
1615
|
+
selfAid: modelSelector.self,
|
|
1546
1616
|
});
|
|
1547
1617
|
if (!decision.ok) {
|
|
1548
1618
|
return { kind: 'command.error', text: decision.message || `invalid model: ${newModel}` };
|
|
1549
1619
|
}
|
|
1550
|
-
|
|
1620
|
+
// The decision validates the resolved model; retain the user's selection
|
|
1621
|
+
// for configuration and replies, just like menu.update and local model use.
|
|
1551
1622
|
}
|
|
1552
1623
|
const changes = [];
|
|
1553
1624
|
if (!('error' in relationTarget)) {
|
|
@@ -1659,7 +1730,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1659
1730
|
return { kind: 'command.error', text: '⚠️ 当前模型不支持推理强度设置' };
|
|
1660
1731
|
}
|
|
1661
1732
|
// /effort(无参数):显示当前推理强度 + 发送 CommandCard 卡片
|
|
1662
|
-
if (this.interactionRouter) {
|
|
1733
|
+
if (!groupSlash && this.interactionRouter) {
|
|
1663
1734
|
const allItems = [...efforts, 'auto'];
|
|
1664
1735
|
const interaction = {
|
|
1665
1736
|
type: 'interaction',
|
|
@@ -1687,7 +1758,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
1687
1758
|
// 降级:文本
|
|
1688
1759
|
const effortDisplay = currentEffort === 'auto' ? 'auto (SDK默认)' : currentEffort;
|
|
1689
1760
|
const effortOptions = [...efforts, 'auto'].join(' / ');
|
|
1690
|
-
if (isAdmin) {
|
|
1761
|
+
if (isAdmin && !groupSlash) {
|
|
1691
1762
|
return { kind: 'command.result', text: `推理强度: ${effortDisplay} 可选: ${effortOptions} 用法: /effort <level>` };
|
|
1692
1763
|
}
|
|
1693
1764
|
return { kind: 'command.result', text: `推理强度: ${effortDisplay}` };
|
|
@@ -2109,6 +2180,8 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2109
2180
|
const currentMode = readSlashMentionMode(mentionTarget, mentionFallback);
|
|
2110
2181
|
if (!arg) {
|
|
2111
2182
|
const displayMode = currentMode ?? '未设置(跟随群设置)';
|
|
2183
|
+
if (groupSlash)
|
|
2184
|
+
return { kind: 'command.result', text: `@ 处理模式: ${displayMode}` };
|
|
2112
2185
|
// 尝试发送 CommandCard 卡片
|
|
2113
2186
|
if (isAdmin) {
|
|
2114
2187
|
const modes = [
|
|
@@ -2195,6 +2268,9 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2195
2268
|
const hasActive = stopAgent.hasActiveStream(sessionKey);
|
|
2196
2269
|
const isProcessing = this.messageQueue.isProcessing(sessionKey);
|
|
2197
2270
|
if (queueLength === 0 && !hasActive && !isProcessing) {
|
|
2271
|
+
// Even an idle session can have an undelivered task:error recovery.
|
|
2272
|
+
// Persist the stop fence before acknowledging that nothing is running.
|
|
2273
|
+
await this.processor.interruptSession(sessionKey, 'stop');
|
|
2198
2274
|
return { kind: 'command.result', text: '当前没有正在处理的任务' };
|
|
2199
2275
|
}
|
|
2200
2276
|
// 发布中断事件,让 MessageProcessor 标记为 interrupted(而非 done)
|
|
@@ -2486,6 +2562,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2486
2562
|
session.name = fileInfo.title;
|
|
2487
2563
|
}
|
|
2488
2564
|
}
|
|
2565
|
+
const sessionSubtasks = this.sessionManager.getRunnerTaskHistory(session.id).length;
|
|
2489
2566
|
const lines = [];
|
|
2490
2567
|
const chatMode = getEffectiveChatmode(session);
|
|
2491
2568
|
const sessionRole = session.identity?.role || identity.role || 'none';
|
|
@@ -2508,7 +2585,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2508
2585
|
if (gitInfo) {
|
|
2509
2586
|
lines.push(`Git: ${gitInfo}`);
|
|
2510
2587
|
}
|
|
2511
|
-
lines.push(`会话状态: ${sessionStatus} / 轮数: ${sessionTurns}`, sessionRoleLine, chatModeLine, ...(mentionModeLine ? [mentionModeLine] : []));
|
|
2588
|
+
lines.push(`会话状态: ${sessionStatus} / 轮数: ${sessionTurns} / 已记录子任务数: ${sessionSubtasks}`, sessionRoleLine, chatModeLine, ...(mentionModeLine ? [mentionModeLine] : []));
|
|
2512
2589
|
if (health.consecutiveErrors > 0) {
|
|
2513
2590
|
lines.push(`异常计数: ${health.consecutiveErrors}`);
|
|
2514
2591
|
}
|
|
@@ -2516,7 +2593,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2516
2593
|
}
|
|
2517
2594
|
else {
|
|
2518
2595
|
lines.push(`📊 ${isThread ? '话题' : '会话'}状态 (Agent: ${agentName}):`, `渠道: ${channel} / 项目: ${projectName} / ${session.baseagent}会话`);
|
|
2519
|
-
lines.push(`状态: ${sessionStatus} / 轮数: ${sessionTurns}`, sessionRoleLine, chatModeLine, ...(mentionModeLine ? [mentionModeLine] : []), `最后活跃: ${timeStr}`);
|
|
2596
|
+
lines.push(`状态: ${sessionStatus} / 轮数: ${sessionTurns} / 已记录子任务数: ${sessionSubtasks}`, sessionRoleLine, chatModeLine, ...(mentionModeLine ? [mentionModeLine] : []), `最后活跃: ${timeStr}`);
|
|
2520
2597
|
}
|
|
2521
2598
|
if (health.lastError) {
|
|
2522
2599
|
lines.push('');
|
|
@@ -2863,7 +2940,8 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
2863
2940
|
text: `❌ ${excludeKey ? '其他会话' : '该 Agent'} 有 ${busyInfo.count} 个任务执行中,无法重启。\n\n处理中的会话:\n${processingLines}\n\n建议:等待这些任务完成后重试。可通过 ec ctl status 查看队列状态;典型等待时间 30-60 秒,群聊大型任务可能更长。`,
|
|
2864
2941
|
};
|
|
2865
2942
|
}
|
|
2866
|
-
|
|
2943
|
+
// Archiving only changes list visibility; pending work must still be checked.
|
|
2944
|
+
const allSessions = await this.sessionManager.listSessions(channel, channelId, { archiveFilter: 'all' });
|
|
2867
2945
|
const sessionsWithMessages = allSessions
|
|
2868
2946
|
.filter((s) => this.messageCache.hasMessages(s.id))
|
|
2869
2947
|
.map((s) => {
|
|
@@ -3223,10 +3301,10 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3223
3301
|
// /slist cli — 仅 CLI 会话(未导入的)
|
|
3224
3302
|
if (normalizedContent === '/slist' || normalizedContent === '/slist cli') {
|
|
3225
3303
|
if (!session) {
|
|
3226
|
-
return { kind: 'command.error', text: `❌ 当前没有活跃会话
|
|
3227
|
-
|
|
3228
|
-
请先执行以下操作之一:
|
|
3229
|
-
1. 发送任意消息 - 自动创建新会话
|
|
3304
|
+
return { kind: 'command.error', text: `❌ 当前没有活跃会话
|
|
3305
|
+
|
|
3306
|
+
请先执行以下操作之一:
|
|
3307
|
+
1. 发送任意消息 - 自动创建新会话
|
|
3230
3308
|
2. /new [名称] - 创建命名会话` };
|
|
3231
3309
|
}
|
|
3232
3310
|
const showCliOnly = normalizedContent === '/slist cli';
|
|
@@ -3497,11 +3575,11 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3497
3575
|
if (!newName)
|
|
3498
3576
|
return { kind: 'command.result', text: '用法: /name <新名称> 或 /rename <新名称>' };
|
|
3499
3577
|
if (!session) {
|
|
3500
|
-
return { kind: 'command.error', text: `❌ 当前没有活跃会话
|
|
3501
|
-
|
|
3502
|
-
请先执行以下操作之一:
|
|
3503
|
-
1. 发送任意消息 - 自动创建新会话
|
|
3504
|
-
2. /new [名称] - 创建命名会话
|
|
3578
|
+
return { kind: 'command.error', text: `❌ 当前没有活跃会话
|
|
3579
|
+
|
|
3580
|
+
请先执行以下操作之一:
|
|
3581
|
+
1. 发送任意消息 - 自动创建新会话
|
|
3582
|
+
2. /new [名称] - 创建命名会话
|
|
3505
3583
|
3. /session <名称> - 切换到已有会话` };
|
|
3506
3584
|
}
|
|
3507
3585
|
const existing = await this.sessionManager.getSessionByName(channel, channelId, newName);
|
|
@@ -3584,7 +3662,9 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3584
3662
|
}
|
|
3585
3663
|
await interruptPausedSessionBeforeReplacement(session);
|
|
3586
3664
|
try {
|
|
3587
|
-
const forkedSessionId = await forkAgent.forkSession(session.agentSessionId, session.projectPath, forkName
|
|
3665
|
+
const forkedSessionId = await forkAgent.forkSession(session.agentSessionId, session.projectPath, forkName, {
|
|
3666
|
+
sessionId: session.id, permissionMode: authSubject.permissionMode, role: authSubject.role,
|
|
3667
|
+
});
|
|
3588
3668
|
const newSession = await this.sessionManager.createForkedSession(session, forkedSessionId, forkName);
|
|
3589
3669
|
await forkAgent.updateSessionMetadata?.(forkedSessionId, {
|
|
3590
3670
|
gitInfo: {
|
|
@@ -294,6 +294,10 @@ const CATALOG = [
|
|
|
294
294
|
description: 'agent 任务失败',
|
|
295
295
|
fields: [
|
|
296
296
|
{ path: 'sessionId', type: 'string' },
|
|
297
|
+
{ path: 'agentAid', type: 'string', optional: true },
|
|
298
|
+
{ path: 'peerId', type: 'string', optional: true },
|
|
299
|
+
{ path: 'encrypted', type: 'boolean', optional: true },
|
|
300
|
+
{ path: 'originTriggerId', type: 'string', optional: true },
|
|
297
301
|
{ path: 'taskId', type: 'string', optional: true },
|
|
298
302
|
{ path: 'generation', type: 'number', optional: true },
|
|
299
303
|
{ path: 'error', type: 'string' },
|
|
@@ -6,6 +6,7 @@ import { agentPersonalDir } from '../paths.js';
|
|
|
6
6
|
import { invalidateAgentDisplayName, resolveAgentDisplayName } from '../aun/aid/agentmd.js';
|
|
7
7
|
import { loadAllAgents, ensureAgentDirSkeleton, loadAgent, validateAgentConfig, } from '../config-store.js';
|
|
8
8
|
import { ConfigTarget, read as readConfig, resolveEffective } from '../config/config-manager.js';
|
|
9
|
+
import { resolveAgentLifecycle } from '../config/lifecycle.js';
|
|
9
10
|
// ── Channel Fingerprint ───────────────────────────────────────────────────
|
|
10
11
|
// 用于检测多 agent 之间复用同一外部凭证的冲突(appId、aid、token 等)。
|
|
11
12
|
// 格式:{type}:{primaryKey}
|
|
@@ -58,6 +59,8 @@ export class EvolAgentRegistry {
|
|
|
58
59
|
agents = new Map();
|
|
59
60
|
/** channel key (`<type>#<selfAID>#<name>`) → agent aid */
|
|
60
61
|
channelIndex = new Map();
|
|
62
|
+
/** Agents stopped through stopAgent; distinct from the initial load state. */
|
|
63
|
+
manuallyStopped = new Set();
|
|
61
64
|
/** 启动期被 ConfigStore 跳过的目录(命名非法 / 缺 config.json / 校验失败等) */
|
|
62
65
|
skipped = [];
|
|
63
66
|
/**
|
|
@@ -81,6 +84,7 @@ export class EvolAgentRegistry {
|
|
|
81
84
|
void _globalConfig;
|
|
82
85
|
this.agents.clear();
|
|
83
86
|
this.channelIndex.clear();
|
|
87
|
+
this.manuallyStopped.clear();
|
|
84
88
|
this.skipped = [];
|
|
85
89
|
const { agents: rawAgents, skipped, invalidAgents = [] } = loadAllAgents({ includeInvalid: true });
|
|
86
90
|
this.skipped = skipped;
|
|
@@ -285,6 +289,7 @@ export class EvolAgentRegistry {
|
|
|
285
289
|
if (!hotLoad)
|
|
286
290
|
throw new Error(`Cannot enable agent "${aidOrName}": hot-load handler not initialized`);
|
|
287
291
|
this.agents.delete(oldAgent.aid);
|
|
292
|
+
this.manuallyStopped.delete(oldAgent.aid);
|
|
288
293
|
this.channelIndex.clear();
|
|
289
294
|
this.buildChannelIndex();
|
|
290
295
|
await hotLoad(oldAgent.aid);
|
|
@@ -298,6 +303,7 @@ export class EvolAgentRegistry {
|
|
|
298
303
|
const previousConfig = oldAgent.captureConfigSnapshot();
|
|
299
304
|
const previousStatus = oldAgent.status;
|
|
300
305
|
const previousError = oldAgent.error;
|
|
306
|
+
const previousManuallyStopped = this.manuallyStopped.has(oldAgent.aid);
|
|
301
307
|
try {
|
|
302
308
|
await hooks.prepareHandoffReload?.(oldAgent.aid);
|
|
303
309
|
prepared = true;
|
|
@@ -312,6 +318,7 @@ export class EvolAgentRegistry {
|
|
|
312
318
|
}
|
|
313
319
|
oldAgent.swapConfig(raw, merged);
|
|
314
320
|
oldAgent.status = 'disabled';
|
|
321
|
+
this.manuallyStopped.delete(oldAgent.aid);
|
|
315
322
|
this.channelIndex.clear();
|
|
316
323
|
this.buildChannelIndex();
|
|
317
324
|
runnerTransaction?.commit();
|
|
@@ -331,6 +338,10 @@ export class EvolAgentRegistry {
|
|
|
331
338
|
oldAgent.invalidatePersonaCache();
|
|
332
339
|
oldAgent.status = previousStatus;
|
|
333
340
|
oldAgent.error = previousError;
|
|
341
|
+
if (previousManuallyStopped)
|
|
342
|
+
this.manuallyStopped.add(oldAgent.aid);
|
|
343
|
+
else
|
|
344
|
+
this.manuallyStopped.delete(oldAgent.aid);
|
|
334
345
|
await runnerTransaction?.rollback().catch(rollbackError => {
|
|
335
346
|
rollbackErrors.push(`runners: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
336
347
|
});
|
|
@@ -370,11 +381,16 @@ export class EvolAgentRegistry {
|
|
|
370
381
|
const previousConfig = oldAgent.captureConfigSnapshot();
|
|
371
382
|
const previousStatus = oldAgent.status;
|
|
372
383
|
const previousError = oldAgent.error;
|
|
384
|
+
const previousManuallyStopped = this.manuallyStopped.has(oldAgent.aid);
|
|
373
385
|
try {
|
|
374
386
|
await hooks.prepareHandoffReload?.(oldAgent.aid);
|
|
375
387
|
prepared = true;
|
|
376
388
|
runnerTransaction = await hooks.stageAgentRunners?.(new EvolAgent(raw, merged));
|
|
377
|
-
|
|
389
|
+
// stopAgent removes runtime transports but preserves configuration.
|
|
390
|
+
// Reload transitions a manually stopped Agent back to running.
|
|
391
|
+
const oldChannels = this.manuallyStopped.has(oldAgent.aid)
|
|
392
|
+
? new Set()
|
|
393
|
+
: new Set(oldAgent.channelInstanceNames());
|
|
378
394
|
const aunKey = oldAgent.effectiveChannelName('aun', 'main');
|
|
379
395
|
const otherKeys = merged.channels.filter(c => c.type !== 'aun').map(c => oldAgent.effectiveChannelName(c.type, c.name));
|
|
380
396
|
const newChannels = new Set([aunKey, ...otherKeys]);
|
|
@@ -404,6 +420,7 @@ export class EvolAgentRegistry {
|
|
|
404
420
|
addedSuccessfully.push(ch);
|
|
405
421
|
}
|
|
406
422
|
oldAgent.status = 'running';
|
|
423
|
+
this.manuallyStopped.delete(oldAgent.aid);
|
|
407
424
|
this.channelIndex.clear();
|
|
408
425
|
this.buildChannelIndex();
|
|
409
426
|
runnerTransaction?.commit();
|
|
@@ -466,6 +483,10 @@ export class EvolAgentRegistry {
|
|
|
466
483
|
if (rollbackErrors.length === 0) {
|
|
467
484
|
oldAgent.status = previousStatus;
|
|
468
485
|
oldAgent.error = previousError;
|
|
486
|
+
if (previousManuallyStopped)
|
|
487
|
+
this.manuallyStopped.add(oldAgent.aid);
|
|
488
|
+
else
|
|
489
|
+
this.manuallyStopped.delete(oldAgent.aid);
|
|
469
490
|
}
|
|
470
491
|
else {
|
|
471
492
|
oldAgent.status = 'error';
|
|
@@ -481,8 +502,10 @@ export class EvolAgentRegistry {
|
|
|
481
502
|
throw new Error(`Agent "${aidOrName}" not found`);
|
|
482
503
|
if (agent.status === 'disabled')
|
|
483
504
|
throw new Error('Agent is disabled; use enable/disable instead');
|
|
484
|
-
if (agent.status === 'stopped')
|
|
505
|
+
if (agent.status === 'stopped') {
|
|
506
|
+
this.manuallyStopped.add(agent.aid);
|
|
485
507
|
return;
|
|
508
|
+
}
|
|
486
509
|
for (const ch of agent.channelInstanceNames()) {
|
|
487
510
|
try {
|
|
488
511
|
await hooks.disconnectChannel(ch);
|
|
@@ -490,6 +513,7 @@ export class EvolAgentRegistry {
|
|
|
490
513
|
catch { }
|
|
491
514
|
}
|
|
492
515
|
agent.status = 'stopped';
|
|
516
|
+
this.manuallyStopped.add(agent.aid);
|
|
493
517
|
this.channelIndex.clear();
|
|
494
518
|
this.buildChannelIndex();
|
|
495
519
|
logger.info(`[Registry] Stopped agent ${aidOrName}`);
|
|
@@ -508,6 +532,7 @@ export class EvolAgentRegistry {
|
|
|
508
532
|
await hooks.startChannel(agent, ch);
|
|
509
533
|
}
|
|
510
534
|
agent.status = 'running';
|
|
535
|
+
this.manuallyStopped.delete(agent.aid);
|
|
511
536
|
this.channelIndex.clear();
|
|
512
537
|
this.buildChannelIndex();
|
|
513
538
|
logger.info(`[Registry] Started agent ${aidOrName}`);
|
|
@@ -575,6 +600,7 @@ export class EvolAgentRegistry {
|
|
|
575
600
|
personalName,
|
|
576
601
|
aid: agent.aid,
|
|
577
602
|
status: agent.status,
|
|
603
|
+
lifecycle: resolveAgentLifecycle(agent.config),
|
|
578
604
|
channels,
|
|
579
605
|
projectPath,
|
|
580
606
|
baseagent,
|