{"_id":"@botaoxyz/zhao","_rev":"6-ada3148945bf13954492aa38275d064e","name":"@botaoxyz/zhao","dist-tags":{"latest":"0.6.0"},"versions":{"0.1.0":{"name":"@botaoxyz/zhao","version":"0.1.0","author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"_id":"@botaoxyz/zhao@0.1.0","maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"homepage":"https://github.com/Bo-Tao/zhao#readme","bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"bin":{"zhao":"dist/index.mjs"},"dist":{"shasum":"1b598921aa77836b6542d1d334a400612c48e7cf","tarball":"https://registry.npmjs.org/@botaoxyz/zhao/-/zhao-0.1.0.tgz","fileCount":5,"integrity":"sha512-6kTKyEMDTF/8wzWjdQxtptTFCuMYbUibOx+QttXwTSO5f4m95hKORHCBmxoyb+IzogXIhcFmAK1sRKyDuZ8Bjg==","signatures":[{"sig":"MEYCIQCWJHgcVx+zmVvarZCFl3Y9NVNq4vjXAlnGEE0mwyzJzAIhAIduD4Pe4dUpHWDt1qz8t1rV+6KG6YlvkKTfTI8AFDFw","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":181875},"type":"module","engines":{"node":">=18"},"gitHead":"6af316d6894ea4dac9b22580a1dd03af1d1772bb","scripts":{"dev":"bun src/index.ts","lint":"oxlint . --report-unused-disable-directives","test":"vitest run --dir test","build":"tsdown","check":"pnpm format:check && pnpm lint && pnpm typecheck && pnpm test","format":"oxfmt .","prepack":"pnpm build","lint:fix":"oxlint . --fix --report-unused-disable-directives","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"oxfmt . --check"},"_npmUser":{"name":"melody0z","email":"botaoxyz@gmail.com"},"repository":{"url":"git+https://github.com/Bo-Tao/zhao.git","type":"git"},"_npmVersion":"11.16.0","description":"按域名、关键词和模块快速检索本地项目的 CLI","directories":{},"_nodeVersion":"24.18.0","dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","citty":"^0.2.2","fast-glob":"^3.3.3","@clack/prompts":"^1.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.15.1","devDependencies":{"oxfmt":"^0.60.0","oxlint":"^1.75.0","tsdown":"^0.22.13","vitest":"^4.1.10","typescript":"^7.0.2","@types/node":"^24.13.3"},"_npmOperationalInternal":{"tmp":"tmp/zhao_0.1.0_1784718144334_0.8391260893789536","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@botaoxyz/zhao","version":"0.2.0","author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"_id":"@botaoxyz/zhao@0.2.0","maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"homepage":"https://github.com/Bo-Tao/zhao#readme","bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"bin":{"zhao":"dist/index.mjs"},"dist":{"shasum":"7590e6c0921a5b4ccb735eca209707018641cf70","tarball":"https://registry.npmjs.org/@botaoxyz/zhao/-/zhao-0.2.0.tgz","fileCount":5,"integrity":"sha512-rri6oDXxdvj6w2OEV9v1E50KibvT2oq4dij5/fY7wNERogcCcvSFFY+gOxReO627PfX2rAUEUVmpOKD7kHJKIA==","signatures":[{"sig":"MEYCIQD2j4DSn6MqIl/CqWlDWhbfg7e/0p09/NAp0GMh6BBHWQIhAONv256omfYTwCxmeLII78WLmKFyZ3KjBeCaGMQ6aksc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":185825},"type":"module","engines":{"node":">=18"},"gitHead":"e2bc41ad2f863fd99456a69c2f4537a53bf081e6","scripts":{"dev":"bun src/index.ts","lint":"oxlint . --report-unused-disable-directives","test":"vitest run --dir test","build":"tsdown","check":"pnpm format:check && pnpm lint && pnpm typecheck && pnpm test","format":"oxfmt .","prepack":"pnpm build","lint:fix":"oxlint . --fix --report-unused-disable-directives","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"oxfmt . --check"},"_npmUser":{"name":"melody0z","email":"botaoxyz@gmail.com"},"repository":{"url":"git+https://github.com/Bo-Tao/zhao.git","type":"git"},"_npmVersion":"11.16.0","description":"按域名、关键词和模块快速检索本地项目的 CLI","directories":{},"_nodeVersion":"24.18.0","dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","citty":"^0.2.2","fast-glob":"^3.3.3","@clack/prompts":"^1.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.15.1","devDependencies":{"oxfmt":"^0.60.0","oxlint":"^1.75.0","tsdown":"^0.22.13","vitest":"^4.1.10","typescript":"^7.0.2","@types/node":"^24.13.3"},"_npmOperationalInternal":{"tmp":"tmp/zhao_0.2.0_1784825602732_0.4298855883800312","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@botaoxyz/zhao","version":"0.3.0","author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"_id":"@botaoxyz/zhao@0.3.0","maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"homepage":"https://github.com/Bo-Tao/zhao#readme","bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"bin":{"zhao":"dist/index.mjs"},"dist":{"shasum":"cd97d2ea9b24a590395b2e1b283bf68e584e3f2a","tarball":"https://registry.npmjs.org/@botaoxyz/zhao/-/zhao-0.3.0.tgz","fileCount":5,"integrity":"sha512-MULsNa5FdiVKw13xyI6twm/X2eVY1RBfi+NfQhBAU4aJU+9ypkjrzf5NDYlJwA4pvE252aLJH7TcbHq35t7XEw==","signatures":[{"sig":"MEQCIEjIiodd04aHjVbOMxzQkvJ1Msbgn8PAnS2S0URd6gloAiBlP3Pa52nPDeNymhjaukyRMHGMQnoY/nkLWfJMpGVUFw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":190795},"type":"module","engines":{"node":">=18"},"gitHead":"d85e961ca0c3a8dc5b66212f853362b77c703fe0","scripts":{"dev":"bun src/index.ts","lint":"oxlint . --report-unused-disable-directives","test":"vitest run --dir test","build":"tsdown","check":"pnpm format:check && pnpm lint && pnpm typecheck && pnpm test","format":"oxfmt .","prepack":"pnpm build","lint:fix":"oxlint . --fix --report-unused-disable-directives","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"oxfmt . --check"},"_npmUser":{"name":"melody0z","email":"botaoxyz@gmail.com"},"repository":{"url":"git+https://github.com/Bo-Tao/zhao.git","type":"git"},"_npmVersion":"11.16.0","description":"按域名、关键词和模块快速检索本地项目的 CLI","directories":{},"_nodeVersion":"24.18.0","dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","citty":"^0.2.2","fast-glob":"^3.3.3","@clack/prompts":"^1.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.15.1","devDependencies":{"oxfmt":"^0.60.0","oxlint":"^1.75.0","tsdown":"^0.22.13","vitest":"^4.1.10","typescript":"^7.0.2","@types/node":"^24.13.3"},"_npmOperationalInternal":{"tmp":"tmp/zhao_0.3.0_1784885688764_0.0499125098969635","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@botaoxyz/zhao","version":"0.4.0","author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"_id":"@botaoxyz/zhao@0.4.0","maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"homepage":"https://github.com/Bo-Tao/zhao#readme","bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"bin":{"zhao":"dist/index.mjs"},"dist":{"shasum":"9cb54ea1623688b5c43886549dd3f6196139cd44","tarball":"https://registry.npmjs.org/@botaoxyz/zhao/-/zhao-0.4.0.tgz","fileCount":5,"integrity":"sha512-aDFE8KOOnjSxGjU2m9vTmmHIcjSsqFkGAb9MR5X5yOgusRVu3c+tnafVu2fnLBsLAsPKVPtjOT0qYwDbyj8q4A==","signatures":[{"sig":"MEUCIDAKhJj6X1MflSZjGSU+lLhjga4p1/Ol17jheeFMKjMKAiEAgFDWd5lFKERRD03Y2afGwjk4ARg+EsWlUkWwHoIjyxY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":199312},"type":"module","engines":{"node":">=18"},"gitHead":"3f462d0a0e5c20eca309e868e6fee2f55e3117e1","scripts":{"dev":"bun src/index.ts","lint":"oxlint . --report-unused-disable-directives","test":"vitest run --dir test","build":"tsdown","check":"pnpm format:check && pnpm lint && pnpm typecheck && pnpm test","format":"oxfmt .","prepack":"pnpm build","lint:fix":"oxlint . --fix --report-unused-disable-directives","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"oxfmt . --check"},"_npmUser":{"name":"melody0z","email":"botaoxyz@gmail.com"},"repository":{"url":"git+https://github.com/Bo-Tao/zhao.git","type":"git"},"_npmVersion":"11.16.0","description":"按域名、关键词和模块快速检索本地项目的 CLI","directories":{},"_nodeVersion":"24.18.0","dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","citty":"^0.2.2","fast-glob":"^3.3.3","@clack/prompts":"^1.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.15.1","devDependencies":{"oxfmt":"^0.60.0","oxlint":"^1.75.0","tsdown":"^0.22.13","vitest":"^4.1.10","typescript":"^7.0.2","@types/node":"^24.13.3"},"_npmOperationalInternal":{"tmp":"tmp/zhao_0.4.0_1786526234975_0.6510635468671362","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@botaoxyz/zhao","version":"0.5.0","author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"_id":"@botaoxyz/zhao@0.5.0","maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"homepage":"https://github.com/Bo-Tao/zhao#readme","bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"bin":{"zhao":"dist/index.mjs"},"dist":{"shasum":"d94fbe7ee5167ca0b39ec41d440865c8c0c497c8","tarball":"https://registry.npmjs.org/@botaoxyz/zhao/-/zhao-0.5.0.tgz","fileCount":5,"integrity":"sha512-poI6Otv/E5ocAkiZGke/0ymAO67MufVVdgdx6MRSNmm6/oPGYRd3Ig1TRqSV8ii9fFPAECKH9qeCwI8qLU9SiQ==","signatures":[{"sig":"MEUCIAgcONlIK32zoSieoZJ7p9etjXb2D0vhe/ArSyYebADMAiEA1AuCXM5SIWp3QZhgrOSbpo5Eijoyauj2Jnn+4gQFBx0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":217604},"type":"module","engines":{"node":">=18"},"gitHead":"4a63e61d7b108573b9885e5e31e01f566ab4ac7f","scripts":{"dev":"bun src/index.ts","lint":"oxlint . --report-unused-disable-directives","test":"vitest run --dir test","build":"tsdown","check":"pnpm format:check && pnpm lint && pnpm typecheck && pnpm test","format":"oxfmt .","prepack":"pnpm build","lint:fix":"oxlint . --fix --report-unused-disable-directives","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"oxfmt . --check"},"_npmUser":{"name":"melody0z","email":"botaoxyz@gmail.com"},"repository":{"url":"git+https://github.com/Bo-Tao/zhao.git","type":"git"},"_npmVersion":"11.16.0","description":"按域名、关键词和模块快速检索本地项目的 CLI","directories":{},"_nodeVersion":"24.18.0","dependencies":{"zod":"^4.4.3","yaml":"^2.9.0","citty":"^0.2.2","fast-glob":"^3.3.3","@clack/prompts":"^1.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@11.15.1","devDependencies":{"oxfmt":"^0.60.0","oxlint":"^1.75.0","tsdown":"^0.22.13","vitest":"^4.1.10","typescript":"^7.0.2","@types/node":"^24.13.3"},"_npmOperationalInternal":{"tmp":"tmp/zhao_0.5.0_1786691342951_0.49256969269095885","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@botaoxyz/zhao","version":"0.6.0","description":"按域名、关键词和模块快速检索本地项目的 CLI","author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"repository":{"type":"git","url":"git+https://github.com/Bo-Tao/zhao.git"},"bin":{"zhao":"dist/index.mjs"},"type":"module","publishConfig":{"access":"public"},"scripts":{"build":"tsdown","check":"pnpm format:check && pnpm lint && pnpm typecheck && pnpm test","dev":"bun src/index.ts","format":"oxfmt .","format:check":"oxfmt . --check","lint":"oxlint . --report-unused-disable-directives","lint:fix":"oxlint . --fix --report-unused-disable-directives","prepack":"pnpm build","test":"vitest run --dir test","test:watch":"vitest","typecheck":"tsc --noEmit"},"dependencies":{"@clack/prompts":"^1.7.0","citty":"^0.2.2","fast-glob":"^3.3.3","yaml":"^2.9.0","zod":"^4.4.3"},"devDependencies":{"@types/node":"^24.13.3","oxfmt":"^0.60.0","oxlint":"^1.75.0","tsdown":"^0.22.13","typescript":"^7.0.2","vitest":"^4.1.10"},"engines":{"node":">=18"},"packageManager":"pnpm@11.15.1","gitHead":"f0a47c95fdf7714b574ae6120d3e78e66fabe7c7","_id":"@botaoxyz/zhao@0.6.0","bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"homepage":"https://github.com/Bo-Tao/zhao#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-Y1lqGkAgOvY0x396IpxjXyl8/JFYJJR3YRv9S4x4U6czBhtIw/73FZb4kfRJ4BoQ4S+9va/uvuH/dsrEcG/8yw==","shasum":"5e2412a22acfa578c091e613664fc97a80b75dc1","tarball":"https://registry.npmjs.org/@botaoxyz/zhao/-/zhao-0.6.0.tgz","fileCount":5,"unpackedSize":239656,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGmCbNihNhVc8UQZ9bxpgY31mh3K76tY1ZageI537bIGAiAJ6ewgMMrWiq7dq+1jwg7Z8QtjdwJw3UqfL52RKqQhJA=="}]},"_npmUser":{"name":"melody0z","email":"botaoxyz@gmail.com"},"directories":{},"maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/zhao_0.6.0_1787036065266_0.48692472566384826"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-22T11:02:24.211Z","modified":"2026-08-18T06:54:25.618Z","0.1.0":"2026-07-22T11:02:24.465Z","0.2.0":"2026-07-23T16:53:22.938Z","0.3.0":"2026-07-24T09:34:48.985Z","0.4.0":"2026-08-12T09:17:15.103Z","0.5.0":"2026-08-14T07:09:03.121Z","0.6.0":"2026-08-18T06:54:25.445Z"},"bugs":{"url":"https://github.com/Bo-Tao/zhao/issues"},"author":{"name":"BoTao","email":"botaoxyz@gmail.com"},"homepage":"https://github.com/Bo-Tao/zhao#readme","repository":{"type":"git","url":"git+https://github.com/Bo-Tao/zhao.git"},"description":"按域名、关键词和模块快速检索本地项目的 CLI","maintainers":[{"name":"melody0z","email":"botaoxyz@gmail.com"}],"readme":"# zhao\n\n`zhao`（“找”）是一个面向本地多仓库场景的项目检索 CLI。它会扫描 Git 仓库，建立包含项目名、描述、技术栈、域名和远程仓库信息的本地索引，让你可以通过域名、别名、关键词或项目名快速找到项目，并直接进入目录、打开代码助手、GitHub/GitLab 仓库地址或 CI 页面。\n\n```\n           █████\n          ░░███\n █████████ ░███████    ██████    ██████\n░█░░░░███  ░███░░███  ░░░░░███  ███░░███\n░   ███░   ░███ ░███   ███████ ░███ ░███\n  ███░   █ ░███ ░███  ███░░███ ░███ ░███\n █████████ ████ █████░░████████░░██████\n░░░░░░░░░ ░░░░ ░░░░░  ░░░░░░░░  ░░░░░░\n```\n\n```text\n域名 / 别名 / 关键词 / 项目名\n              ↓\n       本地索引与手动元数据\n              ↓\n   进入目录 / 打开编辑器 / GitLab / CI\n```\n\n## 特性\n\n- 给项目打标签，可以按项目域名、API 域名、别名、关键词、项目名或描述检索项目\n- 多个结果时显示交互式选择器，可选用 `fzf`\n- 通过 shell wrapper 真正切换当前终端目录\n- 可在进入项目后启动 Claude Code 或 Codex\n- 支持在 tmux 新窗口或新会话中打开项目\n- 扫描 `package.json`、README、Git remote 和常见配置文件生成索引\n- 支持为项目补充别名、页面域名、关键词和 CI 链接\n- 可从项目任意子目录打开 GitHub/GitLab 或 CI 页面\n- 使用 frecency（访问频率与时间衰减）优化检索排序\n- 配置和索引均保存在本地，不修改被扫描的项目\n\n## 环境要求\n\n- Node.js 18 或更高版本\n- zsh 或 bash（用于安装目录跳转 wrapper）\n- macOS、Linux 或 Windows 可运行构建产物；shell wrapper 当前仅支持 zsh 和 bash\n\n以下工具按需安装：\n\n- `fzf`：启用 `useFzf` 后用于项目选择，缺失时自动回退到内置选择器\n- `tmux`：使用 `--tmux` 时需要\n- `claude`：使用 `--claude` 时需要\n- `codex`：使用 `--codex` 时需要\n- Linux 剪贴板：使用 `--copy` 时需要 `wl-copy` 或 `xclip`\n\n## 安装\n\n```bash\nnpm install @botaoxyz/zhao -g\n```\n\n安装 shell wrapper：\n\n```bash\nzhao setup\n```\n\n`setup` 会自动识别 zsh 或 bash，并在 `~/.zshrc` 或 `~/.bashrc` 中追加：\n\n```bash\neval \"$(zhao init zsh)\"\n```\n\n它会在写入前展示内容并请求确认；重复运行不会重复写入。如果 rc 文件是符号链接，还会额外提示。完成后重新打开终端，或手动加载配置：\n\n```bash\nsource ~/.zshrc\n# bash 用户使用：source ~/.bashrc\n```\n\n也可以跳过 `setup`，自行把对应命令加入 shell 配置：\n\n```bash\neval \"$(zhao init zsh)\"\n# 或：eval \"$(zhao init bash)\"\n```\n\n## 快速开始\n\n第一次在交互式终端运行 `zhao` 时，会引导你完成以下操作：\n\n1. 检查 shell wrapper 是否生效。\n2. 输入一个或多个项目扫描根目录。\n3. 创建 `~/.config/zhao/config.yaml`。\n4. 扫描 Git 仓库并生成本地索引。\n\n完成后即可检索：\n\n```bash\n# 按项目名、关键词或别名检索并进入目录\nzhao 'report'\nzhao '学习报告'\n\n# 按域名检索\nzhao 'example.com'\n\n# 只打印路径，不切换目录\nzhao '学习报告' --print\n\n# 进入目录后启动 Claude Code\nzhao '学习报告' --claude\n\n# 进入目录后启动 Codex\nzhao '学习报告' --codex\n\n# 在 tmux 中打开项目\nzhao '学习报告' --tmux\n\n# 在 tmux 中打开项目并启动 Codex 或 Claude Code\nzhao '学习报告' --tmux --codex\nzhao '学习报告' --tmux --claude\n```\n\n`--claude` 与 `--codex` 不能同时使用。查询包含空格时需要加引号，并且一次只接受一个查询参数：\n\n```bash\nzhao \"学习 报告\"\n```\n\n## 工作原理\n\n子进程无法改变父 shell 的当前目录，因此 `zhao` 分为两层：\n\n- Node.js CLI 负责扫描、检索、交互选择以及输出目标路径。\n- shell wrapper 调用 CLI 获取路径，再在当前 shell 中执行 `cd`、启动代码助手或创建 tmux 窗口。\n\n如果未安装 wrapper，直接运行 `zhao <query>` 只会输出项目路径，不会改变当前目录。可通过下面的命令检查状态：\n\n```bash\nzhao doctor\n```\n\n## 命令参考\n\n### 项目检索\n\n```text\nzhao [query] [--print] [--claude] [--codex] [--tmux]\n```\n\n| 参数       | 简写   | 说明                                                                          |\n| ---------- | ------ | ----------------------------------------------------------------------------- |\n| `query`    | —      | 域名、别名、关键词或项目名；省略时从当前 Git 项目解析，否则显示全部项目供选择 |\n| `--print`  | `-p`   | 只打印选中的项目路径                                                          |\n| `--claude` | `-cc`  | 进入目录后启动 Claude Code                                                    |\n| `--codex`  | `-cdx` | 进入目录后启动 Codex                                                          |\n| `--tmux`   | `-t`   | 在 tmux 新窗口中打开；不在 tmux 中时创建新会话                                |\n\n显式 `query` 的优先级高于当前目录。若检索到多个项目，`zhao` 会展示项目名、描述和命中原因供选择。\n\n### `zhao setup`\n\n安装 shell wrapper，并在需要时继续首次配置和索引创建。\n\n```bash\nzhao setup\nzhao setup --shell zsh\nzhao setup --shell bash\n```\n\n### `zhao init`\n\n输出 shell wrapper 内容，适合手动安装或 dotfiles 管理。\n\n```bash\nzhao init zsh\nzhao init bash\n```\n\n### `zhao scan`\n\n扫描配置的根目录并全量重建 `index.json`：\n\n```bash\nzhao scan\n```\n\n扫描还会自动维护 `projects.yaml`：文件不存在时创建，并用 Git remote 生成的稳定项目 ID 补齐缺失 key。新项目会初始化空的 `aliases`、`domains`、`keywords`，以及空的 `links.ci-test`、`links.ci-prod`。已有手工元数据和未被本次扫描发现的旧条目都会保留；没有新增项目时不会重写文件。\n\n扫描会跳过损坏或没有 Git remote 的仓库，不会因为单个仓库失败而中断。已不在扫描目录中的项目会在重建后从索引中移除。\n\n### `zhao browse`\n\n打开项目的 GitHub/GitLab 页面。没有查询时优先使用当前 Git 项目：\n\n```bash\nzhao browse\nzhao browse '学习报告'\nzhao browse '学习报告' --print\nzhao browse '学习报告' --copy\n```\n\n| 参数      | 简写 | 说明                |\n| --------- | ---- | ------------------- |\n| `query`   | —    | 可选项目查询        |\n| `--print` | `-p` | 只打印仓库 URL      |\n| `--copy`  | `-c` | 将 URL 复制到剪贴板 |\n\nSSH 会话或无图形界面的 Linux 环境会自动降级为打印 URL。SSH 和 HTTPS 格式的 Git remote 都会转换为 Web URL。\n\n`--copy` 只负责复制 URL，不会阻止图形界面继续打开页面；如需仅复制而不打开，请同时添加 `--print`。\n\n### `zhao open`\n\n使用本机 macOS 应用打开项目。没有查询时优先使用当前 Zhao 项目；无法识别当前目录时显示项目选择器：\n\n```bash\n# 选择项目和打开工具\nzhao open\n\n# 指定项目，再选择打开工具\nzhao open '学习报告'\n\n# 跳过工具选择，直接使用 Cursor\nzhao open '学习报告' --with cursor\nzhao open --with cursor\n```\n\n| 参数     | 简写 | 说明                                   |\n| -------- | ---- | -------------------------------------- |\n| `query`  | —    | 可选项目查询，仅支持已登记的 Zhao 项目 |\n| `--with` | `-w` | 直接使用指定工具，不显示工具选择器     |\n\n支持的工具按以下固定顺序展示，未安装的应用不会出现在选择器中：\n\n| 工具           | `--with` 参数                     |\n| -------------- | --------------------------------- |\n| VS Code        | `vscode`、`code`                  |\n| Cursor         | `cursor`                          |\n| Zed            | `zed`                             |\n| Antigravity    | `antigravity`                     |\n| Finder         | `finder`                          |\n| Terminal       | `terminal`                        |\n| iTerm2         | `iterm`、`iterm2`                 |\n| Warp           | `warp`                            |\n| Xcode          | `xcode`                           |\n| Android Studio | `android-studio`、`androidstudio` |\n\n工具参数忽略大小写。显式指定未安装的工具会报错，不会自动改用其他应用。Terminal、iTerm2 和 Warp 会收到项目目录，但最终打开新窗口还是新标签页取决于应用自身设置。\n\n该命令首版仅支持本地图形化 macOS 会话；非 macOS 或 SSH 环境会直接报错。\n\n### `zhao ci`\n\n打开项目的测试或生产 CI 页面：\n\n```bash\n# 默认 test 环境\nzhao ci '学习报告'\nzhao ci test '学习报告'\nzhao ci prod '学习报告'\n\n# monorepo target 与普通项目一样通过名称或别名查询\nzhao ci test '运营后台'\nzhao ci prod '学生端'\n\n# 用于脚本或复制\nzhao ci prod '学习报告' --print\nzhao ci test '学习报告' --copy\n```\n\n| 参数      | 简写 | 说明                |\n| --------- | ---- | ------------------- |\n| `query`   | —    | 可选项目查询        |\n| `--print` | `-p` | 只打印 CI URL       |\n| `--copy`  | `-c` | 将 URL 复制到剪贴板 |\n\n首个位置参数只有在值为 `test` 或 `prod` 时才会被解释为环境，否则它就是项目查询。URL 读取解析：\n\n`projects.yaml` 中该项目的 `links.ci-test` 或 `links.ci-prod`。\n\nmonorepo 中每个 `targets` 项拥有独立的 CI 链接。进入 target 的 `path`\n目录或其任意子目录后，不传 query 也会自动使用该 target：\n\n```bash\ncd frontend-platform/apps/admin-web\nzhao ci test\n```\n\ntarget 不会继承父仓库的 CI 链接，避免误打开其他子项目的构建页面；没有手动\n链接时仍按普通项目规则尝试 `config.yaml` 中的 CI 模板。\n\n与 `browse` 一样，`--copy/-c` 可和 `--print/-p` 组合，做到复制并输出 URL、但不打开页面。\n\n### `zhao tag`\n\n为已索引项目追加手动元数据：\n\n```bash\nzhao tag '学习报告' --alias report\nzhao tag '学习报告' --kw 报告\nzhao tag '学习报告' --domain report.example.com\nzhao tag '学习报告' --rm-domain api.invalid.example.com\nzhao tag report \\\n  --ci-test https://build.example.com/report/test \\\n  --ci-prod https://build.example.com/report/prod\n```\n\n| 参数          | 说明                                       |\n| ------------- | ------------------------------------------ |\n| `--alias`     | 添加别名                                   |\n| `--kw`        | 添加手动关键词                             |\n| `--domain`    | 添加页面域名                               |\n| `--rm-domain` | 拉黑自动扫描出的域名，使后续扫描不再加入它 |\n| `--ci-test`   | 设置测试环境 CI 链接                       |\n| `--ci-prod`   | 设置生产环境 CI 链接                       |\n\n`--alias`、`--kw`、`--domain` 和 `--rm-domain` 可重复使用，也可用逗号分隔多个值。命令会追加并去重，不会覆盖其他已有手动元数据。\n\n### `zhao list`\n\n列出所有已索引项目：\n\n```bash\nzhao list\nzhao list --json\n```\n\n默认以表格展示项目名、路径和描述，并根据终端宽度截断过长内容；`--json` 输出自动索引与手动元数据合并后的完整数据。\n\n### `zhao info`\n\n查看单个项目的完整合并数据，并标明自动扫描、手动配置、模板或猜测来源：\n\n```bash\nzhao info '学习报告'\n```\n\n输出会按“基本信息 / 标记 / 域名 / 链接”分区显示为表格，并根据终端宽度自动换行长路径和 URL。\n\n### `zhao edit`\n\n使用 `$EDITOR` 打开 `projects.yaml`：\n\n```bash\nEDITOR=vim zhao edit\n```\n\n未设置 `$EDITOR` 时默认使用 `vim`。\n\n### `zhao config`\n\n不带参数时使用 `$EDITOR` 打开 `config.yaml`：\n\n```bash\nzhao config\n```\n\n也可以读取或设置受支持的配置键：\n\n```bash\nzhao config get scanRoots\nzhao config set scanRoots ~/work/fe,~/work/mobile\nzhao config set useFzf true\nzhao config set scanDepth 6\n```\n\n支持的键包括：\n\n- `scanRoots`\n- `useFzf`\n- `scanDepth`（1 到 10）\n\n修改 `scanRoots` 或 `scanDepth` 后，请运行 `zhao scan` 更新索引。手动域名黑名单会立即过滤现有索引，并在后续扫描中继续生效。\n\n### `zhao doctor`\n\n检查 shell wrapper、配置文件、索引、索引新鲜度、扫描目录和 Node.js 版本：\n\n```bash\nzhao doctor\n```\n\n存在失败项时命令返回非零退出码；索引超过 7 天未更新会显示警告。\n\n### 帮助与版本\n\n```bash\nzhao --help\nzhao tag --help\nzhao --version\n```\n\n## 配置\n\n默认数据目录是 `~/.config/zhao/`。可以通过 `ZHAO_CONFIG_DIR` 环境变量覆盖，适合隔离环境或自动化测试。\n\n### `config.yaml`\n\n```yaml\nscanRoots:\n  - ~/work/fe\n  - ~/work/mobile\n\n# true 时优先使用 fzf，调用失败或未安装时回退到内置选择器\nuseFzf: false\n\n# 扫描根目录下查找 .git 的最大深度，范围 1～10，默认 5\nscanDepth: 5\n```\n\n### `projects.yaml`\n\n手动元数据以规范化后的 Git remote 路径作为项目 ID。这样即使本地目录移动，或不同成员将仓库克隆到不同位置，配置仍能对应同一个项目。\n\n普通多仓库项目保持一个 Git 仓库对应一个顶层配置：\n\n```yaml\ngit.example.com/group/name:\n  aliases:\n    - alias1\n    - alias2\n  domains:\n    - value: domain.example.com\n      type: page\n  keywords:\n    - keyword1\n    - keyword2\n  links:\n    ci-test: https://build.example.com/group/name/test\n    ci-prod: https://build.example.com/group/name/prod\n  blockedDomains:\n    - cdn.example.com\n```\n\nmonorepo 在仓库配置中使用**手动维护**的 `targets`。target key（例如\n`admin-web`）是稳定标识，`path` 是相对于仓库根目录的路径；移动子项目时只需\n修改 `path`，不要修改 target key：\n\n```yaml\ngit.example.com/group/frontend-platform:\n  aliases:\n    - 前端平台\n  keywords:\n    - frontend\n    - monorepo\n  targets:\n    admin-web:\n      name: 运营后台\n      path: apps/admin-web\n      aliases:\n        - 后台\n      keywords:\n        - 运营\n      domains:\n        - value: admin.example.com\n          type: page\n      links:\n        ci-test: https://build.example.com/frontend-platform/admin-web/test\n        ci-prod: https://build.example.com/frontend-platform/admin-web/prod\n\n    student-web:\n      name: 学生端\n      path: apps/student-web\n      aliases:\n        - 学生中心\n      links:\n        ci-test: https://build.example.com/frontend-platform/student-web/test\n        ci-prod: https://build.example.com/frontend-platform/student-web/prod\n```\n\n`zhao scan` 只自动发现 Git 仓库，不自动创建或删除 `targets`。workspace 中可能\n同时包含应用、组件库和工具包，Zhao 无法仅根据目录可靠判断哪些子项目拥有独立\n构建，因此 target 的 key、名称、路径和 CI 链接均由用户维护。\n\n建议优先使用 `zhao tag` 修改手动元数据；需要批量调整时再使用 `zhao edit`。\n\n### 数据文件\n\n| 文件            | 维护者                  | 用途                                                                              |\n| --------------- | ----------------------- | --------------------------------------------------------------------------------- |\n| `config.yaml`   | 用户                    | 扫描根目录、CI 模板、选择器和扫描深度                                             |\n| `projects.yaml` | `zhao scan`、用户或团队 | 自动补齐仓库 key；用户维护别名、关键词、域名、链接、域名黑名单和 monorepo targets |\n| `index.json`    | `zhao scan`             | 自动生成的项目索引，可随时删除后重建                                              |\n| `state.json`    | 程序                    | 项目使用次数和最近使用时间，用于排序                                              |\n\n## 扫描内容\n\n`zhao scan` 会在 `scanRoots` 下查找 `.git`，然后从每个有效仓库提取：\n\n- Git remote：生成稳定项目 ID、仓库分组和 GitLab URL\n- `package.json`：项目名、描述、关键词和依赖\n- README 一级标题：在 `package.json` 没有描述时作为项目描述\n- 依赖特征：识别 Vue 2/3、React、Next.js、Nuxt、Vite、Webpack、TypeScript 和 Pinia\n- 常见配置文件中的域名：包括 `.env*`、根目录配置文件、`src/api/**`、`src/config/**` 和 nginx 配置\n\n扫描域名时会忽略 `node_modules`、`dist`、`.git`、常见 registry/CDN、示例域名和项目的 `blockedDomains`。对于 `api.example.com` 形式的 API 域名，还会生成低置信度的 `example.com` 页面域名候选。\n\n## 检索与排序\n\n项目按命中质量和 frecency 综合排序，主要优先级为：\n\n1. 页面域名、API 域名和猜测域名的精确、前缀或包含匹配。\n2. 手动别名。\n3. 手动关键词。\n4. 项目名、描述、自动关键词和技术栈。\n5. 最近且经常使用的项目获得额外权重。\n\n手动页面域名的置信度最高，并会覆盖同值的自动扫描域名。`blockedDomains` 中的自动域名不会参与检索。\n\n## 常见问题\n\n### 执行 `zhao <query>` 后没有切换目录\n\nshell wrapper 尚未生效。运行：\n\n```bash\nzhao setup\nsource ~/.zshrc\n# bash 用户使用：source ~/.bashrc\nzhao doctor\n```\n\n### 找不到新项目或刚添加的关键词\n\n项目路径、自动提取元数据发生变化后，需要重建索引：\n\n```bash\nzhao scan\n```\n\n`zhao tag` 添加的别名和手动关键词会立即写入 `projects.yaml`，无需重新扫描。\n\n### 索引损坏或不存在\n\n`index.json` 不包含手工数据，可以直接重建：\n\n```bash\nzhao scan\n```\n\n### CI 页面提示没有链接\n\n为项目单独设置链接：\n\n```bash\nzhao tag '学习报告' --ci-test https://build.example.com/group/name/test\n```\n\n### 在脚本中使用\n\n使用 `--print` 避免打开页面或切换目录：\n\n```bash\nproject_path=\"$(zhao '学习报告' --print)\"\nrepository_url=\"$(zhao browse '学习报告' --print)\"\nci_url=\"$(zhao ci prod '学习报告' --print)\"\n```\n\n## 本地开发\n\n开发环境使用 Bun 直接运行 TypeScript，依赖管理使用 pnpm 11；发布产物由 tsdown 构建为 Node.js 18 兼容的 ESM 可执行文件。\n\n```bash\npnpm install\n\n# 直接运行源码\npnpm dev\n\n# 构建 dist/index.mjs\npnpm build\n\n# 运行测试\npnpm test\n\n# 格式、lint、类型检查和测试\npnpm check\n```\n\n监听模式：\n\n```bash\npnpm test:watch\n```\n\n### 项目结构\n\n```text\nsrc/\n├── index.ts       # 可执行入口与调用分类\n├── cli.ts         # Citty 命令注册和帮助输出\n├── commands/      # 管理命令实现\n├── core/          # 扫描、存储、检索、排序和动作逻辑\n├── middleware/    # 首次使用引导\n├── shell/         # zsh/bash wrapper 与安装逻辑\n└── ui/            # 交互提示和项目选择器\n\ntest/\n├── fixtures/      # 测试配置与数据样本\n├── helpers/       # 共享测试工具\n└── *.test.ts      # Vitest 单元与 CLI 集成测试\n```\n\n新增命令时将薄命令处理器放在 `src/commands/`，可复用的领域逻辑放在 `src/core/`。本地 ESM 导入需保留 `.js` 扩展名，不要直接修改生成的 `dist/` 文件。\n\n## 安全与数据边界\n\n- 所有配置、索引和使用记录默认只保存在本机 `~/.config/zhao/`。\n- 扫描过程只读取项目文件，不会修改被扫描的仓库。\n- 索引只保存提取后的元数据、域名及其来源路径，不复制配置文件正文。\n- `index.json` 可重建；需要备份或共享时应优先保留 `config.yaml` 和 `projects.yaml`。\n- `projects.yaml` 可能包含内部仓库 ID 和 CI URL，请勿提交到公开仓库。\n","readmeFilename":"README.md"}