🐛 fix(vscode): 提示词对齐 ECC 实际命令,需求文档改走 specs 布局
头脑风暴、实施、审查三套提示词引用的 /ecc:plan-prd、grill-me、 /ecc:tdd-workflow、/review 在 ECC 2.2.15 里都不存在,会话拿到的是一 条无效命令。审查提示词里的 /ecc:review-pr 走 gh,对 Gitea 不可用。 改为 ECC 实际链路:/ecc:grilling 讨论、/ecc:spec 出设计文档、 /ecc:plan 出计划、/ecc:tdd 实施,审查直接派 ecc:code-reviewer 等子代 理审 git diff。文档路径随 ECC 约定改成 .claude/specs/<stem>.md 与 .claude/plans/<stem>.md,stem 两者共用,不再带 .prd.md / .plan.md 后 缀;deriveSlug 相应改成取文件名 stem,通用文件名才退回目录名。 Claude-Session: https://claude.ai/code/session_01REdhpbaNyqWASF2HWsnTFv
This commit is contained in:
1 parent
ef0750b4ef
commit
518d471b7a
11 files changed
+60
-58
No files matched your search
+6
-6
@@ -17,8 +17,8 @@
|
||||
+ feature 分支 测试会话可随时开
|
||||
```
|
||||
|
||||
1. **新建工单**:待办列头的 `+` → 写需求(可粘贴截图)→ 开一个 `claude` 头脑风暴会话,它用 `spx issue create` 建工单,再经 `/ecc:plan-prd` + `/ecc:plan` 写出 PRD / 计划并回填两者路径。
|
||||
2. **实施**:把卡拖到「进行中」(或点计划文件行的 ▶)。插件创建 `feature/<slug>` 分支 + git worktree,在里面开 `issue-N-实施` 终端并发实施 prompt,实施方对计划跑 `/ecc:tdd-workflow`,在 PR body 里写 `Closes #N`。
|
||||
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 分支。
|
||||
@@ -41,7 +41,7 @@
|
||||
|---|---|
|
||||
| `git` | worktree、分支、fetch / merge |
|
||||
| `claude` | 规划、实施、测试、冲突解决、提交、PR 摘要(找不到时会提示常见位置 `~/.local/bin`) |
|
||||
| ECC 插件(`ecc@ecc`) | Claude Code 插件,头脑风暴 / 实施会话用它的 `/ecc:plan-prd` `/ecc:plan` `/ecc:tdd-workflow` `/ecc:code-review` |
|
||||
| ECC 插件(`ecc@ecc`) | Claude Code 插件,头脑风暴 / 实施会话用它的 `/ecc:grilling` `/ecc:spec` `/ecc:plan` `/ecc:tdd` 和审查子代理 |
|
||||
| `codex` | 审查会话(开启自动审查时必需) |
|
||||
| `tea` | `spx` 从 `~/.config/tea/config.yml` 读取 Gitea host + token;审查 prompt 也用 `tea pulls` 看 PR |
|
||||
| `spx` | 本仓库 `cli/` 里的 Go CLI,见下文 |
|
||||
@@ -172,8 +172,8 @@ prompts 在 `prompts/*.md`,随 VSIX 一起安装,改完即生效,也可在
|
||||
## 工作区约定
|
||||
|
||||
```
|
||||
.claude/prds/<slug>.prd.md # PRD,即工单的 spec marker
|
||||
.claude/plans/<slug>.plan.md # 实施计划,即 plan marker
|
||||
.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
|
||||
@@ -184,7 +184,7 @@ docs/pr-diff/pr-<pr>-issue-<n>.md # PR 变更摘要
|
||||
.spx/*.sh # 钩子脚本
|
||||
```
|
||||
|
||||
实施分支名 `feature/<slug>`,slug 取 plan 路径里 `plans/` 后的一段(去掉 `.plan.md`)。
|
||||
实施分支名 `feature/<slug>`,slug 取计划文件名的 stem(`.claude/plans/<stem>.md` 里的 stem),与设计文档同名。
|
||||
|
||||
## 开发
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
"publisher": "clurdra",
|
||||
"name": "superpowers-vscode-clurdra",
|
||||
"displayName": "Superpowers-clurdra",
|
||||
"version": "0.2.126",
|
||||
"version": "0.2.127",
|
||||
"packageManager": "pnpm@10.27.0",
|
||||
"description": "Superpowers specs and plans Kanban explorer",
|
||||
"author": "clurdra",
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
/ecc:plan-prd 讨论下 {issueNumber} 号工单
|
||||
/ecc:grilling 讨论下 {issueNumber} 号工单
|
||||
|
||||
用 tea 命令找工单,用 grill-me skill 讨论细节,用表单形式和我交互,每次只问一个问题(`/ecc:plan-prd` 里成组的问题也拆成一次一问)。
|
||||
用 tea 命令找工单,用 `ecc:grilling` 技能讨论细节,用表单形式和我交互,每次只问一个问题(成组的问题也拆成一次一问)。
|
||||
|
||||
## 产物与顺序
|
||||
|
||||
1. 需求讨论清楚后,按 `/ecc:plan-prd` 的模板写 PRD 到 `.claude/prds/<slug>.prd.md`,让我确认。
|
||||
2. PRD 我确认后,用 Skill 工具调 `ecc:plan`,参数是 PRD 路径,产出 `.claude/plans/<slug>.plan.md`;计划出来后停下等我确认。
|
||||
3. `<slug>` 取工单标题的英文短横线名,PRD 与计划共用;工单已有 marker 就沿用其中的 slug。
|
||||
1. 需求讨论到共识后,用 Skill 工具调 `ecc:spec` 写设计文档到 `.claude/specs/<stem>.md`,让我确认。
|
||||
2. 设计文档我确认后,用 Skill 工具调 `ecc:plan`,参数是设计文档路径,产出 `.claude/plans/<stem>.md`;计划出来后停下等我确认。
|
||||
3. `<stem>` 取工单标题的英文短横线名,设计文档与计划共用同一个 stem;文件名里不要带 `spec` / `plan` 字样,目录已经表达了。工单已有 marker 就沿用其中的 stem。
|
||||
|
||||
## marker 维护(本会话有效)
|
||||
|
||||
PRD / 计划文件**一律在当前主 worktree(main 分支)创建并提交**,每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 需求文档` / `📝 docs: #<工单号> 实施计划`),不要为此新建或切换分支。创建后追加对应 marker:
|
||||
设计文档 / 计划文件**一律在当前主 worktree(main 分支)创建并提交**(`ecc:spec` 默认不提交,这里要显式提交),每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 设计文档` / `📝 docs: #<工单号> 实施计划`),不要为此新建或切换分支。创建后追加对应 marker:
|
||||
|
||||
```
|
||||
opencli spx issue marker --issue <工单号> --type spec --value .claude/prds/<slug>.prd.md
|
||||
opencli spx issue marker --issue <工单号> --type plan --value .claude/plans/<slug>.plan.md
|
||||
opencli spx issue marker --issue <工单号> --type spec --value .claude/specs/<stem>.md
|
||||
opencli spx issue marker --issue <工单号> --type plan --value .claude/plans/<stem>.md
|
||||
```
|
||||
|
||||
## 严禁擅自继续
|
||||
|
||||
如果你创建/更新了 PRD 或计划文件并 marker 已同步,**立即停下**汇报;不要进入实施流程。
|
||||
如果你创建/更新了设计文档或计划文件并 marker 已同步,**立即停下**汇报;不要进入实施流程。
|
||||
|
||||
特别地:
|
||||
|
||||
- 不要创建分支
|
||||
- 不要切换分支,包括 `git checkout` / `git switch`
|
||||
- 除 PRD / 计划文件外不要修改任何文件
|
||||
- 除设计文档 / 计划文件外不要修改任何文件
|
||||
- 不要创建 PR
|
||||
- 不要调用 gitea 其他写操作(除上面的 marker 同步)
|
||||
@@ -25,20 +25,20 @@ opencli spx issue create --title "<标题>" --body-file /tmp/issue-body.md
|
||||
|
||||
spx 返回工单号 + html_url。记下工单号,后续命令用。
|
||||
|
||||
## 后续需求文档 / 计划维护(本会话有效)
|
||||
## 后续设计文档 / 计划维护(本会话有效)
|
||||
|
||||
需求与计划走 ECC 工作流:`/ecc:plan-prd` 产出需求文档(PRD),`/ecc:plan <PRD 路径>` 产出实施计划。文件路径固定:
|
||||
需求与计划走 ECC 工作流:`/ecc:grilling` 讨论需求,`/ecc:spec` 产出设计文档,`/ecc:plan <设计文档路径>` 产出实施计划。文件路径固定:
|
||||
|
||||
- PRD:`.claude/prds/<slug>.prd.md`
|
||||
- 计划:`.claude/plans/<slug>.plan.md`
|
||||
- 设计文档:`.claude/specs/<stem>.md`
|
||||
- 计划:`.claude/plans/<stem>.md`
|
||||
|
||||
`<slug>` 取工单标题的英文短横线名(如 `app-entity`),PRD 与计划用同一个 slug。两个文件**一律在当前主 worktree(main 分支)创建并提交**,每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 需求文档` / `📝 docs: #<工单号> 实施计划`);实施 worktree 从 main 当前提交切出,没提交的文件在那边看不到。
|
||||
`<stem>` 取工单标题的英文短横线名(如 `app-entity`),两个文件用同一个 stem,文件名里不要带 `spec` / `plan` 字样。两个文件**一律在当前主 worktree(main 分支)创建并提交**(`ecc:spec` 默认不提交,这里要显式提交),每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 设计文档` / `📝 docs: #<工单号> 实施计划`);实施 worktree 从 main 当前提交切出,没提交的文件在那边看不到。
|
||||
|
||||
**只有**当你真正创建了 PRD 或计划文件后才追加对应 marker:
|
||||
**只有**当你真正创建了设计文档或计划文件后才追加对应 marker:
|
||||
|
||||
```
|
||||
opencli spx issue marker --issue <工单号> --type spec --value .claude/prds/<slug>.prd.md
|
||||
opencli spx issue marker --issue <工单号> --type plan --value .claude/plans/<slug>.plan.md
|
||||
opencli spx issue marker --issue <工单号> --type spec --value .claude/specs/<stem>.md
|
||||
opencli spx issue marker --issue <工单号> --type plan --value .claude/plans/<stem>.md
|
||||
```
|
||||
|
||||
spx 自动找到对应行替换或追加,保留所有其他 marker。**不要自己手写 `<!-- spx:* -->` 行**。
|
||||
@@ -51,4 +51,4 @@ spx 自动找到对应行替换或追加,保留所有其他 marker。**不要
|
||||
|
||||
- 不要创建分支
|
||||
- 不要切换分支
|
||||
- 除 PRD / 计划文件外不要改动或提交任何文件
|
||||
- 除设计文档 / 计划文件外不要改动或提交任何文件
|
||||
@@ -1,6 +1,6 @@
|
||||
/ecc:tdd-workflow @{planFile}
|
||||
/ecc:tdd @{planFile}
|
||||
|
||||
按计划实施 {issueNumber} 号工单:具体编码派子代理去做,全程保持测试绿灯。计划里的验证命令只当意图,落地时用仓库自己的 test / lint / typecheck 命令。提 PR 前先 `/ecc:code-review` 自审并修掉严重问题。发起 PR 时务必在 PR body 中包含 "Closes #{issueNumber}"。
|
||||
按计划实施 {issueNumber} 号工单:具体编码派子代理去做,全程保持测试绿灯。计划里的验证命令只当意图,落地时用仓库自己的 test / lint / typecheck 命令。提 PR 前先自审并修掉严重问题:把 `git diff origin/main...HEAD` 交给 `ecc:code-reviewer` 子代理(`/ecc:code-review` 的本地模式只看未提交改动,提交过就看不到了)。发起 PR 时务必在 PR body 中包含 "Closes #{issueNumber}"。
|
||||
|
||||
**严禁合并 PR**:你的职责只到发起 PR 为止,后续审查反馈到了请继续修复并 push,永远不要执行 `tea pulls merge` 或任何合并操作。
|
||||
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
/review 审查这个仓库的 PR #{prNumber}。
|
||||
审查这个仓库的 PR #{prNumber}。
|
||||
|
||||
用 `tea pulls {prNumber}` 看 PR 元信息(标题/描述/分支)。看代码差异用 git(当前目录就是 PR 分支的 worktree):先 `git fetch origin main`,再 `git diff origin/main...HEAD`(概览可加 --stat)。注意 tea 没有 `diff` 子命令,不要尝试 `tea pulls diff`。
|
||||
|
||||
## 审查方式
|
||||
|
||||
ECC 的 `/ecc:review-pr` 和 `/ecc:code-review` 的 PR 模式都走 `gh`,对 Gitea 不可用,不要调。直接把上面的 diff 喂给 ECC 的审查子代理,按改动涉及的语言挑:
|
||||
|
||||
- `ecc:code-reviewer`(必跑)
|
||||
- `ecc:silent-failure-hunter`、`ecc:pr-test-analyzer`(必跑)
|
||||
- 语言专项:TypeScript 用 `ecc:typescript-reviewer`,Python 用 `ecc:python-reviewer`,React 用 `ecc:react-reviewer`,其余同理
|
||||
|
||||
汇总时去重、按严重程度排序,只报置信度高的问题。
|
||||
|
||||
## 提交审查意见
|
||||
|
||||
把审查意见(markdown 格式)写到 `/tmp/review-{prNumber}.md`,调 spx:
|
||||
|
||||
@@ -5,19 +5,14 @@ import * as path from 'node:path'
|
||||
export const DEFAULT_WORKTREE_TEMPLATE = '~/Sources/worktree/$project_name/$feature_name'
|
||||
|
||||
/**
|
||||
* PRD / 计划按 ECC 布局存放:`.claude/prds/<slug>.prd.md`、`.claude/plans/<slug>.plan.md`。
|
||||
* slug 取 `plans` / `prds` / `specs` 后一段并去掉 `.plan.md` / `.prd.md` / `.md` 后缀。
|
||||
* 兜底父目录名,再兜底路径 hash,保证目录名不为空。
|
||||
* 设计文档 / 计划按 ECC 布局存放:`.claude/specs/<stem>.md`、`.claude/plans/<stem>.md`,
|
||||
* 文件名的 stem 就是 slug,两者共用同一个 stem。少数布局把文件名固定成
|
||||
* `plan.md` / `spec.md`,这时 slug 退回父目录名;再兜底路径 hash,保证不为空。
|
||||
*/
|
||||
export function deriveSlug(planFile: string): string {
|
||||
const segments = planFile.split('/').filter(Boolean)
|
||||
const anchor = segments.findIndex(s => s === 'plans' || s === 'prds' || s === 'specs')
|
||||
const next = anchor >= 0 ? segments[anchor + 1] : undefined
|
||||
if (next) {
|
||||
const slug = next.replace(/\.(?:plan|prd)\.md$|\.md$/, '')
|
||||
if (slug)
|
||||
return slug
|
||||
}
|
||||
const stem = path.basename(planFile).replace(/\.md$/, '')
|
||||
if (stem && stem !== 'plan' && stem !== 'spec')
|
||||
return stem
|
||||
const parent = path.basename(path.dirname(planFile))
|
||||
if (parent && parent !== '.' && parent !== '/')
|
||||
return parent
|
||||
|
||||
@@ -48,13 +48,13 @@ export interface Issue {
|
||||
/**
|
||||
* Optional workspace-relative path to the spec file for this issue, as
|
||||
* surfaced from the Claude session transcript. Lives under
|
||||
* `.claude/prds/<slug>.prd.md`.
|
||||
* `.claude/specs/<stem>.md`.
|
||||
*/
|
||||
specFile?: string
|
||||
/**
|
||||
* Optional workspace-relative path to the plan file for this issue, as
|
||||
* surfaced from the Claude session transcript. Lives under
|
||||
* `.claude/plans/<slug>.plan.md`.
|
||||
* `.claude/plans/<stem>.md`.
|
||||
*/
|
||||
planFile?: string
|
||||
/** Optional workspace-relative path to the generated PR diff summary. */
|
||||
|
||||
@@ -26,11 +26,11 @@ import { normalizeReleasePrefix } from '../git/release'
|
||||
*/
|
||||
const FALLBACK_BRAINSTORM_PROMPT = `我现在有这样一个需求 {userRequest},你用 spx 命令创建 gitea 工单。工单 body 末尾必须包含 <!-- spx:nonce={nonce} -->。创建完工单立即停下汇报,不要擅自实施。`
|
||||
|
||||
const FALLBACK_BRAINSTORM_CONTINUE_PROMPT = `/ecc:plan-prd 讨论下 {issueNumber} 号工单。PRD 写到 .claude/prds/<slug>.prd.md,我确认后用 ecc:plan 出 .claude/plans/<slug>.plan.md,两个文件在 main 上提交并用 spx issue marker 同步 marker。不要 git checkout / 不要写代码 / 不要建 PR。`
|
||||
const FALLBACK_BRAINSTORM_CONTINUE_PROMPT = `/ecc:grilling 讨论下 {issueNumber} 号工单。达成共识后用 ecc:spec 写 .claude/specs/<stem>.md,我确认后用 ecc:plan 出 .claude/plans/<stem>.md,两个文件在 main 上提交并用 spx issue marker 同步 marker。不要 git checkout / 不要写代码 / 不要建 PR。`
|
||||
|
||||
const FALLBACK_IMPLEMENT_PLAN_PROMPT = `/ecc:tdd-workflow @{planFile} 按计划实施,编码派子代理,发起 PR 时在 body 中包含 "Closes #{issueNumber}"。严禁合并 PR。`
|
||||
const FALLBACK_IMPLEMENT_PLAN_PROMPT = `/ecc:tdd @{planFile} 按计划实施,编码派子代理,发起 PR 时在 body 中包含 "Closes #{issueNumber}"。严禁合并 PR。`
|
||||
|
||||
const FALLBACK_REVIEW_PROMPT = `/review 用 tea 拿到 #{prNumber} PR 审查。审查意见用 spx pr review-comment 发评论,body 第一行写 <!-- spx:review=1 -->。`
|
||||
const FALLBACK_REVIEW_PROMPT = `用 tea 拿到 #{prNumber} PR,diff 交给 ecc:code-reviewer 子代理审查。审查意见用 spx pr review-comment 发评论,body 第一行写 <!-- spx:review=1 -->。`
|
||||
|
||||
type PromptName = 'brainstorm' | 'brainstorm-continue' | 'implement-plan' | 'review'
|
||||
|
||||
|
||||
@@ -4,20 +4,17 @@ import { describe, expect, it } from 'vitest'
|
||||
import { DEFAULT_WORKTREE_TEMPLATE, deriveSlug, resolveWorktreeDir, slugFromBranch } from '../../src/git/worktreePath'
|
||||
|
||||
describe('deriveSlug', () => {
|
||||
it('plans/ 后一段去掉 .plan.md', () => {
|
||||
expect(deriveSlug('.claude/plans/app-entity.plan.md')).toBe('app-entity')
|
||||
it('计划文件名的 stem 就是 slug', () => {
|
||||
expect(deriveSlug('.claude/plans/app-entity.md')).toBe('app-entity')
|
||||
})
|
||||
it('prds/ 后一段去掉 .prd.md', () => {
|
||||
expect(deriveSlug('.claude/prds/app-entity.prd.md')).toBe('app-entity')
|
||||
it('设计文档与计划共用同一个 stem', () => {
|
||||
expect(deriveSlug('.claude/specs/app-entity.md')).toBe('app-entity')
|
||||
})
|
||||
it('目录形式取 plans/ 后的目录名', () => {
|
||||
expect(deriveSlug('docs/superpowers/plans/x/plan.md')).toBe('x')
|
||||
it('文件名是通用的 plan.md 时退回父目录名', () => {
|
||||
expect(deriveSlug('.claude/plans/x/plan.md')).toBe('x')
|
||||
})
|
||||
it('没有 plans/prds/specs 锚点时退回父目录名', () => {
|
||||
expect(deriveSlug('foo/bar/notes.md')).toBe('bar')
|
||||
})
|
||||
it('没有父目录时退回路径 hash 前 8 位', () => {
|
||||
expect(deriveSlug('notes.md')).toMatch(/^[0-9a-f]{8}$/)
|
||||
it('通用文件名且没有父目录时退回路径 hash 前 8 位', () => {
|
||||
expect(deriveSlug('plan.md')).toMatch(/^[0-9a-f]{8}$/)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -29,13 +29,13 @@ export interface Issue {
|
||||
/**
|
||||
* Optional workspace-relative path to the spec file for this issue, as
|
||||
* surfaced from the Claude session transcript. Lives under
|
||||
* `.claude/prds/<slug>.prd.md`.
|
||||
* `.claude/specs/<stem>.md`.
|
||||
*/
|
||||
specFile?: string
|
||||
/**
|
||||
* Optional workspace-relative path to the plan file for this issue, as
|
||||
* surfaced from the Claude session transcript. Lives under
|
||||
* `.claude/plans/<slug>.plan.md`.
|
||||
* `.claude/plans/<stem>.md`.
|
||||
*/
|
||||
planFile?: string
|
||||
/** Optional workspace-relative path to the generated PR diff summary. */
|
||||
|
||||
Reference in new issue
Block a user