✨ feat(vscode): 续聊提示词告诉规划会话怎么找原型会话

讨论里发现原型要改时,规划会话既不该自己动插件代码,也不该去翻 git log 猜
会话 id。提示词现在带上原型会话 id 和终端名,并指明走 spawning-peer-sessions
技能 SendMessage 过去;没有活会话就停下让用户从面板起一个。

Claude-Session: https://claude.ai/code/session_01Kgmb1LvrPmFX3NoUDB4zZC
This commit is contained in:
cruldra committed 2026-09-15 00:16:22 +08:00
1 parent 9a388b50ce
commit 0792c9262d
2 files changed
+23 -6

No files matched your search

+17 -5
View File
@@ -31,25 +31,37 @@ export function getBrainstormPrompt(
export function getBrainstormContinuePrompt( export function getBrainstormContinuePrompt(
ctx: ExtensionContext, ctx: ExtensionContext,
vars: { issueNumber: number, issueRef?: string, prototypeFile?: string }, vars: { issueNumber: number, issueRef?: string, prototypeFile?: string, prototypeSessionId?: string },
): string { ): string {
const tpl = getSettings(ctx).brainstormContinuePrompt const tpl = getSettings(ctx).brainstormContinuePrompt
// For youtrack cards the board number is synthetic; substitute the readable // For youtrack cards the board number is synthetic; substitute the readable
// id (e.g. LXF-12) so the cc agent references the real issue (readable via // id (e.g. LXF-12) so the cc agent references the real issue (readable via
// `opencli yt issues show <id>`), not a non-existent gitea number. // `opencli yt issues show <id>`), not a non-existent gitea number.
const out = tpl.split('{issueNumber}').join(vars.issueRef ?? String(vars.issueNumber)) const out = tpl.split('{issueNumber}').join(vars.issueRef ?? String(vars.issueNumber))
return fillPrototypeRef(out, vars.prototypeFile) return fillPrototypeRef(out, vars.prototypeFile, {
issueNumber: vars.issueRef ?? String(vars.issueNumber),
prototypeSessionId: vars.prototypeSessionId,
})
} }
/** /**
* `{prototypeRef}` 在模板里独占一段:有原型插件就填一段「先读它」的交代, * `{prototypeRef}` 在模板里独占一段:有原型插件就填一段「先读它」的交代,
* 没有就连同前后空行一起抹掉——否则模板里会留下一个空洞段落。 * 没有就连同前后空行一起抹掉——否则模板里会留下一个空洞段落。
*/ */
function fillPrototypeRef(tpl: string, prototypeFile: string | undefined): string { function fillPrototypeRef(
tpl: string,
prototypeFile: string | undefined,
ctx: { issueNumber: string, prototypeSessionId: string | undefined },
): string {
if (!prototypeFile) if (!prototypeFile)
return tpl.replace(/\n*\{prototypeRef\}\n*/g, '\n\n').trimEnd() return tpl.replace(/\n*\{prototypeRef\}\n*/g, '\n\n').trimEnd()
const para = `工单已有原型插件 ${prototypeFile},先读它了解已经定下来的界面和交互,在此基础上只对齐还不明确的地方,不要从零重画。` const lines = [
return tpl.split('{prototypeRef}').join(para) `工单已有原型插件 ${prototypeFile},先读它了解已经定下来的界面和交互,在此基础上只对齐还不明确的地方,不要从零重画。`,
// 讨论里冒出来的原型改动要回到原型会话去做:那边有画图上下文,这边动插件
// 代码会和它打架。定位靠会话 id——transcript 文件名就是它。
`讨论中发现原型要改时,不要自己动插件代码,也不要去翻 git log 猜:用 ecc 的 \`spawning-peer-sessions\` 技能,ListAgents 找到本工单的原型会话(终端名 issue-${ctx.issueNumber}-原型${ctx.prototypeSessionId ? `,会话 id ${ctx.prototypeSessionId},它的 transcript 文件名就是这个 id` : ''}),SendMessage 说清要改哪块、为什么改、改完怎么算对。找不到活会话就停下告诉我去工单面板的「原型会话id」行点 ▶ 起一个。`,
]
return tpl.split('{prototypeRef}').join(lines.join('\n\n'))
} }
export function getImplementPlanPrompt(ctx: ExtensionContext, vars: { planFile: string, issueNumber: number, issueRef?: string }): string { export function getImplementPlanPrompt(ctx: ExtensionContext, vars: { planFile: string, issueNumber: number, issueRef?: string }): string {
+6 -1
View File
@@ -947,8 +947,10 @@ export async function handleContinueBrainstorm(panel: KanbanWebviewPanel, issueN
// 头脑风暴只用 brainstormProfilePath;空 = DEFAULT,不回退实施 profile。 // 头脑风暴只用 brainstormProfilePath;空 = DEFAULT,不回退实施 profile。
let brainstormProfilePath: string | undefined let brainstormProfilePath: string | undefined
let sessionId: string | undefined let sessionId: string | undefined
// 工单已有原型插件时,续聊提示词里让 cc 先读它,别把已经画定的界面又讨论一遍。 // 工单已有原型插件时,续聊提示词里让 cc 先读它,别把已经画定的界面又讨论一遍;
// 会话 id 一并带上,讨论里要改原型时直接 SendMessage 给原型会话。
let prototypeFile: string | undefined let prototypeFile: string | undefined
let prototypeSessionId: string | undefined
try { try {
const stateObj = await panel.readIssueState(issueNumber) const stateObj = await panel.readIssueState(issueNumber)
if (stateObj && typeof stateObj.brainstormProfilePath === 'string' && stateObj.brainstormProfilePath.length > 0) if (stateObj && typeof stateObj.brainstormProfilePath === 'string' && stateObj.brainstormProfilePath.length > 0)
@@ -957,6 +959,8 @@ export async function handleContinueBrainstorm(panel: KanbanWebviewPanel, issueN
sessionId = stateObj.sessionId sessionId = stateObj.sessionId
if (stateObj && typeof stateObj.prototypeFile === 'string' && stateObj.prototypeFile.length > 0) if (stateObj && typeof stateObj.prototypeFile === 'string' && stateObj.prototypeFile.length > 0)
prototypeFile = stateObj.prototypeFile prototypeFile = stateObj.prototypeFile
if (stateObj && typeof stateObj.prototypeSessionId === 'string' && stateObj.prototypeSessionId.length > 0)
prototypeSessionId = stateObj.prototypeSessionId
} }
catch (err) { catch (err) {
logger.add({ logger.add({
@@ -971,6 +975,7 @@ export async function handleContinueBrainstorm(panel: KanbanWebviewPanel, issueN
issueNumber, issueNumber,
issueRef: panel.refFor(issueNumber).externalId, issueRef: panel.refFor(issueNumber).externalId,
prototypeFile, prototypeFile,
prototypeSessionId,
}) })
const terminalName = `issue-${issueNumber}-规划` const terminalName = `issue-${issueNumber}-规划`
// 新建工单流程的 tab 叫 issue-new-{nonce}-规划,只能靠 newIssueTerminals 反查。 // 新建工单流程的 tab 叫 issue-new-{nonce}-规划,只能靠 newIssueTerminals 反查。