⚡ perf(vscode): 开会话去掉多余远程往返,spinner 跟随真实进度

开会话原先要先全量拉工单(含每张工单的评论、依赖、PR)做前置锁检查,
再各读一次 state JSON 给 pre-create 钩子和终端图标,几秒后才 createTerminal。

- 锁检查改用主进程已算好的工单快照,快照里没有该工单才回落全量拉取
- state JSON 一次读两处用,且提前发起与本地准备重叠
- 会话行 spinner 由扩展的 session/tab-settled 消息驱动,不再是固定 1.5s 假动画,
  消息丢失时 60s 超时兜底

Claude-Session: https://claude.ai/code/session_01Kgmb1LvrPmFX3NoUDB4zZC
This commit is contained in:
cruldra committed 2026-09-13 10:14:48 +08:00
1 parent b182e0ac5b
commit 70b826123c
12 files changed
+218 -71

No files matched your search

+39 -17
View File
@@ -696,7 +696,10 @@ export class KanbanWebviewPanel {
* Persistence failures are logged and swallowed.
*/
// internal: handler 模块访问
async resolveIssueIcon(issueNumber: number): Promise<{ themeColor: ThemeColor, iconUri: Uri }> {
async resolveIssueIcon(
issueNumber: number,
presetState?: Record<string, unknown> | null,
): Promise<{ themeColor: ThemeColor, iconUri: Uri }> {
// Helper: produce both representations from a palette id.
const pack = (id: string) => ({
themeColor: new ThemeColor(id),
@@ -707,24 +710,34 @@ export class KanbanWebviewPanel {
// pick so the icon is still stable across sessions.
const fallbackId = PALETTE[((issueNumber % PALETTE.length) + PALETTE.length) % PALETTE.length]
const workspaceRoot = workspace.workspaceFolders?.[0]?.uri.fsPath
if (!workspaceRoot)
return pack(fallbackId)
const remote = await detectRepo(workspaceRoot)
if (!remote)
return pack(fallbackId)
const token = await getToken(this.context, remote.host)
if (!token)
return pack(fallbackId)
let stored: string | undefined
try {
const state = await this.readIssueState(issueNumber)
if (typeof state.color === 'string' && state.color.length > 0)
stored = state.color
// 调用方已经读过 state(开会话热路径就一次)时直接复用,省一次远程往返;
// presetState 为 null 表示那次读取失败,按 tracker 不可达处理。
if (presetState !== undefined) {
if (presetState === null)
return pack(fallbackId)
if (typeof presetState.color === 'string' && presetState.color.length > 0)
stored = presetState.color
}
catch (err) {
console.warn('[superpowers] failed to read state JSON for color:', err)
else {
const workspaceRoot = workspace.workspaceFolders?.[0]?.uri.fsPath
if (!workspaceRoot)
return pack(fallbackId)
const remote = await detectRepo(workspaceRoot)
if (!remote)
return pack(fallbackId)
const token = await getToken(this.context, remote.host)
if (!token)
return pack(fallbackId)
try {
const state = await this.readIssueState(issueNumber)
if (typeof state.color === 'string' && state.color.length > 0)
stored = state.color
}
catch (err) {
console.warn('[superpowers] failed to read state JSON for color:', err)
}
}
const { id, isNew } = resolveIssueColor(stored)
@@ -871,6 +884,15 @@ export class KanbanWebviewPanel {
* `{ locked: false }` so a transient Gitea hiccup can't lock the user out
* of starting a session.
*/
/**
* 主进程上一次算好的工单快照(issues/update 的 payload)。锁检查等只读
* 判断直接用它,省掉一次全量 loadIssues 往返;面板还没加载过时为 undefined。
*/
// internal: handler 模块访问
snapshotIssues(): Issue[] | undefined {
return this.lastIssuesUpdate?.issues
}
// internal: handler 模块访问
async resolveLockedReason(
issueNumber: number,