codeblog-app 2.1.2 → 2.1.4

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 (69) hide show
  1. package/drizzle/0000_init.sql +34 -0
  2. package/drizzle/meta/_journal.json +13 -0
  3. package/drizzle.config.ts +10 -0
  4. package/package.json +71 -8
  5. package/src/ai/__tests__/chat.test.ts +110 -0
  6. package/src/ai/__tests__/provider.test.ts +184 -0
  7. package/src/ai/__tests__/tools.test.ts +54 -0
  8. package/src/ai/chat.ts +170 -0
  9. package/src/ai/configure.ts +134 -0
  10. package/src/ai/provider.ts +238 -0
  11. package/src/ai/tools.ts +91 -0
  12. package/src/auth/index.ts +47 -0
  13. package/src/auth/oauth.ts +94 -0
  14. package/src/cli/__tests__/commands.test.ts +225 -0
  15. package/src/cli/cmd/agent.ts +97 -0
  16. package/src/cli/cmd/chat.ts +190 -0
  17. package/src/cli/cmd/comment.ts +67 -0
  18. package/src/cli/cmd/config.ts +153 -0
  19. package/src/cli/cmd/feed.ts +53 -0
  20. package/src/cli/cmd/forum.ts +106 -0
  21. package/src/cli/cmd/login.ts +45 -0
  22. package/src/cli/cmd/logout.ts +12 -0
  23. package/src/cli/cmd/me.ts +188 -0
  24. package/src/cli/cmd/post.ts +25 -0
  25. package/src/cli/cmd/publish.ts +64 -0
  26. package/src/cli/cmd/scan.ts +78 -0
  27. package/src/cli/cmd/search.ts +35 -0
  28. package/src/cli/cmd/setup.ts +273 -0
  29. package/src/cli/cmd/tui.ts +20 -0
  30. package/src/cli/cmd/uninstall.ts +156 -0
  31. package/src/cli/cmd/update.ts +123 -0
  32. package/src/cli/cmd/vote.ts +50 -0
  33. package/src/cli/cmd/whoami.ts +18 -0
  34. package/src/cli/mcp-print.ts +6 -0
  35. package/src/cli/ui.ts +195 -0
  36. package/src/config/index.ts +54 -0
  37. package/src/flag/index.ts +23 -0
  38. package/src/global/index.ts +38 -0
  39. package/src/id/index.ts +20 -0
  40. package/src/index.ts +200 -0
  41. package/src/mcp/__tests__/client.test.ts +149 -0
  42. package/src/mcp/__tests__/e2e.ts +327 -0
  43. package/src/mcp/__tests__/integration.ts +148 -0
  44. package/src/mcp/client.ts +148 -0
  45. package/src/server/index.ts +48 -0
  46. package/src/storage/chat.ts +71 -0
  47. package/src/storage/db.ts +85 -0
  48. package/src/storage/schema.sql.ts +39 -0
  49. package/src/storage/schema.ts +1 -0
  50. package/src/tui/app.tsx +179 -0
  51. package/src/tui/commands.ts +187 -0
  52. package/src/tui/context/exit.tsx +15 -0
  53. package/src/tui/context/helper.tsx +25 -0
  54. package/src/tui/context/route.tsx +24 -0
  55. package/src/tui/context/theme.tsx +470 -0
  56. package/src/tui/routes/home.tsx +508 -0
  57. package/src/tui/routes/model.tsx +207 -0
  58. package/src/tui/routes/notifications.tsx +87 -0
  59. package/src/tui/routes/post.tsx +102 -0
  60. package/src/tui/routes/search.tsx +105 -0
  61. package/src/tui/routes/setup.tsx +255 -0
  62. package/src/tui/routes/trending.tsx +107 -0
  63. package/src/util/__tests__/context.test.ts +31 -0
  64. package/src/util/__tests__/lazy.test.ts +37 -0
  65. package/src/util/context.ts +23 -0
  66. package/src/util/error.ts +46 -0
  67. package/src/util/lazy.ts +18 -0
  68. package/src/util/log.ts +142 -0
  69. package/tsconfig.json +11 -0
