♻️ refactor(vscode): claude 会话命令收口到 buildCcCommand 并移除已卸载的 serena --system-prompt

9 处手拼的 claude 启动命令(managedSessions/sessions/issues)统一改用新增的
cc/ccCommand.ts:buildCcCommand({ profilePath, effort?, resumeSessionId?, prompt? }),
去掉各处重复的 --system-prompt="$(serena prompts ...)"(serena 已卸载)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-25 00:57:29 +08:00
co-authored by Claude Opus 4.8
parent 02b0aca891
commit 7be4e38620
4 changed files with 49 additions and 15 deletions
+35
View File
@@ -0,0 +1,35 @@
/**
* Single source of truth for the `claude` (cc) terminal launch command.
*
* Every session entry point (brainstorm / implement / test / review / resume /
* managed session) shells out `claude` with the same flags; building the
* string in one place keeps those call sites from drifting apart.
*
* We deliberately pass no `--system-prompt`; cc runs with its own default
* system prompt.
*/
export interface CcCommandOpts {
/** Path passed to `--settings` (caller guarantees it contains no single quote). */
profilePath: string
/** e.g. 'high' → `--effort high`; omitted means no `--effort`. */
effort?: string
/** When set, append `--resume <id>`. Mutually exclusive with prompt; resume wins. */
resumeSessionId?: string
/** When set (and no resume), append the prompt as a positional `'<prompt>'` arg. */
prompt?: string
}
export function buildCcCommand(opts: CcCommandOpts): string {
const parts = ['claude']
if (opts.effort)
parts.push(`--effort ${opts.effort}`)
parts.push('--dangerously-skip-permissions', `--settings '${opts.profilePath}'`)
// resume and prompt are mutually exclusive; a resumed session restores its
// own conversation, so a fresh prompt would be meaningless.
if (opts.resumeSessionId)
parts.push(`--resume ${opts.resumeSessionId}`)
else if (opts.prompt)
parts.push(`'${opts.prompt}'`)
return parts.join(' ')
}
+2 -1
View File
@@ -10,6 +10,7 @@ import * as path from 'node:path'
import { resolveWorktreePath } from '../../git/worktree'
import { commands, env, ThemeColor, Uri, window, workspace } from 'vscode'
import { getToken } from '../../auth/secrets'
import { buildCcCommand } from '../../cc/ccCommand'
import { getBrainstormPrompt } from '../../cc/prompts'
import { projectsDirFor, watchForNewSession } from '../../cc/sessionWatcher'
import { spawnClaude } from '../../cc/spawnClaude'
@@ -1283,7 +1284,7 @@ export async function handleIssueCreate(
createdAt: Date.now(),
})
const cmd = `claude --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" '${prompt}'`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, prompt })
terminal.sendText(cmd)
logger.add({
level: 'info',
+5 -7
View File
@@ -1,6 +1,7 @@
import type { KanbanWebviewPanel } from '../KanbanPanel'
import { promises as fsp } from 'node:fs'
import { window, workspace } from 'vscode'
import { buildCcCommand } from '../../cc/ccCommand'
import { pollForNewSession, projectsDirFor } from '../../cc/sessionWatcher'
import { logger } from '../../logging/logger'
import { readManagedSessions, writeManagedSessions } from '../../sessions/managedStore'
@@ -53,9 +54,8 @@ export async function handleManagedSessionsGet(panel: KanbanWebviewPanel): Promi
/**
* 从会话管理 tab 创建一个新的 cc 会话:
* - cwd 用项目根(workspaceRoot,非 worktree)。
* - 启动命令照搬头脑风暴风格claude --dangerously-skip-permissions --settings
* '<profilePath>' --system-prompt="$(serena prompts ...)"),prompt 非空时
* 再追加 ' <prompt>'。
* - 启动命令统一由 buildCcCommand 构建claude --dangerously-skip-permissions
* --settings '<profilePath>'),prompt 非空时作为位置参数传入。
* - 用 pollForNewSession 捕获新 sessionId(共享 projects 目录用轮询更可靠),
* 落进 .spx/session-names.json 后推全量列表。
*/
@@ -121,9 +121,7 @@ export async function handleManagedSessionsCreate(panel: KanbanWebviewPanel, pro
message: `已创建终端 "${terminal.name}"`,
})
let cmd = `claude --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)"`
if (effectivePrompt)
cmd += ` '${effectivePrompt}'`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, prompt: effectivePrompt || undefined })
terminal.sendText(cmd)
logger.add({
level: 'info',
@@ -243,7 +241,7 @@ export async function handleManagedSessionsResume(panel: KanbanWebviewPanel, ses
message: `已创建终端 "${terminal.name}" (resume ${sessionId})`,
})
const cmd = `claude --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" --resume ${sessionId}`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, resumeSessionId: sessionId })
terminal.sendText(cmd)
// 登记终端并推 show,让列表的 tabOpen 立即为 true。
+7 -7
View File
@@ -8,6 +8,7 @@ import * as os from 'node:os'
import * as path from 'node:path'
import { window, workspace } from 'vscode'
import { getToken } from '../../auth/secrets'
import { buildCcCommand } from '../../cc/ccCommand'
import { watchForNewCodexSession } from '../../cc/codexSessionWatcher'
import { getBrainstormContinuePrompt, getImplementPlanPrompt } from '../../cc/prompts'
import { projectsDirFor, watchForNewSession } from '../../cc/sessionWatcher'
@@ -205,8 +206,7 @@ export async function handleResumeSession(panel: KanbanWebviewPanel, sessionId:
dismissOnTimer: 5000,
})
}
const effortArg = sessionKind === 'implement' ? ' --effort high' : ''
const cmd = `claude${effortArg} --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" --resume ${sessionId}`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, effort: sessionKind === 'implement' ? 'high' : undefined, resumeSessionId: sessionId })
terminal.sendText(cmd)
}
finally {
@@ -870,7 +870,7 @@ export async function handleImplement(
source: 'terminal',
message: `已创建终端 "${terminal.name}"`,
})
const cmd = `claude --effort high --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" '${prompt}'`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, effort: 'high', prompt })
terminal.sendText(cmd)
logger.add({
level: 'info',
@@ -1020,7 +1020,7 @@ export async function handleStartBrainstormSession(panel: KanbanWebviewPanel, is
message: `已创建终端 "${terminal.name}"`,
})
const cmd = `claude --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" '${prompt}'`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, prompt })
terminal.sendText(cmd)
logger.add({
level: 'info',
@@ -1220,7 +1220,7 @@ export async function handleStartTestSession(panel: KanbanWebviewPanel, issueNum
message: `已创建终端 "${terminal.name}"`,
})
const cmd = `claude --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" '${prompt}'`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, prompt })
terminal.sendText(cmd)
logger.add({
level: 'info',
@@ -1366,7 +1366,7 @@ export async function handleResumeTestSession(panel: KanbanWebviewPanel, session
message: `已创建测试会话终端 #${issueNumber} cwd=${effectiveCwd}`,
})
const cmd = `claude --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt=\"$(serena prompts print-cc-system-prompt-override)\" --resume ${sessionId}`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, resumeSessionId: sessionId })
terminal.sendText(cmd)
}
finally {
@@ -1568,7 +1568,7 @@ export async function startConflictResolution(panel: KanbanWebviewPanel, opts: {
})
return
}
const cmd = `claude --effort high --dangerously-skip-permissions --settings '${effectiveProfilePath}' --system-prompt="$(serena prompts print-cc-system-prompt-override)" '${prompt}'`
const cmd = buildCcCommand({ profilePath: effectiveProfilePath, effort: 'high', prompt })
terminal.sendText(cmd)
logger.add({