evolcore 0.0.5 → 0.0.7
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 +49 -0
- package/README.md +4 -12
- package/dist/agents/baseagent.js +39 -0
- package/dist/agents/claude-runner.js +10 -2
- package/dist/agents/codex-runner.js +37 -8
- package/dist/agents/ecagent-runner.js +1159 -0
- package/dist/agents/gemini-runner.js +4 -1
- package/dist/agents/runner-types.js +20 -4
- package/dist/aun/msg/history.js +32 -9
- package/dist/aun/outbox.js +4 -9
- package/dist/channels/aun.js +32 -6
- package/dist/channels/daemon.js +7 -4
- package/dist/channels/dingtalk.js +3 -5
- package/dist/channels/feishu.js +16 -108
- package/dist/channels/wechat.js +4 -4
- package/dist/channels/wecom.js +4 -6
- package/dist/cli/agent-command.js +1 -1
- package/dist/cli/agent.js +42 -11
- package/dist/cli/aun-commands.js +50 -3
- package/dist/cli/daemon-commands.js +88 -8
- package/dist/cli/data-command.js +132 -0
- package/dist/cli/index.js +11 -3
- package/dist/cli/init.js +76 -17
- package/dist/cli/net-check.js +9 -20
- package/dist/cli/restart-monitor.js +25 -2
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg.js +12 -25
- package/dist/config/builtin-roles.js +3 -1
- package/dist/config/config-field-policy.js +1 -1
- package/dist/config/gateway-config.js +21 -4
- package/dist/config/resolved-config-op.js +10 -0
- package/dist/core/command/command-handler.js +2 -2
- package/dist/core/command/menu-handler.js +11 -9
- package/dist/core/command/role-menu.js +11 -0
- package/dist/core/command/slash-handler.js +18 -14
- package/dist/core/data-migration.js +1434 -0
- package/dist/core/handoff/store.js +14 -4
- package/dist/core/inference/text-inference.js +42 -1
- package/dist/core/message/pending-hints.js +1 -1
- package/dist/core/message/response-engine.js +406 -167
- package/dist/core/message/retry-scheduler.js +71 -0
- package/dist/core/model/model-catalog.js +7 -2
- package/dist/core/model/model-fallback.js +81 -0
- package/dist/core/protected-paths.js +41 -8
- package/dist/core/session/adapters/ecagent-session-file-adapter.js +112 -0
- package/dist/core/session/session-fs-store.js +283 -59
- package/dist/core/session/session-manager.js +19 -21
- package/dist/core/session/session-title.js +1 -0
- package/dist/core/session/session-turn-coordinator.js +8 -1
- package/dist/core/system-channels.js +1 -0
- package/dist/index.js +13 -10
- package/dist/paths.js +35 -27
- package/dist/trigger/feedback.js +16 -0
- package/dist/trigger/legacy-session-history.js +19 -0
- package/dist/trigger/manager.js +12 -1
- package/dist/trigger/parser.js +4 -2
- package/dist/trigger/scheduler.js +185 -15
- package/dist/trigger/session-lock.js +62 -0
- package/dist/trigger/state.js +64 -0
- package/dist/trigger/validation.js +32 -2
- package/dist/utils/aid-bind.js +1 -1
- package/dist/utils/error-utils.js +9 -0
- package/dist/utils/instance-registry.js +2 -2
- package/dist/utils/welcome.js +2 -3
- package/ecagent/LICENSE +21 -0
- package/ecagent/NOTICE +11 -0
- package/ecagent/README.md +61 -0
- package/ecagent/dist/agent-loop.d.ts +24 -0
- package/ecagent/dist/agent-loop.d.ts.map +1 -0
- package/ecagent/dist/agent-loop.js +547 -0
- package/ecagent/dist/agent-loop.js.map +1 -0
- package/ecagent/dist/agent.d.ts +127 -0
- package/ecagent/dist/agent.d.ts.map +1 -0
- package/ecagent/dist/agent.js +386 -0
- package/ecagent/dist/agent.js.map +1 -0
- package/ecagent/dist/harness/agent-harness.d.ts +95 -0
- package/ecagent/dist/harness/agent-harness.d.ts.map +1 -0
- package/ecagent/dist/harness/agent-harness.js +926 -0
- package/ecagent/dist/harness/agent-harness.js.map +1 -0
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts +51 -0
- package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +1 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js +174 -0
- package/ecagent/dist/harness/compaction/branch-summarization.js.map +1 -0
- package/ecagent/dist/harness/compaction/compaction.d.ts +95 -0
- package/ecagent/dist/harness/compaction/compaction.d.ts.map +1 -0
- package/ecagent/dist/harness/compaction/compaction.js +528 -0
- package/ecagent/dist/harness/compaction/compaction.js.map +1 -0
- package/ecagent/dist/harness/compaction/utils.d.ts +25 -0
- package/ecagent/dist/harness/compaction/utils.d.ts.map +1 -0
- package/ecagent/dist/harness/compaction/utils.js +131 -0
- package/ecagent/dist/harness/compaction/utils.js.map +1 -0
- package/ecagent/dist/harness/env/nodejs.d.ts +51 -0
- package/ecagent/dist/harness/env/nodejs.d.ts.map +1 -0
- package/ecagent/dist/harness/env/nodejs.js +513 -0
- package/ecagent/dist/harness/env/nodejs.js.map +1 -0
- package/ecagent/dist/harness/messages.d.ts +51 -0
- package/ecagent/dist/harness/messages.d.ts.map +1 -0
- package/ecagent/dist/harness/messages.js +102 -0
- package/ecagent/dist/harness/messages.js.map +1 -0
- package/ecagent/dist/harness/prompt-templates.d.ts +48 -0
- package/ecagent/dist/harness/prompt-templates.d.ts.map +1 -0
- package/ecagent/dist/harness/prompt-templates.js +230 -0
- package/ecagent/dist/harness/prompt-templates.js.map +1 -0
- package/ecagent/dist/harness/session/jsonl-repo.d.ts +26 -0
- package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +1 -0
- package/ecagent/dist/harness/session/jsonl-repo.js +100 -0
- package/ecagent/dist/harness/session/jsonl-repo.js.map +1 -0
- package/ecagent/dist/harness/session/jsonl-storage.d.ts +34 -0
- package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +1 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +234 -0
- package/ecagent/dist/harness/session/jsonl-storage.js.map +1 -0
- package/ecagent/dist/harness/session/memory-repo.d.ts +18 -0
- package/ecagent/dist/harness/session/memory-repo.d.ts.map +1 -0
- package/ecagent/dist/harness/session/memory-repo.js +44 -0
- package/ecagent/dist/harness/session/memory-repo.js.map +1 -0
- package/ecagent/dist/harness/session/memory-storage.d.ts +25 -0
- package/ecagent/dist/harness/session/memory-storage.d.ts.map +1 -0
- package/ecagent/dist/harness/session/memory-storage.js +111 -0
- package/ecagent/dist/harness/session/memory-storage.js.map +1 -0
- package/ecagent/dist/harness/session/repo-utils.d.ts +11 -0
- package/ecagent/dist/harness/session/repo-utils.d.ts.map +1 -0
- package/ecagent/dist/harness/session/repo-utils.js +39 -0
- package/ecagent/dist/harness/session/repo-utils.js.map +1 -0
- package/ecagent/dist/harness/session/session.d.ts +47 -0
- package/ecagent/dist/harness/session/session.d.ts.map +1 -0
- package/ecagent/dist/harness/session/session.js +245 -0
- package/ecagent/dist/harness/session/session.js.map +1 -0
- package/ecagent/dist/harness/session/uuid.d.ts +2 -0
- package/ecagent/dist/harness/session/uuid.d.ts.map +1 -0
- package/ecagent/dist/harness/session/uuid.js +50 -0
- package/ecagent/dist/harness/session/uuid.js.map +1 -0
- package/ecagent/dist/harness/skills.d.ts +44 -0
- package/ecagent/dist/harness/skills.d.ts.map +1 -0
- package/ecagent/dist/harness/skills.js +311 -0
- package/ecagent/dist/harness/skills.js.map +1 -0
- package/ecagent/dist/harness/system-prompt.d.ts +3 -0
- package/ecagent/dist/harness/system-prompt.d.ts.map +1 -0
- package/ecagent/dist/harness/system-prompt.js +30 -0
- package/ecagent/dist/harness/system-prompt.js.map +1 -0
- package/ecagent/dist/harness/types.d.ts +619 -0
- package/ecagent/dist/harness/types.d.ts.map +1 -0
- package/ecagent/dist/harness/types.js +81 -0
- package/ecagent/dist/harness/types.js.map +1 -0
- package/ecagent/dist/harness/utils/shell-output.d.ts +14 -0
- package/ecagent/dist/harness/utils/shell-output.d.ts.map +1 -0
- package/ecagent/dist/harness/utils/shell-output.js +126 -0
- package/ecagent/dist/harness/utils/shell-output.js.map +1 -0
- package/ecagent/dist/harness/utils/truncate.d.ts +70 -0
- package/ecagent/dist/harness/utils/truncate.d.ts.map +1 -0
- package/ecagent/dist/harness/utils/truncate.js +290 -0
- package/ecagent/dist/harness/utils/truncate.js.map +1 -0
- package/ecagent/dist/index.d.ts +22 -0
- package/ecagent/dist/index.d.ts.map +1 -0
- package/ecagent/dist/index.js +27 -0
- package/ecagent/dist/index.js.map +1 -0
- package/ecagent/dist/node.d.ts +3 -0
- package/ecagent/dist/node.d.ts.map +1 -0
- package/ecagent/dist/node.js +3 -0
- package/ecagent/dist/node.js.map +1 -0
- package/ecagent/dist/proxy.d.ts +69 -0
- package/ecagent/dist/proxy.d.ts.map +1 -0
- package/ecagent/dist/proxy.js +278 -0
- package/ecagent/dist/proxy.js.map +1 -0
- package/ecagent/dist/runtime/api/lazy.d.ts +15 -0
- package/ecagent/dist/runtime/api/lazy.d.ts.map +1 -0
- package/ecagent/dist/runtime/api/lazy.js +59 -0
- package/ecagent/dist/runtime/api/lazy.js.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.d.ts +97 -0
- package/ecagent/dist/runtime/api/pi-messages.d.ts.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.js +307 -0
- package/ecagent/dist/runtime/api/pi-messages.js.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts +3 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +1 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.js +3 -0
- package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +1 -0
- package/ecagent/dist/runtime/auth/context.d.ts +7 -0
- package/ecagent/dist/runtime/auth/context.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/context.js +42 -0
- package/ecagent/dist/runtime/auth/context.js.map +1 -0
- package/ecagent/dist/runtime/auth/credential-store.d.ts +16 -0
- package/ecagent/dist/runtime/auth/credential-store.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/credential-store.js +39 -0
- package/ecagent/dist/runtime/auth/credential-store.js.map +1 -0
- package/ecagent/dist/runtime/auth/helpers.d.ts +20 -0
- package/ecagent/dist/runtime/auth/helpers.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/helpers.js +46 -0
- package/ecagent/dist/runtime/auth/helpers.js.map +1 -0
- package/ecagent/dist/runtime/auth/resolve.d.ts +26 -0
- package/ecagent/dist/runtime/auth/resolve.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/resolve.js +100 -0
- package/ecagent/dist/runtime/auth/resolve.js.map +1 -0
- package/ecagent/dist/runtime/auth/types.d.ts +180 -0
- package/ecagent/dist/runtime/auth/types.d.ts.map +1 -0
- package/ecagent/dist/runtime/auth/types.js +2 -0
- package/ecagent/dist/runtime/auth/types.js.map +1 -0
- package/ecagent/dist/runtime/compat.d.ts +28 -0
- package/ecagent/dist/runtime/compat.d.ts.map +1 -0
- package/ecagent/dist/runtime/compat.js +86 -0
- package/ecagent/dist/runtime/compat.js.map +1 -0
- package/ecagent/dist/runtime/index.d.ts +20 -0
- package/ecagent/dist/runtime/index.d.ts.map +1 -0
- package/ecagent/dist/runtime/index.js +17 -0
- package/ecagent/dist/runtime/index.js.map +1 -0
- package/ecagent/dist/runtime/models.d.ts +142 -0
- package/ecagent/dist/runtime/models.d.ts.map +1 -0
- package/ecagent/dist/runtime/models.js +245 -0
- package/ecagent/dist/runtime/models.js.map +1 -0
- package/ecagent/dist/runtime/oauth.d.ts +2 -0
- package/ecagent/dist/runtime/oauth.d.ts.map +1 -0
- package/ecagent/dist/runtime/oauth.js +2 -0
- package/ecagent/dist/runtime/oauth.js.map +1 -0
- package/ecagent/dist/runtime/providers/faux.d.ts +97 -0
- package/ecagent/dist/runtime/providers/faux.d.ts.map +1 -0
- package/ecagent/dist/runtime/providers/faux.js +395 -0
- package/ecagent/dist/runtime/providers/faux.js.map +1 -0
- package/ecagent/dist/runtime/types.d.ts +607 -0
- package/ecagent/dist/runtime/types.d.ts.map +1 -0
- package/ecagent/dist/runtime/types.js +2 -0
- package/ecagent/dist/runtime/types.js.map +1 -0
- package/ecagent/dist/runtime/utils/diagnostics.d.ts +19 -0
- package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/diagnostics.js +25 -0
- package/ecagent/dist/runtime/utils/diagnostics.js.map +1 -0
- package/ecagent/dist/runtime/utils/event-stream.d.ts +21 -0
- package/ecagent/dist/runtime/utils/event-stream.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/event-stream.js +77 -0
- package/ecagent/dist/runtime/utils/event-stream.js.map +1 -0
- package/ecagent/dist/runtime/utils/headers.d.ts +4 -0
- package/ecagent/dist/runtime/utils/headers.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/headers.js +18 -0
- package/ecagent/dist/runtime/utils/headers.js.map +1 -0
- package/ecagent/dist/runtime/utils/json-parse.d.ts +16 -0
- package/ecagent/dist/runtime/utils/json-parse.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/json-parse.js +113 -0
- package/ecagent/dist/runtime/utils/json-parse.js.map +1 -0
- package/ecagent/dist/runtime/utils/oauth/types.d.ts +64 -0
- package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/oauth/types.js +2 -0
- package/ecagent/dist/runtime/utils/oauth/types.js.map +1 -0
- package/ecagent/dist/runtime/utils/overflow.d.ts +58 -0
- package/ecagent/dist/runtime/utils/overflow.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/overflow.js +158 -0
- package/ecagent/dist/runtime/utils/overflow.js.map +1 -0
- package/ecagent/dist/runtime/utils/provider-env.d.ts +7 -0
- package/ecagent/dist/runtime/utils/provider-env.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/provider-env.js +44 -0
- package/ecagent/dist/runtime/utils/provider-env.js.map +1 -0
- package/ecagent/dist/runtime/utils/retry.d.ts +12 -0
- package/ecagent/dist/runtime/utils/retry.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/retry.js +90 -0
- package/ecagent/dist/runtime/utils/retry.js.map +1 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts +17 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.js +21 -0
- package/ecagent/dist/runtime/utils/typebox-helpers.js.map +1 -0
- package/ecagent/dist/runtime/utils/validation.d.ts +18 -0
- package/ecagent/dist/runtime/utils/validation.d.ts.map +1 -0
- package/ecagent/dist/runtime/utils/validation.js +269 -0
- package/ecagent/dist/runtime/utils/validation.js.map +1 -0
- package/ecagent/dist/types.d.ts +401 -0
- package/ecagent/dist/types.d.ts.map +1 -0
- package/ecagent/dist/types.js +2 -0
- package/ecagent/dist/types.js.map +1 -0
- package/ecagent/package.json +93 -0
- package/ecagent/src/agent-loop.ts +792 -0
- package/ecagent/src/agent.ts +575 -0
- package/ecagent/src/harness/agent-harness.ts +1029 -0
- package/ecagent/src/harness/compaction/branch-summarization.ts +261 -0
- package/ecagent/src/harness/compaction/compaction.ts +753 -0
- package/ecagent/src/harness/compaction/utils.ts +144 -0
- package/ecagent/src/harness/env/nodejs.ts +569 -0
- package/ecagent/src/harness/messages.ts +164 -0
- package/ecagent/src/harness/prompt-templates.ts +267 -0
- package/ecagent/src/harness/session/jsonl-repo.ts +179 -0
- package/ecagent/src/harness/session/jsonl-storage.ts +314 -0
- package/ecagent/src/harness/session/memory-repo.ts +50 -0
- package/ecagent/src/harness/session/memory-storage.ts +133 -0
- package/ecagent/src/harness/session/repo-utils.ts +51 -0
- package/ecagent/src/harness/session/session.ts +338 -0
- package/ecagent/src/harness/session/uuid.ts +54 -0
- package/ecagent/src/harness/skills.ts +375 -0
- package/ecagent/src/harness/system-prompt.ts +34 -0
- package/ecagent/src/harness/types.ts +838 -0
- package/ecagent/src/harness/utils/shell-output.ts +135 -0
- package/ecagent/src/harness/utils/truncate.ts +344 -0
- package/ecagent/src/index.ts +46 -0
- package/ecagent/src/node.ts +2 -0
- package/ecagent/src/proxy.ts +367 -0
- package/ecagent/src/runtime/api/lazy.ts +70 -0
- package/ecagent/src/runtime/api/pi-messages.lazy.ts +4 -0
- package/ecagent/src/runtime/api/pi-messages.ts +436 -0
- package/ecagent/src/runtime/auth/context.ts +45 -0
- package/ecagent/src/runtime/auth/credential-store.ts +47 -0
- package/ecagent/src/runtime/auth/helpers.ts +46 -0
- package/ecagent/src/runtime/auth/resolve.ts +141 -0
- package/ecagent/src/runtime/auth/types.ts +182 -0
- package/ecagent/src/runtime/compat.ts +158 -0
- package/ecagent/src/runtime/index.ts +31 -0
- package/ecagent/src/runtime/models.ts +452 -0
- package/ecagent/src/runtime/oauth.ts +1 -0
- package/ecagent/src/runtime/providers/faux.ts +538 -0
- package/ecagent/src/runtime/types.ts +718 -0
- package/ecagent/src/runtime/utils/diagnostics.ts +45 -0
- package/ecagent/src/runtime/utils/event-stream.ts +88 -0
- package/ecagent/src/runtime/utils/headers.ts +18 -0
- package/ecagent/src/runtime/utils/json-parse.ts +124 -0
- package/ecagent/src/runtime/utils/oauth/types.ts +79 -0
- package/ecagent/src/runtime/utils/overflow.ts +165 -0
- package/ecagent/src/runtime/utils/provider-env.ts +52 -0
- package/ecagent/src/runtime/utils/retry.ts +101 -0
- package/ecagent/src/runtime/utils/typebox-helpers.ts +24 -0
- package/ecagent/src/runtime/utils/validation.ts +310 -0
- package/ecagent/src/types.ts +430 -0
- package/ecagent/tsconfig.build.json +32 -0
- package/kits/schemas/_meta.json +7 -4
- package/kits/schemas/agent-config.schema.10.json +370 -0
- package/kits/schemas/defaults.schema.4.json +93 -0
- package/kits/schemas/relation-config.schema.8.json +69 -0
- package/kits/templates/roles/admin.json +1 -1
- package/package.json +22 -6
- package/skills/eclink/SKILL.md +70 -0
- package/skills/eclink/agents/openai.yaml +4 -0
- package/assets/.env.template +0 -4
package/dist/cli/agent.js
CHANGED
|
@@ -13,6 +13,7 @@ import { ensureInitialRoleRegistry } from '../config/role-service.js';
|
|
|
13
13
|
import { isValidChannelName } from '../core/channel-loader.js';
|
|
14
14
|
import { commandExists } from '../utils/cross-platform.js';
|
|
15
15
|
import { getCodexAppServerAvailability, isCodexAppServerAvailable } from '../agents/codex-runner.js';
|
|
16
|
+
import { resolveEcagentConfig } from '../agents/baseagent.js';
|
|
16
17
|
import { agentProjectRootFromDefaults, deriveAgentProjectPath } from '../utils/project-path.js';
|
|
17
18
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
18
19
|
function withStaticOwner(config, owner) {
|
|
@@ -25,19 +26,29 @@ function withStaticOwner(config, owner) {
|
|
|
25
26
|
return { ...config, owners: [...owners, value] };
|
|
26
27
|
}
|
|
27
28
|
// ==================== Helpers ====================
|
|
28
|
-
const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
29
|
+
const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini', 'ecagent'];
|
|
30
|
+
const AUTO_BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
29
31
|
function isBaseagentAvailable(baseagent) {
|
|
30
32
|
if (baseagent === 'codex')
|
|
31
33
|
return isCodexAppServerAvailable();
|
|
34
|
+
if (baseagent === 'ecagent')
|
|
35
|
+
return true;
|
|
32
36
|
return commandExists(baseagent);
|
|
33
37
|
}
|
|
34
38
|
function detectAvailableBaseagents() {
|
|
35
39
|
return BASEAGENT_CANDIDATES.filter(isBaseagentAvailable);
|
|
36
40
|
}
|
|
37
41
|
function pickDefaultBaseagent(available) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
return AUTO_BASEAGENT_CANDIDATES.find(candidate => available.includes(candidate)) ?? null;
|
|
43
|
+
}
|
|
44
|
+
function ecagentUnavailableReason() {
|
|
45
|
+
try {
|
|
46
|
+
resolveEcagentConfig({ agents: { ecagent: {} } });
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return error instanceof Error ? error.message : String(error);
|
|
51
|
+
}
|
|
41
52
|
}
|
|
42
53
|
function buildBaseagentsBlock(chosen) {
|
|
43
54
|
return { [chosen]: {} };
|
|
@@ -301,19 +312,24 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
301
312
|
}
|
|
302
313
|
// Baseagent
|
|
303
314
|
const available = detectAvailableBaseagents();
|
|
304
|
-
if (available.length === 0) {
|
|
305
|
-
return { ok: false, error: `No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server.` };
|
|
315
|
+
if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
|
|
316
|
+
return { ok: false, error: `No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.` };
|
|
306
317
|
}
|
|
307
318
|
const defaultBa = pickDefaultBaseagent(available);
|
|
308
319
|
let baseagent;
|
|
309
|
-
if (available.length === 1) {
|
|
320
|
+
if (available.length === 1 && defaultBa) {
|
|
310
321
|
console.log(` Baseagent: ${defaultBa}`);
|
|
311
322
|
baseagent = defaultBa;
|
|
312
323
|
}
|
|
313
324
|
else {
|
|
314
325
|
let chosen = null;
|
|
315
326
|
while (chosen === null) {
|
|
316
|
-
const
|
|
327
|
+
const defaultHint = defaultBa ? ` [${defaultBa}]` : '';
|
|
328
|
+
const input = (await ask(`Baseagent (${available.join('/')})${defaultHint}: `)).trim() || defaultBa;
|
|
329
|
+
if (!input) {
|
|
330
|
+
console.log(' ecagent is optional; enter ecagent to select it explicitly.');
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
317
333
|
if (!BASEAGENT_CANDIDATES.includes(input)) {
|
|
318
334
|
console.log(` Invalid choice. Options: ${BASEAGENT_CANDIDATES.join('/')}`);
|
|
319
335
|
continue;
|
|
@@ -322,6 +338,13 @@ export async function agentCreateInteractive(opts = {}) {
|
|
|
322
338
|
console.log(` ${input} is not available in the current environment. Available: ${available.join('/')}`);
|
|
323
339
|
continue;
|
|
324
340
|
}
|
|
341
|
+
if (input === 'ecagent') {
|
|
342
|
+
const reason = ecagentUnavailableReason();
|
|
343
|
+
if (reason) {
|
|
344
|
+
console.log(` ecagent is unavailable: ${reason}`);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
325
348
|
chosen = input;
|
|
326
349
|
}
|
|
327
350
|
baseagent = chosen;
|
|
@@ -535,8 +558,8 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
535
558
|
}
|
|
536
559
|
// Baseagent
|
|
537
560
|
const available = detectAvailableBaseagents();
|
|
538
|
-
if (available.length === 0) {
|
|
539
|
-
return failValidating(`No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server.`);
|
|
561
|
+
if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
|
|
562
|
+
return failValidating(`No usable baseagent detected. Install claude/gemini CLI or codex CLI with app-server, or configure bundled ecagent.`);
|
|
540
563
|
}
|
|
541
564
|
let baseagent;
|
|
542
565
|
if (opts.baseagent) {
|
|
@@ -549,10 +572,18 @@ export async function agentCreateNonInteractive(opts) {
|
|
|
549
572
|
: undefined;
|
|
550
573
|
return failValidating(reason || `${opts.baseagent} is not available in the current environment (available: ${available.join('/')})`);
|
|
551
574
|
}
|
|
575
|
+
if (opts.baseagent === 'ecagent') {
|
|
576
|
+
const reason = ecagentUnavailableReason();
|
|
577
|
+
if (reason)
|
|
578
|
+
return failValidating(reason);
|
|
579
|
+
}
|
|
552
580
|
baseagent = opts.baseagent;
|
|
553
581
|
}
|
|
554
582
|
else {
|
|
555
|
-
|
|
583
|
+
const defaultBaseagent = pickDefaultBaseagent(available);
|
|
584
|
+
if (!defaultBaseagent)
|
|
585
|
+
return failValidating('ecagent is optional; pass --baseagent ecagent after configuring its API key');
|
|
586
|
+
baseagent = defaultBaseagent;
|
|
556
587
|
}
|
|
557
588
|
if (!path.isAbsolute(opts.project)) {
|
|
558
589
|
return failValidating(`--project must be absolute: ${opts.project}`);
|
package/dist/cli/aun-commands.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { agentMdPath, resolvePaths, resolveRoot } from '../paths.js';
|
|
3
4
|
import { isExplicitGroupId } from '../aun/group-identity.js';
|
|
4
5
|
import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
5
6
|
// ==================== AID ====================
|
|
@@ -814,6 +815,8 @@ Options:
|
|
|
814
815
|
--before <time> 只返回该时间之前的历史
|
|
815
816
|
--after <time> 只返回该时间之后的历史
|
|
816
817
|
--direction <value> 历史方向:in|out|all
|
|
818
|
+
--channel <type> 历史渠道:aun|feishu|wechat|dingtalk|qqbot|wecom
|
|
819
|
+
--channel-name <name> 历史渠道实例名(非 AUN 渠道必须匹配 Agent 配置)
|
|
817
820
|
--return <none|required> 跨会话发送必填:none=仅补充目标上下文,required=回答回流来源
|
|
818
821
|
--content-type <mime> 显式覆盖 MIME(仅 --file 模式)
|
|
819
822
|
--as <type> 附件类型:image|video|voice|file(仅 --file 模式)
|
|
@@ -841,7 +844,7 @@ Options:
|
|
|
841
844
|
if (sub === 'history' && wantsHelp(args)) {
|
|
842
845
|
console.log(`用法: ec msg history <self-aid> <target-aid> [options]
|
|
843
846
|
|
|
844
|
-
|
|
847
|
+
查询指定会话对的本地历史,不调用 message.pull,也不影响收件箱游标。非 AUN 历史仅通过当前 Agent 已配置的渠道实例读取,不能传入文件路径。
|
|
845
848
|
|
|
846
849
|
Options:
|
|
847
850
|
--session <latest|all|id> 默认 latest;all 查询全部;也可指定会话 ID
|
|
@@ -849,12 +852,15 @@ Options:
|
|
|
849
852
|
--before <time> 开区间;epoch 毫秒或 ISO 时间
|
|
850
853
|
--after <time> 开区间;epoch 毫秒或 ISO 时间
|
|
851
854
|
--direction <value> in|out|all(默认 all)
|
|
855
|
+
--channel <type> aun|feishu|wechat|dingtalk|qqbot|wecom(默认 aun)
|
|
856
|
+
--channel-name <name> 渠道实例名;省略时仅允许该类型恰好配置一个实例
|
|
852
857
|
--format <text|json> 输出格式(默认 text)
|
|
853
858
|
|
|
854
859
|
示例:
|
|
855
860
|
ec msg history alice.agentid.pub bob.agentid.pub
|
|
856
861
|
ec msg history alice.agentid.pub bob.agentid.pub --session latest
|
|
857
862
|
ec msg history alice.agentid.pub bob.agentid.pub --session all
|
|
863
|
+
ec msg history alice.agentid.pub oc_xxx --channel feishu --channel-name main --session all --format json
|
|
858
864
|
ec msg history alice.agentid.pub bob.agentid.pub --session meta_20260713_1783920000000 --format json`);
|
|
859
865
|
return;
|
|
860
866
|
}
|
|
@@ -876,7 +882,7 @@ Options:
|
|
|
876
882
|
console.error('用法: ec msg history <self-aid> <target-aid> [options]');
|
|
877
883
|
process.exit(1);
|
|
878
884
|
}
|
|
879
|
-
const historyValueFlags = new Set(['--session', '--limit', '--before', '--after', '--direction', '--format']);
|
|
885
|
+
const historyValueFlags = new Set(['--session', '--limit', '--before', '--after', '--direction', '--channel', '--channel-name', '--format']);
|
|
880
886
|
const seenHistoryFlags = new Set();
|
|
881
887
|
for (let index = 3; index < args.length; index++) {
|
|
882
888
|
const flag = args[index];
|
|
@@ -915,9 +921,25 @@ Options:
|
|
|
915
921
|
console.error(`❌ --after 必须是 epoch 毫秒或有效时间: ${afterRaw}`);
|
|
916
922
|
process.exit(1);
|
|
917
923
|
}
|
|
924
|
+
const channel = getArgValue(args, '--channel') ?? 'aun';
|
|
925
|
+
const channelTypes = new Set(['aun', 'feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom']);
|
|
926
|
+
if (!channelTypes.has(channel)) {
|
|
927
|
+
console.error(`❌ 不支持的 channel: ${channel}`);
|
|
928
|
+
process.exit(1);
|
|
929
|
+
}
|
|
930
|
+
let channelName;
|
|
931
|
+
try {
|
|
932
|
+
channelName = resolveHistoryChannelName(from, channel, getArgValue(args, '--channel-name'));
|
|
933
|
+
}
|
|
934
|
+
catch (error) {
|
|
935
|
+
console.error(`❌ ${error instanceof Error ? error.message : String(error)}`);
|
|
936
|
+
process.exit(1);
|
|
937
|
+
}
|
|
918
938
|
const result = msgHistory({
|
|
919
939
|
from,
|
|
920
940
|
target,
|
|
941
|
+
channel: channel,
|
|
942
|
+
channelName,
|
|
921
943
|
session: getArgValue(args, '--session'),
|
|
922
944
|
limit,
|
|
923
945
|
before,
|
|
@@ -2001,3 +2023,28 @@ function parseMsgHistoryTime(value) {
|
|
|
2001
2023
|
const timestamp = Date.parse(trimmed);
|
|
2002
2024
|
return Number.isFinite(timestamp) ? timestamp : undefined;
|
|
2003
2025
|
}
|
|
2026
|
+
/** Resolve a configured channel instance without exposing Agent session paths. */
|
|
2027
|
+
function resolveHistoryChannelName(agentAid, channel, requested) {
|
|
2028
|
+
if (channel === 'aun' && requested === undefined)
|
|
2029
|
+
return undefined;
|
|
2030
|
+
const configPath = path.join(resolvePaths().root, 'agents', agentAid, 'config.json');
|
|
2031
|
+
let config;
|
|
2032
|
+
try {
|
|
2033
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
2034
|
+
}
|
|
2035
|
+
catch {
|
|
2036
|
+
throw new Error(`无法读取 Agent 渠道配置: ${agentAid}`);
|
|
2037
|
+
}
|
|
2038
|
+
const instances = (Array.isArray(config?.channels) ? config.channels : [])
|
|
2039
|
+
.filter((item) => item && item.type === channel && item.enabled !== false && typeof item.name === 'string');
|
|
2040
|
+
if (requested !== undefined) {
|
|
2041
|
+
if (!instances.some((item) => item.name === requested)) {
|
|
2042
|
+
throw new Error(`Agent 未配置 ${channel} 渠道实例: ${requested}`);
|
|
2043
|
+
}
|
|
2044
|
+
return requested;
|
|
2045
|
+
}
|
|
2046
|
+
if (instances.length !== 1) {
|
|
2047
|
+
throw new Error(`${channel} 渠道实例不唯一,请指定 --channel-name`);
|
|
2048
|
+
}
|
|
2049
|
+
return instances[0].name;
|
|
2050
|
+
}
|
|
@@ -28,6 +28,7 @@ import { getProcessStartTime } from '../utils/process-introspect.js';
|
|
|
28
28
|
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
29
29
|
import { WEB_CLI_BIN, WEB_PACKAGE_LATEST, WEB_PACKAGE_NAME } from '../product.js';
|
|
30
30
|
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
31
|
+
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
31
32
|
const execFileAsync = promisify(execFile);
|
|
32
33
|
function printNoSelfAgentHints(options) {
|
|
33
34
|
const { daemonConfig, ecwebStarted, skipped } = options;
|
|
@@ -110,11 +111,58 @@ function buildDaemonEnv(p, opts) {
|
|
|
110
111
|
...(opts.bindBootstrap ? { EVOLCORE_BIND_BOOTSTRAP: '1' } : {}),
|
|
111
112
|
};
|
|
112
113
|
}
|
|
113
|
-
function serviceProxyNeedsEcweb(cfg) {
|
|
114
|
+
export function serviceProxyNeedsEcweb(cfg) {
|
|
114
115
|
if (!cfg.serviceProxy?.enabled)
|
|
115
116
|
return false;
|
|
116
117
|
return (cfg.serviceProxy.services ?? []).some(s => s.enabled !== false && s.source === 'ecweb');
|
|
117
118
|
}
|
|
119
|
+
function latestSourceMtime(dir) {
|
|
120
|
+
let latest = 0;
|
|
121
|
+
try {
|
|
122
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
123
|
+
const filePath = path.join(dir, entry.name);
|
|
124
|
+
if (entry.isDirectory()) {
|
|
125
|
+
latest = Math.max(latest, latestSourceMtime(filePath));
|
|
126
|
+
}
|
|
127
|
+
else if (entry.isFile()) {
|
|
128
|
+
latest = Math.max(latest, fs.statSync(filePath).mtimeMs);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch { }
|
|
133
|
+
return latest;
|
|
134
|
+
}
|
|
135
|
+
function sourceBuildNeedsRefresh() {
|
|
136
|
+
const packageRoot = getPackageRoot();
|
|
137
|
+
const sourceCli = path.join(packageRoot, 'src', 'cli', 'index.ts');
|
|
138
|
+
if (!fs.existsSync(sourceCli))
|
|
139
|
+
return false;
|
|
140
|
+
const daemonEntry = path.join(packageRoot, 'dist', 'index.js');
|
|
141
|
+
if (!fs.existsSync(daemonEntry))
|
|
142
|
+
return true;
|
|
143
|
+
const sourceMtime = Math.max(latestSourceMtime(path.join(packageRoot, 'src')), latestSourceMtime(path.join(packageRoot, 'ecagent', 'src')));
|
|
144
|
+
return sourceMtime > fs.statSync(daemonEntry).mtimeMs;
|
|
145
|
+
}
|
|
146
|
+
function requireFreshSourceBuild() {
|
|
147
|
+
if (!sourceBuildNeedsRefresh())
|
|
148
|
+
return true;
|
|
149
|
+
console.error('❌ 源码比 daemon 编译产物更新,服务未启动。');
|
|
150
|
+
console.error(' 请先执行: ec stop && npm run build');
|
|
151
|
+
console.error(' 然后执行: ec start');
|
|
152
|
+
process.exitCode = 2;
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
function requireCompletedDataMigration(root) {
|
|
156
|
+
const requirement = inspectDataMigrationRequirement(root);
|
|
157
|
+
if (!requirement.required)
|
|
158
|
+
return true;
|
|
159
|
+
console.error(`❌ 检测到 ${requirement.operationCount} 项待确认的用户数据迁移,服务未启动。`);
|
|
160
|
+
console.error(' 先执行: ec data migrate --dry-run');
|
|
161
|
+
console.error(' 确认后: ec data migrate --apply');
|
|
162
|
+
console.error(' 迁移成功并校验后,再执行 ec start 或 ec restart。');
|
|
163
|
+
process.exitCode = 2;
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
118
166
|
// ==================== Commands ====================
|
|
119
167
|
/**
|
|
120
168
|
* 检测并展示跨 HOME 残留的 evolcore 主进程。
|
|
@@ -200,6 +248,8 @@ export async function cmdStart(opts = {}) {
|
|
|
200
248
|
return;
|
|
201
249
|
}
|
|
202
250
|
ensureDataDirs();
|
|
251
|
+
if (!requireFreshSourceBuild())
|
|
252
|
+
return;
|
|
203
253
|
// 旧配置自动迁移(daemon.json → 新结构)
|
|
204
254
|
const { autoMigrateIfNeeded } = await import('../config-store.js');
|
|
205
255
|
autoMigrateIfNeeded();
|
|
@@ -267,6 +317,8 @@ export async function cmdStart(opts = {}) {
|
|
|
267
317
|
console.log('ℹ 未配置任何 self-agent,绑定 bootstrap 将仅启动控制 AID');
|
|
268
318
|
}
|
|
269
319
|
}
|
|
320
|
+
if (!requireCompletedDataMigration(p.root))
|
|
321
|
+
return;
|
|
270
322
|
// 检查 instance 目录中的进程状态
|
|
271
323
|
const status = scanInstances();
|
|
272
324
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
@@ -545,6 +597,8 @@ export async function cmdRestart(opts = {}) {
|
|
|
545
597
|
}
|
|
546
598
|
if (rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
547
599
|
return;
|
|
600
|
+
if (!requireFreshSourceBuild())
|
|
601
|
+
return;
|
|
548
602
|
// 版本检查与自动升级
|
|
549
603
|
console.log('📦 Checking for updates...');
|
|
550
604
|
const upgrade = await tryUpgrade();
|
|
@@ -588,6 +642,8 @@ export async function cmdRestart(opts = {}) {
|
|
|
588
642
|
console.log(`⚠ ${WEB_PACKAGE_NAME} upgrade failed (${ecwebUpgrade.from} → ${ecwebUpgrade.to})`);
|
|
589
643
|
break;
|
|
590
644
|
}
|
|
645
|
+
if (!requireCompletedDataMigration(resolveRoot()))
|
|
646
|
+
return;
|
|
591
647
|
// 停止所有活 main 进程(可能不止一个)
|
|
592
648
|
const status = scanInstances();
|
|
593
649
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
@@ -844,7 +900,7 @@ export async function cmdStatus() {
|
|
|
844
900
|
// Runtime statistics (read from sessions filesystem)
|
|
845
901
|
if (fs.existsSync(p.sessionsDir)) {
|
|
846
902
|
try {
|
|
847
|
-
const { scanChatDirs, scanMetaFiles, readJsonFile, readLastJsonlLine } = await import('../core/session/session-fs-store.js');
|
|
903
|
+
const { chatDirPath, scanChatDirs, scanMetaFiles, readJsonFile, readLastJsonlLine } = await import('../core/session/session-fs-store.js');
|
|
848
904
|
const chatDirs = scanChatDirs(p.sessionsDir);
|
|
849
905
|
const allSessions = [];
|
|
850
906
|
for (const { dirPath } of chatDirs) {
|
|
@@ -863,23 +919,42 @@ export async function cmdStatus() {
|
|
|
863
919
|
}
|
|
864
920
|
// 最近 5 个(按 updatedAt 倒排)
|
|
865
921
|
const recentSessions = [...allSessions].sort((a, b) => b.updatedAt - a.updatedAt).slice(0, 5);
|
|
866
|
-
// 检测 orphan
|
|
922
|
+
// 检测 orphan:按物理 session 路由而非历史 meta 判定。保留的旧
|
|
923
|
+
// 实例副本在唯一的当前实例已存在时属于迁移来源,不应误报。
|
|
867
924
|
let orphanCount = 0;
|
|
868
925
|
try {
|
|
869
926
|
const { agents } = loadAllAgents();
|
|
870
927
|
const configChannelNames = new Set();
|
|
928
|
+
const configuredByAgentType = new Map();
|
|
871
929
|
for (const cfg of agents) {
|
|
872
930
|
// AUN 是从 agent 自身 AID 隐式派生的内建通道,不出现在 cfg.channels 里。
|
|
873
931
|
// 不补这条,所有 aun#<aid>#main 会话都会被误判成 orphan。
|
|
874
932
|
configChannelNames.add(`aun#${cfg.aid}#main`);
|
|
875
933
|
for (const inst of cfg.channels) {
|
|
876
934
|
// effective key: <type>#<selfAID>#<name>
|
|
877
|
-
|
|
935
|
+
const channelKey = `${inst.type}#${cfg.aid}#${inst.name}`;
|
|
936
|
+
configChannelNames.add(channelKey);
|
|
937
|
+
const identity = `${inst.type}\0${cfg.aid}`;
|
|
938
|
+
configuredByAgentType.set(identity, [...(configuredByAgentType.get(identity) ?? []), channelKey]);
|
|
878
939
|
}
|
|
879
940
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
941
|
+
// The daemon control identity owns AUN transcripts but deliberately
|
|
942
|
+
// has no Agent config, so include it explicitly in route validity.
|
|
943
|
+
const daemonConfig = readJsonFile(p.daemonConfig);
|
|
944
|
+
if (daemonConfig?.aid)
|
|
945
|
+
configChannelNames.add(`aun#${daemonConfig.aid}#main`);
|
|
946
|
+
for (const chat of chatDirs) {
|
|
947
|
+
const channelKey = chat.channelKey;
|
|
948
|
+
if (!channelKey || configChannelNames.has(channelKey) || isNonAgentSessionChannel(channelKey))
|
|
949
|
+
continue;
|
|
950
|
+
const [type, aid] = channelKey.split('#');
|
|
951
|
+
const candidates = type && aid ? configuredByAgentType.get(`${type}\0${aid}`) : undefined;
|
|
952
|
+
if (candidates?.length === 1) {
|
|
953
|
+
const canonical = chatDirPath(p.sessionsDir, type, chat.channelId, type === 'aun' ? aid : undefined, candidates[0]);
|
|
954
|
+
if (canonical !== chat.dirPath && fs.existsSync(canonical))
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
957
|
+
orphanCount++;
|
|
883
958
|
}
|
|
884
959
|
}
|
|
885
960
|
catch { }
|
|
@@ -2455,7 +2530,12 @@ function ensureServiceProxyConfig(cfg, port) {
|
|
|
2455
2530
|
console.log(` 自动配置 Service Proxy: https://${cfg.aid}/proxy/ecweb/`);
|
|
2456
2531
|
}
|
|
2457
2532
|
}
|
|
2458
|
-
|
|
2533
|
+
/**
|
|
2534
|
+
* Start the separately installed `ec-web` process for a configured runtime.
|
|
2535
|
+
* Kept public for restart-monitor, which launches the daemon directly and
|
|
2536
|
+
* therefore cannot rely on cmdStart's post-ready ECWeb startup path.
|
|
2537
|
+
*/
|
|
2538
|
+
export async function startEcwebIfEnabled(p) {
|
|
2459
2539
|
const cfg = loadDaemonConfig();
|
|
2460
2540
|
if (!cfg.ecweb?.enabled)
|
|
2461
2541
|
return false;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { resolvePaths, resolveRoot } from '../paths.js';
|
|
4
|
+
import { applyDataMigration, planDataMigration, readDataMigration, verifyDataMigration } from '../core/data-migration.js';
|
|
5
|
+
import { scanInstances } from '../utils/instance-registry.js';
|
|
6
|
+
import { isProcessRunning, killProcess } from '../utils/cross-platform.js';
|
|
7
|
+
import { ipcQuery } from '../ipc.js';
|
|
8
|
+
import { cmdStart, cmdStop } from './daemon-commands.js';
|
|
9
|
+
function printSummary(manifest) {
|
|
10
|
+
const counts = manifest.operations.reduce((result, operation) => {
|
|
11
|
+
result[operation.status] = (result[operation.status] ?? 0) + 1;
|
|
12
|
+
return result;
|
|
13
|
+
}, {});
|
|
14
|
+
console.log(`migration: ${manifest.id}`);
|
|
15
|
+
console.log(`state: ${manifest.state}`);
|
|
16
|
+
console.log(`operations: ${manifest.operations.length}`);
|
|
17
|
+
console.log(`status: ${Object.entries(counts).map(([key, value]) => `${key}=${value}`).join(', ') || 'none'}`);
|
|
18
|
+
if (manifest.warnings.length) {
|
|
19
|
+
console.log('warnings:');
|
|
20
|
+
for (const warning of manifest.warnings)
|
|
21
|
+
console.log(` - ${warning}`);
|
|
22
|
+
console.log('note: 上述数据无法唯一归属,因此被原样保留;本次不会迁移、修改或删除它们。');
|
|
23
|
+
console.log('next: 可继续迁移已计划项;如需迁移这些保留项,请补齐所属 Agent/通道或匹配的 Trigger 定义后重新执行 --dry-run。');
|
|
24
|
+
}
|
|
25
|
+
const failed = manifest.operations.filter(operation => operation.status === 'error');
|
|
26
|
+
if (failed.length) {
|
|
27
|
+
console.log('errors:');
|
|
28
|
+
for (const operation of failed)
|
|
29
|
+
console.log(` - ${operation.id}: ${operation.error}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function latestMigrationId(root) {
|
|
33
|
+
const dir = path.join(root, 'data', 'daemon', 'migrations');
|
|
34
|
+
const candidates = fs.readdirSync(dir, { withFileTypes: true })
|
|
35
|
+
.filter(entry => entry.isFile() && entry.name.endsWith('.json'))
|
|
36
|
+
.map(entry => ({ name: entry.name.slice(0, -'.json'.length), mtime: fs.statSync(path.join(dir, entry.name)).mtimeMs }))
|
|
37
|
+
.sort((left, right) => right.mtime - left.mtime);
|
|
38
|
+
if (!candidates[0])
|
|
39
|
+
throw new Error('no migration manifest found');
|
|
40
|
+
return candidates[0].name;
|
|
41
|
+
}
|
|
42
|
+
async function daemonIpcReachable() {
|
|
43
|
+
const response = await ipcQuery(resolvePaths().socket, { type: 'ping' }, 1_000);
|
|
44
|
+
return response?.pong === true;
|
|
45
|
+
}
|
|
46
|
+
function liveRuntime() {
|
|
47
|
+
const status = scanInstances();
|
|
48
|
+
return {
|
|
49
|
+
mainCount: status.mains.filter(instance => instance.alive).length,
|
|
50
|
+
monitorPids: status.restartMonitors
|
|
51
|
+
.filter(instance => instance.alive)
|
|
52
|
+
.map(instance => instance.record.pid),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function delay(ms) {
|
|
56
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
57
|
+
}
|
|
58
|
+
async function stopRestartMonitors(pids) {
|
|
59
|
+
for (const pid of pids)
|
|
60
|
+
killProcess(pid);
|
|
61
|
+
for (let attempt = 0; attempt < 8 && pids.some(isProcessRunning); attempt++)
|
|
62
|
+
await delay(250);
|
|
63
|
+
for (const pid of pids)
|
|
64
|
+
if (isProcessRunning(pid))
|
|
65
|
+
killProcess(pid, true);
|
|
66
|
+
}
|
|
67
|
+
async function waitForMaintenanceWindow() {
|
|
68
|
+
for (let attempt = 0; attempt < 12; attempt++) {
|
|
69
|
+
const runtime = liveRuntime();
|
|
70
|
+
if (runtime.mainCount === 0 && runtime.monitorPids.length === 0 && !await daemonIpcReachable())
|
|
71
|
+
return;
|
|
72
|
+
await delay(250);
|
|
73
|
+
}
|
|
74
|
+
const runtime = liveRuntime();
|
|
75
|
+
const ipc = await daemonIpcReachable();
|
|
76
|
+
throw new Error(`cannot begin migration while runtime remains active (main=${runtime.mainCount}, restart-monitor=${runtime.monitorPids.length}, ipc=${ipc})`);
|
|
77
|
+
}
|
|
78
|
+
export async function cmdData(args) {
|
|
79
|
+
if (args[0] !== 'migrate' || args.includes('--help')) {
|
|
80
|
+
console.log('用法: ec data migrate --dry-run | --apply | --resume <migration-id> | --verify [migration-id]');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const root = resolveRoot();
|
|
84
|
+
if (args.includes('--dry-run')) {
|
|
85
|
+
printSummary(planDataMigration(root));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const resumeIndex = args.indexOf('--resume');
|
|
89
|
+
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
|
+
if (verify) {
|
|
94
|
+
// A completed migration's destination becomes live runtime data. Operator
|
|
95
|
+
// verification therefore validates source integrity and target structure
|
|
96
|
+
// without treating normal post-migration writes as a migration conflict.
|
|
97
|
+
const manifest = verifyDataMigration(readDataMigration(root, requestedId ?? latestMigrationId(root)), { strictTargetContent: false });
|
|
98
|
+
printSummary(manifest);
|
|
99
|
+
if (manifest.state === 'completed_with_errors')
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
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
|
+
}
|
|
132
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -53,6 +53,7 @@ AUN:
|
|
|
53
53
|
mv 迁移项目目录和会话路径
|
|
54
54
|
|
|
55
55
|
维护命令:
|
|
56
|
+
data migrate 迁移 per-Agent 用户数据(显式维护窗口)
|
|
56
57
|
mode 切换开发源码与 npm 包运行模式
|
|
57
58
|
restart-monitor 运行 daemon 重启监控器
|
|
58
59
|
bench AUN 消息性能基准测试
|
|
@@ -103,13 +104,13 @@ export async function main(args) {
|
|
|
103
104
|
仅初始化 defaults.json:
|
|
104
105
|
ec init 交互式(写完 defaults.json 后嵌套 agent new)
|
|
105
106
|
ec init --non-interactive [选项]
|
|
106
|
-
--baseagent <claude|codex|gemini> 默认: PATH
|
|
107
|
+
--baseagent <claude|codex|gemini|ecagent> 默认: PATH 中第一个可用项;ecagent 需显式选择
|
|
107
108
|
--force 已存在 defaults.json 时覆盖
|
|
108
109
|
|
|
109
110
|
云部署非交互式初始化(结构化 JSON 输出):
|
|
110
111
|
ec init --non-interactive --owner <aid> [--format json] [选项]
|
|
111
112
|
--owner <aid> 必填。唯一 daemon owner AID
|
|
112
|
-
--baseagent <claude|codex|gemini> 可选。默认从 PATH
|
|
113
|
+
--baseagent <claude|codex|gemini|ecagent> 可选。默认从 PATH 检测,ecagent 需显式选择
|
|
113
114
|
--projectpath <abs-path> 可选。默认项目目录(必须绝对路径,自动创建)
|
|
114
115
|
--ecweb 可选。安装 EC Web 并启用自启动
|
|
115
116
|
--format json 可选但推荐。stdout 输出 init.result JSON
|
|
@@ -161,7 +162,7 @@ export async function main(args) {
|
|
|
161
162
|
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
162
163
|
suppressSdkLogs();
|
|
163
164
|
const nonInteractive = args.includes('--non-interactive');
|
|
164
|
-
await cmdInit({
|
|
165
|
+
const initialized = await cmdInit({
|
|
165
166
|
nonInteractive,
|
|
166
167
|
baseagent: getArgValue(args, '--baseagent'),
|
|
167
168
|
force: args.includes('--force'),
|
|
@@ -170,6 +171,8 @@ export async function main(args) {
|
|
|
170
171
|
ecweb: args.includes('--ecweb'),
|
|
171
172
|
format: getArgValue(args, '--format'),
|
|
172
173
|
});
|
|
174
|
+
if (!initialized)
|
|
175
|
+
process.exitCode = 1;
|
|
173
176
|
}
|
|
174
177
|
break;
|
|
175
178
|
case 'start':
|
|
@@ -253,6 +256,11 @@ export async function main(args) {
|
|
|
253
256
|
}
|
|
254
257
|
await cmdDiagnose();
|
|
255
258
|
break;
|
|
259
|
+
case 'data': {
|
|
260
|
+
const { cmdData } = await import('./data-command.js');
|
|
261
|
+
await cmdData(args.slice(1));
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
256
264
|
case 'net': {
|
|
257
265
|
const { cmdNet } = await import('./net-check.js');
|
|
258
266
|
await cmdNet(args.slice(1));
|