saeeol 1.2.2 → 1.2.3

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 (50) hide show
  1. package/bin/saeeol.cjs +187 -0
  2. package/npm/bin/saeeol +0 -0
  3. package/package.json +2 -2
  4. package/src/cli/cmd/tui/component/dialog/dialog-mcp.tsx +3 -3
  5. package/src/cli/cmd/tui/component/dialog/dialog-model.tsx +1 -1
  6. package/src/cli/cmd/tui/component/dialog/dialog-provider.tsx +5 -5
  7. package/src/cli/cmd/tui/component/dialog/dialog-session-delete-failed.tsx +4 -4
  8. package/src/cli/cmd/tui/component/dialog/dialog-session-list.tsx +5 -5
  9. package/src/cli/cmd/tui/component/dialog/dialog-session-rename.tsx +3 -3
  10. package/src/cli/cmd/tui/component/dialog/dialog-stash.tsx +2 -2
  11. package/src/cli/cmd/tui/component/dialog/dialog-status.tsx +3 -3
  12. package/src/cli/cmd/tui/component/dialog/dialog-theme-list.tsx +4 -4
  13. package/src/cli/cmd/tui/component/dialog/dialog-workspace-create.tsx +4 -4
  14. package/src/cli/cmd/tui/component/dialog/dialog-workspace-unavailable.tsx +4 -4
  15. package/src/cli/cmd/tui/context/app/args.tsx +15 -0
  16. package/src/cli/cmd/tui/context/app/directory.ts +15 -0
  17. package/src/cli/cmd/tui/context/app/editor-zed.ts +281 -0
  18. package/src/cli/cmd/tui/context/app/editor.ts +425 -0
  19. package/src/cli/cmd/tui/context/app/helper.tsx +25 -0
  20. package/src/cli/cmd/tui/context/app/project.tsx +109 -0
  21. package/src/cli/cmd/tui/context/app/route.tsx +67 -0
  22. package/src/cli/cmd/tui/context/app/sdk.tsx +142 -0
  23. package/src/cli/cmd/tui/context/app/sync.tsx +713 -0
  24. package/src/cli/cmd/tui/context/app/theme.tsx +307 -0
  25. package/src/cli/cmd/tui/context/app/tui-config.tsx +9 -0
  26. package/src/cli/cmd/tui/context/args.tsx +1 -15
  27. package/src/cli/cmd/tui/context/directory.ts +1 -15
  28. package/src/cli/cmd/tui/context/editor-zed.ts +1 -281
  29. package/src/cli/cmd/tui/context/editor.ts +1 -425
  30. package/src/cli/cmd/tui/context/event.ts +1 -45
  31. package/src/cli/cmd/tui/context/exit.tsx +1 -67
  32. package/src/cli/cmd/tui/context/helper.tsx +1 -25
  33. package/src/cli/cmd/tui/context/keybind.tsx +1 -105
  34. package/src/cli/cmd/tui/context/kv.tsx +1 -76
  35. package/src/cli/cmd/tui/context/local.tsx +1 -478
  36. package/src/cli/cmd/tui/context/plugin-keybinds.ts +1 -41
  37. package/src/cli/cmd/tui/context/project.tsx +1 -109
  38. package/src/cli/cmd/tui/context/prompt.tsx +1 -18
  39. package/src/cli/cmd/tui/context/route.tsx +1 -67
  40. package/src/cli/cmd/tui/context/runtime/event.ts +45 -0
  41. package/src/cli/cmd/tui/context/runtime/exit.tsx +67 -0
  42. package/src/cli/cmd/tui/context/runtime/keybind.tsx +105 -0
  43. package/src/cli/cmd/tui/context/runtime/kv.tsx +76 -0
  44. package/src/cli/cmd/tui/context/runtime/local.tsx +478 -0
  45. package/src/cli/cmd/tui/context/runtime/plugin-keybinds.ts +41 -0
  46. package/src/cli/cmd/tui/context/sdk.tsx +1 -142
  47. package/src/cli/cmd/tui/context/session/prompt.tsx +18 -0
  48. package/src/cli/cmd/tui/context/sync.tsx +1 -713
  49. package/src/cli/cmd/tui/context/theme.tsx +1 -307
  50. package/src/cli/cmd/tui/context/tui-config.tsx +1 -9
