@jack200714/mafw 4.5.1 → 4.8.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 (330) hide show
  1. package/README.md +5 -2
  2. package/bin/mafw.js +16 -14
  3. package/gateway/dist/index.js +52 -38
  4. package/gateway/dist/media/media-plugin-loader.js +0 -12
  5. package/gateway/dist/plugins/hub.js +153 -19
  6. package/gateway/dist/routes/plugins.js +15 -5
  7. package/gateway/dist/runtime/event-broadcast.js +33 -0
  8. package/gateway/dist/runtime/loader.js +23 -13
  9. package/gateway/dist/usage/builtin-plugins/gateway.js +25 -3
  10. package/gateway/dist/usage/plugin-loader.js +0 -11
  11. package/gateway/package.json +2 -2
  12. package/package.json +1 -7
  13. package/packages/tui/dist/cli.js +8 -3
  14. package/.opencode/mafw/.backup-v61/parametric/base-skill-manifest.yaml +0 -2
  15. package/.opencode/mafw/STATUS.md +0 -6
  16. package/.opencode/mafw/ledger.md +0 -20
  17. package/.opencode/mafw/memory/.harmonic_index.json +0 -28
  18. package/.opencode/mafw/memory/.review_queue.json +0 -1
  19. package/.opencode/mafw/memory/tier3/parametric.json +0 -13
  20. package/.opencode/mafw/memory/tier3/test-goal.json +0 -19
  21. package/.opencode/mafw/memory-index.json +0 -6
  22. package/.opencode/mafw/parametric/base-skill-manifest.yaml +0 -2
  23. package/.opencode/mafw/waves.json +0 -4
  24. package/.opencode/opencode.json +0 -3
  25. package/.opencode/plugins/mafw-plugin.ts +0 -8
  26. package/.opencode/skills/banner-design/SKILL.md +0 -196
  27. package/.opencode/skills/banner-design/references/banner-sizes-and-styles.md +0 -118
  28. package/.opencode/skills/brand/SKILL.md +0 -97
  29. package/.opencode/skills/brand/references/approval-checklist.md +0 -169
  30. package/.opencode/skills/brand/references/asset-organization.md +0 -157
  31. package/.opencode/skills/brand/references/brand-guideline-template.md +0 -140
  32. package/.opencode/skills/brand/references/color-palette-management.md +0 -186
  33. package/.opencode/skills/brand/references/consistency-checklist.md +0 -94
  34. package/.opencode/skills/brand/references/logo-usage-rules.md +0 -185
  35. package/.opencode/skills/brand/references/messaging-framework.md +0 -85
  36. package/.opencode/skills/brand/references/typography-specifications.md +0 -214
  37. package/.opencode/skills/brand/references/update.md +0 -118
  38. package/.opencode/skills/brand/references/visual-identity.md +0 -96
  39. package/.opencode/skills/brand/references/voice-framework.md +0 -88
  40. package/.opencode/skills/brand/scripts/extract-colors.cjs +0 -341
  41. package/.opencode/skills/brand/scripts/inject-brand-context.cjs +0 -349
  42. package/.opencode/skills/brand/scripts/sync-brand-to-tokens.cjs +0 -248
  43. package/.opencode/skills/brand/scripts/tests/test_sync_brand_to_tokens.py +0 -52
  44. package/.opencode/skills/brand/scripts/validate-asset.cjs +0 -387
  45. package/.opencode/skills/brand/templates/brand-guidelines-starter.md +0 -275
  46. package/.opencode/skills/design/SKILL.md +0 -313
  47. package/.opencode/skills/design/data/cip/deliverables.csv +0 -51
  48. package/.opencode/skills/design/data/cip/industries.csv +0 -21
  49. package/.opencode/skills/design/data/cip/mockup-contexts.csv +0 -21
  50. package/.opencode/skills/design/data/cip/styles.csv +0 -21
  51. package/.opencode/skills/design/data/icon/styles.csv +0 -16
  52. package/.opencode/skills/design/data/logo/colors.csv +0 -56
  53. package/.opencode/skills/design/data/logo/industries.csv +0 -56
  54. package/.opencode/skills/design/data/logo/styles.csv +0 -56
  55. package/.opencode/skills/design/references/banner-sizes-and-styles.md +0 -118
  56. package/.opencode/skills/design/references/cip-deliverable-guide.md +0 -95
  57. package/.opencode/skills/design/references/cip-design.md +0 -121
  58. package/.opencode/skills/design/references/cip-prompt-engineering.md +0 -84
  59. package/.opencode/skills/design/references/cip-style-guide.md +0 -68
  60. package/.opencode/skills/design/references/design-routing.md +0 -207
  61. package/.opencode/skills/design/references/icon-design.md +0 -122
  62. package/.opencode/skills/design/references/logo-color-psychology.md +0 -101
  63. package/.opencode/skills/design/references/logo-design.md +0 -92
  64. package/.opencode/skills/design/references/logo-prompt-engineering.md +0 -158
  65. package/.opencode/skills/design/references/logo-style-guide.md +0 -109
  66. package/.opencode/skills/design/references/slides-copywriting-formulas.md +0 -84
  67. package/.opencode/skills/design/references/slides-create.md +0 -4
  68. package/.opencode/skills/design/references/slides-html-template.md +0 -295
  69. package/.opencode/skills/design/references/slides-layout-patterns.md +0 -137
  70. package/.opencode/skills/design/references/slides-strategies.md +0 -94
  71. package/.opencode/skills/design/references/slides.md +0 -42
  72. package/.opencode/skills/design/references/social-photos-design.md +0 -329
  73. package/.opencode/skills/design/scripts/cip/core.py +0 -215
  74. package/.opencode/skills/design/scripts/cip/generate.py +0 -484
  75. package/.opencode/skills/design/scripts/cip/render-html.py +0 -424
  76. package/.opencode/skills/design/scripts/cip/search.py +0 -127
  77. package/.opencode/skills/design/scripts/icon/generate.py +0 -487
  78. package/.opencode/skills/design/scripts/logo/core.py +0 -175
  79. package/.opencode/skills/design/scripts/logo/generate.py +0 -362
  80. package/.opencode/skills/design/scripts/logo/search.py +0 -114
  81. package/.opencode/skills/design-system/SKILL.md +0 -244
  82. package/.opencode/skills/design-system/data/slide-backgrounds.csv +0 -11
  83. package/.opencode/skills/design-system/data/slide-charts.csv +0 -26
  84. package/.opencode/skills/design-system/data/slide-color-logic.csv +0 -14
  85. package/.opencode/skills/design-system/data/slide-copy.csv +0 -26
  86. package/.opencode/skills/design-system/data/slide-layout-logic.csv +0 -16
  87. package/.opencode/skills/design-system/data/slide-layouts.csv +0 -26
  88. package/.opencode/skills/design-system/data/slide-strategies.csv +0 -16
  89. package/.opencode/skills/design-system/data/slide-typography.csv +0 -15
  90. package/.opencode/skills/design-system/references/component-specs.md +0 -236
  91. package/.opencode/skills/design-system/references/component-tokens.md +0 -214
  92. package/.opencode/skills/design-system/references/primitive-tokens.md +0 -203
  93. package/.opencode/skills/design-system/references/semantic-tokens.md +0 -215
  94. package/.opencode/skills/design-system/references/states-and-variants.md +0 -241
  95. package/.opencode/skills/design-system/references/tailwind-integration.md +0 -251
  96. package/.opencode/skills/design-system/references/token-architecture.md +0 -224
  97. package/.opencode/skills/design-system/scripts/embed-tokens.cjs +0 -99
  98. package/.opencode/skills/design-system/scripts/fetch-background.py +0 -317
  99. package/.opencode/skills/design-system/scripts/generate-slide.py +0 -770
  100. package/.opencode/skills/design-system/scripts/generate-tokens.cjs +0 -205
  101. package/.opencode/skills/design-system/scripts/html-token-validator.py +0 -327
  102. package/.opencode/skills/design-system/scripts/search-slides.py +0 -218
  103. package/.opencode/skills/design-system/scripts/slide-token-validator.py +0 -35
  104. package/.opencode/skills/design-system/scripts/slide_search_core.py +0 -453
  105. package/.opencode/skills/design-system/scripts/tests/test_validate_tokens.py +0 -48
  106. package/.opencode/skills/design-system/scripts/validate-tokens.cjs +0 -246
  107. package/.opencode/skills/design-system/templates/design-tokens-starter.json +0 -143
  108. package/.opencode/skills/frontend-design/LICENSE.txt +0 -21
  109. package/.opencode/skills/frontend-design/SKILL.md +0 -115
  110. package/.opencode/skills/mafw-automation-interview/SKILL.md +0 -43
  111. package/.opencode/skills/mafw-cli-scanner/SKILL.md +0 -37
  112. package/.opencode/skills/mafw-compression-verifier/SKILL.md +0 -52
  113. package/.opencode/skills/mafw-desktop-inspector/SKILL.md +0 -170
  114. package/.opencode/skills/mafw-execute/SKILL.md +0 -62
  115. package/.opencode/skills/mafw-gateway-restart/SKILL.md +0 -87
  116. package/.opencode/skills/mafw-github-scanner/SKILL.md +0 -38
  117. package/.opencode/skills/mafw-goal/SKILL.md +0 -76
  118. package/.opencode/skills/mafw-interview/SKILL.md +0 -68
  119. package/.opencode/skills/mafw-memory-extractor/SKILL.md +0 -65
  120. package/.opencode/skills/mafw-plan/SKILL.md +0 -58
  121. package/.opencode/skills/mafw-review/SKILL.md +0 -85
  122. package/.opencode/skills/runtime-plugin-authoring/SKILL.md +0 -791
  123. package/.opencode/skills/slides/SKILL.md +0 -40
  124. package/.opencode/skills/slides/references/copywriting-formulas.md +0 -84
  125. package/.opencode/skills/slides/references/create.md +0 -4
  126. package/.opencode/skills/slides/references/html-template.md +0 -295
  127. package/.opencode/skills/slides/references/layout-patterns.md +0 -137
  128. package/.opencode/skills/slides/references/slide-strategies.md +0 -94
  129. package/.opencode/skills/ui-styling/LICENSE.txt +0 -202
  130. package/.opencode/skills/ui-styling/SKILL.md +0 -324
  131. package/.opencode/skills/ui-styling/references/canvas-design-system.md +0 -320
  132. package/.opencode/skills/ui-styling/references/shadcn-accessibility.md +0 -471
  133. package/.opencode/skills/ui-styling/references/shadcn-components.md +0 -424
  134. package/.opencode/skills/ui-styling/references/shadcn-theming.md +0 -373
  135. package/.opencode/skills/ui-styling/references/tailwind-customization.md +0 -483
  136. package/.opencode/skills/ui-styling/references/tailwind-responsive.md +0 -382
  137. package/.opencode/skills/ui-styling/references/tailwind-utilities.md +0 -455
  138. package/.opencode/skills/ui-styling/scripts/requirements.txt +0 -17
  139. package/.opencode/skills/ui-styling/scripts/shadcn_add.py +0 -308
  140. package/.opencode/skills/ui-styling/scripts/tailwind_config_gen.py +0 -473
  141. package/.opencode/skills/ui-styling/scripts/tests/coverage-ui.json +0 -1
  142. package/.opencode/skills/ui-styling/scripts/tests/requirements.txt +0 -3
  143. package/.opencode/skills/ui-styling/scripts/tests/test_shadcn_add.py +0 -266
  144. package/.opencode/skills/ui-styling/scripts/tests/test_tailwind_config_gen.py +0 -394
  145. package/.opencode/skills/ui-ux-pro-max/SKILL.md +0 -388
  146. package/.opencode/skills/ui-ux-pro-max/data/app-interface.csv +0 -31
  147. package/.opencode/skills/ui-ux-pro-max/data/charts.csv +0 -26
  148. package/.opencode/skills/ui-ux-pro-max/data/colors.csv +0 -193
  149. package/.opencode/skills/ui-ux-pro-max/data/google-fonts.csv +0 -1924
  150. package/.opencode/skills/ui-ux-pro-max/data/icons.csv +0 -106
  151. package/.opencode/skills/ui-ux-pro-max/data/landing.csv +0 -35
  152. package/.opencode/skills/ui-ux-pro-max/data/motion.csv +0 -17
  153. package/.opencode/skills/ui-ux-pro-max/data/products.csv +0 -193
  154. package/.opencode/skills/ui-ux-pro-max/data/react-performance.csv +0 -45
  155. package/.opencode/skills/ui-ux-pro-max/data/stacks/angular.csv +0 -51
  156. package/.opencode/skills/ui-ux-pro-max/data/stacks/astro.csv +0 -54
  157. package/.opencode/skills/ui-ux-pro-max/data/stacks/avalonia.csv +0 -57
  158. package/.opencode/skills/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  159. package/.opencode/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  160. package/.opencode/skills/ui-ux-pro-max/data/stacks/javafx.csv +0 -76
  161. package/.opencode/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
  162. package/.opencode/skills/ui-ux-pro-max/data/stacks/laravel.csv +0 -51
  163. package/.opencode/skills/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  164. package/.opencode/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -71
  165. package/.opencode/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  166. package/.opencode/skills/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  167. package/.opencode/skills/ui-ux-pro-max/data/stacks/react.csv +0 -54
  168. package/.opencode/skills/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
  169. package/.opencode/skills/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  170. package/.opencode/skills/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  171. package/.opencode/skills/ui-ux-pro-max/data/stacks/threejs.csv +0 -54
  172. package/.opencode/skills/ui-ux-pro-max/data/stacks/uno.csv +0 -60
  173. package/.opencode/skills/ui-ux-pro-max/data/stacks/uwp.csv +0 -56
  174. package/.opencode/skills/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  175. package/.opencode/skills/ui-ux-pro-max/data/stacks/winui.csv +0 -60
  176. package/.opencode/skills/ui-ux-pro-max/data/stacks/wpf.csv +0 -57
  177. package/.opencode/skills/ui-ux-pro-max/data/styles.csv +0 -85
  178. package/.opencode/skills/ui-ux-pro-max/data/typography.csv +0 -75
  179. package/.opencode/skills/ui-ux-pro-max/data/ui-reasoning.csv +0 -162
  180. package/.opencode/skills/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  181. package/.opencode/skills/ui-ux-pro-max/scripts/core.py +0 -464
  182. package/.opencode/skills/ui-ux-pro-max/scripts/design_system.py +0 -1479
  183. package/.opencode/skills/ui-ux-pro-max/scripts/search.py +0 -162
  184. package/.opencode/skills/ui-ux-pro-max/scripts/tests/test_core.py +0 -134
  185. package/.opencode/skills/ui-ux-pro-max/scripts/tests/test_design_system_mode.py +0 -159
  186. package/.opencode/skills/ui-ux-pro-max/scripts/validate_data.py +0 -114
  187. package/dist/hooks/bash-python-guide.d.ts +0 -4
  188. package/dist/hooks/bash-python-guide.d.ts.map +0 -1
  189. package/dist/hooks/bash-python-guide.js +0 -67
  190. package/dist/hooks/bash-python-guide.js.map +0 -1
  191. package/dist/hooks/handoff.d.ts +0 -9
  192. package/dist/hooks/handoff.d.ts.map +0 -1
  193. package/dist/hooks/handoff.js +0 -8
  194. package/dist/hooks/handoff.js.map +0 -1
  195. package/dist/hooks/hook-manager.d.ts +0 -32
  196. package/dist/hooks/hook-manager.d.ts.map +0 -1
  197. package/dist/hooks/hook-manager.js +0 -91
  198. package/dist/hooks/hook-manager.js.map +0 -1
  199. package/dist/hooks/llm-after.d.ts +0 -8
  200. package/dist/hooks/llm-after.d.ts.map +0 -1
  201. package/dist/hooks/llm-after.js +0 -8
  202. package/dist/hooks/llm-after.js.map +0 -1
  203. package/dist/hooks/media-ingest.d.ts +0 -43
  204. package/dist/hooks/media-ingest.d.ts.map +0 -1
  205. package/dist/hooks/media-ingest.js +0 -269
  206. package/dist/hooks/media-ingest.js.map +0 -1
  207. package/dist/hooks/memory-guide.d.ts +0 -3
  208. package/dist/hooks/memory-guide.d.ts.map +0 -1
  209. package/dist/hooks/memory-guide.js +0 -47
  210. package/dist/hooks/memory-guide.js.map +0 -1
  211. package/dist/hooks/observation-capture.d.ts +0 -17
  212. package/dist/hooks/observation-capture.d.ts.map +0 -1
  213. package/dist/hooks/observation-capture.js +0 -20
  214. package/dist/hooks/observation-capture.js.map +0 -1
  215. package/dist/hooks/session-compacting.d.ts +0 -6
  216. package/dist/hooks/session-compacting.d.ts.map +0 -1
  217. package/dist/hooks/session-compacting.js +0 -6
  218. package/dist/hooks/session-compacting.js.map +0 -1
  219. package/dist/hooks/session-ending.d.ts +0 -20
  220. package/dist/hooks/session-ending.d.ts.map +0 -1
  221. package/dist/hooks/session-ending.js +0 -113
  222. package/dist/hooks/session-ending.js.map +0 -1
  223. package/dist/hooks/session-recall.d.ts +0 -2
  224. package/dist/hooks/session-recall.d.ts.map +0 -1
  225. package/dist/hooks/session-recall.js +0 -103
  226. package/dist/hooks/session-recall.js.map +0 -1
  227. package/dist/hooks/session-start.d.ts +0 -9
  228. package/dist/hooks/session-start.d.ts.map +0 -1
  229. package/dist/hooks/session-start.js +0 -42
  230. package/dist/hooks/session-start.js.map +0 -1
  231. package/dist/hooks/tool-before.d.ts +0 -10
  232. package/dist/hooks/tool-before.d.ts.map +0 -1
  233. package/dist/hooks/tool-before.js +0 -6
  234. package/dist/hooks/tool-before.js.map +0 -1
  235. package/dist/hooks/tool-executed.d.ts +0 -19
  236. package/dist/hooks/tool-executed.d.ts.map +0 -1
  237. package/dist/hooks/tool-executed.js +0 -12
  238. package/dist/hooks/tool-executed.js.map +0 -1
  239. package/dist/hooks/user-profile.d.ts +0 -2
  240. package/dist/hooks/user-profile.d.ts.map +0 -1
  241. package/dist/hooks/user-profile.js +0 -30
  242. package/dist/hooks/user-profile.js.map +0 -1
  243. package/dist/hooks/user-prompt.d.ts +0 -9
  244. package/dist/hooks/user-prompt.d.ts.map +0 -1
  245. package/dist/hooks/user-prompt.js +0 -8
  246. package/dist/hooks/user-prompt.js.map +0 -1
  247. package/dist/hooks/voice-guide.d.ts +0 -8
  248. package/dist/hooks/voice-guide.d.ts.map +0 -1
  249. package/dist/hooks/voice-guide.js +0 -101
  250. package/dist/hooks/voice-guide.js.map +0 -1
  251. package/dist/plugin.d.ts +0 -55
  252. package/dist/plugin.d.ts.map +0 -1
  253. package/dist/plugin.js +0 -342
  254. package/dist/plugin.js.map +0 -1
  255. package/dist/tools/add-memory.d.ts +0 -17
  256. package/dist/tools/add-memory.d.ts.map +0 -1
  257. package/dist/tools/add-memory.js +0 -60
  258. package/dist/tools/add-memory.js.map +0 -1
  259. package/dist/tools/media-ask.d.ts +0 -14
  260. package/dist/tools/media-ask.d.ts.map +0 -1
  261. package/dist/tools/media-ask.js +0 -224
  262. package/dist/tools/media-ask.js.map +0 -1
  263. package/dist/tools/media-speak.d.ts +0 -16
  264. package/dist/tools/media-speak.d.ts.map +0 -1
  265. package/dist/tools/media-speak.js +0 -78
  266. package/dist/tools/media-speak.js.map +0 -1
  267. package/dist/tools/media-upload.d.ts +0 -14
  268. package/dist/tools/media-upload.d.ts.map +0 -1
  269. package/dist/tools/media-upload.js +0 -155
  270. package/dist/tools/media-upload.js.map +0 -1
  271. package/dist/tools/python-exec.d.ts +0 -13
  272. package/dist/tools/python-exec.d.ts.map +0 -1
  273. package/dist/tools/python-exec.js +0 -99
  274. package/dist/tools/python-exec.js.map +0 -1
  275. package/dist/tools/python-restart.d.ts +0 -11
  276. package/dist/tools/python-restart.d.ts.map +0 -1
  277. package/dist/tools/python-restart.js +0 -33
  278. package/dist/tools/python-restart.js.map +0 -1
  279. package/dist/utils/circuit-breaker.d.ts +0 -23
  280. package/dist/utils/circuit-breaker.d.ts.map +0 -1
  281. package/dist/utils/circuit-breaker.js +0 -75
  282. package/dist/utils/circuit-breaker.js.map +0 -1
  283. package/dist/utils/config-loader.d.ts +0 -20
  284. package/dist/utils/config-loader.d.ts.map +0 -1
  285. package/dist/utils/config-loader.js +0 -194
  286. package/dist/utils/config-loader.js.map +0 -1
  287. package/dist/utils/fallback.d.ts +0 -7
  288. package/dist/utils/fallback.d.ts.map +0 -1
  289. package/dist/utils/fallback.js +0 -20
  290. package/dist/utils/fallback.js.map +0 -1
  291. package/dist/utils/git.d.ts +0 -24
  292. package/dist/utils/git.d.ts.map +0 -1
  293. package/dist/utils/git.js +0 -71
  294. package/dist/utils/git.js.map +0 -1
  295. package/dist/utils/github.d.ts +0 -37
  296. package/dist/utils/github.d.ts.map +0 -1
  297. package/dist/utils/github.js +0 -53
  298. package/dist/utils/github.js.map +0 -1
  299. package/dist/utils/global-path.d.ts +0 -2
  300. package/dist/utils/global-path.d.ts.map +0 -1
  301. package/dist/utils/global-path.js +0 -32
  302. package/dist/utils/global-path.js.map +0 -1
  303. package/dist/utils/logger.d.ts +0 -6
  304. package/dist/utils/logger.d.ts.map +0 -1
  305. package/dist/utils/logger.js +0 -69
  306. package/dist/utils/logger.js.map +0 -1
  307. package/dist/utils/obs-capture.d.ts +0 -7
  308. package/dist/utils/obs-capture.d.ts.map +0 -1
  309. package/dist/utils/obs-capture.js +0 -49
  310. package/dist/utils/obs-capture.js.map +0 -1
  311. package/dist/utils/retry.d.ts +0 -11
  312. package/dist/utils/retry.d.ts.map +0 -1
  313. package/dist/utils/retry.js +0 -45
  314. package/dist/utils/retry.js.map +0 -1
  315. package/dist/utils/self-wiring.d.ts +0 -13
  316. package/dist/utils/self-wiring.d.ts.map +0 -1
  317. package/dist/utils/self-wiring.js +0 -86
  318. package/dist/utils/self-wiring.js.map +0 -1
  319. package/dist/utils/state.d.ts +0 -106
  320. package/dist/utils/state.d.ts.map +0 -1
  321. package/dist/utils/state.js +0 -166
  322. package/dist/utils/state.js.map +0 -1
  323. package/dist/utils/status.d.ts +0 -47
  324. package/dist/utils/status.d.ts.map +0 -1
  325. package/dist/utils/status.js +0 -147
  326. package/dist/utils/status.js.map +0 -1
  327. package/dist/utils/ttl-map.d.ts +0 -17
  328. package/dist/utils/ttl-map.d.ts.map +0 -1
  329. package/dist/utils/ttl-map.js +0 -67
  330. package/dist/utils/ttl-map.js.map +0 -1
