@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,341 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * extract-colors.cjs
4
- *
5
- * Extract dominant colors from an image and compare against brand palette.
6
- * Uses pure Node.js without external image processing dependencies.
7
- *
8
- * For full color extraction from images, integrate with ai-multimodal skill
9
- * or use ImageMagick via shell commands.
10
- *
11
- * Usage:
12
- * node extract-colors.cjs <image-path>
13
- * node extract-colors.cjs <image-path> --brand-file <path>
14
- * node extract-colors.cjs --palette # Show brand palette from guidelines
15
- *
16
- * Integration:
17
- * For image color analysis, use: ai-multimodal skill or ImageMagick
18
- * magick <image> -colors 10 -depth 8 -format "%c" histogram:info:
19
- */
20
-
21
- const fs = require("fs");
22
- const path = require("path");
23
-
24
- // Default brand guidelines path
25
- const DEFAULT_GUIDELINES_PATH = "docs/brand-guidelines.md";
26
-
27
- /**
28
- * Extract hex colors from markdown content
29
- */
30
- function extractHexColors(text) {
31
- const hexPattern = /#[0-9A-Fa-f]{6}\b/g;
32
- return [...new Set(text.match(hexPattern) || [])];
33
- }
34
-
35
- /**
36
- * Parse brand guidelines for color palette
37
- */
38
- function parseBrandColors(guidelinesPath) {
39
- const resolvedPath = path.isAbsolute(guidelinesPath)
40
- ? guidelinesPath
41
- : path.join(process.cwd(), guidelinesPath);
42
-
43
- if (!fs.existsSync(resolvedPath)) {
44
- return null;
45
- }
46
-
47
- const content = fs.readFileSync(resolvedPath, "utf-8");
48
-
49
- const palette = {
50
- primary: [],
51
- secondary: [],
52
- neutral: [],
53
- semantic: [],
54
- all: [],
55
- };
56
-
57
- // Extract colors from different sections
58
- const sections = [
59
- { name: "primary", regex: /### Primary[\s\S]*?(?=###|##|$)/i },
60
- { name: "secondary", regex: /### Secondary[\s\S]*?(?=###|##|$)/i },
61
- { name: "neutral", regex: /### Neutral[\s\S]*?(?=###|##|$)/i },
62
- { name: "semantic", regex: /### Semantic[\s\S]*?(?=###|##|$)/i },
63
- ];
64
-
65
- sections.forEach(({ name, regex }) => {
66
- const match = content.match(regex);
67
- if (match) {
68
- const colors = extractHexColors(match[0]);
69
- palette[name] = colors;
70
- palette.all.push(...colors);
71
- }
72
- });
73
-
74
- // Dedupe all
75
- palette.all = [...new Set(palette.all)];
76
-
77
- return palette;
78
- }
79
-
80
- /**
81
- * Convert hex to RGB
82
- */
83
- function hexToRgb(hex) {
84
- const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
85
- return result
86
- ? {
87
- r: parseInt(result[1], 16),
88
- g: parseInt(result[2], 16),
89
- b: parseInt(result[3], 16),
90
- }
91
- : null;
92
- }
93
-
94
- /**
95
- * Convert RGB to hex
96
- */
97
- function rgbToHex(r, g, b) {
98
- return (
99
- "#" +
100
- [r, g, b]
101
- .map((x) => {
102
- const hex = Math.round(x).toString(16);
103
- return hex.length === 1 ? "0" + hex : hex;
104
- })
105
- .join("")
106
- .toUpperCase()
107
- );
108
- }
109
-
110
- /**
111
- * Calculate color distance (Euclidean in RGB space)
112
- */
113
- function colorDistance(color1, color2) {
114
- const rgb1 = typeof color1 === "string" ? hexToRgb(color1) : color1;
115
- const rgb2 = typeof color2 === "string" ? hexToRgb(color2) : color2;
116
-
117
- if (!rgb1 || !rgb2) return Infinity;
118
-
119
- return Math.sqrt(
120
- Math.pow(rgb1.r - rgb2.r, 2) +
121
- Math.pow(rgb1.g - rgb2.g, 2) +
122
- Math.pow(rgb1.b - rgb2.b, 2)
123
- );
124
- }
125
-
126
- /**
127
- * Find nearest brand color
128
- */
129
- function findNearestBrandColor(color, brandColors) {
130
- let nearest = null;
131
- let minDistance = Infinity;
132
-
133
- brandColors.forEach((brandColor) => {
134
- const distance = colorDistance(color, brandColor);
135
- if (distance < minDistance) {
136
- minDistance = distance;
137
- nearest = brandColor;
138
- }
139
- });
140
-
141
- return { color: nearest, distance: minDistance };
142
- }
143
-
144
- /**
145
- * Calculate brand compliance percentage
146
- * Distance threshold: 50 (out of max ~441 for RGB)
147
- */
148
- function calculateCompliance(extractedColors, brandColors, threshold = 50) {
149
- if (!extractedColors || extractedColors.length === 0) return 100;
150
- if (!brandColors || brandColors.length === 0) return 0;
151
-
152
- let matchCount = 0;
153
-
154
- extractedColors.forEach((color) => {
155
- const nearest = findNearestBrandColor(color, brandColors);
156
- if (nearest.distance <= threshold) {
157
- matchCount++;
158
- }
159
- });
160
-
161
- return Math.round((matchCount / extractedColors.length) * 100);
162
- }
163
-
164
- /**
165
- * Generate ImageMagick command for color extraction
166
- */
167
- function generateImageMagickCommand(imagePath, numColors = 10) {
168
- return `magick "${imagePath}" -colors ${numColors} -depth 8 -format "%c" histogram:info:`;
169
- }
170
-
171
- /**
172
- * Parse ImageMagick histogram output to extract colors
173
- */
174
- function parseImageMagickOutput(output) {
175
- const colors = [];
176
- const lines = output.trim().split("\n");
177
-
178
- lines.forEach((line) => {
179
- // Match pattern like: 12345: (255,128,64) #FF8040 srgb(255,128,64)
180
- const hexMatch = line.match(/#([0-9A-Fa-f]{6})/);
181
- const countMatch = line.match(/^\s*(\d+):/);
182
-
183
- if (hexMatch) {
184
- colors.push({
185
- hex: "#" + hexMatch[1].toUpperCase(),
186
- count: countMatch ? parseInt(countMatch[1]) : 0,
187
- });
188
- }
189
- });
190
-
191
- // Sort by count (most common first)
192
- colors.sort((a, b) => b.count - a.count);
193
-
194
- return colors;
195
- }
196
-
197
- /**
198
- * Display brand palette
199
- */
200
- function displayPalette(palette) {
201
- console.log("\n" + "=".repeat(50));
202
- console.log("BRAND COLOR PALETTE");
203
- console.log("=".repeat(50));
204
-
205
- if (palette.primary.length > 0) {
206
- console.log("\nPrimary Colors:");
207
- palette.primary.forEach((c) => console.log(` ${c}`));
208
- }
209
-
210
- if (palette.secondary.length > 0) {
211
- console.log("\nSecondary Colors:");
212
- palette.secondary.forEach((c) => console.log(` ${c}`));
213
- }
214
-
215
- if (palette.neutral.length > 0) {
216
- console.log("\nNeutral Colors:");
217
- palette.neutral.forEach((c) => console.log(` ${c}`));
218
- }
219
-
220
- if (palette.semantic.length > 0) {
221
- console.log("\nSemantic Colors:");
222
- palette.semantic.forEach((c) => console.log(` ${c}`));
223
- }
224
-
225
- console.log("\n" + "=".repeat(50));
226
- console.log(`Total: ${palette.all.length} colors in brand palette`);
227
- console.log("=".repeat(50) + "\n");
228
- }
229
-
230
- /**
231
- * Main function
232
- */
233
- function main() {
234
- const args = process.argv.slice(2);
235
- const jsonOutput = args.includes("--json");
236
- const showPalette = args.includes("--palette");
237
- const brandFileIdx = args.indexOf("--brand-file");
238
- const brandFile =
239
- brandFileIdx !== -1 ? args[brandFileIdx + 1] : DEFAULT_GUIDELINES_PATH;
240
- const brandFileValue = brandFileIdx !== -1 ? args[brandFileIdx + 1] : null;
241
- const imagePath = args.find(
242
- (a) => !a.startsWith("--") && a !== brandFileValue
243
- );
244
-
245
- // Load brand palette
246
- const brandPalette = parseBrandColors(brandFile);
247
-
248
- if (!brandPalette) {
249
- console.error(`Brand guidelines not found at: ${brandFile}`);
250
- console.error(`Create brand guidelines or specify path with --brand-file`);
251
- process.exit(1);
252
- }
253
-
254
- // Show palette mode
255
- if (showPalette || !imagePath) {
256
- if (jsonOutput) {
257
- console.log(JSON.stringify(brandPalette, null, 2));
258
- } else {
259
- displayPalette(brandPalette);
260
-
261
- if (!imagePath) {
262
- console.log("To extract colors from an image:");
263
- console.log(" node extract-colors.cjs <image-path>");
264
- console.log("\nOr use ImageMagick directly:");
265
- console.log(' magick image.png -colors 10 -depth 8 -format "%c" histogram:info:');
266
- }
267
- }
268
- return;
269
- }
270
-
271
- // Resolve image path
272
- const resolvedPath = path.isAbsolute(imagePath)
273
- ? imagePath
274
- : path.join(process.cwd(), imagePath);
275
-
276
- if (!fs.existsSync(resolvedPath)) {
277
- console.error(`Image not found: ${resolvedPath}`);
278
- process.exit(1);
279
- }
280
-
281
- // Generate extraction instructions
282
- const result = {
283
- image: resolvedPath,
284
- brandPalette: brandPalette,
285
- extractionCommand: generateImageMagickCommand(resolvedPath),
286
- instructions: [
287
- "1. Run the ImageMagick command to extract colors:",
288
- ` ${generateImageMagickCommand(resolvedPath)}`,
289
- "",
290
- "2. Or use the ai-multimodal skill:",
291
- ` python .claude/skills/ai-multimodal/scripts/gemini_batch_process.py \\`,
292
- ` --files "${resolvedPath}" \\`,
293
- ` --task analyze \\`,
294
- ` --prompt "Extract the 10 most dominant colors as hex values"`,
295
- "",
296
- "3. Then compare extracted colors against brand palette",
297
- ],
298
- complianceCheck: {
299
- threshold: 50,
300
- description:
301
- "Colors within distance 50 (RGB space) are considered brand-compliant",
302
- brandColors: brandPalette.all,
303
- },
304
- };
305
-
306
- if (jsonOutput) {
307
- console.log(JSON.stringify(result, null, 2));
308
- } else {
309
- console.log("\n" + "=".repeat(60));
310
- console.log("COLOR EXTRACTION HELPER");
311
- console.log("=".repeat(60));
312
- console.log(`\nImage: ${result.image}`);
313
- console.log(`\nBrand Colors: ${brandPalette.all.length} colors loaded`);
314
- console.log("\nTo extract colors from this image:\n");
315
- result.instructions.forEach((line) => console.log(line));
316
- console.log("\n" + "=".repeat(60));
317
-
318
- // Show brand palette for reference
319
- console.log("\nBrand Palette Reference:");
320
- console.log(` Primary: ${brandPalette.primary.join(", ") || "none"}`);
321
- console.log(` Secondary: ${brandPalette.secondary.join(", ") || "none"}`);
322
- console.log(` Neutral: ${brandPalette.neutral.join(", ") || "none"}`);
323
- console.log("=".repeat(60) + "\n");
324
- }
325
- }
326
-
327
- // Export functions for use as module
328
- module.exports = {
329
- parseBrandColors,
330
- hexToRgb,
331
- rgbToHex,
332
- colorDistance,
333
- findNearestBrandColor,
334
- calculateCompliance,
335
- parseImageMagickOutput,
336
- };
337
-
338
- // Run if called directly
339
- if (require.main === module) {
340
- main();
341
- }
@@ -1,349 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * inject-brand-context.cjs
4
- *
5
- * Extracts brand context from markdown brand guidelines
6
- * and outputs a formatted system prompt addition.
7
- *
8
- * Usage:
9
- * node inject-brand-context.cjs [path-to-guidelines]
10
- * node inject-brand-context.cjs --json [path-to-guidelines]
11
- *
12
- * Default path: docs/brand-guidelines.md
13
- */
14
-
15
- const fs = require("fs");
16
- const path = require("path");
17
-
18
- // Default brand guidelines path
19
- const DEFAULT_GUIDELINES_PATH = "docs/brand-guidelines.md";
20
-
21
- /**
22
- * Extract hex colors from text
23
- */
24
- function extractHexColors(text) {
25
- const hexPattern = /#[0-9A-Fa-f]{6}\b/g;
26
- return [...new Set(text.match(hexPattern) || [])];
27
- }
28
-
29
- /**
30
- * Extract color data from markdown table
31
- */
32
- function extractColorsFromTable(content) {
33
- const colors = {
34
- primary: [],
35
- secondary: [],
36
- neutral: [],
37
- semantic: [],
38
- };
39
-
40
- // Find color tables
41
- const primaryMatch = content.match(
42
- /### Primary Colors[\s\S]*?\|[\s\S]*?(?=###|$)/i
43
- );
44
- const secondaryMatch = content.match(
45
- /### Secondary Colors[\s\S]*?\|[\s\S]*?(?=###|$)/i
46
- );
47
- const neutralMatch = content.match(
48
- /### Neutral[\s\S]*?\|[\s\S]*?(?=###|$)/i
49
- );
50
- const semanticMatch = content.match(
51
- /### Semantic[\s\S]*?\|[\s\S]*?(?=###|$)/i
52
- );
53
-
54
- if (primaryMatch) colors.primary = extractHexColors(primaryMatch[0]);
55
- if (secondaryMatch) colors.secondary = extractHexColors(secondaryMatch[0]);
56
- if (neutralMatch) colors.neutral = extractHexColors(neutralMatch[0]);
57
- if (semanticMatch) colors.semantic = extractHexColors(semanticMatch[0]);
58
-
59
- return colors;
60
- }
61
-
62
- /**
63
- * Extract typography info
64
- */
65
- function extractTypography(content) {
66
- const typography = {
67
- heading: null,
68
- body: null,
69
- mono: null,
70
- };
71
-
72
- // Look for font definitions
73
- const headingMatch = content.match(/--font-heading:\s*['"]([^'"]+)['"]/);
74
- const bodyMatch = content.match(/--font-body:\s*['"]([^'"]+)['"]/);
75
- const monoMatch = content.match(/--font-mono:\s*['"]([^'"]+)['"]/);
76
-
77
- // Fallback: look in tables
78
- const fontStackMatch = content.match(/### Font Stack[\s\S]*?(?=###|##|$)/i);
79
- if (fontStackMatch) {
80
- const stackText = fontStackMatch[0];
81
- const headingAlt = stackText.match(/heading[^']*['"]([^'"]+)['"]/i);
82
- const bodyAlt = stackText.match(/body[^']*['"]([^'"]+)['"]/i);
83
-
84
- if (headingAlt) typography.heading = headingAlt[1];
85
- if (bodyAlt) typography.body = bodyAlt[1];
86
- }
87
-
88
- if (headingMatch) typography.heading = headingMatch[1];
89
- if (bodyMatch) typography.body = bodyMatch[1];
90
- if (monoMatch) typography.mono = monoMatch[1];
91
-
92
- return typography;
93
- }
94
-
95
- /**
96
- * Extract voice/tone information
97
- */
98
- function extractVoice(content) {
99
- const voice = {
100
- traits: [],
101
- prohibited: [],
102
- personality: "",
103
- };
104
-
105
- // Extract personality traits from table
106
- const personalityMatch = content.match(
107
- /### Brand Personality[\s\S]*?\|[\s\S]*?(?=###|##|$)/i
108
- );
109
- if (personalityMatch) {
110
- const traits = personalityMatch[0].match(
111
- /\*\*([^*]+)\*\*\s*\|\s*([^|]+)/g
112
- );
113
- if (traits) {
114
- voice.traits = traits.map((t) => {
115
- const match = t.match(/\*\*([^*]+)\*\*/);
116
- return match ? match[1].trim() : "";
117
- }).filter(Boolean);
118
- }
119
- }
120
-
121
- // Extract prohibited terms
122
- const prohibitedMatch = content.match(
123
- /### Prohibited[\s\S]*?(?=###|##|$)/i
124
- );
125
- if (prohibitedMatch) {
126
- const terms = prohibitedMatch[0].match(/\|\s*([^|]+)\s*\|/g);
127
- if (terms) {
128
- voice.prohibited = terms
129
- .map((t) => t.replace(/\|/g, "").trim())
130
- .filter((t) => t && !t.includes("Avoid") && !t.includes("---"));
131
- }
132
- }
133
-
134
- // Fallback: look for Forbidden Phrases
135
- const forbiddenMatch = content.match(
136
- /### Forbidden Phrases[\s\S]*?(?=###|##|$)/i
137
- );
138
- if (forbiddenMatch && voice.prohibited.length === 0) {
139
- const items = forbiddenMatch[0].match(/-\s*["']?([^"'\n(]+)/g);
140
- if (items) {
141
- voice.prohibited = items
142
- .map((item) => item.replace(/^-\s*["']?/, "").trim())
143
- .filter(Boolean);
144
- }
145
- }
146
-
147
- voice.personality = voice.traits.join(", ");
148
-
149
- return voice;
150
- }
151
-
152
- /**
153
- * Extract core attributes
154
- */
155
- function extractCoreAttributes(content) {
156
- const attributes = [];
157
-
158
- const attributesMatch = content.match(
159
- /### Core Attributes[\s\S]*?\|[\s\S]*?(?=###|##|$)/i
160
- );
161
- if (attributesMatch) {
162
- const rows = attributesMatch[0].match(
163
- /\|\s*\*\*([^*]+)\*\*\s*\|\s*([^|]+)\|/g
164
- );
165
- if (rows) {
166
- rows.forEach((row) => {
167
- const match = row.match(/\*\*([^*]+)\*\*\s*\|\s*([^|]+)/);
168
- if (match) {
169
- attributes.push({
170
- name: match[1].trim(),
171
- description: match[2].trim(),
172
- });
173
- }
174
- });
175
- }
176
- }
177
-
178
- return attributes;
179
- }
180
-
181
- /**
182
- * Extract AI image generation context
183
- */
184
- function extractImageStyle(content) {
185
- const imageStyle = {
186
- basePrompt: "",
187
- keywords: [],
188
- mood: [],
189
- donts: [],
190
- examplePrompts: [],
191
- };
192
-
193
- // Extract base prompt template (content between ``` blocks after "Base Prompt Template")
194
- const basePromptMatch = content.match(
195
- /### Base Prompt Template[\s\S]*?```\n?([\s\S]*?)```/i
196
- );
197
- if (basePromptMatch) {
198
- imageStyle.basePrompt = basePromptMatch[1].trim().replace(/\n/g, " ");
199
- }
200
-
201
- // Extract style keywords from table
202
- const keywordsMatch = content.match(
203
- /### Style Keywords[\s\S]*?\|[\s\S]*?(?=###|##|$)/i
204
- );
205
- if (keywordsMatch) {
206
- const keywordRows = keywordsMatch[0].match(/\|\s*\*\*[^*]+\*\*\s*\|\s*([^|]+)\|/g);
207
- if (keywordRows) {
208
- keywordRows.forEach((row) => {
209
- const match = row.match(/\|\s*\*\*[^*]+\*\*\s*\|\s*([^|]+)\|/);
210
- if (match) {
211
- const keywords = match[1].split(",").map((k) => k.trim()).filter(Boolean);
212
- imageStyle.keywords.push(...keywords);
213
- }
214
- });
215
- }
216
- }
217
-
218
- // Extract visual mood descriptors (bullet points)
219
- const moodMatch = content.match(
220
- /### Visual Mood Descriptors[\s\S]*?(?=###|##|$)/i
221
- );
222
- if (moodMatch) {
223
- const moodItems = moodMatch[0].match(/-\s*([^\n]+)/g);
224
- if (moodItems) {
225
- imageStyle.mood = moodItems.map((item) => item.replace(/^-\s*/, "").trim());
226
- }
227
- }
228
-
229
- // Extract visual don'ts from table
230
- const dontsMatch = content.match(
231
- /### Visual Don'ts[\s\S]*?\|[\s\S]*?(?=###|##|$)/i
232
- );
233
- if (dontsMatch) {
234
- const dontRows = dontsMatch[0].match(/\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|/g);
235
- if (dontRows) {
236
- dontRows.forEach((row) => {
237
- const match = row.match(/\|\s*([^|]+)\s*\|\s*([^|]+)\s*\|/);
238
- if (match && !match[1].includes("Avoid") && !match[1].includes("---")) {
239
- imageStyle.donts.push(match[1].trim());
240
- }
241
- });
242
- }
243
- }
244
-
245
- // Extract example prompts (content between ``` blocks after specific headers)
246
- const exampleMatch = content.match(/### Example Prompts[\s\S]*?(?=##|$)/i);
247
- if (exampleMatch) {
248
- const prompts = exampleMatch[0].match(/\*\*([^*]+)\*\*:\s*```\n?([\s\S]*?)```/g);
249
- if (prompts) {
250
- prompts.forEach((p) => {
251
- const match = p.match(/\*\*([^*]+)\*\*:\s*```\n?([\s\S]*?)```/);
252
- if (match) {
253
- imageStyle.examplePrompts.push({
254
- type: match[1].trim(),
255
- prompt: match[2].trim().replace(/\n/g, " "),
256
- });
257
- }
258
- });
259
- }
260
- }
261
-
262
- return imageStyle;
263
- }
264
-
265
- /**
266
- * Generate system prompt addition
267
- */
268
- function generatePromptAddition(brandContext) {
269
- const { colors, typography, voice, attributes, imageStyle } = brandContext;
270
-
271
- let prompt = `
272
- BRAND CONTEXT:
273
- ==============
274
-
275
- VISUAL IDENTITY:
276
- - Primary Colors: ${colors.primary.join(", ") || "Not specified"}
277
- - Secondary Colors: ${colors.secondary.join(", ") || "Not specified"}
278
- - Typography: ${typography.heading || typography.body || "System fonts"}
279
-
280
- BRAND VOICE:
281
- - Personality: ${voice.personality || "Professional"}
282
- - Core Attributes: ${attributes.map((a) => a.name).join(", ") || "Not specified"}
283
-
284
- CONTENT RULES:
285
- - Prohibited Terms: ${voice.prohibited.join(", ") || "None specified"}
286
- `;
287
-
288
- // Add image style context if available
289
- if (imageStyle && imageStyle.basePrompt) {
290
- prompt += `
291
- IMAGE GENERATION:
292
- - Base Prompt: ${imageStyle.basePrompt}
293
- - Style Keywords: ${imageStyle.keywords.slice(0, 10).join(", ") || "Not specified"}
294
- - Visual Mood: ${imageStyle.mood.slice(0, 5).join("; ") || "Not specified"}
295
- - Avoid: ${imageStyle.donts.join(", ") || "None specified"}
296
- `;
297
- }
298
-
299
- prompt += `
300
- Apply these brand guidelines to all generated content.
301
- Maintain consistent voice, colors, and messaging.
302
- `;
303
-
304
- return prompt.trim();
305
- }
306
-
307
- /**
308
- * Main function
309
- */
310
- function main() {
311
- const args = process.argv.slice(2);
312
- const jsonOutput = args.includes("--json");
313
- const guidelinesPath = args.find((a) => !a.startsWith("--")) || DEFAULT_GUIDELINES_PATH;
314
-
315
- // Resolve path
316
- const resolvedPath = path.isAbsolute(guidelinesPath)
317
- ? guidelinesPath
318
- : path.join(process.cwd(), guidelinesPath);
319
-
320
- // Check if file exists
321
- if (!fs.existsSync(resolvedPath)) {
322
- console.error(`Error: Brand guidelines not found at ${resolvedPath}`);
323
- console.error(`Create brand guidelines at ${DEFAULT_GUIDELINES_PATH} or specify a path.`);
324
- process.exit(1);
325
- }
326
-
327
- // Read file
328
- const content = fs.readFileSync(resolvedPath, "utf-8");
329
-
330
- // Extract brand context
331
- const brandContext = {
332
- colors: extractColorsFromTable(content),
333
- typography: extractTypography(content),
334
- voice: extractVoice(content),
335
- attributes: extractCoreAttributes(content),
336
- imageStyle: extractImageStyle(content),
337
- source: resolvedPath,
338
- extractedAt: new Date().toISOString(),
339
- };
340
-
341
- // Output
342
- if (jsonOutput) {
343
- console.log(JSON.stringify(brandContext, null, 2));
344
- } else {
345
- console.log(generatePromptAddition(brandContext));
346
- }
347
- }
348
-
349
- main();