stanlyzoolo/keepkit

GitHub: stanlyzoolo/keepkit

keepkit 是一个纯终端界面的 CLI 工具版本追踪器,帮助开发者在统一列表中监控和更新本地安装的各种命令行工具。

Stars: 24 | Forks: 3

keepkit

CI Latest release Go Report Card Go version License

**keepkit** 是一个轻量级的 TUI,用于追踪你最喜欢工具的版本。 它将你的工具包整合在一个列表中:已安装版本与最新版本并排显示,以及仓库卡片、笔记和标签 —— 还可以直接在界面中更新过时的工具。 纯 TUI,没有子命令;唯一的 flags 是 `--version` 和 `--help`。 ![keepkit — 按标签分组的工具列表,一张卡片在超过其 24 小时缓存后被刷新,同时 GitHub API 仪表盘统计着请求数,面板 [3] 在 README、man page 和工具自带的 --help 之间循环切换](demo/hero.gif) ## 目录 - [核心功能](#key-features) - [安装说明](#installation) - [用法](#usage) - [更新工具](#updating-tools) - [更新 keepkit 自身](#updating-keepkit-itself) - [GitHub API 和 token](#github-api-and-token) - [数据存储](#data-storage) - [架构](#architecture) - [技术栈](#stack) - [贡献](#contributing) - [许可证](#license) ## 核心功能 - **追踪你的工具** — 通过 GitHub URL 或短名称添加,循环切换状态 (`active` / `trying` / `inactive`),保留每个工具的一条笔记和一个标签;`m` 用于在二进制文件名与仓库 (repo) 名称不同时重命名工具(例如 `claude-code` → `claude`), 这也是使其能够解析已安装版本的关键 - **版本一目了然** — 每一行都在其右侧独立列中显示已安装版本 (在本地检测,对于不响应 `--version` 的工具带有 Homebrew 和 cargo 回退机制); 最新版本信息来自 GitHub。过时的 工具会被标记为 `↑`,聚集在列表顶部,并在面板 标题和状态栏中进行计数 - **从 TUI 内部更新** — 在卡片上按 `enter` 会检测包管理器 (brew / go / cargo / pipx / uv / pnpm / bun / npm,或来自 `meta.yaml` 的 `update_cmd`),询问 确认并实时将命令输出流式传输到面板 `[3]` 中 - **自我更新** — 当存在较新的 keepkit 版本时,状态栏会提供提示; 更新后,再按一个键即可在同一个终端标签页中原地重启 keepkit - **文档面板** — 面板 `[3]` 通过快捷键在渲染后的仓库 README、 `--help` 输出和 `man` page 之间切换;在 `--help` / `man` 模式下,`j` / `k` 可遍历 flags 和子命令,并高亮当前条目。每个 README 都会 按照统一的内部风格进行渲染:badge、logo、HTML 包裹层、不可点击的链接 URL、 终端字体无法绘制的象形 emoji 以及卡片已显示的标题页都会被移除, 标题遵循 keepkit 自己的配色方案 —— 代码 示例则完全保持原样 - **可点击的卡片** — 工具卡片上的仓库和发布链接可通过 点击鼠标在浏览器中打开,或通过快捷键打开仓库和更新日志页面 - **语言技术栈** — 卡片会列出仓库使用的语言及其比例, 并使用 GitHub 自带的各语言专属颜色将其绘制为按比例分配的色带 - **标签和分组** — 每个工具一个标签;`space` 键可将扁平列表重新 归类到各个小节标题下,其中有待处理更新的工具排在最前,再次按下可切回原样 - **运行工具** — 在新的终端标签页 (tmux / iTerm2 / kitty / WezTerm / Terminal.app) 或当前窗口中启动任何被追踪的工具,而无需离开 keepkit - **搜索** — `/` 按名称和标签进行过滤,带有匹配高亮和 `N/M` 计数器 - **GitHub API token** — 状态栏中的配额仪表盘,加上 `a` 覆盖层中的 token 管理,可将匿名状态下的每小时 60 次请求限制提升至 5000 次 - **会话错误日志** — 错误(仅限错误)会被记录到按会话划分的 文件中,以便在事后排查行为异常的会话;没有错误就没有文件 - **鼠标支持** — 滚动、面板焦点、选择和卡片链接均响应 鼠标操作 状态栏包含了在每个面板中含义相同的按键,每个 面板各自的特定操作则位于其底部,而 `?` 可打开完整的快捷键覆盖层 — 包含按面板分组的每个快捷键。这就是你需要学习的全部内容。它的左角标明了 你正在运行的构建版本 (`keepkit v0.1.0`),当有较新的 keepkit 版本等待更新时,它会带有与过时 工具行相同的 `↑` 标记;配额仪表盘位于右角。 ## 安装说明 ### Homebrew (macOS / Linux) ``` brew install stanlyzoolo/apps/keepkit ``` 或者只需 tap 一次,然后按名称安装: ``` brew tap stanlyzoolo/apps brew install keepkit ``` 之后使用 `brew upgrade keepkit` 进行升级。 ### go install 需要 Go 1.25+: ``` go install github.com/stanlyzoolo/keepkit@latest ``` 二进制文件会存放在 `~/go/bin/keepkit` (确保 `~/go/bin` 在你的 `PATH` 中)。 ### 预编译二进制文件 macOS、Linux 和 Windows (amd64 / arm64) 的归档文件附在每个 [GitHub release](https://github.com/stanlyzoolo/keepkit/releases/latest) 中。解压并将 `keepkit` 放到你的 `PATH` 中。 ### 从源码编译 ``` git clone https://github.com/stanlyzoolo/keepkit cd keepkit go install . ``` 注意:从工作副本进行的构建属于 *开发 (dev)* 版本 — 出于设计考量, 自我更新检查处于关闭状态。 ## 用法 运行 `keepkit` — 将打开一个三面板界面: - **`[1] Tools`** — 追踪器列表,每一行都带有其已安装的版本: 搜索、标签分组、追踪 / 取消追踪 / 重命名,以及按 `enter` 运行选定的 工具。 - **`[2] Brief`** — 工具卡片:工具的名称和仓库、其标语,然后是 指标条 (已安装 / 最新 / 维护状态 / 星数) 以及一行包含 语言、状态、标签和笔记的信息。在此按 `enter` 会安装待处理的版本, 在浏览器中打开仓库或更新日志,并强制刷新卡片数据。 - **`[3] Readme / Help / Man`** — 文档面板:渲染后的仓库 README ( 默认,`R`)、工具的 `--help` 输出 (`H`) 或其 `man` page (`M`) — 这三个 来源均为大写字母,因此不会与 `r` 刷新或 `m` 重命名冲突。README 在渲染前会被清理 — 移除 badge、logo、HTML 和象形 emoji,保留链接文本但 不带其 URL,标题 (以及其下仅仅是重复卡片内容的标语) 会被 舍弃,以便面板能直接显示带有新内容的第一句话,而 代码块则保持原样。当有更新在运行时,此面板会显示其实时日志, 并在随后将其保留在一行说明更新结果的文字下方。 使用 `←` / `→` 或数字键 `1` / `2` / `3` 移动焦点 (每个面板的编号都显示在 其标题中,获得焦点的面板带有 `▸` 标记及颜色高亮)。状态栏包含了在 每个焦点下执行相同操作的六个按键 — `t` 追踪,`u` 取消追踪,`m` 重命名,`a` api,`?` 快捷键,`q` 退出 — 它们居中显示在左侧的运行 版本和右侧的配额仪表盘之间。所有面板局部的操作都位于 该面板自己的底部:`/` 过滤,`enter` 运行以及 `[1]` 中的 `space` 分组, `[2]` 中卡片的操作。随时按 `?` 可调出按面板分组的完整快捷键覆盖层。 当你输入 GitHub URL (`https://github.com/owner/repo`,带 `.git`,不带 scheme,或 SSH 形式 `git@github.com:owner/repo.git`) 时,keepkit 会将短工具 名称放入 `name`,并将标准化的 `github.com/owner/repo` 放入 `github` 字段。 新工具会获得 `trying` 状态。 `name` 字段也是 keepkit 在本地探测的依据:已安装版本来自 依次运行 ` --version`、然后是 `-V`、然后检查 `Caskroom/` / `Cellar/` 目录、最后是 `cargo install --list`。因此,当仓库的名称与其安装的二进制文件名不一致时 — 比如 `anthropics/claude-code` 提供的是 `claude` 二进制文件 — 每次探测都会失败,该行 将没有版本信息。按下 `m` 并将工具重命名为该二进制文件自身的名称:`github` 字段依然指向该仓库,因此关于版本发布的数据不会发生任何改变,同时 已安装的版本、`↑` 标记以及背后的对比机制将开始正常工作。 ## 更新工具 ![TUI 内更新 — 卡片对比了已安装版本与最新发布版本,按下 enter 会检测包管理器并要求确认其命令,管理器的输出会流式传输到面板 [3] 直到报告结果以及 keepkit 随后验证的版本](demo/update.gif) 当已安装版本落后于最新发布版本时 (即 `↑` 标记),在 工具卡片上按 `enter`。keepkit 会检测该二进制文件是使用哪个包管理器安装的: - `brew` — 路径为 `/Cellar//…` → `brew upgrade `; - `go` — buildinfo (`go version -m`) 包含 `path` 字段 → `go install @latest`; - `cargo` — 二进制文件位于 `~/.cargo/bin` → `cargo install `; - `pipx` — venv 位于 `~/.local/pipx/venvs//` → `pipx upgrade `; - `uv` — 工具位于 `$UV_TOOL_DIR` (默认为 `~/.local/share/uv/tools//`) → `uv tool upgrade `; - `pnpm` — 全局包位于 `$PNPM_HOME` (macOS 下默认为 `~/Library/pnpm`, Linux 下为 `~/.local/share/pnpm`) → `pnpm add -g `; - `bun` — 全局包位于 `$BUN_INSTALL` (默认为 `~/.bun`) → `bun add -g `; - `npm` — 全局的 `node_modules/` → `npm install -g `. 故意在 npm 之前检查 pnpm 和 bun:两者都将其全局包放在 `node_modules` 路径下,否则 npm 会认领它们并提供 `npm install -g ` 的建议 — 这会在 npm 的 prefix 下产生一个重复的副本,而原始版本依然在 `PATH` 中 覆盖它。两者均使用 `add -g` 而非 `update -g`,因为 `update` 会遵循安装时记录的版本范围,并可能悄无声息地拒绝卡片提供的 大版本更新。 如果二进制文件无法归属于上述任何一种 — 或者该工具在 `PATH` 中根本 没有自己的二进制文件 — 在放弃之前还会运行最后一次检查:寻找与工具同名的 Homebrew keg 或 cask → `brew upgrade `。这涵盖了其 二进制文件名称不同的 formula (`rust` 安装的是 `rustc` 和 `cargo`,因此没有 `rust` 二进制可供检测) 以及其可执行文件位于 `.app` bundle 内部的 cask 应用,因为其路径本身无法指明任何管理器。 有两个限制值得了解。对 uv、pnpm、bun 和 npm 的检测依赖于读取路径 约定,因此在 **Windows** 上,它们的 bin 文件是 keepkit 无法解析的 `.cmd` shim — 这是三个新管理器继承自 npm 的既有限制;而在 macOS 和 Linux 上 pnpm 的 shim 是 `#!/bin/sh` 脚本,keepkit 可以读取。并且管理器**自身** 的二进制文件不在范围内:不会提供 `bun upgrade`、`pnpm self-update` 等 建议,这些工具会自行更新。任何检查均无法识别的环境通常会导致降级为 与未知管理器相同的 `update_cmd` 提示。 有一种情况并非如此,且值得了解:pnpm 和 bun 的全局包位于 `node_modules` 路径下,因此如果 keepkit 无法弄清它们的根目录在哪里,该路径 看起来仍然像是一次普通的 npm 安装,从而给出的建议变为 `npm install -g `。运行它会在 npm 的 prefix 下安装第二个副本,而原始版本依然在 `PATH 中 覆盖它。keepkit 会读取 `$PNPM_HOME` 和 `$BUN_INSTALL` (以及平台默认值) 并展开其中的 symlinks,因此只有当根目录位于环境变量未指明的位置时 (比如通过配置文件移动过的存储位置, 或者在没有加载你的 shell profile 的情况下开启的会话) 才会发生这种情况。导出 该变量,或者在该工具上设置 `update_cmd`,就会选择正确的管理器。 命令会在状态栏中显示以供确认;其输出会实时流式传输到 面板 `[3] update` 中,同时 TUI 保持响应。一次只能运行一个更新; 命令的超时时间为 10 分钟 (如果其中包含 sudo 密码提示则会快速失败, 而不会一直挂起)。 当其结束时,日志会留在原处 — 它是所发生事件的记录 — 并在结尾给出面板边框现在所显示的内容,`[3] update finished` 或 `[3] update failed`: ``` ✓ finished · brew · 14s ✓ fd v10.2.0 → v10.3.0 R readme · H help · M man ``` 日志本身显示为暗色 — 因为它是管理器输出的内容,而最后这几行是 keepkit 对管理器执行结果的自我判定。 第二行会在片刻后写入,一旦版本被重新检测到 — 这同样也是使得 `↑` 标记消失的原因。它作为单独的一行,是因为 管理器成功退出并不等同于工具已经更新:如果 没有任何变化,它会显示为 `⚠ fd still v10.2.0`,而如果更新后没有 留下可用的二进制文件,则会显示 `✕ fd not on PATH`。如果失败,会在 第一行下方打印原因,并通常会在此停止,因为之后不会再进行重新检测。 如果无法检测到管理器 (手动安装),keepkit 会建议设置 `update_cmd` 字段或手动更新。`meta.yaml` 中的 `update_cmd` 始终优先于 自动检测,并通过 `sh -c` 运行 (支持管道和 `&&`): ``` - name: mytool github: github.com/owner/mytool update_cmd: mytool self-update ``` ## 更新 keepkit 自身 keepkit 也会监视自身的发布版本。在启动时,它会检查最新版本 — 这是一个单一的 请求,缓存 24 小时;对于从工作副本构建的版本,此功能完全关闭。当存在 较新的版本时,状态栏会显示通知: ``` keepkit v0.5.0 available — U update X dismiss ``` `U` 通过与任何工具相同的 pipeline 进行更新 — 管理器检测、确认、 面板 `[3]` 中的实时日志 (无论选中哪个工具均可见,即使追踪器 为空)。`X` 会将通知折叠为状态栏右角版本号旁边的一个紧凑的 `U update` 单元, 在那里 `U` 依然有效;不会有任何信息被写入磁盘,因此被忽略的通知会在下次 启动时重新出现。更新成功后,状态栏会显示 `keepkit updated — U restart`: `U` 会用新的二进制文件替换正在运行的进程 — 同一个终端标签页,同一个 tmux 窗格,相同的参数。在 Windows 上不支持原地重启:keepkit 会打印 `keepkit updated — run keepkit again` 然后退出。 对于上述所有操作,keepkit 不需要被放入你自己的追踪器中 — 检查功能是 内建的。如果它*确实*被追踪了,其 `update_cmd` 将完全像控制该行上的 `enter` 操作 一样控制自我更新,并且发布数据与其卡片共享。需要了解的是: - 一次只能进行一个更新:当有更新正在运行时,`U` 和 `enter` 均会回复 `another update is running` 而不会启动第二个更新。 - Homebrew formula 可能会落后于 GitHub 发布版本:更新后,已安装的 版本可能仍然早于最新的 tag,因此通知会重新出现。这是 对状态的真实反映,而不是 bug。 - 如果发布检查失败 (无网络、配额耗尽),仅仅是不显示 通知 — 其他一切功能照常运作。 - 如果更新失败,状态栏会显示 `update failed — see [3]`,原因会保留在 面板 `[3]` 中。 - 更新的目标是你 `PATH` 中的 `keepkit`。如果你通过路径启动了一个副本 (`./keepkit`),而系统中安装了另一个不同的版本,那么被安装的那个版本才是被 更新的对象 — 而重启会带回你启动的那个副本,因此通知会 重新出现。 ## GitHub API 和 token keepkit 通过 GitHub REST API 获取发布版本和仓库卡片。如果没有 token,限制为每个 IP **每小时 60 次请求**,如果有 token — **则为 5000 次**。启动时, 每个带有 `github` 字段的工具会消耗 3 次请求,当你在面板 `[3]` 中打开其 README 时还会再消耗一次;在没有 token 的情况下,如果列表很长并进行冷启动可能会触及 限制 — 在时间窗口重置之前,卡片会保持空白。keepkit 的发布检查每 24 小时会增加一次请求 (开发版构建中则没有)。 一旦配额数据已知,其使用情况会显示在状态栏的右角 (`api ▮▮░░░░░░░░░░ 12/60`) 并在整个会话期间保留,当配额窗口即将耗尽时,进度条会变红。这也是 keepkit 拥有 API 层面的唯一可见标志,因此如果在静止时隐藏它,也会连同它一起隐藏覆盖层; 在狭窄的终端中,这是角落里最先被舍弃的内容。`a` 键可打开 API 状态覆盖层:token 来源、带有警告图标的 配额使用情况以及重置时间;在覆盖层中,你可以直接输入 token (在保存前会进行验证)、 移除 token 或刷新数据。 token 来源遵循环境变量优先原则:`GITHUB_TOKEN` 变量始终 优先于文件。在 TUI 中输入的 token 会存储在 `~/.config/keepkit/token` 中, 权限为 `0600`;环境变量中的 token 绝不会写入磁盘。当 配额耗尽时,已加载的卡片不会被抹除,而没有数据的 卡片会显示 `rate limited — press L` 提示。 ## 数据存储 工具列表存放在 `~/.config/keepkit/meta.yaml` 中 — 每个工具一个条目 (`name`、 `status`、`added`,可选的 `tags`、`note`、`github`、`update_cmd`)。该文件完全由 TUI 管理;不需要手动编辑,但手动编辑也是安全的 — 因为写入是 原子操作。`tags` 在文件格式中仍然是一个列表,但一个工具只有**一个**标签:更长 的遗留列表会被读取为其第一个条目,而在此次迁移之前的文件会 作为 `meta.yaml.bak` 保留。 | 内容 | 位置 | |------|-------| | 追踪器元数据 | `~/.config/keepkit/meta.yaml` | | 版本、README 和自我检查缓存 (各 24 小时 TTL) | `~/.config/keepkit/cache.json` | | GitHub token (`0600`) | `~/.config/keepkit/token` | | 会话错误日志 | `~/.config/keepkit/logs/keepkit-.log` | | 单标签迁移之前的追踪器副本 | `~/.config/keepkit/meta.yaml.bak` | 上述路径适用于 macOS 和 Linux (如果设置了 `$XDG_CONFIG_HOME` 则为其路径, 否则为 `~/.config`)。在 Windows 上,基础目录变为 `%AppData%\keepkit\`。对于由早期版本以之前名称 (`keeptui`) 留下的配置目录, 首次启动时会被自动提取并重命名。 错误日志是延迟创建的 — 仅在发生第一次错误时。没有错误的会话 完全不会留下任何文件,因此文件的存在本身就是一种信号。系统会保留最近的 20 份 日志。 ## 架构 关于代码的组织方式 — package 依赖图、数据流、TUI 状态机、 子进程沙箱 — 在 [ARCHITECTURE.md](ARCHITECTURE.md) 中有详细描述。 ## 技术栈 - [Bubble Tea](https://github.com/charmbracelet/bubbletea) — TUI 框架 - [Bubbles](https://github.com/charmbracelet/bubbles) — 文本输入、视口、spinner - [Lip Gloss](https://github.com/charmbracelet/lipgloss) — 样式 - [Glamour](https://github.com/charmbracelet/glamour) — 用于 README 面板的 markdown 渲染 - [goldmark-emoji](https://github.com/yuin/goldmark-emoji) — GitHub 的 `:shortcode:` 词典,用于将它们从 README 中剔除 - [x/ansi](https://github.com/charmbracelet/x) — 从捕获的工具输出中剔除 escape 序列 - [termenv](https://github.com/muesli/termenv) — 终端颜色配置检测 - [go-runewidth](https://github.com/mattn/go-runewidth) — 字符宽度测量 - [golang.org/x/mod/semver](https://pkg.go.dev/golang.org/x/mod/semver) — 版本比较 - [gopkg.in/yaml.v3](https://pkg.go.dev/gopkg.in/yaml.v3) — 读写 `meta.yaml` ## 贡献 欢迎提交 Bug 报告和 pull request。在提交之前,请运行 `go test -race ./...` 和 `go vet ./...` — CI 检查的内容也是如此。 ## 许可证 [MIT](LICENSE)
标签:EVTX分析, Go, Ruby工具, SOC Prime, TUI, 开发工具, 日志审计, 版本管理