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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ensureDir } from '../../utils/atomic-write.js';
|
|
2
2
|
import { logger } from '../../utils/logger.js';
|
|
3
3
|
import { encodePath } from '../../utils/cross-platform.js';
|
|
4
|
-
import { chatDirPath, generateSessionId, formatTimestamp, atomicWriteJson, appendJsonl, readJsonFile, readLastJsonlLine, readAllJsonlLines, scanChatDirs, scanMetaFiles, ensureChatDir, readThreadIndex, writeThreadIndex, } from './session-fs-store.js';
|
|
4
|
+
import { chatDirPath, generateSessionId, formatTimestamp, atomicWriteJson, atomicWriteText, appendJsonl, readJsonFile, readLastJsonlLine, readAllJsonlLines, scanChatDirs, scanMetaFiles, ensureChatDir, readThreadIndex, writeThreadIndex, } from './session-fs-store.js';
|
|
5
5
|
import { sessionToFile, fileToSession } from './session-mapper.js';
|
|
6
6
|
import { formatSessionKey, DEFAULT_THREAD_ID } from './session-key.js';
|
|
7
7
|
import { tryParseChannelKey } from '../channel-loader.js';
|
|
@@ -38,8 +38,6 @@ export class SessionManager {
|
|
|
38
38
|
this.sessionsDir = sessionsDir;
|
|
39
39
|
this.eventBus = eventBus;
|
|
40
40
|
this.identityResolver = identityResolver;
|
|
41
|
-
this.migrateChannelKeyFormat();
|
|
42
|
-
this.migrateWecomChannelDirs();
|
|
43
41
|
}
|
|
44
42
|
setIdentityResolver(resolver) {
|
|
45
43
|
this.identityResolver = resolver;
|
|
@@ -378,7 +376,7 @@ export class SessionManager {
|
|
|
378
376
|
logger.error(`[SessionManager] validateSessionFile: no adapter for baseagent=${session.baseagent}, session=${session.id}`);
|
|
379
377
|
return agentSessionId;
|
|
380
378
|
}
|
|
381
|
-
if (adapter.checkExists(session.projectPath, agentSessionId))
|
|
379
|
+
if (adapter.checkExists(session.projectPath, agentSessionId, session.selfAID))
|
|
382
380
|
return agentSessionId;
|
|
383
381
|
logger.warn(`Session file not found for ${session.baseagent}: ${agentSessionId}, clearing session ID`);
|
|
384
382
|
session.agentSessionId = undefined;
|
|
@@ -1315,16 +1313,16 @@ export class SessionManager {
|
|
|
1315
1313
|
});
|
|
1316
1314
|
return session;
|
|
1317
1315
|
}
|
|
1318
|
-
async scanCliSessions(projectPath, baseagent, limit = 10) {
|
|
1316
|
+
async scanCliSessions(projectPath, baseagent, limit = 10, agentAid) {
|
|
1319
1317
|
const adapter = this.getFileAdapter(baseagent);
|
|
1320
1318
|
if (!adapter)
|
|
1321
1319
|
return [];
|
|
1322
|
-
return adapter.scanCliSessions(projectPath, limit);
|
|
1320
|
+
return adapter.scanCliSessions(projectPath, limit, agentAid);
|
|
1323
1321
|
}
|
|
1324
|
-
async listImportableCliSessions(projectPath, baseagent) {
|
|
1322
|
+
async listImportableCliSessions(projectPath, baseagent, agentAid) {
|
|
1325
1323
|
const boundSessionIds = this.listBoundAgentSessionIds(projectPath, baseagent);
|
|
1326
1324
|
const displayLimit = 10;
|
|
1327
|
-
const cliSessions = await this.scanCliSessions(projectPath, baseagent, boundSessionIds.size + displayLimit);
|
|
1325
|
+
const cliSessions = await this.scanCliSessions(projectPath, baseagent, boundSessionIds.size + displayLimit, agentAid);
|
|
1328
1326
|
return cliSessions
|
|
1329
1327
|
.filter(session => !boundSessionIds.has(session.uuid))
|
|
1330
1328
|
.slice(0, displayLimit);
|
|
@@ -1343,25 +1341,25 @@ export class SessionManager {
|
|
|
1343
1341
|
}
|
|
1344
1342
|
return sessionIds;
|
|
1345
1343
|
}
|
|
1346
|
-
checkSessionFileExists(projectPath, agentSessionId, baseagent) {
|
|
1344
|
+
checkSessionFileExists(projectPath, agentSessionId, baseagent, agentAid) {
|
|
1347
1345
|
const adapter = this.getFileAdapter(baseagent);
|
|
1348
1346
|
if (!adapter)
|
|
1349
1347
|
return false;
|
|
1350
|
-
return adapter.checkExists(projectPath, agentSessionId);
|
|
1348
|
+
return adapter.checkExists(projectPath, agentSessionId, agentAid);
|
|
1351
1349
|
}
|
|
1352
|
-
readSessionFirstMessage(projectPath, agentSessionId, baseagent) {
|
|
1350
|
+
readSessionFirstMessage(projectPath, agentSessionId, baseagent, agentAid) {
|
|
1353
1351
|
const adapter = this.getFileAdapter(baseagent);
|
|
1354
1352
|
if (!adapter)
|
|
1355
1353
|
return null;
|
|
1356
|
-
return adapter.readFirstMessage(projectPath, agentSessionId);
|
|
1354
|
+
return adapter.readFirstMessage(projectPath, agentSessionId, agentAid);
|
|
1357
1355
|
}
|
|
1358
|
-
readSessionLastUserMessage(projectPath, agentSessionId, baseagent) {
|
|
1356
|
+
readSessionLastUserMessage(projectPath, agentSessionId, baseagent, agentAid) {
|
|
1359
1357
|
const adapter = this.getFileAdapter(baseagent);
|
|
1360
1358
|
if (!adapter)
|
|
1361
1359
|
return null;
|
|
1362
|
-
return adapter.readLastUserMessage(projectPath, agentSessionId);
|
|
1360
|
+
return adapter.readLastUserMessage(projectPath, agentSessionId, agentAid);
|
|
1363
1361
|
}
|
|
1364
|
-
getSessionFileInfo(projectPath, agentSessionId, baseagent) {
|
|
1362
|
+
getSessionFileInfo(projectPath, agentSessionId, baseagent, agentAid) {
|
|
1365
1363
|
if (!baseagent) {
|
|
1366
1364
|
logger.error(`[SessionManager] getSessionFileInfo: baseagent is empty, returning turns=0. agentSessionId=${agentSessionId}`);
|
|
1367
1365
|
return { turns: 0 };
|
|
@@ -1371,13 +1369,13 @@ export class SessionManager {
|
|
|
1371
1369
|
logger.error(`[SessionManager] getSessionFileInfo: no adapter for baseagent=${baseagent}, returning turns=0`);
|
|
1372
1370
|
return { turns: 0 };
|
|
1373
1371
|
}
|
|
1374
|
-
return adapter.getFileInfo(projectPath, agentSessionId);
|
|
1372
|
+
return adapter.getFileInfo(projectPath, agentSessionId, agentAid);
|
|
1375
1373
|
}
|
|
1376
|
-
async listSdkSessions(projectPath, baseagent) {
|
|
1374
|
+
async listSdkSessions(projectPath, baseagent, agentAid) {
|
|
1377
1375
|
const adapter = this.getFileAdapter(baseagent);
|
|
1378
1376
|
if (!adapter?.listSdkSessions)
|
|
1379
1377
|
return [];
|
|
1380
|
-
return adapter.listSdkSessions(projectPath);
|
|
1378
|
+
return adapter.listSdkSessions(projectPath, agentAid);
|
|
1381
1379
|
}
|
|
1382
1380
|
async getSessionByUuidPrefix(channel, channelId, uuidPrefix) {
|
|
1383
1381
|
const chatDir = this.resolveChatDirSafe(channel, channelId);
|
|
@@ -1390,15 +1388,16 @@ export class SessionManager {
|
|
|
1390
1388
|
}
|
|
1391
1389
|
return matched[0];
|
|
1392
1390
|
}
|
|
1393
|
-
async importCliSession(channel, channelId, projectPath, agentSessionId, baseagent = 'claude') {
|
|
1391
|
+
async importCliSession(channel, channelId, projectPath, agentSessionId, baseagent = 'claude', agentAid) {
|
|
1394
1392
|
const inheritedChatType = this.getActiveChatType(channel, channelId);
|
|
1395
|
-
const
|
|
1393
|
+
const resolvedAgentAid = agentAid || this.deriveChannelIdentity(channel, channelId).selfAID;
|
|
1394
|
+
const fileInfo = this.getSessionFileInfo(projectPath, agentSessionId, baseagent, resolvedAgentAid);
|
|
1396
1395
|
const name = fileInfo.title || `CLI会话-${new Date().toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}`;
|
|
1397
1396
|
// Derive selfAID and channelType from existing sessions
|
|
1398
1397
|
const existingDir = this.findExistingChatDir(channel, channelId);
|
|
1399
1398
|
const identity = this.deriveChannelIdentity(channel, channelId);
|
|
1400
1399
|
let channelType = identity.channelType;
|
|
1401
|
-
let selfAID = identity.selfAID;
|
|
1400
|
+
let selfAID = identity.selfAID || resolvedAgentAid || '';
|
|
1402
1401
|
if (existingDir) {
|
|
1403
1402
|
const active = readJsonFile(path.join(existingDir, 'active.json'));
|
|
1404
1403
|
if (active) {
|
|
@@ -1662,4 +1661,209 @@ export class SessionManager {
|
|
|
1662
1661
|
logger.info(`[SessionManager] Migrated ${migrated} WeCom session director${migrated === 1 ? 'y' : 'ies'} to channelKey isolation`);
|
|
1663
1662
|
}
|
|
1664
1663
|
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Recover legacy AUN chats written beneath `_unknown` before selfAID was
|
|
1666
|
+
* persisted. A channel key or persisted selfAID is required to make the
|
|
1667
|
+
* migration unambiguous; all other directories remain untouched.
|
|
1668
|
+
*/
|
|
1669
|
+
migrateUnknownAunDirs() {
|
|
1670
|
+
const legacyDirs = scanChatDirs(this.sessionsDir)
|
|
1671
|
+
.filter(entry => entry.channelType === 'aun' && entry.selfAID === '_unknown');
|
|
1672
|
+
let migrated = 0;
|
|
1673
|
+
for (const entry of legacyDirs) {
|
|
1674
|
+
const selfAIDs = this.findAunSelfAIDCandidates(entry.dirPath);
|
|
1675
|
+
if (selfAIDs.size !== 1) {
|
|
1676
|
+
if (selfAIDs.size > 1) {
|
|
1677
|
+
logger.error(`[SessionManager] Cannot auto-migrate mixed unknown AUN session directory: ${entry.dirPath}`);
|
|
1678
|
+
}
|
|
1679
|
+
continue;
|
|
1680
|
+
}
|
|
1681
|
+
const selfAID = [...selfAIDs][0];
|
|
1682
|
+
const target = chatDirPath(this.sessionsDir, 'aun', entry.channelId, selfAID);
|
|
1683
|
+
try {
|
|
1684
|
+
this.mergeUnknownAunDirectory(entry.dirPath, target, selfAID);
|
|
1685
|
+
migrated++;
|
|
1686
|
+
}
|
|
1687
|
+
catch (error) {
|
|
1688
|
+
logger.error(`[SessionManager] Failed to migrate unknown AUN session directory ${entry.dirPath}: ${String(error)}`);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
if (migrated > 0) {
|
|
1692
|
+
logger.info(`[SessionManager] Migrated ${migrated} unknown AUN session director${migrated === 1 ? 'y' : 'ies'} to selfAID isolation`);
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
findAunSelfAIDCandidates(chatDir) {
|
|
1696
|
+
const candidates = new Set();
|
|
1697
|
+
const visitRecord = (record) => {
|
|
1698
|
+
if (!record || typeof record !== 'object')
|
|
1699
|
+
return;
|
|
1700
|
+
const session = record;
|
|
1701
|
+
const direct = typeof session.selfAID === 'string' ? session.selfAID.trim() : '';
|
|
1702
|
+
if (direct && direct !== '_unknown')
|
|
1703
|
+
candidates.add(direct);
|
|
1704
|
+
const channel = typeof session.channel === 'string' ? tryParseChannelKey(session.channel) : null;
|
|
1705
|
+
if (channel?.type === 'aun' && channel.selfAID !== '_unknown')
|
|
1706
|
+
candidates.add(channel.selfAID);
|
|
1707
|
+
};
|
|
1708
|
+
const visitJsonl = (filePath) => {
|
|
1709
|
+
for (const record of readAllJsonlLines(filePath))
|
|
1710
|
+
visitRecord(record);
|
|
1711
|
+
};
|
|
1712
|
+
visitRecord(readJsonFile(path.join(chatDir, 'active.json')));
|
|
1713
|
+
for (const metaFile of scanMetaFiles(chatDir))
|
|
1714
|
+
visitJsonl(path.join(chatDir, metaFile));
|
|
1715
|
+
const threadDir = path.join(chatDir, '_threads');
|
|
1716
|
+
for (const metaFile of scanMetaFiles(threadDir))
|
|
1717
|
+
visitJsonl(path.join(threadDir, metaFile));
|
|
1718
|
+
return candidates;
|
|
1719
|
+
}
|
|
1720
|
+
mergeUnknownAunDirectory(sourceDir, targetDir, selfAID) {
|
|
1721
|
+
if (sourceDir === targetDir)
|
|
1722
|
+
return;
|
|
1723
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
1724
|
+
this.mergeUnknownAunDirectoryContents(sourceDir, targetDir, selfAID);
|
|
1725
|
+
fs.rmdirSync(sourceDir);
|
|
1726
|
+
}
|
|
1727
|
+
mergeUnknownAunDirectoryContents(sourceDir, targetDir, selfAID) {
|
|
1728
|
+
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
|
|
1729
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
1730
|
+
const targetPath = path.join(targetDir, entry.name);
|
|
1731
|
+
if (entry.isDirectory()) {
|
|
1732
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
1733
|
+
this.mergeUnknownAunDirectoryContents(sourcePath, targetPath, selfAID);
|
|
1734
|
+
fs.rmdirSync(sourcePath);
|
|
1735
|
+
continue;
|
|
1736
|
+
}
|
|
1737
|
+
if (!entry.isFile())
|
|
1738
|
+
continue;
|
|
1739
|
+
if (entry.name === 'active.json') {
|
|
1740
|
+
this.mergeUnknownAunActiveFile(sourcePath, targetPath, selfAID);
|
|
1741
|
+
}
|
|
1742
|
+
else if (entry.name.endsWith('.jsonl')) {
|
|
1743
|
+
this.mergeUnknownAunJsonlFile(sourcePath, targetPath, selfAID);
|
|
1744
|
+
}
|
|
1745
|
+
else if (entry.name.endsWith('.json')) {
|
|
1746
|
+
this.mergeUnknownAunJsonFile(sourcePath, targetPath);
|
|
1747
|
+
}
|
|
1748
|
+
else if (!fs.existsSync(targetPath)) {
|
|
1749
|
+
fs.renameSync(sourcePath, targetPath);
|
|
1750
|
+
}
|
|
1751
|
+
else if (fs.readFileSync(sourcePath).equals(fs.readFileSync(targetPath))) {
|
|
1752
|
+
fs.unlinkSync(sourcePath);
|
|
1753
|
+
}
|
|
1754
|
+
else {
|
|
1755
|
+
fs.renameSync(sourcePath, this.uniqueLegacyFilePath(targetPath));
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
mergeUnknownAunActiveFile(sourcePath, targetPath, selfAID) {
|
|
1760
|
+
const source = this.normalizeAunSessionRecord(readJsonFile(sourcePath), selfAID);
|
|
1761
|
+
const target = this.normalizeAunSessionRecord(readJsonFile(targetPath), selfAID);
|
|
1762
|
+
const sourceUpdatedAt = typeof source?.updatedAt === 'number' ? source.updatedAt : 0;
|
|
1763
|
+
const targetUpdatedAt = typeof target?.updatedAt === 'number' ? target.updatedAt : 0;
|
|
1764
|
+
const selected = target && targetUpdatedAt >= sourceUpdatedAt ? target : source;
|
|
1765
|
+
if (selected)
|
|
1766
|
+
atomicWriteJson(targetPath, selected);
|
|
1767
|
+
fs.unlinkSync(sourcePath);
|
|
1768
|
+
}
|
|
1769
|
+
mergeUnknownAunJsonlFile(sourcePath, targetPath, selfAID) {
|
|
1770
|
+
const records = [
|
|
1771
|
+
...this.readNormalizedAunJsonl(sourcePath, selfAID),
|
|
1772
|
+
...this.readNormalizedAunJsonl(targetPath, selfAID),
|
|
1773
|
+
];
|
|
1774
|
+
const seen = new Set();
|
|
1775
|
+
const unique = records.filter(record => {
|
|
1776
|
+
if (seen.has(record.key))
|
|
1777
|
+
return false;
|
|
1778
|
+
seen.add(record.key);
|
|
1779
|
+
return true;
|
|
1780
|
+
});
|
|
1781
|
+
unique.sort((left, right) => left.timestamp - right.timestamp || left.order - right.order);
|
|
1782
|
+
atomicWriteText(targetPath, unique.map(record => record.line).join('\n') + (unique.length ? '\n' : ''));
|
|
1783
|
+
fs.unlinkSync(sourcePath);
|
|
1784
|
+
}
|
|
1785
|
+
readNormalizedAunJsonl(filePath, selfAID) {
|
|
1786
|
+
let content;
|
|
1787
|
+
try {
|
|
1788
|
+
content = fs.readFileSync(filePath, 'utf-8');
|
|
1789
|
+
}
|
|
1790
|
+
catch (error) {
|
|
1791
|
+
if (error?.code === 'ENOENT')
|
|
1792
|
+
return [];
|
|
1793
|
+
throw error;
|
|
1794
|
+
}
|
|
1795
|
+
return content.split('\n').flatMap((rawLine, order) => {
|
|
1796
|
+
const line = rawLine.trim();
|
|
1797
|
+
if (!line)
|
|
1798
|
+
return [];
|
|
1799
|
+
try {
|
|
1800
|
+
const record = this.normalizeAunSessionRecord(JSON.parse(line), selfAID);
|
|
1801
|
+
const normalizedLine = JSON.stringify(record);
|
|
1802
|
+
return [{
|
|
1803
|
+
key: this.stableJson(record),
|
|
1804
|
+
line: normalizedLine,
|
|
1805
|
+
timestamp: this.recordTimestamp(record),
|
|
1806
|
+
order,
|
|
1807
|
+
}];
|
|
1808
|
+
}
|
|
1809
|
+
catch {
|
|
1810
|
+
return [{ key: `raw:${line}`, line, timestamp: Number.MAX_SAFE_INTEGER, order }];
|
|
1811
|
+
}
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
normalizeAunSessionRecord(record, selfAID) {
|
|
1815
|
+
if (!record || typeof record !== 'object' || Array.isArray(record))
|
|
1816
|
+
return record;
|
|
1817
|
+
const result = { ...record };
|
|
1818
|
+
const isSessionRecord = 'channel' in result || 'channelType' in result || 'sessionKey' in result || 'selfAID' in result;
|
|
1819
|
+
if (!isSessionRecord)
|
|
1820
|
+
return result;
|
|
1821
|
+
if (!result.selfAID || result.selfAID === '_unknown')
|
|
1822
|
+
result.selfAID = selfAID;
|
|
1823
|
+
return result;
|
|
1824
|
+
}
|
|
1825
|
+
stableJson(value) {
|
|
1826
|
+
if (Array.isArray(value))
|
|
1827
|
+
return `[${value.map(item => this.stableJson(item)).join(',')}]`;
|
|
1828
|
+
if (value && typeof value === 'object') {
|
|
1829
|
+
return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${this.stableJson(value[key])}`).join(',')}}`;
|
|
1830
|
+
}
|
|
1831
|
+
return JSON.stringify(value);
|
|
1832
|
+
}
|
|
1833
|
+
recordTimestamp(record) {
|
|
1834
|
+
if (!record || typeof record !== 'object')
|
|
1835
|
+
return Number.MAX_SAFE_INTEGER;
|
|
1836
|
+
const value = record;
|
|
1837
|
+
for (const key of ['ts', 'at', 'updatedAt', 'createdAt']) {
|
|
1838
|
+
if (typeof value[key] === 'number' && Number.isFinite(value[key]))
|
|
1839
|
+
return value[key];
|
|
1840
|
+
}
|
|
1841
|
+
return Number.MAX_SAFE_INTEGER;
|
|
1842
|
+
}
|
|
1843
|
+
mergeUnknownAunJsonFile(sourcePath, targetPath) {
|
|
1844
|
+
if (!fs.existsSync(targetPath)) {
|
|
1845
|
+
fs.renameSync(sourcePath, targetPath);
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
const source = readJsonFile(sourcePath);
|
|
1849
|
+
const target = readJsonFile(targetPath);
|
|
1850
|
+
if (source && target && !Array.isArray(source) && !Array.isArray(target)) {
|
|
1851
|
+
atomicWriteJson(targetPath, { ...source, ...target });
|
|
1852
|
+
fs.unlinkSync(sourcePath);
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
if (fs.readFileSync(sourcePath).equals(fs.readFileSync(targetPath))) {
|
|
1856
|
+
fs.unlinkSync(sourcePath);
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
fs.renameSync(sourcePath, this.uniqueLegacyFilePath(targetPath));
|
|
1860
|
+
}
|
|
1861
|
+
uniqueLegacyFilePath(targetPath) {
|
|
1862
|
+
let index = 1;
|
|
1863
|
+
let candidate = `${targetPath}.legacy-unknown`;
|
|
1864
|
+
while (fs.existsSync(candidate)) {
|
|
1865
|
+
candidate = `${targetPath}.legacy-unknown-${index++}`;
|
|
1866
|
+
}
|
|
1867
|
+
return candidate;
|
|
1868
|
+
}
|
|
1665
1869
|
}
|
|
@@ -30,6 +30,7 @@ const BACKEND_SYNTHETIC_CLI_PROMPT_PREFIXES = {
|
|
|
30
30
|
],
|
|
31
31
|
codex: [],
|
|
32
32
|
gemini: [],
|
|
33
|
+
ecagent: [],
|
|
33
34
|
};
|
|
34
35
|
// Claude Code 斜杠命令 / skill / hook 注入的脚手架,经真实会话数据核对,形态包括:
|
|
35
36
|
// - <local-command-caveat> / <local-command-stdout> / <local-command-stderr> 等 local-command 标签族
|
|
@@ -142,9 +142,16 @@ export class SessionTurnCoordinator {
|
|
|
142
142
|
if (evidence.openToolUseIds.length > 0)
|
|
143
143
|
return { ok: false, reason: 'tool_open' };
|
|
144
144
|
const madeProgress = evidence.textCount > 0 || evidence.toolUseCount > 0 || !!evidence.resultText?.trim();
|
|
145
|
-
|
|
145
|
+
// Not every runner can emit input_accepted. Token usage is equally strong
|
|
146
|
+
// evidence that the upstream model consumed the input, even for a silent result.
|
|
147
|
+
const inputConsumed = evidence.inputAccepted
|
|
148
|
+
|| evidence.hasTokenUsage === true
|
|
149
|
+
|| evidence.inputTokens > 0
|
|
150
|
+
|| evidence.outputTokens > 0;
|
|
151
|
+
if (!inputConsumed && !madeProgress)
|
|
146
152
|
return { ok: false, reason: 'input_not_consumed' };
|
|
147
153
|
const emptySuccess = !evidence.explicitNoop
|
|
154
|
+
&& !evidence.hasTokenUsage
|
|
148
155
|
&& evidence.inputTokens === 0
|
|
149
156
|
&& evidence.outputTokens === 0
|
|
150
157
|
&& !madeProgress;
|
|
@@ -14,6 +14,7 @@ export function isSystemControlChannel(channel) {
|
|
|
14
14
|
export function isNonAgentSessionChannel(channel) {
|
|
15
15
|
return channel === 'daemon' || isSystemControlChannel(channel);
|
|
16
16
|
}
|
|
17
|
+
/** Explicit maintenance helper; startup never invokes it. */
|
|
17
18
|
export function cleanupLegacySystemControlSessions(sessionsDir) {
|
|
18
19
|
const removed = [];
|
|
19
20
|
for (const channel of LEGACY_SYSTEM_CONTROL_CHANNELS) {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// 【重要】最先加载环境变量,确保后续模块初始化时可用
|
|
2
2
|
import dotenv from 'dotenv';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import { ensureDataDirs, resolvePaths, getPackageRoot, agentMdPath, eckDebugDir } from './paths.js';
|
|
4
|
+
import { ensureDataDirs, resolvePaths, getPackageRoot, agentMdPath, eckDebugDir, daemonControlDir, daemonQueuePath } from './paths.js';
|
|
5
5
|
// 立即加载 .env 文件(在其他模块导入之前)
|
|
6
6
|
try {
|
|
7
7
|
dotenv.config({ path: path.join(resolvePaths().root, '.env') });
|
|
@@ -12,6 +12,7 @@ catch {
|
|
|
12
12
|
import { ClaudeSessionFileAdapter } from './core/session/adapters/claude-session-file-adapter.js';
|
|
13
13
|
import { CodexSessionFileAdapter } from './core/session/adapters/codex-session-file-adapter.js';
|
|
14
14
|
import { GeminiSessionFileAdapter } from './core/session/adapters/gemini-session-file-adapter.js';
|
|
15
|
+
import { EcagentSessionFileAdapter } from './core/session/adapters/ecagent-session-file-adapter.js';
|
|
15
16
|
import { loadDefaults, loadAllAgents, migrateIdentitiesIfNeeded, loadDaemonConfig, initializeEckSnapshotsConfig } from './config-store.js';
|
|
16
17
|
import { ConfigTarget, initConfigManager, onConfigWrite } from './config/config-manager.js';
|
|
17
18
|
import { ensureRoleConfigV4OnStartup } from './config/role-config-v4-startup.js';
|
|
@@ -30,6 +31,7 @@ import { SessionManager } from './core/session/session-manager.js';
|
|
|
30
31
|
import { ClaudeAgentPlugin } from './agents/claude-runner.js';
|
|
31
32
|
import { CodexAgentPlugin } from './agents/codex-runner.js';
|
|
32
33
|
import { GeminiAgentPlugin } from './agents/gemini-runner.js';
|
|
34
|
+
import { EcagentAgentPlugin } from './agents/ecagent-runner.js';
|
|
33
35
|
import { FeishuChannelPlugin, registerPendingFeishuContactBind } from './channels/feishu.js';
|
|
34
36
|
import { WechatChannelPlugin, registerPendingWechatContactBind } from './channels/wechat.js';
|
|
35
37
|
import { AUN_HANDOFF_MARKER_FIELD, AUNChannel, AUNChannelPlugin } from './channels/aun.js';
|
|
@@ -78,13 +80,13 @@ import { TriggerAuditLogger } from './trigger/audit.js';
|
|
|
78
80
|
import { TriggerScriptExecutor } from './trigger/script-executor.js';
|
|
79
81
|
import { TriggerFeedbackDispatcher } from './trigger/feedback.js';
|
|
80
82
|
import { TriggerRuntimeScheduler } from './trigger/scheduler.js';
|
|
83
|
+
import { TargetSessionLockRegistry } from './trigger/session-lock.js';
|
|
81
84
|
import { DaemonChannel } from './channels/daemon.js';
|
|
82
85
|
import { definitionRevision, normalizeTriggerDefinition } from './trigger/validation.js';
|
|
83
86
|
import { applyTriggerPatch } from './trigger/patch.js';
|
|
84
87
|
import { validateModelSelectionForRole } from './core/model/model-permission.js';
|
|
85
88
|
import { constrainRuntimePermissionMode, validateRuntimeStringFieldOverride, } from './core/role/runtime-policy.js';
|
|
86
89
|
import { atomicWriteJson } from './core/session/session-fs-store.js';
|
|
87
|
-
import { cleanupLegacySystemControlSessions } from './core/system-channels.js';
|
|
88
90
|
import { appendMessageLog, buildOutboundEntry, classifyAunPayloadForLog } from './core/message/message-log.js';
|
|
89
91
|
import fs from 'fs';
|
|
90
92
|
import crypto from 'crypto';
|
|
@@ -844,21 +846,19 @@ async function main() {
|
|
|
844
846
|
});
|
|
845
847
|
return roleToSessionIdentity(detail.effectiveRole);
|
|
846
848
|
};
|
|
847
|
-
const removedLegacyControlSessions = cleanupLegacySystemControlSessions(paths.sessionsDir);
|
|
848
|
-
if (removedLegacyControlSessions.length > 0) {
|
|
849
|
-
logger.info(`[startup] Removed legacy synthetic control sessions: ${removedLegacyControlSessions.join(', ')}`);
|
|
850
|
-
}
|
|
851
849
|
const sessionManager = new SessionManager(paths.sessionsDir, eventBus, resolveSessionIdentity);
|
|
852
850
|
logger.info('✓ Database initialized');
|
|
853
851
|
// 注册会话文件适配器(Claude / Codex 各自的会话文件操作)
|
|
854
852
|
sessionManager.registerFileAdapter(new ClaudeSessionFileAdapter());
|
|
855
853
|
sessionManager.registerFileAdapter(new CodexSessionFileAdapter());
|
|
856
854
|
sessionManager.registerFileAdapter(new GeminiSessionFileAdapter());
|
|
855
|
+
sessionManager.registerFileAdapter(new EcagentSessionFileAdapter());
|
|
857
856
|
// Agent 插件系统:每个 EvolAgent × 每个 baseagent 一个独立 runner(H1/H2 修复)
|
|
858
857
|
const agentLoader = new AgentLoader();
|
|
859
858
|
agentLoader.register(new ClaudeAgentPlugin());
|
|
860
859
|
agentLoader.register(new CodexAgentPlugin());
|
|
861
860
|
agentLoader.register(new GeminiAgentPlugin());
|
|
861
|
+
agentLoader.register(new EcagentAgentPlugin());
|
|
862
862
|
const agentInstances = agentLoader.createAll(agentRegistry, {
|
|
863
863
|
onSessionIdUpdate: async (sessionId, agentSessionId) => {
|
|
864
864
|
await sessionManager.updateAgentSessionIdBySessionId(sessionId, agentSessionId);
|
|
@@ -1010,7 +1010,7 @@ async function main() {
|
|
|
1010
1010
|
const messageQueue = new MessageQueue(async (message) => {
|
|
1011
1011
|
await processor.processMessage(message);
|
|
1012
1012
|
}, {
|
|
1013
|
-
persistencePath:
|
|
1013
|
+
persistencePath: daemonQueuePath(),
|
|
1014
1014
|
});
|
|
1015
1015
|
// 设置中断回调(精确中断正在处理的 agent)
|
|
1016
1016
|
messageQueue.setInterruptCallback(async (sessionKey, baseagent, evolagentName, reason = 'new_message') => {
|
|
@@ -1074,6 +1074,7 @@ async function main() {
|
|
|
1074
1074
|
responseEngine.setHandoffRuntime(handoffRuntime);
|
|
1075
1075
|
// Trigger runtime: daemon-level script + feedback scheduler.
|
|
1076
1076
|
const triggerSchedulers = new Map();
|
|
1077
|
+
const targetSessionLocks = new TargetSessionLockRegistry();
|
|
1077
1078
|
const triggerAudit = new TriggerAuditLogger();
|
|
1078
1079
|
const triggerScriptExecutor = new TriggerScriptExecutor();
|
|
1079
1080
|
const daemonChannel = new DaemonChannel(sessionManager, messageQueue, {
|
|
@@ -1446,7 +1447,7 @@ async function main() {
|
|
|
1446
1447
|
baseagent: owner.baseagent,
|
|
1447
1448
|
getBaseagent: () => agentRegistry.get(owner.aid)?.baseagent || owner.baseagent,
|
|
1448
1449
|
authorizeExecution: authorizeTriggerExecution,
|
|
1449
|
-
}, eventBus);
|
|
1450
|
+
}, eventBus, targetSessionLocks);
|
|
1450
1451
|
triggerSchedulers.set(owner.aid, scheduler);
|
|
1451
1452
|
try {
|
|
1452
1453
|
await scheduler.init();
|
|
@@ -1710,7 +1711,7 @@ async function main() {
|
|
|
1710
1711
|
}
|
|
1711
1712
|
const connectedChannels = new Set();
|
|
1712
1713
|
const onlineNoticeSent = new Set();
|
|
1713
|
-
const pendingFile = path.join(
|
|
1714
|
+
const pendingFile = path.join(daemonControlDir(), 'restart-pending.json');
|
|
1714
1715
|
let pendingRestartNoticeInFlight = null;
|
|
1715
1716
|
let pendingRestartNoticeSent = false;
|
|
1716
1717
|
const sendOnlineNoticeForChannel = (inst) => {
|
package/dist/paths.js
CHANGED
|
@@ -25,15 +25,19 @@ export function _resetRoot() {
|
|
|
25
25
|
}
|
|
26
26
|
export function resolvePaths() {
|
|
27
27
|
const root = resolveRoot();
|
|
28
|
+
const agentsDir = path.join(root, 'agents');
|
|
28
29
|
return {
|
|
29
30
|
root,
|
|
30
|
-
|
|
31
|
+
// Session storage is partitioned by owning Agent. Keep the historical
|
|
32
|
+
// location separately so the explicit data migration can inventory it.
|
|
33
|
+
sessionsDir: agentsDir,
|
|
34
|
+
legacySessionsDir: path.join(root, 'data', 'sessions'),
|
|
31
35
|
instanceDir: path.join(root, 'data', 'instance'),
|
|
32
36
|
outboxDir: path.join(root, 'data', 'outbox'),
|
|
33
37
|
dataDir: path.join(root, 'data'),
|
|
34
38
|
claudeModelCache: path.join(root, 'data', 'claude-model-cache.json'),
|
|
35
39
|
logs: path.join(root, 'logs'),
|
|
36
|
-
agentsDir
|
|
40
|
+
agentsDir,
|
|
37
41
|
lineStats: path.join(root, 'logs', 'line-stats.log'),
|
|
38
42
|
readySignal: path.join(root, 'data', 'instance', 'ready.signal'),
|
|
39
43
|
controlToken: path.join(root, 'data', 'instance', 'control.token'),
|
|
@@ -126,8 +130,36 @@ export function agentDataDir(aid) {
|
|
|
126
130
|
export function agentDataCacheDir(aid) {
|
|
127
131
|
return path.join(agentDataDir(aid), 'cache');
|
|
128
132
|
}
|
|
133
|
+
export function agentHandoffDir(aid) {
|
|
134
|
+
return path.join(agentDataDir(aid), 'handoff');
|
|
135
|
+
}
|
|
136
|
+
export function agentOutboxPath(aid) {
|
|
137
|
+
return path.join(agentDataDir(aid), 'outbox.jsonl');
|
|
138
|
+
}
|
|
139
|
+
/** Directory-safe channel instance key used by connector runtime state. */
|
|
140
|
+
function encodePathKey(value) {
|
|
141
|
+
return encodeURIComponent(value);
|
|
142
|
+
}
|
|
143
|
+
export function daemonDataDir() {
|
|
144
|
+
return path.join(resolveRoot(), 'data', 'daemon');
|
|
145
|
+
}
|
|
146
|
+
export function daemonControlDir() {
|
|
147
|
+
return path.join(daemonDataDir(), 'control');
|
|
148
|
+
}
|
|
149
|
+
export function daemonQueuePath() {
|
|
150
|
+
return path.join(daemonDataDir(), 'message-queue.json');
|
|
151
|
+
}
|
|
152
|
+
export function channelStateDir(channelKey) {
|
|
153
|
+
if (!channelKey || channelKey === '.' || channelKey === '..') {
|
|
154
|
+
throw new Error('channelKey is required');
|
|
155
|
+
}
|
|
156
|
+
return path.join(resolveRoot(), 'data', 'channel-state', encodePathKey(channelKey));
|
|
157
|
+
}
|
|
158
|
+
export function channelStatePath(channelKey, ...parts) {
|
|
159
|
+
return path.join(channelStateDir(channelKey), ...parts);
|
|
160
|
+
}
|
|
129
161
|
export function agentTriggersDir(aid) {
|
|
130
|
-
return path.join(
|
|
162
|
+
return path.join(agentDir(aid), 'triggers');
|
|
131
163
|
}
|
|
132
164
|
function resolveInstanceSocketPath(root) {
|
|
133
165
|
if (isWindows) {
|
|
@@ -147,7 +179,6 @@ export function ensureDataDirs() {
|
|
|
147
179
|
fs.mkdirSync(p.outboxDir, { recursive: true });
|
|
148
180
|
fs.mkdirSync(p.eckDir, { recursive: true });
|
|
149
181
|
fs.mkdirSync(aidsDir(), { recursive: true });
|
|
150
|
-
seedConfigTemplates();
|
|
151
182
|
migrateFromAun();
|
|
152
183
|
}
|
|
153
184
|
const MIGRATION_MARKER = '.migrated-from-aun';
|
|
@@ -211,29 +242,6 @@ function migrateFromAun() {
|
|
|
211
242
|
}
|
|
212
243
|
catch { }
|
|
213
244
|
}
|
|
214
|
-
/**
|
|
215
|
-
* 首次运行时从 assets/ 模板拷贝 .env 到 $EVOLCORE_HOME。
|
|
216
|
-
* 已存在则跳过,不覆盖用户修改。
|
|
217
|
-
*/
|
|
218
|
-
function seedConfigTemplates() {
|
|
219
|
-
const root = resolveRoot();
|
|
220
|
-
const assetsDir = path.join(getPackageRoot(), 'assets');
|
|
221
|
-
const templates = [
|
|
222
|
-
{ src: '.env.template', dst: '.env' },
|
|
223
|
-
];
|
|
224
|
-
for (const { src, dst } of templates) {
|
|
225
|
-
const dstPath = path.join(root, dst);
|
|
226
|
-
if (fs.existsSync(dstPath))
|
|
227
|
-
continue;
|
|
228
|
-
const srcPath = path.join(assetsDir, src);
|
|
229
|
-
if (!fs.existsSync(srcPath))
|
|
230
|
-
continue;
|
|
231
|
-
try {
|
|
232
|
-
fs.copyFileSync(srcPath, dstPath);
|
|
233
|
-
}
|
|
234
|
-
catch { /* best-effort */ }
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
245
|
// ── kits 路径(始终从包内读取,不复制到 EVOLCORE_HOME)──
|
|
238
246
|
export function kitsDir() {
|
|
239
247
|
return path.join(getPackageRoot(), 'kits');
|
package/dist/trigger/feedback.js
CHANGED
|
@@ -69,6 +69,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
69
69
|
const deadlineTimer = setTimeout(() => abortDelivery('timeout', new Error(`target session timed out after ${TARGET_SESSION_DEADLINE_MS}ms`)), TARGET_SESSION_DEADLINE_MS);
|
|
70
70
|
deadlineTimer.unref?.();
|
|
71
71
|
let outcome;
|
|
72
|
+
let releaseSessionLock;
|
|
72
73
|
try {
|
|
73
74
|
if (delivery.signal.aborted) {
|
|
74
75
|
const aborted = targetSessionCancellationError(abortKind, delivery.signal.reason, false);
|
|
@@ -128,6 +129,20 @@ export class TriggerFeedbackDispatcher {
|
|
|
128
129
|
}
|
|
129
130
|
return this.failed(feedback, [], 'session_error', err?.message || String(err));
|
|
130
131
|
}
|
|
132
|
+
if (input.onSessionResolved) {
|
|
133
|
+
const access = await input.onSessionResolved(session);
|
|
134
|
+
if (access.kind === 'conflict') {
|
|
135
|
+
return {
|
|
136
|
+
status: 'skipped',
|
|
137
|
+
reason: 'concurrency_forbid',
|
|
138
|
+
conflictRunId: access.conflictRunId,
|
|
139
|
+
feedback,
|
|
140
|
+
effects: [],
|
|
141
|
+
error: null,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
releaseSessionLock = access.release;
|
|
145
|
+
}
|
|
131
146
|
const message = {
|
|
132
147
|
channel: target.channelKey,
|
|
133
148
|
channelType,
|
|
@@ -241,6 +256,7 @@ export class TriggerFeedbackDispatcher {
|
|
|
241
256
|
}
|
|
242
257
|
}
|
|
243
258
|
finally {
|
|
259
|
+
releaseSessionLock?.();
|
|
244
260
|
clearTimeout(deadlineTimer);
|
|
245
261
|
input.signal?.removeEventListener('abort', onInputAbort);
|
|
246
262
|
outcome?.cancel();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const HISTORY_CHANNELS = new Set(['aun', 'feishu', 'wechat', 'dingtalk', 'qqbot', 'wecom']);
|
|
2
|
+
/**
|
|
3
|
+
* Turns legacy raw session-file references into the controlled history CLI.
|
|
4
|
+
* The replacement deliberately keeps the explicit peer/channel scope but
|
|
5
|
+
* never carries a filesystem location into a Trigger prompt.
|
|
6
|
+
*/
|
|
7
|
+
export function rewriteLegacyTriggerSessionPaths(prompt, triggerAid) {
|
|
8
|
+
const legacyPath = /data\/sessions\/([A-Za-z0-9_-]+)\/([^/\s`"'<>]+)(?:\/([^/\s`"'<>]+))?\/messages\.jsonl/g;
|
|
9
|
+
return prompt.replace(legacyPath, (match, channel, first, second) => {
|
|
10
|
+
if (!HISTORY_CHANNELS.has(channel))
|
|
11
|
+
return match;
|
|
12
|
+
const isAun = channel === 'aun';
|
|
13
|
+
const target = isAun ? second : first;
|
|
14
|
+
const selfAid = triggerAid ?? (isAun ? first : undefined);
|
|
15
|
+
if (!selfAid || !target)
|
|
16
|
+
return match;
|
|
17
|
+
return `ec msg history ${selfAid} ${target} --channel ${channel} --session all --direction in --format json`;
|
|
18
|
+
});
|
|
19
|
+
}
|
package/dist/trigger/manager.js
CHANGED
|
@@ -4,6 +4,7 @@ import { agentTriggersDir } from '../paths.js';
|
|
|
4
4
|
import { definitionRevision, normalizeTriggerDefinition, resolveScriptPath, safeRelativePath, } from './validation.js';
|
|
5
5
|
import { atomicWriteJson } from '../core/session/session-fs-store.js';
|
|
6
6
|
import { TriggerHistoryStore } from './history.js';
|
|
7
|
+
import { rewriteLegacyTriggerSessionPaths } from './legacy-session-history.js';
|
|
7
8
|
export class TriggerDefinitionManager {
|
|
8
9
|
agentAid;
|
|
9
10
|
rootDir;
|
|
@@ -34,7 +35,17 @@ export class TriggerDefinitionManager {
|
|
|
34
35
|
if (!fs.existsSync(file))
|
|
35
36
|
return undefined;
|
|
36
37
|
const raw = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
37
|
-
|
|
38
|
+
const definition = normalizeTriggerDefinition(raw);
|
|
39
|
+
if (typeof definition.execution.prompt === 'string') {
|
|
40
|
+
const rewritten = rewriteLegacyTriggerSessionPaths(definition.execution.prompt, definition.agentAid);
|
|
41
|
+
if (rewritten !== definition.execution.prompt) {
|
|
42
|
+
definition.execution = { ...definition.execution, prompt: rewritten };
|
|
43
|
+
definition.updatedAt = Date.now();
|
|
44
|
+
this.writeDefinition(definition);
|
|
45
|
+
this.history.recordDefinition('trigger.updated', definition, { reason: 'legacy-session-history-paths' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return definition;
|
|
38
49
|
}
|
|
39
50
|
require(triggerId) {
|
|
40
51
|
const def = this.get(triggerId);
|
package/dist/trigger/parser.js
CHANGED
|
@@ -210,11 +210,13 @@ function parseTriggerThread(flags) {
|
|
|
210
210
|
return { ok: false, error: '--trigger-thread 不能为空' };
|
|
211
211
|
if (raw === 'per-run')
|
|
212
212
|
return { ok: true, value: 'per_run' };
|
|
213
|
+
if (raw === 'by-run')
|
|
214
|
+
return { ok: true, value: 'by_run' };
|
|
213
215
|
if (raw === 'by-trigger')
|
|
214
216
|
return { ok: true, value: 'by_trigger' };
|
|
215
|
-
if (raw === 'per_run' || raw === 'by_trigger')
|
|
217
|
+
if (raw === 'per_run' || raw === 'by_run' || raw === 'by_trigger')
|
|
216
218
|
return { ok: true, value: raw };
|
|
217
|
-
return { ok: false, error: '--trigger-thread 只接受
|
|
219
|
+
return { ok: false, error: '--trigger-thread 只接受 by-run 或 by-trigger(兼容 per-run)' };
|
|
218
220
|
}
|
|
219
221
|
function parseTargetSession(flags) {
|
|
220
222
|
if (!flags.has('target-session'))
|