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/init.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import readline from 'readline';
|
|
4
5
|
import { resolvePaths, ensureDataDirs } from '../paths.js';
|
|
@@ -7,28 +8,54 @@ import { scanInstances } from '../utils/instance-registry.js';
|
|
|
7
8
|
import { saveDefaultsSafe, loadAllAgents, loadDaemonConfig, saveDaemonConfig } from '../config-store.js';
|
|
8
9
|
import { generateControlAid, resolveControlIssuer } from '../aun/aid/control-aid.js';
|
|
9
10
|
import { getCodexAppServerAvailability, isCodexAppServerAvailable } from '../agents/codex-runner.js';
|
|
11
|
+
import { resolveEcagentConfig } from '../agents/baseagent.js';
|
|
10
12
|
import { defaultProjectsRoot } from '../utils/project-path.js';
|
|
11
13
|
import { WEB_CLI_BIN, WEB_PACKAGE_LATEST } from '../product.js';
|
|
12
14
|
// ==================== Helpers ====================
|
|
13
15
|
function ask(rl, question) {
|
|
14
16
|
return new Promise(resolve => rl.question(question, resolve));
|
|
15
17
|
}
|
|
16
|
-
|
|
18
|
+
/** 展开用户在交互式输入中使用的 home 目录简写(shell 不会替 readline 自动做这件事)。 */
|
|
19
|
+
export function expandLeadingTildePath(value, homeDir = os.homedir()) {
|
|
20
|
+
if (value === '~')
|
|
21
|
+
return homeDir;
|
|
22
|
+
if (value.startsWith('~/') || value.startsWith('~\\')) {
|
|
23
|
+
return path.join(homeDir, value.slice(2));
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
}
|
|
27
|
+
const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini', 'ecagent'];
|
|
28
|
+
const AUTO_BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
17
29
|
function isBaseagentAvailable(baseagent) {
|
|
18
30
|
if (baseagent === 'codex')
|
|
19
31
|
return isCodexAppServerAvailable();
|
|
32
|
+
if (baseagent === 'ecagent')
|
|
33
|
+
return true;
|
|
20
34
|
return commandExists(baseagent);
|
|
21
35
|
}
|
|
22
36
|
function detectAvailable() {
|
|
23
37
|
return BASEAGENT_CANDIDATES.filter(isBaseagentAvailable);
|
|
24
38
|
}
|
|
25
39
|
function pickDefault(available) {
|
|
26
|
-
return (available.includes(
|
|
40
|
+
return AUTO_BASEAGENT_CANDIDATES.find(candidate => available.includes(candidate));
|
|
41
|
+
}
|
|
42
|
+
function ecagentUnavailableReason() {
|
|
43
|
+
try {
|
|
44
|
+
resolveEcagentConfig({ agents: { ecagent: {} } });
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
return error instanceof Error ? error.message : String(error);
|
|
49
|
+
}
|
|
27
50
|
}
|
|
28
51
|
function buildDefaults(chosen, available, projectsDefaultPath) {
|
|
29
52
|
const baseagents = {};
|
|
30
|
-
for (const b of available)
|
|
53
|
+
for (const b of available) {
|
|
54
|
+
// ecagent is bundled but opt-in; do not declare it merely because it is available.
|
|
55
|
+
if (b === 'ecagent' && chosen !== 'ecagent')
|
|
56
|
+
continue;
|
|
31
57
|
baseagents[b] = {};
|
|
58
|
+
}
|
|
32
59
|
return {
|
|
33
60
|
$schema_version: 1,
|
|
34
61
|
active_baseagent: chosen,
|
|
@@ -94,7 +121,7 @@ export async function cmdInit(options) {
|
|
|
94
121
|
// 云部署非交互式路径:当带 --owner 或 --format json 时走结构化分支,与交互式 tail 完全隔离。
|
|
95
122
|
// 预留方案 B:当 daemon 支持 Control Plane 无 agent 启动时,可在此分支跳过 agent new 预创建。
|
|
96
123
|
if (options?.nonInteractive && (options.owner || options.format === 'json' || options.projectpath || options.ecweb)) {
|
|
97
|
-
|
|
124
|
+
await cmdInitNonInteractive({
|
|
98
125
|
owner: options.owner,
|
|
99
126
|
baseagent: options.baseagent,
|
|
100
127
|
projectpath: options.projectpath,
|
|
@@ -102,6 +129,7 @@ export async function cmdInit(options) {
|
|
|
102
129
|
force: options.force,
|
|
103
130
|
format: options.format,
|
|
104
131
|
});
|
|
132
|
+
return true;
|
|
105
133
|
}
|
|
106
134
|
const p = resolvePaths();
|
|
107
135
|
ensureDataDirs();
|
|
@@ -110,17 +138,17 @@ export async function cmdInit(options) {
|
|
|
110
138
|
if (aliveMains.length > 0) {
|
|
111
139
|
const pids = aliveMains.map(m => m.record.pid).join(', ');
|
|
112
140
|
console.log(`❌ EvolCore 正在运行 (PID: ${pids}),请先执行 ec stop`);
|
|
113
|
-
return;
|
|
141
|
+
return false;
|
|
114
142
|
}
|
|
115
143
|
// ── 2. 探测 baseagent ──
|
|
116
144
|
const available = detectAvailable();
|
|
117
|
-
if (available.length === 0) {
|
|
145
|
+
if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
|
|
118
146
|
console.log('❌ 未检测到可用 baseagent。请安装至少一款:');
|
|
119
147
|
console.log(' - claude CLI');
|
|
120
148
|
console.log(' - gemini CLI');
|
|
121
149
|
console.log(' - codex CLI with app-server');
|
|
122
150
|
console.log('\n安装后重新运行 ec init');
|
|
123
|
-
return;
|
|
151
|
+
return false;
|
|
124
152
|
}
|
|
125
153
|
console.log('检测到可用的 baseagent:');
|
|
126
154
|
for (const b of available)
|
|
@@ -142,19 +170,31 @@ export async function cmdInit(options) {
|
|
|
142
170
|
if (options.baseagent) {
|
|
143
171
|
if (!BASEAGENT_CANDIDATES.includes(options.baseagent)) {
|
|
144
172
|
console.log(`❌ 无效 baseagent: ${options.baseagent}(可选: ${BASEAGENT_CANDIDATES.join('/')})`);
|
|
145
|
-
return; // 硬错误:不落 tail
|
|
173
|
+
return false; // 硬错误:不落 tail
|
|
146
174
|
}
|
|
147
175
|
if (!available.includes(options.baseagent)) {
|
|
148
176
|
const reason = options.baseagent === 'codex'
|
|
149
177
|
? getCodexAppServerAvailability().reason
|
|
150
178
|
: undefined;
|
|
151
179
|
console.log(`❌ ${options.baseagent} 当前环境不可用${reason ? `:${reason}` : `(可用: ${available.join('/')})`}`);
|
|
152
|
-
return; // 硬错误:不落 tail
|
|
180
|
+
return false; // 硬错误:不落 tail
|
|
181
|
+
}
|
|
182
|
+
if (options.baseagent === 'ecagent') {
|
|
183
|
+
const reason = ecagentUnavailableReason();
|
|
184
|
+
if (reason) {
|
|
185
|
+
console.log(`❌ ecagent 当前环境不可用:${reason}`);
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
153
188
|
}
|
|
154
189
|
chosen = options.baseagent;
|
|
155
190
|
}
|
|
156
191
|
else {
|
|
157
|
-
|
|
192
|
+
const defaultBaseagent = pickDefault(available);
|
|
193
|
+
if (!defaultBaseagent) {
|
|
194
|
+
console.log('❌ ecagent 为可选 baseagent,请显式使用 --baseagent ecagent,并配置 API key');
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
chosen = defaultBaseagent;
|
|
158
198
|
}
|
|
159
199
|
writeDefaults(chosen, available);
|
|
160
200
|
console.log(`✓ 已${defaultsExisted ? '覆盖' : '创建'}: ${defaultsPath}`);
|
|
@@ -167,19 +207,24 @@ export async function cmdInit(options) {
|
|
|
167
207
|
await runInteractive();
|
|
168
208
|
}
|
|
169
209
|
// ── 共享 tail(单一出口):提示创建 agent + 生成控制 AID ──
|
|
170
|
-
|
|
210
|
+
return initTail({ invokedByStart: options?.invokedByStart });
|
|
171
211
|
// ── 内部函数 ──
|
|
172
212
|
async function runInteractive() {
|
|
173
213
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
174
214
|
async function askBaseagent() {
|
|
175
215
|
const defaultBa = pickDefault(available);
|
|
176
|
-
if (available.length === 1) {
|
|
216
|
+
if (available.length === 1 && defaultBa) {
|
|
177
217
|
console.log(` baseagent: ${defaultBa}`);
|
|
178
218
|
return defaultBa;
|
|
179
219
|
}
|
|
180
220
|
let chosen = null;
|
|
181
221
|
while (chosen === null) {
|
|
182
|
-
const
|
|
222
|
+
const defaultHint = defaultBa ? ` [${defaultBa}]` : '';
|
|
223
|
+
const input = (await ask(rl, `默认 baseagent (${available.join('/')})${defaultHint}: `)).trim() || defaultBa;
|
|
224
|
+
if (!input) {
|
|
225
|
+
console.log(' ecagent 为可选项,请显式输入 ecagent');
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
183
228
|
if (!BASEAGENT_CANDIDATES.includes(input)) {
|
|
184
229
|
console.log(` 无效选择,可选: ${BASEAGENT_CANDIDATES.join('/')}`);
|
|
185
230
|
continue;
|
|
@@ -188,35 +233,49 @@ export async function cmdInit(options) {
|
|
|
188
233
|
console.log(` ${input} 当前环境不可用(可用: ${available.join('/')})`);
|
|
189
234
|
continue;
|
|
190
235
|
}
|
|
236
|
+
if (input === 'ecagent') {
|
|
237
|
+
const reason = ecagentUnavailableReason();
|
|
238
|
+
if (reason) {
|
|
239
|
+
console.log(` ecagent 当前环境不可用:${reason}`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
191
243
|
chosen = input;
|
|
192
244
|
}
|
|
193
245
|
return chosen;
|
|
194
246
|
}
|
|
195
247
|
async function askProjectsDefaultPath() {
|
|
196
248
|
const defaultDir = path.join(defaultProjectsRoot(p.root), 'default');
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
249
|
+
while (true) {
|
|
250
|
+
const input = (await ask(rl, `项目默认目录 [${defaultDir}](输入 skip 跳过): `)).trim();
|
|
251
|
+
if (input.toLowerCase() === 'skip') {
|
|
252
|
+
console.log(' 已跳过项目默认目录配置');
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
const resolved = expandLeadingTildePath(input || defaultDir);
|
|
256
|
+
if (!path.isAbsolute(resolved)) {
|
|
257
|
+
console.log(' ⚠ 请输入绝对路径或回车使用默认值;输入 skip 可跳过');
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (!fs.existsSync(resolved)) {
|
|
261
|
+
const create = (await ask(rl, ` 目录不存在,是否创建?[Y/n]: `)).trim().toLowerCase();
|
|
262
|
+
if (create === '' || create === 'y' || create === 'yes') {
|
|
263
|
+
try {
|
|
264
|
+
fs.mkdirSync(resolved, { recursive: true });
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
console.log(` ⚠ 创建目录失败: ${e?.message || e}`);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
console.log(` ✓ 已创建 ${resolved}`);
|
|
208
271
|
}
|
|
209
|
-
|
|
210
|
-
console.log(
|
|
211
|
-
|
|
272
|
+
else {
|
|
273
|
+
console.log(' 未创建目录,请重新输入路径;输入 skip 可跳过');
|
|
274
|
+
continue;
|
|
212
275
|
}
|
|
213
|
-
console.log(` ✓ 已创建 ${resolved}`);
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
return undefined;
|
|
217
276
|
}
|
|
277
|
+
return resolved;
|
|
218
278
|
}
|
|
219
|
-
return resolved;
|
|
220
279
|
}
|
|
221
280
|
try {
|
|
222
281
|
if (defaultsExisted) {
|
|
@@ -249,15 +308,16 @@ export async function cmdInit(options) {
|
|
|
249
308
|
}
|
|
250
309
|
}
|
|
251
310
|
/** 补全控制 AID + owners(可单独调用,不走 baseagent 向导)。 */
|
|
252
|
-
export async function initTail() {
|
|
311
|
+
export async function initTail(options = {}) {
|
|
253
312
|
// 提示创建 agent(两分支汇合后执行一次)
|
|
254
313
|
const { agents } = loadAllAgents();
|
|
255
|
-
if (agents.length === 0) {
|
|
314
|
+
if (agents.length === 0 && !options.invokedByStart) {
|
|
256
315
|
console.log('\n提示:尚无 agent,运行以下命令创建:');
|
|
257
316
|
console.log(' ec agent new <aid>.agentid.pub');
|
|
258
317
|
}
|
|
259
318
|
// 控制 AID:daemon 进程身份。缺失则生成并写回 daemon.json(幂等:已存在则跳过)。
|
|
260
319
|
const daemonConfig = loadDaemonConfig();
|
|
320
|
+
let controlAidReady = !!daemonConfig.aid;
|
|
261
321
|
if (daemonConfig.aid) {
|
|
262
322
|
const targetIssuer = resolveControlIssuer();
|
|
263
323
|
const currentIssuer = daemonConfig.aid.split('.').slice(1).join('.');
|
|
@@ -271,10 +331,12 @@ export async function initTail() {
|
|
|
271
331
|
try {
|
|
272
332
|
const { aid } = await generateControlAid();
|
|
273
333
|
saveDaemonConfig({ ...daemonConfig, $schema_version: daemonConfig.$schema_version ?? 1, aid });
|
|
334
|
+
controlAidReady = true;
|
|
274
335
|
console.log(`✓ 已生成控制 AID: ${aid}`);
|
|
275
336
|
}
|
|
276
337
|
catch (e) {
|
|
277
338
|
console.error(`⚠️ 控制 AID 生成失败(Gateway 不可达?联网后重跑 ec init 补全): ${e?.message || e}`);
|
|
339
|
+
controlAidReady = false;
|
|
278
340
|
}
|
|
279
341
|
}
|
|
280
342
|
// 交互式询问:使用单一 readline 实例避免 stdin 状态混乱
|
|
@@ -368,6 +430,13 @@ export async function initTail() {
|
|
|
368
430
|
}
|
|
369
431
|
}
|
|
370
432
|
}
|
|
433
|
+
// ec start 会接着启动 daemon,并在其 ready 后给出可用的 Agent 创建入口。
|
|
434
|
+
if (options.invokedByStart)
|
|
435
|
+
return controlAidReady;
|
|
436
|
+
if (!controlAidReady) {
|
|
437
|
+
console.error('\n❌ EvolCore 初始化未完成:控制 AID 未配置。联网后重新运行 ec init。');
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
371
440
|
// 初始化完成总结
|
|
372
441
|
console.log('\n✓ EvolCore 初始化完成');
|
|
373
442
|
const finalCfg = loadDaemonConfig();
|
|
@@ -385,6 +454,7 @@ export async function initTail() {
|
|
|
385
454
|
console.log(`\n✓ 已有 ${finalAgents.length} 个 agent,可直接运行:`);
|
|
386
455
|
console.log(' ec start');
|
|
387
456
|
}
|
|
457
|
+
return controlAidReady;
|
|
388
458
|
}
|
|
389
459
|
/**
|
|
390
460
|
* Present instance selection menu when existing instances are found.
|
|
@@ -480,8 +550,8 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
480
550
|
}
|
|
481
551
|
// ── 3. baseagent 探测 + 校验 ──
|
|
482
552
|
const available = dependencies.availableBaseagents ?? detectAvailable();
|
|
483
|
-
if (available.length === 0) {
|
|
484
|
-
fail('BASEAGENT_UNAVAILABLE', 'no baseagent
|
|
553
|
+
if (available.length === 0 || (available.length === 1 && available[0] === 'ecagent' && ecagentUnavailableReason())) {
|
|
554
|
+
fail('BASEAGENT_UNAVAILABLE', 'no usable baseagent detected (install claude/codex/gemini or configure bundled ecagent)', EXIT_USAGE, format);
|
|
485
555
|
}
|
|
486
556
|
let chosenBaseagent;
|
|
487
557
|
if (opts.baseagent) {
|
|
@@ -492,10 +562,19 @@ export async function cmdInitNonInteractive(opts, dependencies = {}) {
|
|
|
492
562
|
const reason = opts.baseagent === 'codex' ? getCodexAppServerAvailability().reason : undefined;
|
|
493
563
|
fail('BASEAGENT_UNAVAILABLE', `${opts.baseagent} not available${reason ? `: ${reason}` : ''}`, EXIT_USAGE, format);
|
|
494
564
|
}
|
|
565
|
+
if (opts.baseagent === 'ecagent') {
|
|
566
|
+
const reason = ecagentUnavailableReason();
|
|
567
|
+
if (reason)
|
|
568
|
+
fail('BASEAGENT_UNAVAILABLE', reason, EXIT_USAGE, format);
|
|
569
|
+
}
|
|
495
570
|
chosenBaseagent = opts.baseagent;
|
|
496
571
|
}
|
|
497
572
|
else {
|
|
498
|
-
|
|
573
|
+
const defaultBaseagent = pickDefault(available);
|
|
574
|
+
if (!defaultBaseagent) {
|
|
575
|
+
fail('BASEAGENT_UNAVAILABLE', 'ecagent is optional; pass --baseagent ecagent after configuring its API key', EXIT_USAGE, format);
|
|
576
|
+
}
|
|
577
|
+
chosenBaseagent = defaultBaseagent;
|
|
499
578
|
}
|
|
500
579
|
// ── 4. projectpath 校验 + 创建 ──
|
|
501
580
|
let projectsDefaultPath;
|
package/dist/cli/net-check.js
CHANGED
|
@@ -307,31 +307,20 @@ async function runCheck(aid, formatJson, kickTest) {
|
|
|
307
307
|
// 统计每个 AID 的总消息活跃度(遍历所有本地 AID 的 sessions)
|
|
308
308
|
const { resolvePaths } = await import('../paths.js');
|
|
309
309
|
const p = resolvePaths();
|
|
310
|
-
const
|
|
311
|
-
const encode = (s) => s.replace(/[/%\\:*?"<>|]/g, ch => '%' + ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'));
|
|
312
|
-
const decode = (s) => s.replace(/%([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
310
|
+
const { scanChatDirs } = await import('../core/session/session-fs-store.js');
|
|
313
311
|
function getGlobalMessageCounts() {
|
|
314
312
|
const counts = new Map();
|
|
315
313
|
try {
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
if (!localDir.isDirectory())
|
|
314
|
+
for (const chat of scanChatDirs(p.sessionsDir)) {
|
|
315
|
+
if (chat.channelType !== 'aun')
|
|
319
316
|
continue;
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const peerId = decode(peerDir.name);
|
|
326
|
-
const msgFile = path.join(sessAunDir, localDir.name, peerDir.name, 'messages.jsonl');
|
|
327
|
-
try {
|
|
328
|
-
const content = fs.readFileSync(msgFile, 'utf-8');
|
|
329
|
-
const lineCount = content.split('\n').filter(l => l.trim()).length;
|
|
330
|
-
counts.set(peerId, (counts.get(peerId) ?? 0) + lineCount);
|
|
331
|
-
counts.set(localAid, (counts.get(localAid) ?? 0) + lineCount);
|
|
332
|
-
}
|
|
333
|
-
catch { }
|
|
317
|
+
const msgFile = path.join(chat.dirPath, 'messages.jsonl');
|
|
318
|
+
try {
|
|
319
|
+
const lineCount = fs.readFileSync(msgFile, 'utf-8').split('\n').filter(l => l.trim()).length;
|
|
320
|
+
counts.set(chat.channelId, (counts.get(chat.channelId) ?? 0) + lineCount);
|
|
321
|
+
counts.set(chat.selfAID, (counts.get(chat.selfAID) ?? 0) + lineCount);
|
|
334
322
|
}
|
|
323
|
+
catch { }
|
|
335
324
|
}
|
|
336
325
|
}
|
|
337
326
|
catch { }
|
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { spawn, execFile } from 'child_process';
|
|
4
4
|
import { promisify } from 'util';
|
|
5
|
-
import { resolvePaths, getPackageRoot } from '../paths.js';
|
|
5
|
+
import { resolvePaths, getPackageRoot, daemonControlDir } from '../paths.js';
|
|
6
6
|
import { loadDaemonConfig } from '../config-store.js';
|
|
7
7
|
import * as platform from '../utils/cross-platform.js';
|
|
8
8
|
import { EventBus } from '../core/event-bus.js';
|
|
@@ -14,6 +14,7 @@ import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMoni
|
|
|
14
14
|
import { WEB_PACKAGE_NAME } from '../product.js';
|
|
15
15
|
import { shouldSuppressRealRestart } from '../utils/restart-safety.js';
|
|
16
16
|
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
17
|
+
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
17
18
|
const execFileAsync = promisify(execFile);
|
|
18
19
|
// 清理 Claude Code 环境变量,防止 SDK 认为是嵌套会话
|
|
19
20
|
function cleanEnv() {
|
|
@@ -72,6 +73,14 @@ export async function cmdRestartMonitor() {
|
|
|
72
73
|
return s.mains.some(m => m.alive);
|
|
73
74
|
};
|
|
74
75
|
log('Restart monitor started');
|
|
76
|
+
const migrationRequirement = inspectDataMigrationRequirement(p.root);
|
|
77
|
+
if (migrationRequirement.required) {
|
|
78
|
+
const message = `Pending user-data migration (${migrationRequirement.operationCount} operations); leaving the current service running. Run ec data migrate --dry-run, then ec data migrate --apply.`;
|
|
79
|
+
log(message);
|
|
80
|
+
console.error(`❌ ${message}`);
|
|
81
|
+
process.exitCode = 2;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
75
84
|
// Test daemons live in one temporary HOME per test, so the current HOME's
|
|
76
85
|
// instance registry cannot see them. Their strict environment markers make
|
|
77
86
|
// them safe to reap globally on every real restart.
|
|
@@ -84,7 +93,7 @@ export async function cmdRestartMonitor() {
|
|
|
84
93
|
}
|
|
85
94
|
}
|
|
86
95
|
// restart-pending.json 只留给新主进程发送发起会话内的“重启成功”回执。
|
|
87
|
-
const pendingFile = path.join(
|
|
96
|
+
const pendingFile = path.join(daemonControlDir(), 'restart-pending.json');
|
|
88
97
|
// 等待所有活 main 进程退出(可能不止一个)
|
|
89
98
|
const oldStatus = scanInstances();
|
|
90
99
|
const aliveMains = oldStatus.mains.filter(m => m.alive);
|
|
@@ -110,7 +110,7 @@ Create 参数模式支持:
|
|
|
110
110
|
--tz <时区> (仅 cron)
|
|
111
111
|
--target-channel <channelKey> --target-channel-id <ID> (AUN 可简写为 aun)
|
|
112
112
|
--target-session <main|thread> [--target-thread-id <threadId>]
|
|
113
|
-
--trigger-thread <
|
|
113
|
+
--trigger-thread <by-run|by-trigger> (兼容旧值 per-run)
|
|
114
114
|
--name <名称>
|
|
115
115
|
|
|
116
116
|
通用输出参数:
|
package/dist/cli/watch-msg.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { resolvePaths } from '../paths.js';
|
|
4
|
-
import {
|
|
4
|
+
import { chatDirPath, readAllJsonlLines, scanChatDirs } from '../core/session/session-fs-store.js';
|
|
5
5
|
import { isTransientProtocolMessage } from '../core/message/message-log.js';
|
|
6
6
|
// ==================== ANSI ====================
|
|
7
7
|
const isTTY = !!process.stdout.isTTY;
|
|
@@ -135,36 +135,26 @@ function shortAid(aid) {
|
|
|
135
135
|
// ==================== Data Layer ====================
|
|
136
136
|
export function getSessionsAunDir() {
|
|
137
137
|
const p = resolvePaths();
|
|
138
|
-
return
|
|
138
|
+
return p.sessionsDir;
|
|
139
139
|
}
|
|
140
140
|
export function listLocalAids(aunDir) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
.
|
|
144
|
-
.map(e => decodeDirSegment(e.name));
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
return [];
|
|
148
|
-
}
|
|
141
|
+
return [...new Set(scanChatDirs(aunDir)
|
|
142
|
+
.filter(chat => chat.channelType === 'aun')
|
|
143
|
+
.map(chat => chat.selfAID))].sort();
|
|
149
144
|
}
|
|
150
145
|
export function listPeers(aunDir, localAid) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
.map(e => decodeDirSegment(e.name));
|
|
156
|
-
}
|
|
157
|
-
catch {
|
|
158
|
-
return [];
|
|
159
|
-
}
|
|
146
|
+
return scanChatDirs(aunDir)
|
|
147
|
+
.filter(chat => chat.channelType === 'aun' && chat.selfAID === localAid)
|
|
148
|
+
.map(chat => chat.channelId)
|
|
149
|
+
.sort();
|
|
160
150
|
}
|
|
161
151
|
export function readMessages(aunDir, localAid, peerId) {
|
|
162
|
-
const msgPath = path.join(aunDir,
|
|
152
|
+
const msgPath = path.join(chatDirPath(aunDir, 'aun', peerId, localAid), 'messages.jsonl');
|
|
163
153
|
return readAllJsonlLines(msgPath)
|
|
164
154
|
.filter(m => !isTransientProtocolMessage(m));
|
|
165
155
|
}
|
|
166
156
|
function readPeerName(aunDir, localAid, peerId) {
|
|
167
|
-
const activePath = path.join(aunDir,
|
|
157
|
+
const activePath = path.join(chatDirPath(aunDir, 'aun', peerId, localAid), 'active.json');
|
|
168
158
|
try {
|
|
169
159
|
const data = JSON.parse(fs.readFileSync(activePath, 'utf-8'));
|
|
170
160
|
return data?.metadata?.peerName || null;
|
|
@@ -173,9 +163,6 @@ function readPeerName(aunDir, localAid, peerId) {
|
|
|
173
163
|
return null;
|
|
174
164
|
}
|
|
175
165
|
}
|
|
176
|
-
function encodeSegment(s) {
|
|
177
|
-
return s.replace(/[/%\\:*?"<>|]/g, ch => '%' + ch.charCodeAt(0).toString(16).toUpperCase().padStart(2, '0'));
|
|
178
|
-
}
|
|
179
166
|
export function loadAidInfo(aunDir, aid) {
|
|
180
167
|
const peers = listPeers(aunDir, aid);
|
|
181
168
|
let totalIn = 0, totalOut = 0;
|
|
@@ -457,7 +444,7 @@ export async function cmdWatchMsg() {
|
|
|
457
444
|
watcher.close();
|
|
458
445
|
watcher = null;
|
|
459
446
|
}
|
|
460
|
-
const aidDir = path.
|
|
447
|
+
const aidDir = path.dirname(path.dirname(chatDirPath(aunDir, 'aun', '__watch__', aid)));
|
|
461
448
|
try {
|
|
462
449
|
watcher = fs.watch(aidDir, { recursive: true }, (_, filename) => {
|
|
463
450
|
if (filename && filename.endsWith('messages.jsonl')) {
|
|
@@ -4,18 +4,6 @@ export function validAgentOwnerIds(agent) {
|
|
|
4
4
|
.map(value => String(value || '').trim())
|
|
5
5
|
.filter(isValidAid))];
|
|
6
6
|
}
|
|
7
|
-
export function configuredChannelKeys(selfAid, agent) {
|
|
8
|
-
const keys = (agent?.channels ?? [])
|
|
9
|
-
.filter(channel => channel && channel.enabled !== false)
|
|
10
|
-
.map(channel => {
|
|
11
|
-
const type = String(channel.type || '').trim().toLowerCase();
|
|
12
|
-
const name = String(channel.name || '').trim();
|
|
13
|
-
return type && name ? `${type}#${selfAid}#${name}` : '';
|
|
14
|
-
})
|
|
15
|
-
.filter(Boolean);
|
|
16
|
-
keys.push(`aun#${selfAid}#main`);
|
|
17
|
-
return [...new Set(keys)];
|
|
18
|
-
}
|
|
19
7
|
export function validateAccessPolicyDomain(selfAid, agent) {
|
|
20
8
|
const access = agent.access;
|
|
21
9
|
if (!access)
|
|
@@ -26,13 +14,5 @@ export function validateAccessPolicyDomain(selfAid, agent) {
|
|
|
26
14
|
message: `Agent ${selfAid} cannot use ${access.policyMode} without an Owner`,
|
|
27
15
|
};
|
|
28
16
|
}
|
|
29
|
-
const configured = new Set(configuredChannelKeys(selfAid, agent));
|
|
30
|
-
const unknown = access.allowedGroupChannels.find(channelKey => !configured.has(channelKey));
|
|
31
|
-
if (unknown) {
|
|
32
|
-
return {
|
|
33
|
-
code: 'unknown_group_access_channel',
|
|
34
|
-
message: `Group access channel is not configured or enabled for ${selfAid}: ${unknown}`,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
17
|
return undefined;
|
|
38
18
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import { ConfigError, ConfigTarget, mutateConfig, read, validateConfig, } from './config-manager.js';
|
|
3
|
-
import {
|
|
3
|
+
import { validAgentOwnerIds, validateAccessPolicyDomain, } from './access-policy-domain.js';
|
|
4
4
|
export class AccessPolicyError extends Error {
|
|
5
5
|
code;
|
|
6
6
|
data;
|
|
@@ -13,20 +13,13 @@ export class AccessPolicyError extends Error {
|
|
|
13
13
|
}
|
|
14
14
|
export const DEFAULT_ACCESS_POLICY = Object.freeze({
|
|
15
15
|
policyMode: 'open',
|
|
16
|
-
allowedGroupChannels: Object.freeze([]),
|
|
17
16
|
requestLimit: Object.freeze({ maxTimes: 600, coolDown: 60 * 60 }),
|
|
18
17
|
});
|
|
19
18
|
export function listAgentOwners(selfAid) {
|
|
20
19
|
const agent = read(ConfigTarget.Agent, { self: selfAid }, { cache: true });
|
|
21
20
|
return validAgentOwnerIds(agent);
|
|
22
21
|
}
|
|
23
|
-
|
|
24
|
-
const agent = read(ConfigTarget.Agent, { self: selfAid }, { cache: true });
|
|
25
|
-
if (!agent)
|
|
26
|
-
return [];
|
|
27
|
-
return configuredChannelKeys(selfAid, agent);
|
|
28
|
-
}
|
|
29
|
-
/** Missing AgentConfig.access uses the compatibility view; malformed Agent config never does. */
|
|
22
|
+
/** Missing AgentConfig.access uses the default open policy; malformed Agent config never does. */
|
|
30
23
|
export function readAccessPolicy(selfAid) {
|
|
31
24
|
return readAccessPolicySnapshot(selfAid).policy;
|
|
32
25
|
}
|
|
@@ -49,7 +42,7 @@ export function mutateAccessPolicy(input) {
|
|
|
49
42
|
});
|
|
50
43
|
}
|
|
51
44
|
const next = input.update(clonePolicy(current.policy));
|
|
52
|
-
assertAccessPolicyWrite(input, agent,
|
|
45
|
+
assertAccessPolicyWrite(input, agent, next);
|
|
53
46
|
agent.access = clonePolicy(next);
|
|
54
47
|
return {
|
|
55
48
|
policy: clonePolicy(next),
|
|
@@ -85,37 +78,20 @@ function accessPolicySnapshotFromAgent(selfAid, agent) {
|
|
|
85
78
|
const policy = clonePolicy(access);
|
|
86
79
|
return { policy, accessRevision: accessPolicyRevision(policy) };
|
|
87
80
|
}
|
|
88
|
-
function assertAccessPolicyWrite(input, agent,
|
|
81
|
+
function assertAccessPolicyWrite(input, agent, policy) {
|
|
89
82
|
const owners = validAgentOwnerIds(agent);
|
|
90
83
|
const normalizedActorAid = String(input.actorAid || '').trim();
|
|
91
84
|
const isOwner = input.actorRole === 'owner' || owners.includes(normalizedActorAid);
|
|
92
|
-
|
|
93
|
-
if (!isOwner && !isGroupChannelAdmin) {
|
|
94
|
-
if (input.resource === 'access.allowedGroupChannels') {
|
|
95
|
-
throw new AccessPolicyError('access_policy_manager_required', 'Only an Agent Owner or Admin can change allowed group channels');
|
|
96
|
-
}
|
|
85
|
+
if (!isOwner) {
|
|
97
86
|
throw new AccessPolicyError('access_policy_owner_required', 'Only an Agent Owner can change access policy');
|
|
98
87
|
}
|
|
99
|
-
if (isGroupChannelAdmin) {
|
|
100
|
-
if (current.policyMode !== policy.policyMode
|
|
101
|
-
|| current.requestLimit.maxTimes !== policy.requestLimit.maxTimes
|
|
102
|
-
|| current.requestLimit.coolDown !== policy.requestLimit.coolDown) {
|
|
103
|
-
throw new AccessPolicyError('access_policy_owner_required', 'An Agent Admin may only change allowed group channels');
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
88
|
if (policy.policyMode !== 'open' && owners.length === 0) {
|
|
107
89
|
throw new AccessPolicyError('restricted_mode_without_owner', `Agent ${input.selfAid} cannot use ${policy.policyMode} without an Owner`);
|
|
108
90
|
}
|
|
109
|
-
const configured = new Set(configuredChannelKeys(input.selfAid, agent));
|
|
110
|
-
const unknown = policy.allowedGroupChannels.find(channelKey => !configured.has(channelKey));
|
|
111
|
-
if (unknown) {
|
|
112
|
-
throw new AccessPolicyError('unknown_group_access_channel', `Group access channel is not configured or enabled for ${input.selfAid}: ${unknown}`);
|
|
113
|
-
}
|
|
114
91
|
}
|
|
115
92
|
function clonePolicy(policy) {
|
|
116
93
|
return {
|
|
117
94
|
policyMode: policy.policyMode,
|
|
118
|
-
allowedGroupChannels: [...policy.allowedGroupChannels],
|
|
119
95
|
requestLimit: { ...policy.requestLimit },
|
|
120
96
|
};
|
|
121
97
|
}
|
|
@@ -40,7 +40,9 @@ export function getManagementCommandPermissions(role) {
|
|
|
40
40
|
'config.unset': { allow: true, scopes: ['agent', 'relation'] },
|
|
41
41
|
'role.policy.write': { allow: true, dangerous: true, scopes: ['agent'], constraints: { requireAgentAdmin: true } },
|
|
42
42
|
'*': { allow: true },
|
|
43
|
-
|
|
43
|
+
// Reload is valid from an Agent's own channel and the daemon control plane.
|
|
44
|
+
// The control-channel gate still requires a daemon owner for cross-Agent reloads.
|
|
45
|
+
'agent.reload': { allow: true, dangerous: true, scopes: ['agent', 'control'], constraints: { targetCurrentAgentOnly: true, requireAgentAdmin: true } },
|
|
44
46
|
'dangerous:*': { allow: true, dangerous: true, constraints: { requireDaemonOwner: true } },
|
|
45
47
|
};
|
|
46
48
|
}
|
|
@@ -25,7 +25,7 @@ const BASEAGENT_BEHAVIOR_FIELDS = new Set([
|
|
|
25
25
|
'mode',
|
|
26
26
|
'useVertex',
|
|
27
27
|
]);
|
|
28
|
-
const SUPPORTED_BASEAGENTS = new Set(['claude', 'codex', 'gemini', 'hermes']);
|
|
28
|
+
const SUPPORTED_BASEAGENTS = new Set(['claude', 'codex', 'gemini', 'ecagent', 'hermes']);
|
|
29
29
|
const SENSITIVE_TOP_FIELDS = new Set([
|
|
30
30
|
'$schema_version',
|
|
31
31
|
'aid',
|