## 密钥泄漏闸 把活交给 agent 之后,泄密的形态变了。以前是人手滑,现在是**每一步都很合理的 一串操作**:git add . 顺手把 .env 提了、把真实 token 内联进配置文件当"示例"、 为了确认配置 cat 一下密钥(值就进了 transcript,0644、永久、每轮重发给 API)。 **没有一条能靠「这条命令危不危险」判断出来。** 它们都不危险。唯一可靠的信号是 这次调用的内容里有没有出现真实的密钥值。 所以加了一道闸,默认开:参数里出现库里的真实值 → 拒;git add/commit 会把 .env 一类文件或含真实值的文件带进仓库 → 拒。拒绝理由里写明正确做法 (用 $KEY、先加 .gitignore),否则模型只会换个写法再试一次。 **它跑在 hubctl 本地,不依赖 app 在不在跑。** 仓库其它拦截都是「app 没开就放行」 (一个监控工具不该让你的命令跑不起来),这一条反过来 —— 密钥漏出去不可逆。 几条守住的边界,判宽了比判窄了危险:值短于 8 字符不参与匹配(abc/true/test 会命中一切);.example/.template/.sample 结尾放行(模板文件本来就该提交, 误拦一次用户就把整个功能关掉了);只认 EnvRenderer 写出来的格式,不做通用 dotenv 解析;不是 git add/commit 就一个子进程都不起。 拒了之后事件照发给 app(不等应答),进审批日志 —— 一道看不见的闸, 用户第一次被拦时只会觉得 Claude 抽风。开关在密钥页底部, 落成 ~/.vibe-foreman/guard.json,且**只在关掉时才写**: 默认开,「文件不存在 = 开着」,这样没打开过密钥页的人也受保护。 明确写了它挡不住什么:python -c 读、软链、base64 转一道、库外手写的值。 它是一道减少手滑的闸,不是沙箱。 ## 截图 主窗口现在也能自动截了:HUB_WINDOW_SECTION 钉住打开哪一页, 配 DemoFixtures.seed 造的假密钥和假账号(刻意编得一眼假 —— 一个像真的 token 混进去,读者会去试)。 两个坑:find-window 按面积取第一个会截到岛(它比主窗口先出现一瞬), 改成按宽度 ≥900 筛;.accessory 的进程从后台 shell 起来抢不到焦点, 而非活跃窗口里的系统控件会被去饱和 —— 截出来开关全是灰的, 正好把要展示的东西说反了,所以截图模式下改用 .regular。 顺带:进密钥页自动选中第一组。有组却什么都不选,右边一大片空白, 那是"还没建组"的样子而不是"有四组等你挑"的样子。 646 个测试全过(原 625)。真 hubctl 二进制端到端验过四种情况: 写入真值被拒、约定的 source 用法放行、git add . 带 .env 被拒、普通命令放行。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4.1 KiB
参与共创
先说结论:欢迎,而且有几件事是真的缺人做(往下翻到「现在最缺什么」)。
跑起来
git clone https://github.com/gulugulu-cn/vibe-foreman.git ~/Documents/code/vibe-foreman
cd ~/Documents/code/vibe-foreman
bash scripts/setup.sh # 编译 + 安装到 /Applications
cd HubKit && swift test # 646 个测试,约 45 秒
需要 macOS 26 SDK(Xcode 26) —— 灵动岛依赖 Liquid Glass API,这是硬门槛。
零第三方依赖,swift build 之外什么都不用装。
改完代码重新装:
bash scripts/build-swift-app.sh # 几秒,只编当前架构
bash scripts/release.sh # 打 universal + dmg,几分钟
这个仓库的写法
代码风格没什么特别的,但注释和测试的写法是有讲究的,PR 会按这个看。
注释写「为什么」,不写「是什么」
// ✗ 不要:检查目录是否存在
// ✓ 要:
// tmux 对不存在的 `-c` 目录**返回 0 并静默回落到家目录** ——
// 实测 exit=0,pane_current_path 变成 /Users/xxx。`open /不存在` 则什么都不做。
// 两者都不报错,于是一条坏数据表现成"右键菜单坏了"。
代码本身已经说清楚"是什么"了。值得写下来的是下一个人(包括三个月后的你)会踩的那个坑: 为什么不用那个看起来更简单的写法、这个魔数是怎么来的、改成另一种会怎样。
HubKit/NOTES.md 里攒着所有实机撞出来的坑,改动碰到相关的地方请顺手补一条。
测试钉的是边界,不是覆盖率
优先测写错了不会报错、只会静默失灵的那些判断。这个仓库里几乎每个测试 都对应一次真实事故,测试的文档注释里写着那次事故是什么样的:
/// **绑不到 pane 的不算 detached。**
///
/// 那是「根本不在 tmux 里」——VS Code 扩展、直接开的终端、后台任务。
/// 它们有没有终端连着这里判断不了,报成 detached 就是拿"不知道"当结论,
/// 会让一堆正常会话集体显示成"终端已关"。
中文注释
现有代码全是中文注释,继续用中文即可。代码标识符用英文。
提 PR 之前
cd HubKit && swift test # 必须全过
commit message 用中文,写清楚为什么这么改,不只是改了什么。 碰到用户可见的行为变化,请一并更新 README。
现在最缺什么
按优先级,都是真实的缺口,不是造出来的任务:
1. 终端支持(最缺)
现在只有 iTerm2 能精准跳转到具体 tab,Terminal.app 只能前置。 Ghostty / Warp / Kitty / WezTerm 的用户点「跳转终端」完全没反应。
这是目前最硬的门槛。跳转的核心算法(进程树祖先链求交,见
HubJump/JumpEngine.swift)是终端无关的,缺的是每个终端的「枚举会话 + 前置指定
tab」适配层 —— 参考 HubJump/ITermLocator.swift,一个终端一个文件。
只做到"把终端拉到前面"也是巨大的改进,不必一步到位做到精准 tab。
2. 支持别的 AI CLI
目前只认 Claude Code(读它的 ~/.claude/sessions/<PID>.json)。
Codex 的 ~/.codex/sessions/ 调研过、结构接得上,
难点在"在跑还是在等"这一层要另走一条路 —— Claude Code 有权威的 status 字段,
别家不一定有。
3. 公证(Notarization)
现在是自签名,别人下载后要绕 Gatekeeper。这需要 Apple Developer Program
账号,不是纯代码问题,但如果你有经验,scripts/release.sh 里加一段
notarytool 就能让"双击即用"成立。
4. 外接屏上的胶囊形态
岛跟随光标换屏做完了,但没在 4K 屏上逐项核对过。 有外接屏的话,帮忙看一眼尺寸和位置对不对就很有价值。
有想法但不确定要不要做?
直接开 issue 聊。这个工具是从一个人的真实工作流里长出来的, 很多设计取舍(比如「盯梢默认全关」「审批只拦不可逆那一档」)都有具体理由, 先聊一下能省掉双方的返工。