evolcore 0.0.28 → 0.0.29
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 +12 -0
- package/bin/ec-safe-output.js +270 -54
- package/dist/agents/baseagent-availability.js +37 -1
- package/dist/agents/baseagent.js +19 -9
- package/dist/agents/claude-runner.js +171 -13
- package/dist/agents/codex/app-server-client.js +6 -2
- package/dist/agents/codex/diagnostics.js +4 -3
- package/dist/agents/codex-runner.js +396 -95
- package/dist/agents/gemini-runner.js +35 -17
- package/dist/aun/group/history.js +130 -90
- package/dist/aun/group/operations.js +1 -3
- package/dist/aun/menu/transport.js +5 -3
- package/dist/aun/msg/managed-operation.js +70 -0
- package/dist/aun/msg/p2p.js +1 -3
- package/dist/aun/msg/upload.js +2 -2
- package/dist/aun/outbox.js +1 -37
- package/dist/channels/aun.js +249 -89
- package/dist/channels/daemon.js +18 -1
- package/dist/channels/feishu.js +1 -2
- package/dist/cli/agent-command.js +23 -3
- package/dist/cli/agent-create.js +68 -2
- package/dist/cli/agent.js +12 -2
- package/dist/cli/aun-commands.js +87 -13
- package/dist/cli/cli-argv.js +26 -0
- package/dist/cli/daemon-commands.js +40 -10
- package/dist/cli/data-command.js +4 -4
- package/dist/cli/handoff-command.js +2 -0
- package/dist/cli/index.js +18 -1
- package/dist/cli/managed-command-guard.js +10 -0
- package/dist/cli/memory-command.js +441 -0
- package/dist/cli/restart-monitor.js +62 -6
- package/dist/cli/skill-command.js +41 -0
- package/dist/cli/task-context.js +2 -23
- package/dist/cli/trigger-command.js +9 -1
- package/dist/cli/watch-msg-diag.js +209 -0
- package/dist/config/config-field-policy.js +52 -3
- package/dist/config/config-manager.js +17 -4
- package/dist/config/contact-book-store.js +2 -2
- package/dist/config/mention-mode.js +7 -2
- package/dist/config/merge.js +28 -9
- package/dist/config/resolved-config-op.js +1 -1
- package/dist/config/runtime-env.js +137 -0
- package/dist/config/schema-registry.js +11 -1
- package/dist/config-store.js +10 -10
- package/dist/core/audit/event-key.js +3 -1
- package/dist/core/audit/log-integrity.js +4 -0
- package/dist/core/auth/agent-delegation.js +2 -1
- package/dist/core/auth/auth-gateway.js +13 -6
- package/dist/core/auth/authorization-audit.js +54 -19
- package/dist/core/auth/operation-authorizer.js +17 -0
- package/dist/core/auth/operation-catalog.js +9 -0
- package/dist/core/causation/context.js +5 -1
- package/dist/core/command/agent-control.js +1 -2
- package/dist/core/command/command-handler.js +51 -23
- package/dist/core/command/memory-slash.js +270 -0
- package/dist/core/command/menu-catalog.js +1 -0
- package/dist/core/command/menu-handler.js +315 -60
- package/dist/core/command/menu-protocol.js +42 -4
- package/dist/core/command/slash-gate.js +10 -10
- package/dist/core/command/slash-handler.js +206 -64
- package/dist/core/data-migration.js +282 -505
- package/dist/core/event-catalog.js +26 -0
- package/dist/core/evolagent-registry.js +6 -0
- package/dist/core/evolagent.js +0 -10
- package/dist/core/handoff/store.js +1 -20
- package/dist/core/inference/text-inference.js +57 -1
- package/dist/core/memory/consolidation-context.js +505 -0
- package/dist/core/memory/consolidation-ops-records.js +124 -0
- package/dist/core/memory/consolidation-trigger.js +394 -0
- package/dist/core/memory/index-manager.js +308 -0
- package/dist/core/memory/launch-consolidation.js +395 -0
- package/dist/core/memory/memory-admin.js +234 -0
- package/dist/core/memory/memory-document.js +100 -0
- package/dist/core/memory/memory-session-policy.js +41 -0
- package/dist/core/memory/memory-signature.js +257 -0
- package/dist/core/memory/memory-writer.js +432 -0
- package/dist/core/memory/staleness.js +117 -0
- package/dist/core/message/auto-mention-gate.js +454 -0
- package/dist/core/message/im-renderer.js +69 -16
- package/dist/core/message/message-bridge.js +287 -21
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +114 -27
- package/dist/core/message/pending-hints.js +329 -161
- package/dist/core/message/response-engine.js +567 -80
- package/dist/core/permission/ec-command-parser.js +1029 -80
- package/dist/core/permission/protected-paths.js +376 -126
- package/dist/core/permission/sandbox-runtime.js +40 -12
- package/dist/core/permission/tool-error-code.js +96 -13
- package/dist/core/permission/tool-policy.js +276 -23
- package/dist/core/role/runtime-policy.js +3 -7
- package/dist/core/session/{runner-task-history.js → runner-event-summary.js} +1 -1
- package/dist/core/session/session-fs-store.js +0 -76
- package/dist/core/session/session-idle-monitor.js +355 -0
- package/dist/core/session/session-manager.js +478 -17
- package/dist/core/session/session-mapper.js +33 -16
- package/dist/core/session/session-renew.js +217 -155
- package/dist/core/session/{session-turns.js → session-transcript.js} +35 -6
- package/dist/core/skill/global-watcher.js +282 -0
- package/dist/core/skill/index-generator.js +84 -0
- package/dist/core/skill/startup.js +73 -0
- package/dist/core/skill/switch-resolver.js +115 -0
- package/dist/core/task/task-activity-store.js +219 -0
- package/dist/eck/kit-renderer.js +30 -3
- package/dist/eck/manifest-engine.js +26 -4
- package/dist/index.js +708 -18
- package/dist/ipc.js +564 -2
- package/dist/paths.js +30 -9
- package/dist/response-system/engines/v1/proactive-flow.js +116 -15
- package/dist/response-system/modes/single-session/index.js +3 -0
- package/dist/trigger/feedback.js +1 -0
- package/dist/trigger/manager.js +0 -10
- package/dist/trigger/scheduler.js +11 -0
- package/dist/trigger/validation.js +22 -0
- package/dist/utils/avatar-upload.js +59 -18
- package/dist/utils/error-dict.json +6 -3
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/logger.js +32 -10
- package/dist/utils/media-cache.js +84 -0
- package/dist/utils/msg-diag.js +97 -0
- package/dist/utils/welcome.js +37 -8
- package/kits/docs/AUTHORING.md +314 -0
- package/kits/docs/GUIDE.md +2 -0
- package/kits/docs/INDEX.md +2 -0
- package/kits/docs/aun/CHEATSHEET.md +4 -0
- package/kits/docs/aun/SDK.md +60 -0
- package/kits/docs/context-assembly.md +10 -6
- package/kits/docs/evolcore/INDEX.md +17 -3
- package/kits/docs/evolcore/agent-create.md +24 -0
- package/kits/docs/evolcore/agent.md +5 -2
- package/kits/docs/evolcore/config.md +1 -1
- package/kits/docs/evolcore/ec-capabilities.md +364 -0
- package/kits/docs/evolcore/group.md +34 -18
- package/kits/docs/evolcore/memory-architecture.md +78 -0
- package/kits/docs/evolcore/memory-consolidation-batches.md +133 -0
- package/kits/docs/evolcore/memory-consolidation.md +263 -0
- package/kits/docs/evolcore/memory-tags.md +63 -0
- package/kits/docs/evolcore/memory.md +110 -0
- package/kits/docs/evolcore/menu-client.md +27 -11
- package/kits/{schemas → docs/evolcore}/menu-exec-schema-commands.md +12 -6
- package/kits/docs/evolcore/menu-protocol.md +213 -0
- package/kits/docs/evolcore/msg.md +2 -0
- package/kits/docs/evolcore/trigger.md +7 -5
- package/kits/docs/path-registry.md +6 -8
- package/kits/docs/prompt-loading-architecture.md +5 -3
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +294 -88
- package/kits/eck_manifest.memory.json +257 -0
- package/kits/rules/03-identity.md +8 -8
- package/kits/rules/05-venue.md +4 -2
- package/kits/rules/06-channel.md +1 -1
- package/kits/schemas/_meta.json +276 -47
- package/kits/schemas/agent-config.schema.12.json +38 -2
- package/kits/schemas/agent-config.schema.13.json +591 -0
- package/kits/schemas/daemon.schema.6.json +9 -9
- package/kits/schemas/defaults.schema.5.json +29 -0
- package/kits/schemas/relation-config.schema.8.json +14 -1
- package/kits/schemas/relation-config.schema.9.json +129 -0
- package/kits/schemas/role-config.schema.1.json +3 -3
- package/kits/skills/.switches.json +3 -0
- package/kits/skills/ec-skill/SKILL.md +217 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +128 -0
- package/kits/skills/ec-skill/scripts/deps.mjs +107 -0
- package/kits/skills/ec-skill/scripts/frontmatter.mjs +104 -0
- package/kits/skills/ec-skill/scripts/skill.mjs +629 -0
- package/kits/skills/ec-skill/scripts/template/SKILL.md.tmpl +30 -0
- package/kits/templates/decision/auto-mention.md +25 -0
- package/kits/templates/decision/session-renew.md +22 -0
- package/kits/templates/memory-consolidation/forget.md +104 -0
- package/kits/templates/memory-consolidation/generalize.md +76 -0
- package/kits/templates/memory-consolidation/notes.md +133 -0
- package/kits/templates/memory-consolidation/profile.md +58 -0
- package/kits/templates/memory-consolidation/promote.md +72 -0
- package/kits/templates/memory-consolidation/workflow.md +75 -0
- package/kits/templates/system-fragments/bootstrap.md +14 -5
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/group-history.md +6 -0
- package/kits/templates/system-fragments/identity.md +0 -3
- package/kits/templates/system-fragments/memory.md +79 -0
- package/kits/templates/system-fragments/reply.md +1 -0
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -6
- package/dist/trigger/legacy-session-history.js +0 -19
- package/kits/templates/system-fragments/group-unread-history.md +0 -7
package/dist/channels/daemon.js
CHANGED
|
@@ -222,7 +222,24 @@ export class DaemonChannel {
|
|
|
222
222
|
const threadId = mode.thread === 'by_run'
|
|
223
223
|
? `trigger:${trigger.id}:${runId}`
|
|
224
224
|
: `trigger:${trigger.id}`;
|
|
225
|
-
|
|
225
|
+
// 记忆整理会话:把会话原型与整理模式写进 metadata,供渲染层选 manifest / 手册,
|
|
226
|
+
// 供 ipc 侧校验写命令的 --scope。
|
|
227
|
+
const { memoryMode, memoryScope, consolidationBatchDir, consolidationChatDir, consolidationMemoryDir } = trigger.execution;
|
|
228
|
+
// 反馈目标与触发方式(launch-consolidation 在 normalize 后补挂的字段):
|
|
229
|
+
// 收尾时据此投递反馈,并判断是否该反馈(定时触发不反馈)。
|
|
230
|
+
const { feedbackOrigin, consolidationTriggeredBy } = trigger.execution;
|
|
231
|
+
return await this.sessionManager.getOrCreateSession(this.channelName, channelId, projectPath, threadId, {
|
|
232
|
+
channelKey: this.channelKey,
|
|
233
|
+
peerId: `trigger:${trigger.id}`,
|
|
234
|
+
peerName: trigger.name,
|
|
235
|
+
...(memoryMode ? { sessionType: 'memory', memoryMode } : {}),
|
|
236
|
+
...(memoryScope ? { memoryScope } : {}),
|
|
237
|
+
...(consolidationBatchDir ? { consolidationBatchDir } : {}),
|
|
238
|
+
...(consolidationChatDir ? { consolidationChatDir } : {}),
|
|
239
|
+
...(consolidationMemoryDir ? { consolidationMemoryDir } : {}),
|
|
240
|
+
...(feedbackOrigin ? { feedbackOrigin } : {}),
|
|
241
|
+
...(consolidationTriggeredBy ? { consolidationTriggeredBy } : {}),
|
|
242
|
+
}, trigger.name, undefined, 'private', baseagent, trigger.agentAid, this.channelName, 'system');
|
|
226
243
|
}
|
|
227
244
|
executionDeadlineAt(startedAt = Date.now()) {
|
|
228
245
|
return this.totalExecutionMs === undefined
|
package/dist/channels/feishu.js
CHANGED
|
@@ -1734,8 +1734,7 @@ export class FeishuChannelPlugin {
|
|
|
1734
1734
|
case 'system.error':
|
|
1735
1735
|
case 'result.error': {
|
|
1736
1736
|
const sendCtx = { ...(replyCtx ?? {}) };
|
|
1737
|
-
|
|
1738
|
-
sendCtx.title = '✅ 最终回复:';
|
|
1737
|
+
// isFinal is now carried via payload.ext by response-engine; no title injection here.
|
|
1739
1738
|
if (replyCtx?.metadata?.onThreadCreated)
|
|
1740
1739
|
sendCtx.onThreadCreated = replyCtx.metadata.onThreadCreated;
|
|
1741
1740
|
const ids = await channel.sendMessage(channelId, payload.text, sendCtx);
|
|
@@ -4,6 +4,9 @@ import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
|
4
4
|
import { isHostChinese } from '../utils/locale.js';
|
|
5
5
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
6
6
|
import { parseAgentWelcomeArgs } from './agent-create.js';
|
|
7
|
+
import { assertEcSingleLine } from './cli-argv.js';
|
|
8
|
+
import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
|
|
9
|
+
import { parseAgentAvatarArgs } from './agent-create.js';
|
|
7
10
|
function printBootstrapDeliveries(result) {
|
|
8
11
|
for (const delivery of result?.deliveries ?? []) {
|
|
9
12
|
if (delivery.status === 'sent')
|
|
@@ -40,7 +43,13 @@ function formatBytes(bytes) {
|
|
|
40
43
|
}
|
|
41
44
|
// ==================== Agent ====================
|
|
42
45
|
export async function cmdAgent(args) {
|
|
46
|
+
args = canonicalizeEvolcoreCommandArgv(['ec', 'agent', ...args]).slice(2);
|
|
43
47
|
const sub = args[0];
|
|
48
|
+
if (sub === 'new') {
|
|
49
|
+
const nameIndex = args.indexOf('--name');
|
|
50
|
+
if (nameIndex >= 0)
|
|
51
|
+
assertEcSingleLine(args[nameIndex + 1], '--name');
|
|
52
|
+
}
|
|
44
53
|
const formatJson = getArgValue(args, '--format') === 'json';
|
|
45
54
|
const commands = new Set(['list', 'show', 'new', 'initialize', 'enable', 'disable', 'get', 'set', 'persona', 'welcome', 'rename', 'ready', 'reload', 'delete']);
|
|
46
55
|
if (sub === 'create') {
|
|
@@ -95,7 +104,7 @@ Options:
|
|
|
95
104
|
}
|
|
96
105
|
if ((sub === 'new' && args.includes('--initialize')) || sub === 'initialize') {
|
|
97
106
|
if (wantsHelp(args)) {
|
|
98
|
-
console.log('ec agent new <aid> --initialize
|
|
107
|
+
console.log('ec agent new <aid> --initialize ... [--avatar-file <path> | --avatar-url <https-url>] [--wait 0..300] [--format json]\nec agent initialize <aid> --resume [--wait 0..300] [--format json]\n--initialize implies --non-interactive; waits for activation (default 60 seconds).');
|
|
99
108
|
return;
|
|
100
109
|
}
|
|
101
110
|
try {
|
|
@@ -270,6 +279,8 @@ Options:
|
|
|
270
279
|
--owner <aid> 默认: daemon.json 第一个 owner
|
|
271
280
|
--owners <json-array> 多个 Owner;与 --owner 互斥
|
|
272
281
|
--handoff <context> 当前任务的 Bootstrap 上下文
|
|
282
|
+
--avatar-file <path> 头像图片文件(沿用 ec aid avatar)
|
|
283
|
+
--avatar-url <https-url> 头像 HTTPS 地址(沿用 ec aid avatar)
|
|
273
284
|
--name <display-name> 默认: package.json name,否则目录名
|
|
274
285
|
--description <text> 默认: package.json description,否则使用 EvolCore 默认描述
|
|
275
286
|
--type <type> 主体类型: human|agent|group|service|device|org|host(默认 agent)
|
|
@@ -306,8 +317,10 @@ Options:
|
|
|
306
317
|
return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
|
|
307
318
|
};
|
|
308
319
|
let ownerOptions;
|
|
320
|
+
let avatarOptions;
|
|
309
321
|
try {
|
|
310
322
|
ownerOptions = parseAgentOwnerArgs(args);
|
|
323
|
+
avatarOptions = parseAgentAvatarArgs(args);
|
|
311
324
|
}
|
|
312
325
|
catch (error) {
|
|
313
326
|
const result = { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
@@ -336,6 +349,7 @@ Options:
|
|
|
336
349
|
project: getArg('--project'),
|
|
337
350
|
baseagent: getArg('--baseagent'),
|
|
338
351
|
...ownerOptions,
|
|
352
|
+
...avatarOptions,
|
|
339
353
|
handoff: getArg('--handoff'),
|
|
340
354
|
name: getArg('--name'),
|
|
341
355
|
description: getArg('--description'),
|
|
@@ -381,6 +395,8 @@ Options:
|
|
|
381
395
|
type: plan.type,
|
|
382
396
|
tags: plan.tags,
|
|
383
397
|
force: args.includes('--force'),
|
|
398
|
+
avatarFile: plan.avatarFile,
|
|
399
|
+
avatarUrl: plan.avatarUrl,
|
|
384
400
|
});
|
|
385
401
|
if (!result.ok) {
|
|
386
402
|
if (formatJson) {
|
|
@@ -498,11 +514,14 @@ Options:
|
|
|
498
514
|
热重载 agent 配置。
|
|
499
515
|
无参数 全量 resync(扫磁盘,新增上线、删除下线、修改热更新)
|
|
500
516
|
<aid> 仅热重载指定 agent
|
|
501
|
-
--force 中断目标 Agent 的运行中任务并清空排队任务后重载(仅与 <aid>
|
|
517
|
+
--force 中断目标 Agent 的运行中任务并清空排队任务后重载(仅与 <aid> 同用)
|
|
518
|
+
重载时自动读取当前终端的 ANTHROPIC_* 环境变量`);
|
|
502
519
|
return;
|
|
503
520
|
}
|
|
504
521
|
const target = args[1] && !args[1].startsWith('--') ? args[1] : undefined;
|
|
505
|
-
const result = await agentReload(target, {
|
|
522
|
+
const result = await agentReload(target, {
|
|
523
|
+
force: args.includes('--force'),
|
|
524
|
+
});
|
|
506
525
|
if (!result.ok) {
|
|
507
526
|
if (formatJson) {
|
|
508
527
|
console.log(JSON.stringify(result));
|
|
@@ -906,6 +925,7 @@ Options:
|
|
|
906
925
|
console.error('用法: ec agent rename <aid> <name>');
|
|
907
926
|
process.exit(1);
|
|
908
927
|
}
|
|
928
|
+
assertEcSingleLine(name, '<name>');
|
|
909
929
|
const result = await agentRename(aid, name);
|
|
910
930
|
if (!result.ok) {
|
|
911
931
|
if (formatJson) {
|
package/dist/cli/agent-create.js
CHANGED
|
@@ -19,6 +19,7 @@ import { AGENT_DESCRIPTION_MAX_LENGTH, AGENT_TAG_MAX_COUNT, AGENT_TAG_MIN_COUNT,
|
|
|
19
19
|
import { atomicWriteJson } from '../utils/atomic-write.js';
|
|
20
20
|
import { isHClassPath, isLClassPath, isSameOrDescendant } from '../core/permission/protected-paths.js';
|
|
21
21
|
import { MAIN_CLI_BIN } from '../product.js';
|
|
22
|
+
import { uploadAvatarFile, uploadAvatarUrl } from '../utils/avatar-upload.js';
|
|
22
23
|
/** Parse the current Agent's Bootstrap welcome subcommand. */
|
|
23
24
|
export function parseAgentWelcomeArgs(args) {
|
|
24
25
|
const tail = args.at(-2) === '--format' && args.at(-1) === 'json' ? args.slice(0, -2) : args;
|
|
@@ -29,6 +30,25 @@ export function parseAgentWelcomeArgs(args) {
|
|
|
29
30
|
}
|
|
30
31
|
throw new Error(`用法: ${MAIN_CLI_BIN} agent welcome show | --text <text> [--format json]`);
|
|
31
32
|
}
|
|
33
|
+
export function parseAgentAvatarArgs(argv) {
|
|
34
|
+
const hasFile = argv.includes('--avatar-file');
|
|
35
|
+
const hasUrl = argv.includes('--avatar-url');
|
|
36
|
+
if (argv.filter(arg => arg === '--avatar-file').length > 1 || argv.filter(arg => arg === '--avatar-url').length > 1) {
|
|
37
|
+
throw new Error('--avatar-file and --avatar-url may each be supplied once');
|
|
38
|
+
}
|
|
39
|
+
if (hasFile && hasUrl)
|
|
40
|
+
throw new Error('--avatar-file and --avatar-url are mutually exclusive');
|
|
41
|
+
const flag = hasFile ? '--avatar-file' : hasUrl ? '--avatar-url' : undefined;
|
|
42
|
+
if (!flag)
|
|
43
|
+
return {};
|
|
44
|
+
const value = argv[argv.indexOf(flag) + 1];
|
|
45
|
+
if (!value || value.startsWith('--'))
|
|
46
|
+
throw new Error(`${flag} requires a value`);
|
|
47
|
+
if (value.startsWith('attachment:') && !process.env.EVOLCORE_SESSION_ID) {
|
|
48
|
+
throw new Error('attachment:<id> avatar sources require a managed Agent task');
|
|
49
|
+
}
|
|
50
|
+
return hasFile ? { avatarFile: value } : { avatarUrl: value };
|
|
51
|
+
}
|
|
32
52
|
export function parseAgentTags(raw) {
|
|
33
53
|
if (raw === undefined)
|
|
34
54
|
return undefined;
|
|
@@ -203,7 +223,8 @@ export function resolveAgentCreatePlan(options) {
|
|
|
203
223
|
const type = requestedType ? (normalizeAgentType(requestedType) ?? requestedType) : DEFAULT_AGENT_TYPE;
|
|
204
224
|
const configExists = isValidAid(aid) && fs.existsSync(path.join(resolvePaths().agentsDir, aid, 'config.json'));
|
|
205
225
|
return {
|
|
206
|
-
aid, project, baseagent, owner, owners, handoff: options.handoff,
|
|
226
|
+
aid, project, baseagent, owner, owners, handoff: options.handoff, avatarFile: options.avatarFile, avatarUrl: options.avatarUrl,
|
|
227
|
+
name, description, type, tags: options.tags,
|
|
207
228
|
force: options.force === true, configExists, baseagentSource, ownerSource,
|
|
208
229
|
nameSource: options.name?.trim() ? 'argument' : metadata.name ? 'package' : 'directory',
|
|
209
230
|
descriptionSource: explicitDescription ? 'argument' : packageDescription ? 'package' : 'default',
|
|
@@ -216,6 +237,8 @@ export function validateAgentCreatePlan(plan) {
|
|
|
216
237
|
return ownerError;
|
|
217
238
|
if (!isValidAid(plan.aid))
|
|
218
239
|
return `Invalid AID "${plan.aid}": must be a valid multi-level domain (e.g. mybot.agentid.pub)`;
|
|
240
|
+
if (plan.avatarFile !== undefined && plan.avatarUrl !== undefined)
|
|
241
|
+
return '--avatar-file and --avatar-url are mutually exclusive';
|
|
219
242
|
if (plan.configExists && !plan.force)
|
|
220
243
|
return `Agent "${plan.aid}" already exists (use --force to overwrite)`;
|
|
221
244
|
if (plan.tags !== undefined) {
|
|
@@ -655,6 +678,26 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
|
|
|
655
678
|
agentmdError = `generation failed: ${e?.message || e}`;
|
|
656
679
|
opts.onPhase?.('uploading_agentmd', 'warn', agentmdError);
|
|
657
680
|
}
|
|
681
|
+
let avatarUploaded = false;
|
|
682
|
+
if (opts.avatarFile || opts.avatarUrl) {
|
|
683
|
+
opts.onPhase?.('uploading_avatar', 'begin');
|
|
684
|
+
try {
|
|
685
|
+
if (!agentmdUploaded)
|
|
686
|
+
throw new Error('头像上传前 agent.md 尚未成功发布');
|
|
687
|
+
const avatar = opts.avatarFile
|
|
688
|
+
? await uploadAvatarFile(opts.aid, opts.avatarFile)
|
|
689
|
+
: await uploadAvatarUrl(opts.aid, opts.avatarUrl);
|
|
690
|
+
if (!avatar.ok)
|
|
691
|
+
throw new Error(avatar.error || '头像上传失败');
|
|
692
|
+
avatarUploaded = true;
|
|
693
|
+
opts.onPhase?.('uploading_avatar', 'done', `${avatar.width}x${avatar.height} ${avatar.mime}`);
|
|
694
|
+
}
|
|
695
|
+
catch (error) {
|
|
696
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
697
|
+
opts.onPhase?.('uploading_avatar', 'failed', detail);
|
|
698
|
+
return { ok: false, code: 'AVATAR_UPLOAD_FAILED', error: `头像上传失败:${detail}` };
|
|
699
|
+
}
|
|
700
|
+
}
|
|
658
701
|
let hotLoaded = false;
|
|
659
702
|
let hotLoadError;
|
|
660
703
|
opts.onPhase?.('hot_loading', 'begin');
|
|
@@ -692,6 +735,7 @@ export async function agentCreateNonInteractive(opts, runtime = {}) {
|
|
|
692
735
|
agentmdError,
|
|
693
736
|
hotLoaded,
|
|
694
737
|
hotLoadError,
|
|
738
|
+
...(opts.avatarFile || opts.avatarUrl ? { avatarUploaded } : {}),
|
|
695
739
|
...ownerContactSync,
|
|
696
740
|
};
|
|
697
741
|
}
|
|
@@ -712,6 +756,7 @@ export function initializationFingerprint(plan) {
|
|
|
712
756
|
return createHash('sha256').update(JSON.stringify([
|
|
713
757
|
plan.aid, plan.project, plan.baseagent, plan.owners, plan.name,
|
|
714
758
|
plan.description, plan.type, plan.tags, plan.persona ?? null,
|
|
759
|
+
plan.avatarFile ?? null, plan.avatarUrl ?? null,
|
|
715
760
|
])).digest('hex');
|
|
716
761
|
}
|
|
717
762
|
export function readInitialization(aid) {
|
|
@@ -749,6 +794,7 @@ export function initializationSummary(aid) {
|
|
|
749
794
|
nextStep: r.status === 'failed' ? `ec agent initialize ${aid} --resume` : undefined,
|
|
750
795
|
agentmd: { published: r.published === true, verified: r.verified === true },
|
|
751
796
|
persona: { provided: r.plan.persona !== undefined },
|
|
797
|
+
avatar: { requested: r.plan.avatarFile !== undefined || r.plan.avatarUrl !== undefined, uploaded: r.avatarUploaded === true },
|
|
752
798
|
welcome: r.welcome, startedAt: r.startedAt, updatedAt: r.updatedAt,
|
|
753
799
|
};
|
|
754
800
|
}
|
|
@@ -782,6 +828,8 @@ export function validateInitializationPlan(plan) {
|
|
|
782
828
|
}
|
|
783
829
|
if (plan.type !== 'agent')
|
|
784
830
|
failure('INVALID_ARGS', 'Initialized targets must have type=agent');
|
|
831
|
+
if (plan.avatarFile !== undefined && plan.avatarUrl !== undefined)
|
|
832
|
+
failure('INVALID_ARGS', 'avatar-file and avatar-url are mutually exclusive');
|
|
785
833
|
const error = validateAgentCreatePlan({
|
|
786
834
|
...plan, force: false, configExists: false, baseagentSource: 'argument', ownerSource: 'argument',
|
|
787
835
|
nameSource: 'argument', descriptionSource: 'argument', typeSource: 'argument',
|
|
@@ -958,6 +1006,7 @@ export class AgentInitializationService {
|
|
|
958
1006
|
failure('INITIALIZE_PLAN_CONFLICT');
|
|
959
1007
|
fs.writeFileSync(file, p.persona, { encoding: 'utf8', mode: 0o600 });
|
|
960
1008
|
}
|
|
1009
|
+
const resolvedAvatarFile = p.avatarFile;
|
|
961
1010
|
await syncOwnerContactsAfterCreate(p.aid, p.owners);
|
|
962
1011
|
this.phase(r, 'uploading_agentmd');
|
|
963
1012
|
let remote;
|
|
@@ -1013,6 +1062,15 @@ export class AgentInitializationService {
|
|
|
1013
1062
|
if (!fs.existsSync(agentMdPath(p.aid)) || !matchesCard(fs.readFileSync(agentMdPath(p.aid), 'utf8'), p)) {
|
|
1014
1063
|
failure('INITIALIZE_AGENTMD_VERIFY_FAILED');
|
|
1015
1064
|
}
|
|
1065
|
+
if ((resolvedAvatarFile || p.avatarUrl) && !r.avatarUploaded) {
|
|
1066
|
+
const avatar = resolvedAvatarFile
|
|
1067
|
+
? await uploadAvatarFile(p.aid, resolvedAvatarFile)
|
|
1068
|
+
: await uploadAvatarUrl(p.aid, p.avatarUrl);
|
|
1069
|
+
if (!avatar.ok)
|
|
1070
|
+
failure('INITIALIZE_AVATAR_FAILED', avatar.error || 'avatar upload failed');
|
|
1071
|
+
r.avatarUploaded = true;
|
|
1072
|
+
saveInitialization(r);
|
|
1073
|
+
}
|
|
1016
1074
|
r.published = true;
|
|
1017
1075
|
r.verified = true;
|
|
1018
1076
|
this.phase(r, 'hot_loading');
|
|
@@ -1074,7 +1132,7 @@ export function parseInitializationArgs(args) {
|
|
|
1074
1132
|
throw new Error('Invalid initialization command or AID');
|
|
1075
1133
|
const booleans = new Set(resume ? ['--resume'] : ['--initialize', '--non-interactive', '--dry-run']);
|
|
1076
1134
|
const strings = new Set(resume ? ['--wait', '--format'] : [
|
|
1077
|
-
'--project', '--baseagent', '--owner', '--owners', '--name', '--description', '--tags', '--type',
|
|
1135
|
+
'--project', '--baseagent', '--owner', '--owners', '--name', '--description', '--tags', '--type', '--avatar-file', '--avatar-url',
|
|
1078
1136
|
'--persona-file', '--persona-text', '--wait', '--format',
|
|
1079
1137
|
]);
|
|
1080
1138
|
const seen = new Set();
|
|
@@ -1114,16 +1172,24 @@ export function resolveInitializationPlan(args) {
|
|
|
1114
1172
|
if (parsed.resume)
|
|
1115
1173
|
throw new Error('A resume request cannot supply a new plan');
|
|
1116
1174
|
const v = parsed.values;
|
|
1175
|
+
if (v['--avatar-file'] !== undefined && v['--avatar-url'] !== undefined)
|
|
1176
|
+
throw new Error('--avatar-file and --avatar-url are mutually exclusive');
|
|
1177
|
+
if (v['--avatar-file']?.startsWith('attachment:') && !process.env.EVOLCORE_SESSION_ID) {
|
|
1178
|
+
throw new Error('attachment:<id> avatar sources require a managed Agent task');
|
|
1179
|
+
}
|
|
1117
1180
|
if (v['--persona-file'] !== undefined)
|
|
1118
1181
|
throw new Error('CLI must submit persona file contents as text');
|
|
1119
1182
|
const p = resolveAgentCreatePlan({
|
|
1120
1183
|
aid: parsed.aid, project: v['--project'], baseagent: v['--baseagent'], ...parseAgentOwnerArgs(args),
|
|
1184
|
+
avatarFile: v['--avatar-file'], avatarUrl: v['--avatar-url'],
|
|
1121
1185
|
name: v['--name'], description: v['--description'], tags: parseAgentTags(v['--tags']), type: v['--type'],
|
|
1122
1186
|
});
|
|
1123
1187
|
return {
|
|
1124
1188
|
aid: p.aid, project: p.project, baseagent: p.baseagent ?? '', owners: p.owners ?? (p.owner ? [p.owner] : []),
|
|
1125
1189
|
name: p.name, description: p.description, tags: p.tags, type: p.type,
|
|
1126
1190
|
...(v['--persona-text'] !== undefined ? { persona: v['--persona-text'] } : {}),
|
|
1191
|
+
...(v['--avatar-file'] !== undefined ? { avatarFile: v['--avatar-file'] } : {}),
|
|
1192
|
+
...(v['--avatar-url'] !== undefined ? { avatarUrl: v['--avatar-url'] } : {}),
|
|
1127
1193
|
};
|
|
1128
1194
|
}
|
|
1129
1195
|
export function readInitializationPersona(file, managed) {
|
package/dist/cli/agent.js
CHANGED
|
@@ -19,6 +19,7 @@ import { findPostBootstrapWelcomeOutbox } from '../core/bootstrap-messages.js';
|
|
|
19
19
|
import { resolveAgentLifecycle } from '../config/lifecycle.js';
|
|
20
20
|
import { initializationSummary } from './agent-create.js';
|
|
21
21
|
import { parseAgentWelcomeMetadata, readAgentWelcomeTemplate, renderPostBootstrapWelcomeMessage, saveAgentWelcomeTemplate, validateWelcomeTemplate } from '../utils/welcome.js';
|
|
22
|
+
import { RUNTIME_ENVIRONMENT_NAMES } from '../config/runtime-env.js';
|
|
22
23
|
export { agentCreateInteractive, agentCreateNonInteractive, parseAgentOwnerArgs, resolveAgentCreatePlan, validateAgentCreatePlan, validateAgentOwnerOptions, } from './agent-create.js';
|
|
23
24
|
/** Route agent lifecycle commands from a managed task through daemon IPC. */
|
|
24
25
|
export async function runManagedAgentOperation(argv) {
|
|
@@ -306,13 +307,17 @@ const AGENT_RELOAD_TIMEOUT_MS = 45_000;
|
|
|
306
307
|
const AGENT_RESYNC_TIMEOUT_MS = 5 * 60_000;
|
|
307
308
|
export async function agentReload(aid, options = {}) {
|
|
308
309
|
const p = resolvePaths();
|
|
310
|
+
const runtimeEnv = Object.fromEntries(RUNTIME_ENVIRONMENT_NAMES.map(name => [name, process.env[name] || null]));
|
|
309
311
|
if (!aid) {
|
|
310
312
|
if (options.force) {
|
|
311
313
|
return { ok: false, code: 'INVALID_ARGS', error: '--force requires a target Agent AID' };
|
|
312
314
|
}
|
|
313
315
|
// Full resync
|
|
314
316
|
try {
|
|
315
|
-
const result = await ipcQuery(p.socket, {
|
|
317
|
+
const result = await ipcQuery(p.socket, {
|
|
318
|
+
type: 'evolagent.resync',
|
|
319
|
+
runtimeEnv,
|
|
320
|
+
}, AGENT_RESYNC_TIMEOUT_MS, { throwOnError: true });
|
|
316
321
|
if (result === null) {
|
|
317
322
|
return { ok: false, code: 'IPC_INVALID_RESPONSE', error: 'daemon IPC 未返回有效响应,请检查 ec status' };
|
|
318
323
|
}
|
|
@@ -327,7 +332,12 @@ export async function agentReload(aid, options = {}) {
|
|
|
327
332
|
}
|
|
328
333
|
// Single agent reload
|
|
329
334
|
try {
|
|
330
|
-
const result = await ipcQuery(p.socket, {
|
|
335
|
+
const result = await ipcQuery(p.socket, {
|
|
336
|
+
type: 'evolagent.reload',
|
|
337
|
+
name: aid,
|
|
338
|
+
force: options.force === true,
|
|
339
|
+
runtimeEnv,
|
|
340
|
+
}, AGENT_RELOAD_TIMEOUT_MS, { throwOnError: true });
|
|
331
341
|
if (result === null) {
|
|
332
342
|
return { ok: false, code: 'IPC_INVALID_RESPONSE', error: 'daemon IPC 未返回有效响应,请检查 ec status' };
|
|
333
343
|
}
|
package/dist/cli/aun-commands.js
CHANGED
|
@@ -7,6 +7,9 @@ import { ipcQuery } from '../ipc.js';
|
|
|
7
7
|
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
8
8
|
import { isManagementRole } from '../config/builtin-roles.js';
|
|
9
9
|
import { readBestTaskRuntimeContext } from './task-context.js';
|
|
10
|
+
import { assertEcSingleLine } from './cli-argv.js';
|
|
11
|
+
import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
|
|
12
|
+
import { ManagedGroupOperationError } from '../aun/msg/managed-operation.js';
|
|
10
13
|
// ==================== AID ====================
|
|
11
14
|
function resolveAunPath(args) {
|
|
12
15
|
const idx = args.indexOf('--aun-path');
|
|
@@ -318,14 +321,17 @@ function renderManagedGroupResult(args, result, formatJson) {
|
|
|
318
321
|
if (message.content_truncated)
|
|
319
322
|
console.log('正文尚未读完');
|
|
320
323
|
if (message.content_truncated && message.msgId) {
|
|
321
|
-
console.log('--
|
|
324
|
+
console.log('--message ' + message.msgId + ' --offset ' + message.next_offset);
|
|
322
325
|
}
|
|
323
326
|
}
|
|
324
327
|
}
|
|
325
328
|
if (result.next_offset != null)
|
|
326
329
|
console.log('next_offset=' + result.next_offset);
|
|
327
|
-
if (result.has_more)
|
|
328
|
-
|
|
330
|
+
if (result.has_more) {
|
|
331
|
+
const cursor = result.next_before ?? result.next_after;
|
|
332
|
+
const direction = result.next_before ? 'before' : 'after';
|
|
333
|
+
console.log(`还有更多历史,请使用 --${direction} ${cursor.ts} --${direction}-id ${cursor.id}`);
|
|
334
|
+
}
|
|
329
335
|
return;
|
|
330
336
|
}
|
|
331
337
|
if (sub === 'list') {
|
|
@@ -389,6 +395,31 @@ function renderManagedGroupResult(args, result, formatJson) {
|
|
|
389
395
|
console.log(typeof result.message === 'string' ? result.message : `✓ group ${sub} 完成`);
|
|
390
396
|
return;
|
|
391
397
|
}
|
|
398
|
+
if (sub === 'mention') {
|
|
399
|
+
const renderMode = (value) => {
|
|
400
|
+
if (value === 'mention-only')
|
|
401
|
+
return '@提及时响应';
|
|
402
|
+
if (value === 'disabled')
|
|
403
|
+
return '所有消息响应';
|
|
404
|
+
if (value === 'auto')
|
|
405
|
+
return 'auto(本地自动判断)';
|
|
406
|
+
return String(value);
|
|
407
|
+
};
|
|
408
|
+
const sourceLabel = result.source === 'relation' ? '本群覆盖'
|
|
409
|
+
: result.source === 'agent' ? 'Agent 全局'
|
|
410
|
+
: result.source === 'aun' ? 'AUN 服务端'
|
|
411
|
+
: result.source === 'defaults' ? '默认配置' : '内置默认';
|
|
412
|
+
if (result.override === null) {
|
|
413
|
+
console.log(`@ 处理模式: ${renderMode(result.mode)}(跟随上级设置,当前生效来源:${sourceLabel})`);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (result.override === undefined) {
|
|
417
|
+
console.log(`@ 处理模式: ${renderMode(result.mode)}(${sourceLabel})`);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
console.log(`@ 处理模式: ${renderMode(result.override)}(本群覆盖${result.mode !== undefined ? `,实际生效 ${renderMode(result.mode)}` : ''})`);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
392
423
|
console.log(`✓ group ${sub} 完成`);
|
|
393
424
|
}
|
|
394
425
|
export async function cmdAid(args) {
|
|
@@ -1204,6 +1235,7 @@ Options:
|
|
|
1204
1235
|
}
|
|
1205
1236
|
// ==================== Msg ====================
|
|
1206
1237
|
export async function cmdMsg(args) {
|
|
1238
|
+
args = canonicalizeEvolcoreCommandArgv(['ec', 'msg', ...args]).slice(2);
|
|
1207
1239
|
const sub = args[0];
|
|
1208
1240
|
const aunPath = resolveAunPath(args);
|
|
1209
1241
|
const formatJson = getArgValue(args, '--format') === 'json';
|
|
@@ -1487,6 +1519,7 @@ Options:
|
|
|
1487
1519
|
body = { mode: 'text', text };
|
|
1488
1520
|
}
|
|
1489
1521
|
else if (linkVal) {
|
|
1522
|
+
assertEcSingleLine(getArgValue(args, '--title'), '--title');
|
|
1490
1523
|
body = {
|
|
1491
1524
|
mode: 'link',
|
|
1492
1525
|
url: linkVal,
|
|
@@ -1695,25 +1728,28 @@ function printGroupSendAidHint() {
|
|
|
1695
1728
|
console.error('查询真实群 AID: ec group list <发送方AID>');
|
|
1696
1729
|
}
|
|
1697
1730
|
export async function cmdGroup(args) {
|
|
1731
|
+
args = canonicalizeEvolcoreCommandArgv(['ec', 'group', ...args]).slice(2);
|
|
1698
1732
|
const sub = args[0];
|
|
1733
|
+
if (sub === 'create')
|
|
1734
|
+
assertEcSingleLine(args[2], '<name>');
|
|
1735
|
+
if (sub === 'update')
|
|
1736
|
+
assertEcSingleLine(getArgValue(args, '--name'), '--name');
|
|
1699
1737
|
const aunPath = resolveAunPath(args);
|
|
1700
1738
|
const formatJson = getArgValue(args, '--format') === 'json';
|
|
1701
1739
|
const appSlot = getArgValue(args, '--app');
|
|
1702
1740
|
if (sub === 'history' && wantsHelp(args)) {
|
|
1703
|
-
console.log(`用法: ec group history <self-aid> <group-aid>
|
|
1741
|
+
console.log(`用法: ec group history <self-aid> <group-aid> [options]
|
|
1704
1742
|
本地 messages.jsonl 查询,不访问 Gateway,不推进 group pull/ack 游标。
|
|
1705
|
-
|
|
1706
|
-
--all 浏览群会话历史(返回最近 N 条),不改变已读状态
|
|
1743
|
+
查询始终只读,不维护本地已读游标
|
|
1707
1744
|
--limit <N> 默认 50,范围 1–500;另有 24 KiB 单页消息预算
|
|
1708
1745
|
--thread <main|all|id> 当前群任务缺省继承当前话题;其他调用缺省 all
|
|
1709
1746
|
--direction <in|out|all> 按方向筛选,默认 all
|
|
1710
1747
|
--before/--after <time> 按接收时间筛选,开区间;epoch 毫秒或 ISO 时间
|
|
1748
|
+
--before-id/--after-id <id> 同一时间戳分页用的 64 位游标(需配合对应时间)
|
|
1711
1749
|
--format <text|json> 默认 text
|
|
1712
|
-
--message <msg-id>
|
|
1750
|
+
--message <msg-id> 查看指定长消息正文
|
|
1713
1751
|
--offset <bytes> 配合 --message 从 next_offset 继续读取,默认 0
|
|
1714
|
-
|
|
1715
|
-
visitor 不开放历史;群权限仍由托管会话校验。
|
|
1716
|
-
旧日志通过 --all 查询,只有带本地未提及标记的新记录参与 --unread。`);
|
|
1752
|
+
visitor 不开放历史;群权限仍由托管会话校验。`);
|
|
1717
1753
|
return;
|
|
1718
1754
|
}
|
|
1719
1755
|
const rulesActionHelp = sub === 'rules' && isHelpFlag(args[3]);
|
|
@@ -1726,7 +1762,7 @@ visitor 不开放历史;群权限仍由托管会话校验。
|
|
|
1726
1762
|
send <from> <group-id> --payload <json> 发送自定义 payload
|
|
1727
1763
|
pull <from> <group-id> [--after-seq N] [--limit N] --app <name> 拉取群消息(必须使用独立 slot)
|
|
1728
1764
|
ack <from> <group-id> <seq> [--app <name>] 确认已读
|
|
1729
|
-
history <from> <group-id> [
|
|
1765
|
+
history <from> <group-id> [options] 查询本地群消息历史(只读)
|
|
1730
1766
|
|
|
1731
1767
|
群管理:
|
|
1732
1768
|
create <from> <name> [--visibility public|private] [--description D]
|
|
@@ -1741,6 +1777,8 @@ visitor 不开放历史;群权限仍由托管会话校验。
|
|
|
1741
1777
|
rules <from> <group-id> set <file> 上传并发布群规则文件
|
|
1742
1778
|
rules <from> <group-id> publish 发布当前群空间 /rules.md
|
|
1743
1779
|
rules <from> <group-id> [--mode M] [--question Q] [--max-pending N] 查看/更新入群规则
|
|
1780
|
+
mention <from> <group-id> [<mention-only|disabled|auto>] [--clear]
|
|
1781
|
+
查看/设置本群 @ 提及模式(不带 mode 为查看;--clear 清除本群覆盖跟随上级)
|
|
1744
1782
|
|
|
1745
1783
|
成员:
|
|
1746
1784
|
join <from> <group-id> [--message M] [--answer A] 申请加入
|
|
@@ -2599,7 +2637,43 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
2599
2637
|
});
|
|
2600
2638
|
return;
|
|
2601
2639
|
}
|
|
2602
|
-
|
|
2640
|
+
if (sub === 'mention') {
|
|
2641
|
+
const groupId = requireGroupId();
|
|
2642
|
+
if (args[3])
|
|
2643
|
+
assertEcSingleLine(args[3], '<mode>');
|
|
2644
|
+
const values = collectPositional(args, 3);
|
|
2645
|
+
if (values.length > 1) {
|
|
2646
|
+
console.error('用法: ec group mention <from> <group-id> [<mention-only|disabled|auto>] [--clear]');
|
|
2647
|
+
process.exit(1);
|
|
2648
|
+
}
|
|
2649
|
+
const mode = values[0];
|
|
2650
|
+
const clear = args.includes('--clear');
|
|
2651
|
+
if (mode !== undefined && clear) {
|
|
2652
|
+
console.error('❌ <mode> 与 --clear 互斥');
|
|
2653
|
+
process.exit(1);
|
|
2654
|
+
}
|
|
2655
|
+
if (mode !== undefined && !['mention-only', 'disabled', 'auto'].includes(mode)) {
|
|
2656
|
+
console.error(`❌ 无效提及模式: ${mode}(可选 mention-only|disabled|auto)`);
|
|
2657
|
+
process.exit(1);
|
|
2658
|
+
}
|
|
2659
|
+
const operationArgs = ['mention', from, groupId, ...(mode ? [mode] : []), ...(clear ? ['--clear'] : [])];
|
|
2660
|
+
const { resolveManagedGroupOperation, executeManagedGroupOperation } = await import('../aun/msg/managed-operation.js');
|
|
2661
|
+
const parsed = resolveManagedGroupOperation(operationArgs);
|
|
2662
|
+
if (!parsed.ok)
|
|
2663
|
+
failManagedGroup(formatJson, parsed.code, parsed.reason);
|
|
2664
|
+
try {
|
|
2665
|
+
const result = await executeManagedGroupOperation(parsed.command);
|
|
2666
|
+
renderManagedGroupResult(operationArgs, result, formatJson);
|
|
2667
|
+
}
|
|
2668
|
+
catch (error) {
|
|
2669
|
+
if (error instanceof ManagedGroupOperationError) {
|
|
2670
|
+
failManagedGroup(formatJson, error.code, error.message);
|
|
2671
|
+
}
|
|
2672
|
+
throw error;
|
|
2673
|
+
}
|
|
2674
|
+
return;
|
|
2675
|
+
}
|
|
2676
|
+
console.error(`未知子命令: ${sub}\n用法: ec group [send|pull|ack|history|create|list|info|update|dissolve|suspend|resume|rules|mention|join|leave|invite|invites|accept-invite|reject-invite|revoke-invite|kick|members|online|role|owner|ban|unban|block|unblock|blocklist|report-status|member-statuses]`);
|
|
2603
2677
|
process.exit(1);
|
|
2604
2678
|
}
|
|
2605
2679
|
// ==================== Main ====================
|
|
@@ -2625,7 +2699,7 @@ const VALUE_FLAGS = new Set([
|
|
|
2625
2699
|
'--aun-path', '--thread', '--return', '--handoff-context',
|
|
2626
2700
|
]);
|
|
2627
2701
|
const BOOLEAN_FLAGS = new Set([
|
|
2628
|
-
'--encrypt', '--no-encrypt', '--mention-all',
|
|
2702
|
+
'--encrypt', '--no-encrypt', '--mention-all', '--clear',
|
|
2629
2703
|
]);
|
|
2630
2704
|
function collectPositional(args, startIdx, extraValueFlags) {
|
|
2631
2705
|
const out = [];
|
package/dist/cli/cli-argv.js
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
|
+
import { decodeEvolcoreInlineText } from '../core/permission/ec-command-parser.js';
|
|
1
2
|
export function normalizeCliArgv(argv) {
|
|
2
3
|
if (argv[0] === 'ec' && argv[1])
|
|
3
4
|
return argv.slice(1);
|
|
4
5
|
return argv;
|
|
5
6
|
}
|
|
7
|
+
export function decodeEcInlineText(value) {
|
|
8
|
+
return decodeEvolcoreInlineText(value);
|
|
9
|
+
}
|
|
10
|
+
export function decodeEcInlineOptions(args, flags) {
|
|
11
|
+
const decoded = [...args];
|
|
12
|
+
for (let index = 0; index < decoded.length; index++) {
|
|
13
|
+
const flag = decoded[index];
|
|
14
|
+
if (flag === '--')
|
|
15
|
+
break;
|
|
16
|
+
if (flags.has(flag) && decoded[index + 1] !== undefined) {
|
|
17
|
+
decoded[++index] = decodeEcInlineText(decoded[index]);
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const separator = flag.indexOf('=');
|
|
21
|
+
if (separator > 0 && flags.has(flag.slice(0, separator))) {
|
|
22
|
+
decoded[index] = flag.slice(0, separator + 1) + decodeEcInlineText(flag.slice(separator + 1));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return decoded;
|
|
26
|
+
}
|
|
27
|
+
export function assertEcSingleLine(value, field) {
|
|
28
|
+
if (value !== undefined && /[\x00-\x1f\x7f]/.test(value)) {
|
|
29
|
+
throw new Error(`${field} 不允许换行或控制字符`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
6
32
|
export function splitConfigBatchGetArgv(inputArgv) {
|
|
7
33
|
const argv = normalizeCliArgv(inputArgv);
|
|
8
34
|
if (argv[0] !== 'config' || argv[1] !== 'get')
|
|
@@ -291,18 +291,14 @@ async function launchPackageLifecycle(source, log, options = {}) {
|
|
|
291
291
|
platform.cleanupMonitorStage(launch.stageDir);
|
|
292
292
|
return { ok: result.ok, ...(!result.ok ? { reason: result.reason } : {}) };
|
|
293
293
|
}
|
|
294
|
-
function requireCompletedDataMigration(root
|
|
294
|
+
function requireCompletedDataMigration(root) {
|
|
295
295
|
const requirement = inspectDataMigrationRequirement(root);
|
|
296
296
|
if (!requirement.required)
|
|
297
297
|
return true;
|
|
298
|
-
console.error(
|
|
299
|
-
? `❌ 检测到 ${requirement.operationCount} 项待确认的用户数据迁移,本次不停止当前服务。`
|
|
300
|
-
: `❌ 检测到 ${requirement.operationCount} 项待确认的用户数据迁移,服务未启动。`);
|
|
298
|
+
console.error(`❌ 检测到 ${requirement.operationCount} 项待确认的用户数据迁移,服务未启动。`);
|
|
301
299
|
console.error(' 先执行: ec data migrate --dry-run');
|
|
302
300
|
console.error(' 确认后: ec data migrate --apply');
|
|
303
|
-
console.error(' 迁移成功并校验后,再执行 ec start
|
|
304
|
-
if (action === 'restart')
|
|
305
|
-
console.error(' 本次 ec restart 仅完成只读检查,未停止当前服务。');
|
|
301
|
+
console.error(' 迁移成功并校验后,再执行 ec start。');
|
|
306
302
|
process.exitCode = 2;
|
|
307
303
|
return false;
|
|
308
304
|
}
|
|
@@ -925,9 +921,8 @@ export async function cmdRestart(opts = {}) {
|
|
|
925
921
|
}
|
|
926
922
|
// The shared launchPackageLifecycle path delegates to launchMonitorAndConfirm;
|
|
927
923
|
// the monitor retains shutdown, orphan checks, build and rollback ownership.
|
|
928
|
-
//
|
|
929
|
-
|
|
930
|
-
return;
|
|
924
|
+
// restart-monitor performs the read-only preflight before stopping the
|
|
925
|
+
// current daemon, then applies the migration during the stopped window.
|
|
931
926
|
const launched = await launchPackageLifecycle('restart', console.log, { clear: opts.clear });
|
|
932
927
|
if (!launched.ok) {
|
|
933
928
|
console.error(`❌ 重启中止:restart-monitor 未能启动(${launched.reason});当前服务未主动停止`);
|
|
@@ -1809,6 +1804,7 @@ async function cmdWatchMenu() {
|
|
|
1809
1804
|
{ key: 'log', label: 'log', desc: 'real-time log tail' },
|
|
1810
1805
|
{ key: 'aid', label: 'aid', desc: 'AID connection stats' },
|
|
1811
1806
|
{ key: 'msg', label: 'msg', desc: 'message inspector' },
|
|
1807
|
+
{ key: 'diag', label: 'diag', desc: 'message lifecycle diagnostics (AUN→queue→task)' },
|
|
1812
1808
|
{ key: 'web', label: 'web', desc: 'browser dashboard (aid/msg/session)' },
|
|
1813
1809
|
];
|
|
1814
1810
|
let index = 0;
|
|
@@ -1873,6 +1869,10 @@ async function cmdWatchMenu() {
|
|
|
1873
1869
|
const { cmdWatchMsg } = await import('./watch-msg.js');
|
|
1874
1870
|
await cmdWatchMsg();
|
|
1875
1871
|
}
|
|
1872
|
+
else if (chosen === 'diag') {
|
|
1873
|
+
const { cmdWatchMsgDiag } = await import('./watch-msg-diag.js');
|
|
1874
|
+
await cmdWatchMsgDiag([]);
|
|
1875
|
+
}
|
|
1876
1876
|
else if (chosen === 'web') {
|
|
1877
1877
|
await cmdWatchWeb();
|
|
1878
1878
|
}
|
|
@@ -3295,6 +3295,36 @@ export async function cmdWatchCommand(args) {
|
|
|
3295
3295
|
const { cmdWatchMsg } = await import('./watch-msg.js');
|
|
3296
3296
|
await cmdWatchMsg();
|
|
3297
3297
|
}
|
|
3298
|
+
else if (args[0] === 'diag' || args[0] === 'msg-diag') {
|
|
3299
|
+
if (isHelpFlag(args[1])) {
|
|
3300
|
+
console.log(`用法: ec watch diag
|
|
3301
|
+
|
|
3302
|
+
实时诊断消息生命周期,从 AUN SDK 入站到 daemon 处理全过程。
|
|
3303
|
+
|
|
3304
|
+
显示内容:
|
|
3305
|
+
✓ AUN入站 消息到达 AUN SDK
|
|
3306
|
+
→ 队列入队 消息进入 daemon 队列
|
|
3307
|
+
⚡ 任务创建 daemon 创建处理任务
|
|
3308
|
+
✓ 任务完成 任务处理完成
|
|
3309
|
+
← AUN出站 回复消息发送
|
|
3310
|
+
|
|
3311
|
+
每条消息显示:
|
|
3312
|
+
- 时间戳(精确到毫秒)
|
|
3313
|
+
- 阶段标识
|
|
3314
|
+
- AID(前12字符)
|
|
3315
|
+
- 消息ID
|
|
3316
|
+
- 内容预览(前50字符)
|
|
3317
|
+
|
|
3318
|
+
用途:
|
|
3319
|
+
排查消息丢失、处理延迟、队列阻塞等问题
|
|
3320
|
+
|
|
3321
|
+
操作:
|
|
3322
|
+
Ctrl+C 退出`);
|
|
3323
|
+
return;
|
|
3324
|
+
}
|
|
3325
|
+
const { cmdWatchMsgDiag } = await import('./watch-msg-diag.js');
|
|
3326
|
+
await cmdWatchMsgDiag(args.slice(1));
|
|
3327
|
+
}
|
|
3298
3328
|
else if (args[0] === 'log' || args[0] === 'logs') {
|
|
3299
3329
|
const requested = args.slice(1);
|
|
3300
3330
|
if (requested.length > 0) {
|