@brimveyn/aimux 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +3 -0
  2. package/package.json +2 -2
  3. package/src/app-runtime/backend-attach-runtime.ts +6 -0
  4. package/src/app-runtime/backend-runtime-events.ts +21 -21
  5. package/src/app-runtime/side-effects.ts +43 -12
  6. package/src/app-runtime/use-backend-runtime.ts +2 -20
  7. package/src/app-runtime/use-directory-search.ts +6 -1
  8. package/src/app.tsx +6 -1
  9. package/src/config.ts +28 -1
  10. package/src/daemon/daemon.ts +197 -15
  11. package/src/daemon/session-manager.ts +9 -0
  12. package/src/daemon/session-registry.ts +5 -5
  13. package/src/git/diff-hash.ts +10 -0
  14. package/src/index.tsx +10 -2
  15. package/src/input/keymap/help-entries.ts +5 -5
  16. package/src/input/modes/bridge.ts +5 -8
  17. package/src/input/modes/transitions.ts +15 -23
  18. package/src/input/modes/types.ts +3 -5
  19. package/src/ipc/protocol.ts +49 -5
  20. package/src/platform/project-search.ts +45 -12
  21. package/src/pty/assistant-status-detection-loop.ts +192 -0
  22. package/src/pty/assistant-status-detector.ts +226 -0
  23. package/src/pty/pty-manager.ts +3 -37
  24. package/src/session-backend/bootstrap.ts +4 -1
  25. package/src/session-backend/local-session-backend.ts +43 -56
  26. package/src/session-backend/remote-session-backend.ts +15 -0
  27. package/src/session-backend/types.ts +10 -1
  28. package/src/state/git-tree.ts +42 -16
  29. package/src/state/reducers/diff-cache.ts +64 -0
  30. package/src/state/reducers/git-mode-state.ts +91 -33
  31. package/src/state/reducers/git-panel-state.ts +33 -2
  32. package/src/state/reducers/modal-state.ts +91 -134
  33. package/src/state/reducers/session-state.ts +13 -6
  34. package/src/state/reducers/tab-state.ts +0 -10
  35. package/src/state/selectors.ts +12 -0
  36. package/src/state/session-persistence.ts +20 -15
  37. package/src/state/store.ts +13 -3
  38. package/src/state/types.ts +87 -14
  39. package/src/ui/breaking-update-screen.tsx +31 -0
  40. package/src/ui/components/bare-input.tsx +44 -0
  41. package/src/ui/components/create-session-modal.tsx +16 -8
  42. package/src/ui/components/diff-renderer/fold-strip.tsx +5 -13
  43. package/src/ui/components/diff-renderer/pierre-diff.tsx +9 -31
  44. package/src/ui/components/diff-renderer/prepare-diff.ts +66 -0
  45. package/src/ui/components/diff-renderer/split-view.tsx +35 -16
  46. package/src/ui/components/diff-renderer/stacked-view.tsx +30 -12
  47. package/src/ui/components/diff-renderer/use-diff-prefetch.ts +191 -0
  48. package/src/ui/components/diff-renderer/use-diff-preparation.ts +106 -0
  49. package/src/ui/components/git-pane-widget.tsx +2 -0
  50. package/src/ui/components/git-panel.tsx +27 -10
  51. package/src/ui/components/git-view.tsx +23 -9
  52. package/src/ui/components/help-modal.tsx +45 -160
  53. package/src/ui/components/input-field.tsx +6 -2
  54. package/src/ui/components/list-item.tsx +36 -28
  55. package/src/ui/components/modal-shell.tsx +51 -13
  56. package/src/ui/components/new-tab-modal.tsx +78 -45
  57. package/src/ui/components/picker.tsx +179 -0
  58. package/src/ui/components/session-bar.tsx +47 -21
  59. package/src/ui/components/session-picker-modal.tsx +58 -56
  60. package/src/ui/components/sidebar.tsx +49 -22
  61. package/src/ui/components/snippet-picker-modal.tsx +43 -34
  62. package/src/ui/components/status-bar.tsx +3 -2
  63. package/src/ui/components/surface.tsx +11 -8
  64. package/src/ui/components/tab-item.tsx +38 -22
  65. package/src/ui/components/terminal-pane.tsx +8 -8
  66. package/src/ui/components/theme-picker-modal.tsx +51 -91
  67. package/src/ui/root.tsx +14 -23
  68. package/src/ui/status-bar-model.ts +5 -5
  69. package/src/ui/theme-store.ts +26 -2
  70. package/src/ui/theme.ts +9 -1
  71. package/src/ui/components/modal-filter-bar.tsx +0 -19
