@brimveyn/aimux-config 0.5.5 → 0.5.7

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 (51) hide show
  1. package/package.json +1 -1
  2. package/src/index.ts +21 -31
  3. package/src/resolver.ts +1 -1
  4. package/src/tui/index.ts +5 -0
  5. package/src/tui/registry.ts +95 -0
  6. package/src/tui/resolve.ts +156 -0
  7. package/src/tui/shiki.ts +149 -0
  8. package/src/tui/themes/aimux.json +110 -0
  9. package/src/tui/themes/aura.json +69 -0
  10. package/src/tui/themes/ayu.json +80 -0
  11. package/src/tui/themes/carbonfox.json +248 -0
  12. package/src/tui/themes/catppuccin-frappe.json +230 -0
  13. package/src/tui/themes/catppuccin-macchiato.json +230 -0
  14. package/src/tui/themes/catppuccin.json +112 -0
  15. package/src/tui/themes/cobalt2.json +225 -0
  16. package/src/tui/themes/cursor.json +249 -0
  17. package/src/tui/themes/dracula.json +219 -0
  18. package/src/tui/themes/everforest.json +241 -0
  19. package/src/tui/themes/flexoki.json +237 -0
  20. package/src/tui/themes/github.json +233 -0
  21. package/src/tui/themes/gruvbox.json +242 -0
  22. package/src/tui/themes/kanagawa.json +77 -0
  23. package/src/tui/themes/lucent-orng.json +234 -0
  24. package/src/tui/themes/material.json +235 -0
  25. package/src/tui/themes/matrix.json +77 -0
  26. package/src/tui/themes/mercury.json +252 -0
  27. package/src/tui/themes/monokai.json +221 -0
  28. package/src/tui/themes/nightowl.json +221 -0
  29. package/src/tui/themes/nord.json +223 -0
  30. package/src/tui/themes/one-dark.json +84 -0
  31. package/src/tui/themes/opencode.json +245 -0
  32. package/src/tui/themes/orng.json +249 -0
  33. package/src/tui/themes/osaka-jade.json +93 -0
  34. package/src/tui/themes/palenight.json +222 -0
  35. package/src/tui/themes/rosepine.json +234 -0
  36. package/src/tui/themes/solarized.json +223 -0
  37. package/src/tui/themes/synthwave84.json +226 -0
  38. package/src/tui/themes/tokyonight.json +243 -0
  39. package/src/tui/themes/vercel.json +245 -0
  40. package/src/tui/themes/vesper.json +218 -0
  41. package/src/tui/themes/zenburn.json +223 -0
  42. package/src/tui/tokens.ts +111 -0
  43. package/src/tui/types.ts +30 -0
  44. package/src/types.ts +6 -35
  45. package/src/house-themes.ts +0 -55
  46. package/src/neutral-scale.ts +0 -75
  47. package/src/oklch.ts +0 -164
  48. package/src/palette-to-shiki.ts +0 -134
  49. package/src/palette-utils.ts +0 -130
  50. package/src/themes/opencode.ts +0 -1460
  51. package/src/themes.ts +0 -30
