@omega.js/manager 0.1.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 (416) hide show
  1. package/.claude-plugin/marketplace.json +14 -0
  2. package/LICENSE +98 -0
  3. package/README.md +165 -0
  4. package/bin/omega +2 -0
  5. package/bin/omg +2 -0
  6. package/claude-plugin/.claude-plugin/plugin.json +11 -0
  7. package/claude-plugin/.mcp.json +9 -0
  8. package/claude-plugin/README.md +139 -0
  9. package/claude-plugin/hooks/gate/mark.sh +58 -0
  10. package/claude-plugin/hooks/gate/run.sh +97 -0
  11. package/claude-plugin/hooks/guard/run.sh +249 -0
  12. package/claude-plugin/hooks/hooks.json +63 -0
  13. package/claude-plugin/hooks/inject/run.sh +127 -0
  14. package/claude-plugin/hooks/lib/omega-gate.sh +20 -0
  15. package/claude-plugin/hooks/lib/omega-scope.sh +41 -0
  16. package/claude-plugin/hooks/lib/omega-skills.sh +209 -0
  17. package/claude-plugin/hooks/quality/run.sh +132 -0
  18. package/claude-plugin/hooks/shape/run.sh +45 -0
  19. package/claude-plugin/mcp-router-launch.js +29 -0
  20. package/claude-plugin/skills/README.md +48 -0
  21. package/claude-plugin/skills/accessibility/SKILL.md +31 -0
  22. package/claude-plugin/skills/analytics/SKILL.md +30 -0
  23. package/claude-plugin/skills/backend/SKILL.md +25 -0
  24. package/claude-plugin/skills/brandcheck/SKILL.md +29 -0
  25. package/claude-plugin/skills/browser/SKILL.md +64 -0
  26. package/claude-plugin/skills/client/SKILL.md +24 -0
  27. package/claude-plugin/skills/desktop/SKILL.md +25 -0
  28. package/claude-plugin/skills/extension/SKILL.md +25 -0
  29. package/claude-plugin/skills/main/SKILL.md +54 -0
  30. package/claude-plugin/skills/manager/SKILL.md +25 -0
  31. package/claude-plugin/skills/seo/SKILL.md +36 -0
  32. package/claude-plugin/skills/theme/SKILL.md +33 -0
  33. package/claude-plugin/skills/web/SKILL.md +29 -0
  34. package/dist/cli-run.js +34 -0
  35. package/dist/cli.js +29 -0
  36. package/dist/commands/build.js +17 -0
  37. package/dist/commands/clean.js +16 -0
  38. package/dist/commands/company.js +46 -0
  39. package/dist/commands/deploy.js +143 -0
  40. package/dist/commands/dev.js +437 -0
  41. package/dist/commands/devlog.js +25 -0
  42. package/dist/commands/help.js +48 -0
  43. package/dist/commands/manage.js +53 -0
  44. package/dist/commands/migrate.js +76 -0
  45. package/dist/commands/onboard.js +31 -0
  46. package/dist/commands/pipeline.js +319 -0
  47. package/dist/commands/test.js +380 -0
  48. package/dist/commands/update.js +128 -0
  49. package/dist/commands/version.js +8 -0
  50. package/dist/company-init.js +167 -0
  51. package/dist/company.js +283 -0
  52. package/dist/config.js +1359 -0
  53. package/dist/devlog/index.js +226 -0
  54. package/dist/devlog/lib/collect-commits.js +136 -0
  55. package/dist/devlog/lib/generate-post.js +201 -0
  56. package/dist/devlog/lib/ghostii.js +122 -0
  57. package/dist/devlog/lib/project-map.js +98 -0
  58. package/dist/devlog/lib/publish-website.js +88 -0
  59. package/dist/index.js +45 -0
  60. package/dist/lib/agents-md.js +201 -0
  61. package/dist/lib/analytics-secret.js +22 -0
  62. package/dist/lib/argv.js +21 -0
  63. package/dist/lib/auth-admin.js +120 -0
  64. package/dist/lib/automation-client.js +210 -0
  65. package/dist/lib/backend-marketing.js +49 -0
  66. package/dist/lib/brand.js +240 -0
  67. package/dist/lib/bundle-id.js +53 -0
  68. package/dist/lib/claude-settings.js +125 -0
  69. package/dist/lib/company-scaffold.js +213 -0
  70. package/dist/lib/company.js +227 -0
  71. package/dist/lib/config-flow.js +350 -0
  72. package/dist/lib/config-write.js +41 -0
  73. package/dist/lib/custom-target.js +75 -0
  74. package/dist/lib/domain-utils.js +19 -0
  75. package/dist/lib/duration.js +39 -0
  76. package/dist/lib/env-order.js +236 -0
  77. package/dist/lib/env-secret.js +78 -0
  78. package/dist/lib/firestore-rest.js +326 -0
  79. package/dist/lib/framework-bin.js +156 -0
  80. package/dist/lib/gitignore.js +63 -0
  81. package/dist/lib/google-auth.js +495 -0
  82. package/dist/lib/google-token.js +66 -0
  83. package/dist/lib/jwt.js +31 -0
  84. package/dist/lib/legacy-oauth.js +59 -0
  85. package/dist/lib/node-version.js +127 -0
  86. package/dist/lib/owner-plan.js +78 -0
  87. package/dist/lib/package-scripts.js +152 -0
  88. package/dist/lib/preflight.js +470 -0
  89. package/dist/lib/product-create.js +144 -0
  90. package/dist/lib/run-command.js +74 -0
  91. package/dist/lib/run-gates.js +70 -0
  92. package/dist/lib/run-output.js +42 -0
  93. package/dist/lib/run-summary.js +384 -0
  94. package/dist/lib/scaffold.js +427 -0
  95. package/dist/lib/service-input.js +207 -0
  96. package/dist/lib/service-runner.js +466 -0
  97. package/dist/lib/stale.js +24 -0
  98. package/dist/lib/target-selection.js +155 -0
  99. package/dist/lib/verb-fanout.js +128 -0
  100. package/dist/lib/verify-live.js +188 -0
  101. package/dist/manage.js +311 -0
  102. package/dist/omega-bin.js +7 -0
  103. package/dist/onboard.js +532 -0
  104. package/dist/services/account/ensure/users.js +259 -0
  105. package/dist/services/account/index.js +97 -0
  106. package/dist/services/account/lib/backend-client.js +107 -0
  107. package/dist/services/account/lib/password.js +36 -0
  108. package/dist/services/account/lib/resolve-password.js +100 -0
  109. package/dist/services/advertising/ensure/sites.js +101 -0
  110. package/dist/services/advertising/index.js +101 -0
  111. package/dist/services/advertising/lib/adsense-api.js +41 -0
  112. package/dist/services/ai/ensure/keys.js +21 -0
  113. package/dist/services/ai/index.js +36 -0
  114. package/dist/services/analytics/ensure/google-firebase-link.js +230 -0
  115. package/dist/services/analytics/ensure/google-streams.js +256 -0
  116. package/dist/services/analytics/ensure/meta-pixel.js +22 -0
  117. package/dist/services/analytics/ensure/tiktok-pixel.js +22 -0
  118. package/dist/services/analytics/index.js +134 -0
  119. package/dist/services/analytics/lib/analytics-api.js +156 -0
  120. package/dist/services/analytics/lib/meta-api.js +83 -0
  121. package/dist/services/analytics/lib/pixel-account.js +78 -0
  122. package/dist/services/analytics/lib/pixel-provision.js +152 -0
  123. package/dist/services/analytics/lib/pixel-specs.js +57 -0
  124. package/dist/services/analytics/lib/pixel-token.js +88 -0
  125. package/dist/services/analytics/lib/property-flow.js +77 -0
  126. package/dist/services/analytics/lib/tiktok-api.js +157 -0
  127. package/dist/services/analytics/lib/tiktok-auth.js +153 -0
  128. package/dist/services/assets/ensure/logo-gen.js +68 -0
  129. package/dist/services/assets/index.js +109 -0
  130. package/dist/services/assets/lib/assets-config.js +168 -0
  131. package/dist/services/assets/lib/brandmark-api.js +160 -0
  132. package/dist/services/assets/lib/derived.js +113 -0
  133. package/dist/services/assets/lib/font-loader.js +67 -0
  134. package/dist/services/assets/lib/reconcile.js +122 -0
  135. package/dist/services/assets/lib/reset.js +118 -0
  136. package/dist/services/assets/lib/svg-logo-generator.js +154 -0
  137. package/dist/services/assets/lib/svg-to-black.js +32 -0
  138. package/dist/services/assets/write/favicons.js +82 -0
  139. package/dist/services/assets/write/icons.js +64 -0
  140. package/dist/services/assets/write/process.js +96 -0
  141. package/dist/services/assets/write/reconcile.js +30 -0
  142. package/dist/services/assets/write/social-icons.js +108 -0
  143. package/dist/services/assets/write/templates.js +345 -0
  144. package/dist/services/bookmark/ensure/sync.js +255 -0
  145. package/dist/services/bookmark/index.js +17 -0
  146. package/dist/services/campaigns/ensure/contact-person.js +40 -0
  147. package/dist/services/campaigns/ensure/custom-fields.js +84 -0
  148. package/dist/services/campaigns/ensure/domain-auth.js +92 -0
  149. package/dist/services/campaigns/ensure/event-webhook.js +89 -0
  150. package/dist/services/campaigns/ensure/link-branding.js +187 -0
  151. package/dist/services/campaigns/ensure/list.js +50 -0
  152. package/dist/services/campaigns/ensure/segments.js +109 -0
  153. package/dist/services/campaigns/ensure/sender-identity.js +153 -0
  154. package/dist/services/campaigns/ensure/unsubscribe-groups.js +116 -0
  155. package/dist/services/campaigns/index.js +79 -0
  156. package/dist/services/campaigns/lib/dns-sync.js +81 -0
  157. package/dist/services/campaigns/lib/segment-query.js +138 -0
  158. package/dist/services/campaigns/lib/sendgrid-api.js +287 -0
  159. package/dist/services/captcha/ensure/site-key.js +83 -0
  160. package/dist/services/captcha/index.js +78 -0
  161. package/dist/services/captcha/lib/console-url.js +45 -0
  162. package/dist/services/captcha/lib/recaptcha-api.js +36 -0
  163. package/dist/services/certificates/ensure/api-key.js +22 -0
  164. package/dist/services/certificates/ensure/bundle-ids.js +115 -0
  165. package/dist/services/certificates/ensure/certificates.js +187 -0
  166. package/dist/services/certificates/ensure/profiles.js +143 -0
  167. package/dist/services/certificates/index.js +225 -0
  168. package/dist/services/certificates/lib/apple-api.js +183 -0
  169. package/dist/services/certificates/lib/certificate-manager.js +252 -0
  170. package/dist/services/certificates/lib/identifier-manager.js +107 -0
  171. package/dist/services/certificates/lib/keychain.js +135 -0
  172. package/dist/services/certificates/lib/manual-walkthrough.js +165 -0
  173. package/dist/services/certificates/lib/profile-manager.js +115 -0
  174. package/dist/services/chat/data/baseline-knowledge.md +96 -0
  175. package/dist/services/chat/ensure/chat.js +106 -0
  176. package/dist/services/chat/ensure/user.js +45 -0
  177. package/dist/services/chat/index.js +139 -0
  178. package/dist/services/chat/lib/baseline-knowledge.js +137 -0
  179. package/dist/services/cloud/ensure/authentication.js +267 -0
  180. package/dist/services/cloud/ensure/billing.js +120 -0
  181. package/dist/services/cloud/ensure/cloud-messaging.js +105 -0
  182. package/dist/services/cloud/ensure/database.js +60 -0
  183. package/dist/services/cloud/ensure/firestore.js +79 -0
  184. package/dist/services/cloud/ensure/functions.js +49 -0
  185. package/dist/services/cloud/ensure/hosting.js +398 -0
  186. package/dist/services/cloud/ensure/oauth-consent.js +248 -0
  187. package/dist/services/cloud/ensure/project-settings.js +72 -0
  188. package/dist/services/cloud/ensure/sdk-config.js +95 -0
  189. package/dist/services/cloud/ensure/service-account.js +152 -0
  190. package/dist/services/cloud/ensure/services.js +103 -0
  191. package/dist/services/cloud/ensure/storage.js +47 -0
  192. package/dist/services/cloud/index.js +130 -0
  193. package/dist/services/cloud/lib/access-heal.js +130 -0
  194. package/dist/services/cloud/lib/firebase-api.js +662 -0
  195. package/dist/services/cloud/lib/project-flow.js +102 -0
  196. package/dist/services/directory/ensure/entry.js +48 -0
  197. package/dist/services/directory/index.js +64 -0
  198. package/dist/services/directory/lib/blocks.js +104 -0
  199. package/dist/services/disperse/index.js +45 -0
  200. package/dist/services/disperse/write/certs.js +117 -0
  201. package/dist/services/domain/ensure/nameservers.js +179 -0
  202. package/dist/services/domain/index.js +69 -0
  203. package/dist/services/domain/lib/namecheap-api.js +167 -0
  204. package/dist/services/domain/lib/registrars.js +46 -0
  205. package/dist/services/domain/lib/whitelist-walkthrough.js +76 -0
  206. package/dist/services/edge/ensure/cache-rules.js +105 -0
  207. package/dist/services/edge/ensure/dns-records.js +304 -0
  208. package/dist/services/edge/ensure/email-routing.js +292 -0
  209. package/dist/services/edge/ensure/rules-configuration.js +98 -0
  210. package/dist/services/edge/ensure/rules-managed-transforms.js +101 -0
  211. package/dist/services/edge/ensure/rules-redirect.js +107 -0
  212. package/dist/services/edge/ensure/rules-response-headers.js +90 -0
  213. package/dist/services/edge/ensure/rules-security.js +142 -0
  214. package/dist/services/edge/ensure/speed-scheduled-tests.js +98 -0
  215. package/dist/services/edge/ensure/workers.js +219 -0
  216. package/dist/services/edge/ensure/zone-settings.js +108 -0
  217. package/dist/services/edge/ensure/zone.js +183 -0
  218. package/dist/services/edge/index.js +73 -0
  219. package/dist/services/edge/lib/cloudflare-api.js +84 -0
  220. package/dist/services/edge/lib/dns-records-helpers.js +518 -0
  221. package/dist/services/edge/lib/read-cache.js +16 -0
  222. package/dist/services/edge/lib/ruleset-helper.js +108 -0
  223. package/dist/services/edge/workers/omega-api-proxy.js +43 -0
  224. package/dist/services/email/data/baseline-filter.md +4 -0
  225. package/dist/services/email/data/baseline-knowledge.md +86 -0
  226. package/dist/services/email/ensure/agent.js +107 -0
  227. package/dist/services/email/ensure/user.js +45 -0
  228. package/dist/services/email/index.js +138 -0
  229. package/dist/services/email/lib/baseline.js +82 -0
  230. package/dist/services/email/lib/knowledge-file.js +53 -0
  231. package/dist/services/forms/ensure/form.js +46 -0
  232. package/dist/services/forms/ensure/user.js +45 -0
  233. package/dist/services/forms/index.js +138 -0
  234. package/dist/services/migrations/ensure/notifications.js +189 -0
  235. package/dist/services/migrations/ensure/orders.js +34 -0
  236. package/dist/services/migrations/ensure/payment-provider.js +132 -0
  237. package/dist/services/migrations/ensure/payments-intents.js +34 -0
  238. package/dist/services/migrations/ensure/state-retirement.js +266 -0
  239. package/dist/services/migrations/ensure/targets-rename.js +124 -0
  240. package/dist/services/migrations/ensure/users.js +1176 -0
  241. package/dist/services/migrations/index.js +101 -0
  242. package/dist/services/migrations/lib/attribution-touch.js +64 -0
  243. package/dist/services/migrations/lib/ensure-metadata.js +144 -0
  244. package/dist/services/migrations/lib/migration-runner.js +473 -0
  245. package/dist/services/migrations/lib/sanitize-strings.js +112 -0
  246. package/dist/services/migrations/lib/schema-validator.js +154 -0
  247. package/dist/services/monitoring/ensure/dsn.js +54 -0
  248. package/dist/services/monitoring/ensure/projects.js +135 -0
  249. package/dist/services/monitoring/index.js +54 -0
  250. package/dist/services/monitoring/lib/sentry-api.js +94 -0
  251. package/dist/services/newsletter/ensure/custom-fields.js +90 -0
  252. package/dist/services/newsletter/ensure/publication.js +94 -0
  253. package/dist/services/newsletter/ensure/segments.js +140 -0
  254. package/dist/services/newsletter/ensure/webhook.js +108 -0
  255. package/dist/services/newsletter/index.js +64 -0
  256. package/dist/services/newsletter/lib/beehiiv-api.js +124 -0
  257. package/dist/services/newsletter/lib/segment-automation.js +577 -0
  258. package/dist/services/payment/ensure/chargebee-account.js +30 -0
  259. package/dist/services/payment/ensure/chargebee-products.js +359 -0
  260. package/dist/services/payment/ensure/chargebee-webhook.js +113 -0
  261. package/dist/services/payment/ensure/paypal-account.js +36 -0
  262. package/dist/services/payment/ensure/paypal-products.js +374 -0
  263. package/dist/services/payment/ensure/paypal-webhook.js +128 -0
  264. package/dist/services/payment/ensure/stripe-account.js +93 -0
  265. package/dist/services/payment/ensure/stripe-disputes.js +56 -0
  266. package/dist/services/payment/ensure/stripe-products.js +245 -0
  267. package/dist/services/payment/ensure/stripe-radar.js +74 -0
  268. package/dist/services/payment/ensure/stripe-webhook.js +130 -0
  269. package/dist/services/payment/index.js +163 -0
  270. package/dist/services/payment/lib/chargebee-api.js +338 -0
  271. package/dist/services/payment/lib/payment-utils.js +116 -0
  272. package/dist/services/payment/lib/paypal-api.js +354 -0
  273. package/dist/services/payment/lib/provider-setup.js +134 -0
  274. package/dist/services/payment/lib/stripe-api.js +152 -0
  275. package/dist/services/repo/ensure/org.js +70 -0
  276. package/dist/services/repo/ensure/pages.js +72 -0
  277. package/dist/services/repo/ensure/repo.js +90 -0
  278. package/dist/services/repo/index.js +52 -0
  279. package/dist/services/repo/lib/github-api.js +196 -0
  280. package/dist/services/search/ensure/ga-link.js +57 -0
  281. package/dist/services/search/ensure/property.js +137 -0
  282. package/dist/services/search/ensure/sitemaps.js +70 -0
  283. package/dist/services/search/index.js +61 -0
  284. package/dist/services/search/lib/search-console-api.js +92 -0
  285. package/dist/services/seo/ensure/github-repos.js +271 -0
  286. package/dist/services/seo/index.js +55 -0
  287. package/dist/services/seo/lib/gh-api.js +161 -0
  288. package/dist/services/seo/templates/developer-tool/.github/workflows/maintenance.yml +25 -0
  289. package/dist/services/seo/templates/developer-tool/.nvmrc +1 -0
  290. package/dist/services/seo/templates/developer-tool/_README.md.js +121 -0
  291. package/dist/services/seo/templates/developer-tool/_package.json.js +33 -0
  292. package/dist/services/seo/templates/developer-tool/src/index.js +120 -0
  293. package/dist/services/seo/templates/index.js +57 -0
  294. package/dist/services/server/ensure/brands.js +63 -0
  295. package/dist/services/server/index.js +42 -0
  296. package/dist/services/testing/ensure/target-checks.js +97 -0
  297. package/dist/services/testing/index.js +11 -0
  298. package/dist/services/testing/lib/checks.js +467 -0
  299. package/dist/services/update/index.js +20 -0
  300. package/dist/services/update/lib/cache.js +59 -0
  301. package/dist/services/update/lib/fingerprint.js +157 -0
  302. package/dist/services/update/write/targets.js +206 -0
  303. package/dist/services/workspace/ensure/agents.js +42 -0
  304. package/dist/services/workspace/ensure/claude-settings.js +34 -0
  305. package/dist/services/workspace/ensure/config.js +54 -0
  306. package/dist/services/workspace/ensure/defaults.js +60 -0
  307. package/dist/services/workspace/ensure/env-keys.js +55 -0
  308. package/dist/services/workspace/ensure/env-order.js +66 -0
  309. package/dist/services/workspace/ensure/env-rules.js +97 -0
  310. package/dist/services/workspace/ensure/gitignore.js +18 -0
  311. package/dist/services/workspace/ensure/scripts.js +126 -0
  312. package/dist/services/workspace/ensure/structure.js +97 -0
  313. package/dist/services/workspace/ensure/translation-sdk.js +148 -0
  314. package/dist/services/workspace/ensure/workflows.js +54 -0
  315. package/dist/services/workspace/index.js +8 -0
  316. package/dist/vendor/account/engine.js +182 -0
  317. package/dist/vendor/account/features.js +220 -0
  318. package/dist/vendor/account/index.js +53 -0
  319. package/dist/vendor/account/schema.js +272 -0
  320. package/dist/vendor/account/subscription.js +38 -0
  321. package/dist/vendor/config/company.js +31 -0
  322. package/dist/vendor/config/defaults.js +173 -0
  323. package/dist/vendor/config/demo.js +18 -0
  324. package/dist/vendor/config/desktop-artifacts.js +110 -0
  325. package/dist/vendor/config/edit.js +769 -0
  326. package/dist/vendor/config/env-delivery.js +145 -0
  327. package/dist/vendor/config/env-rules.js +93 -0
  328. package/dist/vendor/config/env-schema.js +1078 -0
  329. package/dist/vendor/config/env.js +445 -0
  330. package/dist/vendor/config/hooks.js +97 -0
  331. package/dist/vendor/config/index.js +237 -0
  332. package/dist/vendor/config/instances.js +208 -0
  333. package/dist/vendor/config/load.js +490 -0
  334. package/dist/vendor/config/merge.js +68 -0
  335. package/dist/vendor/config/order.js +139 -0
  336. package/dist/vendor/config/ports.js +374 -0
  337. package/dist/vendor/config/providers.js +32 -0
  338. package/dist/vendor/config/repo.js +142 -0
  339. package/dist/vendor/config/retired-keys.js +430 -0
  340. package/dist/vendor/config/schema.js +1610 -0
  341. package/dist/vendor/config/secrets.js +50 -0
  342. package/dist/vendor/config/seed.js +34 -0
  343. package/dist/vendor/config/site-global.js +205 -0
  344. package/dist/vendor/config/validate.js +554 -0
  345. package/dist/vendor/config/winback.js +61 -0
  346. package/dist/vendor/devkit/attach-log-file.js +262 -0
  347. package/dist/vendor/devkit/certs.js +199 -0
  348. package/dist/vendor/devkit/ci-workflows.js +520 -0
  349. package/dist/vendor/devkit/cli-router.js +156 -0
  350. package/dist/vendor/devkit/command-path.js +46 -0
  351. package/dist/vendor/devkit/deploy-record.js +180 -0
  352. package/dist/vendor/devkit/flows.js +317 -0
  353. package/dist/vendor/devkit/local-https.js +360 -0
  354. package/dist/vendor/devkit/local.js +1905 -0
  355. package/dist/vendor/devkit/logger.js +128 -0
  356. package/dist/vendor/devkit/omega-bin.js +345 -0
  357. package/dist/vendor/devkit/prompt.js +187 -0
  358. package/dist/vendor/devkit/safe-install.js +18 -0
  359. package/dist/vendor/devkit/stop-signals.js +28 -0
  360. package/dist/vendor/devkit/test/scope.js +162 -0
  361. package/dist/vendor/devkit/translate/cache.js +84 -0
  362. package/dist/vendor/devkit/translate/engine.js +243 -0
  363. package/dist/vendor/devkit/translate/index.js +49 -0
  364. package/dist/vendor/devkit/translate/languages.js +134 -0
  365. package/dist/vendor/devkit/translate/providers.js +188 -0
  366. package/dist/vendor/devkit/update.js +569 -0
  367. package/docs/AGENTS.md +200 -0
  368. package/docs/account.md +45 -0
  369. package/docs/advertising.md +46 -0
  370. package/docs/ai.md +34 -0
  371. package/docs/analytics.md +69 -0
  372. package/docs/assets.md +57 -0
  373. package/docs/bookmark.md +26 -0
  374. package/docs/brand.md +151 -0
  375. package/docs/campaigns.md +96 -0
  376. package/docs/captcha.md +46 -0
  377. package/docs/certificates.md +68 -0
  378. package/docs/chat.md +47 -0
  379. package/docs/cloud.md +110 -0
  380. package/docs/company.md +64 -0
  381. package/docs/directory.md +140 -0
  382. package/docs/disperse.md +46 -0
  383. package/docs/domain.md +56 -0
  384. package/docs/edge.md +234 -0
  385. package/docs/email.md +42 -0
  386. package/docs/forms.md +48 -0
  387. package/docs/index.md +109 -0
  388. package/docs/migration.md +203 -0
  389. package/docs/migrations.md +56 -0
  390. package/docs/monitoring.md +41 -0
  391. package/docs/newsletter.md +48 -0
  392. package/docs/payment.md +83 -0
  393. package/docs/repo.md +48 -0
  394. package/docs/search.md +44 -0
  395. package/docs/seo.md +34 -0
  396. package/docs/server.md +37 -0
  397. package/docs/shared/agent-docs.md +89 -0
  398. package/docs/shared/analytics.md +612 -0
  399. package/docs/shared/brands.md +51 -0
  400. package/docs/shared/breaking-changes.md +497 -0
  401. package/docs/shared/config.md +1387 -0
  402. package/docs/shared/deploys.md +215 -0
  403. package/docs/shared/icons.md +201 -0
  404. package/docs/shared/local-dev.md +147 -0
  405. package/docs/shared/logging.md +202 -0
  406. package/docs/shared/monitoring.md +153 -0
  407. package/docs/shared/publishing.md +183 -0
  408. package/docs/shared/rulings.md +34 -0
  409. package/docs/shared/testing.md +147 -0
  410. package/docs/shared/theming.md +604 -0
  411. package/docs/shared/translation.md +291 -0
  412. package/docs/shared/updates.md +61 -0
  413. package/docs/testing.md +34 -0
  414. package/docs/update.md +36 -0
  415. package/docs/workspace.md +64 -0
  416. package/package.json +88 -0
