evolcore 0.0.25 → 0.0.27

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 (304) hide show
  1. package/CHANGELOG.md +632 -565
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +203 -160
  5. package/bin/codex-managed-hook.mjs +208 -208
  6. package/bin/ec-safe-output.js +327 -327
  7. package/bin/ec.js +40 -29
  8. package/bin/install-codex-managed-hooks.mjs +582 -555
  9. package/dist/agents/baseagent-availability.js +68 -0
  10. package/dist/agents/baseagent.js +96 -46
  11. package/dist/agents/claude-runner.js +172 -33
  12. package/dist/agents/codex/app-server-client.js +76 -31
  13. package/dist/agents/codex/catalog.js +1 -1
  14. package/dist/agents/codex/diagnostics.js +34 -1
  15. package/dist/agents/codex-runner.js +434 -446
  16. package/dist/agents/ecagent-runner.js +174 -34
  17. package/dist/agents/gemini-runner.js +8 -7
  18. package/dist/agents/runner-types.js +75 -19
  19. package/dist/aun/aid/agentmd.js +151 -36
  20. package/dist/aun/aid/client.js +1 -1
  21. package/dist/aun/aid/control-aid.js +180 -1
  22. package/dist/aun/aid/identity.js +4 -4
  23. package/dist/aun/aid/index.js +1 -1
  24. package/dist/aun/aid/store.js +17 -13
  25. package/dist/aun/group/history.js +303 -0
  26. package/dist/aun/group/identity.js +43 -0
  27. package/dist/aun/group/index.js +5 -0
  28. package/dist/aun/{msg/group.js → group/operations.js} +162 -39
  29. package/dist/aun/{menu-client.js → menu/client.js} +85 -6
  30. package/dist/aun/menu/index.js +2 -0
  31. package/dist/aun/menu/transport.js +49 -0
  32. package/dist/aun/msg/index.js +2 -1
  33. package/dist/aun/msg/managed-operation.js +85 -19
  34. package/dist/aun/msg/mention-schema.js +51 -0
  35. package/dist/aun/msg/p2p.js +19 -9
  36. package/dist/aun/msg/upload.js +43 -80
  37. package/dist/aun/outbox.js +29 -7
  38. package/dist/aun/rpc/client.js +1 -0
  39. package/dist/aun/storage/client.js +39 -50
  40. package/dist/channels/aun.js +842 -318
  41. package/dist/channels/daemon.js +10 -6
  42. package/dist/cli/agent-command.js +212 -89
  43. package/dist/cli/agent-create.js +626 -11
  44. package/dist/cli/agent.js +125 -13
  45. package/dist/cli/aun-commands.js +487 -337
  46. package/dist/cli/bench.js +20 -20
  47. package/dist/cli/config.js +55 -33
  48. package/dist/cli/contact.js +72 -15
  49. package/dist/cli/ctl-command.js +24 -24
  50. package/dist/cli/daemon-commands.js +140 -63
  51. package/dist/cli/diag.js +31 -0
  52. package/dist/cli/fs-command.js +70 -70
  53. package/dist/cli/handoff-command.js +46 -14
  54. package/dist/cli/index.js +91 -79
  55. package/dist/cli/init.js +34 -1
  56. package/dist/cli/link-rules.js +21 -21
  57. package/dist/cli/managed-command-guard.js +5 -1
  58. package/dist/cli/menu-client.js +51 -32
  59. package/dist/cli/model.js +3 -3
  60. package/dist/cli/net-check.js +22 -22
  61. package/dist/cli/queue-command.js +31 -31
  62. package/dist/cli/response.js +32 -32
  63. package/dist/cli/restart-monitor.js +103 -42
  64. package/dist/cli/stats.js +51 -51
  65. package/dist/cli/task-command.js +59 -0
  66. package/dist/cli/task-context.js +97 -49
  67. package/dist/cli/trigger-command.js +74 -64
  68. package/dist/config/builtin-roles.js +11 -0
  69. package/dist/config/config-field-policy.js +11 -0
  70. package/dist/config/config-manager.js +32 -4
  71. package/dist/config/config-operation-service.js +160 -0
  72. package/dist/config/contact-book-store.js +1 -1
  73. package/dist/config/contact-book.js +1 -1
  74. package/dist/config/contact-operation-service.js +97 -8
  75. package/dist/config/peer-role-resolver.js +1 -1
  76. package/dist/config/resolved-config-op.js +30 -7
  77. package/dist/config-store.js +1 -1
  78. package/dist/core/agent-application-service.js +7 -1
  79. package/dist/core/audit/event-key.js +17 -2
  80. package/dist/core/audit/log-integrity.js +34 -8
  81. package/dist/core/auth/agent-delegation.js +48 -14
  82. package/dist/core/auth/auth-gateway.js +2 -0
  83. package/dist/core/auth/authorization-audit.js +53 -49
  84. package/dist/core/auth/operation-authorizer.js +90 -7
  85. package/dist/core/auth/operation-catalog.js +145 -4
  86. package/dist/core/auth/remote-access-store.js +155 -10
  87. package/dist/core/bootstrap-messages.js +66 -7
  88. package/dist/core/bootstrap-service.js +111 -20
  89. package/dist/core/command/agent-control.js +88 -7
  90. package/dist/core/command/agent-storage-menu.js +443 -0
  91. package/dist/core/command/cli-intent-parser.js +19 -0
  92. package/dist/core/command/command-handler.js +159 -65
  93. package/dist/core/command/data-root-resolver.js +273 -0
  94. package/dist/core/command/diag-service.js +118 -0
  95. package/dist/core/command/group-menu.js +7 -2
  96. package/dist/core/command/menu-catalog.js +46 -7
  97. package/dist/core/command/menu-handler.js +392 -100
  98. package/dist/core/command/menu-protocol.js +45 -6
  99. package/dist/core/command/menu-token-store.js +41 -8
  100. package/dist/core/command/role-menu.js +2 -2
  101. package/dist/core/command/slash-gate.js +34 -4
  102. package/dist/core/command/slash-handler.js +123 -43
  103. package/dist/core/event-catalog.js +4 -0
  104. package/dist/core/evolagent-registry.js +28 -2
  105. package/dist/core/group/invite-service.js +924 -0
  106. package/dist/core/handoff/runtime.js +205 -27
  107. package/dist/core/handoff/store.js +193 -4
  108. package/dist/core/interaction-router.js +22 -8
  109. package/dist/core/message/im-renderer.js +146 -34
  110. package/dist/core/message/message-bridge.js +163 -20
  111. package/dist/core/message/message-log.js +5 -3
  112. package/dist/core/message/message-queue.js +99 -41
  113. package/dist/core/message/message-utils.js +1 -0
  114. package/dist/core/message/response-engine.js +755 -144
  115. package/dist/core/model/catalog-service.js +79 -49
  116. package/dist/core/model/context-window-suffix.js +33 -0
  117. package/dist/core/model/model-catalog.js +1 -1
  118. package/dist/core/model/model-permission.js +12 -3
  119. package/dist/core/permission/approval-gateway.js +36 -3
  120. package/dist/core/permission/ec-command-parser.js +112 -41
  121. package/dist/core/permission/protected-paths.js +134 -16
  122. package/dist/core/permission/sandbox-runtime.js +108 -17
  123. package/dist/core/permission/tool-error-code.js +15 -0
  124. package/dist/core/permission/tool-policy.js +9 -8
  125. package/dist/core/relation/peer-identity.js +57 -6
  126. package/dist/core/relation/shared-data.js +106 -0
  127. package/dist/core/role/runtime-policy.js +64 -0
  128. package/dist/core/runtime-lock.js +10 -26
  129. package/dist/core/session/runner-task-history.js +170 -0
  130. package/dist/core/session/session-manager.js +34 -6
  131. package/dist/core/session/session-mapper.js +41 -0
  132. package/dist/core/session/session-turn-coordinator.js +37 -7
  133. package/dist/core/session/session-turns.js +48 -7
  134. package/dist/core/task/task-recovery-service.js +176 -0
  135. package/dist/core/task/task-resume-operation.js +32 -0
  136. package/dist/eck/group-rules-sync.js +5 -3
  137. package/dist/eck/kit-renderer.js +1 -0
  138. package/dist/index.js +588 -217
  139. package/dist/ipc.js +193 -15
  140. package/dist/paths.js +17 -4
  141. package/dist/product.js +2 -0
  142. package/dist/response-system/engines/v1/proactive-flow.js +59 -2
  143. package/dist/stats/billing.js +41 -15
  144. package/dist/stats/db.js +159 -159
  145. package/dist/stats/eck-vars.js +9 -9
  146. package/dist/stats/price-resolver.js +28 -10
  147. package/dist/stats/query.js +139 -139
  148. package/dist/stats/role-budget.js +6 -6
  149. package/dist/stats/writer.js +51 -51
  150. package/dist/trigger/event-source.js +19 -0
  151. package/dist/trigger/feedback.js +233 -40
  152. package/dist/trigger/parser.js +55 -5
  153. package/dist/trigger/patch.js +9 -0
  154. package/dist/trigger/scheduler.js +30 -4
  155. package/dist/trigger/validation.js +20 -3
  156. package/dist/utils/cross-platform.js +30 -1
  157. package/dist/utils/ecweb-utils.js +1 -0
  158. package/dist/utils/error-dict.json +160 -160
  159. package/dist/utils/error-utils.js +61 -2
  160. package/dist/utils/evolcore-version.js +129 -0
  161. package/dist/utils/logger.js +26 -14
  162. package/dist/utils/macos-autostart.js +22 -22
  163. package/dist/utils/model-prices.jsonl +23 -23
  164. package/dist/utils/npm-ops.js +176 -35
  165. package/dist/utils/tool-summary.js +59 -3
  166. package/dist/utils/welcome.js +196 -23
  167. package/ecagent/LICENSE +21 -21
  168. package/ecagent/NOTICE +11 -11
  169. package/ecagent/README.md +61 -61
  170. package/ecagent/dist/harness/agent-harness.js +3 -0
  171. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  172. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  173. package/ecagent/dist/harness/messages.js +7 -7
  174. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  175. package/kits/docs/GUIDE.md +20 -20
  176. package/kits/docs/INDEX.md +60 -66
  177. package/kits/docs/aun/CHEATSHEET.md +19 -19
  178. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  179. package/kits/docs/channels/aun.md +69 -56
  180. package/kits/docs/channels/feishu.md +56 -56
  181. package/kits/docs/context-assembly.md +379 -367
  182. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  183. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  184. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  185. package/kits/docs/eck_templates/runtime.template.md +19 -19
  186. package/kits/docs/evolcore/INDEX.md +76 -71
  187. package/kits/docs/evolcore/agent-create.md +202 -165
  188. package/kits/docs/evolcore/agent.md +99 -67
  189. package/kits/docs/evolcore/aid.md +68 -60
  190. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
  191. package/kits/docs/evolcore/config.md +241 -195
  192. package/kits/docs/evolcore/contact.md +75 -68
  193. package/kits/docs/evolcore/ctl.md +46 -46
  194. package/kits/docs/evolcore/event.md +216 -216
  195. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  196. package/kits/docs/evolcore/fs.md +110 -110
  197. package/kits/docs/evolcore/group-collaboration.md +244 -244
  198. package/kits/docs/evolcore/group-fs.md +17 -17
  199. package/kits/docs/evolcore/group-rules.md +251 -251
  200. package/kits/docs/evolcore/group.md +267 -152
  201. package/kits/docs/evolcore/menu-client.md +58 -34
  202. package/kits/docs/evolcore/model.md +50 -50
  203. package/kits/docs/evolcore/msg.md +169 -165
  204. package/kits/docs/evolcore/response.md +75 -75
  205. package/kits/docs/evolcore/rpc.md +37 -37
  206. package/kits/docs/evolcore/self-summary.md +29 -29
  207. package/kits/docs/evolcore/stats.md +83 -83
  208. package/kits/docs/evolcore/storage.md +53 -50
  209. package/kits/docs/evolcore/task.md +14 -0
  210. package/kits/docs/evolcore/trigger.md +623 -575
  211. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  212. package/kits/docs/identity/PATH_OPS.md +16 -16
  213. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  214. package/kits/docs/identity/identity-tools.md +26 -26
  215. package/kits/docs/path-registry.md +62 -62
  216. package/kits/docs/prompt-loading-architecture.md +269 -269
  217. package/kits/docs/venues/aun-group.md +45 -45
  218. package/kits/docs/venues/aun-private.md +10 -10
  219. package/kits/docs/venues/client-desktop.md +10 -10
  220. package/kits/docs/venues/client-mobile.md +10 -10
  221. package/kits/docs/venues/feishu-group.md +13 -13
  222. package/kits/docs/venues/feishu-private.md +9 -9
  223. package/kits/docs/venues/group.md +42 -25
  224. package/kits/docs/venues/private.md +10 -10
  225. package/kits/eck_manifest.auxiliary.json +43 -43
  226. package/kits/eck_manifest.json +217 -190
  227. package/kits/eck_message_manifest.json +74 -74
  228. package/kits/migrations/README-role-config-v4.md +32 -32
  229. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  230. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  231. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  232. package/kits/migrations/rename-config-file.mjs +99 -99
  233. package/kits/rules/01-overview.md +166 -162
  234. package/kits/rules/02-navigation.md +96 -96
  235. package/kits/rules/03-identity.md +36 -36
  236. package/kits/rules/04-relation.md +76 -75
  237. package/kits/rules/05-venue.md +60 -60
  238. package/kits/rules/06-channel.md +65 -63
  239. package/kits/schemas/_meta.json +53 -53
  240. package/kits/schemas/agent-config.schema.1.json +177 -177
  241. package/kits/schemas/agent-config.schema.10.json +395 -395
  242. package/kits/schemas/agent-config.schema.11.json +421 -421
  243. package/kits/schemas/agent-config.schema.12.json +451 -427
  244. package/kits/schemas/agent-config.schema.2.json +239 -239
  245. package/kits/schemas/agent-config.schema.3.json +119 -119
  246. package/kits/schemas/agent-config.schema.4.json +208 -208
  247. package/kits/schemas/agent-config.schema.5.json +326 -326
  248. package/kits/schemas/agent-config.schema.6.json +322 -322
  249. package/kits/schemas/agent-config.schema.7.json +303 -303
  250. package/kits/schemas/agent-config.schema.8.json +304 -304
  251. package/kits/schemas/agent-config.schema.9.json +364 -364
  252. package/kits/schemas/contact-book.schema.1.json +36 -36
  253. package/kits/schemas/contact-book.schema.2.json +43 -43
  254. package/kits/schemas/contact-book.schema.3.json +67 -67
  255. package/kits/schemas/daemon.schema.1.json +91 -91
  256. package/kits/schemas/daemon.schema.2.json +101 -101
  257. package/kits/schemas/daemon.schema.3.json +123 -123
  258. package/kits/schemas/daemon.schema.4.json +136 -136
  259. package/kits/schemas/daemon.schema.5.json +135 -135
  260. package/kits/schemas/daemon.schema.6.json +131 -131
  261. package/kits/schemas/defaults.schema.1.json +81 -81
  262. package/kits/schemas/defaults.schema.2.json +85 -85
  263. package/kits/schemas/defaults.schema.3.json +73 -73
  264. package/kits/schemas/defaults.schema.4.json +107 -107
  265. package/kits/schemas/defaults.schema.5.json +119 -119
  266. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  267. package/kits/schemas/migrations/README.md +30 -30
  268. package/kits/schemas/relation-config.schema.1.json +158 -158
  269. package/kits/schemas/relation-config.schema.2.json +73 -73
  270. package/kits/schemas/relation-config.schema.3.json +50 -50
  271. package/kits/schemas/relation-config.schema.4.json +47 -47
  272. package/kits/schemas/relation-config.schema.5.json +47 -47
  273. package/kits/schemas/relation-config.schema.6.json +46 -46
  274. package/kits/schemas/relation-config.schema.7.json +59 -59
  275. package/kits/schemas/relation-config.schema.8.json +103 -103
  276. package/kits/schemas/role-config.schema.1.json +215 -201
  277. package/kits/schemas/role-registry.schema.1.json +35 -35
  278. package/kits/schemas/single-session.schema.1.json +31 -31
  279. package/kits/schemas/single-session.schema.2.json +57 -57
  280. package/kits/schemas/single-session.schema.3.json +32 -32
  281. package/kits/templates/bootstrap-welcome.md +17 -17
  282. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  283. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  284. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  285. package/kits/templates/message-fragments/inject-default.md +2 -2
  286. package/kits/templates/message-fragments/item.md +2 -2
  287. package/kits/templates/roles/admin.json +92 -92
  288. package/kits/templates/roles/member.json +101 -96
  289. package/kits/templates/roles/owner.json +9 -9
  290. package/kits/templates/roles/visitor.json +90 -85
  291. package/kits/templates/system-fragments/baseagent.md +14 -14
  292. package/kits/templates/system-fragments/bootstrap.md +53 -34
  293. package/kits/templates/system-fragments/channel.md +28 -64
  294. package/kits/templates/system-fragments/commands.md +36 -28
  295. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  296. package/kits/templates/system-fragments/identity.md +13 -13
  297. package/kits/templates/system-fragments/relation.md +19 -19
  298. package/kits/templates/system-fragments/reply.md +56 -0
  299. package/kits/templates/system-fragments/session.md +59 -59
  300. package/kits/templates/system-fragments/venue.md +31 -31
  301. package/package.json +104 -98
  302. package/dist/aun/group-identity.js +0 -9
  303. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  304. /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
