evolcore 0.0.32 → 0.0.34
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 +61 -0
- package/bin/ec.js +3 -2
- package/bin/install-codex-managed-hooks.mjs +135 -37
- package/dist/agents/baseagent-availability.js +20 -36
- package/dist/agents/claude-runner.js +111 -15
- package/dist/agents/codex/app-server-client.js +3 -0
- package/dist/agents/codex/diagnostics.js +112 -54
- package/dist/agents/codex-runner.js +241 -63
- package/dist/agents/ecagent-runner.js +78 -33
- package/dist/agents/runner-types.js +5 -6
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/group/operations.js +0 -1
- package/dist/aun/msg/history.js +1 -0
- package/dist/aun/msg/p2p.js +0 -1
- package/dist/aun/outbox.js +50 -1
- package/dist/channels/aun.js +44 -8
- package/dist/channels/daemon.js +261 -3
- package/dist/cli/agent-command.js +58 -24
- package/dist/cli/agent.js +1 -1
- package/dist/cli/aun-commands.js +368 -31
- package/dist/cli/contact.js +8 -2
- package/dist/cli/ctl-command.js +3 -1
- package/dist/cli/daemon-commands.js +197 -27
- package/dist/cli/debug-mode.js +154 -0
- package/dist/cli/fs-command.js +2 -1
- package/dist/cli/handoff-command.js +3 -0
- package/dist/cli/index.js +98 -67
- package/dist/cli/init.js +2 -2
- package/dist/cli/integrity-command.js +196 -0
- package/dist/cli/managed-command-guard.js +5 -0
- package/dist/cli/memory-command.js +166 -146
- package/dist/cli/queue-command.js +9 -4
- package/dist/cli/session-command.js +194 -0
- package/dist/cli/skill-command.js +78 -2
- package/dist/cli/task-context.js +1 -0
- package/dist/cli/thread-command.js +622 -0
- package/dist/cli/trigger-command.js +10 -3
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-field-policy.js +6 -3
- package/dist/config/config-manager.js +26 -2
- package/dist/config/contact-book-store.js +5 -0
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config/role-service.js +13 -0
- package/dist/config/runtime-env.js +16 -0
- package/dist/config-store.js +45 -0
- package/dist/core/audit/log-integrity.js +3 -1
- package/dist/core/auth/agent-delegation.js +133 -36
- package/dist/core/auth/debug-context.js +139 -0
- package/dist/core/auth/delegation-diagnostics.js +414 -0
- package/dist/core/auth/operation-authorizer.js +25 -2
- package/dist/core/auth/operation-catalog.js +49 -0
- package/dist/core/background-session/session-cleanup.js +212 -0
- package/dist/core/background-session/types.js +10 -0
- package/dist/core/bootstrap-messages.js +1 -1
- package/dist/core/bootstrap-service.js +6 -3
- package/dist/core/command/agent-control.js +18 -26
- package/dist/core/command/command-handler.js +197 -27
- package/dist/core/command/daemon-diagnostics.js +1 -0
- package/dist/core/command/memory-slash.js +6 -2
- package/dist/core/command/menu-catalog.js +51 -1
- package/dist/core/command/menu-handler.js +114 -23
- package/dist/core/command/menu-protocol.js +25 -1
- package/dist/core/command/skill-slash.js +322 -0
- package/dist/core/command/slash-gate.js +6 -4
- package/dist/core/command/slash-handler.js +195 -13
- package/dist/core/command/topic-slash.js +528 -0
- package/dist/core/daemon-bootstrap.js +4 -7
- package/dist/core/evolagent-registry.js +20 -5
- package/dist/core/file-integrity/read.js +61 -0
- package/dist/core/file-integrity/store.js +262 -0
- package/dist/core/handoff/runtime.js +5 -11
- package/dist/core/handoff/store.js +5 -0
- package/dist/core/ipc-registration.js +175 -3
- package/dist/core/memory/batch-meta.js +132 -0
- package/dist/core/memory/consolidation-context.js +83 -29
- package/dist/core/memory/consolidation-ops-records.js +49 -16
- package/dist/core/memory/consolidation-queue-format.js +21 -0
- package/dist/core/memory/consolidation.js +264 -205
- package/dist/core/memory/index-manager.js +19 -28
- package/dist/core/memory/memory-admin.js +19 -14
- package/dist/core/memory/memory-document.js +53 -9
- package/dist/core/memory/memory-writer.js +30 -15
- package/dist/core/message/aun-ipc-sender.js +161 -6
- package/dist/core/message/im-renderer.js +169 -10
- package/dist/core/message/message-bridge.js +15 -4
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/peer-mode.js +6 -1
- package/dist/core/message/response-engine.js +929 -110
- package/dist/core/message/subtask-tool-projection.js +140 -0
- package/dist/core/model/catalog-service.js +17 -12
- package/dist/core/permission/ec-command-parser.js +217 -9
- package/dist/core/permission/protected-paths.js +5 -1
- package/dist/core/permission/readonly-shell-query.js +43 -5
- package/dist/core/permission/session-path-grants.js +334 -0
- package/dist/core/permission/tool-canonical.js +226 -0
- package/dist/core/permission/tool-policy.js +30 -62
- package/dist/core/role/runtime-policy.js +21 -10
- package/dist/core/session/session-fs-store.js +123 -8
- package/dist/core/session/session-idle-monitor.js +249 -22
- package/dist/core/session/session-manager.js +129 -14
- package/dist/core/skill/command-parser.js +13 -0
- package/dist/core/skill/index-generator.js +21 -4
- package/dist/core/skill/startup.js +41 -0
- package/dist/core/skill/switch-resolver.js +55 -29
- package/dist/core/system-session/grants.js +40 -0
- package/dist/core/system-session/memory.js +222 -0
- package/dist/core/system-session/registry.js +74 -0
- package/dist/core/system-session/types.js +14 -0
- package/dist/core/thread/command-parser.js +125 -0
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +95 -0
- package/dist/core/thread/thread-context-storage.js +131 -0
- package/dist/core/thread/thread-operation.js +258 -0
- package/dist/core/thread/thread-route.js +33 -0
- package/dist/core/thread/thread-service.js +770 -0
- package/dist/core/thread/types.js +1 -0
- package/dist/eck/kit-renderer.js +7 -2
- package/dist/eck/manifest-engine.js +24 -4
- package/dist/eck/message-renderer.js +35 -0
- package/dist/index.js +19 -7
- package/dist/ipc.js +140 -50
- package/dist/paths.js +93 -0
- package/dist/response-system/engines/v1/proactive-flow.js +169 -80
- package/dist/stats/billing.js +20 -8
- package/dist/trigger/authorization.js +57 -28
- package/dist/trigger/feedback.js +13 -2
- package/dist/trigger/parser.js +70 -1
- package/dist/trigger/system-definitions.js +3 -3
- package/dist/trigger/validation.js +14 -0
- package/dist/utils/cross-platform.js +11 -2
- package/dist/utils/error-dict.json +18 -4
- package/dist/utils/error-utils.js +143 -1
- package/dist/utils/instance-registry.js +13 -8
- package/dist/utils/log-writer.js +12 -0
- package/dist/utils/process-introspect.js +11 -0
- package/kits/docs/context-assembly.md +1 -1
- package/kits/docs/evolcore/INDEX.md +1 -0
- package/kits/docs/evolcore/agent-create.md +40 -28
- package/kits/docs/evolcore/agent.md +21 -6
- package/kits/docs/evolcore/config.md +2 -2
- package/kits/docs/evolcore/ctl.md +2 -2
- package/kits/docs/evolcore/ec-capabilities.md +5 -1
- package/kits/docs/evolcore/fs-architecture.md +4 -5
- package/kits/docs/evolcore/fs.md +1 -1
- package/kits/docs/evolcore/group-collaboration.md +4 -6
- package/kits/docs/evolcore/group.md +11 -12
- package/kits/docs/evolcore/memory-architecture.md +4 -5
- package/kits/docs/evolcore/memory-consolidation.md +19 -15
- package/kits/docs/evolcore/memory-tags.md +3 -1
- package/kits/docs/evolcore/memory.md +24 -12
- package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
- package/kits/docs/evolcore/menu-protocol.md +7 -0
- package/kits/docs/evolcore/model.md +16 -0
- package/kits/docs/evolcore/msg.md +8 -11
- package/kits/docs/evolcore/thread-chain.md +267 -0
- package/kits/docs/prompt-loading-architecture.md +1 -1
- package/kits/eck_manifest.json +55 -40
- package/kits/eck_manifest.memory.json +0 -12
- package/kits/eck_message_manifest.json +169 -10
- package/kits/rules/01-overview.md +11 -0
- package/kits/rules/03-identity.md +6 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +1 -1
- package/kits/rules/07-memory-and-thread.md +199 -0
- package/kits/schemas/_meta.json +7 -1
- package/kits/schemas/agent-config.schema.13.json +1 -1
- package/kits/schemas/daemon.schema.7.json +140 -0
- package/kits/schemas/relation-config.schema.9.json +18 -3
- package/kits/schemas/role-config.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.2.json +6 -6
- package/kits/schemas/single-session.schema.3.json +6 -6
- package/kits/skills/.switches.json +12 -1
- package/kits/skills/ec-group/SKILL.md +234 -0
- package/kits/skills/ec-skill/SKILL.md +10 -1
- package/kits/skills/ec-skill/scripts/cli.mjs +16 -2
- package/kits/skills/ec-skill/scripts/skill.mjs +1 -1
- package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
- package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
- package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
- package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
- package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
- package/kits/skills/thread-ops/SKILL.md +492 -0
- package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
- package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
- package/kits/skills/wechat-article-reader/SKILL.md +97 -0
- package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
- package/kits/templates/bootstrap-welcome.md +7 -7
- package/kits/templates/memory-consolidation/forget.md +7 -2
- package/kits/templates/memory-consolidation/generalize.md +9 -4
- package/kits/templates/memory-consolidation/notes.md +11 -11
- package/kits/templates/memory-consolidation/profile.md +8 -3
- package/kits/templates/memory-consolidation/promote.md +8 -3
- package/kits/templates/memory-consolidation/workflow.md +6 -6
- package/kits/templates/message-fragments/handoff-request-to-target.md +1 -1
- package/kits/templates/message-fragments/item.md +2 -1
- package/kits/templates/message-fragments/thread-context.md +6 -0
- package/kits/templates/message-fragments/trigger-session.md +2 -0
- package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
- package/kits/templates/roles/member.json +2 -0
- package/kits/templates/roles/visitor.json +2 -0
- package/kits/templates/system-fragments/bootstrap.md +67 -72
- package/kits/templates/system-fragments/channel.md +3 -6
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/managed-runtime.md +15 -0
- package/kits/templates/system-fragments/memory.md +16 -9
- package/kits/templates/system-fragments/reply.md +7 -6
- package/kits/templates/system-fragments/session.md +5 -14
- package/package.json +6 -3
- package/dist/core/memory/memory-session-policy.js +0 -41
- package/dist/core/memory/memory-signature.js +0 -257
- package/kits/docs/evolcore/group-fs.md +0 -17
- package/kits/docs/venues/aun-group.md +0 -45
- package/kits/docs/venues/group.md +0 -43
|
@@ -43,7 +43,7 @@ export function probeSessionActivity(evidence, probes) {
|
|
|
43
43
|
return evaluateSessionActivity(collected);
|
|
44
44
|
}
|
|
45
45
|
// 支持的命令列表
|
|
46
|
-
const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mention', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory'];
|
|
46
|
+
const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mention', '/loop', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory', '/skill', '/thread'];
|
|
47
47
|
const deprecatedCommands = ['/clear'];
|
|
48
48
|
commands.push('/diag');
|
|
49
49
|
const exactBoundaryCommands = new Set(['/pause', '/resume', '/stop', '/pair', '/diag']);
|
|
@@ -69,6 +69,8 @@ const aliases = {
|
|
|
69
69
|
const GROUP_READ_ONLY_COMMANDS = new Set(['/model', '/effort', '/perm', '/baseagent']);
|
|
70
70
|
const GROUP_TASK_COMMANDS = new Set([
|
|
71
71
|
'/help', '/evolhelp', '/status', '/check', '/ask', '/pause', '/resume', '/stop', '/compact', '/renew', '/mention', '/memory',
|
|
72
|
+
// /skill 与 /thread 在群里只放行到 handler:写操作由各自 handler 内部按 admin 判定拒绝
|
|
73
|
+
'/skill', '/thread', '/loop',
|
|
72
74
|
]);
|
|
73
75
|
/** Group slash policy applies to every role, including old command-card clicks. */
|
|
74
76
|
export function guardGroupSlashCommand(content, chatType) {
|
|
@@ -95,7 +97,7 @@ export function guardGroupSlashCommand(content, chatType) {
|
|
|
95
97
|
};
|
|
96
98
|
}
|
|
97
99
|
// 命令快速路径前缀(所有命令都不进入消息队列)
|
|
98
|
-
const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mention', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory'];
|
|
100
|
+
const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mention', '/loop', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair', '/memory', '/skill', '/thread'];
|
|
99
101
|
quickCommandPrefixes.push('/diag');
|
|
100
102
|
/**
|
|
101
103
|
* 计算两个字符串的 Levenshtein 距离(编辑距离)
|
|
@@ -159,9 +161,9 @@ export function guardRoleCommand(content, activeChatType, isAdmin) {
|
|
|
159
161
|
return undefined;
|
|
160
162
|
// visitor/member 在群聊和私聊中均可访问的只读命令:纯查询形态(带参写操作由各 handler 内部守卫拦截)
|
|
161
163
|
const userGroupCommands = [
|
|
162
|
-
'/status', '/help', '/evolhelp', '/check', '/chatmode', '/mention',
|
|
164
|
+
'/status', '/help', '/evolhelp', '/check', '/chatmode', '/mention', '/loop',
|
|
163
165
|
'/model', '/effort', '/baseagent', '/perm', '/activity', '/stop', '/pause',
|
|
164
|
-
'/resume', '/trigger', '/file', '/ask', '/memory',
|
|
166
|
+
'/resume', '/trigger', '/file', '/ask', '/memory', '/skill', '/thread',
|
|
165
167
|
];
|
|
166
168
|
const userCommands = activeChatType === 'group' && !isAdmin
|
|
167
169
|
? userGroupCommands
|
|
@@ -13,11 +13,13 @@ import { remoteAccessService } from '../auth/remote-access-store.js';
|
|
|
13
13
|
import { read as cfgRead, resolveEffective, routeFieldPath, write as cfgWrite, } from '../../config/config-manager.js';
|
|
14
14
|
import { execAgentAction } from './agent-control.js';
|
|
15
15
|
import { handleMemorySlash, memoryHelpEntries } from './memory-slash.js';
|
|
16
|
+
import { handleSkillSlash, skillHelpEntries } from './skill-slash.js';
|
|
17
|
+
import { handleTopicSlash, topicHelpEntries, canUseTopicSlash } from './topic-slash.js';
|
|
16
18
|
import { authorizeOperation, buildAuthSubject } from '../auth/auth-gateway.js';
|
|
17
19
|
import { authorizationNextStep, formatAuthorizationDenial } from '../auth/authorization-denial.js';
|
|
18
20
|
import { resolvePermissionMode, writeScope } from '../model/config-scope.js';
|
|
19
21
|
import { formatPeerKey } from '../relation/peer-identity.js';
|
|
20
|
-
import { modelMatches, getCatalog, assertCatalogSelectable, resolveCatalogModel } from '../model/model-catalog.js';
|
|
22
|
+
import { modelMatches, getCatalog, assertCatalogSelectable, resolveCatalogModel, CONFIGURABLE_EFFORTS, configurableEfforts } from '../model/model-catalog.js';
|
|
21
23
|
import { formatModelCheck, runModelCheck } from '../model/model-diagnostics.js';
|
|
22
24
|
import { constrainResolvedModelForRole, filterModelsForRole, validateModelSelectionForRole } from '../model/model-permission.js';
|
|
23
25
|
import { resolveRuntimeStringField } from '../role/runtime-policy.js';
|
|
@@ -30,7 +32,8 @@ import { launchMonitorAndConfirm, resolveMonitorLaunch, cleanupMonitorStage } fr
|
|
|
30
32
|
import { scanInstances } from '../../utils/instance-registry.js';
|
|
31
33
|
import { guardIdleCommand, guardGroupSlashCommand, guardKnownCommand, guardRoleCommand, guardThreadCommand, isRecognizedSlashCommand, normalizeSlashContent, probeSessionActivity, } from './slash-gate.js';
|
|
32
34
|
import { MAX_AUN_ATTACHMENT_SIZE } from '../../aun/msg/upload.js';
|
|
33
|
-
|
|
35
|
+
import { DEFAULT_SESSION_LOOP_SECONDS, MAX_SESSION_LOOP_SECONDS, MIN_SESSION_LOOP_SECONDS, refreshSessionLoopTarget, resolveCurrentSessionLoopTarget, sessionLoopPayload, validateIdleSeconds, writeSessionLoopConfig, } from '../session/session-idle-monitor.js';
|
|
36
|
+
const allEfforts = CONFIGURABLE_EFFORTS;
|
|
34
37
|
const PERMISSION_MODE_KEYS = PUBLIC_PERMISSION_MODES;
|
|
35
38
|
function defaultSlashChatmode(field) {
|
|
36
39
|
return field === 'private' ? 'interactive' : 'proactive';
|
|
@@ -144,7 +147,8 @@ function resolveSlashRelationTarget(params) {
|
|
|
144
147
|
};
|
|
145
148
|
}
|
|
146
149
|
async function getAvailableEfforts(agent, model) {
|
|
147
|
-
|
|
150
|
+
const dynamic = await agent.getAvailableEfforts?.(model);
|
|
151
|
+
return configurableEfforts(agent?.baseagent || agent?.name, dynamic);
|
|
148
152
|
}
|
|
149
153
|
function modelDisplayLabel(agent, model) {
|
|
150
154
|
const full = agent.resolveModelId?.(model);
|
|
@@ -490,7 +494,9 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
490
494
|
const isDaemonOwner = authSubject.isDaemonOwner;
|
|
491
495
|
const authorizeIntent = (params) => authorizeSlashIntent({
|
|
492
496
|
...params,
|
|
493
|
-
subject:
|
|
497
|
+
subject: params.intent.operation.startsWith('session.loop.')
|
|
498
|
+
? { ...authSubject, sessionId: params.session?.id }
|
|
499
|
+
: authSubject,
|
|
494
500
|
});
|
|
495
501
|
const canAccessSlashOperation = (operation, scope) => {
|
|
496
502
|
const args = scope === 'relation'
|
|
@@ -534,6 +540,81 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
534
540
|
const isCmd = isRecognizedSlashCommand(normalizedContent);
|
|
535
541
|
if (!isCmd)
|
|
536
542
|
return undefined;
|
|
543
|
+
if (normalizedContent === '/loop' || normalizedContent.startsWith('/loop ')) {
|
|
544
|
+
const rawArgs = normalizedContent.slice('/loop'.length).trim();
|
|
545
|
+
const parts = rawArgs ? rawArgs.split(/\s+/) : [];
|
|
546
|
+
if (parts.length > 2 || (parts.length > 0 && !['on', 'off'].includes(parts[0]))) {
|
|
547
|
+
return { kind: 'command.error', text: `❌ 用法: /loop | /loop on [${MIN_SESSION_LOOP_SECONDS}-${MAX_SESSION_LOOP_SECONDS}] | /loop off` };
|
|
548
|
+
}
|
|
549
|
+
const route = {
|
|
550
|
+
channel,
|
|
551
|
+
channelId,
|
|
552
|
+
selfAid: authSubject.selfAid ?? selfAID ?? '',
|
|
553
|
+
...(threadId ? { threadId } : {}),
|
|
554
|
+
};
|
|
555
|
+
let target;
|
|
556
|
+
try {
|
|
557
|
+
if (!route.selfAid)
|
|
558
|
+
throw Object.assign(new Error('当前 agent 身份不可用'), { code: 'MISSING_AID' });
|
|
559
|
+
target = await resolveCurrentSessionLoopTarget(this.sessionManager, route);
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
const code = error?.code;
|
|
563
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
564
|
+
return { kind: 'command.error', text: `❌ ${message}${code ? ` (${code})` : ''}` };
|
|
565
|
+
}
|
|
566
|
+
const operation = parts.length === 0 ? 'session.loop.current' : 'session.loop.update';
|
|
567
|
+
const denied = await authorizeIntent({
|
|
568
|
+
intent: { operation, scope: 'relation', source: 'slash', args: { sessionId: target.session.id, peer: target.peerKey, value: parts[0] } },
|
|
569
|
+
identity,
|
|
570
|
+
session: target.session,
|
|
571
|
+
explicitChatType: target.session.chatType,
|
|
572
|
+
channel,
|
|
573
|
+
channelId,
|
|
574
|
+
userId,
|
|
575
|
+
selfAid: route.selfAid,
|
|
576
|
+
isDaemonOwner,
|
|
577
|
+
});
|
|
578
|
+
if (denied)
|
|
579
|
+
return denied;
|
|
580
|
+
if (parts.length === 0) {
|
|
581
|
+
try {
|
|
582
|
+
const current = await refreshSessionLoopTarget(this.sessionManager, route, target);
|
|
583
|
+
const payload = sessionLoopPayload(current);
|
|
584
|
+
return { kind: 'command.result', text: `当前 idle 触发(${current.level},session=${current.session.id}):${payload.value ? `开启,${payload.idleSeconds} 秒` : '关闭'}` };
|
|
585
|
+
}
|
|
586
|
+
catch (error) {
|
|
587
|
+
return { kind: 'command.error', text: `❌ ${error instanceof Error ? error.message : String(error)}` };
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
let next;
|
|
591
|
+
if (parts[0] === 'off') {
|
|
592
|
+
if (parts.length !== 1)
|
|
593
|
+
return { kind: 'command.error', text: '❌ /loop off 不接受秒数' };
|
|
594
|
+
next = { enabled: false };
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
const seconds = parts.length === 2
|
|
598
|
+
? /^[1-9]\d*$/.test(parts[1]) ? validateIdleSeconds(Number(parts[1])) : undefined
|
|
599
|
+
: DEFAULT_SESSION_LOOP_SECONDS;
|
|
600
|
+
if (seconds === undefined)
|
|
601
|
+
return { kind: 'command.error', text: `❌ 秒数必须是 ${MIN_SESSION_LOOP_SECONDS}-${MAX_SESSION_LOOP_SECONDS} 的整数` };
|
|
602
|
+
next = { enabled: true, idleSeconds: seconds };
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
const latest = await refreshSessionLoopTarget(this.sessionManager, route, target);
|
|
606
|
+
if (next.enabled)
|
|
607
|
+
this.assertSessionLoopTrigger(latest.session);
|
|
608
|
+
const updated = writeSessionLoopConfig(this.sessionManager, latest, next);
|
|
609
|
+
const payload = sessionLoopPayload(updated);
|
|
610
|
+
if (this.shouldSuppressCardTriggerResult(source, channel))
|
|
611
|
+
return null;
|
|
612
|
+
return { kind: 'command.result', text: `✅ idle 触发(${updated.level},session=${updated.session.id})已${payload.value ? `开启(${payload.idleSeconds} 秒)` : '关闭'}` };
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
return { kind: 'command.error', text: `❌ ${error instanceof Error ? error.message : String(error)}` };
|
|
616
|
+
}
|
|
617
|
+
}
|
|
537
618
|
const interruptPausedSessionBeforeReplacement = async (commandSession) => {
|
|
538
619
|
if (commandSession && (this.processor?.isPauseRequested?.(commandSession.id) ?? false)) {
|
|
539
620
|
this.eventBus.publish({
|
|
@@ -642,6 +723,8 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
642
723
|
};
|
|
643
724
|
// /help 命令不需要会话
|
|
644
725
|
if (normalizedContent === '/help') {
|
|
726
|
+
const canReadLoop = canAccessSlashOperation('session.loop.current', 'relation');
|
|
727
|
+
const canUpdateLoop = canAccessSlashOperation('session.loop.update', 'relation');
|
|
645
728
|
if (groupSlash) {
|
|
646
729
|
const lines = [
|
|
647
730
|
'群聊可用命令:',
|
|
@@ -653,6 +736,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
653
736
|
' /baseagent - 查看 Agent 后端',
|
|
654
737
|
' /perm - 查看权限模式',
|
|
655
738
|
' /mention - 查看群聊 @ 处理模式',
|
|
739
|
+
...(canReadLoop ? [` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
656
740
|
' /ask <选项> - 回答待处理问题',
|
|
657
741
|
' /pause - 在下一次工具调用前暂停任务',
|
|
658
742
|
' /resume - 继续已暂停的任务',
|
|
@@ -660,6 +744,9 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
660
744
|
...(isAdmin ? [
|
|
661
745
|
' /compact - 压缩会话上下文',
|
|
662
746
|
...(threadId ? [' /renew - 轮换当前话题的后端会话'] : []),
|
|
747
|
+
' /memory - 查看本群关系记忆',
|
|
748
|
+
' /skill - 查看技能列表',
|
|
749
|
+
' /thread - 查看本群话题',
|
|
663
750
|
] : []),
|
|
664
751
|
'',
|
|
665
752
|
'模型、推理强度、后端与权限在群聊中仅支持查询;@ 模式可由管理员切换。',
|
|
@@ -695,6 +782,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
695
782
|
'',
|
|
696
783
|
'💬 聊天设置:',
|
|
697
784
|
...(canReadChatmode || canSetChatmode ? [` /chatmode${canSetChatmode ? ' [interactive|proactive]' : ''} - 查看${canSetChatmode ? '或切换' : ''}会话模式`] : []),
|
|
785
|
+
...(canReadLoop ? [` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
698
786
|
...(canReadMentionmode || canSetMentionmode ? [` /mention${canSetMentionmode ? ' [mention-only|disabled]' : ''} - 查看${canSetMentionmode ? '或切换' : ''}群聊 @ 处理模式`] : []),
|
|
699
787
|
] : []),
|
|
700
788
|
...(canReadPermission || canAnswerPermission ? [
|
|
@@ -739,6 +827,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
739
827
|
'💬 聊天设置:',
|
|
740
828
|
` /chatmode${canSetChatmode ? ' [interactive|proactive]' : ''} - 查看${canSetChatmode ? '或切换' : ''}会话模式`,
|
|
741
829
|
] : []),
|
|
830
|
+
...(canReadLoop ? ['', ` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
742
831
|
...(canReadPermission || canAnswerPermission ? [
|
|
743
832
|
'',
|
|
744
833
|
'🔐 权限管理:',
|
|
@@ -786,6 +875,12 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
786
875
|
' /activity [all|text|none] - 查看/控制中间输出显示模式',
|
|
787
876
|
...(canReadChatmode || canSetChatmode ? [` /chatmode${canSetChatmode ? ' [interactive|proactive]' : ''} - 查看${canSetChatmode ? '/切换' : ''}会话模式(被动响应或主动推进)`] : []),
|
|
788
877
|
...(canReadMentionmode || canSetMentionmode ? [` /mention${canSetMentionmode ? ' [mention-only|disabled]' : ''} - 查看${canSetMentionmode ? '/切换' : ''}群聊 @ 处理模式`] : []),
|
|
878
|
+
...(canReadLoop ? [` /loop${canUpdateLoop ? ' [on [seconds]|off]' : ''} - 查看${canUpdateLoop ? '或设置' : ''}当前会话的单次闲置触发`] : []),
|
|
879
|
+
'',
|
|
880
|
+
'🧠 上下文:',
|
|
881
|
+
' /memory - 记忆概览与维护',
|
|
882
|
+
' /skill - 技能列表与索引刷新',
|
|
883
|
+
' /thread - 话题列表、更名与 summary',
|
|
789
884
|
'',
|
|
790
885
|
'🔐 权限管理:',
|
|
791
886
|
...(canReadPermission ? [' /perm - 查看当前权限模式'] : []),
|
|
@@ -848,9 +943,19 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
848
943
|
}
|
|
849
944
|
// /evolhelp 命令:返回 JSON 格式的命令列表(供程序解析)
|
|
850
945
|
if (normalizedContent === '/evolhelp') {
|
|
946
|
+
const canReadLoop = canAccessSlashOperation('session.loop.current', 'relation');
|
|
947
|
+
const canUpdateLoop = canAccessSlashOperation('session.loop.update', 'relation');
|
|
948
|
+
const loopHelp = canReadLoop || canUpdateLoop ? [{
|
|
949
|
+
command: '/loop',
|
|
950
|
+
...(canUpdateLoop ? { args: '[on [seconds]|off]' } : {}),
|
|
951
|
+
description: '查看或设置当前主会话/话题的单次闲置触发',
|
|
952
|
+
category: '聊天设置',
|
|
953
|
+
roles: [identity.role],
|
|
954
|
+
}] : [];
|
|
851
955
|
if (groupSlash) {
|
|
852
956
|
const canSetMentionmode = canAccessSlashOperation('mentionmode.update', 'relation');
|
|
853
957
|
const commands = [
|
|
958
|
+
...loopHelp,
|
|
854
959
|
{ command: '/help', description: '显示帮助信息', category: '帮助', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
855
960
|
{ command: '/status', description: '显示会话状态', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
856
961
|
{ command: '/check', description: '检查 EvolAgent 实例健康', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] },
|
|
@@ -867,13 +972,24 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
867
972
|
if (isAdmin) {
|
|
868
973
|
commands.push({ command: '/compact', description: '压缩会话上下文', category: '会话管理', roles: ['admin', 'owner'] }, ...(threadId ? [{ command: '/renew', description: '轮换当前话题 backend', category: '会话管理', roles: ['admin', 'owner'] }] : []));
|
|
869
974
|
}
|
|
870
|
-
//
|
|
975
|
+
// 记忆管理紧跟权限管理;技能 / 话题管理跟随其后
|
|
871
976
|
const groupMemoryEntries = memoryHelpEntries({ chatType: 'group', role: identity.role, isAdmin, isOwnerSelf: false });
|
|
872
977
|
const lastPermIdx = commands.map(c => c.category).lastIndexOf('权限管理');
|
|
873
|
-
|
|
978
|
+
const insertAt = lastPermIdx >= 0 ? lastPermIdx + 1 : commands.length;
|
|
979
|
+
commands.splice(insertAt, 0, ...groupMemoryEntries);
|
|
980
|
+
const groupExtras = [
|
|
981
|
+
...skillHelpEntries({ chatType: 'group', role: identity.role, isAdmin }),
|
|
982
|
+
...topicHelpEntries({
|
|
983
|
+
chatType: 'group',
|
|
984
|
+
role: identity.role,
|
|
985
|
+
isAdmin,
|
|
986
|
+
peerKey: authSubject.peerKey,
|
|
987
|
+
}),
|
|
988
|
+
];
|
|
989
|
+
commands.splice(insertAt + groupMemoryEntries.length, 0, ...groupExtras);
|
|
874
990
|
return { kind: 'command.result', text: JSON.stringify({ commands, categories: [...new Set(commands.map(c => c.category))] }) };
|
|
875
991
|
}
|
|
876
|
-
const cmds = [];
|
|
992
|
+
const cmds = [...loopHelp];
|
|
877
993
|
const canReadModel = canAccessSlashOperation('model.current', 'relation')
|
|
878
994
|
|| canAccessSlashOperation('model.list', 'relation');
|
|
879
995
|
const canUseModel = canAccessSlashOperation('model.use', 'relation');
|
|
@@ -920,6 +1036,16 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
920
1036
|
isAdmin,
|
|
921
1037
|
isOwnerSelf: isOwner && !!memoryOwnerForHelp && (authSubject.principalId ?? userId) === memoryOwnerForHelp,
|
|
922
1038
|
}));
|
|
1039
|
+
// 技能管理 / 话题管理(紧随记忆管理)
|
|
1040
|
+
cmds.push(...skillHelpEntries({ chatType: 'private', role: identity.role, isAdmin }));
|
|
1041
|
+
const topicHelpCtx = {
|
|
1042
|
+
chatType: activeChatType === 'group' ? 'group' : 'private',
|
|
1043
|
+
role: identity.role,
|
|
1044
|
+
isAdmin,
|
|
1045
|
+
peerKey: authSubject.peerKey,
|
|
1046
|
+
};
|
|
1047
|
+
if (canUseTopicSlash(topicHelpCtx))
|
|
1048
|
+
cmds.push(...topicHelpEntries(topicHelpCtx));
|
|
923
1049
|
// 运维
|
|
924
1050
|
cmds.push({ command: '/status', description: '显示会话状态', category: '运维', roles: ['visitor', 'member', 'admin', 'owner'] });
|
|
925
1051
|
cmds.push({ command: '/pause', description: '在下一次工具调用前暂停当前任务', category: '运维', roles: ['admin', 'owner'] });
|
|
@@ -3130,11 +3256,23 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3130
3256
|
channelId,
|
|
3131
3257
|
agentName: 'system',
|
|
3132
3258
|
chatmode: 'interactive',
|
|
3133
|
-
replyContext:
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3259
|
+
replyContext: {
|
|
3260
|
+
...(restartReplyContext ?? (chatType === 'group'
|
|
3261
|
+
? { delivery: { chatType: 'group', groupId: channelId } }
|
|
3262
|
+
: chatType === 'private'
|
|
3263
|
+
? { delivery: { chatType: 'private' } }
|
|
3264
|
+
: {})),
|
|
3265
|
+
// This notice describes the process that is about to die. If it
|
|
3266
|
+
// cannot be handed to the gateway before the shutdown tears the
|
|
3267
|
+
// transport down, the replacement process must NOT replay it:
|
|
3268
|
+
// it already sends its own "restart succeeded" confirmation, and
|
|
3269
|
+
// a late copy of the pre-restart notice is confusing rather than
|
|
3270
|
+
// informative.
|
|
3271
|
+
metadata: {
|
|
3272
|
+
...(restartReplyContext?.metadata ?? {}),
|
|
3273
|
+
processScopedDelivery: true,
|
|
3274
|
+
},
|
|
3275
|
+
},
|
|
3138
3276
|
});
|
|
3139
3277
|
await adapter.send(envelope, { kind: 'command.result', text: '🔄 服务正在重启,请稍候...(约 5 秒后恢复)' });
|
|
3140
3278
|
// 等待消息发送完成后再延迟 kill
|
|
@@ -3670,6 +3808,21 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3670
3808
|
logger.debug('[CommandHandler] Backend session rename sync failed:', error);
|
|
3671
3809
|
});
|
|
3672
3810
|
}
|
|
3811
|
+
// P1.2: 若当前是话题会话,同步更新话题索引
|
|
3812
|
+
if (success && session.threadId) {
|
|
3813
|
+
try {
|
|
3814
|
+
const { ThreadService } = await import('../../core/thread/index.js');
|
|
3815
|
+
const selfAid = session.selfAID;
|
|
3816
|
+
const peer = session.channelId;
|
|
3817
|
+
if (selfAid && peer) {
|
|
3818
|
+
const svc = new ThreadService(this.sessionManager);
|
|
3819
|
+
await svc.renameThread({ selfAid, peer, threadId: session.threadId, name: newName });
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
catch (err) {
|
|
3823
|
+
logger.debug('[CommandHandler] Thread index rename sync failed:', err);
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3673
3826
|
if (!success) {
|
|
3674
3827
|
return { kind: 'command.error', text: `❌ 重命名失败` };
|
|
3675
3828
|
}
|
|
@@ -3886,6 +4039,35 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3886
4039
|
return { kind: 'command.error', text: `❌ 修复失败: ${error.message}` };
|
|
3887
4040
|
}
|
|
3888
4041
|
}
|
|
4042
|
+
// /skill 命令:技能查看与索引刷新(写操作请走 ec skill / ec-skill 技能)
|
|
4043
|
+
if (normalizedContent === '/skill' || normalizedContent.startsWith('/skill ')) {
|
|
4044
|
+
return await handleSkillSlash({
|
|
4045
|
+
content: normalizedContent,
|
|
4046
|
+
selfAid: authSubject.selfAid,
|
|
4047
|
+
chatType: activeChatType === 'group' ? 'group' : 'private',
|
|
4048
|
+
role: identity.role,
|
|
4049
|
+
isAdmin,
|
|
4050
|
+
// 注意:getSkillIndexRefresher 是 getter,必须调用取值;只 .bind 会把这个
|
|
4051
|
+
// getter 本身当成 refresher 传下去,导致 /skill refresh 永远返回「未知错误」。
|
|
4052
|
+
refresher: this.getSkillIndexRefresher?.(),
|
|
4053
|
+
// manifest 的 when 判定要用同一个 lifecycle 值,否则 /skill index 会误报未加载
|
|
4054
|
+
lifecycle: this.agentRegistry?.get?.(authSubject.selfAid ?? '')?.lifecycle ?? null,
|
|
4055
|
+
});
|
|
4056
|
+
}
|
|
4057
|
+
// /thread 命令:话题查看与管理
|
|
4058
|
+
if (normalizedContent === '/thread' || normalizedContent.startsWith('/thread ')) {
|
|
4059
|
+
return await handleTopicSlash({
|
|
4060
|
+
content: normalizedContent,
|
|
4061
|
+
selfAid: authSubject.selfAid,
|
|
4062
|
+
peerKey: authSubject.peerKey,
|
|
4063
|
+
chatType: activeChatType === 'group' ? 'group' : 'private',
|
|
4064
|
+
role: identity.role,
|
|
4065
|
+
isAdmin,
|
|
4066
|
+
threadId,
|
|
4067
|
+
sessionId: activeSession?.id,
|
|
4068
|
+
sessionManager: this.sessionManager,
|
|
4069
|
+
});
|
|
4070
|
+
}
|
|
3889
4071
|
// /trigger 命令
|
|
3890
4072
|
if (normalizedContent === '/memory' || normalizedContent.startsWith('/memory ')) {
|
|
3891
4073
|
const memoryAgent = this.agentRegistry?.get?.(authSubject.selfAid ?? '');
|
|
@@ -3928,7 +4110,7 @@ export async function handleSlashCommand(content, channel, channelId, sendMessag
|
|
|
3928
4110
|
});
|
|
3929
4111
|
if (triggerAuthDenied)
|
|
3930
4112
|
return triggerAuthDenied;
|
|
3931
|
-
const text = await this.handleTrigger(normalizedContent, channel, channelId, userId ?? '', isAdmin, messageId,
|
|
4113
|
+
const text = await this.handleTrigger(normalizedContent, channel, channelId, userId ?? '', isAdmin, messageId, activeChatType, threadId, isDaemonOwner, authSubject.canApprovePersistentFullAccess);
|
|
3932
4114
|
return { kind: 'command.result', text };
|
|
3933
4115
|
}
|
|
3934
4116
|
return null;
|