@@ -0,0 +1,223 @@
1
+ {
2
+ "$schema": "https://opencode.ai/theme.json",
3
+ "defs": {
4
+ "bg": "#3f3f3f",
5
+ "bgAlt": "#4f4f4f",
6
+ "bgPanel": "#5f5f5f",
7
+ "fg": "#dcdccc",
8
+ "fgMuted": "#9f9f9f",
9
+ "red": "#cc9393",
10
+ "redBright": "#dca3a3",
11
+ "green": "#7f9f7f",
12
+ "greenBright": "#8fb28f",
13
+ "yellow": "#f0dfaf",
14
+ "yellowDim": "#e0cf9f",
15
+ "blue": "#8cd0d3",
16
+ "blueDim": "#7cb8bb",
17
+ "magenta": "#dc8cc3",
18
+ "cyan": "#93e0e3",
19
+ "orange": "#dfaf8f"
20
+ },
21
+ "theme": {
22
+ "primary": {
23
+ "dark": "blue",
24
+ "light": "#5f7f8f"
25
+ },
26
+ "secondary": {
27
+ "dark": "magenta",
28
+ "light": "#8f5f8f"
29
+ },
30
+ "accent": {
31
+ "dark": "cyan",
32
+ "light": "#5f8f8f"
33
+ },
34
+ "error": {
35
+ "dark": "red",
36
+ "light": "#8f5f5f"
37
+ },
38
+ "warning": {
39
+ "dark": "yellow",
40
+ "light": "#8f8f5f"
41
+ },
42
+ "success": {
43
+ "dark": "green",
44
+ "light": "#5f8f5f"
45
+ },
46
+ "info": {
47
+ "dark": "orange",
48
+ "light": "#8f7f5f"
49
+ },
50
+ "text": {
51
+ "dark": "fg",
52
+ "light": "#3f3f3f"
53
+ },
54
+ "textMuted": {
55
+ "dark": "fgMuted",
56
+ "light": "#6f6f6f"
57
+ },
58
+ "background": {
59
+ "dark": "bg",
60
+ "light": "#ffffef"
61
+ },
62
+ "backgroundPanel": {
63
+ "dark": "bgAlt",
64
+ "light": "#f5f5e5"
65
+ },
66
+ "backgroundElement": {
67
+ "dark": "bgPanel",
68
+ "light": "#ebebdb"
69
+ },
70
+ "border": {
71
+ "dark": "#5f5f5f",
72
+ "light": "#d0d0c0"
73
+ },
74
+ "borderActive": {
75
+ "dark": "blue",
76
+ "light": "#5f7f8f"
77
+ },
78
+ "borderSubtle": {
79
+ "dark": "#4f4f4f",
80
+ "light": "#e0e0d0"
81
+ },
82
+ "diffAdded": {
83
+ "dark": "green",
84
+ "light": "#5f8f5f"
85
+ },
86
+ "diffRemoved": {
87
+ "dark": "red",
88
+ "light": "#8f5f5f"
89
+ },
90
+ "diffContext": {
91
+ "dark": "fgMuted",
92
+ "light": "#6f6f6f"
93
+ },
94
+ "diffHunkHeader": {
95
+ "dark": "cyan",
96
+ "light": "#5f8f8f"
97
+ },
98
+ "diffHighlightAdded": {
99
+ "dark": "greenBright",
100
+ "light": "#5f8f5f"
101
+ },
102
+ "diffHighlightRemoved": {
103
+ "dark": "redBright",
104
+ "light": "#8f5f5f"
105
+ },
106
+ "diffAddedBg": {
107
+ "dark": "#4f5f4f",
108
+ "light": "#efffef"
109
+ },
110
+ "diffRemovedBg": {
111
+ "dark": "#5f4f4f",
112
+ "light": "#ffefef"
113
+ },
114
+ "diffContextBg": {
115
+ "dark": "bgAlt",
116
+ "light": "#f5f5e5"
117
+ },
118
+ "diffLineNumber": {
119
+ "dark": "#d2d2d2",
120
+ "light": "textMuted"
121
+ },
122
+ "diffAddedLineNumberBg": {
123
+ "dark": "#4f5f4f",
124
+ "light": "#efffef"
125
+ },
126
+ "diffRemovedLineNumberBg": {
127
+ "dark": "#5f4f4f",
128
+ "light": "#ffefef"
129
+ },
130
+ "markdownText": {
131
+ "dark": "fg",
132
+ "light": "#3f3f3f"
133
+ },
134
+ "markdownHeading": {
135
+ "dark": "yellow",
136
+ "light": "#8f8f5f"
137
+ },
138
+ "markdownLink": {
139
+ "dark": "blue",
140
+ "light": "#5f7f8f"
141
+ },
142
+ "markdownLinkText": {
143
+ "dark": "cyan",
144
+ "light": "#5f8f8f"
145
+ },
146
+ "markdownCode": {
147
+ "dark": "green",
148
+ "light": "#5f8f5f"
149
+ },
150
+ "markdownBlockQuote": {
151
+ "dark": "fgMuted",
152
+ "light": "#6f6f6f"
153
+ },
154
+ "markdownEmph": {
155
+ "dark": "yellowDim",
156
+ "light": "#8f8f5f"
157
+ },
158
+ "markdownStrong": {
159
+ "dark": "orange",
160
+ "light": "#8f7f5f"
161
+ },
162
+ "markdownHorizontalRule": {
163
+ "dark": "fgMuted",
164
+ "light": "#6f6f6f"
165
+ },
166
+ "markdownListItem": {
167
+ "dark": "blue",
168
+ "light": "#5f7f8f"
169
+ },
170
+ "markdownListEnumeration": {
171
+ "dark": "cyan",
172
+ "light": "#5f8f8f"
173
+ },
174
+ "markdownImage": {
175
+ "dark": "blue",
176
+ "light": "#5f7f8f"
177
+ },
178
+ "markdownImageText": {
179
+ "dark": "cyan",
180
+ "light": "#5f8f8f"
181
+ },
182
+ "markdownCodeBlock": {
183
+ "dark": "fg",
184
+ "light": "#3f3f3f"
185
+ },
186
+ "syntaxComment": {
187
+ "dark": "#7f9f7f",
188
+ "light": "#5f7f5f"
189
+ },
190
+ "syntaxKeyword": {
191
+ "dark": "yellow",
192
+ "light": "#8f8f5f"
193
+ },
194
+ "syntaxFunction": {
195
+ "dark": "blue",
196
+ "light": "#5f7f8f"
197
+ },
198
+ "syntaxVariable": {
199
+ "dark": "fg",
200
+ "light": "#3f3f3f"
201
+ },
202
+ "syntaxString": {
203
+ "dark": "red",
204
+ "light": "#8f5f5f"
205
+ },
206
+ "syntaxNumber": {
207
+ "dark": "greenBright",
208
+ "light": "#5f8f5f"
209
+ },
210
+ "syntaxType": {
211
+ "dark": "cyan",
212
+ "light": "#5f8f8f"
213
+ },
214
+ "syntaxOperator": {
215
+ "dark": "yellow",
216
+ "light": "#8f8f5f"
217
+ },
218
+ "syntaxPunctuation": {
219
+ "dark": "fg",
220
+ "light": "#3f3f3f"
221
+ }
222
+ }
223
+ }
@@ -0,0 +1,111 @@
1
+ // 44-token namespace ported 1:1 from opencode TUI
2
+ // (opencode/packages/plugin/src/tui.ts:191-245).
3
+
4
+ export type TuiColorToken =
5
+ | 'primary'
6
+ | 'secondary'
7
+ | 'accent'
8
+ | 'error'
9
+ | 'warning'
10
+ | 'success'
11
+ | 'info'
12
+ | 'text'
13
+ | 'textMuted'
14
+ | 'selectedListItemText'
15
+ | 'background'
16
+ | 'backgroundPanel'
17
+ | 'backgroundElement'
18
+ | 'backgroundMenu'
19
+ | 'border'
20
+ | 'borderActive'
21
+ | 'borderSubtle'
22
+ | 'diffAdded'
23
+ | 'diffRemoved'
24
+ | 'diffContext'
25
+ | 'diffHunkHeader'
26
+ | 'diffHighlightAdded'
27
+ | 'diffHighlightRemoved'
28
+ | 'diffAddedBg'
29
+ | 'diffRemovedBg'
30
+ | 'diffContextBg'
31
+ | 'diffLineNumber'
32
+ | 'diffAddedLineNumberBg'
33
+ | 'diffRemovedLineNumberBg'
34
+ | 'markdownText'
35
+ | 'markdownHeading'
36
+ | 'markdownLink'
37
+ | 'markdownLinkText'
38
+ | 'markdownCode'
39
+ | 'markdownBlockQuote'
40
+ | 'markdownEmph'
41
+ | 'markdownStrong'
42
+ | 'markdownHorizontalRule'
43
+ | 'markdownListItem'
44
+ | 'markdownListEnumeration'
45
+ | 'markdownImage'
46
+ | 'markdownImageText'
47
+ | 'markdownCodeBlock'
48
+ | 'syntaxComment'
49
+ | 'syntaxKeyword'
50
+ | 'syntaxFunction'
51
+ | 'syntaxVariable'
52
+ | 'syntaxString'
53
+ | 'syntaxNumber'
54
+ | 'syntaxType'
55
+ | 'syntaxOperator'
56
+ | 'syntaxPunctuation'
57
+
58
+ export const TUI_COLOR_TOKENS: readonly TuiColorToken[] = [
59
+ 'primary',
60
+ 'secondary',
61
+ 'accent',
62
+ 'error',
63
+ 'warning',
64
+ 'success',
65
+ 'info',
66
+ 'text',
67
+ 'textMuted',
68
+ 'selectedListItemText',
69
+ 'background',
70
+ 'backgroundPanel',
71
+ 'backgroundElement',
72
+ 'backgroundMenu',
73
+ 'border',
74
+ 'borderActive',
75
+ 'borderSubtle',
76
+ 'diffAdded',
77
+ 'diffRemoved',
78
+ 'diffContext',
79
+ 'diffHunkHeader',
80
+ 'diffHighlightAdded',
81
+ 'diffHighlightRemoved',
82
+ 'diffAddedBg',
83
+ 'diffRemovedBg',
84
+ 'diffContextBg',
85
+ 'diffLineNumber',
86
+ 'diffAddedLineNumberBg',
87
+ 'diffRemovedLineNumberBg',
88
+ 'markdownText',
89
+ 'markdownHeading',
90
+ 'markdownLink',
91
+ 'markdownLinkText',
92
+ 'markdownCode',
93
+ 'markdownBlockQuote',
94
+ 'markdownEmph',
95
+ 'markdownStrong',
96
+ 'markdownHorizontalRule',
97
+ 'markdownListItem',
98
+ 'markdownListEnumeration',
99
+ 'markdownImage',
100
+ 'markdownImageText',
101
+ 'markdownCodeBlock',
102
+ 'syntaxComment',
103
+ 'syntaxKeyword',
104
+ 'syntaxFunction',
105
+ 'syntaxVariable',
106
+ 'syntaxString',
107
+ 'syntaxNumber',
108
+ 'syntaxType',
109
+ 'syntaxOperator',
110
+ 'syntaxPunctuation',
111
+ ] as const
@@ -0,0 +1,30 @@
1
+ import type { TuiColorToken } from './tokens'
2
+
3
+ export type ThemeMode = 'dark' | 'light'
4
+
5
+ /** RGBA in 0..255 (alpha 0..255, where 255 == opaque). */
6
+ export interface RGBA {
7
+ r: number
8
+ g: number
9
+ b: number
10
+ a: number
11
+ }
12
+
13
+ /** A single color value as it appears in a TUI theme JSON. */
14
+ export type TuiColorValue =
15
+ | string // hex (#rgb, #rrggbb, #rrggbbaa), ref to defs/token, "transparent", "none"
16
+ | number // ANSI color code 0..255
17
+ | { dark: TuiColorValue; light: TuiColorValue }
18
+
19
+ export interface TuiThemeJson {
20
+ $schema?: string
21
+ defs?: Record<string, TuiColorValue>
22
+ theme: Partial<Record<TuiColorToken, TuiColorValue>> & {
23
+ thinkingOpacity?: number
24
+ }
25
+ }
26
+
27
+ /** Resolved theme: every color token → CSS-style color string consumable by opentui. */
28
+ export type ResolvedTuiTheme = Record<TuiColorToken, string> & {
29
+ thinkingOpacity: number
30
+ }
package/src/types.ts CHANGED
@@ -656,40 +656,10 @@ export interface ModeContext {
656
656
 
657
657
  // ─── Themes ───────────────────────────────────────────────────────────────────
658
658
 
659
- /**
660
- * Compact opencode-style semantic palette. Required tokens cover every UI role;
661
- * optional tokens fall back via helpers in `palette-utils.ts`.
662
- */
663
- export interface AimuxPalette {
664
- // required
665
- neutral: string
666
- ink: string
667
- primary: string
668
- success: string
669
- warning: string
670
- error: string
671
- info: string
672
- // optional
673
- accent?: string
674
- interactive?: string
675
- diffAdd?: string
676
- diffDelete?: string
677
- }
659
+ // Theme types now live in `./tui` (1:1 port of opencode TUI). The aliases
660
+ // below preserve internal type wiring for the user-facing config API.
678
661
 
679
662
  export type ThemeMode = 'light' | 'dark'
680
- // eslint-disable-next-line typescript/no-redundant-type-constituents
681
- export type ThemeId = 'aimux-light' | 'aimux-dark' | (string & {})
682
-
683
- export interface AimuxTheme {
684
- name: string
685
- mode: ThemeMode
686
- displayName: string
687
- palette: AimuxPalette
688
- fg: string
689
- bg: string
690
- }
691
-
692
- export type Theme = AimuxTheme
693
663
 
694
664
  // ─── Backend config (stub) ────────────────────────────────────────────────────
695
665
 
@@ -846,9 +816,10 @@ export interface MultiRepoConfig {
846
816
  }
847
817
 
848
818
  export interface AimuxThemeConfig {
849
- /** Startup override for light/dark theme family. Reapplied on each launch. */
819
+ /** Startup theme id (one of `THEME_IDS` from `@brimveyn/aimux-config`). */
820
+ initialId?: string
821
+ /** Startup override for light/dark mode. Reapplied on each launch. */
850
822
  initialMode?: ThemeMode
851
- paletteOverrides?: Partial<AimuxPalette>
852
823
  /** @deprecated Use `initialMode` instead. */
853
824
  mode?: ThemeMode
854
825
  }
@@ -906,8 +877,8 @@ export interface ResolvedKeymapConfig {
906
877
  export interface ResolvedConfig {
907
878
  theme:
908
879
  | {
880
+ initialId?: string
909
881
  initialMode?: ThemeMode
910
- paletteOverrides?: Partial<AimuxPalette>
911
882
  }
912
883
  | undefined
913
884
  keymaps: ResolvedKeymapConfig
@@ -1,55 +0,0 @@
1
- // Hand-curated aimux house palettes. The opencode-style semantic palette
2
- // drives both UI chrome and the runtime-generated Shiki theme — see
3
- // `palette-to-shiki.ts`.
4
- /* eslint-disable perfectionist/sort-objects */
5
-
6
- import type { AimuxPalette, AimuxTheme } from './types'
7
-
8
- const AIMUX_DARK_PALETTE: AimuxPalette = {
9
- neutral: '#11151b',
10
- ink: '#edf4ff',
11
- primary: '#7cd1b8',
12
- success: '#8bd5ca',
13
- warning: '#f6c177',
14
- error: '#f38ba8',
15
- info: '#7cb3ff',
16
- accent: '#c4a7e7',
17
- interactive: '#1f3344',
18
- diffAdd: '#1e3d2b',
19
- diffDelete: '#3b1e27',
20
- }
21
-
22
- const AIMUX_LIGHT_PALETTE: AimuxPalette = {
23
- neutral: '#f7f9fc',
24
- ink: '#11151b',
25
- primary: '#1f8a72',
26
- success: '#2e9a83',
27
- warning: '#b8770f',
28
- error: '#c43b58',
29
- info: '#2e6cc1',
30
- accent: '#7d57b8',
31
- interactive: '#dbe6f0',
32
- diffAdd: '#d4ebd9',
33
- diffDelete: '#f0d6dc',
34
- }
35
-
36
- export const HOUSE_THEMES: Record<string, AimuxTheme> = {
37
- 'aimux-dark': {
38
- name: 'aimux',
39
- mode: 'dark',
40
- displayName: 'Aimux Dark',
41
- palette: AIMUX_DARK_PALETTE,
42
- fg: AIMUX_DARK_PALETTE.ink,
43
- bg: AIMUX_DARK_PALETTE.neutral,
44
- },
45
- 'aimux-light': {
46
- name: 'aimux',
47
- mode: 'light',
48
- displayName: 'Aimux Light',
49
- palette: AIMUX_LIGHT_PALETTE,
50
- fg: AIMUX_LIGHT_PALETTE.ink,
51
- bg: AIMUX_LIGHT_PALETTE.neutral,
52
- },
53
- }
54
-
55
- export const HOUSE_THEME_IDS: string[] = ['aimux-dark', 'aimux-light']
@@ -1,75 +0,0 @@
1
- // Port (minimal) of sst/opencode's generateNeutralScale + generateNeutralAlphaScale
2
- // from packages/ui/src/theme/resolve.ts. Only the `ink`-provided branch of
3
- // generateNeutralScale is needed — every aimux theme supplies an `ink` seed.
4
-
5
- import { blend, hexToOklch, mixColors, oklchToHex } from './oklch'
6
-
7
- function clamp(v: number, min: number, max: number): number {
8
- return Math.max(min, Math.min(max, v))
9
- }
10
-
11
- export type NeutralScale = readonly [
12
- string,
13
- string,
14
- string,
15
- string,
16
- string,
17
- string,
18
- string,
19
- string,
20
- string,
21
- string,
22
- string,
23
- string,
24
- ]
25
-
26
- function pickDarkBg(base: { c: number; h: number; l: number }): string {
27
- const tone = clamp(0.19 + Math.max(0, base.l - 0.12) * 0.33 + base.c * 1.95, 0.17, 0.27)
28
- return oklchToHex({
29
- c: base.c * Math.max(0, 1 - tone * 0.12),
30
- h: base.h,
31
- l: base.l * (1 - tone),
32
- })
33
- }
34
-
35
- function pickLightBg(base: { c: number; h: number; l: number }): string {
36
- const tone =
37
- base.l < 0.82 ? 0.86 : clamp(0.1 + base.c * 3.2 + Math.max(0, 0.95 - base.l) * 0.35, 0.1, 0.28)
38
- return oklchToHex({
39
- c: base.c * Math.max(0, 1 - tone),
40
- h: base.h,
41
- l: base.l + (1 - base.l) * tone,
42
- })
43
- }
44
-
45
- /**
46
- * Produce a 12-step neutral scale from a palette seed.
47
- *
48
- * Step 0 is the effective app background (`palette.neutral` is treated as a
49
- * seed, not a direct hex). Step 11 lands close to `ink`. Intermediate steps
50
- * mix the computed bg toward ink using opencode's fixed lightness stops.
51
- */
52
- export function generateNeutralScale(seed: string, isDark: boolean, ink: string): NeutralScale {
53
- const base = hexToOklch(seed)
54
- const bg = isDark ? pickDarkBg(base) : pickLightBg(base)
55
-
56
- const steps = isDark
57
- ? [0, 0.018, 0.039, 0.064, 0.097, 0.143, 0.212, 0.31, 0.46, 0.649, 0.845, 0.984]
58
- : [0, 0.022, 0.042, 0.068, 0.102, 0.146, 0.208, 0.296, 0.432, 0.61, 0.81, 0.965]
59
-
60
- return steps.map((step) => mixColors(bg, ink, step)) as unknown as NeutralScale
61
- }
62
-
63
- /**
64
- * 12-step alpha overlay scale blending ink → bg. Used for surface-base /
65
- * surface-hover / border-base tokens so they stay consistent with the
66
- * computed bg above.
67
- */
68
- export function generateNeutralAlphaScale(neutral: NeutralScale, isDark: boolean): NeutralScale {
69
- const alphas = isDark
70
- ? [0.038, 0.066, 0.1, 0.142, 0.19, 0.252, 0.334, 0.446, 0.58, 0.718, 0.854, 0.985]
71
- : [0.03, 0.06, 0.1, 0.145, 0.2, 0.265, 0.35, 0.47, 0.61, 0.74, 0.86, 0.97]
72
- const ink = neutral[11]
73
- const bg = neutral[0]
74
- return alphas.map((alpha) => blend(ink, bg, alpha)) as unknown as NeutralScale
75
- }