@brimveyn/aimux-config 0.3.5 → 0.4.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/src/themes.ts CHANGED
@@ -1,252 +1,53 @@
1
- import type { ThemeColors, ThemeDefinition, ThemeId } from './types'
1
+ import type {
2
+ NamedTheme,
3
+ NamedThemeDefinition,
4
+ Theme,
5
+ ThemeColorMap,
6
+ ThemeDefinition,
7
+ ThemeId,
8
+ } from './types'
2
9
 
3
- export const THEMES: Record<ThemeId, { name: string; colors: ThemeColors }> = {
4
- 'aimux': {
5
- colors: {
6
- accent: '#7cd1b8',
7
- accentAlt: '#c4a7e7',
8
- background: '#11151b',
9
- border: '#2d3f52',
10
- borderActive: '#7cd1b8',
11
- danger: '#f38ba8',
12
- dim: '#243242',
13
- overlay: '#0b1016',
14
- panel: '#16202b',
15
- panelHighlight: '#1f3344',
16
- panelMuted: '#1c2734',
17
- success: '#8bd5ca',
18
- text: '#edf4ff',
19
- textMuted: '#6b829a',
20
- warning: '#f6c177',
21
- },
22
- name: 'Aimux',
23
- },
24
- 'catppuccin-mocha': {
25
- colors: {
26
- accent: '#cba6f7',
27
- accentAlt: '#f5c2e7',
28
- background: '#1e1e2e',
29
- border: '#45475a',
30
- borderActive: '#cba6f7',
31
- danger: '#f38ba8',
32
- dim: '#313244',
33
- overlay: '#181825',
34
- panel: '#232334',
35
- panelHighlight: '#313244',
36
- panelMuted: '#2a2a3c',
37
- success: '#a6e3a1',
38
- text: '#cdd6f4',
39
- textMuted: '#6c7086',
40
- warning: '#f9e2af',
41
- },
42
- name: 'Catppuccin Mocha',
43
- },
44
- 'dracula': {
45
- colors: {
46
- accent: '#bd93f9',
47
- accentAlt: '#ff79c6',
48
- background: '#282a36',
49
- border: '#44475a',
50
- borderActive: '#bd93f9',
51
- danger: '#ff5555',
52
- dim: '#383a4a',
53
- overlay: '#1f2029',
54
- panel: '#2d2f3d',
55
- panelHighlight: '#3d4056',
56
- panelMuted: '#343746',
57
- success: '#50fa7b',
58
- text: '#f8f8f2',
59
- textMuted: '#6272a4',
60
- warning: '#f1fa8c',
61
- },
62
- name: 'Dracula',
63
- },
64
- 'dracula-at-night': {
65
- colors: {
66
- accent: '#bd93f9',
67
- accentAlt: '#ff79c6',
68
- background: '#0e1419',
69
- border: '#2a3440',
70
- borderActive: '#bd93f9',
71
- danger: '#ff5555',
72
- dim: '#1e2630',
73
- overlay: '#090d11',
74
- panel: '#131920',
75
- panelHighlight: '#222a33',
76
- panelMuted: '#1a2129',
77
- success: '#50fa7b',
78
- text: '#f8f8f2',
79
- textMuted: '#6272a4',
80
- warning: '#f1fa8c',
81
- },
82
- name: 'Dracula At Night',
83
- },
84
- 'everforest': {
85
- colors: {
86
- accent: '#a7c080',
87
- accentAlt: '#d699b6',
88
- background: '#2d353b',
89
- border: '#4f585e',
90
- borderActive: '#a7c080',
91
- danger: '#e67e80',
92
- dim: '#3d484d',
93
- overlay: '#232a2e',
94
- panel: '#343f44',
95
- panelHighlight: '#475258',
96
- panelMuted: '#3d484d',
97
- success: '#a7c080',
98
- text: '#d3c6aa',
99
- textMuted: '#859289',
100
- warning: '#dbbc7f',
101
- },
102
- name: 'Everforest',
103
- },
104
- 'gruvbox-dark': {
105
- colors: {
106
- accent: '#b8bb26',
107
- accentAlt: '#d3869b',
108
- background: '#282828',
109
- border: '#504945',
110
- borderActive: '#b8bb26',
111
- danger: '#fb4934',
112
- dim: '#3c3836',
113
- overlay: '#1f1d1b',
114
- panel: '#2e2e2e',
115
- panelHighlight: '#504945',
116
- panelMuted: '#3c3836',
117
- success: '#b8bb26',
118
- text: '#ebdbb2',
119
- textMuted: '#928374',
120
- warning: '#fabd2f',
121
- },
122
- name: 'Gruvbox Dark',
123
- },
124
- 'kanagawa': {
125
- colors: {
126
- accent: '#7e9cd8',
127
- accentAlt: '#957fb8',
128
- background: '#1f1f28',
129
- border: '#363646',
130
- borderActive: '#7e9cd8',
131
- danger: '#e82424',
132
- dim: '#2a2a37',
133
- overlay: '#171720',
134
- panel: '#24242e',
135
- panelHighlight: '#363646',
136
- panelMuted: '#2a2a37',
137
- success: '#76946a',
138
- text: '#dcd7ba',
139
- textMuted: '#727169',
140
- warning: '#e6c384',
141
- },
142
- name: 'Kanagawa',
143
- },
144
- 'nord': {
145
- colors: {
146
- accent: '#88c0d0',
147
- accentAlt: '#b48ead',
148
- background: '#2e3440',
149
- border: '#434c5e',
150
- borderActive: '#88c0d0',
151
- danger: '#bf616a',
152
- dim: '#3b4252',
153
- overlay: '#252a33',
154
- panel: '#333a47',
155
- panelHighlight: '#434c5e',
156
- panelMuted: '#3b4252',
157
- success: '#a3be8c',
158
- text: '#eceff4',
159
- textMuted: '#7b88a1',
160
- warning: '#ebcb8b',
161
- },
162
- name: 'Nord',
163
- },
164
- 'one-dark': {
165
- colors: {
166
- accent: '#61afef',
167
- accentAlt: '#c678dd',
168
- background: '#282c34',
169
- border: '#3e4452',
170
- borderActive: '#61afef',
171
- danger: '#e06c75',
172
- dim: '#3b4048',
173
- overlay: '#1f2329',
174
- panel: '#2c313a',
175
- panelHighlight: '#3b4048',
176
- panelMuted: '#333842',
177
- success: '#98c379',
178
- text: '#abb2bf',
179
- textMuted: '#636d83',
180
- warning: '#e5c07b',
181
- },
182
- name: 'One Dark',
183
- },
184
- 'solarized-dark': {
185
- colors: {
186
- accent: '#268bd2',
187
- accentAlt: '#d33682',
188
- background: '#002b36',
189
- border: '#2e5560',
190
- borderActive: '#268bd2',
191
- danger: '#dc322f',
192
- dim: '#073642',
193
- overlay: '#00242c',
194
- panel: '#003340',
195
- panelHighlight: '#0a4050',
196
- panelMuted: '#073642',
197
- success: '#859900',
198
- text: '#fdf6e3',
199
- textMuted: '#657b83',
200
- warning: '#b58900',
201
- },
202
- name: 'Solarized Dark',
203
- },
204
- 'tokyo-night': {
205
- colors: {
206
- accent: '#7aa2f7',
207
- accentAlt: '#bb9af7',
208
- background: '#1a1b26',
209
- border: '#3b4261',
210
- borderActive: '#7aa2f7',
211
- danger: '#f7768e',
212
- dim: '#292e42',
213
- overlay: '#141722',
214
- panel: '#1f2335',
215
- panelHighlight: '#292e42',
216
- panelMuted: '#24283b',
217
- success: '#9ece6a',
218
- text: '#c0caf5',
219
- textMuted: '#565f89',
220
- warning: '#e0af68',
221
- },
222
- name: 'Tokyo Night',
223
- },
10
+ import { HOUSE_THEME_IDS, HOUSE_THEMES } from './house-themes'
11
+ import { GENERATED_THEME_IDS, GENERATED_THEMES } from './themes.generated'
12
+
13
+ export const THEMES: Record<string, Theme> = { ...GENERATED_THEMES, ...HOUSE_THEMES }
14
+ export const THEME_IDS: ThemeId[] = [...GENERATED_THEME_IDS, ...HOUSE_THEME_IDS]
15
+
16
+ const LEGACY_THEME_ALIASES: Record<string, ThemeId> = {
17
+ 'everforest': 'everforest-dark',
18
+ 'gruvbox-dark': 'gruvbox-dark-hard',
19
+ 'kanagawa': 'kanagawa-wave',
20
+ 'one-dark': 'one-dark-pro',
224
21
  }
225
22
 
226
- export const THEME_IDS = Object.keys(THEMES) as ThemeId[]
23
+ export function migrateThemeId(id: string | undefined): ThemeId {
24
+ if (id !== undefined && id in THEMES) return id as ThemeId
25
+ if (id !== undefined) {
26
+ const alias = LEGACY_THEME_ALIASES[id]
27
+ if (alias !== undefined) return alias
28
+ }
29
+ return 'aimux'
30
+ }
227
31
 
228
- /**
229
- * Theme helpers for user configs.
230
- */
231
32
  export const themes = {
232
33
  /**
233
- * Create a fully custom theme from scratch.
34
+ * Palette shortcut. Clones `base`'s Theme and patches a few VSCode color keys
35
+ * in `colors`. Token settings inherit from the base unchanged.
234
36
  */
235
- create(colors: ThemeColors): ThemeDefinition {
236
- return { colors }
37
+ define(name: string, base: ThemeId, overrides: Partial<ThemeColorMap>): NamedThemeDefinition {
38
+ return { base, colors: overrides, name }
39
+ },
40
+ /**
41
+ * Lower-level, unnamed variant of `define`. Prefer `define` for config entries.
42
+ */
43
+ extend(base: ThemeId, overrides: Partial<ThemeColorMap>): ThemeDefinition {
44
+ return { base, colors: overrides }
237
45
  },
238
-
239
46
  /**
240
- * Create a new theme by extending an existing built-in theme with overrides.
47
+ * Identity passthrough for a full raw Shiki theme. Use this to drop a VSCode
48
+ * theme JSON verbatim into aimux config.
241
49
  */
242
- extend(base: ThemeId, overrides: Partial<ThemeColors>): ThemeDefinition {
243
- const baseTheme = THEMES[base]
244
- if (!baseTheme) {
245
- throw new Error(`themes.extend: unknown base theme "${base}"`)
246
- }
247
- return {
248
- base,
249
- colors: { ...baseTheme.colors, ...overrides },
250
- }
50
+ full(theme: NamedTheme): NamedTheme {
51
+ return theme
251
52
  },
252
53
  }
package/src/types.ts CHANGED
@@ -23,6 +23,7 @@ export type ModeId =
23
23
  | 'modal.snippet-picker.filtering'
24
24
  | 'modal.snippet-editor'
25
25
  | 'modal.theme-picker'
26
+ | 'modal.theme-picker.filtering'
26
27
  | 'modal.help'
27
28
  | 'modal.help.filtering'
28
29
  | 'modal.split-picker'
@@ -162,6 +163,8 @@ export interface GitPaneState {
162
163
  mode: 'embedded' | 'pane'
163
164
  position: 'top' | 'bottom' | 'left' | 'right'
164
165
  ratio: number
166
+ diffModeRatio: number
167
+ fileListMode: GitFileListMode
165
168
  path: GitPanePathConfig
166
169
  diffCount: GitPaneDiffCountConfig
167
170
  }
@@ -200,12 +203,23 @@ export interface DiffData {
200
203
  errorMessage?: string
201
204
  }
202
205
 
206
+ export type GitDiffView = 'split' | 'stacked'
207
+ export type GitFileListMode = 'tree' | 'flat'
208
+
209
+ export interface FoldState {
210
+ top: number
211
+ bottom: number
212
+ }
213
+
203
214
  export interface GitModeState {
204
- selectedFileIndex: number
215
+ selectedEntryKey: string | null
216
+ collapsedFolders: Record<string, true>
205
217
  diffs: Record<string, DiffData>
206
218
  loading: Record<string, boolean>
207
219
  pendingDeletePath: string | null
208
220
  actionMessage: string | null
221
+ diffView: GitDiffView
222
+ folds: Record<string, Record<string, FoldState>>
209
223
  }
210
224
 
211
225
  interface ModalBase {
@@ -238,10 +252,12 @@ export interface ModalSnippetPicker extends ModalBase {
238
252
  }
239
253
  export interface ModalThemePicker extends ModalBase {
240
254
  type: 'theme-picker'
255
+ entryCount: number
241
256
  }
242
257
  export interface ModalHelp extends ModalBase {
243
258
  type: 'help'
244
259
  entryCount: number
260
+ scope: ModeId | null
245
261
  }
246
262
  export interface ModalSplitPicker extends ModalBase {
247
263
  type: 'split-picker'
@@ -323,7 +339,7 @@ export interface AppState {
323
339
 
324
340
  export type ModalAction =
325
341
  | { type: 'open-new-tab-modal' }
326
- | { type: 'open-help-modal' }
342
+ | { type: 'open-help-modal'; scope?: ModeId }
327
343
  | { type: 'open-split-picker'; direction: SplitDirection }
328
344
  | { type: 'open-session-picker' }
329
345
  | { type: 'open-session-name-modal'; sessionTargetId?: string; initialName?: string }
@@ -343,7 +359,9 @@ export type ModalAction =
343
359
  | { type: 'open-snippet-editor'; snippetId?: string }
344
360
  | { type: 'begin-snippet-filter' }
345
361
  | { type: 'begin-help-filter' }
362
+ | { type: 'begin-theme-filter' }
346
363
  | { type: 'set-help-entry-count'; count: number }
364
+ | { type: 'set-theme-entry-count'; count: number }
347
365
  | { type: 'open-theme-picker' }
348
366
  | { type: 'open-update-available-modal'; currentVersion: string; latestVersion: string }
349
367
 
@@ -415,6 +433,7 @@ export type UIAction =
415
433
  | { type: 'set-terminal-size'; cols: number; rows: number }
416
434
  | { type: 'toggle-git-pane' }
417
435
  | { type: 'resize-git-pane'; delta: number }
436
+ | { type: 'resize-git-diff-pane'; delta: number }
418
437
  | { type: 'set-git-pane-mode'; mode: 'embedded' | 'pane' }
419
438
  | { type: 'set-git-pane-position'; position: 'top' | 'bottom' | 'left' | 'right' }
420
439
  | { type: 'set-pending-chords'; chords: string[] | null }
@@ -436,12 +455,28 @@ export type GitPanelAction =
436
455
  export type GitModeAction =
437
456
  | { type: 'enter-git-mode' }
438
457
  | { type: 'exit-git-mode' }
439
- | { type: 'git-mode-select-file'; delta: -1 | 1 }
440
- | { type: 'git-mode-set-diff'; path: string; diff: DiffData }
441
- | { type: 'git-mode-set-loading'; path: string; loading: boolean }
458
+ | { type: 'git-mode-move-selection'; delta: -1 | 1 }
459
+ | { type: 'git-mode-move-file-selection'; delta: -1 | 1 }
460
+ | { type: 'git-mode-select-entry-by-key'; key: string }
461
+ | { type: 'git-mode-toggle-folder'; key: string }
462
+ | { type: 'git-mode-toggle-selected-folder' }
463
+ | { type: 'git-mode-collapse-selection' }
464
+ | { type: 'git-mode-expand-selection' }
465
+ | { type: 'git-mode-toggle-file-list-mode' }
466
+ | { type: 'git-mode-set-diff'; key: string; diff: DiffData }
467
+ | { type: 'git-mode-set-loading'; key: string; loading: boolean }
442
468
  | { type: 'git-mode-set-pending-delete'; path: string | null }
443
469
  | { type: 'git-mode-clear-diff-cache'; path: string }
444
470
  | { type: 'git-mode-set-message'; message: string | null }
471
+ | { type: 'git-mode-toggle-diff-view' }
472
+ | {
473
+ type: 'git-mode-fold-adjust'
474
+ key: string
475
+ foldId: string
476
+ side: 'top' | 'bottom'
477
+ delta: number
478
+ }
479
+ | { type: 'git-mode-fold-set'; key: string; foldId: string; top: number; bottom: number }
445
480
  | {
446
481
  type: 'git-mode-optimistic-move'
447
482
  path: string
@@ -489,6 +524,8 @@ export type SideEffect =
489
524
  | { type: 'split-pane'; direction: SplitDirection }
490
525
  | { type: 'confirm-split' }
491
526
  | { type: 'scroll-git-diff'; delta: number }
527
+ | { type: 'persist-git-diff-mode-ratio'; ratio: number }
528
+ | { type: 'persist-git-file-list-mode'; mode: GitFileListMode }
492
529
  | { type: 'git-stage'; path: string }
493
530
  | { type: 'git-unstage'; path: string }
494
531
  | { type: 'git-restore'; path: string }
@@ -521,40 +558,126 @@ export interface ModeContext {
521
558
 
522
559
  // ─── Themes ───────────────────────────────────────────────────────────────────
523
560
 
524
- export interface ThemeColors {
525
- background: string
526
- panel: string
527
- panelMuted: string
528
- panelHighlight: string
529
- overlay: string
530
- border: string
531
- borderActive: string
532
- text: string
533
- textMuted: string
534
- accent: string
535
- accentAlt: string
536
- warning: string
537
- danger: string
538
- success: string
539
- dim: string
540
- }
541
-
542
- export type ThemeId =
543
- | 'aimux'
544
- | 'dracula'
545
- | 'dracula-at-night'
546
- | 'everforest'
547
- | 'tokyo-night'
548
- | 'gruvbox-dark'
549
- | 'catppuccin-mocha'
550
- | 'nord'
551
- | 'solarized-dark'
552
- | 'one-dark'
553
- | 'kanagawa'
554
-
561
+ import type { BundledTheme } from 'shiki'
562
+
563
+ export type ThemeId = BundledTheme | (string & {})
564
+
565
+ /**
566
+ * VSCode workbench color keys aimux's UI depends on. The build-time normalizer
567
+ * guarantees every `Theme` has all of these populated.
568
+ */
569
+ export const AIMUX_COLOR_KEYS = [
570
+ // editor
571
+ 'editor.background',
572
+ 'editor.foreground',
573
+ 'editor.lineHighlightBackground',
574
+ 'editor.selectionBackground',
575
+ 'editorLineNumber.foreground',
576
+ 'editorCursor.foreground',
577
+ // sidebar / panels
578
+ 'sideBar.background',
579
+ 'sideBar.foreground',
580
+ 'sideBarSectionHeader.background',
581
+ 'sideBarSectionHeader.foreground',
582
+ 'editorGroupHeader.tabsBackground',
583
+ 'editorWidget.background',
584
+ 'panel.background',
585
+ 'panel.border',
586
+ // borders & focus
587
+ 'focusBorder',
588
+ 'editorGroup.border',
589
+ 'contrastBorder',
590
+ // lists
591
+ 'list.activeSelectionBackground',
592
+ 'list.activeSelectionForeground',
593
+ 'list.hoverBackground',
594
+ // text & links
595
+ 'foreground',
596
+ 'descriptionForeground',
597
+ 'textLink.foreground',
598
+ 'textLink.activeForeground',
599
+ // status
600
+ 'errorForeground',
601
+ 'editorError.foreground',
602
+ 'editorWarning.foreground',
603
+ // terminal ANSI
604
+ 'terminal.ansiRed',
605
+ 'terminal.ansiGreen',
606
+ 'terminal.ansiYellow',
607
+ 'terminal.ansiBlue',
608
+ 'terminal.ansiMagenta',
609
+ 'terminal.ansiCyan',
610
+ // git decorations
611
+ 'gitDecoration.addedResourceForeground',
612
+ 'gitDecoration.modifiedResourceForeground',
613
+ 'gitDecoration.deletedResourceForeground',
614
+ 'gitDecoration.untrackedResourceForeground',
615
+ // diff editor
616
+ 'diffEditor.insertedLineBackground',
617
+ 'diffEditor.removedLineBackground',
618
+ // input
619
+ 'input.background',
620
+ 'input.foreground',
621
+ 'input.border',
622
+ ] as const
623
+
624
+ export type AimuxColorKey = (typeof AIMUX_COLOR_KEYS)[number]
625
+
626
+ export type ThemeColorMap = Record<AimuxColorKey, string> & Record<string, string>
627
+
628
+ export interface ThemeSettings {
629
+ fontStyle?: string
630
+ foreground?: string
631
+ background?: string
632
+ // Some bundled shiki themes include non-standard keys (e.g. `content`); allow passthrough.
633
+ [key: string]: string | undefined
634
+ }
635
+
636
+ export interface ThemeTokenRule {
637
+ name?: string
638
+ scope?: string | string[]
639
+ // `foreground` at the top level is used by a handful of shiki themes as a
640
+ // shorthand for `settings.foreground` — accept both forms.
641
+ foreground?: string
642
+ settings?: ThemeSettings
643
+ }
644
+
645
+ export interface Theme {
646
+ name: string
647
+ displayName: string
648
+ type: 'dark' | 'light'
649
+ fg: string
650
+ bg: string
651
+ colors: ThemeColorMap
652
+ settings: ThemeTokenRule[]
653
+ tokenColors?: ThemeTokenRule[]
654
+ colorReplacements?: Record<string, string>
655
+ semanticHighlighting?: boolean
656
+ semanticTokenColors?: Record<
657
+ string,
658
+ | string
659
+ | {
660
+ foreground?: string
661
+ fontStyle?: string
662
+ bold?: boolean
663
+ italic?: boolean
664
+ underline?: boolean
665
+ }
666
+ >
667
+ }
668
+
669
+ /** Partial-override shape for `themes.define(name, base, overrides)`. */
555
670
  export interface ThemeDefinition {
556
671
  base?: ThemeId
557
- colors: ThemeColors
672
+ colors: Partial<ThemeColorMap>
673
+ }
674
+
675
+ export interface NamedThemeDefinition extends ThemeDefinition {
676
+ name: string
677
+ }
678
+
679
+ export interface NamedTheme extends Theme {
680
+ displayName: string
558
681
  }
559
682
 
560
683
  // ─── Backend config (stub) ────────────────────────────────────────────────────
@@ -648,6 +771,8 @@ export type GitPaneDiffCountConfig = { enabled: boolean }
648
771
  interface GitPaneBaseConfig {
649
772
  visible?: boolean
650
773
  ratio?: number
774
+ diffModeRatio?: number
775
+ fileListMode?: GitFileListMode
651
776
  path?: GitPanePathConfig
652
777
  diffCount?: GitPaneDiffCountConfig
653
778
  }
@@ -665,7 +790,8 @@ export interface GitPanePaneConfig extends GitPaneBaseConfig {
665
790
  export type GitPaneConfig = GitPaneEmbeddedConfig | GitPanePaneConfig
666
791
 
667
792
  export interface AimuxUserConfig {
668
- theme?: ThemeId | ThemeDefinition
793
+ theme?: ThemeId
794
+ themes?: Record<string, NamedThemeDefinition>
669
795
  keymaps?: (k: KeymapBuilderApi) => KeymapBuilderApi
670
796
  backends?: Record<string, BackendConfig>
671
797
  sidebar?: SidebarConfig
@@ -698,7 +824,8 @@ export interface ResolvedKeymapConfig {
698
824
  }
699
825
 
700
826
  export interface ResolvedConfig {
701
- theme: ThemeId | ThemeDefinition | undefined
827
+ theme: ThemeId | undefined
828
+ themes: Record<string, NamedThemeDefinition>
702
829
  keymaps: ResolvedKeymapConfig
703
830
  backends: Record<string, BackendConfig>
704
831
  sidebar: SidebarConfig