evolcore 0.0.7 → 0.0.9
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 +43 -0
- package/README.md +38 -4
- package/dist/agents/baseagent.js +117 -24
- package/dist/agents/claude-runner.js +31 -2
- package/dist/agents/codex-app-server-client.js +37 -2
- package/dist/agents/codex-runner.js +11 -3
- package/dist/aun/aid/control-aid.js +40 -27
- package/dist/aun/aid/domain.js +23 -0
- package/dist/aun/msg/group.js +9 -9
- package/dist/aun/msg/p2p.js +11 -6
- package/dist/aun/msg/upload.js +43 -29
- package/dist/aun/outbox.js +48 -5
- package/dist/channels/aun.js +225 -71
- package/dist/cli/aun-commands.js +10 -7
- package/dist/cli/bench.js +4 -3
- package/dist/cli/daemon-commands.js +208 -68
- package/dist/cli/data-command.js +62 -35
- package/dist/cli/index.js +11 -1
- package/dist/cli/init-channel.js +1 -1
- package/dist/cli/init.js +112 -17
- package/dist/cli/model.js +5 -5
- package/dist/cli/restart-monitor.js +102 -22
- package/dist/config/builtin-role-templates.js +4 -3
- package/dist/config/config-field-policy.js +6 -2
- package/dist/config/config-manager.js +79 -11
- package/dist/config/gateway-config.js +80 -35
- package/dist/config/role-schema.js +18 -3
- package/dist/config/role-service.js +3 -3
- package/dist/config/role-store.js +4 -3
- package/dist/config-store.js +19 -3
- package/dist/core/auth/operation-authorizer.js +3 -1
- package/dist/core/baseagent-loader.js +5 -3
- package/dist/core/bootstrap-service.js +0 -12
- package/dist/core/capability/providers/codex-capability-provider.js +2 -2
- package/dist/core/channel-loader.js +15 -2
- package/dist/core/command/command-handler.js +1 -1
- package/dist/core/command/evol-menu-version-gate.js +3 -2
- package/dist/core/command/menu-handler.js +50 -28
- package/dist/core/command/menu-protocol.js +7 -4
- package/dist/core/command/slash-handler.js +4 -4
- package/dist/core/data-migration.js +517 -24
- package/dist/core/inference/text-inference.js +18 -5
- package/dist/core/message/message-bridge.js +17 -6
- package/dist/core/message/response-engine.js +22 -3
- package/dist/core/model/config-scope.js +3 -3
- package/dist/core/permission/tool-policy.js +18 -0
- package/dist/core/protected-paths.js +12 -1
- package/dist/index.js +794 -725
- package/dist/ipc.js +3 -1
- package/dist/product.js +1 -0
- package/dist/utils/autostart.js +27 -0
- package/dist/utils/codex-cli.js +39 -0
- package/dist/utils/cross-platform.js +147 -18
- package/dist/utils/ecweb-utils.js +15 -2
- package/dist/utils/instance-registry.js +43 -6
- package/dist/utils/macos-autostart.js +179 -0
- package/dist/utils/process-introspect.js +7 -3
- package/dist/utils/windows-autostart.js +130 -0
- package/ecagent/dist/agent-loop.d.ts +1 -1
- package/ecagent/dist/agent-loop.js +1 -1
- package/ecagent/dist/agent.d.ts +1 -1
- package/ecagent/dist/agent.js +1 -1
- package/ecagent/dist/harness/agent-harness.d.ts +1 -1
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts +1 -1
- package/ecagent/dist/harness/compaction/compaction.d.ts +1 -1
- package/ecagent/dist/harness/compaction/utils.d.ts +1 -1
- package/ecagent/dist/harness/messages.d.ts +1 -1
- package/ecagent/dist/harness/session/session.d.ts +1 -1
- package/ecagent/dist/harness/types.d.ts +1 -1
- package/ecagent/dist/proxy.d.ts +1 -1
- package/ecagent/dist/proxy.js +1 -1
- package/ecagent/dist/types.d.ts +1 -1
- package/kits/migrations/migrate-role-config-v5.mjs +27 -2
- package/kits/rules/01-overview.md +3 -2
- package/kits/schemas/_meta.json +2 -1
- package/kits/schemas/agent-config.schema.10.json +19 -1
- package/kits/schemas/daemon.schema.4.json +136 -0
- package/kits/schemas/defaults.schema.4.json +15 -1
- package/kits/schemas/relation-config.schema.8.json +22 -1
- package/kits/schemas/role-config.schema.1.json +2 -2
- package/package.json +2 -4
- package/ecagent/dist/agent-loop.d.ts.map +0 -1
- package/ecagent/dist/agent-loop.js.map +0 -1
- package/ecagent/dist/agent.d.ts.map +0 -1
- package/ecagent/dist/agent.js.map +0 -1
- package/ecagent/dist/harness/agent-harness.d.ts.map +0 -1
- package/ecagent/dist/harness/agent-harness.js.map +0 -1
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/branch-summarization.js.map +0 -1
- package/ecagent/dist/harness/compaction/compaction.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/compaction.js.map +0 -1
- package/ecagent/dist/harness/compaction/utils.d.ts.map +0 -1
- package/ecagent/dist/harness/compaction/utils.js.map +0 -1
- package/ecagent/dist/harness/env/nodejs.d.ts.map +0 -1
- package/ecagent/dist/harness/env/nodejs.js.map +0 -1
- package/ecagent/dist/harness/messages.d.ts.map +0 -1
- package/ecagent/dist/harness/messages.js.map +0 -1
- package/ecagent/dist/harness/prompt-templates.d.ts.map +0 -1
- package/ecagent/dist/harness/prompt-templates.js.map +0 -1
- package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +0 -1
- package/ecagent/dist/harness/session/jsonl-repo.js.map +0 -1
- package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +0 -1
- package/ecagent/dist/harness/session/jsonl-storage.js.map +0 -1
- package/ecagent/dist/harness/session/memory-repo.d.ts.map +0 -1
- package/ecagent/dist/harness/session/memory-repo.js.map +0 -1
- package/ecagent/dist/harness/session/memory-storage.d.ts.map +0 -1
- package/ecagent/dist/harness/session/memory-storage.js.map +0 -1
- package/ecagent/dist/harness/session/repo-utils.d.ts.map +0 -1
- package/ecagent/dist/harness/session/repo-utils.js.map +0 -1
- package/ecagent/dist/harness/session/session.d.ts.map +0 -1
- package/ecagent/dist/harness/session/session.js.map +0 -1
- package/ecagent/dist/harness/session/uuid.d.ts.map +0 -1
- package/ecagent/dist/harness/session/uuid.js.map +0 -1
- package/ecagent/dist/harness/skills.d.ts.map +0 -1
- package/ecagent/dist/harness/skills.js.map +0 -1
- package/ecagent/dist/harness/system-prompt.d.ts.map +0 -1
- package/ecagent/dist/harness/system-prompt.js.map +0 -1
- package/ecagent/dist/harness/types.d.ts.map +0 -1
- package/ecagent/dist/harness/types.js.map +0 -1
- package/ecagent/dist/harness/utils/shell-output.d.ts.map +0 -1
- package/ecagent/dist/harness/utils/shell-output.js.map +0 -1
- package/ecagent/dist/harness/utils/truncate.d.ts.map +0 -1
- package/ecagent/dist/harness/utils/truncate.js.map +0 -1
- package/ecagent/dist/index.d.ts.map +0 -1
- package/ecagent/dist/index.js.map +0 -1
- package/ecagent/dist/node.d.ts.map +0 -1
- package/ecagent/dist/node.js.map +0 -1
- package/ecagent/dist/proxy.d.ts.map +0 -1
- package/ecagent/dist/proxy.js.map +0 -1
- package/ecagent/dist/runtime/api/lazy.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/lazy.js.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.js.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +0 -1
- package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +0 -1
- package/ecagent/dist/runtime/auth/context.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/context.js.map +0 -1
- package/ecagent/dist/runtime/auth/credential-store.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/credential-store.js.map +0 -1
- package/ecagent/dist/runtime/auth/helpers.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/helpers.js.map +0 -1
- package/ecagent/dist/runtime/auth/resolve.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/resolve.js.map +0 -1
- package/ecagent/dist/runtime/auth/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/auth/types.js.map +0 -1
- package/ecagent/dist/runtime/compat.d.ts.map +0 -1
- package/ecagent/dist/runtime/compat.js.map +0 -1
- package/ecagent/dist/runtime/index.d.ts.map +0 -1
- package/ecagent/dist/runtime/index.js.map +0 -1
- package/ecagent/dist/runtime/models.d.ts.map +0 -1
- package/ecagent/dist/runtime/models.js.map +0 -1
- package/ecagent/dist/runtime/oauth.d.ts.map +0 -1
- package/ecagent/dist/runtime/oauth.js.map +0 -1
- package/ecagent/dist/runtime/providers/faux.d.ts.map +0 -1
- package/ecagent/dist/runtime/providers/faux.js.map +0 -1
- package/ecagent/dist/runtime/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/types.js.map +0 -1
- package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/diagnostics.js.map +0 -1
- package/ecagent/dist/runtime/utils/event-stream.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/event-stream.js.map +0 -1
- package/ecagent/dist/runtime/utils/headers.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/headers.js.map +0 -1
- package/ecagent/dist/runtime/utils/json-parse.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/json-parse.js.map +0 -1
- package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/oauth/types.js.map +0 -1
- package/ecagent/dist/runtime/utils/overflow.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/overflow.js.map +0 -1
- package/ecagent/dist/runtime/utils/provider-env.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/provider-env.js.map +0 -1
- package/ecagent/dist/runtime/utils/retry.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/retry.js.map +0 -1
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/typebox-helpers.js.map +0 -1
- package/ecagent/dist/runtime/utils/validation.d.ts.map +0 -1
- package/ecagent/dist/runtime/utils/validation.js.map +0 -1
- package/ecagent/dist/types.d.ts.map +0 -1
- package/ecagent/dist/types.js.map +0 -1
- package/ecagent/package.json +0 -93
- package/ecagent/src/agent-loop.ts +0 -792
- package/ecagent/src/agent.ts +0 -575
- package/ecagent/src/harness/agent-harness.ts +0 -1029
- package/ecagent/src/harness/compaction/branch-summarization.ts +0 -261
- package/ecagent/src/harness/compaction/compaction.ts +0 -753
- package/ecagent/src/harness/compaction/utils.ts +0 -144
- package/ecagent/src/harness/env/nodejs.ts +0 -569
- package/ecagent/src/harness/messages.ts +0 -164
- package/ecagent/src/harness/prompt-templates.ts +0 -267
- package/ecagent/src/harness/session/jsonl-repo.ts +0 -179
- package/ecagent/src/harness/session/jsonl-storage.ts +0 -314
- package/ecagent/src/harness/session/memory-repo.ts +0 -50
- package/ecagent/src/harness/session/memory-storage.ts +0 -133
- package/ecagent/src/harness/session/repo-utils.ts +0 -51
- package/ecagent/src/harness/session/session.ts +0 -338
- package/ecagent/src/harness/session/uuid.ts +0 -54
- package/ecagent/src/harness/skills.ts +0 -375
- package/ecagent/src/harness/system-prompt.ts +0 -34
- package/ecagent/src/harness/types.ts +0 -838
- package/ecagent/src/harness/utils/shell-output.ts +0 -135
- package/ecagent/src/harness/utils/truncate.ts +0 -344
- package/ecagent/src/index.ts +0 -46
- package/ecagent/src/node.ts +0 -2
- package/ecagent/src/proxy.ts +0 -367
- package/ecagent/src/runtime/api/lazy.ts +0 -70
- package/ecagent/src/runtime/api/pi-messages.lazy.ts +0 -4
- package/ecagent/src/runtime/api/pi-messages.ts +0 -436
- package/ecagent/src/runtime/auth/context.ts +0 -45
- package/ecagent/src/runtime/auth/credential-store.ts +0 -47
- package/ecagent/src/runtime/auth/helpers.ts +0 -46
- package/ecagent/src/runtime/auth/resolve.ts +0 -141
- package/ecagent/src/runtime/auth/types.ts +0 -182
- package/ecagent/src/runtime/compat.ts +0 -158
- package/ecagent/src/runtime/index.ts +0 -31
- package/ecagent/src/runtime/models.ts +0 -452
- package/ecagent/src/runtime/oauth.ts +0 -1
- package/ecagent/src/runtime/providers/faux.ts +0 -538
- package/ecagent/src/runtime/types.ts +0 -718
- package/ecagent/src/runtime/utils/diagnostics.ts +0 -45
- package/ecagent/src/runtime/utils/event-stream.ts +0 -88
- package/ecagent/src/runtime/utils/headers.ts +0 -18
- package/ecagent/src/runtime/utils/json-parse.ts +0 -124
- package/ecagent/src/runtime/utils/oauth/types.ts +0 -79
- package/ecagent/src/runtime/utils/overflow.ts +0 -165
- package/ecagent/src/runtime/utils/provider-env.ts +0 -52
- package/ecagent/src/runtime/utils/retry.ts +0 -101
- package/ecagent/src/runtime/utils/typebox-helpers.ts +0 -24
- package/ecagent/src/runtime/utils/validation.ts +0 -310
- package/ecagent/src/types.ts +0 -430
- package/ecagent/tsconfig.build.json +0 -32
|
@@ -15,9 +15,8 @@ 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
17
|
import { tryUpgrade, tryUpgradeAunSdk, tryUpgradeGlobalPkg, resolveGlobalPkg } from '../utils/npm-ops.js';
|
|
18
|
-
import { fetchEcwebPairCode } from '../utils/ecweb-utils.js';
|
|
18
|
+
import { ecwebVersionRequirementError, fetchEcwebPairCode, resolveEcwebLaunchCommand } from '../utils/ecweb-utils.js';
|
|
19
19
|
import { isHostChinese } from '../utils/locale.js';
|
|
20
|
-
import { resolveEcwebLaunchCommand } from '../utils/ecweb-utils.js';
|
|
21
20
|
import { resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG } from '../aun/aid/client.js';
|
|
22
21
|
import { scanInstances, cleanupInstances, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
|
|
23
22
|
import { filterLogFiles, deriveLogTypes, computePreChecked, validateLogTypes, shortLogName as shortLogNameLocal } from './watch-logs.js';
|
|
@@ -33,7 +32,7 @@ const execFileAsync = promisify(execFile);
|
|
|
33
32
|
function printNoSelfAgentHints(options) {
|
|
34
33
|
const { daemonConfig, ecwebStarted, skipped } = options;
|
|
35
34
|
console.log('\nℹ 未配置任何 self-agent,Control Plane 已启动。');
|
|
36
|
-
console.log(' 命令行:ec agent new <aid>.
|
|
35
|
+
console.log(' 命令行:ec agent new <aid>.example.com');
|
|
37
36
|
if (daemonConfig.aid && (daemonConfig.owners?.length ?? 0) > 0) {
|
|
38
37
|
console.log(' Evol App:可通过进程级菜单创建 agent');
|
|
39
38
|
}
|
|
@@ -301,9 +300,10 @@ export async function cmdStart(opts = {}) {
|
|
|
301
300
|
if (ans.trim() === '2') {
|
|
302
301
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
303
302
|
suppressSdkLogs();
|
|
304
|
-
const { generateControlAid } = await import('../aun/aid/control-aid.js');
|
|
305
|
-
const
|
|
306
|
-
|
|
303
|
+
const { generateControlAid, resolveControlAidDomain } = await import('../aun/aid/control-aid.js');
|
|
304
|
+
const cfg = loadDaemonConfig();
|
|
305
|
+
const result = await generateControlAid(resolveControlAidDomain(cfg.aun?.defaultAidDomain));
|
|
306
|
+
saveDaemonConfig({ ...cfg, aid: result.aid });
|
|
307
307
|
console.log(`✓ 新控制 AID: ${result.aid}`);
|
|
308
308
|
}
|
|
309
309
|
}
|
|
@@ -349,8 +349,19 @@ export async function cmdStart(opts = {}) {
|
|
|
349
349
|
await sleep(2000);
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
|
-
//
|
|
353
|
-
|
|
352
|
+
// A missing/stale instance record must not turn into a duplicate daemon.
|
|
353
|
+
// On Windows/macOS the process environment may be unavailable, so an
|
|
354
|
+
// unregistered process from this package is conservatively treated as a
|
|
355
|
+
// blocker when its HOME cannot be identified.
|
|
356
|
+
const orphans = findOrphanProcesses();
|
|
357
|
+
const blockingOrphans = orphans.filter(o => isRuntimeOrphan(o));
|
|
358
|
+
if (blockingOrphans.length > 0) {
|
|
359
|
+
console.error(`❌ 检测到未登记的 EvolCore 进程(PID: ${blockingOrphans.map(o => o.pid).join(', ')}),已停止启动以避免重复连接 AUN。`);
|
|
360
|
+
console.error(' 请先停止这些进程,再重新执行 ec start。');
|
|
361
|
+
process.exitCode = 1;
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
reportOrphans(orphans);
|
|
354
365
|
console.log('🚀 Starting EvolCore...');
|
|
355
366
|
const stdoutRotation = rotateStdoutLog(p.logs);
|
|
356
367
|
if (stdoutRotation.rotatedPath) {
|
|
@@ -549,36 +560,54 @@ export async function cmdStart(opts = {}) {
|
|
|
549
560
|
async function stopPid(pid) {
|
|
550
561
|
console.log(`🛑 Stopping EvolCore (PID: ${pid})...`);
|
|
551
562
|
platform.killProcess(pid);
|
|
552
|
-
await
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
563
|
+
if (await platform.waitForProcessExit(pid, 10_000)) {
|
|
564
|
+
console.log('✓ EvolCore stopped');
|
|
565
|
+
return true;
|
|
566
|
+
}
|
|
567
|
+
console.log(`⚠ EvolCore PID ${pid} did not exit gracefully; forcing termination...`);
|
|
568
|
+
platform.killProcess(pid, true);
|
|
569
|
+
if (await platform.waitForProcessExit(pid, 5_000)) {
|
|
570
|
+
console.log('✓ EvolCore stopped (forced)');
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
console.error(`❌ EvolCore PID ${pid} is still running; restart aborted`);
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
function isRuntimeOrphan(orphan, currentHome = resolveRoot()) {
|
|
577
|
+
if (orphan.confirmedTestDaemon)
|
|
578
|
+
return false;
|
|
579
|
+
const homeMatches = orphan.evolcoreHome
|
|
580
|
+
&& normalizeRuntimePath(orphan.evolcoreHome) === normalizeRuntimePath(currentHome);
|
|
581
|
+
// Windows/macOS may not expose another process's environment. In that case
|
|
582
|
+
// the exact installed package path is the conservative ownership proof.
|
|
583
|
+
const packageMatches = !orphan.evolcoreHome
|
|
584
|
+
&& normalizeRuntimePath(orphan.cmdline).includes(normalizeRuntimePath(getPackageRoot()));
|
|
585
|
+
return Boolean(homeMatches || packageMatches);
|
|
570
586
|
}
|
|
571
587
|
export async function cmdStop() {
|
|
572
588
|
const status = scanInstances();
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
589
|
+
const p = resolvePaths();
|
|
590
|
+
const initialOrphans = findOrphanProcesses();
|
|
591
|
+
const runtimeOrphans = initialOrphans.filter(orphan => isRuntimeOrphan(orphan, p.root));
|
|
592
|
+
const ping = await probeDaemon(p.socket);
|
|
593
|
+
if (ping && !hasVisibleDaemonPid(status, ping) && runtimeOrphans.length === 0) {
|
|
594
|
+
if (rejectPidIsolatedLifecycle('stop', status, ping))
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
576
597
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
577
|
-
if (aliveMains.length === 0) {
|
|
598
|
+
if (aliveMains.length === 0 && runtimeOrphans.length === 0) {
|
|
578
599
|
console.log('⚠ EvolCore is not running');
|
|
579
600
|
return;
|
|
580
601
|
}
|
|
581
|
-
|
|
602
|
+
const pids = new Set([...aliveMains.map(entry => entry.record.pid), ...runtimeOrphans.map(orphan => orphan.pid)]);
|
|
603
|
+
if (runtimeOrphans.length > 0) {
|
|
604
|
+
console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(orphan => orphan.pid).join(', ')}`);
|
|
605
|
+
}
|
|
606
|
+
const stopped = await Promise.all([...pids].map(pid => stopPid(pid)));
|
|
607
|
+
if (stopped.some(result => !result)) {
|
|
608
|
+
process.exitCode = 1;
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
582
611
|
await sleep(500);
|
|
583
612
|
cleanupInstances();
|
|
584
613
|
if (aliveMains.length > 1) {
|
|
@@ -589,14 +618,16 @@ export async function cmdRestart(opts = {}) {
|
|
|
589
618
|
const cmdStartedAt = Date.now();
|
|
590
619
|
console.log('🔄 Restarting EvolCore...');
|
|
591
620
|
const initialStatus = scanInstances();
|
|
621
|
+
const initialOrphans = findOrphanProcesses();
|
|
622
|
+
const initialRuntimeOrphans = initialOrphans.filter(orphan => isRuntimeOrphan(orphan));
|
|
592
623
|
const socketPath = resolvePaths().socket;
|
|
593
624
|
const ping = await probeDaemon(socketPath);
|
|
594
625
|
if (ping && !hasVisibleDaemonPid(initialStatus, ping)) {
|
|
595
626
|
if (await tryDelegatedDaemonRestart(socketPath))
|
|
596
627
|
return;
|
|
628
|
+
if (initialRuntimeOrphans.length === 0 && rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
629
|
+
return;
|
|
597
630
|
}
|
|
598
|
-
if (rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
599
|
-
return;
|
|
600
631
|
if (!requireFreshSourceBuild())
|
|
601
632
|
return;
|
|
602
633
|
// 版本检查与自动升级
|
|
@@ -651,29 +682,49 @@ export async function cmdRestart(opts = {}) {
|
|
|
651
682
|
if (aliveMains.length > 1) {
|
|
652
683
|
console.log(`⚠ 检测到 ${aliveMains.length} 个 main 实例,将一并停止: ${aliveMains.map(m => m.record.pid).join(', ')}`);
|
|
653
684
|
}
|
|
654
|
-
await Promise.all(aliveMains.map(m => stopPid(m.record.pid)));
|
|
685
|
+
const stopped = await Promise.all(aliveMains.map(m => stopPid(m.record.pid)));
|
|
686
|
+
if (stopped.some(result => !result)) {
|
|
687
|
+
console.error('❌ Restart aborted because an existing EvolCore process could not be stopped');
|
|
688
|
+
process.exitCode = 1;
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
655
691
|
await sleep(500);
|
|
656
692
|
}
|
|
657
693
|
cleanupInstances();
|
|
658
|
-
|
|
694
|
+
const remainingMainProcesses = scanInstances().mains.filter(entry => entry.alive);
|
|
695
|
+
if (remainingMainProcesses.length > 0) {
|
|
696
|
+
console.error(`❌ Restart aborted: EvolCore process still registered and alive (PID: ${remainingMainProcesses.map(entry => entry.record.pid).join(', ')})`);
|
|
697
|
+
process.exitCode = 1;
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
// 孤儿处理:同 HOME/同安装包的孤儿属于本运行时,先确认退出再替换;
|
|
659
701
|
// 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。
|
|
660
702
|
{
|
|
661
703
|
const orphans = findOrphanProcesses();
|
|
662
704
|
const confirmedTestDaemons = orphans.filter(o => o.confirmedTestDaemon);
|
|
663
|
-
const nonTestOrphans = orphans.filter(o => !o.confirmedTestDaemon);
|
|
664
705
|
if (confirmedTestDaemons.length > 0) {
|
|
665
706
|
const killed = killOrphans(confirmedTestDaemons);
|
|
666
707
|
console.log(`☠ 已清理 ${killed.length} 个泄漏的测试 daemon: ${killed.join(', ')}`);
|
|
667
708
|
await sleep(500);
|
|
668
709
|
}
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
710
|
+
const runtimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
|
|
711
|
+
if (runtimeOrphans.length > 0) {
|
|
712
|
+
console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(o => o.pid).join(', ')}`);
|
|
713
|
+
const stopped = await Promise.all(runtimeOrphans.map(o => stopPid(o.pid)));
|
|
714
|
+
if (stopped.some(result => !result)) {
|
|
715
|
+
console.error('❌ Restart aborted because an unregistered EvolCore process could not be stopped');
|
|
716
|
+
process.exitCode = 1;
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
675
719
|
await sleep(500);
|
|
676
720
|
}
|
|
721
|
+
const remainingRuntimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
|
|
722
|
+
if (remainingRuntimeOrphans.length > 0) {
|
|
723
|
+
console.error(`❌ Restart aborted: EvolCore process still running (PID: ${remainingRuntimeOrphans.map(o => o.pid).join(', ')})`);
|
|
724
|
+
process.exitCode = 1;
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const otherHome = findOrphanProcesses().filter(o => !o.confirmedTestDaemon && !isRuntimeOrphan(o));
|
|
677
728
|
if (opts.clear && otherHome.length > 0) {
|
|
678
729
|
const killed = killOrphans(otherHome);
|
|
679
730
|
console.log(`☠ 已 SIGKILL ${killed.length} 个跨 HOME 孤儿进程: ${killed.join(', ')}`);
|
|
@@ -707,6 +758,9 @@ export async function cmdRestart(opts = {}) {
|
|
|
707
758
|
printCodeStats(getPackageRoot(), resolvePaths().logs);
|
|
708
759
|
}
|
|
709
760
|
}
|
|
761
|
+
function normalizeRuntimePath(value) {
|
|
762
|
+
return value.replace(/[\\/]+/g, '/').toLowerCase();
|
|
763
|
+
}
|
|
710
764
|
function formatTimeAgo(ms) {
|
|
711
765
|
const sec = Math.floor(ms / 1000);
|
|
712
766
|
if (sec < 60)
|
|
@@ -2382,8 +2436,22 @@ async function printEcwebStatus(p) {
|
|
|
2382
2436
|
// still provide an authoritative runtime status without local config access.
|
|
2383
2437
|
}
|
|
2384
2438
|
const entries = readEcwebInstanceEntries(p);
|
|
2385
|
-
|
|
2439
|
+
const aliveEntries = [];
|
|
2386
2440
|
for (const entry of entries) {
|
|
2441
|
+
if (platform.isProcessRunning(entry.record.pid)) {
|
|
2442
|
+
aliveEntries.push(entry);
|
|
2443
|
+
}
|
|
2444
|
+
else {
|
|
2445
|
+
// A stale EC Web record must never be used to report the PID of an
|
|
2446
|
+
// unrelated process that later inherited the port.
|
|
2447
|
+
try {
|
|
2448
|
+
fs.unlinkSync(entry.filePath);
|
|
2449
|
+
}
|
|
2450
|
+
catch { }
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
let readyEntry;
|
|
2454
|
+
for (const entry of aliveEntries) {
|
|
2387
2455
|
if (await probeEcwebReady(entry.record.port)) {
|
|
2388
2456
|
readyEntry = entry;
|
|
2389
2457
|
break;
|
|
@@ -2394,11 +2462,19 @@ async function printEcwebStatus(p) {
|
|
|
2394
2462
|
console.log(`🔭 ECWeb: 运行中 (PID: ${readyEntry.record.pid}) http://localhost:${readyEntry.record.port}`);
|
|
2395
2463
|
return;
|
|
2396
2464
|
}
|
|
2397
|
-
const
|
|
2465
|
+
const occupiedPids = new Set();
|
|
2466
|
+
for (const entry of entries) {
|
|
2467
|
+
for (const pid of platform.findProcessByPort(entry.record.port))
|
|
2468
|
+
occupiedPids.add(pid);
|
|
2469
|
+
}
|
|
2398
2470
|
console.log('');
|
|
2399
|
-
if (
|
|
2471
|
+
if (aliveEntries.length > 0) {
|
|
2472
|
+
const visibleEntry = aliveEntries[0];
|
|
2400
2473
|
console.log(`🔭 ECWeb: 进程存活 (PID: ${visibleEntry.record.pid}) 但 HTTP 未就绪 (端口 ${visibleEntry.record.port}),查看 logs/watch-web.log`);
|
|
2401
2474
|
}
|
|
2475
|
+
else if (occupiedPids.size > 0) {
|
|
2476
|
+
console.log(`🔭 ECWeb: 端口仍被未登记进程占用 (PID: ${[...occupiedPids].join(', ')}),请先执行 ec restart`);
|
|
2477
|
+
}
|
|
2402
2478
|
else if (entries.length > 0) {
|
|
2403
2479
|
console.log('🔭 ECWeb: instance 记录存在,但宿主 PID 不可见且 HTTP 未就绪');
|
|
2404
2480
|
}
|
|
@@ -2432,31 +2508,34 @@ function stopCodexAppServerOrphans() {
|
|
|
2432
2508
|
}
|
|
2433
2509
|
return killed;
|
|
2434
2510
|
}
|
|
2435
|
-
/** 若 ecweb
|
|
2436
|
-
function stopEcwebIfRunning(p) {
|
|
2511
|
+
/** 若 ecweb 在运行则杀掉并确认 pid/端口都已释放。 */
|
|
2512
|
+
async function stopEcwebIfRunning(p) {
|
|
2437
2513
|
const alive = findAliveEcweb(p);
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2514
|
+
const port = loadDaemonConfig().ecweb?.port ?? 42705;
|
|
2515
|
+
const pids = new Set([
|
|
2516
|
+
...(alive ? [alive.pid] : []),
|
|
2517
|
+
...platform.findProcessByPort(port),
|
|
2518
|
+
]);
|
|
2519
|
+
for (const pid of pids)
|
|
2520
|
+
platform.killProcess(pid, true);
|
|
2521
|
+
const exited = await Promise.all([...pids].map(pid => platform.waitForProcessExit(pid, 5_000)));
|
|
2522
|
+
const portReleased = await waitForPortRelease(port, 5_000);
|
|
2523
|
+
if (exited.some(result => !result) || !portReleased) {
|
|
2524
|
+
throw new Error(`EC Web old process or port ${port} could not be released`);
|
|
2445
2525
|
}
|
|
2446
2526
|
// 清理 pid 文件(仅 ecweb-<pid>.json / watch-web-<pid>.json,
|
|
2447
2527
|
// 不碰 ecweb-tokens.json 等非 pid 文件,否则会清空配对 token 库导致每次重启都要重新配对)
|
|
2448
2528
|
removeEcwebInstanceFiles(p);
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
catch { }
|
|
2529
|
+
return pids.size > 0;
|
|
2530
|
+
}
|
|
2531
|
+
async function waitForPortRelease(port, timeoutMs) {
|
|
2532
|
+
const deadline = Date.now() + timeoutMs;
|
|
2533
|
+
while (Date.now() < deadline) {
|
|
2534
|
+
if (platform.findProcessByPort(port).length === 0)
|
|
2535
|
+
return true;
|
|
2536
|
+
await sleep(250);
|
|
2458
2537
|
}
|
|
2459
|
-
return
|
|
2538
|
+
return platform.findProcessByPort(port).length === 0;
|
|
2460
2539
|
}
|
|
2461
2540
|
/**
|
|
2462
2541
|
* 后台 detached 启动 ecweb;若已运行则先停再启(确保加载最新代码)。
|
|
@@ -2539,12 +2618,35 @@ export async function startEcwebIfEnabled(p) {
|
|
|
2539
2618
|
const cfg = loadDaemonConfig();
|
|
2540
2619
|
if (!cfg.ecweb?.enabled)
|
|
2541
2620
|
return false;
|
|
2542
|
-
const
|
|
2621
|
+
const installedPkg = resolveGlobalPkg(WEB_PACKAGE_NAME);
|
|
2622
|
+
if (!installedPkg) {
|
|
2623
|
+
console.log(`⚠ EC Web 未安装,跳过启动(运行 npm i -g ${WEB_PACKAGE_NAME}@latest 后可用)`);
|
|
2624
|
+
return false;
|
|
2625
|
+
}
|
|
2626
|
+
const versionError = ecwebVersionRequirementError(installedPkg.version);
|
|
2627
|
+
if (versionError) {
|
|
2628
|
+
try {
|
|
2629
|
+
await stopEcwebIfRunning(p);
|
|
2630
|
+
}
|
|
2631
|
+
catch (error) {
|
|
2632
|
+
console.log(`⚠ EC Web 旧进程未清理干净: ${error instanceof Error ? error.message : String(error)}`);
|
|
2633
|
+
}
|
|
2634
|
+
console.log(`❌ ${versionError}`);
|
|
2635
|
+
return false;
|
|
2636
|
+
}
|
|
2637
|
+
let wasRunning = false;
|
|
2638
|
+
try {
|
|
2639
|
+
wasRunning = await stopEcwebIfRunning(p); // 先停旧进程(有则停),保证加载最新代码
|
|
2640
|
+
}
|
|
2641
|
+
catch (error) {
|
|
2642
|
+
console.log(`❌ EC Web 旧进程未清理干净,取消启动: ${error instanceof Error ? error.message : String(error)}`);
|
|
2643
|
+
return false;
|
|
2644
|
+
}
|
|
2543
2645
|
const port = cfg.ecweb.port ?? 42705;
|
|
2544
2646
|
const args = ['--home', p.root, '--port', String(port)];
|
|
2545
|
-
const launch = resolveEcwebLaunchCommand(args);
|
|
2647
|
+
const launch = resolveEcwebLaunchCommand(args, { installedPkg });
|
|
2546
2648
|
if (!launch) {
|
|
2547
|
-
console.log(`⚠ EC Web
|
|
2649
|
+
console.log(`⚠ EC Web 启动入口不存在,请重新安装: npm i -g ${WEB_PACKAGE_NAME}@latest`);
|
|
2548
2650
|
return false;
|
|
2549
2651
|
}
|
|
2550
2652
|
// 防御性检查:确保 command 和 args 有效
|
|
@@ -2553,6 +2655,7 @@ export async function startEcwebIfEnabled(p) {
|
|
|
2553
2655
|
console.log(` command: ${launch.command}, args: ${JSON.stringify(launch.args)}`);
|
|
2554
2656
|
return false;
|
|
2555
2657
|
}
|
|
2658
|
+
let startedPid;
|
|
2556
2659
|
try {
|
|
2557
2660
|
const child = spawn(launch.command, launch.args, {
|
|
2558
2661
|
detached: true,
|
|
@@ -2565,6 +2668,7 @@ export async function startEcwebIfEnabled(p) {
|
|
|
2565
2668
|
});
|
|
2566
2669
|
child.unref();
|
|
2567
2670
|
const pid = child.pid;
|
|
2671
|
+
startedPid = pid;
|
|
2568
2672
|
if (!pid) {
|
|
2569
2673
|
console.log('❌ ECWeb 启动失败(进程创建失败)');
|
|
2570
2674
|
return false;
|
|
@@ -2592,9 +2696,17 @@ export async function startEcwebIfEnabled(p) {
|
|
|
2592
2696
|
return true;
|
|
2593
2697
|
}
|
|
2594
2698
|
console.log(`❌ ECWeb 启动失败:端口 ${port} 未就绪(进程 PID ${pid} 可能已退出,查看 logs/watch-web.log)`);
|
|
2699
|
+
platform.killProcess(pid, true);
|
|
2700
|
+
await platform.waitForProcessExit(pid, 5_000);
|
|
2701
|
+
removeEcwebInstanceFiles(p);
|
|
2595
2702
|
return false;
|
|
2596
2703
|
}
|
|
2597
2704
|
catch (err) {
|
|
2705
|
+
if (startedPid) {
|
|
2706
|
+
platform.killProcess(startedPid, true);
|
|
2707
|
+
await platform.waitForProcessExit(startedPid, 5_000);
|
|
2708
|
+
}
|
|
2709
|
+
removeEcwebInstanceFiles(p);
|
|
2598
2710
|
console.log(`⚠ ECWeb 启动失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
2599
2711
|
console.log(` command: ${launch.command}`);
|
|
2600
2712
|
console.log(` args: ${JSON.stringify(launch.args)}`);
|
|
@@ -2771,8 +2883,15 @@ export async function cmdDiagnose() {
|
|
|
2771
2883
|
try {
|
|
2772
2884
|
const instStatus = scanInstances();
|
|
2773
2885
|
const aliveMains = instStatus.mains.filter(m => m.alive);
|
|
2886
|
+
const orphanMains = findOrphanProcesses();
|
|
2774
2887
|
if (aliveMains.length > 0) {
|
|
2775
2888
|
console.log(`[diagnose] ⚠️ 已有进程运行中: PID ${aliveMains.map(m => m.record.pid).join(', ')}`);
|
|
2889
|
+
hasError = true;
|
|
2890
|
+
}
|
|
2891
|
+
else if (orphanMains.length > 0) {
|
|
2892
|
+
console.error(`[diagnose] ❌ 发现未登记的 EvolCore 进程: PID ${orphanMains.map(o => o.pid).join(', ')}`);
|
|
2893
|
+
console.error('[diagnose] 请先执行 ec stop 或手动结束这些 PID,再运行 ec start。');
|
|
2894
|
+
hasError = true;
|
|
2776
2895
|
}
|
|
2777
2896
|
else {
|
|
2778
2897
|
console.log(`[diagnose] ✓ 无残留进程`);
|
|
@@ -2781,7 +2900,28 @@ export async function cmdDiagnose() {
|
|
|
2781
2900
|
catch {
|
|
2782
2901
|
console.log(`[diagnose] ✓ 无 instance 文件`);
|
|
2783
2902
|
}
|
|
2784
|
-
// 6.
|
|
2903
|
+
// 6. 检查 EC Web 端口与实例记录是否一致。
|
|
2904
|
+
try {
|
|
2905
|
+
const cfg = loadDaemonConfig();
|
|
2906
|
+
if (cfg.ecweb?.enabled) {
|
|
2907
|
+
const port = cfg.ecweb.port ?? 42705;
|
|
2908
|
+
const portPids = platform.findProcessByPort(port);
|
|
2909
|
+
const recordedPids = new Set(readEcwebInstanceEntries(p).map(entry => entry.record.pid));
|
|
2910
|
+
const unregisteredPids = portPids.filter(pid => !recordedPids.has(pid));
|
|
2911
|
+
if (unregisteredPids.length > 0) {
|
|
2912
|
+
console.error(`[diagnose] ❌ EC Web 端口 ${port} 被未登记进程占用: PID ${unregisteredPids.join(', ')}`);
|
|
2913
|
+
console.error('[diagnose] 请执行 ec restart 清理 EC Web 后再启动。');
|
|
2914
|
+
hasError = true;
|
|
2915
|
+
}
|
|
2916
|
+
else {
|
|
2917
|
+
console.log(`[diagnose] ✓ EC Web 端口 ${port} 未发现未登记占用`);
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
catch (e) {
|
|
2922
|
+
console.error(`[diagnose] ⚠️ EC Web 端口检查失败: ${e instanceof Error ? e.message : String(e)}`);
|
|
2923
|
+
}
|
|
2924
|
+
// 7. 检查关键文件
|
|
2785
2925
|
const appMain = path.join(getPackageRoot(), 'dist', 'index.js');
|
|
2786
2926
|
if (!fs.existsSync(appMain)) {
|
|
2787
2927
|
console.error(`[diagnose] ❌ 编译产物不存在: ${appMain}`);
|
package/dist/cli/data-command.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolvePaths, resolveRoot } from '../paths.js';
|
|
4
|
-
import { applyDataMigration, planDataMigration, readDataMigration, verifyDataMigration } from '../core/data-migration.js';
|
|
4
|
+
import { applyDataMigration, finalizeDataMigration, planDataMigration, readDataMigration, verifyDataMigration } from '../core/data-migration.js';
|
|
5
5
|
import { scanInstances } from '../utils/instance-registry.js';
|
|
6
6
|
import { isProcessRunning, killProcess } from '../utils/cross-platform.js';
|
|
7
7
|
import { ipcQuery } from '../ipc.js';
|
|
@@ -11,9 +11,11 @@ function printSummary(manifest) {
|
|
|
11
11
|
result[operation.status] = (result[operation.status] ?? 0) + 1;
|
|
12
12
|
return result;
|
|
13
13
|
}, {});
|
|
14
|
+
const pending = manifest.operations.filter(operation => !['committed', 'skipped', 'acknowledged'].includes(operation.status)).length;
|
|
14
15
|
console.log(`migration: ${manifest.id}`);
|
|
15
16
|
console.log(`state: ${manifest.state}`);
|
|
16
17
|
console.log(`operations: ${manifest.operations.length}`);
|
|
18
|
+
console.log(`pending: ${pending}`);
|
|
17
19
|
console.log(`status: ${Object.entries(counts).map(([key, value]) => `${key}=${value}`).join(', ') || 'none'}`);
|
|
18
20
|
if (manifest.warnings.length) {
|
|
19
21
|
console.log('warnings:');
|
|
@@ -77,19 +79,72 @@ async function waitForMaintenanceWindow() {
|
|
|
77
79
|
}
|
|
78
80
|
export async function cmdData(args) {
|
|
79
81
|
if (args[0] !== 'migrate' || args.includes('--help')) {
|
|
80
|
-
console.log('用法: ec data migrate --dry-run | --apply
|
|
82
|
+
console.log('用法: ec data migrate --dry-run | --apply [migration-id] | --verify [migration-id]');
|
|
81
83
|
return;
|
|
82
84
|
}
|
|
83
85
|
const root = resolveRoot();
|
|
84
86
|
if (args.includes('--dry-run')) {
|
|
87
|
+
if (args.length !== 2)
|
|
88
|
+
throw new Error('--dry-run cannot be combined with another migration action');
|
|
85
89
|
printSummary(planDataMigration(root));
|
|
86
90
|
return;
|
|
87
91
|
}
|
|
88
|
-
const resumeIndex = args.indexOf('--resume');
|
|
89
92
|
const verify = args.includes('--verify');
|
|
90
|
-
const requestedId =
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
+
const requestedId = args.find(value => value.startsWith('data-'));
|
|
94
|
+
if (args.includes('--apply')) {
|
|
95
|
+
if (verify) {
|
|
96
|
+
throw new Error('--apply cannot be combined with another migration action');
|
|
97
|
+
}
|
|
98
|
+
// Planning is read-only, so avoid an unnecessary service interruption
|
|
99
|
+
// when there is no legacy source to process.
|
|
100
|
+
const existing = requestedId ? readDataMigration(root, requestedId) : undefined;
|
|
101
|
+
let manifest = existing ?? planDataMigration(root);
|
|
102
|
+
if (manifest.operations.length === 0 && Object.keys(manifest.supersededSourceHashes ?? {}).length === 0) {
|
|
103
|
+
printSummary(manifest);
|
|
104
|
+
console.log('No legacy data requires migration.');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const initialRuntime = liveRuntime();
|
|
108
|
+
const wasRunning = initialRuntime.mainCount > 0
|
|
109
|
+
|| initialRuntime.monitorPids.length > 0
|
|
110
|
+
|| await daemonIpcReachable();
|
|
111
|
+
if (wasRunning) {
|
|
112
|
+
console.log('Stopping daemon and all Agent runtimes for data migration...');
|
|
113
|
+
await stopRestartMonitors(initialRuntime.monitorPids);
|
|
114
|
+
await cmdStop();
|
|
115
|
+
await waitForMaintenanceWindow();
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
if (existing?.state !== 'completed') {
|
|
119
|
+
manifest = applyDataMigration(manifest);
|
|
120
|
+
manifest = verifyDataMigration(manifest, { strictTargetContent: true });
|
|
121
|
+
printSummary(manifest);
|
|
122
|
+
if (manifest.state !== 'completed') {
|
|
123
|
+
throw new Error(`migration is not fully verified; fix the listed operations and run ec data migrate --apply ${manifest.id}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
// A completed manifest may come from the previous copy-only workflow,
|
|
128
|
+
// or from an earlier successful --apply. The finalization routine is
|
|
129
|
+
// idempotent and verifies the archive receipt before returning it.
|
|
130
|
+
printSummary(manifest);
|
|
131
|
+
}
|
|
132
|
+
const finalization = finalizeDataMigration(root, manifest);
|
|
133
|
+
console.log(`archive: ${finalization.archivePath}`);
|
|
134
|
+
console.log(`archive-sha256: ${finalization.archiveSha256}`);
|
|
135
|
+
console.log(`removed legacy sources: ${finalization.sourcePaths.length}`);
|
|
136
|
+
if (wasRunning) {
|
|
137
|
+
console.log('Starting daemon and Agent runtimes after data migration...');
|
|
138
|
+
await cmdStart();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (wasRunning)
|
|
143
|
+
console.error('Data migration failed; daemon remains stopped.');
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
93
148
|
if (verify) {
|
|
94
149
|
// A completed migration's destination becomes live runtime data. Operator
|
|
95
150
|
// verification therefore validates source integrity and target structure
|
|
@@ -100,33 +155,5 @@ export async function cmdData(args) {
|
|
|
100
155
|
process.exitCode = 1;
|
|
101
156
|
return;
|
|
102
157
|
}
|
|
103
|
-
|
|
104
|
-
throw new Error('select --dry-run, --apply, --resume, or --verify');
|
|
105
|
-
const initialRuntime = liveRuntime();
|
|
106
|
-
const wasRunning = initialRuntime.mainCount > 0
|
|
107
|
-
|| initialRuntime.monitorPids.length > 0
|
|
108
|
-
|| await daemonIpcReachable();
|
|
109
|
-
if (wasRunning) {
|
|
110
|
-
console.log('Stopping daemon and all Agent runtimes for data migration...');
|
|
111
|
-
// A restart monitor would otherwise relaunch the daemon in the middle of
|
|
112
|
-
// a copy transaction, so it must leave the maintenance window first.
|
|
113
|
-
await stopRestartMonitors(initialRuntime.monitorPids);
|
|
114
|
-
await cmdStop();
|
|
115
|
-
await waitForMaintenanceWindow();
|
|
116
|
-
}
|
|
117
|
-
let manifest = resumeIndex >= 0
|
|
118
|
-
? applyDataMigration(readDataMigration(root, requestedId))
|
|
119
|
-
: applyDataMigration(planDataMigration(root));
|
|
120
|
-
manifest = verifyDataMigration(manifest);
|
|
121
|
-
printSummary(manifest);
|
|
122
|
-
// A partial migration must be inspected before any runtime can write the new
|
|
123
|
-
// layout. All independent operations have still been attempted and recorded.
|
|
124
|
-
if (wasRunning && manifest.state === 'completed') {
|
|
125
|
-
console.log('Starting daemon and Agent runtimes after verified migration...');
|
|
126
|
-
await cmdStart();
|
|
127
|
-
}
|
|
128
|
-
else if (wasRunning) {
|
|
129
|
-
console.error('Migration has errors; daemon remains stopped. Fix or resume the listed operations before restarting.');
|
|
130
|
-
process.exitCode = 1;
|
|
131
|
-
}
|
|
158
|
+
throw new Error('select --dry-run, --apply, or --verify');
|
|
132
159
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -113,6 +113,8 @@ export async function main(args) {
|
|
|
113
113
|
--baseagent <claude|codex|gemini|ecagent> 可选。默认从 PATH 检测,ecagent 需显式选择
|
|
114
114
|
--projectpath <abs-path> 可选。默认项目目录(必须绝对路径,自动创建)
|
|
115
115
|
--ecweb 可选。安装 EC Web 并启用自启动
|
|
116
|
+
--auto-start Windows/macOS 上启用 EvolCore 登录自启动
|
|
117
|
+
--no-auto-start Windows/macOS 上禁用 EvolCore 登录自启动
|
|
116
118
|
--format json 可选但推荐。stdout 输出 init.result JSON
|
|
117
119
|
--force 已有不同 owner 时强制覆盖
|
|
118
120
|
|
|
@@ -162,14 +164,22 @@ export async function main(args) {
|
|
|
162
164
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
163
165
|
suppressSdkLogs();
|
|
164
166
|
const nonInteractive = args.includes('--non-interactive');
|
|
167
|
+
const wantsAutoStart = args.includes('--auto-start');
|
|
168
|
+
const wantsNoAutoStart = args.includes('--no-auto-start');
|
|
169
|
+
if (wantsAutoStart && wantsNoAutoStart) {
|
|
170
|
+
console.error('❌ --auto-start 与 --no-auto-start 不能同时使用');
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
165
174
|
const initialized = await cmdInit({
|
|
166
175
|
nonInteractive,
|
|
167
176
|
baseagent: getArgValue(args, '--baseagent'),
|
|
168
177
|
force: args.includes('--force'),
|
|
169
178
|
owner: getArgValue(args, '--owner'),
|
|
170
179
|
projectpath: getArgValue(args, '--projectpath'),
|
|
171
|
-
ecweb: args.includes('--ecweb'),
|
|
180
|
+
ecweb: args.includes('--ecweb') ? true : undefined,
|
|
172
181
|
format: getArgValue(args, '--format'),
|
|
182
|
+
autoStart: wantsAutoStart ? true : wantsNoAutoStart ? false : undefined,
|
|
173
183
|
});
|
|
174
184
|
if (!initialized)
|
|
175
185
|
process.exitCode = 1;
|
package/dist/cli/init-channel.js
CHANGED
|
@@ -1250,7 +1250,7 @@ async function pickAgentForChannel(rl) {
|
|
|
1250
1250
|
const { agents } = loadAllAgents();
|
|
1251
1251
|
if (agents.length === 0) {
|
|
1252
1252
|
console.log('❌ 暂无 agent,请先创建:');
|
|
1253
|
-
console.log(' ec agent new <aid>.
|
|
1253
|
+
console.log(' ec agent new <aid>.example.com');
|
|
1254
1254
|
return null;
|
|
1255
1255
|
}
|
|
1256
1256
|
const letters = 'abcdefghijklmnopqrstuvwxyz';
|