@@ -0,0 +1,470 @@
1
+ import path from "path"
2
+ import fs from "fs"
3
+ import { createStore } from "solid-js/store"
4
+ import { createSimpleContext } from "./helper"
5
+ import { Global } from "../../global"
6
+
7
+ export type ThemeColors = {
8
+ text: string
9
+ textMuted: string
10
+ primary: string
11
+ accent: string
12
+ success: string
13
+ error: string
14
+ warning: string
15
+ input: string
16
+ cursor: string
17
+ logo1: string
18
+ logo2: string
19
+ }
20
+
21
+ type ThemeDef = {
22
+ dark: ThemeColors
23
+ light: ThemeColors
24
+ }
25
+
26
+ const codeblog: ThemeDef = {
27
+ dark: {
28
+ text: "#e7e9eb",
29
+ textMuted: "#6a737c",
30
+ primary: "#0074cc",
31
+ accent: "#f48225",
32
+ success: "#48a868",
33
+ error: "#d73a49",
34
+ warning: "#f48225",
35
+ input: "#e7e9eb",
36
+ cursor: "#6a737c",
37
+ logo1: "#f48225",
38
+ logo2: "#0074cc",
39
+ },
40
+ light: {
41
+ text: "#232629",
42
+ textMuted: "#6a737c",
43
+ primary: "#0074cc",
44
+ accent: "#f48225",
45
+ success: "#2ea44f",
46
+ error: "#cf222e",
47
+ warning: "#bf8700",
48
+ input: "#232629",
49
+ cursor: "#838c95",
50
+ logo1: "#f48225",
51
+ logo2: "#0074cc",
52
+ },
53
+ }
54
+
55
+ const dracula: ThemeDef = {
56
+ dark: {
57
+ text: "#f8f8f2",
58
+ textMuted: "#6272a4",
59
+ primary: "#bd93f9",
60
+ accent: "#ff79c6",
61
+ success: "#50fa7b",
62
+ error: "#ff5555",
63
+ warning: "#f1fa8c",
64
+ input: "#f8f8f2",
65
+ cursor: "#6272a4",
66
+ logo1: "#ff79c6",
67
+ logo2: "#bd93f9",
68
+ },
69
+ light: {
70
+ text: "#282a36",
71
+ textMuted: "#6272a4",
72
+ primary: "#7c3aed",
73
+ accent: "#db2777",
74
+ success: "#16a34a",
75
+ error: "#dc2626",
76
+ warning: "#ca8a04",
77
+ input: "#282a36",
78
+ cursor: "#6272a4",
79
+ logo1: "#db2777",
80
+ logo2: "#7c3aed",
81
+ },
82
+ }
83
+
84
+ const nord: ThemeDef = {
85
+ dark: {
86
+ text: "#eceff4",
87
+ textMuted: "#4c566a",
88
+ primary: "#88c0d0",
89
+ accent: "#81a1c1",
90
+ success: "#a3be8c",
91
+ error: "#bf616a",
92
+ warning: "#ebcb8b",
93
+ input: "#eceff4",
94
+ cursor: "#4c566a",
95
+ logo1: "#88c0d0",
96
+ logo2: "#81a1c1",
97
+ },
98
+ light: {
99
+ text: "#2e3440",
100
+ textMuted: "#4c566a",
101
+ primary: "#5e81ac",
102
+ accent: "#81a1c1",
103
+ success: "#a3be8c",
104
+ error: "#bf616a",
105
+ warning: "#d08770",
106
+ input: "#2e3440",
107
+ cursor: "#4c566a",
108
+ logo1: "#5e81ac",
109
+ logo2: "#81a1c1",
110
+ },
111
+ }
112
+
113
+ const tokyonight: ThemeDef = {
114
+ dark: {
115
+ text: "#c0caf5",
116
+ textMuted: "#565f89",
117
+ primary: "#7aa2f7",
118
+ accent: "#bb9af7",
119
+ success: "#9ece6a",
120
+ error: "#f7768e",
121
+ warning: "#e0af68",
122
+ input: "#c0caf5",
123
+ cursor: "#565f89",
124
+ logo1: "#bb9af7",
125
+ logo2: "#7aa2f7",
126
+ },
127
+ light: {
128
+ text: "#343b58",
129
+ textMuted: "#6172b0",
130
+ primary: "#2e7de9",
131
+ accent: "#9854f1",
132
+ success: "#587539",
133
+ error: "#f52a65",
134
+ warning: "#8c6c3e",
135
+ input: "#343b58",
136
+ cursor: "#6172b0",
137
+ logo1: "#9854f1",
138
+ logo2: "#2e7de9",
139
+ },
140
+ }
141
+
142
+ const monokai: ThemeDef = {
143
+ dark: {
144
+ text: "#f8f8f2",
145
+ textMuted: "#75715e",
146
+ primary: "#66d9ef",
147
+ accent: "#f92672",
148
+ success: "#a6e22e",
149
+ error: "#f92672",
150
+ warning: "#e6db74",
151
+ input: "#f8f8f2",
152
+ cursor: "#75715e",
153
+ logo1: "#f92672",
154
+ logo2: "#66d9ef",
155
+ },
156
+ light: {
157
+ text: "#272822",
158
+ textMuted: "#75715e",
159
+ primary: "#0089b3",
160
+ accent: "#c4265e",
161
+ success: "#718c00",
162
+ error: "#c4265e",
163
+ warning: "#c99e00",
164
+ input: "#272822",
165
+ cursor: "#75715e",
166
+ logo1: "#c4265e",
167
+ logo2: "#0089b3",
168
+ },
169
+ }
170
+
171
+ const github: ThemeDef = {
172
+ dark: {
173
+ text: "#c9d1d9",
174
+ textMuted: "#8b949e",
175
+ primary: "#58a6ff",
176
+ accent: "#bc8cff",
177
+ success: "#3fb950",
178
+ error: "#f85149",
179
+ warning: "#d29922",
180
+ input: "#c9d1d9",
181
+ cursor: "#8b949e",
182
+ logo1: "#58a6ff",
183
+ logo2: "#bc8cff",
184
+ },
185
+ light: {
186
+ text: "#24292f",
187
+ textMuted: "#57606a",
188
+ primary: "#0969da",
189
+ accent: "#8250df",
190
+ success: "#1a7f37",
191
+ error: "#cf222e",
192
+ warning: "#9a6700",
193
+ input: "#24292f",
194
+ cursor: "#57606a",
195
+ logo1: "#0969da",
196
+ logo2: "#8250df",
197
+ },
198
+ }
199
+
200
+ const solarized: ThemeDef = {
201
+ dark: {
202
+ text: "#839496",
203
+ textMuted: "#586e75",
204
+ primary: "#268bd2",
205
+ accent: "#d33682",
206
+ success: "#859900",
207
+ error: "#dc322f",
208
+ warning: "#b58900",
209
+ input: "#93a1a1",
210
+ cursor: "#586e75",
211
+ logo1: "#cb4b16",
212
+ logo2: "#268bd2",
213
+ },
214
+ light: {
215
+ text: "#657b83",
216
+ textMuted: "#93a1a1",
217
+ primary: "#268bd2",
218
+ accent: "#d33682",
219
+ success: "#859900",
220
+ error: "#dc322f",
221
+ warning: "#b58900",
222
+ input: "#586e75",
223
+ cursor: "#93a1a1",
224
+ logo1: "#cb4b16",
225
+ logo2: "#268bd2",
226
+ },
227
+ }
228
+
229
+ const catppuccin: ThemeDef = {
230
+ dark: {
231
+ text: "#cdd6f4",
232
+ textMuted: "#6c7086",
233
+ primary: "#89b4fa",
234
+ accent: "#cba6f7",
235
+ success: "#a6e3a1",
236
+ error: "#f38ba8",
237
+ warning: "#f9e2af",
238
+ input: "#cdd6f4",
239
+ cursor: "#6c7086",
240
+ logo1: "#cba6f7",
241
+ logo2: "#89b4fa",
242
+ },
243
+ light: {
244
+ text: "#4c4f69",
245
+ textMuted: "#8c8fa1",
246
+ primary: "#1e66f5",
247
+ accent: "#8839ef",
248
+ success: "#40a02b",
249
+ error: "#d20f39",
250
+ warning: "#df8e1d",
251
+ input: "#4c4f69",
252
+ cursor: "#8c8fa1",
253
+ logo1: "#8839ef",
254
+ logo2: "#1e66f5",
255
+ },
256
+ }
257
+
258
+ const rosepine: ThemeDef = {
259
+ dark: {
260
+ text: "#e0def4",
261
+ textMuted: "#6e6a86",
262
+ primary: "#c4a7e7",
263
+ accent: "#ebbcba",
264
+ success: "#31748f",
265
+ error: "#eb6f92",
266
+ warning: "#f6c177",
267
+ input: "#e0def4",
268
+ cursor: "#6e6a86",
269
+ logo1: "#ebbcba",
270
+ logo2: "#c4a7e7",
271
+ },
272
+ light: {
273
+ text: "#575279",
274
+ textMuted: "#9893a5",
275
+ primary: "#907aa9",
276
+ accent: "#d7827e",
277
+ success: "#286983",
278
+ error: "#b4637a",
279
+ warning: "#ea9d34",
280
+ input: "#575279",
281
+ cursor: "#9893a5",
282
+ logo1: "#d7827e",
283
+ logo2: "#907aa9",
284
+ },
285
+ }
286
+
287
+ const gruvbox: ThemeDef = {
288
+ dark: {
289
+ text: "#ebdbb2",
290
+ textMuted: "#928374",
291
+ primary: "#83a598",
292
+ accent: "#d3869b",
293
+ success: "#b8bb26",
294
+ error: "#fb4934",
295
+ warning: "#fabd2f",
296
+ input: "#ebdbb2",
297
+ cursor: "#928374",
298
+ logo1: "#fe8019",
299
+ logo2: "#83a598",
300
+ },
301
+ light: {
302
+ text: "#3c3836",
303
+ textMuted: "#928374",
304
+ primary: "#076678",
305
+ accent: "#8f3f71",
306
+ success: "#79740e",
307
+ error: "#9d0006",
308
+ warning: "#b57614",
309
+ input: "#3c3836",
310
+ cursor: "#928374",
311
+ logo1: "#af3a03",
312
+ logo2: "#076678",
313
+ },
314
+ }
315
+
316
+ const onedark: ThemeDef = {
317
+ dark: {
318
+ text: "#abb2bf",
319
+ textMuted: "#5c6370",
320
+ primary: "#61afef",
321
+ accent: "#c678dd",
322
+ success: "#98c379",
323
+ error: "#e06c75",
324
+ warning: "#e5c07b",
325
+ input: "#abb2bf",
326
+ cursor: "#5c6370",
327
+ logo1: "#e06c75",
328
+ logo2: "#61afef",
329
+ },
330
+ light: {
331
+ text: "#383a42",
332
+ textMuted: "#a0a1a7",
333
+ primary: "#4078f2",
334
+ accent: "#a626a4",
335
+ success: "#50a14f",
336
+ error: "#e45649",
337
+ warning: "#c18401",
338
+ input: "#383a42",
339
+ cursor: "#a0a1a7",
340
+ logo1: "#e45649",
341
+ logo2: "#4078f2",
342
+ },
343
+ }
344
+
345
+ const kanagawa: ThemeDef = {
346
+ dark: {
347
+ text: "#dcd7ba",
348
+ textMuted: "#727169",
349
+ primary: "#7e9cd8",
350
+ accent: "#957fb8",
351
+ success: "#76946a",
352
+ error: "#c34043",
353
+ warning: "#dca561",
354
+ input: "#dcd7ba",
355
+ cursor: "#727169",
356
+ logo1: "#ff5d62",
357
+ logo2: "#7e9cd8",
358
+ },
359
+ light: {
360
+ text: "#1f1f28",
361
+ textMuted: "#8a8980",
362
+ primary: "#4e8ca2",
363
+ accent: "#624c83",
364
+ success: "#6f894e",
365
+ error: "#c84053",
366
+ warning: "#cc6d00",
367
+ input: "#1f1f28",
368
+ cursor: "#8a8980",
369
+ logo1: "#d7474b",
370
+ logo2: "#4e8ca2",
371
+ },
372
+ }
373
+
374
+ const everforest: ThemeDef = {
375
+ dark: {
376
+ text: "#d3c6aa",
377
+ textMuted: "#859289",
378
+ primary: "#7fbbb3",
379
+ accent: "#d699b6",
380
+ success: "#a7c080",
381
+ error: "#e67e80",
382
+ warning: "#dbbc7f",
383
+ input: "#d3c6aa",
384
+ cursor: "#859289",
385
+ logo1: "#e69875",
386
+ logo2: "#7fbbb3",
387
+ },
388
+ light: {
389
+ text: "#5c6a72",
390
+ textMuted: "#939f91",
391
+ primary: "#3a94c5",
392
+ accent: "#df69ba",
393
+ success: "#8da101",
394
+ error: "#f85552",
395
+ warning: "#dfa000",
396
+ input: "#5c6a72",
397
+ cursor: "#939f91",
398
+ logo1: "#f57d26",
399
+ logo2: "#3a94c5",
400
+ },
401
+ }
402
+
403
+ export const THEMES: Record<string, ThemeDef> = {
404
+ codeblog,
405
+ dracula,
406
+ nord,
407
+ tokyonight,
408
+ monokai,
409
+ github,
410
+ solarized,
411
+ catppuccin,
412
+ rosepine,
413
+ gruvbox,
414
+ onedark,
415
+ kanagawa,
416
+ everforest,
417
+ }
418
+
419
+ export const THEME_NAMES = Object.keys(THEMES)
420
+
421
+ const configPath = path.join(Global.Path.config, "theme.json")
422
+
423
+ type SavedTheme = { name: string; mode: "dark" | "light" }
424
+
425
+ function load(): SavedTheme | null {
426
+ try {
427
+ const data = JSON.parse(fs.readFileSync(configPath, "utf-8"))
428
+ if (data.name && data.mode) return data as SavedTheme
429
+ } catch {}
430
+ return null
431
+ }
432
+
433
+ function save(cfg: SavedTheme) {
434
+ Bun.write(configPath, JSON.stringify(cfg, null, 2)).catch(() => {})
435
+ }
436
+
437
+ export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
438
+ name: "Theme",
439
+ init: () => {
440
+ const saved = load()
441
+ const [store, setStore] = createStore({
442
+ name: saved?.name || "codeblog",
443
+ mode: (saved?.mode || "light") as "dark" | "light",
444
+ needsSetup: !saved,
445
+ })
446
+
447
+ return {
448
+ get colors(): ThemeColors {
449
+ const def = THEMES[store.name] || THEMES.codeblog
450
+ return def[store.mode]
451
+ },
452
+ get name() { return store.name },
453
+ get mode() { return store.mode },
454
+ get needsSetup() { return store.needsSetup },
455
+ set(name: string) {
456
+ if (!THEMES[name]) return
457
+ setStore("name", name)
458
+ save({ name, mode: store.mode })
459
+ },
460
+ setMode(mode: "dark" | "light") {
461
+ setStore("mode", mode)
462
+ save({ name: store.name, mode })
463
+ },
464
+ finishSetup() {
465
+ setStore("needsSetup", false)
466
+ save({ name: store.name, mode: store.mode })
467
+ },
468
+ }
469
+ },
470
+ })