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..f26eb8043 --- /dev/null +++ b/codev/projects/bugfix-804-vscode-don-t-force-create-a-se/status.yaml @@ -0,0 +1,17 @@ +id: bugfix-804 +title: vscode-don-t-force-create-a-se +protocol: bugfix +phase: pr +plan_phases: [] +current_plan_phase: null +gates: + pr: + 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:59:28.780Z' +pr_ready_for_human: false 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 });