Omrylo 文章

给本地 CLI 工具箱补上一层记忆

包管理器解决安装,但不会替开发者记住分散脚本的用途、仓库和状态;tool-manage 如何把这部分上下文留在本机。

开发环境用得越久,本机命令越不像一个整齐的软件列表。里面会有全局安装的 npm 包、复制到 PATH 的脚本、公司内部 CLI、AI Coding 辅助工具,以及只为某次任务写过的自动化。它们可能都能运行,但用途、来源和维护状态很容易被忘记。

这时再次安装并不是答案。真正缺少的是一份能够回看的记录:命令叫什么、路径在哪里、解决什么问题、仓库和作者是谁、怎样使用,以及它现在是否仍属于活动工具箱。tool-manage 就从这层缺失的上下文开始。

先划清与包管理器的边界

npm、pnpm、Homebrew 或运行时管理器已经擅长安装与版本切换。tool-manage 不解析依赖、不替用户选择版本,也不接管命令执行。它只登记已经存在的工具,并保存以后理解它所需的上下文。

这个边界让命令面保持很小:`tm --add` 登记,直接运行 `tm` 查看活动列表,`--show` 读取详情,`--edit` 补充说明,`--update` 刷新检测信息,`--generate` 生成描述骨架,`--remove` 归档。每个动作都围绕记录生命周期,而不是软件生命周期。

自动发现和手工描述必须同时存在

对于标准包命令,工具可以从 PATH 找到可执行文件,再尽量读取 package.json 中的名称、版本、描述、作者、仓库和许可,并保存一段帮助输出。这个路径减少了重复输入,也让已有包快速进入目录。

但内部脚本可能没有 package.json,甚至只有一个可执行文件。为此,tool-manage 接受本地或远程 JSON 描述,也能通过 `tm --generate` 创建一个包含 commandName、description、version、repository、author 和 helpPreview 的起始模板。手工信息不是异常,而是产品需要正式支持的来源。

记录最终还要适合人在终端里读取。`tm --show` 会把描述、版本、仓库、作者和帮助预览放到同一视图,并省略没有值的字段。这个细节避免了大量空标签,也让自动发现不完整时,手工补充的少量关键信息仍然能够形成清楚结果。列表视图则只承担快速扫描,不把全部元数据塞进一张宽表;需要判断时再进入单条详情。把“发现工具”和“理解工具”分成两个阅读层级,终端输出在命令数量增加后仍然比较容易使用,也降低了日常查询的视觉负担。

两条登记路径
PATH 中的命令 → 发现路径与包元数据 → 保存记录

私有脚本 → 补充 JSON 描述 → 导入同一登记库

为什么选择本地 SQLite

工具目录可能包含私有仓库、内部作者、帮助文字和本机路径。为了查看这些内容而要求登录远程服务,会给一个个人工具增加不必要的数据暴露和运维成本。SQLite 足以提供结构化字段、查询和迁移,同时把数据库留在 `~/.tool-manage`。

数据模型将命令主记录和人工 overrides 分开。这样,`--update` 可以重新检测版本与包信息,而不会轻易覆盖用户主动补充的上下文。数据库还保留 app_meta,用于记录应用级状态和迁移信息。

删除应该允许反悔

个人目录需要清理,但“暂时不用”不等于“这段历史毫无价值”。`tm --remove` 因此通过 `deleted_at` 做软删除:记录从活动列表消失,数据库行仍然存在;同一命令再次添加时,可以恢复原记录。

这种可恢复性也被自动化测试覆盖。测试不仅检查命令输出,还直接读取 SQLite,确认删除后记录仍在、重新添加后原有行恢复。对一个宣称“帮助记忆”的工具来说,不在正常清理中丢失记忆是基本一致性。

小工具的价值来自准确命名

tool-manage 没有试图覆盖所有开发者工作流。它不适合只使用少量知名命令的人,也不能替代版本管理、任务编排或团队软件资产管理。

它真正服务的是一个越来越常见的状态:工具已经存在,数量也在增长,但上下文散落在 README、Shell 历史和记忆里。把这一层明确命名并做成可查询、可维护、可恢复的本地登记库,就是这个小产品的完整价值。