✨ feat(vscode): 新增第五种工单会话「原型会话」

照测试会话那条链路补一份 prototype:

- 消息与路由:session/start-prototype、session/resume-prototype、
  issue/update-prototype-profile-path,都进只读门禁
- 会话:handleStartPrototypeSession / handleResumePrototypeSession,
  终端名 issue-N-原型;cwd 有 worktree 用 worktree、没有退主仓库根
  (原 resolveTestSessionCwd 改名 resolveWorktreeOrRootCwd 两种会话共用)
- 不要求有 PR,任何阶段都能起;前置工单锁仍然拦
- 提示词:新增 prompts/prototype.md,设置里可改,占位符 {issueNumber}
- profile:工单级 prototypeProfilePath > 设置里的原型默认 profile >
  内置默认,与其它会话互不回退
- 状态字段 prototypeSessionId / prototypeProfilePath / prototypeTabOpen
  贯通 gitea、youtrack、本机 state 与移交包
- 详情面板加「原型会话id」「原型配置文件」两行,设置面板加对应两项

Claude-Session: https://claude.ai/code/session_01Kgmb1LvrPmFX3NoUDB4zZC
This commit is contained in:
cruldra committed 2026-09-14 10:20:30 +08:00
1 parent 3fff796a61
commit b62e58d739
27 files changed
+760 -50

No files matched your search

+20 -3
View File
@@ -7,6 +7,7 @@ import type {
import type { HookContext } from '../git/worktreeHooks'
import type { Issue } from '../gitea/types'
import type { IssueRef } from '../issues/stateRouter'
import type { SessionTabKind } from './handlers/terminals'
import type { IssueOwnershipFacts } from './issueOwnership'
import type { KanbanScope } from './kanbanScope'
import type { ExtensionToWebview, WebviewToExtension } from './messages'
@@ -164,7 +165,7 @@ export class KanbanWebviewPanel {
* Map 更易于 inspect / debug。条目数顶天就是当前活跃 tab 数,无压力。
*/
// internal: handler 模块访问
readonly terminalOrigin = new Map<Terminal, { issueNumber: number, kind: 'brainstorm' | 'implement' | 'review' | 'test' }>()
readonly terminalOrigin = new Map<Terminal, { issueNumber: number, kind: SessionTabKind }>()
/**
* 防 handleResumeSession/handleResumeReviewSession 在 await 钩子/终端创建期间被重入触发,
@@ -296,7 +297,7 @@ export class KanbanWebviewPanel {
const origin = this.terminalOrigin.get(closed)
// 反查 terminalOrigin 给详情面板推 *TabOpen: false,让关闭按钮消失。
this.untrackClosedTerminal(closed)
if (origin?.kind === 'implement' || origin?.kind === 'test')
if (origin?.kind === 'implement' || origin?.kind === 'test' || origin?.kind === 'prototype')
void this.dispatchImplTabPostCloseAsync(origin.issueNumber)
// 冲突解决会话不进 terminalOrigin,按终端名触发 post-close 钩子。
const conflictMatch = closed.name.match(/^issue-(\d+)-冲突解决/)
@@ -451,6 +452,14 @@ export class KanbanWebviewPanel {
void sessions.handleResumeTestSession(this, msg.sessionId, msg.issueNumber, msg.cwd)
return
}
if (msg.type === 'session/start-prototype') {
void sessions.handleStartPrototypeSession(this, msg.issueNumber)
return
}
if (msg.type === 'session/resume-prototype') {
void sessions.handleResumePrototypeSession(this, msg.sessionId, msg.issueNumber, msg.cwd)
return
}
if (msg.type === 'editor/open-file') {
void issues.handleOpenFile(this, msg.path)
return
@@ -550,6 +559,10 @@ export class KanbanWebviewPanel {
void issues.handleUpdateTestProfilePath(this, msg.issueNumber, msg.testProfilePath)
return
}
if (msg.type === 'issue/update-prototype-profile-path') {
void issues.handleUpdatePrototypeProfilePath(this, msg.issueNumber, msg.prototypeProfilePath)
return
}
if (msg.type === 'logs/fetch') {
this.postMessage({ type: 'logs/snapshot', entries: logger.snapshot() })
return
@@ -989,6 +1002,7 @@ export class KanbanWebviewPanel {
autoReview: s.autoReview,
reviewPrompt: s.reviewPrompt,
testPrompt: s.testPrompt,
prototypePrompt: s.prototypePrompt,
devBranch: s.devBranch,
releaseBranchPrefix: s.releaseBranchPrefix,
jenkinsJob: s.jenkinsJob,
@@ -1004,6 +1018,7 @@ export class KanbanWebviewPanel {
defaultBrainstormProfilePath: s.defaultBrainstormProfilePath,
defaultImplementProfilePath: s.defaultImplementProfilePath,
defaultTestProfilePath: s.defaultTestProfilePath,
defaultPrototypeProfilePath: s.defaultPrototypeProfilePath,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath: await getEffectiveCommitProfilePath(this.context),
prDiffSummaryProfilePath: await getEffectivePrDiffSummaryProfilePath(this.context),
@@ -1078,6 +1093,7 @@ export class KanbanWebviewPanel {
autoReview: s.autoReview,
reviewPrompt: s.reviewPrompt,
testPrompt: s.testPrompt,
prototypePrompt: s.prototypePrompt,
devBranch: s.devBranch,
releaseBranchPrefix: s.releaseBranchPrefix,
jenkinsJob: s.jenkinsJob,
@@ -1093,6 +1109,7 @@ export class KanbanWebviewPanel {
defaultBrainstormProfilePath: s.defaultBrainstormProfilePath,
defaultImplementProfilePath: s.defaultImplementProfilePath,
defaultTestProfilePath: s.defaultTestProfilePath,
defaultPrototypeProfilePath: s.defaultPrototypeProfilePath,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath: await getEffectiveCommitProfilePath(this.context),
prDiffSummaryProfilePath: await getEffectivePrDiffSummaryProfilePath(this.context),
@@ -1202,7 +1219,7 @@ export class KanbanWebviewPanel {
trackSessionTerminal(
terminal: Terminal,
issueNumber: number,
kind: 'brainstorm' | 'implement' | 'review' | 'test',
kind: SessionTabKind,
): void {
terminals.trackSessionTerminal(this, terminal, issueNumber, kind)
}