@@ -1,205 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Generate CSS variables from design tokens JSON
4
- *
5
- * Usage:
6
- * node generate-tokens.cjs --config tokens.json -o tokens.css
7
- * node generate-tokens.cjs --config tokens.json --format tailwind
8
- */
9
-
10
- const fs = require('fs');
11
- const path = require('path');
12
-
13
- /**
14
- * Parse command line arguments
15
- */
16
- function parseArgs() {
17
- const args = process.argv.slice(2);
18
- const options = {
19
- config: null,
20
- output: null,
21
- format: 'css' // css | tailwind
22
- };
23
-
24
- for (let i = 0; i < args.length; i++) {
25
- if (args[i] === '--config' || args[i] === '-c') {
26
- options.config = args[++i];
27
- } else if (args[i] === '--output' || args[i] === '-o') {
28
- options.output = args[++i];
29
- } else if (args[i] === '--format' || args[i] === '-f') {
30
- options.format = args[++i];
31
- } else if (args[i] === '--help' || args[i] === '-h') {
32
- console.log(`
33
- Usage: node generate-tokens.cjs [options]
34
-
35
- Options:
36
- -c, --config <file> Input JSON token file (required)
37
- -o, --output <file> Output file (default: stdout)
38
- -f, --format <type> Output format: css | tailwind (default: css)
39
- -h, --help Show this help
40
- `);
41
- process.exit(0);
42
- }
43
- }
44
-
45
- return options;
46
- }
47
-
48
- /**
49
- * Resolve token references like {primitive.color.blue.600}
50
- */
51
- function resolveReference(value, tokens) {
52
- if (typeof value !== 'string' || !value.startsWith('{')) {
53
- return value;
54
- }
55
-
56
- const path = value.slice(1, -1).split('.');
57
- let result = tokens;
58
-
59
- for (const key of path) {
60
- result = result?.[key];
61
- }
62
-
63
- if (result?.$value) {
64
- return resolveReference(result.$value, tokens);
65
- }
66
-
67
- return result || value;
68
- }
69
-
70
- /**
71
- * Convert token name to CSS variable name
72
- */
73
- function toCssVarName(path) {
74
- return '--' + path.join('-').replace(/\./g, '-');
75
- }
76
-
77
- /**
78
- * Flatten tokens into CSS variables
79
- */
80
- function flattenTokens(obj, tokens, prefix = [], result = {}) {
81
- for (const [key, value] of Object.entries(obj)) {
82
- const currentPath = [...prefix, key];
83
-
84
- if (value && typeof value === 'object') {
85
- if (value.$value !== undefined) {
86
- // This is a token
87
- const cssVar = toCssVarName(currentPath);
88
- const resolvedValue = resolveReference(value.$value, tokens);
89
- result[cssVar] = resolvedValue;
90
- } else {
91
- // Recurse into nested object
92
- flattenTokens(value, tokens, currentPath, result);
93
- }
94
- }
95
- }
96
-
97
- return result;
98
- }
99
-
100
- /**
101
- * Generate CSS output
102
- */
103
- function generateCSS(tokens) {
104
- const primitive = flattenTokens(tokens.primitive || {}, tokens, ['primitive']);
105
- const semantic = flattenTokens(tokens.semantic || {}, tokens, []);
106
- const component = flattenTokens(tokens.component || {}, tokens, []);
107
- const darkSemantic = flattenTokens(tokens.dark?.semantic || {}, tokens, []);
108
-
109
- let css = `/* Design Tokens - Auto-generated */
110
- /* Do not edit directly - modify tokens.json instead */
111
-
112
- /* === PRIMITIVES === */
113
- :root {
114
- ${Object.entries(primitive).map(([k, v]) => ` ${k}: ${v};`).join('\n')}
115
- }
116
-
117
- /* === SEMANTIC === */
118
- :root {
119
- ${Object.entries(semantic).map(([k, v]) => ` ${k}: ${v};`).join('\n')}
120
- }
121
-
122
- /* === COMPONENTS === */
123
- :root {
124
- ${Object.entries(component).map(([k, v]) => ` ${k}: ${v};`).join('\n')}
125
- }
126
- `;
127
-
128
- if (Object.keys(darkSemantic).length > 0) {
129
- css += `
130
- /* === DARK MODE === */
131
- .dark {
132
- ${Object.entries(darkSemantic).map(([k, v]) => ` ${k}: ${v};`).join('\n')}
133
- }
134
- `;
135
- }
136
-
137
- return css;
138
- }
139
-
140
- /**
141
- * Generate Tailwind config output
142
- */
143
- function generateTailwind(tokens) {
144
- const semantic = flattenTokens(tokens.semantic || {}, tokens, []);
145
-
146
- // Extract colors for Tailwind
147
- const colors = {};
148
- for (const [key, value] of Object.entries(semantic)) {
149
- if (key.includes('color')) {
150
- const name = key.replace('--color-', '').replace(/-/g, '.');
151
- colors[name] = `var(${key})`;
152
- }
153
- }
154
-
155
- return `// Tailwind color config - Auto-generated
156
- // Add to tailwind.config.ts theme.extend.colors
157
-
158
- module.exports = {
159
- colors: ${JSON.stringify(colors, null, 2).replace(/"/g, "'")}
160
- };
161
- `;
162
- }
163
-
164
- /**
165
- * Main
166
- */
167
- function main() {
168
- const options = parseArgs();
169
-
170
- if (!options.config) {
171
- console.error('Error: --config is required');
172
- process.exit(1);
173
- }
174
-
175
- // Resolve config path
176
- const configPath = path.resolve(process.cwd(), options.config);
177
-
178
- if (!fs.existsSync(configPath)) {
179
- console.error(`Error: Config file not found: ${configPath}`);
180
- process.exit(1);
181
- }
182
-
183
- // Read and parse tokens
184
- const tokens = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
185
-
186
- // Generate output
187
- let output;
188
- if (options.format === 'tailwind') {
189
- output = generateTailwind(tokens);
190
- } else {
191
- output = generateCSS(tokens);
192
- }
193
-
194
- // Write output
195
- if (options.output) {
196
- const outputPath = path.resolve(process.cwd(), options.output);
197
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
198
- fs.writeFileSync(outputPath, output);
199
- console.log(`Generated: ${outputPath}`);
200
- } else {
201
- console.log(output);
202
- }
203
- }
204
-
205
- main();
@@ -1,327 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- HTML Design Token Validator
4
- Ensures all HTML assets (slides, infographics, etc.) use design tokens.
5
- Source of truth: assets/design-tokens.css
6
-
7
- Usage:
8
- python html-token-validator.py # Validate all HTML assets
9
- python html-token-validator.py --type slides # Validate only slides
10
- python html-token-validator.py --type infographics # Validate only infographics
11
- python html-token-validator.py path/to/file.html # Validate specific file
12
- python html-token-validator.py --fix # Auto-fix issues (WIP)
13
- """
14
-
15
- import re
16
- import json
17
- import sys
18
- from pathlib import Path
19
- from typing import Dict, List, Tuple, Optional
20
-
21
- # Project root relative to this script
22
- PROJECT_ROOT = Path(__file__).parent.parent.parent.parent.parent
23
- TOKENS_JSON_PATH = PROJECT_ROOT / 'assets' / 'design-tokens.json'
24
- TOKENS_CSS_PATH = PROJECT_ROOT / 'assets' / 'design-tokens.css'
25
-
26
- # Asset directories to validate
27
- ASSET_DIRS = {
28
- 'slides': PROJECT_ROOT / 'assets' / 'designs' / 'slides',
29
- 'infographics': PROJECT_ROOT / 'assets' / 'infographics',
30
- }
31
-
32
- # Patterns that indicate hardcoded values (should use tokens)
33
- FORBIDDEN_PATTERNS = [
34
- (r'#[0-9A-Fa-f]{3,8}\b', 'hex color'),
35
- (r'rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)', 'rgb color'),
36
- (r'rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)', 'rgba color'),
37
- (r'hsl\([^)]+\)', 'hsl color'),
38
- (r"font-family:\s*'[^v][^a][^r][^']*',", 'hardcoded font'), # Exclude var()
39
- (r'font-family:\s*"[^v][^a][^r][^"]*",', 'hardcoded font'),
40
- ]
41
-
42
- # Allowed rgba patterns (brand colors with transparency - CSS limitation)
43
- # These are derived from brand tokens but need rgba for transparency
44
- ALLOWED_RGBA_PATTERNS = [
45
- r'rgba\(\s*59\s*,\s*130\s*,\s*246', # --color-primary (#3B82F6)
46
- r'rgba\(\s*245\s*,\s*158\s*,\s*11', # --color-secondary (#F59E0B)
47
- r'rgba\(\s*16\s*,\s*185\s*,\s*129', # --color-accent (#10B981)
48
- r'rgba\(\s*20\s*,\s*184\s*,\s*166', # --color-accent alt (#14B8A6)
49
- r'rgba\(\s*0\s*,\s*0\s*,\s*0', # black transparency (common)
50
- r'rgba\(\s*255\s*,\s*255\s*,\s*255', # white transparency (common)
51
- r'rgba\(\s*15\s*,\s*23\s*,\s*42', # --color-surface (#0F172A)
52
- r'rgba\(\s*7\s*,\s*11\s*,\s*20', # --color-background (#070B14)
53
- ]
54
-
55
- # Allowed exceptions (external images, etc.)
56
- ALLOWED_EXCEPTIONS = [
57
- 'pexels.com', 'unsplash.com', 'youtube.com', 'ytimg.com',
58
- 'googlefonts', 'fonts.googleapis.com', 'fonts.gstatic.com',
59
- ]
60
-
61
-
62
- class ValidationResult:
63
- """Validation result for a single file."""
64
- def __init__(self, file_path: Path):
65
- self.file_path = file_path
66
- self.errors: List[str] = []
67
- self.warnings: List[str] = []
68
- self.passed = True
69
-
70
- def add_error(self, msg: str):
71
- self.errors.append(msg)
72
- self.passed = False
73
-
74
- def add_warning(self, msg: str):
75
- self.warnings.append(msg)
76
-
77
-
78
- def load_css_variables() -> Dict[str, str]:
79
- """Load CSS variables from design-tokens.css."""
80
- variables = {}
81
- if TOKENS_CSS_PATH.exists():
82
- content = TOKENS_CSS_PATH.read_text()
83
- # Extract --var-name: value patterns
84
- for match in re.finditer(r'(--[\w-]+):\s*([^;]+);', content):
85
- variables[match.group(1)] = match.group(2).strip()
86
- return variables
87
-
88
-
89
- def is_inside_block(content: str, match_pos: int, open_tag: str, close_tag: str) -> bool:
90
- """Check if position is inside a specific HTML block."""
91
- pre = content[:match_pos]
92
- tag_open = pre.rfind(open_tag)
93
- tag_close = pre.rfind(close_tag)
94
- return tag_open > tag_close
95
-
96
-
97
- def is_allowed_exception(context: str) -> bool:
98
- """Check if the hardcoded value is in an allowed exception context."""
99
- context_lower = context.lower()
100
- return any(exc in context_lower for exc in ALLOWED_EXCEPTIONS)
101
-
102
-
103
- def is_allowed_rgba(match_text: str) -> bool:
104
- """Check if rgba pattern uses brand colors (allowed for transparency)."""
105
- return any(re.match(pattern, match_text) for pattern in ALLOWED_RGBA_PATTERNS)
106
-
107
-
108
- def get_context(content: str, pos: int, chars: int = 100) -> str:
109
- """Get surrounding context for a match position."""
110
- start = max(0, pos - chars)
111
- end = min(len(content), pos + chars)
112
- return content[start:end]
113
-
114
-
115
- def validate_html(content: str, file_path: Path, verbose: bool = False) -> ValidationResult:
116
- """
117
- Validate HTML content for design token compliance.
118
-
119
- Checks:
120
- 1. design-tokens.css import present
121
- 2. No hardcoded colors in CSS (except in <script> for Chart.js)
122
- 3. No hardcoded fonts
123
- 4. Uses var(--token-name) pattern
124
- """
125
- result = ValidationResult(file_path)
126
-
127
- # 1. Check for design-tokens.css import
128
- if 'design-tokens.css' not in content:
129
- result.add_error("Missing design-tokens.css import")
130
-
131
- # 2. Check for forbidden patterns in CSS
132
- for pattern, description in FORBIDDEN_PATTERNS:
133
- for match in re.finditer(pattern, content):
134
- match_text = match.group()
135
- match_pos = match.start()
136
- context = get_context(content, match_pos)
137
-
138
- # Skip if in <script> block (Chart.js allowed)
139
- if is_inside_block(content, match_pos, '<script', '</script>'):
140
- if verbose:
141
- result.add_warning(f"Allowed in <script>: {match_text}")
142
- continue
143
-
144
- # Skip if in allowed exception context (external URLs)
145
- if is_allowed_exception(context):
146
- if verbose:
147
- result.add_warning(f"Allowed external: {match_text}")
148
- continue
149
-
150
- # Skip rgba using brand colors (needed for transparency effects)
151
- if description == 'rgba color' and is_allowed_rgba(match_text):
152
- if verbose:
153
- result.add_warning(f"Allowed brand rgba: {match_text}")
154
- continue
155
-
156
- # Skip if part of var() reference (false positive)
157
- if 'var(' in context and match_text in context:
158
- # Check if it's a fallback value in var()
159
- var_pattern = rf'var\([^)]*{re.escape(match_text)}[^)]*\)'
160
- if re.search(var_pattern, context):
161
- continue
162
-
163
- # Error if in <style> or inline style
164
- if is_inside_block(content, match_pos, '<style', '</style>'):
165
- result.add_error(f"Hardcoded {description} in <style>: {match_text}")
166
- elif 'style="' in context:
167
- result.add_error(f"Hardcoded {description} in inline style: {match_text}")
168
-
169
- # 3. Check for required var() usage indicators
170
- token_patterns = [
171
- r'var\(--color-',
172
- r'var\(--primitive-',
173
- r'var\(--typography-',
174
- r'var\(--card-',
175
- r'var\(--button-',
176
- ]
177
- token_count = sum(len(re.findall(p, content)) for p in token_patterns)
178
-
179
- if token_count < 5:
180
- result.add_warning(f"Low token usage ({token_count} var() references). Consider using more design tokens.")
181
-
182
- return result
183
-
184
-
185
- def validate_file(file_path: Path, verbose: bool = False) -> ValidationResult:
186
- """Validate a single HTML file."""
187
- if not file_path.exists():
188
- result = ValidationResult(file_path)
189
- result.add_error("File not found")
190
- return result
191
-
192
- content = file_path.read_text()
193
- return validate_html(content, file_path, verbose)
194
-
195
-
196
- def validate_directory(dir_path: Path, verbose: bool = False) -> List[ValidationResult]:
197
- """Validate all HTML files in a directory."""
198
- results = []
199
- if dir_path.exists():
200
- for html_file in sorted(dir_path.glob('*.html')):
201
- results.append(validate_file(html_file, verbose))
202
- return results
203
-
204
-
205
- def print_result(result: ValidationResult, verbose: bool = False):
206
- """Print validation result for a file."""
207
- status = "✓" if result.passed else "✗"
208
- print(f" {status} {result.file_path.name}")
209
-
210
- if result.errors:
211
- for error in result.errors[:5]: # Limit output
212
- print(f" ├─ {error}")
213
- if len(result.errors) > 5:
214
- print(f" └─ ... and {len(result.errors) - 5} more errors")
215
-
216
- if verbose and result.warnings:
217
- for warning in result.warnings[:3]:
218
- print(f" [warn] {warning}")
219
-
220
-
221
- def print_summary(all_results: Dict[str, List[ValidationResult]]):
222
- """Print summary of all validation results."""
223
- total_files = 0
224
- total_passed = 0
225
- total_errors = 0
226
-
227
- print("\n" + "=" * 60)
228
- print("HTML DESIGN TOKEN VALIDATION SUMMARY")
229
- print("=" * 60)
230
-
231
- for asset_type, results in all_results.items():
232
- if not results:
233
- continue
234
-
235
- passed = sum(1 for r in results if r.passed)
236
- failed = len(results) - passed
237
- errors = sum(len(r.errors) for r in results)
238
-
239
- total_files += len(results)
240
- total_passed += passed
241
- total_errors += errors
242
-
243
- status = "✓" if failed == 0 else "✗"
244
- print(f"\n{status} {asset_type.upper()}: {passed}/{len(results)} passed")
245
-
246
- for result in results:
247
- if not result.passed:
248
- print_result(result)
249
-
250
- print("\n" + "-" * 60)
251
- if total_errors == 0:
252
- print(f"✓ ALL PASSED: {total_passed}/{total_files} files valid")
253
- else:
254
- print(f"✗ FAILED: {total_files - total_passed}/{total_files} files have issues ({total_errors} total errors)")
255
- print("-" * 60)
256
-
257
- return total_errors == 0
258
-
259
-
260
- def main():
261
- """CLI entry point."""
262
- import argparse
263
-
264
- parser = argparse.ArgumentParser(
265
- description='Validate HTML assets for design token compliance',
266
- formatter_class=argparse.RawDescriptionHelpFormatter,
267
- epilog="""
268
- Examples:
269
- %(prog)s # Validate all HTML assets
270
- %(prog)s --type slides # Validate only slides
271
- %(prog)s --type infographics # Validate only infographics
272
- %(prog)s path/to/file.html # Validate specific file
273
- %(prog)s --colors # Show brand colors from tokens
274
- """
275
- )
276
- parser.add_argument('files', nargs='*', help='Specific HTML files to validate')
277
- parser.add_argument('-t', '--type', choices=['slides', 'infographics', 'all'],
278
- default='all', help='Asset type to validate')
279
- parser.add_argument('-v', '--verbose', action='store_true', help='Show warnings')
280
- parser.add_argument('--colors', action='store_true', help='Print CSS variables from tokens')
281
- parser.add_argument('--fix', action='store_true', help='Auto-fix issues (experimental)')
282
-
283
- args = parser.parse_args()
284
-
285
- # Show colors mode
286
- if args.colors:
287
- variables = load_css_variables()
288
- print("\nDesign Tokens (from design-tokens.css):")
289
- print("-" * 40)
290
- for name, value in sorted(variables.items())[:30]:
291
- print(f" {name}: {value}")
292
- if len(variables) > 30:
293
- print(f" ... and {len(variables) - 30} more")
294
- return
295
-
296
- all_results: Dict[str, List[ValidationResult]] = {}
297
-
298
- # Validate specific files
299
- if args.files:
300
- results = []
301
- for file_path in args.files:
302
- path = Path(file_path)
303
- if path.exists():
304
- results.append(validate_file(path, args.verbose))
305
- else:
306
- result = ValidationResult(path)
307
- result.add_error("File not found")
308
- results.append(result)
309
- all_results['specified'] = results
310
- else:
311
- # Validate by type
312
- types_to_check = ASSET_DIRS.keys() if args.type == 'all' else [args.type]
313
-
314
- for asset_type in types_to_check:
315
- if asset_type in ASSET_DIRS:
316
- results = validate_directory(ASSET_DIRS[asset_type], args.verbose)
317
- all_results[asset_type] = results
318
-
319
- # Print results
320
- success = print_summary(all_results)
321
-
322
- if not success:
323
- sys.exit(1)
324
-
325
-
326
- if __name__ == '__main__':
327
- main()