@@ -0,0 +1,153 @@
1
+ /**
2
+ * TikTok pixel authorization (#448, Ian 2026-08-21) — the ONE pass that puts
3
+ * a TikTok Events API token in a brand's hands, as an instance of the shared
4
+ * setup contract (#608, lib/service-input.js): ask when needed, never demand
5
+ * a standing key.
6
+ *
7
+ * Meta's token is minted in a dashboard and pasted, so it rides the generic
8
+ * paste lane. TikTok's is minted by an OAuth exchange, so its acquire is its
9
+ * own flow — and the app secret is a MINT-TIME credential, not a standing one:
10
+ *
11
+ * 1. the app id is public config (`analytics.providers.tiktok.appId`);
12
+ * 2. the app secret is pasted ONCE, masked, and never persisted anywhere;
13
+ * 3. the portal authorization is OFFERED (Enter-gated open, house rule: ask
14
+ * permission, never auto-open) and the `auth_code` it lands is pasted back;
15
+ * 4. the exchange runs inline;
16
+ * 5. ONLY the long-lived TIKTOK_ACCESS_TOKEN reaches the brand .env — the
17
+ * name @omega.js/backend reads.
18
+ *
19
+ * A re-authorization asks for the secret again (a company-level home for it is
20
+ * #446). Nothing here ever fails a walk: a headless run, a declined gate, an
21
+ * empty paste, or a rejected exchange all return false, and the caller keeps
22
+ * its warned where-to-get guidance.
23
+ */
24
+ const chalk = require('chalk').default;
25
+
26
+ const { writeEnvValue } = require('../../../lib/env-secret.js');
27
+ const { canPrompt } = require('../../../lib/run-gates.js');
28
+ const { confirmSetup, resolveConfigValue } = require('../../../lib/config-flow.js');
29
+ const { exchangeAuthCode, TIKTOK_APP_URL, TIKTOK_APPS_URL, TIKTOK_AUTH_BASE, isAuthUrlFor, parseAuthCode } = require('./tiktok-api.js');
30
+
31
+ /**
32
+ * Put a long-lived TikTok access token in the environment, walking the portal
33
+ * authorization when the run can ask.
34
+ *
35
+ * @param {Object} context - Handler context ({ brandRoot, brandConfig, options };
36
+ * `tiktokExchange` is the test seam that replaces the live exchange).
37
+ * @param {Object} spec - The TikTok pixel spec (envVar, label, key).
38
+ * @param {Object} [options]
39
+ * @param {boolean} [options.gate] - false = the caller already ran the
40
+ * Provide / Skip / Disable gate for this provider.
41
+ * @param {Object} [options.prompt] - Test seam over devkit/prompt members.
42
+ * @returns {Promise<boolean>} Whether the token is now in process.env.
43
+ */
44
+ async function acquireTikTokToken(context, spec, options = {}) {
45
+ const { brandRoot, brandConfig, options: runOptions = {} } = context;
46
+
47
+ if (process.env[spec.envVar]) {
48
+ return true;
49
+ }
50
+
51
+ if (!canPrompt(runOptions)) {
52
+ return false;
53
+ }
54
+
55
+ const provider = brandConfig.analytics?.providers?.[spec.key] || {};
56
+
57
+ // Whether this flow's Provide / Skip / Disable gate has already been opened.
58
+ let gated = options.gate === false;
59
+
60
+ let appId = provider.appId;
61
+ if (!appId) {
62
+ // The app id is the developer app's — public config, so it is ASKED for
63
+ // right here (#635) rather than warned about, and the mint continues into
64
+ // the same pass on the id just entered.
65
+ console.log(` ${chalk.dim('Create a TikTok developer app, then copy its App ID from the app\'s Basic Information')}`);
66
+ appId = await resolveConfigValue(context, {
67
+ path: `analytics.providers.${spec.key}.appId`,
68
+ label: 'TikTok developer app id',
69
+ instructions: [
70
+ '1. The next step opens the TikTok developer portal',
71
+ '2. Create (or open) the app, then paste back its App ID',
72
+ `3. The authorization and the exchange run here and only the long-lived token is saved (${chalk.cyan(spec.envVar)})`,
73
+ ],
74
+ entry: { url: TIKTOK_APPS_URL, message: 'Paste the TikTok developer app id:' },
75
+ disablePath: `analytics.providers.${spec.key}`,
76
+ ...(gated ? { gate: false } : {}),
77
+ });
78
+ if (!appId) {
79
+ // Skipped, disabled, or headless — the caller keeps its guidance
80
+ return false;
81
+ }
82
+ // That ask WAS this flow's gate: asking again for the same setup would
83
+ // put the same question twice in one pass.
84
+ gated = true;
85
+ }
86
+
87
+ if (!gated) {
88
+ const action = await confirmSetup(context, {
89
+ label: spec.label,
90
+ instructions: [
91
+ '1. The next step opens your app\'s page in the TikTok developer portal: paste its secret, then its "Advertiser authorization URL"',
92
+ '2. That URL opens next: approve the advertiser account, then paste back the redirect URL (it carries the auth_code)',
93
+ `3. The exchange runs here and only the long-lived token is saved (${chalk.cyan(spec.envVar)})`,
94
+ ],
95
+ disablePath: `analytics.providers.${spec.key}`,
96
+ });
97
+ if (action !== 'yes') {
98
+ return false;
99
+ }
100
+ }
101
+
102
+ const prompt = { ...require('../../../vendor/devkit/prompt.js'), ...options.prompt };
103
+
104
+ // The app page shows the "Advertiser authorization URL" TikTok built for the
105
+ // app (app id, state, and the redirect URI configured ON the app). The secret
106
+ // lives there too, so the page opens FIRST; the link is pasted back here, so
107
+ // it is never wrong and never stored (Ian 2026-08-27).
108
+ await prompt.pressEnterToOpen(
109
+ TIKTOK_APP_URL(appId),
110
+ `the ${spec.label} app page`,
111
+ );
112
+
113
+ // Mint-time only: masked, held in a local, never written to .env or config
114
+ const secret = (await prompt.password({ message: 'TikTok app secret (used once, never saved):' }) || '').trim();
115
+ if (!secret) {
116
+ return false;
117
+ }
118
+
119
+ const authUrl = (await prompt.input({ message: 'Paste the "Advertiser authorization URL" from the app page:' }) || '').trim();
120
+ if (!authUrl) {
121
+ return false;
122
+ }
123
+ if (!isAuthUrlFor(authUrl, appId)) {
124
+ console.log(` ${chalk.yellow('⚠')} That is not the authorization URL for app ${chalk.cyan(appId)} ${chalk.dim(`(expected ${TIKTOK_AUTH_BASE}?app_id=${appId}&…)`)}`);
125
+ return false;
126
+ }
127
+
128
+ await prompt.pressEnterToOpen(authUrl, `the ${spec.label} authorization portal`);
129
+
130
+ const authCode = parseAuthCode((await prompt.input({ message: 'Paste the redirect URL (or just the auth_code):' }) || '').trim());
131
+ if (!authCode) {
132
+ return false;
133
+ }
134
+
135
+ const exchange = context.tiktokExchange || ((params) => exchangeAuthCode(params));
136
+
137
+ let token;
138
+ try {
139
+ token = await exchange({ appId, secret, authCode });
140
+ } catch (error) {
141
+ // A rejected exchange is a normal outcome of a stale/mistyped code — the
142
+ // caller's guidance stands and the manage walk continues
143
+ console.log(` ${chalk.yellow('⚠')} TikTok token exchange failed${chalk.dim(`: ${error.message}`)}`);
144
+ return false;
145
+ }
146
+
147
+ writeEnvValue(brandRoot, spec.envVar, token);
148
+ process.env[spec.envVar] = token;
149
+ console.log(` ${chalk.green('✓')} ${spec.envVar} minted and saved to the brand .env`);
150
+ return true;
151
+ }
152
+
153
+ module.exports = { acquireTikTokToken };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Generate the wordmark and combomark SVGs from the brandmark + brand
3
+ * name + brand.font — text rendered as path outlines via opentype.js, so
4
+ * the output SVGs are self-contained. Generation is missing-only: an
5
+ * existing (possibly hand-tuned) wordmark or combomark is never
6
+ * overwritten.
7
+ *
8
+ * `brand.font` names a font file (without extension) resolved from the
9
+ * brand repo's `assets/fonts/` or the system font dirs. No font
10
+ * configured → nothing to generate with, noted and moved past (a brand
11
+ * with hand-made logo files never needs one). Configured but not found →
12
+ * error, the config intent failed.
13
+ */
14
+ const { join } = require('node:path');
15
+ const chalk = require('chalk').default;
16
+ const jetpack = require('fs-jetpack');
17
+ const { loadFont } = require('../lib/font-loader.js');
18
+ const { generateWordmark, generateCombomark } = require('../lib/svg-logo-generator.js');
19
+
20
+ module.exports = async function ensureLogoGen(context) {
21
+ const { brandConfig, brandRoot, logoDir, brandmarkPath, options } = context;
22
+ const dryRun = options?.dryRun || false;
23
+
24
+ const brandName = brandConfig.brand.name;
25
+ const fontName = brandConfig.brand.font;
26
+
27
+ const wordmarkPath = join(logoDir, 'wordmark.svg');
28
+ const combomarkPath = join(logoDir, 'combomark.svg');
29
+
30
+ const missing = [
31
+ ['wordmark', wordmarkPath],
32
+ ['combomark', combomarkPath],
33
+ ].filter(([, path]) => !jetpack.exists(path));
34
+
35
+ if (missing.length === 0) {
36
+ console.log(` ${chalk.green('✓')} Logo sources ${chalk.dim('(wordmark + combomark)')} in sync`);
37
+ return { output: { logos: { synced: true } } };
38
+ }
39
+
40
+ if (!fontName) {
41
+ console.log(` ${chalk.dim(`⊘ No brand.font configured — ${missing.map(([name]) => name).join(' + ')} not generated (set brand.font + a font file in assets/fonts/, or add the SVGs by hand)`)}`);
42
+ return { output: { logos: { skipped: 'no brand.font' } } };
43
+ }
44
+
45
+ if (dryRun) {
46
+ console.log(` ${chalk.yellow('[DRY RUN]')} Would generate ${missing.map(([name]) => chalk.cyan(`${name}.svg`)).join(' + ')}`);
47
+ return { output: { logos: { planned: missing.map(([name]) => name) } } };
48
+ }
49
+
50
+ const font = loadFont(fontName, brandRoot);
51
+ if (!font) {
52
+ console.log(` ${chalk.red('✗')} Font ${chalk.cyan(fontName)} not found in ${chalk.dim('assets/fonts/')} or the system font dirs`);
53
+ return { status: 'error', error: `font "${fontName}" not found` };
54
+ }
55
+
56
+ const generated = [];
57
+
58
+ for (const [name, path] of missing) {
59
+ const svg = name === 'wordmark'
60
+ ? generateWordmark(brandName, font)
61
+ : generateCombomark(brandName, jetpack.read(brandmarkPath), font);
62
+ jetpack.write(path, svg);
63
+ console.log(` ${chalk.green('✓')} Generated ${chalk.cyan(`${name}.svg`)}`);
64
+ generated.push(name);
65
+ }
66
+
67
+ return { output: { logos: { generated } } };
68
+ };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Assets service — the brand's derived visual collateral generated from
3
+ * its logo sources: wordmark/combomark SVGs from the brandmark +
4
+ * brand.font, color/black SVG variants + PNG size ladders, PSD templates
5
+ * (seeded from the company root, logo/text layers refreshed, PNGs
6
+ * exported), macOS/Windows app icons, social profile icons, and the web
7
+ * favicon set.
8
+ *
9
+ * Sources are committed brand collateral at `assets/logo/*.svg` and
10
+ * `assets/templates/*.psd` in the brand repo (omega-manager read
11
+ * `.brands/{id}/assets/`); derived files land in the gitignored
12
+ * `.omega/assets/` (omega-manager's `.output/{id}/assets/`). Every
13
+ * operation is mtime-diffed — only missing or stale outputs regenerate —
14
+ * which replaces omega-manager's `--onboarding` gate on the write
15
+ * operations (it regenerated blindly, so running every time was too
16
+ * expensive; it also had no dry-run guard). `--reset-assets` forces a
17
+ * rebuild the timestamps would skip by clearing the cache first
18
+ * (lib/reset.js).
19
+ *
20
+ * The brandmark is the root of every derived asset. When it's missing
21
+ * and MrLogo credentials are present (MRLOGO_SERVICE_ACCOUNT /
22
+ * MRLOGO_API_KEY / LOGO_API_ID_TOKEN — the product-service ladder,
23
+ * lib/brandmark-api.js; zero config options by design), the AI generation
24
+ * flow runs; otherwise the service skips with guidance. Not ported:
25
+ * omega-manager's social-images/store-images
26
+ * write operations — dead code whose template-name lists never matched
27
+ * TEMPLATE_CONFIG keys (they could never generate anything); their
28
+ * intended outputs are the templates operation's og-image and
29
+ * store/chrome exports.
30
+ */
31
+ const { join } = require('node:path');
32
+ const jetpack = require('fs-jetpack');
33
+ const chalk = require('chalk').default;
34
+ const { createServiceRunner } = require('../../lib/service-runner.js');
35
+ const { input } = require('../../vendor/devkit/prompt.js');
36
+ const { withSpinner } = require('../../vendor/devkit/flows.js');
37
+ const { resolveLogoAuth, generateBrandmark, MRLOGO_URL } = require('./lib/brandmark-api.js');
38
+ const { resolveResetKinds, resetAssetsCache } = require('./lib/reset.js');
39
+ const { canPrompt } = require('../../lib/run-gates.js');
40
+
41
+ module.exports.run = createServiceRunner({
42
+ serviceDir: __dirname,
43
+ setup: async (context) => {
44
+ const config = context.brandConfig.assets;
45
+
46
+ if (config === false || config?.enabled === false) {
47
+ return { skip: true, reason: 'assets.enabled = false' };
48
+ }
49
+
50
+ const logoDir = join(context.brandRoot, 'assets', 'logo');
51
+ const brandmarkPath = join(logoDir, 'brandmark.svg');
52
+
53
+ // The brandmark is the root of every derived asset — when the brand has
54
+ // none and MrLogo credentials resolve (the product-service ladder:
55
+ // operator SA → api key → pasted ID token; setting a credential IS the
56
+ // consent to spend the API call), generate it. Interactive runs ask for
57
+ // optional art direction. Dry runs never mint.
58
+ if (!jetpack.exists(brandmarkPath)) {
59
+ if (!context.options?.dryRun) {
60
+ try {
61
+ const auth = await resolveLogoAuth({
62
+ brandConfig: context.brandConfig,
63
+ brandRoot: context.brandRoot,
64
+ db: context.mrlogoDb,
65
+ authAdmin: context.mrlogoAuthAdmin,
66
+ log: (line) => console.log(` ${line}`),
67
+ });
68
+
69
+ if (auth) {
70
+ const direction = canPrompt(context.options)
71
+ ? (await input({ message: 'Logo prompt (press Enter to skip):', default: '' })).trim()
72
+ : '';
73
+ await withSpinner('Generating brandmark via MrLogo', () =>
74
+ generateBrandmark({ brandConfig: context.brandConfig, brandmarkPath, direction, token: auth.token }));
75
+ }
76
+ } catch (error) {
77
+ console.log(` ${chalk.yellow('⚠')} Brandmark generation failed${chalk.dim(`: ${error.message}`)}`);
78
+ }
79
+ }
80
+
81
+ if (!jetpack.exists(brandmarkPath)) {
82
+ return { skip: true, reason: `no assets/logo/brandmark.svg in the brand repo (add the brand's logo source, set MRLOGO_SERVICE_ACCOUNT / MRLOGO_API_KEY / LOGO_API_ID_TOKEN in the brand .env for AI generation, or make one at ${MRLOGO_URL})` };
83
+ }
84
+ }
85
+
86
+ const outDir = join(context.brandRoot, '.omega', 'assets');
87
+
88
+ // The force refresh (#214): clear the asked kinds before the operations
89
+ // run, so the mtime gate below sees them missing and rebuilds them. Loud
90
+ // by design, because this is the one thing the service destroys and an
91
+ // operator who typed the flag by accident has to see what went.
92
+ const resetKinds = resolveResetKinds(context.options?.resetAssets);
93
+ if (resetKinds.length > 0) {
94
+ const dryRun = context.options?.dryRun || false;
95
+ const { removed } = resetAssetsCache({ outDir, kinds: resetKinds, dryRun });
96
+ const what = `${chalk.bold(resetKinds.join(' + '))} ${chalk.dim(`(${removed.length} path${removed.length === 1 ? '' : 's'} under .omega/assets/)`)}`;
97
+
98
+ console.log(dryRun
99
+ ? ` ${chalk.yellow('[DRY RUN]')} Would reset ${what}`
100
+ : ` ${chalk.yellow('↺')} Reset ${what}; regenerating below`);
101
+ }
102
+
103
+ return {
104
+ logoDir,
105
+ brandmarkPath,
106
+ outDir,
107
+ };
108
+ },
109
+ });
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Assets processing rules — which logo sources produce which derived files.
3
+ *
4
+ * Sources live in the brand repo at `assets/logo/*.svg` (committed brand
5
+ * collateral — omega-manager read `.brands/{id}/assets/`); derived files
6
+ * land in `.omega/assets/` (gitignored, regenerable — omega-manager's
7
+ * `.output/{id}/assets/`).
8
+ *
9
+ * Logo naming conventions:
10
+ * - brandmark: Square icon/symbol (no text)
11
+ * - wordmark: Text-only logo
12
+ * - combomark: Icon + text combined
13
+ */
14
+
15
+ const BRANDMARK_SIZES = [16, 32, 48, 64, 128, 256, 512, 1024, 2048];
16
+ const WIDE_LOGO_SIZES = [128, 256, 512, 1024, 2048];
17
+
18
+ /**
19
+ * Each logo source gets two variants — the SVG as-is (colors/gradients
20
+ * preserved) and an all-black conversion — exported as SVG + PNGs at all
21
+ * sizes.
22
+ */
23
+ const PROCESSING_RULES = {
24
+ brandmark: {
25
+ source: 'assets/logo/brandmark.svg',
26
+ outputDir: 'logo/brandmark',
27
+ square: true,
28
+ sizes: BRANDMARK_SIZES,
29
+ },
30
+ wordmark: {
31
+ source: 'assets/logo/wordmark.svg',
32
+ outputDir: 'logo/wordmark',
33
+ square: false,
34
+ sizes: WIDE_LOGO_SIZES,
35
+ },
36
+ combomark: {
37
+ source: 'assets/logo/combomark.svg',
38
+ outputDir: 'logo/combomark',
39
+ square: false,
40
+ sizes: WIDE_LOGO_SIZES,
41
+ },
42
+ };
43
+
44
+ /**
45
+ * Social profile icons — square brandmark on a white background for
46
+ * profile pictures (YouTube, Twitter, …).
47
+ */
48
+ const SOCIAL_ICON_CONFIG = {
49
+ outputDir: 'social/brandmark',
50
+ sizes: [512, 1024, 2048],
51
+ padding: 0.15, // 15% padding on each side
52
+ background: { r: 255, g: 255, b: 255, alpha: 1 },
53
+ };
54
+
55
+ /**
56
+ * PSD templates — brand-editable Photoshop sources for app icons, social
57
+ * images, and store promos. Each `{key}.psd` lives in the brand repo at
58
+ * `assets/templates/` (seeded on first run from the company root's
59
+ * `assets/templates/` when the brand is company-managed — omega-manager
60
+ * baked ITW's binaries into its own `src/defaults/`); exports land in
61
+ * `.omega/assets/{outputDir}/`.
62
+ *
63
+ * Layer replacement types:
64
+ * - logo: replace the layer canvas with the brandmark SVG
65
+ * - path: slash-delimited layer path (e.g. 'Main/Logo/Logo')
66
+ * - size: logo size as a fraction of canvas width (0-1)
67
+ * - bounds: [left, top, right, bottom] fractions to center within (optional)
68
+ * - useBlackLogo: render the pure-black brandmark variant
69
+ * - text: replace a text layer's content with a brandConfig value
70
+ * - path: slash-delimited layer path
71
+ * - value: dot-notation config path (e.g. 'brand.name')
72
+ * - maxWidth: max text width as a fraction of canvas width — shrinks the
73
+ * font when the value overflows
74
+ */
75
+ const TEMPLATE_CONFIG = {
76
+ // --- App: macOS ---
77
+ 'app-macos-icon': {
78
+ dimensions: [1024, 1024],
79
+ outputDir: 'app/macos',
80
+ outputName: 'icon',
81
+ layers: [
82
+ { type: 'logo', path: 'Main/Logo/Logo', size: 0.575, bounds: [0.078, 0.089, 0.922, 0.933] },
83
+ ],
84
+ },
85
+ 'app-macos-tray': {
86
+ dimensions: [32, 32],
87
+ outputDir: 'app/macos',
88
+ // The desktop framework consumes this as `tray.png` and renames its dist
89
+ // output to `trayTemplate.png` itself (the `Template` suffix is a macOS
90
+ // magic marker for dark-mode auto-inversion). Native @2x size; the
91
+ // framework downscales the @1x sibling.
92
+ outputName: 'tray',
93
+ layers: [
94
+ // macOS tray template images MUST be pure black (with alpha) so the
95
+ // system can invert them in dark mode
96
+ { type: 'logo', path: 'Main/Logo/Logo', size: 1.0, useBlackLogo: true },
97
+ ],
98
+ },
99
+ 'app-macos-dmg': {
100
+ dimensions: [1080, 760],
101
+ outputDir: 'app/macos',
102
+ outputName: 'dmg',
103
+ },
104
+
105
+ // --- App: Windows ---
106
+ 'app-windows-icon': {
107
+ dimensions: [1024, 1024],
108
+ outputDir: 'app/windows',
109
+ outputName: 'icon',
110
+ layers: [
111
+ { type: 'logo', path: 'Main/Logo/Logo', size: 0.7 },
112
+ ],
113
+ },
114
+
115
+ // --- Social ---
116
+ 'social-og-image': {
117
+ dimensions: [1200, 630],
118
+ outputDir: 'social',
119
+ outputName: 'og-image',
120
+ layers: [
121
+ { type: 'logo', path: 'Main/Logo/Logo', size: 0.25 },
122
+ { type: 'text', path: 'Main/Text/Brand Name', value: 'brand.name', maxWidth: 0.8 },
123
+ { type: 'text', path: 'Main/Text/Brand Tagline', value: 'brand.tagline', maxWidth: 0.7 },
124
+ ],
125
+ },
126
+
127
+ // --- Store: Chrome Web Store ---
128
+ 'store-chrome-promo-small': {
129
+ dimensions: [440, 280],
130
+ outputDir: 'store/chrome',
131
+ outputName: 'promo-small',
132
+ },
133
+ 'store-chrome-promo-large': {
134
+ dimensions: [920, 680],
135
+ outputDir: 'store/chrome',
136
+ outputName: 'promo-large',
137
+ },
138
+ 'store-chrome-promo-marquee': {
139
+ dimensions: [1400, 560],
140
+ outputDir: 'store/chrome',
141
+ outputName: 'promo-marquee',
142
+ },
143
+ };
144
+
145
+ /**
146
+ * App icon formats per platform. The composited `icon.png` from the
147
+ * templates operation is the source when present, else the brandmark SVG.
148
+ */
149
+ const ICON_PLATFORMS = {
150
+ macos: { format: 'icns' },
151
+ windows: { format: 'ico' },
152
+ };
153
+
154
+ /**
155
+ * Web favicon set.
156
+ */
157
+ const FAVICON_CONFIG = {
158
+ outputDir: 'favicon',
159
+ files: [
160
+ { name: 'favicon-16x16.png', size: 16 },
161
+ { name: 'favicon-32x32.png', size: 32 },
162
+ { name: 'apple-touch-icon.png', size: 180 },
163
+ { name: 'android-chrome-192x192.png', size: 192 },
164
+ { name: 'android-chrome-512x512.png', size: 512 },
165
+ ],
166
+ };
167
+
168
+ module.exports = { PROCESSING_RULES, SOCIAL_ICON_CONFIG, TEMPLATE_CONFIG, ICON_PLATFORMS, FAVICON_CONFIG };
@@ -0,0 +1,160 @@
1
+ /**
2
+ * AI brandmark generation via MrLogo (mrlogo.ai — a sibling ITW product) —
3
+ * the fallback when a brand has no assets/logo/brandmark.svg yet. MrLogo is
4
+ * OURS, so the endpoint is a product constant (like the Ghostii client's
5
+ * write URL) and auth rides the same credential ladder as the other product
6
+ * services (forms/chat/email — Ian 2026-07-14: no config options,
7
+ * "use an API key or service account or whatever slapform, chatsy,
8
+ * replyify use"):
9
+ *
10
+ * 1. MRLOGO_SERVICE_ACCOUNT (path to MrLogo's service-account JSON,
11
+ * absolute or brand-root-relative) — full auto: ensures the brand's
12
+ * OWN MrLogo product user (email = brand.contact.email, canonical
13
+ * account shape via lib/product-create) and calls the API with that
14
+ * user's api.privateKey. New users land on MrLogo's basic plan
15
+ * (100 credits), plenty for brandmark generation.
16
+ * 2. MRLOGO_API_KEY — an existing MrLogo account's api.privateKey used
17
+ * directly. Verified against the live wire contract: BEM's
18
+ * authenticate() resolves a non-JWT Bearer value by querying
19
+ * users.api.privateKey, and MrLogo's logos route rides that auth.
20
+ * 3. LOGO_API_ID_TOKEN — a pasted Firebase ID token (manual escape
21
+ * hatch; ID tokens expire hourly, so the durable tiers rank first).
22
+ *
23
+ * No credentials → the assets service skips with guidance (generate at
24
+ * mrlogo.ai by hand and drop the SVG in assets/logo/). The API returns a
25
+ * monochrome SVG (preferred) or color SVG URL; the download lands at
26
+ * assets/logo/brandmark.svg as committed collateral.
27
+ */
28
+ const { randomUUID } = require('node:crypto');
29
+ const chalk = require('chalk').default;
30
+ const jetpack = require('fs-jetpack');
31
+ const { FirestoreREST, loadServiceAccount } = require('../../../lib/firestore-rest.js');
32
+ const { createAuthAdmin } = require('../../../lib/auth-admin.js');
33
+ const { ensureProductUser } = require('../../../lib/product-create.js');
34
+ const { createPasswordResolver } = require('../../account/lib/resolve-password.js');
35
+
36
+ // MrLogo's LIVE production route (the old-world /backend-manager path IS its
37
+ // api). Env override is a test/staging seam, not brand config.
38
+ const MRLOGO_API_URL = 'https://api.mrlogo.ai/backend-manager/logos';
39
+ const MRLOGO_URL = 'https://mrlogo.ai';
40
+
41
+ function apiUrl() {
42
+ return process.env.MRLOGO_API_URL || MRLOGO_API_URL;
43
+ }
44
+
45
+ /**
46
+ * Resolve the logo API's Bearer credential down the product ladder, or null
47
+ * when no tier is configured. The SA tier ensures the brand's own MrLogo
48
+ * product user and uses ITS api.privateKey — BEM auth accepts a privateKey
49
+ * and an ID token through the same Authorization header.
50
+ *
51
+ * @param {object} spec
52
+ * @param {object} spec.brandConfig - Merged brand config
53
+ * @param {string} spec.brandRoot - Brand root (SA paths + password channels)
54
+ * @param {object} [spec.db] - FirestoreREST test seam (with authAdmin)
55
+ * @param {object} [spec.authAdmin] - auth-admin test seam
56
+ * @param {function} spec.log - line logger
57
+ * @returns {Promise<{ token: string, source: string }|null>}
58
+ */
59
+ async function resolveLogoAuth({ brandConfig, brandRoot, db, authAdmin, log }) {
60
+ // Tier 1 — operator SA: mint/reuse the brand's own product user
61
+ if (!db) {
62
+ const envPath = process.env.MRLOGO_SERVICE_ACCOUNT;
63
+ if (envPath) {
64
+ const serviceAccount = loadServiceAccount(envPath, brandRoot);
65
+ db = new FirestoreREST(serviceAccount);
66
+ authAdmin = createAuthAdmin(serviceAccount);
67
+ }
68
+ }
69
+
70
+ if (db && authAdmin) {
71
+ const brand = brandConfig.brand || {};
72
+ const email = brand.contact?.email;
73
+ if (!email) {
74
+ throw new Error('MRLOGO_SERVICE_ACCOUNT is set but brand.contact.email is missing — the brand\'s product user needs it');
75
+ }
76
+
77
+ const { uid } = await ensureProductUser({
78
+ db,
79
+ authAdmin,
80
+ email,
81
+ resolvePassword: createPasswordResolver({
82
+ brandRoot,
83
+ domain: new URL(brand.url || 'https://invalid.test').hostname,
84
+ brand,
85
+ dryRun: false,
86
+ }),
87
+ log,
88
+ });
89
+
90
+ const userDoc = await db.getDoc(`users/${uid}`);
91
+ const privateKey = userDoc?.api?.privateKey;
92
+ if (!privateKey) {
93
+ throw new Error(`MrLogo user ${email} (${uid}) has no api.privateKey in its user doc`);
94
+ }
95
+ return { token: privateKey, source: 'MRLOGO_SERVICE_ACCOUNT' };
96
+ }
97
+
98
+ // Tier 2 — an existing account's api.privateKey, used directly
99
+ if (process.env.MRLOGO_API_KEY) {
100
+ return { token: process.env.MRLOGO_API_KEY, source: 'MRLOGO_API_KEY' };
101
+ }
102
+
103
+ // Tier 3 — pasted Firebase ID token (expires hourly)
104
+ if (process.env.LOGO_API_ID_TOKEN) {
105
+ return { token: process.env.LOGO_API_ID_TOKEN, source: 'LOGO_API_ID_TOKEN' };
106
+ }
107
+
108
+ return null;
109
+ }
110
+
111
+ /**
112
+ * Generate the brandmark via the logo API and write it to brandmarkPath.
113
+ *
114
+ * @returns {boolean} whether the SVG landed
115
+ */
116
+ async function generateBrandmark({ brandConfig, brandmarkPath, direction, token }) {
117
+ const response = await fetch(apiUrl(), {
118
+ method: 'POST',
119
+ headers: {
120
+ 'Content-Type': 'application/json',
121
+ 'Authorization': `Bearer ${token}`,
122
+ },
123
+ body: JSON.stringify({
124
+ brandName: brandConfig.brand.name,
125
+ mode: 'brandmark',
126
+ style: 'flat',
127
+ mood: 'professional',
128
+ industry: brandConfig.brand.tagline || '',
129
+ description: [brandConfig.brand.description || '', direction].filter(Boolean).join('. '),
130
+ colors: ['#000000'],
131
+ id: randomUUID(),
132
+ }),
133
+ signal: AbortSignal.timeout(120000),
134
+ });
135
+
136
+ if (!response.ok) {
137
+ const text = await response.text();
138
+ throw new Error(`logo API responded ${response.status}: ${text}`);
139
+ }
140
+
141
+ const result = await response.json();
142
+ const files = result.iteration?.files || {};
143
+ const svgUrl = files.monoSvg?.url || files.colorSvg?.url;
144
+
145
+ if (!svgUrl) {
146
+ console.log(` ${chalk.yellow('⚠')} No SVG in the logo API response — check the provider's logs`);
147
+ return false;
148
+ }
149
+
150
+ const svgResponse = await fetch(svgUrl, { signal: AbortSignal.timeout(30000) });
151
+ if (!svgResponse.ok) {
152
+ throw new Error(`failed to download the SVG (${svgResponse.status})`);
153
+ }
154
+
155
+ jetpack.write(brandmarkPath, await svgResponse.text());
156
+ console.log(` ${chalk.green('✓')} Generated ${chalk.cyan('assets/logo/brandmark.svg')} via MrLogo`);
157
+ return true;
158
+ }
159
+
160
+ module.exports = { resolveLogoAuth, generateBrandmark, MRLOGO_URL };