evolcore 0.0.35-test.0 → 0.0.36
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 +31 -0
- package/README.md +6 -0
- package/bin/install-codex-managed-hooks.mjs +20 -3
- package/dist/agents/baseagent-availability.js +1 -1
- package/dist/agents/baseagent.js +88 -0
- package/dist/agents/claude-runner.js +59 -12
- package/dist/agents/codex/app-server-client.js +18 -1
- package/dist/agents/codex-runner.js +262 -21
- package/dist/agents/ecagent-runner.js +47 -11
- package/dist/agents/gemini-runner.js +36 -12
- package/dist/aun/aid/client.js +4 -3
- package/dist/aun/aid/control-aid.js +270 -8
- package/dist/aun/aid/identity.js +6 -3
- package/dist/aun/aid/ownership-operation.js +58 -0
- package/dist/aun/aid/store.js +1 -0
- package/dist/aun/group/fs-download.js +67 -2
- package/dist/aun/group/history.js +20 -5
- package/dist/aun/group/operations.js +8 -2
- package/dist/aun/menu/client.js +39 -2
- package/dist/aun/menu/transport.js +1 -1
- package/dist/aun/msg/history.js +43 -4
- package/dist/aun/msg/managed-operation.js +30 -53
- package/dist/aun/msg/p2p.js +51 -15
- package/dist/aun/outbox.js +4 -0
- package/dist/channels/aun.js +260 -73
- package/dist/channels/daemon.js +6 -4
- package/dist/channels/feishu.js +3 -0
- package/dist/cli/agent-command.js +161 -223
- package/dist/cli/agent-create.js +190 -223
- package/dist/cli/agent.js +3 -1
- package/dist/cli/aid-bind-command.js +53 -0
- package/dist/cli/aun-commands.js +384 -91
- package/dist/cli/bench.js +1 -1
- package/dist/cli/cli-argv.js +74 -0
- package/dist/cli/daemon-commands.js +105 -74
- package/dist/cli/diag.js +1 -1
- package/dist/cli/fs-command.js +18 -19
- package/dist/cli/getmeta-command.js +159 -6
- package/dist/cli/index.js +6 -12
- package/dist/cli/init-channel.js +8 -55
- package/dist/cli/init.js +125 -218
- package/dist/cli/queue-command.js +11 -8
- package/dist/cli/restart-monitor.js +134 -48
- package/dist/cli/session-command.js +1 -1
- package/dist/cli/stats.js +7 -5
- package/dist/cli/thread-command.js +103 -30
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg-diag.js +1 -0
- package/dist/config/access-policy.js +2 -2
- package/dist/config/boot-log.js +14 -11
- package/dist/config/config-field-policy.js +9 -1
- package/dist/config/config-manager.js +176 -90
- package/dist/config/config-operation-service.js +7 -14
- package/dist/config/contact-book-store.js +142 -26
- package/dist/config/contact-book.js +4 -2
- package/dist/config/lifecycle.js +1 -1
- package/dist/config/owner-config.js +96 -0
- package/dist/config/peer-role-resolver.js +12 -18
- package/dist/config/providers-config.js +382 -0
- package/dist/config/providers-import.js +74 -0
- package/dist/config/providers-management.js +328 -0
- package/dist/config/providers.js +22 -0
- package/dist/config/resolved-config-op.js +17 -14
- package/dist/config/snapshot.js +28 -16
- package/dist/config-store.js +18 -14
- package/dist/core/agent-ipc-registration.js +21 -63
- package/dist/core/agent-runtime.js +16 -5
- package/dist/core/auth/agent-delegation.js +199 -25
- package/dist/core/auth/auth-gateway.js +44 -2
- package/dist/core/auth/authorization-denial.js +1 -1
- package/dist/core/auth/debug-context.js +2 -1
- package/dist/core/auth/delegation-authorization.js +2 -2
- package/dist/core/auth/delegation-diagnostics.js +4 -1
- package/dist/core/auth/operation-authorizer.js +10 -1
- package/dist/core/auth/operation-catalog.js +19 -1
- package/dist/core/bootstrap-service.js +43 -20
- package/dist/core/channel-loader.js +0 -1
- package/dist/core/channel-runtime.js +30 -4
- package/dist/core/command/agent-control.js +196 -37
- package/dist/core/command/cli-intent-parser.js +60 -4
- package/dist/core/command/command-handler.js +212 -60
- package/dist/core/command/connect-menu.js +1 -0
- package/dist/core/command/diag-service.js +5 -4
- package/dist/core/command/file-search.js +368 -0
- package/dist/core/command/menu-catalog.js +2 -1
- package/dist/core/command/menu-handler.js +292 -107
- package/dist/core/command/menu-protocol.js +23 -0
- package/dist/core/command/role-menu.js +7 -19
- package/dist/core/command/skill-slash.js +130 -25
- package/dist/core/command/slash-handler.js +101 -53
- package/dist/core/command/topic-slash.js +16 -5
- package/dist/core/daemon-bootstrap.js +7 -1
- package/dist/core/daemon-control.js +19 -1
- package/dist/core/daemon-lifecycle.js +2 -1
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/evolagent-registry.js +13 -2
- package/dist/core/evolagent.js +3 -6
- package/dist/core/handoff/ipc-registration.js +2 -2
- package/dist/core/handoff/runtime.js +40 -6
- package/dist/core/handoff/store.js +1 -0
- package/dist/core/inference/text-inference.js +95 -6
- package/dist/core/ipc-registration.js +43 -24
- package/dist/core/memory/consolidation-context.js +4 -1
- package/dist/core/memory/consolidation.js +25 -14
- package/dist/core/message/aun-ipc-sender.js +296 -88
- package/dist/core/message/aun-request-registry.js +226 -0
- package/dist/core/message/create-status.js +33 -4
- package/dist/core/message/message-bridge.js +62 -13
- package/dist/core/message/message-log.js +0 -1
- package/dist/core/message/message-queue.js +4 -1
- package/dist/core/message/message-utils.js +8 -1
- package/dist/core/message/peer-mode.js +17 -9
- package/dist/core/message/response-engine.js +266 -124
- package/dist/core/message/retry-scheduler.js +11 -8
- package/dist/core/model/catalog-service.js +60 -18
- package/dist/core/model/model-catalog.js +112 -9
- package/dist/core/model/model-fallback.js +94 -26
- package/dist/core/ownership/owner-resolver.js +687 -0
- package/dist/core/permission/approval-gateway.js +196 -62
- package/dist/core/permission/ec-command-parser.js +138 -25
- package/dist/core/permission/filesystem-approval-scope.js +141 -0
- package/dist/core/permission/protected-paths.js +14 -1
- package/dist/core/permission/sandbox-runtime.js +171 -18
- package/dist/core/permission/tool-policy.js +13 -2
- package/dist/core/role/runtime-policy.js +3 -4
- package/dist/core/session/session-idle-monitor.js +10 -8
- package/dist/core/session/session-manager.js +72 -45
- package/dist/core/session/session-mapper.js +18 -7
- package/dist/core/session/session-renew.js +5 -4
- package/dist/core/session/session-title.js +2 -1
- package/dist/core/session/session-turn-coordinator.js +4 -2
- package/dist/core/skill/index-generator.js +2 -16
- package/dist/core/task/task-recovery-service.js +15 -2
- package/dist/core/thread/command-parser.js +28 -13
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +11 -8
- package/dist/core/thread/thread-operation.js +79 -44
- package/dist/core/thread/thread-route.js +54 -6
- package/dist/core/thread/thread-service.js +236 -45
- package/dist/core/thread/topic-id.js +248 -0
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/eck/message-renderer.js +12 -2
- package/dist/index.js +50 -27
- package/dist/ipc.js +59 -6
- package/dist/paths.js +1 -0
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +10 -3
- package/dist/stats/db.js +8 -0
- package/dist/stats/writer.js +26 -4
- package/dist/trigger/authorization.js +48 -3
- package/dist/trigger/feedback.js +28 -10
- package/dist/trigger/ipc-service.js +86 -10
- package/dist/trigger/local-files.js +55 -23
- package/dist/trigger/scheduler.js +57 -11
- package/dist/trigger/system-definitions.js +1 -0
- package/dist/trigger/validation.js +44 -15
- package/dist/utils/aid-bind.js +17 -297
- package/dist/utils/avatar-upload.js +16 -4
- package/dist/utils/cross-platform.js +109 -34
- package/dist/utils/ecweb-supervisor.js +1 -1
- package/dist/utils/ecweb-utils.js +8 -1
- package/dist/utils/error-utils.js +44 -6
- package/dist/utils/instance-registry.js +12 -2
- package/dist/utils/npm-ops.js +102 -27
- package/dist/utils/package-version-info.js +72 -27
- package/dist/utils/restart-safety.js +50 -0
- package/dist/utils/upgrade-jobs.js +304 -0
- package/dist/utils/windows-autostart.js +17 -10
- package/kits/docs/INDEX.md +5 -0
- package/kits/docs/aun/ABILITY_CALLING.md +239 -0
- package/kits/docs/evolcore/INDEX.md +14 -3
- package/kits/docs/evolcore/agent-create.md +55 -141
- package/kits/docs/evolcore/agent.md +38 -16
- package/kits/docs/evolcore/aid.md +34 -0
- package/kits/docs/evolcore/config.md +20 -1
- package/kits/docs/evolcore/event.md +2 -2
- package/kits/docs/evolcore/fs.md +18 -2
- package/kits/docs/evolcore/group-collaboration.md +13 -246
- package/kits/docs/evolcore/group.md +2 -1
- package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +65 -1
- package/kits/docs/evolcore/msg.md +64 -2
- package/kits/docs/evolcore/skill.md +86 -0
- package/kits/docs/evolcore/stats.md +6 -0
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +145 -51
- package/kits/docs/evolcore/trigger.md +48 -3
- package/kits/eck_manifest.json +21 -0
- package/kits/eck_message_manifest.json +4 -4
- package/kits/migrations/migrate-role-config-v5.mjs +20 -7
- package/kits/rules/01-overview.md +2 -1
- package/kits/rules/03-identity.md +3 -1
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/07-memory-and-thread.md +1 -1
- package/kits/schemas/_meta.json +16 -1
- package/kits/schemas/agent-config.schema.13.json +44 -2
- package/kits/schemas/contact-book.schema.3.json +5 -0
- package/kits/schemas/daemon.schema.6.json +3 -1
- package/kits/schemas/daemon.schema.8.json +329 -0
- package/kits/schemas/defaults.schema.5.json +39 -3
- package/kits/schemas/providers.schema.1.json +76 -0
- package/kits/schemas/relation-config.schema.9.json +5 -1
- package/kits/skills/.switches.json +28 -0
- package/kits/skills/aid-ability/SKILL.md +214 -0
- package/kits/skills/ec-agent-create/SKILL.md +162 -0
- package/kits/skills/ec-group/SKILL.md +2 -1
- package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
- package/kits/skills/ec-identity/SKILL.md +143 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
- package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
- package/kits/skills/ec-trigger/SKILL.md +167 -0
- package/kits/skills/ec-trigger/references/examples.md +153 -0
- package/kits/skills/thread-ops/SKILL.md +108 -420
- package/kits/templates/message-fragments/thread-context.md +1 -2
- package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
- package/kits/templates/roles/member.json +1 -1
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +1 -0
- package/kits/templates/system-fragments/channel.md +2 -1
- package/kits/templates/system-fragments/commands.md +5 -4
- package/kits/templates/system-fragments/identity.md +2 -0
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -3
package/dist/cli/bench.js
CHANGED
|
@@ -491,7 +491,7 @@ Options:
|
|
|
491
491
|
const hex = crypto.randomBytes(4).toString('hex');
|
|
492
492
|
const newAid = `bench-${hex}.${aidDomain}`;
|
|
493
493
|
try {
|
|
494
|
-
await aidCreate(newAid, { aunPath });
|
|
494
|
+
await aidCreate(newAid, { aunPath, type: 'service' });
|
|
495
495
|
aids.push(newAid);
|
|
496
496
|
if (!formatJson)
|
|
497
497
|
console.log(ok(`创建 ${newAid}`));
|
package/dist/cli/cli-argv.js
CHANGED
|
@@ -1,4 +1,78 @@
|
|
|
1
1
|
import { decodeEvolcoreInlineText } from '../core/permission/ec-command-parser.js';
|
|
2
|
+
export const TIME_ARG_FORMATS = 'epoch 毫秒/秒、ISO 8601、YYYY-MM-DD HH:mm:ss [+08:00]、YYYY/MM/DD HH:mm:ss、相对时间 30s/5m/2h/1d、now';
|
|
3
|
+
const RELATIVE_TIME_RE = /^(\d+)\s*(s|sec|secs|m|min|mins|h|hr|hrs|d|day|days)$/i;
|
|
4
|
+
const DATE_TIME_RE = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(?:(?:T|\s+)(\d{1,2}):(\d{2})(?::(\d{2})(?:[.,](\d{1,9}))?)?)?\s*(Z|UTC|GMT|[+-]\d{2}(?::?\d{2})?)?$/i;
|
|
5
|
+
const MONTH_NAME_RE = /\b(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\b/i;
|
|
6
|
+
const TIME_UNIT_MS = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000 };
|
|
7
|
+
export function parseTimeArg(value, now = Date.now()) {
|
|
8
|
+
if (typeof value !== 'string')
|
|
9
|
+
return undefined;
|
|
10
|
+
const raw = value.trim();
|
|
11
|
+
if (!raw)
|
|
12
|
+
return undefined;
|
|
13
|
+
if (/^\d+$/.test(raw)) {
|
|
14
|
+
const parsed = Number(raw);
|
|
15
|
+
if (!Number.isSafeInteger(parsed))
|
|
16
|
+
return undefined;
|
|
17
|
+
return raw.length === 10 ? parsed * 1000 : parsed;
|
|
18
|
+
}
|
|
19
|
+
if (raw.toLowerCase() === 'now')
|
|
20
|
+
return now;
|
|
21
|
+
const relative = RELATIVE_TIME_RE.exec(raw);
|
|
22
|
+
if (relative) {
|
|
23
|
+
const result = now - Number(relative[1]) * TIME_UNIT_MS[relative[2][0].toLowerCase()];
|
|
24
|
+
return Number.isSafeInteger(result) && result >= 0 ? result : undefined;
|
|
25
|
+
}
|
|
26
|
+
const match = DATE_TIME_RE.exec(raw);
|
|
27
|
+
if (match)
|
|
28
|
+
return parseTimeDate(match);
|
|
29
|
+
if (MONTH_NAME_RE.test(raw)) {
|
|
30
|
+
const parsed = Date.parse(raw);
|
|
31
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : undefined;
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
function parseTimeDate(match) {
|
|
36
|
+
const [, y, mo, d, h, mi, s, frac, zone] = match;
|
|
37
|
+
const year = Number(y), month = Number(mo), day = Number(d);
|
|
38
|
+
const hour = h === undefined ? 0 : Number(h);
|
|
39
|
+
const minute = mi === undefined ? 0 : Number(mi);
|
|
40
|
+
const second = s === undefined ? 0 : Number(s);
|
|
41
|
+
const ms = frac === undefined ? 0 : Number(frac.slice(0, 3).padEnd(3, '0'));
|
|
42
|
+
if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59)
|
|
43
|
+
return undefined;
|
|
44
|
+
let result;
|
|
45
|
+
if (zone === undefined) {
|
|
46
|
+
const local = new Date(year, month - 1, day, hour, minute, second, ms);
|
|
47
|
+
if (local.getFullYear() !== year || local.getMonth() !== month - 1 || local.getDate() !== day)
|
|
48
|
+
return undefined;
|
|
49
|
+
result = local.getTime();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const utc = Date.UTC(year, month - 1, day, hour, minute, second, ms);
|
|
53
|
+
const check = new Date(utc);
|
|
54
|
+
if (check.getUTCFullYear() !== year || check.getUTCMonth() !== month - 1 || check.getUTCDate() !== day)
|
|
55
|
+
return undefined;
|
|
56
|
+
const offset = parseTimeZoneOffset(zone);
|
|
57
|
+
if (offset === undefined)
|
|
58
|
+
return undefined;
|
|
59
|
+
result = utc - offset * 60_000;
|
|
60
|
+
}
|
|
61
|
+
return Number.isFinite(result) && result >= 0 ? result : undefined;
|
|
62
|
+
}
|
|
63
|
+
function parseTimeZoneOffset(zone) {
|
|
64
|
+
if (/^(z|utc|gmt)$/i.test(zone))
|
|
65
|
+
return 0;
|
|
66
|
+
const match = /^([+-])(\d{2}):?(\d{2})?$/.exec(zone);
|
|
67
|
+
if (!match)
|
|
68
|
+
return undefined;
|
|
69
|
+
const hours = Number(match[2]);
|
|
70
|
+
const minutes = match[3] === undefined ? 0 : Number(match[3]);
|
|
71
|
+
if (hours > 14 || minutes > 59)
|
|
72
|
+
return undefined;
|
|
73
|
+
const total = hours * 60 + minutes;
|
|
74
|
+
return match[1] === '-' ? -total : total;
|
|
75
|
+
}
|
|
2
76
|
export function normalizeCliArgv(argv) {
|
|
3
77
|
if (argv[0] === 'ec' && argv[1])
|
|
4
78
|
return argv.slice(1);
|
|
@@ -4,7 +4,7 @@ import os from 'os';
|
|
|
4
4
|
import { spawn, execFile } from 'child_process';
|
|
5
5
|
import { promisify } from 'util';
|
|
6
6
|
import readline from 'readline';
|
|
7
|
-
import { resolveRoot, resolvePaths, ensureDataDirs, getPackageRoot, agentMdPath, asModeOverridePath } from '../paths.js';
|
|
7
|
+
import { resolveRoot, resolvePaths, ensureDataDirs, getPackageRoot, agentMdPath, asModeOverridePath, daemonControlDir } from '../paths.js';
|
|
8
8
|
import { loadDefaults, loadAllAgents, loadDaemonConfig, saveDaemonConfig } from '../config-store.js';
|
|
9
9
|
import { resolveEffective } from '../config/config-manager.js';
|
|
10
10
|
import { resolveAnthropicConfig } from '../agents/baseagent.js';
|
|
@@ -14,9 +14,9 @@ import { isHelpFlag } from './help.js';
|
|
|
14
14
|
import { cmdInit, needsControlAidInit, initTail } from './init.js';
|
|
15
15
|
import * as platform from '../utils/cross-platform.js';
|
|
16
16
|
import { EventBus } from '../core/event-bus.js';
|
|
17
|
-
import {
|
|
17
|
+
import { resolveGlobalPkg } from '../utils/npm-ops.js';
|
|
18
18
|
import { ensureFreshPackageVersionInfo } from '../utils/package-version-info.js';
|
|
19
|
-
import { ecwebVersionRequirementError, resolveEcwebLaunchCommand, fetchRemotePairingCode } from '../utils/ecweb-utils.js';
|
|
19
|
+
import { ecwebVersionRequirementError, resolveEcwebLaunchCommand, resolveEcwebExternalUrl, fetchRemotePairingCode, } from '../utils/ecweb-utils.js';
|
|
20
20
|
import { isHostChinese } from '../utils/locale.js';
|
|
21
21
|
import { scanInstances, cleanupInstances, findOrphanProcesses } from '../utils/instance-registry.js';
|
|
22
22
|
import { filterLogFiles, deriveLogTypes, computePreChecked, validateLogTypes, shortLogName as shortLogNameLocal, isWatchLogFile } from './watch-logs.js';
|
|
@@ -25,7 +25,8 @@ import { isNonAgentSessionChannel } from '../core/system-channels.js';
|
|
|
25
25
|
import { printCodeStats } from './code-stats.js';
|
|
26
26
|
import { getProcessStartTime, startTimeMatches } from '../utils/process-introspect.js';
|
|
27
27
|
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
28
|
-
import { MAIN_CLI_BIN, RUNTIME_HOME_ENV, TARGET_PACKAGE_ROOT_ENV, WEB_CLI_BIN,
|
|
28
|
+
import { MAIN_CLI_BIN, RESTART_REQUEST_ID_ENV, RUNTIME_HOME_ENV, TARGET_PACKAGE_ROOT_ENV, WEB_CLI_BIN, WEB_PACKAGE_NAME, } from '../product.js';
|
|
29
|
+
import { readRestartRequest, updateRestartRequest } from '../utils/restart-safety.js';
|
|
29
30
|
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
30
31
|
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
31
32
|
import { isInitCancelledError, printInitCancelHint } from './init-cancel.js';
|
|
@@ -33,6 +34,8 @@ import { computeBuildId } from '../utils/evolcore-version.js';
|
|
|
33
34
|
import { listCodexAppServerProcesses, unregisterCodexAppServerProcess } from '../agents/codex/app-server-registry.js';
|
|
34
35
|
import { DEFAULT_ECWEB_PORT, ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
|
|
35
36
|
import { checkCodexProjectPath, inspectCodexManagedHook, ensureCodexManagedHook, runCodexHookLaunchDiagnostic, } from '../agents/codex/diagnostics.js';
|
|
37
|
+
import { isTopicThreadId } from '../core/thread/topic-id.js';
|
|
38
|
+
import { formatClaudeSandboxDependencies, formatCodexSandboxAvailability, inspectClaudeSandboxDependencies, inspectCodexSandboxAvailability, probeClaudeSandboxDependencies, probeCodexSandboxAvailability, } from '../core/permission/sandbox-runtime.js';
|
|
36
39
|
const execFileAsync = promisify(execFile);
|
|
37
40
|
export async function confirmCodexHookRebind(state, packageRoot) {
|
|
38
41
|
console.log('⚠️ Codex 受管 Hook 绑定的另一套 EvolCore/Node 路径仍存在,需确认是否切换:');
|
|
@@ -132,8 +135,8 @@ function printNoSelfAgentHints(options) {
|
|
|
132
135
|
const { daemonConfig, ecwebStarted, skipped } = options;
|
|
133
136
|
console.log('\nℹ 未配置任何 self-agent,Control Plane 已启动。');
|
|
134
137
|
console.log(' 命令行:ec agent new <aid>.example.com');
|
|
135
|
-
if (daemonConfig.aid
|
|
136
|
-
console.log('
|
|
138
|
+
if (daemonConfig.aid) {
|
|
139
|
+
console.log(' 使用 ec aid bind <ownerAid> 绑定协议 Owner 后,可通过进程级菜单创建 agent');
|
|
137
140
|
}
|
|
138
141
|
if (ecwebStarted) {
|
|
139
142
|
console.log(' ECWeb:可通过控制台创建 agent');
|
|
@@ -296,7 +299,9 @@ async function requireFreshSourceBuild() {
|
|
|
296
299
|
return await runSourceBuild();
|
|
297
300
|
}
|
|
298
301
|
async function launchPackageLifecycle(source, log, options = {}) {
|
|
299
|
-
|
|
302
|
+
const correlated = options.requestId ?? process.env[RESTART_REQUEST_ID_ENV];
|
|
303
|
+
const upgradeJobId = correlated ? readRestartRequest(path.join(daemonControlDir(), 'restart-pending.json'), correlated)?.upgradeJobId : undefined;
|
|
304
|
+
if (!options.prepared && !upgradeJobId)
|
|
300
305
|
await ensureFreshPackageVersionInfo(undefined, { source, log });
|
|
301
306
|
const root = resolvePaths().root;
|
|
302
307
|
const launch = platform.resolveMonitorLaunch(getPackageRoot(), path.join(root, 'data', 'monitor-stage'));
|
|
@@ -307,8 +312,15 @@ async function launchPackageLifecycle(source, log, options = {}) {
|
|
|
307
312
|
platform.cleanupMonitorStage(launch.stageDir);
|
|
308
313
|
return { ok: false, reason: 'RESTART_ENTRY_MISSING' };
|
|
309
314
|
}
|
|
315
|
+
const requestId = options.requestId ?? process.env[RESTART_REQUEST_ID_ENV];
|
|
310
316
|
const args = [...launch.args, 'restart-monitor', ...(options.clear ? ['--clear'] : [])];
|
|
311
|
-
const env = {
|
|
317
|
+
const env = {
|
|
318
|
+
...options.env,
|
|
319
|
+
[RUNTIME_HOME_ENV]: root,
|
|
320
|
+
...launch.env,
|
|
321
|
+
[AGENT_DELEGATION_TOKEN_ENV]: '',
|
|
322
|
+
...(requestId ? { [RESTART_REQUEST_ID_ENV]: requestId } : {}),
|
|
323
|
+
};
|
|
312
324
|
if (options.foreground) {
|
|
313
325
|
return new Promise(resolve => {
|
|
314
326
|
const child = spawn(process.execPath, [...args, '--foreground'], {
|
|
@@ -325,9 +337,23 @@ async function launchPackageLifecycle(source, log, options = {}) {
|
|
|
325
337
|
});
|
|
326
338
|
});
|
|
327
339
|
}
|
|
328
|
-
const result = await platform.launchMonitorAndConfirm(args, env, pid =>
|
|
329
|
-
|
|
340
|
+
const result = await platform.launchMonitorAndConfirm(args, env, pid => requestId
|
|
341
|
+
? readRestartRequest(path.join(root, 'data', 'daemon', 'control', 'restart-pending.json'), requestId)?.status === 'accepted'
|
|
342
|
+
|| readRestartRequest(path.join(root, 'data', 'daemon', 'control', 'restart-pending.json'), requestId)?.status === 'ready'
|
|
343
|
+
: scanInstances().restartMonitors.some(item => item.alive && item.record.pid === pid), pid => scanInstances().restartMonitors.some(item => item.alive
|
|
344
|
+
&& item.record.pid !== pid
|
|
345
|
+
&& (!requestId || (item.record.requestId === requestId && item.record.phase === 'accepted'))), {
|
|
346
|
+
requestId,
|
|
347
|
+
logFilePath: requestId ? path.join(root, 'logs', `restart-launch-${requestId}.log`) : undefined,
|
|
348
|
+
onSpawn: pid => { if (requestId)
|
|
349
|
+
updateRestartRequest(path.join(root, 'data', 'daemon', 'control', 'restart-pending.json'), requestId, { launcherPid: pid }); },
|
|
350
|
+
isPendingInRegistry: () => !!requestId && scanInstances().restartMonitors.some(item => item.alive && item.record.requestId === requestId),
|
|
351
|
+
});
|
|
352
|
+
if (!result.ok && !result.pending && launch.stageDir)
|
|
330
353
|
platform.cleanupMonitorStage(launch.stageDir);
|
|
354
|
+
if (result.pending) {
|
|
355
|
+
return { ok: false, reason: result.reason, pending: true, pid: result.pid };
|
|
356
|
+
}
|
|
331
357
|
if (!result.ok) {
|
|
332
358
|
for (const line of (result.stderrTail ?? '').split(/\r?\n/).filter(Boolean).slice(-8)) {
|
|
333
359
|
console.error(` | ${line}`);
|
|
@@ -351,8 +377,8 @@ function requireCompletedDataMigration(root) {
|
|
|
351
377
|
* A failed upgrade is reported, but the currently installed version remains
|
|
352
378
|
* usable and the caller continues with its normal lifecycle.
|
|
353
379
|
*/
|
|
354
|
-
export async function runUpgradeChecks(upgradeFn,
|
|
355
|
-
if (!upgradeFn
|
|
380
|
+
export async function runUpgradeChecks(upgradeFn, timeoutMs = 60_000) {
|
|
381
|
+
if (!upgradeFn) {
|
|
356
382
|
await ensureFreshPackageVersionInfo(undefined, { source: 'start', log: console.log });
|
|
357
383
|
return;
|
|
358
384
|
}
|
|
@@ -379,10 +405,7 @@ export async function runUpgradeChecks(upgradeFn, ecwebUpgradeFn, timeoutMs = 60
|
|
|
379
405
|
clearTimeout(timer);
|
|
380
406
|
}
|
|
381
407
|
};
|
|
382
|
-
const
|
|
383
|
-
runWithTimeout('EvolCore', upgradeFn),
|
|
384
|
-
runWithTimeout(WEB_PACKAGE_NAME, ecwebUpgradeFn),
|
|
385
|
-
]);
|
|
408
|
+
const upgrade = await runWithTimeout('EvolCore', upgradeFn);
|
|
386
409
|
switch (upgrade.status) {
|
|
387
410
|
case 'upgraded':
|
|
388
411
|
console.log(`✅ Upgraded: ${upgrade.from} → ${upgrade.to}`);
|
|
@@ -399,16 +422,6 @@ export async function runUpgradeChecks(upgradeFn, ecwebUpgradeFn, timeoutMs = 60
|
|
|
399
422
|
console.log(`⚠ Upgrade failed${upgrade.from && upgrade.to ? ` (${upgrade.from} → ${upgrade.to})` : ''}, continuing with current version${upgrade.error ? `: ${upgrade.error}` : ''}`);
|
|
400
423
|
break;
|
|
401
424
|
}
|
|
402
|
-
switch (ecwebUpgrade.status) {
|
|
403
|
-
case 'upgraded':
|
|
404
|
-
console.log(`✅ ${WEB_PACKAGE_NAME} upgraded: ${ecwebUpgrade.from} → ${ecwebUpgrade.to}`);
|
|
405
|
-
break;
|
|
406
|
-
case 'no-update':
|
|
407
|
-
break;
|
|
408
|
-
case 'failed':
|
|
409
|
-
console.log(`⚠ ${WEB_PACKAGE_NAME} upgrade failed${ecwebUpgrade.from && ecwebUpgrade.to ? ` (${ecwebUpgrade.from} → ${ecwebUpgrade.to})` : ''}${ecwebUpgrade.error ? `: ${ecwebUpgrade.error}` : ''}`);
|
|
410
|
-
break;
|
|
411
|
-
}
|
|
412
425
|
}
|
|
413
426
|
// ==================== Commands ====================
|
|
414
427
|
/**
|
|
@@ -608,8 +621,9 @@ export async function cmdStart(opts = {}) {
|
|
|
608
621
|
return;
|
|
609
622
|
// A stopped container may miss the daily upgrade trigger. Check once on
|
|
610
623
|
// every real start so the service does not stay on an old installation.
|
|
611
|
-
const
|
|
612
|
-
|
|
624
|
+
const autoUpgrade = loadDaemonConfig().upgrade?.autoOnStart !== false;
|
|
625
|
+
const versionInfo = autoUpgrade ? await ensureFreshPackageVersionInfo(undefined, { source: 'start', log: console.log }) : [];
|
|
626
|
+
if (autoUpgrade && opts.upgradeChecks)
|
|
613
627
|
await opts.upgradeChecks();
|
|
614
628
|
// 旧配置自动迁移(daemon.json → 新结构)
|
|
615
629
|
const { autoMigrateIfNeeded } = await import('../config-store.js');
|
|
@@ -644,7 +658,7 @@ export async function cmdStart(opts = {}) {
|
|
|
644
658
|
// process is launched.
|
|
645
659
|
if (!await ensureCodexHookBeforeLifecycle())
|
|
646
660
|
return;
|
|
647
|
-
// 控制 AID 门禁:缺 aid 且交互式 → 只补全控制 AID +
|
|
661
|
+
// 控制 AID 门禁:缺 aid 且交互式 → 只补全控制 AID + owner(不重走 baseagent 向导)。
|
|
648
662
|
// 非 TTY(restart-monitor/systemd/管道)不补全(无法交互),只提示后继续启动,daemon 侧 warn 兜底。
|
|
649
663
|
const daemonCfgStart = loadDaemonConfig();
|
|
650
664
|
if (needsControlAidInit(daemonCfgStart.aid, !!process.stdin.isTTY)) {
|
|
@@ -747,8 +761,11 @@ export async function cmdStart(opts = {}) {
|
|
|
747
761
|
prepared: true, foreground: opts.foreground, env: buildDaemonEnv(p, opts),
|
|
748
762
|
});
|
|
749
763
|
if (!launched.ok) {
|
|
750
|
-
|
|
751
|
-
|
|
764
|
+
if (!launched.pending)
|
|
765
|
+
clearAsModeOverride(overrideFile);
|
|
766
|
+
console.error(launched.pending
|
|
767
|
+
? `⚠ 启动状态暂不可确认(PID ${launched.pid ?? 'unknown'}):restart-monitor 仍在运行,可能继续执行。`
|
|
768
|
+
: `❌ 启动事务未能建立:${launched.reason}`);
|
|
752
769
|
process.exitCode = 1;
|
|
753
770
|
}
|
|
754
771
|
else if (!opts.foreground) {
|
|
@@ -1097,9 +1114,20 @@ export async function cmdRestart(opts = {}) {
|
|
|
1097
1114
|
// the monitor retains shutdown, orphan checks, build and rollback ownership.
|
|
1098
1115
|
// restart-monitor performs the read-only preflight before stopping the
|
|
1099
1116
|
// current daemon, then applies the migration during the stopped window.
|
|
1100
|
-
const
|
|
1117
|
+
const requestId = process.env[RESTART_REQUEST_ID_ENV];
|
|
1118
|
+
if (requestId) {
|
|
1119
|
+
const pendingFile = path.join(daemonControlDir(), 'restart-pending.json');
|
|
1120
|
+
if (!readRestartRequest(pendingFile, requestId)) {
|
|
1121
|
+
console.error('❌ 重启请求已被替换或过期,服务未停止;请重新发起重启。');
|
|
1122
|
+
process.exitCode = 1;
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
const launched = await launchPackageLifecycle('restart', console.log, { clear: opts.clear, requestId });
|
|
1101
1127
|
if (!launched.ok) {
|
|
1102
|
-
console.error(
|
|
1128
|
+
console.error(launched.pending
|
|
1129
|
+
? `⚠ 重启状态暂不可确认(PID ${launched.pid ?? 'unknown'}):restart-monitor 仍在运行,可能继续执行;请勿立即重复发起。`
|
|
1130
|
+
: `❌ 重启中止:restart-monitor 未能启动(${launched.reason});当前服务未主动停止`);
|
|
1103
1131
|
process.exitCode = 1;
|
|
1104
1132
|
return;
|
|
1105
1133
|
}
|
|
@@ -1385,7 +1413,7 @@ export async function cmdStatus() {
|
|
|
1385
1413
|
console.log('📋 Recent Active Sessions:');
|
|
1386
1414
|
for (const s of recentSessions) {
|
|
1387
1415
|
const projectName = path.basename(s.projectPath);
|
|
1388
|
-
const sessionType = s.threadId ? '话题会话' : '主会话';
|
|
1416
|
+
const sessionType = isTopicThreadId(s.threadId) ? '话题会话' : '主会话';
|
|
1389
1417
|
const chatType = s.chatType === 'group' ? '群聊' : '单聊';
|
|
1390
1418
|
const sessionName = displaySessionTitle(s.name);
|
|
1391
1419
|
const timeAgo = formatTimeAgo(Date.now() - s.updatedAt);
|
|
@@ -2876,6 +2904,7 @@ async function waitForExistingEcweb(p, timeoutMs = 3_000) {
|
|
|
2876
2904
|
* 某些 CLI 运行在隔离 PID namespace 中,看不到宿主 ECWeb PID 是正常情况。
|
|
2877
2905
|
*/
|
|
2878
2906
|
async function printEcwebStatus(p) {
|
|
2907
|
+
let externalUrl = null;
|
|
2879
2908
|
try {
|
|
2880
2909
|
const cfg = loadDaemonConfig();
|
|
2881
2910
|
if (ecwebService(cfg.services)?.enabled === false) {
|
|
@@ -2883,6 +2912,7 @@ async function printEcwebStatus(p) {
|
|
|
2883
2912
|
console.log('🔭 ECWeb: 已禁用 (daemon.json → services[name=ecweb].enabled: false)');
|
|
2884
2913
|
return;
|
|
2885
2914
|
}
|
|
2915
|
+
externalUrl = resolveEcwebExternalUrl(cfg);
|
|
2886
2916
|
}
|
|
2887
2917
|
catch {
|
|
2888
2918
|
// Agent tool sandboxes may mask daemon.json. Instance and HTTP probes below
|
|
@@ -2921,6 +2951,10 @@ async function printEcwebStatus(p) {
|
|
|
2921
2951
|
const pidVisible = aliveEntries.some(entry => entry.filePath === readyEntry.filePath);
|
|
2922
2952
|
const pidText = pidVisible ? `PID: ${readyEntry.record.pid}` : `PID: ${readyEntry.record.pid}(当前 namespace 不可见)`;
|
|
2923
2953
|
console.log(`🔭 ECWeb: 运行中 (${pidText}) http://localhost:${readyEntry.record.port}`);
|
|
2954
|
+
if (externalUrl) {
|
|
2955
|
+
console.log(` 外网访问: ${externalUrl}`);
|
|
2956
|
+
console.log(` 命令行输入 ${MAIN_CLI_BIN} watch web/${WEB_CLI_BIN} 获取配对码`);
|
|
2957
|
+
}
|
|
2924
2958
|
return;
|
|
2925
2959
|
}
|
|
2926
2960
|
const occupiedPids = new Set();
|
|
@@ -3016,7 +3050,7 @@ async function waitForPortRelease(port, timeoutMs) {
|
|
|
3016
3050
|
return platform.findProcessByPort(port).length === 0;
|
|
3017
3051
|
}
|
|
3018
3052
|
/**
|
|
3019
|
-
* Start the
|
|
3053
|
+
* Start the `ec-web` dependency bundled with EvolCore for a configured runtime.
|
|
3020
3054
|
* Kept public for restart-monitor, which launches the daemon directly and
|
|
3021
3055
|
* therefore cannot rely on cmdStart's post-ready ECWeb startup path.
|
|
3022
3056
|
*/
|
|
@@ -3025,6 +3059,7 @@ export async function startEcwebIfEnabled(p, options = {}) {
|
|
|
3025
3059
|
const service = ecwebService(cfg.services);
|
|
3026
3060
|
if (!service?.enabled)
|
|
3027
3061
|
return false;
|
|
3062
|
+
const externalUrl = resolveEcwebExternalUrl(cfg);
|
|
3028
3063
|
// The daemon is the lifecycle owner. CLI callers normally only need to
|
|
3029
3064
|
// ensure ECWeb is available, so adopt a healthy process instead of killing
|
|
3030
3065
|
// it. `ec watch web` passes forceRestart explicitly for an intentional
|
|
@@ -3033,12 +3068,14 @@ export async function startEcwebIfEnabled(p, options = {}) {
|
|
|
3033
3068
|
const existing = await waitForExistingEcweb(p);
|
|
3034
3069
|
if (existing) {
|
|
3035
3070
|
console.log(`✓ ECWeb 已在运行 (PID: ${existing.pid}) http://localhost:${existing.port}`);
|
|
3071
|
+
if (externalUrl)
|
|
3072
|
+
console.log(` 外网访问: ${externalUrl}`);
|
|
3036
3073
|
return true;
|
|
3037
3074
|
}
|
|
3038
3075
|
}
|
|
3039
3076
|
const installedPkg = resolveGlobalPkg(WEB_PACKAGE_NAME);
|
|
3040
3077
|
if (!installedPkg) {
|
|
3041
|
-
console.log(
|
|
3078
|
+
console.log('⚠ 当前 EvolCore 安装未包含 EC Web,跳过启动;请升级 EvolCore 后重试。');
|
|
3042
3079
|
return false;
|
|
3043
3080
|
}
|
|
3044
3081
|
const versionError = ecwebVersionRequirementError(installedPkg.version);
|
|
@@ -3064,7 +3101,7 @@ export async function startEcwebIfEnabled(p, options = {}) {
|
|
|
3064
3101
|
const args = ['--home', p.root, '--port', String(port)];
|
|
3065
3102
|
const launch = resolveEcwebLaunchCommand(args, { installedPkg });
|
|
3066
3103
|
if (!launch) {
|
|
3067
|
-
console.log(
|
|
3104
|
+
console.log('⚠ 当前 EvolCore 安装中的 EC Web 启动入口不存在,请重新安装 EvolCore。');
|
|
3068
3105
|
return false;
|
|
3069
3106
|
}
|
|
3070
3107
|
// 防御性检查:确保 command 和 args 有效
|
|
@@ -3113,6 +3150,8 @@ export async function startEcwebIfEnabled(p, options = {}) {
|
|
|
3113
3150
|
}
|
|
3114
3151
|
const actionLabel = wasRunning ? '已重启' : '启动成功';
|
|
3115
3152
|
console.log(`✓ ECWeb ${actionLabel} (PID: ${pid}) http://localhost:${port}`);
|
|
3153
|
+
if (externalUrl)
|
|
3154
|
+
console.log(` 外网访问: ${externalUrl}`);
|
|
3116
3155
|
if (pair) {
|
|
3117
3156
|
const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
|
|
3118
3157
|
console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,已配对过的浏览器无需重新配对)`);
|
|
@@ -3159,43 +3198,10 @@ async function printEcwebAccess(port) {
|
|
|
3159
3198
|
}
|
|
3160
3199
|
async function cmdWatchWeb() {
|
|
3161
3200
|
const p = resolvePaths();
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
process.
|
|
3165
|
-
|
|
3166
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
3167
|
-
const ans = await new Promise(res => rl.question(' 立即安装?[Y/n] ', res));
|
|
3168
|
-
rl.close();
|
|
3169
|
-
if (ans.trim().toLowerCase() === 'n') {
|
|
3170
|
-
process.exit(0);
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
else {
|
|
3174
|
-
process.stdout.write(' 当前命令会自动安装。\n');
|
|
3175
|
-
}
|
|
3176
|
-
process.stdout.write('\n');
|
|
3177
|
-
const { npmInstallGlobal } = await import('../utils/npm-ops.js');
|
|
3178
|
-
try {
|
|
3179
|
-
await npmInstallGlobal(WEB_PACKAGE_LATEST);
|
|
3180
|
-
process.stdout.write(`✅ ${WEB_PACKAGE_NAME} 安装完成\n`);
|
|
3181
|
-
}
|
|
3182
|
-
catch (e) {
|
|
3183
|
-
process.stderr.write(`❌ 安装失败: ${e?.stderr || e?.message || e}\n`);
|
|
3184
|
-
process.exit(1);
|
|
3185
|
-
}
|
|
3186
|
-
}
|
|
3187
|
-
else {
|
|
3188
|
-
// 已安装:检查并自动升级独立的 EC Web 全局包。
|
|
3189
|
-
const upgrade = await tryUpgradeGlobalPkg(() => resolveGlobalPkg(WEB_PACKAGE_NAME), WEB_PACKAGE_NAME);
|
|
3190
|
-
switch (upgrade.status) {
|
|
3191
|
-
case 'upgraded':
|
|
3192
|
-
process.stdout.write(`✅ ${WEB_PACKAGE_NAME} 已升级: ${upgrade.from} → ${upgrade.to}\n`);
|
|
3193
|
-
break;
|
|
3194
|
-
case 'failed':
|
|
3195
|
-
process.stdout.write(`⚠ ${WEB_PACKAGE_NAME} 升级失败 (${upgrade.from} → ${upgrade.to}),继续使用当前版本\n`);
|
|
3196
|
-
break;
|
|
3197
|
-
// no-update / skipped: 静默
|
|
3198
|
-
}
|
|
3201
|
+
if (!resolveGlobalPkg(WEB_PACKAGE_NAME)) {
|
|
3202
|
+
process.stderr.write(`⚠ ${WEB_PACKAGE_NAME} 未随当前 EvolCore 包安装;请升级 EvolCore 后重试。\n`);
|
|
3203
|
+
process.exitCode = 1;
|
|
3204
|
+
return;
|
|
3199
3205
|
}
|
|
3200
3206
|
// 2. 启动(后台)并同步配置。默认行为是替换旧实例,确保新配置/新版静态资源生效。
|
|
3201
3207
|
const cfg = loadDaemonConfig();
|
|
@@ -3262,6 +3268,19 @@ export async function cmdDiagnose(args = []) {
|
|
|
3262
3268
|
try {
|
|
3263
3269
|
// 2. 加载 self-agents
|
|
3264
3270
|
const { agents, skipped } = loadAllAgents();
|
|
3271
|
+
const checkClaudeSandbox = args.includes('--claude-sandbox')
|
|
3272
|
+
|| agents.some(agent => resolveEffective({ self: agent.aid }).active_baseagent === 'claude');
|
|
3273
|
+
if (checkClaudeSandbox) {
|
|
3274
|
+
const dependencies = inspectClaudeSandboxDependencies();
|
|
3275
|
+
const missing = dependencies.status === 'missing';
|
|
3276
|
+
(missing ? console.error : console.log)(`[diagnose] ${missing ? '❌' : '✓'} ${formatClaudeSandboxDependencies(dependencies)}`);
|
|
3277
|
+
hasError ||= missing;
|
|
3278
|
+
if (dependencies.status === 'ready') {
|
|
3279
|
+
const probe = probeClaudeSandboxDependencies(dependencies);
|
|
3280
|
+
(probe.ok ? console.log : console.error)(`[diagnose] ${probe.ok ? '✓' : '❌'} ${probe.detail}`);
|
|
3281
|
+
hasError ||= !probe.ok;
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3265
3284
|
if (agents.length === 0) {
|
|
3266
3285
|
console.error(`[diagnose] ❌ 未配置 self-agent。请运行 \`ec aid new <name>\``);
|
|
3267
3286
|
hasError = true;
|
|
@@ -3286,6 +3305,18 @@ export async function cmdDiagnose(args = []) {
|
|
|
3286
3305
|
return false;
|
|
3287
3306
|
}
|
|
3288
3307
|
});
|
|
3308
|
+
const checkCodexSandbox = args.includes('--codex-sandbox') || codexAgents.length > 0;
|
|
3309
|
+
if (checkCodexSandbox) {
|
|
3310
|
+
const availability = inspectCodexSandboxAvailability();
|
|
3311
|
+
const missing = availability.status === 'missing';
|
|
3312
|
+
(missing ? console.error : console.log)(`[diagnose] ${missing ? '❌' : '✓'} ${formatCodexSandboxAvailability(availability)}`);
|
|
3313
|
+
hasError ||= missing;
|
|
3314
|
+
if (availability.status === 'ready') {
|
|
3315
|
+
const probe = probeCodexSandboxAvailability(availability);
|
|
3316
|
+
(probe.ok ? console.log : console.error)(`[diagnose] ${probe.ok ? '✓' : '❌'} ${probe.detail}`);
|
|
3317
|
+
hasError ||= !probe.ok;
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3289
3320
|
for (const agent of codexAgents) {
|
|
3290
3321
|
try {
|
|
3291
3322
|
const effective = resolveEffective({ self: agent.aid });
|
package/dist/cli/diag.js
CHANGED
|
@@ -5,7 +5,7 @@ import { parseDiagArgs } from '../core/command/diag-service.js';
|
|
|
5
5
|
import { wantsHelp } from './help.js';
|
|
6
6
|
export async function cmdDiag(args) {
|
|
7
7
|
if (wantsHelp(args)) {
|
|
8
|
-
console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机
|
|
8
|
+
console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机 Control AID 的协议 Owner;有效诊断期间再次执行会追加到原 case。');
|
|
9
9
|
return;
|
|
10
10
|
}
|
|
11
11
|
const argv = ['diag', ...args];
|
package/dist/cli/fs-command.js
CHANGED
|
@@ -6,7 +6,7 @@ import { agentmdGet, getAidStore, isValidAid, loadClient, SLOT } from '../aun/ai
|
|
|
6
6
|
import { ipcQuery } from '../ipc.js';
|
|
7
7
|
import { resolvePaths } from '../paths.js';
|
|
8
8
|
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
9
|
-
import { downloadGroupFsBytes } from '../aun/group/
|
|
9
|
+
import { DEFAULT_FS_CAT_BYTES, MAX_FS_CAT_BYTES, FsReadBudgetError, downloadGroupFsBytes, readPersonalFsBytesWithinBudget, } from '../aun/group/fs-download.js';
|
|
10
10
|
class FsCliError extends Error {
|
|
11
11
|
code;
|
|
12
12
|
suggestion;
|
|
@@ -25,7 +25,7 @@ Commands:
|
|
|
25
25
|
ls <AID>:<path> 列目录
|
|
26
26
|
stat [-L] <AID>:<path> 查看节点元数据(默认不跟随软链;-L 跟随)
|
|
27
27
|
lstat <AID>:<path> 查看节点本身(不跟随末级软链)
|
|
28
|
-
cat <AID>:<path>
|
|
28
|
+
cat <AID>:<path> 预算内输出文本或二进制头部摘要;超出预算报错
|
|
29
29
|
cp <local> <AID>:<path> 上传本地文件
|
|
30
30
|
cp <AID>:<path> <local> 下载远程文件
|
|
31
31
|
cp <AID>:<path> <AID>:<path> 远程复制(同后端)
|
|
@@ -72,7 +72,7 @@ Options:
|
|
|
72
72
|
--size <expr> find 大小过滤,如 +1M
|
|
73
73
|
--mtime <expr> find 修改时间过滤
|
|
74
74
|
--head-bytes <n> cat 二进制头部字节数,默认 256
|
|
75
|
-
--max-bytes <n> cat
|
|
75
|
+
--max-bytes <n> cat 读取预算,默认及最高 131072;超限终止读取
|
|
76
76
|
--aun-path <path> 指定 AUN keystore 根
|
|
77
77
|
--app <name> 指定 AUN app slot
|
|
78
78
|
|
|
@@ -284,9 +284,9 @@ async function runManagedFs(args, formatJson) {
|
|
|
284
284
|
}
|
|
285
285
|
function parseCommonOptions(args) {
|
|
286
286
|
const maxCatBytesRaw = getArgValue(args, '--max-bytes');
|
|
287
|
-
const maxCatBytes = maxCatBytesRaw === undefined ?
|
|
288
|
-
if (!Number.
|
|
289
|
-
throw new FsCliError('INVALID_ARGUMENT', `--max-bytes
|
|
287
|
+
const maxCatBytes = maxCatBytesRaw === undefined ? DEFAULT_FS_CAT_BYTES : Number(maxCatBytesRaw);
|
|
288
|
+
if (!Number.isSafeInteger(maxCatBytes) || maxCatBytes <= 0 || maxCatBytes > MAX_FS_CAT_BYTES) {
|
|
289
|
+
throw new FsCliError('INVALID_ARGUMENT', `--max-bytes 必须是 1 到 ${MAX_FS_CAT_BYTES} 的整数`);
|
|
290
290
|
}
|
|
291
291
|
const headBytesRaw = getArgValue(args, '--head-bytes');
|
|
292
292
|
const headBytes = headBytesRaw === undefined ? 256 : Number(headBytesRaw);
|
|
@@ -404,31 +404,27 @@ async function fsCat(args, opts) {
|
|
|
404
404
|
const route = await resolveRoute(target.aid, store);
|
|
405
405
|
let statInfo;
|
|
406
406
|
let bytes;
|
|
407
|
-
let binaryHeadOnly = false;
|
|
408
407
|
if (route.backend === 'group') {
|
|
409
408
|
statInfo = await client.group.fs.stat(remoteRef(target));
|
|
410
409
|
const size = numberFrom(statInfo, ['size', 'size_bytes', 'bytes']);
|
|
411
|
-
|
|
410
|
+
if (size !== undefined && size > opts.maxCatBytes)
|
|
411
|
+
throw new FsReadBudgetError(opts.maxCatBytes);
|
|
412
|
+
const downloaded = await downloadGroupFsBytes(client, remoteRef(target), { maxBytes: opts.maxCatBytes });
|
|
412
413
|
bytes = downloaded.bytes;
|
|
413
414
|
statInfo = { ...statInfo, ...downloaded.ticket };
|
|
414
415
|
statInfo = { ...statInfo, size: bytes.byteLength };
|
|
415
|
-
if (size !== undefined && size > opts.maxCatBytes) {
|
|
416
|
-
binaryHeadOnly = true;
|
|
417
|
-
}
|
|
418
416
|
}
|
|
419
417
|
else {
|
|
420
418
|
statInfo = await client.storage.stat(target.path, { owner: target.aid, token: opts.token });
|
|
421
419
|
const size = numberFrom(statInfo, ['size', 'sizeBytes', 'size_bytes']);
|
|
422
|
-
if (size !== undefined && size > opts.maxCatBytes)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
bytes = await client.storage.readBytes(target.path, { owner: target.aid, token: opts.token });
|
|
428
|
-
}
|
|
420
|
+
if (size !== undefined && size > opts.maxCatBytes)
|
|
421
|
+
throw new FsReadBudgetError(opts.maxCatBytes);
|
|
422
|
+
bytes = await readPersonalFsBytesWithinBudget(client, target.path, opts.maxCatBytes, {
|
|
423
|
+
owner: target.aid, token: opts.token,
|
|
424
|
+
});
|
|
429
425
|
}
|
|
430
426
|
const binary = looksBinary(bytes, contentTypeFrom(statInfo));
|
|
431
|
-
if (binary
|
|
427
|
+
if (binary) {
|
|
432
428
|
const size = numberFrom(statInfo, ['size', 'sizeBytes', 'size_bytes']) ?? bytes.byteLength;
|
|
433
429
|
const payload = {
|
|
434
430
|
command: 'cat',
|
|
@@ -1532,6 +1528,9 @@ function outputError(error, formatJson) {
|
|
|
1532
1528
|
function mapBackendError(error) {
|
|
1533
1529
|
if (error instanceof FsCliError)
|
|
1534
1530
|
return error;
|
|
1531
|
+
if (error instanceof FsReadBudgetError) {
|
|
1532
|
+
return new FsCliError(error.code, error.message, '请使用 ec fs cp 下载大文件。');
|
|
1533
|
+
}
|
|
1535
1534
|
const code = String(error?.code ?? error?.name ?? 'BACKEND_ERROR');
|
|
1536
1535
|
const message = String(error?.message || error);
|
|
1537
1536
|
const upper = code.toUpperCase();
|