✨ feat(vscode): 测试提示词改成可配置模板并带上工单号
启动测试会话原先硬编码发 `/pr-acceptance-testing`,不带目标,验收技能只能
反问要测哪个。现在做成 prompts/test.md 模板 + 设置里的「测试提示词」,占位符
{issueNumber} 和 {prRef}(worktree 里是分支,主仓库里是已合并的 PR)。
Claude-Session: https://claude.ai/code/session_01Kgmb1LvrPmFX3NoUDB4zZC
This commit is contained in:
1 parent
e05a5234db
commit
f946e5cfee
11 files changed
+77
-4
No files matched your search
@@ -0,0 +1,3 @@
|
||||
/pr-acceptance-testing 验收 {issueNumber} 号工单({prRef})。
|
||||
|
||||
验收目标以工单正文为准,不要再问验收哪个。测出问题就停下报告,不要顺手改代码。
|
||||
@@ -46,6 +46,19 @@ export function getImplementPlanPrompt(ctx: ExtensionContext, vars: { planFile:
|
||||
.join(vars.issueRef ?? String(vars.issueNumber))
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试会话首个提示词。`prRef` 是给验收技能的定位线索:主 worktree 上是
|
||||
* 已合并的 PR,worktree 里就是那条分支。
|
||||
*/
|
||||
export function getTestPrompt(ctx: ExtensionContext, vars: { issueNumber: number, issueRef?: string, prRef: string }): string {
|
||||
const tpl = getSettings(ctx).testPrompt
|
||||
return tpl
|
||||
.split('{issueNumber}')
|
||||
.join(vars.issueRef ?? String(vars.issueNumber))
|
||||
.split('{prRef}')
|
||||
.join(vars.prRef)
|
||||
}
|
||||
|
||||
export function getReviewPrompt(ctx: ExtensionContext, vars: { prNumber: string }): string {
|
||||
const tpl = getSettings(ctx).reviewPrompt
|
||||
return tpl.split('{prNumber}').join(vars.prNumber)
|
||||
|
||||
@@ -988,6 +988,7 @@ export class KanbanWebviewPanel {
|
||||
implementPlanPrompt: s.implementPlanPrompt,
|
||||
autoReview: s.autoReview,
|
||||
reviewPrompt: s.reviewPrompt,
|
||||
testPrompt: s.testPrompt,
|
||||
devBranch: s.devBranch,
|
||||
releaseBranchPrefix: s.releaseBranchPrefix,
|
||||
jenkinsJob: s.jenkinsJob,
|
||||
@@ -1076,6 +1077,7 @@ export class KanbanWebviewPanel {
|
||||
implementPlanPrompt: s.implementPlanPrompt,
|
||||
autoReview: s.autoReview,
|
||||
reviewPrompt: s.reviewPrompt,
|
||||
testPrompt: s.testPrompt,
|
||||
devBranch: s.devBranch,
|
||||
releaseBranchPrefix: s.releaseBranchPrefix,
|
||||
jenkinsJob: s.jenkinsJob,
|
||||
|
||||
@@ -13,7 +13,7 @@ import { buildCcCommand } from '../../cc/ccCommand'
|
||||
import { buildCodexCommandString } from '../../cc/codexCommand'
|
||||
import { watchForNewCodexSession } from '../../cc/codexSessionWatcher'
|
||||
import { resolveProfilePath } from '../../cc/profiles'
|
||||
import { getBrainstormContinuePrompt, getImplementPlanPrompt, getReviewPrompt } from '../../cc/prompts'
|
||||
import { getBrainstormContinuePrompt, getImplementPlanPrompt, getReviewPrompt, getTestPrompt } from '../../cc/prompts'
|
||||
import { projectsDirFor, watchForNewSession } from '../../cc/sessionWatcher'
|
||||
import { detectRepo } from '../../git/remote'
|
||||
import { ensureWorktree, resolveWorktreePath } from '../../git/worktree'
|
||||
@@ -1176,8 +1176,14 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
|
||||
}
|
||||
|
||||
// worktree 里:代码就在当前工作目录,不用 tea 拉取,直接测;
|
||||
// 主 worktree:PR 已合并,先用 tea 熟悉改动再测。
|
||||
const prompt = '/pr-acceptance-testing'
|
||||
// 主 worktree:PR 已合并,先用 tea 熟悉改动再测。验收目标直接写进提示词,
|
||||
// 省得验收技能反问要测哪个。
|
||||
const prompt = getTestPrompt(panel.context, {
|
||||
issueNumber,
|
||||
prRef: inWorktree
|
||||
? `worktree 分支 ${branch || effectiveCwd}`
|
||||
: `PR #${pr}`,
|
||||
})
|
||||
if (prompt.includes('\'')) {
|
||||
void window.showErrorMessage('启动测试失败:prompt 含单引号,拒绝执行')
|
||||
return
|
||||
|
||||
@@ -27,6 +27,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
@@ -113,6 +114,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
|
||||
implementPlanPrompt: payload.implementPlanPrompt || prev.implementPlanPrompt,
|
||||
autoReview: payload.autoReview,
|
||||
reviewPrompt: payload.reviewPrompt || prev.reviewPrompt,
|
||||
testPrompt: payload.testPrompt || prev.testPrompt,
|
||||
devBranch: trimmedDevBranch || prev.devBranch,
|
||||
releaseBranchPrefix: trimmedReleasePrefix || prev.releaseBranchPrefix,
|
||||
jenkinsJob: trimmedJenkinsJob,
|
||||
@@ -145,6 +147,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
|
||||
implementPlanPrompt: payload.implementPlanPrompt,
|
||||
autoReview: payload.autoReview,
|
||||
reviewPrompt: payload.reviewPrompt,
|
||||
testPrompt: payload.testPrompt,
|
||||
devBranch: trimmedDevBranch,
|
||||
releaseBranchPrefix: trimmedReleasePrefix,
|
||||
jenkinsJob: trimmedJenkinsJob,
|
||||
@@ -254,6 +257,7 @@ export async function handleEditSettingsRequest(panel: KanbanWebviewPanel): Prom
|
||||
implementPlanPrompt: s.implementPlanPrompt,
|
||||
autoReview: s.autoReview,
|
||||
reviewPrompt: s.reviewPrompt,
|
||||
testPrompt: s.testPrompt,
|
||||
devBranch: s.devBranch,
|
||||
releaseBranchPrefix: s.releaseBranchPrefix,
|
||||
jenkinsJob: s.jenkinsJob,
|
||||
|
||||
@@ -76,6 +76,7 @@ export type ExtensionToWebview
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
@@ -158,6 +159,7 @@ export type WebviewToExtension
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
|
||||
@@ -30,9 +30,11 @@ const FALLBACK_BRAINSTORM_CONTINUE_PROMPT = `/ecc:grilling 讨论下 {issueNumbe
|
||||
|
||||
const FALLBACK_IMPLEMENT_PLAN_PROMPT = `/ecc:tdd @{planFile} 按计划实施,编码派子代理,发起 PR 时在 body 中包含 "Closes #{issueNumber}"。严禁合并 PR。`
|
||||
|
||||
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 -->。`
|
||||
|
||||
type PromptName = 'brainstorm' | 'brainstorm-continue' | 'implement-plan' | 'review'
|
||||
type PromptName = 'brainstorm' | 'brainstorm-continue' | 'implement-plan' | 'review' | 'test'
|
||||
|
||||
/**
|
||||
* Read a default prompt template from `${extensionPath}/prompts/${name}.md`.
|
||||
@@ -54,6 +56,7 @@ export function readDefaultPrompt(extensionPath: string, name: PromptName): stri
|
||||
case 'brainstorm-continue': return FALLBACK_BRAINSTORM_CONTINUE_PROMPT
|
||||
case 'implement-plan': return FALLBACK_IMPLEMENT_PLAN_PROMPT
|
||||
case 'review': return FALLBACK_REVIEW_PROMPT
|
||||
case 'test': return FALLBACK_TEST_PROMPT
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +90,8 @@ export interface Settings {
|
||||
autoReview: boolean
|
||||
/** Prompt template for the auto-review flow. `{prNumber}` placeholder. */
|
||||
reviewPrompt: string
|
||||
/** 测试会话首个提示词模板;占位符 {issueNumber} / {prRef}。 */
|
||||
testPrompt: string
|
||||
/** Day-to-day development branch (e.g. `main`). Jenkins doesn't watch it. */
|
||||
devBranch: string
|
||||
/**
|
||||
@@ -266,6 +271,7 @@ function defaults(ctx: ExtensionContext): Settings {
|
||||
implementPlanPrompt: readDefaultPrompt(ctx.extensionPath, 'implement-plan'),
|
||||
autoReview: true,
|
||||
reviewPrompt: readDefaultPrompt(ctx.extensionPath, 'review'),
|
||||
testPrompt: readDefaultPrompt(ctx.extensionPath, 'test'),
|
||||
devBranch: 'main',
|
||||
releaseBranchPrefix: 'release/',
|
||||
jenkinsJob: '',
|
||||
@@ -319,6 +325,9 @@ export function getSettings(ctx: ExtensionContext): Settings {
|
||||
const reviewPrompt = typeof stored.reviewPrompt === 'string' && stored.reviewPrompt.length > 0
|
||||
? stored.reviewPrompt
|
||||
: base.reviewPrompt
|
||||
const testPrompt = typeof stored.testPrompt === 'string' && stored.testPrompt.length > 0
|
||||
? stored.testPrompt
|
||||
: base.testPrompt
|
||||
// devBranch always has a usable value — fall back to 'main' if missing/blank
|
||||
// so we never end up trying to fetch the empty string.
|
||||
const devBranch = typeof stored.devBranch === 'string' && stored.devBranch.length > 0
|
||||
@@ -424,6 +433,7 @@ export function getSettings(ctx: ExtensionContext): Settings {
|
||||
implementPlanPrompt,
|
||||
autoReview,
|
||||
reviewPrompt,
|
||||
testPrompt,
|
||||
devBranch,
|
||||
releaseBranchPrefix,
|
||||
jenkinsJob,
|
||||
|
||||
@@ -538,6 +538,7 @@ export function App() {
|
||||
initialImplementPlanPrompt={settings?.implementPlanPrompt ?? ''}
|
||||
initialAutoReview={settings?.autoReview ?? true}
|
||||
initialReviewPrompt={settings?.reviewPrompt ?? ''}
|
||||
initialTestPrompt={settings?.testPrompt ?? ''}
|
||||
initialDevBranch={settings?.devBranch ?? 'main'}
|
||||
initialReleaseBranchPrefix={settings?.releaseBranchPrefix ?? 'release/'}
|
||||
initialJenkinsJob={settings?.jenkinsJob ?? ''}
|
||||
|
||||
@@ -25,6 +25,7 @@ interface SubmitValues {
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
@@ -78,6 +79,7 @@ export interface SettingsModalProps {
|
||||
initialImplementPlanPrompt: string
|
||||
initialAutoReview: boolean
|
||||
initialReviewPrompt: string
|
||||
initialTestPrompt: string
|
||||
initialDevBranch: string
|
||||
initialReleaseBranchPrefix: string
|
||||
initialJenkinsJob: string
|
||||
@@ -167,6 +169,7 @@ export function SettingsModal({
|
||||
initialImplementPlanPrompt,
|
||||
initialAutoReview,
|
||||
initialReviewPrompt,
|
||||
initialTestPrompt,
|
||||
initialDevBranch,
|
||||
initialReleaseBranchPrefix,
|
||||
initialJenkinsJob,
|
||||
@@ -208,6 +211,7 @@ export function SettingsModal({
|
||||
const [implementPlanPrompt, setImplementPlanPrompt] = useState(initialImplementPlanPrompt)
|
||||
const [autoReview, setAutoReview] = useState(initialAutoReview)
|
||||
const [reviewPrompt, setReviewPrompt] = useState(initialReviewPrompt)
|
||||
const [testPrompt, setTestPrompt] = useState(initialTestPrompt)
|
||||
const [devBranch, setDevBranch] = useState(initialDevBranch)
|
||||
const [releaseBranchPrefix, setReleaseBranchPrefix] = useState(initialReleaseBranchPrefix)
|
||||
const [jenkinsJob, setJenkinsJob] = useState(initialJenkinsJob)
|
||||
@@ -251,6 +255,7 @@ export function SettingsModal({
|
||||
setImplementPlanPrompt(initialImplementPlanPrompt)
|
||||
setAutoReview(initialAutoReview)
|
||||
setReviewPrompt(initialReviewPrompt)
|
||||
setTestPrompt(initialTestPrompt)
|
||||
setDevBranch(initialDevBranch)
|
||||
setReleaseBranchPrefix(initialReleaseBranchPrefix)
|
||||
setJenkinsJob(initialJenkinsJob)
|
||||
@@ -342,6 +347,7 @@ export function SettingsModal({
|
||||
implementPlanPrompt,
|
||||
autoReview,
|
||||
reviewPrompt,
|
||||
testPrompt,
|
||||
devBranch: devBranch.trim(),
|
||||
releaseBranchPrefix: releaseBranchPrefix.trim(),
|
||||
jenkinsJob: jenkinsJob.trim(),
|
||||
@@ -1002,6 +1008,26 @@ export function SettingsModal({
|
||||
className={`${inputClass} resize-y font-mono`}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
label="测试提示词"
|
||||
hint={(
|
||||
<>
|
||||
可用占位符:
|
||||
<code>{'{issueNumber}'}</code>
|
||||
、
|
||||
<code>{'{prRef}'}</code>
|
||||
(worktree 里是分支,主仓库里是已合并的 PR)
|
||||
</>
|
||||
)}
|
||||
>
|
||||
<textarea
|
||||
rows={4}
|
||||
value={testPrompt}
|
||||
onChange={e => setTestPrompt(e.target.value)}
|
||||
className={`${inputClass} resize-y font-mono`}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ export interface SettingsValues {
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
@@ -82,6 +83,7 @@ export interface SettingsOverlayState {
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
@@ -421,6 +423,7 @@ export function useIssues(): UseIssuesResult {
|
||||
implementPlanPrompt: values.implementPlanPrompt,
|
||||
autoReview: values.autoReview,
|
||||
reviewPrompt: values.reviewPrompt,
|
||||
testPrompt: values.testPrompt,
|
||||
devBranch: values.devBranch,
|
||||
releaseBranchPrefix: values.releaseBranchPrefix,
|
||||
jenkinsJob: values.jenkinsJob,
|
||||
@@ -886,6 +889,7 @@ export function useIssues(): UseIssuesResult {
|
||||
implementPlanPrompt: msg.implementPlanPrompt,
|
||||
autoReview: msg.autoReview,
|
||||
reviewPrompt: msg.reviewPrompt,
|
||||
testPrompt: msg.testPrompt,
|
||||
devBranch: msg.devBranch,
|
||||
releaseBranchPrefix: msg.releaseBranchPrefix,
|
||||
jenkinsJob: msg.jenkinsJob,
|
||||
|
||||
@@ -107,6 +107,7 @@ export type ExtensionToWebview
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
@@ -189,6 +190,7 @@ export type WebviewToExtension
|
||||
implementPlanPrompt: string
|
||||
autoReview: boolean
|
||||
reviewPrompt: string
|
||||
testPrompt: string
|
||||
devBranch: string
|
||||
releaseBranchPrefix: string
|
||||
jenkinsJob: string
|
||||
|
||||
Reference in new issue
Block a user