package/README.md CHANGED
@@ -202,6 +202,9 @@ not collide with a globally installed `aimux` instance.
202
202
  and focusing on the first change rather than the top of the file.
203
203
  - [shiki](https://shiki.style) — syntax highlighting for the git diff view
204
204
  and the source of the bundled theme catalog.
205
+ - [herdr](https://github.com/ogulcancelik/herdr) by @ogulcancelik — the
206
+ per-CLI assistant status heuristics (working / waiting-input / idle)
207
+ used in the session bar are adapted from herdr's `detect.rs` rule tables.
205
208
 
206
209
  ## License
207
210
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brimveyn/aimux",
3
- "version": "1.6.1",
3
+ "version": "1.7.0",
4
4
  "description": "A terminal multiplexer for AI CLIs. Run Claude, Codex, OpenCode side-by-side with tabbed navigation, split panes, and persistent sessions.",
5
5
  "keywords": [
6
6
  "ai",
@@ -61,7 +61,7 @@
61
61
  "generate-themes": "bun run scripts/generate-themes.ts"
62
62
  },
63
63
  "dependencies": {
64
- "@brimveyn/aimux-config": "0.4.1",
64
+ "@brimveyn/aimux-config": "0.4.3",
65
65
  "@opentui/core": "^0.1.90",
66
66
  "@opentui/react": "^0.1.90",
67
67
  "@xterm/headless": "^6.0.0",
@@ -48,6 +48,12 @@ function hydrateAttachedSession(
48
48
  tabs: result.tabs,
49
49
  type: 'hydrate-workspace',
50
50
  })
51
+ // Dispatch the session-status snapshot *after* hydrate-workspace so
52
+ // sidebar chips reflect per-session state on attach without waiting
53
+ // for the next daemon-side status transition.
54
+ for (const entry of result.initialSessionStatuses) {
55
+ dispatch({ sessionId: entry.sessionId, status: entry.status, type: 'set-session-status' })
56
+ }
51
57
  resizeSnapshotPanes(workspaceSnapshot, layoutRef, backend)
52
58
  return
53
59
  }
@@ -1,25 +1,22 @@
1
1
  import type { MutableRefObject } from 'react'
2
2
 
3
3
  import type { SessionBackend } from '../session-backend/types'
4
- import type { AppAction, TabSession, TerminalModeState } from '../state/types'
4
+ import type {
5
+ AppAction,
6
+ SessionStatus,
7
+ TabActivity,
8
+ TabSession,
9
+ TerminalModeState,
10
+ } from '../state/types'
5
11
 
6
12
  import { logInputDebug } from '../debug/input-log'
7
13
  import { type TabRuntimeTimeouts } from './tab-runtime-timeouts'
8
14
 
9
- const IDLE_ACTIVITY_TIMEOUT_MS = 2_000
10
-
11
15
  interface BindBackendRuntimeEventsOptions {
12
16
  backend: SessionBackend
13
17
  dispatch: (action: AppAction) => void
14
18
  resizingRef: MutableRefObject<boolean>
15
- timeouts: Pick<
16
- TabRuntimeTimeouts,
17
- | 'clearIdleTimer'
18
- | 'clearStartupGrace'
19
- | 'isStartupGraceActive'
20
- | 'scheduleIdle'
21
- | 'clearAllTimers'
22
- >
19
+ timeouts: Pick<TabRuntimeTimeouts, 'clearIdleTimer' | 'clearStartupGrace' | 'clearAllTimers'>
23
20
  }
24
21
 
25
22
  function clearTabRuntimeState(
@@ -58,19 +55,14 @@ export function bindBackendRuntimeEvents({
58
55
  type: 'replace-tab-viewport',
59
56
  viewport,
60
57
  })
61
- if (timeouts.isStartupGraceActive(tabId) || resizingRef.current) {
62
- return
63
- }
64
-
65
- dispatch({ activity: 'busy', tabId, type: 'set-tab-activity' })
66
- timeouts.scheduleIdle(tabId, IDLE_ACTIVITY_TIMEOUT_MS)
58
+ // Per-tab activity is driven by the backend's status-detection loop via
59
+ // the `tabActivity` event — no client-side idle timer needed.
67
60
  }
68
61
 
69
62
  const handleExit = (tabId: string, exitCode: number) => {
70
63
  logInputDebug('app.backend.event.exit', { exitCode, tabId })
71
64
  clearTabRuntimeState(timeouts, tabId)
72
- dispatch({ exitCode, status: 'exited', tabId, type: 'set-tab-status' })
73
- dispatch({ activity: undefined, tabId, type: 'set-tab-activity' })
65
+ dispatch({ tabId, type: 'close-tab' })
74
66
  }
75
67
 
76
68
  const handleError = (tabId: string, message: string) => {
@@ -79,14 +71,21 @@ export function bindBackendRuntimeEvents({
79
71
  dispatch({ message, tabId, type: 'set-tab-error' })
80
72
  }
81
73
 
82
- const handleSessionActivity = (sessionId: string, busy: boolean) => {
83
- dispatch({ busy, sessionId, type: 'set-session-busy' })
74
+ const handleSessionActivity = (sessionId: string, status: SessionStatus) => {
75
+ logInputDebug('app.backend.event.sessionActivity', { sessionId, status })
76
+ dispatch({ sessionId, status, type: 'set-session-status' })
77
+ }
78
+
79
+ const handleTabActivity = (tabId: string, activity: TabActivity) => {
80
+ logInputDebug('app.backend.event.tabActivity', { activity, tabId })
81
+ dispatch({ activity, tabId, type: 'set-tab-activity' })
84
82
  }
85
83
 
86
84
  backend.on('render', handleRender)
87
85
  backend.on('exit', handleExit)
88
86
  backend.on('error', handleError)
89
87
  backend.on('sessionActivity', handleSessionActivity)
88
+ backend.on('tabActivity', handleTabActivity)
90
89
 
91
90
  return () => {
92
91
  timeouts.clearAllTimers()
@@ -94,6 +93,7 @@ export function bindBackendRuntimeEvents({
94
93
  backend.off('exit', handleExit)
95
94
  backend.off('error', handleError)
96
95
  backend.off('sessionActivity', handleSessionActivity)
96
+ backend.off('tabActivity', handleTabActivity)
97
97
  void backend.destroy(true)
98
98
  }
99
99
  }
@@ -24,7 +24,7 @@ import {
24
24
  type SplitDirection,
25
25
  splitNode,
26
26
  } from '../state/layout-tree'
27
- import { filterSessions, filterSnippets } from '../state/selectors'
27
+ import { filterAssistants, filterSessions, filterSnippets } from '../state/selectors'
28
28
  import { createDefaultTerminalModes } from '../state/terminal-modes'
29
29
  import {
30
30
  type AppAction,
@@ -36,7 +36,7 @@ import {
36
36
  import { saveCurrentWorkspace } from '../state/workspace-save'
37
37
  import { filterThemeIds } from '../ui/filter-themes'
38
38
  import { scrollGitDiff } from '../ui/git-view-controls'
39
- import { applyTheme } from '../ui/theme'
39
+ import { applyTheme, getTransparent, setTransparent } from '../ui/theme'
40
40
  import { type ThemeId } from '../ui/themes'
41
41
  import {
42
42
  handleCreateSessionEffect,
@@ -68,9 +68,10 @@ export interface SideEffectContext {
68
68
  }
69
69
 
70
70
  function getSelectedAssistantOption(state: AppState) {
71
- return (
72
- getAllAssistantOptions(state.customCommands)[state.modal.selectedIndex] ?? getAssistantOption(0)
73
- )
71
+ const all = getAllAssistantOptions(state.customCommands)
72
+ const filter = state.modal.type === 'new-tab' ? state.modal.editBuffer : null
73
+ const list = filterAssistants(all, filter)
74
+ return list[state.modal.selectedIndex] ?? list[0] ?? getAssistantOption(0)
74
75
  }
75
76
 
76
77
  function handleSessionSelection(ctx: SideEffectContext): void {
@@ -87,7 +88,7 @@ function handleSessionSelection(ctx: SideEffectContext): void {
87
88
  return
88
89
  }
89
90
 
90
- dispatch({ type: 'open-create-session-modal' })
91
+ dispatch({ returnToSessionPicker: true, type: 'open-create-session-modal' })
91
92
  }
92
93
 
93
94
  function handleSelectedSessionDelete(ctx: SideEffectContext): void {
@@ -143,24 +144,28 @@ function pasteSnippetToActiveGroup(ctx: SideEffectContext): void {
143
144
  }
144
145
  }
145
146
 
146
- function saveCustomCommandSelection(state: AppState): void {
147
- const option = getAllAssistantOptions(state.customCommands)[state.modal.selectedIndex]
148
- if (!option || state.modal.editBuffer === null) {
147
+ function saveCustomCommandSelection(ctx: SideEffectContext): void {
148
+ const { dispatch, state } = ctx
149
+ if (state.modal.type !== 'new-tab' || state.modal.editingCommand === null) {
149
150
  return
150
151
  }
152
+ const assistantId = state.modal.editingCommand
153
+ if (state.modal.editBuffer === null) return
151
154
 
152
155
  const trimmed = state.modal.editBuffer.trim()
153
156
  const newCustomCommands = { ...state.customCommands }
154
157
  if (trimmed) {
155
- newCustomCommands[option.id] = trimmed
158
+ newCustomCommands[assistantId] = trimmed
156
159
  } else {
157
- delete newCustomCommands[option.id]
160
+ delete newCustomCommands[assistantId]
158
161
  }
159
162
 
160
163
  saveConfig({
161
164
  ...loadConfig(),
162
165
  customCommands: newCustomCommands,
163
166
  })
167
+ dispatch({ customCommands: newCustomCommands, type: 'set-custom-commands' })
168
+ dispatch({ type: 'cancel-command-edit' })
164
169
  }
165
170
 
166
171
  function applyThemeEffect(
@@ -299,6 +304,7 @@ function launchAssistant(ctx: SideEffectContext, assistant: AssistantId): void {
299
304
  tabId: tab.id,
300
305
  })
301
306
  dispatch({ tab, type: 'add-tab' })
307
+ dispatch({ focusMode: 'terminal-input', type: 'set-focus-mode' })
302
308
  startTabSession(
303
309
  backend,
304
310
  dispatch,
@@ -435,7 +441,7 @@ export function executeSideEffect(effect: SideEffect, ctx: SideEffectContext): v
435
441
  return
436
442
  }
437
443
  case 'save-custom-command': {
438
- saveCustomCommandSelection(state)
444
+ saveCustomCommandSelection(ctx)
439
445
  return
440
446
  }
441
447
  case 'apply-theme': {
@@ -471,6 +477,7 @@ export function executeSideEffect(effect: SideEffect, ctx: SideEffectContext): v
471
477
  mode: persistedGitPane?.mode ?? 'embedded',
472
478
  position: persistedGitPane?.position ?? 'bottom',
473
479
  ratio: persistedGitPane?.ratio ?? 0.5,
480
+ treeCompaction: persistedGitPane?.treeCompaction,
474
481
  visible: persistedGitPane?.visible ?? true,
475
482
  },
476
483
  })
@@ -487,6 +494,24 @@ export function executeSideEffect(effect: SideEffect, ctx: SideEffectContext): v
487
494
  mode: persistedGitPane?.mode ?? 'embedded',
488
495
  position: persistedGitPane?.position ?? 'bottom',
489
496
  ratio: persistedGitPane?.ratio ?? 0.5,
497
+ treeCompaction: persistedGitPane?.treeCompaction,
498
+ visible: persistedGitPane?.visible ?? true,
499
+ },
500
+ })
501
+ return
502
+ }
503
+ case 'persist-git-tree-compaction': {
504
+ const config = loadConfig()
505
+ const persistedGitPane = config.gitPane
506
+ saveConfig({
507
+ ...config,
508
+ gitPane: {
509
+ diffModeRatio: persistedGitPane?.diffModeRatio,
510
+ fileListMode: persistedGitPane?.fileListMode,
511
+ mode: persistedGitPane?.mode ?? 'embedded',
512
+ position: persistedGitPane?.position ?? 'bottom',
513
+ ratio: persistedGitPane?.ratio ?? 0.5,
514
+ treeCompaction: effect.enabled,
490
515
  visible: persistedGitPane?.visible ?? true,
491
516
  },
492
517
  })
@@ -527,6 +552,12 @@ export function executeSideEffect(effect: SideEffect, ctx: SideEffectContext): v
527
552
  handleSwitchSessionByIndex(ctx, effect.index)
528
553
  return
529
554
  }
555
+ case 'toggle-transparent': {
556
+ const next = !getTransparent()
557
+ setTransparent(next)
558
+ saveConfig({ ...loadConfig(), themeTransparent: next })
559
+ return
560
+ }
530
561
  default:
531
562
  effect satisfies never
532
563
  }
@@ -36,14 +36,7 @@ export function useBackendRuntime({
36
36
  }: BackendRuntimeOptions): TabRuntimeControls {
37
37
  const attachRequestIdRef = useRef(0)
38
38
  const timeouts = useTabRuntimeTimeouts(dispatch)
39
- const {
40
- clearAllTimers,
41
- clearIdleTimer,
42
- clearStartupGrace,
43
- isStartupGraceActive,
44
- scheduleIdle,
45
- startStartupGrace,
46
- } = timeouts
39
+ const { clearAllTimers, clearIdleTimer, clearStartupGrace, startStartupGrace } = timeouts
47
40
 
48
41
  useEffect(() => {
49
42
  if (!currentSessionId) {
@@ -81,20 +74,9 @@ export function useBackendRuntime({
81
74
  clearAllTimers,
82
75
  clearIdleTimer,
83
76
  clearStartupGrace,
84
- isStartupGraceActive,
85
- scheduleIdle,
86
77
  },
87
78
  })
88
- }, [
89
- backend,
90
- clearAllTimers,
91
- clearIdleTimer,
92
- clearStartupGrace,
93
- dispatch,
94
- isStartupGraceActive,
95
- resizingRef,
96
- scheduleIdle,
97
- ])
79
+ }, [backend, clearAllTimers, clearIdleTimer, clearStartupGrace, dispatch, resizingRef])
98
80
 
99
81
  return {
100
82
  clearIdleTimer,
@@ -2,7 +2,7 @@ import { useEffect } from 'react'
2
2
 
3
3
  import type { AppAction, ModalState } from '../state/types'
4
4
 
5
- import { searchProjectDirectories } from '../platform/project-search'
5
+ import { searchProjectDirectories, warmDirectoryCache } from '../platform/project-search'
6
6
 
7
7
  const DEFAULT_DIRECTORY_SEARCH_DEBOUNCE_MS = 200
8
8
 
@@ -25,6 +25,11 @@ export function useDirectorySearch(
25
25
  ): void {
26
26
  const directoryQuery = getDirectoryQuery(modal)
27
27
 
28
+ useEffect(() => {
29
+ if (modal.type !== 'create-session') return
30
+ void warmDirectoryCache()
31
+ }, [modal.type])
32
+
28
33
  useEffect(() => {
29
34
  if (modal.type !== 'create-session') {
30
35
  return
package/src/app.tsx CHANGED
@@ -37,7 +37,7 @@ import { loadSnippetCatalog } from './state/snippet-catalog'
37
37
  import { appReducer, createInitialState } from './state/store'
38
38
  import { KeymapContext } from './ui/keymap-context'
39
39
  import { RootView } from './ui/root'
40
- import { applyTheme } from './ui/theme'
40
+ import { applyTheme, setTransparent } from './ui/theme'
41
41
  import { isKnownThemeId, registerUserThemes, type ThemeId } from './ui/themes'
42
42
  import {
43
43
  fetchLatestNpmVersion,
@@ -75,6 +75,7 @@ export function App({
75
75
  : undefined
76
76
  const initial = persisted ?? fromConfig ?? 'aimux'
77
77
  applyTheme(initial)
78
+ setTransparent(config.themeTransparent ?? false)
78
79
  return initial
79
80
  })
80
81
  const [state, dispatch] = useReducer(appReducer, undefined, () => {
@@ -88,10 +89,14 @@ export function App({
88
89
  const userGitPane = resolvedConfig.gitPane
89
90
  const fileListMode = userGitPane?.fileListMode ?? json.gitPane?.fileListMode ?? 'tree'
90
91
  const diffModeRatio = userGitPane?.diffModeRatio ?? json.gitPane?.diffModeRatio ?? 0.35
92
+ const treeCompaction = userGitPane?.treeCompaction ?? json.gitPane?.treeCompaction ?? true
93
+ const prefetchRadius = userGitPane?.prefetchRadius ?? json.gitPane?.prefetchRadius ?? 5
91
94
  const gitPaneOverrides = {
92
95
  ...json.gitPane,
93
96
  diffModeRatio,
94
97
  fileListMode,
98
+ prefetchRadius,
99
+ treeCompaction,
95
100
  ...(userGitPane?.visible !== undefined ? { visible: userGitPane.visible } : {}),
96
101
  ...(userGitPane?.mode !== undefined ? { mode: userGitPane.mode } : {}),
97
102
  ...(userGitPane?.position !== undefined ? { position: userGitPane.position } : {}),
package/src/config.ts CHANGED
@@ -25,6 +25,8 @@ export const CONFIG_PATH = `${getProfileConfigDir()}/aimux.json`
25
25
  export interface PersistedGitPane {
26
26
  diffModeRatio?: number
27
27
  fileListMode?: GitFileListMode
28
+ treeCompaction?: boolean
29
+ prefetchRadius?: number
28
30
  visible: boolean
29
31
  mode: 'embedded' | 'pane'
30
32
  position: 'top' | 'bottom' | 'left' | 'right'
@@ -35,6 +37,7 @@ export interface AimuxConfig {
35
37
  version: 2
36
38
  customCommands: Record<string, string>
37
39
  themeId?: ThemeId
40
+ themeTransparent?: boolean
38
41
  gitPane?: PersistedGitPane
39
42
  sessionBarVisible?: boolean
40
43
  sessionBarPosition?: SessionBarPosition
@@ -62,7 +65,23 @@ function isPersistedGitPane(value: unknown): value is PersistedGitPane {
62
65
  const visibleOk = typeof v.visible === 'boolean'
63
66
  const fileListModeOk =
64
67
  v.fileListMode === undefined || v.fileListMode === 'tree' || v.fileListMode === 'flat'
65
- if (!modeOk || !positionOk || !ratioOk || !diffModeRatioOk || !visibleOk || !fileListModeOk) {
68
+ const treeCompactionOk = v.treeCompaction === undefined || typeof v.treeCompaction === 'boolean'
69
+ const prefetchRadiusOk =
70
+ v.prefetchRadius === undefined ||
71
+ (typeof v.prefetchRadius === 'number' &&
72
+ Number.isFinite(v.prefetchRadius) &&
73
+ v.prefetchRadius >= 0 &&
74
+ v.prefetchRadius <= 50)
75
+ if (
76
+ !modeOk ||
77
+ !positionOk ||
78
+ !ratioOk ||
79
+ !diffModeRatioOk ||
80
+ !visibleOk ||
81
+ !fileListModeOk ||
82
+ !treeCompactionOk ||
83
+ !prefetchRadiusOk
84
+ ) {
66
85
  return false
67
86
  }
68
87
  // cross-field coherence: embedded => top|bottom; pane => left|right
@@ -108,6 +127,7 @@ export function loadConfigResult(): ConfigLoadResult {
108
127
  version?: number
109
128
  customCommands?: unknown
110
129
  themeId?: unknown
130
+ themeTransparent?: unknown
111
131
  gitPane?: unknown
112
132
  gitPanelVisible?: unknown
113
133
  gitPanelRatio?: unknown
@@ -131,6 +151,12 @@ export function loadConfigResult(): ConfigLoadResult {
131
151
  issues.push('ignored invalid themeId')
132
152
  }
133
153
 
154
+ const validThemeTransparent =
155
+ typeof parsed.themeTransparent === 'boolean' ? parsed.themeTransparent : undefined
156
+ if (parsed.themeTransparent !== undefined && validThemeTransparent === undefined) {
157
+ issues.push('ignored invalid themeTransparent')
158
+ }
159
+
134
160
  let validGitPane = isPersistedGitPane(parsed.gitPane) ? parsed.gitPane : undefined
135
161
  if (parsed.gitPane !== undefined && validGitPane === undefined) {
136
162
  issues.push('ignored invalid gitPane')
@@ -200,6 +226,7 @@ export function loadConfigResult(): ConfigLoadResult {
200
226
  sessionBarVisible: validSessionBarVisible,
201
227
  skippedUpdateVersion: validSkippedUpdateVersion,
202
228
  themeId: migrateThemeId(parsed.themeId),
229
+ themeTransparent: validThemeTransparent,
203
230
  version: 2,
204
231
  workspaceSnapshot: isWorkspaceSnapshotV1(parsed.workspaceSnapshot)
205
232
  ? parsed.workspaceSnapshot