✨ feat(vscode): 头脑风暴 profile 独立 + codex 命令统一组装收尾
- 头脑风暴/实施/测试会话 profile 彻底独立,互不回退,各自空值回落默认 - 新建工单弹窗的 profile 选择改为头脑风暴专用 brainstormProfilePath - 详情面板新增「头脑风暴配置文件」下拉 - 删除从未接线的死代码 reviewFlow.ts(runReview 全仓库无调用方) - codexCommand 精简为仅 resume/interactive 两种终端命令形态 - 版本号 0.2.55 → 0.2.60
This commit is contained in:
@@ -68,12 +68,11 @@ export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId:
|
||||
existing.show(false)
|
||||
return
|
||||
}
|
||||
// 实施 resume 走工单级 profilePath > 默认 的优先级(同 handleImplement);
|
||||
// 头脑风暴 resume 保持现状,只看工单级 + 默认。
|
||||
// 实施 / 头脑风暴各自独立:调用方传入对应字段,空 = DEFAULT。
|
||||
const effectiveProfilePath
|
||||
= sessionKind === 'implement'
|
||||
? panel.resolveImplementProfilePath(profilePath)
|
||||
: (profilePath && profilePath.trim() !== '' ? profilePath : DEFAULT_PROFILE_PATH)
|
||||
: resolveBrainstormProfilePath(panel, profilePath)
|
||||
// Reject paths containing single quotes — we shell-quote with single
|
||||
// quotes below, and embedded quotes would break out of the wrap. In
|
||||
// practice profile paths live under `/home/<user>/...` so this is a
|
||||
@@ -977,14 +976,12 @@ export async function handleStartBrainstormSession(panel: KanbanWebviewPanel, is
|
||||
return
|
||||
}
|
||||
|
||||
// Pull profilePath from the issue's state JSON so the new cc session
|
||||
// reuses whatever profile the user set when the issue was first created.
|
||||
// Tolerated: missing/unparseable comment falls back to DEFAULT_PROFILE_PATH.
|
||||
let profilePath: string | undefined
|
||||
// 头脑风暴只用 brainstormProfilePath;空 = DEFAULT,不回退实施 profile。
|
||||
let brainstormProfilePath: string | undefined
|
||||
try {
|
||||
const stateObj = await panel.readIssueState(issueNumber)
|
||||
if (stateObj && typeof stateObj.profilePath === 'string' && stateObj.profilePath.length > 0)
|
||||
profilePath = stateObj.profilePath
|
||||
if (stateObj && typeof stateObj.brainstormProfilePath === 'string' && stateObj.brainstormProfilePath.length > 0)
|
||||
brainstormProfilePath = stateObj.brainstormProfilePath
|
||||
}
|
||||
catch (err) {
|
||||
logger.add({
|
||||
@@ -995,11 +992,10 @@ export async function handleStartBrainstormSession(panel: KanbanWebviewPanel, is
|
||||
})
|
||||
}
|
||||
|
||||
const effectiveProfilePath
|
||||
= profilePath && profilePath.trim() !== '' ? profilePath : DEFAULT_PROFILE_PATH
|
||||
const effectiveProfilePath = resolveBrainstormProfilePath(panel, brainstormProfilePath)
|
||||
if (effectiveProfilePath.includes('\'')) {
|
||||
void window.showErrorMessage(
|
||||
`启动规划失败:profilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
|
||||
`启动规划失败:brainstormProfilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1089,7 +1085,7 @@ export async function handleStartBrainstormSession(panel: KanbanWebviewPanel, is
|
||||
* 与 handleStartBrainstormSession 的差异:
|
||||
* - 首条 prompt 依赖 state JSON 里的 `pr`(合并的 PR 号);没有 PR 直接 toast 拒绝。
|
||||
* - cwd 优先用 worktree(存在时),否则退回 workspaceRoot——测试本质要读真实代码,
|
||||
* profile 走 resolveTestProfilePath(testProfilePath > profilePath > 默认)。
|
||||
* profile 走 resolveTestProfilePath(testProfilePath > 默认,不回退实施)。
|
||||
* - 捕获到的 session id 写进 state JSON 的 `testSessionId`。
|
||||
*
|
||||
* in-flight 锁 key `${issueNumber}:test`,防 createTerminal 期间用户重复点击。
|
||||
@@ -1136,11 +1132,10 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
|
||||
return
|
||||
}
|
||||
|
||||
// 从 state JSON 读 pr / profile / worktree。pr 仅在主 worktree(已合并)
|
||||
// 从 state JSON 读 pr / testProfile / worktree。pr 仅在主 worktree(已合并)
|
||||
// 测试时必需——那条路径要靠 tea 了解合并进来的改动;worktree 内测试代码
|
||||
// 本就在工作目录,不依赖 PR。
|
||||
let pr: string | undefined
|
||||
let profilePath: string | undefined
|
||||
let testProfilePath: string | undefined
|
||||
let worktreePathRel: string | undefined
|
||||
let branch: string | undefined
|
||||
@@ -1149,8 +1144,6 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
|
||||
if (stateObj) {
|
||||
if (typeof stateObj.pr === 'string' && stateObj.pr.length > 0)
|
||||
pr = stateObj.pr
|
||||
if (typeof stateObj.profilePath === 'string' && stateObj.profilePath.length > 0)
|
||||
profilePath = stateObj.profilePath
|
||||
if (typeof stateObj.testProfilePath === 'string' && stateObj.testProfilePath.length > 0)
|
||||
testProfilePath = stateObj.testProfilePath
|
||||
if (typeof stateObj.worktreePath === 'string' && stateObj.worktreePath.length > 0)
|
||||
@@ -1179,11 +1172,11 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
|
||||
return
|
||||
}
|
||||
|
||||
// 测试会话优先用专用 testProfilePath,未设置时回退实施 profile,再回退默认。
|
||||
const effectiveProfilePath = resolveTestProfilePath(panel, testProfilePath, profilePath)
|
||||
// 测试会话只用 testProfilePath;空 = DEFAULT,不回退实施 profile。
|
||||
const effectiveProfilePath = resolveTestProfilePath(panel, testProfilePath)
|
||||
if (effectiveProfilePath.includes('\'')) {
|
||||
void window.showErrorMessage(
|
||||
`启动测试失败:profilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
|
||||
`启动测试失败:testProfilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1289,7 +1282,7 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
|
||||
* `issue-${N}-测试`、命令 `claude ... --resume ${sessionId}`。
|
||||
*
|
||||
* cwd 优先用 worktree(relCwd 存在且在磁盘上),否则退回 workspaceRoot。
|
||||
* profile 与 start 对称:resolveTestProfilePath(testProfilePath > profilePath > 默认)。
|
||||
* profile 与 start 对称:resolveTestProfilePath(testProfilePath > 默认)。
|
||||
* in-flight 锁 key `${issueNumber}:test`。
|
||||
*/
|
||||
export async function handleResumeTestSession(panel: KanbanWebviewPanel, sessionId: string, issueNumber: number, _relCwd?: string): Promise<void> {
|
||||
@@ -1312,7 +1305,6 @@ export async function handleResumeTestSession(panel: KanbanWebviewPanel, session
|
||||
let effectiveCwd = workspaceRoot
|
||||
// 顺带读出 branch 给 impl-tab-pre-create 钩子用;读不到就空字符串。
|
||||
let branchForHook = ''
|
||||
let profilePath: string | undefined
|
||||
let testProfilePath: string | undefined
|
||||
if (workspaceRoot) {
|
||||
const remote = await detectRepo(workspaceRoot)
|
||||
@@ -1323,8 +1315,6 @@ export async function handleResumeTestSession(panel: KanbanWebviewPanel, session
|
||||
const worktreePathRel = typeof stateObj?.worktreePath === 'string' ? stateObj.worktreePath : undefined
|
||||
if (stateObj && typeof stateObj.branch === 'string')
|
||||
branchForHook = stateObj.branch
|
||||
if (typeof stateObj?.profilePath === 'string' && stateObj.profilePath.length > 0)
|
||||
profilePath = stateObj.profilePath
|
||||
if (typeof stateObj?.testProfilePath === 'string' && stateObj.testProfilePath.length > 0)
|
||||
testProfilePath = stateObj.testProfilePath
|
||||
effectiveCwd = await resolveTestSessionCwd(workspaceRoot, worktreePathRel)
|
||||
@@ -1341,10 +1331,10 @@ export async function handleResumeTestSession(panel: KanbanWebviewPanel, session
|
||||
}
|
||||
|
||||
// --settings 决定 provider/model/鉴权,resume 也必须与 start 一致解析 profile。
|
||||
const effectiveProfilePath = resolveTestProfilePath(panel, testProfilePath, profilePath)
|
||||
const effectiveProfilePath = resolveTestProfilePath(panel, testProfilePath)
|
||||
if (effectiveProfilePath.includes('\'')) {
|
||||
void window.showErrorMessage(
|
||||
`resume 失败:profilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
|
||||
`resume 失败:testProfilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
|
||||
)
|
||||
return
|
||||
}
|
||||
@@ -1611,15 +1601,12 @@ export async function startConflictResolution(panel: KanbanWebviewPanel, opts: {
|
||||
* Pick the profile.json that implement-class cc sessions
|
||||
* (handleImplement / handleResumeSession when sessionKind === 'implement')
|
||||
* should launch with. Priority:
|
||||
* 1. The per-issue `profilePath` recorded in state JSON (preserves the
|
||||
* brainstorm-time choice, overridable from the issue detail panel).
|
||||
* 2. The hard-coded `DEFAULT_PROFILE_PATH` fallback.
|
||||
* 1. 工单级 `profilePath`(详情面板「实施配置文件」)
|
||||
* 2. DEFAULT_PROFILE_PATH
|
||||
*
|
||||
* Conflict-resolution sessions use the global
|
||||
* `settings.conflictResolutionProfilePath` instead of this helper.
|
||||
* Brainstorm sessions deliberately don't go through this helper — they
|
||||
* keep the legacy `profilePath || DEFAULT_PROFILE_PATH` so creators can
|
||||
* still pick a profile per issue at brainstorm time.
|
||||
* 冲突解决用全局 `settings.conflictResolutionProfilePath`。
|
||||
* 头脑风暴用 resolveBrainstormProfilePath;测试用 resolveTestProfilePath。
|
||||
* 三者互不回退。
|
||||
*/
|
||||
export function resolveImplementProfilePath(_panel: KanbanWebviewPanel, issueLevelProfilePath: string | undefined): string {
|
||||
const issueLevel = issueLevelProfilePath?.trim()
|
||||
@@ -1629,12 +1616,19 @@ export function resolveImplementProfilePath(_panel: KanbanWebviewPanel, issueLev
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试会话的 profile 解析:专用 `testProfilePath` 优先,未单独设置时回退到
|
||||
* 实施会话的 `profilePath`,再回退默认。让测试会话既能独立锁 profile,
|
||||
* 又默认与实施会话一致。
|
||||
* 头脑风暴会话 profile:工单级 `brainstormProfilePath` > DEFAULT。
|
||||
* 不回退实施 profile。
|
||||
*/
|
||||
export function resolveTestProfilePath(_panel: KanbanWebviewPanel, testProfilePath: string | undefined, implementProfilePath: string | undefined): string {
|
||||
return testProfilePath?.trim() || implementProfilePath?.trim() || DEFAULT_PROFILE_PATH
|
||||
export function resolveBrainstormProfilePath(_panel: KanbanWebviewPanel, brainstormProfilePath: string | undefined): string {
|
||||
return brainstormProfilePath?.trim() || DEFAULT_PROFILE_PATH
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试会话 profile:工单级 `testProfilePath` > DEFAULT。
|
||||
* 不回退实施 profile。
|
||||
*/
|
||||
export function resolveTestProfilePath(_panel: KanbanWebviewPanel, testProfilePath: string | undefined): string {
|
||||
return testProfilePath?.trim() || DEFAULT_PROFILE_PATH
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user