Skip to content

Commit 3660f19

Browse files
authored
fix: auto-stash during /orch-integrate + clearer completion message (#89)
* fix: clearer batch completion message with integration guidance Simplified to two options (apply now vs PR for review). Removed --merge from default message (shown in error fallback if ff fails). Added 'Your branch was not modified' to reassure users. * fix: auto-stash dirty working tree during /orch-integrate + clearer completion message Three changes: 1. /orch-integrate stashes dirty working tree before ff/merge and pops after. Workspace mode leaves STATUS.md modifications in the working tree for dashboard visibility — these blocked ff with 'local changes would be overwritten'. 2. Batch completion message simplified to two options (apply now vs PR). Removed --merge from default display (shown in ff error fallback). Added 'Your branch was not modified' reassurance. 3. Updated tests for new stash-check git call ordering.
1 parent 6695195 commit 3660f19

3 files changed

Lines changed: 45 additions & 9 deletions

File tree

extensions/taskplane/extension.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,24 @@ export function executeIntegration(
327327
const { orchBranch, currentBranch, batchId } = context;
328328

329329
if (mode === "ff") {
330-
// Fast-forward merge
330+
// Fast-forward merge.
331+
// Stash any dirty working tree files first — workspace mode leaves
332+
// STATUS.md modifications in the working tree for dashboard visibility.
333+
// These would block ff if the orch branch has different versions.
334+
let stashed = false;
335+
const statusCheck = deps.runGit(["status", "--porcelain"]);
336+
if (statusCheck.ok && statusCheck.stdout.trim()) {
337+
deps.runGit(["stash", "push", "--include-untracked", "-m", `orch-integrate-autostash-${batchId}`]);
338+
stashed = true;
339+
}
340+
331341
const result = deps.runGit(["merge", "--ff-only", orchBranch]);
342+
343+
// Always pop stash if we stashed, regardless of ff result
344+
if (stashed) {
345+
deps.runGit(["stash", "pop"]);
346+
}
347+
332348
if (!result.ok) {
333349
return {
334350
success: false,
@@ -359,7 +375,20 @@ export function executeIntegration(
359375
}
360376

361377
if (mode === "merge") {
378+
// Stash dirty working tree (same as ff mode — workspace STATUS.md artifacts)
379+
let mergeStashed = false;
380+
const mergeStatusCheck = deps.runGit(["status", "--porcelain"]);
381+
if (mergeStatusCheck.ok && mergeStatusCheck.stdout.trim()) {
382+
deps.runGit(["stash", "push", "--include-untracked", "-m", `orch-integrate-autostash-${batchId}`]);
383+
mergeStashed = true;
384+
}
385+
362386
const result = deps.runGit(["merge", orchBranch, "--no-edit"]);
387+
// Pop stash regardless of merge result
388+
if (mergeStashed) {
389+
deps.runGit(["stash", "pop"]);
390+
}
391+
363392
if (!result.ok) {
364393
return {
365394
success: false,

extensions/taskplane/messages.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@ export const ORCH_MESSAGES = {
5050
}
5151
if (orchBranch && succeeded > 0) {
5252
lines.push("");
53-
lines.push(` ℹ Orch branch: ${orchBranch}`);
53+
lines.push(` ℹ All work is on orch branch: ${orchBranch}`);
54+
lines.push(` Your ${baseBranch || "working"} branch was not modified.`);
5455
if (baseBranch) {
55-
lines.push(` Review changes: git log ${baseBranch}..${orchBranch}`);
56+
lines.push(` Preview: git log ${baseBranch}..${orchBranch}`);
5657
}
57-
lines.push(" Next steps:");
58-
lines.push(" • /orch-integrate — fast-forward into your branch");
59-
lines.push(" • /orch-integrate --merge — merge (if branches diverged)");
60-
lines.push(" • /orch-integrate --pr — push and open a PR");
58+
lines.push("");
59+
lines.push(" To apply the changes:");
60+
lines.push(" • /orch-integrate Apply now (fast-forward, recommended)");
61+
lines.push(" • /orch-integrate --pr Push orch branch & open a PR for team review");
6162
}
6263
return lines.join("\n");
6364
},

extensions/tests/orch-integrate.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,10 @@ describe("executeIntegration — fast-forward mode", () => {
675675
},
676676
});
677677
executeIntegration("ff", makeContext(), deps);
678-
expect(gitCalls[0]).toEqual(["merge", "--ff-only", "orch/henry-20260318T140000"]);
678+
// First call is status --porcelain (stash check), then merge
679+
expect(gitCalls[0]).toEqual(["status", "--porcelain"]);
680+
const mergeCall = gitCalls.find(c => c[0] === "merge");
681+
expect(mergeCall).toEqual(["merge", "--ff-only", "orch/henry-20260318T140000"]);
679682
});
680683

681684
it("returns error when ff fails (diverged branches)", () => {
@@ -736,7 +739,10 @@ describe("executeIntegration — merge mode", () => {
736739
},
737740
});
738741
executeIntegration("merge", makeContext(), deps);
739-
expect(gitCalls[0]).toEqual(["merge", "orch/henry-20260318T140000", "--no-edit"]);
742+
// First call is status --porcelain (stash check), then merge
743+
expect(gitCalls[0]).toEqual(["status", "--porcelain"]);
744+
const mergeCall = gitCalls.find(c => c[0] === "merge");
745+
expect(mergeCall).toEqual(["merge", "orch/henry-20260318T140000", "--no-edit"]);
740746
});
741747

742748
it("returns error when merge fails (conflict)", () => {

0 commit comments

Comments
 (0)