@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,14 @@
1
+ {
2
+ "name": "omega",
3
+ "owner": {
4
+ "name": "ITW Creative Works",
5
+ "url": "https://github.com/ITW-Creative-Works"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "omega",
10
+ "source": "./claude-plugin",
11
+ "description": "OMEGA framework knowledge for Claude — skills for the @omega.js packages, shipped beside the code they describe."
12
+ }
13
+ ]
14
+ }
package/LICENSE ADDED
@@ -0,0 +1,98 @@
1
+ Copyright (c) 2026 ITW Creative Works
2
+
3
+ Licensor: ITW Creative Works
4
+ Software: @omega.js/manager
5
+
6
+ Elastic License 2.0
7
+
8
+ URL: https://www.elastic.co/licensing/elastic-license
9
+
10
+ ## Acceptance
11
+
12
+ By using the software, you agree to all of the terms and conditions below.
13
+
14
+ ## Copyright License
15
+
16
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
17
+ non-sublicensable, non-transferable license to use, copy, distribute, make
18
+ available, and prepare derivative works of the software, in each case subject to
19
+ the limitations and conditions below.
20
+
21
+ ## Limitations
22
+
23
+ You may not provide the software to third parties as a hosted or managed
24
+ service, where the service provides users with access to any substantial set of
25
+ the features or functionality of the software.
26
+
27
+ You may not move, change, disable, or circumvent the license key functionality
28
+ in the software, and you may not remove or obscure any functionality in the
29
+ software that is protected by the license key.
30
+
31
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
32
+ of the licensor in the software. Any use of the licensor’s trademarks is subject
33
+ to applicable law.
34
+
35
+ ## Patents
36
+
37
+ The licensor grants you a license, under any patent claims the licensor can
38
+ license, or becomes able to license, to make, have made, use, sell, offer for
39
+ sale, import and have imported the software, in each case subject to the
40
+ limitations and conditions in this license. This license does not cover any
41
+ patent claims that you cause to be infringed by modifications or additions to
42
+ the software. If you or your company make any written claim that the software
43
+ infringes or contributes to infringement of any patent, your patent license for
44
+ the software granted under these terms ends immediately. If your company makes
45
+ such a claim, your patent license ends immediately for work on behalf of your
46
+ company.
47
+
48
+ ## Notices
49
+
50
+ You must ensure that anyone who gets a copy of any part of the software from you
51
+ also gets a copy of these terms.
52
+
53
+ If you modify the software, you must include in any modified copies of the
54
+ software prominent notices stating that you have modified the software.
55
+
56
+ ## No Other Rights
57
+
58
+ These terms do not imply any licenses other than those expressly granted in
59
+ these terms.
60
+
61
+ ## Termination
62
+
63
+ If you use the software in violation of these terms, such use is not licensed,
64
+ and your licenses will automatically terminate. If the licensor provides you
65
+ with a notice of your violation, and you cease all violation of this license no
66
+ later than 30 days after you receive that notice, your licenses will be
67
+ reinstated retroactively. However, if you violate these terms after such
68
+ reinstatement, any additional violation of these terms will cause your licenses
69
+ to terminate automatically and permanently.
70
+
71
+ ## No Liability
72
+
73
+ *As far as the law allows, the software comes as is, without any warranty or
74
+ condition, and the licensor will not be liable to you for any damages arising
75
+ out of these terms or the use or nature of the software, under any kind of
76
+ legal claim.*
77
+
78
+ ## Definitions
79
+
80
+ The **licensor** is the entity offering these terms, and the **software** is the
81
+ software the licensor makes available under these terms, including any portion
82
+ of it.
83
+
84
+ **you** refers to the individual or entity agreeing to these terms.
85
+
86
+ **your company** is any legal entity, sole proprietorship, or other kind of
87
+ organization that you work for, plus all organizations that have control over,
88
+ are under the control of, or are under common control with that
89
+ organization. **control** means ownership of substantially all the assets of an
90
+ entity, or the power to direct its management and policies by vote, contract, or
91
+ otherwise. Control can be direct or indirect.
92
+
93
+ **your licenses** are all the licenses granted to you for the software under
94
+ these terms.
95
+
96
+ **use** means anything you do with the software requiring one of your licenses.
97
+
98
+ **trademark** means trademarks, service marks, and similar rights.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @omega.js/manager
2
+
3
+ The OMEGA orchestration engine — omega-manager's brains, ported into the monorepo for the brand-monorepo world. `npx omega manage` at a brand root (the context-aware dispatcher hands brand roots here; the package's own direct bin is `omega-manager`, per the `omega-<framework>` convention) walks every service in dependency order and reconciles each one to the brand's `config/omega.json5`, **idempotently**: run it twice, get the same result. A bare `npx omega` prints help and touches nothing ([#229](https://github.com/Omega-JS-Stack/omega/issues/229)).
4
+
5
+ ```bash
6
+ npx omega manage # the whole walk: all services against the brand containing cwd
7
+ npx omega manage --service=update # one service
8
+ npx omega manage --dry-run # preview update's install/build work without running it
9
+ npx omega manage --continue-on-error # don't stop at the first failing service
10
+ npx omega manage --strict # preflight failures (missing env/scopes) fail hard instead of skipping
11
+ npx omega manage --reset-assets # force-refresh the derived assets cache (=logos or =templates for one kind)
12
+ npx omega manage --force # rebuild every target, ignoring the update service's incremental cache
13
+ npx omega manage --migration # audit the Firestore data migrations (=<name> for one); --execute writes
14
+ npx omega onboard # create (or converge) a brand — wizard in a TTY, derivation otherwise
15
+ # (incl. the managed-accounts step: keep the inherited list —
16
+ # company config or the support@{domain} default — or write your own)
17
+ npx omega deploy # DELIBERATE publish fan-out: each target's own deploy verb, backend first
18
+ # (--target= picks targets; every other flag forwards; docs/shared/deploys.md)
19
+ npx omega update # dependency-freshness fan-out: each target's own update verb (targets
20
+ # independent — one failure never blocks the rest; docs/shared/updates.md)
21
+ npx omega help # command listing (also bare `npx omega`, -h, --help)
22
+
23
+ # The COMPANY workspace (config/omega.json5 has a `brands` key) — one command each:
24
+ npx omega company init [path] # scaffold a company workspace (default: cwd; idempotent)
25
+ npx omega company adopt <brand-path> # stamp a brand so it inherits this company — the ONLY step it needs
26
+
27
+ # From a company root, the same verb runs every managed brand:
28
+ npx omega manage # all brands, all services
29
+ npx omega manage --brand=acme,zen # only these brands
30
+ npx omega manage --parallel # concurrent brands (--concurrency=N, default: CPU count)
31
+ ```
32
+
33
+ Works from the brand root, from inside any `targets/{dir}`, or from inside a backend's `functions/` dir — the brand root resolves by the same walk-up rule `@omega.js/config` uses. Run from a company root instead and the same manage fans out per brand (see [Company mode](#company-mode)).
34
+
35
+ ## Two homes, one log
36
+
37
+ | Location | Contains | Lifetime |
38
+ |----------|----------|----------|
39
+ | `config/omega.json5` | **Every provisioned fact** — user choices AND everything the run resolves (API-returned ids, zone ids, the confirmations no API can re-check). The same file every framework reads; no `.brands/` mirror to disperse | Committed, human-edited, machine-written (comment-preserving) |
40
+ | `.env` (brand root) | **Every secret** — loaded before any service runs; `@omega.js/config` hard-fails on secret-shaped keys in omega.json5 | Gitignored, per-machine |
41
+ | `.omega/runs/{ts}.json` | **Transient per-run output** (counts, status flags, errors) | One file per process |
42
+
43
+ The old third bucket — the durable CACHE of derived data `.omega/state.json` carried — is **retired** ([#434](https://github.com/Omega-JS-Stack/omega/issues/434)): it mostly duplicated what each idempotent ensure re-reads from the platform anyway, and it kept ids and secrets out of the homes the frameworks actually read. Brands that still carry that content convert with `npx omega manage --migration=state-retirement --execute`. The FILE lives on as the ONE per-machine RECORD file, sectioned per fact kind ([#479](https://github.com/Omega-JS-Stack/omega/issues/479)): its `deploy` section is `@omega.js/devkit`'s deploy record (written by every deploy verb, read by the testing service; the interim `.omega/deploys.json` of [#449](https://github.com/Omega-JS-Stack/omega/issues/449) folds into it on the first read or write), and future record kinds join as sibling sections. The migration removes only the sections it retires — every record section survives it untouched.
44
+
45
+ ## Service runner contract (ported verbatim from omega-manager)
46
+
47
+ Services declare operations in [src/config.js](src/config.js) `OPERATIONS`; handlers live in `src/services/{service}/{ensure,read,transform,write}/{operation}.js`. Handler returns are **strictly validated** — allowed top-level keys are `state`, `output`, `status`, `error` only; anything else throws. `state` is the WITHIN-RUN carry: it accumulates into each later operation's `serviceData` and is never written anywhere. `output` lands in the run file. A fact that must outlive the run goes to `config/omega.json5` via [src/lib/config-write.js](src/lib/config-write.js), or to the brand `.env` via [src/lib/env-secret.js](src/lib/env-secret.js) when it is secret-shaped. Statuses: `success` (✓), `warned` (⚠), `error` (✗), `skipped`.
48
+
49
+ **Run-mode gates are standardized** in [src/lib/run-gates.js](src/lib/run-gates.js) — never hand-compose them: `canPrompt(options)` (TTY **and** not dry-run — the only prompt gate), `dryRunPlan(message, result?)` (the canonical `⊘ Dry run — would <message>` line, optionally passing a handler return through for one-statement gates), and `needsInteractiveSkip(key, action, note?)` (the warned step-aside carrying the `needsInteractive` marker the run summary aggregates into its ⚑ section with per-service rerun hints).
50
+
51
+ **Env secrets gate through `ensureEnvSecrets`** ([src/lib/env-secrets.js](src/lib/env-secrets.js), cp114) — a service setup declares the vars its APIs need (`[{ name, label, url }]`): present → proceed; missing + interactive → masked ask, persisted to the brand `.env`, exported, run continues; missing + non-interactive → skip carrying `missingEnv`, which the run summary aggregates into its 🔑 section (exact keys + the interactive rerun command). Never hand-roll `process.env.X` skip checks in setups.
52
+
53
+ **Requirements are declared once, in the `REQUIRES` registry** ([src/config.js](src/config.js)) — per service, `requires`-style `{ env, scopes }` plus `why` (what the requirement buys) and `when(brandConfig)` gates (service-level and per-entry) mirroring the service's own config gate. Services with an `ensureEnvSecrets` gate reference these same entries, so every env NAME has one home; the `scopes` leg lists the Google OAuth scopes the service's API calls actually hit (each a member of google-auth's union — every consent grants the union).
54
+
55
+ **Preflight runs the registry before any service** ([src/lib/preflight.js](src/lib/preflight.js), modeled on cp236's google-auth 403 diagnostics): env presence (names only — values never print) and Google scopes against the token store's granted-scopes record — what IS knowable before a call; the live grant is only proven at call time, with the 403 diagnostics as the backstop. Failures print ONE consolidated walkthrough (what's missing, which service, why, the exact fix + mint URL, then the rerun verb) instead of N mid-run skips. Verdicts per failing service: **run** (interactive and the run itself collects the fix — the paste/consent flows), **skip** (the fix needs the operator; the walkthrough prints, the cycle continues, and the skip's `missingEnv` feeds the 🔑 aggregate), or **error** with `--strict`. Services without a `REQUIRES` entry are untouched — their needs are conditional in ways config can't see up front (per-provider payment keys, operator-only service accounts).
56
+
57
+ ## Services (ported so far)
58
+
59
+ | Service | Operations | What it ensures |
60
+ |---------|-----------|-----------------|
61
+ | `workspace` | structure, config, gitignore, scripts, agents, claude-settings, env-keys, env-order, translation-sdk | Root `targets/*` workspaces; a dir per enabled target (dir→target via declared `targets` in the dir's omega.json5, else `website*`/`backend*`/… dir conventions); brand + target configs load and validate; `.omega/` is gitignored; the root scripts speak `omega` (legacy `omega-manager` script VALUES healed in place with args preserved, a `deploy: 'omega deploy'` script guaranteed); the agent-docs chain (the `node_modules/@omega.js/AGENTS.md` link at the top-level omega map, the brand AGENTS.md import of it, the one-line CLAUDE.md pointer); the brand's committed `.claude/settings.json` registers the omega marketplace from the INSTALLED manager package and enables the plugin, so every session in the brand loads it — published installs only (a symlinked, locally linked manager is the local-era signal and the step skips), and no other setting is ever touched; the keys OMEGA generates for itself — the `OMEGA_*` trio plus `UNSUBSCRIBE_HMAC_KEY` — are minted into the brand `.env` when the cascade serves none ([#569](https://github.com/Omega-JS-Stack/omega/issues/569)): one SSOT (@omega.js/config's env schema — the entries carrying a `generated` function; [config.md](../../docs/shared/config.md)) shared with the onboard stub, so a brand onboarded before a key existed gains it on the next manage instead of discovering the hole at the first send; a value the company `.env` already serves is never shadowed, a minted value is published into the run's own env so the SAME walk's disperse composes it into `targets/backend/.env`, and the run names the key it minted, never the value; the brand .env (and the company .env when company-managed) converges to the canonical group order — rendered by `lib/env-order.js` from the env schema's groups (the ONE key inventory, [config.md](../../docs/shared/config.md)) and shared with the scaffold stub and every `writeEnvValue` writeback, machine comments regenerated, hand comments travelling with their key, duplicates collapsed to the dotenv winner (last occurrence), unknown keys kept in an Other section, and anything the parser doesn't recognize (multi-line values) left untouched; a web target whose resolved config translates with the `claude` provider declares `@anthropic-ai/claude-agent-sdk` (at the range `@omega.js/web` declares as its optional peer) and one `npm install` at the brand root puts it in place (already declared is a zero-mutation no-op, translation off or provider `chatgpt` is untouched, and disabling translation never removes the dep) ([translation.md](../../docs/shared/translation.md)) |
62
+ | `repo` | org, repo, pages | The brand's GitHub presence matches `repo.providers.github: {}` in omega.json5: org profile (name, support/billing email, description ≤160, blog; `location` only when configured; skipped whole for `shared` orgs), THE brand-monorepo repo (`repo.providers.github.repo` when typed, else the derived `<brand.id>-omega` of the `<brand.id>-<role>` rule; created empty when missing — you push, no clone; visibility + homepage diffed and patched), Pages on gh-pages + custom domain for web brands (a missing gh-pages branch = deploy-first guidance, not an error). Auth via the `gh` CLI (`gh auth login`, or `GH_TOKEN` in the brand `.env`). No `repo.providers.github.org` configured → clean skip. Repo identity is pure derivation from config (@omega.js/config's `brandRepo()`: the typed slug, else `<brand.id>-omega` under `repo.providers.github.org`) — nothing about it is persisted |
63
+ | `edge` | zone, dns-records, email-routing, zone-settings, cache-rules, rules-managed-transforms, rules-redirect, rules-configuration, rules-response-headers, rules-security, speed-scheduled-tests, workers | The zone matches `edge.providers.cloudflare`: zone created when missing (pending zones report their nameservers; interactive runs with a manual registrar open its nameserver page and poll until activation — API registrars defer to the domain service, non-interactive runs move on), platform DNS record set diff-synced (GitHub Pages A/AAAA, www, email-provider MX/SPF, DMARC; **company extras are config-gated, not hardcoded**: `dns.dmarcReports`, `dns.bimiLogo`, verification TXTs via `dns.records`; the SendGrid domain-auth set is read LIVE off SendGrid per run, never config — custom TXT records are additive and never suppress the SPF default), Email Routing forwarding rules when `domain.email.providers.cloudflare` (unverified destinations get a verification email; interactive runs open the dashboard and retry the rule once verified, others warn — rerun after verifying), ~40 zone settings diffed in one pass, the five ruleset families + managed transforms reconciled by rule name (stale rules removed), speed-test schedule, worker scripts + routes. Auth via `CLOUDFLARE_TOKEN` in the brand `.env`; no token → clean skip. Subdomain brands (brand.url below the apex) use the parent zone and only run zone + dns-records. Reads cache to `.omega/cache/cloudflare/{op}.json`; `zoneId` lands in state |
64
+ | `domain` | nameservers | The registrar's nameservers point at the Cloudflare zone. `domain.providers.namecheap` reconciles via the Namecheap API (`NAMECHEAP_USERNAME` + `NAMECHEAP_API_KEY` in the brand `.env`; already-set nameservers are a no-op; a domain not in the account yet warns and moves on); manual registrars (`'squarespace'`, anything else) print the values to set only while the zone is pending — an active zone proves they're already set. SLD/TLD split uses the public suffix list (omega-manager popped one label, breaking `.co.uk`-style TLDs). The email half of `domain` config is consumed by cloudflare's dns-records + email-routing ops |
65
+ | `cloud` | billing, services, project-settings, oauth-consent, service-account, hosting, firestore, database, authentication, storage, functions, cloud-messaging, sdk-config | The Firebase/GCP project matches `cloud: {}`: Blaze billing (**`cloud.billingAccount` is config — omega-manager silently linked a hardcoded company account**; unconfigured Spark projects warn with guidance), the 14 required Google Cloud APIs + compute deploy roles (diff-first — omega-manager batch-enabled every run), project display name + the 'Web App' web app (diffed, not blind-PATCHed), OAuth consent screen (`cloud.supportEmail`, default `support@{domain}`; its **branding page** — logo, home/privacy/terms links, authorized domains — has NO API either, so the run NAMES it as a manual step with the console link: links and authorized domains are safe anytime, a LOGO upload starts Google's verification review for External apps), the Admin SDK service account with diff-aware role grants and its once-only key (`.omega/secrets/service-account.json`, copied into the backend target's `functions/`), Hosting api.{domain} custom domains with ownership/ACME DNS written via Cloudflare in ONE pass (interactive runs then poll until Firebase verifies — writing any records it demands mid-poll; the ACME challenge appears once ownership passes — and finish by proxying the CNAME; non-interactive runs stay warned-pending and reruns converge), Firestore (nam5 + PITR), Realtime Database, Authentication (Identity Platform, email sign-in + privacy + anon auto-delete + password policy + authorized domains diffed; Google sign-in has NO Google API — instructions + warned until enabled; the OAuth redirect URIs (no API either) confirm interactively and stamp state, non-interactive runs warn), Storage, Functions readiness, FCM + the VAPID pair (missing keys are pasted in interactively with length validation and land in gitignored state; non-interactive runs warn), and the web SDK config (fetched to state with authDomain set to the BRAND host — first-party sign-in redirects under browser storage partitioning; the web build self-hosts Firebase's `/__/auth/*` handler files so the path resolves on the site domain; drift is written back into omega.json5 key-by-key via the comment-preserving editor — dry-run prints the paste-able block + warns instead). Auth: `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` in the brand `.env` (OAuth2 tokens cache to `.omega/auth/`; first run prints the auth URL); **sign every consent as the COMPANY account** — the consenting identity becomes the owner of every project the manager creates ([src/lib/google-auth.js](src/lib/google-auth.js) is the identity seam), so company ownership requires company consents; personal accounts are IAM members only, and [access-heal.js](src/services/cloud/lib/access-heal.js) repairs a wrong-identity project; no credentials → clean skip. `cloud.shared: true` runs only service-account + sdk-config |
66
+ | `captcha` | site-key | The brand's **OWN** classic reCAPTCHA keys in the brand `.env` (`RECAPTCHA_SITE_KEY` + `RECAPTCHA_SECRET_KEY`) actually work: the secret is **proven valid via the documented siteverify endpoint** (omega-manager only printed a checkmark); an invalid secret fails the service with `.env` guidance. A **half-keyed brand fails too** ([#507](https://github.com/Omega-JS-Stack/omega/issues/507)): `RECAPTCHA_SECRET_KEY` set without `captcha.providers.recaptcha.siteKey` in config (the public half the client renders) — or that site key set without the secret — is a silent 403 on every protected POST, so the one place that sees both halves fails loudly with the console link instead of proving the secret and calling the brand green; NEITHER half is the sanctioned unkeyed brand and stays green ([#17](https://github.com/Omega-JS-Stack/omega/issues/17)). De-ITW: no default/shared key exists anywhere — missing keys → interactive runs ASK via the paste flow, whose walkthrough mints the key at the **GCP reCAPTCHA console** (`console.cloud.google.com/security/recaptcha`) in the brand's own project, never a company-shared key (non-interactive → clean skip). Classic reCAPTCHA has no key-management API, so the key's domain list stays printed guidance — `{domain}` + `www.{domain}` + the console link (`captcha.providers.recaptcha.project` deep-links the Cloud Console key page; **omega-manager hardcoded the company project**). Interactive runs open the console, confirm the domain list once, and stamp it in config at `captcha.providers.recaptcha.domainsConfirmed` — the state file is retired ([#434](https://github.com/Omega-JS-Stack/omega/issues/434)); a changed brand domain re-prompts |
67
+ | `analytics` | google-streams, google-firebase-link, meta-pixel, tiktok-pixel | The brand's analytics match `analytics.providers`: one GA4 **web data stream per enabled target** (web → the root domain, backend → `api.`, desktop/extension/mobile → virtual subdomains; found by URI, renamed on drift, enhanced measurement **diffed before patching** — omega-manager blind-PATCHed every run — and a clean Measurement Protocol secret each, regenerated until dash/underscore-free; GA's data-collection acknowledgement has no API → warned with the settings URL, rerun converges), the **GA property ↔ Firebase project link** (wrong-property links are moved to the configured property; a property linked to someone else's project warns; the project NUMBER comes from the cloud service's state — no second client; "link still propagating" → warned, rerun converges), and the **Meta/TikTok pixels** — created when missing and then token-checked ([#417](https://github.com/Omega-JS-Stack/omega/issues/417)). **Meta asks for nothing up front** (Ian 2026-08-21 — the GA4 half's near-zero-input standard applied to the pixel): an interactive pass leads with the uniform Yes / Skip / **Disable** gate, then walks to the page that mints the system-user token — the URL is printed and **Enter opens it**, asked every time, never auto-opened — takes the paste-in that saves `META_ACCESS_TOKEN` into the brand `.env`, and asks that token which **ad accounts** it can see (`GET /me/adaccounts`): exactly one is auto-selected with no prompt, several is a pick (brand matches first, with a "No Meta Pixel" opt-out in the list), none warns with the assign-an-asset fix. The resolved account lands in `analytics.providers.meta.accountId`, the pixel is created on it, and its id lands too — all in ONE run, so a brand configures Meta by saying Yes. With `analytics.providers.{meta,tiktok}.accountId` already in config (the Meta AD ACCOUNT / the TikTok ADVERTISER — non-secret platform ids live in config beside `google.accountId`, never in `.env`) and no `id` yet, the pixel is found BY NAME (the brand name) on the account before anything is created, then created via Meta's Marketing API (`POST /act_<id>/adspixels`) or TikTok's Business API (`POST /open_api/v1.3/pixel/create/`), and the resulting id is written back into omega.json5 (`analytics.providers.{provider}.id`, comment-preserving) so the same pass reports the pixel it just made; a configured id is converged proof and the platform API is never called. **The access token is the gate for both halves** (`META_ACCESS_TOKEN` / `TIKTOK_ACCESS_TOKEN` in the brand `.env` — the names @omega.js/backend reads; ONE token per platform serves both the create and the conversions sender, and Meta's is a Business Manager **system-user** token with `ads_management`): no token → warned with the where-to-get guidance and nothing is called, never a failure — and a run that cannot ask (no TTY, dry run) with nothing configured stays silent instead of nagging. **`analytics.providers.meta: false` is the off switch**: the tri-state opt-out (the gate's Disable and the picker's opt-out both write it) stops every call, prompt and warning for that provider — delete the line to be asked again. **TikTok is the SCAFFOLD half** (Ian 2026-08-21): the client, the config slot, and the wiring are complete and the token flips it on, but TikTok's app is not provisioned yet, so no brand carries the key and the create path has never run against the live API — it gets no token-page walk and no advertiser discovery until then, so its create still waits for a configured `accountId`. Pixel-token checks are unchanged for a configured id — missing → interactive runs offer the same guided paste-in that saves the token to the brand `.env` (the disperse service carries it into the backend's `functions/.env`), while leaving it empty, non-interactive, and dry runs keep the warned where-to-get guidance. Google auth: `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` (tokens cache to `.omega/auth/google-analytics-tokens.json` — separate scope from firebase). `analytics.providers.google.propertyId` is **required config** — interactive runs offer the account + property selection/creation flow (create-new provisions the GA4 property via the Admin API with the config time zone/currency) and land both ids in omega.json5; a company-managed brand inherits the **company's `analytics.providers.google.accountId`** through the merge chain, so setup notes "defaulting to company account" instead of prompting the account picker (an explicit brand-level `accountId` always wins; the picker stays the fallback when no company default exists); without it (or without credentials) the google operations are filtered out and the pixel half still runs. Per-target `measurementId` + `apiSecret` land in state as `streams.{target}`, and each stream's **measurement id also lands in config** at `targets.{target}.analytics.providers.google.id` — the per-surface override every framework reads through the merge chain (the same shape the `monitoring` service uses for its DSNs; the resolved value wins, so a stale hand-set id is patched and a converged rerun leaves the file byte-identical). Until [#417](https://github.com/Omega-JS-Stack/omega/issues/417) the ids only ever reached state, so a brand's `analytics.providers.google.id` stayed null and each target's Measurement Protocol secret had no measurement id of its own stream to pair with |
68
+ | `search` | property, ga-link, sitemaps | Search Console matches the brand: the **domain property** (`sc-domain:{domain}` — covers every subdomain) exists, verified in ONE pass when missing (DNS_TXT token → TXT record via Cloudflare with stale google-site-verification records replaced → verify — interactive runs poll until DNS propagates, non-interactive runs verify once with still-propagating DNS → warned, rerun converges; no Cloudflare token → the record to add manually; subdomain brands verify at their label in the apex zone); the **GA association** has NO API on either side — warned with the associations URL until confirmed — in a TTY the run asks and stamps `gaLinked` in state; non-interactive runs keep warning; **sitemaps** (`search.providers.searchConsole.sitemapPaths`, default `/sitemap.xml`) submitted only when MISSING — omega-manager resubmitted existing ones every run; brands without a web target skip submission. Auth: the same `GOOGLE_CLIENT_ID`/`GOOGLE_CLIENT_SECRET` (own token cache — webmasters + siteverification scopes). omega-manager's dead `searchConsole.subdomains` config key was dropped (the section is `search.providers.searchConsole` now) |
69
+ | `advertising` | sites | The brand's domain is present in the configured AdSense account, with its approval state reported: `READY` = converged success; `GETTING_READY`/`REQUIRES_REVIEW`/`NEEDS_ATTENTION` warn with what Google is waiting on. The Management API v2 is **read-only** — no site add/config writes exist — so interactive runs open the add-site console page and poll until the domain appears; non-interactive runs warn with the exact deep-link and the rerun converges once it appears. `advertising.providers.adsense.client` (ca-pub-…) is required config — the provider-neutral advertising section, never a brand-named top-level key; the entry's PRESENCE is the opt-in (**omega-manager defaulted the account to the company's shared one**). Auth: the same `GOOGLE_CLIENT_ID`/`GOOGLE_CLIENT_SECRET` (adsense.readonly scope, own token cache); missing → clean skip |
70
+ | `monitoring` | projects, dsn | One error-monitoring project per enabled target (web/backend/desktop/extension), reconciled against the Sentry API (**new capability — omega-manager had no monitoring service; DSNs were hand-set**). Org resolution: `monitoring.providers.sentry.org` from config wins, else the token's single org is used and written back (self-heal); multi-org tokens without config warn with guidance, and every org-scoped call follows the org's `links.regionUrl` (multi-region SaaS). Projects are `{brand.id}-{target}` under a `{brand.id}` team (ensured on first need) with per-target platforms (web/extension `javascript`, backend `node`, desktop `electron`); existing slugs are converged proof — nothing renamed or deleted. The `dsn` operation fetches each project's active client key and lands it in `targets.<type>.monitoring.providers.sentry.dsn` via the comment-preserving writeback — the exact key every framework's runtime reads through the config merge chain (DSNs are public by design; a hand-set stale DSN is drift and gets patched). Gates: a `monitoring.providers.sentry` entry (presence IS the pick, #425) + `SENTRY_AUTH_TOKEN` in the brand `.env` — a PERSONAL auth token with `org:read`, `project:read`, `project:write`, `team:read`, `team:write` (Sentry org tokens are CI-scoped and cannot create teams/projects); missing → clean skip with the 🔑 aggregate naming it |
71
+ | `campaigns` | domain-auth, link-branding, sender-identity, list, unsubscribe-groups, custom-fields, segments, event-webhook, contact-person | The brand's email-marketing stack matches `marketing.campaigns` (provider key `sendgrid`): **domain authentication** created in one pass when missing (SendGrid's 3 DKIM/bounce CNAMEs diff-synced into the Cloudflare apex zone — exact match untouched, wrong content patched — then validated: interactive runs poll until DNS propagates, non-interactive runs validate ONCE with still-propagating DNS → warned, rerun converges; no Cloudflare token → the records to add manually, and validation still runs so a manual fix converges); a **verified sender** for Single Sends (`offers@{contact domain}`, unverified leftovers recreated) — CAN-SPAM's physical address comes from `brand.address`, **required config: omega-manager silently stamped the company's mailing address on every brand**; the brand's **marketing list** resolved config → state → name → create (the resolved id is written back into omega.json5 — `marketing.campaigns.providers.sendgrid.listId` — and mirrored in state); **custom fields** and **segments** from @omega.js/backend's marketing SSOT (required through the workspace — no filesystem climb into a sibling repo; type mismatches recreated, stale `query_dsl` patched in place with delete+recreate fallback, leaked `__temp_` segments swept, non-@omega.js/backend fields/segments never touched); and the **account-global Event Webhook** pointed at the parent @omega.js/backend's forwarder (`parent` in omega.json5, `'self'` for the parent brand — **omega-manager defaulted it to the company URL**; consent toggles enforced, tracking toggles untouched, drift patched with the minimum diff; needs `OMEGA_WEBHOOK_KEY`); and **`brand.contact.person.name`**, the human @omega.js/backend's welcome, discount-nudge and checkup emails sign off as — missing → the walk FAILS naming the key, instead of leaving three sends to throw on the first live signup. Auth via `SENDGRID_API_KEY` in the brand `.env`; missing → clean skip |
72
+ | `newsletter` | publication, custom-fields, segments, webhook | The brand's newsletter matches `marketing.newsletter` (provider key `beehiiv`): the **publication** resolved config id → state id → auto-match by brand name (publications have no create API — nothing matching prints the exact name/description/subdomain values to copy into the dashboard + warned; interactive runs then open the create page and poll until the new publication auto-matches (non-interactive/dry runs stay warned); the resolved id is written back into omega.json5 — `marketing.newsletter.providers.beehiiv.publicationId` — with a state mirror); **custom fields** from @omega.js/backend's marketing SSOT, diffed by display name (Beehiiv matches subscriber values by display; each provider's view of the catalog comes from the SSOT's own `fieldsForProvider()`, skip lists included), kind mismatches recreated; **segments** — **Beehiiv has no segment-create API**: the API side only reads, so missing ones warn with human-readable conditions, and interactive runs offer to create them by driving the dashboard UI through the companion Chrome extension (trusted-CDP automation over `extension/`'s WebSocket protocol; conditions needing Beehiiv's built-in Signup-date attribute fail with the exact manual steps) or to open the dashboard for manual creation — either way the operation **re-lists afterwards**, so success means Beehiiv reports every segment (non-interactive/dry runs keep the warn and never mutate); the **publication webhook** points at the parent @omega.js/backend's forwarder (publications can be shared across sibling brands, so the parent fans events out), matched by its managed description first so it survives parent moves, drift patched with the minimum diff (needs `OMEGA_WEBHOOK_KEY`). Auth via `BEEHIIV_API_KEY` in the brand `.env`; missing → clean skip |
73
+ | `payment` | paypal-account, paypal-webhook, paypal-products, stripe-account, stripe-radar, stripe-disputes, stripe-webhook, stripe-products, chargebee-account, chargebee-webhook, chargebee-products | The brand's payment providers match `payment.products` (priced, non-archived products only). **Stripe**: the account's business profile diffed to the brand (name/url/support email — unsupported account types warn instead of erroring; `updateAccountInfo: false` opts out), **products + prices** resolved config id → state → **metadata match** (`{ brandId, productId }` stamped on every product we create — lost state self-heals without duplicates) → create, with wrong-amount actives archived (Stripe can't delete prices) and the correct price created; the **webhook** matched by URL, re-enabled when Stripe auto-disabled it, `enabled_events` diffed; **Radar rules and Enhanced Dispute Protection have NO API** — printed as guidance + Dashboard deep-links, then confirmed interactively in a TTY (state-stamped `radarConfirmed`/`disputesConfirmed`); non-interactive runs stay warned. **PayPal**: live-vs-sandbox auto-detected by the auth probe; catalog products resolved config → state → **exact-name match** → create; **billing plans** matched by interval + amount + trial with duplicates and stale plans deactivated; legacy products' plans deactivated (`paypal.legacyProductIds`); webhook event_types diffed via JSON Patch. **Chargebee**: fully **deterministic IDs** (family = brandId, item = `{brandId}-{productId}`, price = `…-{interval}`) so resolution needs no stored state; item fields diffed, price amounts updated in place, legacy plans reported read-only; webhook URL carries `&brand=` (shared sites serve multiple brands). All webhooks point at `api.{domain}/omega/payments/webhook` (need `OMEGA_WEBHOOK_KEY`; `cloud.shared` brands skip them — no brand API exists), and every provider keeps **exactly one endpoint on that host**: any other endpoint whose URL carries the same host + webhook path (omega-manager's `?processor=` twin, an endpoint minted with a rotated key) is stale — deleted with one loud line naming the redacted URL, since it received every event and answered `400 Missing provider parameter` forever ([#570](https://github.com/Omega-JS-Stack/omega/issues/570)). Endpoints on OTHER hosts are never touched: the account may run whatever else it likes. Product images come from `brand.images.brandmark` — **omega-manager hardcoded the company CDN**; the company Stripe org ID default is gone too. Auth per provider: `STRIPE_SECRET_KEY` / `paypal.clientId` + `PAYPAL_CLIENT_SECRET` / `chargebee.site` + `CHARGEBEE_API_KEY` (a provider set to `false` in config is off — the setup flow's Disable answer writes that; interactive runs offer the key-entry flow when an enabled provider is missing credentials: public keys land in omega.json5, secrets in the brand `.env` + `process.env` so the same run proceeds); no provider configured → clean skip. `--provider=stripe\|paypal\|chargebee` narrows the run. Product IDs are written back into omega.json5 (`payment.products[id=…].{stripe,paypal}.productId`) and mirrored in state |
74
+ | `forms` | form, user | The brand's Slapform contact form (slapform.com) matches the brand — a **Slapform-operator integration** that writes into Slapform's own Firestore, via `SLAPFORM_SERVICE_ACCOUNT` in the brand `.env` (a path to the Slapform Firebase project's service-account JSON, absolute or brand-root-relative — **omega-manager read the company-mode `.output/slapform/secrets/`**; the client is plain Firestore REST + a service-account JWT, no firebase-admin dependency). The **form** document (`forms.providers.slapform.formId` — with the operator SA + `forms.providers.slapform.templateFormId` (the company layer's shape donor), a missing id MINTS the brand's OWN form: product user (email = brand contact email, password via the account service's owner channels) + doc shape-templated from the donor with the embedded `id` re-pointed, id written back into omega.json5, converged by the ensures in the same run (2b); interactive runs still offer the paste-back setup flow — Disable writes `forms.providers.slapform: false`; `SLAPFORM_API_KEY` is recognized as the future product-API tier) is diff-synced on name + enabled — omega-manager merge-wrote it on every run and silently created a name-only orphan document when the id was wrong; a missing form is now a visible error. The **form-owner account** (the form's `owner` UID) is set to `forms.providers.slapform.plan` (default: Slapform's Grandmaster top tier — **omega-manager resolved it from the slapform brand's `.brands/` config, a company-mode read**) as an internal comp, patched with a leaf-field mask so Slapform-written subscription fields (trial, cancellation flags) survive. Missing formId or service account → clean skip; brands without a web target skip too (the form lives on the website) |
75
+ | `chat` | chat, user | The brand's support chat agent on Chatsy (chatsy.ai) matches the brand — the forms pattern on Chatsy's Firestore (`CHATSY_SERVICE_ACCOUNT` in the brand `.env`, same shared REST client). The **agent** document (`inbound.chat.providers.chatsy.agentId` — with the operator SA + `inbound.chat.providers.chatsy.templateAgentId`, a missing id MINTS the brand's OWN agent the same 2b way as forms, id written back; interactive paste-back still offered — Disable writes `inbound.chat.providers.chatsy: false`; `CHATSY_API_KEY` recognized as the future product-API tier) is diff-synced on name, welcome message, language, auto-translate, brand details, and **knowledge**: the packaged baseline (support policies with the brand's URL/description filled in + pricing **generated from `payment.products`** — free/limits/trials formatted, archived skipped) plus the brand repo's `config/chatsy.md` appended when present (omega-manager read `.brands/{id}/chatsy.md`). Patches are leaf-masked so Chatsy-owned fields (owner, id, metadata) survive; a missing agent is a visible error. **De-ITW'd**: the agent image comes from `brand.images.brandmark` (omega-manager hardcoded the company CDN; no brandmark → the image isn't managed), the baseline's sponsorship line is `inbound.chat.providers.chatsy.sponsorshipsUrl` config (default `{website}/contact` — omega-manager hardcoded the company page), and a real omega-manager bug died in the port: it replaced `{website}` before inserting the generated pricing, so every agent's knowledge shipped with a literal `{website}/pricing`. The **agent-owner account** is set to `inbound.chat.providers.chatsy.plan` (default: Chatsy's Max top tier — the company-mode `.brands/` read became config) via the shared owner-plan reconciliation. `inbound.chat.providers.chatsy.updateAgentInfo: false` skips the service (a shared agent managed by another brand); missing agentId or service account → clean skip; no web target skips too |
76
+ | `email` | agent, user | The brand's customer-service email agent on Replyify (replyify.app) matches the brand — the forms/chat pattern on Replyify's Firestore (`REPLYIFY_SERVICE_ACCOUNT` in the brand `.env`, same shared REST client), gated on the **backend** target (the agent answers the brand's support email). The **agent** document (`inbound.email.providers.replyify.agentId` — with the operator SA + `inbound.email.providers.replyify.templateAgentId`, a missing id MINTS the brand's OWN agent the same 2b way as forms, id written back; interactive paste-back still offered; `REPLYIFY_API_KEY` recognized as the future product-API tier) is diff-synced on name, **Gmail filter query** (the brand filter from `config/replyify.md`'s `---filter---` section, or auto-generated `to:(@domain)`, ANDed with the baseline exclusions for transactional addresses), brand details, and **knowledge**: the packaged baseline support policies plus the file's `---knowledge---` section appended (omega-manager read `.brands/{id}/replyify.md`; all four file formats supported). Patches are leaf-masked so Replyify-owned fields survive; a missing agent is a visible error. **De-ITW'd hard**: omega-manager's baseline shipped the company's entire sponsorship business block (guest-post rules, the company sponsorship URL, its WELCOME10 code) and a hardcoded GIFT15 discount to every brand's agent — the sponsorship block is **gone from the package** (company business prose belongs in `config/replyify.md`), and the discount section renders only when `inbound.email.providers.replyify.discount { code, label }` is configured, so agents can never invent a code. The **agent-owner account** is set to `inbound.email.providers.replyify.plan` (default: Replyify's Max top tier — the company-mode `.brands/` read became config) via the shared owner-plan reconciliation. `inbound.email.providers.replyify.updateAgentInfo: false` skips the service (shared agent); missing agentId or service account → clean skip |
77
+ | `server` | brands | The brand's registry entry on the **company server's** Firestore (`brands/{brand.id}`) matches config — for operators whose parent backend keeps a registry of the brands it serves (webhook fan-out, cross-brand features). Only the whitelisted top-level sections cross (`brand`, `github`, `sponsorships`) and the document is **replace-synced**: read first, rewritten only on drift — where drift includes a leftover key in the registry, since a full replace removes keys dropped from config (omega-manager's `merge: false` semantic, but it overwrote the document blindly on every run with no dry-run guard, hardcoded the company project `itw-creative-works`, and read company-instance secrets from `.output/`; the port takes `SERVER_SERVICE_ACCOUNT` in the brand `.env` — same shared REST client, which gained a `setDoc` full-replace method here). No service account → clean skip |
78
+ | `directory` | entry | The brand's own entry in the **PARENT project's** `brands` collection (`brands/{brand.id}`) — a PUSH, so a brand migrated onto OMEGA keeps its listing current from its own omega.json5 instead of from a central config store the way legacy omega-manager wrote it ([#246](https://github.com/Omega-JS-Stack/omega/issues/246)). **Opt-in and generic**: three clean-skip gates — `directory.enabled: true` (absent config never pushes; the parent declares the collection world-readable in its own rules, so participation is never implicit), a `parent` naming the relationship, and not a `demo-*` brand (the cloud service's emulator-only gate). The payload is brand identity (`brand.{id,name,url}`) plus repo slugs from `@omega.js/config`'s ONE derivation (`{ owner, name, repo }`, the same value the backend exposes as `config.resolved.github` — omitted rather than pushed half-resolved) plus the opt-in **BLOCKS** the brand declares; `sponsorships` (`acceptable`, `unacceptable`, `prices` per placement type) is the first, and the next is one entry in `lib/blocks.js` plus a schema line. Read first, written only on drift, and the write is a **merge** with an updateMask over the framework-owned sections — unlike `server`'s replace, because the hub keeps its own fields on the same document and the framework owes only the entry (a section dropped from config is still removed: its path stays in the mask). Auth is `DIRECTORY_SERVICE_ACCOUNT` in the brand `.env` (path to the parent project's service-account JSON) — no service account → clean skip. Config shape, entry shape and the legacy→doc field mapping: [docs/manager/directory.md](../../docs/manager/directory.md) |
79
+ | `assets` | logo-gen, process, templates, icons, social-icons, favicons | The brand's derived visual collateral generated **locally** (no external API) from its logo sources — `assets/logo/*.svg` in the brand repo (committed collateral; omega-manager read `.brands/{id}/assets/`) into the gitignored `.omega/assets/` (omega-manager's `.output/{id}/assets/`). **logo-gen**: wordmark + combomark SVGs from the brandmark + brand name + `brand.font` via opentype.js text-to-path (missing-only — a hand-tuned file is never overwritten; **de-ITW'd: omega-manager packaged the company's commercial fonts and defaulted every brand to CromaSans** — the port ships no fonts, `brand.font` resolves from the brand's `assets/fonts/` or system dirs; unset → noted and skipped, configured-but-missing → error). **process**: color + all-black SVG variants and PNG size ladders per source. **templates**: brand-editable PSDs at `assets/templates/{name}.psd`, seeded on first run from the company root's `assets/templates/` (**de-ITW'd: omega-manager baked ITW's binary templates into its own `src/defaults/`**) — logo layers re-rastered from the brandmark (black variant for the macOS tray template) and text layers filled from config with the font auto-shrunk to fit, via ag-psd + node-canvas, then composited to PNG exports (og-image, app icons, Chrome-store promos); manual Photoshop edits persist and re-export on the next run (replaced TEXT renders after the PSD is opened + saved once — PSDs store per-layer rasters; the logo layers are re-rastered here so they're always current). **icons**: macOS `.icns` + Windows `.ico` (from the templates-composited icon.png when present, brandmark otherwise). **social-icons**: brandmark on white for profile pictures. **favicons**: the web favicon set + `site.webmanifest` (content-diffed against config). Every operation is **mtime-diffed** — only missing/stale outputs regenerate — which replaced omega-manager's `--onboarding` gate on the write ops (it regenerated blindly with no dry-run guard). **`--reset-assets`** ([#214](https://github.com/Omega-JS-Stack/omega/issues/214)) forces the rebuild timestamps would skip: it clears the derived cache first, so the same walk regenerates it. Bare resets both kinds; `--reset-assets=logos` clears the logo variants + app icons + social icons + favicons, `--reset-assets=templates` the PSD exports, and the run names what it cleared. Only `.omega/assets/` is cache: the brand's committed `assets/logo/*.svg` and `assets/templates/*.psd` sources are never touched (omega-manager's `--reset-logos` / `--reset-templates`, ported). No brandmark → the **AI brandmark generation** runs first when MrLogo credentials are present (ZERO config options — MrLogo is a sibling ITW product, so the endpoint is a code constant and auth rides the same ladder as the product services: `MRLOGO_SERVICE_ACCOUNT` ensures the brand's OWN MrLogo product user and calls with its `api.privateKey` · `MRLOGO_API_KEY` uses an existing account's key directly (BEM auth resolves a non-JWT Bearer by `users.api.privateKey` — verified against the live route) · `LOGO_API_ID_TOKEN` is the pasted-ID-token escape hatch (expires hourly); an optional creative-direction prompt rides the request and the returned SVG lands as committed `assets/logo/brandmark.svg`), otherwise a clean skip with guidance. **Not ported — dead code**: omega-manager's social-images/store-images write ops iterated template names (`og-image`, `chrome-small`, …) that never matched its TEMPLATE_CONFIG keys (`social-og-image`, `store-chrome-promo-small`, …), so they could never generate anything; their intended outputs are the templates operation's `social/og-image.png` + `store/chrome/promo-*.png` exports |
80
+ | `certificates` | api-key, certificates, bundle-ids, profiles | Apple code-signing for brands with `desktop`/`mobile` targets, reconciled via the App Store Connect API (ES256 JWT over node:crypto — no SDK). Signing certs live in the SIGNING TREE — `{companyRoot||brandRoot}/.omega/certificates/apple/`: one Apple account signs everything a company ships, so company-managed brands (the `.omega/company.json` marker) share the company workspace's material (**omega-manager's shared-set model reborn, keyed by the marker instead of a hardcoded ITW instance**) while standalone brands keep it brand-local; certs download there or are created via CSR — the CSR private key is **preserved across runs** because it pairs with the issued cert; `.p12` exports are mtime-diffed against their `.cer` and import into the macOS login keychain non-interactively (trusted-tool ACLs + partition list). Manual types (`DEVELOPER_ID_*_G2` — Apple requires Account Holder login) validate the local `.cer` via openssl; when missing, **interactive runs get a full walkthrough** (`lib/manual-walkthrough.js`): the pipeline stages its own CSR (a picker-friendly `.certSigningRequest` copy lands in Downloads), opens the portal's create page Enter-gated, then watches Downloads for the issued `.cer` — accepting it only when it modulus-pairs with the staged key AND its CN names the expected type — before installing/exporting/importing like any other cert. Non-interactive runs keep printed guidance + converge-on-rerun (omega-manager auto-opened the browser but still sent users to Keychain Access for the CSR; expired-agreements handling still prints the URL). A downloaded cert **without its paired local key warns** on the `.p12` skip instead of silently not exporting. Bundle ID = `certificates.providers.apple.bundleIdPrefix` + `brand.id` with dashes as dots (`com.itwcreativeworks` + `omega-playground` → `com.itwcreativeworks.omega.playground`; the prefix is reverse-DNS config the onboard wizard derives from the company/brand domain — **de-ITW'd: omega-manager hardcoded the company prefix**) with capability reconciliation (Sign in with Apple consent block); provisioning profiles per platform × cert type download to `.omega/certificates/apple/profiles/`. Needs `APPLE_API_ISSUER`/`APPLE_API_KEY_ID`/`APPLE_TEAM_ID` in the brand `.env` + an `AuthKey_*.p8` — a missing .p8 gets its own interactive rescue (Enter-gated open of the App Store Connect keys page, then the fresh `AuthKey_*.p8` is detected in Downloads and FILED into the signing tree; each .p8 downloads ONCE, so losing it to Downloads clutter is the failure mode this kills); `CSC_KEY_PASSWORD` auto-generates and persists to the SIGNING ROOT's `.env` on first run (the company `.env` when shared — the env chain loads it under every sibling brand). omega-manager's `--force-recreate` flag was not ported (delete the local `.cer` to force a re-download; expired certs recreate automatically) |
81
+ | `ai` | keys | The AI provider credentials the backend needs — `OPENAI_API_KEY` and `ANTHROPIC_API_KEY` ([#639](https://github.com/Omega-JS-Stack/omega/issues/639)). It provisions nothing: there is no AI platform API to reconcile against, so the whole service is the shared setup contract's gate — a brand that wants AI pastes both keys mid-walk, a brand that does not answers Disable once (`ai.enabled: false`). ONE name per provider: the legacy `OMEGA_*` twins are gone and a company-wide key is simply the company `.env` layer of the cascade under that same name. Both are OPTIONAL (`gates: false`), so preflight never blocks a run on them and a brand using one provider is never nagged about the other. It runs BEFORE disperse, so the keys are in the brand `.env` when disperse composes the backend target's own |
82
+ | `disperse` | certs, env | The remnant of omega-manager's disperse after the config hierarchy dissolved file dispersal — targets read `config/omega.json5` directly, so the old repos/products/pricing-md/cdn config writes have no counterpart; what can't ride the hierarchy still moves, right after `certificates` and before `update` builds. **certs**: signing artifacts copied from the signing tree — `{companyRoot||brandRoot}/.omega/certificates/apple/`, the same resolution as the certificates service (**de-ITW'd: omega-manager pulled from the company instance's shared `.output/_shared/` tree; the company share is back, marker-keyed**) — into every desktop target's `config/certs/` (EM v1.4.1+ layout) and mobile target's `build/certs/` — byte-compared so a converged run rewrites nothing, optional rules (installer p12, provisioning profiles) skip silently while required misses warn, an unset `{env.APPLE_API_KEY_ID}` placeholder warns instead of resolving to a nonsense `AuthKey_.p8`, no artifacts at all (or `certificates.enabled = false`) is a quiet note rather than a warning, and every certs dir gets a self-protecting `.gitignore` (`*`) so signing material can never be committed even before the framework's `mgr setup` writes its own. **env**: each target's gitignored `.env` composed — secrets hard-fail in omega.json5 by design, and two values genuinely differ per target under one name: `GOOGLE_ANALYTICS_SECRET` is the target's own GA4 stream secret (from analytics state, per surface) and the signing paths (`CSC_LINK`, `APPLE_API_KEY`) are target-relative, stamped **only when the certs operation actually placed the file**. Brand-level values pass through from the env manage.js already layered — shell > brand `.env` > company `.env` (**omega-manager's `.brands/{id}/.env` override layer dissolved into that chain**); empty values never write, so framework template placeholders survive. Keys update in place wherever they live (every duplicate — dotenv lets the last win), new keys land in the "Default Values" section (`npx omega push-secrets` pushes exactly that section), the Custom section survives verbatim, a missing `.env` is created with the markers, and multi-line blobs (`SNAPCRAFT_STORE_CREDENTIALS`) serialize line-safe as `\n` escapes dotenv expands back. WHICH brand-level keys reach the backend is the env schema's to say — every entry whose `targets` name `backend` ([config.md](../../docs/shared/config.md)), so a new key is one entry there and never an edit here ([#581](https://github.com/Omega-JS-Stack/omega/issues/581)). Deliberately not composed: per-listing store IDs (`CHROME_EXTENSION_ID` and friends — user-managed per target) and the schema's `runtime` group (developer tooling credentials like `CLAUDE_CODE_OAUTH_TOKEN`, config-derived values, the per-target stream secret above). Mobile targets get certs only (MAM parked, no `.env` contract yet) |
83
+ | `seo` | github-repos | Parasite SEO — programmatically created GitHub repos with a templated README, download script, and daily-cron maintenance workflow. Content items live in `seo.github.content` (config/omega.json5) or the **`config/seo.json5` sidecar** (the chatsy.md/replyify.md convention; omega-manager kept them in `.brands/{id}/seo.json` and auto-created a default entry per brand — the port never writes config, no content = clean skip). Per item: repo created if missing (public, auto-init), template files pushed **content-compared** (unchanged files never rewritten), stale non-template files deleted, description/homepage/topics reconciled (normalized compares — omega-manager re-PATCHed empty descriptions every run), starred as the author. **Collision guardrail ported verbatim**: more than 10 non-template files means the name collides with a REAL repo → the item errors without touching anything. Per-item author identity (`author.token` `env:VAR` + `author.git` commit identity) for repos owned by separate accounts; `org` defaults to `repo.providers.github.org`. Item failures surface as a service error (omega-manager swallowed them into a success). Auth via the `gh` CLI |
84
+ | `update` | targets | One resolution-gated `npm install` at the brand root (skipped when every target's deps already resolve through the node_modules climb — a brand nested in a bigger workspace never grows a stray install), then each target's own `npm run build` (targets without a build script are recorded skipped, not failed). The builds are **incremental** ([#445](https://github.com/Omega-JS-Stack/omega/issues/445)): each target carries two fingerprints — a stat sweep of its own tree (`node_modules`, `dist`, `logs`, `.temp`, `.omega`, `.cache`, `.firebase`, `.git` and `*.log` excluded, so a build never dirties its own inputs) and the installed identity of every `@omega.js/*` dep it declares (the version string for an npm install; for a local link, the link target's version plus a sweep of its `dist`). Both unchanged since the last successful build → the target is **converged** and skips with one line; either fresh → the full build. The pair lives in `.omega/cache/update.json`, rewritten after each successful build; `--force` ignores it, and a missing or unreadable cache simply means a full run (a cache never fails the walk) |
85
+ | `account` | users | The required accounts exist in the brand's **own Firebase Auth** with the expected passwords, carry `roles.admin` + the highest `payment.products` plan on their Firestore user doc, and — the audit — **nobody else holds `roles.admin`** (an unauthorized admin fails the service with its email + uid). Accounts come from `account.admins` (**de-ITW'd: omega-manager hardcoded the company's personal emails as `ADMIN_EMAILS` in config.js** — the default is just `support@{domain}`; a company's own list lives in its company omega.json5 and replaces the default whole, so per-company personal accounts need zero framework code); passwords are **owner-resolved per account, never stored** (cp91): `OMEGA_ACCOUNT_PASSWORD__<EMAIL>` env pin (email uppercased, non-alphanumerics → `_`; rides the D15 cascade) → the `config/hooks/account/password.js` owner hook (`({ email, domain, apex, brand }) => password`, brand root else company root — a company formula without a line of it in any framework repo; broken hooks fail the service loudly) → HMAC-SHA256 of email + apex domain keyed by `ACCOUNT_PASSWORD_SEED`, generated + persisted to the brand `.env` **lazily on first need** — a brand fully covered by env/hook never grows a seed (**omega-manager derived every password from a personal formula compiled into the code**). Non-default channels are called out per account in the run log (`· via env …` / `· via hook …`). Existing accounts are verified by an actual sign-in probe and only updated on mismatch; new accounts complete the real `POST /user/signup` flow against the live backend (welcome email, marketing lists), and `marketing: true` entries push the contact to the providers — which is why the service runs **after** update/deploy. Runs on the Identity Toolkit REST API + Firestore REST with the brand's own `.omega/secrets/service-account.json` (custom tokens signed locally via the shared JWT helper — no firebase-admin). `cloud.shared` brands skip (the owning brand manages accounts) |
86
+ | `migrations` | targets-rename, notifications, users, orders, payments-intents, payment-provider, state-retirement | Firestore data migrations — **only with `--migration`** (bare = all, `--migration=<name>` = one), so a normal manage run never touches collection data, and **only with `--execute`**: a bare `--migration` is the audit pass — every fix computed, counted, logged and snapshotted, nothing written. The framework is omega-manager's: per-collection fix pipelines with batched iteration, one merged leaf-masked REST patch per doc (overlapping ancestor/descendant paths conflict-resolved first), before/after snapshots + `_summary.json` under `.omega/migrations/{collection}/{ts}/`, `--limit` / `--ids` / `--verbose`, and schema validation — with fix/write failures and invalid docs downgrading the service to **warned** (omega-manager printed the ⚠ but reported success). The ported migrations are the two canonical @omega.js/backend-schema ones: **notifications** (uid→owner, owner.uid flatten, legacy created/updated → metadata.\*, url → context.client.url with the full context build, the legacy `attribution.utm` blob folded into first/last touches, attribution backfill, string trim) and **users** (orphaned docs with no auth record deleted; plan→subscription; flat subscription.id/name → product object; trial.activated→claimed; deprecated-field removal; referrer-UID → attribution.affiliate.code via DB lookup; metadata.created reconciled to Firebase Auth's canonical creation time; auth.uid/email backfill; implicit-signup consent backfill; the full @omega.js/backend default-user backfill; per-doc affiliate.code/api credential generation; sentinel + null normalization; the same attribution fold; usage period→monthly + zero-total cleanup). **orders** and **payments-intents** are native to OMEGA — that one fold on `payments-orders` and `payments-intents`, attribution and nothing else. **payment-provider** is native too ([#428](https://github.com/Omega-JS-Stack/omega/issues/428)): the data half of the `processor` → `provider` word rename, sweeping the stored field across all five payment-touching collections (`users` at `subscription.payment.processor`, `payments-orders`/`payments-intents`/`payments-webhooks` at `processor`, `payments-disputes` at `alert.processor`) — idempotent, a doc carrying both keys keeps `provider`, and its stats are namespaced `payment-provider:<collection>` so they never overwrite another migration’s. Two are LOCAL — the brand's own files, no backend target and no service account: **state-retirement** ([#434](https://github.com/Omega-JS-Stack/omega/issues/434)) moves the retired `.omega/state.json` CONTENT into config + `.env`, leaving the file's machine records ([#479](https://github.com/Omega-JS-Stack/omega/issues/479)) untouched, and **targets-rename** ([#443](https://github.com/Omega-JS-Stack/omega/issues/443)) moves a pre-#443 brand's `apps/` folder to `targets/` with the root `workspaces` glob following it. The rename is the one migration a walk can never reach on the brand it fixes — discovery fails loud on the old shape — so `runManage` runs `--migration=targets-rename` ALONE, ahead of the load that would throw; the registered entry only ever re-checks a converged brand. **De-ITW'd: omega-manager's other 25 registered migrations are company one-offs** (per-brand usage-key renames, damage repairs from old middleware and prior bad runs, the somiibo keep-plan carve-out) and stay in the company instance. Runs on the shared Identity Toolkit + Firestore REST clients (which gained listDocs pagination, aggregation counts, doc metadata, and delete here) over the brand's own `.omega/secrets/service-account.json`; `cloud.shared` brands skip (the owning brand migrates the shared project) |
87
+ | `bookmark` | sync | The brand's console/dashboard bookmarks pushed to the **companion Chrome extension** (`extension/` — MV3, load unpacked; it auto-connects to `ws://localhost:9876`, port override via `OMEGA_EXTENSION_PORT`) and filed under `Ω / {Brand} / {Category}`. Links derive from config + state in new-world shapes: Cloud/Firebase consoles from `cloud.config.projectId` (per-function log deep links via a `gcloud functions list` read when available), Analytics from `analytics.providers.google.accountId` + `propertyId`, Search Console from `brand.url`'s domain, Stripe dashboard links **unslugged** (**de-ITW'd: omega-manager deep-linked the ITW platform account id from state — per-brand keys make the key's own account the dashboard default**), GitHub as the ONE brand monorepo repo + its Actions (omega-manager linked per-target repos), and Live website/API URLs (API only when a dir maps to the backend target). Interactive sessions only — the sync opens the WebSocket server the extension reconnects to (10s wait), sends one `OMEGA_BOOKMARK_SYNC`, and reads the ack (refusals and no-connection warn); headless runs skip cleanly, and dry runs print the planned groups without opening a server or shelling to gcloud |
88
+ | `testing` | target-checks | Health checks after every other service ran, grouped per target + a repo section. **Local** (always): parseable `package.json`; web → `dist/index.html` exists; backend → `firebase.json` + `functions/package.json`; each target's **installed framework version** (resolved through the node_modules climb — file:/workspace refs read their real version) vs the npm latest, outdated → warned, unpublished/no-registry → dim note. **Live** (skipped under `--dry-run` with `⊘ would …` lines — a dry run never touches the network): web → homepage fetch on `brand.url` (3 attempts, backoff, retries network errors AND non-2xx like omega-manager's original website-check — its consolidated target-checks had dropped non-2xx retries); backend → API health on `https://api.{host}/omega/health` (the @omega.js/backend `getApiUrl` + route-mount convention) with the payload's deployed version compared to the npm latest (`cloud.shared` brands skip — the owning brand deploys); repo-level → working tree clean (`git status` scoped `-- .` so a nested brand only sees its own files; not a repo → silent) and the latest GitHub Actions run of the brand repo via `gh` (success ✓ / in-progress warned / failed ✗ — **de-ITW'd: omega-manager defaulted the org to `itw-creative-works`**; no `repo.providers.github.org` → silent, matching the repo service's gate). Any failed check → error, any warning → warned; results feed RunSummary's per-check drill-down. **Stays behind**: the build.json check (a UJM artifact — @omega.js/web has no build manifest) and the stash check (nothing stashes in the new update service) |
89
+
90
+ `--dry-run` in repo, edge, domain, cloud, analytics, search, monitoring, campaigns, newsletter, payment, forms, chat, email, server, assets, certificates, seo, account, migrations (would-fix/would-delete counts + before/after preview snapshots, zero Firestore writes), and testing (local checks still run; every remote action — fetch, npm view, gh — prints a `⊘ would …` line instead, zero network) performs reads only: every drift is reported as `planned`, zero mutations (omega-manager's stripe operations had no dry-run guard at all — every payment mutation is guarded now). The captcha and advertising services never mutate anything — the captcha service's one siteverify probe is a read and the AdSense Management API has no writes at all — so their dry-run and normal runs are identical.
91
+
92
+ **The porting queue**: omega-manager's service order is **fully drained** — every service in it now runs here (external services joined one at a time with their `.env` credentials and their DEFAULTS sections). `disperse` mostly dissolved — the config hierarchy replaces file dispersal — and what remained (cert files, `.env` composition) **now runs as the `disperse` service** (see its row above). Old-world repo behaviors (per-target template repos, cloning, GitHub Desktop, setup commands, subdomain Pages repos), the edge service's interactive flows (nameserver browser poll, email-verification poll), the domain schema prompts (registrar choice, forwarding destination), firebase's interactive flows (project selection/creation, hosting-verification poll, Google sign-in poll), the captcha service's onboarding add-domain browser poll, analytics' interactive flows (GA account/property selection + creation, the data-collection acknowledgement poll, pixel-token paste-in), the search service's flows (the DNS-propagation verification poll), the advertising service's flows (the add-site browser poll, account selection), beehiiv's flows (publication select/create browser poll, the extension-driven segment automation), payment's flows (the three provider account-setup browser + key-entry prompts with secrets writeback), and the forms/chat/email setup flows (open the product dashboard, form-id / agent-id entry with config writeback, the disable-in-config choice) split three ways: the value-landing flows are **live** (the onboarding-flows port below), the wait-and-verify polls are **live too** (the verification-poll adoptions below), and the Beehiiv segment automation is **live too** (the extension port below); schema prompting (`ensureSchemaFields`) is superseded by per-service `resolveConfigValue` specs. **The config-writeback port is done**: `@omega.js/config` grew the comment-preserving omega.json5 editor (`applyConfigEdits`/`writeConfigValues` — surgical span edits, `[key=value]` array matchers, already-equal skips, and a never-write-corrupt verification gate), and resolved IDs now land in config directly — the sendgrid list, the beehiiv publication, stripe/paypal product IDs, and the firebase SDK config — with state keeping a mirror as the resolution cache. **The prompting port itself is done**: `@omega.js/devkit/prompt` plus the state-stamped flows now live — the Stripe Radar/dispute confirms, the Search Console GA-association confirm, the OAuth redirect-URI confirm, and the VAPID paste-back. **The onboarding wizard is done too** (`omega onboard` — see [Onboarding](#onboarding)). **And the onboarding-flows port is done**: `@omega.js/devkit/flows` grew the TTY-safe flow primitives (`openBrowser` with a test seam, `withSpinner`, `pollWithSpinner` with ENTER/S keyboard controls, `openBrowserAndPoll` — all riding the prompt-stream seam, degrading to printed guidance without a TTY), and the manager grew `src/lib/config-flow.js` (`resolveConfigValue` — the schema-prompter engine reshaped: a uniform Yes/Skip/Disable gate, brand-match-sorted selections whose cursor never lands on create-new by accident, create-new via API handler or browser + refresh, paste-back entry — every value landing through the comment-preserving writeback with the in-memory config patched so the rest of the run sees it). Live in interactive sessions: the chat/email/forms paste-backs, the GA account + property selection/creation, the meta/tiktok pixel-token paste-ins (secrets → brand `.env`), the AdSense account selection, the Firebase project selection + quota-aware creation inside `cloud.organizationId`, the three providers' key entry (public → omega.json5, secrets → brand `.env`), the Beehiiv create-publication browser poll, the AI brandmark generation (the MrLogo credential ladder — see the assets row), the extension-driven Beehiiv segment automation, and the extension bookmark sync; non-interactive and dry runs keep their clean skips. **And the verification-poll adoptions are done**: every wait-and-verify site now rides the live primitives in interactive runs — the pending Cloudflare zone opens the manual registrar's nameserver page (from the `domain/lib/registrars.js` SSOT; API registrars still defer to the domain service) and polls for activation, email-routing retries the rule write once the destination verifies, Firebase hosting polls domain verification (writing the mid-poll ACME record and proxying the CNAME after), AdSense polls the add-site page, reCAPTCHA confirms the domain list once and stamps state, and SendGrid domain-auth + Search Console verification poll out DNS propagation — while non-interactive and dry runs keep their exact one-shot + warned behavior (a headless run never sits in a poll). **And the extension port is done — nothing from omega-manager remains unported**: the companion Chrome extension (MV3 — bookmark filing + trusted-CDP browser automation via `chrome.debugger`, with an MCP bridge for AI-driven automation) lives at `extension/` as a standalone BXM consumer project (own deps + build; excluded from the npm package via `.npmignore`), the manager speaks its WebSocket protocol through `src/lib/automation-client.js` (env-overridable port, correlation-id command/result envelopes), the `bookmark` service pushes brand bookmarks through it, and the Beehiiv segment automation drives the dashboard UI over the same channel (see their service rows). **The devlog subsystem** — which upstream omega-manager grew AFTER the drain — is folded in too (see [Devlog](#devlog)).
93
+
94
+ ## Company mode
95
+
96
+ The COMPANY → BRAND rung of the hierarchy (Ian's omega-manager case: many brands from one workspace). A **company root** is a directory whose `config/omega.json5` has a `brands` key:
97
+
98
+ ```json5
99
+ {
100
+ brand: { name: 'My Co' }, // any shared key here becomes an inherited default
101
+ monitoring: { providers: { sentry: { dsn: '…' } } },
102
+ analytics: { providers: { google: { accountId: '123456789' } } }, // company GA ACCOUNT — sub-brand setup defaults to it (dim note) instead of prompting; a brand-level accountId overrides
103
+ brands: { roots: ['./brands'] }, // dirs to scan, RELATIVE to the company root
104
+ }
105
+ ```
106
+
107
+ Anything under a root with its own `config/omega.json5` is a brand (Ian's shape — the company workspace as a sibling repo in the org folder — is `roots: ['..']`; the company itself and nested companies are skipped). Running `omega` from a company root discovers the brands and runs **the same per-brand manage as a child process per brand** (cwd = brand root): sequential by default with live output teed to `.omega/logs/{brandId}.log` at the company root, `--parallel` for concurrent children with buffered per-brand output blocks and a TTY progress line, `--brand=<id[,id]>` to filter, every other flag (`--service`, `--dry-run`, `--migration`, …) forwarded to the children verbatim. Results aggregate into one summary from each brand's own `.omega/runs/` file; a child that dies before writing one gets a synthetic error entry.
108
+
109
+ Child processes are the point, not an implementation detail: **brands own their secrets**, so each child builds its own env chain — `shell > brand .env > company .env` — and one brand's `STRIPE_SECRET_KEY` can never bleed into the next (omega-manager ran brands in-process with AsyncLocalStorage console patching; it could, because its secrets weren't per-brand `.env` files).
110
+
111
+ **A brand behaves identically everywhere** — standalone, nested under `brands/`, or a loose sibling. The company layer only changes what defaults it inherits: company runs idempotently stamp `.omega/company.json` (`{ root }`) into each managed brand, and brand-local runs read the stamp, layer the company config (minus the `brands` key) between manager DEFAULTS and the brand file — the same agnostic deep-merge as every other layer — load the company `.env` under the brand's, and print a `Company:` line in the header. A stale stamp (the target is no longer a company) warns and runs standalone; no stamp = standalone. Merge chain: `manager DEFAULTS ← company ← brand ← brand targets.<type> ← local ← local targets.<type>`.
112
+
113
+ Brands stay their own git repos — the company workspace gitignores its `.omega/` (runCompany ensures the entry) and never takes ownership of brand trees. The remotes manifest for re-cloning a company's brands is a parked onboarding follow-up; company-scoped services (shared promo-server etc.) ride their own ports.
114
+
115
+ **Making one is one command, joining one is one stamp** ([#446](https://github.com/Omega-JS-Stack/omega/issues/446)): `omega company init [path]` scaffolds the workspace — `config/omega.json5` (the real `brands` key plus commented, brand-agnostic placeholders for the sections a company owns: identity, `account.admins`, the GA account, the Sentry org, the Apple `bundleIdPrefix`), a `.env` template rendered from the canonical group SSOT with every key commented out (no values, nothing generated), a `.gitignore`, a README stub, the shared signing tree `.omega/certificates/apple/{certificates,csr,profiles}/` with its own self-protecting `*` ignore, and the default `brands/` root. Fill-missing semantics, same as onboard: a rerun creates nothing and rewrites not one byte. What the repo TRACKS is the config skeleton, the README and the `.gitignore`; `.env`, `.omega/` (the signing tree's `.p8`/`.p12`/CSR private keys), `logs/`, and `brands/` (each brand is its OWN repo, never embedded) stay out of git — signing material moves between machines out of band. `omega company adopt <brand-path>` writes the brand's `.omega/company.json` and nothing else: idempotent, refusing a non-company cwd, a path with no `config/omega.json5`, and a path that is itself a company (one rung), and warning when the adopted brand sits outside `brands.roots` — it inherits the company on its own runs, but company-wide runs won't walk it. Full guide: [docs/manager/company.md](../../docs/manager/company.md).
116
+
117
+ ## Onboarding
118
+
119
+ `omega onboard` is the brand-creation wizard — the "Use this template" story: it scaffolds the brand-monorepo skeleton (`config/omega.json5` with the brand identity + seeded `theme` + enabled `targets`, a root package.json with `targets/*` workspaces, `.gitignore`, a fully-commented `.env` credential stub documenting every service's keys, README.md, and a minimal package.json per target's dir) and proves the config loads before calling it done. Context-sensitive like manage: from a **company root** the new brand lands under `brands.roots[0]` (a root select when several are configured) and gets the company stamp; **inside an existing brand** it resumes — no wizard, answers come from the brand's own config, and only missing files fill in; **anywhere else** the cwd becomes the brand root (clone a template repo, run onboard). Scaffolding has fill-missing semantics: existing files are NEVER touched, so rerunning onboard converges instead of clobbering. Onboard is also **port time** for the one legacy secret whose shape changed: a carried `.omega/secrets/oauth.json` (`{ googleClientId, googleClientSecret }`) is converted ONCE into the canonical `.omega/secrets/google-oauth.json` (`{ clientId, clientSecret }`) and the legacy file is removed ([#501](https://github.com/Omega-JS-Stack/omega/issues/501)) — the cloud service never learns the old name, and a dry run converts nothing.
120
+
121
+ Flags pre-answer the wizard (`--id/--name/--url/--description/--tagline/--contactName/--targets=web,backend`); a TTY prompts for the gaps with derived defaults; non-interactive runs derive everything from the id (name, url, `support@` email, the web+backend target default) — `onboard --id=acme` completes with zero prompts, and only a missing, underivable id is an error. The ONE answer nothing derives is the contact PERSON ([#770](https://github.com/Omega-JS-Stack/omega/issues/770)): the wizard asks for it right after the tagline ("signs the personal emails: welcome, nudges, checkups") and requires an answer, then offers the headshot URL and the link URL as skippable follow-ups, writing `brand.contact.person` beside the derived `contact.email`; `--contactName` (with the optional `--contactImage`/`--contactUrl`) is the non-interactive form, and a run without it writes no person at all rather than inventing a name — the campaigns gate ([#694](https://github.com/Omega-JS-Stack/omega/issues/694)) fails the manage walk when the value is still missing. A resume run keeps whatever the brand already declared. `--dry-run` prints the file plan without writing or prompting. After a valid scaffold a TTY asks to run manage (a real child process in the new brand); `--manage`/`--no-manage` forces the choice. The scaffold is install-ready (cp95a): each target package.json declares its framework as a `devDependencies: { '@omega.js/<fw>': '*' }` (workspace link in a monorepo, `mgr i local` pre-publish, npm once published — a failed install of unpublished `@omega.js/*` prints that guidance), the backend target additionally gets `functions/package.json` carrying `@omega.js/backend` in `dependencies` (a Cloud Functions runtime dep, and the omega dispatcher's context anchor), backend brands seed an emulator-bootable `cloud: { config: { projectId: 'demo-<id>' } }`, and the brand config ships a commented `payment.products` starter catalog. Each framework's setup still owns its consumer INTERIOR — and seeds it layer-aware (friction #1): inside a brand monorepo NO local-layer `config/omega.json5` is seeded at all, because the brand root's file and its `targets.<type>` entry are the home (a local file is the standalone escape hatch, and a seed kept resurrecting one the target had deliberately deleted); a standalone project gets the framework's full config template.
122
+
123
+ ## Devlog
124
+
125
+ `omega devlog` — auto-generated commit-digest blog posts (omega-manager grew this subsystem after the port drain; folded in from upstream): collect recent commits across the `devlog.providers.ghostii.orgs` GitHub listings PLUS every brand repo derived from the brand configs (the backlink SSOT — one monorepo repo per brand, addressed by @omega.js/config's `brandRepo()` (the typed `repo.providers.github.repo` slug, else `<brand.id>-omega` under `repo.providers.github.org`), the repo service's exact derivation; omega-manager's per-target + subdomain fan-out collapsed at the redesign), have Ghostii write a first-person devlog article (digest → `sourceContent` with per-repo project labels, brief → `description` assembled task > `excludeTopics` blocklist > voice with only the voice ever truncated, project links → Ghostii's `links` param), and publish it into the brand's website target — `targets/{website}/src/_posts/{year}/{devlog.providers.ghostii.postPath}/{date}-{slug}.md` with blueprint front matter and a **local**-date stamp (UTC would future-date late-night runs), committing ONLY the post file in the brand monorepo and pushing; the site auto-builds. Filtering is layered: org listings pre-filter archived/stale/excluded/private repos, merge/`[bot]`/`📦 Omega:` fleet commits never reach the digest, and `excludeCommits` regexes are **the reliable ban** (brief-level topic bans lose to commit messages that discuss the topic; filtering at the source can't leak) — capped at the newest 30 commits per repo.
126
+
127
+ **Standalone command, not a service** — publishing a new post every run is not idempotent reconciliation, so devlog never runs during manage — and **stateless by design**: every run computes `since = now − lookbackDays` and fetches fresh; nothing is read from or written to `.omega/state.json` (run twice in one window, get two posts — the cadence is owned by whoever runs it). Context-sensitive like manage: from a **brand root** that brand publishes (company siblings still feed the backlink map via the `.omega/company.json` stamp); from a **company root** `--brand=<id>` or the single brand with `devlog.enabled` picks the publisher. `--days=<n>` overrides the window; `--dry-run` collects + generates and previews to `.omega/devlog/{slug}.md` instead of publishing. Auth: the `gh` CLI (collect) + `OMEGA_ADMIN_KEY` in the brand/company `.env` (Ghostii — the client at `src/devlog/lib/ghostii.js` mirrors @omega.js/backend's; @omega.js/backend is the request-shape SSOT, keep in sync). Destinations: `website` is live; `devto`/`hashnode`/`medium` are planned syndication adapters.
128
+
129
+ ## Pipeline (live full-cycle test)
130
+
131
+ `omega pipeline` at a brand root (cp117, built for the playground) — the "shit-test the whole stack" command: it spawns the REAL manage cycle with stdin detached **and** `OMEGA_NON_INTERACTIVE=1`, so no prompt, consent flow, or press-Enter can ever fire regardless of the parent terminal; every answer must already be seeded in its non-interactive home (omega.json5 choices, brand `.env` secrets, Google token-cache scopes, state latches). It then asserts the machine-readable run record (`.omega/runs/{ts}.json`, which now serializes skip `reason` + `missingEnv`): any `error` fails; CORE services (workspace, repo, edge, domain, firebase, testing — plus the graduated seeds: search, campaigns, account, captcha) must run green — a core skip means a missing seed and fails; other skips are listed with reasons, not failed. `--require=a,b` promotes services into the core set as their seeds land; `--service=x` narrows the child run (core-presence waived); `--dry-run` forwards; `--deploy=web,backend,desktop,extension` runs the deploy legs after the cycle (web = `omega deploy --direct` gh-pages push with cached-only translation; backend = the target's own `omega deploy`, a REAL functions deploy; desktop/extension are PUBLISH legs — GH release flow / store CI dispatch — and record a gated skip unless `--publish` is also passed, since releases and dispatches are gated) as `deploy:<target>` scorecard rows — a non-zero leg fails the run. After the deploy legs, the verify sweep runs automatically for what was deployed (`--verify` runs it alone, without deploying): `verify:site` (200 + HTML on the brand URL), `verify:domain` (DNS on the owned hostnames), `verify:cloudflare` (the response arrives through Cloudflare) as scorecard rows — a failed check fails the run, and a `demo-*` (emulator-only) brand records them as gated skips with no network touched (#48). Prints a scorecard, exits non-zero on fail. **Spends real API calls and reconciles real infrastructure — run on demand, sparingly; deliberately NOT part of `npm test` or CI.** Headless Google-consent paths fail fast with the exact seeding instruction (google-auth refuses to open browsers or camp on its 5-minute callback wait when headless). Mirror law (cp121): under `OMEGA_NON_INTERACTIVE=1` the update service builds web targets with `--cached-only` translation — a certification run is deterministic and can never stall on a live LLM pass, so the local pipeline, CI, and deploys all build identically (a human `omega build` in a terminal keeps the default live-translate). The playground bakes its converged extras into the script: `omega pipeline --require=analytics,disperse,update,bookmark` (search/campaigns/account/captcha graduated into the built-in core set).
132
+
133
+ ## Interactive prompts
134
+
135
+ All prompts go through `@omega.js/devkit/prompt` — a TTY-safe wrapper around `@inquirer/prompts` (never import that directly). Without a TTY (CI, cron, company-mode children — always piped) `input`/`select`/`checkbox` throw immediately instead of hanging, and `confirm` auto-returns its default unless the call passes `{ required: true }` (destructive confirmations must never auto-accept). `OMEGA_NON_INTERACTIVE=1` forces the same headless behavior even on a TTY (the pipeline command sets it for its child run). Handlers with a non-prompting fallback gate on `isInteractive()` and keep their warn path, so non-interactive runs behave exactly as they did before the prompts existed — and dry-run never prompts, even in a TTY. omega-manager's `setParallelMode` global died by construction: parallel execution is company mode, whose child processes are piped, so the TTY check already covers it. Tests drive the REAL inquirer prompts through fake TTY streams via `setPromptStreams` ([test/lib/interactive.js](test/lib/interactive.js)).
136
+
137
+ ## Module map
138
+
139
+ - `src/manage.js` — the per-brand orchestrator: resolve brand root → `apps/`→`targets/` migration → company stamp → load brand → walk SERVICE_ORDER → persist state per service → run output → summary (exit 1 on errors)
140
+ - `src/company.js` — the company orchestrator: discover brands → stamp → one manage child per brand (sequential streams / `--parallel` buffers) → aggregate summary
141
+ - `src/config.js` — SERVICE_ORDER, OPERATIONS, manager DEFAULTS (deliberately minimal: defaults move here WITH their service), app-dir conventions, `templateObject` (`{ domain }` templating)
142
+ - `src/lib/company.js` — company detection, brand discovery under `brands.roots`, the `.omega/company.json` stamp lifecycle, the inheritable config layer, the child-argv filter
143
+ - `src/company-init.js` + `src/lib/company-scaffold.js` — the `omega company` verb: `init` (the fill-missing company file plan — config layer, `.env` template, gitignore, README, the shared signing tree) and `adopt` (the stamp, plus the guards and the outside-`brands.roots` warning)
144
+ - `src/onboard.js` + `src/lib/scaffold.js` — the brand-creation wizard: context resolution (company / resume / in-place), flags → prompts → derivation, the fill-missing scaffold plan, the config self-check, the manage handoff
145
+ - `src/lib/service-runner.js` — the ported runner (ensure/read/transform/write phases, strict return contract)
146
+ - `src/lib/run-summary.js` — cross-service summary with update/testing drill-downs + retry command
147
+ - `src/lib/brand.js` — brand-root resolution, omega.json5 loading (defaults ← brand, whole-file merge), target discovery — which FAILS LOUD on a brand still carrying `apps/` instead of `targets/` ([#443](https://github.com/Omega-JS-Stack/omega/issues/443)) and names the one-time migration that fixes it, because the old shape is not a brand with zero targets and walking it as empty would quietly do the wrong thing in every service downstream
148
+ - `src/lib/state.js` — the `.omega/` store
149
+ - `src/lib/config-write.js` — brand-config writeback: `@omega.js/config`'s comment-preserving editor behind the uniform dry-run gate + logging (resolved IDs land in omega.json5; state mirrors)
150
+ - `src/lib/config-flow.js` — config-landing interactive flows (`resolveConfigValue`): Yes/Skip/Disable gate, brand-match-sorted selections, create-new via API handler or browser + refresh, paste-back entry — values land via config-write and patch the in-memory config
151
+ - `src/devlog/` — the standalone devlog command: collect (gh api over `orgs` listings + brand repos) → project map (the brand configs are the backlink SSOT) → generate (Ghostii digest/brief/links) → publish (website app, post-file-only commit + push)
152
+ - `src/cli.js` + `src/commands/` — devkit cli-router; `manage` is the default command; `src/cli-run.js` is the `'@omega.js/manager/cli'` surface the omega-bin dispatcher hands over to at a brand root (so `omega test`/`omega onboard`/bare `omega` there reach the manager)
153
+ - `src/commands/test.js` — the brand-root C5 test fan-out: universal targets to every target-mapped target, per-framework ids (`web:`/`desktop:`/…) only to the owning target, sequential per-target `omega test` spawns (each target's own framework bin, cwd = the target), aggregate exit — grammar + semantics in [docs/shared/testing.md](../../docs/shared/testing.md)
154
+ - `src/commands/deploy.js` — the brand-root D13 deploy fan-out: each target's own framework `omega deploy` verb, backend first then web then the rest, the `--target=` picker (a token matching nothing is an error, never a deploy-everything fallback; `--only`/`--except` are retired and refused by name, [#780](https://github.com/Omega-JS-Stack/omega/issues/780)), every other flag forwarded verbatim, stop-on-failure unless `--continue-on-error` — contract in [docs/shared/deploys.md](../../docs/shared/deploys.md)
155
+ - `src/commands/build.js` + `src/commands/clean.js` — the brand-root build/clean fan-outs over EVERY target type ([#603](https://github.com/Omega-JS-Stack/omega/issues/603)): one shared walk (`src/lib/verb-fanout.js`) with the deploy fan-out's discovery, `--target=` picker and dependency order, each target running its framework's own verb or its matching `package.json` script, a loud skip when it declares none, and independent targets (a failure never stops the walk; any failure exits 1)
156
+
157
+ ## Tests
158
+
159
+ `npm test` — 1044 tests: the runner contract (strict returns, accumulation, stop-on-error, setup skip), the apps/ → targets/ migration (the default run auditing without moving a byte, `--execute` renaming with the workspaces glob following and every other glob surviving, migrated reruns a no-op, a brand born on targets/ untouched, a hand-renamed folder still healing the manifest, and BOTH folders refused rather than guessed — plus discovery failing loud on the old shape with the migration pointer, and `--migration=targets-rename` running ALONE on the one brand discovery refuses to walk), brand loading (root resolution from any depth including a brand nested in a parent workspace's `targets/`, declared-vs-convention target mapping, `{ domain }` templating, secret-key load failure), end-to-end manage over staged fixture brands (full loop with a real `npm run build`, idempotent rerun, dry-run, missing-target and unloadable-config failures), the canonical .env ordering (the scaffold-shape render with placeholders, organic-file regrouping with stale machine comments regenerated and hand comments travelling, duplicate collapse to the dotenv last-wins winner incl. the empty-last case, the unrecognized-structure decline, idempotent double-pass, the default-header rule, the writeEnvValue integration, and the workspace op over brand + company files with dry-run parity), the repo service against a recording fake API (converged brand = zero-mutation no-op, drift patches exactly the drifted fields, shared-org filtering, dry-run zero-mutation guarantee), the edge service against a recording fake API (a fully converged zone is a zero-mutation no-op across all 12 operations, DNS drift diffing incl. obsolete-provider MX cleanup and additive apex TXT records, ruleset create-vs-update, subdomain filtering, unverified email destinations, dry-run guarantees), the domain service against recording fakes for both APIs (converged-nameserver no-op, drift update, the psl SLD/TLD split for multi-part TLDs, manual-registrar active-vs-pending handling, not-in-account warning, dry-run guarantee), and the cloud service (Firebase provider) against a method-level recording fake of the whole API surface (a fully converged project is a zero-mutation no-op across all 13 operations, shared-project filtering, de-ITW'd billing guidance, diff-first service enablement + IAM grants, the key-download lifecycle incl. the backend copy, manual-flow warns, the cloud.config drift writeback (comments intact) with its warned dry-run paste block, and a fully-drifted dry-run proving zero mutations), the captcha service against a recording fake of siteverify (valid secret = one read probe, invalid secret fails with guidance, the de-ITW'd console URL, dry-run parity), and the analytics service against a method-level recording fake of the Analytics Admin API (a fully converged brand is a zero-mutation no-op across all 4 operations, per-target stream creation, diff-first rename + enhanced measurement, the clean-secret lifecycle, the acknowledgement-gate warn, wrong-property link moves, pixel-token checks incl. the interactive paste-in landing the token in the brand `.env` and the empty-skip staying warned, and a fully-drifted dry-run proving zero mutations), the search service against recording fakes for both APIs (converged no-op, the one-pass TXT-verify-add flow incl. stale-record replacement and subdomain labels, pending-verification warns, the no-API ga-link warn, missing-only sitemap submission, and the dry-run guarantee — not even a verification token is minted), the advertising service against a recording fake of the read-only Management API (READY = one-read converged success, the per-state warn ladder, the missing-site add deep-link, the DEFAULTS-absence pin + the advertising.providers presence gate, and dry-run parity), the monitoring service (Sentry provider) against a method-level recording fake with the config writeback REAL on temp brand roots (the converged zero-mutation no-op leaving omega.json5 byte-identical, org resolution — config wins, lone-org self-heal writeback, multi-org and invisible-org warns — the region repoint, per-target project creation with platform pins, DSN drift patching, the missing-token skip with machine-readable missingEnv, and the dry-run zero-mutation guarantee), the campaigns service (SendGrid provider) against recording fakes for both APIs (converged zero-mutation no-op across all 6 operations, the one-pass domain-auth flow with exact CNAME diff-sync, sender recreation + the CAN-SPAM address requirement, list resolution through config/state/name/create with omega.json5 writeback (config-known ids leave the file byte-identical; state-known ids are promoted), SSOT-driven field/segment reconciliation incl. the PATCH-rejection fallback and `__temp_` sweep, the min-diff webhook patch, and the dry-run zero-mutation guarantee), the newsletter service (Beehiiv provider) against a method-level recording fake (converged zero-mutation no-op across all 4 operations, publication resolution incl. the inaccessible-id warn gating downstream operations and the auto-match written back into omega.json5, display-diffed field reconciliation, the segments operation (the API side never mutates; the interactive automation path drives a REAL ws client standing in for the extension through the full protocol — the /segments/new navigation, trusted-typed name, and save click pinned on the wire — with the Skip/manual gates over fake TTYs and the post-automation re-verify pinned to what the API reports), the description-matched min-diff webhook, and dry-run parity), and the payment service against recording fakes for all three providers (a fully converged brand is a zero-mutation no-op across all 11 operations, per-provider credential/config-`false`/`--provider` gating, exact product + price/plan/item create payloads, the Stripe metadata and PayPal exact-name self-heal matches (both written back into `payment.products[id=…]`), price/plan drift reconciliation incl. archive-and-recreate and deactivate-duplicates, webhook create/diff/re-enable for all three, the no-API radar/disputes warned-until-confirmed pattern, free/archived product exclusion, and a fully-drifted dry-run proving zero mutations on all three APIs), and the forms service against a recording fake of the Firestore REST client (converged zero-mutation no-op across both operations, form name/enabled diff-sync, the form-not-found error instead of omega-manager's silent orphan create, leaf-masked plan patches proven to ignore Slapform-written sibling fields, the plan override, skip semantics incl. scalar `slapform: false`, dry-run parity, and the typed-value codec round-trip), and the chat service against the same fake surface (converged zero-mutation no-op, baseline-knowledge generation incl. the pricing formats, the de-ITW'd sponsorships URL, and the fixed `{website}`-in-pricing placeholder omega-manager shipped broken, the `config/chatsy.md` merge with `{website}` replacement, brandmark-gated image management proven both ways, exact leaf-mask patches, the shared-agent `updateAgentInfo` skip, owner-plan reconciliation through the shared lib, and dry-run parity), and the email service likewise (converged zero-mutation no-op, the anti-company baseline pins — no sponsorship block, no hardcoded promo codes — the config-gated discount section, filter-query composition proven for both the auto-generated and file-provided brand filters, the four-format `config/replyify.md` parser, exact leaf-mask patches, the backend-target gate, and dry-run parity), and the server service against the same fake surface (converged zero-mutation no-op proven key-order-insensitive, the section whitelist — payment/analytics config never crosses — the exact full-replace write on drift incl. stale-key removal, absent-section omission, skip semantics incl. scalar `server: false`, and dry-run parity for both the create and update paths), and the assets service through the REAL pipeline on temp brand roots — nothing faked because nothing leaves the machine (the full 33-file derived set from one brandmark with black-conversion and container-magic-byte pins, converged rerun = zero writes proven by mtimes, touched-source staleness regeneration, config-only webmanifest rewrite, the dry-run zero-write guarantee with exact planned counts, wordmark/combomark generation from a programmatically built opentype font incl. the never-overwrite pin, the missing-font error, the svg-to-black unit, the PSD templates pipeline against ag-psd-built fixture PSDs (company seeding, logo layers re-rastered to brandmark pixels at the configured size/bounds, config-driven text replacement with the overflow font-shrink proven, template-dimension PNG exports feeding the icons op, converged mtime no-ops + touched-PSD reprocessing, dry-run zero-write, and the all-absent quiet note), and the AI brandmark flow against a local logo API — the generated SVG rooting the whole derived set in one run with the token + typed creative direction pinned on the wire, the no-token skip guidance, and headless/dry runs proven to never call out), and the certificates service against a URL-level recording fake of the App Store Connect client with the local pipeline kept real — openssl generates the fixture key/CSR/DER cert, CSR generation and the `.p12` export run for real, and the keychain import is always a recorder (a fully converged brand is a zero-mutation no-op across all four operations, the preserved-CSR create proving the POSTed CSR matches the on-disk key that pairs with the issued cert, first-time CSR generation, the manual-cert warn ladder + local openssl validation, bundle-ID creation with the exact Sign-in-with-Apple consent payload, capability top-up, platform derivation from targets, the required-`bundleIdPrefix` config error, profile creation pinning the bundle-ID/cert relationships with no device fetch for distribution types, the local-file-only-cert guard, `CSC_KEY_PASSWORD` generation + `.env` persistence with the dry-run never writing it, and a dry run on an empty account planning everything while writing zero files — plus the manual-cert interactive walkthrough over fake TTYs with a stubbed opener playing Apple against the service-staged CSR (paired download installed + exported + imported; wrong-type and wrong-key downloads pinned rejected), the company-shared signing tree (a company-managed brand's CSR reuse/create/download/`.p12` land at `context.companyRoot` with the brand tree never created), the interactive `.p8` rescue filing a fresh Downloads `AuthKey_*.p8` into the COMPANY tree with `CSC_KEY_PASSWORD` persisting to the COMPANY `.env`, and ES256/RS256 verification of the shared JWT signer that now also backs firestore-rest), and the disperse service over temp brand monorepos with the whole fs pipeline real and the REAL desktop/backend framework `.env` templates pinning the cross-package key contract (the full desktop signing set landing in `config/certs/` with the self-protecting `.gitignore`, byte-compared converged reruns copying nothing, required-miss warns vs optional-miss skips, the unset-placeholder warn that never writes `AuthKey_.p8`, the certificates-disabled and no-artifacts-yet quiet notes, mobile's `build/certs/` paths, template composition — env pass-throughs, the per-surface stream secret, exists-gated signing paths, untouched placeholders and Custom sections — Default-section appends above the Custom marker, fresh-file creation with markers, backend's `functions/.env` with tooling credentials pinned excluded, converged no-rewrite reruns proven by mtime, dry-run zero-write guarantees for both operations, and the env-updater units: orphan-tail-free multi-line replacement and every-duplicate rewriting), and the seo service against a method-level recording fake of the gh-backed API with the template pipeline real (auto-discovery finding all six developer-tool files incl. dotfiles from any cwd, README/package.json generator pins, the converged zero-mutation no-op with order-insensitive topics, full-template push on creation with exact Contents-API bodies, the missing-owner guidance error, surgical drift updates + stale-file deletion, the MAX_STALE_FILES collision guardrail proven to touch nothing while other items still reconcile, per-item author token + git identity riding every call and commit, the sidecar merge, org/homepage defaults, and dry-run zero-mutation guarantees for both the create and drifted paths), and the account service against method-level recording fakes of the auth-admin, Firestore, and backend clients with the password derivation and custom-token signing real (registry + DEFAULTS pins, deterministic HMAC passwords with apex-domain stability so subdomain changes never rotate them, RS256 custom-token claims verified against the signing key, the `ACCOUNT_PASSWORD_SEED` `.env` writeback with the derived password pinned to the freshly persisted seed — and the dry run never writing it, the converged zero-mutation no-op, creation with the exact Identity Toolkit payload + leaf-masked admin/plan patch + signup call, password-drift convergence, the pinned `roles.admin` structured query, the unauthorized-admin and ghost-admin audit errors, `{domain}` templating, marketing-only entries both ways, the no-products no-op omega-manager got wrong, warned-not-failed signup outages, and dry-run zero-mutation guarantees — plus the shared env-secret writeback's append/replace-in-place unit pins), and the migrations service against a method-level recording fake of the extended Firestore REST surface with the fix pipelines, conflict resolution, and patch construction real (the --migration flag / name-filter / shared-project / service-account gating, pinned single-patch REST payloads for the legacy notifications and users transforms incl. absorbed dotted paths and the #384 attribution fold on all four surfaces, orphan deletion with before/after snapshots, converged zero-mutation no-ops for both collections, warned on write failures and schema-invalid docs, --ids / --limit / pagination pins, and the `--execute` write gate proven both ways (the default pass counts and snapshots the same work, only `--execute` patches), and the #428 payment-provider rename across all five collections — pinned per-path patches, the null value that still moves, the both-keys doc that keeps `provider`, the converged no-op, and its own REAL-emulator lane (migrations-emulator.test.js: audit → `--execute` → idempotent rerun against an actual Firestore server, with the dispute doc's alert-source `provider` and Chargeblast's `subprovider` proven untouched) — plus units for the schema validator, the trim fix, the server-timestamp metadata fix, and the FieldValue.delete identity sentinel), and the testing service against recording fetch/exec fakes injected through the same options seam runManage exposes, with the check pipeline, retry loop, and version comparison real (the exact all-green pass set with one fetch per URL and one npm view per package, retry pins for network errors and a 500→200 recovery, the framework-version states — up to date / outdated / unpublished dims out / file:-declared-but-not-installed never consults npm — the shared-Firebase and no-URL gates, working-tree clean/dirty/not-a-repo outcomes, the exact `gh run list` command incl. the `repo.providers.github.repo` override with success/failure/in-progress/gh-unavailable outcomes, the dry-run zero-network guarantee, and the honest missing-build-output error — plus units for the version comparator and the node_modules-climb version resolver), and the automation client against a REAL ws extension stand-in (command/result correlation, error codes surfaced with their protocol code, progress-frame tolerance, command + connect timeouts, disconnect cleanup of in-flight commands, and the env port override), and the bookmark service (new-world link-derivation pins — the single monorepo repo, unslugged Stripe, the per-target backend API link, unmet-input groups absent — plus the sync against a real ws client: the OMEGA_BOOKMARK_SYNC envelope, ack → success, refusal → warned, connect-timeout → warned, the non-interactive clean skip, and dry-run planning the groups without a server), and company mode over staged fixture companies with REAL manage child processes (discovery incl. Ian's `roots: ['..']` sibling shape, nested-company and non-brand skips, absolute/missing-root config errors; the DEFAULTS ← company ← brand merge chain with brand values winning and the `brands` key stripped; the stamp lifecycle — idempotent no-rewrite, stale-marker standalone fallback; the shell > brand `.env` > company `.env` precedence proven through a real stamped run; sequential and `--parallel` end-to-end runs with per-brand run files, company-side logs capturing the layered `Company:` header, and one aggregate summary; the `--brand` filter incl. the unknown-brand error; disabled brands stamped but never spawned; the synthetic error entry for a child that dies before writing run output; and the company-flag argv filter pins), and the company-workspace verb over real temp dirs (`init` scaffolding every piece — the `brands`-keyed config layer parsed back with JSON5, a `.env` template proven to set not one key, the gitignore's exact tracked-vs-ignored decision list which the shared healer then reports 'present', the signing tree + its self-protecting ignore — a rerun proven a byte- AND mtime-level no-op with an operator's own edits and a dropped `AuthKey_*.p8` untouched, a deleted piece refilled without touching the rest, and `adopt` stamping the existing marker shape, re-adopting without a rewrite, the adopted brand inheriting the company layer through the REAL config loader, the stamped-but-outside-`brands.roots` warning, and the three refusals), and the interactive prompt layer through REAL inquirer prompts driven over fake TTY streams (devkit's own suite pins the guards — input/select/checkbox throwing without a TTY, confirm auto-accept vs the required-confirm throw, sequential prompts on one stream pair, and the flow primitives: the browser-opener seam, TTY-degraded spinner + quiet polling, the ENTER/S keypress controls, check-error surfacing, and openBrowserAndPoll's confirm-gated open — and the manager flows run end-to-end: the radar + disputes confirms stamping state and flipping the service to success, the decline path staying warned, dry-run never prompting even with a TTY, the GA-association confirm, the OAuth redirect-URI confirm, and the VAPID paste-back incl. its validation retry — plus the onboarding flows end-to-end: the config-flow gates (existing-value short-circuit, non-TTY null, dry-run never prompting, Skip writing nothing, Disable writing `<section>: false` with the comment kept), the never-create-new-by-accident cursor rule, create-new via API handler and via browser + refreshed re-list, the chat/email/forms paste-backs landing ids in omega.json5 bytes with comments intact, the GA account + property selection running the google operations in the same pass plus Admin-API property creation pinned to the config time zone/currency, the AdSense account selection feeding the landed account straight into the sites check, the Firebase project selection and quota-aware org-scoped creation, the Stripe key entry splitting public → config and secret → `.env` + `process.env` (with Disable and non-TTY pins), and the Beehiiv create-publication poll landing the id after the browser stub — plus the verification polls end-to-end: the pending zone activating through the registrar-page poll and the API-registrar deferral that never polls, the email-routing rule retried and counted created once its destination verifies, the hosting poll writing the mid-poll ACME record and proxying the CNAME after verification, the AdSense add-site poll reporting the found site's state, the reCAPTCHA manual confirm stamping the domain list with the stamp never re-prompting, the SendGrid validation poll, and the Search Console DNS-propagation poll gating the property add — all real keystrokes over fake TTY streams), and the onboard wizard (derivation units, the full-flag and derived-from-dirname non-interactive scaffolds with config/package/env-stub content pins, the real-prompt wizard end-to-end — typed id, accepted derived defaults, checkbox targets, the declined manage confirm — dry-run never prompting or writing even with a TTY, never-overwrite convergence on rerun, resume-from-inside-a-brand filling only the gaps with the existing brand's identity, company-mode placement + stamp + rediscovery, the workspace-green and honest-testing-nudge manage pins, and the real `--manage` child handoff writing run output), and the devlog pipeline against fakes and real temp git repos (project-map derivation matching the repo service's repo identity incl. the no-org skip and exclude/dedupe rules, collect filtering — archived/stale/excluded/private listings, merge/bot/fleet/excludeCommits drops, the 30-per-repo cap, the `--paginate` concat repair, the quiet missing-repo probe skip — digest/brief/links assembly + blocksToPost through an injected writer with the excludeTopics blocklist and voice pins, renderPostFile front-matter pins, the real-git publish proving a post-file-only commit pushed to a local bare remote with unrelated dirty files untouched plus the no-website-target error, and runDevlog resolution — company single-enabled/multiple/unknown-brand errors, brand-root disabled/mismatched-`--brand`/no-orgs errors, the empty-window early return that never generates, and the `--dry-run` preview landing under `.omega/devlog/` with the sibling backlink map covering the whole company), and the brand-root test fan-out over a staged fixture brand whose fake framework bins record every spawn (bare = every target project-only in its own cwd, per-framework ids routed solely to the owning target with targets forwarded verbatim, universal/mixed/only-invalid routing incl. the bare-everywhere fallback, an id with no matching target running nothing cleanly, sequential no-bail failure aggregation to exit 1, the outside-a-brand error, and the cli routing `test` through ALIASES to the command file), and the brand-root deploy fan-out over the same fixture shape (backend-before-web ordering from DEPLOY_ORDER rather than the directory listing, verbatim flag forwarding with the yargs camelCase twins deduped and `--target=`/`--continue-on-error` consumed, target-or-dir picking with the retired `--only`/`--except` refused by name, the nothing-matches error that never falls back to deploy-everything, the stop-on-failure bail vs `--continue-on-error`, the outside-a-brand error, and the cli `deploy` alias routing), and the workspace scripts heal (leading-token-only `omega-manager` → `omega` value rewrites with args preserved incl. the npx form, the minted `deploy` script vs an existing one kept, byte-identical converged reruns, dry-run planning without writes, and the missing/unparseable package.json step-asides).
160
+
161
+ Live-proven against [brands/sandbox-brand](../../brands/sandbox-brand): both targets map, install is correctly skipped (deps resolve through the monorepo), the website builds, and a second run changes nothing. The testing service's live layer is proven both ways there: the dry run prints `⊘ would …` for every remote action with zero network, and the live run resolves the backend's file:-installed framework through the node_modules climb, matches it against the real npm latest, then honestly fails the homepage/API checks — the sandbox's `.example.com` domains never resolve, so the run proves the retry + failure path without touching any real resource. Company mode is live-proven on a scratch fixture company (two brands under `brands/`): the real CLI routed to the company loop, streamed both children sequentially with layered `Company:` headers, built both websites for real under `--parallel`, filtered with `--brand`, stamped every brand, teed company-side logs, and a brand-local run inherited the company `monitoring.dsn` and a company `.env` var through the stamp alone. The repo service is live-proven read-only: a `--dry-run` against the real `itw-creative-works/ultimate-jekyll` repo diffed real settings (public repo vs `private: true` default), filtered org reconciliation for the shared org, and reported the missing gh-pages branch — zero writes. The onboard wizard is live-proven under a real PTY (`script -q`): every prompt renders and resolves from paced keystrokes — typed id, accepted derived defaults, the five-target checkbox, the declined manage confirm — then the scratch brand runs workspace green and a full `--dry-run` manage: 2 passed, 20 clean skips, testing honestly naming the missing framework internals, `⊘ would fetch` for every remote action, credentials scrubbed throughout.
162
+
163
+ ## License
164
+
165
+ [Elastic License 2.0](LICENSE). The source is free to use and modify; a license key unlocks payments in production deploys and removes the attribution (local dev and test payments are always free); and you may not offer `@omega.js/manager` to third parties as a hosted or managed service.
package/bin/omega ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/omega-bin.js');
package/bin/omg ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/omega-bin.js');
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "omega",
3
+ "displayName": "OMEGA",
4
+ "description": "OMEGA framework knowledge for Claude — skills for the @omega.js packages, shipped beside the code they describe.",
5
+ "version": "0.1.0",
6
+ "author": {
7
+ "name": "ITW Creative Works",
8
+ "url": "https://github.com/ITW-Creative-Works"
9
+ },
10
+ "license": "Elastic-2.0"
11
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "mcpServers": {
3
+ "mcp-router": {
4
+ "type": "stdio",
5
+ "command": "node",
6
+ "args": ["${CLAUDE_PLUGIN_ROOT}/mcp-router-launch.js"]
7
+ }
8
+ }
9
+ }