Files
superwork/vscode/README.md
T

222 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Superpowers-clurdra
把 GitHub 或 Gitea 仓库的工单变成 VS Code 里的看板,每张卡片背后挂着一组 AI 会话(头脑风暴 → 实施 → 审查 → 测试),从建工单到合并 PR 全程在编辑器里完成。
- 数据源:**GitHub / Gitea** 仓库工单(主,按工作区 git origin 的 host 区分:`github.com` 是 GitHub,其余都按 Gitea)+ **YouTrack** 工单(可选镜像)
- 执行者:`claude` CLI 负责规划 / 实施 / 测试 / 提交,`codex` 负责审查
- 状态存放:工单评论里的一段 state JSON(隐藏注释格式,网页上看不到),多人、多机共享;本机专属字段(会话 id、worktree 路径等)留在本机
- 联动:仓库 webhook 推回本机,PR 开了自动审查、审查意见自动注入实施终端、合并后自动清 worktree 和分支
## 工作流
```
待办 ──拖到进行中──▶ 进行中 ──PR 打开──▶ 审查 ──拖到完成──▶ 完成
│ │ │ │
头脑风暴会话 实施会话 审查会话(codex) 插件代为合并 PR
产出 spec / plan 独立 worktree 意见注入实施终端 关工单 · 删 worktree · 删分支
+ feature 分支 测试会话可随时开
```
1. **新建工单**:待办列头的 `+` → 写需求(可粘贴截图)→ 开一个 `claude` 头脑风暴会话,它用 `spx issue create` 建工单,再经 `/ecc:grilling` + `/ecc:spec` + `/ecc:plan` 写出设计文档 / 计划并回填两者路径。
2. **实施**:把卡拖到「进行中」(或点计划文件行的 ▶)。插件创建 `feature/<slug>` 分支 + git worktree,在里面开 `issue-N-实施` 终端并发实施 prompt,实施方对计划跑 `/ecc:tdd`,在 PR body 里写 `Closes #N`。
3. **审查**:PR opened / synchronize 的 webhook 到达后,插件自动开 `issue-N-审查`(codex);审查意见通过 `spx pr review-comment` 发到 PR,webhook 再把意见注入实施终端形成闭环。
4. **测试**:工单面板里 ▶ 开 `issue-N-测试` 会话(`/pr-acceptance-testing`)。
5. **完成**:拖到「完成」列。有 PR 就由插件合并(冲突时开 `issue-N-冲突解决` 会话,解决后再拖一次),然后关工单、把会话记录拷回主仓库、删 worktree、删 feature 分支。
6. **回退**:进行中 / 审查中的卡可「重置为待办」,关 PR、删 worktree、清分支和实施痕迹,spec / plan 保留。
7. **移交**:前置条件:两台机器的 spx 都已 `cd cli && make install` 到含 `handoffBundleKey` 的版本,否则移交期间旧 spx 的 state 写入会被 schema 拒绝;两台机器都在命令面板跑过「Superpowers: 配置移交存储」(阿里云 OSS 的 endpoint、bucket、AccessKey ID / Secret,AccessKey 存在 VS Code 的密钥存储里),没配的话移交和接管都会直接提示去配。工单 tab 头部「移交」→ 选同事。插件校验 worktree 已全部 push,关掉该工单的终端,把头脑风暴 / 实施 / 测试的 claude 会话(jsonl + 子目录)和 codex 审查会话打成 xz 压缩的 `issue-N-<时间>.tar.xz`,以私有权限传到 OSS 的 `spx-handoff/<owner>/<repo>/` 下,写 `handoffBundleKey` / `handoffFrom`,把工单指派给对方,最后删本机 worktree 与本地分支(远端分支保留)。对方看板上该卡显示「待接管」,工单 tab 点「接管」:从 OSS 下载会话包、从 origin 重建 worktree(`git worktree add -B <branch> … origin/<branch>`)、把会话文件装到本机 `~/.claude/projects/` 对应目录(先清同 sid 副本)与 `~/.codex/sessions/`、写本机字段、清移交字段并删掉 OSS 上的会话包。两边的进度提示会一步步显示打包 / 上传 / 下载了多少 MB。之后 resume / 合并 / 冲突解决 / 测试与本机实施的工单无异。
8. **发布**:工具栏「发布」按钮下拉三项。「切新发布」从 `origin/<devBranch>` 切当天的 `<releaseBranchPrefix>YYYY-MM-DD` 并推远端(纯远端,不建本地分支),配了 `jenkinsJob` 会顺带问要不要立刻部署。「摘修复到当期发布」列出 `devBranch` 上还没进发布分支的提交(按文件改动指纹比对,另认 `cherry-pick -x` 留下的「cherry picked from commit」尾注,所以解过冲突、内容已变的复制品也算已摘;手工 pick 请带 `-x`),多选后在发布 worktree(`worktreeDirectory` 模板,目录名为分支名把 `/` 换成 `-`)里按序 `cherry-pick -x` 并推远端,成功后删 worktree。中途冲突则保留冲突现场、远端不变,开 `<发布分支>-冲突解决` 会话让 claude 解冲突、`cherry-pick --continue`、按序摘完剩余提交再推远端;上次冲突还没处理完时再摘会被拒绝。「部署到正式服」选一个发布分支(默认当期,选旧的即回滚)执行 `opencli jks build <jenkinsJob> -p REF=<分支> -p REMOTE_HOST=<jenkinsProdHost>`。
其他看板规则:
- 待办列里卡片拖到另一张卡上 = 设前置依赖,拖回列头 = 清依赖。前置未完成的卡显示 🔒,不能拖出待办、不能开会话。待办列按依赖链渲染成缩进树。
- 完成列按合并时间倒序,其余列按工单号倒序。
- 每张卡首次开会话时随机分配一个颜色,之后该工单所有终端 tab 用同色圆点。
- 选中卡片会聚焦它的终端(新建 > 实施 > 规划 > 审查 > 测试);点终端 tab 也会反向选中卡片。
- 键盘:`↑↓←→` 移动选中,`Enter` 恢复实施会话(没有则头脑风暴会话),`Esc` 取消选中。
- 看板范围:工具栏 👤/👥 在「我创建或指派给我的」与「仓库全部」之间切换。
## 环境要求
| 工具 | 用途 |
|---|---|
| `git` | worktree、分支、fetch / merge |
| `claude` | 规划、实施、测试、冲突解决、提交、PR 摘要(找不到时会提示常见位置 `~/.local/bin`) |
| ECC 插件(`ecc@ecc`) | Claude Code 插件,头脑风暴 / 实施会话用它的 `/ecc:grilling` `/ecc:spec` `/ecc:plan` `/ecc:tdd` 和审查子代理 |
| `codex` | 审查会话(开启自动审查时必需) |
| `gh` | GitHub 仓库必需:插件和 `spx` 都现取 `gh auth token` 当凭据,先在终端 `gh auth login` |
| `tea` | Gitea 仓库:`spx` 从 tea 配置(`~/.config/tea/config.yml`,先 `tea login add`)里 host 匹配的 login 取 token |
| `spx` | 本仓库 `cli/` 里的 Go CLI,提示词里查工单、查 PR、发起 PR、写状态都用它,见下文 |
| `opencli` | prompts 里统一以 `opencli spx ...` 调用 spx |
| `tar` | 移交时打包 / 解包会话文件 |
| `bash` | 执行钩子脚本 |
- 支持 github.com 和自建 Gitea(`https://<host>/api/v1`);不支持 GitHub Enterprise,`github.com` 以外的 host 一律按 Gitea 处理。
- POSIX 环境。删 worktree 前扫 `/proc` 杀占用进程只在 Linux 生效,macOS 上降级为直接删。
- 依赖内置 `vscode.git` 扩展检测工作区改动(提交按钮)。
### 安装 spx
```bash
cd cli && make install # 编译到 bin/spx 并安装到 ~/.local/bin/(这个目录要在 PATH 里)
```
`spx` 按当前目录 git origin 的 host 选仓库:`github.com` 走 GitHub,凭据取 `gh auth token`;其余走 Gitea,凭据取 tea 配置里 host 匹配的 login,没有时回退环境变量 `GITEA_TOKEN`(tea 把 token 存在系统钥匙串里时就要设它)。
| 命令 | 作用 |
|---|---|
| `spx issue create --title T (--body B\|--body-file F) [--spec P] [--plan P] [--state-json J\|--state-file F]` | 建工单;spec / plan 同时写 body marker 和 state JSON |
| `spx issue view --issue N [--comments]` | 看工单标题、正文、状态、作者、指派人、链接;`--comments` 附带评论(不含 state 评论) |
| `spx issue marker --issue N --type spec\|plan\|prototype --value P` | 更新 body 里的 `<!-- spx:spec=... -->` 等 marker 并同步 state |
| `spx issue state get --issue N` | 读 state JSON |
| `spx issue state merge --issue N (--state-json J\|--state-file F)` | 浅合并写回(按 schema 校验) |
| `spx pr view --pr N` | 看 PR 标题、正文、状态、是否已合并、head / base 分支与 SHA、作者、链接 |
| `spx pr create --title T (--body B\|--body-file F) --head BRANCH [--base BRANCH]` | 发起 PR,`--base` 缺省为仓库默认分支;描述里写 `Closes #N` 看板才能把 PR 关联到工单 |
| `spx pr review-comment --pr N (--body B\|--body-file F)` | 发审查评论,自动加 `<!-- spx:review=1 -->` 标记 |
全局 flag:`--repo OWNER/REPO`、`--host`(默认都从 origin 推断)、`--json`、`--cwd`。
### 仓库与 webhook 配置
1. 认证:
- GitHub 仓库:终端里 `gh auth login` 即可,插件每次现取 `gh auth token`,自己不存 GitHub token。
- Gitea 仓库:打开看板 → 设置 → 认证,填 Personal Access Token(存 VS Code SecretStorage)。Gitea 邮箱和 `git config user.email` 不一致时会警告。
- 状态栏常驻显示当前身份 `spx: <login>`,凭据失效变红。
2. 在仓库上配一个 webhook 指向本机的 `http://<公网地址>/webhook`(本机默认监听 `17421`,通常经 frp 之类反代暴露)。Content type 必须选 **application/json**,表单编码的请求会被拒收(返回 415,日志里有提示)。建议设置 Secret 并在插件设置的 `webhookSecret` 里同填,插件按 `X-Hub-Signature-256: sha256=<HMAC-SHA256>` 校验,不填则不校验签名。
- **GitHub**:仓库 Settings → Webhooks → Add webhook。Payload URL 填上面的地址,Content type 选 `application/json`,Secret 同插件设置;事件选「Let me select individual events」,勾 **Issues、Issue comments、Pull requests、Pushes**。保存后 GitHub 发一个 `ping`,Recent Deliveries 里是 200 就通了。
- **Gitea**:仓库设置 → Web 钩子 → 添加 Gitea 钩子。目标 URL 填上面的地址,HTTP 方法 `POST`,POST Content Type 选 `application/json`,密钥文本同插件设置(Gitea 同样发 `X-GitHub-Event` 和 `X-Hub-Signature-256`);触发条件选自定义事件,勾 **Issues、Issue Comment、Pull Request、Push**。
3. 一个公网地址可以给多个仓库共用。本机开着多个 VS Code 窗口时只有一个窗口占得到端口,它把验过签的事件转给其余窗口,每个窗口只处理自己工作区 origin 对应仓库的事件;占端口的窗口关掉后,其余窗口几秒内接手端口。
4. webhook 会广播到每个开发者的机器,只有工单 assignee 所在的机器执行副作用(写状态、触发审查、注入终端),其他机器只刷新 UI。实施即认领,所以正常情况下不用手动指派。
### YouTrack(可选)
设置 → YouTrack 填 base URL、Permanent Token、项目 shortName 后,工具栏出现「导入 YouTrack 工单」,QuickPick 多选后镜像到看板(卡片 id 形如 `youtrack:LXF-12`)。状态同样以评论形式存在 YouTrack 工单上;拖到完成列执行 `youtrackCloseCommand`(留空则自动取项目第一个已解决状态)。
## 面板
编辑器主区的 webview = 顶部工具栏 + 四列看板 + 底部四个 tab。
**工具栏**:发布(切发布分支 · 摘修复 · 触发正式服部署,见工作流第 8 条;角标 = `devBranch` 上未发布的提交数)· `.env*` 文件锁(批量 chmod 只读,首次启动默认锁定)· 提交代码(有未提交改动时才显示,后台跑无头 `claude` 提交)· 导入 YouTrack 工单 · 看板范围 · 刷新 · 设置。
**工单 tab**:state JSON 的属性网格。会话 id 行双击恢复会话、▶ 新开、✕ 关 tab;spec / plan 行双击打开文件,plan 行 ▶ 实施;PR 行双击打开浏览器、▶ 生成 PR 变更摘要(写到 `docs/pr-diff/`);分支行 🔀 本地预合并;工作树行双击用 VS Code / PyCharm 打开、🗑 删除。顶部有重置为待办、移交 / 接管(见上文工作流第 7 条)、关闭工单、删除工单(关 tab → 删 worktree → 关 PR → 删分支 → 删 issue)、查看日志。
**Profile tab**:工作区级 KV 表(行 = key,列 = dev / prod 等),值可多行、可贴图,落盘 `.spx/profiles.json`。
**会话 tab**:项目级 Claude 会话管理器——新建(可指定 profile 和首条 prompt)、重命名、恢复、导入已 `/rename` 的会话。落盘 `.spx/session-names.json`。单个会话可以「交接」给同事:会话包打成 xz 包、以私有权限传到移交存储(同工单移交,没配会直接提示去跑「配置移交存储」)里对方的收件箱 `spx-handoff/<owner>/<repo>/session/<对方>/`;对方会话 tab 顶部「待接收」列出自己收件箱里的包,点「接收」下载装好会话、删掉 OSS 上的包。同一会话再交给同一人只保留最新一份;两边进度提示一步步显示打包 / 上传 / 下载了多少 MB。
**改动 tab**:PR 文件审阅。左侧文件树 + 统计(可过滤 `tests/`),右侧内联 diff(统一 / 分栏),「已查看」按文件变更指纹失效,每个文件可用 deepseek 生成一句话改动说明。
也可以从外部拉起会话:`vscode://clurdra.superpowers-vscode-clurdra/create-session?profile=<名>&name=<tab名>&prompt=<提示词>&cwd=<路径>`(参数需两层 urlencode)。
从 env 文件配置移交存储:`vscode://clurdra.superpowers-vscode-clurdra/configure-handoff-store?envFile=<env 文件绝对路径>`(参数同样两层 urlencode),读文件里的 `OSS_ENDPOINT` / `OSS_BUCKET_NAME` / `OSS_ACCESS_KEY` / `OSS_SECRET_KEY`,四项齐了就保存,缺项或读不到只报错、什么都不改。
## 会话与 profile
| 会话 | 终端名 | CLI | 工作目录 | profile |
|---|---|---|---|---|
| 新建工单 | `issue-new-<nonce>-规划` | claude | 主仓库 | 弹窗里选 |
| 头脑风暴(续) | `issue-N-规划` | claude | 主仓库 | 工单 `brainstormProfilePath` |
| 实施 | `issue-N-实施` | claude `--effort high` | worktree | 工单 `profilePath` |
| 审查 | `issue-N-审查` | codex | worktree | 设置里的 `codexModel` / `codexReasoningEffort` |
| 测试 | `issue-N-测试` | claude | worktree | 工单 `testProfilePath` |
| 冲突解决 | `issue-N-冲突解决` | claude `--effort high` | worktree | 设置 `conflictResolutionProfilePath` |
| 摘修复冲突解决 | `<发布分支>-冲突解决` | claude `--effort high` | 发布 worktree | 设置 `conflictResolutionProfilePath` |
所有终端固定开在编辑器第二分组。claude 会话统一以 `--settings <profile.json> --dangerously-skip-permissions` 启动,后台无头调用会剥掉 `ANTHROPIC_*` 环境变量,让 profile 成为唯一鉴权来源。
profile 是 Claude 的 settings JSON 文件。目录按 `$SUPERPOWERS_PROFILES_DIR` → 设置 `profilesDirectory` → `~/Sources/cruldra-profile/claude-config/profiles` / `~/.claude/profile-settings` / `~/.claude/profiles` 顺序探测;三种会话 profile 留空时各自回落默认 profile(`offical.json` / `official.json`),互不回退。跨机器的绝对路径按文件名重新映射。
prompts 在 `prompts/*.md`,随 VSIX 一起安装,改完即生效,也可在设置 → 提示词里覆盖。模板走 Handlebars:变量写 `{{name}}`,分支写 `{{#if name}}…{{else}}…{{/if}}`。上下文是工单 state JSON 的全部字段(`planFile` `specFile` `prototypeFile` `branch` `pr` `worktreePath` `prototypeSessionId` …)外加下表这几个:
| 文件 | 额外变量 |
|---|---|
| `brainstorm.md` | `issueNumber`(有 = 续聊已有工单,无 = 新建工单)、`userRequest`、`nonce` |
| `implement-plan.md` | `issueNumber`、`planFile` |
| `review.md` | `issueNumber`、`prNumber` |
| `test.md` | `issueNumber`、`prRef` |
| `prototype.md` | `issueNumber` |
`brainstorm.md` 一份管三件事:`{{#if issueNumber}}` 走续聊(其中 `{{#if prototypeFile}}` 嵌原型段落),`{{else}}` 走新建工单。老版本里 `{issueNumber}` 这种单花括号写法不再支持;升级后首次启动会自动把存量自定义提示词改写成双花括号,并把「续聊」「续聊·原型段落」两份并进 `brainstormPrompt`,改写前会把 `settings.json` 备份成 `settings.json.bak-<时间戳>`。
## 设置
全部在看板的设置弹窗里(存 globalState),不走 VS Code 原生 settings。
| 分组 | 键 | 默认 | 说明 |
|---|---|---|---|
| 认证 | `devBranch` | `main` | 日常开发分支 |
| | `releaseBranchPrefix` | `release/` | 发布分支前缀;远端该前缀下名字最大的分支即当期发布点 |
| | `jenkinsJob` | 空 | 正式服部署的 Jenkins 任务名;空 = 不显示「部署到正式服」 |
| | `jenkinsProdHost` | `正式服` | 触发 Jenkins 时 `REMOTE_HOST` 参数的值 |
| | `conflictResolutionProfilePath` | 空 | 冲突解决会话 profile |
| | `commitProfilePath` | `deepseek-v4-pro` | 「提交代码」用的 profile;未配置时提交直接失败 |
| | `prDiffSummaryProfilePath` | `deepseek-v4-pro` | 「改动」说明 / PR 变更摘要用的 profile;未配置时生成失败 |
| | `codexModel` / `codexReasoningEffort` | 空 | 审查会话的 codex `-c` 覆盖;空 = 用 codex 自己的 config |
| 网络 | `webhookPort` | `17421` | 本机 webhook 端口 |
| | `webhookSecret` | 空 | 仓库 webhook 的 Secret(GitHub / Gitea 通用,校验 `X-Hub-Signature-256`),空 = 不校验签名 |
| | `autoReview` | `true` | 全局自动审查;工单级 `autoReview` 可覆盖 |
| | `profilesDirectory` | 空 | Claude profiles 目录,空 = 自动探测 |
| YouTrack | `youtrackBaseUrl` / `youtrackProjectShortName` / `youtrackCloseCommand` | 空 | 见上文 |
| 钩子 | `worktreeDirectory` | `~/Sources/worktree/$project_name/$feature_name` | 占位符 `$project_root` `$project_name` `$feature_name` |
| | `worktreeOpenWith` / `pycharmCommand` | `vscode` / `pycharm` | 工作树行双击的打开方式 |
| | `worktreePostCreateScript` | `.spx/worktree-post-create.sh` | worktree 创建后 |
| | `worktreePreRemoveScript` | `.spx/worktree-pre-remove.sh` | worktree 删除前 |
| | `implTabPreCreateScript` | `.spx/impl-tab-pre-create.sh` | 实施 / 测试 / 冲突解决 tab 创建前(复用 tab 不触发) |
| | `implTabPostCloseScript` | `.spx/impl-tab-post-close.sh` | 实施 tab 关闭后 |
钩子用 `bash <script>` 执行,cwd 为 worktree,超时 30s,脚本不存在静默跳过,失败只告警不阻断。可用环境变量:`WORKTREE_PATH` `WORKSPACE_ROOT` `BRANCH` `ISSUE_NUMBER` `MAIN_BRANCH`。
## 工单上的 state JSON
以工单最后一条 state 评论为准,写入是读 → 浅合并 → 追加新评论,带一次乐观并发重放。schema 在 `schemas/state-json.schema.json`(`spx` 写入前按它校验)。
| 字段 | 说明 |
|---|---|
| `column` | `todo` / `in-progress` / `review` / `done` |
| `specFile` / `planFile` | 相对主仓库的 md 路径 |
| `branch` / `pr` / `prMerged` / `prMergedAt` | 实施分支与 PR 状态 |
| `implementStatus` | `running` / `done` / `failed` |
| `color` | 终端 tab 颜色 |
| `autoReview` | 工单级自动审查开关 |
| `handoffBundleKey` / `handoffFrom` | 移交中:会话包在 OSS 上的对象 key 与发起人;接管后清空 |
| `sessionId` / `implementSessionId` / `reviewSessionId` / `testSessionId` | 各会话 id |
| `profilePath` / `brainstormProfilePath` / `testProfilePath` | 各会话 profile |
| `worktreePath` / `prDiffFile` | 本机路径 |
最后两行(会话 id、profile、路径共 9 个字段)是**本机字段**,只存在 VS Code workspaceState 里,不写进共享评论,所以同一工单在不同机器上可以各自有会话。
## 工作区约定
```
.claude/specs/<stem>.md # 设计文档,即工单的 spec marker
.claude/plans/<stem>.md # 实施计划,即 plan marker
docs/pr-diff/pr-<pr>-issue-<n>.md # PR 变更摘要
.spx/profiles.json # Profile tab
.spx/session-names.json # 会话 tab
.spx/pr-review-confirmed.json # 改动 tab 已查看态
.spx/pr-file-summaries.json # 改动 tab 文件说明
.spx/youtrack-imported.json # YouTrack 导入集
.spx/profile-assets/ # Profile 值里粘贴的图片
.spx/*.sh # 钩子脚本
```
实施分支名 `feature/<slug>`,slug 取计划文件名的 stem(`.claude/plans/<stem>.md` 里的 stem),与设计文档同名。
## 开发
```bash
pnpm install
pnpm dev # webview (Vite) + 扩展 (esbuild) 双 watch,配合 .vscode/launch.json 的 Extension 调试
pnpm test # vitest,只测不依赖 vscode API 的纯逻辑模块
pnpm lint
pnpm typecheck
pnpm ext:package # 构建并打 VSIX,产物在本目录
```
安装本地包:`code --install-extension superpowers-vscode-clurdra-<ver>.vsix --force`(用了 VS Code profile 的窗口要加 `--profile <name>`)。
技术栈:TypeScript、VS Code Extension API、React 19 + Tailwind 4(webview)、esbuild、Vitest;CLI 为 Go + cobra。
## 许可证
MIT