diff --git a/src/resources/extensions/gsd/index.ts b/src/resources/extensions/gsd/index.ts index b92317a7f..b20d4ee42 100644 --- a/src/resources/extensions/gsd/index.ts +++ b/src/resources/extensions/gsd/index.ts @@ -795,6 +795,12 @@ export default function (pi: ExtensionAPI) { // ── agent_end: auto-mode advancement or auto-start after discuss ─────────── pi.on("agent_end", async (event, ctx: ExtensionContext) => { + // Clean up quick-task branch if one just completed (#1269) + try { + const { cleanupQuickBranch } = await import("./quick.js"); + cleanupQuickBranch(); + } catch { /* non-fatal */ } + // If discuss phase just finished, start auto-mode if (checkAutoStartAfterDiscuss()) { depthVerifiedMilestones.clear(); diff --git a/src/resources/extensions/gsd/quick.ts b/src/resources/extensions/gsd/quick.ts index 299b48a2a..41269abba 100644 --- a/src/resources/extensions/gsd/quick.ts +++ b/src/resources/extensions/gsd/quick.ts @@ -107,10 +107,11 @@ export async function handleQuick( const skipBranch = git.prefs.isolation === "none"; let branchCreated = false; + let originalBranch: string | undefined; if (!skipBranch) { try { - const current = git.getCurrentBranch(); - if (current !== branchName) { + originalBranch = git.getCurrentBranch(); + if (originalBranch !== branchName) { // Auto-commit any dirty state before switching try { git.autoCommit("quick-task", `Q${taskNum}`, []); @@ -154,4 +155,57 @@ export async function handleQuick( }, { triggerTurn: true }, ); + + // Schedule branch merge-back after the quick task agent session ends. + // Without this, auto-mode resumes on the quick-task branch (#1269). + if (branchCreated && originalBranch) { + _pendingQuickBranchReturn = { + basePath, + originalBranch, + quickBranch: branchName, + taskNum, + slug, + description, + }; + } +} + +/** Pending quick-task branch return — consumed by cleanupQuickBranch(). */ +let _pendingQuickBranchReturn: { + basePath: string; + originalBranch: string; + quickBranch: string; + taskNum: number; + slug: string; + description: string; +} | null = null; + +/** + * Merge the quick-task branch back to the original branch and switch. + * Called from the agent_end handler after a quick task completes. + * Returns true if a branch return was performed. + */ +export function cleanupQuickBranch(): boolean { + if (!_pendingQuickBranchReturn) return false; + const { basePath, originalBranch, quickBranch, taskNum, slug, description } = _pendingQuickBranchReturn; + _pendingQuickBranchReturn = null; + + try { + // Auto-commit any remaining work + try { runGit(basePath, ["add", "-A"]); } catch {} + try { runGit(basePath, ["commit", "-m", `quick(Q${taskNum}): ${slug}`]); } catch {} + + // Switch back and merge + runGit(basePath, ["checkout", originalBranch]); + try { + runGit(basePath, ["merge", "--squash", quickBranch]); + runGit(basePath, ["commit", "-m", `quick(Q${taskNum}): ${description.slice(0, 72)}`]); + } catch { /* merge conflict or nothing — non-fatal */ } + + // Clean up quick branch + try { runGit(basePath, ["branch", "-D", quickBranch]); } catch {} + return true; + } catch { + return false; + } }