@epoch-agent/infra

中文文档
6.2.0发布于 2026/11/13Apache-2.0TypeScriptES Module近 30 天下载 6153

epoch-agent 基础设施:路径真源、SQLite 连接与迁移、日志、平台兼容、命令安全表

中文使用文档
文档目录5 节
  1. 文件
  2. 界面文案: t() 与三层回落
  3. Windows 上的 shell 选择
  4. 凭据存储的后端顺序
  5. 开发

@epoch-agent/infra

基础设施层。跨模块共用的叶子能力。

  • ✅ 做:路径真源、SQLite 连接与迁移、日志、凭据存储、平台兼容、命令安全启发式表、 工作区归属判定(workspace.ts)、外部可执行文件的探测与降级(ripgrep.ts)、异步小工具
  • ❌ 不做:任何领域逻辑(ReAct / 记忆 / 权限判定都属于 core)、任何 UI
  • 依赖:只有 node 内置模块 + better-sqlite3 + zod。不依赖任何 @epoch-agent/* 包

判断一个东西该不该放这里:无状态或只管进程级资源,且被两层以上共用。

workspace.ts 和 command-safety.ts 看着像「权限判定」,其实是同一类东西: 一张纯判据(这个路径在不在地盘里 / 这条命令像不像手滑),谁都能问、问了不改变 任何状态。「问到之后要不要放行、要不要弹审批」才是权限判定,那部分在 core。 判据落在 infra 是因为按分层 plugin-* 只能依赖 protocol + infra,够不着 core —— 放 core 就意味着两个 plugin 各抄一份,而这次 --add-dir 就是被那三份抄本坑到才收归一处的。

文件

文件内容
paths.ts~/.epoch/ 下每个文件的唯一真源,外加机器级的 managedSettingsPath()。别处再 join(homedir(), '.epoch') 就是埋雷
artifact-store.ts往 artifact 目录写文件的唯一写法:0700 目录 / 0600 文件 / open(path,'wx') 独占写。core 的多模态闸门和 plugin-terminal 的大输出落盘共用
text-slice.ts按 Unicode 码点取头尾,截断不许切出半个字符(emoji 和 CJK 扩展 B 是代理对)。命令输出预览和工具结果裁剪共用
workspace.tsisInWorkspace(target, workDir, extraRoots)——「这个路径算不算在地盘里」的唯一判定,权限层 / plugin-file / plugin-terminal 共用
sqlite.ts连接池(引用计数)+ 迁移。openDatabase / releaseDatabase 配对使用
logger.ts结构化日志
jobs.ts长期子进程作业表的真源(t1 后台命令 / s1 持久会话 / a1 后台子 agent 共用一张表,kind 无关)。task_* 与 shell_* 两组工具都读它,判据在文件头 —— 2026-11-03 补进这张表(上一版漏了它,而 core / plugin-terminal 两份 README 都在指它)
config-yaml.tsconfig.yaml 的按行手术(改一行不重写整份,用户的注释和顺序一个字节不动)+ 手写解析与 schema 校验的接合点。epoch config set 与设置页都走它
mask.ts脱敏(maskApiKey / isSensitiveKey),epoch config show 靠它
platform.tsWindows / POSIX 差异:shell 选择、spawn 与 pty 参数、控制台编码探测与解码
ripgrep.tsrg 从哪来的分档解析(几档、每档说什么,真源是文件头那张表):系统 PATH → 随包带的 vendor 二进制 → 都没有。嵌入宿主里 vendor 那一档会绕开 app.asar、改取 app.asar.unpacked 里那份(unpackAsarPath)。file_search 和将来的 @ 补全共用
git-probe.tscanProbeGit()——后台探测 git 之前先问的那一句。mac 上 /usr/bin/git 是命令行开发者工具的存根(和 clang / python3 / swift 同一个 inode),没装过工具的机器上一执行就弹系统安装框,而那个框 stdio: 'ignore' 挡不住、catch 也接不住。三处调用点共用:getGitStatus()、@ 补全的 listWorkspaceFiles()、工作区 diff 的 runGit()。拦下来一律退化不报错
process-tree.ts进程树清理——杀干净孙进程,且只杀该杀的
spawn-guard.tsguardSpawn(start, onSpawnError)——起子进程那一下的同步失败通道。node 只把 EACCES / EAGAIN / EMFILE / ENFILE / ENOENT 转成异步 error 事件,名单外的(最常见 ENOTDIR:cwd 不是目录、PATH 里某一项是文件)同步抛,execFile 连回调都不调。全仓每一处 spawn / execFile 都要经过它,由根 __tests__/spawn-guard-callsites.test.ts 扫 AST 守着(六处登记在案的例外自己用 try/catch 接住了)
child-process.ts长期子进程(后台任务 / language server / PTY)的启动、登记、回收。start() 起不来时返回 null(2026-09-20,同步抛那一族)。表按所有者分:每个 runtime 一张(createProcessTable(),按 sessionId 路由)+ 一张进程级兜底表(引用计数,归零才收)—— 判据和那条真 bug 写在文件头。detached: false 的理由也在那儿。还有 EXEC_PATH_AS_NODE_ENV——「拿 process.execPath 当 node 使」的地方必须带的那一格(嵌入 Electron 的宿主里它不是 node),两个消费者分在 core 和 plugin-lsp
shell-parse.ts命令分词与分段(引号感知,带 POSIX / Windows 两种口味)。危险判定、权限规则匹配、斜杠命令的位置参数都建在它上面
command-safety.ts危险命令与混淆的启发式表,建在 shell-parse 之上。是护栏不是沙箱
sandbox/这个才是沙箱:Seatbelt(macOS)/ bubblewrap(Linux,运行时暂未验证)/ Windows 的受限令牌 + 完整性标签(2026-11-11 接上,只覆盖写与删,enforcement 恒为 partial)/ 探测不到就降级。confine() 按调用带 policy 并如实报强制完整度;两组 stderr 分类器分开「被挡住」和「沙箱没起来」。2026-08-16 从 core 搬来,理由同 command-safety.ts:code_exec 和 plugin-terminal 共用,而 plugin 够不着 core
schema.ts配置校验(zod + 宽松解析,坏字段降级而不是整份拒绝)
i18n.tst() / 语言解析 / catalog 加载与三层回落。文案真源是仓库根的 locales/*.yaml
async.ts异步小工具
secret/凭据存储:DPAPI(Windows)/ Keychain(macOS)/ libsecret / 明文回落 + 迁移

界面文案:t() 与三层回落

i18n.ts 也是一个进程级状态(setLang('zh' | 'en'),形状同 setShell)。 Lang 的值域在这里和 protocol 各写了一份 —— 同 ShellKind, 本包零内部依赖,import 不了 protocol;根 __tests__/i18n-catalog.test.ts 里有一条用例锁着两边逐项相等。

文案的真源是仓库根的 locales/{zh,en}.yaml,不在本包里。发布时由 scripts/copy-locales.mjs 在 tsup 之后拷进 dist/locales (files: ["dist"] 只发 dist,不拷就等于装了包的人满屏 key 路径)。

t() 永远返回字符串、永远不抛,三层回落:

目标语言的 key → zh(DEFAULT_LANG)的 key → 返回 key 路径本身

第三层是关键:catalog 写坏了不能让 agent 起不来。同一条原则下,坏 YAML / 缺文件 只产出 i18nDiagnostics() 里的一条 warn,宿主拿去塞进启动诊断。 语言怎么选出来(EPOCH_LANGUAGE → display.language → 系统 locale → 中文) 见 docs/CONFIGURATION.md。

Windows 上的 shell 选择

platform.ts 里有一个进程级状态:setShell('cmd' | 'powershell' | 'pwsh'), 装配层(runtime)读完配置调一次,shellSpawnArgs / shellPtyArgs 据此拼参数。形状跟 setLogLevel / setSecretStore 一致。POSIX 上是空操作, 永远 /bin/sh —— macOS 走的就是这一支。

只收这三个具名值,不收任意可执行文件路径:每加一种都要重新验「引号怎么转义」 和「退出码怎么传」两件事,放开成任意路径等于承诺一件没验过的事。

PowerShell 那条路上有两个不报错的坑,都写进了 platform.ts 的注释:

  • PowerShell 5.1 不传播被调命令的退出码(实测 -Command "cmd /c exit 3" → 1), 所以命令后面必须接一段同时读 $? 和 $LASTEXITCODE 的收尾语句。只读后者更糟: 命令不存在时它是 $null,exit $null → 0,一次彻底失败被报成成功
  • 命令和收尾之间必须是真换行,不能用 ;。用 ; 的话命令末尾带一句 # 注释 就把整段收尾注释掉了,实测 cmd /c exit 5 # note 退出码变成 1

ShellKind 的值域在这里和 protocol 各写了一份——本包零内部依赖, import 不了 protocol。core 里有一条用例锁着两边相等。

凭据存储的后端顺序

secret/catalog.ts 按平台探测可用后端,探不到就降级,最后回落到 ~/.epoch/.env 明文。 epoch config secret 打的就是这个判定结果。

⚠️ POSIX 分支不等于 Linux 分支,别顺手删。 macOS 走的就是 POSIX 那一支 (pgrep / kill 进程树、/bin/sh、危险命令表的 POSIX 那张)——删这些等于砍掉 macOS。真正只有 Linux 会走到的是显式判 platform() === 'linux' 的分支 (secret/libsecret.ts):Linux 暂不支持,所以那条路径尚未实测,但代码留着, 将来补 Linux 支持时从它接着往下走。

开发

pnpm --filter @epoch-agent/infra test

版本与发布记录

@epoch-agent/infra 共发布 57 个版本,首次发布于 2026/08/19;过去 12 个月发布了 57 个版本。

版本发布日期距今
6.2.0latest2026/11/13今天
6.1.02026/11/112 天前
6.0.02026/11/112 天前
5.0.02026/11/103 天前
4.1.12026/11/067 天前
4.1.02026/11/067 天前

关于 @epoch-agent/infra 的常见问题

@epoch-agent/infra 是什么?

epoch-agent 基础设施:路径真源、SQLite 连接与迁移、日志、平台兼容、命令安全表

如何安装 @epoch-agent/infra?

在项目目录运行 npm install @epoch-agent/infra,或使用 pnpm add / yarn add / bun add。

@epoch-agent/infra 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@epoch-agent/infra 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@epoch-agent/infra 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@epoch-agent/infra 可以商用吗?

@epoch-agent/infra 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@epoch-agent/infra 的下载量有多少?

根据 npm 官方下载统计,@epoch-agent/infra 在 2026/10/14 – 2026/11/12 这 30 天内被下载 6,153 次,日均约 205 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@epoch-agent/infra 还在维护吗?

最新版本 6.2.0 发布于 2026/11/13(今天);至今共发布 57 个版本,其中过去 12 个月发布了 57 个;首次发布于 2026/08/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。