evolcore 0.0.4 → 0.0.6
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 +65 -3
- 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 +127 -21
- package/dist/cli/data-command.js +132 -0
- package/dist/cli/index.js +11 -3
- package/dist/cli/init.js +116 -37
- package/dist/cli/net-check.js +9 -20
- package/dist/cli/restart-monitor.js +11 -2
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg.js +12 -25
- package/dist/config/access-policy-domain.js +0 -20
- package/dist/config/access-policy.js +5 -29
- 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/auth/operation-catalog.js +1 -1
- package/dist/core/command/command-handler.js +2 -2
- package/dist/core/command/connect-menu.js +20 -42
- package/dist/core/command/menu-handler.js +11 -9
- package/dist/core/command/role-menu.js +27 -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/inbound-admission.js +23 -13
- 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 +300 -61
- package/dist/core/session/session-manager.js +225 -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 +10 -9
- 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/cross-platform.js +8 -2
- package/dist/utils/error-utils.js +9 -0
- package/dist/utils/process-introspect.js +19 -3
- 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/docs/evolcore/config.md +4 -4
- package/kits/docs/evolcore/contact.md +2 -1
- package/kits/schemas/_meta.json +7 -4
- package/kits/schemas/agent-config.schema.10.json +370 -0
- package/kits/schemas/agent-config.schema.9.json +2 -12
- 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,7 +28,24 @@ 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);
|
|
33
|
+
function printNoSelfAgentHints(options) {
|
|
34
|
+
const { daemonConfig, ecwebStarted, skipped } = options;
|
|
35
|
+
console.log('\nℹ 未配置任何 self-agent,Control Plane 已启动。');
|
|
36
|
+
console.log(' 命令行:ec agent new <aid>.agentid.pub');
|
|
37
|
+
if (daemonConfig.aid && (daemonConfig.owners?.length ?? 0) > 0) {
|
|
38
|
+
console.log(' Evol App:可通过进程级菜单创建 agent');
|
|
39
|
+
}
|
|
40
|
+
if (ecwebStarted) {
|
|
41
|
+
console.log(' ECWeb:可通过控制台创建 agent');
|
|
42
|
+
}
|
|
43
|
+
if (skipped.length > 0) {
|
|
44
|
+
console.log('跳过的目录:');
|
|
45
|
+
for (const skippedAgent of skipped)
|
|
46
|
+
console.log(` - ${skippedAgent.dirName}: ${skippedAgent.reason}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
32
49
|
async function probeDaemon(socketPath, timeoutMs = 1000) {
|
|
33
50
|
const response = await ipcQuery(socketPath, { type: 'ping' }, timeoutMs);
|
|
34
51
|
if (response?.pong !== true || !Number.isInteger(response.pid) || response.pid <= 0)
|
|
@@ -99,6 +116,53 @@ function serviceProxyNeedsEcweb(cfg) {
|
|
|
99
116
|
return false;
|
|
100
117
|
return (cfg.serviceProxy.services ?? []).some(s => s.enabled !== false && s.source === 'ecweb');
|
|
101
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
|
+
}
|
|
102
166
|
// ==================== Commands ====================
|
|
103
167
|
/**
|
|
104
168
|
* 检测并展示跨 HOME 残留的 evolcore 主进程。
|
|
@@ -184,6 +248,8 @@ export async function cmdStart(opts = {}) {
|
|
|
184
248
|
return;
|
|
185
249
|
}
|
|
186
250
|
ensureDataDirs();
|
|
251
|
+
if (!requireFreshSourceBuild())
|
|
252
|
+
return;
|
|
187
253
|
// 旧配置自动迁移(daemon.json → 新结构)
|
|
188
254
|
const { autoMigrateIfNeeded } = await import('../config-store.js');
|
|
189
255
|
autoMigrateIfNeeded();
|
|
@@ -196,8 +262,16 @@ export async function cmdStart(opts = {}) {
|
|
|
196
262
|
}
|
|
197
263
|
else {
|
|
198
264
|
console.log('⚡ 未检测到初始化配置,自动启动初始化向导...\n');
|
|
199
|
-
|
|
200
|
-
|
|
265
|
+
// cmdStart 直接调用 cmdInit,不会经过 CLI 的 `init` 分发分支;
|
|
266
|
+
// 这里需显式抑制 AUN SDK 的常规 keystore 日志。
|
|
267
|
+
const { suppressSdkLogs } = await import('../aun/aid/index.js');
|
|
268
|
+
suppressSdkLogs();
|
|
269
|
+
await cmdInit({ invokedByStart: true });
|
|
270
|
+
if (!loadDefaults()) {
|
|
271
|
+
console.log('⚠ 初始化未完成,未启动 EvolCore。');
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
console.log('\n初始化完成,开始启动 EvolCore ....');
|
|
201
275
|
}
|
|
202
276
|
}
|
|
203
277
|
// 控制 AID 门禁:缺 aid 且交互式 → 只补全控制 AID + owners(不重走 baseagent 向导)。
|
|
@@ -236,20 +310,15 @@ export async function cmdStart(opts = {}) {
|
|
|
236
310
|
}
|
|
237
311
|
// 检查至少有一个 self-agent
|
|
238
312
|
const { agents, skipped } = loadAllAgents();
|
|
313
|
+
const isControlAidBootstrap = opts.bindBootstrap && !!daemonCfgStart.aid;
|
|
314
|
+
const shouldPrintNoSelfAgentHints = agents.length === 0 && !isControlAidBootstrap;
|
|
239
315
|
if (agents.length === 0) {
|
|
240
|
-
if (
|
|
316
|
+
if (isControlAidBootstrap) {
|
|
241
317
|
console.log('ℹ 未配置任何 self-agent,绑定 bootstrap 将仅启动控制 AID');
|
|
242
318
|
}
|
|
243
|
-
else {
|
|
244
|
-
console.log('ℹ 未配置任何 self-agent,将仅启动 Control Plane。');
|
|
245
|
-
console.log(' 可通过控制 AID 远程创建 agent,或稍后运行 ec agent new <aid>.agentid.pub');
|
|
246
|
-
if (skipped.length > 0) {
|
|
247
|
-
console.log(`跳过的目录:`);
|
|
248
|
-
for (const s of skipped)
|
|
249
|
-
console.log(` - ${s.dirName}: ${s.reason}`);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
319
|
}
|
|
320
|
+
if (!requireCompletedDataMigration(p.root))
|
|
321
|
+
return;
|
|
253
322
|
// 检查 instance 目录中的进程状态
|
|
254
323
|
const status = scanInstances();
|
|
255
324
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
@@ -323,10 +392,22 @@ export async function cmdStart(opts = {}) {
|
|
|
323
392
|
console.log(` Logs: ${p.logs}/`);
|
|
324
393
|
console.log(`⏱ ready in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
|
|
325
394
|
if (!ecwebStartedBeforeDaemon) {
|
|
326
|
-
startEcwebIfEnabled(p)
|
|
395
|
+
startEcwebIfEnabled(p)
|
|
396
|
+
.then((ecwebStarted) => {
|
|
397
|
+
if (shouldPrintNoSelfAgentHints) {
|
|
398
|
+
printNoSelfAgentHints({ daemonConfig: loadDaemonConfig(), ecwebStarted, skipped });
|
|
399
|
+
}
|
|
400
|
+
})
|
|
401
|
+
.catch((err) => {
|
|
327
402
|
console.error(`⚠ ECWeb 启动检查失败: ${err instanceof Error ? err.message : String(err)}`);
|
|
403
|
+
if (shouldPrintNoSelfAgentHints) {
|
|
404
|
+
printNoSelfAgentHints({ daemonConfig: loadDaemonConfig(), ecwebStarted: false, skipped });
|
|
405
|
+
}
|
|
328
406
|
});
|
|
329
407
|
}
|
|
408
|
+
else if (shouldPrintNoSelfAgentHints) {
|
|
409
|
+
printNoSelfAgentHints({ daemonConfig: loadDaemonConfig(), ecwebStarted: true, skipped });
|
|
410
|
+
}
|
|
330
411
|
}, 500);
|
|
331
412
|
let forwardingShutdown = false;
|
|
332
413
|
const forwardSignal = (signal) => {
|
|
@@ -426,8 +507,10 @@ export async function cmdStart(opts = {}) {
|
|
|
426
507
|
}
|
|
427
508
|
console.log(`⏱ done in ${((Date.now() - cmdStartedAt) / 1000).toFixed(1)}s`);
|
|
428
509
|
// ECWeb 自动后台启动
|
|
429
|
-
|
|
430
|
-
|
|
510
|
+
const ecwebStarted = ecwebStartedBeforeDaemon || await startEcwebIfEnabled(p);
|
|
511
|
+
if (shouldPrintNoSelfAgentHints) {
|
|
512
|
+
printNoSelfAgentHints({ daemonConfig: loadDaemonConfig(), ecwebStarted, skipped });
|
|
513
|
+
}
|
|
431
514
|
return;
|
|
432
515
|
}
|
|
433
516
|
// 超时
|
|
@@ -514,6 +597,8 @@ export async function cmdRestart(opts = {}) {
|
|
|
514
597
|
}
|
|
515
598
|
if (rejectPidIsolatedLifecycle('restart', initialStatus, ping))
|
|
516
599
|
return;
|
|
600
|
+
if (!requireFreshSourceBuild())
|
|
601
|
+
return;
|
|
517
602
|
// 版本检查与自动升级
|
|
518
603
|
console.log('📦 Checking for updates...');
|
|
519
604
|
const upgrade = await tryUpgrade();
|
|
@@ -557,6 +642,8 @@ export async function cmdRestart(opts = {}) {
|
|
|
557
642
|
console.log(`⚠ ${WEB_PACKAGE_NAME} upgrade failed (${ecwebUpgrade.from} → ${ecwebUpgrade.to})`);
|
|
558
643
|
break;
|
|
559
644
|
}
|
|
645
|
+
if (!requireCompletedDataMigration(resolveRoot()))
|
|
646
|
+
return;
|
|
560
647
|
// 停止所有活 main 进程(可能不止一个)
|
|
561
648
|
const status = scanInstances();
|
|
562
649
|
const aliveMains = status.mains.filter(m => m.alive);
|
|
@@ -813,7 +900,7 @@ export async function cmdStatus() {
|
|
|
813
900
|
// Runtime statistics (read from sessions filesystem)
|
|
814
901
|
if (fs.existsSync(p.sessionsDir)) {
|
|
815
902
|
try {
|
|
816
|
-
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');
|
|
817
904
|
const chatDirs = scanChatDirs(p.sessionsDir);
|
|
818
905
|
const allSessions = [];
|
|
819
906
|
for (const { dirPath } of chatDirs) {
|
|
@@ -832,23 +919,42 @@ export async function cmdStatus() {
|
|
|
832
919
|
}
|
|
833
920
|
// 最近 5 个(按 updatedAt 倒排)
|
|
834
921
|
const recentSessions = [...allSessions].sort((a, b) => b.updatedAt - a.updatedAt).slice(0, 5);
|
|
835
|
-
// 检测 orphan
|
|
922
|
+
// 检测 orphan:按物理 session 路由而非历史 meta 判定。保留的旧
|
|
923
|
+
// 实例副本在唯一的当前实例已存在时属于迁移来源,不应误报。
|
|
836
924
|
let orphanCount = 0;
|
|
837
925
|
try {
|
|
838
926
|
const { agents } = loadAllAgents();
|
|
839
927
|
const configChannelNames = new Set();
|
|
928
|
+
const configuredByAgentType = new Map();
|
|
840
929
|
for (const cfg of agents) {
|
|
841
930
|
// AUN 是从 agent 自身 AID 隐式派生的内建通道,不出现在 cfg.channels 里。
|
|
842
931
|
// 不补这条,所有 aun#<aid>#main 会话都会被误判成 orphan。
|
|
843
932
|
configChannelNames.add(`aun#${cfg.aid}#main`);
|
|
844
933
|
for (const inst of cfg.channels) {
|
|
845
934
|
// effective key: <type>#<selfAID>#<name>
|
|
846
|
-
|
|
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]);
|
|
847
939
|
}
|
|
848
940
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
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++;
|
|
852
958
|
}
|
|
853
959
|
}
|
|
854
960
|
catch { }
|
|
@@ -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));
|