@botaoxyz/zhao
v0.6.0
Published
按域名、关键词和模块快速检索本地项目的 CLI
Readme
zhao
zhao(“找”)是一个面向本地多仓库场景的项目检索 CLI。它会扫描 Git 仓库,建立包含项目名、描述、技术栈、域名和远程仓库信息的本地索引,让你可以通过域名、别名、关键词或项目名快速找到项目,并直接进入目录、打开代码助手、GitHub/GitLab 仓库地址或 CI 页面。
█████
░░███
█████████ ░███████ ██████ ██████
░█░░░░███ ░███░░███ ░░░░░███ ███░░███
░ ███░ ░███ ░███ ███████ ░███ ░███
███░ █ ░███ ░███ ███░░███ ░███ ░███
█████████ ████ █████░░████████░░██████
░░░░░░░░░ ░░░░ ░░░░░ ░░░░░░░░ ░░░░░░域名 / 别名 / 关键词 / 项目名
↓
本地索引与手动元数据
↓
进入目录 / 打开编辑器 / GitLab / CI特性
- 给项目打标签,可以按项目域名、API 域名、别名、关键词、项目名或描述检索项目
- 多个结果时显示交互式选择器,可选用
fzf - 通过 shell wrapper 真正切换当前终端目录
- 可在进入项目后启动 Claude Code 或 Codex
- 支持在 tmux 新窗口或新会话中打开项目
- 扫描
package.json、README、Git remote 和常见配置文件生成索引 - 支持为项目补充别名、页面域名、关键词和 CI 链接
- 可从项目任意子目录打开 GitHub/GitLab 或 CI 页面
- 使用 frecency(访问频率与时间衰减)优化检索排序
- 配置和索引均保存在本地,不修改被扫描的项目
环境要求
- Node.js 18 或更高版本
- zsh 或 bash(用于安装目录跳转 wrapper)
- macOS、Linux 或 Windows 可运行构建产物;shell wrapper 当前仅支持 zsh 和 bash
以下工具按需安装:
fzf:启用useFzf后用于项目选择,缺失时自动回退到内置选择器tmux:使用--tmux时需要claude:使用--claude时需要codex:使用--codex时需要- Linux 剪贴板:使用
--copy时需要wl-copy或xclip
安装
npm install @botaoxyz/zhao -g安装 shell wrapper:
zhao setupsetup 会自动识别 zsh 或 bash,并在 ~/.zshrc 或 ~/.bashrc 中追加:
eval "$(zhao init zsh)"它会在写入前展示内容并请求确认;重复运行不会重复写入。如果 rc 文件是符号链接,还会额外提示。完成后重新打开终端,或手动加载配置:
source ~/.zshrc
# bash 用户使用:source ~/.bashrc也可以跳过 setup,自行把对应命令加入 shell 配置:
eval "$(zhao init zsh)"
# 或:eval "$(zhao init bash)"快速开始
第一次在交互式终端运行 zhao 时,会引导你完成以下操作:
- 检查 shell wrapper 是否生效。
- 输入一个或多个项目扫描根目录。
- 创建
~/.config/zhao/config.yaml。 - 扫描 Git 仓库并生成本地索引。
完成后即可检索:
# 按项目名、关键词或别名检索并进入目录
zhao 'report'
zhao '学习报告'
# 按域名检索
zhao 'example.com'
# 只打印路径,不切换目录
zhao '学习报告' --print
# 进入目录后启动 Claude Code
zhao '学习报告' --claude
# 进入目录后启动 Codex
zhao '学习报告' --codex
# 在 tmux 中打开项目
zhao '学习报告' --tmux
# 在 tmux 中打开项目并启动 Codex 或 Claude Code
zhao '学习报告' --tmux --codex
zhao '学习报告' --tmux --claude--claude 与 --codex 不能同时使用。查询包含空格时需要加引号,并且一次只接受一个查询参数:
zhao "学习 报告"工作原理
子进程无法改变父 shell 的当前目录,因此 zhao 分为两层:
- Node.js CLI 负责扫描、检索、交互选择以及输出目标路径。
- shell wrapper 调用 CLI 获取路径,再在当前 shell 中执行
cd、启动代码助手或创建 tmux 窗口。
如果未安装 wrapper,直接运行 zhao <query> 只会输出项目路径,不会改变当前目录。可通过下面的命令检查状态:
zhao doctor命令参考
项目检索
zhao [query] [--print] [--claude] [--codex] [--tmux]| 参数 | 简写 | 说明 |
| ---------- | ------ | ----------------------------------------------------------------------------- |
| query | — | 域名、别名、关键词或项目名;省略时从当前 Git 项目解析,否则显示全部项目供选择 |
| --print | -p | 只打印选中的项目路径 |
| --claude | -cc | 进入目录后启动 Claude Code |
| --codex | -cdx | 进入目录后启动 Codex |
| --tmux | -t | 在 tmux 新窗口中打开;不在 tmux 中时创建新会话 |
显式 query 的优先级高于当前目录。若检索到多个项目,zhao 会展示项目名、描述和命中原因供选择。
zhao setup
安装 shell wrapper,并在需要时继续首次配置和索引创建。
zhao setup
zhao setup --shell zsh
zhao setup --shell bashzhao init
输出 shell wrapper 内容,适合手动安装或 dotfiles 管理。
zhao init zsh
zhao init bashzhao scan
扫描配置的根目录并全量重建 index.json:
zhao scan扫描还会自动维护 projects.yaml:文件不存在时创建,并用 Git remote 生成的稳定项目 ID 补齐缺失 key。新项目会初始化空的 aliases、domains、keywords,以及空的 links.ci-test、links.ci-prod。已有手工元数据和未被本次扫描发现的旧条目都会保留;没有新增项目时不会重写文件。
扫描会跳过损坏或没有 Git remote 的仓库,不会因为单个仓库失败而中断。已不在扫描目录中的项目会在重建后从索引中移除。
zhao browse
打开项目的 GitHub/GitLab 页面。没有查询时优先使用当前 Git 项目:
zhao browse
zhao browse '学习报告'
zhao browse '学习报告' --print
zhao browse '学习报告' --copy| 参数 | 简写 | 说明 |
| --------- | ---- | ------------------- |
| query | — | 可选项目查询 |
| --print | -p | 只打印仓库 URL |
| --copy | -c | 将 URL 复制到剪贴板 |
SSH 会话或无图形界面的 Linux 环境会自动降级为打印 URL。SSH 和 HTTPS 格式的 Git remote 都会转换为 Web URL。
--copy 只负责复制 URL,不会阻止图形界面继续打开页面;如需仅复制而不打开,请同时添加 --print。
zhao open
使用本机 macOS 应用打开项目。没有查询时优先使用当前 Zhao 项目;无法识别当前目录时显示项目选择器:
# 选择项目和打开工具
zhao open
# 指定项目,再选择打开工具
zhao open '学习报告'
# 跳过工具选择,直接使用 Cursor
zhao open '学习报告' --with cursor
zhao open --with cursor| 参数 | 简写 | 说明 |
| -------- | ---- | -------------------------------------- |
| query | — | 可选项目查询,仅支持已登记的 Zhao 项目 |
| --with | -w | 直接使用指定工具,不显示工具选择器 |
支持的工具按以下固定顺序展示,未安装的应用不会出现在选择器中:
| 工具 | --with 参数 |
| -------------- | --------------------------------- |
| VS Code | vscode、code |
| Cursor | cursor |
| Zed | zed |
| Antigravity | antigravity |
| Finder | finder |
| Terminal | terminal |
| iTerm2 | iterm、iterm2 |
| Warp | warp |
| Xcode | xcode |
| Android Studio | android-studio、androidstudio |
工具参数忽略大小写。显式指定未安装的工具会报错,不会自动改用其他应用。Terminal、iTerm2 和 Warp 会收到项目目录,但最终打开新窗口还是新标签页取决于应用自身设置。
该命令首版仅支持本地图形化 macOS 会话;非 macOS 或 SSH 环境会直接报错。
zhao ci
打开项目的测试或生产 CI 页面:
# 默认 test 环境
zhao ci '学习报告'
zhao ci test '学习报告'
zhao ci prod '学习报告'
# monorepo target 与普通项目一样通过名称或别名查询
zhao ci test '运营后台'
zhao ci prod '学生端'
# 用于脚本或复制
zhao ci prod '学习报告' --print
zhao ci test '学习报告' --copy| 参数 | 简写 | 说明 |
| --------- | ---- | ------------------- |
| query | — | 可选项目查询 |
| --print | -p | 只打印 CI URL |
| --copy | -c | 将 URL 复制到剪贴板 |
首个位置参数只有在值为 test 或 prod 时才会被解释为环境,否则它就是项目查询。URL 读取解析:
projects.yaml 中该项目的 links.ci-test 或 links.ci-prod。
monorepo 中每个 targets 项拥有独立的 CI 链接。进入 target 的 path
目录或其任意子目录后,不传 query 也会自动使用该 target:
cd frontend-platform/apps/admin-web
zhao ci testtarget 不会继承父仓库的 CI 链接,避免误打开其他子项目的构建页面;没有手动
链接时仍按普通项目规则尝试 config.yaml 中的 CI 模板。
与 browse 一样,--copy/-c 可和 --print/-p 组合,做到复制并输出 URL、但不打开页面。
zhao tag
为已索引项目追加手动元数据:
zhao tag '学习报告' --alias report
zhao tag '学习报告' --kw 报告
zhao tag '学习报告' --domain report.example.com
zhao tag '学习报告' --rm-domain api.invalid.example.com
zhao tag report \
--ci-test https://build.example.com/report/test \
--ci-prod https://build.example.com/report/prod| 参数 | 说明 |
| ------------- | ------------------------------------------ |
| --alias | 添加别名 |
| --kw | 添加手动关键词 |
| --domain | 添加页面域名 |
| --rm-domain | 拉黑自动扫描出的域名,使后续扫描不再加入它 |
| --ci-test | 设置测试环境 CI 链接 |
| --ci-prod | 设置生产环境 CI 链接 |
--alias、--kw、--domain 和 --rm-domain 可重复使用,也可用逗号分隔多个值。命令会追加并去重,不会覆盖其他已有手动元数据。
zhao list
列出所有已索引项目:
zhao list
zhao list --json默认以表格展示项目名、路径和描述,并根据终端宽度截断过长内容;--json 输出自动索引与手动元数据合并后的完整数据。
zhao info
查看单个项目的完整合并数据,并标明自动扫描、手动配置、模板或猜测来源:
zhao info '学习报告'输出会按“基本信息 / 标记 / 域名 / 链接”分区显示为表格,并根据终端宽度自动换行长路径和 URL。
zhao edit
使用 $EDITOR 打开 projects.yaml:
EDITOR=vim zhao edit未设置 $EDITOR 时默认使用 vim。
zhao config
不带参数时使用 $EDITOR 打开 config.yaml:
zhao config也可以读取或设置受支持的配置键:
zhao config get scanRoots
zhao config set scanRoots ~/work/fe,~/work/mobile
zhao config set useFzf true
zhao config set scanDepth 6支持的键包括:
scanRootsuseFzfscanDepth(1 到 10)
修改 scanRoots 或 scanDepth 后,请运行 zhao scan 更新索引。手动域名黑名单会立即过滤现有索引,并在后续扫描中继续生效。
zhao doctor
检查 shell wrapper、配置文件、索引、索引新鲜度、扫描目录和 Node.js 版本:
zhao doctor存在失败项时命令返回非零退出码;索引超过 7 天未更新会显示警告。
帮助与版本
zhao --help
zhao tag --help
zhao --version配置
默认数据目录是 ~/.config/zhao/。可以通过 ZHAO_CONFIG_DIR 环境变量覆盖,适合隔离环境或自动化测试。
config.yaml
scanRoots:
- ~/work/fe
- ~/work/mobile
# true 时优先使用 fzf,调用失败或未安装时回退到内置选择器
useFzf: false
# 扫描根目录下查找 .git 的最大深度,范围 1~10,默认 5
scanDepth: 5projects.yaml
手动元数据以规范化后的 Git remote 路径作为项目 ID。这样即使本地目录移动,或不同成员将仓库克隆到不同位置,配置仍能对应同一个项目。
普通多仓库项目保持一个 Git 仓库对应一个顶层配置:
git.example.com/group/name:
aliases:
- alias1
- alias2
domains:
- value: domain.example.com
type: page
keywords:
- keyword1
- keyword2
links:
ci-test: https://build.example.com/group/name/test
ci-prod: https://build.example.com/group/name/prod
blockedDomains:
- cdn.example.commonorepo 在仓库配置中使用手动维护的 targets。target key(例如
admin-web)是稳定标识,path 是相对于仓库根目录的路径;移动子项目时只需
修改 path,不要修改 target key:
git.example.com/group/frontend-platform:
aliases:
- 前端平台
keywords:
- frontend
- monorepo
targets:
admin-web:
name: 运营后台
path: apps/admin-web
aliases:
- 后台
keywords:
- 运营
domains:
- value: admin.example.com
type: page
links:
ci-test: https://build.example.com/frontend-platform/admin-web/test
ci-prod: https://build.example.com/frontend-platform/admin-web/prod
student-web:
name: 学生端
path: apps/student-web
aliases:
- 学生中心
links:
ci-test: https://build.example.com/frontend-platform/student-web/test
ci-prod: https://build.example.com/frontend-platform/student-web/prodzhao scan 只自动发现 Git 仓库,不自动创建或删除 targets。workspace 中可能
同时包含应用、组件库和工具包,Zhao 无法仅根据目录可靠判断哪些子项目拥有独立
构建,因此 target 的 key、名称、路径和 CI 链接均由用户维护。
建议优先使用 zhao tag 修改手动元数据;需要批量调整时再使用 zhao edit。
数据文件
| 文件 | 维护者 | 用途 |
| --------------- | ----------------------- | --------------------------------------------------------------------------------- |
| config.yaml | 用户 | 扫描根目录、CI 模板、选择器和扫描深度 |
| projects.yaml | zhao scan、用户或团队 | 自动补齐仓库 key;用户维护别名、关键词、域名、链接、域名黑名单和 monorepo targets |
| index.json | zhao scan | 自动生成的项目索引,可随时删除后重建 |
| state.json | 程序 | 项目使用次数和最近使用时间,用于排序 |
扫描内容
zhao scan 会在 scanRoots 下查找 .git,然后从每个有效仓库提取:
- Git remote:生成稳定项目 ID、仓库分组和 GitLab URL
package.json:项目名、描述、关键词和依赖- README 一级标题:在
package.json没有描述时作为项目描述 - 依赖特征:识别 Vue 2/3、React、Next.js、Nuxt、Vite、Webpack、TypeScript 和 Pinia
- 常见配置文件中的域名:包括
.env*、根目录配置文件、src/api/**、src/config/**和 nginx 配置
扫描域名时会忽略 node_modules、dist、.git、常见 registry/CDN、示例域名和项目的 blockedDomains。对于 api.example.com 形式的 API 域名,还会生成低置信度的 example.com 页面域名候选。
检索与排序
项目按命中质量和 frecency 综合排序,主要优先级为:
- 页面域名、API 域名和猜测域名的精确、前缀或包含匹配。
- 手动别名。
- 手动关键词。
- 项目名、描述、自动关键词和技术栈。
- 最近且经常使用的项目获得额外权重。
手动页面域名的置信度最高,并会覆盖同值的自动扫描域名。blockedDomains 中的自动域名不会参与检索。
常见问题
执行 zhao <query> 后没有切换目录
shell wrapper 尚未生效。运行:
zhao setup
source ~/.zshrc
# bash 用户使用:source ~/.bashrc
zhao doctor找不到新项目或刚添加的关键词
项目路径、自动提取元数据发生变化后,需要重建索引:
zhao scanzhao tag 添加的别名和手动关键词会立即写入 projects.yaml,无需重新扫描。
索引损坏或不存在
index.json 不包含手工数据,可以直接重建:
zhao scanCI 页面提示没有链接
为项目单独设置链接:
zhao tag '学习报告' --ci-test https://build.example.com/group/name/test在脚本中使用
使用 --print 避免打开页面或切换目录:
project_path="$(zhao '学习报告' --print)"
repository_url="$(zhao browse '学习报告' --print)"
ci_url="$(zhao ci prod '学习报告' --print)"本地开发
开发环境使用 Bun 直接运行 TypeScript,依赖管理使用 pnpm 11;发布产物由 tsdown 构建为 Node.js 18 兼容的 ESM 可执行文件。
pnpm install
# 直接运行源码
pnpm dev
# 构建 dist/index.mjs
pnpm build
# 运行测试
pnpm test
# 格式、lint、类型检查和测试
pnpm check监听模式:
pnpm test:watch项目结构
src/
├── index.ts # 可执行入口与调用分类
├── cli.ts # Citty 命令注册和帮助输出
├── commands/ # 管理命令实现
├── core/ # 扫描、存储、检索、排序和动作逻辑
├── middleware/ # 首次使用引导
├── shell/ # zsh/bash wrapper 与安装逻辑
└── ui/ # 交互提示和项目选择器
test/
├── fixtures/ # 测试配置与数据样本
├── helpers/ # 共享测试工具
└── *.test.ts # Vitest 单元与 CLI 集成测试新增命令时将薄命令处理器放在 src/commands/,可复用的领域逻辑放在 src/core/。本地 ESM 导入需保留 .js 扩展名,不要直接修改生成的 dist/ 文件。
安全与数据边界
- 所有配置、索引和使用记录默认只保存在本机
~/.config/zhao/。 - 扫描过程只读取项目文件,不会修改被扫描的仓库。
- 索引只保存提取后的元数据、域名及其来源路径,不复制配置文件正文。
index.json可重建;需要备份或共享时应优先保留config.yaml和projects.yaml。projects.yaml可能包含内部仓库 ID 和 CI URL,请勿提交到公开仓库。
