@zentao-hub/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +175 -0
  3. package/README.zh-CN.md +192 -0
  4. package/dist/agents.d.ts +62 -0
  5. package/dist/agents.js +202 -0
  6. package/dist/agents.js.map +1 -0
  7. package/dist/commands/init.d.ts +9 -0
  8. package/dist/commands/init.js +94 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/install-claude-md.d.ts +12 -0
  11. package/dist/commands/install-claude-md.js +25 -0
  12. package/dist/commands/install-claude-md.js.map +1 -0
  13. package/dist/commands/install-commands.d.ts +8 -0
  14. package/dist/commands/install-commands.js +27 -0
  15. package/dist/commands/install-commands.js.map +1 -0
  16. package/dist/commands/install-hooks.d.ts +7 -0
  17. package/dist/commands/install-hooks.js +31 -0
  18. package/dist/commands/install-hooks.js.map +1 -0
  19. package/dist/commands/install-mcp.d.ts +20 -0
  20. package/dist/commands/install-mcp.js +203 -0
  21. package/dist/commands/install-mcp.js.map +1 -0
  22. package/dist/commands/login.d.ts +17 -0
  23. package/dist/commands/login.js +110 -0
  24. package/dist/commands/login.js.map +1 -0
  25. package/dist/commands/logout.d.ts +7 -0
  26. package/dist/commands/logout.js +59 -0
  27. package/dist/commands/logout.js.map +1 -0
  28. package/dist/commands/profiles.d.ts +5 -0
  29. package/dist/commands/profiles.js +26 -0
  30. package/dist/commands/profiles.js.map +1 -0
  31. package/dist/commands/register.d.ts +12 -0
  32. package/dist/commands/register.js +26 -0
  33. package/dist/commands/register.js.map +1 -0
  34. package/dist/commands/repos.d.ts +8 -0
  35. package/dist/commands/repos.js +28 -0
  36. package/dist/commands/repos.js.map +1 -0
  37. package/dist/commands/uninstall-claude-md.d.ts +6 -0
  38. package/dist/commands/uninstall-claude-md.js +13 -0
  39. package/dist/commands/uninstall-claude-md.js.map +1 -0
  40. package/dist/commands/uninstall-commands.d.ts +7 -0
  41. package/dist/commands/uninstall-commands.js +21 -0
  42. package/dist/commands/uninstall-commands.js.map +1 -0
  43. package/dist/commands/uninstall-hooks.d.ts +6 -0
  44. package/dist/commands/uninstall-hooks.js +36 -0
  45. package/dist/commands/uninstall-hooks.js.map +1 -0
  46. package/dist/commands/uninstall-mcp.d.ts +8 -0
  47. package/dist/commands/uninstall-mcp.js +99 -0
  48. package/dist/commands/uninstall-mcp.js.map +1 -0
  49. package/dist/commands/uninstall.d.ts +14 -0
  50. package/dist/commands/uninstall.js +28 -0
  51. package/dist/commands/uninstall.js.map +1 -0
  52. package/dist/commands/use.d.ts +6 -0
  53. package/dist/commands/use.js +20 -0
  54. package/dist/commands/use.js.map +1 -0
  55. package/dist/commands/whoami.d.ts +6 -0
  56. package/dist/commands/whoami.js +48 -0
  57. package/dist/commands/whoami.js.map +1 -0
  58. package/dist/commands/workspace.d.ts +8 -0
  59. package/dist/commands/workspace.js +28 -0
  60. package/dist/commands/workspace.js.map +1 -0
  61. package/dist/index.d.ts +2 -0
  62. package/dist/index.js +496 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/paths.d.ts +16 -0
  65. package/dist/paths.js +36 -0
  66. package/dist/paths.js.map +1 -0
  67. package/dist/prompt.d.ts +7 -0
  68. package/dist/prompt.js +43 -0
  69. package/dist/prompt.js.map +1 -0
  70. package/dist/registry.d.ts +16 -0
  71. package/dist/registry.js +42 -0
  72. package/dist/registry.js.map +1 -0
  73. package/dist/util.d.ts +27 -0
  74. package/dist/util.js +70 -0
  75. package/dist/util.js.map +1 -0
  76. package/package.json +57 -0
  77. package/templates/.claude/commands/bug-analyze.md +46 -0
  78. package/templates/.claude/commands/fix-bug.md +193 -0
  79. package/templates/.githooks/commit-msg +47 -0
  80. package/templates/CLAUDE.md +86 -0
  81. package/templates/repos.yaml.example +26 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Deven Liu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # @zentao-hub/cli
