evolcore 0.0.24 → 0.0.26
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 +59 -0
- package/bin/ec.js +12 -1
- package/bin/install-codex-managed-hooks.mjs +28 -1
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +54 -13
- package/dist/agents/codex/app-server-client.js +13 -5
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +128 -42
- package/dist/agents/ecagent-runner.js +14 -18
- package/dist/agents/gemini-runner.js +24 -9
- package/dist/agents/runner-types.js +25 -17
- package/dist/aun/aid/agentmd.js +135 -10
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/aid/index.js +2 -1
- package/dist/aun/aid/managed-operation.js +53 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/menu-client.js +74 -0
- package/dist/aun/msg/group.js +1 -1
- package/dist/aun/msg/managed-operation.js +1 -1
- package/dist/aun/msg/p2p.js +6 -1
- package/dist/aun/msg/upload.js +30 -22
- package/dist/aun/storage/client.js +4 -1
- package/dist/aun/storage/index.js +1 -1
- package/dist/channels/aun.js +329 -94
- package/dist/cli/agent-command.js +125 -5
- package/dist/cli/agent-create.js +151 -11
- package/dist/cli/agent.js +119 -6
- package/dist/cli/aun-commands.js +74 -7
- package/dist/cli/config.js +27 -8
- package/dist/cli/contact.js +63 -6
- package/dist/cli/daemon-commands.js +90 -25
- package/dist/cli/diag.js +31 -0
- package/dist/cli/handoff-command.js +35 -3
- package/dist/cli/index.js +7 -1
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/menu-client.js +38 -23
- package/dist/cli/restart-monitor.js +57 -10
- package/dist/config/builtin-roles.js +2 -0
- package/dist/config/config-manager.js +15 -0
- package/dist/config/config-operation-service.js +165 -3
- package/dist/config/contact-operation-service.js +96 -7
- package/dist/config/resolved-config-op.js +66 -8
- package/dist/core/agent-application-service.js +2 -1
- package/dist/core/auth/authorization-audit.js +20 -12
- package/dist/core/auth/operation-authorizer.js +87 -8
- package/dist/core/auth/operation-catalog.js +51 -4
- package/dist/core/auth/remote-access-store.js +40 -1
- package/dist/core/bootstrap-service.js +1 -1
- package/dist/core/command/agent-control.js +54 -25
- package/dist/core/command/cli-intent-parser.js +18 -0
- package/dist/core/command/command-handler.js +152 -20
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/menu-catalog.js +13 -3
- package/dist/core/command/menu-handler.js +88 -31
- package/dist/core/command/menu-protocol.js +6 -0
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +77 -12
- package/dist/core/event-catalog.js +5 -0
- package/dist/core/evolagent.js +3 -3
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/message/im-renderer.js +72 -21
- package/dist/core/message/message-bridge.js +69 -9
- package/dist/core/message/message-queue.js +26 -0
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +48 -23
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/ec-command-parser.js +51 -12
- package/dist/core/permission/sandbox-runtime.js +36 -14
- package/dist/core/permission/tool-policy.js +47 -7
- package/dist/index.js +195 -31
- package/dist/ipc.js +54 -2
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/price-resolver.js +28 -10
- package/dist/utils/avatar-upload.js +282 -23
- package/dist/utils/cross-platform.js +30 -1
- package/dist/utils/error-utils.js +21 -0
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +3 -1
- package/dist/utils/model-prices.jsonl +3 -3
- package/dist/utils/npm-ops.js +176 -35
- package/kits/docs/context-assembly.md +1 -0
- package/kits/docs/evolcore/INDEX.md +3 -1
- package/kits/docs/evolcore/agent-create.md +30 -11
- package/kits/docs/evolcore/agent.md +18 -8
- package/kits/docs/evolcore/aid.md +6 -4
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -0
- package/kits/docs/evolcore/config.md +7 -0
- package/kits/docs/evolcore/contact.md +12 -5
- package/kits/docs/evolcore/menu-client.md +11 -3
- package/kits/docs/evolcore/msg.md +1 -0
- package/kits/docs/prompt-loading-architecture.md +1 -0
- package/kits/docs/venues/group.md +12 -0
- package/kits/eck_manifest.json +12 -0
- package/kits/rules/03-identity.md +3 -1
- package/kits/templates/message-fragments/handoff-request-to-target.md +3 -3
- package/kits/templates/roles/admin.json +14 -2
- package/kits/templates/roles/member.json +3 -2
- package/kits/templates/roles/visitor.json +4 -3
- package/kits/templates/system-fragments/bootstrap.md +16 -5
- package/kits/templates/system-fragments/channel.md +1 -1
- package/kits/templates/system-fragments/session.md +1 -1
- package/package.json +6 -4
- package/skills/eclink/SKILL.md +0 -84
- package/skills/eclink/agents/openai.yaml +0 -4
package/dist/cli/aun-commands.js
CHANGED
|
@@ -116,7 +116,7 @@ async function runManagedAid(args, formatJson) {
|
|
|
116
116
|
if (!parsed.ok)
|
|
117
117
|
failManagedAid(formatJson, parsed.code, parsed.reason);
|
|
118
118
|
const runtime = await readBestTaskRuntimeContext();
|
|
119
|
-
const requiresSelfAid = parsed.command.kind === 'show' || parsed.command.kind === 'agentmd.put';
|
|
119
|
+
const requiresSelfAid = parsed.command.kind === 'show' || parsed.command.kind === 'agentmd.put' || parsed.command.kind === 'avatar';
|
|
120
120
|
if (requiresSelfAid && runtime?.selfAid && parsed.command.aid !== runtime.selfAid.replace(/^@/, '')) {
|
|
121
121
|
failManagedAid(formatJson, 'SCOPE_MISMATCH', `托管任务只能操作当前 self AID:${runtime.selfAid}`);
|
|
122
122
|
}
|
|
@@ -155,6 +155,22 @@ async function runManagedAid(args, formatJson) {
|
|
|
155
155
|
console.log(JSON.stringify({ ok: true, aid: response.result.aid, path: response.result.path }, null, 2));
|
|
156
156
|
else
|
|
157
157
|
console.log('✓ agent.md 已发布');
|
|
158
|
+
return;
|
|
159
|
+
case 'avatar':
|
|
160
|
+
if (formatJson)
|
|
161
|
+
console.log(JSON.stringify({
|
|
162
|
+
ok: true,
|
|
163
|
+
aid: response.result.aid,
|
|
164
|
+
avatar: response.result.avatar,
|
|
165
|
+
objectKey: response.result.objectKey,
|
|
166
|
+
sha256: response.result.sha256,
|
|
167
|
+
mime: response.result.mime,
|
|
168
|
+
width: response.result.width,
|
|
169
|
+
height: response.result.height,
|
|
170
|
+
aspectRatio: response.result.aspectRatio,
|
|
171
|
+
}, null, 2));
|
|
172
|
+
else
|
|
173
|
+
console.log(`✓ 头像已更新${response.result.avatar ? `: ${response.result.avatar}` : ''}${response.result.sha256 ? ` (sha256: ${response.result.sha256})` : ''}`);
|
|
158
174
|
}
|
|
159
175
|
}
|
|
160
176
|
function failManagedGroup(formatJson, code, error) {
|
|
@@ -346,6 +362,7 @@ Commands:
|
|
|
346
362
|
lookup <aid> 远程探测 AID(是否存在 + 网关 + agent.md)
|
|
347
363
|
agentmd put <aid> 读本地 agent.md → 签名 → 上传
|
|
348
364
|
agentmd get <aid> 下载 agent.md → 验签 → 本地持久化
|
|
365
|
+
avatar <aid> --file <path> | --url <https-url> 上传头像并更新 agent.md
|
|
349
366
|
|
|
350
367
|
Options:
|
|
351
368
|
--format json 输出 JSON 格式
|
|
@@ -795,7 +812,56 @@ Options:
|
|
|
795
812
|
console.error(`未知子命令: aid agentmd ${verb ?? ''}\n用法: ec aid agentmd [put|get] <aid>`);
|
|
796
813
|
process.exit(1);
|
|
797
814
|
}
|
|
798
|
-
|
|
815
|
+
if (sub === 'avatar') {
|
|
816
|
+
const aid = args[1];
|
|
817
|
+
const fileIndex = args.indexOf('--file');
|
|
818
|
+
const urlIndex = args.indexOf('--url');
|
|
819
|
+
const filePath = fileIndex >= 0 ? args[fileIndex + 1] : undefined;
|
|
820
|
+
const url = urlIndex >= 0 ? args[urlIndex + 1] : undefined;
|
|
821
|
+
if (wantsHelp(args)) {
|
|
822
|
+
console.log('用法: ec aid avatar <aid> (--file <path> | --url <https-url>) [--format json]');
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
const sourceCount = (fileIndex >= 0 ? 1 : 0) + (urlIndex >= 0 ? 1 : 0);
|
|
826
|
+
if (!aid || sourceCount !== 1 || (fileIndex >= 0 && (!filePath || filePath.startsWith('-')))
|
|
827
|
+
|| (urlIndex >= 0 && (!url || url.startsWith('-'))) || (fileIndex >= 0 && fileIndex !== 2) || (urlIndex >= 0 && urlIndex !== 2)
|
|
828
|
+
|| args.filter(value => value === '--file').length > 1 || args.filter(value => value === '--url').length > 1 || !isValidAid(aid)
|
|
829
|
+
|| (args.includes('--format') && !formatJson) || (args.includes('--format') && args.filter(value => value === '--format').length !== 1)) {
|
|
830
|
+
const usage = '用法: ec aid avatar <aid> (--file <path> | --url <https-url>) [--format json]';
|
|
831
|
+
if (formatJson)
|
|
832
|
+
console.log(JSON.stringify({ ok: false, code: 'INVALID_ARGUMENT', error: usage }, null, 2));
|
|
833
|
+
else
|
|
834
|
+
console.error(usage);
|
|
835
|
+
process.exit(1);
|
|
836
|
+
}
|
|
837
|
+
const { uploadAvatarFile, uploadAvatarUrl } = await import('../utils/avatar-upload.js');
|
|
838
|
+
const result = filePath
|
|
839
|
+
? await uploadAvatarFile(aid, filePath, { aunPath })
|
|
840
|
+
: await uploadAvatarUrl(aid, url, { aunPath });
|
|
841
|
+
if (!result.ok) {
|
|
842
|
+
if (formatJson)
|
|
843
|
+
console.log(JSON.stringify({ ok: false, code: result.code, error: result.error }, null, 2));
|
|
844
|
+
else
|
|
845
|
+
console.error(`❌ 头像上传失败: ${result.error}`);
|
|
846
|
+
process.exit(1);
|
|
847
|
+
}
|
|
848
|
+
if (formatJson)
|
|
849
|
+
console.log(JSON.stringify({
|
|
850
|
+
ok: true,
|
|
851
|
+
aid,
|
|
852
|
+
avatar: result.publicUrl,
|
|
853
|
+
objectKey: result.objectKey,
|
|
854
|
+
sha256: result.sha256,
|
|
855
|
+
mime: result.mime,
|
|
856
|
+
width: result.width,
|
|
857
|
+
height: result.height,
|
|
858
|
+
aspectRatio: result.aspectRatio,
|
|
859
|
+
}, null, 2));
|
|
860
|
+
else
|
|
861
|
+
console.log(`✓ 头像已更新${result.publicUrl ? `: ${result.publicUrl}` : ''}${result.sha256 ? ` (sha256: ${result.sha256})` : ''}`);
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
console.error(`未知子命令: ${sub}\n用法: ec aid [list|show|new|delete|lookup|agentmd|avatar] <aid>`);
|
|
799
865
|
process.exit(1);
|
|
800
866
|
}
|
|
801
867
|
// ==================== RPC ====================
|
|
@@ -1079,6 +1145,7 @@ Commands:
|
|
|
1079
1145
|
|
|
1080
1146
|
Options:
|
|
1081
1147
|
--text-from-file <path> 从文件读取文本(UTF-8),用于超长消息或避免 Shell 转义
|
|
1148
|
+
--handoff-context <text> 仅托管会话:为目标会话补充本地上下文,不发给对端
|
|
1082
1149
|
--app <name> 指定应用 slot(独立消费通道,不影响 daemon)
|
|
1083
1150
|
--aun-path <path> 指定 AUN keystore 根
|
|
1084
1151
|
--format json 输出 JSON 格式
|
|
@@ -1397,7 +1464,7 @@ Options:
|
|
|
1397
1464
|
process.stderr.write(' ⏫ finalizing upload...\n');
|
|
1398
1465
|
}
|
|
1399
1466
|
};
|
|
1400
|
-
const result = await msgSend({ from, to, body, encrypt, thread, returnPolicy: returnPolicyRaw, onUploadProgress, ...commonOpts });
|
|
1467
|
+
const result = await msgSend({ from, to, body, encrypt, thread, returnPolicy: returnPolicyRaw, handoffContext: getArgValue(args, '--handoff-context'), onUploadProgress, ...commonOpts });
|
|
1401
1468
|
if (!result.ok) {
|
|
1402
1469
|
if (formatJson) {
|
|
1403
1470
|
console.log(JSON.stringify(result));
|
|
@@ -1622,7 +1689,7 @@ Options:
|
|
|
1622
1689
|
--text <说明> 附件说明文字(仅 --file 模式)
|
|
1623
1690
|
--transcript <text> 语音转写(仅 --as voice)
|
|
1624
1691
|
--group-id <aid> 指定自定义群 AID(仅 create)
|
|
1625
|
-
--member-type <type> 定向邀请成员类型:human|
|
|
1692
|
+
--member-type <type> 定向邀请成员类型:human|agent(仅 invite)
|
|
1626
1693
|
-- end-of-options:其后所有参数按正文处理
|
|
1627
1694
|
(用于发送恰好等于某 flag 的文本,如 send a g -- --encrypt)
|
|
1628
1695
|
|
|
@@ -2226,8 +2293,8 @@ Options:
|
|
|
2226
2293
|
}
|
|
2227
2294
|
}
|
|
2228
2295
|
const memberType = getArgValue(args, '--member-type');
|
|
2229
|
-
if (memberType !== undefined && memberType !== 'human' && memberType !== '
|
|
2230
|
-
console.error('❌ --member-type 必须是 human 或
|
|
2296
|
+
if (memberType !== undefined && memberType !== 'human' && memberType !== 'agent') {
|
|
2297
|
+
console.error('❌ --member-type 必须是 human 或 agent');
|
|
2231
2298
|
process.exit(1);
|
|
2232
2299
|
}
|
|
2233
2300
|
const result = await groupInvite({ from, groupId, members, memberType: memberType, ...commonOpts });
|
|
@@ -2406,7 +2473,7 @@ const VALUE_FLAGS = new Set([
|
|
|
2406
2473
|
'--as', '--content-type', '--mention', '--visibility', '--join-mode',
|
|
2407
2474
|
'--group-id', '--name', '--message', '--answer', '--page', '--size',
|
|
2408
2475
|
'--member-type',
|
|
2409
|
-
'--aun-path', '--thread', '--return',
|
|
2476
|
+
'--aun-path', '--thread', '--return', '--handoff-context',
|
|
2410
2477
|
]);
|
|
2411
2478
|
const BOOLEAN_FLAGS = new Set([
|
|
2412
2479
|
'--encrypt', '--no-encrypt', '--mention-all',
|
package/dist/cli/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
|
|
2
2
|
import { initConfigManager } from '../config/config-manager.js';
|
|
3
3
|
import { resolveConfigCommand } from '../config/resolved-config-op.js';
|
|
4
|
-
import { AUTHENTICATED_CONFIG_ROLE_ENV,
|
|
4
|
+
import { AUTHENTICATED_CONFIG_ROLE_ENV, executeResolvedConfigCommandAsync, } from '../config/config-operation-service.js';
|
|
5
5
|
import { ipcQuery } from '../ipc.js';
|
|
6
6
|
import { resolvePaths } from '../paths.js';
|
|
7
7
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
@@ -31,6 +31,7 @@ function getResultPayload(result) {
|
|
|
31
31
|
...(result.source ? { source: result.source } : {}),
|
|
32
32
|
...(result.schemaDefault ? { schemaDefault: true } : {}),
|
|
33
33
|
...(result.note ? { note: result.note } : {}),
|
|
34
|
+
...(result.roleDetails ? { role: result.roleDetails } : {}),
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
function getResultLine(result) {
|
|
@@ -39,7 +40,10 @@ function getResultLine(result) {
|
|
|
39
40
|
: !result.source
|
|
40
41
|
? `${result.field} = ${JSON.stringify(result.value)} (${result.scope})`
|
|
41
42
|
: `${result.field} = ${JSON.stringify(result.value)} [source: ${result.source.target}]`;
|
|
42
|
-
|
|
43
|
+
const role = result.roleDetails
|
|
44
|
+
? `\n role: explicit=${JSON.stringify(result.roleDetails.explicitRole)} effective=${JSON.stringify(result.roleDetails.effectiveRole)} [${result.roleDetails.effectiveRoleSource}]`
|
|
45
|
+
: '';
|
|
46
|
+
return `${head}${role}${result.note ? `\n ↳ ${result.note}` : ''}`;
|
|
43
47
|
}
|
|
44
48
|
function renderConfigExecution(result, formatJson) {
|
|
45
49
|
if (!result.ok)
|
|
@@ -56,6 +60,7 @@ function renderConfigExecution(result, formatJson) {
|
|
|
56
60
|
value: result.value,
|
|
57
61
|
scope: result.scope,
|
|
58
62
|
file: result.file,
|
|
63
|
+
...(result.roleDetails ? { role: result.roleDetails } : {}),
|
|
59
64
|
}, () => `Set ${result.field} = ${JSON.stringify(result.value)} [${result.scope}]`);
|
|
60
65
|
case 'unset':
|
|
61
66
|
return emit(formatJson, {
|
|
@@ -63,6 +68,7 @@ function renderConfigExecution(result, formatJson) {
|
|
|
63
68
|
field: result.field,
|
|
64
69
|
removed: result.removed,
|
|
65
70
|
...(result.removed ? { scope: result.scope } : {}),
|
|
71
|
+
...(result.roleDetails ? { role: result.roleDetails } : {}),
|
|
66
72
|
}, () => result.removed ? `Removed ${result.field} from ${result.scope}` : `${result.field} was not set`);
|
|
67
73
|
case 'show':
|
|
68
74
|
return emit(formatJson, { ok: true, scope: result.scope, configs: result.configs }, () => JSON.stringify(result.configs, null, 2));
|
|
@@ -172,18 +178,18 @@ function renderBatchGet(results, formatJson) {
|
|
|
172
178
|
if (!allOk)
|
|
173
179
|
process.exit(1);
|
|
174
180
|
}
|
|
175
|
-
function runDirectBatchGet(fields, rest, formatJson) {
|
|
176
|
-
const results = fields.map(field => {
|
|
181
|
+
async function runDirectBatchGet(fields, rest, formatJson) {
|
|
182
|
+
const results = await Promise.all(fields.map(async (field) => {
|
|
177
183
|
const resolved = resolveConfigCommand(['config', 'get', field, ...rest]);
|
|
178
184
|
if (!resolved.ok)
|
|
179
185
|
return { ok: false, field, code: resolved.code, error: resolved.reason };
|
|
180
|
-
const result =
|
|
186
|
+
const result = await executeResolvedConfigCommandAsync(resolved.command, { role: 'owner' });
|
|
181
187
|
if (!result.ok)
|
|
182
188
|
return { ok: false, field, code: result.code, error: result.error };
|
|
183
189
|
if (result.subcommand === 'get')
|
|
184
190
|
return result;
|
|
185
191
|
return { ok: false, field, code: 'UNEXPECTED_RESULT', error: `config get ${field} produced a non-get result` };
|
|
186
|
-
});
|
|
192
|
+
}));
|
|
187
193
|
renderBatchGet(results, formatJson);
|
|
188
194
|
}
|
|
189
195
|
async function runManagedBatchGet(fields, rest, formatJson) {
|
|
@@ -215,6 +221,11 @@ Global commands:
|
|
|
215
221
|
Selectors:
|
|
216
222
|
--self <aid> [--peer <peerKey>] | --default | --process
|
|
217
223
|
|
|
224
|
+
Relation role (AUN peer AID):
|
|
225
|
+
get role --self <aid> --peer <peer-aid>
|
|
226
|
+
set role <role-id> --self <aid> --peer <peer-aid>
|
|
227
|
+
unset role --self <aid> --peer <peer-aid>
|
|
228
|
+
|
|
218
229
|
Output:
|
|
219
230
|
--format json`;
|
|
220
231
|
export async function cmdConfig(args) {
|
|
@@ -241,13 +252,21 @@ export async function cmdConfig(args) {
|
|
|
241
252
|
fail(formatJson, 'SCHEMA_INIT_FAILED', error instanceof Error ? error.message : String(error));
|
|
242
253
|
}
|
|
243
254
|
if (isBatchGet) {
|
|
244
|
-
runDirectBatchGet(batchGet.fields, batchGet.rest, formatJson);
|
|
255
|
+
await runDirectBatchGet(batchGet.fields, batchGet.rest, formatJson);
|
|
245
256
|
return;
|
|
246
257
|
}
|
|
247
258
|
const resolved = resolveConfigCommand(['config', ...args]);
|
|
248
259
|
if (!resolved.ok)
|
|
249
260
|
fail(formatJson, resolved.code, resolved.reason);
|
|
250
|
-
renderConfigExecution(
|
|
261
|
+
renderConfigExecution(await executeResolvedConfigCommandAsync(resolved.command, {
|
|
251
262
|
role: process.env[AUTHENTICATED_CONFIG_ROLE_ENV],
|
|
263
|
+
roleContext: {
|
|
264
|
+
self: resolved.command.self || '',
|
|
265
|
+
actorRole: process.env[AUTHENTICATED_CONFIG_ROLE_ENV] || 'owner',
|
|
266
|
+
actorRoleSource: 'local-cli',
|
|
267
|
+
isDaemonOwner: false,
|
|
268
|
+
fromControlChannel: false,
|
|
269
|
+
aunAvailable: true,
|
|
270
|
+
},
|
|
252
271
|
}), formatJson);
|
|
253
272
|
}
|
package/dist/cli/contact.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { resolvePaths } from '../paths.js';
|
|
2
|
+
import { loadAllAgents } from '../config-store.js';
|
|
2
3
|
import { executeResolvedContactCommand, resolveContactCommand, } from '../config/contact-operation-service.js';
|
|
3
4
|
import { ipcQuery } from '../ipc.js';
|
|
4
5
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
@@ -14,9 +15,17 @@ export async function cmdContact(args) {
|
|
|
14
15
|
output(result, json);
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
if (!args.includes('--self') && isListCommand(args) && !process.env.EVOLCORE_SELF_AID?.trim()) {
|
|
19
|
+
output(await executeAggregateList(args), json);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const resolved = resolveContactCommand(withDefaultSelf(args));
|
|
23
|
+
if (!resolved.ok) {
|
|
24
|
+
const message = resolved.code === 'INVALID_SELF' && !args.includes('--self')
|
|
25
|
+
? `${resolved.reason}; multiple local Agents are configured, add --self <agent-aid>`
|
|
26
|
+
: resolved.reason;
|
|
27
|
+
fail(message, resolved.code);
|
|
28
|
+
}
|
|
20
29
|
const result = await executeResolvedContactCommand(resolved.command);
|
|
21
30
|
if (!result.ok)
|
|
22
31
|
fail(result.error, result.code, result.data);
|
|
@@ -62,11 +71,59 @@ function printHelp() {
|
|
|
62
71
|
ec contact add <primaryId> --self <agent-aid>
|
|
63
72
|
ec contact block <primaryId> --self <agent-aid>
|
|
64
73
|
ec contact unblock <primaryId> --self <agent-aid>
|
|
65
|
-
ec contact list --blocked --self <agent-aid>
|
|
74
|
+
ec contact list --blocked [--self <agent-aid>]
|
|
75
|
+
ec contact list --pending [--self <agent-aid>]
|
|
76
|
+
ec contact list --all [--self <agent-aid>]
|
|
77
|
+
ec contact approve <primaryId> --request-id <id> [--self <agent-aid>]
|
|
78
|
+
ec contact reject <primaryId> --request-id <id> [--self <agent-aid>]
|
|
79
|
+
ec contact block-request <primaryId> --request-id <id> [--self <agent-aid>]
|
|
66
80
|
|
|
67
81
|
Options:
|
|
68
|
-
--self <agent-aid>
|
|
69
|
-
--blocked
|
|
82
|
+
--self <agent-aid> 本端 agent AID;省略时从当前运行环境推断
|
|
83
|
+
--blocked 仅列出已拉黑联系人
|
|
84
|
+
--pending 仅列出待审核联系人申请
|
|
85
|
+
--all 列出所有联系人及状态
|
|
86
|
+
--request-id <id> 联系人申请 ID(审批命令必填)
|
|
87
|
+
--contact-revision <revision> 申请审批时使用的联系人版本(可选)
|
|
70
88
|
--format json 输出 JSON
|
|
71
89
|
--help, -h 显示帮助`);
|
|
72
90
|
}
|
|
91
|
+
function withDefaultSelf(args) {
|
|
92
|
+
if (args.includes('--self'))
|
|
93
|
+
return args;
|
|
94
|
+
const selfAid = resolveStandaloneSelfAid();
|
|
95
|
+
return selfAid ? [...args, '--self', selfAid] : args;
|
|
96
|
+
}
|
|
97
|
+
function isListCommand(args) {
|
|
98
|
+
return args[0] === 'list';
|
|
99
|
+
}
|
|
100
|
+
async function executeAggregateList(args) {
|
|
101
|
+
const agents = loadAllAgents().agents.map(agent => agent.aid).filter(Boolean).sort();
|
|
102
|
+
const results = [];
|
|
103
|
+
for (const aid of agents) {
|
|
104
|
+
const resolved = resolveContactCommand([...args, '--self', aid]);
|
|
105
|
+
if (!resolved.ok)
|
|
106
|
+
fail(resolved.reason, resolved.code);
|
|
107
|
+
const result = await executeResolvedContactCommand(resolved.command);
|
|
108
|
+
if (!result.ok)
|
|
109
|
+
fail(result.error, result.code, result.data);
|
|
110
|
+
results.push(result);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
ok: true,
|
|
114
|
+
operation: args.includes('--blocked') ? 'list-blocked'
|
|
115
|
+
: args.includes('--pending') ? 'list-pending' : 'list-all',
|
|
116
|
+
scope: 'all-agents',
|
|
117
|
+
agents: results,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** Resolve the local Agent identity for standalone CLI commands. */
|
|
121
|
+
export function resolveStandaloneSelfAid() {
|
|
122
|
+
const runtimeAid = process.env.EVOLCORE_SELF_AID?.trim();
|
|
123
|
+
if (runtimeAid)
|
|
124
|
+
return runtimeAid;
|
|
125
|
+
const agents = loadAllAgents().agents
|
|
126
|
+
.map(agent => agent.aid)
|
|
127
|
+
.filter(Boolean);
|
|
128
|
+
return agents.length === 1 ? agents[0] : undefined;
|
|
129
|
+
}
|
|
@@ -28,6 +28,7 @@ import { WEB_CLI_BIN, WEB_PACKAGE_LATEST, WEB_PACKAGE_NAME } from '../product.js
|
|
|
28
28
|
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
29
29
|
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
30
30
|
import { isInitCancelledError, printInitCancelHint } from './init-cancel.js';
|
|
31
|
+
import { computeBuildId } from '../utils/evolcore-version.js';
|
|
31
32
|
import { listCodexAppServerProcesses, unregisterCodexAppServerProcess } from '../agents/codex/app-server-registry.js';
|
|
32
33
|
import { DEFAULT_ECWEB_PORT, ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
|
|
33
34
|
import { checkCodexProjectPath, inspectCodexManagedHook, ensureCodexManagedHook, runCodexHookLaunchDiagnostic, } from '../agents/codex/diagnostics.js';
|
|
@@ -312,7 +313,10 @@ export async function runUpgradeChecks(upgradeFn = signal => tryUpgrade({ signal
|
|
|
312
313
|
clearTimeout(timer);
|
|
313
314
|
}
|
|
314
315
|
};
|
|
315
|
-
const upgrade = await
|
|
316
|
+
const [upgrade, ecwebUpgrade] = await Promise.all([
|
|
317
|
+
runWithTimeout('EvolCore', upgradeFn),
|
|
318
|
+
runWithTimeout(WEB_PACKAGE_NAME, ecwebUpgradeFn),
|
|
319
|
+
]);
|
|
316
320
|
switch (upgrade.status) {
|
|
317
321
|
case 'upgraded':
|
|
318
322
|
console.log(`✅ Upgraded: ${upgrade.from} → ${upgrade.to}`);
|
|
@@ -329,7 +333,6 @@ export async function runUpgradeChecks(upgradeFn = signal => tryUpgrade({ signal
|
|
|
329
333
|
console.log(`⚠ Upgrade failed${upgrade.from && upgrade.to ? ` (${upgrade.from} → ${upgrade.to})` : ''}, continuing with current version${upgrade.error ? `: ${upgrade.error}` : ''}`);
|
|
330
334
|
break;
|
|
331
335
|
}
|
|
332
|
-
const ecwebUpgrade = await runWithTimeout(WEB_PACKAGE_NAME, ecwebUpgradeFn);
|
|
333
336
|
switch (ecwebUpgrade.status) {
|
|
334
337
|
case 'upgraded':
|
|
335
338
|
console.log(`✅ ${WEB_PACKAGE_NAME} upgraded: ${ecwebUpgrade.from} → ${ecwebUpgrade.to}`);
|
|
@@ -769,21 +772,50 @@ export async function cmdStart(opts = {}) {
|
|
|
769
772
|
};
|
|
770
773
|
setTimeout(checkReady, 1000);
|
|
771
774
|
}
|
|
772
|
-
|
|
775
|
+
function isPidReused(pid, expectedStartedAt) {
|
|
776
|
+
if (expectedStartedAt === undefined)
|
|
777
|
+
return false;
|
|
778
|
+
const actualStartedAt = getProcessStartTime(pid);
|
|
779
|
+
return actualStartedAt !== null && !startTimeMatches(expectedStartedAt, actualStartedAt);
|
|
780
|
+
}
|
|
781
|
+
function reportPidReused(pid) {
|
|
782
|
+
console.log(`ℹ EvolCore PID ${pid} no longer refers to the recorded process; treating it as stopped`);
|
|
783
|
+
}
|
|
784
|
+
async function stopPid(pid, gracefulRequested = false, expectedStartedAt) {
|
|
773
785
|
console.log(`🛑 Stopping EvolCore (PID: ${pid})...`);
|
|
786
|
+
if (isPidReused(pid, expectedStartedAt)) {
|
|
787
|
+
reportPidReused(pid);
|
|
788
|
+
return true;
|
|
789
|
+
}
|
|
774
790
|
if (!gracefulRequested)
|
|
775
791
|
platform.killProcess(pid);
|
|
776
792
|
if (await platform.waitForProcessExit(pid, gracefulRequested ? 30_000 : 10_000)) {
|
|
777
793
|
console.log('✓ EvolCore stopped');
|
|
778
794
|
return true;
|
|
779
795
|
}
|
|
780
|
-
|
|
796
|
+
if (isPidReused(pid, expectedStartedAt)) {
|
|
797
|
+
reportPidReused(pid);
|
|
798
|
+
return true;
|
|
799
|
+
}
|
|
800
|
+
const state = platform.getProcessState(pid);
|
|
801
|
+
const stateSuffix = state ? ` (state=${state})` : '';
|
|
802
|
+
console.log(`⚠ EvolCore PID ${pid} did not exit gracefully${stateSuffix}; forcing termination...`);
|
|
803
|
+
if (isPidReused(pid, expectedStartedAt)) {
|
|
804
|
+
reportPidReused(pid);
|
|
805
|
+
return true;
|
|
806
|
+
}
|
|
781
807
|
platform.killProcess(pid, true);
|
|
782
808
|
if (await platform.waitForProcessExit(pid, 5_000)) {
|
|
783
809
|
console.log('✓ EvolCore stopped (forced)');
|
|
784
810
|
return true;
|
|
785
811
|
}
|
|
786
|
-
|
|
812
|
+
if (isPidReused(pid, expectedStartedAt)) {
|
|
813
|
+
reportPidReused(pid);
|
|
814
|
+
return true;
|
|
815
|
+
}
|
|
816
|
+
const finalState = platform.getProcessState(pid);
|
|
817
|
+
const finalStateSuffix = finalState ? ` (state=${finalState})` : '';
|
|
818
|
+
console.error(`❌ EvolCore PID ${pid} is still running${finalStateSuffix}; restart aborted`);
|
|
787
819
|
return false;
|
|
788
820
|
}
|
|
789
821
|
function isRuntimeOrphan(orphan, currentHome = resolveRoot()) {
|
|
@@ -813,13 +845,14 @@ export async function cmdStop() {
|
|
|
813
845
|
return;
|
|
814
846
|
}
|
|
815
847
|
const pids = new Set([...aliveMains.map(entry => entry.record.pid), ...runtimeOrphans.map(orphan => orphan.pid)]);
|
|
848
|
+
const expectedStarts = new Map(aliveMains.map(entry => [entry.record.pid, entry.record.startedAt]));
|
|
816
849
|
if (runtimeOrphans.length > 0) {
|
|
817
850
|
console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(orphan => orphan.pid).join(', ')}`);
|
|
818
851
|
}
|
|
819
852
|
const gracefulPid = ping && pids.has(ping.pid)
|
|
820
853
|
? await requestDaemonShutdown(p.socket, DAEMON_SHUTDOWN_TIMEOUT_MS, 'ec stop', pids)
|
|
821
854
|
: null;
|
|
822
|
-
const stopped = await Promise.all([...pids].map(pid => stopPid(pid, pid === gracefulPid)));
|
|
855
|
+
const stopped = await Promise.all([...pids].map(pid => stopPid(pid, pid === gracefulPid, expectedStarts.get(pid))));
|
|
823
856
|
if (stopped.some(result => !result)) {
|
|
824
857
|
process.exitCode = 1;
|
|
825
858
|
return;
|
|
@@ -836,11 +869,13 @@ export async function cmdRestart(opts = {}) {
|
|
|
836
869
|
if (!ensureCodexHookBeforeLifecycle())
|
|
837
870
|
return;
|
|
838
871
|
const initialStatus = scanInstances();
|
|
839
|
-
const initialOrphans = findOrphanProcesses();
|
|
840
|
-
const initialRuntimeOrphans = initialOrphans.filter(orphan => isRuntimeOrphan(orphan));
|
|
841
872
|
const socketPath = resolvePaths().socket;
|
|
842
873
|
const ping = await probeDaemon(socketPath);
|
|
843
874
|
if (ping && !hasVisibleDaemonPid(initialStatus, ping)) {
|
|
875
|
+
// Only pay for a cross-host process-table scan when the IPC PID is not
|
|
876
|
+
// present in our registry. This is the exceptional PID-namespace case;
|
|
877
|
+
// healthy restarts no longer scan every Node process before stopping.
|
|
878
|
+
const initialRuntimeOrphans = findOrphanProcesses().filter(orphan => isRuntimeOrphan(orphan));
|
|
844
879
|
if (await tryDelegatedDaemonRestart(socketPath))
|
|
845
880
|
return;
|
|
846
881
|
if (initialRuntimeOrphans.length === 0 && rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
@@ -848,13 +883,13 @@ export async function cmdRestart(opts = {}) {
|
|
|
848
883
|
}
|
|
849
884
|
// 构建交给 restart-monitor:它在 daemon 停止之后才编译,dist/ 不会被活进程
|
|
850
885
|
// 占用,失败还能回滚到上一份产物。这里再编译一次会落在事务保护之外。
|
|
851
|
-
//
|
|
852
|
-
//
|
|
853
|
-
|
|
886
|
+
// restart-monitor owns upgrade checks. Running them here as well caused a
|
|
887
|
+
// normal restart to perform every registry lookup twice, and in installed
|
|
888
|
+
// mode could race the monitor while it was preparing its rollback point.
|
|
854
889
|
if (!requireCompletedDataMigration(resolveRoot(), 'restart'))
|
|
855
890
|
return;
|
|
856
891
|
// 停止所有活 main 进程(可能不止一个)
|
|
857
|
-
const status =
|
|
892
|
+
const status = initialStatus;
|
|
858
893
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
859
894
|
if (aliveMains.length > 0) {
|
|
860
895
|
if (aliveMains.length > 1) {
|
|
@@ -865,7 +900,7 @@ export async function cmdRestart(opts = {}) {
|
|
|
865
900
|
const gracefulPid = currentPing && mainPids.has(currentPing.pid)
|
|
866
901
|
? await requestDaemonShutdown(socketPath, DAEMON_SHUTDOWN_TIMEOUT_MS, 'ec restart', mainPids)
|
|
867
902
|
: null;
|
|
868
|
-
const stopped = await Promise.all(aliveMains.map(m => stopPid(m.record.pid, m.record.pid === gracefulPid)));
|
|
903
|
+
const stopped = await Promise.all(aliveMains.map(m => stopPid(m.record.pid, m.record.pid === gracefulPid, m.record.startedAt)));
|
|
869
904
|
if (stopped.some(result => !result)) {
|
|
870
905
|
console.error('❌ Restart aborted because an existing EvolCore process could not be stopped');
|
|
871
906
|
process.exitCode = 1;
|
|
@@ -881,7 +916,8 @@ export async function cmdRestart(opts = {}) {
|
|
|
881
916
|
return;
|
|
882
917
|
}
|
|
883
918
|
// 孤儿处理:同 HOME/同安装包的孤儿属于本运行时,先确认退出再替换;
|
|
884
|
-
// 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。
|
|
919
|
+
// 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。findOrphanProcesses
|
|
920
|
+
// 在 Windows 上需要一次 CIM 查询;保留一个快照,避免同一阶段重复扫描。
|
|
885
921
|
{
|
|
886
922
|
const orphans = findOrphanProcesses();
|
|
887
923
|
const confirmedTestDaemons = orphans.filter(o => o.confirmedTestDaemon);
|
|
@@ -890,7 +926,7 @@ export async function cmdRestart(opts = {}) {
|
|
|
890
926
|
console.log(`☠ 已清理 ${killed.length} 个泄漏的测试 daemon: ${killed.join(', ')}`);
|
|
891
927
|
await sleep(500);
|
|
892
928
|
}
|
|
893
|
-
const runtimeOrphans =
|
|
929
|
+
const runtimeOrphans = orphans.filter(o => isRuntimeOrphan(o));
|
|
894
930
|
if (runtimeOrphans.length > 0) {
|
|
895
931
|
console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(o => o.pid).join(', ')}`);
|
|
896
932
|
const orphanPids = new Set(runtimeOrphans.map(orphan => orphan.pid));
|
|
@@ -906,13 +942,9 @@ export async function cmdRestart(opts = {}) {
|
|
|
906
942
|
}
|
|
907
943
|
await sleep(500);
|
|
908
944
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
process.exitCode = 1;
|
|
913
|
-
return;
|
|
914
|
-
}
|
|
915
|
-
const otherHome = findOrphanProcesses().filter(o => !o.confirmedTestDaemon && !isRuntimeOrphan(o));
|
|
945
|
+
// stopPid() already waited for every runtime orphan above, so avoid a
|
|
946
|
+
// second scan before handling cross-HOME records.
|
|
947
|
+
const otherHome = orphans.filter(o => !o.confirmedTestDaemon && !isRuntimeOrphan(o));
|
|
916
948
|
if (opts.clear && otherHome.length > 0) {
|
|
917
949
|
const killed = killOrphans(otherHome);
|
|
918
950
|
console.log(`☠ 已 SIGKILL ${killed.length} 个跨 HOME 孤儿进程: ${killed.join(', ')}`);
|
|
@@ -921,6 +953,14 @@ export async function cmdRestart(opts = {}) {
|
|
|
921
953
|
else if (otherHome.length > 0) {
|
|
922
954
|
reportOrphans(otherHome);
|
|
923
955
|
}
|
|
956
|
+
// Keep the post-stop ownership guard: a process that appeared during the
|
|
957
|
+
// cleanup window must still block replacement.
|
|
958
|
+
const remainingRuntimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
|
|
959
|
+
if (remainingRuntimeOrphans.length > 0) {
|
|
960
|
+
console.error(`❌ Restart aborted: EvolCore process still running (PID: ${remainingRuntimeOrphans.map(o => o.pid).join(', ')})`);
|
|
961
|
+
process.exitCode = 1;
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
924
964
|
}
|
|
925
965
|
// 只清理 EvolCore 自己登记的 codex app-server,不能影响桌面端实例。
|
|
926
966
|
{
|
|
@@ -955,8 +995,7 @@ export async function cmdRestart(opts = {}) {
|
|
|
955
995
|
process.exitCode = 1;
|
|
956
996
|
return;
|
|
957
997
|
}
|
|
958
|
-
console.log('🔄 Restart monitor started
|
|
959
|
-
await sleep(2000);
|
|
998
|
+
console.log('🔄 Restart monitor started; service is coming back online in the background...');
|
|
960
999
|
// 代码统计(开发环境)
|
|
961
1000
|
if (path.normalize(resolveRoot()) === path.normalize(getPackageRoot())) {
|
|
962
1001
|
console.log('');
|
|
@@ -1125,6 +1164,7 @@ export async function cmdStatus() {
|
|
|
1125
1164
|
const p = resolvePaths();
|
|
1126
1165
|
const status = scanInstances();
|
|
1127
1166
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
1167
|
+
const aliveRestartMonitors = status.restartMonitors.filter(m => m.alive);
|
|
1128
1168
|
// Start all read-only daemon queries together. On a busy Windows host each
|
|
1129
1169
|
// query can otherwise wait behind the same IPC/event-loop delay and make the
|
|
1130
1170
|
// total `ec status` time the sum of several individual timeouts.
|
|
@@ -1263,6 +1303,10 @@ export async function cmdStatus() {
|
|
|
1263
1303
|
catch { }
|
|
1264
1304
|
}
|
|
1265
1305
|
}
|
|
1306
|
+
else if (aliveRestartMonitors.length > 0) {
|
|
1307
|
+
console.log(`🔄 EvolCore 正在重启,daemon 尚未就绪(monitor PID: ${aliveRestartMonitors.map(m => m.record.pid).join(', ')})`);
|
|
1308
|
+
console.log(' 请稍后再次执行 ec status。');
|
|
1309
|
+
}
|
|
1266
1310
|
else {
|
|
1267
1311
|
console.log(ipcFailure ? '⚠ 无法确认 EvolCore 运行状态:IPC 不可用,且没有可见的存活 PID。' : '⚠ EvolCore is not running');
|
|
1268
1312
|
if (ipcFailure)
|
|
@@ -1312,6 +1356,24 @@ export async function cmdStatus() {
|
|
|
1312
1356
|
]);
|
|
1313
1357
|
agentsResponse = agentResponse;
|
|
1314
1358
|
if (statusResponse) {
|
|
1359
|
+
if (statusResponse.build) {
|
|
1360
|
+
if (statusResponse.build.runtimeMode === 'source') {
|
|
1361
|
+
console.log(` Build ID: runtime=source dist=${statusResponse.build.diskDistId || '?'}`);
|
|
1362
|
+
console.log(' ℹ daemon 当前由源码入口运行,dist build ID 不参与一致性比较。');
|
|
1363
|
+
}
|
|
1364
|
+
else {
|
|
1365
|
+
const runtimeBuildId = statusResponse.build.runtimeId || '?';
|
|
1366
|
+
const diskDistBuildId = statusResponse.build.diskDistId || '?';
|
|
1367
|
+
console.log(` Build ID: runtime=${runtimeBuildId} dist=${diskDistBuildId}`);
|
|
1368
|
+
if (runtimeBuildId !== '?' && diskDistBuildId !== '?' && runtimeBuildId !== diskDistBuildId) {
|
|
1369
|
+
console.log(' ⚠ 运行进程 build ID 与磁盘 dist 不一致;请重启 daemon 后再判断源码行为。');
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
else {
|
|
1374
|
+
console.log(` Build ID: runtime=unavailable (daemon 未提供 build identity) dist=${computeBuildId(path.join(getPackageRoot(), 'dist')) ?? '?'}`);
|
|
1375
|
+
console.log(' ⚠ 当前 daemon 未提供 build ID;请重启到包含 build identity 的版本后再判断源码行为。');
|
|
1376
|
+
}
|
|
1315
1377
|
// 🔑 AUN AIDs 表格(详细 AUN 实例状态)
|
|
1316
1378
|
try {
|
|
1317
1379
|
if (aidsResponse?.ok && aidsResponse.aids?.length > 0) {
|
|
@@ -2771,9 +2833,12 @@ function removeEcwebInstanceFiles(p) {
|
|
|
2771
2833
|
}
|
|
2772
2834
|
/** 清理 EvolCore 登记的 codex app-server 孤儿进程,返回清理的进程数。 */
|
|
2773
2835
|
export function stopCodexAppServerOrphans() {
|
|
2836
|
+
const entries = listCodexAppServerProcesses();
|
|
2837
|
+
if (entries.length === 0)
|
|
2838
|
+
return 0;
|
|
2774
2839
|
const codexProcs = new Set(platform.findProcesses('codex app-server'));
|
|
2775
2840
|
let killed = 0;
|
|
2776
|
-
for (const entry of
|
|
2841
|
+
for (const entry of entries) {
|
|
2777
2842
|
const { pid, startedAt } = entry.record;
|
|
2778
2843
|
if (!platform.isProcessRunning(pid)) {
|
|
2779
2844
|
unregisterCodexAppServerProcess(entry.filePath);
|
package/dist/cli/diag.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ipcQuery } from '../ipc.js';
|
|
2
|
+
import { resolvePaths } from '../paths.js';
|
|
3
|
+
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
4
|
+
import { parseDiagArgs } from '../core/command/diag-service.js';
|
|
5
|
+
import { wantsHelp } from './help.js';
|
|
6
|
+
export async function cmdDiag(args) {
|
|
7
|
+
if (wantsHelp(args)) {
|
|
8
|
+
console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机 daemon.json.owners[0]。');
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const json = args.at(-2) === '--format' && args.at(-1) === 'json';
|
|
12
|
+
const argv = json ? args.slice(0, -2) : args;
|
|
13
|
+
let result;
|
|
14
|
+
try {
|
|
15
|
+
parseDiagArgs(argv);
|
|
16
|
+
result = await ipcQuery(resolvePaths().socket, {
|
|
17
|
+
type: 'diag', argv,
|
|
18
|
+
...(process.env.EVOLCORE_SESSION_ID ? {
|
|
19
|
+
sessionId: process.env.EVOLCORE_SESSION_ID,
|
|
20
|
+
delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
|
|
21
|
+
} : {}),
|
|
22
|
+
}, 30_000) ?? { ok: false, code: 'DAEMON_UNAVAILABLE', message: 'daemon 未返回结果,请检查其运行状态;发送结果尚未确认' };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
result = { ok: false, code: 'INVALID_ARGUMENT', message: error.message };
|
|
26
|
+
}
|
|
27
|
+
result.message ??= result.error ?? '诊断请求未完成';
|
|
28
|
+
console.log(json ? JSON.stringify(result, null, 2) : result.message);
|
|
29
|
+
if (!result.ok)
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
}
|