✨ feat(vscode): 头脑风暴 profile 独立 + codex 命令统一组装收尾
- 头脑风暴/实施/测试会话 profile 彻底独立,互不回退,各自空值回落默认 - 新建工单弹窗的 profile 选择改为头脑风暴专用 brainstormProfilePath - 详情面板新增「头脑风暴配置文件」下拉 - 删除从未接线的死代码 reviewFlow.ts(runReview 全仓库无调用方) - codexCommand 精简为仅 resume/interactive 两种终端命令形态 - 版本号 0.2.55 → 0.2.60
This commit is contained in:
@@ -55,6 +55,7 @@ export function App() {
|
||||
clearDependency,
|
||||
updateIssueAutoReview,
|
||||
updateIssueProfilePath,
|
||||
updateIssueBrainstormProfilePath,
|
||||
updateIssueTestProfilePath,
|
||||
logs,
|
||||
clearLogs,
|
||||
@@ -90,9 +91,9 @@ export function App() {
|
||||
// effect 跳过它——否则 选中→聚焦→终端激活→反向选中 会死循环、CPU 飙升。
|
||||
const lastProgrammaticSelectRef = useRef<string | null>(null)
|
||||
|
||||
function handleSubmitNewIssue(userRequest: string, images: PastedImage[], profilePath?: string): void {
|
||||
function handleSubmitNewIssue(userRequest: string, images: PastedImage[], brainstormProfilePath?: string): void {
|
||||
const payload = images.map(({ mediaType, base64 }) => ({ mediaType, base64 }))
|
||||
createIssue(userRequest, payload.length > 0 ? payload : undefined, profilePath)
|
||||
createIssue(userRequest, payload.length > 0 ? payload : undefined, brainstormProfilePath)
|
||||
setShowNewIssueModal(false)
|
||||
}
|
||||
|
||||
@@ -195,7 +196,11 @@ export function App() {
|
||||
e.preventDefault()
|
||||
const isImpl = !!selectedIssue?.implementSessionId
|
||||
const cwd = isImpl ? selectedIssue?.worktreePath : undefined
|
||||
resumeSession(sid, selectedIssue?.profilePath, cwd, selectedIssue?.number)
|
||||
// 实施 resume 用 profilePath;头脑风暴 resume 用 brainstormProfilePath。
|
||||
const profileForResume = isImpl
|
||||
? selectedIssue?.profilePath
|
||||
: selectedIssue?.brainstormProfilePath
|
||||
resumeSession(sid, profileForResume, cwd, selectedIssue?.number)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -355,6 +360,7 @@ export function App() {
|
||||
onStartBrainstormSession={startBrainstormSession}
|
||||
onUpdateAutoReview={updateIssueAutoReview}
|
||||
onUpdateProfilePath={updateIssueProfilePath}
|
||||
onUpdateBrainstormProfilePath={updateIssueBrainstormProfilePath}
|
||||
onUpdateTestProfilePath={updateIssueTestProfilePath}
|
||||
onOpenLogs={() => setShowLogs(true)}
|
||||
profileData={profileData}
|
||||
@@ -424,7 +430,6 @@ export function App() {
|
||||
onCancel={() => setShowNewIssueModal(false)}
|
||||
onSubmit={handleSubmitNewIssue}
|
||||
profiles={profiles}
|
||||
defaultProfileName="offical"
|
||||
/>
|
||||
<LogModal
|
||||
open={showLogs}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -127,7 +127,7 @@ export interface UseIssuesResult {
|
||||
youtrackProjects: YouTrackProjectsState
|
||||
dismissSettings: () => void
|
||||
requestEditAuth: () => void
|
||||
createIssue: (userRequest: string, images?: Array<{ mediaType: string, base64: string }>, profilePath?: string) => void
|
||||
createIssue: (userRequest: string, images?: Array<{ mediaType: string, base64: string }>, brainstormProfilePath?: string) => void
|
||||
dismissToast: (id: string) => void
|
||||
openUrl: (url: string) => void
|
||||
resumeSession: (sessionId: string, profilePath?: string, cwd?: string, issueNumber?: number) => void
|
||||
@@ -153,8 +153,8 @@ export interface UseIssuesResult {
|
||||
* onDidCloseTerminal and clears `*TabOpen` so the X button disappears. */
|
||||
closeSessionTab: (issueNumber: number, kind: 'brainstorm' | 'implement' | 'review' | 'test') => void
|
||||
/** Spawn a fresh "规划" cc tab for an existing issue whose sessionId is
|
||||
* still empty. The extension picks up profilePath from the issue's state
|
||||
* JSON, watches `~/.claude/projects/<encoded-workspaceRoot>` for the new
|
||||
* still empty. Extension 用工单级 brainstormProfilePath(空 = 默认),
|
||||
* watches `~/.claude/projects/<encoded-workspaceRoot>` for the new
|
||||
* session jsonl, then writes the id back as `sessionId`. */
|
||||
startBrainstormSession: (issueNumber: number) => void
|
||||
changeColumn: (issueNumber: number, toColumn: IssueColumn, source?: 'gitea' | 'youtrack', externalId?: string) => void
|
||||
@@ -164,6 +164,9 @@ export interface UseIssuesResult {
|
||||
/** 覆盖该工单实施会话使用的 Claude 配置文件,乐观更新本地 state 后
|
||||
* postMessage 持久化到 state JSON。失败时扩展端 push `issue/patch` 回滚。 */
|
||||
updateIssueProfilePath: (issueNumber: number, profilePath: string) => void
|
||||
/** 覆盖该工单头脑风暴会话专用的 Claude 配置文件,乐观更新本地 state 后
|
||||
* postMessage 持久化到 state JSON。失败时扩展端 push `issue/patch` 回滚。 */
|
||||
updateIssueBrainstormProfilePath: (issueNumber: number, brainstormProfilePath: string) => void
|
||||
/** 覆盖该工单测试会话专用的 Claude 配置文件,乐观更新本地 state 后
|
||||
* postMessage 持久化到 state JSON。失败时扩展端 push `issue/patch` 回滚。 */
|
||||
updateIssueTestProfilePath: (issueNumber: number, testProfilePath: string) => void
|
||||
@@ -314,9 +317,9 @@ export function useIssues(): UseIssuesResult {
|
||||
const createIssue = useCallback((
|
||||
userRequest: string,
|
||||
images?: Array<{ mediaType: string, base64: string }>,
|
||||
profilePath?: string,
|
||||
brainstormProfilePath?: string,
|
||||
): void => {
|
||||
postMessage({ type: 'issue/create', userRequest, images, profilePath })
|
||||
postMessage({ type: 'issue/create', userRequest, images, brainstormProfilePath })
|
||||
}, [])
|
||||
|
||||
const dismissToast = useCallback((id: string): void => {
|
||||
@@ -458,6 +461,20 @@ export function useIssues(): UseIssuesResult {
|
||||
postMessage({ type: 'issue/update-profile-path', issueNumber, profilePath })
|
||||
}, [])
|
||||
|
||||
const updateIssueBrainstormProfilePath = useCallback((issueNumber: number, brainstormProfilePath: string): void => {
|
||||
setState((prev) => {
|
||||
if (prev.status !== 'ready')
|
||||
return prev
|
||||
return {
|
||||
status: 'ready',
|
||||
issues: prev.issues.map(i =>
|
||||
i.number === issueNumber ? { ...i, brainstormProfilePath } : i,
|
||||
),
|
||||
}
|
||||
})
|
||||
postMessage({ type: 'issue/update-brainstorm-profile-path', issueNumber, brainstormProfilePath })
|
||||
}, [])
|
||||
|
||||
const updateIssueTestProfilePath = useCallback((issueNumber: number, testProfilePath: string): void => {
|
||||
// Optimistically update local state so the dropdown reflects immediately
|
||||
// without remounting the issues list / detail panel via a full reload.
|
||||
@@ -721,5 +738,5 @@ export function useIssues(): UseIssuesResult {
|
||||
return cleanup
|
||||
}, [clearPrDiffSummaryRunning])
|
||||
|
||||
return { state, settings, globalAutoReview, youtrackConfigured, importYouTrack, toasts, profiles, setIssues, refresh, saveSettings, listYouTrackProjects, youtrackProjects, dismissSettings, requestEditAuth, createIssue, dismissToast, openUrl, resumeSession, resumeReviewSession, startTestSession, resumeTestSession, focusSession, openFile, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, startBrainstormSession, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueTestProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, branchSyncBehind, branchSyncRunning, branchSyncDisabled, branchSyncTitle, runBranchSync, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock }
|
||||
return { state, settings, globalAutoReview, youtrackConfigured, importYouTrack, toasts, profiles, setIssues, refresh, saveSettings, listYouTrackProjects, youtrackProjects, dismissSettings, requestEditAuth, createIssue, dismissToast, openUrl, resumeSession, resumeReviewSession, startTestSession, resumeTestSession, focusSession, openFile, implement, generatePrDiffSummary, isPrDiffSummaryRunning, openPr, openWorktree, deleteWorktree, mergeBranch, deleteIssue, closeIssue, closeSessionTab, startBrainstormSession, changeColumn, setDependency, clearDependency, updateIssueAutoReview, updateIssueProfilePath, updateIssueBrainstormProfilePath, updateIssueTestProfilePath, logs, fetchLogs, clearLogs, pendingSelectId, clearPendingSelect, commitRunning, runCommit, hasChanges, branchSyncBehind, branchSyncRunning, branchSyncDisabled, branchSyncTitle, runBranchSync, envLocked, envFileCount, envLockRunning, envLockTitle, toggleEnvLock }
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export type ExtensionToWebview
|
||||
= | { type: 'issues/loading' }
|
||||
| { type: 'issues/update', issues: Issue[], globalAutoReview: boolean, youtrackConfigured: boolean }
|
||||
| { type: 'issues/error', message: string }
|
||||
| { type: 'issue/patch', issueNumber: number, patch: { autoReview?: boolean, specFile?: string, planFile?: string, prDiffFile?: string, sessionId?: string, implementSessionId?: string, reviewSessionId?: string, testSessionId?: string, pr?: string, implementStatus?: 'running' | 'done' | 'failed', column?: IssueColumn, worktreePath?: string, prMerged?: boolean, prMergedAt?: string, branch?: string, color?: string, worktreeExists?: boolean, brainstormTabOpen?: boolean, implementTabOpen?: boolean, reviewTabOpen?: boolean, testTabOpen?: boolean, profilePath?: string, testProfilePath?: string } }
|
||||
| { type: 'issue/patch', issueNumber: number, patch: { autoReview?: boolean, specFile?: string, planFile?: string, prDiffFile?: string, sessionId?: string, implementSessionId?: string, reviewSessionId?: string, testSessionId?: string, pr?: string, implementStatus?: 'running' | 'done' | 'failed', column?: IssueColumn, worktreePath?: string, prMerged?: boolean, prMergedAt?: string, branch?: string, color?: string, worktreeExists?: boolean, brainstormTabOpen?: boolean, implementTabOpen?: boolean, reviewTabOpen?: boolean, testTabOpen?: boolean, profilePath?: string, brainstormProfilePath?: string, testProfilePath?: string } }
|
||||
| { type: 'issue/pr-diff-summary-done', issueNumber: number }
|
||||
| { type: 'issue/append', issue: Issue, select?: boolean }
|
||||
| { type: 'issue/select-by-number', issueNumber: number }
|
||||
@@ -156,7 +156,7 @@ export type WebviewToExtension
|
||||
| { type: 'settings/edit-request' }
|
||||
| { type: 'youtrack/list-projects', baseUrl: string, token: string }
|
||||
| { type: 'youtrack/import' }
|
||||
| { type: 'issue/create', userRequest: string, images?: Array<{ mediaType: string, base64: string }>, profilePath?: string }
|
||||
| { type: 'issue/create', userRequest: string, images?: Array<{ mediaType: string, base64: string }>, brainstormProfilePath?: string }
|
||||
| { type: 'toast/open-url', url: string }
|
||||
| { type: 'session/resume', sessionId: string, profilePath?: string, cwd?: string, issueNumber?: number }
|
||||
| { type: 'session/focus', issueNumber: number }
|
||||
@@ -176,6 +176,7 @@ export type WebviewToExtension
|
||||
| { type: 'dependency/clear', issueNumber: number, prerequisiteNumber: number }
|
||||
| { type: 'issue/update-auto-review', issueNumber: number, value: boolean }
|
||||
| { type: 'issue/update-profile-path', issueNumber: number, profilePath: string }
|
||||
| { type: 'issue/update-brainstorm-profile-path', issueNumber: number, brainstormProfilePath: string }
|
||||
| { type: 'issue/update-test-profile-path', issueNumber: number, testProfilePath: string }
|
||||
| { type: 'logs/fetch' }
|
||||
| { type: 'logs/clear' }
|
||||
|
||||
@@ -16,9 +16,11 @@ export interface Issue {
|
||||
sessionId?: string
|
||||
/** Absolute path to the Claude settings profile used at creation; passed
|
||||
* as --settings on resume. */
|
||||
/** 实施会话专用的 Claude 配置文件;空 = 默认,不回退其它字段。 */
|
||||
profilePath?: string
|
||||
/** 测试会话专用的 Claude 配置文件,独立于实施会话的 `profilePath`;
|
||||
* 留空时测试会话回退到 `profilePath`,再回退默认。 */
|
||||
/** 头脑风暴会话专用的 Claude 配置文件;空 = 默认,不回退其它字段。 */
|
||||
brainstormProfilePath?: string
|
||||
/** 测试会话专用的 Claude 配置文件;空 = 默认,不回退其它字段。 */
|
||||
testProfilePath?: string
|
||||
/** Optional workspace-relative path to the spec file for this issue, as
|
||||
* surfaced from the Claude session transcript. Lives under
|
||||
|
||||
Reference in New Issue
Block a user