@@ -23,11 +23,12 @@ import { displaySessionTitle } from '../core/session/session-title.js';
23
23
  import { isNonAgentSessionChannel } from '../core/system-channels.js';
24
24
  import { printCodeStats } from './code-stats.js';
25
25
  import { getProcessStartTime, startTimeMatches } from '../utils/process-introspect.js';
26
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
26
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
27
27
  import { WEB_CLI_BIN, WEB_PACKAGE_LATEST, WEB_PACKAGE_NAME } from '../product.js';
28
28
  import { rotateStdoutLog } from '../utils/log-writer.js';
29
29
  import { inspectDataMigrationRequirement } from '../core/data-migration.js';
30
30
  import { isInitCancelledError, printInitCancelHint } from './init-cancel.js';
31
+ import { computeBuildId } from '../utils/evolcore-version.js';
31
32
  import { listCodexAppServerProcesses, unregisterCodexAppServerProcess } from '../agents/codex/app-server-registry.js';
32
33
  import { DEFAULT_ECWEB_PORT, ecwebService, setEcwebEnabled } from '../config/daemon-services.js';
33
34
  import { checkCodexProjectPath, inspectCodexManagedHook, ensureCodexManagedHook, runCodexHookLaunchDiagnostic, } from '../agents/codex/diagnostics.js';
