evolcore 0.0.32 → 0.0.34
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 +61 -0
- package/bin/ec.js +3 -2
- package/bin/install-codex-managed-hooks.mjs +135 -37
- package/dist/agents/baseagent-availability.js +20 -36
- package/dist/agents/claude-runner.js +111 -15
- package/dist/agents/codex/app-server-client.js +3 -0
- package/dist/agents/codex/diagnostics.js +112 -54
- package/dist/agents/codex-runner.js +241 -63
- package/dist/agents/ecagent-runner.js +78 -33
- package/dist/agents/runner-types.js +5 -6
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/group/operations.js +0 -1
- package/dist/aun/msg/history.js +1 -0
- package/dist/aun/msg/p2p.js +0 -1
- package/dist/aun/outbox.js +50 -1
- package/dist/channels/aun.js +44 -8
- package/dist/channels/daemon.js +261 -3
- package/dist/cli/agent-command.js +58 -24
- package/dist/cli/agent.js +1 -1
- package/dist/cli/aun-commands.js +368 -31
- package/dist/cli/contact.js +8 -2
- package/dist/cli/ctl-command.js +3 -1
- package/dist/cli/daemon-commands.js +197 -27
- package/dist/cli/debug-mode.js +154 -0
- package/dist/cli/fs-command.js +2 -1
- package/dist/cli/handoff-command.js +3 -0
- package/dist/cli/index.js +98 -67
- package/dist/cli/init.js +2 -2
- package/dist/cli/integrity-command.js +196 -0
- package/dist/cli/managed-command-guard.js +5 -0
- package/dist/cli/memory-command.js +166 -146
- package/dist/cli/queue-command.js +9 -4
- package/dist/cli/session-command.js +194 -0
- package/dist/cli/skill-command.js +78 -2
- package/dist/cli/task-context.js +1 -0
- package/dist/cli/thread-command.js +622 -0
- package/dist/cli/trigger-command.js +10 -3
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-field-policy.js +6 -3
- package/dist/config/config-manager.js +26 -2
- package/dist/config/contact-book-store.js +5 -0
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config/role-service.js +13 -0
- package/dist/config/runtime-env.js +16 -0
- package/dist/config-store.js +45 -0
- package/dist/core/audit/log-integrity.js +3 -1
- package/dist/core/auth/agent-delegation.js +133 -36
- package/dist/core/auth/debug-context.js +139 -0
- package/dist/core/auth/delegation-diagnostics.js +414 -0
- package/dist/core/auth/operation-authorizer.js +25 -2
- package/dist/core/auth/operation-catalog.js +49 -0
- package/dist/core/background-session/session-cleanup.js +212 -0
- package/dist/core/background-session/types.js +10 -0
- package/dist/core/bootstrap-messages.js +1 -1
- package/dist/core/bootstrap-service.js +6 -3
- package/dist/core/command/agent-control.js +18 -26
- package/dist/core/command/command-handler.js +197 -27
- package/dist/core/command/daemon-diagnostics.js +1 -0
- package/dist/core/command/memory-slash.js +6 -2
- package/dist/core/command/menu-catalog.js +51 -1
- package/dist/core/command/menu-handler.js +114 -23
- package/dist/core/command/menu-protocol.js +25 -1
- package/dist/core/command/skill-slash.js +322 -0
- package/dist/core/command/slash-gate.js +6 -4
- package/dist/core/command/slash-handler.js +195 -13
- package/dist/core/command/topic-slash.js +528 -0
- package/dist/core/daemon-bootstrap.js +4 -7
- package/dist/core/evolagent-registry.js +20 -5
- package/dist/core/file-integrity/read.js +61 -0
- package/dist/core/file-integrity/store.js +262 -0
- package/dist/core/handoff/runtime.js +5 -11
- package/dist/core/handoff/store.js +5 -0
- package/dist/core/ipc-registration.js +175 -3
- package/dist/core/memory/batch-meta.js +132 -0
- package/dist/core/memory/consolidation-context.js +83 -29
- package/dist/core/memory/consolidation-ops-records.js +49 -16
- package/dist/core/memory/consolidation-queue-format.js +21 -0
- package/dist/core/memory/consolidation.js +264 -205
- package/dist/core/memory/index-manager.js +19 -28
- package/dist/core/memory/memory-admin.js +19 -14
- package/dist/core/memory/memory-document.js +53 -9
- package/dist/core/memory/memory-writer.js +30 -15
- package/dist/core/message/aun-ipc-sender.js +161 -6
- package/dist/core/message/im-renderer.js +169 -10
- package/dist/core/message/message-bridge.js +15 -4
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/peer-mode.js +6 -1
- package/dist/core/message/response-engine.js +929 -110
- package/dist/core/message/subtask-tool-projection.js +140 -0
- package/dist/core/model/catalog-service.js +17 -12
- package/dist/core/permission/ec-command-parser.js +217 -9
- package/dist/core/permission/protected-paths.js +5 -1
- package/dist/core/permission/readonly-shell-query.js +43 -5
- package/dist/core/permission/session-path-grants.js +334 -0
- package/dist/core/permission/tool-canonical.js +226 -0
- package/dist/core/permission/tool-policy.js +30 -62
- package/dist/core/role/runtime-policy.js +21 -10
- package/dist/core/session/session-fs-store.js +123 -8
- package/dist/core/session/session-idle-monitor.js +249 -22
- package/dist/core/session/session-manager.js +129 -14
- package/dist/core/skill/command-parser.js +13 -0
- package/dist/core/skill/index-generator.js +21 -4
- package/dist/core/skill/startup.js +41 -0
- package/dist/core/skill/switch-resolver.js +55 -29
- package/dist/core/system-session/grants.js +40 -0
- package/dist/core/system-session/memory.js +222 -0
- package/dist/core/system-session/registry.js +74 -0
- package/dist/core/system-session/types.js +14 -0
- package/dist/core/thread/command-parser.js +125 -0
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +95 -0
- package/dist/core/thread/thread-context-storage.js +131 -0
- package/dist/core/thread/thread-operation.js +258 -0
- package/dist/core/thread/thread-route.js +33 -0
- package/dist/core/thread/thread-service.js +770 -0
- package/dist/core/thread/types.js +1 -0
- package/dist/eck/kit-renderer.js +7 -2
- package/dist/eck/manifest-engine.js +24 -4
- package/dist/eck/message-renderer.js +35 -0
- package/dist/index.js +19 -7
- package/dist/ipc.js +140 -50
- package/dist/paths.js +93 -0
- package/dist/response-system/engines/v1/proactive-flow.js +169 -80
- package/dist/stats/billing.js +20 -8
- package/dist/trigger/authorization.js +57 -28
- package/dist/trigger/feedback.js +13 -2
- package/dist/trigger/parser.js +70 -1
- package/dist/trigger/system-definitions.js +3 -3
- package/dist/trigger/validation.js +14 -0
- package/dist/utils/cross-platform.js +11 -2
- package/dist/utils/error-dict.json +18 -4
- package/dist/utils/error-utils.js +143 -1
- package/dist/utils/instance-registry.js +13 -8
- package/dist/utils/log-writer.js +12 -0
- package/dist/utils/process-introspect.js +11 -0
- package/kits/docs/context-assembly.md +1 -1
- package/kits/docs/evolcore/INDEX.md +1 -0
- package/kits/docs/evolcore/agent-create.md +40 -28
- package/kits/docs/evolcore/agent.md +21 -6
- package/kits/docs/evolcore/config.md +2 -2
- package/kits/docs/evolcore/ctl.md +2 -2
- package/kits/docs/evolcore/ec-capabilities.md +5 -1
- package/kits/docs/evolcore/fs-architecture.md +4 -5
- package/kits/docs/evolcore/fs.md +1 -1
- package/kits/docs/evolcore/group-collaboration.md +4 -6
- package/kits/docs/evolcore/group.md +11 -12
- package/kits/docs/evolcore/memory-architecture.md +4 -5
- package/kits/docs/evolcore/memory-consolidation.md +19 -15
- package/kits/docs/evolcore/memory-tags.md +3 -1
- package/kits/docs/evolcore/memory.md +24 -12
- package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
- package/kits/docs/evolcore/menu-protocol.md +7 -0
- package/kits/docs/evolcore/model.md +16 -0
- package/kits/docs/evolcore/msg.md +8 -11
- package/kits/docs/evolcore/thread-chain.md +267 -0
- package/kits/docs/prompt-loading-architecture.md +1 -1
- package/kits/eck_manifest.json +55 -40
- package/kits/eck_manifest.memory.json +0 -12
- package/kits/eck_message_manifest.json +169 -10
- package/kits/rules/01-overview.md +11 -0
- package/kits/rules/03-identity.md +6 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +1 -1
- package/kits/rules/07-memory-and-thread.md +199 -0
- package/kits/schemas/_meta.json +7 -1
- package/kits/schemas/agent-config.schema.13.json +1 -1
- package/kits/schemas/daemon.schema.7.json +140 -0
- package/kits/schemas/relation-config.schema.9.json +18 -3
- package/kits/schemas/role-config.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.1.json +6 -6
- package/kits/schemas/single-session.schema.2.json +6 -6
- package/kits/schemas/single-session.schema.3.json +6 -6
- package/kits/skills/.switches.json +12 -1
- package/kits/skills/ec-group/SKILL.md +234 -0
- package/kits/skills/ec-skill/SKILL.md +10 -1
- package/kits/skills/ec-skill/scripts/cli.mjs +16 -2
- package/kits/skills/ec-skill/scripts/skill.mjs +1 -1
- package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
- package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
- package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
- package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
- package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
- package/kits/skills/thread-ops/SKILL.md +492 -0
- package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
- package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
- package/kits/skills/wechat-article-reader/SKILL.md +97 -0
- package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
- package/kits/templates/bootstrap-welcome.md +7 -7
- package/kits/templates/memory-consolidation/forget.md +7 -2
- package/kits/templates/memory-consolidation/generalize.md +9 -4
- package/kits/templates/memory-consolidation/notes.md +11 -11
- package/kits/templates/memory-consolidation/profile.md +8 -3
- package/kits/templates/memory-consolidation/promote.md +8 -3
- package/kits/templates/memory-consolidation/workflow.md +6 -6
- package/kits/templates/message-fragments/handoff-request-to-target.md +1 -1
- package/kits/templates/message-fragments/item.md +2 -1
- package/kits/templates/message-fragments/thread-context.md +6 -0
- package/kits/templates/message-fragments/trigger-session.md +2 -0
- package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
- package/kits/templates/roles/member.json +2 -0
- package/kits/templates/roles/visitor.json +2 -0
- package/kits/templates/system-fragments/bootstrap.md +67 -72
- package/kits/templates/system-fragments/channel.md +3 -6
- package/kits/templates/system-fragments/commands.md +1 -0
- package/kits/templates/system-fragments/managed-runtime.md +15 -0
- package/kits/templates/system-fragments/memory.md +16 -9
- package/kits/templates/system-fragments/reply.md +7 -6
- package/kits/templates/system-fragments/session.md +5 -14
- package/package.json +6 -3
- package/dist/core/memory/memory-session-policy.js +0 -41
- package/dist/core/memory/memory-signature.js +0 -257
- package/kits/docs/evolcore/group-fs.md +0 -17
- package/kits/docs/venues/aun-group.md +0 -45
- package/kits/docs/venues/group.md +0 -43
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,67 @@
|
|
|
5
5
|
|
|
6
6
|
## Unreleased
|
|
7
7
|
|
|
8
|
+
## 0.0.34 (2026-10-18)
|
|
9
|
+
|
|
10
|
+
### 模型与上下文
|
|
11
|
+
|
|
12
|
+
- 统一 Claude Code、Codex 和 ecagent 的模型参数解析与上下文窗口统计,减少执行窗口、压缩阈值和用量展示之间的不一致。
|
|
13
|
+
- Claude Code 和 ecagent 按模型参数表应用上下文窗口与输出上限;Codex 优先使用 app-server 提供的实时窗口,缺失时仅补充统计信息,不虚构执行窗口。
|
|
14
|
+
- 统一模型窗口后缀、模型参数覆盖和查询/压缩路径的处理,支持新模型参数在不修改 runner 代码的情况下生效。
|
|
15
|
+
|
|
16
|
+
### 会话与工具
|
|
17
|
+
|
|
18
|
+
- 完善 Codex 排队任务取消及中断后的状态核验,避免停止操作影响错误轮次。
|
|
19
|
+
- 改进 Shell 工具结果处理,分别保留实际退出码、原始输出和错误摘要,避免将普通输出误当作失败原因。
|
|
20
|
+
- 新增任务授权与会话凭据生命周期诊断,提供可追踪的失效原因和事件信息。
|
|
21
|
+
- 闲置巡检覆盖私聊与群聊,开启前校验必要配置,仅针对未完成且停滞的事项推进或提醒。
|
|
22
|
+
- 补充任务运行结果的结构化错误类型、终止原因和原始诊断信息,区分超时、输出上限、协议不完整及目标会话丢失等终态。
|
|
23
|
+
|
|
24
|
+
### 错误反馈与运行稳定性
|
|
25
|
+
|
|
26
|
+
- 细化 AUN 错误反馈展示,保留原始错误详情并避免将未知 403 错误套用无差别的重试或“API 访问受限”提示。
|
|
27
|
+
- 对客户端过旧、积分不足、团队上下文超限等已知 403 原因提供针对性提示;未知原因保留诊断信息并停止自动猜测。
|
|
28
|
+
- 支持目标会话丢失、触发器超时和输出上限等错误在消息协议中携带稳定的 `subtype` 与 `reason`。
|
|
29
|
+
- 抑制 CLI 子进程的 Node.js 实验性 SQLite 警告,减少正常命令输出噪声。
|
|
30
|
+
- 支持创建 AID 时明确登记主体类型,避免身份类型缺失。
|
|
31
|
+
|
|
32
|
+
### 管理与发布
|
|
33
|
+
|
|
34
|
+
- 支持同时具备目标 Agent Owner 与 Daemon Owner 身份的用户,通过菜单配置 Agent Fullaccess。
|
|
35
|
+
- Trigger 创建支持填写说明,并在列表和详情中展示。
|
|
36
|
+
- 优化 Windows 进程探测与启动、停止速度,修正 Node 路径识别,并统一 Claude 可用性检测与实际执行程序。
|
|
37
|
+
- 统一列表类命令参数的解析,减少 PowerShell 下逗号分隔参数与审批校验不一致的问题。
|
|
38
|
+
- 升级 AUN SDK 至 `0.5.20`,并收紧 npm 包发布内容,避免将内部文件完整性写入模块打入发行包。
|
|
39
|
+
|
|
40
|
+
### 兼容性调整
|
|
41
|
+
|
|
42
|
+
- 首次设定的协作交接统一写入 `persona.md`;`personal.md` 不再自动注入上下文。
|
|
43
|
+
- 移除 `ec memory feedback` 命令,整理反馈改由专用会话按任务要求写入反馈文件。
|
|
44
|
+
|
|
45
|
+
## 0.0.33 (2026-10-15)
|
|
46
|
+
|
|
47
|
+
### 话题与会话
|
|
48
|
+
|
|
49
|
+
- 新增话题管理与跨话题协作,支持查询历史、维护摘要和状态、删除与恢复话题,并通过定时复查跟进跨话题消息。
|
|
50
|
+
- 新增当前主会话和话题的闲置触发设置,可通过聊天命令或菜单单独开启、关闭和调整等待时间。
|
|
51
|
+
- 支持按会话编号查找本地存档,完善话题上下文衔接和后台会话清理。
|
|
52
|
+
- 改进消息中断与任务恢复,避免已提交输入重复执行或未提交输入丢失。
|
|
53
|
+
- 优化后台任务与子智能体的状态展示,将关联任务结果合并到原工具卡片,减少重复提示,并正确展示耗时及完成、失败、停止等状态。
|
|
54
|
+
|
|
55
|
+
### Agent 与模型
|
|
56
|
+
|
|
57
|
+
- 简化首次设定:沿用已有有效资料,仅确认缺失、歧义或新增内容;人格和头像可稍后完善,正式欢迎文案由 Agent 自主准备。
|
|
58
|
+
- 完善模型推理强度选项,在模型目录未提供能力信息时按基座支持范围提供选项,并统一角色与关系设置。
|
|
59
|
+
- 强化 Codex 安装与启动检查,支持修复失效绑定,切换到另一套有效安装路径前要求明确确认。
|
|
60
|
+
- 改进 Codex 工具结果诊断,区分策略拒绝、用户拒绝和实际执行结果,减少错误归因。
|
|
61
|
+
|
|
62
|
+
### 权限与运行稳定性
|
|
63
|
+
|
|
64
|
+
- 强化受管命令、话题操作及个人和群文件访问的身份与目标校验,发送被拒时提供更明确的原因。
|
|
65
|
+
- 无人值守任务不再请求交互审批,任务恢复与跨会话交接沿用原有审批策略。
|
|
66
|
+
- 查看任务运行上下文不再消耗一次性授权,避免后续操作重复审批。
|
|
67
|
+
- 修复重启提示被恢复后的进程重复投递的问题,并在无法判断错误原因时保留原始诊断信息。
|
|
68
|
+
|
|
8
69
|
## 0.0.32 (2026-10-12)
|
|
9
70
|
|
|
10
71
|
- 统一受管命令的原始参数与审批哈希校验,按会话项目目录解析 Agent 初始化、人格和头像文件,强化授权后的文件访问边界。
|
package/bin/ec.js
CHANGED
|
@@ -11,6 +11,7 @@ const repoRoot = path.resolve(here, '..');
|
|
|
11
11
|
const srcEntry = path.join(repoRoot, 'src', 'cli', 'index.ts');
|
|
12
12
|
const distEntry = path.join(repoRoot, 'dist', 'cli', 'index.js');
|
|
13
13
|
const args = process.argv.slice(2);
|
|
14
|
+
const nodeOptions = ['--no-warnings=ExperimentalWarning'];
|
|
14
15
|
|
|
15
16
|
// tsx derives its cache directory from `process.geteuid()` on POSIX and
|
|
16
17
|
// `os.userInfo()` on Windows. In managed Windows sessions the latter can
|
|
@@ -26,13 +27,13 @@ if (fs.existsSync(srcEntry)) {
|
|
|
26
27
|
const imports = tsxWindowsCompatImport
|
|
27
28
|
? ['--import', tsxWindowsCompatImport, '--import', tsxImport]
|
|
28
29
|
: ['--import', tsxImport];
|
|
29
|
-
const result = spawnSync(process.execPath, [...imports, srcEntry, ...args], { stdio: 'inherit' });
|
|
30
|
+
const result = spawnSync(process.execPath, [...nodeOptions, ...imports, srcEntry, ...args], { stdio: 'inherit' });
|
|
30
31
|
process.exit(result.status ?? (result.error ? 1 : 0));
|
|
31
32
|
} catch {}
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
if (fs.existsSync(distEntry)) {
|
|
35
|
-
const result = spawnSync(process.execPath, [distEntry, ...args], { stdio: 'inherit' });
|
|
36
|
+
const result = spawnSync(process.execPath, [...nodeOptions, distEntry, ...args], { stdio: 'inherit' });
|
|
36
37
|
process.exit(result.status ?? (result.error ? 1 : 0));
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
7
7
|
import { execFileSync } from 'node:child_process';
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
9
9
|
import { isDeepStrictEqual } from 'node:util';
|
|
@@ -285,8 +285,66 @@ export function samePackageRoot(embedded, expected) {
|
|
|
285
285
|
return normalize(embedded) === normalize(expected) || resolved(embedded) === resolved(expected);
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
// Windows accepts an executable path without its `.exe` suffix. Keep an older
|
|
289
|
+
// `...\\node` binding from being treated as a different runtime than
|
|
290
|
+
// `...\\node.exe` during installer verification.
|
|
291
|
+
function sameRuntimePath(embedded, expected) {
|
|
292
|
+
if (samePackageRoot(embedded, expected)) return true;
|
|
293
|
+
if (process.platform !== 'win32' || !embedded) return false;
|
|
294
|
+
const appendExe = value => path.extname(value) ? value : `${value}.exe`;
|
|
295
|
+
return samePackageRoot(appendExe(embedded), expected)
|
|
296
|
+
|| samePackageRoot(embedded, appendExe(expected));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function normalizedPath(value) {
|
|
300
|
+
return path.normalize(String(value || '')).replace(/[\\/]+$/, '').toLowerCase();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function parseManagedCommand(value, hookPath) {
|
|
304
|
+
if (typeof value !== 'string') return null;
|
|
305
|
+
const match = /^"([^"\r\n]+)"\s+"([^"\r\n]+)"\s+%EVOLCORE_INSTANCE_SOCKET%$/i.exec(value.trim());
|
|
306
|
+
if (!match) return null;
|
|
307
|
+
const nodePath = match[1];
|
|
308
|
+
const commandHookPath = match[2];
|
|
309
|
+
if (!path.isAbsolute(nodePath) || /[%!]/.test(nodePath + commandHookPath)) return null;
|
|
310
|
+
if (normalizedPath(commandHookPath) !== normalizedPath(hookPath)) return null;
|
|
311
|
+
return { nodePath };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function runtimeFileMayExist(file) {
|
|
315
|
+
try { return fs.statSync(file).isFile(); }
|
|
316
|
+
catch (error) { return !['ENOENT', 'ENOTDIR'].includes(error?.code); }
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export function managedBinding(source, launcher, hookPath) {
|
|
320
|
+
const embeddedPackageRoot = launcherPackageRoot(launcher);
|
|
321
|
+
if (!embeddedPackageRoot || !path.isAbsolute(embeddedPackageRoot)
|
|
322
|
+
|| launcher.replaceAll('\r\n', '\n') !== managedHookLauncher(embeddedPackageRoot)) return null;
|
|
323
|
+
const retained = removeManagedBlock(source);
|
|
324
|
+
if (retained === source) return null;
|
|
325
|
+
const original = parseToml(source);
|
|
326
|
+
const retainedConfig = parseToml(retained);
|
|
327
|
+
const groups = original.hooks?.PreToolUse;
|
|
328
|
+
const retainedGroups = retainedConfig.hooks?.PreToolUse || [];
|
|
329
|
+
const owned = groups.filter(group => !retainedGroups.some(other => isDeepStrictEqual(group, other)));
|
|
330
|
+
if (owned.length !== 1) return null;
|
|
331
|
+
const group = owned[0];
|
|
332
|
+
if (group.matcher !== '*' || !Array.isArray(group.hooks) || group.hooks.length !== 1) return null;
|
|
333
|
+
const handler = group.hooks[0];
|
|
334
|
+
if (handler.type !== 'command' || handler.async === true) return null;
|
|
335
|
+
const command = parseManagedCommand(handler.command, hookPath);
|
|
336
|
+
const windowsCommand = parseManagedCommand(handler.command_windows, hookPath);
|
|
337
|
+
if (!command || !windowsCommand || normalizedPath(command.nodePath) !== normalizedPath(windowsCommand.nodePath)) return null;
|
|
338
|
+
if (!isDeepStrictEqual(group, { matcher: '*', hooks: [{
|
|
339
|
+
type: 'command', command: handler.command, command_windows: handler.command_windows,
|
|
340
|
+
statusMessage: 'Checking EvolCore session policy',
|
|
341
|
+
}] })) return null;
|
|
342
|
+
if (retainedGroups.some(other => JSON.stringify(other).toLowerCase().includes('pre-tool-use.mjs'))) return null;
|
|
343
|
+
return { embeddedPackageRoot, managedNodePath: command.nodePath };
|
|
344
|
+
}
|
|
345
|
+
|
|
288
346
|
/** Inspect only the canonical EvolCore managed-hook targets. */
|
|
289
|
-
export function inspectManagedHookInstallation({ requirements, managedDir, packageRoot }) {
|
|
347
|
+
export function inspectManagedHookInstallation({ requirements, managedDir, packageRoot, nodePath = process.execPath }) {
|
|
290
348
|
const canonicalRequirements = path.resolve(requirements);
|
|
291
349
|
const canonicalManagedDir = path.resolve(managedDir);
|
|
292
350
|
const hookPath = path.join(canonicalManagedDir, 'pre-tool-use.mjs');
|
|
@@ -297,11 +355,12 @@ export function inspectManagedHookInstallation({ requirements, managedDir, packa
|
|
|
297
355
|
return { status: 'unsafe', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: `${directory} must be a real directory` };
|
|
298
356
|
}
|
|
299
357
|
} catch (error) {
|
|
300
|
-
if (error?.code !== 'ENOENT') return { status: '
|
|
358
|
+
if (error?.code !== 'ENOENT') return { status: 'unavailable', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: error?.message || String(error) };
|
|
301
359
|
}
|
|
302
360
|
}
|
|
303
361
|
const req = regularFile(canonicalRequirements);
|
|
304
362
|
const hook = regularFile(hookPath);
|
|
363
|
+
if (req.error || hook.error) return { status: 'unavailable', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: 'unable to inspect requirements or launcher' };
|
|
305
364
|
if (req.unsafe || hook.unsafe) return { status: 'unsafe', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: 'requirements or launcher is not a regular file' };
|
|
306
365
|
if (!req.ok && hook.ok) return { status: 'unsafe', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: 'canonical launcher exists but requirements.toml is missing' };
|
|
307
366
|
if (req.ok && !hook.ok) {
|
|
@@ -324,48 +383,81 @@ export function inspectManagedHookInstallation({ requirements, managedDir, packa
|
|
|
324
383
|
}
|
|
325
384
|
}
|
|
326
385
|
if (!req.ok || !hook.ok) return { status: 'missing', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: 'requirements or launcher is missing' };
|
|
327
|
-
let
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
386
|
+
let source;
|
|
387
|
+
let launcher;
|
|
388
|
+
try {
|
|
389
|
+
source = fs.readFileSync(canonicalRequirements, 'utf8');
|
|
390
|
+
launcher = fs.readFileSync(hookPath, 'utf8');
|
|
391
|
+
} catch (error) {
|
|
392
|
+
return { status: 'unavailable', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: error?.message || String(error) };
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
const parsed = parseToml(source);
|
|
396
|
+
const binding = managedBinding(source, launcher, hookPath);
|
|
397
|
+
if (!binding || parsed.allow_managed_hooks_only !== true || parsed.features?.hooks !== true
|
|
398
|
+
|| normalizedPath(parsed.hooks?.windows_managed_dir) !== normalizedPath(canonicalManagedDir)
|
|
399
|
+
|| (parsed.hooks?.managed_dir !== undefined
|
|
400
|
+
&& normalizedPath(parsed.hooks.managed_dir) !== normalizedPath(canonicalManagedDir))) {
|
|
401
|
+
throw new Error('managed-hook policy is missing, altered, or points outside the canonical target');
|
|
402
|
+
}
|
|
403
|
+
const { embeddedPackageRoot, managedNodePath } = binding;
|
|
404
|
+
const packageMatches = samePackageRoot(embeddedPackageRoot, path.resolve(packageRoot || process.cwd()));
|
|
405
|
+
const nodeMatches = sameRuntimePath(managedNodePath, nodePath);
|
|
406
|
+
const state = {
|
|
407
|
+
requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath,
|
|
408
|
+
managedPackageRoot: embeddedPackageRoot, managedNodePath,
|
|
409
|
+
repairFingerprint: createHash('sha256').update(source).update('\0').update(launcher).digest('hex'),
|
|
410
|
+
};
|
|
411
|
+
if (packageMatches && nodeMatches) return { ...state, status: 'installed' };
|
|
412
|
+
return {
|
|
413
|
+
...state, status: 'stale',
|
|
414
|
+
repairAmbiguous: runtimeFileMayExist(path.join(embeddedPackageRoot, 'bin', 'codex-managed-hook.mjs'))
|
|
415
|
+
&& runtimeFileMayExist(managedNodePath),
|
|
416
|
+
reason: !packageMatches && !nodeMatches
|
|
417
|
+
? 'managed-hook points to a different EvolCore package root and Node runtime'
|
|
418
|
+
: !packageMatches ? 'managed-hook points to a different EvolCore package root'
|
|
419
|
+
: 'managed-hook points to a different Node runtime',
|
|
420
|
+
};
|
|
421
|
+
} catch (error) {
|
|
422
|
+
return { status: 'unsafe', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, reason: error?.message || String(error) };
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/** Idempotently repair a missing or stale canonical installation; unsafe edits fail closed. */
|
|
356
427
|
export function repairManagedHookInstallation(options, acl = windowsAcl) {
|
|
357
428
|
const { requirements, managedDir, packageRoot, nodePath = process.execPath } = options;
|
|
358
429
|
const canonicalRequirements = path.resolve(requirements);
|
|
359
430
|
const canonicalManagedDir = path.resolve(managedDir);
|
|
360
431
|
const hookPath = path.join(canonicalManagedDir, 'pre-tool-use.mjs');
|
|
361
432
|
const sourceHook = path.join(packageRoot, 'bin', 'codex-managed-hook.mjs');
|
|
362
|
-
const state = inspectManagedHookInstallation({ requirements: canonicalRequirements, managedDir: canonicalManagedDir, packageRoot });
|
|
433
|
+
const state = inspectManagedHookInstallation({ requirements: canonicalRequirements, managedDir: canonicalManagedDir, packageRoot, nodePath });
|
|
363
434
|
if (state.status === 'installed') return { ...state, repaired: false, warnings: [] };
|
|
364
|
-
if (state.status
|
|
435
|
+
if (!['missing', 'stale'].includes(state.status)) throw new Error(`Refusing automatic managed-hook repair: ${state.reason}`);
|
|
436
|
+
if (state.status === 'stale' && (options.expectedFingerprint !== state.repairFingerprint
|
|
437
|
+
|| (state.repairAmbiguous && options.confirmRebind !== true))) {
|
|
438
|
+
throw new Error('Refusing automatic managed-hook repair: binding changed or requires explicit confirmation');
|
|
439
|
+
}
|
|
365
440
|
if (!fs.existsSync(sourceHook)) throw new Error(`Required Hook runtime file was not found: ${sourceHook}`);
|
|
366
441
|
const previousContent = fs.existsSync(canonicalRequirements) ? fs.readFileSync(canonicalRequirements, 'utf8') : '';
|
|
367
442
|
const content = buildManagedRequirements(previousContent, { targetDirectory: canonicalManagedDir, nodePath, hookPath });
|
|
368
|
-
const
|
|
443
|
+
const inspect = () => inspectManagedHookInstallation({
|
|
444
|
+
requirements: canonicalRequirements, managedDir: canonicalManagedDir, packageRoot, nodePath,
|
|
445
|
+
});
|
|
446
|
+
const warnings = provisionManagedFiles({
|
|
447
|
+
requirements: canonicalRequirements, hookPath, sourceHook, nodePath, previousContent, content,
|
|
448
|
+
launcher: managedHookLauncher(packageRoot),
|
|
449
|
+
beforePublish: () => {
|
|
450
|
+
const latest = inspect();
|
|
451
|
+
if (latest.status !== state.status || latest.repairFingerprint !== state.repairFingerprint
|
|
452
|
+
|| latest.repairAmbiguous !== state.repairAmbiguous) {
|
|
453
|
+
throw new Error('Managed-hook state changed before publication; retry the startup check');
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
verifyPublished: () => {
|
|
457
|
+
const verified = inspect();
|
|
458
|
+
if (verified.status !== 'installed') throw new Error('Managed-hook verification failed: ' + verified.reason);
|
|
459
|
+
},
|
|
460
|
+
}, acl);
|
|
369
461
|
return { status: 'installed', requirements: canonicalRequirements, managedDir: canonicalManagedDir, hookPath, repaired: true, warnings };
|
|
370
462
|
}
|
|
371
463
|
|
|
@@ -475,6 +567,7 @@ export function provisionManagedFiles(options, acl = windowsAcl) {
|
|
|
475
567
|
let committed = false;
|
|
476
568
|
try {
|
|
477
569
|
fs.writeFileSync(lock, JSON.stringify({ pid: process.pid, started: new Date().toISOString() }));
|
|
570
|
+
options.beforePublish?.();
|
|
478
571
|
const existing = existingFile(requirements, fs);
|
|
479
572
|
// Detect edits made after configuration generation, including a second
|
|
480
573
|
// installer completing just before this process acquired the lock.
|
|
@@ -509,11 +602,13 @@ export function provisionManagedFiles(options, acl = windowsAcl) {
|
|
|
509
602
|
const target = temporary ? entry.temporary : entry.file;
|
|
510
603
|
if (fs.readFileSync(target, 'utf8') !== entry.value) throw new Error(`Installed content differs: ${target}`);
|
|
511
604
|
}
|
|
512
|
-
|
|
605
|
+
const report = acl('verify', { entries: [
|
|
513
606
|
{ path: directory, protected: true, execute: true },
|
|
514
607
|
...staged.map(entry => ({ path: temporary ? entry.temporary : entry.file, protected: true })),
|
|
515
608
|
...readable,
|
|
516
609
|
] });
|
|
610
|
+
if (temporary === false) options.verifyPublished?.();
|
|
611
|
+
return report;
|
|
517
612
|
};
|
|
518
613
|
verify(true);
|
|
519
614
|
let accessReport;
|
|
@@ -561,7 +656,10 @@ function main() {
|
|
|
561
656
|
if (!fs.statSync(file).isFile()) fail(`Required Hook runtime file was not found: ${file}`);
|
|
562
657
|
}
|
|
563
658
|
if (hasArgument('--repair')) {
|
|
564
|
-
const result = repairManagedHookInstallation({
|
|
659
|
+
const result = repairManagedHookInstallation({
|
|
660
|
+
requirements, managedDir: targetDirectory, packageRoot, nodePath,
|
|
661
|
+
expectedFingerprint: argument('--expected-fingerprint'), confirmRebind: hasArgument('--confirm-rebind'),
|
|
662
|
+
});
|
|
565
663
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
566
664
|
return;
|
|
567
665
|
}
|
|
@@ -1,39 +1,17 @@
|
|
|
1
1
|
import { normalizeBaseagent } from './baseagent.js';
|
|
2
2
|
import { commandExists } from '../utils/cross-platform.js';
|
|
3
3
|
import { getCodexAppServerAvailability } from './codex-runner.js';
|
|
4
|
-
import {
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
const _resolveModule = createRequire(import.meta.url);
|
|
4
|
+
import { probeBundledClaudeVersion, resolveBundledClaudeExecutable } from './claude-runner.js';
|
|
8
5
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* Claude 的检测判据就是执行判据:会话只会在 Windows 上跑内置的、与 SDK 锁定版本
|
|
7
|
+
* 配套的 claude.exe。PATH 里的全局 claude 执行层从不使用,因此不能作为可用判据——
|
|
8
|
+
* 那个假阳性正是「检测说可用、会话全失败」持续 21 小时没被发现的成因。
|
|
12
9
|
*/
|
|
13
|
-
function
|
|
14
|
-
if (process.platform
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
: process.arch === 'x64'
|
|
19
|
-
? '@anthropic-ai/claude-agent-sdk-win32-x64'
|
|
20
|
-
: undefined;
|
|
21
|
-
if (!nativePackage)
|
|
22
|
-
return false;
|
|
23
|
-
try {
|
|
24
|
-
const exe = _resolveModule.resolve(`${nativePackage}/claude.exe`);
|
|
25
|
-
if (fs.existsSync(exe))
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
catch { /* fall through */ }
|
|
29
|
-
try {
|
|
30
|
-
const sdkEntry = _resolveModule.resolve('@anthropic-ai/claude-agent-sdk');
|
|
31
|
-
const exe = path.resolve(path.dirname(sdkEntry), '..', '@anthropic-ai', nativePackage.slice('@anthropic-ai/'.length), 'claude.exe');
|
|
32
|
-
return fs.existsSync(exe);
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
10
|
+
function claudeExecutable() {
|
|
11
|
+
if (process.platform === 'win32')
|
|
12
|
+
return resolveBundledClaudeExecutable();
|
|
13
|
+
// 非 Windows 平台由 SDK 自己解析平台包,此处沿用命令探测。
|
|
14
|
+
return commandExists('claude') ? 'claude' : undefined;
|
|
37
15
|
}
|
|
38
16
|
export const BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini', 'ecagent'];
|
|
39
17
|
export const AUTO_BASEAGENT_CANDIDATES = ['claude', 'codex', 'gemini'];
|
|
@@ -49,19 +27,25 @@ export function detectAvailableBaseagents(codexAvailability = getCodexAppServerA
|
|
|
49
27
|
if (baseagent === 'codex')
|
|
50
28
|
return codexAvailability.available;
|
|
51
29
|
if (baseagent === 'claude')
|
|
52
|
-
return
|
|
30
|
+
return claudeExecutable() !== undefined;
|
|
53
31
|
return commandExists(baseagent);
|
|
54
32
|
});
|
|
55
33
|
}
|
|
56
34
|
export function detectBaseagentDetails(codexAvailability = getCodexAppServerAvailability()) {
|
|
57
|
-
const claude =
|
|
35
|
+
const claude = claudeExecutable();
|
|
36
|
+
const claudeVersion = claude ? probeBundledClaudeVersion() : undefined;
|
|
58
37
|
const gemini = commandExists('gemini');
|
|
59
38
|
return [
|
|
60
39
|
{
|
|
61
40
|
id: 'claude',
|
|
62
|
-
detected: claude,
|
|
63
|
-
detectionSource: claude ? ['PATH'] : [],
|
|
64
|
-
reason: claude
|
|
41
|
+
detected: claude !== undefined,
|
|
42
|
+
detectionSource: claude ? [process.platform === 'win32' ? 'bundled SDK binary' : 'PATH'] : [],
|
|
43
|
+
reason: claude
|
|
44
|
+
? undefined
|
|
45
|
+
: process.platform === 'win32'
|
|
46
|
+
? '未找到内置 claude.exe(@anthropic-ai/claude-agent-sdk-win32-x64)。请重新安装 SDK 的平台包。'
|
|
47
|
+
: '未检测到 Claude CLI。',
|
|
48
|
+
version: claudeVersion,
|
|
65
49
|
},
|
|
66
50
|
{
|
|
67
51
|
id: 'codex',
|