@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,484 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- CIP Design Generator - Generate corporate identity mockups using Gemini Nano Banana
5
-
6
- Uses Gemini's native image generation (Nano Banana Flash/Pro) for high-quality mockups.
7
- Supports text-and-image-to-image generation for using actual brand logos.
8
-
9
- - gemini-2.5-flash-image: Fast generation, cost-effective (default)
10
- - gemini-3-pro-image-preview: Pro quality, 4K text rendering
11
-
12
- Image Editing (text-and-image-to-image):
13
- When --logo is provided, the script uses Gemini's image editing capability
14
- to incorporate the actual logo into CIP mockups instead of generating one.
15
- """
16
-
17
- import argparse
18
- import json
19
- import os
20
- import sys
21
- from pathlib import Path
22
- from datetime import datetime
23
-
24
- # Add parent directory for imports
25
- sys.path.insert(0, str(Path(__file__).parent))
26
- from core import search, get_cip_brief
27
-
28
- # Model options
29
- MODELS = {
30
- "flash": "gemini-2.5-flash-image", # Nano Banana Flash - fast, default
31
- "pro": "gemini-3-pro-image-preview" # Nano Banana Pro - quality, 4K text
32
- }
33
- DEFAULT_MODEL = "flash"
34
-
35
-
36
- def load_logo_image(logo_path):
37
- """Load logo image using PIL for Gemini image editing"""
38
- try:
39
- from PIL import Image
40
- except ImportError:
41
- print("Error: pillow package not installed.")
42
- print("Install with: pip install pillow")
43
- return None
44
-
45
- logo_path = Path(logo_path)
46
- if not logo_path.exists():
47
- print(f"Error: Logo file not found: {logo_path}")
48
- return None
49
-
50
- try:
51
- img = Image.open(logo_path)
52
- # Convert to RGB if necessary (Gemini works best with RGB)
53
- if img.mode in ('RGBA', 'P'):
54
- # Create white background for transparent images
55
- background = Image.new('RGB', img.size, (255, 255, 255))
56
- if img.mode == 'RGBA':
57
- background.paste(img, mask=img.split()[3]) # Use alpha channel as mask
58
- else:
59
- background.paste(img)
60
- img = background
61
- elif img.mode != 'RGB':
62
- img = img.convert('RGB')
63
- return img
64
- except Exception as e:
65
- print(f"Error loading logo: {e}")
66
- return None
67
-
68
- # Load environment variables
69
- def load_env():
70
- """Load environment variables from .env files"""
71
- env_paths = [
72
- Path(__file__).parent.parent.parent / ".env",
73
- Path.home() / ".claude" / "skills" / ".env",
74
- Path.home() / ".claude" / ".env"
75
- ]
76
- for env_path in env_paths:
77
- if env_path.exists():
78
- with open(env_path) as f:
79
- for line in f:
80
- line = line.strip()
81
- if line and not line.startswith("#") and "=" in line:
82
- key, value = line.split("=", 1)
83
- if key not in os.environ:
84
- os.environ[key] = value.strip('"\'')
85
-
86
- load_env()
87
-
88
-
89
- def build_cip_prompt(deliverable, brand_name, style=None, industry=None, mockup=None, use_logo_image=False):
90
- """Build an optimized prompt for CIP mockup generation
91
-
92
- Args:
93
- deliverable: Type of deliverable (business card, letterhead, etc.)
94
- brand_name: Name of the brand
95
- style: Design style preference
96
- industry: Industry for style recommendations
97
- mockup: Mockup context override
98
- use_logo_image: If True, prompt is optimized for image editing with logo
99
- """
100
-
101
- # Get deliverable details
102
- deliverable_info = search(deliverable, "deliverable", 1)
103
- deliverable_data = deliverable_info.get("results", [{}])[0] if deliverable_info.get("results") else {}
104
-
105
- # Get style details
106
- style_info = search(style or "corporate minimal", "style", 1) if style else {}
107
- style_data = style_info.get("results", [{}])[0] if style_info.get("results") else {}
108
-
109
- # Get industry details
110
- industry_info = search(industry or "technology", "industry", 1) if industry else {}
111
- industry_data = industry_info.get("results", [{}])[0] if industry_info.get("results") else {}
112
-
113
- # Get mockup context
114
- mockup_context = deliverable_data.get("Mockup Context", "clean professional")
115
- if mockup:
116
- mockup_info = search(mockup, "mockup", 1)
117
- if mockup_info.get("results"):
118
- mockup_data = mockup_info["results"][0]
119
- mockup_context = mockup_data.get("Scene Description", mockup_context)
120
-
121
- # Build prompt components
122
- deliverable_name = deliverable_data.get("Deliverable", deliverable)
123
- description = deliverable_data.get("Description", "")
124
- dimensions = deliverable_data.get("Dimensions", "")
125
- logo_placement = deliverable_data.get("Logo Placement", "center")
126
-
127
- style_name = style_data.get("Style Name", style or "corporate")
128
- primary_colors = style_data.get("Primary Colors", industry_data.get("Primary Colors", "#0F172A #FFFFFF"))
129
- typography = style_data.get("Typography", industry_data.get("Typography", "clean sans-serif"))
130
- materials = style_data.get("Materials", "premium quality")
131
- finishes = style_data.get("Finishes", "professional")
132
-
133
- mood = style_data.get("Mood", industry_data.get("Mood", "professional"))
134
-
135
- # Construct the prompt - different for image editing vs pure generation
136
- if use_logo_image:
137
- # Image editing prompt: instructs to USE the provided logo image
138
- prompt_parts = [
139
- f"Create a professional corporate identity mockup photograph of a {deliverable_name}",
140
- f"Use the EXACT logo from the provided image - do NOT modify or recreate the logo",
141
- f"The logo MUST appear exactly as shown in the input image",
142
- f"Place the logo on the {deliverable_name} at: {logo_placement}",
143
- f"Brand name: '{brand_name}'",
144
- f"{description}" if description else "",
145
- f"Design style: {style_name}",
146
- f"Color scheme matching the logo colors",
147
- f"Materials: {materials} with {finishes} finish",
148
- f"Setting: {mockup_context}",
149
- f"Mood: {mood}",
150
- "Photorealistic product photography",
151
- "Soft natural lighting, professional studio quality",
152
- "8K resolution, sharp details"
153
- ]
154
- else:
155
- # Pure text-to-image prompt
156
- prompt_parts = [
157
- f"Professional corporate identity mockup photograph",
158
- f"showing {deliverable_name} for brand '{brand_name}'",
159
- f"{description}" if description else "",
160
- f"{style_name} design style",
161
- f"using colors {primary_colors}",
162
- f"{typography} typography",
163
- f"logo placement: {logo_placement}",
164
- f"{materials} materials with {finishes} finish",
165
- f"{mockup_context} setting",
166
- f"{mood} mood",
167
- "photorealistic product photography",
168
- "soft natural lighting",
169
- "high quality professional shot",
170
- "8k resolution detailed"
171
- ]
172
-
173
- prompt = ", ".join([p for p in prompt_parts if p])
174
-
175
- return {
176
- "prompt": prompt,
177
- "deliverable": deliverable_name,
178
- "style": style_name,
179
- "brand": brand_name,
180
- "colors": primary_colors,
181
- "mockup_context": mockup_context,
182
- "logo_placement": logo_placement
183
- }
184
-
185
-
186
- def generate_with_nano_banana(prompt_data, output_dir=None, model_key="flash", aspect_ratio="1:1", logo_image=None):
187
- """Generate image using Gemini Nano Banana (native image generation)
188
-
189
- Supports two modes:
190
- 1. Text-to-image: Pure prompt-based generation (logo_image=None)
191
- 2. Image editing: Text-and-image-to-image using provided logo (logo_image=PIL.Image)
192
-
193
- Models:
194
- - flash: gemini-2.5-flash-image (fast, cost-effective) - DEFAULT
195
- - pro: gemini-3-pro-image-preview (quality, 4K text rendering)
196
-
197
- Args:
198
- prompt_data: Dict with prompt, deliverable, brand, etc.
199
- output_dir: Output directory for generated images
200
- model_key: 'flash' or 'pro'
201
- aspect_ratio: Output aspect ratio (1:1, 16:9, etc.)
202
- logo_image: PIL.Image object of the brand logo for image editing mode
203
- """
204
- try:
205
- from google import genai
206
- from google.genai import types
207
- except ImportError:
208
- print("Error: google-genai package not installed.")
209
- print("Install with: pip install google-genai")
210
- return None
211
-
212
- api_key = os.environ.get("GEMINI_API_KEY") or os.environ.get("GOOGLE_API_KEY")
213
- if not api_key:
214
- print("Error: GEMINI_API_KEY or GOOGLE_API_KEY not set")
215
- return None
216
-
217
- client = genai.Client(api_key=api_key)
218
-
219
- prompt = prompt_data["prompt"]
220
- model_name = MODELS.get(model_key, MODELS[DEFAULT_MODEL])
221
-
222
- # Determine mode
223
- mode = "image-editing" if logo_image else "text-to-image"
224
-
225
- print(f"\n🎨 Generating CIP mockup...")
226
- print(f" Mode: {mode}")
227
- print(f" Deliverable: {prompt_data['deliverable']}")
228
- print(f" Brand: {prompt_data['brand']}")
229
- print(f" Style: {prompt_data['style']}")
230
- print(f" Model: {model_name}")
231
- print(f" Context: {prompt_data['mockup_context']}")
232
- if logo_image:
233
- print(f" Logo: Using provided image ({logo_image.size[0]}x{logo_image.size[1]})")
234
-
235
- try:
236
- # Build contents: either just prompt or [prompt, image] for image editing
237
- if logo_image:
238
- # Image editing mode: pass both prompt and logo image
239
- contents = [prompt, logo_image]
240
- else:
241
- # Text-to-image mode: just the prompt
242
- contents = prompt
243
-
244
- # Use generate_content with response_modalities=['IMAGE'] for Nano Banana
245
- response = client.models.generate_content(
246
- model=model_name,
247
- contents=contents,
248
- config=types.GenerateContentConfig(
249
- response_modalities=['IMAGE'], # Uppercase required
250
- image_config=types.ImageConfig(
251
- aspect_ratio=aspect_ratio
252
- )
253
- )
254
- )
255
-
256
- # Extract image from response
257
- if response.candidates and response.candidates[0].content.parts:
258
- for part in response.candidates[0].content.parts:
259
- if hasattr(part, 'inline_data') and part.inline_data:
260
- # Save image
261
- output_dir = output_dir or Path.cwd()
262
- output_dir = Path(output_dir)
263
- output_dir.mkdir(parents=True, exist_ok=True)
264
-
265
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
266
- brand_slug = prompt_data["brand"].lower().replace(" ", "-")
267
- deliverable_slug = prompt_data["deliverable"].lower().replace(" ", "-")
268
- filename = f"{brand_slug}-{deliverable_slug}-{timestamp}.png"
269
- filepath = output_dir / filename
270
-
271
- image_data = part.inline_data.data
272
- with open(filepath, "wb") as f:
273
- f.write(image_data)
274
-
275
- print(f"\n✅ Generated: {filepath}")
276
- return str(filepath)
277
-
278
- print("No image generated in response")
279
- return None
280
-
281
- except Exception as e:
282
- print(f"Error generating image: {e}")
283
- return None
284
-
285
-
286
- def generate_cip_set(brand_name, industry, style=None, deliverables=None, output_dir=None, model_key="flash", logo_path=None, aspect_ratio="1:1"):
287
- """Generate a complete CIP set for a brand
288
-
289
- Args:
290
- brand_name: Brand name to generate for
291
- industry: Industry type for style recommendations
292
- style: Optional specific style override
293
- deliverables: List of deliverables to generate (default: core set)
294
- output_dir: Output directory for images
295
- model_key: 'flash' (fast) or 'pro' (quality)
296
- logo_path: Path to brand logo image for image editing mode
297
- aspect_ratio: Output aspect ratio
298
- """
299
-
300
- # Load logo image if provided
301
- logo_image = None
302
- if logo_path:
303
- logo_image = load_logo_image(logo_path)
304
- if not logo_image:
305
- print("Warning: Could not load logo, falling back to text-to-image mode")
306
-
307
- # Get CIP brief for the brand
308
- brief = get_cip_brief(brand_name, industry, style)
309
-
310
- # Default deliverables if not specified
311
- if not deliverables:
312
- deliverables = ["business card", "letterhead", "office signage", "vehicle", "polo shirt"]
313
-
314
- results = []
315
- for deliverable in deliverables:
316
- prompt_data = build_cip_prompt(
317
- deliverable=deliverable,
318
- brand_name=brand_name,
319
- style=brief.get("style", {}).get("Style Name"),
320
- industry=industry,
321
- use_logo_image=(logo_image is not None)
322
- )
323
-
324
- filepath = generate_with_nano_banana(
325
- prompt_data,
326
- output_dir,
327
- model_key=model_key,
328
- aspect_ratio=aspect_ratio,
329
- logo_image=logo_image
330
- )
331
- if filepath:
332
- results.append({
333
- "deliverable": deliverable,
334
- "filepath": filepath,
335
- "prompt": prompt_data["prompt"]
336
- })
337
-
338
- return results
339
-
340
-
341
- def check_logo_required(brand_name, skip_prompt=False):
342
- """Check if logo is required and suggest logo-design skill if not provided
343
-
344
- Returns:
345
- str: 'continue' to proceed without logo, 'generate' to use logo-design skill, 'exit' to abort
346
- """
347
- if skip_prompt:
348
- return 'continue'
349
-
350
- print(f"\n⚠️ No logo image provided for '{brand_name}'")
351
- print(" Without a logo, AI will generate its own interpretation of the brand logo.")
352
- print("")
353
- print(" Options:")
354
- print(" 1. Continue without logo (AI-generated logo interpretation)")
355
- print(" 2. Generate a logo first using 'logo-design' skill")
356
- print(" 3. Exit and provide a logo path with --logo")
357
- print("")
358
-
359
- try:
360
- choice = input(" Enter choice [1/2/3] (default: 1): ").strip()
361
- if choice == '2':
362
- return 'generate'
363
- elif choice == '3':
364
- return 'exit'
365
- return 'continue'
366
- except (EOFError, KeyboardInterrupt):
367
- return 'continue'
368
-
369
-
370
- def main():
371
- parser = argparse.ArgumentParser(
372
- description="Generate CIP mockups using Gemini Nano Banana",
373
- formatter_class=argparse.RawDescriptionHelpFormatter,
374
- epilog="""
375
- Examples:
376
- # Generate with brand logo (RECOMMENDED)
377
- python generate.py --brand "TopGroup" --logo /path/to/logo.png --deliverable "business card"
378
-
379
- # Generate CIP set with logo
380
- python generate.py --brand "TopGroup" --logo /path/to/logo.png --industry "consulting" --set
381
-
382
- # Generate without logo (AI interprets brand)
383
- python generate.py --brand "TechFlow" --deliverable "business card" --no-logo-prompt
384
-
385
- # Generate with Pro model (higher quality, 4K text)
386
- python generate.py --brand "TechFlow" --logo logo.png --deliverable "business card" --model pro
387
-
388
- # Specify output directory and aspect ratio
389
- python generate.py --brand "MyBrand" --logo logo.png --deliverable "vehicle" --output ./mockups --ratio 16:9
390
-
391
- Models:
392
- flash (default): gemini-2.5-flash-image - Fast, cost-effective
393
- pro: gemini-3-pro-image-preview - Quality, 4K text rendering
394
-
395
- Image Editing Mode:
396
- When --logo is provided, uses Gemini's text-and-image-to-image capability
397
- to incorporate your ACTUAL logo into the CIP mockups.
398
- """
399
- )
400
-
401
- parser.add_argument("--brand", "-b", required=True, help="Brand name")
402
- parser.add_argument("--logo", "-l", help="Path to brand logo image (enables image editing mode)")
403
- parser.add_argument("--deliverable", "-d", help="Single deliverable to generate")
404
- parser.add_argument("--deliverables", help="Comma-separated list of deliverables")
405
- parser.add_argument("--industry", "-i", default="technology", help="Industry type")
406
- parser.add_argument("--style", "-s", help="Design style")
407
- parser.add_argument("--mockup", "-m", help="Mockup context")
408
- parser.add_argument("--set", action="store_true", help="Generate full CIP set")
409
- parser.add_argument("--output", "-o", help="Output directory")
410
- parser.add_argument("--model", default="flash", choices=["flash", "pro"], help="Model: flash (fast) or pro (quality)")
411
- parser.add_argument("--ratio", default="1:1", help="Aspect ratio (1:1, 16:9, 4:3, etc.)")
412
- parser.add_argument("--prompt-only", action="store_true", help="Only show prompt, don't generate")
413
- parser.add_argument("--json", "-j", action="store_true", help="Output as JSON")
414
- parser.add_argument("--no-logo-prompt", action="store_true", help="Skip logo prompt, proceed without logo")
415
-
416
- args = parser.parse_args()
417
-
418
- # Check if logo is provided, prompt user if not
419
- logo_image = None
420
- if args.logo:
421
- logo_image = load_logo_image(args.logo)
422
- if not logo_image:
423
- print("Error: Could not load logo image")
424
- sys.exit(1)
425
- elif not args.prompt_only:
426
- # No logo provided - ask user what to do
427
- action = check_logo_required(args.brand, skip_prompt=args.no_logo_prompt)
428
- if action == 'generate':
429
- print("\n💡 To generate a logo, use the logo-design skill:")
430
- print(f" python ~/.claude/skills/design/scripts/logo/generate.py --brand \"{args.brand}\" --industry \"{args.industry}\"")
431
- print("\n Then re-run this command with --logo <generated_logo.png>")
432
- sys.exit(0)
433
- elif action == 'exit':
434
- print("\n Provide logo with: --logo /path/to/your/logo.png")
435
- sys.exit(0)
436
- # else: continue without logo
437
-
438
- use_logo = logo_image is not None
439
-
440
- if args.set or args.deliverables:
441
- # Generate multiple deliverables
442
- deliverables = args.deliverables.split(",") if args.deliverables else None
443
-
444
- if args.prompt_only:
445
- results = []
446
- deliverables = deliverables or ["business card", "letterhead", "office signage", "vehicle", "polo shirt"]
447
- for d in deliverables:
448
- prompt_data = build_cip_prompt(d, args.brand, args.style, args.industry, args.mockup, use_logo_image=use_logo)
449
- results.append(prompt_data)
450
- if args.json:
451
- print(json.dumps(results, indent=2))
452
- else:
453
- for r in results:
454
- print(f"\n{r['deliverable']}:\n{r['prompt']}\n")
455
- else:
456
- results = generate_cip_set(
457
- args.brand, args.industry, args.style, deliverables, args.output,
458
- model_key=args.model, logo_path=args.logo, aspect_ratio=args.ratio
459
- )
460
- if args.json:
461
- print(json.dumps(results, indent=2))
462
- else:
463
- print(f"\n✅ Generated {len(results)} CIP mockups")
464
- else:
465
- # Generate single deliverable
466
- deliverable = args.deliverable or "business card"
467
- prompt_data = build_cip_prompt(deliverable, args.brand, args.style, args.industry, args.mockup, use_logo_image=use_logo)
468
-
469
- if args.prompt_only:
470
- if args.json:
471
- print(json.dumps(prompt_data, indent=2))
472
- else:
473
- print(f"\nPrompt:\n{prompt_data['prompt']}")
474
- else:
475
- filepath = generate_with_nano_banana(
476
- prompt_data, args.output, model_key=args.model,
477
- aspect_ratio=args.ratio, logo_image=logo_image
478
- )
479
- if args.json:
480
- print(json.dumps({"filepath": filepath, **prompt_data}, indent=2))
481
-
482
-
483
- if __name__ == "__main__":
484
- main()