@@ -39,6 +40,8 @@ export function ensureCodexHookBeforeLifecycle(onRepaired) {
39
40
  try {
40
41
  const usesCodex = loadDefaults()?.active_baseagent === 'codex'
41
42
  || loadAllAgents().agents.some(agent => {
43
+ if (agent.enabled === false)
44
+ return false;
42
45
  try {
43
46
  return resolveEffective({ self: agent.aid }).active_baseagent === 'codex';
44
47
  }
@@ -145,7 +148,7 @@ function rejectPidIsolatedLifecycle(action, status, ping) {
145
148
  }
146
149
  async function tryDelegatedDaemonRestart(socketPath) {
147
150
  const sessionId = process.env.EVOLCORE_SESSION_ID;
148
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
151
+ const delegationToken = readDelegationCredential();
149
152
  if (!sessionId || !delegationToken)
150
153
  return false;
151
154
  const response = await ipcQuery(socketPath, {
@@ -312,7 +315,10 @@ export async function runUpgradeChecks(upgradeFn = signal => tryUpgrade({ signal
312
315
  clearTimeout(timer);
313
316
  }
314
317
  };
315
- const upgrade = await runWithTimeout('EvolCore', upgradeFn);
318
+ const [upgrade, ecwebUpgrade] = await Promise.all([
319
+ runWithTimeout('EvolCore', upgradeFn),
320
+ runWithTimeout(WEB_PACKAGE_NAME, ecwebUpgradeFn),
321
+ ]);
316
322
  switch (upgrade.status) {
317
323
  case 'upgraded':
318
324
  console.log(`✅ Upgraded: ${upgrade.from} → ${upgrade.to}`);
@@ -329,7 +335,6 @@ export async function runUpgradeChecks(upgradeFn = signal => tryUpgrade({ signal
329
335
  console.log(`⚠ Upgrade failed${upgrade.from && upgrade.to ? ` (${upgrade.from} → ${upgrade.to})` : ''}, continuing with current version${upgrade.error ? `: ${upgrade.error}` : ''}`);
330
336
  break;
331
337
  }
332
- const ecwebUpgrade = await runWithTimeout(WEB_PACKAGE_NAME, ecwebUpgradeFn);
333
338
  switch (ecwebUpgrade.status) {
334
339
  case 'upgraded':
335
340
  console.log(`✅ ${WEB_PACKAGE_NAME} upgraded: ${ecwebUpgrade.from} → ${ecwebUpgrade.to}`);
@@ -769,21 +774,50 @@ export async function cmdStart(opts = {}) {
769
774
  };
770
775
  setTimeout(checkReady, 1000);
771
776
  }
772
- async function stopPid(pid, gracefulRequested = false) {
777
+ function isPidReused(pid, expectedStartedAt) {
778
+ if (expectedStartedAt === undefined)
779
+ return false;
780
+ const actualStartedAt = getProcessStartTime(pid);
781
+ return actualStartedAt !== null && !startTimeMatches(expectedStartedAt, actualStartedAt);
782
+ }
783
+ function reportPidReused(pid) {
784
+ console.log(`ℹ EvolCore PID ${pid} no longer refers to the recorded process; treating it as stopped`);
785
+ }
786
+ async function stopPid(pid, gracefulRequested = false, expectedStartedAt) {
773
787
  console.log(`🛑 Stopping EvolCore (PID: ${pid})...`);
788
+ if (isPidReused(pid, expectedStartedAt)) {
789
+ reportPidReused(pid);
790
+ return true;
791
+ }
774
792
  if (!gracefulRequested)
775
793
  platform.killProcess(pid);
776
794
  if (await platform.waitForProcessExit(pid, gracefulRequested ? 30_000 : 10_000)) {
777
795
  console.log('✓ EvolCore stopped');
778
796
  return true;
779
797
  }
780
- console.log(`⚠ EvolCore PID ${pid} did not exit gracefully; forcing termination...`);
798
+ if (isPidReused(pid, expectedStartedAt)) {
799
+ reportPidReused(pid);
800
+ return true;
801
+ }
802
+ const state = platform.getProcessState(pid);
803
+ const stateSuffix = state ? ` (state=${state})` : '';
804
+ console.log(`⚠ EvolCore PID ${pid} did not exit gracefully${stateSuffix}; forcing termination...`);
805
+ if (isPidReused(pid, expectedStartedAt)) {
806
+ reportPidReused(pid);
807
+ return true;
808
+ }
781
809
  platform.killProcess(pid, true);
782
810
  if (await platform.waitForProcessExit(pid, 5_000)) {
783
811
  console.log('✓ EvolCore stopped (forced)');
784
812
  return true;
785
813
  }
786
- console.error(`❌ EvolCore PID ${pid} is still running; restart aborted`);
814
+ if (isPidReused(pid, expectedStartedAt)) {
815
+ reportPidReused(pid);
816
+ return true;
817
+ }
818
+ const finalState = platform.getProcessState(pid);
819
+ const finalStateSuffix = finalState ? ` (state=${finalState})` : '';
820
+ console.error(`❌ EvolCore PID ${pid} is still running${finalStateSuffix}; restart aborted`);
787
821
  return false;
788
822
  }
789
823
  function isRuntimeOrphan(orphan, currentHome = resolveRoot()) {
@@ -813,13 +847,14 @@ export async function cmdStop() {
813
847
  return;
814
848
  }
815
849
  const pids = new Set([...aliveMains.map(entry => entry.record.pid), ...runtimeOrphans.map(orphan => orphan.pid)]);
850
+ const expectedStarts = new Map(aliveMains.map(entry => [entry.record.pid, entry.record.startedAt]));
816
851
  if (runtimeOrphans.length > 0) {
817
852
  console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(orphan => orphan.pid).join(', ')}`);
818
853
  }
819
854
  const gracefulPid = ping && pids.has(ping.pid)
820
855
  ? await requestDaemonShutdown(p.socket, DAEMON_SHUTDOWN_TIMEOUT_MS, 'ec stop', pids)
821
856
  : null;
822
- const stopped = await Promise.all([...pids].map(pid => stopPid(pid, pid === gracefulPid)));
857
+ const stopped = await Promise.all([...pids].map(pid => stopPid(pid, pid === gracefulPid, expectedStarts.get(pid))));
823
858
  if (stopped.some(result => !result)) {
824
859
  process.exitCode = 1;
825
860
  return;
@@ -836,11 +871,13 @@ export async function cmdRestart(opts = {}) {
836
871
  if (!ensureCodexHookBeforeLifecycle())
837
872
  return;
838
873
  const initialStatus = scanInstances();
839
- const initialOrphans = findOrphanProcesses();
840
- const initialRuntimeOrphans = initialOrphans.filter(orphan => isRuntimeOrphan(orphan));
841
874
  const socketPath = resolvePaths().socket;
842
875
  const ping = await probeDaemon(socketPath);
843
876
  if (ping && !hasVisibleDaemonPid(initialStatus, ping)) {
877
+ // Only pay for a cross-host process-table scan when the IPC PID is not
878
+ // present in our registry. This is the exceptional PID-namespace case;
879
+ // healthy restarts no longer scan every Node process before stopping.
880
+ const initialRuntimeOrphans = findOrphanProcesses().filter(orphan => isRuntimeOrphan(orphan));
844
881
  if (await tryDelegatedDaemonRestart(socketPath))
845
882
  return;
846
883
  if (initialRuntimeOrphans.length === 0 && rejectPidIsolatedLifecycle('restart', initialStatus, ping))
@@ -848,13 +885,13 @@ export async function cmdRestart(opts = {}) {
848
885
  }
849
886
  // 构建交给 restart-monitor:它在 daemon 停止之后才编译,dist/ 不会被活进程
850
887
  // 占用,失败还能回滚到上一份产物。这里再编译一次会落在事务保护之外。
851
- // Keep restart behavior identical to startup: both paths use one upgrade
852
- // check implementation and continue when an upgrade is unavailable.
853
- await runUpgradeChecks();
888
+ // restart-monitor owns upgrade checks. Running them here as well caused a
889
+ // normal restart to perform every registry lookup twice, and in installed
890
+ // mode could race the monitor while it was preparing its rollback point.
854
891
  if (!requireCompletedDataMigration(resolveRoot(), 'restart'))
855
892
  return;
856
893
  // 停止所有活 main 进程(可能不止一个)
857
- const status = scanInstances();
894
+ const status = initialStatus;
858
895
  const aliveMains = status.mains.filter(m => m.alive);
859
896
  if (aliveMains.length > 0) {
860
897
  if (aliveMains.length > 1) {
@@ -865,7 +902,7 @@ export async function cmdRestart(opts = {}) {
865
902
  const gracefulPid = currentPing && mainPids.has(currentPing.pid)
866
903
  ? await requestDaemonShutdown(socketPath, DAEMON_SHUTDOWN_TIMEOUT_MS, 'ec restart', mainPids)
867
904
  : null;
868
- const stopped = await Promise.all(aliveMains.map(m => stopPid(m.record.pid, m.record.pid === gracefulPid)));
905
+ const stopped = await Promise.all(aliveMains.map(m => stopPid(m.record.pid, m.record.pid === gracefulPid, m.record.startedAt)));
869
906
  if (stopped.some(result => !result)) {
870
907
  console.error('❌ Restart aborted because an existing EvolCore process could not be stopped');
871
908
  process.exitCode = 1;
@@ -881,7 +918,8 @@ export async function cmdRestart(opts = {}) {
881
918
  return;
882
919
  }
883
920
  // 孤儿处理:同 HOME/同安装包的孤儿属于本运行时,先确认退出再替换;
884
- // 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。
921
+ // 跨 HOME 的孤儿只在 --clear 时 kill,否则仅警告。findOrphanProcesses
922
+ // 在 Windows 上需要一次 CIM 查询;保留一个快照,避免同一阶段重复扫描。
885
923
  {
886
924
  const orphans = findOrphanProcesses();
887
925
  const confirmedTestDaemons = orphans.filter(o => o.confirmedTestDaemon);
@@ -890,7 +928,7 @@ export async function cmdRestart(opts = {}) {
890
928
  console.log(`☠ 已清理 ${killed.length} 个泄漏的测试 daemon: ${killed.join(', ')}`);
891
929
  await sleep(500);
892
930
  }
893
- const runtimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
931
+ const runtimeOrphans = orphans.filter(o => isRuntimeOrphan(o));
894
932
  if (runtimeOrphans.length > 0) {
895
933
  console.log(`⚠ 检测到未登记的 EvolCore 进程,将一并停止: ${runtimeOrphans.map(o => o.pid).join(', ')}`);
896
934
  const orphanPids = new Set(runtimeOrphans.map(orphan => orphan.pid));
@@ -906,13 +944,9 @@ export async function cmdRestart(opts = {}) {
906
944
  }
907
945
  await sleep(500);
908
946
  }
909
- const remainingRuntimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
910
- if (remainingRuntimeOrphans.length > 0) {
911
- console.error(`❌ Restart aborted: EvolCore process still running (PID: ${remainingRuntimeOrphans.map(o => o.pid).join(', ')})`);
912
- process.exitCode = 1;
913
- return;
914
- }
915
- const otherHome = findOrphanProcesses().filter(o => !o.confirmedTestDaemon && !isRuntimeOrphan(o));
947
+ // stopPid() already waited for every runtime orphan above, so avoid a
948
+ // second scan before handling cross-HOME records.
949
+ const otherHome = orphans.filter(o => !o.confirmedTestDaemon && !isRuntimeOrphan(o));
916
950
  if (opts.clear && otherHome.length > 0) {
917
951
  const killed = killOrphans(otherHome);
918
952
  console.log(`☠ 已 SIGKILL ${killed.length} 个跨 HOME 孤儿进程: ${killed.join(', ')}`);
@@ -921,6 +955,14 @@ export async function cmdRestart(opts = {}) {
921
955
  else if (otherHome.length > 0) {
922
956
  reportOrphans(otherHome);
923
957
  }
958
+ // Keep the post-stop ownership guard: a process that appeared during the
959
+ // cleanup window must still block replacement.
960
+ const remainingRuntimeOrphans = findOrphanProcesses().filter(o => isRuntimeOrphan(o));
961
+ if (remainingRuntimeOrphans.length > 0) {
962
+ console.error(`❌ Restart aborted: EvolCore process still running (PID: ${remainingRuntimeOrphans.map(o => o.pid).join(', ')})`);
963
+ process.exitCode = 1;
964
+ return;
965
+ }
924
966
  }
925
967
  // 只清理 EvolCore 自己登记的 codex app-server,不能影响桌面端实例。
926
968
  {
@@ -955,8 +997,7 @@ export async function cmdRestart(opts = {}) {
955
997
  process.exitCode = 1;
956
998
  return;
957
999
  }
958
- console.log('🔄 Restart monitor started, waiting for service to come back online...');
959
- await sleep(2000);
1000
+ console.log('🔄 Restart monitor started; service is coming back online in the background...');
960
1001
  // 代码统计(开发环境)
961
1002
  if (path.normalize(resolveRoot()) === path.normalize(getPackageRoot())) {
962
1003
  console.log('');
@@ -1125,6 +1166,7 @@ export async function cmdStatus() {
1125
1166
  const p = resolvePaths();
1126
1167
  const status = scanInstances();
1127
1168
  const aliveMains = status.mains.filter(m => m.alive);
1169
+ const aliveRestartMonitors = status.restartMonitors.filter(m => m.alive);
1128
1170
  // Start all read-only daemon queries together. On a busy Windows host each
1129
1171
  // query can otherwise wait behind the same IPC/event-loop delay and make the
1130
1172
  // total `ec status` time the sum of several individual timeouts.
@@ -1263,6 +1305,10 @@ export async function cmdStatus() {
1263
1305
  catch { }
1264
1306
  }
1265
1307
  }
1308
+ else if (aliveRestartMonitors.length > 0) {
1309
+ console.log(`🔄 EvolCore 正在重启,daemon 尚未就绪(monitor PID: ${aliveRestartMonitors.map(m => m.record.pid).join(', ')})`);
1310
+ console.log(' 请稍后再次执行 ec status。');
1311
+ }
1266
1312
  else {
1267
1313
  console.log(ipcFailure ? '⚠ 无法确认 EvolCore 运行状态:IPC 不可用,且没有可见的存活 PID。' : '⚠ EvolCore is not running');
1268
1314
  if (ipcFailure)
@@ -1312,6 +1358,24 @@ export async function cmdStatus() {
1312
1358
  ]);
1313
1359
  agentsResponse = agentResponse;
1314
1360
  if (statusResponse) {
1361
+ if (statusResponse.build) {
1362
+ if (statusResponse.build.runtimeMode === 'source') {
1363
+ console.log(` Build ID: runtime=source dist=${statusResponse.build.diskDistId || '?'}`);
1364
+ console.log(' ℹ daemon 当前由源码入口运行,dist build ID 不参与一致性比较。');
1365
+ }
1366
+ else {
1367
+ const runtimeBuildId = statusResponse.build.runtimeId || '?';
1368
+ const diskDistBuildId = statusResponse.build.diskDistId || '?';
1369
+ console.log(` Build ID: runtime=${runtimeBuildId} dist=${diskDistBuildId}`);
1370
+ if (runtimeBuildId !== '?' && diskDistBuildId !== '?' && runtimeBuildId !== diskDistBuildId) {
1371
+ console.log(' ⚠ 运行进程 build ID 与磁盘 dist 不一致;请重启 daemon 后再判断源码行为。');
1372
+ }
1373
+ }
1374
+ }
1375
+ else {
1376
+ console.log(` Build ID: runtime=unavailable (daemon 未提供 build identity) dist=${computeBuildId(path.join(getPackageRoot(), 'dist')) ?? '?'}`);
1377
+ console.log(' ⚠ 当前 daemon 未提供 build ID;请重启到包含 build identity 的版本后再判断源码行为。');
1378
+ }
1315
1379
  // 🔑 AUN AIDs 表格(详细 AUN 实例状态)
1316
1380
  try {
1317
1381
  if (aidsResponse?.ok && aidsResponse.aids?.length > 0) {
@@ -2658,17 +2722,18 @@ function findAliveEcweb(p) {
2658
2722
  return alive[0] ?? null;
2659
2723
  }
2660
2724
  /**
2661
- * 轻量 HTTP 就绪探测:GET / 返回 2xx 即视为就绪。
2662
- * 不走 /api/pair-code(会触发配对码刷新副作用),不走 /api/health(不存在)。
2663
- * 根路径由 serveStatic 处理,返回 index.html,无副作用。
2725
+ * 轻量 HTTP 就绪探测:ECWeb 的健康端点必须返回明确的服务标识。
2726
+ * 不走 /api/pair-code(会触发配对码刷新副作用),也不依赖静态页面内容。
2664
2727
  */
2665
2728
  async function probeEcwebReady(port) {
2666
2729
  try {
2667
- const res = await fetch(`http://127.0.0.1:${port}/`, {
2668
- method: 'GET',
2730
+ const res = await fetch(`http://127.0.0.1:${port}/api/health`, {
2669
2731
  signal: AbortSignal.timeout(2000),
2670
2732
  });
2671
- return res.ok;
2733
+ if (!res.ok)
2734
+ return false;
2735
+ const body = await res.json();
2736
+ return body.ok === true && body.service === 'ecweb';
2672
2737
  }
2673
2738
  catch {
2674
2739
  return false;
@@ -2694,8 +2759,9 @@ async function waitForExistingEcweb(p, timeoutMs = 3_000) {
2694
2759
  }
2695
2760
  /**
2696
2761
  * 输出 ECWeb 状态。判定口径:
2697
- * 1. 进程是否存活(instance/ 下的 pid 文件 + isProcessRunning)
2698
- * 2. HTTP 是否就绪——探测根路径 /(serveStatic → index.html, 无副作用)。
2762
+ * 1. HTTP 是否就绪——探测 ECWeb 专用 /api/health 端点。
2763
+ * 2. 进程是否存活(instance/ 下的 pid 文件 + isProcessRunning)仅用于补充诊断;
2764
+ * 某些 CLI 运行在隔离 PID namespace 中,看不到宿主 ECWeb PID 是正常情况。
2699
2765
  */
2700
2766
  async function printEcwebStatus(p) {
2701
2767
  try {
@@ -2711,6 +2777,15 @@ async function printEcwebStatus(p) {
2711
2777
  // still provide an authoritative runtime status without local config access.
2712
2778
  }
2713
2779
  const entries = readEcwebInstanceEntries(p);
2780
+ // Probe before consulting PID visibility. The daemon and CLI can be in
2781
+ // different PID namespaces while sharing the host network namespace.
2782
+ let readyEntry;
2783
+ for (const entry of entries) {
2784
+ if (await probeEcwebReady(entry.record.port)) {
2785
+ readyEntry = entry;
2786
+ break;
2787
+ }
2788
+ }
2714
2789
  const aliveEntries = [];
2715
2790
  for (const entry of entries) {
2716
2791
  if (platform.isProcessRunning(entry.record.pid)) {
@@ -2719,22 +2794,21 @@ async function printEcwebStatus(p) {
2719
2794
  else {
2720
2795
  // A stale EC Web record must never be used to report the PID of an
2721
2796
  // unrelated process that later inherited the port.
2722
- try {
2723
- fs.unlinkSync(entry.filePath);
2797
+ // Keep a record whose dedicated health endpoint just proved live: the
2798
+ // PID may be hidden by a namespace boundary rather than actually dead.
2799
+ if (entry.filePath !== readyEntry?.filePath) {
2800
+ try {
2801
+ fs.unlinkSync(entry.filePath);
2802
+ }
2803
+ catch { }
2724
2804
  }
2725
- catch { }
2726
- }
2727
- }
2728
- let readyEntry;
2729
- for (const entry of aliveEntries) {
2730
- if (await probeEcwebReady(entry.record.port)) {
2731
- readyEntry = entry;
2732
- break;
2733
2805
  }
2734
2806
  }
2735
2807
  if (readyEntry) {
2736
2808
  console.log('');
2737
- console.log(`🔭 ECWeb: 运行中 (PID: ${readyEntry.record.pid}) http://localhost:${readyEntry.record.port}`);
2809
+ const pidVisible = aliveEntries.some(entry => entry.filePath === readyEntry.filePath);
2810
+ const pidText = pidVisible ? `PID: ${readyEntry.record.pid}` : `PID: ${readyEntry.record.pid}(当前 namespace 不可见)`;
2811
+ console.log(`🔭 ECWeb: 运行中 (${pidText}) http://localhost:${readyEntry.record.port}`);
2738
2812
  return;
2739
2813
  }
2740
2814
  const occupiedPids = new Set();
@@ -2771,9 +2845,12 @@ function removeEcwebInstanceFiles(p) {
2771
2845
  }
2772
2846
  /** 清理 EvolCore 登记的 codex app-server 孤儿进程,返回清理的进程数。 */
2773
2847
  export function stopCodexAppServerOrphans() {
2848
+ const entries = listCodexAppServerProcesses();
2849
+ if (entries.length === 0)
2850
+ return 0;
2774
2851
  const codexProcs = new Set(platform.findProcesses('codex app-server'));
2775
2852
  let killed = 0;
2776
- for (const entry of listCodexAppServerProcesses()) {
2853
+ for (const entry of entries) {
2777
2854
  const { pid, startedAt } = entry.record;
2778
2855
  if (!platform.isProcessRunning(pid)) {
2779
2856
  unregisterCodexAppServerProcess(entry.filePath);
@@ -2926,7 +3003,7 @@ export async function startEcwebIfEnabled(p, options = {}) {
2926
3003
  console.log(`✓ ECWeb ${actionLabel} (PID: ${pid}) http://localhost:${port}`);
2927
3004
  if (pair) {
2928
3005
  const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
2929
- console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,已配对过的浏览器无需重新配对)`);
3006
+ console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,已配对过的浏览器无需重新配对)`);
2930
3007
  }
2931
3008
  else {
2932
3009
  console.log(' daemon 尚未提供配对码;EvolCore 启动后可通过 /pair 或 ECWeb 页面获取');
@@ -2962,7 +3039,7 @@ async function printEcwebAccess(port) {
2962
3039
  }
2963
3040
  if (pair) {
2964
3041
  const mins = Math.max(0, Math.round((pair.expiresAt - Date.now()) / 60000));
2965
- console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,配对后远程访问 token 缓存 30 天)`);
3042
+ console.log(` 配对码: ${pair.code} (约 ${mins} 分钟内有效,仅可配对一次,token 缓存 7 天,有访问自动续期)`);
2966
3043
  }
2967
3044
  else {
2968
3045
  console.log(' 配对码: 暂不可用(稍后重试 ec watch web,或查看 logs/watch-web.log)');
@@ -3260,21 +3337,21 @@ export async function cmdWatchCommand(args) {
3260
3337
  }
3261
3338
  else if (args[0] === 'msg') {
3262
3339
  if (isHelpFlag(args[1])) {
3263
- console.log(`用法: ec watch msg
3264
-
3265
- 三面板交互式消息监控 TUI。
3266
-
3267
- 面板:
3268
- 左 (Scope) 本地 AID 列表,显示收发统计和对端数量
3269
- 中 (Stats) 选中 AID 的对端列表(默认 All),显示 per-peer 收发数
3270
- 右 (Messages) 消息流,带滚动条
3271
-
3272
- 操作:
3273
- ↑↓ 当前面板内导航
3274
- ←→ / Tab 切换面板
3275
- Enter 选中 AID / 选中对端
3276
- Backspace 返回上一级
3277
- Page Up/Down 消息滚动
3340
+ console.log(`用法: ec watch msg
3341
+
3342
+ 三面板交互式消息监控 TUI。
3343
+
3344
+ 面板:
3345
+ 左 (Scope) 本地 AID 列表,显示收发统计和对端数量
3346
+ 中 (Stats) 选中 AID 的对端列表(默认 All),显示 per-peer 收发数
3347
+ 右 (Messages) 消息流,带滚动条
3348
+
3349
+ 操作:
3350
+ ↑↓ 当前面板内导航
3351
+ ←→ / Tab 切换面板
3352
+ Enter 选中 AID / 选中对端
3353
+ Backspace 返回上一级
3354
+ Page Up/Down 消息滚动
3278
3355
  ESC 退出`);
3279
3356
  return;
3280
3357
  }
@@ -0,0 +1,31 @@
1
+ import { ipcQuery } from '../ipc.js';
2
+ import { resolvePaths } from '../paths.js';
3
+ import { readDelegationCredential } from '../core/auth/agent-delegation.js';
4
+ import { parseDiagArgs } from '../core/command/diag-service.js';
5
+ import { wantsHelp } from './help.js';
6
+ export async function cmdDiag(args) {
7
+ if (wantsHelp(args)) {
8
+ console.log('用法:ec diag <问题描述> [--owner <daemonOwner-aid>] [--format json]\n ec diag stop [--format json]\n未指定 --owner 时联系本机 daemon.json.owners[0]。');
9
+ return;
10
+ }
11
+ const json = args.at(-2) === '--format' && args.at(-1) === 'json';
12
+ const argv = json ? args.slice(0, -2) : args;
13
+ let result;
14
+ try {
15
+ parseDiagArgs(argv);
16
+ result = await ipcQuery(resolvePaths().socket, {
17
+ type: 'diag', argv,
18
+ ...(process.env.EVOLCORE_SESSION_ID ? {
19
+ sessionId: process.env.EVOLCORE_SESSION_ID,
20
+ delegationToken: readDelegationCredential(),
21
+ } : {}),
22
+ }, 30_000) ?? { ok: false, code: 'DAEMON_UNAVAILABLE', message: 'daemon 未返回结果,请检查其运行状态;发送结果尚未确认' };
23
+ }
24
+ catch (error) {
25
+ result = { ok: false, code: 'INVALID_ARGUMENT', message: error.message };
26
+ }
27
+ result.message ??= result.error ?? '诊断请求未完成';
28
+ console.log(json ? JSON.stringify(result, null, 2) : result.message);
29
+ if (!result.ok)
30
+ process.exitCode = 1;
31
+ }
@@ -5,8 +5,8 @@ import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
5
5
  import { agentmdGet, getAidStore, isValidAid, loadClient, SLOT } from '../aun/aid/index.js';
6
6
  import { ipcQuery } from '../ipc.js';
7
7
  import { resolvePaths } from '../paths.js';
8
- import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
9
- import { downloadGroupFsBytes } from '../aun/group-fs-download.js';
8
+ import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
9
+ import { downloadGroupFsBytes } from '../aun/group/index.js';
10
10
  class FsCliError extends Error {
11
11
  code;
12
12
  suggestion;
@@ -19,73 +19,73 @@ class FsCliError extends Error {
19
19
  this.details = details;
20
20
  }
21
21
  }
22
- const HELP = `用法: ec fs <command> [args...] [options]
23
-
24
- Commands:
25
- ls <AID>:<path> 列目录
26
- stat [-L] <AID>:<path> 查看节点元数据(默认不跟随软链;-L 跟随)
27
- lstat <AID>:<path> 查看节点本身(不跟随末级软链)
28
- cat <AID>:<path> 输出文本文件内容;二进制/大文件返回头部摘要
29
- cp <local> <AID>:<path> 上传本地文件
30
- cp <AID>:<path> <local> 下载远程文件
31
- cp <AID>:<path> <AID>:<path> 远程复制(同后端)
32
- mv <AID>:<path> <AID>:<path> 移动/改名(同后端)
33
- rm [-r] <AID>:<path> 删除文件或目录
34
- mkdir [-p] <AID>:<path> 创建目录
35
- ln -s <target> <AID>:<path> 创建软链(personal storage)
36
- chmod [mode] <AID>:<path> 切换公开/私有(personal storage)
37
- setfacl <AID>:<path> -m|-x ... 设置/移除 ACL(群路径使用 role:member|role:admin)
38
- getfacl <AID>:<path> 查看 ACL
39
- token issue|revoke|ls <path> 管理访问 token(personal storage)
40
- find <AID>:<path> [filters] 查找节点
41
- df <AID>: 查看容量/配额
42
- mount <target> --volume <id> 挂载实体卷
43
- mount <target> --source <src> 挂载远程子树
44
- approve <AID>:<path> 批准待审挂载(personal storage)
45
- reject <AID>:<path> 拒绝待审挂载(personal storage)
46
- umount <AID>:<path> 卸载挂载点
47
-
48
- Options:
49
- --as <aid> 操作者 AID;也可由 EVOLCORE_SELF_AID 注入
50
- --format json 输出 JSON
51
- --overwrite, --force 覆盖目标(用于 cp/mv/ln)或强制删除(用于 rm)
52
- -r, --recursive 递归(用于 rm/cp)
53
- -p, --parents 自动创建父目录(用于 mkdir/group 上传)
54
- -L, --follow stat 跟随末级软链
55
- --token <token> 读取时携带访问 token(personal storage)
56
- --content-type <mime> 上传时指定内容类型
57
- --public 上传后公开可读(personal storage)
58
- --visibility <public|private> chmod 可见性
59
- --allow-roles <roles> chmod 角色约束,逗号分隔
60
- -m aid:<aid>:<perms> setfacl 新增/更新 ACL
61
- -x aid:<aid> setfacl 移除 ACL
62
- --source <AID>:<path> mount 虚拟卷来源
63
- --volume <id> mount 实体卷 ID
64
- --require-approval mount 需要来源 owner 审批
65
- --expires <time> mount/token/ACL 过期时间,Unix 秒或 ISO 日期
66
- --max-uses <n> ACL 最大使用次数
67
- --max-reads <n> token 最大读取次数
68
- --readonly, --readwrite mount 只读/读写
69
- --name <glob> find 名称过滤
70
- --type <f|d|l> find 类型过滤
71
- --size <expr> find 大小过滤,如 +1M
72
- --mtime <expr> find 修改时间过滤
73
- --head-bytes <n> cat 二进制头部字节数,默认 256
74
- --max-bytes <n> cat 最大直接输出字节数,默认 1048576
75
- --aun-path <path> 指定 AUN keystore 根
76
- --app <name> 指定 AUN app slot
77
-
78
- 示例:
79
- ec fs ls alice.agentid.pub:/private/
80
- ec fs cp ./report.md alice.agentid.pub:/private/report.md --as alice.agentid.pub
81
- ec fs cp alice.agentid.pub:/private/report.md ./report.md --as alice.agentid.pub
82
- ec fs cp alice.agentid.pub:/private/a.md bob.agentid.pub:/inbox/a.md --as alice.agentid.pub
83
- ec fs cat alice.agentid.pub:/private/report.md --as alice.agentid.pub
84
- ec fs ln -s alice.agentid.pub:/private/report.md alice.agentid.pub:/public/report.md --as alice.agentid.pub
85
- ec fs chmod +r alice.agentid.pub:/public/report.md --as alice.agentid.pub
86
- ec fs setfacl alice.agentid.pub:/private/report.md -m aid:bob.agentid.pub:r --as alice.agentid.pub
87
- ec fs token issue alice.agentid.pub:/public/report.md --expires 2026-12-31 --as alice.agentid.pub
88
- ec fs find alice.agentid.pub:/private/ --name "*.md" --as alice.agentid.pub
22
+ const HELP = `用法: ec fs <command> [args...] [options]
23
+
24
+ Commands:
25
+ ls <AID>:<path> 列目录
26
+ stat [-L] <AID>:<path> 查看节点元数据(默认不跟随软链;-L 跟随)
27
+ lstat <AID>:<path> 查看节点本身(不跟随末级软链)
28
+ cat <AID>:<path> 输出文本文件内容;二进制/大文件返回头部摘要
29
+ cp <local> <AID>:<path> 上传本地文件
30
+ cp <AID>:<path> <local> 下载远程文件
31
+ cp <AID>:<path> <AID>:<path> 远程复制(同后端)
32
+ mv <AID>:<path> <AID>:<path> 移动/改名(同后端)
33
+ rm [-r] <AID>:<path> 删除文件或目录
34
+ mkdir [-p] <AID>:<path> 创建目录
35
+ ln -s <target> <AID>:<path> 创建软链(personal storage)
36
+ chmod [mode] <AID>:<path> 切换公开/私有(personal storage)
37
+ setfacl <AID>:<path> -m|-x ... 设置/移除 ACL(群路径使用 role:member|role:admin)
38
+ getfacl <AID>:<path> 查看 ACL
39
+ token issue|revoke|ls <path> 管理访问 token(personal storage)
40
+ find <AID>:<path> [filters] 查找节点
41
+ df <AID>: 查看容量/配额
42
+ mount <target> --volume <id> 挂载实体卷
43
+ mount <target> --source <src> 挂载远程子树
44
+ approve <AID>:<path> 批准待审挂载(personal storage)
45
+ reject <AID>:<path> 拒绝待审挂载(personal storage)
46
+ umount <AID>:<path> 卸载挂载点
47
+
48
+ Options:
49
+ --as <aid> 操作者 AID;也可由 EVOLCORE_SELF_AID 注入
50
+ --format json 输出 JSON
51
+ --overwrite, --force 覆盖目标(用于 cp/mv/ln)或强制删除(用于 rm)
52
+ -r, --recursive 递归(用于 rm/cp)
53
+ -p, --parents 自动创建父目录(用于 mkdir/group 上传)
54
+ -L, --follow stat 跟随末级软链
55
+ --token <token> 读取时携带访问 token(personal storage)
56
+ --content-type <mime> 上传时指定内容类型
57
+ --public 上传后公开可读(personal storage)
58
+ --visibility <public|private> chmod 可见性
59
+ --allow-roles <roles> chmod 角色约束,逗号分隔
60
+ -m aid:<aid>:<perms> setfacl 新增/更新 ACL
61
+ -x aid:<aid> setfacl 移除 ACL
62
+ --source <AID>:<path> mount 虚拟卷来源
63
+ --volume <id> mount 实体卷 ID
64
+ --require-approval mount 需要来源 owner 审批
65
+ --expires <time> mount/token/ACL 过期时间,Unix 秒或 ISO 日期
66
+ --max-uses <n> ACL 最大使用次数
67
+ --max-reads <n> token 最大读取次数
68
+ --readonly, --readwrite mount 只读/读写
69
+ --name <glob> find 名称过滤
70
+ --type <f|d|l> find 类型过滤
71
+ --size <expr> find 大小过滤,如 +1M
72
+ --mtime <expr> find 修改时间过滤
73
+ --head-bytes <n> cat 二进制头部字节数,默认 256
74
+ --max-bytes <n> cat 最大直接输出字节数,默认 1048576
75
+ --aun-path <path> 指定 AUN keystore 根
76
+ --app <name> 指定 AUN app slot
77
+
78
+ 示例:
79
+ ec fs ls alice.agentid.pub:/private/
80
+ ec fs cp ./report.md alice.agentid.pub:/private/report.md --as alice.agentid.pub
81
+ ec fs cp alice.agentid.pub:/private/report.md ./report.md --as alice.agentid.pub
82
+ ec fs cp alice.agentid.pub:/private/a.md bob.agentid.pub:/inbox/a.md --as alice.agentid.pub
83
+ ec fs cat alice.agentid.pub:/private/report.md --as alice.agentid.pub
84
+ ec fs ln -s alice.agentid.pub:/private/report.md alice.agentid.pub:/public/report.md --as alice.agentid.pub
85
+ ec fs chmod +r alice.agentid.pub:/public/report.md --as alice.agentid.pub
86
+ ec fs setfacl alice.agentid.pub:/private/report.md -m aid:bob.agentid.pub:r --as alice.agentid.pub
87
+ ec fs token issue alice.agentid.pub:/public/report.md --expires 2026-12-31 --as alice.agentid.pub
88
+ ec fs find alice.agentid.pub:/private/ --name "*.md" --as alice.agentid.pub
89
89
  ec fs df alice.agentid.pub: --as alice.agentid.pub`;
90
90
  const VALUE_FLAGS = new Set([
91
91
  '--as',
@@ -209,7 +209,7 @@ export async function cmdFs(args) {
209
209
  }
210
210
  async function runManagedFs(args, formatJson) {
211
211
  const sessionId = process.env.EVOLCORE_SESSION_ID;
212
- const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
212
+ const delegationToken = readDelegationCredential();
213
213
  const fail = (code, message) => {
214
214
  if (formatJson)
215
215
  console.log(JSON.stringify({ ok: false, code, error: message }));