✨ feat(vscode): 提示词不再绑定 Gitea,查工单、查 PR、发起 PR 统一走 spx

- 去掉 tea、gh、Gitea 字样:查工单 spx issue view,查 PR spx pr view,发起 PR spx pr create 且描述必须含 Closes #N
- 审查和实施的 diff 不再写死 origin/main:审查取 PR 的目标分支,实施取计划里的目标分支或仓库默认分支
- 工单模板同时看 .gitea/ISSUE_TEMPLATE/ 和 .github/ISSUE_TEMPLATE/,禁止合并的说法不带工具名
- 内联兜底提示词同步改;设置里存着旧版的用户激活时按现有机制被问是否换新版
- 新增测试守住自带提示词和兜底不再点名平台
This commit is contained in:
cruldra committed 2026-10-19 08:26:08 +11:00
1 parent ae06c8e5d1
commit 1bec57a1cb
7 files changed
+73 -21

No files matched your search

+6 -6
View File
@@ -1,7 +1,7 @@
{{#if issueNumber}} {{#if issueNumber}}
/ecc:grilling 讨论下 {{issueNumber}} 号工单 /ecc:grilling 讨论下 {{issueNumber}} 号工单
用 tea 命令找工单,用 `ecc:grilling` 技能讨论细节,用表单形式和我交互,每次只问一个问题(成组的问题也拆成一次一问)。 先用 `opencli spx issue view --issue {{issueNumber}} --comments` 看工单正文和讨论,再用 `ecc:grilling` 技能讨论细节,用表单形式和我交互,每次只问一个问题(成组的问题也拆成一次一问)。
{{#if prototypeFile}} {{#if prototypeFile}}
工单已有原型插件 {{prototypeFile}},先读它了解已经定下来的界面和交互,在此基础上只对齐还不明确的地方,不要从零重画。 工单已有原型插件 {{prototypeFile}},先读它了解已经定下来的界面和交互,在此基础上只对齐还不明确的地方,不要从零重画。
@@ -24,7 +24,7 @@
## marker 维护(本会话有效) ## marker 维护(本会话有效)
设计文档 / 计划文件**一律在当前主 worktree(main 分支)创建并提交**(`ecc:spec` 默认不提交,这里要显式提交),每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 设计文档` / `📝 docs: #<工单号> 实施计划`),不要为此新建或切换分支。创建后追加对应 marker: 设计文档 / 计划文件**一律在当前主 worktree(仓库默认分支)创建并提交**(`ecc:spec` 默认不提交,这里要显式提交),每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 设计文档` / `📝 docs: #<工单号> 实施计划`),不要为此新建或切换分支。创建后追加对应 marker:
``` ```
opencli spx issue marker --issue <工单号> --type spec --value .claude/specs/<stem>.md opencli spx issue marker --issue <工单号> --type spec --value .claude/specs/<stem>.md
@@ -41,15 +41,15 @@ opencli spx issue marker --issue <工单号> --type plan --value .claude/plans/<
- 不要切换分支,包括 `git checkout` / `git switch` - 不要切换分支,包括 `git checkout` / `git switch`
- 除设计文档 / 计划文件外不要修改任何文件 - 除设计文档 / 计划文件外不要修改任何文件
- 不要创建 PR - 不要创建 PR
- 不要调用 gitea 其他写操作(除上面的 marker 同步) - 除上面的 marker 同步外,不要对工单、PR 做任何写操作
{{else}} {{else}}
接下来我要实现下面这样的功能: {{userRequest}} 接下来我要实现下面这样的功能: {{userRequest}}
你的任务:用 spx CLI 创建一个 Gitea 工单。spx 用法参考 `using-spx-cli` skill。 你的任务:用 spx CLI 创建工单。spx 用法参考 `using-spx-cli` skill。
## 工单格式 ## 工单格式
先检查仓库的 `.gitea/ISSUE_TEMPLATE/` 目录: 先检查仓库的 `.gitea/ISSUE_TEMPLATE/` 和 `.github/ISSUE_TEMPLATE/` 目录:
- 有模板(`.md` 或 `.yaml`)→ 严格按模板填 body:标题前缀、章节标题、必填字段都写齐 - 有模板(`.md` 或 `.yaml`)→ 严格按模板填 body:标题前缀、章节标题、必填字段都写齐
- 没有模板 → 用普通 markdown 自由写 - 没有模板 → 用普通 markdown 自由写
@@ -77,7 +77,7 @@ spx 返回工单号 + html_url。记下工单号,后续命令用。
- 设计文档:`.claude/specs/<stem>.md` - 设计文档:`.claude/specs/<stem>.md`
- 计划:`.claude/plans/<stem>.md` - 计划:`.claude/plans/<stem>.md`
`<stem>` 取工单标题的英文短横线名(如 `app-entity`),两个文件用同一个 stem,文件名里不要带 `spec` / `plan` 字样。两个文件**一律在当前主 worktree(main 分支)创建并提交**(`ecc:spec` 默认不提交,这里要显式提交),每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 设计文档` / `📝 docs: #<工单号> 实施计划`);实施 worktree 从 main 当前提交切出,没提交的文件在那边看不到。 `<stem>` 取工单标题的英文短横线名(如 `app-entity`),两个文件用同一个 stem,文件名里不要带 `spec` / `plan` 字样。两个文件**一律在当前主 worktree(仓库默认分支)创建并提交**(`ecc:spec` 默认不提交,这里要显式提交),每次只提交这两个文件(提交信息形如 `📝 docs: #<工单号> 设计文档` / `📝 docs: #<工单号> 实施计划`);实施 worktree 从默认分支当前提交切出,没提交的文件在那边看不到。
**只有**当你真正创建了设计文档或计划文件后才追加对应 marker: **只有**当你真正创建了设计文档或计划文件后才追加对应 marker:
+12 -2
View File
@@ -1,5 +1,15 @@
/ecc:tdd @{{planFile}} /ecc:tdd @{{planFile}}
按计划实施 {{issueNumber}} 号工单:具体编码派子代理去做,全程保持测试绿灯。计划里的验证命令只当意图,落地时用仓库自己的 test / lint / typecheck 命令。提 PR 前先自审并修掉严重问题:把 `git diff origin/main...HEAD` 交给 `ecc:code-reviewer` 子代理(`/ecc:code-review` 的本地模式只看未提交改动,提交过就看不到了)。发起 PR 时务必在 PR body 中包含 "Closes #{{issueNumber}}"。 按计划实施 {{issueNumber}} 号工单:具体编码派子代理去做,全程保持测试绿灯。计划里的验证命令只当意图,落地时用仓库自己的 test / lint / typecheck 命令。
**严禁合并 PR**:你的职责只到发起 PR 为止,后续审查反馈到了请继续修复并 push,永远不要执行 `tea pulls merge` 或任何合并操作。 下面的 `<base>` 是 PR 要合进的分支:计划里写明了就用计划里的,没写就用仓库默认分支(`git remote show origin` 输出里的 `HEAD branch`)。
提 PR 前先自审并修掉严重问题:`git fetch origin <base>` 后,把 `git diff origin/<base>...HEAD` 交给 `ecc:code-reviewer` 子代理(`/ecc:code-review` 的本地模式只看未提交改动,提交过就看不到了)。
push 当前分支后用 spx 发起 PR。PR 描述写到 `/tmp/pr-{{issueNumber}}.md`,里面**必须**有 `Closes #{{issueNumber}}` 这一行,看板靠它把 PR 关联到工单:
```
opencli spx pr create --title "<标题>" --body-file /tmp/pr-{{issueNumber}}.md --head <当前分支> --base <base>
```
**严禁合并 PR**:你的职责只到发起 PR 为止,后续审查反馈到了请继续修复并 push,永远不要执行任何合并 PR 的命令或操作。
+1 -1
View File
@@ -1,6 +1,6 @@
/ecc:ui-prototyping 给 {{issueNumber}} 号工单画原型。 /ecc:ui-prototyping 给 {{issueNumber}} 号工单画原型。
先读工单正文,锁定要确认的界面和状态。画法按这个技能来:工单正文已经指定 Figma 插件或 OpenPencil 就用指定的那个;没指定就先问用哪一个,再按技能里对应的做法画。不要改业务代码。 先用 `opencli spx issue view --issue {{issueNumber}}` 读工单正文,锁定要确认的界面和状态。画法按这个技能来:工单正文已经指定 Figma 插件或 OpenPencil 就用指定的那个;没指定就先问用哪一个,再按技能里对应的做法画。不要改业务代码。
画完把原型源文件的仓库相对路径挂到工单上: 画完把原型源文件的仓库相对路径挂到工单上:
+4 -4
View File
@@ -1,10 +1,10 @@
审查这个仓库的 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`。 用 `opencli spx pr view --pr {{prNumber}}` 看 PR 元信息(标题、描述、head → base 分支)。看代码差异用 git(当前目录就是 PR 分支的 worktree):`<base>` 是上面查到的目标分支(加 `--json` 时是 `base.branch`),先 `git fetch origin <base>`,再 `git diff origin/<base>...HEAD`(概览可加 --stat)。
## 审查方式 ## 审查方式
ECC 的 `/ecc:review-pr` 和 `/ecc:code-review` 的 PR 模式都走 `gh`,对 Gitea 不可用,不要调。直接把上面的 diff 喂给 ECC 的审查子代理,按改动涉及的语言挑: 直接把上面的 diff 喂给 ECC 的审查子代理,按改动涉及的语言挑:
- `ecc:code-reviewer`(必跑) - `ecc:code-reviewer`(必跑)
- `ecc:silent-failure-hunter`、`ecc:pr-test-analyzer`(必跑) - `ecc:silent-failure-hunter`、`ecc:pr-test-analyzer`(必跑)
@@ -39,7 +39,7 @@ opencli spx issue state merge --issue {{issueNumber}} --state-json '{"reviewPass
## 严禁 ## 严禁
- 不要在审查意见里建议"合并 PR"或"merge" - 不要在审查意见里建议"合并 PR"或"merge"
- 不要执行 `tea pulls merge` 或任何合并命令 - 不要执行任何合并 PR 的命令或操作
- 不要 push 到 main / dev 分支 - 不要往 PR 的目标分支或其他共享分支 push
合并权完全在用户手上,你的工作只是指出问题或确认通过。 合并权完全在用户手上,你的工作只是指出问题或确认通过。
+1 -1
View File
@@ -2,4 +2,4 @@
验收目标以工单正文为准,不要再问验收哪个。测出问题就停下报告,不要顺手改代码。 验收目标以工单正文为准,不要再问验收哪个。测出问题就停下报告,不要顺手改代码。
先看下目前有没有合进main 如果已经手动合过了 就发main到测试服验证 如果没合 就发当前pr对应的分支去测试服验证 先确认 PR 有没有合并(上面给的是 PR 号时用 `opencli spx pr view --pr <PR 号>` 看):已经合了就把它的目标分支发到测试服验证,没合就把 PR 对应的分支发到测试服验证。
+44 -2
View File
@@ -1,5 +1,10 @@
import { describe, expect, it } from 'vitest' import path from 'node:path'
import { promptDigest, promptUpdatesToAsk } from './promptUpdatePlan' import { describe, expect, it, vi } from 'vitest'
import { PREVIOUS_DEFAULT_REVIEW_PROMPT } from './previousReviewPrompt'
import { PROMPT_UPDATE_FIELDS, promptDigest, promptUpdatesToAsk } from './promptUpdatePlan'
import { readDefaultPrompt } from './store'
const EXTENSION_ROOT = path.resolve(__dirname, '../..')
describe('promptUpdatesToAsk', () => { describe('promptUpdatesToAsk', () => {
it('和自带的不一样就问', () => { it('和自带的不一样就问', () => {
@@ -36,3 +41,40 @@ describe('promptUpdatesToAsk', () => {
})).toEqual([]) })).toEqual([])
}) })
}) })
describe('自带提示词不绑定代码托管平台', () => {
// `.gitea/` `.github/` 是工单模板目录,不算点名平台。
const FORGE_TOOLS = /(?<![./])\b(?:tea|gh|gitea)\b/i
it.each(PROMPT_UPDATE_FIELDS.map(field => [field.file]))('prompts/%s.md 不提 tea / gh / Gitea,也不写死 origin/main', (file) => {
const text = readDefaultPrompt(EXTENSION_ROOT, file)
expect(text).not.toMatch(FORGE_TOOLS)
expect(text).not.toContain('origin/main')
})
it.each(PROMPT_UPDATE_FIELDS.map(field => [field.file]))('%s 的内联兜底同样不提', (file) => {
vi.spyOn(console, 'warn').mockImplementation(() => {})
const text = readDefaultPrompt(path.join(EXTENSION_ROOT, 'no-such-dir'), file)
expect(text).not.toMatch(FORGE_TOOLS)
expect(text).not.toContain('origin/main')
})
it('查工单、查 PR、发起 PR 都走 spx,PR 描述必须关联工单', () => {
expect(readDefaultPrompt(EXTENSION_ROOT, 'brainstorm')).toContain('spx issue view')
expect(readDefaultPrompt(EXTENSION_ROOT, 'review')).toContain('spx pr view')
const implement = readDefaultPrompt(EXTENSION_ROOT, 'implement-plan')
expect(implement).toContain('spx pr create')
expect(implement).toContain('Closes #{{issueNumber}}')
})
it('设置里存着旧版自带审查提示词的,激活时会被问要不要换成新版', () => {
const next = readDefaultPrompt(EXTENSION_ROOT, 'review')
const out = promptUpdatesToAsk({
stored: { reviewPrompt: PREVIOUS_DEFAULT_REVIEW_PROMPT },
defaults: { reviewPrompt: next },
decided: { reviewPrompt: promptDigest(PREVIOUS_DEFAULT_REVIEW_PROMPT) },
})
expect(out.map(item => item.key)).toEqual(['reviewPrompt'])
expect(out[0].next).toBe(next)
})
})
+5 -5
View File
@@ -29,20 +29,20 @@ import { planPromptMigration, planReviewPromptMigration } from './promptMigratio
* the extension usable if the file is missing/corrupt. * the extension usable if the file is missing/corrupt.
*/ */
const FALLBACK_BRAINSTORM_PROMPT = `{{#if issueNumber}} const FALLBACK_BRAINSTORM_PROMPT = `{{#if issueNumber}}
/ecc:grilling 讨论下 {{issueNumber}} 号工单。 /ecc:grilling 讨论下 {{issueNumber}} 号工单,先用 spx issue view 看工单。
{{#if prototypeFile}} {{#if prototypeFile}}
工单已有原型插件 {{prototypeFile}},先读它;原型要改就 ListAgents 找到 issue-{{issueNumber}}-原型 会话{{#if prototypeSessionId}}(id {{prototypeSessionId}}){{/if}}并 SendMessage 给它,不要派子代理、不要自己动插件代码。 工单已有原型插件 {{prototypeFile}},先读它;原型要改就 ListAgents 找到 issue-{{issueNumber}}-原型 会话{{#if prototypeSessionId}}(id {{prototypeSessionId}}){{/if}}并 SendMessage 给它,不要派子代理、不要自己动插件代码。
{{/if}} {{/if}}
达成共识后用 ecc:spec 写 .claude/specs/<stem>.md,我确认后用 ecc:plan 出 .claude/plans/<stem>.md,两个文件在 main 上提交并用 spx issue marker 同步 marker。不要 git checkout / 不要写代码 / 不要建 PR。 达成共识后用 ecc:spec 写 .claude/specs/<stem>.md,我确认后用 ecc:plan 出 .claude/plans/<stem>.md,两个文件在仓库默认分支上提交并用 spx issue marker 同步 marker。不要 git checkout / 不要写代码 / 不要建 PR。
{{else}} {{else}}
我现在有这样一个需求 {{userRequest}},你用 spx 命令创建 gitea 工单。工单 body 末尾必须包含 <!-- spx:nonce={{nonce}} -->。创建完工单立即停下汇报,不要擅自实施。 我现在有这样一个需求 {{userRequest}},你用 spx 命令创建工单。工单 body 末尾必须包含 <!-- spx:nonce={{nonce}} -->。创建完工单立即停下汇报,不要擅自实施。
{{/if}}` {{/if}}`
const FALLBACK_IMPLEMENT_PLAN_PROMPT = `/ecc:tdd @{{planFile}} 按计划实施,编码派子代理,发起 PR 时在 body 中包含 "Closes #{{issueNumber}}"。严禁合并 PR。` const FALLBACK_IMPLEMENT_PLAN_PROMPT = `/ecc:tdd @{{planFile}} 按计划实施,编码派子代理,用 spx pr create 发起 PR,body 中必须包含 "Closes #{{issueNumber}}"。严禁合并 PR。`
const FALLBACK_TEST_PROMPT = `/pr-acceptance-testing 验收 {{issueNumber}} 号工单({{prRef}})。验收目标以工单正文为准,不要再问验收哪个。` const FALLBACK_TEST_PROMPT = `/pr-acceptance-testing 验收 {{issueNumber}} 号工单({{prRef}})。验收目标以工单正文为准,不要再问验收哪个。`
const FALLBACK_REVIEW_PROMPT = `用 tea 拿到 #{{prNumber}} PR,diff 交给 ecc:code-reviewer 子代理审查。审查意见用 spx pr review-comment 发评论,body 第一行写 <!-- spx:review=1 -->。` const FALLBACK_REVIEW_PROMPT = `用 spx pr view 查 #{{prNumber}} PR 的目标分支 <base>,把 git diff origin/<base>...HEAD 交给 ecc:code-reviewer 子代理审查。审查意见用 spx pr review-comment 发评论。严禁合并 PR。`
const FALLBACK_PROTOTYPE_PROMPT = `/ecc:figma-plugin-prototyping 给 {{issueNumber}} 号工单画原型:先读工单正文锁定要画的界面和状态,再写本地 Figma 插件把画板和点击流做出来。画完汇报插件路径和怎么导入,不要改业务代码。 const FALLBACK_PROTOTYPE_PROMPT = `/ecc:figma-plugin-prototyping 给 {{issueNumber}} 号工单画原型:先读工单正文锁定要画的界面和状态,再写本地 Figma 插件把画板和点击流做出来。画完汇报插件路径和怎么导入,不要改业务代码。