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.
Files changed (230) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +38 -4
  3. package/dist/agents/baseagent.js +117 -24
  4. package/dist/agents/claude-runner.js +31 -2
  5. package/dist/agents/codex-app-server-client.js +37 -2
  6. package/dist/agents/codex-runner.js +11 -3
  7. package/dist/aun/aid/control-aid.js +40 -27
  8. package/dist/aun/aid/domain.js +23 -0
  9. package/dist/aun/msg/group.js +9 -9
  10. package/dist/aun/msg/p2p.js +11 -6
  11. package/dist/aun/msg/upload.js +43 -29
  12. package/dist/aun/outbox.js +48 -5
  13. package/dist/channels/aun.js +225 -71
  14. package/dist/cli/aun-commands.js +10 -7
  15. package/dist/cli/bench.js +4 -3
  16. package/dist/cli/daemon-commands.js +208 -68
  17. package/dist/cli/data-command.js +62 -35
  18. package/dist/cli/index.js +11 -1
  19. package/dist/cli/init-channel.js +1 -1
  20. package/dist/cli/init.js +112 -17
  21. package/dist/cli/model.js +5 -5
  22. package/dist/cli/restart-monitor.js +102 -22
  23. package/dist/config/builtin-role-templates.js +4 -3
  24. package/dist/config/config-field-policy.js +6 -2
  25. package/dist/config/config-manager.js +79 -11
  26. package/dist/config/gateway-config.js +80 -35
  27. package/dist/config/role-schema.js +18 -3
  28. package/dist/config/role-service.js +3 -3
  29. package/dist/config/role-store.js +4 -3
  30. package/dist/config-store.js +19 -3
  31. package/dist/core/auth/operation-authorizer.js +3 -1
  32. package/dist/core/baseagent-loader.js +5 -3
  33. package/dist/core/bootstrap-service.js +0 -12
  34. package/dist/core/capability/providers/codex-capability-provider.js +2 -2
  35. package/dist/core/channel-loader.js +15 -2
  36. package/dist/core/command/command-handler.js +1 -1
  37. package/dist/core/command/evol-menu-version-gate.js +3 -2
  38. package/dist/core/command/menu-handler.js +50 -28
  39. package/dist/core/command/menu-protocol.js +7 -4
  40. package/dist/core/command/slash-handler.js +4 -4
  41. package/dist/core/data-migration.js +517 -24
  42. package/dist/core/inference/text-inference.js +18 -5
  43. package/dist/core/message/message-bridge.js +17 -6
  44. package/dist/core/message/response-engine.js +22 -3
  45. package/dist/core/model/config-scope.js +3 -3
  46. package/dist/core/permission/tool-policy.js +18 -0
  47. package/dist/core/protected-paths.js +12 -1
  48. package/dist/index.js +794 -725
  49. package/dist/ipc.js +3 -1
  50. package/dist/product.js +1 -0
  51. package/dist/utils/autostart.js +27 -0
  52. package/dist/utils/codex-cli.js +39 -0
  53. package/dist/utils/cross-platform.js +147 -18
  54. package/dist/utils/ecweb-utils.js +15 -2
  55. package/dist/utils/instance-registry.js +43 -6
  56. package/dist/utils/macos-autostart.js +179 -0
  57. package/dist/utils/process-introspect.js +7 -3
  58. package/dist/utils/windows-autostart.js +130 -0
  59. package/ecagent/dist/agent-loop.d.ts +1 -1
  60. package/ecagent/dist/agent-loop.js +1 -1
  61. package/ecagent/dist/agent.d.ts +1 -1
  62. package/ecagent/dist/agent.js +1 -1
  63. package/ecagent/dist/harness/agent-harness.d.ts +1 -1
  64. package/ecagent/dist/harness/compaction/branch-summarization.d.ts +1 -1
  65. package/ecagent/dist/harness/compaction/compaction.d.ts +1 -1
  66. package/ecagent/dist/harness/compaction/utils.d.ts +1 -1
  67. package/ecagent/dist/harness/messages.d.ts +1 -1
  68. package/ecagent/dist/harness/session/session.d.ts +1 -1
  69. package/ecagent/dist/harness/types.d.ts +1 -1
  70. package/ecagent/dist/proxy.d.ts +1 -1
  71. package/ecagent/dist/proxy.js +1 -1
  72. package/ecagent/dist/types.d.ts +1 -1
  73. package/kits/migrations/migrate-role-config-v5.mjs +27 -2
  74. package/kits/rules/01-overview.md +3 -2
  75. package/kits/schemas/_meta.json +2 -1
  76. package/kits/schemas/agent-config.schema.10.json +19 -1
  77. package/kits/schemas/daemon.schema.4.json +136 -0
  78. package/kits/schemas/defaults.schema.4.json +15 -1
  79. package/kits/schemas/relation-config.schema.8.json +22 -1
  80. package/kits/schemas/role-config.schema.1.json +2 -2
  81. package/package.json +2 -4
  82. package/ecagent/dist/agent-loop.d.ts.map +0 -1
  83. package/ecagent/dist/agent-loop.js.map +0 -1
  84. package/ecagent/dist/agent.d.ts.map +0 -1
  85. package/ecagent/dist/agent.js.map +0 -1
  86. package/ecagent/dist/harness/agent-harness.d.ts.map +0 -1
  87. package/ecagent/dist/harness/agent-harness.js.map +0 -1
  88. package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +0 -1
  89. package/ecagent/dist/harness/compaction/branch-summarization.js.map +0 -1
  90. package/ecagent/dist/harness/compaction/compaction.d.ts.map +0 -1
  91. package/ecagent/dist/harness/compaction/compaction.js.map +0 -1
  92. package/ecagent/dist/harness/compaction/utils.d.ts.map +0 -1
  93. package/ecagent/dist/harness/compaction/utils.js.map +0 -1
  94. package/ecagent/dist/harness/env/nodejs.d.ts.map +0 -1
  95. package/ecagent/dist/harness/env/nodejs.js.map +0 -1
  96. package/ecagent/dist/harness/messages.d.ts.map +0 -1
  97. package/ecagent/dist/harness/messages.js.map +0 -1
  98. package/ecagent/dist/harness/prompt-templates.d.ts.map +0 -1
  99. package/ecagent/dist/harness/prompt-templates.js.map +0 -1
  100. package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +0 -1
  101. package/ecagent/dist/harness/session/jsonl-repo.js.map +0 -1
  102. package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +0 -1
  103. package/ecagent/dist/harness/session/jsonl-storage.js.map +0 -1
  104. package/ecagent/dist/harness/session/memory-repo.d.ts.map +0 -1
  105. package/ecagent/dist/harness/session/memory-repo.js.map +0 -1
  106. package/ecagent/dist/harness/session/memory-storage.d.ts.map +0 -1
  107. package/ecagent/dist/harness/session/memory-storage.js.map +0 -1
  108. package/ecagent/dist/harness/session/repo-utils.d.ts.map +0 -1
  109. package/ecagent/dist/harness/session/repo-utils.js.map +0 -1
  110. package/ecagent/dist/harness/session/session.d.ts.map +0 -1
  111. package/ecagent/dist/harness/session/session.js.map +0 -1
  112. package/ecagent/dist/harness/session/uuid.d.ts.map +0 -1
  113. package/ecagent/dist/harness/session/uuid.js.map +0 -1
  114. package/ecagent/dist/harness/skills.d.ts.map +0 -1
  115. package/ecagent/dist/harness/skills.js.map +0 -1
  116. package/ecagent/dist/harness/system-prompt.d.ts.map +0 -1
  117. package/ecagent/dist/harness/system-prompt.js.map +0 -1
  118. package/ecagent/dist/harness/types.d.ts.map +0 -1
  119. package/ecagent/dist/harness/types.js.map +0 -1
  120. package/ecagent/dist/harness/utils/shell-output.d.ts.map +0 -1
  121. package/ecagent/dist/harness/utils/shell-output.js.map +0 -1
  122. package/ecagent/dist/harness/utils/truncate.d.ts.map +0 -1
  123. package/ecagent/dist/harness/utils/truncate.js.map +0 -1
  124. package/ecagent/dist/index.d.ts.map +0 -1
  125. package/ecagent/dist/index.js.map +0 -1
  126. package/ecagent/dist/node.d.ts.map +0 -1
  127. package/ecagent/dist/node.js.map +0 -1
  128. package/ecagent/dist/proxy.d.ts.map +0 -1
  129. package/ecagent/dist/proxy.js.map +0 -1
  130. package/ecagent/dist/runtime/api/lazy.d.ts.map +0 -1
  131. package/ecagent/dist/runtime/api/lazy.js.map +0 -1
  132. package/ecagent/dist/runtime/api/pi-messages.d.ts.map +0 -1
  133. package/ecagent/dist/runtime/api/pi-messages.js.map +0 -1
  134. package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +0 -1
  135. package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +0 -1
  136. package/ecagent/dist/runtime/auth/context.d.ts.map +0 -1
  137. package/ecagent/dist/runtime/auth/context.js.map +0 -1
  138. package/ecagent/dist/runtime/auth/credential-store.d.ts.map +0 -1
  139. package/ecagent/dist/runtime/auth/credential-store.js.map +0 -1
  140. package/ecagent/dist/runtime/auth/helpers.d.ts.map +0 -1
  141. package/ecagent/dist/runtime/auth/helpers.js.map +0 -1
  142. package/ecagent/dist/runtime/auth/resolve.d.ts.map +0 -1
  143. package/ecagent/dist/runtime/auth/resolve.js.map +0 -1
  144. package/ecagent/dist/runtime/auth/types.d.ts.map +0 -1
  145. package/ecagent/dist/runtime/auth/types.js.map +0 -1
  146. package/ecagent/dist/runtime/compat.d.ts.map +0 -1
  147. package/ecagent/dist/runtime/compat.js.map +0 -1
  148. package/ecagent/dist/runtime/index.d.ts.map +0 -1
  149. package/ecagent/dist/runtime/index.js.map +0 -1
  150. package/ecagent/dist/runtime/models.d.ts.map +0 -1
  151. package/ecagent/dist/runtime/models.js.map +0 -1
  152. package/ecagent/dist/runtime/oauth.d.ts.map +0 -1
  153. package/ecagent/dist/runtime/oauth.js.map +0 -1
  154. package/ecagent/dist/runtime/providers/faux.d.ts.map +0 -1
  155. package/ecagent/dist/runtime/providers/faux.js.map +0 -1
  156. package/ecagent/dist/runtime/types.d.ts.map +0 -1
  157. package/ecagent/dist/runtime/types.js.map +0 -1
  158. package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +0 -1
  159. package/ecagent/dist/runtime/utils/diagnostics.js.map +0 -1
  160. package/ecagent/dist/runtime/utils/event-stream.d.ts.map +0 -1
  161. package/ecagent/dist/runtime/utils/event-stream.js.map +0 -1
  162. package/ecagent/dist/runtime/utils/headers.d.ts.map +0 -1
  163. package/ecagent/dist/runtime/utils/headers.js.map +0 -1
  164. package/ecagent/dist/runtime/utils/json-parse.d.ts.map +0 -1
  165. package/ecagent/dist/runtime/utils/json-parse.js.map +0 -1
  166. package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +0 -1
  167. package/ecagent/dist/runtime/utils/oauth/types.js.map +0 -1
  168. package/ecagent/dist/runtime/utils/overflow.d.ts.map +0 -1
  169. package/ecagent/dist/runtime/utils/overflow.js.map +0 -1
  170. package/ecagent/dist/runtime/utils/provider-env.d.ts.map +0 -1
  171. package/ecagent/dist/runtime/utils/provider-env.js.map +0 -1
  172. package/ecagent/dist/runtime/utils/retry.d.ts.map +0 -1
  173. package/ecagent/dist/runtime/utils/retry.js.map +0 -1
  174. package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +0 -1
  175. package/ecagent/dist/runtime/utils/typebox-helpers.js.map +0 -1
  176. package/ecagent/dist/runtime/utils/validation.d.ts.map +0 -1
  177. package/ecagent/dist/runtime/utils/validation.js.map +0 -1
  178. package/ecagent/dist/types.d.ts.map +0 -1
  179. package/ecagent/dist/types.js.map +0 -1
  180. package/ecagent/package.json +0 -93
  181. package/ecagent/src/agent-loop.ts +0 -792
  182. package/ecagent/src/agent.ts +0 -575
  183. package/ecagent/src/harness/agent-harness.ts +0 -1029
  184. package/ecagent/src/harness/compaction/branch-summarization.ts +0 -261
  185. package/ecagent/src/harness/compaction/compaction.ts +0 -753
  186. package/ecagent/src/harness/compaction/utils.ts +0 -144
  187. package/ecagent/src/harness/env/nodejs.ts +0 -569
  188. package/ecagent/src/harness/messages.ts +0 -164
  189. package/ecagent/src/harness/prompt-templates.ts +0 -267
  190. package/ecagent/src/harness/session/jsonl-repo.ts +0 -179
  191. package/ecagent/src/harness/session/jsonl-storage.ts +0 -314
  192. package/ecagent/src/harness/session/memory-repo.ts +0 -50
  193. package/ecagent/src/harness/session/memory-storage.ts +0 -133
  194. package/ecagent/src/harness/session/repo-utils.ts +0 -51
  195. package/ecagent/src/harness/session/session.ts +0 -338
  196. package/ecagent/src/harness/session/uuid.ts +0 -54
  197. package/ecagent/src/harness/skills.ts +0 -375
  198. package/ecagent/src/harness/system-prompt.ts +0 -34
  199. package/ecagent/src/harness/types.ts +0 -838
  200. package/ecagent/src/harness/utils/shell-output.ts +0 -135
  201. package/ecagent/src/harness/utils/truncate.ts +0 -344
  202. package/ecagent/src/index.ts +0 -46
  203. package/ecagent/src/node.ts +0 -2
  204. package/ecagent/src/proxy.ts +0 -367
  205. package/ecagent/src/runtime/api/lazy.ts +0 -70
  206. package/ecagent/src/runtime/api/pi-messages.lazy.ts +0 -4
  207. package/ecagent/src/runtime/api/pi-messages.ts +0 -436
  208. package/ecagent/src/runtime/auth/context.ts +0 -45
  209. package/ecagent/src/runtime/auth/credential-store.ts +0 -47
  210. package/ecagent/src/runtime/auth/helpers.ts +0 -46
  211. package/ecagent/src/runtime/auth/resolve.ts +0 -141
  212. package/ecagent/src/runtime/auth/types.ts +0 -182
  213. package/ecagent/src/runtime/compat.ts +0 -158
  214. package/ecagent/src/runtime/index.ts +0 -31
  215. package/ecagent/src/runtime/models.ts +0 -452
  216. package/ecagent/src/runtime/oauth.ts +0 -1
  217. package/ecagent/src/runtime/providers/faux.ts +0 -538
  218. package/ecagent/src/runtime/types.ts +0 -718
  219. package/ecagent/src/runtime/utils/diagnostics.ts +0 -45
  220. package/ecagent/src/runtime/utils/event-stream.ts +0 -88
  221. package/ecagent/src/runtime/utils/headers.ts +0 -18
  222. package/ecagent/src/runtime/utils/json-parse.ts +0 -124
  223. package/ecagent/src/runtime/utils/oauth/types.ts +0 -79
  224. package/ecagent/src/runtime/utils/overflow.ts +0 -165
  225. package/ecagent/src/runtime/utils/provider-env.ts +0 -52
  226. package/ecagent/src/runtime/utils/retry.ts +0 -101
  227. package/ecagent/src/runtime/utils/typebox-helpers.ts +0 -24
  228. package/ecagent/src/runtime/utils/validation.ts +0 -310
  229. package/ecagent/src/types.ts +0 -430
  230. 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>.agentid.pub');
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 result = await generateControlAid();
306
- saveDaemonConfig({ ...loadDaemonConfig(), aid: result.aid });
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
- // HOME 孤儿(未登记进程)只警告,不动
353
- reportOrphans(findOrphanProcesses());
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 new Promise((resolve) => {
553
- let waited = 0;
554
- const check = setInterval(() => {
555
- waited++;
556
- if (!platform.isProcessRunning(pid)) {
557
- clearInterval(check);
558
- console.log('✓ EvolCore stopped');
559
- resolve();
560
- return;
561
- }
562
- if (waited >= 10) {
563
- clearInterval(check);
564
- platform.killProcess(pid, true);
565
- console.log('✓ EvolCore stopped (forced)');
566
- resolve();
567
- }
568
- }, 1000);
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 ping = await probeDaemon(resolvePaths().socket);
574
- if (rejectPidIsolatedLifecycle('stop', status, ping))
575
- return;
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
- await Promise.all(aliveMains.map(m => stopPid(m.record.pid)));
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
- // 孤儿处理:同 HOME 的孤儿无条件 kill(restart 必须替换旧实例);
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 currentHome = resolveRoot();
670
- const sameHome = nonTestOrphans.filter(o => o.evolcoreHome === currentHome);
671
- const otherHome = nonTestOrphans.filter(o => o.evolcoreHome !== currentHome);
672
- if (sameHome.length > 0) {
673
- const killed = killOrphans(sameHome);
674
- console.log(`☠ SIGKILL ${killed.length} 个同 HOME 孤儿进程: ${killed.join(', ')}`);
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
- let readyEntry;
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 visibleEntry = entries.find(entry => platform.isProcessRunning(entry.record.pid));
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 (visibleEntry) {
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 在运行则杀掉并清理 pid 文件,返回是否成功 kill。 */
2436
- function stopEcwebIfRunning(p) {
2511
+ /** 若 ecweb 在运行则杀掉并确认 pid/端口都已释放。 */
2512
+ async function stopEcwebIfRunning(p) {
2437
2513
  const alive = findAliveEcweb(p);
2438
- let killed = false;
2439
- if (alive) {
2440
- try {
2441
- platform.killProcess(alive.pid, true);
2442
- }
2443
- catch { }
2444
- killed = true;
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
- // 端口兜底:杀掉任何仍占用 ecweb 端口的残留进程(含手动启动、未登记 pid 文件的)。
2450
- // 仅靠 pid 文件无法清理这类进程,会导致下次启动端口被占。
2451
- const port = loadDaemonConfig().ecweb?.port ?? 42705;
2452
- for (const pid of platform.findProcessByPort(port)) {
2453
- try {
2454
- platform.killProcess(pid, true);
2455
- killed = true;
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 killed;
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 wasRunning = stopEcwebIfRunning(p); // 先停旧进程(有则停),保证加载最新代码
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 未安装,跳过启动(运行 npm i -g ${WEB_PACKAGE_NAME} 后可用)`);
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}`);
@@ -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 | --resume <migration-id> | --verify [migration-id]');
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 = resumeIndex >= 0 ? args[resumeIndex + 1] : args.find(value => value.startsWith('data-'));
91
- if (resumeIndex >= 0 && !requestedId)
92
- throw new Error('--resume requires a migration id');
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
- if (!args.includes('--apply') && resumeIndex < 0)
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;
@@ -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>.agentid.pub');
1253
+ console.log(' ec agent new <aid>.example.com');
1254
1254
  return null;
1255
1255
  }
1256
1256
  const letters = 'abcdefghijklmnopqrstuvwxyz';