diff --git a/vscode/src/panel/KanbanPanel.ts b/vscode/src/panel/KanbanPanel.ts
index 3b7fca0..a82f95b 100644
--- a/vscode/src/panel/KanbanPanel.ts
+++ b/vscode/src/panel/KanbanPanel.ts
@@ -932,6 +932,7 @@ export class KanbanWebviewPanel {
worktreePreRemoveScript: s.worktreePreRemoveScript,
implTabPreCreateScript: s.implTabPreCreateScript,
implTabPostCloseScript: s.implTabPostCloseScript,
+ splitNewTerminals: s.splitNewTerminals,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath: await getEffectiveCommitProfilePath(this.context),
prDiffSummaryProfilePath: await getEffectivePrDiffSummaryProfilePath(this.context),
@@ -1010,6 +1011,7 @@ export class KanbanWebviewPanel {
worktreePreRemoveScript: s.worktreePreRemoveScript,
implTabPreCreateScript: s.implTabPreCreateScript,
implTabPostCloseScript: s.implTabPostCloseScript,
+ splitNewTerminals: s.splitNewTerminals,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath: await getEffectiveCommitProfilePath(this.context),
prDiffSummaryProfilePath: await getEffectivePrDiffSummaryProfilePath(this.context),
diff --git a/vscode/src/panel/handlers/settings.ts b/vscode/src/panel/handlers/settings.ts
index 9aa24ef..5040aeb 100644
--- a/vscode/src/panel/handlers/settings.ts
+++ b/vscode/src/panel/handlers/settings.ts
@@ -38,6 +38,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
+ splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -116,6 +117,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
worktreePreRemoveScript: trimmedPreRemove,
implTabPreCreateScript: trimmedImplPre,
implTabPostCloseScript: trimmedImplPost,
+ splitNewTerminals: payload.splitNewTerminals,
conflictResolutionProfilePath: trimmedConflictProfile,
commitProfilePath: trimmedCommitProfile,
prDiffSummaryProfilePath: trimmedPrDiffSummaryProfile,
@@ -144,6 +146,7 @@ export async function handleSettingsSave(panel: KanbanWebviewPanel, payload: {
worktreePreRemoveScript: trimmedPreRemove,
implTabPreCreateScript: trimmedImplPre,
implTabPostCloseScript: trimmedImplPost,
+ splitNewTerminals: payload.splitNewTerminals,
conflictResolutionProfilePath: trimmedConflictProfile,
commitProfilePath: trimmedCommitProfile,
prDiffSummaryProfilePath: trimmedPrDiffSummaryProfile,
@@ -249,6 +252,7 @@ export async function handleEditSettingsRequest(panel: KanbanWebviewPanel): Prom
worktreePreRemoveScript: s.worktreePreRemoveScript,
implTabPreCreateScript: s.implTabPreCreateScript,
implTabPostCloseScript: s.implTabPostCloseScript,
+ splitNewTerminals: s.splitNewTerminals,
conflictResolutionProfilePath: s.conflictResolutionProfilePath,
commitProfilePath,
prDiffSummaryProfilePath,
diff --git a/vscode/src/panel/handlers/terminals.test.ts b/vscode/src/panel/handlers/terminals.test.ts
new file mode 100644
index 0000000..d1522cf
--- /dev/null
+++ b/vscode/src/panel/handlers/terminals.test.ts
@@ -0,0 +1,11 @@
+import { describe, expect, it } from 'vitest'
+import { terminalEditorColumn } from '../terminalColumn'
+
+describe('terminalEditorColumn', () => {
+ it('分屏 → 右侧第 2 栏', () => {
+ expect(terminalEditorColumn(true)).toBe(2)
+ })
+ it('不分屏 → 当前栏(只加标签)', () => {
+ expect(terminalEditorColumn(false)).toBe(-1)
+ })
+})
diff --git a/vscode/src/panel/handlers/terminals.ts b/vscode/src/panel/handlers/terminals.ts
index 88fcbdf..2a74786 100644
--- a/vscode/src/panel/handlers/terminals.ts
+++ b/vscode/src/panel/handlers/terminals.ts
@@ -4,16 +4,14 @@ import type {
} from 'vscode'
import type { Issue } from '../../gitea/types'
import type { KanbanWebviewPanel } from '../KanbanPanel'
-import { ViewColumn, window } from 'vscode'
+import { window } from 'vscode'
import { logger } from '../../logging/logger'
+import { getSettings } from '../../settings/store'
+import { terminalEditorColumn } from '../terminalColumn'
export function resolveTerminalLocation(panel: KanbanWebviewPanel | null, preserveFocus: boolean): TerminalEditorLocationOptions {
- void panel
- // Pin all plugin-managed terminals to editor group 2 (right side of the
- // kanban panel in column 1). VS Code creates the group on demand if it
- // doesn't exist yet, and stacks new terminals as tabs in that group when
- // it does — exactly what we want, no manual scan of existing tabs needed.
- return { viewColumn: ViewColumn.Two, preserveFocus }
+ const split = panel ? getSettings(panel.context).splitNewTerminals : true
+ return { viewColumn: terminalEditorColumn(split), preserveFocus }
}
/**
diff --git a/vscode/src/panel/messages.ts b/vscode/src/panel/messages.ts
index 1f9cdf5..8b57807 100644
--- a/vscode/src/panel/messages.ts
+++ b/vscode/src/panel/messages.ts
@@ -84,6 +84,7 @@ export type ExtensionToWebview
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
+ splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -162,6 +163,7 @@ export type WebviewToExtension
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
+ splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
diff --git a/vscode/src/panel/terminalColumn.ts b/vscode/src/panel/terminalColumn.ts
new file mode 100644
index 0000000..45ac4b5
--- /dev/null
+++ b/vscode/src/panel/terminalColumn.ts
@@ -0,0 +1,7 @@
+/**
+ * 会话终端落在编辑区哪一栏。
+ * 数值对齐 VS Code ViewColumn:2 = Two(右侧分屏),-1 = Active(当前栏只加标签)。
+ */
+export function terminalEditorColumn(split: boolean): 2 | -1 {
+ return split ? 2 : -1
+}
diff --git a/vscode/src/settings/store.ts b/vscode/src/settings/store.ts
index 734468f..5f08099 100644
--- a/vscode/src/settings/store.ts
+++ b/vscode/src/settings/store.ts
@@ -159,6 +159,10 @@ export interface Settings {
* Same env vars as the worktree hooks.
*/
implTabPostCloseScript: string
+ /**
+ * 新开会话终端是否分到右侧一栏。关掉则在当前编辑组加标签,适合小屏。
+ */
+ splitNewTerminals: boolean
/**
* YouTrack instance base URL (e.g. `https://ziwuxian.youtrack.cloud`). Empty
* string means "YouTrack source disabled" — the loader returns no issues.
@@ -264,6 +268,7 @@ function defaults(ctx: ExtensionContext): Settings {
worktreePreRemoveScript: '',
implTabPreCreateScript: '',
implTabPostCloseScript: '',
+ splitNewTerminals: true,
youtrackBaseUrl: '',
youtrackProjectShortName: '',
youtrackCloseCommand: '',
@@ -350,6 +355,9 @@ export function getSettings(ctx: ExtensionContext): Settings {
const implTabPostCloseScript = typeof stored.implTabPostCloseScript === 'string'
? stored.implTabPostCloseScript
: base.implTabPostCloseScript
+ const splitNewTerminals = typeof stored.splitNewTerminals === 'boolean'
+ ? stored.splitNewTerminals
+ : base.splitNewTerminals
// YouTrack config: '' is meaningful (= "source disabled" / "auto-detect close
// command"), so don't coerce. Non-string legacy values collapse to ''.
const youtrackBaseUrl = typeof stored.youtrackBaseUrl === 'string'
@@ -405,6 +413,7 @@ export function getSettings(ctx: ExtensionContext): Settings {
worktreePreRemoveScript,
implTabPreCreateScript,
implTabPostCloseScript,
+ splitNewTerminals,
youtrackBaseUrl,
youtrackProjectShortName,
youtrackCloseCommand,
diff --git a/vscode/webview-ui/src/App.tsx b/vscode/webview-ui/src/App.tsx
index d18ad65..a0315c2 100644
--- a/vscode/webview-ui/src/App.tsx
+++ b/vscode/webview-ui/src/App.tsx
@@ -534,6 +534,7 @@ export function App() {
initialWorktreePreRemoveScript={settings?.worktreePreRemoveScript ?? ''}
initialImplTabPreCreateScript={settings?.implTabPreCreateScript ?? ''}
initialImplTabPostCloseScript={settings?.implTabPostCloseScript ?? ''}
+ initialSplitNewTerminals={settings?.splitNewTerminals ?? true}
initialConflictResolutionProfilePath={settings?.conflictResolutionProfilePath ?? ''}
initialCommitProfilePath={settings?.commitProfilePath ?? ''}
initialPrDiffSummaryProfilePath={settings?.prDiffSummaryProfilePath ?? ''}
diff --git a/vscode/webview-ui/src/components/SettingsModal.tsx b/vscode/webview-ui/src/components/SettingsModal.tsx
index 0a31e08..737af49 100644
--- a/vscode/webview-ui/src/components/SettingsModal.tsx
+++ b/vscode/webview-ui/src/components/SettingsModal.tsx
@@ -36,6 +36,7 @@ interface SubmitValues {
worktreePreRemoveScript: string
implTabPreCreateScript: string
implTabPostCloseScript: string
+ splitNewTerminals: boolean
conflictResolutionProfilePath: string
commitProfilePath: string
prDiffSummaryProfilePath: string
@@ -85,6 +86,7 @@ export interface SettingsModalProps {
initialWorktreePreRemoveScript: string
initialImplTabPreCreateScript: string
initialImplTabPostCloseScript: string
+ initialSplitNewTerminals: boolean
initialConflictResolutionProfilePath: string
initialCommitProfilePath: string
initialPrDiffSummaryProfilePath: string
@@ -170,6 +172,7 @@ export function SettingsModal({
initialWorktreePreRemoveScript,
initialImplTabPreCreateScript,
initialImplTabPostCloseScript,
+ initialSplitNewTerminals,
initialConflictResolutionProfilePath,
initialCommitProfilePath,
initialPrDiffSummaryProfilePath,
@@ -207,6 +210,7 @@ export function SettingsModal({
const [worktreePreRemoveScript, setWorktreePreRemoveScript] = useState(initialWorktreePreRemoveScript)
const [implTabPreCreateScript, setImplTabPreCreateScript] = useState(initialImplTabPreCreateScript)
const [implTabPostCloseScript, setImplTabPostCloseScript] = useState(initialImplTabPostCloseScript)
+ const [splitNewTerminals, setSplitNewTerminals] = useState(initialSplitNewTerminals)
const [conflictResolutionProfilePath, setConflictResolutionProfilePath] = useState(initialConflictResolutionProfilePath)
const [commitProfilePath, setCommitProfilePath] = useState(initialCommitProfilePath)
const [prDiffSummaryProfilePath, setPrDiffSummaryProfilePath] = useState(initialPrDiffSummaryProfilePath)
@@ -246,6 +250,7 @@ export function SettingsModal({
setWorktreePreRemoveScript(initialWorktreePreRemoveScript)
setImplTabPreCreateScript(initialImplTabPreCreateScript)
setImplTabPostCloseScript(initialImplTabPostCloseScript)
+ setSplitNewTerminals(initialSplitNewTerminals)
setConflictResolutionProfilePath(initialConflictResolutionProfilePath)
setCommitProfilePath(initialCommitProfilePath)
setPrDiffSummaryProfilePath(initialPrDiffSummaryProfilePath)
@@ -336,6 +341,7 @@ export function SettingsModal({
worktreePreRemoveScript: worktreePreRemoveScript.trim(),
implTabPreCreateScript: implTabPreCreateScript.trim(),
implTabPostCloseScript: implTabPostCloseScript.trim(),
+ splitNewTerminals,
// 冲突解决 profile:空串 = 用 DEFAULT_PROFILE_PATH
conflictResolutionProfilePath: conflictResolutionProfilePath.trim(),
// 提交代码 profile:空串 = 未配置 → 提交严格失败
@@ -910,6 +916,19 @@ export function SettingsModal({
{activeGroup === 'hooks' && (
<>
+
+
+