@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,210 @@
1
+ /**
2
+ * Automation client — drives the companion Chrome extension (extension/)
3
+ * over its WebSocket protocol. The manager side is the SERVER: it listens
4
+ * on the port the extension auto-connects to (ws://localhost:9876,
5
+ * reconnecting every 5s), then sends OMEGA_AUTOMATE commands and awaits
6
+ * OMEGA_AUTOMATE_RESULT responses by correlation id. The extension turns
7
+ * the commands into trusted CDP input events (chrome.debugger), so the
8
+ * automated pages can't tell a human from the manager.
9
+ *
10
+ * Port and timeouts are constructor-injectable (tests bind ephemeral
11
+ * ports; OMEGA_EXTENSION_PORT overrides the default when 9876 is taken —
12
+ * the extension side must be pointed at the same port).
13
+ *
14
+ * Usage:
15
+ * const client = new AutomationClient();
16
+ * await client.connect();
17
+ * await client.navigate('https://example.com');
18
+ * await client.click('#submit');
19
+ * await client.type('input', 'hello');
20
+ * const result = await client.evaluate('document.title');
21
+ * await client.disconnect();
22
+ */
23
+ const { WebSocketServer } = require('ws');
24
+
25
+ const DEFAULT_PORT = 9876;
26
+ const CONNECT_TIMEOUT = 15000;
27
+ const COMMAND_TIMEOUT = 30000;
28
+
29
+ let cmdCounter = 0;
30
+
31
+ /** The port the extension protocol runs on (env-overridable). */
32
+ function resolveExtensionPort() {
33
+ return Number(process.env.OMEGA_EXTENSION_PORT) || DEFAULT_PORT;
34
+ }
35
+
36
+ class AutomationClient {
37
+ constructor(options = {}) {
38
+ this.port = options.port || resolveExtensionPort();
39
+ this.connectTimeout = options.connectTimeout || CONNECT_TIMEOUT;
40
+ this.commandTimeout = options.commandTimeout || COMMAND_TIMEOUT;
41
+ this.wss = null;
42
+ this.ws = null;
43
+ this.pending = new Map(); // id → { resolve, reject, timeout }
44
+ }
45
+
46
+ /**
47
+ * Start the WebSocket server and wait for the extension to connect.
48
+ */
49
+ async connect() {
50
+ if (this.ws) {
51
+ return;
52
+ }
53
+
54
+ return new Promise((resolve, reject) => {
55
+ this.wss = new WebSocketServer({ port: this.port });
56
+
57
+ const timeout = setTimeout(() => {
58
+ this.wss.close();
59
+ this.wss = null;
60
+ reject(new Error('Extension did not connect (timeout). Make sure the Omega extension is installed and enabled.'));
61
+ }, this.connectTimeout);
62
+
63
+ this.wss.on('error', (error) => {
64
+ clearTimeout(timeout);
65
+ if (error.code === 'EADDRINUSE') {
66
+ reject(new Error(`Port ${this.port} already in use`));
67
+ } else {
68
+ reject(error);
69
+ }
70
+ });
71
+
72
+ this.wss.on('connection', (ws) => {
73
+ clearTimeout(timeout);
74
+ this.ws = ws;
75
+
76
+ ws.on('message', (data) => {
77
+ try {
78
+ const msg = JSON.parse(data.toString());
79
+ this._handleResponse(msg);
80
+ } catch {
81
+ // Ignore parse errors
82
+ }
83
+ });
84
+
85
+ ws.on('close', () => {
86
+ this.ws = null;
87
+ // Reject all pending commands
88
+ for (const [id, entry] of this.pending) {
89
+ clearTimeout(entry.timeout);
90
+ entry.reject(new Error('Extension disconnected'));
91
+ this.pending.delete(id);
92
+ }
93
+ });
94
+
95
+ resolve();
96
+ });
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Disconnect and clean up.
102
+ */
103
+ async disconnect() {
104
+ if (this.ws) {
105
+ this.ws.terminate();
106
+ this.ws = null;
107
+ }
108
+ if (this.wss) {
109
+ for (const client of this.wss.clients) {
110
+ client.terminate();
111
+ }
112
+ await new Promise((resolve) => this.wss.close(resolve));
113
+ this.wss = null;
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Send a single automation command and wait for the result.
119
+ */
120
+ async send(command, params = {}, target = {}) {
121
+ if (!this.ws) {
122
+ throw new Error('Not connected to extension');
123
+ }
124
+
125
+ const id = `cmd_${++cmdCounter}_${Date.now()}`;
126
+
127
+ return new Promise((resolve, reject) => {
128
+ const timeout = setTimeout(() => {
129
+ this.pending.delete(id);
130
+ reject(new Error(`Command "${command}" timed out after ${this.commandTimeout}ms`));
131
+ }, this.commandTimeout);
132
+
133
+ this.pending.set(id, { resolve, reject, timeout });
134
+
135
+ this.ws.send(JSON.stringify({
136
+ type: 'OMEGA_AUTOMATE',
137
+ id,
138
+ command,
139
+ params,
140
+ target,
141
+ }));
142
+ });
143
+ }
144
+
145
+ /**
146
+ * Handle a response message from the extension.
147
+ */
148
+ _handleResponse(msg) {
149
+ if (msg.type === 'OMEGA_AUTOMATE_PROGRESS') {
150
+ // Progress events during sequences — informational only
151
+ return;
152
+ }
153
+
154
+ if (msg.type !== 'OMEGA_AUTOMATE_RESULT') {
155
+ return;
156
+ }
157
+
158
+ const entry = this.pending.get(msg.id);
159
+ if (!entry) {
160
+ return;
161
+ }
162
+
163
+ clearTimeout(entry.timeout);
164
+ this.pending.delete(msg.id);
165
+
166
+ if (msg.success) {
167
+ entry.resolve(msg.result);
168
+ } else {
169
+ const err = new Error(msg.error?.message || 'Automation command failed');
170
+ err.code = msg.error?.code;
171
+ entry.reject(err);
172
+ }
173
+ }
174
+
175
+ // =========================================================================
176
+ // Convenience methods
177
+ // =========================================================================
178
+
179
+ /** Navigate to a URL (opens a new tab when target.create is true). */
180
+ async navigate(url, target = {}) {
181
+ return this.send('navigate', { url }, target);
182
+ }
183
+
184
+ /** Click an element by CSS selector. */
185
+ async click(selector, options = {}) {
186
+ return this.send('click', { selector, ...options });
187
+ }
188
+
189
+ /** Type text into an element with trusted key events. */
190
+ async type(selector, text, options = {}) {
191
+ return this.send('type', { selector, text, ...options });
192
+ }
193
+
194
+ /** Read DOM content. */
195
+ async read(params = {}) {
196
+ return this.send('read', params);
197
+ }
198
+
199
+ /** Wait for an element, condition, or delay. */
200
+ async wait(params = {}) {
201
+ return this.send('wait', params);
202
+ }
203
+
204
+ /** Evaluate arbitrary JavaScript in the page context. */
205
+ async evaluate(expression) {
206
+ return this.send('evaluate', { expression });
207
+ }
208
+ }
209
+
210
+ module.exports = { AutomationClient, resolveExtensionPort, DEFAULT_PORT };
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @omega.js/backend's marketing SSOT — the FIELDS + SEGMENTS dictionaries that
3
+ * define every custom field and segment @omega.js/backend expects in the marketing
4
+ * providers (SendGrid, Beehiiv), plus GROUP_KEYS, the unsubscribe groups its
5
+ * send path names. Required straight from the @omega.js/backend
6
+ * workspace package so the definitions can never drift from the code that
7
+ * consumes them at runtime (omega-manager climbed the filesystem into the
8
+ * sibling repo for the same reason — this is the same SSOT, resolved
9
+ * properly through the workspace).
10
+ *
11
+ * omega-manager also carried an OMEGA-owned `import_batch` field here; its
12
+ * only writer is the legacy-contact import script, which hasn't ported —
13
+ * the field rides that port.
14
+ */
15
+ const { FIELDS, SEGMENTS, GROUP_KEYS, fieldsForProvider } = require('@omega.js/backend/dist/manager/libraries/email/constants.js');
16
+
17
+ // Array shapes for handlers that iterate
18
+ const BEM_FIELDS = Object.entries(FIELDS).map(([name, field]) => ({
19
+ name,
20
+ display: field.display,
21
+ type: field.type,
22
+ skip: field.skip || [],
23
+ }));
24
+
25
+ const BEM_SEGMENTS = Object.entries(SEGMENTS).map(([name, segment]) => ({
26
+ name,
27
+ display: segment.display,
28
+ conditions: segment.conditions,
29
+ logic: segment.logic || 'and',
30
+ skip: segment.skip || [],
31
+ }));
32
+
33
+ const BEM_FIELDS_BY_NAME = Object.fromEntries(BEM_FIELDS.map((field) => [field.name, field]));
34
+
35
+ /**
36
+ * Fields a given provider should provision — @omega.js/backend's OWN view of its
37
+ * catalog (#695), so what OMEGA creates and what the backend's contact sync
38
+ * writes can never be two different lists.
39
+ */
40
+ function fieldsFor(provider) {
41
+ return fieldsForProvider(provider).map((name) => BEM_FIELDS_BY_NAME[name]);
42
+ }
43
+
44
+ /** Segments a given provider should provision (honors each segment's skip list). */
45
+ function segmentsFor(provider) {
46
+ return BEM_SEGMENTS.filter((segment) => !segment.skip.includes(provider));
47
+ }
48
+
49
+ module.exports = { BACKEND_FIELDS_MAP: FIELDS, BEM_FIELDS, BEM_SEGMENTS, BEM_GROUP_KEYS: GROUP_KEYS, fieldsFor, segmentsFor };
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Brand-monorepo loading — resolve the brand root from any cwd inside it,
3
+ * load config/omega.json5 through @omega.js/config (whole-file merge, manager
4
+ * defaults as the lowest layer), enumerate enabled targets, and discover the
5
+ * target dirs under targets/.
6
+ *
7
+ * This replaces omega-manager's .brands/{id}/config.json + buildBrandConfig()
8
+ * pair: in the brand-monorepo world the brand's own omega.json5 IS the single
9
+ * source of user choices — the manager reads the same file every framework
10
+ * reads, no mirror to disperse.
11
+ *
12
+ * Target dir → target mapping, first match wins:
13
+ * 1. Declared — the dir's own config/omega.json5 lists exactly the target
14
+ * under `targets` (key presence = enabled).
15
+ * 2. Directory convention — targets/website* → web, targets/backend* → backend,
16
+ * targets/desktop* → desktop, targets/extension* → extension, targets/mobile* → mobile.
17
+ * Unmapped dirs surface as workspace-service warnings, never silent skips.
18
+ *
19
+ * A CUSTOM target (#603) is neither: the brand config declares it
20
+ * (`targets.<name>: { type: 'custom' }`) and its dir carries no framework. It
21
+ * is marked `custom: true` with `target` left NULL, which is what makes every
22
+ * framework service's `filter((entry) => entry.target)` skip it for free —
23
+ * only the ONE op that must see it (the workspace service) reads the flag.
24
+ *
25
+ * A backend entry also carries `projectType` (#584) — 'firebase' (Cloud
26
+ * Functions) or 'custom' (the same backend as its own server on a container
27
+ * host). That is a framework target either way; the mode only decides which
28
+ * verbs its framework can serve (framework-bin.js).
29
+ */
30
+
31
+ const fs = require('node:fs');
32
+ const path = require('node:path');
33
+ const JSON5 = require('json5');
34
+
35
+ // resolveBrandRoot moved into @omega.js/config (cp73c) — the hierarchy walk
36
+ // has ONE home there, alongside findBrandRoot and the env cascade.
37
+ const { loadConfig, resolveConfigPath, getEnabledTargets, resolveBrandRoot, backendProjectType, normalizeTargetInstances } = require('../vendor/config/index.js');
38
+ const { DEFAULTS, DIR_TARGETS, templateObject } = require('../config.js');
39
+ const { customTargetDirs } = require('./custom-target.js');
40
+
41
+ /**
42
+ * Read a target's raw omega.json5 (no merge, no validation) purely to see which
43
+ * targets it declares. Discovery must never throw — validation is the
44
+ * workspace service's job.
45
+ */
46
+ function readDeclaredTargets(targetPath) {
47
+ const configPath = resolveConfigPath(targetPath);
48
+ if (!configPath) return null;
49
+
50
+ try {
51
+ const raw = JSON5.parse(fs.readFileSync(configPath, 'utf8'));
52
+ const targets = getEnabledTargets(raw);
53
+ return targets.length > 0 ? targets : null;
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Map a target directory name to a target via the naming convention:
61
+ * exact match or `<name>-*` prefix (targets/website-docs → web).
62
+ */
63
+ function targetFromDirName(dirName) {
64
+ for (const [prefix, target] of Object.entries(DIR_TARGETS)) {
65
+ if (dirName === prefix || dirName.startsWith(`${prefix}-`)) {
66
+ return target;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+
72
+ /**
73
+ * Discover the targets under {brandRoot}/targets.
74
+ *
75
+ * A brand still carrying `apps/` fails LOUDLY here (#443): the old shape is
76
+ * not a brand with zero targets, it is a brand that never ran the one-time
77
+ * rename, and walking it as empty would quietly do the wrong thing in every
78
+ * service downstream. The fix is a migration, run once, by hand — nothing
79
+ * heals it inside a run.
80
+ *
81
+ * @param {string} brandRoot - Absolute brand-monorepo root
82
+ * @returns {Array<{ name, dir, path, target, projectType, declaredTargets }>} -
83
+ * One entry per target directory; `target` is null when unmapped (workspace
84
+ * warns), and `projectType` rides the backend entry only (#584).
85
+ * @throws {Error} when the brand is still on the pre-#443 `apps/` shape
86
+ */
87
+ function discoverTargets(brandRoot) {
88
+ // The brand file's own raw view — read here (never through loadBrand, which
89
+ // calls US) purely to learn which dirs are declared custom. Discovery must
90
+ // never throw: an unreadable brand file simply declares no custom targets,
91
+ // and the workspace service reports the real problem.
92
+ let customDirs = new Set();
93
+ // How the backend RUNS (#584) — 'firebase' (Cloud Functions) or 'custom'
94
+ // (its own server on a container host). Read from the same raw view, since
95
+ // it steers which verbs the fan-outs may dispatch at that target.
96
+ let backendMode = 'firebase';
97
+ try {
98
+ const brandConfigPath = resolveConfigPath(brandRoot);
99
+ if (brandConfigPath) {
100
+ const raw = JSON5.parse(fs.readFileSync(brandConfigPath, 'utf8'));
101
+ customDirs = new Set(customTargetDirs(raw));
102
+ backendMode = backendProjectType(normalizeTargetInstances(raw.targets?.backend)[0]);
103
+ }
104
+ } catch {
105
+ // Unreadable brand config — no custom declarations to honor
106
+ }
107
+
108
+ const targetsDir = path.join(brandRoot, 'targets');
109
+ if (!fs.existsSync(targetsDir)) {
110
+ if (fs.existsSync(path.join(brandRoot, 'apps'))) {
111
+ throw new Error(
112
+ `${brandRoot} still carries apps/ instead of targets/ (#443) — `
113
+ + 'run `npx omega manage --migration=targets-rename --execute` once, then `npm install`.',
114
+ );
115
+ }
116
+
117
+ return [];
118
+ }
119
+
120
+ const targets = [];
121
+
122
+ for (const entry of fs.readdirSync(targetsDir, { withFileTypes: true })) {
123
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
124
+
125
+ const targetPath = path.join(targetsDir, entry.name);
126
+
127
+ // A custom target (#603) has no framework to map to — the brand's own
128
+ // declaration is the whole mapping, and `target` stays null on purpose
129
+ if (customDirs.has(entry.name)) {
130
+ targets.push({
131
+ name: entry.name,
132
+ dir: `targets/${entry.name}`,
133
+ path: targetPath,
134
+ target: null,
135
+ custom: true,
136
+ declaredTargets: null,
137
+ });
138
+ continue;
139
+ }
140
+
141
+ const declaredTargets = readDeclaredTargets(targetPath);
142
+
143
+ // Declared target wins; a single declaration is unambiguous, multiple
144
+ // declarations fall back to the directory convention as the tiebreaker.
145
+ let target = null;
146
+ if (declaredTargets && declaredTargets.length === 1) {
147
+ target = declaredTargets[0];
148
+ } else {
149
+ target = targetFromDirName(entry.name);
150
+ if (!target && declaredTargets) target = declaredTargets[0];
151
+ }
152
+
153
+ targets.push({
154
+ name: entry.name,
155
+ dir: `targets/${entry.name}`,
156
+ path: targetPath,
157
+ target,
158
+ // Backend only: the mode decides which verbs its framework can serve
159
+ // (#584). Every other target has one shape, so it carries no key.
160
+ ...(target === 'backend' ? { projectType: backendMode } : {}),
161
+ declaredTargets,
162
+ });
163
+ }
164
+
165
+ return targets;
166
+ }
167
+
168
+ /**
169
+ * Load a brand monorepo: config (manager defaults ← [company ←] brand file,
170
+ * whole-file merge with `{ domain }` templating applied), enabled targets,
171
+ * discovered target dirs.
172
+ *
173
+ * The COMPANY layer is @omega.js/config's, not ours (#83): loadConfig reads
174
+ * the brand's `.omega/company.json` stamp itself and folds the company file
175
+ * (minus `brands`) between the defaults and the brand file. The manager keeps
176
+ * the company config only as PROVENANCE — runManage hangs it on the loaded
177
+ * brand as `companyRoot`/`companyConfig` for services that ask "did this come
178
+ * from the company?" — never as a second fold.
179
+ *
180
+ * Config load failures (parse error, secret-shaped keys, legacy targets
181
+ * array) do NOT throw here — they land in `configError` so the workspace
182
+ * service reports them through the normal status flow.
183
+ *
184
+ * @param {string} brandRoot - Absolute brand-monorepo root
185
+ * @returns {{ root, id, config, configError, configErrors, enabledTargets, targets, files }}
186
+ */
187
+ function loadBrand(brandRoot) {
188
+ let loaded = null;
189
+ let configError = null;
190
+
191
+ try {
192
+ loaded = loadConfig(brandRoot, undefined, { defaults: DEFAULTS });
193
+ } catch (error) {
194
+ configError = error.message;
195
+ }
196
+
197
+ let config = loaded ? loaded.config : { ...DEFAULTS, brand: { id: path.basename(brandRoot) } };
198
+
199
+ // Template `{ domain }` placeholders from brand.url (omega-manager parity)
200
+ const url = config.brand?.url || '';
201
+ const domain = url.replace(/^https?:\/\//, '');
202
+ if (domain) {
203
+ config = templateObject(config, {
204
+ domain,
205
+ domainDashed: domain.replace(/\./g, '-'),
206
+ });
207
+ }
208
+
209
+ return {
210
+ root: brandRoot,
211
+ id: config.brand?.id || path.basename(brandRoot),
212
+ config,
213
+ configError,
214
+ configErrors: loaded ? loaded.errors : [],
215
+ enabledTargets: loaded ? getEnabledTargets(loaded.config) : [],
216
+ targets: discoverTargets(brandRoot),
217
+ files: loaded ? loaded.files : null,
218
+ };
219
+ }
220
+
221
+ /**
222
+ * Resolve a brand image (brand.images.<key>) to an ABSOLUTE URL for external
223
+ * services (Stripe product images, Chatsy avatars, …). Config stores
224
+ * site-relative paths (served by the web build's static channel — the site
225
+ * itself absolutizes per environment); external surfaces can't resolve a
226
+ * relative path, so join against brand.url. Full URLs pass through.
227
+ * @param {object} brandConfig - merged brand config
228
+ * @param {string} key - images key ('brandmark' | 'social' | ...)
229
+ * @returns {string|null} absolute URL, or null when unresolvable
230
+ */
231
+ function absoluteBrandImage(brandConfig, key) {
232
+ const value = brandConfig?.brand?.images?.[key] || null;
233
+ if (!value) return null;
234
+ if (/^https?:\/\//.test(value)) return value;
235
+
236
+ const base = String(brandConfig?.brand?.url || '').replace(/\/$/, '');
237
+ return base ? `${base}${value.startsWith('/') ? '' : '/'}${value}` : null;
238
+ }
239
+
240
+ module.exports = { resolveBrandRoot, loadBrand, discoverTargets, targetFromDirName, absoluteBrandImage };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Bundle-identifier policy — reverse-DNS ids derived from the brand's web
3
+ * identity (Ian 2026-07-14: the prefix is the reverse domain, autoset at
4
+ * onboarding from the parent company when one exists, else the brand's own
5
+ * url).
6
+ *
7
+ * deriveBundleIdPrefix('https://itwcreativeworks.com') → 'com.itwcreativeworks'
8
+ * deriveBundleIdPrefix('https://playground.omegajs.dev') → 'dev.omegajs.playground'
9
+ * composeBundleId('com.itwcreativeworks', 'omega-playground')
10
+ * → 'com.itwcreativeworks.omega.playground'
11
+ *
12
+ * Sanitization keeps ids legal on BOTH stores: Apple allows hyphens but
13
+ * Android package segments don't, so domain labels drop non-alphanumerics
14
+ * and brand-id hyphens become dots (each id word is its own segment).
15
+ */
16
+
17
+ /**
18
+ * Reverse-DNS prefix from a company/brand url, or null when the url does
19
+ * not parse. `www.` is dropped; every other hostname label survives (a
20
+ * subdomain brand derives a subdomain-scoped prefix).
21
+ *
22
+ * @param {string} url - http(s) url (brand.url shape)
23
+ * @returns {string|null}
24
+ */
25
+ function deriveBundleIdPrefix(url) {
26
+ let hostname;
27
+ try {
28
+ hostname = new URL(url).hostname;
29
+ } catch {
30
+ return null;
31
+ }
32
+
33
+ const labels = hostname
34
+ .replace(/^www\./, '')
35
+ .split('.')
36
+ .map((label) => label.toLowerCase().replace(/[^a-z0-9]/g, ''))
37
+ .filter(Boolean);
38
+
39
+ return labels.length > 0 ? labels.reverse().join('.') : null;
40
+ }
41
+
42
+ /**
43
+ * Full bundle identifier: prefix + the brand id with hyphens as dots.
44
+ *
45
+ * @param {string} prefix - reverse-DNS prefix (config or derived)
46
+ * @param {string} brandId - brand.id ('omega-playground')
47
+ * @returns {string}
48
+ */
49
+ function composeBundleId(prefix, brandId) {
50
+ return `${prefix}.${String(brandId).toLowerCase().replace(/-+/g, '.')}`;
51
+ }
52
+
53
+ module.exports = { deriveBundleIdPrefix, composeBundleId };
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Brand Claude settings ([#62](https://github.com/Omega-JS-Stack/omega/issues/62)):
3
+ * a brand's committed `.claude/settings.json` registers the omega marketplace
4
+ * that the INSTALLED `@omega.js/manager` package carries (the plugin is
5
+ * vendored into it at prepare time) and enables the plugin, so every session
6
+ * in that brand — anyone's, on any machine — loads the omega skills and hooks.
7
+ *
8
+ * Gated on a PUBLISHED install: the manager package must carry the vendored
9
+ * `.claude-plugin/marketplace.json` AND be a real installed directory. In the
10
+ * local era the brand's `@omega.js/manager` is a SYMLINK into the monorepo —
11
+ * whose packages/manager carries that same generated marketplace — so the
12
+ * link itself is the signal, and this is a silent no-op —
13
+ * the developer's own user-scope install serves those sessions, and the brand
14
+ * file must never point at a machine-specific monorepo path.
15
+ *
16
+ * Non-clobbering: only the two omega keys are ever written; every other
17
+ * setting in the file is preserved, and an already-correct file is not
18
+ * rewritten.
19
+ */
20
+ const fs = require('node:fs');
21
+ const { join } = require('node:path');
22
+ const { isDeepStrictEqual } = require('node:util');
23
+ const jetpack = require('fs-jetpack');
24
+
25
+ const SETTINGS_FILE = join('.claude', 'settings.json');
26
+ const MARKETPLACE_KEY = 'extraKnownMarketplaces';
27
+ const PLUGIN_KEY = 'enabledPlugins';
28
+ const MARKETPLACE_NAME = 'omega';
29
+ const PLUGIN_ID = 'omega@omega';
30
+ // Brand-root-relative on purpose: portable to every machine and every clone.
31
+ const MANAGER_PATH = './node_modules/@omega.js/manager';
32
+ const MANAGER_DIR = join('node_modules', '@omega.js', 'manager');
33
+ const VENDORED_MARKETPLACE = join(MANAGER_DIR, '.claude-plugin', 'marketplace.json');
34
+
35
+ /**
36
+ * The marketplace entry a brand's settings must carry.
37
+ *
38
+ * @returns {object} - The `extraKnownMarketplaces.omega` value
39
+ */
40
+ function marketplaceEntry() {
41
+ return { source: { source: 'directory', path: MANAGER_PATH } };
42
+ }
43
+
44
+ /**
45
+ * Does this brand have a PUBLISHED manager install (one carrying the vendored
46
+ * plugin marketplace)?
47
+ *
48
+ * A LOCALLY LINKED manager never counts, whatever it carries: the monorepo's
49
+ * own packages/manager grows the vendored marketplace on every prepare/pack,
50
+ * and `omega i local` symlinks the brand at it — so the file resolves through
51
+ * the link and the marketplace check alone would write settings pointing at
52
+ * one developer's machine. The symlink IS the local era.
53
+ *
54
+ * @param {string} brandRoot - Absolute brand monorepo root
55
+ * @returns {boolean}
56
+ */
57
+ function hasVendoredPlugin(brandRoot) {
58
+ let stats;
59
+ try {
60
+ stats = fs.lstatSync(join(brandRoot, MANAGER_DIR));
61
+ } catch {
62
+ return false; // nothing installed yet
63
+ }
64
+ if (stats.isSymbolicLink()) {
65
+ return false;
66
+ }
67
+
68
+ return jetpack.exists(join(brandRoot, VENDORED_MARKETPLACE)) === 'file';
69
+ }
70
+
71
+ /**
72
+ * Ensure the brand's `.claude/settings.json` registers and enables the omega
73
+ * plugin from its installed manager package.
74
+ *
75
+ * @param {string} brandRoot - Absolute brand monorepo root
76
+ * @returns {'skipped'|'present'|'created'|'healed'|'invalid'} - What happened
77
+ */
78
+ function ensureClaudeSettings(brandRoot) {
79
+ if (!hasVendoredPlugin(brandRoot)) {
80
+ return 'skipped';
81
+ }
82
+
83
+ const file = join(brandRoot, SETTINGS_FILE);
84
+ const raw = jetpack.read(file);
85
+
86
+ let settings = {};
87
+ if (raw !== undefined) {
88
+ try {
89
+ settings = JSON.parse(raw);
90
+ } catch (error) {
91
+ // A consumer's own malformed file — expected external condition, and
92
+ // never ours to overwrite. The caller warns.
93
+ return 'invalid';
94
+ }
95
+ }
96
+
97
+ const marketplaces = settings[MARKETPLACE_KEY] || {};
98
+ const plugins = settings[PLUGIN_KEY] || {};
99
+ if (isDeepStrictEqual(marketplaces[MARKETPLACE_NAME], marketplaceEntry()) && plugins[PLUGIN_ID] === true) {
100
+ return 'present';
101
+ }
102
+
103
+ const updated = {
104
+ ...settings,
105
+ [MARKETPLACE_KEY]: { ...marketplaces, [MARKETPLACE_NAME]: marketplaceEntry() },
106
+ [PLUGIN_KEY]: { ...plugins, [PLUGIN_ID]: true },
107
+ };
108
+ jetpack.write(file, `${JSON.stringify(updated, null, 2)}\n`);
109
+
110
+ return raw === undefined ? 'created' : 'healed';
111
+ }
112
+
113
+ module.exports = {
114
+ SETTINGS_FILE,
115
+ MARKETPLACE_KEY,
116
+ PLUGIN_KEY,
117
+ MARKETPLACE_NAME,
118
+ PLUGIN_ID,
119
+ MANAGER_PATH,
120
+ MANAGER_DIR,
121
+ VENDORED_MARKETPLACE,
122
+ marketplaceEntry,
123
+ hasVendoredPlugin,
124
+ ensureClaudeSettings,
125
+ };