feat(vscode): 历史会话可换 profile 恢复

This commit is contained in:
2026-08-25 13:06:48 +08:00
parent 1c3e66bdc7
commit 07b2bf75a0
9 changed files with 177 additions and 34 deletions
+1 -1
View File
@@ -556,7 +556,7 @@ export class KanbanWebviewPanel {
return
}
if (msg.type === 'managed-sessions/resume') {
void managedSessions.handleManagedSessionsResume(this, msg.sessionId)
void managedSessions.handleManagedSessionsResume(this, msg.sessionId, msg.profilePath)
return
}
if (msg.type === 'managed-sessions/delete') {
+24 -17
View File
@@ -5,6 +5,7 @@ import { buildCcCommand } from '../../cc/ccCommand'
import { pollForNewSession, projectsDirFor } from '../../cc/sessionWatcher'
import { logger } from '../../logging/logger'
import { listImportableNamedSessions } from '../../sessions/importableNamedSessions'
import { decideManagedResumeProfile } from '../../sessions/managedResumeProfile'
import { readManagedSessions, writeManagedSessions } from '../../sessions/managedStore'
import { inferProfilePathForSession } from '../../sessions/sessionProfileInference'
import { resolveProfilePath } from '../../cc/profiles'
@@ -225,7 +226,7 @@ export async function handleManagedSessionsRename(panel: KanbanWebviewPanel, ses
* 恢复一个受管理会话:在新终端 tab 里跑 `claude ... --resume <id>`
* cwd = workspaceRoot。in-flight 锁防止重复点击重复 createTerminal。
*/
export async function handleManagedSessionsResume(panel: KanbanWebviewPanel, sessionId: string): Promise<void> {
export async function handleManagedSessionsResume(panel: KanbanWebviewPanel, sessionId: string, profilePath?: string): Promise<void> {
const lockKey = `managed:${sessionId}`
if (panel.resumeInFlight.has(lockKey)) {
logger.add({
@@ -244,29 +245,35 @@ export async function handleManagedSessionsResume(panel: KanbanWebviewPanel, ses
return
}
const data = await readManagedSessions(workspaceRoot)
const target = data.sessions.find(s => s.id === sessionId)
const override = profilePath?.trim() || undefined
let inferred: string | null = null
if (!override && (!target?.profilePath || target.profilePath.trim() === '') && target) {
inferred = await inferProfilePathForSession(sessionId, projectsDirFor(workspaceRoot))
}
const decided = decideManagedResumeProfile({
storedProfile: target?.profilePath,
overrideProfile: profilePath,
inferredProfile: inferred,
})
if (decided.persist && target) {
target.profilePath = decided.persist
await writeManagedSessions(workspaceRoot, data)
}
// 已有该会话的存活终端,直接聚焦、不再开新的(防重复)。
const existing = panel.managedTerminals.get(sessionId)
if (existing) {
if (decided.persist)
await pushManagedSessions(panel)
existing.show(false)
return
}
const data = await readManagedSessions(workspaceRoot)
const target = data.sessions.find(s => s.id === sessionId)
// store 缺 profilePath 时从 transcript 推断并回写,避免 resume 落到 default profile。
let storedProfile = target?.profilePath
if ((!storedProfile || storedProfile.trim() === '') && target) {
const inferred = await inferProfilePathForSession(sessionId, projectsDirFor(workspaceRoot))
if (inferred) {
storedProfile = inferred
target.profilePath = inferred
await writeManagedSessions(workspaceRoot, data)
}
}
const effectiveProfilePath = resolveProfilePath(
storedProfile && storedProfile.trim() !== '' ? storedProfile : undefined,
)
const effectiveProfilePath = resolveProfilePath(decided.effective)
if (effectiveProfilePath.includes('\'')) {
void window.showErrorMessage(
`resume 失败:profilePath 含单引号,拒绝执行 (${effectiveProfilePath})`,
+1 -1
View File
@@ -191,7 +191,7 @@ export type WebviewToExtension
| { type: 'managed-sessions/get' }
| { type: 'managed-sessions/create', profilePath: string, name?: string, prompt?: string }
| { type: 'managed-sessions/rename', sessionId: string, name: string }
| { type: 'managed-sessions/resume', sessionId: string }
| { type: 'managed-sessions/resume', sessionId: string, profilePath?: string }
| { type: 'managed-sessions/delete', sessionId: string }
| { type: 'managed-sessions/close-tab', sessionId: string }
| { type: 'managed-sessions/list-importable' }