npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@epoch-agent/infra

v0.20.1

Published

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

Readme

@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.ts | isInWorkspace(target, workDir, extraRoots)——「这个路径算不算在地盘里」的唯一判定,权限层 / plugin-file / plugin-terminal 共用 | | sqlite.ts | 连接池(引用计数)+ 迁移。openDatabase / releaseDatabase 配对使用 | | logger.ts | 结构化日志 | | mask.ts | 脱敏(maskApiKey / isSensitiveKey),epoch config show 靠它 | | platform.ts | Windows / POSIX 差异:shell 选择、spawn 与 pty 参数、控制台编码探测与解码 | | ripgrep.ts | rg 从哪来的分档解析(几档、每档说什么,真源是文件头那张表):系统 PATH → 随包带的 vendor 二进制 → 都没有。嵌入宿主里 vendor 那一档会绕开 app.asar、改取 app.asar.unpacked 里那份(unpackAsarPath)。file_search 和将来的 @ 补全共用 | | git-probe.ts | canProbeGit()——后台探测 git 之前先问的那一句。mac 上 /usr/bin/git 是命令行开发者工具的存根(和 clang / python3 / swift 同一个 inode),没装过工具的机器上一执行就弹系统安装框,而那个框 stdio: 'ignore' 挡不住、catch 也接不住。三处调用点共用:getGitStatus()、@ 补全的 listWorkspaceFiles()、工作区 diff 的 runGit()。拦下来一律退化不报错 | | process-tree.ts | 进程树清理——杀干净孙进程,且只杀该杀的 | | spawn-guard.ts | guardSpawn(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,运行时暂未验证)/ 探测不到就降级。confine() 按调用带 policy 并如实报强制完整度;两组 stderr 分类器分开「被挡住」和「沙箱没起来」。2026-08-16 从 core 搬来,理由同 command-safety.ts:code_exec 和 plugin-terminal 共用,而 plugin 够不着 core | | schema.ts | 配置校验(zod + 宽松解析,坏字段降级而不是整份拒绝) | | i18n.ts | t() / 语言解析 / 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