2
+
3
+ English | [简体中文](README.zh-CN.md)
4
+
5
+ > **Not the official [`zentao-cli`](https://github.com/easysoft/zentao-cli).** This is the companion CLI for `@zentao-hub/mcp` — it installs slash commands / prompts, MCP server entries, hooks, and per-agent instruction files for the AI agent of your choice. For general-purpose terminal CRUD against ZenTao, use the official CLI instead.
6
+
7
+ The companion CLI for `@zentao-hub/mcp`. **The MCP server itself does not need it** — this CLI just bundles a handful of "manually copy or hand-write the script" tasks into subcommands:
8
+
9
+ - Install `/fix-bug` and `/bug-analyze` into the chosen agent's slash-command / prompt dir
10
+ - `--agent claude` → `~/.claude/commands/*.md`
11
+ - `--agent codex` → `~/.codex/prompts/*.md`
12
+ - `--agent copilot` → `<repo>/.github/prompts/*.prompt.md`
13
+ - `--agent copilot-cli` → `~/.copilot/agents/*.agent.md`
14
+ - Register the `zentao-hub` MCP server in the agent's config (Claude Code / Copilot in VS Code / Copilot CLI / Codex CLI)
15
+ - Install a commit-msg hook (blocks AI signatures + enforces Conventional Commits) into a target repository
16
+ - Drop the per-agent instructions file: `CLAUDE.md` (Claude Code), `AGENTS.md` (Codex / Copilot CLI), `.github/copilot-instructions.md` (Copilot in VS Code)
17
+ - **Uninstall** every `install` artifact in one shot, or one target at a time
18
+ - Initialize / inspect the bug-context workspace — **one workspace per profile** at `<$ZENTAO_HUB or ~/.zentao-hub>/<profile>/`
19
+ - Maintain the `repos.yaml` registry inside each profile's workspace (productId → one or more repositories)
20
+
21
+ > The CLI does not run the bug-fixing flow on behalf of the agent. The flow still goes through the slash commands / prompts and the MCP server, because "waiting for the user to confirm", "reading screenshots", and "exploring code" only make sense with an LLM in the loop. The CLI only handles _setting up the environment_.
22
+
23
+ ## Supported agents
24
+
25
+ | Agent ID | Tool | MCP config file | Instructions file |
26
+ | -------------- | ------------------------------- | --------------------------------------------------------------------------------- | ---------------------------------------------- |
27
+ | `claude` | Claude Code | `~/.claude.json` or `<repo>/.mcp.json` | `CLAUDE.md` |
28
+ | `copilot` | GitHub Copilot (VS Code) | User `User/mcp.json` or `<repo>/.vscode/mcp.json` | `.github/copilot-instructions.md` |
29
+ | `copilot-cli` | GitHub Copilot CLI | `~/.copilot/mcp-config.json` (user) or `<repo>/.mcp.json` (workspace) | `AGENTS.md` |
30
+ | `codex` | OpenAI Codex CLI | `~/.codex/config.toml` (user-only) | `AGENTS.md` |
31
+
32
+ ## Install
33
+
34
+ ```bash
35
+ npm install -g @zentao-hub/cli
36
+ ```
37
+
38
+ Or for development inside this monorepo (uses pnpm):
39
+
40
+ ```bash
41
+ corepack enable
42
+ pnpm install
43
+ pnpm run build
44
+ node packages/cli/dist/index.js help
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ```text
50
+ zentao-hub <command> [options]
51
+
52
+ install <target> install one of: commands | hooks | claude-md | mcp
53
+ uninstall [target] reverse a single target, or omit for a one-shot revert
54
+ of commands + hooks + claude-md (mcp not included)
55
+ init initialize the per-profile workspace
56
+ register <pid> <path> register a repository under a productId in the active profile's repos.yaml
57
+ repos [productId] print the active profile's registry
58
+ workspace, ws show the currently resolved workspace (supports --print-path for scripts)
59
+ login / logout / whoami / profiles / use manage credentials
60
+ help print help
61
+ ```
62
+
63
+ Run `zentao-hub help` for the full set of options.
64
+
65
+ ## A typical one-time setup
66
+
67
+ The example below targets Claude Code (`--agent claude`). Swap `--agent` for
68
+ `copilot` / `copilot-cli` / `codex` to set the same thing up for another
69
+ agent — credentials, workspace, and registry are shared across agents.
70
+
71
+ ```bash
72
+ # 1. Install the packages and log in once (credentials are shared across agents).
73
+ npm install -g @zentao-hub/mcp @zentao-hub/cli
74
+ zentao-hub login
75
+
76
+ # 2. Register the zentao-hub MCP server in the agent's config.
77
+ zentao-hub install mcp --agent claude
78
+
79
+ # 3. Install the slash commands / prompts.
80
+ zentao-hub install commands --agent claude
81
+
82
+ # 4. Initialize the bug-context workspace (agent-agnostic).
83
+ zentao-hub init
84
+ echo 'export ZENTAO_HUB=$HOME/.zentao-hub' >> ~/.zshrc
85
+
86
+ # 5. Per target repository: drop the instructions file, the commit-msg hook,
87
+ # and register the repo under a productId.
88
+ cd ~/projects/venus-fe
89
+ zentao-hub install claude-md --agent claude # claude→CLAUDE.md, codex/copilot-cli→AGENTS.md, copilot→.github/copilot-instructions.md
90
+ zentao-hub install hooks # commit-msg hook (agent-agnostic)
91
+ zentao-hub register 2 . --name venus-frontend --tag frontend --tag electron
92
+ ```
93
+
94
+ After that, open the chosen agent (Claude Code / Copilot Chat / Copilot CLI / Codex CLI) and type:
95
+
96
+ ```
97
+ /bug-analyze 9634 # analyze only
98
+ /fix-bug 27 # list active bugs assigned to you under product 27 and let you pick
99
+ /fix-bug 27 9634 # fix it directly
100
+ ```
101
+
102
+ ## Workspace layout
103
+
104
+ `$ZENTAO_HUB` (default `~/.zentao-hub`) is the *hub root*. The actual workspace is per-profile: `<root>/<profile>/`. This keeps bug context, registry, and attachments isolated when you have logins for multiple ZenTao instances (e.g. one per client). After `zentao-hub init --profile <name>`:
105
+
106
+ ```
107
+ $ZENTAO_HUB/
108
+ ├── credentials.json ← shared across profiles
109
+ ├── default/ ← profile workspace
110
+ │ ├── repos.yaml ← registry: productId → list of repositories
111
+ │ ├── repos.yaml.example ← template
112
+ │ └── bugs/ ← one sub-directory per bug, written by the slash commands
113
+ │ └── <bugId>/
114
+ │ ├── raw.json
115
+ │ ├── description.md
116
+ │ ├── history.md
117
+ │ ├── analysis.md
118
+ │ └── attachments/
119
+ │ ├── <id>-<title>.<ext>
120
+ │ └── inline/
121
+ │ └── inline-N-<basename>
122
+ └── client-foo/ ← second profile, fully isolated
123
+ ├── repos.yaml
124
+ └── bugs/
125
+ ```
126
+
127
+ Slash commands / prompts pick the workspace via the active `$ZENTAO_PROFILE` (which the MCP server already honors for auth). When `zentao-hub` is on `$PATH`, they run `zentao-hub workspace --profile $ZENTAO_PROFILE --print-path` to get the directory.
128
+
129
+ ### Migrating from the old flat layout
130
+
131
+ Earlier versions wrote `bugs/` and `repos.yaml` directly under the root. If you upgrade and still have files there, `zentao-hub init --migrate-legacy` moves them into the `default/` profile workspace.
132
+
133
+ ## The `repos.yaml` registry
134
+
135
+ A single productId can map to multiple repositories (frontend / backend / DB migrations / ...). `/fix-bug` Phase 2 supports multi-select; for cross-repo bugs it iterates per repository with worktree → commit → squash.
136
+
137
+ Structure:
138
+
139
+ ```yaml
140
+ products:
141
+ 27:
142
+ - name: eda-schematic
143
+ path: /Users/you/projects/eda-studio/eda-schematic
144
+ tags: [frontend]
145
+ - name: eda-interop
146
+ path: /Users/you/projects/eda-studio/eda-interop
147
+ tags: [api]
148
+ ```
149
+
150
+ You can edit it by hand, or append entries with `zentao-hub register`.
151
+
152
+ ## Flow overview (what the slash commands actually do)
153
+
154
+ `/fix-bug` has three phases:
155
+
156
+ ```
157
+ Phase 1 — Bug context (does not touch any repository)
158
+ Phase 2 — Pick repositories (multi-select; new inputs are written back to repos.yaml)
159
+ Phase 3 — For each chosen repo: worktree → edit → test → squash merge
160
+ Phase 4 — Wrap-up suggestions (push / resolve_bug / delete worktree)
161
+ ```
162
+
163
+ `/bug-analyze` runs only Phase 1. If you later want to actually fix the bug, run `/fix-bug <productId> <bugId>` and the previously downloaded context is reused.
164
+
165
+ ## Design trade-offs
166
+
167
+ - **The CLI installs environment, it does not run the flow.** Slash commands / prompts are LLM-in-the-loop by design; the CLI is not a replacement.
168
+ - **A central workspace, not a per-repo directory.** During analysis you don't yet know which repo to change; in multi-repo scenarios, putting context inside any one of them is awkward.
169
+ - **`worktree`, not `checkout`.** Leaves the main checkout alone, and multi-repo work is naturally parallel.
170
+ - **Squash, not fast-forward.** The main branch should see one clean `fix: #N` commit.
171
+ - **No automatic push / resolve / branch delete.** Side-effecting cross-boundary operations are kept explicit, for the user to trigger.
172
+
173
+ ## License
174
+
175
+ [MIT](../../LICENSE) © Deven Liu
@@ -0,0 +1,192 @@
1
+ # @zentao-hub/cli
2
+
3
+ [English](README.md) | 简体中文
4
+
5
+ > **不是禅道官方的 [`zentao-cli`](https://github.com/easysoft/zentao-cli)。** 本包是 `@zentao-hub/mcp` 的配套 CLI——只装 AI agent 的 slash command / prompt、hook、模板。要在终端直接 CRUD 禅道,请用官方的 `zentao-cli`。
6
+
7
+ `@zentao-hub/mcp` 的配套 CLI。**MCP server 本身不需要它** —— 它只是把原本要靠手抄/复制脚本完成的事情包成几个子命令:
8
+
9
+ - 把 `/fix-bug`、`/bug-analyze` 装到目标 agent 的 slash command / prompt 目录
10
+ - `--agent claude` → `~/.claude/commands/*.md`
11
+ - `--agent codex` → `~/.codex/prompts/*.md`
12
+ - `--agent copilot` → `<repo>/.github/prompts/*.prompt.md`
13
+ - `--agent copilot-cli` → `~/.copilot/agents/*.agent.md`
14
+ - 在目标 agent 的配置里注册 `zentao-hub` MCP server(Claude Code / Copilot in VS Code / Copilot CLI / Codex CLI 各自的 config 文件)
15
+ - 把 commit-msg hook(拦 AI 署名 + 校 Conventional Commits)装到目标代码库
16
+ - 按 agent 复制协作规则文件:`CLAUDE.md`(Claude Code)/ `AGENTS.md`(Codex / Copilot CLI)/ `.github/copilot-instructions.md`(Copilot in VS Code)
17
+ - 初始化 / 查看 bug-context workspace —— **每个 profile 一个 workspace**,在 `<$ZENTAO_HUB 或 ~/.zentao-hub>/<profile>/`
18
+ - 维护每个 profile workspace 里的 `repos.yaml` 注册表(productId → 多个代码库)
19
+
20
+ > CLI 不替 agent 跑修 bug 流程 —— 流程仍然走 slash command + MCP,因为「等用户确认」「读截图」「调研代码」这些只有 LLM 在循环里才合理。CLI 只解决 _装环境_ 这一段。
21
+
22
+ ## 支持的 agent
23
+
24
+ | Agent ID | 说明 | MCP 配置文件 | 协作规则文件 |
25
+ | -------------- | ----------------------------- | -------------------------------------------------------------------- | ----------------------------------------- |
26
+ | `claude` | Claude Code | `~/.claude.json` 或 `<repo>/.mcp.json` | `CLAUDE.md` |
27
+ | `copilot` | GitHub Copilot (VS Code) | 用户 `User/mcp.json` 或 `<repo>/.vscode/mcp.json` | `.github/copilot-instructions.md` |
28
+ | `copilot-cli` | GitHub Copilot CLI | `~/.copilot/mcp-config.json`(user)或 `<repo>/.mcp.json`(workspace)| `AGENTS.md` |
29
+ | `codex` | OpenAI Codex CLI | `~/.codex/config.toml`(user-only) | `AGENTS.md` |
30
+
31
+ ## 安装
32
+
33
+ ```bash
34
+ npm install -g @zentao-hub/cli
35
+ ```
36
+
37
+ 或本 monorepo 内开发(使用 pnpm):
38
+
39
+ ```bash
40
+ corepack enable
41
+ pnpm install
42
+ pnpm run build
43
+ node packages/cli/dist/index.js help
44
+ ```
45
+
46
+ ## 用法
47
+
48
+ ```text
49
+ zentao-hub <command> [options]
50
+
51
+ install <target> 装其中一项:commands | hooks | claude-md | mcp
52
+ uninstall [target] 回滚单项,或不带 target 一键回滚 commands + hooks + claude-md
53
+ (mcp 不在一键回滚里,要单独执行 uninstall mcp)
54
+ init 初始化当前 profile 的 workspace
55
+ register <pid> <path> 把仓库登记到当前 profile 的 repos.yaml
56
+ repos [productId] 打印当前 profile 的注册表
57
+ workspace, ws 显示当前 profile 解析到的 workspace(支持 --print-path 给脚本用)
58
+ login / logout / whoami / profiles / use 凭据管理
59
+ help 打印帮助
60
+ ```
61
+
62
+ 跑 `zentao-hub help` 看完整选项。
63
+
64
+ ## 典型一次性安装流程
65
+
66
+ 下面以 Claude Code 为例(`--agent claude`)。把每条命令里的 `--agent` 换成 `copilot` / `copilot-cli` / `codex` 即可装到对应 agent;凭据、workspace、注册表跨 agent 共用。
67
+
68
+ ```bash
69
+ # 1. 装包 + 登录(凭据所有 agent 共用)
70
+ npm install -g @zentao-hub/mcp @zentao-hub/cli
71
+ zentao-hub login
72
+
73
+ # 2. 在 agent 配置里注册 zentao-hub MCP server
74
+ zentao-hub install mcp --agent claude
75
+
76
+ # 3. 装 slash command / prompt
77
+ zentao-hub install commands --agent claude
78
+
79
+ # 4. 初始化 bug-context workspace(与具体 agent 无关)
80
+ zentao-hub init
81
+ echo 'export ZENTAO_HUB=$HOME/.zentao-hub' >> ~/.zshrc
82
+
83
+ # 5. 每个目标代码库:装协作规则文件 + commit-msg hook + 登记 productId
84
+ cd ~/projects/venus-fe
85
+ zentao-hub install claude-md --agent claude # claude→CLAUDE.md, codex/copilot-cli→AGENTS.md, copilot→.github/copilot-instructions.md
86
+ zentao-hub install hooks # commit-msg hook(与 agent 无关)
87
+ zentao-hub register 2 . --name venus-frontend --tag 前端 --tag electron
88
+ ```
89
+
90
+ 之后在所选 agent 里(Claude Code / Copilot Chat / Copilot CLI / Codex CLI)启动并输入:
91
+
92
+ ```
93
+ /bug-analyze 9634 # 只分析
94
+ /fix-bug 27 # 列产品 27 你名下 active bug 让你挑
95
+ /fix-bug 27 9634 # 直接修
96
+ ```
97
+
98
+ ## 一键卸载
99
+
100
+ ```bash
101
+ zentao-hub uninstall # 全卸:slash command + 当前仓库的 hook + 当前仓库的 CLAUDE.md
102
+ zentao-hub uninstall --repo ~/projects/foo
103
+ zentao-hub uninstall --keep-hooks-path
104
+ ```
105
+
106
+ 需要更细粒度:
107
+
108
+ ```bash
109
+ zentao-hub uninstall commands
110
+ zentao-hub uninstall hooks --repo .
111
+ zentao-hub uninstall claude-md --repo .
112
+ zentao-hub uninstall mcp --agent claude
113
+ ```
114
+
115
+ 凭据和 workspace 不会被动 —— 那是用户数据,用 `zentao-hub logout --all` 删凭据,`rm -rf <hub-root>/<profile>` 删 workspace。
116
+
117
+ ## Workspace 目录结构
118
+
119
+ `$ZENTAO_HUB`(默认 `~/.zentao-hub`)是 *hub root*,每个 profile 一个 workspace:`<root>/<profile>/`。这样多个禅道实例(比如不同客户)的 bug 上下文、注册表、附件天然隔离。`zentao-hub init --profile <name>` 之后:
120
+
121
+ ```
122
+ $ZENTAO_HUB/
123
+ ├── credentials.json ← 跨 profile 共用
124
+ ├── default/ ← profile workspace
125
+ │ ├── repos.yaml ← 注册表:productId → 代码库列表
126
+ │ ├── repos.yaml.example ← 模板
127
+ │ └── bugs/ ← 每个 bug 一个子目录,由 slash command 写入
128
+ │ └── <bugId>/
129
+ │ ├── raw.json
130
+ │ ├── description.md
131
+ │ ├── history.md
132
+ │ ├── analysis.md
133
+ │ └── attachments/
134
+ │ ├── <id>-<title>.<ext>
135
+ │ └── inline/
136
+ │ └── inline-N-<basename>
137
+ └── client-foo/ ← 第二个 profile,完全隔离
138
+ ├── repos.yaml
139
+ └── bugs/
140
+ ```
141
+
142
+ slash command / prompt 通过当前的 `$ZENTAO_PROFILE`(MCP server 鉴权也用这个)来挑 workspace。`zentao-hub` 在 `$PATH` 上时,会跑 `zentao-hub workspace --profile $ZENTAO_PROFILE --print-path` 拿到目录。
143
+
144
+ ### 从老的扁平结构迁移
145
+
146
+ 更早的版本把 `bugs/` 和 `repos.yaml` 直接写在根目录下。如果升级后这些文件还在那儿,`zentao-hub init --migrate-legacy` 会把它们搬到 `default/` profile workspace。
147
+
148
+ ## 注册表 `repos.yaml`
149
+
150
+ 一个 productId 可以对应多个代码库(前端 / 后端 / 数据库迁移 / …)。`/fix-bug` 在 Phase 2 支持多选,跨库 bug 时按仓库循环 worktree + commit + squash。
151
+
152
+ 结构:
153
+
154
+ ```yaml
155
+ products:
156
+ 27:
157
+ - name: eda-schematic
158
+ path: /Users/you/projects/eda-studio/eda-schematic
159
+ tags: [前端]
160
+ - name: eda-interop
161
+ path: /Users/you/projects/eda-studio/eda-interop
162
+ tags: [api]
163
+ ```
164
+
165
+ 可以手工编辑,也可以用 `zentao-hub register` 追加。
166
+
167
+ ## 流程概览(slash command 跑的事)
168
+
169
+ `/fix-bug` 三阶段:
170
+
171
+ ```
172
+ Phase 1 — Bug 上下文(不依赖任何代码库)
173
+ Phase 2 — 选代码库(多选;新输入的写回 repos.yaml)
174
+ Phase 3 — 按每个选中的库循环:worktree → 改 → 测 → squash merge
175
+ Phase 4 — 收尾建议(push / resolve_bug / 删 worktree)
176
+ ```
177
+
178
+ `/bug-analyze` 只跑 Phase 1。之后想真修,直接 `/fix-bug <productId> <bugId>`,已下载的 context 会复用。
179
+
180
+ ## 设计取舍
181
+
182
+ - **CLI 只装环境,不跑流程**:slash command / prompt 是 LLM-in-the-loop 的设计,CLI 不取代它。
183
+ - **集中 workspace 而非仓库内**:bug 分析阶段不知道改哪个库;多库场景下放任何一个库都尴尬。
184
+ - **workspace 按 profile 隔离**:多 ZenTao 实例(不同客户/环境)的 bug 上下文与注册表互不污染。
185
+ - **worktree 而非 checkout**:主仓库不动,多库场景天然并行。
186
+ - **squash 而非 fast-forward**:主分支只想看一个干净的「fix: #N」commit。
187
+ - **不主动 push / resolve / 删分支**:副作用 / 跨边界操作留给用户显式触发。
188
+ - **uninstall 不动用户数据**:凭据、workspace 不会被 uninstall 删,避免误伤。
189
+
190
+ ## License
191
+
192
+ [MIT](../../LICENSE) © Deven Liu
@@ -0,0 +1,62 @@
1
+ export type AgentId = "claude" | "copilot" | "copilot-cli" | "codex";
2
+ export interface AgentInfo {
3
+ id: AgentId;
4
+ label: string;
5
+ }
6
+ export declare const AGENTS: readonly AgentInfo[];
7
+ /** Pretty label for log output. Centralized so commands don't drift. */
8
+ export declare function describeAgent(agent: AgentId): string;
9
+ /**
10
+ * Resolve which agent to target. If `explicit` is provided it must match a
11
+ * known id (case-insensitive). Otherwise — in interactive shells — show the
12
+ * menu; in non-interactive shells refuse rather than silently picking one.
13
+ */
14
+ export declare function resolveAgent(explicit?: string): Promise<AgentId>;
15
+ /**
16
+ * Where slash-command / prompt files live for each agent.
17
+ *
18
+ * Claude and Codex have a user-level prompts dir; Copilot has no such concept,
19
+ * so we drop into the repo's `.github/prompts/` (workspace-level prompts).
20
+ */
21
+ export declare function resolveAgentPromptsDir(agent: AgentId, opts?: {
22
+ explicit?: string;
23
+ repo?: string;
24
+ }): {
25
+ dir: string;
26
+ suffix: string;
27
+ scope: "user" | "workspace";
28
+ };
29
+ /**
30
+ * Repo-level "tell the AI how to work in this repo" file. Each agent reads a
31
+ * different filename, so we map agent → relative path inside the repo.
32
+ */
33
+ export declare function resolveAgentInstructionsFile(agent: AgentId, repo: string): {
34
+ abs: string;
35
+ rel: string;
36
+ };
37
+ export interface McpTarget {
38
+ /** File the config will be merged into. */
39
+ path: string;
40
+ /** Format that file uses. */
41
+ format: "json" | "toml";
42
+ /** Top-level key under which servers live (JSON formats). */
43
+ jsonKey?: "mcpServers" | "servers";
44
+ /** Section header used (TOML format). */
45
+ tomlSectionPrefix?: string;
46
+ /** Whether this is a user-level or workspace-level config. */
47
+ scope: "user" | "workspace";
48
+ /** Human-friendly description for log output. */
49
+ describe: string;
50
+ }
51
+ /**
52
+ * Resolve where an MCP server entry should be written for the given agent.
53
+ *
54
+ * Scope:
55
+ * - "user" (default for all agents): user-level config in the home dir
56
+ * - "workspace": project-level config inside `<repo>` (Claude + Copilot only;
57
+ * Codex has no documented workspace config so we fall back to user-level)
58
+ */
59
+ export declare function resolveMcpTarget(agent: AgentId, opts?: {
60
+ scope?: "user" | "workspace";
61
+ repo?: string;
62
+ }): McpTarget;
package/dist/agents.js ADDED
@@ -0,0 +1,202 @@
1
+ import path from "node:path";
2
+ import os from "node:os";
3
+ import { CliError } from "./util.js";
4
+ import { promptLine } from "./prompt.js";
5
+ export const AGENTS = [
6
+ { id: "claude", label: "Claude Code" },
7
+ { id: "copilot", label: "GitHub Copilot (VS Code)" },
8
+ { id: "copilot-cli", label: "GitHub Copilot CLI" },
9
+ { id: "codex", label: "OpenAI Codex CLI" },
10
+ ];
11
+ /** Pretty label for log output. Centralized so commands don't drift. */
12
+ export function describeAgent(agent) {
13
+ return AGENTS.find((a) => a.id === agent)?.label ?? agent;
14
+ }
15
+ /** Resolve ~/.copilot honoring $COPILOT_HOME, used by Copilot CLI. */
16
+ function copilotHome() {
17
+ return process.env.COPILOT_HOME
18
+ ? path.resolve(process.env.COPILOT_HOME)
19
+ : path.join(os.homedir(), ".copilot");
20
+ }
21
+ /**
22
+ * Resolve which agent to target. If `explicit` is provided it must match a
23
+ * known id (case-insensitive). Otherwise — in interactive shells — show the
24
+ * menu; in non-interactive shells refuse rather than silently picking one.
25
+ */
26
+ export async function resolveAgent(explicit) {
27
+ if (explicit) {
28
+ const lower = explicit.toLowerCase();
29
+ const hit = AGENTS.find((a) => a.id === lower);
30
+ if (!hit) {
31
+ throw new CliError(`Unknown agent '${explicit}'. Supported: ${AGENTS.map((a) => a.id).join(", ")}`);
32
+ }
33
+ return hit.id;
34
+ }
35
+ if (!process.stdin.isTTY) {
36
+ throw new CliError(`--agent is required in non-interactive mode. Supported: ${AGENTS.map((a) => a.id).join(", ")}`);
37
+ }
38
+ process.stdout.write(`Pick a target agent:\n`);
39
+ AGENTS.forEach((a, i) => {
40
+ process.stdout.write(` ${i + 1}) ${a.id.padEnd(8)} ${a.label}\n`);
41
+ });
42
+ const answer = (await promptLine(`Choice [1-${AGENTS.length}] (default 1): `)).trim();
43
+ if (!answer)
44
+ return AGENTS[0].id;
45
+ const byNum = Number(answer);
46
+ if (Number.isInteger(byNum) && byNum >= 1 && byNum <= AGENTS.length) {
47
+ return AGENTS[byNum - 1].id;
48
+ }
49
+ const byId = AGENTS.find((a) => a.id === answer.toLowerCase());
50
+ if (byId)
51
+ return byId.id;
52
+ throw new CliError(`Invalid choice '${answer}'`);
53
+ }
54
+ /**
55
+ * Where slash-command / prompt files live for each agent.
56
+ *
57
+ * Claude and Codex have a user-level prompts dir; Copilot has no such concept,
58
+ * so we drop into the repo's `.github/prompts/` (workspace-level prompts).
59
+ */
60
+ export function resolveAgentPromptsDir(agent, opts = {}) {
61
+ if (opts.explicit) {
62
+ return { dir: path.resolve(opts.explicit), suffix: promptSuffix(agent), scope: "user" };
63
+ }
64
+ switch (agent) {
65
+ case "claude":
66
+ return { dir: path.join(os.homedir(), ".claude", "commands"), suffix: ".md", scope: "user" };
67
+ case "codex":
68
+ return { dir: path.join(os.homedir(), ".codex", "prompts"), suffix: ".md", scope: "user" };
69
+ case "copilot": {
70
+ const repo = path.resolve(opts.repo ?? process.cwd());
71
+ return { dir: path.join(repo, ".github", "prompts"), suffix: ".prompt.md", scope: "workspace" };
72
+ }
73
+ case "copilot-cli":
74
+ // Copilot CLI has no "slash command" concept; the closest mapping is
75
+ // custom agents at ~/.copilot/agents/<name>.agent.md. They run as
76
+ // /<name> from inside `copilot`.
77
+ return { dir: path.join(copilotHome(), "agents"), suffix: ".agent.md", scope: "user" };
78
+ }
79
+ }
80
+ function promptSuffix(agent) {
81
+ if (agent === "copilot")
82
+ return ".prompt.md";
83
+ if (agent === "copilot-cli")
84
+ return ".agent.md";
85
+ return ".md";
86
+ }
87
+ /**
88
+ * Repo-level "tell the AI how to work in this repo" file. Each agent reads a
89
+ * different filename, so we map agent → relative path inside the repo.
90
+ */
91
+ export function resolveAgentInstructionsFile(agent, repo) {
92
+ const repoAbs = path.resolve(repo);
93
+ const rel = agentInstructionsRel(agent);
94
+ return { abs: path.join(repoAbs, rel), rel };
95
+ }
96
+ function agentInstructionsRel(agent) {
97
+ switch (agent) {
98
+ case "claude":
99
+ return "CLAUDE.md";
100
+ case "codex":
101
+ return "AGENTS.md";
102
+ case "copilot":
103
+ return path.join(".github", "copilot-instructions.md");
104
+ case "copilot-cli":
105
+ // Copilot CLI reads AGENTS.md as primary instructions (cross-tool
106
+ // standard, shared with Codex). The .github/copilot-instructions.md
107
+ // file is also read but already covered by the "copilot" target.
108
+ return "AGENTS.md";
109
+ }
110
+ }
111
+ /**
112
+ * Resolve where an MCP server entry should be written for the given agent.
113
+ *
114
+ * Scope:
115
+ * - "user" (default for all agents): user-level config in the home dir
116
+ * - "workspace": project-level config inside `<repo>` (Claude + Copilot only;
117
+ * Codex has no documented workspace config so we fall back to user-level)
118
+ */
119
+ export function resolveMcpTarget(agent, opts = {}) {
120
+ const scope = opts.scope ?? "user";
121
+ const repo = path.resolve(opts.repo ?? process.cwd());
122
+ if (agent === "claude") {
123
+ if (scope === "workspace") {
124
+ return {
125
+ path: path.join(repo, ".mcp.json"),
126
+ format: "json",
127
+ jsonKey: "mcpServers",
128
+ scope: "workspace",
129
+ describe: "Claude Code project-scope config (.mcp.json)",
130
+ };
131
+ }
132
+ return {
133
+ path: path.join(os.homedir(), ".claude.json"),
134
+ format: "json",
135
+ jsonKey: "mcpServers",
136
+ scope: "user",
137
+ describe: "Claude Code user config (~/.claude.json)",
138
+ };
139
+ }
140
+ if (agent === "copilot") {
141
+ if (scope === "workspace") {
142
+ return {
143
+ path: path.join(repo, ".vscode", "mcp.json"),
144
+ format: "json",
145
+ jsonKey: "servers",
146
+ scope: "workspace",
147
+ describe: "VS Code workspace MCP config (.vscode/mcp.json)",
148
+ };
149
+ }
150
+ return {
151
+ path: vsCodeUserMcpPath(),
152
+ format: "json",
153
+ jsonKey: "servers",
154
+ scope: "user",
155
+ describe: "VS Code user MCP config (User/mcp.json)",
156
+ };
157
+ }
158
+ if (agent === "copilot-cli") {
159
+ if (scope === "workspace") {
160
+ // Copilot CLI accepts either `<repo>/.mcp.json` or
161
+ // `<repo>/.github/mcp.json` at the project level. We default to
162
+ // `.mcp.json` because it's the shared cross-tool path also used by
163
+ // Claude Code's project scope — one file covers both agents.
164
+ return {
165
+ path: path.join(repo, ".mcp.json"),
166
+ format: "json",
167
+ jsonKey: "mcpServers",
168
+ scope: "workspace",
169
+ describe: "Copilot CLI project config (.mcp.json)",
170
+ };
171
+ }
172
+ return {
173
+ path: path.join(copilotHome(), "mcp-config.json"),
174
+ format: "json",
175
+ jsonKey: "mcpServers",
176
+ scope: "user",
177
+ describe: "Copilot CLI user config (~/.copilot/mcp-config.json)",
178
+ };
179
+ }
180
+ // codex — TOML, user-only.
181
+ return {
182
+ path: path.join(os.homedir(), ".codex", "config.toml"),
183
+ format: "toml",
184
+ tomlSectionPrefix: "mcp_servers",
185
+ scope: "user",
186
+ describe: "Codex CLI config (~/.codex/config.toml)",
187
+ };
188
+ }
189
+ function vsCodeUserMcpPath() {
190
+ const home = os.homedir();
191
+ if (process.platform === "darwin") {
192
+ return path.join(home, "Library", "Application Support", "Code", "User", "mcp.json");
193
+ }
194
+ if (process.platform === "win32") {
195
+ const appData = process.env.APPDATA ?? path.join(home, "AppData", "Roaming");
196
+ return path.join(appData, "Code", "User", "mcp.json");
197
+ }
198
+ // linux + others
199
+ const xdg = process.env.XDG_CONFIG_HOME ?? path.join(home, ".config");
200
+ return path.join(xdg, "Code", "User", "mcp.json");
201
+ }
202
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}