✨ feat(vscode): 头脑风暴 profile 独立 + codex 命令统一组装收尾
- 头脑风暴/实施/测试会话 profile 彻底独立,互不回退,各自空值回落默认 - 新建工单弹窗的 profile 选择改为头脑风暴专用 brainstormProfilePath - 详情面板新增「头脑风暴配置文件」下拉 - 删除从未接线的死代码 reviewFlow.ts(runReview 全仓库无调用方) - codexCommand 精简为仅 resume/interactive 两种终端命令形态 - 版本号 0.2.55 → 0.2.60
This commit is contained in:
1 parent
5188c23765
commit
b585016cd7
22 files changed
+258
-366
No files matched your search
@@ -43,6 +43,7 @@ interface BottomTabsProps {
|
||||
onStartBrainstormSession: (issueNumber: number) => void
|
||||
onUpdateAutoReview: (issueNumber: number, value: boolean) => void
|
||||
onUpdateProfilePath: (issueNumber: number, profilePath: string) => void
|
||||
onUpdateBrainstormProfilePath: (issueNumber: number, brainstormProfilePath: string) => void
|
||||
onUpdateTestProfilePath: (issueNumber: number, testProfilePath: string) => void
|
||||
onOpenLogs: () => void
|
||||
|
||||
@@ -120,6 +121,7 @@ export function BottomTabs(props: BottomTabsProps) {
|
||||
onStartBrainstormSession={props.onStartBrainstormSession}
|
||||
onUpdateAutoReview={props.onUpdateAutoReview}
|
||||
onUpdateProfilePath={props.onUpdateProfilePath}
|
||||
onUpdateBrainstormProfilePath={props.onUpdateBrainstormProfilePath}
|
||||
onUpdateTestProfilePath={props.onUpdateTestProfilePath}
|
||||
profiles={props.profiles}
|
||||
onOpenLogs={props.onOpenLogs}
|
||||
|
||||
@@ -61,6 +61,8 @@ interface IssueDetailPanelProps {
|
||||
profiles: ClaudeProfile[]
|
||||
/** Persist a per-issue `profilePath` override into the state JSON. */
|
||||
onUpdateProfilePath: (issueNumber: number, profilePath: string) => void
|
||||
/** Persist a per-issue `brainstormProfilePath` override into the state JSON. */
|
||||
onUpdateBrainstormProfilePath: (issueNumber: number, brainstormProfilePath: string) => void
|
||||
/** Persist a per-issue `testProfilePath` override into the state JSON. */
|
||||
onUpdateTestProfilePath: (issueNumber: number, testProfilePath: string) => void
|
||||
/** Open the in-webview log modal. */
|
||||
@@ -99,6 +101,7 @@ export function IssueDetailPanel({
|
||||
onUpdateAutoReview,
|
||||
profiles,
|
||||
onUpdateProfilePath,
|
||||
onUpdateBrainstormProfilePath,
|
||||
onUpdateTestProfilePath,
|
||||
onOpenLogs,
|
||||
}: IssueDetailPanelProps) {
|
||||
@@ -195,7 +198,7 @@ export function IssueDetailPanel({
|
||||
return
|
||||
if (!throttleBySessionId(v))
|
||||
return
|
||||
onResumeSession(v, issue?.profilePath, undefined, issue?.number)
|
||||
onResumeSession(v, issue?.brainstormProfilePath, undefined, issue?.number)
|
||||
},
|
||||
secondaryActionIcon,
|
||||
secondaryActionTitle,
|
||||
@@ -321,40 +324,46 @@ export function IssueDetailPanel({
|
||||
description: '首次开会话时随机分配的终端颜色(VS Code ThemeColor),用于该工单所有会话的终端 tab 着色',
|
||||
},
|
||||
{
|
||||
key: 'profilePath',
|
||||
label: '实施配置文件',
|
||||
key: 'brainstormProfilePath',
|
||||
label: '头脑风暴配置文件',
|
||||
type: 'select',
|
||||
options: (() => {
|
||||
// 占位项:value='' 对应「未设置」。原生 select 在 value 不匹配任何
|
||||
// option 时会假显示第一项且 selectedIndex=0,导致点第一项不触发
|
||||
// onChange、永远存不进去;占位项让未设置态有真实匹配项。
|
||||
const opts = [{ label: '(默认)', value: '' }, ...profiles.map(p => ({ label: p.name, value: p.path }))]
|
||||
const current = issue?.profilePath
|
||||
// 自定义路径兜底:state JSON 里存的 profile 不在已知列表时,
|
||||
// 额外追加一项以免下拉显示空白、丢失当前选择。
|
||||
const current = issue?.brainstormProfilePath
|
||||
if (current && !opts.some(o => o.value === current))
|
||||
opts.push({ label: `自定义:${current}`, value: current })
|
||||
return opts
|
||||
})(),
|
||||
description: '实施会话使用的 Claude 配置文件;选「(默认)」用内置默认(offical),选具体 profile 则覆盖(持久化 state JSON)',
|
||||
description: '头脑风暴会话使用的 Claude 配置文件;选「(默认)」用内置默认,与实施/测试互不回退',
|
||||
},
|
||||
{
|
||||
key: 'profilePath',
|
||||
label: '实施配置文件',
|
||||
type: 'select',
|
||||
options: (() => {
|
||||
const opts = [{ label: '(默认)', value: '' }, ...profiles.map(p => ({ label: p.name, value: p.path }))]
|
||||
const current = issue?.profilePath
|
||||
if (current && !opts.some(o => o.value === current))
|
||||
opts.push({ label: `自定义:${current}`, value: current })
|
||||
return opts
|
||||
})(),
|
||||
description: '实施会话使用的 Claude 配置文件;选「(默认)」用内置默认,与头脑风暴/测试互不回退',
|
||||
},
|
||||
{
|
||||
key: 'testProfilePath',
|
||||
label: '测试配置文件',
|
||||
type: 'select',
|
||||
options: (() => {
|
||||
// 占位项:value='' 对应「未设置」。原生 select 在 value 不匹配任何
|
||||
// option 时会假显示第一项且 selectedIndex=0,导致点第一项不触发
|
||||
// onChange、永远存不进去;占位项让未设置态有真实匹配项。
|
||||
const opts = [{ label: '(默认)', value: '' }, ...profiles.map(p => ({ label: p.name, value: p.path }))]
|
||||
const current = issue?.testProfilePath
|
||||
// 自定义路径兜底:state JSON 里存的 profile 不在已知列表时,
|
||||
// 额外追加一项以免下拉显示空白、丢失当前选择。
|
||||
if (current && !opts.some(o => o.value === current))
|
||||
opts.push({ label: `自定义:${current}`, value: current })
|
||||
return opts
|
||||
})(),
|
||||
description: '测试会话使用的 Claude 配置文件;留空时回退实施配置文件',
|
||||
description: '测试会话使用的 Claude 配置文件;选「(默认)」用内置默认,与头脑风暴/实施互不回退',
|
||||
},
|
||||
{
|
||||
key: 'specFile',
|
||||
@@ -476,6 +485,7 @@ export function IssueDetailPanel({
|
||||
testSessionId: issue.testSessionId ?? null,
|
||||
autoReview: issue.autoReview ?? globalAutoReview,
|
||||
color: issue.color ?? null,
|
||||
brainstormProfilePath: issue.brainstormProfilePath ?? null,
|
||||
profilePath: issue.profilePath ?? null,
|
||||
testProfilePath: issue.testProfilePath ?? null,
|
||||
specFile: issue.specFile ?? null,
|
||||
@@ -582,6 +592,8 @@ export function IssueDetailPanel({
|
||||
onChange={(key, value) => {
|
||||
if (key === 'autoReview' && issue && typeof value === 'boolean')
|
||||
onUpdateAutoReview(issue.number, value)
|
||||
if (key === 'brainstormProfilePath' && issue && typeof value === 'string')
|
||||
onUpdateBrainstormProfilePath(issue.number, value)
|
||||
if (key === 'profilePath' && issue && typeof value === 'string')
|
||||
onUpdateProfilePath(issue.number, value)
|
||||
if (key === 'testProfilePath' && issue && typeof value === 'string')
|
||||
|
||||
@@ -33,7 +33,7 @@ export interface ClaudeProfile {
|
||||
interface Props {
|
||||
open: boolean
|
||||
onCancel: () => void
|
||||
onSubmit: (userRequest: string, images: PastedImage[], profilePath?: string) => void
|
||||
onSubmit: (userRequest: string, images: PastedImage[], brainstormProfilePath?: string) => void
|
||||
profiles: ClaudeProfile[]
|
||||
defaultProfileName?: string
|
||||
}
|
||||
@@ -55,13 +55,10 @@ export function NewIssueModal({ open, onCancel, onSubmit, profiles, defaultProfi
|
||||
setSelectedProfile(null)
|
||||
return
|
||||
}
|
||||
// Pick default profile when the modal opens. Prefer the one matching
|
||||
// `defaultProfileName`, otherwise fall back to the first alphabetically.
|
||||
if (profiles.length > 0) {
|
||||
const match = defaultProfileName
|
||||
? profiles.find(p => p.name === defaultProfileName)
|
||||
: undefined
|
||||
setSelectedProfile(match ? match.name : profiles[0].name)
|
||||
// 默认不预选 profile(空 = 系统默认);仅当显式传入 defaultProfileName 时预选。
|
||||
if (profiles.length > 0 && defaultProfileName) {
|
||||
const match = profiles.find(p => p.name === defaultProfileName)
|
||||
setSelectedProfile(match ? match.name : null)
|
||||
}
|
||||
else {
|
||||
setSelectedProfile(null)
|
||||
@@ -208,7 +205,7 @@ export function NewIssueModal({ open, onCancel, onSubmit, profiles, defaultProfi
|
||||
function handleSubmit(): void {
|
||||
if (!canSubmit)
|
||||
return
|
||||
const profilePath = selectedProfile
|
||||
const brainstormProfilePath = selectedProfile
|
||||
? profiles.find(p => p.name === selectedProfile)?.path
|
||||
: undefined
|
||||
const pending = [...pastedTexts]
|
||||
@@ -224,7 +221,7 @@ export function NewIssueModal({ open, onCancel, onSubmit, profiles, defaultProfi
|
||||
onSubmit(
|
||||
finalRequest,
|
||||
images.map(({ mediaType, base64, previewDataUrl }) => ({ mediaType, base64, previewDataUrl })),
|
||||
profilePath,
|
||||
brainstormProfilePath,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -248,8 +245,19 @@ export function NewIssueModal({ open, onCancel, onSubmit, profiles, defaultProfi
|
||||
|
||||
{profiles.length > 0 && (
|
||||
<fieldset className="mb-3 border-0 p-0">
|
||||
<legend className="mb-1 text-xs opacity-70">配置文件</legend>
|
||||
<legend className="mb-1 text-xs opacity-70">头脑风暴配置文件</legend>
|
||||
<div className="flex flex-wrap gap-3 text-xs">
|
||||
<label className="flex cursor-pointer items-center gap-1">
|
||||
<input
|
||||
type="radio"
|
||||
name="claude-profile"
|
||||
value=""
|
||||
checked={selectedProfile === null}
|
||||
onChange={() => setSelectedProfile(null)}
|
||||
className="accent-[var(--vscode-focusBorder)]"
|
||||
/>
|
||||
<span>(默认)</span>
|
||||
</label>
|
||||
{profiles.map(p => (
|
||||
<label key={p.name} className="flex cursor-pointer items-center gap-1">
|
||||
<input
|
||||
|
||||
Reference in new issue
Block a user