evolcore 0.0.31 → 0.0.32
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 +11 -0
- package/dist/agents/codex-runner.js +28 -5
- package/dist/agents/ecagent-runner.js +4 -0
- package/dist/agents/gemini-runner.js +4 -0
- package/dist/aun/aid/store.js +0 -81
- package/dist/aun/group/fs-download.js +1 -10
- package/dist/aun/msg/managed-operation.js +130 -32
- package/dist/aun/service-proxy.js +12 -18
- package/dist/aun/storage/index.js +29 -0
- package/dist/channels/aun.js +10 -135
- package/dist/cli/agent-command.js +6 -7
- package/dist/cli/agent-create.js +43 -24
- package/dist/cli/agent.js +15 -69
- package/dist/cli/aun-commands.js +149 -5
- package/dist/cli/ctl-command.js +1 -2
- package/dist/cli/daemon-commands.js +1 -1
- package/dist/cli/diag.js +2 -2
- package/dist/cli/handoff-command.js +15 -5
- package/dist/cli/memory-command.js +85 -11
- package/dist/cli/model.js +14 -138
- package/dist/cli/queue-command.js +46 -0
- package/dist/cli/response.js +5 -54
- package/dist/cli/skill-command.js +9 -3
- package/dist/cli/stats.js +10 -4
- package/dist/cli/task-command.js +1 -0
- package/dist/cli/task-context.js +15 -0
- package/dist/cli/trigger-command.js +73 -49
- package/dist/config/builtin-roles.js +8 -7
- package/dist/core/agent-ipc-registration.js +65 -22
- package/dist/core/auth/agent-delegation.js +17 -1
- package/dist/core/auth/delegation-authorization.js +1 -0
- package/dist/core/auth/operation-catalog.js +11 -3
- package/dist/core/command/command-handler.js +164 -21
- package/dist/core/command/diag-service.js +5 -1
- package/dist/core/handoff/ipc-registration.js +38 -0
- package/dist/core/ipc-registration.js +71 -7
- package/dist/core/message/aun-ipc-sender.js +48 -4
- package/dist/core/message/message-queue.js +131 -3
- package/dist/core/message/response-engine.js +30 -2
- package/dist/core/permission/sandbox-runtime.js +14 -1
- package/dist/core/task/task-recovery-service.js +2 -0
- package/dist/core/task/task-resume-operation.js +11 -0
- package/dist/index.js +2 -2
- package/dist/ipc.js +146 -8
- package/dist/trigger/authorization.js +2 -1
- package/dist/trigger/ipc-service.js +49 -35
- package/dist/trigger/script-sandbox.js +58 -77
- package/kits/docs/AUTHORING.md +1 -1
- package/kits/docs/channels/aun.md +8 -0
- package/kits/docs/evolcore/INDEX.md +2 -2
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/trigger.md +2 -2
- package/kits/rules/01-overview.md +0 -9
- package/kits/rules/06-channel.md +7 -1
- package/kits/templates/system-fragments/commands.md +1 -1
- package/package.json +1 -1
package/dist/cli/agent.js
CHANGED
|
@@ -14,7 +14,6 @@ import { isValidChannelName } from '../core/channel-loader.js';
|
|
|
14
14
|
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
15
15
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
16
16
|
import { isValidAid } from '../aun/aid/validation.js';
|
|
17
|
-
import { isHClassPath, isLClassPath, isSameOrDescendant } from '../core/permission/protected-paths.js';
|
|
18
17
|
import { findPostBootstrapWelcomeOutbox } from '../core/bootstrap-messages.js';
|
|
19
18
|
import { resolveAgentLifecycle } from '../config/lifecycle.js';
|
|
20
19
|
import { initializationSummary } from './agent-create.js';
|
|
@@ -22,7 +21,7 @@ import { parseAgentWelcomeMetadata, readAgentWelcomeTemplate, renderPostBootstra
|
|
|
22
21
|
import { RUNTIME_ENVIRONMENT_NAMES } from '../config/runtime-env.js';
|
|
23
22
|
export { agentCreateInteractive, agentCreateNonInteractive, parseAgentOwnerArgs, resolveAgentCreatePlan, validateAgentCreatePlan, validateAgentOwnerOptions, } from './agent-create.js';
|
|
24
23
|
/** Route agent lifecycle commands from a managed task through daemon IPC. */
|
|
25
|
-
export async function runManagedAgentOperation(argv) {
|
|
24
|
+
export async function runManagedAgentOperation(argv, timeoutMs = 60_000) {
|
|
26
25
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
27
26
|
if (!sessionId)
|
|
28
27
|
return { ok: false, code: 'MANAGED_ONLY', error: 'agent operation is not running in a managed task' };
|
|
@@ -36,7 +35,7 @@ export async function runManagedAgentOperation(argv) {
|
|
|
36
35
|
argv: ['agent', ...argv],
|
|
37
36
|
sessionId,
|
|
38
37
|
delegationToken,
|
|
39
|
-
},
|
|
38
|
+
}, timeoutMs);
|
|
40
39
|
if (!response)
|
|
41
40
|
return { ok: false, code: 'DAEMON_UNAVAILABLE', error: 'Unable to connect to the evolcore daemon' };
|
|
42
41
|
if (!response.ok)
|
|
@@ -398,37 +397,12 @@ async function agentSetEnabled(aid, enabled, options = {}) {
|
|
|
398
397
|
return { ok: true, aid, enabled, reloaded };
|
|
399
398
|
}
|
|
400
399
|
async function runManagedAgentConfig(args, options) {
|
|
401
|
-
|
|
402
|
-
if (!sessionId || options.trustedLocal)
|
|
400
|
+
if (!process.env.EVOLCORE_SESSION_ID || options.trustedLocal)
|
|
403
401
|
return { managed: false };
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
error: { ok: false, code: 'DELEGATION_REQUIRED', error: `${AGENT_DELEGATION_TOKEN_ENV} is not set for the active task` },
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
try {
|
|
412
|
-
const response = await ipcQuery(resolvePaths().socket, {
|
|
413
|
-
type: 'config.op',
|
|
414
|
-
argv: ['config', ...args],
|
|
415
|
-
sessionId,
|
|
416
|
-
delegationToken,
|
|
417
|
-
}, 10_000);
|
|
418
|
-
if (!response) {
|
|
419
|
-
return { managed: true, error: { ok: false, code: 'DAEMON_UNAVAILABLE', error: 'Unable to connect to the evolcore daemon' } };
|
|
420
|
-
}
|
|
421
|
-
if (!response.ok || !response.result?.ok) {
|
|
422
|
-
return {
|
|
423
|
-
managed: true,
|
|
424
|
-
error: { ok: false, code: response.code || 'CONFIG_AUTH_FAILED', error: response.error || 'config operation failed' },
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
return { managed: true, response };
|
|
428
|
-
}
|
|
429
|
-
catch {
|
|
430
|
-
return { managed: true, error: { ok: false, code: 'DAEMON_UNAVAILABLE', error: 'Unable to connect to the evolcore daemon' } };
|
|
431
|
-
}
|
|
402
|
+
const result = await runManagedAgentOperation(options.argv ?? args, 10_000);
|
|
403
|
+
return result.ok
|
|
404
|
+
? { managed: true, response: { ok: true, result } }
|
|
405
|
+
: { managed: true, error: result };
|
|
432
406
|
}
|
|
433
407
|
async function executeLocalAgentConfig(args) {
|
|
434
408
|
initConfigManager();
|
|
@@ -448,7 +422,7 @@ async function executeLocalAgentConfig(args) {
|
|
|
448
422
|
});
|
|
449
423
|
}
|
|
450
424
|
export async function agentGet(aid, key, options = {}) {
|
|
451
|
-
const managed = await runManagedAgentConfig(['get',
|
|
425
|
+
const managed = await runManagedAgentConfig(['get', aid, key], options);
|
|
452
426
|
if (managed.managed) {
|
|
453
427
|
if ('error' in managed)
|
|
454
428
|
return managed.error;
|
|
@@ -472,7 +446,7 @@ export async function agentGet(aid, key, options = {}) {
|
|
|
472
446
|
}
|
|
473
447
|
}
|
|
474
448
|
export async function agentSet(aid, key, rawValue, options = {}) {
|
|
475
|
-
const managed = await runManagedAgentConfig(['set', key, rawValue
|
|
449
|
+
const managed = await runManagedAgentConfig(['set', aid, key, rawValue], options);
|
|
476
450
|
if (managed.managed) {
|
|
477
451
|
if ('error' in managed)
|
|
478
452
|
return managed.error;
|
|
@@ -539,36 +513,7 @@ export async function agentPersona(aid, options = {}) {
|
|
|
539
513
|
return { ok: false, code: 'INVALID_ARGS', error: '--text 与 --file 不能同时使用' };
|
|
540
514
|
const managedSession = !!process.env.EVOLCORE_SESSION_ID && !options.trustedLocal;
|
|
541
515
|
let text = options.text;
|
|
542
|
-
if (options.file !== undefined) {
|
|
543
|
-
if (managedSession) {
|
|
544
|
-
const resolved = path.resolve(options.file);
|
|
545
|
-
const projectRoot = path.resolve(process.cwd());
|
|
546
|
-
const tempRoot = process.env.TMPDIR?.trim() && path.isAbsolute(process.env.TMPDIR)
|
|
547
|
-
? path.resolve(process.env.TMPDIR)
|
|
548
|
-
: undefined;
|
|
549
|
-
const allowed = isSameOrDescendant(resolved, projectRoot)
|
|
550
|
-
|| (!!tempRoot && isSameOrDescendant(resolved, tempRoot));
|
|
551
|
-
if (!allowed || isHClassPath(resolved) || isLClassPath(resolved)) {
|
|
552
|
-
return { ok: false, code: 'INVALID_ARGS', error: '--file 必须位于当前项目或会话 $TMPDIR,且不能读取 EvolCore 受保护路径' };
|
|
553
|
-
}
|
|
554
|
-
try {
|
|
555
|
-
const stat = fs.lstatSync(resolved);
|
|
556
|
-
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
557
|
-
return { ok: false, code: 'INVALID_ARGS', error: '--file 必须指向当前项目或会话 $TMPDIR 内的普通文件' };
|
|
558
|
-
}
|
|
559
|
-
const realPath = fs.realpathSync(resolved);
|
|
560
|
-
const realProjectRoot = fs.realpathSync(projectRoot);
|
|
561
|
-
const realTempRoot = tempRoot ? fs.realpathSync(tempRoot) : undefined;
|
|
562
|
-
const realAllowed = isSameOrDescendant(realPath, realProjectRoot)
|
|
563
|
-
|| (!!realTempRoot && isSameOrDescendant(realPath, realTempRoot));
|
|
564
|
-
if (!realAllowed || isHClassPath(realPath) || isLClassPath(realPath)) {
|
|
565
|
-
return { ok: false, code: 'INVALID_ARGS', error: '--file 解析后越出允许目录或命中 EvolCore 受保护路径' };
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
catch (e) {
|
|
569
|
-
return { ok: false, code: 'READ_FAILED', error: `无法校验 --file: ${e?.message || e}` };
|
|
570
|
-
}
|
|
571
|
-
}
|
|
516
|
+
if (options.file !== undefined && !managedSession) {
|
|
572
517
|
const source = readPersonaSource(options.file);
|
|
573
518
|
if (!source.ok)
|
|
574
519
|
return source;
|
|
@@ -582,10 +527,10 @@ export async function agentPersona(aid, options = {}) {
|
|
|
582
527
|
const managedArgs = options.text !== undefined
|
|
583
528
|
? ['persona', '--text', text]
|
|
584
529
|
: options.file !== undefined
|
|
585
|
-
? ['persona', '--
|
|
530
|
+
? ['persona', '--file', options.file]
|
|
586
531
|
: ['persona', 'show'];
|
|
587
532
|
if (managedSession) {
|
|
588
|
-
const managed = await runManagedAgentOperation(managedArgs);
|
|
533
|
+
const managed = await runManagedAgentOperation(options.argv ?? managedArgs);
|
|
589
534
|
if (!managed.ok)
|
|
590
535
|
return managed;
|
|
591
536
|
return { ok: true, aid, content: managed.content ?? null, ...(managed.path ? { path: managed.path } : {}), ...(managed.saved ? { saved: true } : {}) };
|
|
@@ -625,7 +570,7 @@ export async function agentWelcome(aid, options = {}) {
|
|
|
625
570
|
if (readTaskRuntimeContextFromEnv()?.selfAid !== aid) {
|
|
626
571
|
return { ok: false, code: 'SELF_AGENT_REQUIRED', error: 'welcome only targets the current Agent' };
|
|
627
572
|
}
|
|
628
|
-
const managed = await runManagedAgentOperation(managedArgs);
|
|
573
|
+
const managed = await runManagedAgentOperation(options.argv ?? managedArgs);
|
|
629
574
|
if (!managed.ok)
|
|
630
575
|
return managed;
|
|
631
576
|
return {
|
|
@@ -803,7 +748,7 @@ export async function agentRename(aid, name) {
|
|
|
803
748
|
return { ok: true, aid, name };
|
|
804
749
|
}
|
|
805
750
|
// ==================== agentReady ====================
|
|
806
|
-
export async function agentReady(aid) {
|
|
751
|
+
export async function agentReady(aid, commandArgs) {
|
|
807
752
|
const managedSessionId = process.env.EVOLCORE_SESSION_ID;
|
|
808
753
|
const taskSelfAid = managedSessionId ? readTaskRuntimeContextFromEnv()?.selfAid : undefined;
|
|
809
754
|
if (taskSelfAid && taskSelfAid.replace(/^@/, '') !== aid.replace(/^@/, '')) {
|
|
@@ -822,6 +767,7 @@ export async function agentReady(aid) {
|
|
|
822
767
|
const result = await ipcQuery(p.socket, {
|
|
823
768
|
type: 'evolagent.bootstrapComplete',
|
|
824
769
|
aid,
|
|
770
|
+
...(managedSessionId ? { argv: ['agent', ...(commandArgs ?? ['ready', aid])] } : {}),
|
|
825
771
|
...(managedSessionId ? { sessionId: managedSessionId, delegationToken } : {}),
|
|
826
772
|
}, 30_000);
|
|
827
773
|
if (!result)
|
package/dist/cli/aun-commands.js
CHANGED
|
@@ -4,6 +4,7 @@ import { agentMdPath, resolvePaths, resolveRoot } from '../paths.js';
|
|
|
4
4
|
import { isExplicitGroupId, normalizeGroupAid, sameGroupAid } from '../aun/group/index.js';
|
|
5
5
|
import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
6
6
|
import { ipcQuery } from '../ipc.js';
|
|
7
|
+
import { isValidAid as validSendAid } from '../aun/aid/validation.js';
|
|
7
8
|
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
8
9
|
import { isManagementRole } from '../config/builtin-roles.js';
|
|
9
10
|
import { readBestTaskRuntimeContext } from './task-context.js';
|
|
@@ -1088,6 +1089,7 @@ Options:
|
|
|
1088
1089
|
}
|
|
1089
1090
|
// ==================== Storage ====================
|
|
1090
1091
|
export async function cmdStorage(args) {
|
|
1092
|
+
args = canonicalizeEvolcoreCommandArgv(['ec', 'storage', ...args]).slice(2);
|
|
1091
1093
|
const sub = args[0];
|
|
1092
1094
|
const aunPath = resolveAunPath(args);
|
|
1093
1095
|
const formatJson = getArgValue(args, '--format') === 'json';
|
|
@@ -1142,12 +1144,9 @@ Options:
|
|
|
1142
1144
|
console.error('用法: ec storage upload <aid> <local-file> <remote-path> [--public]');
|
|
1143
1145
|
process.exit(1);
|
|
1144
1146
|
}
|
|
1145
|
-
if (!fs.existsSync(localFile)) {
|
|
1146
|
-
console.error(`❌ 文件不存在: ${localFile}`);
|
|
1147
|
-
process.exit(1);
|
|
1148
|
-
}
|
|
1149
1147
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
1150
1148
|
type: 'storage.upload',
|
|
1149
|
+
argv: ['storage', ...args],
|
|
1151
1150
|
aid,
|
|
1152
1151
|
localFile,
|
|
1153
1152
|
remotePath,
|
|
@@ -1172,12 +1171,25 @@ Options:
|
|
|
1172
1171
|
return;
|
|
1173
1172
|
}
|
|
1174
1173
|
const authorization = await ipcQuery(resolvePaths().socket, {
|
|
1175
|
-
type: 'storage.auth', operation, aid, sessionId: process.env.EVOLCORE_SESSION_ID, delegationToken,
|
|
1174
|
+
type: 'storage.auth', argv: ['storage', ...args], operation, aid, sessionId: process.env.EVOLCORE_SESSION_ID, delegationToken,
|
|
1176
1175
|
}, 10_000);
|
|
1177
1176
|
if (!authorization)
|
|
1178
1177
|
failManagedGroup(formatJson, 'DAEMON_UNAVAILABLE', 'Unable to connect to the evolcore daemon');
|
|
1179
1178
|
if (!authorization.ok)
|
|
1180
1179
|
failManagedGroup(formatJson, authorization.code || 'STORAGE_AUTH_FAILED', authorization.error || 'Storage operation denied');
|
|
1180
|
+
if (sub === 'ls') {
|
|
1181
|
+
const objects = authorization.result?.objects ?? authorization.result ?? [];
|
|
1182
|
+
console.log(Array.isArray(objects) && !objects.length ? '(空)' : JSON.stringify(objects, null, 2));
|
|
1183
|
+
}
|
|
1184
|
+
else if (sub === 'quota')
|
|
1185
|
+
console.log(JSON.stringify(authorization.result, null, 2));
|
|
1186
|
+
else if (formatJson)
|
|
1187
|
+
console.log(JSON.stringify(authorization));
|
|
1188
|
+
else if (sub === 'download')
|
|
1189
|
+
console.log(`✓ 已下载: ${authorization.localPath} (${authorization.size} bytes)`);
|
|
1190
|
+
else
|
|
1191
|
+
console.log(`✓ 已删除: ${authorization.objectKey}`);
|
|
1192
|
+
return;
|
|
1181
1193
|
}
|
|
1182
1194
|
const { storageUpload, storageDownload, storageLs, storageRm, storageQuota } = await import('../aun/storage/index.js');
|
|
1183
1195
|
if (sub === 'upload') {
|
|
@@ -1398,6 +1410,8 @@ Options:
|
|
|
1398
1410
|
renderManagedMsgResult(sub, result, formatJson);
|
|
1399
1411
|
return;
|
|
1400
1412
|
}
|
|
1413
|
+
if (process.env.EVOLCORE_SESSION_ID && sub === 'send')
|
|
1414
|
+
return runManagedSend(['msg', ...args], formatJson);
|
|
1401
1415
|
const { msgSend, msgPull, msgAck, msgRecall, msgOnline, msgHistory } = await import('../aun/msg/index.js');
|
|
1402
1416
|
const commonOpts = { aunPath, slotId: appSlot };
|
|
1403
1417
|
const requireConsumerSlot = (operation) => {
|
|
@@ -1935,6 +1949,21 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
1935
1949
|
renderManagedGroupResult(args, result, formatJson);
|
|
1936
1950
|
return;
|
|
1937
1951
|
}
|
|
1952
|
+
if (process.env.EVOLCORE_SESSION_ID && sub === 'send') {
|
|
1953
|
+
if (args.includes('--aun-path') || args.includes('--app')) {
|
|
1954
|
+
failManagedGroup(formatJson, 'NOT_ALLOWED', '--aun-path and --app are not allowed in a managed task');
|
|
1955
|
+
}
|
|
1956
|
+
let groupId;
|
|
1957
|
+
try {
|
|
1958
|
+
groupId = normalizeGroupAid(args[2] ?? '', from.slice(from.indexOf('.') + 1));
|
|
1959
|
+
}
|
|
1960
|
+
catch (error) {
|
|
1961
|
+
failManagedGroup(formatJson, 'INVALID_ARGUMENT', `Invalid group AID: ${error instanceof Error ? error.message : String(error)}`);
|
|
1962
|
+
}
|
|
1963
|
+
const runtime = await readBestTaskRuntimeContext();
|
|
1964
|
+
validateManagedGroupScope(from, groupId, runtime, formatJson);
|
|
1965
|
+
return runManagedSend(['group', ...args], formatJson);
|
|
1966
|
+
}
|
|
1938
1967
|
const { groupSend, groupPull, groupAck, groupHistory, parseGroupHistoryArgs, groupCreate, groupInfo, groupList, groupUpdate, groupDissolve, groupSuspend, groupResume, groupJoin, groupLeave, groupInvite, groupInvites, groupAcceptInvite, groupRejectInvite, groupRevokeInvite, groupKick, groupMembers, groupOnline, groupSetRole, groupTransferOwner, groupBan, groupUnban, groupBanlist, groupBlock, groupUnblock, groupBlocklist, groupReportStatus, groupMemberStatuses, groupRules, groupUpdateRules, groupRulesFileGet, groupRulesFileSet, groupRulesFilePublish, } = await import('../aun/msg/index.js');
|
|
1939
1968
|
const commonOpts = { aunPath, slotId: appSlot };
|
|
1940
1969
|
if (['block', 'unblock', 'blocklist', 'report-status', 'member-statuses'].includes(sub)) {
|
|
@@ -2737,6 +2766,121 @@ g- 是名称的一部分,会完整保留;默认命名格式为 g-10000 至 g
|
|
|
2737
2766
|
process.exit(1);
|
|
2738
2767
|
}
|
|
2739
2768
|
// ==================== Main ====================
|
|
2769
|
+
async function runManagedSend(argv, formatJson) {
|
|
2770
|
+
const delegationToken = readDelegationCredential();
|
|
2771
|
+
if (!delegationToken)
|
|
2772
|
+
failManagedGroup(formatJson, 'DELEGATION_REQUIRED', 'Managed send requires delegation');
|
|
2773
|
+
const runtime = await readBestTaskRuntimeContext();
|
|
2774
|
+
const result = await ipcQuery(resolvePaths().socket, {
|
|
2775
|
+
type: 'aun-msg-send', argv, delegationToken,
|
|
2776
|
+
originSessionId: process.env.EVOLCORE_SESSION_ID, originMessageId: runtime?.messageId,
|
|
2777
|
+
}, null);
|
|
2778
|
+
if (!result)
|
|
2779
|
+
failManagedGroup(formatJson, 'AUN_DAEMON_UNAVAILABLE', 'Unable to connect to the EvolCore daemon');
|
|
2780
|
+
if (!result.ok)
|
|
2781
|
+
failManagedGroup(formatJson, result.code ?? 'AUN_SEND_FAILED', result.error ?? 'Send failed');
|
|
2782
|
+
if (formatJson)
|
|
2783
|
+
console.log(JSON.stringify(result));
|
|
2784
|
+
else if (result.handoff_id)
|
|
2785
|
+
console.log(`✓ handoff ${result.handoff_id} ${result.status === 'delivered' ? '已投递' : '已排队'} ${result.message_id ?? ''}`.trimEnd());
|
|
2786
|
+
else
|
|
2787
|
+
console.log(`✓ 已发送 message_id=${result.message_id ?? '-'} seq=${result.seq ?? result.message?.seq ?? '-'}`);
|
|
2788
|
+
}
|
|
2789
|
+
export function resolveManagedSendArgv(argv) {
|
|
2790
|
+
if (!['msg', 'group'].includes(argv[0]) || argv[1] !== 'send' || !validSendAid(argv[2]))
|
|
2791
|
+
throw new Error('Invalid managed send command');
|
|
2792
|
+
const scope = argv[0];
|
|
2793
|
+
const aid = argv[2];
|
|
2794
|
+
const to = scope === 'group' ? normalizeGroupAid(argv[3], aid.slice(aid.indexOf('.') + 1)) : argv[3];
|
|
2795
|
+
if (!to || !validSendAid(to))
|
|
2796
|
+
throw new Error('Invalid send target');
|
|
2797
|
+
const values = new Map();
|
|
2798
|
+
const booleans = new Set();
|
|
2799
|
+
const text = [];
|
|
2800
|
+
const mentions = [];
|
|
2801
|
+
const valueFlags = new Set(['--format', '--file', '--payload', '--text-from-file', '--link', '--title', '--description', '--as', '--content-type', '--text', '--transcript', '--thread', '--return', '--handoff-context', '--mention']);
|
|
2802
|
+
const booleanFlags = new Set(['--encrypt', '--no-encrypt', '--mention-all']);
|
|
2803
|
+
for (let index = 4; index < argv.length; index++) {
|
|
2804
|
+
const flag = argv[index];
|
|
2805
|
+
if (flag === '--') {
|
|
2806
|
+
text.push(...argv.slice(index + 1));
|
|
2807
|
+
break;
|
|
2808
|
+
}
|
|
2809
|
+
if (flag === '--app' || flag === '--aun-path')
|
|
2810
|
+
throw new Error(`${flag} is not allowed for managed sends`);
|
|
2811
|
+
if (booleanFlags.has(flag))
|
|
2812
|
+
booleans.add(flag);
|
|
2813
|
+
else if (valueFlags.has(flag)) {
|
|
2814
|
+
const value = argv[++index];
|
|
2815
|
+
if (value === undefined || valueFlags.has(value) || booleanFlags.has(value))
|
|
2816
|
+
throw new Error(`${flag} requires a value`);
|
|
2817
|
+
if (flag === '--mention') {
|
|
2818
|
+
for (const mention of value.split(',').map(item => item.trim()).filter(Boolean)) {
|
|
2819
|
+
if (!validSendAid(mention))
|
|
2820
|
+
throw new Error('Invalid mention AID');
|
|
2821
|
+
mentions.push({ aid: mention });
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
else {
|
|
2825
|
+
if (values.has(flag))
|
|
2826
|
+
throw new Error(`Duplicate send option: ${flag}`);
|
|
2827
|
+
values.set(flag, value);
|
|
2828
|
+
}
|
|
2829
|
+
}
|
|
2830
|
+
else
|
|
2831
|
+
text.push(flag);
|
|
2832
|
+
}
|
|
2833
|
+
if (booleans.has('--encrypt') && booleans.has('--no-encrypt'))
|
|
2834
|
+
throw new Error('Encryption options are mutually exclusive');
|
|
2835
|
+
if (values.has('--format') && values.get('--format') !== 'json')
|
|
2836
|
+
throw new Error('--format only supports json');
|
|
2837
|
+
const returnPolicy = values.get('--return');
|
|
2838
|
+
if (returnPolicy !== undefined && !['none', 'required'].includes(returnPolicy))
|
|
2839
|
+
throw new Error('Invalid return policy');
|
|
2840
|
+
const handoffContext = values.get('--handoff-context');
|
|
2841
|
+
if (handoffContext !== undefined && (scope !== 'msg' || !handoffContext.trim() || handoffContext.length > 65536))
|
|
2842
|
+
throw new Error('Invalid private handoff context');
|
|
2843
|
+
if (scope === 'msg' && (mentions.length || booleans.has('--mention-all')))
|
|
2844
|
+
throw new Error('Mentions require a group send');
|
|
2845
|
+
if (scope === 'group' && (values.has('--link') || values.has('--text-from-file')))
|
|
2846
|
+
throw new Error('Unsupported group send body');
|
|
2847
|
+
const modes = ['--file', '--payload', '--text-from-file', '--link'].filter(flag => values.has(flag));
|
|
2848
|
+
if (modes.length > 1 || (modes.length && text.length))
|
|
2849
|
+
throw new Error('Message body modes are mutually exclusive');
|
|
2850
|
+
let payload;
|
|
2851
|
+
let file;
|
|
2852
|
+
if (values.has('--file')) {
|
|
2853
|
+
const as = values.get('--as');
|
|
2854
|
+
if (as && !['image', 'video', 'voice', 'file'].includes(as))
|
|
2855
|
+
throw new Error('Invalid attachment type');
|
|
2856
|
+
if (values.has('--transcript') && as !== 'voice')
|
|
2857
|
+
throw new Error('--transcript requires --as voice');
|
|
2858
|
+
file = { filePath: values.get('--file'), as, contentType: values.get('--content-type'), text: values.get('--text'), transcript: values.get('--transcript') };
|
|
2859
|
+
}
|
|
2860
|
+
else if (values.has('--payload')) {
|
|
2861
|
+
payload = JSON.parse(values.get('--payload'));
|
|
2862
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload))
|
|
2863
|
+
throw new Error('--payload must be a JSON object');
|
|
2864
|
+
}
|
|
2865
|
+
else if (values.has('--link')) {
|
|
2866
|
+
assertEcSingleLine(values.get('--title'), '--title');
|
|
2867
|
+
payload = { type: 'link', url: values.get('--link'), ...(values.get('--title') ? { title: values.get('--title') } : {}),
|
|
2868
|
+
...(values.get('--description') ? { description: values.get('--description') } : {}) };
|
|
2869
|
+
}
|
|
2870
|
+
else if (!values.has('--text-from-file')) {
|
|
2871
|
+
if (!text.join(' '))
|
|
2872
|
+
throw new Error('Message content is required');
|
|
2873
|
+
payload = { type: 'text', text: text.join(' ') };
|
|
2874
|
+
}
|
|
2875
|
+
if (!file && ['--as', '--content-type', '--text', '--transcript'].some(flag => values.has(flag)))
|
|
2876
|
+
throw new Error('Attachment options require --file');
|
|
2877
|
+
if (booleans.has('--mention-all'))
|
|
2878
|
+
mentions.push({ scope: 'all' });
|
|
2879
|
+
return { aid, to, scope, payload, file, textFile: values.get('--text-from-file'),
|
|
2880
|
+
encrypt: booleans.has('--no-encrypt') ? false : booleans.has('--encrypt') ? true : undefined,
|
|
2881
|
+
thread: values.get('--thread'), returnPolicy: returnPolicy, handoffContext,
|
|
2882
|
+
mentions: mentions.length ? mentions : undefined };
|
|
2883
|
+
}
|
|
2740
2884
|
/**
|
|
2741
2885
|
* 收集位置参数(从 startIdx 开始)。
|
|
2742
2886
|
*
|
package/dist/cli/ctl-command.js
CHANGED
|
@@ -41,11 +41,10 @@ export async function cmdCtl(args) {
|
|
|
41
41
|
console.error('错误: EVOLCORE_SESSION_ID 未设置(仅在 evolcore 托管环境中可用)');
|
|
42
42
|
process.exit(1);
|
|
43
43
|
}
|
|
44
|
-
const cmd = '/' + args.join(' ');
|
|
45
44
|
const socketPath = resolvePaths().socket;
|
|
46
45
|
const result = await ipcQuery(socketPath, {
|
|
47
46
|
type: 'ctl',
|
|
48
|
-
|
|
47
|
+
argv: ['ctl', ...args],
|
|
49
48
|
sessionId,
|
|
50
49
|
delegationToken: readDelegationCredential(),
|
|
51
50
|
}, 10_000);
|
package/dist/cli/diag.js
CHANGED
|
@@ -8,11 +8,11 @@ export async function cmdDiag(args) {
|
|
|
8
8
|
console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机 daemon.json.owners[0];有效诊断期间再次执行会追加到原 case。');
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
|
+
const argv = ['diag', ...args];
|
|
11
12
|
const json = args.at(-2) === '--format' && args.at(-1) === 'json';
|
|
12
|
-
const argv = json ? args.slice(0, -2) : args;
|
|
13
13
|
let result;
|
|
14
14
|
try {
|
|
15
|
-
parseDiagArgs(
|
|
15
|
+
parseDiagArgs(args);
|
|
16
16
|
result = await ipcQuery(resolvePaths().socket, {
|
|
17
17
|
type: 'diag', argv,
|
|
18
18
|
...(process.env.EVOLCORE_SESSION_ID ? {
|
|
@@ -6,6 +6,7 @@ import { HANDOFF_ID_RE } from '../core/handoff/store.js';
|
|
|
6
6
|
import { isHelpFlag, wantsHelp } from './help.js';
|
|
7
7
|
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
8
8
|
import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
|
|
9
|
+
import { MAIN_CLI_BIN } from '../product.js';
|
|
9
10
|
function parseLimit(value) {
|
|
10
11
|
const limit = Number(value);
|
|
11
12
|
if (!value || !Number.isInteger(limit) || limit < 1 || limit > HANDOFF_QUERY_MAX_LIMIT) {
|
|
@@ -70,8 +71,9 @@ export function parseTrace(args) {
|
|
|
70
71
|
}
|
|
71
72
|
return parsed;
|
|
72
73
|
}
|
|
73
|
-
export function parseReturn(args) {
|
|
74
|
-
|
|
74
|
+
export function parseReturn(args, options = {}) {
|
|
75
|
+
if (!options.canonical)
|
|
76
|
+
args = canonicalizeEvolcoreCommandArgv([MAIN_CLI_BIN, 'handoff', 'return', ...args]).slice(3);
|
|
75
77
|
const dash = args.indexOf('--');
|
|
76
78
|
if (dash >= 0) {
|
|
77
79
|
const beforeDash = args.slice(0, dash);
|
|
@@ -96,8 +98,10 @@ export function parseReturn(args) {
|
|
|
96
98
|
if (filePath && contentArgs.length > 0)
|
|
97
99
|
throw new Error('HANDOFF_CONTENT_FILE_CONFLICT');
|
|
98
100
|
if (filePath) {
|
|
101
|
+
if (options.deferFileRead)
|
|
102
|
+
return { handoffId, content: '' };
|
|
99
103
|
try {
|
|
100
|
-
return { handoffId, content: fs.readFileSync(filePath, 'utf8') };
|
|
104
|
+
return { handoffId, content: options.readFile ? options.readFile(filePath) : fs.readFileSync(filePath, 'utf8') };
|
|
101
105
|
}
|
|
102
106
|
catch {
|
|
103
107
|
throw new Error('HANDOFF_CONTENT_FILE_READ_FAILED');
|
|
@@ -153,6 +157,7 @@ function formatTimestamp(value) {
|
|
|
153
157
|
return new Date(value).toISOString();
|
|
154
158
|
}
|
|
155
159
|
export async function cmdHandoff(args) {
|
|
160
|
+
args = canonicalizeEvolcoreCommandArgv([MAIN_CLI_BIN, 'handoff', ...args]).slice(2);
|
|
156
161
|
const sub = args[0];
|
|
157
162
|
if (!sub || isHelpFlag(sub) || wantsHelp(args)) {
|
|
158
163
|
console.log(`用法: ec handoff <command> [args]
|
|
@@ -170,7 +175,7 @@ Commands:
|
|
|
170
175
|
if (sub === 'return') {
|
|
171
176
|
let parsed;
|
|
172
177
|
try {
|
|
173
|
-
parsed = parseReturn(args.slice(1));
|
|
178
|
+
parsed = parseReturn(args.slice(1), { canonical: true, deferFileRead: !!process.env.EVOLCORE_SESSION_ID });
|
|
174
179
|
}
|
|
175
180
|
catch (error) {
|
|
176
181
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -185,6 +190,7 @@ Commands:
|
|
|
185
190
|
}
|
|
186
191
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
187
192
|
type: 'handoff-return',
|
|
193
|
+
argv: ['handoff', ...args],
|
|
188
194
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
189
195
|
handoffId: parsed.handoffId,
|
|
190
196
|
content: parsed.content,
|
|
@@ -201,7 +207,7 @@ Commands:
|
|
|
201
207
|
if (sub === 'recover-return') {
|
|
202
208
|
let parsed;
|
|
203
209
|
try {
|
|
204
|
-
parsed = parseReturn(args.slice(1));
|
|
210
|
+
parsed = parseReturn(args.slice(1), { canonical: true, deferFileRead: !!process.env.EVOLCORE_SESSION_ID });
|
|
205
211
|
}
|
|
206
212
|
catch (error) {
|
|
207
213
|
console.error(`✗ ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -215,6 +221,7 @@ Commands:
|
|
|
215
221
|
}
|
|
216
222
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
217
223
|
type: 'handoff-recover-return',
|
|
224
|
+
argv: ['handoff', ...args],
|
|
218
225
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
219
226
|
handoffId: parsed.handoffId,
|
|
220
227
|
content: parsed.content,
|
|
@@ -237,6 +244,7 @@ Commands:
|
|
|
237
244
|
}
|
|
238
245
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
239
246
|
type: 'handoff-status', sessionId: process.env.EVOLCORE_SESSION_ID, handoffId,
|
|
247
|
+
argv: ['handoff', ...args],
|
|
240
248
|
delegationToken: readDelegationCredential(),
|
|
241
249
|
}, 5000);
|
|
242
250
|
if (!result) {
|
|
@@ -264,6 +272,7 @@ Commands:
|
|
|
264
272
|
}
|
|
265
273
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
266
274
|
type: 'handoff-list',
|
|
275
|
+
argv: ['handoff', ...args],
|
|
267
276
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
268
277
|
agent: parsed.agent,
|
|
269
278
|
state: parsed.state,
|
|
@@ -308,6 +317,7 @@ Commands:
|
|
|
308
317
|
}
|
|
309
318
|
const result = await ipcQuery(resolvePaths().socket, {
|
|
310
319
|
type: 'handoff-trace',
|
|
320
|
+
argv: ['handoff', ...args],
|
|
311
321
|
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
312
322
|
agent: parsed.agent,
|
|
313
323
|
handoffId: parsed.handoffId,
|