@@ -1,307 +1 @@
1
- import { CliRenderEvents, type TerminalColors } from "@opentui/core"
2
- import path from "path"
3
- import { createEffect, createMemo, onCleanup, onMount } from "solid-js"
4
- import { createSimpleContext } from "./helper"
5
- import { Glob } from "@saeeol/core/util/glob"
6
- import { useKV } from "./kv"
7
- import { useRenderer } from "@opentui/solid"
8
- import { createStore, produce } from "solid-js/store"
9
- import { Global } from "@saeeol/core/global"
10
- import { Filesystem } from "@/util/filesystem"
11
- import { useTuiConfig } from "./tui-config"
12
- import { isRecord } from "@/util/record"
13
- import { selectedForeground, tint } from "./theme/theme-types"
14
- import type { ThemeJson, Theme } from "./theme/theme-types"
15
- import { DEFAULT_THEMES, isValidTheme } from "./theme/theme-themes"
16
- import { resolveTheme } from "./theme/theme-resolve"
17
- import { generateSystem } from "./theme/theme-system"
18
- import { generateSyntax, generateSubtleSyntax } from "./theme/theme-syntax"
19
-
20
- export { selectedForeground, tint }
21
- export type { ThemeJson }
22
- export { DEFAULT_THEMES }
23
- export { resolveTheme }
24
-
25
- type State = {
26
- themes: Record<string, ThemeJson>
27
- mode: "dark" | "light"
28
- lock: "dark" | "light" | undefined
29
- active: string
30
- ready: boolean
31
- }
32
-
33
- const pluginThemes: Record<string, ThemeJson> = {}
34
- let customThemes: Record<string, ThemeJson> = {}
35
- let systemTheme: ThemeJson | undefined
36
-
37
- function listThemes() {
38
- const themes = {
39
- ...DEFAULT_THEMES,
40
- ...pluginThemes,
41
- ...customThemes,
42
- }
43
- if (!systemTheme) return themes
44
- return {
45
- ...themes,
46
- system: systemTheme,
47
- }
48
- }
49
-
50
- function syncThemes() {
51
- setStore("themes", listThemes())
52
- }
53
-
54
- const [store, setStore] = createStore<State>({
55
- themes: listThemes(),
56
- mode: "dark",
57
- lock: undefined,
58
- active: "saeeol",
59
- ready: false,
60
- })
61
-
62
- export function allThemes() {
63
- return store.themes
64
- }
65
-
66
- function isTheme(theme: unknown): theme is ThemeJson {
67
- if (!isRecord(theme)) return false
68
- if (!isRecord(theme.theme)) return false
69
- return true
70
- }
71
-
72
- export function hasTheme(name: string) {
73
- if (!name) return false
74
- return allThemes()[name] !== undefined
75
- }
76
-
77
- export function addTheme(name: string, theme: unknown) {
78
- if (!name) return false
79
- if (!isTheme(theme)) return false
80
- if (hasTheme(name)) return false
81
- pluginThemes[name] = theme
82
- syncThemes()
83
- return true
84
- }
85
-
86
- export function upsertTheme(name: string, theme: unknown) {
87
- if (!name) return false
88
- if (!isTheme(theme)) return false
89
- if (customThemes[name] !== undefined) {
90
- customThemes[name] = theme
91
- } else {
92
- pluginThemes[name] = theme
93
- }
94
- syncThemes()
95
- return true
96
- }
97
-
98
- export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
99
- name: "Theme",
100
- init: (props: { mode: "dark" | "light" }) => {
101
- const renderer = useRenderer()
102
- const config = useTuiConfig()
103
- const kv = useKV()
104
- const pick = (value: unknown) => {
105
- if (value === "dark" || value === "light") return value
106
- return
107
- }
108
-
109
- setStore(
110
- produce((draft) => {
111
- const lock = pick(kv.get("theme_mode_lock"))
112
- const mode = lock ?? pick(renderer.themeMode) ?? props.mode
113
- if (!lock && pick(kv.get("theme_mode")) !== undefined) {
114
- kv.set("theme_mode", undefined)
115
- }
116
- draft.mode = mode
117
- draft.lock = lock
118
- const active = config.theme ?? kv.get("theme", "saeeol")
119
- draft.active = typeof active === "string" ? active : "saeeol"
120
- draft.ready = false
121
- }),
122
- )
123
-
124
- createEffect(() => {
125
- const theme = config.theme
126
- if (theme) setStore("active", theme)
127
- })
128
-
129
- function init() {
130
- void Promise.allSettled([
131
- resolveSystemTheme(store.mode),
132
- getCustomThemes()
133
- .then((custom) => {
134
- customThemes = custom
135
- syncThemes()
136
- })
137
- .catch(() => {
138
- setStore("active", "saeeol")
139
- }),
140
- ]).finally(() => {
141
- setStore("ready", true)
142
- })
143
- }
144
-
145
- onMount(init)
146
-
147
- function resolveSystemTheme(mode: "dark" | "light" = store.mode) {
148
- return renderer
149
- .getPalette({
150
- size: 16,
151
- })
152
- .then((colors: TerminalColors) => {
153
- if (!colors.palette[0]) {
154
- systemTheme = undefined
155
- syncThemes()
156
- if (store.active === "system") {
157
- setStore("active", "saeeol")
158
- }
159
- return
160
- }
161
- systemTheme = generateSystem(colors, mode)
162
- syncThemes()
163
- })
164
- .catch(() => {
165
- systemTheme = undefined
166
- syncThemes()
167
- if (store.active === "system") {
168
- setStore("active", "saeeol")
169
- }
170
- })
171
- }
172
-
173
- function apply(mode: "dark" | "light") {
174
- if (store.lock !== undefined) kv.set("theme_mode", mode)
175
- if (store.mode === mode) return
176
- setStore("mode", mode)
177
- renderer.clearPaletteCache()
178
- void resolveSystemTheme(mode)
179
- }
180
-
181
- function pin(mode: "dark" | "light" = store.mode) {
182
- setStore("lock", mode)
183
- kv.set("theme_mode_lock", mode)
184
- apply(mode)
185
- }
186
-
187
- function free() {
188
- setStore("lock", undefined)
189
- kv.set("theme_mode_lock", undefined)
190
- kv.set("theme_mode", undefined)
191
- const mode = renderer.themeMode
192
- if (mode) apply(mode)
193
- }
194
-
195
- const handle = (mode: "dark" | "light") => {
196
- if (store.lock) return
197
- apply(mode)
198
- }
199
- renderer.on(CliRenderEvents.THEME_MODE, handle)
200
-
201
- const refresh = () => {
202
- renderer.clearPaletteCache()
203
- init()
204
- }
205
- process.on("SIGUSR2", refresh)
206
-
207
- onCleanup(() => {
208
- renderer.off(CliRenderEvents.THEME_MODE, handle)
209
- process.off("SIGUSR2", refresh)
210
- })
211
- const values = createMemo(() => {
212
- const active = store.themes[store.active]
213
- if (active) {
214
- return resolveTheme(active, store.mode)
215
- }
216
-
217
- const saved = kv.get("theme")
218
- if (typeof saved === "string") {
219
- const theme = store.themes[saved]
220
- if (theme) {
221
- return resolveTheme(theme, store.mode)
222
- }
223
- }
224
-
225
- return resolveTheme(store.themes.saeeol, store.mode)
226
- })
227
-
228
- createEffect(() => {
229
- renderer.setBackgroundColor(values().background)
230
- })
231
-
232
- const syntax = createMemo(() => generateSyntax(values()))
233
- const subtleSyntax = createMemo(() => generateSubtleSyntax(values()))
234
- return {
235
- theme: new Proxy({} as Theme, {
236
- get(_target, prop) {
237
- // @ts-expect-error
238
- return values()[prop]
239
- },
240
- }),
241
- get selected() {
242
- return store.active
243
- },
244
- all() {
245
- return allThemes()
246
- },
247
- has(name: string) {
248
- return hasTheme(name)
249
- },
250
- syntax,
251
- subtleSyntax,
252
- mode() {
253
- return store.mode
254
- },
255
- locked() {
256
- return store.lock !== undefined
257
- },
258
- lock() {
259
- pin(store.mode)
260
- },
261
- unlock() {
262
- free()
263
- },
264
- setMode(mode: "dark" | "light") {
265
- pin(mode)
266
- },
267
- set(theme: string) {
268
- if (!hasTheme(theme)) return false
269
- setStore("active", theme)
270
- kv.set("theme", theme)
271
- return true
272
- },
273
- get ready() {
274
- return store.ready
275
- },
276
- }
277
- },
278
- })
279
-
280
- async function getCustomThemes() {
281
- const directories = [
282
- Global.Path.config,
283
- ...(await Array.fromAsync(
284
- Filesystem.up({
285
- targets: [".saeeol", ".saeeol"],
286
- start: process.cwd(),
287
- }),
288
- )),
289
- ]
290
-
291
- const result: Record<string, ThemeJson> = {}
292
- for (const dir of directories) {
293
- for (const item of await Glob.scan("themes/*.json", {
294
- cwd: dir,
295
- absolute: true,
296
- dot: true,
297
- symlink: true,
298
- })) {
299
- const name = path.basename(item, ".json")
300
- if (name in DEFAULT_THEMES) continue
301
- const json = await Filesystem.readJson(item).catch(() => null)
302
- if (!isValidTheme(json)) continue
303
- result[name] = json
304
- }
305
- }
306
- return result
307
- }
1
+ export * from "./app/theme"
@@ -1,9 +1 @@
1
- import { TuiConfig } from "@/cli/cmd/tui/config/tui"
2
- import { createSimpleContext } from "./helper"
3
-
4
- export const { use: useTuiConfig, provider: TuiConfigProvider } = createSimpleContext({
5
- name: "TuiConfig",
6
- init: (props: { config: TuiConfig.Info }) => {
7
- return props.config
8
- },
9
- })
1
+ export * from "./app/tui-config"