From 2ff6e2557678258bacbb04eb30b19bf765fd5ec0 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Sat, 13 Jun 2026 20:52:01 +1000 Subject: [PATCH 1/6] chore(porch): bugfix-804 init bugfix --- .../status.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml diff --git a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml new file mode 100644 index 000000000..e89b03c1f --- /dev/null +++ b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml @@ -0,0 +1,14 @@ +id: bugfix-804 +title: vscode-don-t-force-create-a-se +protocol: bugfix +phase: investigate +plan_phases: [] +current_plan_phase: null +gates: + pr: + status: pending +iteration: 1 +build_complete: false +history: [] +started_at: '2026-06-13T10:52:01.508Z' +updated_at: '2026-06-13T10:52:01.509Z' From bbe4a288005649b470c62fe924706a7cc7b6acc4 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Sat, 13 Jun 2026 20:54:10 +1000 Subject: [PATCH 2/6] chore(porch): bugfix-804 fix phase-transition --- .../bugfix-804-vscode-don-t-force-create-a-se/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml index e89b03c1f..637cc5db0 100644 --- a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml +++ b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml @@ -1,7 +1,7 @@ id: bugfix-804 title: vscode-don-t-force-create-a-se protocol: bugfix -phase: investigate +phase: fix plan_phases: [] current_plan_phase: null gates: @@ -11,4 +11,4 @@ iteration: 1 build_complete: false history: [] started_at: '2026-06-13T10:52:01.508Z' -updated_at: '2026-06-13T10:52:01.509Z' +updated_at: '2026-06-13T10:54:09.955Z' From 5d7400ee21414c52eec03d7d8758c15ef8034c21 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Sat, 13 Jun 2026 20:54:58 +1000 Subject: [PATCH 3/6] [Bugfix #804] vscode: attach builder terminals to second editor group only if it exists openTerminal's else-branch (builder/shell types) unconditionally targeted vscode.ViewColumn.Two. Because that column is fixed by ordinal, VS Code force-created a second editor group whenever the user had only one open, reshaping their layout on every spawn. Now the branch checks vscode.window.tabGroups.all.length: it targets ViewColumn.Two only when a second group already exists, else falls back to ViewColumn.One (the first/default group). Architect (ViewColumn.One) and dev/panel terminals are untouched. Adds 3 source-level regression tests matching this file's existing pattern. --- codev/state/bugfix-804_thread.md | 23 +++++++++++++++ .../src/__tests__/terminal-manager.test.ts | 28 +++++++++++++++++++ packages/vscode/src/terminal-manager.ts | 13 ++++++++- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 codev/state/bugfix-804_thread.md diff --git a/codev/state/bugfix-804_thread.md b/codev/state/bugfix-804_thread.md new file mode 100644 index 000000000..d45f0abc6 --- /dev/null +++ b/codev/state/bugfix-804_thread.md @@ -0,0 +1,23 @@ +# bugfix-804 — vscode: don't force-create a second editor group for builder terminals + +## Investigate + +Root cause: `packages/vscode/src/terminal-manager.ts` `openTerminal()` else-branch +unconditionally sets `location = { viewColumn: vscode.ViewColumn.Two }` for builder/shell +terminals. `ViewColumn.Two` is fixed by ordinal, so VS Code creates a second editor group +on demand when only one group exists — reshaping the user's layout. + +Fix: when the else-branch resolves, pick Two only if ≥2 tab groups already exist, else One. +Architect (`ViewColumn.One`) and dev/panel terminals untouched. + +Test pattern: `terminal-manager.test.ts` uses source-level regex assertions (full +TerminalManager needs heavy vscode mocking). Regression test follows same pattern. + +## Implement (done) + +- `terminal-manager.ts`: else-branch now computes `hasSecondGroup = + vscode.window.tabGroups.all.length >= 2`; Two when true, One otherwise. Used + if/else (not the issue's proposed ternary). Architect/dev/panel untouched. +- Added 3 source-level regression tests (#804 block). +- `pnpm test:unit terminal-manager` → 15 passed. `pnpm check-types` → clean. +- vscode-extension-only change; no codev-skeleton mirror needed. diff --git a/packages/vscode/src/__tests__/terminal-manager.test.ts b/packages/vscode/src/__tests__/terminal-manager.test.ts index 603a65e5f..51f2cbea8 100644 --- a/packages/vscode/src/__tests__/terminal-manager.test.ts +++ b/packages/vscode/src/__tests__/terminal-manager.test.ts @@ -104,6 +104,34 @@ describe('PIR #982 — actionable recovery for a missing terminal', () => { }); }); +describe('#804 — builder/shell terminals do not force-create a second editor group', () => { + // The else-branch of openTerminal's location resolution (builder + shell + // types) must attach to ViewColumn.Two ONLY when a second tab group already + // exists, else fall back to ViewColumn.One — otherwise VS Code spawns a new + // group on demand, reshaping a single-column user's layout. Source-level per + // this file's harness rationale (constructing TerminalManager needs heavy + // vscode mocking). + const elseBranch = + TM_SRC.split("type === 'architect'")[1]?.split('createTerminal')[0] ?? ''; + + it('gates the second-group target on existing tab groups', () => { + expect(elseBranch).toMatch(/vscode\.window\.tabGroups\.all\.length >= 2/); + }); + + it('uses ViewColumn.Two when a second group exists, ViewColumn.One otherwise', () => { + expect(elseBranch).toMatch(/location = \{ viewColumn: vscode\.ViewColumn\.Two \}/); + expect(elseBranch).toMatch(/location = \{ viewColumn: vscode\.ViewColumn\.One \}/); + }); + + it('no longer unconditionally targets ViewColumn.Two for builder/shell terminals', () => { + // Regression guard: the pre-#804 code set `location = { viewColumn: + // vscode.ViewColumn.Two }` with no surrounding group-count check. The fix + // must keep that assignment behind the `hasSecondGroup` conditional. + expect(elseBranch).toMatch(/const hasSecondGroup = vscode\.window\.tabGroups\.all\.length >= 2/); + expect(elseBranch).toMatch(/if \(hasSecondGroup\)/); + }); +}); + describe('#921 — dev surface refresh on manual terminal close', () => { // Regression guard: a dev terminal closed via the generic onDidCloseTerminal // path (tab ✕ / process exit) must clear devStartedAt AND re-fire diff --git a/packages/vscode/src/terminal-manager.ts b/packages/vscode/src/terminal-manager.ts index dce37976f..4fe52b134 100644 --- a/packages/vscode/src/terminal-manager.ts +++ b/packages/vscode/src/terminal-manager.ts @@ -469,7 +469,18 @@ export class TerminalManager { } else if (type === 'architect') { location = { viewColumn: vscode.ViewColumn.One }; } else { - location = { viewColumn: vscode.ViewColumn.Two }; + // Builder/shell terminals prefer the second editor group so they live + // beside the architect's pane. But `ViewColumn.Two` is fixed by ordinal: + // targeting it when only one group is open forces VS Code to spawn a new + // group, reshaping the user's layout (#804). Attach to the second group + // only when it already exists; otherwise fall back to the first/default + // group so single-column users stay undisturbed. + const hasSecondGroup = vscode.window.tabGroups.all.length >= 2; + if (hasSecondGroup) { + location = { viewColumn: vscode.ViewColumn.Two }; + } else { + location = { viewColumn: vscode.ViewColumn.One }; + } } const terminal = vscode.window.createTerminal({ name, pty, location, iconPath: this.iconPath }); From bab84151203732d73e65098be8cbf506d99d0aad Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Sat, 13 Jun 2026 20:55:27 +1000 Subject: [PATCH 4/6] chore(porch): bugfix-804 pr phase-transition --- .../bugfix-804-vscode-don-t-force-create-a-se/status.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml index 637cc5db0..f6c82ec30 100644 --- a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml +++ b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml @@ -1,7 +1,7 @@ id: bugfix-804 title: vscode-don-t-force-create-a-se protocol: bugfix -phase: fix +phase: pr plan_phases: [] current_plan_phase: null gates: @@ -11,4 +11,4 @@ iteration: 1 build_complete: false history: [] started_at: '2026-06-13T10:52:01.508Z' -updated_at: '2026-06-13T10:54:09.955Z' +updated_at: '2026-06-13T10:55:27.806Z' From 0ea40343e172501e2991fb3ab54cb928dc3b2153 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Sat, 13 Jun 2026 20:56:14 +1000 Subject: [PATCH 5/6] chore(porch): bugfix-804 pr gate-requested --- .../bugfix-804-vscode-don-t-force-create-a-se/status.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml index f6c82ec30..cf879dae7 100644 --- a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml +++ b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml @@ -7,8 +7,10 @@ current_plan_phase: null gates: pr: status: pending + requested_at: '2026-06-13T10:56:14.113Z' iteration: 1 build_complete: false history: [] started_at: '2026-06-13T10:52:01.508Z' -updated_at: '2026-06-13T10:55:27.806Z' +updated_at: '2026-06-13T10:56:14.114Z' +pr_ready_for_human: true From 164c2cc731ff76a0a89b18bd333dbf4b68bdd8a5 Mon Sep 17 00:00:00 2001 From: Amr Elsayed Date: Sat, 13 Jun 2026 20:59:28 +1000 Subject: [PATCH 6/6] chore(porch): bugfix-804 pr gate-approved --- .../bugfix-804-vscode-don-t-force-create-a-se/status.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml index cf879dae7..f26eb8043 100644 --- a/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml +++ b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml @@ -6,11 +6,12 @@ plan_phases: [] current_plan_phase: null gates: pr: - status: pending + status: approved requested_at: '2026-06-13T10:56:14.113Z' + approved_at: '2026-06-13T10:59:28.779Z' iteration: 1 build_complete: false history: [] started_at: '2026-06-13T10:52:01.508Z' -updated_at: '2026-06-13T10:56:14.114Z' -pr_ready_for_human: true +updated_at: '2026-06-13T10:59:28.780Z' +pr_ready_for_human: false