@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,113 @@
1
+ /**
2
+ * The derived output NAMES every assets operation owns — the one home of the
3
+ * naming conventions, read by the writers that produce the files, by the
4
+ * `--reset-assets` cache clear (lib/reset.js), and by the reconcile that
5
+ * deletes what the current sources no longer derive (lib/reconcile.js).
6
+ *
7
+ * It has to be ONE list: a name a writer produces but the reconcile does not
8
+ * derive would be deleted on every walk and regenerated on the next one, so
9
+ * the two views of "what belongs under .omega/assets/" can never be allowed
10
+ * to drift apart.
11
+ *
12
+ * Everything here is relative to `.omega/assets/`; the shapes come from
13
+ * assets-config.js, so a new rule/template/platform is covered without a
14
+ * second registry to update.
15
+ */
16
+ const { join } = require('node:path');
17
+
18
+ const {
19
+ PROCESSING_RULES, SOCIAL_ICON_CONFIG, TEMPLATE_CONFIG, ICON_PLATFORMS, FAVICON_CONFIG,
20
+ } = require('./assets-config.js');
21
+
22
+ /** The two variants every logo source produces: the SVG as-is, and all-black. */
23
+ const LOGO_VARIANTS = ['color', 'black'];
24
+
25
+ /** The webmanifest — derived from config, not from the brandmark, so it is content-diffed. */
26
+ const WEBMANIFEST_NAME = 'site.webmanifest';
27
+
28
+ /**
29
+ * One logo variant's files, relative to the rule's output dir.
30
+ *
31
+ * @param {object} rule - A PROCESSING_RULES entry.
32
+ * @param {string} variant - A LOGO_VARIANTS entry.
33
+ * @returns {string[]} The variant SVG plus a PNG per ladder size.
34
+ */
35
+ function logoVariantFiles(rule, variant) {
36
+ return [`${variant}-x.svg`, ...rule.sizes.map((size) => `${variant}-${size}.png`)];
37
+ }
38
+
39
+ /**
40
+ * The social profile icons, relative to SOCIAL_ICON_CONFIG.outputDir.
41
+ *
42
+ * @returns {string[]} The wrapped SVG plus a PNG per size.
43
+ */
44
+ function socialIconFiles() {
45
+ return ['color-x.svg', ...SOCIAL_ICON_CONFIG.sizes.map((size) => `color-${size}.png`)];
46
+ }
47
+
48
+ /**
49
+ * The favicon IMAGES, relative to FAVICON_CONFIG.outputDir — the PNG ladder
50
+ * plus the multi-size .ico. The webmanifest is not here: it derives from
51
+ * config rather than from the brandmark, so it is diffed differently.
52
+ *
53
+ * @returns {string[]} File names.
54
+ */
55
+ function faviconImageFiles() {
56
+ return [...FAVICON_CONFIG.files.map((file) => file.name), 'favicon.ico'];
57
+ }
58
+
59
+ /**
60
+ * One PSD template's exports.
61
+ *
62
+ * @param {object} config - A TEMPLATE_CONFIG entry.
63
+ * @returns {string[]} Paths relative to `.omega/assets/`.
64
+ */
65
+ function templateExportFiles(config) {
66
+ return (config.exports || [{ suffix: '' }])
67
+ .map((exp) => join(config.outputDir, `${config.outputName}${exp.suffix || ''}.png`));
68
+ }
69
+
70
+ /**
71
+ * The platform app icons.
72
+ *
73
+ * @returns {Array<{ platform: string, format: string, file: string }>} `file`
74
+ * is relative to `.omega/assets/`.
75
+ */
76
+ function appIconFiles() {
77
+ return Object.entries(ICON_PLATFORMS).map(([platform, { format }]) => ({
78
+ platform,
79
+ format,
80
+ file: join('app', platform, `icon.${format}`),
81
+ }));
82
+ }
83
+
84
+ /**
85
+ * Every directory under `.omega/assets/` an assets operation writes into —
86
+ * the reconcile's output BOUNDARY. Nested entries are dropped (a recursive
87
+ * walk of `social` already covers `social/brandmark`), so each file is
88
+ * visited once.
89
+ *
90
+ * @returns {string[]} Paths relative to `.omega/assets/`.
91
+ */
92
+ function assetsOutputDirs() {
93
+ const dirs = [...new Set([
94
+ ...Object.values(PROCESSING_RULES).map((rule) => rule.outputDir),
95
+ SOCIAL_ICON_CONFIG.outputDir,
96
+ ...Object.values(TEMPLATE_CONFIG).map((config) => config.outputDir),
97
+ ...Object.keys(ICON_PLATFORMS).map((platform) => join('app', platform)),
98
+ FAVICON_CONFIG.outputDir,
99
+ ])];
100
+
101
+ return dirs.filter((dir) => !dirs.some((other) => other !== dir && dir.startsWith(`${other}/`)));
102
+ }
103
+
104
+ module.exports = {
105
+ LOGO_VARIANTS,
106
+ WEBMANIFEST_NAME,
107
+ logoVariantFiles,
108
+ socialIconFiles,
109
+ faviconImageFiles,
110
+ templateExportFiles,
111
+ appIconFiles,
112
+ assetsOutputDirs,
113
+ };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Font loader for wordmark/combomark generation — resolves `brand.font`
3
+ * (a font filename without extension, e.g. `Inter-Bold`) to a parsed
4
+ * opentype.js Font.
5
+ *
6
+ * Search order: the brand repo's own `assets/fonts/` first, then the
7
+ * system font directories. omega-manager instead PACKAGED the company's
8
+ * commercial fonts (CromaSans/NowAlt — licensed, so they can't ship in a
9
+ * published package) and defaulted every brand to CromaSans-ExtraBold via
10
+ * a hardcoded alias table; the port has no packaged fonts and no default —
11
+ * the brand owns its font choice.
12
+ */
13
+ const { join } = require('node:path');
14
+ const { homedir } = require('node:os');
15
+ const jetpack = require('fs-jetpack');
16
+ const opentype = require('opentype.js');
17
+
18
+ const FONT_EXTENSIONS = ['.otf', '.ttf', '.woff'];
19
+
20
+ const SYSTEM_FONT_DIRS = [
21
+ join(homedir(), 'Library', 'Fonts'),
22
+ '/Library/Fonts',
23
+ '/System/Library/Fonts',
24
+ ];
25
+
26
+ /**
27
+ * Find a font file by name (without extension).
28
+ *
29
+ * @param {string} name - Font filename, e.g. 'Inter-Bold'
30
+ * @param {string} brandRoot - Brand repo root (its assets/fonts/ is searched first)
31
+ * @returns {string|null} Full path to the font file, or null
32
+ */
33
+ function findFontFile(name, brandRoot) {
34
+ const dirs = [join(brandRoot, 'assets', 'fonts'), ...SYSTEM_FONT_DIRS];
35
+
36
+ for (const dir of dirs) {
37
+ for (const ext of FONT_EXTENSIONS) {
38
+ const filePath = join(dir, `${name}${ext}`);
39
+ if (jetpack.exists(filePath)) {
40
+ return filePath;
41
+ }
42
+ }
43
+ }
44
+
45
+ return null;
46
+ }
47
+
48
+ /**
49
+ * Load and parse a font.
50
+ *
51
+ * @param {string} name - Font filename without extension
52
+ * @param {string} brandRoot - Brand repo root
53
+ * @returns {Object|null} opentype.js Font, or null when no file was found
54
+ */
55
+ function loadFont(name, brandRoot) {
56
+ const fontPath = findFontFile(name, brandRoot);
57
+ if (!fontPath) {
58
+ return null;
59
+ }
60
+
61
+ const buffer = jetpack.read(fontPath, 'buffer');
62
+ // opentype.parse expects an ArrayBuffer
63
+ const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
64
+ return opentype.parse(arrayBuffer);
65
+ }
66
+
67
+ module.exports = { loadFont, findFontFile };
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Assets reconcile (#636) — every file under `.omega/assets/` derives from the
3
+ * brand's sources and config, so the walk that writes them also DELETES the
4
+ * ones those sources no longer derive. Dropping `assets/logo/wordmark.svg` is
5
+ * a real removal: the wordmark's variants and ladders go with it, not on the
6
+ * next hand-deletion of the cache.
7
+ *
8
+ * Deleting is safe HERE and only here: `.omega/assets/` is the machine-owned,
9
+ * gitignored cache the reset already clears (lib/reset.js), and every file in
10
+ * it is regenerable from the brand's committed sources. The brand's own
11
+ * collateral (`assets/logo/*.svg`, `assets/templates/*.psd`) is a SOURCE and
12
+ * is never touched.
13
+ *
14
+ * Two locks keep it honest: the derived set comes from the SAME names the
15
+ * writers generate (lib/derived.js), and the diff runs only inside the
16
+ * operations' own output dirs — a file the assets service never writes into
17
+ * cannot be reached from here.
18
+ */
19
+ const { join } = require('node:path');
20
+ const fs = require('node:fs');
21
+ const jetpack = require('fs-jetpack');
22
+
23
+ const { PROCESSING_RULES, SOCIAL_ICON_CONFIG, TEMPLATE_CONFIG, FAVICON_CONFIG } = require('./assets-config.js');
24
+ const {
25
+ LOGO_VARIANTS, WEBMANIFEST_NAME, logoVariantFiles, socialIconFiles,
26
+ faviconImageFiles, templateExportFiles, appIconFiles, assetsOutputDirs,
27
+ } = require('./derived.js');
28
+
29
+ /**
30
+ * The FULL set of files the brand's current sources derive, exactly as the
31
+ * write operations name them. A logo source or a PSD that isn't in the brand
32
+ * derives nothing — which is what makes a removed source remove its outputs.
33
+ *
34
+ * The brandmark is guaranteed by the service's setup, so the operations that
35
+ * read it alone (social icons, favicons, app icons) always derive their set.
36
+ *
37
+ * @param {string} brandRoot - Absolute brand-monorepo root.
38
+ * @returns {Set<string>} Paths relative to `.omega/assets/`.
39
+ */
40
+ function derivedAssetFiles(brandRoot) {
41
+ const files = [];
42
+
43
+ for (const rule of Object.values(PROCESSING_RULES)) {
44
+ if (!jetpack.exists(join(brandRoot, rule.source))) {
45
+ continue;
46
+ }
47
+ for (const variant of LOGO_VARIANTS) {
48
+ files.push(...logoVariantFiles(rule, variant).map((name) => join(rule.outputDir, name)));
49
+ }
50
+ }
51
+
52
+ files.push(...socialIconFiles().map((name) => join(SOCIAL_ICON_CONFIG.outputDir, name)));
53
+
54
+ for (const [name, config] of Object.entries(TEMPLATE_CONFIG)) {
55
+ // The brand's PSD is the source — a template it does not carry (and the
56
+ // company root could not seed) exports nothing
57
+ if (!jetpack.exists(join(brandRoot, 'assets', 'templates', `${name}.psd`))) {
58
+ continue;
59
+ }
60
+ files.push(...templateExportFiles(config));
61
+ }
62
+
63
+ files.push(...appIconFiles().map((entry) => entry.file));
64
+ files.push(...faviconImageFiles().map((name) => join(FAVICON_CONFIG.outputDir, name)));
65
+ files.push(join(FAVICON_CONFIG.outputDir, WEBMANIFEST_NAME));
66
+
67
+ return new Set(files);
68
+ }
69
+
70
+ /**
71
+ * Every file under a directory, relative to it.
72
+ *
73
+ * @param {string} dir - Absolute directory.
74
+ * @returns {string[]} Relative paths.
75
+ */
76
+ function filesUnder(dir) {
77
+ return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => (entry.isDirectory()
78
+ ? filesUnder(join(dir, entry.name)).map((nested) => join(entry.name, nested))
79
+ : [entry.name]));
80
+ }
81
+
82
+ /**
83
+ * Delete the files inside the assets operations' output dirs that the brand's
84
+ * current sources no longer derive. Runs AFTER the write operations, so a file
85
+ * this same walk just generated (or a PSD it just seeded) is already derived.
86
+ *
87
+ * @param {object} args
88
+ * @param {string} args.brandRoot - Absolute brand-monorepo root.
89
+ * @param {string} args.outDir - The brand's `.omega/assets/`.
90
+ * @param {boolean} [args.dryRun] - Report what would go, delete nothing.
91
+ * @returns {{ removed: string[] }} The relative paths that were strays (and,
92
+ * outside a dry run, are now gone).
93
+ */
94
+ function reconcileAssets({ brandRoot, outDir, dryRun = false }) {
95
+ const derived = derivedAssetFiles(brandRoot);
96
+ const removed = [];
97
+
98
+ for (const dir of assetsOutputDirs()) {
99
+ const base = join(outDir, dir);
100
+
101
+ if (jetpack.exists(base) !== 'dir') {
102
+ continue;
103
+ }
104
+
105
+ for (const relative of filesUnder(base)) {
106
+ const path = join(dir, relative);
107
+
108
+ if (derived.has(path)) {
109
+ continue;
110
+ }
111
+
112
+ if (!dryRun) {
113
+ jetpack.remove(join(base, relative));
114
+ }
115
+ removed.push(path);
116
+ }
117
+ }
118
+
119
+ return { removed: removed.sort() };
120
+ }
121
+
122
+ module.exports = { derivedAssetFiles, reconcileAssets };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Assets cache invalidation: the force refresh behind `omega manage
3
+ * --reset-assets` (#214). Every assets operation is mtime-diffed, so a
4
+ * converged brand regenerates nothing; when a derived file is wrong for a
5
+ * reason no timestamp records (a hand-mangled export, a sharp/ag-psd
6
+ * upgrade that renders differently), the only lever was hand-deleting
7
+ * `.omega/assets/`. omega-manager had `--reset-templates` /
8
+ * `--reset-logos` for exactly this.
9
+ *
10
+ * Invalidation IS deletion here: `isStale()` calls a missing derived file
11
+ * stale, so removing a kind's outputs is precisely what makes the same walk
12
+ * regenerate them, with no second freshness mechanism to keep in sync.
13
+ *
14
+ * Only `.omega/assets/` is cache. The brand's committed collateral
15
+ * (`assets/logo/*.svg`, `assets/templates/*.psd`) is a SOURCE and is never
16
+ * resettable: a reset that ate the PSD an operator edited by hand would be
17
+ * unrecoverable.
18
+ *
19
+ * The two kinds together are the whole cache: `templates` is the PSD export
20
+ * PNGs, `logos` is everything the logo sources derive (variants, app icon
21
+ * containers, social icons, favicons).
22
+ */
23
+ const { join } = require('node:path');
24
+ const jetpack = require('fs-jetpack');
25
+
26
+ const {
27
+ PROCESSING_RULES, SOCIAL_ICON_CONFIG, TEMPLATE_CONFIG, FAVICON_CONFIG,
28
+ } = require('./assets-config.js');
29
+ const { templateExportFiles, appIconFiles } = require('./derived.js');
30
+
31
+ const RESET_KINDS = ['logos', 'templates'];
32
+
33
+ /**
34
+ * The derived paths a kind owns, relative to the out dir. Both lists come
35
+ * from the shared name lib (derived.js) so a new rule/template/platform is
36
+ * covered without a second registry to update.
37
+ *
38
+ * @param {string} kind - A RESET_KINDS entry.
39
+ * @returns {string[]} Relative paths (dirs for whole-output operations,
40
+ * files where one dir holds more than one kind's output).
41
+ */
42
+ function kindPaths(kind) {
43
+ if (kind === 'templates') {
44
+ // Files, not dirs: `app/macos` also holds the icons operation's .icns
45
+ return Object.values(TEMPLATE_CONFIG).flatMap(templateExportFiles);
46
+ }
47
+
48
+ return [
49
+ ...Object.values(PROCESSING_RULES).map((rule) => rule.outputDir),
50
+ SOCIAL_ICON_CONFIG.outputDir,
51
+ FAVICON_CONFIG.outputDir,
52
+ ...appIconFiles().map((entry) => entry.file),
53
+ ];
54
+ }
55
+
56
+ /**
57
+ * The kinds a run asked to reset. Mirrors the `--migration` idiom: the bare
58
+ * flag means all of them, a value names one (or a comma list). An unknown
59
+ * kind throws, because a typo that quietly reset everything (or nothing) is
60
+ * worse than a stopped run.
61
+ *
62
+ * @param {boolean|string|undefined} flag - options.resetAssets.
63
+ * @returns {string[]} Kinds in RESET_KINDS order, deduped.
64
+ */
65
+ function resolveResetKinds(flag) {
66
+ if (!flag) {
67
+ return [];
68
+ }
69
+
70
+ if (flag === true) {
71
+ return [...RESET_KINDS];
72
+ }
73
+
74
+ const asked = String(flag).split(',').map((kind) => kind.trim()).filter(Boolean);
75
+ const unknown = asked.filter((kind) => !RESET_KINDS.includes(kind));
76
+
77
+ if (unknown.length > 0) {
78
+ throw new Error(
79
+ `Unknown --reset-assets kind(s): ${unknown.join(', ')}. `
80
+ + `Available: ${RESET_KINDS.join(', ')} (bare --reset-assets resets both).`,
81
+ );
82
+ }
83
+
84
+ return RESET_KINDS.filter((kind) => asked.includes(kind));
85
+ }
86
+
87
+ /**
88
+ * Clear the derived outputs of the given kinds.
89
+ *
90
+ * @param {object} args
91
+ * @param {string} args.outDir - The brand's `.omega/assets/`.
92
+ * @param {string[]} args.kinds - Kinds from resolveResetKinds().
93
+ * @param {boolean} [args.dryRun] - Report what would go, delete nothing.
94
+ * @returns {{ kinds: string[], removed: string[] }} The relative paths that
95
+ * existed (and, outside a dry run, are now gone).
96
+ */
97
+ function resetAssetsCache({ outDir, kinds, dryRun = false }) {
98
+ const removed = [];
99
+
100
+ for (const kind of kinds) {
101
+ for (const relative of kindPaths(kind)) {
102
+ const target = join(outDir, relative);
103
+
104
+ if (!jetpack.exists(target)) {
105
+ continue;
106
+ }
107
+
108
+ if (!dryRun) {
109
+ jetpack.remove(target);
110
+ }
111
+ removed.push(relative);
112
+ }
113
+ }
114
+
115
+ return { kinds, removed };
116
+ }
117
+
118
+ module.exports = { RESET_KINDS, resolveResetKinds, resetAssetsCache };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * SVG logo generator — wordmark and combomark SVGs via opentype.js
3
+ * text-to-path conversion. All text is converted to path outlines so the
4
+ * SVGs are self-contained (no font dependency at render time).
5
+ */
6
+
7
+ /**
8
+ * Generate a wordmark SVG (text-only logo).
9
+ *
10
+ * @param {string} brandName - The brand name text
11
+ * @param {Object} font - opentype.js Font object
12
+ * @returns {string} SVG markup
13
+ */
14
+ function generateWordmark(brandName, font) {
15
+ const fontSize = 72;
16
+ const fill = '#000000';
17
+
18
+ const path = font.getPath(brandName, 0, 0, fontSize);
19
+ const bbox = path.getBoundingBox();
20
+
21
+ const width = bbox.x2 - bbox.x1;
22
+ const height = bbox.y2 - bbox.y1;
23
+
24
+ // Translate path so it starts at origin
25
+ const translateX = -bbox.x1;
26
+ const translateY = -bbox.y1;
27
+
28
+ const pathData = path.toPathData(4);
29
+
30
+ return buildSvg(width, height, [
31
+ `<path d="${pathData}" fill="${fill}" transform="translate(${round(translateX)}, ${round(translateY)})"/>`,
32
+ ]);
33
+ }
34
+
35
+ /**
36
+ * Generate a combomark SVG (brandmark left, text right).
37
+ *
38
+ * @param {string} brandName - The brand name text
39
+ * @param {string} brandmarkSvg - Raw SVG content of the brandmark
40
+ * @param {Object} font - opentype.js Font object
41
+ * @returns {string} SVG markup
42
+ */
43
+ function generateCombomark(brandName, brandmarkSvg, font) {
44
+ const fontSize = 72;
45
+ const fill = '#000000';
46
+ const gapRatio = 0.3; // Gap between brandmark and text as fraction of brandmark height
47
+
48
+ const textPath = font.getPath(brandName, 0, 0, fontSize);
49
+ const textBbox = textPath.getBoundingBox();
50
+ const textWidth = textBbox.x2 - textBbox.x1;
51
+ const textHeight = textBbox.y2 - textBbox.y1;
52
+
53
+ const viewBox = parseBrandmarkViewBox(brandmarkSvg);
54
+ const brandmarkAspect = viewBox.width / viewBox.height;
55
+
56
+ // Scale brandmark to match text height
57
+ const brandmarkHeight = textHeight;
58
+ const brandmarkWidth = brandmarkHeight * brandmarkAspect;
59
+
60
+ // Layout: [brandmark] [gap] [text]
61
+ const gapWidth = brandmarkHeight * gapRatio;
62
+ const totalWidth = brandmarkWidth + gapWidth + textWidth;
63
+ const totalHeight = Math.max(brandmarkHeight, textHeight);
64
+
65
+ const brandmarkX = 0;
66
+ const brandmarkY = (totalHeight - brandmarkHeight) / 2;
67
+
68
+ const textOffsetX = brandmarkWidth + gapWidth - textBbox.x1;
69
+ const textOffsetY = (totalHeight - textHeight) / 2 - textBbox.y1;
70
+
71
+ const textPathData = textPath.toPathData(4);
72
+
73
+ const brandmarkInner = extractSvgInner(brandmarkSvg);
74
+ const viewBoxStr = `${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`;
75
+
76
+ return buildSvg(totalWidth, totalHeight, [
77
+ // Nested <svg> preserves the brandmark's viewBox so the renderer handles
78
+ // content scaling and centering automatically (no manual transform needed)
79
+ `<svg x="${round(brandmarkX)}" y="${round(brandmarkY)}" width="${round(brandmarkWidth)}" height="${round(brandmarkHeight)}" viewBox="${viewBoxStr}">`,
80
+ ...brandmarkInner.map((line) => ` ${line}`),
81
+ `</svg>`,
82
+ `<path d="${textPathData}" fill="${fill}" transform="translate(${round(textOffsetX)}, ${round(textOffsetY)})"/>`,
83
+ ]);
84
+ }
85
+
86
+ /**
87
+ * Build a clean, minimal SVG wrapper.
88
+ */
89
+ function buildSvg(width, height, innerContent) {
90
+ const w = round(width);
91
+ const h = round(height);
92
+
93
+ return [
94
+ `<?xml version="1.0" encoding="UTF-8"?>`,
95
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}" width="100%" height="100%">`,
96
+ ...innerContent.map((line) => ` ${line}`),
97
+ `</svg>`,
98
+ ``,
99
+ ].join('\n');
100
+ }
101
+
102
+ /**
103
+ * Parse brandmark SVG viewBox dimensions.
104
+ */
105
+ function parseBrandmarkViewBox(svgContent) {
106
+ const match = svgContent.match(/viewBox="([^"]+)"/);
107
+ if (!match) {
108
+ return { x: 0, y: 0, width: 100, height: 100 };
109
+ }
110
+
111
+ const [x, y, width, height] = match[1].split(/\s+/).map(Number);
112
+ return { x, y, width, height };
113
+ }
114
+
115
+ /**
116
+ * Extract inner content from an SVG (everything between the opening <svg>
117
+ * and closing </svg>). Preserves <g> groups, transforms, and all element
118
+ * types; strips comments and vendor-specific attributes.
119
+ */
120
+ function extractSvgInner(svgContent) {
121
+ const openMatch = svgContent.match(/<svg\s[^>]*>/);
122
+ if (!openMatch) {
123
+ return [];
124
+ }
125
+
126
+ const innerStart = openMatch.index + openMatch[0].length;
127
+ const innerEnd = svgContent.lastIndexOf('</svg>');
128
+ if (innerEnd <= innerStart) {
129
+ return [];
130
+ }
131
+
132
+ let inner = svgContent.slice(innerStart, innerEnd);
133
+
134
+ inner = inner.replace(/<!--[\s\S]*?-->/g, '');
135
+ inner = inner.replace(/<defs\s*\/>/g, '');
136
+ inner = inner.replace(/\s+vectornator:\w+="[^"]*"/g, '');
137
+ inner = inner.replace(/\s+xmlns:\w+="[^"]*"/g, '');
138
+ inner = inner.replace(/\s+xml:space="[^"]*"/g, '');
139
+ inner = inner.replace(/\s+opacity="1"/g, '');
140
+ inner = inner.replace(/\s+stroke="none"/g, '');
141
+
142
+ return inner.split('\n')
143
+ .map((line) => line.trim())
144
+ .filter((line) => line.length > 0);
145
+ }
146
+
147
+ /**
148
+ * Round to 2 decimal places (for positions/dimensions).
149
+ */
150
+ function round(n) {
151
+ return Math.round(n * 100) / 100;
152
+ }
153
+
154
+ module.exports = { generateWordmark, generateCombomark };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Convert an SVG to a pure black version — the source for the `black-*`
3
+ * logo variants (and macOS template images, which must be pure black with
4
+ * alpha so the system can invert them in dark mode).
5
+ *
6
+ * Replaces all fills and strokes with #000000:
7
+ * - Removes <defs> blocks (gradients, filters, patterns)
8
+ * - Converts fill="..." / stroke="..." attributes (fill="none" preserved)
9
+ * - Converts fill:... / stroke:... in style attributes (none preserved)
10
+ */
11
+
12
+ /**
13
+ * @param {string} svgContent - Raw SVG string
14
+ * @returns {string} SVG with all colors replaced by black
15
+ */
16
+ function convertSvgToBlack(svgContent) {
17
+ let svg = svgContent;
18
+
19
+ svg = svg.replace(/<defs>[\s\S]*?<\/defs>/gi, '');
20
+ svg = svg.replace(/<defs\s*\/>/gi, '');
21
+
22
+ svg = svg.replace(/\bfill="(?!none)[^"]*"/g, 'fill="#000000"');
23
+ svg = svg.replace(/\bstroke="(?!none)[^"]*"/g, 'stroke="#000000"');
24
+
25
+ // fill:url(#...), fill:#hex, fill:rgb(...), fill:colorname inside style="..."
26
+ svg = svg.replace(/\bfill\s*:\s*(?!none)[^;}"]+/g, 'fill:#000000');
27
+ svg = svg.replace(/\bstroke\s*:\s*(?!none)[^;}"]+/g, 'stroke:#000000');
28
+
29
+ return svg;
30
+ }
31
+
32
+ module.exports = { convertSvgToBlack };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Generate the web favicon set from the brandmark — the PNG ladder
3
+ * (favicon/apple-touch/android-chrome), a multi-size favicon.ico, and
4
+ * site.webmanifest — into `.omega/assets/favicon/`. Images are
5
+ * mtime-diffed against the brandmark; the webmanifest derives from
6
+ * config, so it's content-diffed instead.
7
+ */
8
+ const { join } = require('node:path');
9
+ const chalk = require('chalk').default;
10
+ const jetpack = require('fs-jetpack');
11
+ const sharp = require('sharp');
12
+ const png2icons = require('png2icons');
13
+ const { FAVICON_CONFIG } = require('../lib/assets-config.js');
14
+ const { faviconImageFiles, WEBMANIFEST_NAME } = require('../lib/derived.js');
15
+ const { isStale } = require('../../../lib/stale.js');
16
+
17
+ module.exports = async function writeFavicons(context) {
18
+ const { brandConfig, brandmarkPath, outDir, options } = context;
19
+ const dryRun = options?.dryRun || false;
20
+
21
+ const outputDir = join(outDir, FAVICON_CONFIG.outputDir);
22
+
23
+ const staleImages = faviconImageFiles().filter((name) => isStale(brandmarkPath, join(outputDir, name)));
24
+
25
+ const brandName = brandConfig.brand.name;
26
+ const desiredManifest = JSON.stringify({
27
+ name: brandName,
28
+ short_name: brandName,
29
+ icons: [
30
+ { src: '/android-chrome-192x192.png', sizes: '192x192', type: 'image/png' },
31
+ { src: '/android-chrome-512x512.png', sizes: '512x512', type: 'image/png' },
32
+ ],
33
+ theme_color: '#ffffff',
34
+ background_color: '#ffffff',
35
+ display: 'standalone',
36
+ }, null, 2);
37
+
38
+ const manifestPath = join(outputDir, WEBMANIFEST_NAME);
39
+ const manifestStale = jetpack.read(manifestPath) !== desiredManifest;
40
+
41
+ if (staleImages.length === 0 && !manifestStale) {
42
+ console.log(` ${chalk.green('✓')} Favicons in sync ${chalk.dim(`(${FAVICON_CONFIG.files.length + 2} files fresh)`)}`);
43
+ return { output: { favicons: { synced: true } } };
44
+ }
45
+
46
+ if (dryRun) {
47
+ const count = staleImages.length + (manifestStale ? 1 : 0);
48
+ console.log(` ${chalk.yellow('[DRY RUN]')} Would generate ${chalk.cyan(count)} favicon files`);
49
+ return { output: { favicons: { planned: count } } };
50
+ }
51
+
52
+ jetpack.dir(outputDir);
53
+ let generated = 0;
54
+
55
+ for (const file of FAVICON_CONFIG.files) {
56
+ if (!staleImages.includes(file.name)) {
57
+ continue;
58
+ }
59
+ await sharp(brandmarkPath)
60
+ .resize(file.size, file.size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
61
+ .png()
62
+ .toFile(join(outputDir, file.name));
63
+ generated++;
64
+ }
65
+
66
+ if (staleImages.includes('favicon.ico')) {
67
+ const sourcePng = await sharp(brandmarkPath)
68
+ .resize(512, 512, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
69
+ .png()
70
+ .toBuffer();
71
+ jetpack.write(join(outputDir, 'favicon.ico'), png2icons.createICO(sourcePng, png2icons.BICUBIC, 0, true));
72
+ generated++;
73
+ }
74
+
75
+ if (manifestStale) {
76
+ jetpack.write(manifestPath, desiredManifest);
77
+ generated++;
78
+ }
79
+
80
+ console.log(` ${chalk.green('✓')} Generated ${chalk.bold(generated)} favicon files`);
81
+ return { output: { favicons: { generated } } };
82
+ };