@brimveyn/aimux-config 0.8.4 → 0.8.6

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.
package/README.md CHANGED
@@ -188,7 +188,7 @@ palette guidance, and precedence details.
188
188
  | `theme` | Supported | `theme.initialMode` is a startup override; persisted `aimux.json.themeId` still wins |
189
189
  | `themes` | Supported | User themes; appear in the picker and power synthesized highlighting |
190
190
  | `backends` | Typed surface only | Runtime wiring deferred |
191
- | `sidebar` | Typed surface only | Type exists, runtime not currently driven by this field |
191
+ | `sidebar` | Ignored | Superseded by the app-managed `bars` state in `aimux.json` |
192
192
  | `hooks` | Typed surface only | Type exists, runtime use not currently wired |
193
193
  | `snippets` | Typed surface only | Runtime currently uses `aimux-snippets.json` |
194
194
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brimveyn/aimux-config",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "description": "TypeScript configuration API for aimux — keymaps, themes, and backends with a fluent builder.",
5
5
  "keywords": [
6
6
  "aimux",
package/src/actions.ts CHANGED
@@ -51,8 +51,14 @@ export const openFlashJump: KeyResult = r(
51
51
  'modal.flash-jump'
52
52
  )
53
53
 
54
- export const toggleSidebar: KeyResult = r([{ type: 'toggle-sidebar' }])
55
- export const toggleGitPane: KeyResult = r([{ type: 'toggle-git-pane' }])
54
+ export function toggleBar(side: 'left' | 'right'): KeyResult {
55
+ return r([{ side, type: 'toggle-bar' }])
56
+ }
57
+ export const toggleSidebar: KeyResult = toggleBar('left')
58
+ export function toggleWidget(widgetId: string): KeyResult {
59
+ return r([{ type: 'toggle-widget', widgetId }])
60
+ }
61
+ export const toggleGitPane: KeyResult = toggleWidget('git')
56
62
  export const toggleSessionBar: KeyResult = r([{ type: 'toggle-session-bar' }])
57
63
  export const toggleAIUsage: ActionFn = (ctx: ModeContext) => {
58
64
  if (ctx.state.modal.type === 'ai-usage') {
@@ -61,13 +67,6 @@ export const toggleAIUsage: ActionFn = (ctx: ModeContext) => {
61
67
  return r([{ type: 'open-ai-usage-modal' }], [], 'modal.ai-usage')
62
68
  }
63
69
 
64
- export function setGitPaneMode(mode: 'embedded' | 'pane'): KeyResult {
65
- return r([{ mode, type: 'set-git-pane-mode' }])
66
- }
67
-
68
- export function setGitPanePosition(position: 'top' | 'bottom' | 'left' | 'right'): KeyResult {
69
- return r([{ position, type: 'set-git-pane-position' }])
70
- }
71
70
  export const enterGitMode: KeyResult = r([{ type: 'enter-git-mode' }], [], 'git-mode')
72
71
 
73
72
  export function switchSessionByIndex(index: number): KeyResult {
@@ -139,12 +138,20 @@ export function reorderSession(delta: number): KeyResult {
139
138
  return r([{ delta, type: 'reorder-active-session' }])
140
139
  }
141
140
 
141
+ export function resizeBar(side: 'left' | 'right', delta: number): KeyResult {
142
+ return r([{ delta, side, type: 'resize-bar' }])
143
+ }
144
+
142
145
  export function resizeSidebar(delta: number): KeyResult {
143
- return r([{ delta, type: 'resize-sidebar' }])
146
+ return resizeBar('left', delta)
147
+ }
148
+
149
+ export function resizeWidget(widgetId: string, delta: number): KeyResult {
150
+ return r([{ delta, type: 'resize-widget', widgetId }])
144
151
  }
145
152
 
146
153
  export function resizeGitPane(delta: number): KeyResult {
147
- return r([{ delta, type: 'resize-git-pane' }])
154
+ return resizeWidget('git', delta)
148
155
  }
149
156
 
150
157
  export function resizeGitDiffPane(delta: number): ActionFn {
@@ -480,9 +487,11 @@ export const closePane: ActionFn = (ctx: ModeContext) => {
480
487
  }
481
488
 
482
489
  // Navigation-specific dynamic actions
490
+ // Reveals whichever bar hosts the workspace list — it is not pinned to the left.
483
491
  export const ctrlZSidebar: ActionFn = (ctx: ModeContext) => {
484
- if (!ctx.state.sidebar.visible) {
485
- return r([{ type: 'toggle-sidebar' }])
492
+ const side = ctx.state.bars.left.widgets.some((w) => w.id === 'workspaces') ? 'left' : 'right'
493
+ if (!ctx.state.bars[side].visible) {
494
+ return r([{ side, type: 'toggle-bar' }])
486
495
  }
487
496
  return r([])
488
497
  }
@@ -498,7 +507,7 @@ export const leaveTerminalInput: KeyResult = r(
498
507
  'navigation'
499
508
  )
500
509
 
501
- export const toggleSidebarFromInput: KeyResult = r([{ type: 'toggle-sidebar' }])
510
+ export const toggleSidebarFromInput: KeyResult = toggleBar('left')
502
511
 
503
512
  // Session name modal
504
513
  export const confirmSessionRename: ActionFn = (ctx: ModeContext) => {
package/src/defaults.ts CHANGED
@@ -19,10 +19,13 @@ export const DEFAULT_AUTO_COMMIT_CONFIG: AutoCommitConfig = {
19
19
 
20
20
  export const DEFAULT_AUTO_RENAME_CONFIG: AutoRenameConfig = {
21
21
  enabled: true,
22
+ maxAttempts: 3,
23
+ minPromptWords: 3,
22
24
  models: {
23
25
  claude: 'claude-haiku-4-5',
24
26
  codex: 'gpt-5-mini',
25
27
  },
28
+ settleMs: 2_500,
26
29
  timeoutMs: 15_000,
27
30
  }
28
31
 
@@ -99,6 +102,7 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
99
102
  .mode(['navigation', 'terminal-input'], (m) =>
100
103
  m
101
104
  .map('<Leader>b', actions.toggleSessionBar, 'Toggle session bar')
105
+ .map('<Leader>B', actions.toggleBar('right'), 'Toggle right bar')
102
106
  .map('<Leader>u', actions.toggleAIUsage, 'Toggle AI usage')
103
107
  .map('<Leader>1', actions.switchTabByIndex(1), 'Tab 1')
104
108
  .map('<Leader>2', actions.switchTabByIndex(2), 'Tab 2')
package/src/resolver.ts CHANGED
@@ -32,7 +32,16 @@ export function resolveConfig(userConfig: AimuxUserConfig): ResolvedConfig {
32
32
 
33
33
  const autoRename: AutoRenameConfig = {
34
34
  enabled: userConfig.autoRename?.enabled ?? DEFAULT_AUTO_RENAME_CONFIG.enabled,
35
+ maxAttempts: Math.max(
36
+ 1,
37
+ userConfig.autoRename?.maxAttempts ?? DEFAULT_AUTO_RENAME_CONFIG.maxAttempts
38
+ ),
39
+ minPromptWords: Math.max(
40
+ 1,
41
+ userConfig.autoRename?.minPromptWords ?? DEFAULT_AUTO_RENAME_CONFIG.minPromptWords
42
+ ),
35
43
  models: { ...DEFAULT_AUTO_RENAME_CONFIG.models, ...userConfig.autoRename?.models },
44
+ settleMs: Math.max(0, userConfig.autoRename?.settleMs ?? DEFAULT_AUTO_RENAME_CONFIG.settleMs),
36
45
  timeoutMs: userConfig.autoRename?.timeoutMs ?? DEFAULT_AUTO_RENAME_CONFIG.timeoutMs,
37
46
  }
38
47
 
@@ -96,60 +105,17 @@ function resolveSessionBar(
96
105
  }
97
106
  }
98
107
 
99
- function resolvePaneInitialPosition(
100
- userConfig: NonNullable<AimuxUserConfig['gitPane']>
101
- ): 'left' | 'right' | undefined {
102
- if (userConfig.initialPosition === 'left' || userConfig.initialPosition === 'right') {
103
- return userConfig.initialPosition
104
- }
105
- if (userConfig.position === 'left' || userConfig.position === 'right') {
106
- return userConfig.position
107
- }
108
- return undefined
109
- }
110
-
111
- function resolveEmbeddedInitialPosition(
112
- userConfig: NonNullable<AimuxUserConfig['gitPane']>
113
- ): 'top' | 'bottom' | undefined {
114
- if (userConfig.initialPosition === 'top' || userConfig.initialPosition === 'bottom') {
115
- return userConfig.initialPosition
116
- }
117
- if (userConfig.position === 'top' || userConfig.position === 'bottom') {
118
- return userConfig.position
119
- }
120
- return undefined
121
- }
122
-
108
+ /** Placement fields are accepted for backwards compatibility but dropped here. */
123
109
  function resolveGitPane(userConfig: AimuxUserConfig['gitPane']): ResolvedConfig['gitPane'] {
124
110
  if (!userConfig) return {}
125
-
126
- const initialMode = userConfig.initialMode ?? userConfig.mode
127
- const paneInitialPosition = resolvePaneInitialPosition(userConfig)
128
- const embeddedInitialPosition = resolveEmbeddedInitialPosition(userConfig)
129
- const shared = {
111
+ return {
130
112
  diffCount: userConfig.diffCount,
131
113
  initialDiffModeRatio: userConfig.initialDiffModeRatio ?? userConfig.diffModeRatio,
132
114
  initialFileListMode: userConfig.initialFileListMode ?? userConfig.fileListMode,
133
- initialRatio: userConfig.initialRatio ?? userConfig.ratio,
134
115
  initialTreeCompaction: userConfig.initialTreeCompaction ?? userConfig.treeCompaction,
135
- initialVisible: userConfig.initialVisible ?? userConfig.visible,
136
116
  path: userConfig.path,
137
117
  prefetchRadius: userConfig.prefetchRadius,
138
118
  }
139
-
140
- if (initialMode === 'pane') {
141
- return {
142
- ...shared,
143
- initialMode: 'pane',
144
- initialPosition: paneInitialPosition,
145
- }
146
- }
147
-
148
- return {
149
- ...shared,
150
- ...(initialMode === 'embedded' ? { initialMode: 'embedded' as const } : {}),
151
- initialPosition: embeddedInitialPosition,
152
- }
153
119
  }
154
120
 
155
121
  function resolveKeymaps(userConfig: AimuxUserConfig): ResolvedKeymapConfig {
package/src/types.ts CHANGED
@@ -207,21 +207,26 @@ export interface DirectoryResult {
207
207
  type: DirectoryResultType
208
208
  }
209
209
 
210
- // ─── Sidebar / git panel / modal state (for ModeContext) ──────────────────────
210
+ // ─── Bars / git panel / modal state (for ModeContext) ─────────────────────────
211
211
 
212
- export interface SidebarState {
212
+ export type BarSide = 'left' | 'right'
213
+
214
+ export interface BarWidget {
215
+ id: string
216
+ grow: number
217
+ visible: boolean
218
+ }
219
+
220
+ export interface BarState {
213
221
  visible: boolean
214
222
  width: number
215
- minWidth: number
216
- maxWidth: number
223
+ /** Ordered top → bottom. */
224
+ widgets: BarWidget[]
217
225
  }
218
226
 
227
+ export type BarsState = Record<BarSide, BarState>
228
+
219
229
  export interface GitPaneState {
220
- visible: boolean
221
- mode: 'embedded' | 'pane'
222
- position: 'top' | 'bottom' | 'left' | 'right'
223
- paneRatio: number
224
- embeddedRatio: number
225
230
  diffModeRatio: number
226
231
  fileListMode: GitFileListMode
227
232
  treeCompaction: boolean
@@ -536,7 +541,7 @@ export interface AppState {
536
541
  sessionBar: SessionBarState
537
542
  snippets: SnippetRecord[]
538
543
  focusMode: FocusMode
539
- sidebar: SidebarState
544
+ bars: BarsState
540
545
  gitPane: GitPaneState
541
546
  modal: ModalState
542
547
  layout: LayoutState
@@ -695,17 +700,16 @@ export type LayoutAction =
695
700
  }
696
701
 
697
702
  export type UIAction =
698
- | { type: 'toggle-sidebar' }
699
- | { type: 'resize-sidebar'; delta: number }
700
- | { type: 'set-sidebar-width'; width: number }
703
+ | { type: 'toggle-bar'; side: BarSide }
704
+ | { type: 'resize-bar'; side: BarSide; delta: number }
705
+ | { type: 'set-bar-width'; side: BarSide; width: number }
706
+ | { type: 'toggle-widget'; widgetId: string }
707
+ | { type: 'move-widget'; widgetId: string; side: BarSide; index: number }
708
+ | { type: 'set-bar-boundary'; side: BarSide; index: number; ratio: number }
709
+ | { type: 'resize-widget'; widgetId: string; delta: number }
701
710
  | { type: 'set-focus-mode'; focusMode: FocusMode }
702
711
  | { type: 'set-terminal-size'; cols: number; rows: number }
703
- | { type: 'toggle-git-pane' }
704
- | { type: 'resize-git-pane'; delta: number }
705
- | { type: 'set-git-pane-ratio'; target: 'pane' | 'embedded'; ratio: number }
706
712
  | { type: 'resize-git-diff-pane'; delta: number }
707
- | { type: 'set-git-pane-mode'; mode: 'embedded' | 'pane' }
708
- | { type: 'set-git-pane-position'; position: 'top' | 'bottom' | 'left' | 'right' }
709
713
  | { type: 'set-pending-chords'; chords: string[] | null }
710
714
  | { type: 'toggle-session-bar' }
711
715
 
@@ -1096,6 +1100,19 @@ export interface AutoRenameConfig {
1096
1100
  enabled: boolean
1097
1101
  timeoutMs: number
1098
1102
  models: Partial<Record<string, string>>
1103
+ /**
1104
+ * Quiet period after a title-worthy prompt before a title is generated.
1105
+ * Prompts submitted inside the window are appended to the same request, so a
1106
+ * "read X" / "now do Y" opening yields one title instead of two.
1107
+ */
1108
+ settleMs: number
1109
+ /** Generation attempts before falling back to a title derived locally from the prompt. */
1110
+ maxAttempts: number
1111
+ /**
1112
+ * Prompts with fewer words than this are treated as menu answers or
1113
+ * confirmations and ignored (they do not consume an attempt).
1114
+ */
1115
+ minPromptWords: number
1099
1116
  }
1100
1117
 
1101
1118
  export interface MultiRepoConfig {
@@ -1260,31 +1277,19 @@ export interface ResolvedConfig {
1260
1277
  sessionBar: {
1261
1278
  initialVisible?: boolean
1262
1279
  }
1263
- gitPane:
1264
- | {
1265
- initialMode?: 'embedded'
1266
- initialPosition?: 'top' | 'bottom'
1267
- initialVisible?: boolean
1268
- initialRatio?: number
1269
- initialDiffModeRatio?: number
1270
- initialFileListMode?: GitFileListMode
1271
- initialTreeCompaction?: boolean
1272
- path?: GitPanePathConfig
1273
- diffCount?: GitPaneDiffCountConfig
1274
- prefetchRadius?: number
1275
- }
1276
- | {
1277
- initialMode: 'pane'
1278
- initialPosition?: 'left' | 'right'
1279
- initialVisible?: boolean
1280
- initialRatio?: number
1281
- initialDiffModeRatio?: number
1282
- initialFileListMode?: GitFileListMode
1283
- initialTreeCompaction?: boolean
1284
- path?: GitPanePathConfig
1285
- diffCount?: GitPaneDiffCountConfig
1286
- prefetchRadius?: number
1287
- }
1280
+ /**
1281
+ * Placement (`initialMode`/`initialPosition`/`initialRatio`/`initialVisible`)
1282
+ * moved to the bars layout in `aimux.json`; those fields are still accepted
1283
+ * in user config but ignored.
1284
+ */
1285
+ gitPane: {
1286
+ initialDiffModeRatio?: number
1287
+ initialFileListMode?: GitFileListMode
1288
+ initialTreeCompaction?: boolean
1289
+ path?: GitPanePathConfig
1290
+ diffCount?: GitPaneDiffCountConfig
1291
+ prefetchRadius?: number
1292
+ }
1288
1293
  hooks: HooksConfig
1289
1294
  snippets: SnippetDef[]
1290
1295
  snippetTriggerChar: string