diff --git a/vscode/src/panel/handlers/issues.ts b/vscode/src/panel/handlers/issues.ts index 26f26b8..b410661 100644 --- a/vscode/src/panel/handlers/issues.ts +++ b/vscode/src/panel/handlers/issues.ts @@ -33,6 +33,7 @@ import { } from '../../gitea/api' import { isValidSpxFilePath, loadIssues } from '../../gitea/issueLoader' import { mergeStateJsonComment } from '../../gitea/stateJson' +import { mergeLocalIssueState } from '../../issues/localState' import { logger } from '../../logging/logger' import { getEffectivePrDiffSummaryProfilePath, getSettings } from '../../settings/store' import { webhookCoordinator } from '../../webhook/coordinator' @@ -42,6 +43,7 @@ import { evaluateLockedReason } from '../issueLock' import { cleanupFeatureBranch } from './branchCleanup' import { clearSessionConfirmText, clearSessionDoneText, SESSION_KINDS } from './sessionKinds' import * as sessions from './sessions' +import { issueNumberForNewIssueTerminal } from './terminals' import { canResetToTodo, todoResetStateExtra, todoResetUiPatch } from './todoReset' export async function handleColumnChange(panel: KanbanWebviewPanel, issueNumber: number, toColumn: IssueColumn): Promise { @@ -1529,12 +1531,9 @@ export async function handleIssueCreate( dismissOnTimer: 4000, }) - // Background: fill in sessionId once the jsonl materializes. If the - // matching webhook fires before this resolves, the pending entry has - // already been deleted and we silently no-op — the state JSON just - // lacks sessionId in that (rare) race case, and the user can resume - // from a later session id via the terminal. - watchPromise.then((sid) => { + // 工单往往比会话文件先出现。webhook 把 pending 取走时 sessionId 还空, + // 这里在文件落地后补写本机会话 id。 + watchPromise.then(async (sid) => { if (!sid) { logger.add({ level: 'warn', @@ -1551,7 +1550,33 @@ export async function handleIssueCreate( source: 'panel', message: `已捕获新建工单会话 ${sid} nonce=${shortNonce}`, }) + return } + const issueNumber = issueNumberForNewIssueTerminal(panel, terminal) + if (issueNumber === undefined) { + logger.add({ + level: 'warn', + source: 'panel', + message: `新建工单会话 ${sid} 已捕获,但 nonce=${shortNonce} 还没对上工单`, + }) + return + } + try { + const state = await panel.readIssueState(issueNumber) + if (typeof state.sessionId === 'string' && state.sessionId.length > 0) + return + } + catch { + // 本机状态还没有,照写 + } + await mergeLocalIssueState(panel.context, 'gitea', issueNumber, { sessionId: sid }) + panel.terminals.set(sid, terminal) + panel.postMessage({ type: 'issue/patch', issueNumber, patch: { sessionId: sid } }) + logger.add({ + level: 'info', + source: 'panel', + message: `补写工单 #${issueNumber} 头脑风暴会话 ${sid}`, + }) }).catch((err) => { console.warn('[superpowers] new-issue session watch failed:', err) }) diff --git a/vscode/src/panel/handlers/terminals.ts b/vscode/src/panel/handlers/terminals.ts index e07465d..5076faa 100644 --- a/vscode/src/panel/handlers/terminals.ts +++ b/vscode/src/panel/handlers/terminals.ts @@ -405,3 +405,11 @@ export function linkPendingTerminalToIssue(panel: KanbanWebviewPanel, nonce: str panel.terminals.set(pending.sessionId, pending.terminal) trackSessionTerminal(panel, pending.terminal, issueNumber, 'brainstorm') } + +export function issueNumberForNewIssueTerminal(panel: KanbanWebviewPanel, terminal: Terminal): number | undefined { + for (const [issueNumber, linked] of panel.newIssueTerminals) { + if (linked === terminal) + return issueNumber + } + return undefined +}