@thjodann/wk 1.0.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.
Files changed (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +197 -0
  3. package/dist/cli/commands/article.d.ts +2 -0
  4. package/dist/cli/commands/article.js +47 -0
  5. package/dist/cli/commands/article.js.map +1 -0
  6. package/dist/cli/commands/closeout.d.ts +2 -0
  7. package/dist/cli/commands/closeout.js +37 -0
  8. package/dist/cli/commands/closeout.js.map +1 -0
  9. package/dist/cli/commands/compile.d.ts +2 -0
  10. package/dist/cli/commands/compile.js +50 -0
  11. package/dist/cli/commands/compile.js.map +1 -0
  12. package/dist/cli/commands/concept.d.ts +2 -0
  13. package/dist/cli/commands/concept.js +36 -0
  14. package/dist/cli/commands/concept.js.map +1 -0
  15. package/dist/cli/commands/decision.d.ts +2 -0
  16. package/dist/cli/commands/decision.js +38 -0
  17. package/dist/cli/commands/decision.js.map +1 -0
  18. package/dist/cli/commands/event.d.ts +2 -0
  19. package/dist/cli/commands/event.js +32 -0
  20. package/dist/cli/commands/event.js.map +1 -0
  21. package/dist/cli/commands/init.d.ts +2 -0
  22. package/dist/cli/commands/init.js +52 -0
  23. package/dist/cli/commands/init.js.map +1 -0
  24. package/dist/cli/commands/installAgent.d.ts +2 -0
  25. package/dist/cli/commands/installAgent.js +130 -0
  26. package/dist/cli/commands/installAgent.js.map +1 -0
  27. package/dist/cli/commands/link.d.ts +2 -0
  28. package/dist/cli/commands/link.js +36 -0
  29. package/dist/cli/commands/link.js.map +1 -0
  30. package/dist/cli/commands/note.d.ts +2 -0
  31. package/dist/cli/commands/note.js +34 -0
  32. package/dist/cli/commands/note.js.map +1 -0
  33. package/dist/cli/commands/pages.d.ts +2 -0
  34. package/dist/cli/commands/pages.js +46 -0
  35. package/dist/cli/commands/pages.js.map +1 -0
  36. package/dist/cli/commands/record.d.ts +2 -0
  37. package/dist/cli/commands/record.js +101 -0
  38. package/dist/cli/commands/record.js.map +1 -0
  39. package/dist/cli/commands/render.d.ts +2 -0
  40. package/dist/cli/commands/render.js +33 -0
  41. package/dist/cli/commands/render.js.map +1 -0
  42. package/dist/cli/commands/search.d.ts +2 -0
  43. package/dist/cli/commands/search.js +125 -0
  44. package/dist/cli/commands/search.js.map +1 -0
  45. package/dist/cli/commands/setup.d.ts +2 -0
  46. package/dist/cli/commands/setup.js +53 -0
  47. package/dist/cli/commands/setup.js.map +1 -0
  48. package/dist/cli/commands/site.d.ts +2 -0
  49. package/dist/cli/commands/site.js +47 -0
  50. package/dist/cli/commands/site.js.map +1 -0
  51. package/dist/cli/commands/spin.d.ts +2 -0
  52. package/dist/cli/commands/spin.js +43 -0
  53. package/dist/cli/commands/spin.js.map +1 -0
  54. package/dist/cli/commands/status.d.ts +2 -0
  55. package/dist/cli/commands/status.js +63 -0
  56. package/dist/cli/commands/status.js.map +1 -0
  57. package/dist/cli/commands/symbol.d.ts +2 -0
  58. package/dist/cli/commands/symbol.js +37 -0
  59. package/dist/cli/commands/symbol.js.map +1 -0
  60. package/dist/cli/commands/theme.d.ts +2 -0
  61. package/dist/cli/commands/theme.js +52 -0
  62. package/dist/cli/commands/theme.js.map +1 -0
  63. package/dist/cli/commands/validate.d.ts +2 -0
  64. package/dist/cli/commands/validate.js +44 -0
  65. package/dist/cli/commands/validate.js.map +1 -0
  66. package/dist/cli/helpers.d.ts +30 -0
  67. package/dist/cli/helpers.js +131 -0
  68. package/dist/cli/helpers.js.map +1 -0
  69. package/dist/core/articles.d.ts +5 -0
  70. package/dist/core/articles.js +25 -0
  71. package/dist/core/articles.js.map +1 -0
  72. package/dist/core/automation.d.ts +96 -0
  73. package/dist/core/automation.js +384 -0
  74. package/dist/core/automation.js.map +1 -0
  75. package/dist/core/beads.d.ts +43 -0
  76. package/dist/core/beads.js +358 -0
  77. package/dist/core/beads.js.map +1 -0
  78. package/dist/core/compiler.d.ts +45 -0
  79. package/dist/core/compiler.js +399 -0
  80. package/dist/core/compiler.js.map +1 -0
  81. package/dist/core/config.d.ts +59 -0
  82. package/dist/core/config.js +187 -0
  83. package/dist/core/config.js.map +1 -0
  84. package/dist/core/git.d.ts +21 -0
  85. package/dist/core/git.js +109 -0
  86. package/dist/core/git.js.map +1 -0
  87. package/dist/core/ids.d.ts +2 -0
  88. package/dist/core/ids.js +8 -0
  89. package/dist/core/ids.js.map +1 -0
  90. package/dist/core/pages.d.ts +34 -0
  91. package/dist/core/pages.js +233 -0
  92. package/dist/core/pages.js.map +1 -0
  93. package/dist/core/paths.d.ts +15 -0
  94. package/dist/core/paths.js +67 -0
  95. package/dist/core/paths.js.map +1 -0
  96. package/dist/core/profiles.d.ts +30 -0
  97. package/dist/core/profiles.js +243 -0
  98. package/dist/core/profiles.js.map +1 -0
  99. package/dist/core/renderer.d.ts +8 -0
  100. package/dist/core/renderer.js +106 -0
  101. package/dist/core/renderer.js.map +1 -0
  102. package/dist/core/schemas.d.ts +1039 -0
  103. package/dist/core/schemas.js +108 -0
  104. package/dist/core/schemas.js.map +1 -0
  105. package/dist/core/site.d.ts +20 -0
  106. package/dist/core/site.js +2684 -0
  107. package/dist/core/site.js.map +1 -0
  108. package/dist/core/spin.d.ts +42 -0
  109. package/dist/core/spin.js +265 -0
  110. package/dist/core/spin.js.map +1 -0
  111. package/dist/core/store.d.ts +29 -0
  112. package/dist/core/store.js +146 -0
  113. package/dist/core/store.js.map +1 -0
  114. package/dist/core/theme.d.ts +35 -0
  115. package/dist/core/theme.js +1086 -0
  116. package/dist/core/theme.js.map +1 -0
  117. package/dist/core/validator.d.ts +8 -0
  118. package/dist/core/validator.js +154 -0
  119. package/dist/core/validator.js.map +1 -0
  120. package/dist/index.d.ts +3 -0
  121. package/dist/index.js +61 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/templates/articlesPage.d.ts +3 -0
  124. package/dist/templates/articlesPage.js +46 -0
  125. package/dist/templates/articlesPage.js.map +1 -0
  126. package/dist/templates/conceptsPage.d.ts +2 -0
  127. package/dist/templates/conceptsPage.js +24 -0
  128. package/dist/templates/conceptsPage.js.map +1 -0
  129. package/dist/templates/decisionsPage.d.ts +2 -0
  130. package/dist/templates/decisionsPage.js +27 -0
  131. package/dist/templates/decisionsPage.js.map +1 -0
  132. package/dist/templates/devlogPage.d.ts +2 -0
  133. package/dist/templates/devlogPage.js +22 -0
  134. package/dist/templates/devlogPage.js.map +1 -0
  135. package/dist/templates/indexPage.d.ts +6 -0
  136. package/dist/templates/indexPage.js +33 -0
  137. package/dist/templates/indexPage.js.map +1 -0
  138. package/dist/templates/linksPage.d.ts +2 -0
  139. package/dist/templates/linksPage.js +26 -0
  140. package/dist/templates/linksPage.js.map +1 -0
  141. package/dist/templates/notesPage.d.ts +2 -0
  142. package/dist/templates/notesPage.js +26 -0
  143. package/dist/templates/notesPage.js.map +1 -0
  144. package/dist/templates/symbolsPage.d.ts +2 -0
  145. package/dist/templates/symbolsPage.js +25 -0
  146. package/dist/templates/symbolsPage.js.map +1 -0
  147. package/docs/concepts.md +249 -0
  148. package/docs/reference.md +356 -0
  149. package/docs/setup.md +331 -0
  150. package/docs/workflows.md +154 -0
  151. package/package.json +61 -0
  152. package/skills/wk/SKILL.md +251 -0
  153. package/skills/wk/agents/openai.yaml +4 -0
@@ -0,0 +1,1086 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.themeMoods = void 0;
7
+ exports.previewTheme = previewTheme;
8
+ exports.writeTheme = writeTheme;
9
+ exports.parseThemeMood = parseThemeMood;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const config_1 = require("./config");
13
+ const paths_1 = require("./paths");
14
+ exports.themeMoods = ["calm", "vivid", "editorial", "utility", "playful", "dark"];
15
+ const defaultDescription = "A project wiki generated from durable repo knowledge.";
16
+ const moodThemes = {
17
+ calm: {
18
+ light: {
19
+ accent: "#2f7d6d",
20
+ accent_strong: "#185143",
21
+ secondary: "#7a6f42",
22
+ bg: "#f4faf6",
23
+ panel: "#fbfdf8",
24
+ panel_soft: "#eaf5ef",
25
+ text: "#1f2a24",
26
+ muted: "#5d6d64",
27
+ border: "#d1e5da",
28
+ code_bg: "#eaf4ee",
29
+ shadow: "0 18px 45px rgba(30, 55, 47, 0.08)",
30
+ shadow_strong: "0 24px 70px rgba(30, 55, 47, 0.14)",
31
+ radius: "8px",
32
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
33
+ sidebar_bg: "linear-gradient(180deg, rgba(251, 253, 248, 0.94), rgba(234, 245, 239, 0.88))",
34
+ hero_gradient: "linear-gradient(135deg, #fbfdf8 0%, #e7f4ed 100%)",
35
+ card_gradient: "linear-gradient(180deg, #fbfdf8 0%, #f2faf5 100%)",
36
+ brand_gradient: "linear-gradient(135deg, #2f7d6d, #185143)",
37
+ brand_mark_text: "#fffaf0",
38
+ badge_bg: "#dff0e8",
39
+ badge_text: "#185143",
40
+ tag_bg: "#f1edd8",
41
+ tag_text: "#605526",
42
+ success_bg: "#e4f3df",
43
+ success_text: "#2d5c1f",
44
+ warning_bg: "#f6ead9",
45
+ warning_text: "#754716",
46
+ focus_ring: "rgba(47, 125, 109, 0.2)",
47
+ gloss: "rgba(47, 125, 109, 0.13)"
48
+ },
49
+ dark: {
50
+ accent: "#74d4bd",
51
+ accent_strong: "#b5f0dd",
52
+ secondary: "#d8c985",
53
+ bg: "#101b18",
54
+ panel: "#162620",
55
+ panel_soft: "#20342c",
56
+ text: "#f4f1e8",
57
+ muted: "#c6d1cb",
58
+ border: "#315044",
59
+ code_bg: "#0c1512",
60
+ shadow: "0 22px 60px rgba(5, 12, 10, 0.36)",
61
+ shadow_strong: "0 30px 90px rgba(5, 12, 10, 0.5)",
62
+ radius: "8px",
63
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
64
+ sidebar_bg: "linear-gradient(180deg, rgba(22, 38, 32, 0.95), rgba(13, 24, 20, 0.9))",
65
+ hero_gradient: "linear-gradient(135deg, #1b3129 0%, #0d1714 100%)",
66
+ card_gradient: "linear-gradient(180deg, #182a24 0%, #111d19 100%)",
67
+ brand_gradient: "linear-gradient(135deg, #74d4bd, #2f7d6d)",
68
+ brand_mark_text: "#0f1a17",
69
+ badge_bg: "rgba(116, 212, 189, 0.17)",
70
+ badge_text: "#d9fff3",
71
+ tag_bg: "rgba(216, 201, 133, 0.18)",
72
+ tag_text: "#f4e6a6",
73
+ success_bg: "rgba(134, 239, 172, 0.16)",
74
+ success_text: "#bbf7d0",
75
+ warning_bg: "rgba(253, 186, 116, 0.16)",
76
+ warning_text: "#fed7aa",
77
+ focus_ring: "rgba(116, 212, 189, 0.28)",
78
+ gloss: "rgba(116, 212, 189, 0.16)"
79
+ }
80
+ },
81
+ vivid: {
82
+ light: {
83
+ accent: "#d9467d",
84
+ accent_strong: "#8f1d4b",
85
+ secondary: "#6d5dfc",
86
+ bg: "#fff6fa",
87
+ panel: "#fffafd",
88
+ panel_soft: "#fde7f0",
89
+ text: "#2b1f28",
90
+ muted: "#76596a",
91
+ border: "#f1bfd2",
92
+ code_bg: "#fdebf3",
93
+ shadow: "0 18px 45px rgba(78, 25, 54, 0.1)",
94
+ shadow_strong: "0 28px 75px rgba(78, 25, 54, 0.17)",
95
+ radius: "8px",
96
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
97
+ sidebar_bg: "linear-gradient(180deg, rgba(255, 250, 253, 0.94), rgba(253, 231, 240, 0.88))",
98
+ hero_gradient: "linear-gradient(135deg, #fffafd 0%, #fde5ef 52%, #eee8ff 100%)",
99
+ card_gradient: "linear-gradient(180deg, #fffafd 0%, #fff3f8 100%)",
100
+ brand_gradient: "linear-gradient(135deg, #d9467d, #6d5dfc)",
101
+ brand_mark_text: "#fffaf0",
102
+ badge_bg: "#f9dce8",
103
+ badge_text: "#8f1d4b",
104
+ tag_bg: "#ece8ff",
105
+ tag_text: "#4236a3",
106
+ success_bg: "#e7f3df",
107
+ success_text: "#2d5c1f",
108
+ warning_bg: "#f8e2d2",
109
+ warning_text: "#7d3414",
110
+ focus_ring: "rgba(217, 70, 125, 0.22)",
111
+ gloss: "rgba(217, 70, 125, 0.15)"
112
+ },
113
+ dark: {
114
+ accent: "#fb7aad",
115
+ accent_strong: "#f9a8d4",
116
+ secondary: "#a99cff",
117
+ bg: "#21111a",
118
+ panel: "#2c1724",
119
+ panel_soft: "#3a2030",
120
+ text: "#fff0f7",
121
+ muted: "#e8c8d8",
122
+ border: "#593147",
123
+ code_bg: "#170c12",
124
+ shadow: "0 22px 60px rgba(13, 4, 9, 0.38)",
125
+ shadow_strong: "0 30px 90px rgba(13, 4, 9, 0.52)",
126
+ radius: "8px",
127
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
128
+ sidebar_bg: "linear-gradient(180deg, rgba(44, 23, 36, 0.95), rgba(28, 13, 22, 0.9))",
129
+ hero_gradient: "linear-gradient(135deg, #3b1d30 0%, #20101a 55%, #191331 100%)",
130
+ card_gradient: "linear-gradient(180deg, #2f1928 0%, #24131d 100%)",
131
+ brand_gradient: "linear-gradient(135deg, #fb7aad, #8b5cf6)",
132
+ brand_mark_text: "#201018",
133
+ badge_bg: "rgba(251, 122, 173, 0.18)",
134
+ badge_text: "#ffd7e8",
135
+ tag_bg: "rgba(169, 156, 255, 0.2)",
136
+ tag_text: "#ddd6fe",
137
+ success_bg: "rgba(134, 239, 172, 0.16)",
138
+ success_text: "#bbf7d0",
139
+ warning_bg: "rgba(253, 186, 116, 0.16)",
140
+ warning_text: "#fed7aa",
141
+ focus_ring: "rgba(251, 122, 173, 0.3)",
142
+ gloss: "rgba(251, 122, 173, 0.18)"
143
+ }
144
+ },
145
+ editorial: {
146
+ light: {
147
+ accent: "#8a5a2b",
148
+ accent_strong: "#5b3718",
149
+ secondary: "#4f6f82",
150
+ bg: "#faf7f0",
151
+ panel: "#fdfaf4",
152
+ panel_soft: "#f1eadf",
153
+ text: "#292520",
154
+ muted: "#6b6257",
155
+ border: "#dfd4c6",
156
+ code_bg: "#f2eadf",
157
+ shadow: "0 16px 42px rgba(61, 45, 31, 0.09)",
158
+ shadow_strong: "0 24px 70px rgba(61, 45, 31, 0.15)",
159
+ radius: "6px",
160
+ font_family: "Charter, Georgia, serif",
161
+ sidebar_bg: "linear-gradient(180deg, rgba(253, 250, 244, 0.94), rgba(241, 234, 223, 0.88))",
162
+ hero_gradient: "linear-gradient(135deg, #fdfaf4 0%, #efe3d2 100%)",
163
+ card_gradient: "linear-gradient(180deg, #fdfaf4 0%, #f8f1e7 100%)",
164
+ brand_gradient: "linear-gradient(135deg, #8a5a2b, #4f6f82)",
165
+ brand_mark_text: "#fff7e8",
166
+ badge_bg: "#efe1d0",
167
+ badge_text: "#5b3718",
168
+ tag_bg: "#e3edf1",
169
+ tag_text: "#2d566a",
170
+ success_bg: "#e7f0dc",
171
+ success_text: "#2f5e1f",
172
+ warning_bg: "#f4e3d2",
173
+ warning_text: "#7a3c1d",
174
+ focus_ring: "rgba(138, 90, 43, 0.22)",
175
+ gloss: "rgba(138, 90, 43, 0.12)"
176
+ },
177
+ dark: {
178
+ accent: "#d2a063",
179
+ accent_strong: "#f0d4a8",
180
+ secondary: "#9ac5d8",
181
+ bg: "#1d1915",
182
+ panel: "#292219",
183
+ panel_soft: "#352c21",
184
+ text: "#f4ecdf",
185
+ muted: "#d3c5b4",
186
+ border: "#554638",
187
+ code_bg: "#15120f",
188
+ shadow: "0 22px 60px rgba(11, 8, 5, 0.36)",
189
+ shadow_strong: "0 30px 90px rgba(11, 8, 5, 0.5)",
190
+ radius: "6px",
191
+ font_family: "Charter, Georgia, serif",
192
+ sidebar_bg: "linear-gradient(180deg, rgba(41, 34, 25, 0.95), rgba(26, 22, 18, 0.9))",
193
+ hero_gradient: "linear-gradient(135deg, #352719 0%, #1b1713 100%)",
194
+ card_gradient: "linear-gradient(180deg, #2b241b 0%, #211c16 100%)",
195
+ brand_gradient: "linear-gradient(135deg, #d2a063, #7899aa)",
196
+ brand_mark_text: "#20170d",
197
+ badge_bg: "rgba(210, 160, 99, 0.18)",
198
+ badge_text: "#ffe2b8",
199
+ tag_bg: "rgba(154, 197, 216, 0.17)",
200
+ tag_text: "#cae7f3",
201
+ success_bg: "rgba(134, 239, 172, 0.16)",
202
+ success_text: "#bbf7d0",
203
+ warning_bg: "rgba(253, 186, 116, 0.16)",
204
+ warning_text: "#fed7aa",
205
+ focus_ring: "rgba(210, 160, 99, 0.28)",
206
+ gloss: "rgba(210, 160, 99, 0.15)"
207
+ }
208
+ },
209
+ utility: {
210
+ light: {
211
+ accent: "#2563eb",
212
+ accent_strong: "#1e3a8a",
213
+ secondary: "#0f766e",
214
+ bg: "#f6f9fc",
215
+ panel: "#fbfdff",
216
+ panel_soft: "#eaf1f8",
217
+ text: "#1f2937",
218
+ muted: "#5f6b7a",
219
+ border: "#d3dce8",
220
+ code_bg: "#eaf1f8",
221
+ shadow: "0 18px 45px rgba(30, 58, 138, 0.08)",
222
+ shadow_strong: "0 24px 70px rgba(30, 58, 138, 0.14)",
223
+ radius: "6px",
224
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
225
+ sidebar_bg: "linear-gradient(180deg, rgba(251, 253, 255, 0.94), rgba(234, 241, 248, 0.88))",
226
+ hero_gradient: "linear-gradient(135deg, #fbfdff 0%, #e8f0ff 100%)",
227
+ card_gradient: "linear-gradient(180deg, #fbfdff 0%, #f3f7fb 100%)",
228
+ brand_gradient: "linear-gradient(135deg, #2563eb, #0f766e)",
229
+ brand_mark_text: "#f8fbff",
230
+ badge_bg: "#dfeafe",
231
+ badge_text: "#1e3a8a",
232
+ tag_bg: "#dff4f1",
233
+ tag_text: "#0f5a53",
234
+ success_bg: "#e4f3df",
235
+ success_text: "#2d5c1f",
236
+ warning_bg: "#f6ead9",
237
+ warning_text: "#754716",
238
+ focus_ring: "rgba(37, 99, 235, 0.2)",
239
+ gloss: "rgba(37, 99, 235, 0.13)"
240
+ },
241
+ dark: {
242
+ accent: "#7db1ff",
243
+ accent_strong: "#bfdbfe",
244
+ secondary: "#5eead4",
245
+ bg: "#0f1724",
246
+ panel: "#172131",
247
+ panel_soft: "#202d42",
248
+ text: "#eef5ff",
249
+ muted: "#c4cfdd",
250
+ border: "#33455f",
251
+ code_bg: "#0a111d",
252
+ shadow: "0 22px 60px rgba(4, 8, 16, 0.36)",
253
+ shadow_strong: "0 30px 90px rgba(4, 8, 16, 0.5)",
254
+ radius: "6px",
255
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
256
+ sidebar_bg: "linear-gradient(180deg, rgba(23, 33, 49, 0.95), rgba(12, 19, 31, 0.9))",
257
+ hero_gradient: "linear-gradient(135deg, #1d2b45 0%, #0d1421 100%)",
258
+ card_gradient: "linear-gradient(180deg, #192538 0%, #111a29 100%)",
259
+ brand_gradient: "linear-gradient(135deg, #7db1ff, #2dd4bf)",
260
+ brand_mark_text: "#0b1220",
261
+ badge_bg: "rgba(125, 177, 255, 0.17)",
262
+ badge_text: "#dbeafe",
263
+ tag_bg: "rgba(94, 234, 212, 0.17)",
264
+ tag_text: "#ccfbf1",
265
+ success_bg: "rgba(134, 239, 172, 0.16)",
266
+ success_text: "#bbf7d0",
267
+ warning_bg: "rgba(253, 186, 116, 0.16)",
268
+ warning_text: "#fed7aa",
269
+ focus_ring: "rgba(125, 177, 255, 0.28)",
270
+ gloss: "rgba(125, 177, 255, 0.16)"
271
+ }
272
+ },
273
+ playful: {
274
+ light: {
275
+ accent: "#f97316",
276
+ accent_strong: "#9a3412",
277
+ secondary: "#0ea5e9",
278
+ bg: "#fff8ec",
279
+ panel: "#fffbf4",
280
+ panel_soft: "#ffe9c7",
281
+ text: "#2c241d",
282
+ muted: "#735b47",
283
+ border: "#f7c98f",
284
+ code_bg: "#fff0da",
285
+ shadow: "0 18px 45px rgba(120, 54, 12, 0.1)",
286
+ shadow_strong: "0 28px 75px rgba(120, 54, 12, 0.17)",
287
+ radius: "8px",
288
+ font_family: "Nunito, Inter, ui-sans-serif, system-ui, sans-serif",
289
+ sidebar_bg: "linear-gradient(180deg, rgba(255, 251, 244, 0.94), rgba(255, 233, 199, 0.88))",
290
+ hero_gradient: "linear-gradient(135deg, #fffbf4 0%, #ffe6bc 58%, #e0f2fe 100%)",
291
+ card_gradient: "linear-gradient(180deg, #fffbf4 0%, #fff3e2 100%)",
292
+ brand_gradient: "linear-gradient(135deg, #f97316, #0ea5e9)",
293
+ brand_mark_text: "#fffaf0",
294
+ badge_bg: "#ffe2bd",
295
+ badge_text: "#9a3412",
296
+ tag_bg: "#dff2ff",
297
+ tag_text: "#075985",
298
+ success_bg: "#e7f3df",
299
+ success_text: "#2d5c1f",
300
+ warning_bg: "#fde2c8",
301
+ warning_text: "#7d3414",
302
+ focus_ring: "rgba(249, 115, 22, 0.22)",
303
+ gloss: "rgba(249, 115, 22, 0.15)"
304
+ },
305
+ dark: {
306
+ accent: "#ffb36b",
307
+ accent_strong: "#fed7aa",
308
+ secondary: "#7dd3fc",
309
+ bg: "#24180f",
310
+ panel: "#302116",
311
+ panel_soft: "#402d1e",
312
+ text: "#fff1e3",
313
+ muted: "#e6cbb2",
314
+ border: "#5a3f29",
315
+ code_bg: "#170f09",
316
+ shadow: "0 22px 60px rgba(13, 6, 2, 0.38)",
317
+ shadow_strong: "0 30px 90px rgba(13, 6, 2, 0.52)",
318
+ radius: "8px",
319
+ font_family: "Nunito, Inter, ui-sans-serif, system-ui, sans-serif",
320
+ sidebar_bg: "linear-gradient(180deg, rgba(48, 33, 22, 0.95), rgba(30, 19, 12, 0.9))",
321
+ hero_gradient: "linear-gradient(135deg, #422a17 0%, #21150d 58%, #0d2536 100%)",
322
+ card_gradient: "linear-gradient(180deg, #332318 0%, #26190f 100%)",
323
+ brand_gradient: "linear-gradient(135deg, #ffb36b, #38bdf8)",
324
+ brand_mark_text: "#1f1309",
325
+ badge_bg: "rgba(255, 179, 107, 0.18)",
326
+ badge_text: "#ffedd5",
327
+ tag_bg: "rgba(125, 211, 252, 0.18)",
328
+ tag_text: "#d8f3ff",
329
+ success_bg: "rgba(134, 239, 172, 0.16)",
330
+ success_text: "#bbf7d0",
331
+ warning_bg: "rgba(253, 186, 116, 0.18)",
332
+ warning_text: "#fed7aa",
333
+ focus_ring: "rgba(255, 179, 107, 0.3)",
334
+ gloss: "rgba(255, 179, 107, 0.18)"
335
+ }
336
+ },
337
+ dark: {
338
+ light: {
339
+ accent: "#2563eb",
340
+ accent_strong: "#172554",
341
+ secondary: "#64748b",
342
+ bg: "#f3f6fb",
343
+ panel: "#fbfcff",
344
+ panel_soft: "#e7edf7",
345
+ text: "#172033",
346
+ muted: "#5f6b7a",
347
+ border: "#cfd9e8",
348
+ code_bg: "#e7edf7",
349
+ shadow: "0 18px 45px rgba(15, 23, 42, 0.1)",
350
+ shadow_strong: "0 28px 75px rgba(15, 23, 42, 0.17)",
351
+ radius: "8px",
352
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
353
+ sidebar_bg: "linear-gradient(180deg, rgba(251, 252, 255, 0.94), rgba(231, 237, 247, 0.88))",
354
+ hero_gradient: "linear-gradient(135deg, #fbfcff 0%, #e2eaf8 100%)",
355
+ card_gradient: "linear-gradient(180deg, #fbfcff 0%, #f0f4fa 100%)",
356
+ brand_gradient: "linear-gradient(135deg, #2563eb, #172554)",
357
+ brand_mark_text: "#f8fbff",
358
+ badge_bg: "#dce7fa",
359
+ badge_text: "#172554",
360
+ tag_bg: "#e5eaf2",
361
+ tag_text: "#334155",
362
+ success_bg: "#e3f2df",
363
+ success_text: "#2d5c1f",
364
+ warning_bg: "#f5e4d6",
365
+ warning_text: "#7a3c1d",
366
+ focus_ring: "rgba(37, 99, 235, 0.22)",
367
+ gloss: "rgba(37, 99, 235, 0.13)"
368
+ },
369
+ dark: {
370
+ accent: "#38bdf8",
371
+ accent_strong: "#bae6fd",
372
+ secondary: "#a78bfa",
373
+ bg: "#0f172a",
374
+ panel: "#151f33",
375
+ panel_soft: "#202b42",
376
+ text: "#f8fafc",
377
+ muted: "#cbd5e1",
378
+ border: "#334155",
379
+ code_bg: "#0b1220",
380
+ shadow: "0 22px 60px rgba(4, 8, 16, 0.38)",
381
+ shadow_strong: "0 30px 90px rgba(4, 8, 16, 0.54)",
382
+ radius: "8px",
383
+ font_family: "Inter, ui-sans-serif, system-ui, sans-serif",
384
+ sidebar_bg: "linear-gradient(180deg, rgba(21, 31, 51, 0.95), rgba(12, 18, 32, 0.9))",
385
+ hero_gradient: "linear-gradient(135deg, #1d2b48 0%, #0c1220 100%)",
386
+ card_gradient: "linear-gradient(180deg, #172237 0%, #101827 100%)",
387
+ brand_gradient: "linear-gradient(135deg, #38bdf8, #8b5cf6)",
388
+ brand_mark_text: "#07111f",
389
+ badge_bg: "rgba(56, 189, 248, 0.17)",
390
+ badge_text: "#e0f2fe",
391
+ tag_bg: "rgba(167, 139, 250, 0.18)",
392
+ tag_text: "#ede9fe",
393
+ success_bg: "rgba(134, 239, 172, 0.16)",
394
+ success_text: "#bbf7d0",
395
+ warning_bg: "rgba(253, 186, 116, 0.16)",
396
+ warning_text: "#fed7aa",
397
+ focus_ring: "rgba(56, 189, 248, 0.3)",
398
+ gloss: "rgba(56, 189, 248, 0.18)"
399
+ }
400
+ }
401
+ };
402
+ function previewTheme(root, options = {}) {
403
+ const style = inferProjectStyle(root);
404
+ const identity = inferThemeIdentity(root, options);
405
+ const mood = resolveThemeMood(root, identity, options.mood, style);
406
+ const theme = applyProjectStyle(moodThemes[mood], style);
407
+ return {
408
+ ok: true,
409
+ mode: "preview",
410
+ theme_path: (0, paths_1.relativeReportPath)(root, (0, config_1.siteThemePath)(root)),
411
+ exists: fs_1.default.existsSync((0, config_1.siteThemePath)(root)),
412
+ mood,
413
+ style_sources: style.sources.map((source) => (0, paths_1.relativeReportPath)(root, source.file)),
414
+ identity,
415
+ theme: {
416
+ project_name: identity.project_name,
417
+ project_description: identity.project_description,
418
+ default_color_scheme: style.defaultColorScheme ?? "auto",
419
+ ...theme.light,
420
+ modes: {
421
+ light: theme.light,
422
+ dark: theme.dark
423
+ }
424
+ }
425
+ };
426
+ }
427
+ function writeTheme(root, options = {}) {
428
+ const preview = previewTheme(root, options);
429
+ const file = (0, config_1.siteThemePath)(root);
430
+ const exists = fs_1.default.existsSync(file);
431
+ if (exists && options.force !== true) {
432
+ throw new Error(`Theme already exists at ${preview.theme_path}. Pass --force to overwrite it.`);
433
+ }
434
+ fs_1.default.mkdirSync(path_1.default.dirname(file), { recursive: true });
435
+ fs_1.default.writeFileSync(file, `${JSON.stringify(preview.theme, null, 2)}\n`, "utf8");
436
+ return {
437
+ ...preview,
438
+ mode: "init",
439
+ exists: true,
440
+ written: true,
441
+ overwritten: exists
442
+ };
443
+ }
444
+ function parseThemeMood(value) {
445
+ if (!value) {
446
+ return undefined;
447
+ }
448
+ if (exports.themeMoods.includes(value)) {
449
+ return value;
450
+ }
451
+ throw new Error(`Unknown theme mood: ${value}. Expected one of: ${exports.themeMoods.join(", ")}.`);
452
+ }
453
+ function inferThemeIdentity(root, options) {
454
+ const packageJson = readPackageJson(root);
455
+ const readme = readReadme(root);
456
+ const readmeTitle = readme ? readmeH1(readme) : undefined;
457
+ const readmeDescription = readme ? firstUsefulReadmeParagraph(readme) : undefined;
458
+ const packageName = packageJson?.name && typeof packageJson.name === "string"
459
+ ? prettyPackageName(packageJson.name)
460
+ : undefined;
461
+ const packageDescription = packageJson?.description && typeof packageJson.description === "string"
462
+ ? plainText(packageJson.description)
463
+ : undefined;
464
+ const optionName = plainText(options.projectName);
465
+ const optionDescription = plainText(options.description);
466
+ const fallbackName = prettyPackageName(path_1.default.basename(root));
467
+ return {
468
+ project_name: optionName || readmeTitle || packageName || fallbackName,
469
+ project_description: optionDescription || packageDescription || readmeDescription || defaultDescription,
470
+ project_name_source: optionName ? "option" : readmeTitle ? "readme" : packageName ? "package" : "repo",
471
+ project_description_source: optionDescription ? "option" : packageDescription ? "package" : readmeDescription ? "readme" : "default"
472
+ };
473
+ }
474
+ function resolveThemeMood(root, identity, moodOption, style) {
475
+ const parsedMood = parseThemeMood(moodOption);
476
+ if (parsedMood) {
477
+ return parsedMood;
478
+ }
479
+ const readme = readReadme(root) ?? "";
480
+ const packageJson = readPackageJson(root);
481
+ const styleText = style.sources.map((source) => source.content.slice(0, 12000)).join(" ");
482
+ const text = [
483
+ identity.project_name,
484
+ identity.project_description,
485
+ readme,
486
+ styleText,
487
+ typeof packageJson?.description === "string" ? packageJson.description : "",
488
+ typeof packageJson?.name === "string" ? packageJson.name : ""
489
+ ].join(" ").toLowerCase();
490
+ const scored = exports.themeMoods.map((mood) => ({
491
+ mood,
492
+ score: moodKeywords[mood].reduce((score, keyword) => score + countKeyword(text, keyword), 0)
493
+ }));
494
+ scored.sort((a, b) => b.score - a.score || exports.themeMoods.indexOf(a.mood) - exports.themeMoods.indexOf(b.mood));
495
+ if (scored[0].score > 0) {
496
+ return scored[0].mood;
497
+ }
498
+ if (style.accents.length >= 3) {
499
+ return "vivid";
500
+ }
501
+ if (style.defaultColorScheme === "dark") {
502
+ return "dark";
503
+ }
504
+ return exports.themeMoods[stableHash(identity.project_name) % exports.themeMoods.length];
505
+ }
506
+ function inferProjectStyle(root) {
507
+ const sources = findStyleSources(root);
508
+ const colors = extractStyleColors(sources);
509
+ const accents = accentColors(colors);
510
+ const darkSurface = surfaceColor(colors, "dark", ["bg", "background", "body", "shell", "app"]);
511
+ const darkPanel = surfaceColor(colors, "dark", ["panel", "card", "surface", "glass"]);
512
+ const lightSurface = surfaceColor(colors, "light", ["bg", "background", "body", "shell", "app"]);
513
+ const lightPanel = surfaceColor(colors, "light", ["panel", "card", "surface", "glass"]);
514
+ const darkText = textColor(colors, "dark");
515
+ const lightText = textColor(colors, "light");
516
+ const combined = sources.map((source) => source.content).join("\n").toLowerCase();
517
+ const darkSignals = [
518
+ /color-scheme\s*:\s*dark/.test(combined),
519
+ /data-theme=["']dark/.test(combined),
520
+ /prefers-color-scheme\s*:\s*dark/.test(combined),
521
+ Boolean(darkSurface),
522
+ colors.filter((color) => relativeLuminance(color.rgb) < 0.18).length > colors.filter((color) => relativeLuminance(color.rgb) > 0.82).length
523
+ ].filter(Boolean).length;
524
+ const lightSignals = [
525
+ /color-scheme\s*:\s*light/.test(combined),
526
+ /data-theme=["']light/.test(combined),
527
+ Boolean(lightSurface)
528
+ ].filter(Boolean).length;
529
+ return {
530
+ sources,
531
+ colors,
532
+ accents,
533
+ darkSurface,
534
+ darkPanel,
535
+ darkText,
536
+ lightSurface,
537
+ lightPanel,
538
+ lightText,
539
+ defaultColorScheme: darkSignals > lightSignals ? "dark" : lightSignals > darkSignals ? "light" : undefined,
540
+ radius: inferRadius(sources),
541
+ fontFamily: inferFontFamily(sources),
542
+ gradientAngle: inferGradientAngle(sources),
543
+ hasGlow: /radial-gradient|glow|blur\(/i.test(combined),
544
+ hasGlass: /backdrop-filter|glass|rgba\([^)]*,\s*0\.\d+\)/i.test(combined),
545
+ hasShadow: /box-shadow|shadow/i.test(combined)
546
+ };
547
+ }
548
+ function applyProjectStyle(base, style) {
549
+ if (style.sources.length === 0 || (style.accents.length === 0 && !style.darkSurface && !style.lightSurface)) {
550
+ return {
551
+ light: { ...base.light },
552
+ dark: { ...base.dark }
553
+ };
554
+ }
555
+ const accents = style.accents.length > 0
556
+ ? style.accents
557
+ : [base.light.accent ?? base.dark.accent ?? "#2563eb"];
558
+ const primary = accents[0];
559
+ const secondary = accents[1] ?? base.light.secondary ?? base.dark.secondary ?? primary;
560
+ const tertiary = accents[2] ?? base.dark.secondary ?? secondary;
561
+ const primaryRgb = parseHexColor(primary) ?? { r: 37, g: 99, b: 235 };
562
+ const secondaryRgb = parseHexColor(secondary) ?? primaryRgb;
563
+ const tertiaryRgb = parseHexColor(tertiary) ?? secondaryRgb;
564
+ const lightBgRgb = parseHexColor(style.lightSurface) ?? mixRgb(primaryRgb, { r: 255, g: 250, b: 244 }, 0.06);
565
+ const lightPanelRgb = parseHexColor(style.lightPanel) ?? mixRgb(primaryRgb, { r: 255, g: 253, b: 248 }, 0.04);
566
+ const darkBgRgb = parseHexColor(style.darkSurface) ?? mixRgb(primaryRgb, { r: 15, g: 12, b: 14 }, 0.12);
567
+ const darkPanelRgb = parseHexColor(style.darkPanel) ?? mixRgb(primaryRgb, { r: 25, g: 20, b: 24 }, 0.14);
568
+ const darkAccent = colorToHex(readableAccentFor(primaryRgb, darkPanelRgb, "dark"));
569
+ const lightAccent = colorToHex(readableAccentFor(primaryRgb, lightPanelRgb, "light"));
570
+ const darkSecondary = colorToHex(readableAccentFor(secondaryRgb, darkPanelRgb, "dark"));
571
+ const lightSecondary = colorToHex(readableAccentFor(secondaryRgb, lightPanelRgb, "light"));
572
+ const lightAccentStrong = colorToHex(readableAccentFor(mixRgb(primaryRgb, { r: 17, g: 24, b: 39 }, 0.62), lightPanelRgb, "light"));
573
+ const darkAccentStrong = colorToHex(readableAccentFor(mixRgb(primaryRgb, { r: 255, g: 255, b: 255 }, 0.5), darkPanelRgb, "dark"));
574
+ const lightText = style.defaultColorScheme === "light" ? style.lightText : undefined;
575
+ const darkText = style.defaultColorScheme === "dark" ? style.darkText : undefined;
576
+ const radius = style.radius ?? base.light.radius ?? base.dark.radius ?? "8px";
577
+ const fontFamily = style.fontFamily ?? base.light.font_family ?? base.dark.font_family;
578
+ const angle = style.gradientAngle;
579
+ const brandGradient = gradientFromAccents(angle, accents);
580
+ const lightBadgeBg = colorToHex(mixRgb(primaryRgb, lightPanelRgb, 0.16));
581
+ const darkBadgeBg = colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.28));
582
+ const lightTagBg = colorToHex(mixRgb(secondaryRgb, lightPanelRgb, 0.15));
583
+ const darkTagBg = colorToHex(mixRgb(secondaryRgb, darkPanelRgb, 0.26));
584
+ return {
585
+ light: {
586
+ ...base.light,
587
+ accent: lightAccent,
588
+ accent_strong: lightAccentStrong,
589
+ secondary: lightSecondary,
590
+ bg: colorToHex(lightBgRgb),
591
+ panel: colorToHex(lightPanelRgb),
592
+ panel_soft: colorToHex(mixRgb(tertiaryRgb, lightPanelRgb, 0.1)),
593
+ text: lightText ?? readableTextFor(lightPanelRgb),
594
+ muted: colorToHex(mixRgb(parseHexColor(lightText) ?? { r: 31, g: 41, b: 55 }, lightPanelRgb, 0.65)),
595
+ border: colorToHex(mixRgb(primaryRgb, lightPanelRgb, 0.22)),
596
+ code_bg: colorToHex(mixRgb(tertiaryRgb, lightPanelRgb, 0.08)),
597
+ shadow: style.hasShadow ? `0 24px 70px ${rgba(mixRgb(primaryRgb, { r: 17, g: 24, b: 39 }, 0.38), 0.14)}` : base.light.shadow,
598
+ shadow_strong: style.hasShadow ? `0 32px 100px ${rgba(mixRgb(primaryRgb, { r: 17, g: 24, b: 39 }, 0.4), 0.22)}` : base.light.shadow_strong,
599
+ radius,
600
+ font_family: fontFamily,
601
+ sidebar_bg: `linear-gradient(180deg, ${rgba(lightPanelRgb, 0.95)}, ${rgba(mixRgb(primaryRgb, lightBgRgb, 0.08), 0.9)})`,
602
+ hero_gradient: style.hasGlow
603
+ ? `radial-gradient(circle at top left, ${rgba(primaryRgb, 0.18)}, transparent 34%), linear-gradient(${angle}, ${colorToHex(lightPanelRgb)} 0%, ${colorToHex(mixRgb(secondaryRgb, lightBgRgb, 0.12))} 100%)`
604
+ : `linear-gradient(${angle}, ${colorToHex(lightPanelRgb)} 0%, ${colorToHex(mixRgb(primaryRgb, lightBgRgb, 0.14))} 100%)`,
605
+ card_gradient: style.hasGlass
606
+ ? `linear-gradient(180deg, ${rgba(lightPanelRgb, 0.92)} 0%, ${rgba(mixRgb(primaryRgb, lightPanelRgb, 0.07), 0.82)} 100%)`
607
+ : `linear-gradient(180deg, ${colorToHex(lightPanelRgb)} 0%, ${colorToHex(mixRgb(primaryRgb, lightPanelRgb, 0.05))} 100%)`,
608
+ brand_gradient: brandGradient,
609
+ brand_mark_text: readableTextFor(primaryRgb),
610
+ badge_bg: lightBadgeBg,
611
+ badge_text: readableTextForPair(lightBadgeBg, lightAccentStrong),
612
+ tag_bg: lightTagBg,
613
+ tag_text: readableTextForPair(lightTagBg, lightSecondary),
614
+ focus_ring: rgba(primaryRgb, 0.22),
615
+ gloss: rgba(primaryRgb, style.hasGlass ? 0.2 : 0.14)
616
+ },
617
+ dark: {
618
+ ...base.dark,
619
+ accent: darkAccent,
620
+ accent_strong: darkAccentStrong,
621
+ secondary: darkSecondary,
622
+ bg: colorToHex(darkBgRgb),
623
+ panel: colorToHex(darkPanelRgb),
624
+ panel_soft: colorToHex(mixRgb(tertiaryRgb, darkPanelRgb, 0.12)),
625
+ text: darkText ?? readableTextFor(darkPanelRgb),
626
+ muted: colorToHex(mixRgb(parseHexColor(darkText) ?? { r: 248, g: 250, b: 252 }, darkPanelRgb, 0.7)),
627
+ border: colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.26)),
628
+ code_bg: colorToHex(mixRgb(darkBgRgb, { r: 0, g: 0, b: 0 }, 0.76)),
629
+ shadow: `0 24px 80px ${rgba({ r: 0, g: 0, b: 0 }, style.hasShadow ? 0.38 : 0.3)}`,
630
+ shadow_strong: `0 36px 120px ${rgba({ r: 0, g: 0, b: 0 }, style.hasShadow ? 0.55 : 0.45)}`,
631
+ radius,
632
+ font_family: fontFamily,
633
+ sidebar_bg: `linear-gradient(180deg, ${rgba(darkPanelRgb, 0.95)}, ${rgba(darkBgRgb, 0.92)})`,
634
+ hero_gradient: style.hasGlow
635
+ ? `radial-gradient(circle at top left, ${rgba(primaryRgb, 0.3)}, transparent 34%), linear-gradient(${angle}, ${colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.16))} 0%, ${colorToHex(darkBgRgb)} 100%)`
636
+ : `linear-gradient(${angle}, ${colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.14))} 0%, ${colorToHex(darkBgRgb)} 100%)`,
637
+ card_gradient: style.hasGlass
638
+ ? `linear-gradient(180deg, ${rgba(mixRgb(primaryRgb, darkPanelRgb, 0.08), 0.86)} 0%, ${rgba(darkPanelRgb, 0.72)} 100%)`
639
+ : `linear-gradient(180deg, ${colorToHex(mixRgb(primaryRgb, darkPanelRgb, 0.08))} 0%, ${colorToHex(darkPanelRgb)} 100%)`,
640
+ brand_gradient: brandGradient,
641
+ brand_mark_text: readableTextFor(primaryRgb),
642
+ badge_bg: darkBadgeBg,
643
+ badge_text: readableTextForPair(darkBadgeBg, darkAccentStrong),
644
+ tag_bg: darkTagBg,
645
+ tag_text: readableTextForPair(darkTagBg, darkSecondary),
646
+ focus_ring: rgba(primaryRgb, 0.32),
647
+ gloss: rgba(primaryRgb, style.hasGlass ? 0.24 : 0.18)
648
+ }
649
+ };
650
+ }
651
+ function findStyleSources(root) {
652
+ const files = [];
653
+ collectStyleFiles(root, root, files, 0);
654
+ return files
655
+ .map((file) => ({
656
+ file,
657
+ score: styleFileScore((0, paths_1.relativeReportPath)(root, file)),
658
+ content: readStyleFile(file)
659
+ }))
660
+ .filter((source) => source.score > 0 && source.content.trim().length > 0)
661
+ .sort((a, b) => b.score - a.score || a.file.localeCompare(b.file))
662
+ .slice(0, 16);
663
+ }
664
+ function collectStyleFiles(root, directory, files, depth) {
665
+ if (files.length >= 180 || depth > 6) {
666
+ return;
667
+ }
668
+ let entries;
669
+ try {
670
+ entries = fs_1.default.readdirSync(directory, { withFileTypes: true });
671
+ }
672
+ catch {
673
+ return;
674
+ }
675
+ for (const entry of entries) {
676
+ if (entry.name.startsWith(".") && entry.name !== ".storybook") {
677
+ continue;
678
+ }
679
+ const file = path_1.default.join(directory, entry.name);
680
+ const relative = (0, paths_1.relativeReportPath)(root, file);
681
+ if (entry.isDirectory()) {
682
+ if (!ignoredStyleDirectory(entry.name)) {
683
+ collectStyleFiles(root, file, files, depth + 1);
684
+ }
685
+ continue;
686
+ }
687
+ if (entry.isFile() && styleFileScore(relative) > 0) {
688
+ files.push(file);
689
+ }
690
+ }
691
+ }
692
+ function ignoredStyleDirectory(name) {
693
+ return [
694
+ ".git",
695
+ ".wikiwiki",
696
+ "node_modules",
697
+ "dist",
698
+ "build",
699
+ "coverage",
700
+ ".next",
701
+ ".nuxt",
702
+ ".svelte-kit",
703
+ "wiki",
704
+ "wiki-site"
705
+ ].includes(name);
706
+ }
707
+ function styleFileScore(file) {
708
+ const lower = file.toLowerCase();
709
+ const ext = path_1.default.extname(lower);
710
+ if (lower.endsWith(".min.css")) {
711
+ return 0;
712
+ }
713
+ let score = 0;
714
+ if ([".css", ".scss", ".sass", ".less", ".pcss", ".postcss"].includes(ext)) {
715
+ score += 24;
716
+ }
717
+ else if ([".ts", ".tsx", ".js", ".jsx", ".json"].includes(ext)) {
718
+ if (!/(^|\/)(tailwind\.config|theme\.config|[^/]*(theme|tokens?|design|palette|brand)[^/]*)\./.test(lower)) {
719
+ return 0;
720
+ }
721
+ score += 2;
722
+ }
723
+ else {
724
+ return 0;
725
+ }
726
+ if (/(^|\/)(global|globals|app|layout|landing|home|shell|theme|themes|tokens?|design|palette|brand)[^/]*\./.test(lower)) {
727
+ score += 18;
728
+ }
729
+ if (/(^|\/)(src|app|pages|styles?|css|theme|tokens?|design-system|components)\//.test(lower)) {
730
+ score += 8;
731
+ }
732
+ if (/tailwind\.config|theme\.config|tokens?\.json|design-tokens/.test(lower)) {
733
+ score += 12;
734
+ }
735
+ if (/(test|spec|fixture|mock|snapshot|storybook-static)/.test(lower)) {
736
+ score -= 12;
737
+ }
738
+ return Math.max(0, score);
739
+ }
740
+ function readStyleFile(file) {
741
+ try {
742
+ const stat = fs_1.default.statSync(file);
743
+ if (stat.size > 240000) {
744
+ return fs_1.default.readFileSync(file, "utf8").slice(0, 240000);
745
+ }
746
+ return fs_1.default.readFileSync(file, "utf8");
747
+ }
748
+ catch {
749
+ return "";
750
+ }
751
+ }
752
+ function extractStyleColors(sources) {
753
+ const colors = new Map();
754
+ for (const source of sources) {
755
+ const pattern = /#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})\b/gi;
756
+ let match;
757
+ while ((match = pattern.exec(source.content)) !== null) {
758
+ const hex = normalizeHexColor(match[0]);
759
+ const rgb = parseHexColor(hex);
760
+ if (!rgb) {
761
+ continue;
762
+ }
763
+ const context = source.content.slice(Math.max(0, match.index - 90), Math.min(source.content.length, match.index + 120)).toLowerCase();
764
+ const existing = colors.get(hex) ?? {
765
+ hex,
766
+ rgb,
767
+ count: 0,
768
+ score: 0,
769
+ contexts: []
770
+ };
771
+ existing.count += 1;
772
+ existing.score += source.score + colorContextScore(context) + colorfulness(rgb) * 10;
773
+ if (existing.contexts.length < 8) {
774
+ existing.contexts.push(context);
775
+ }
776
+ colors.set(hex, existing);
777
+ }
778
+ }
779
+ return [...colors.values()].sort((a, b) => b.score - a.score || b.count - a.count || a.hex.localeCompare(b.hex));
780
+ }
781
+ function colorContextScore(context) {
782
+ let score = 0;
783
+ if (/(accent|brand|primary|spectrum|rainbow|highlight|active|selected|focus)/.test(context)) {
784
+ score += 24;
785
+ }
786
+ if (/(rose|pink|red|orange|yellow|green|cyan|blue|violet|purple)/.test(context)) {
787
+ score += 10;
788
+ }
789
+ if (/(bg|background|body|shell|surface|panel|card|glass)/.test(context)) {
790
+ score += 8;
791
+ }
792
+ if (/(text|foreground|color)/.test(context)) {
793
+ score += 4;
794
+ }
795
+ if (/(border|shadow|overlay)/.test(context)) {
796
+ score += 2;
797
+ }
798
+ return score;
799
+ }
800
+ function accentColors(colors) {
801
+ return colors
802
+ .filter((color) => {
803
+ const luminance = relativeLuminance(color.rgb);
804
+ const context = color.contexts.join(" ");
805
+ const explicitAccent = /(accent|brand|primary|spectrum|rainbow|highlight|active|selected|focus)/.test(context);
806
+ const textLike = /(muted|text|foreground|fg)/.test(context);
807
+ return colorfulness(color.rgb) >= 0.25 && luminance > 0.08 && luminance < 0.9 && (explicitAccent || !textLike);
808
+ })
809
+ .sort((a, b) => {
810
+ const aAccent = accentContextScore(a);
811
+ const bAccent = accentContextScore(b);
812
+ return bAccent - aAccent || b.score - a.score || a.hex.localeCompare(b.hex);
813
+ })
814
+ .slice(0, 5)
815
+ .map((color) => color.hex);
816
+ }
817
+ function accentContextScore(color) {
818
+ const context = color.contexts.join(" ");
819
+ return color.score
820
+ + colorfulness(color.rgb) * 30
821
+ + (/(accent|brand|primary|spectrum|rainbow|highlight|active|selected|focus)/.test(context) ? 60 : 0);
822
+ }
823
+ function surfaceColor(colors, mode, keywords) {
824
+ const candidates = colors.filter((color) => {
825
+ const luminance = relativeLuminance(color.rgb);
826
+ const context = color.contexts.join(" ");
827
+ const hasKeyword = keywords.some((keyword) => context.includes(keyword));
828
+ return hasKeyword && (mode === "dark" ? luminance < 0.24 : luminance > 0.72);
829
+ });
830
+ candidates.sort((a, b) => surfaceKeywordScore(b, keywords) - surfaceKeywordScore(a, keywords) || b.score - a.score || (mode === "dark" ? relativeLuminance(a.rgb) - relativeLuminance(b.rgb) : relativeLuminance(b.rgb) - relativeLuminance(a.rgb)));
831
+ return candidates[0]?.hex;
832
+ }
833
+ function surfaceKeywordScore(color, keywords) {
834
+ const escapedHex = color.hex.replace("#", "\\#");
835
+ return color.contexts.reduce((score, context) => {
836
+ const declarationMatch = keywords.some((keyword) => new RegExp(`${keyword}[a-z0-9_-]*\\s*:\\s*${escapedHex}|[a-z0-9_-]*${keyword}[a-z0-9_-]*\\s*:\\s*${escapedHex}`, "i").test(context));
837
+ if (declarationMatch) {
838
+ return score + 100;
839
+ }
840
+ const keywordMatch = keywords.some((keyword) => context.includes(keyword));
841
+ return keywordMatch ? score + 10 : score;
842
+ }, 0);
843
+ }
844
+ function textColor(colors, mode) {
845
+ const candidates = colors.filter((color) => {
846
+ const luminance = relativeLuminance(color.rgb);
847
+ const context = color.contexts.join(" ");
848
+ const declarationScore = textDeclarationScore(color);
849
+ return (declarationScore > 0 || (/(text|foreground|color)/.test(context) && !/(bg|background|border|shadow)/.test(context)))
850
+ && (mode === "dark" ? luminance > 0.74 : luminance < 0.28);
851
+ });
852
+ candidates.sort((a, b) => textDeclarationScore(b) - textDeclarationScore(a) || b.score - a.score || a.hex.localeCompare(b.hex));
853
+ return candidates[0]?.hex;
854
+ }
855
+ function textDeclarationScore(color) {
856
+ const escapedHex = color.hex.replace("#", "\\#");
857
+ return color.contexts.reduce((score, context) => {
858
+ const direct = new RegExp(`(?:text|foreground|fg|color)[a-z0-9_-]*\\s*:\\s*${escapedHex}|[a-z0-9_-]*(?:text|foreground|fg)[a-z0-9_-]*\\s*:\\s*${escapedHex}`, "i").test(context);
859
+ return direct ? score + 100 : score;
860
+ }, 0);
861
+ }
862
+ function inferRadius(sources) {
863
+ const candidates = [];
864
+ for (const source of sources) {
865
+ const pattern = /(?:border-radius|--[a-z0-9-]*radius[a-z0-9-]*)\s*:\s*([^;{}\n]+)/gi;
866
+ let match;
867
+ while ((match = pattern.exec(source.content)) !== null) {
868
+ const value = match[1].trim().split(/\s+/)[0].replace(/,$/, "");
869
+ const pixels = radiusPixels(value);
870
+ if (pixels >= 2 && pixels <= 40) {
871
+ candidates.push({ value, pixels, score: source.score + pixels });
872
+ }
873
+ }
874
+ }
875
+ candidates.sort((a, b) => b.score - a.score || b.pixels - a.pixels);
876
+ return candidates[0]?.value;
877
+ }
878
+ function radiusPixels(value) {
879
+ const match = /^([0-9]+(?:\.[0-9]+)?)(px|rem|em)$/i.exec(value);
880
+ if (!match) {
881
+ return 0;
882
+ }
883
+ const amount = Number.parseFloat(match[1]);
884
+ const unit = match[2].toLowerCase();
885
+ return unit === "px" ? amount : amount * 16;
886
+ }
887
+ function inferFontFamily(sources) {
888
+ for (const source of sources) {
889
+ const match = /font-family\s*:\s*([^;{}\n]+)/i.exec(source.content);
890
+ const value = match?.[1]?.trim();
891
+ if (value && !/^var\(/i.test(value) && !/inherit|initial|unset/i.test(value)) {
892
+ return value.replace(/\s+/g, " ");
893
+ }
894
+ }
895
+ return undefined;
896
+ }
897
+ function inferGradientAngle(sources) {
898
+ for (const source of sources) {
899
+ const match = /linear-gradient\(\s*([^,\)]+)/i.exec(source.content);
900
+ const value = match?.[1]?.trim();
901
+ if (value && (/^-?\d+(?:\.\d+)?deg$/.test(value) || /^to\s+/.test(value))) {
902
+ return value;
903
+ }
904
+ }
905
+ return "135deg";
906
+ }
907
+ function plainText(value) {
908
+ const cleaned = value
909
+ ?.replace(/<script[\s\S]*?<\/script>/gi, " ")
910
+ .replace(/<style[\s\S]*?<\/style>/gi, " ")
911
+ .replace(/<img\b[^>]*alt=["']([^"']*)["'][^>]*>/gi, " $1 ")
912
+ .replace(/<img\b[^>]*>/gi, " ")
913
+ .replace(/!\[[^\]]*]\([^)]+\)/g, " ")
914
+ .replace(/\[([^\]]+)]\([^)]+\)/g, "$1")
915
+ .replace(/<[^>]+>/g, " ")
916
+ .replace(/&nbsp;/gi, " ")
917
+ .replace(/&amp;/gi, "&")
918
+ .replace(/&lt;/gi, "<")
919
+ .replace(/&gt;/gi, ">")
920
+ .replace(/&quot;/gi, "\"")
921
+ .replace(/&#39;/g, "'")
922
+ .replace(/[`*_~]/g, "")
923
+ .replace(/\s+/g, " ")
924
+ .trim();
925
+ return cleaned || undefined;
926
+ }
927
+ function gradientFromAccents(angle, accents) {
928
+ const stops = [...new Set(accents)].slice(0, 5);
929
+ return `linear-gradient(${angle}, ${stops.join(", ")})`;
930
+ }
931
+ function normalizeHexColor(value) {
932
+ const hex = value.replace(/^#/, "");
933
+ if (hex.length === 3) {
934
+ return `#${hex.split("").map((char) => `${char}${char}`).join("")}`.toLowerCase();
935
+ }
936
+ return `#${hex.slice(0, 6)}`.toLowerCase();
937
+ }
938
+ function parseHexColor(value) {
939
+ const trimmed = value?.trim();
940
+ if (!trimmed) {
941
+ return undefined;
942
+ }
943
+ const match = /^#([0-9a-f]{6})$/i.exec(normalizeHexColor(trimmed));
944
+ if (!match) {
945
+ return undefined;
946
+ }
947
+ return {
948
+ r: Number.parseInt(match[1].slice(0, 2), 16),
949
+ g: Number.parseInt(match[1].slice(2, 4), 16),
950
+ b: Number.parseInt(match[1].slice(4, 6), 16)
951
+ };
952
+ }
953
+ function colorToHex(color) {
954
+ return `#${[color.r, color.g, color.b]
955
+ .map((channel) => Math.round(Math.max(0, Math.min(255, channel))).toString(16).padStart(2, "0"))
956
+ .join("")}`;
957
+ }
958
+ function mixRgb(a, b, aWeight) {
959
+ const clamped = Math.max(0, Math.min(1, aWeight));
960
+ const bWeight = 1 - clamped;
961
+ return {
962
+ r: a.r * clamped + b.r * bWeight,
963
+ g: a.g * clamped + b.g * bWeight,
964
+ b: a.b * clamped + b.b * bWeight
965
+ };
966
+ }
967
+ function rgba(color, alpha) {
968
+ const clamped = Math.max(0, Math.min(1, alpha));
969
+ return `rgba(${Math.round(color.r)}, ${Math.round(color.g)}, ${Math.round(color.b)}, ${Number(clamped.toFixed(3))})`;
970
+ }
971
+ function relativeLuminance(color) {
972
+ const [r, g, b] = [color.r, color.g, color.b].map((channel) => {
973
+ const value = channel / 255;
974
+ return value <= 0.03928
975
+ ? value / 12.92
976
+ : ((value + 0.055) / 1.055) ** 2.4;
977
+ });
978
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
979
+ }
980
+ function contrastRatio(a, b) {
981
+ const lighter = Math.max(relativeLuminance(a), relativeLuminance(b));
982
+ const darker = Math.min(relativeLuminance(a), relativeLuminance(b));
983
+ return (lighter + 0.05) / (darker + 0.05);
984
+ }
985
+ function readableTextFor(background) {
986
+ return relativeLuminance(background) > 0.5 ? "#111827" : "#f8fafc";
987
+ }
988
+ function readableTextForPair(background, preferred) {
989
+ const bg = parseHexColor(background);
990
+ const text = parseHexColor(preferred);
991
+ if (bg && text && contrastRatio(bg, text) >= 4.5) {
992
+ return preferred;
993
+ }
994
+ return bg ? readableTextFor(bg) : preferred;
995
+ }
996
+ function readableAccentFor(color, surface, mode) {
997
+ if (contrastRatio(color, surface) >= 3) {
998
+ return color;
999
+ }
1000
+ const target = mode === "dark" ? { r: 255, g: 255, b: 255 } : { r: 17, g: 24, b: 39 };
1001
+ for (const weight of [0.75, 0.6, 0.45, 0.3]) {
1002
+ const candidate = mixRgb(color, target, weight);
1003
+ if (contrastRatio(candidate, surface) >= 3) {
1004
+ return candidate;
1005
+ }
1006
+ }
1007
+ return target;
1008
+ }
1009
+ function colorfulness(color) {
1010
+ const max = Math.max(color.r, color.g, color.b);
1011
+ const min = Math.min(color.r, color.g, color.b);
1012
+ return max === 0 ? 0 : (max - min) / max;
1013
+ }
1014
+ function readPackageJson(root) {
1015
+ const file = path_1.default.join(root, "package.json");
1016
+ if (!fs_1.default.existsSync(file)) {
1017
+ return undefined;
1018
+ }
1019
+ try {
1020
+ const parsed = JSON.parse(fs_1.default.readFileSync(file, "utf8"));
1021
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
1022
+ ? parsed
1023
+ : undefined;
1024
+ }
1025
+ catch {
1026
+ return undefined;
1027
+ }
1028
+ }
1029
+ function readReadme(root) {
1030
+ for (const fileName of ["README.md", "readme.md", "Readme.md"]) {
1031
+ const file = path_1.default.join(root, fileName);
1032
+ if (fs_1.default.existsSync(file)) {
1033
+ return fs_1.default.readFileSync(file, "utf8");
1034
+ }
1035
+ }
1036
+ return undefined;
1037
+ }
1038
+ function readmeH1(readme) {
1039
+ const line = readme.split(/\r?\n/).find((item) => /^#\s+/.test(item.trim()));
1040
+ return plainText(line?.replace(/^#\s+/, "")) || undefined;
1041
+ }
1042
+ function firstUsefulReadmeParagraph(readme) {
1043
+ const withoutCode = readme.replace(/```[\s\S]*?```/g, "\n");
1044
+ const paragraphs = withoutCode.split(/\n{2,}/);
1045
+ for (const paragraph of paragraphs) {
1046
+ const normalized = paragraph
1047
+ .split(/\r?\n/)
1048
+ .map((line) => line.trim())
1049
+ .filter((line) => line && !line.startsWith("#") && !line.startsWith("!") && !line.startsWith("|"))
1050
+ .join(" ")
1051
+ .replace(/\s+/g, " ");
1052
+ const plain = plainText(normalized);
1053
+ if (plain && plain.length >= 24 && !/^(npm|wk|git|cd)\s/.test(plain)) {
1054
+ return plain;
1055
+ }
1056
+ }
1057
+ return undefined;
1058
+ }
1059
+ function prettyPackageName(value) {
1060
+ const unscoped = value.replace(/^@[^/]+\//, "");
1061
+ return unscoped
1062
+ .replace(/[-_]+/g, " ")
1063
+ .replace(/\s+/g, " ")
1064
+ .trim()
1065
+ .replace(/\b\w/g, (char) => char.toUpperCase()) || value;
1066
+ }
1067
+ function countKeyword(text, keyword) {
1068
+ const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1069
+ return (text.match(new RegExp(`\\b${escaped}\\b`, "g")) ?? []).length;
1070
+ }
1071
+ function stableHash(value) {
1072
+ let hash = 0;
1073
+ for (const char of value) {
1074
+ hash = ((hash << 5) - hash + char.charCodeAt(0)) | 0;
1075
+ }
1076
+ return Math.abs(hash);
1077
+ }
1078
+ const moodKeywords = {
1079
+ calm: ["local", "private", "privacy", "wellness", "calm", "care", "notes", "knowledge"],
1080
+ vivid: ["brand", "visual", "design", "product", "creative", "marketing", "launch"],
1081
+ editorial: ["wiki", "docs", "documentation", "writing", "publishing", "knowledge", "reader"],
1082
+ utility: ["cli", "api", "tool", "automation", "developer", "system", "script", "test"],
1083
+ playful: ["game", "play", "playful", "toy", "fun", "music", "art", "sprite"],
1084
+ dark: ["terminal", "security", "ops", "infra", "backend", "night", "dark", "monitor"]
1085
+ };
1086
+ //# sourceMappingURL=theme.js.map