@brimveyn/aimux-config 0.4.5 → 0.5.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.
- package/README.md +34 -44
- package/package.json +1 -1
- package/src/actions.ts +89 -9
- package/src/auto-commit-runtime.ts +18 -0
- package/src/defaults.ts +30 -1
- package/src/index.ts +5 -0
- package/src/resolver.ts +87 -4
- package/src/types.ts +155 -11
package/README.md
CHANGED
|
@@ -44,17 +44,21 @@ import { defineConfig, actions } from '@brimveyn/aimux-config'
|
|
|
44
44
|
|
|
45
45
|
export default defineConfig({
|
|
46
46
|
sessionBar: {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
initialPosition: 'top',
|
|
48
|
+
initialVisible: true,
|
|
49
49
|
},
|
|
50
50
|
|
|
51
51
|
keymaps: (k) =>
|
|
52
|
-
k.mode('navigation', (m) => m.map('<C-p>', actions.sessionPicker, '
|
|
52
|
+
k.mode('navigation', (m) => m.map('<C-p>', actions.sessionPicker, 'Workspace picker')),
|
|
53
53
|
})
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
This example only uses surfaces that are wired into the runtime today.
|
|
57
57
|
|
|
58
|
+
Important: typed config expresses startup intent. Fields such as
|
|
59
|
+
`sessionBar.initialVisible` or `gitPane.initialMode` are reapplied on every
|
|
60
|
+
launch; runtime UI changes do not write back into `aimux.config.ts`.
|
|
61
|
+
|
|
58
62
|
## Key Notation
|
|
59
63
|
|
|
60
64
|
| Notation | Meaning |
|
|
@@ -136,7 +140,7 @@ explanation.
|
|
|
136
140
|
Pre-built actions include:
|
|
137
141
|
|
|
138
142
|
- tabs: `nextTab`, `prevTab`, `newTab`, `renameTab`, `closeTab`, `restartTab`
|
|
139
|
-
-
|
|
143
|
+
- workspaces: `sessionPicker`, `switchSessionByIndex(n)` and workspace modal actions
|
|
140
144
|
- snippets: `snippetPicker`, snippet editor and filter actions
|
|
141
145
|
- themes: `themePicker`, `previewTheme`, `confirmTheme`, `restoreTheme`
|
|
142
146
|
- panes: `splitVertical`, `splitHorizontal`, `focusPane`, `resizePane`, `closePane`
|
|
@@ -149,58 +153,44 @@ You can also bind a custom `ActionFn` for dynamic behavior.
|
|
|
149
153
|
|
|
150
154
|
## Themes
|
|
151
155
|
|
|
152
|
-
|
|
153
|
-
(`aimux`, `dracula-at-night`) ship alongside the full Shiki catalog — 67
|
|
154
|
-
themes total. The same `Theme` object powers UI colors and code highlighting.
|
|
156
|
+
`theme` is a startup override surface, not the persisted selected theme.
|
|
155
157
|
|
|
156
|
-
|
|
158
|
+
Use it to choose the built-in light or dark family when there is no persisted
|
|
159
|
+
`aimux.json.themeId`, and to apply palette overrides on top of the chosen base
|
|
160
|
+
theme:
|
|
157
161
|
|
|
158
162
|
```ts
|
|
159
|
-
import { defineConfig
|
|
163
|
+
import { defineConfig } from '@brimveyn/aimux-config'
|
|
160
164
|
|
|
161
165
|
export default defineConfig({
|
|
162
|
-
theme:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}),
|
|
169
|
-
// Or drop a full VSCode theme JSON verbatim:
|
|
170
|
-
'custom': themes.full({
|
|
171
|
-
name: 'custom',
|
|
172
|
-
displayName: 'Custom',
|
|
173
|
-
type: 'dark',
|
|
174
|
-
fg: '#eee',
|
|
175
|
-
bg: '#1a1a1a',
|
|
176
|
-
colors: {
|
|
177
|
-
/* VSCode workbench keys */
|
|
178
|
-
},
|
|
179
|
-
settings: [
|
|
180
|
-
/* TextMate token rules */
|
|
181
|
-
],
|
|
182
|
-
}),
|
|
166
|
+
theme: {
|
|
167
|
+
initialMode: 'dark',
|
|
168
|
+
paletteOverrides: {
|
|
169
|
+
primary: '#7dd3fc',
|
|
170
|
+
warning: '#fbbf24',
|
|
171
|
+
},
|
|
183
172
|
},
|
|
184
173
|
})
|
|
185
174
|
```
|
|
186
175
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
176
|
+
The runtime theme picker persists the selected theme id separately in
|
|
177
|
+
`aimux.json`, and that persisted choice wins on restart. See
|
|
178
|
+
[`../../docs/guide/themes.md`](../../docs/guide/themes.md) for picker behavior,
|
|
179
|
+
palette guidance, and precedence details.
|
|
190
180
|
|
|
191
181
|
## Support Status
|
|
192
182
|
|
|
193
|
-
| Surface | Status | Notes
|
|
194
|
-
| ------------ | ------------------ |
|
|
195
|
-
| `keymaps` | Supported | Fully registered by the runtime
|
|
196
|
-
| `sessionBar` | Supported |
|
|
197
|
-
| `gitPane` | Supported |
|
|
198
|
-
| `theme` | Supported |
|
|
199
|
-
| `themes` | Supported | User themes; appear in the picker and power synthesized highlighting
|
|
200
|
-
| `backends` | Typed surface only | Runtime wiring deferred
|
|
201
|
-
| `sidebar` | Typed surface only | Type exists, runtime not currently driven by this field
|
|
202
|
-
| `hooks` | Typed surface only | Type exists, runtime use not currently wired
|
|
203
|
-
| `snippets` | Typed surface only | Runtime currently uses `aimux-snippets.json`
|
|
183
|
+
| Surface | Status | Notes |
|
|
184
|
+
| ------------ | ------------------ | ------------------------------------------------------------------------------------ |
|
|
185
|
+
| `keymaps` | Supported | Fully registered by the runtime |
|
|
186
|
+
| `sessionBar` | Supported | Startup overrides; app-managed runtime state still persists separately |
|
|
187
|
+
| `gitPane` | Supported | Startup overrides for placement and rendering; runtime state persists separately |
|
|
188
|
+
| `theme` | Supported | `theme.initialMode` is a startup override; persisted `aimux.json.themeId` still wins |
|
|
189
|
+
| `themes` | Supported | User themes; appear in the picker and power synthesized highlighting |
|
|
190
|
+
| `backends` | Typed surface only | Runtime wiring deferred |
|
|
191
|
+
| `sidebar` | Typed surface only | Type exists, runtime not currently driven by this field |
|
|
192
|
+
| `hooks` | Typed surface only | Type exists, runtime use not currently wired |
|
|
193
|
+
| `snippets` | Typed surface only | Runtime currently uses `aimux-snippets.json` |
|
|
204
194
|
|
|
205
195
|
## Backends Subpath
|
|
206
196
|
|
package/package.json
CHANGED
package/src/actions.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { ActionFn, AppAction, KeyResult, ModeContext, ModeId } from './types'
|
|
2
2
|
|
|
3
|
+
import { isAutoCommitEnabled } from './auto-commit-runtime'
|
|
4
|
+
|
|
5
|
+
const AUTO_COMMIT_DISABLED_MESSAGE =
|
|
6
|
+
'auto-commit is disabled — set autoCommit: { enabled: true } in aimux.config.ts'
|
|
7
|
+
|
|
3
8
|
function r(
|
|
4
9
|
actions: KeyResult['actions'] = [],
|
|
5
10
|
effects: KeyResult['effects'] = [],
|
|
@@ -545,7 +550,12 @@ export const gitCommitOpen: ActionFn = (ctx: ModeContext) => {
|
|
|
545
550
|
},
|
|
546
551
|
])
|
|
547
552
|
}
|
|
548
|
-
|
|
553
|
+
const sessionId = ctx.state.currentSessionId ?? undefined
|
|
554
|
+
return r(
|
|
555
|
+
[...clearPendingDelete(ctx), { sessionId, type: 'open-git-commit-modal' }],
|
|
556
|
+
[],
|
|
557
|
+
'modal.git-commit'
|
|
558
|
+
)
|
|
549
559
|
}
|
|
550
560
|
|
|
551
561
|
export const gitPush: ActionFn = (ctx: ModeContext) => {
|
|
@@ -564,18 +574,88 @@ export const gitPush: ActionFn = (ctx: ModeContext) => {
|
|
|
564
574
|
// Modal: git-commit
|
|
565
575
|
// ---------------------------------------------------------------------------
|
|
566
576
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (modal.type !== 'git-commit')
|
|
572
|
-
return r([{ type: 'close-modal' }], [], 'git-mode')
|
|
573
|
-
}
|
|
577
|
+
function extractGitCommitFields(modal: ModeContext['state']['modal']): {
|
|
578
|
+
title: string
|
|
579
|
+
body: string
|
|
580
|
+
} | null {
|
|
581
|
+
if (modal.type !== 'git-commit') return null
|
|
574
582
|
const editBuffer = modal.editBuffer ?? ''
|
|
575
583
|
const activeIsTitle = modal.activeField === 'title'
|
|
576
584
|
const title = (activeIsTitle ? editBuffer : modal.contentBuffer).trim()
|
|
577
585
|
const body = (activeIsTitle ? modal.contentBuffer : editBuffer).trim()
|
|
578
|
-
return
|
|
586
|
+
return { body, title }
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
export const gitCommitCancel: ActionFn = (ctx: ModeContext) => {
|
|
590
|
+
const modal = ctx.state.modal
|
|
591
|
+
if (modal.type === 'git-commit' && modal.stage === 'confirm') {
|
|
592
|
+
return r([{ type: 'git-commit-leave-confirm' }], [], 'modal.git-commit')
|
|
593
|
+
}
|
|
594
|
+
return r([{ type: 'close-modal' }], [], 'git-mode')
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
export const gitCommitEnterConfirm: ActionFn = (ctx: ModeContext) => {
|
|
598
|
+
const modal = ctx.state.modal
|
|
599
|
+
if (modal.type !== 'git-commit') return null
|
|
600
|
+
if (!isAutoCommitEnabled()) {
|
|
601
|
+
return r([{ message: AUTO_COMMIT_DISABLED_MESSAGE, type: 'git-mode-set-message' }])
|
|
602
|
+
}
|
|
603
|
+
const fields = extractGitCommitFields(modal)
|
|
604
|
+
const hasTitle = !!fields && fields.title.length > 0
|
|
605
|
+
if (hasTitle) {
|
|
606
|
+
return r([{ type: 'git-commit-enter-confirm' }], [], 'modal.git-commit.confirm')
|
|
607
|
+
}
|
|
608
|
+
const sessionId = ctx.state.currentSessionId
|
|
609
|
+
if (!sessionId) {
|
|
610
|
+
return r([{ type: 'git-commit-enter-confirm' }], [], 'modal.git-commit.confirm')
|
|
611
|
+
}
|
|
612
|
+
return r(
|
|
613
|
+
[{ sessionId, type: 'git-commit-enter-generating' }],
|
|
614
|
+
[{ sessionId, type: 'generate-auto-commit-now' }],
|
|
615
|
+
'modal.git-commit.generating'
|
|
616
|
+
)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export const gitCommitLeaveConfirm: KeyResult = r(
|
|
620
|
+
[{ type: 'git-commit-leave-confirm' }],
|
|
621
|
+
[],
|
|
622
|
+
'modal.git-commit'
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
export const gitCommitLeaveGenerating: ActionFn = (ctx: ModeContext) => {
|
|
626
|
+
const sessionId = ctx.state.currentSessionId
|
|
627
|
+
const actionsList: AppAction[] = [{ type: 'git-commit-leave-generating' }]
|
|
628
|
+
if (sessionId) {
|
|
629
|
+
actionsList.push({ sessionId, type: 'auto-commit-clear' })
|
|
630
|
+
}
|
|
631
|
+
return r(actionsList, [], 'modal.git-commit')
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export const gitCommitAutoAccept: ActionFn = (ctx: ModeContext) => {
|
|
635
|
+
if (!isAutoCommitEnabled()) {
|
|
636
|
+
return r([{ message: AUTO_COMMIT_DISABLED_MESSAGE, type: 'git-mode-set-message' }])
|
|
637
|
+
}
|
|
638
|
+
const fields = extractGitCommitFields(ctx.state.modal)
|
|
639
|
+
if (!fields) {
|
|
640
|
+
return r([{ type: 'close-modal' }], [], 'git-mode')
|
|
641
|
+
}
|
|
642
|
+
return r(
|
|
643
|
+
[{ type: 'close-modal' }],
|
|
644
|
+
[{ body: fields.body, title: fields.title, type: 'git-commit-auto' }],
|
|
645
|
+
'git-mode'
|
|
646
|
+
)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
export const gitCommitSubmit: ActionFn = (ctx: ModeContext) => {
|
|
650
|
+
const fields = extractGitCommitFields(ctx.state.modal)
|
|
651
|
+
if (!fields) {
|
|
652
|
+
return r([{ type: 'close-modal' }], [], 'git-mode')
|
|
653
|
+
}
|
|
654
|
+
return r(
|
|
655
|
+
[{ type: 'close-modal' }],
|
|
656
|
+
[{ body: fields.body, title: fields.title, type: 'git-commit' }],
|
|
657
|
+
'git-mode'
|
|
658
|
+
)
|
|
579
659
|
}
|
|
580
660
|
|
|
581
661
|
export const gitCommitReturnKey: ActionFn = (ctx: ModeContext) => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level flag that mirrors `autoCommit.enabled` from the resolved config.
|
|
3
|
+
*
|
|
4
|
+
* Actions (which run outside React and can't subscribe to a React context) read
|
|
5
|
+
* this via `isAutoCommitEnabled()`. The app sets it once at startup via
|
|
6
|
+
* `setAutoCommitEnabled(resolvedConfig.autoCommit.enabled)` before any children
|
|
7
|
+
* render, so downstream readers always see the correct value.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let enabled = false
|
|
11
|
+
|
|
12
|
+
export function setAutoCommitEnabled(value: boolean): void {
|
|
13
|
+
enabled = value
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isAutoCommitEnabled(): boolean {
|
|
17
|
+
return enabled
|
|
18
|
+
}
|
package/src/defaults.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import type { ResolvedKeymapConfig } from './types'
|
|
1
|
+
import type { AutoCommitConfig, ResolvedKeymapConfig } from './types'
|
|
2
2
|
|
|
3
3
|
import * as actions from './actions'
|
|
4
4
|
import { KeymapBuilder } from './keymap-builder'
|
|
5
5
|
|
|
6
|
+
export const DEFAULT_AUTO_COMMIT_CONFIG: AutoCommitConfig = {
|
|
7
|
+
enabled: false,
|
|
8
|
+
models: {
|
|
9
|
+
claude: 'claude-haiku-4-5',
|
|
10
|
+
codex: 'gpt-5-mini',
|
|
11
|
+
},
|
|
12
|
+
timeoutMs: 60_000,
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
/**
|
|
7
16
|
* Build the default keymap — 1:1 transcription of all existing handlers.
|
|
8
17
|
*/
|
|
@@ -276,10 +285,30 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
|
|
|
276
285
|
m
|
|
277
286
|
.map('<Esc>', actions.gitCommitCancel, 'Cancel')
|
|
278
287
|
.map('<C-CR>', actions.gitCommitSubmit, 'Commit')
|
|
288
|
+
.map('<C-a>', actions.gitCommitEnterConfirm, 'Auto-commit (stage all)')
|
|
279
289
|
.map('<Tab>', actions.switchField, 'Next field')
|
|
280
290
|
.map('<CR>', actions.gitCommitReturnKey, 'Newline / confirm')
|
|
281
291
|
.passthrough()
|
|
282
292
|
)
|
|
283
293
|
|
|
294
|
+
// -----------------------------------------------------------------------
|
|
295
|
+
// Modal: git-commit confirm (auto-commit stage all + commit)
|
|
296
|
+
// -----------------------------------------------------------------------
|
|
297
|
+
.mode('modal.git-commit.confirm', (m) =>
|
|
298
|
+
m
|
|
299
|
+
.map('<Esc>', actions.gitCommitLeaveConfirm, 'Cancel auto-commit')
|
|
300
|
+
.map('<CR>', actions.gitCommitAutoAccept, 'Stage all + commit')
|
|
301
|
+
.map('<C-CR>', actions.gitCommitAutoAccept, 'Stage all + commit')
|
|
302
|
+
.map('<Tab>', actions.switchField, 'Next field')
|
|
303
|
+
.passthrough()
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
// -----------------------------------------------------------------------
|
|
307
|
+
// Modal: git-commit generating (waiting for LLM)
|
|
308
|
+
// -----------------------------------------------------------------------
|
|
309
|
+
.mode('modal.git-commit.generating', (m) =>
|
|
310
|
+
m.map('<Esc>', actions.gitCommitLeaveGenerating, 'Cancel generation')
|
|
311
|
+
)
|
|
312
|
+
|
|
284
313
|
return kb._build()
|
|
285
314
|
}
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { paletteToShikiTheme } from './palette-to-shiki'
|
|
|
22
22
|
export { GroupBuilder, KeymapBuilder, ModeBindingBuilder } from './keymap-builder'
|
|
23
23
|
export { getDefaultKeymapConfig } from './defaults'
|
|
24
24
|
export { resolveConfig } from './resolver'
|
|
25
|
+
export { isAutoCommitEnabled, setAutoCommitEnabled } from './auto-commit-runtime'
|
|
25
26
|
|
|
26
27
|
// Type exports
|
|
27
28
|
export type {
|
|
@@ -33,8 +34,11 @@ export type {
|
|
|
33
34
|
AimuxThemeConfig,
|
|
34
35
|
// User-facing config
|
|
35
36
|
AimuxUserConfig,
|
|
37
|
+
AIUsageTool,
|
|
38
|
+
AIUsageToolConfig,
|
|
36
39
|
AppAction,
|
|
37
40
|
AppState,
|
|
41
|
+
AutoCommitConfig,
|
|
38
42
|
BackendConfig,
|
|
39
43
|
BindingDef,
|
|
40
44
|
FocusMode,
|
|
@@ -68,6 +72,7 @@ export type {
|
|
|
68
72
|
SnippetDef,
|
|
69
73
|
SnippetRecord,
|
|
70
74
|
SplitDirection,
|
|
75
|
+
StatusBarConfig,
|
|
71
76
|
TabSession,
|
|
72
77
|
Theme,
|
|
73
78
|
ThemeId,
|
package/src/resolver.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AimuxUserConfig,
|
|
3
|
+
AutoCommitConfig,
|
|
3
4
|
ModeId,
|
|
4
5
|
ModeKeymapDef,
|
|
5
6
|
ResolvedConfig,
|
|
6
7
|
ResolvedKeymapConfig,
|
|
7
8
|
} from './types'
|
|
8
9
|
|
|
9
|
-
import { getDefaultKeymapConfig } from './defaults'
|
|
10
|
+
import { DEFAULT_AUTO_COMMIT_CONFIG, getDefaultKeymapConfig } from './defaults'
|
|
10
11
|
import { KeymapBuilder } from './keymap-builder'
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -16,15 +17,97 @@ import { KeymapBuilder } from './keymap-builder'
|
|
|
16
17
|
export function resolveConfig(userConfig: AimuxUserConfig): ResolvedConfig {
|
|
17
18
|
const keymaps = resolveKeymaps(userConfig)
|
|
18
19
|
|
|
20
|
+
const autoCommit: AutoCommitConfig = {
|
|
21
|
+
enabled: userConfig.autoCommit?.enabled ?? DEFAULT_AUTO_COMMIT_CONFIG.enabled,
|
|
22
|
+
models: { ...DEFAULT_AUTO_COMMIT_CONFIG.models, ...userConfig.autoCommit?.models },
|
|
23
|
+
timeoutMs: userConfig.autoCommit?.timeoutMs ?? DEFAULT_AUTO_COMMIT_CONFIG.timeoutMs,
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
return {
|
|
27
|
+
autoCommit,
|
|
20
28
|
backends: userConfig.backends ?? {},
|
|
21
|
-
gitPane: userConfig.gitPane
|
|
29
|
+
gitPane: resolveGitPane(userConfig.gitPane),
|
|
22
30
|
hooks: userConfig.hooks ?? {},
|
|
23
31
|
keymaps,
|
|
24
|
-
sessionBar: userConfig.sessionBar
|
|
32
|
+
sessionBar: resolveSessionBar(userConfig.sessionBar),
|
|
25
33
|
sidebar: userConfig.sidebar ?? {},
|
|
26
34
|
snippets: userConfig.snippets ?? [],
|
|
27
|
-
|
|
35
|
+
statusBar: userConfig.statusBar ?? {},
|
|
36
|
+
theme: resolveTheme(userConfig.theme),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolveTheme(userConfig: AimuxUserConfig['theme']): ResolvedConfig['theme'] {
|
|
41
|
+
if (!userConfig) return undefined
|
|
42
|
+
return {
|
|
43
|
+
initialMode: userConfig.initialMode ?? userConfig.mode,
|
|
44
|
+
paletteOverrides: userConfig.paletteOverrides,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function resolveSessionBar(
|
|
49
|
+
userConfig: AimuxUserConfig['sessionBar']
|
|
50
|
+
): ResolvedConfig['sessionBar'] {
|
|
51
|
+
if (!userConfig) return {}
|
|
52
|
+
return {
|
|
53
|
+
initialPosition: userConfig.initialPosition ?? userConfig.position,
|
|
54
|
+
initialVisible: userConfig.initialVisible ?? userConfig.visible,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function resolvePaneInitialPosition(
|
|
59
|
+
userConfig: NonNullable<AimuxUserConfig['gitPane']>
|
|
60
|
+
): 'left' | 'right' | undefined {
|
|
61
|
+
if (userConfig.initialPosition === 'left' || userConfig.initialPosition === 'right') {
|
|
62
|
+
return userConfig.initialPosition
|
|
63
|
+
}
|
|
64
|
+
if (userConfig.position === 'left' || userConfig.position === 'right') {
|
|
65
|
+
return userConfig.position
|
|
66
|
+
}
|
|
67
|
+
return undefined
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function resolveEmbeddedInitialPosition(
|
|
71
|
+
userConfig: NonNullable<AimuxUserConfig['gitPane']>
|
|
72
|
+
): 'top' | 'bottom' | undefined {
|
|
73
|
+
if (userConfig.initialPosition === 'top' || userConfig.initialPosition === 'bottom') {
|
|
74
|
+
return userConfig.initialPosition
|
|
75
|
+
}
|
|
76
|
+
if (userConfig.position === 'top' || userConfig.position === 'bottom') {
|
|
77
|
+
return userConfig.position
|
|
78
|
+
}
|
|
79
|
+
return undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveGitPane(userConfig: AimuxUserConfig['gitPane']): ResolvedConfig['gitPane'] {
|
|
83
|
+
if (!userConfig) return {}
|
|
84
|
+
|
|
85
|
+
const initialMode = userConfig.initialMode ?? userConfig.mode
|
|
86
|
+
const paneInitialPosition = resolvePaneInitialPosition(userConfig)
|
|
87
|
+
const embeddedInitialPosition = resolveEmbeddedInitialPosition(userConfig)
|
|
88
|
+
const shared = {
|
|
89
|
+
diffCount: userConfig.diffCount,
|
|
90
|
+
initialDiffModeRatio: userConfig.initialDiffModeRatio ?? userConfig.diffModeRatio,
|
|
91
|
+
initialFileListMode: userConfig.initialFileListMode ?? userConfig.fileListMode,
|
|
92
|
+
initialRatio: userConfig.initialRatio ?? userConfig.ratio,
|
|
93
|
+
initialTreeCompaction: userConfig.initialTreeCompaction ?? userConfig.treeCompaction,
|
|
94
|
+
initialVisible: userConfig.initialVisible ?? userConfig.visible,
|
|
95
|
+
path: userConfig.path,
|
|
96
|
+
prefetchRadius: userConfig.prefetchRadius,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (initialMode === 'pane') {
|
|
100
|
+
return {
|
|
101
|
+
...shared,
|
|
102
|
+
initialMode: 'pane',
|
|
103
|
+
initialPosition: paneInitialPosition,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
...shared,
|
|
109
|
+
...(initialMode === 'embedded' ? { initialMode: 'embedded' as const } : {}),
|
|
110
|
+
initialPosition: embeddedInitialPosition,
|
|
28
111
|
}
|
|
29
112
|
}
|
|
30
113
|
|
package/src/types.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type ModeId =
|
|
|
24
24
|
| 'modal.help.filtering'
|
|
25
25
|
| 'modal.split-picker'
|
|
26
26
|
| 'modal.git-commit'
|
|
27
|
+
| 'modal.git-commit.confirm'
|
|
28
|
+
| 'modal.git-commit.generating'
|
|
27
29
|
| 'modal.update-available'
|
|
28
30
|
|
|
29
31
|
// ─── Primitive app types ──────────────────────────────────────────────────────
|
|
@@ -63,6 +65,7 @@ export interface TerminalLine {
|
|
|
63
65
|
|
|
64
66
|
export interface TerminalSnapshot {
|
|
65
67
|
lines: TerminalLine[]
|
|
68
|
+
tailLines?: TerminalLine[]
|
|
66
69
|
viewportY: number
|
|
67
70
|
baseY: number
|
|
68
71
|
cursorVisible: boolean
|
|
@@ -168,7 +171,8 @@ export interface GitPaneState {
|
|
|
168
171
|
visible: boolean
|
|
169
172
|
mode: 'embedded' | 'pane'
|
|
170
173
|
position: 'top' | 'bottom' | 'left' | 'right'
|
|
171
|
-
|
|
174
|
+
paneRatio: number
|
|
175
|
+
embeddedRatio: number
|
|
172
176
|
diffModeRatio: number
|
|
173
177
|
fileListMode: GitFileListMode
|
|
174
178
|
treeCompaction: boolean
|
|
@@ -290,6 +294,7 @@ export interface ModalGitCommit extends ModalBase {
|
|
|
290
294
|
type: 'git-commit'
|
|
291
295
|
activeField: 'title' | 'body'
|
|
292
296
|
contentBuffer: string
|
|
297
|
+
stage: 'edit' | 'generating' | 'confirm'
|
|
293
298
|
}
|
|
294
299
|
export interface ModalSnippetEditor extends ModalBase {
|
|
295
300
|
type: 'snippet-editor'
|
|
@@ -330,6 +335,28 @@ export interface SessionBarState {
|
|
|
330
335
|
position: SessionBarPosition
|
|
331
336
|
}
|
|
332
337
|
|
|
338
|
+
export type AutoCommitSuggestion =
|
|
339
|
+
| { kind: 'idle' }
|
|
340
|
+
| {
|
|
341
|
+
kind: 'generating'
|
|
342
|
+
tabId: string
|
|
343
|
+
workingTreeHash: string
|
|
344
|
+
abortController: AbortController
|
|
345
|
+
startedAt: number
|
|
346
|
+
}
|
|
347
|
+
| {
|
|
348
|
+
kind: 'ready'
|
|
349
|
+
tabId: string
|
|
350
|
+
workingTreeHash: string
|
|
351
|
+
title: string
|
|
352
|
+
body: string
|
|
353
|
+
generatedAt: number
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export interface AutoCommitState {
|
|
357
|
+
bySession: Record<string, AutoCommitSuggestion>
|
|
358
|
+
}
|
|
359
|
+
|
|
333
360
|
export interface AppState {
|
|
334
361
|
tabs: TabSession[]
|
|
335
362
|
activeTabId: string | null
|
|
@@ -348,6 +375,7 @@ export interface AppState {
|
|
|
348
375
|
customCommands: Record<AssistantId, string>
|
|
349
376
|
gitPanel: GitPanelState
|
|
350
377
|
gitMode: GitModeState
|
|
378
|
+
autoCommit: AutoCommitState
|
|
351
379
|
pendingChords: string[] | null
|
|
352
380
|
}
|
|
353
381
|
|
|
@@ -385,7 +413,7 @@ export type SessionAction =
|
|
|
385
413
|
| { type: 'set-sessions'; sessions: SessionRecord[] }
|
|
386
414
|
| { type: 'create-session-record'; session: SessionRecord }
|
|
387
415
|
| { type: 'rename-session-record'; sessionId: string; name: string }
|
|
388
|
-
| { type: 'delete-session-record'; sessionId: string }
|
|
416
|
+
| { type: 'delete-session-record'; sessionId: string; openSessionPicker?: boolean }
|
|
389
417
|
| { type: 'reorder-sessions'; orderedIds: string[] }
|
|
390
418
|
| { type: 'set-session-status'; sessionId: string; status: SessionStatus }
|
|
391
419
|
|
|
@@ -443,10 +471,12 @@ export type LayoutAction =
|
|
|
443
471
|
export type UIAction =
|
|
444
472
|
| { type: 'toggle-sidebar' }
|
|
445
473
|
| { type: 'resize-sidebar'; delta: number }
|
|
474
|
+
| { type: 'set-sidebar-width'; width: number }
|
|
446
475
|
| { type: 'set-focus-mode'; focusMode: FocusMode }
|
|
447
476
|
| { type: 'set-terminal-size'; cols: number; rows: number }
|
|
448
477
|
| { type: 'toggle-git-pane' }
|
|
449
478
|
| { type: 'resize-git-pane'; delta: number }
|
|
479
|
+
| { type: 'set-git-pane-ratio'; target: 'pane' | 'embedded'; ratio: number }
|
|
450
480
|
| { type: 'resize-git-diff-pane'; delta: number }
|
|
451
481
|
| { type: 'set-git-pane-mode'; mode: 'embedded' | 'pane' }
|
|
452
482
|
| { type: 'set-git-pane-position'; position: 'top' | 'bottom' | 'left' | 'right' }
|
|
@@ -500,12 +530,35 @@ export type GitModeAction =
|
|
|
500
530
|
fromSection: GitFileSection
|
|
501
531
|
toSection: GitFileSection | null
|
|
502
532
|
}
|
|
503
|
-
| { type: 'open-git-commit-modal' }
|
|
533
|
+
| { type: 'open-git-commit-modal'; sessionId?: string }
|
|
534
|
+
| { type: 'git-commit-enter-confirm' }
|
|
535
|
+
| { type: 'git-commit-leave-confirm' }
|
|
536
|
+
| { type: 'git-commit-enter-generating'; sessionId: string }
|
|
537
|
+
| { type: 'git-commit-leave-generating' }
|
|
504
538
|
|
|
505
539
|
export type DataAction =
|
|
506
540
|
| { type: 'set-snippets'; snippets: SnippetRecord[] }
|
|
507
541
|
| { type: 'delete-snippet'; snippetId: string }
|
|
508
542
|
|
|
543
|
+
export type AutoCommitAction =
|
|
544
|
+
| {
|
|
545
|
+
type: 'auto-commit-generation-started'
|
|
546
|
+
sessionId: string
|
|
547
|
+
tabId: string
|
|
548
|
+
workingTreeHash: string
|
|
549
|
+
abortController: AbortController
|
|
550
|
+
startedAt: number
|
|
551
|
+
}
|
|
552
|
+
| {
|
|
553
|
+
type: 'auto-commit-generation-ready'
|
|
554
|
+
sessionId: string
|
|
555
|
+
workingTreeHash: string
|
|
556
|
+
title: string
|
|
557
|
+
body: string
|
|
558
|
+
generatedAt: number
|
|
559
|
+
}
|
|
560
|
+
| { type: 'auto-commit-clear'; sessionId: string }
|
|
561
|
+
|
|
509
562
|
export type AppAction =
|
|
510
563
|
| ModalAction
|
|
511
564
|
| SessionAction
|
|
@@ -515,6 +568,7 @@ export type AppAction =
|
|
|
515
568
|
| DataAction
|
|
516
569
|
| GitPanelAction
|
|
517
570
|
| GitModeAction
|
|
571
|
+
| AutoCommitAction
|
|
518
572
|
|
|
519
573
|
// ─── Side effects ─────────────────────────────────────────────────────────────
|
|
520
574
|
|
|
@@ -549,6 +603,8 @@ export type SideEffect =
|
|
|
549
603
|
| { type: 'git-restore'; path: string }
|
|
550
604
|
| { type: 'git-rm'; path: string }
|
|
551
605
|
| { type: 'git-commit'; title: string; body: string }
|
|
606
|
+
| { type: 'git-commit-auto'; title: string; body: string }
|
|
607
|
+
| { type: 'generate-auto-commit-now'; sessionId: string }
|
|
552
608
|
| { type: 'git-push' }
|
|
553
609
|
| { type: 'confirm-update-selection' }
|
|
554
610
|
| { type: 'switch-session-by-index'; index: number }
|
|
@@ -689,7 +745,13 @@ export interface KeymapBuilderApi {
|
|
|
689
745
|
// ─── Top-level user config ────────────────────────────────────────────────────
|
|
690
746
|
|
|
691
747
|
export interface SessionBarConfig {
|
|
748
|
+
/** Startup override for the session bar visibility. Reapplied on each launch. */
|
|
749
|
+
initialVisible?: boolean
|
|
750
|
+
/** Startup override for the session bar position. Reapplied on each launch. */
|
|
751
|
+
initialPosition?: SessionBarPosition
|
|
752
|
+
/** @deprecated Use `initialVisible` instead. */
|
|
692
753
|
visible?: boolean
|
|
754
|
+
/** @deprecated Use `initialPosition` instead. */
|
|
693
755
|
position?: SessionBarPosition
|
|
694
756
|
}
|
|
695
757
|
|
|
@@ -702,32 +764,78 @@ export type GitPanePathConfig =
|
|
|
702
764
|
export type GitPaneDiffCountConfig = { enabled: boolean }
|
|
703
765
|
|
|
704
766
|
interface GitPaneBaseConfig {
|
|
767
|
+
/** Startup override for git pane visibility. Reapplied on each launch. */
|
|
768
|
+
initialVisible?: boolean
|
|
769
|
+
/** Startup override for the pane split ratio. Reapplied on each launch. */
|
|
770
|
+
initialRatio?: number
|
|
771
|
+
/** Startup override for fullscreen diff ratio. Reapplied on each launch. */
|
|
772
|
+
initialDiffModeRatio?: number
|
|
773
|
+
/** Startup override for tree/flat file list mode. Reapplied on each launch. */
|
|
774
|
+
initialFileListMode?: GitFileListMode
|
|
775
|
+
/** Startup override for tree compaction. Reapplied on each launch. */
|
|
776
|
+
initialTreeCompaction?: boolean
|
|
777
|
+
path?: GitPanePathConfig
|
|
778
|
+
diffCount?: GitPaneDiffCountConfig
|
|
779
|
+
/** Prefetch N neighbouring diffs around the cursor; 0 disables. */
|
|
780
|
+
prefetchRadius?: number
|
|
781
|
+
/** @deprecated Use `initialVisible` instead. */
|
|
705
782
|
visible?: boolean
|
|
783
|
+
/** @deprecated Use `initialRatio` instead. */
|
|
706
784
|
ratio?: number
|
|
785
|
+
/** @deprecated Use `initialDiffModeRatio` instead. */
|
|
707
786
|
diffModeRatio?: number
|
|
787
|
+
/** @deprecated Use `initialFileListMode` instead. */
|
|
708
788
|
fileListMode?: GitFileListMode
|
|
789
|
+
/** @deprecated Use `initialTreeCompaction` instead. */
|
|
709
790
|
treeCompaction?: boolean
|
|
710
|
-
path?: GitPanePathConfig
|
|
711
|
-
diffCount?: GitPaneDiffCountConfig
|
|
712
|
-
/** Prefetch N neighbouring diffs around the cursor; 0 disables. */
|
|
713
|
-
prefetchRadius?: number
|
|
714
791
|
}
|
|
715
792
|
|
|
716
793
|
export interface GitPaneEmbeddedConfig extends GitPaneBaseConfig {
|
|
794
|
+
initialMode?: 'embedded'
|
|
795
|
+
initialPosition?: 'top' | 'bottom'
|
|
796
|
+
/** @deprecated Use `initialMode` instead. */
|
|
717
797
|
mode?: 'embedded'
|
|
798
|
+
/** @deprecated Use `initialPosition` instead. */
|
|
718
799
|
position?: 'top' | 'bottom'
|
|
719
800
|
}
|
|
720
801
|
|
|
721
802
|
export interface GitPanePaneConfig extends GitPaneBaseConfig {
|
|
803
|
+
initialMode: 'pane'
|
|
804
|
+
initialPosition?: 'left' | 'right'
|
|
805
|
+
/** @deprecated Use `initialMode` instead. */
|
|
722
806
|
mode: 'pane'
|
|
807
|
+
/** @deprecated Use `initialPosition` instead. */
|
|
723
808
|
position?: 'left' | 'right'
|
|
724
809
|
}
|
|
725
810
|
|
|
726
811
|
export type GitPaneConfig = GitPaneEmbeddedConfig | GitPanePaneConfig
|
|
727
812
|
|
|
813
|
+
export interface AutoCommitConfig {
|
|
814
|
+
enabled: boolean
|
|
815
|
+
timeoutMs: number
|
|
816
|
+
models: Partial<Record<string, string>>
|
|
817
|
+
}
|
|
818
|
+
|
|
728
819
|
export interface AimuxThemeConfig {
|
|
729
|
-
|
|
820
|
+
/** Startup override for light/dark theme family. Reapplied on each launch. */
|
|
821
|
+
initialMode?: ThemeMode
|
|
730
822
|
paletteOverrides?: Partial<AimuxPalette>
|
|
823
|
+
/** @deprecated Use `initialMode` instead. */
|
|
824
|
+
mode?: ThemeMode
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
export type AIUsageTool = 'claude' | 'codex'
|
|
828
|
+
|
|
829
|
+
export interface AIUsageToolConfig {
|
|
830
|
+
enabled?: boolean
|
|
831
|
+
pollSeconds?: number
|
|
832
|
+
claudePlan?: 'auto' | 'pro' | 'max5' | 'max20'
|
|
833
|
+
codexWeeklyLimit?: number
|
|
834
|
+
tools?: AIUsageTool[]
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
export interface StatusBarConfig {
|
|
838
|
+
aiUsage?: AIUsageToolConfig
|
|
731
839
|
}
|
|
732
840
|
|
|
733
841
|
export interface AimuxUserConfig {
|
|
@@ -739,6 +847,8 @@ export interface AimuxUserConfig {
|
|
|
739
847
|
gitPane?: GitPaneConfig
|
|
740
848
|
hooks?: HooksConfig
|
|
741
849
|
snippets?: SnippetDef[]
|
|
850
|
+
autoCommit?: Partial<AutoCommitConfig>
|
|
851
|
+
statusBar?: StatusBarConfig
|
|
742
852
|
}
|
|
743
853
|
|
|
744
854
|
// ─── Resolved config (internal) ───────────────────────────────────────────────
|
|
@@ -764,12 +874,46 @@ export interface ResolvedKeymapConfig {
|
|
|
764
874
|
}
|
|
765
875
|
|
|
766
876
|
export interface ResolvedConfig {
|
|
767
|
-
theme:
|
|
877
|
+
theme:
|
|
878
|
+
| {
|
|
879
|
+
initialMode?: ThemeMode
|
|
880
|
+
paletteOverrides?: Partial<AimuxPalette>
|
|
881
|
+
}
|
|
882
|
+
| undefined
|
|
768
883
|
keymaps: ResolvedKeymapConfig
|
|
769
884
|
backends: Record<string, BackendConfig>
|
|
770
885
|
sidebar: SidebarConfig
|
|
771
|
-
sessionBar:
|
|
772
|
-
|
|
886
|
+
sessionBar: {
|
|
887
|
+
initialVisible?: boolean
|
|
888
|
+
initialPosition?: SessionBarPosition
|
|
889
|
+
}
|
|
890
|
+
gitPane:
|
|
891
|
+
| {
|
|
892
|
+
initialMode?: 'embedded'
|
|
893
|
+
initialPosition?: 'top' | 'bottom'
|
|
894
|
+
initialVisible?: boolean
|
|
895
|
+
initialRatio?: number
|
|
896
|
+
initialDiffModeRatio?: number
|
|
897
|
+
initialFileListMode?: GitFileListMode
|
|
898
|
+
initialTreeCompaction?: boolean
|
|
899
|
+
path?: GitPanePathConfig
|
|
900
|
+
diffCount?: GitPaneDiffCountConfig
|
|
901
|
+
prefetchRadius?: number
|
|
902
|
+
}
|
|
903
|
+
| {
|
|
904
|
+
initialMode: 'pane'
|
|
905
|
+
initialPosition?: 'left' | 'right'
|
|
906
|
+
initialVisible?: boolean
|
|
907
|
+
initialRatio?: number
|
|
908
|
+
initialDiffModeRatio?: number
|
|
909
|
+
initialFileListMode?: GitFileListMode
|
|
910
|
+
initialTreeCompaction?: boolean
|
|
911
|
+
path?: GitPanePathConfig
|
|
912
|
+
diffCount?: GitPaneDiffCountConfig
|
|
913
|
+
prefetchRadius?: number
|
|
914
|
+
}
|
|
773
915
|
hooks: HooksConfig
|
|
774
916
|
snippets: SnippetDef[]
|
|
917
|
+
autoCommit: AutoCommitConfig
|
|
918
|
+
statusBar: StatusBarConfig
|
|
775
919
|
}
|