@miranda0808/maya-codex 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 (270) hide show
  1. package/README.md +30 -0
  2. package/bin/maya-codex.js +36 -0
  3. package/package.json +19 -0
  4. package/payload/.agents/skills/ab-test-setup/SKILL.md +266 -0
  5. package/payload/.agents/skills/ab-test-setup/evals/evals.json +105 -0
  6. package/payload/.agents/skills/ab-test-setup/references/sample-size-guide.md +263 -0
  7. package/payload/.agents/skills/ab-test-setup/references/test-templates.md +277 -0
  8. package/payload/.agents/skills/ad-creative/SKILL.md +362 -0
  9. package/payload/.agents/skills/ad-creative/evals/evals.json +90 -0
  10. package/payload/.agents/skills/ad-creative/references/generative-tools.md +637 -0
  11. package/payload/.agents/skills/ad-creative/references/platform-specs.md +213 -0
  12. package/payload/.agents/skills/ai-seo/SKILL.md +398 -0
  13. package/payload/.agents/skills/ai-seo/evals/evals.json +90 -0
  14. package/payload/.agents/skills/ai-seo/references/content-patterns.md +285 -0
  15. package/payload/.agents/skills/ai-seo/references/platform-ranking-factors.md +152 -0
  16. package/payload/.agents/skills/analytics-tracking/SKILL.md +309 -0
  17. package/payload/.agents/skills/analytics-tracking/evals/evals.json +90 -0
  18. package/payload/.agents/skills/analytics-tracking/references/event-library.md +260 -0
  19. package/payload/.agents/skills/analytics-tracking/references/ga4-implementation.md +300 -0
  20. package/payload/.agents/skills/analytics-tracking/references/gtm-implementation.md +390 -0
  21. package/payload/.agents/skills/churn-prevention/SKILL.md +424 -0
  22. package/payload/.agents/skills/churn-prevention/evals/evals.json +93 -0
  23. package/payload/.agents/skills/churn-prevention/references/cancel-flow-patterns.md +316 -0
  24. package/payload/.agents/skills/churn-prevention/references/dunning-playbook.md +408 -0
  25. package/payload/.agents/skills/cold-email/SKILL.md +158 -0
  26. package/payload/.agents/skills/cold-email/evals/evals.json +94 -0
  27. package/payload/.agents/skills/cold-email/references/benchmarks.md +83 -0
  28. package/payload/.agents/skills/cold-email/references/follow-up-sequences.md +81 -0
  29. package/payload/.agents/skills/cold-email/references/frameworks.md +90 -0
  30. package/payload/.agents/skills/cold-email/references/personalization.md +79 -0
  31. package/payload/.agents/skills/cold-email/references/subject-lines.md +53 -0
  32. package/payload/.agents/skills/competitor-alternatives/SKILL.md +256 -0
  33. package/payload/.agents/skills/competitor-alternatives/evals/evals.json +93 -0
  34. package/payload/.agents/skills/competitor-alternatives/references/content-architecture.md +271 -0
  35. package/payload/.agents/skills/competitor-alternatives/references/templates.md +223 -0
  36. package/payload/.agents/skills/content-strategy/SKILL.md +359 -0
  37. package/payload/.agents/skills/content-strategy/evals/evals.json +90 -0
  38. package/payload/.agents/skills/copy-editing/SKILL.md +447 -0
  39. package/payload/.agents/skills/copy-editing/evals/evals.json +89 -0
  40. package/payload/.agents/skills/copy-editing/references/plain-english-alternatives.md +394 -0
  41. package/payload/.agents/skills/copywriting/SKILL.md +252 -0
  42. package/payload/.agents/skills/copywriting/evals/evals.json +111 -0
  43. package/payload/.agents/skills/copywriting/references/copy-frameworks.md +344 -0
  44. package/payload/.agents/skills/copywriting/references/natural-transitions.md +272 -0
  45. package/payload/.agents/skills/email-sequence/SKILL.md +309 -0
  46. package/payload/.agents/skills/email-sequence/evals/evals.json +93 -0
  47. package/payload/.agents/skills/email-sequence/references/copy-guidelines.md +113 -0
  48. package/payload/.agents/skills/email-sequence/references/email-types.md +515 -0
  49. package/payload/.agents/skills/email-sequence/references/sequence-templates.md +168 -0
  50. package/payload/.agents/skills/form-cro/SKILL.md +429 -0
  51. package/payload/.agents/skills/form-cro/evals/evals.json +90 -0
  52. package/payload/.agents/skills/free-tool-strategy/SKILL.md +178 -0
  53. package/payload/.agents/skills/free-tool-strategy/evals/evals.json +90 -0
  54. package/payload/.agents/skills/free-tool-strategy/references/tool-types.md +217 -0
  55. package/payload/.agents/skills/launch-strategy/SKILL.md +353 -0
  56. package/payload/.agents/skills/launch-strategy/evals/evals.json +91 -0
  57. package/payload/.agents/skills/marketing-ideas/SKILL.md +167 -0
  58. package/payload/.agents/skills/marketing-ideas/evals/evals.json +90 -0
  59. package/payload/.agents/skills/marketing-ideas/references/ideas-by-category.md +366 -0
  60. package/payload/.agents/skills/marketing-psychology/SKILL.md +455 -0
  61. package/payload/.agents/skills/marketing-psychology/evals/evals.json +88 -0
  62. package/payload/.agents/skills/onboarding-cro/SKILL.md +220 -0
  63. package/payload/.agents/skills/onboarding-cro/evals/evals.json +92 -0
  64. package/payload/.agents/skills/onboarding-cro/references/experiments.md +258 -0
  65. package/payload/.agents/skills/page-cro/SKILL.md +182 -0
  66. package/payload/.agents/skills/page-cro/evals/evals.json +111 -0
  67. package/payload/.agents/skills/page-cro/references/experiments.md +248 -0
  68. package/payload/.agents/skills/paid-ads/SKILL.md +315 -0
  69. package/payload/.agents/skills/paid-ads/evals/evals.json +90 -0
  70. package/payload/.agents/skills/paid-ads/references/ad-copy-templates.md +207 -0
  71. package/payload/.agents/skills/paid-ads/references/audience-targeting.md +243 -0
  72. package/payload/.agents/skills/paid-ads/references/platform-setup-checklists.md +277 -0
  73. package/payload/.agents/skills/paywall-upgrade-cro/SKILL.md +227 -0
  74. package/payload/.agents/skills/paywall-upgrade-cro/evals/evals.json +93 -0
  75. package/payload/.agents/skills/paywall-upgrade-cro/references/experiments.md +164 -0
  76. package/payload/.agents/skills/popup-cro/SKILL.md +453 -0
  77. package/payload/.agents/skills/popup-cro/evals/evals.json +94 -0
  78. package/payload/.agents/skills/pricing-strategy/SKILL.md +231 -0
  79. package/payload/.agents/skills/pricing-strategy/evals/evals.json +90 -0
  80. package/payload/.agents/skills/pricing-strategy/references/research-methods.md +152 -0
  81. package/payload/.agents/skills/pricing-strategy/references/tier-structure.md +232 -0
  82. package/payload/.agents/skills/product-marketing-context/SKILL.md +27 -0
  83. package/payload/.agents/skills/product-marketing-context/evals/evals.json +40 -0
  84. package/payload/.agents/skills/programmatic-seo/SKILL.md +238 -0
  85. package/payload/.agents/skills/programmatic-seo/evals/evals.json +94 -0
  86. package/payload/.agents/skills/programmatic-seo/references/playbooks.md +308 -0
  87. package/payload/.agents/skills/referral-program/SKILL.md +255 -0
  88. package/payload/.agents/skills/referral-program/evals/evals.json +89 -0
  89. package/payload/.agents/skills/referral-program/references/affiliate-programs.md +164 -0
  90. package/payload/.agents/skills/referral-program/references/program-examples.md +143 -0
  91. package/payload/.agents/skills/revops/SKILL.md +343 -0
  92. package/payload/.agents/skills/revops/evals/evals.json +91 -0
  93. package/payload/.agents/skills/revops/references/automation-playbooks.md +290 -0
  94. package/payload/.agents/skills/revops/references/lifecycle-definitions.md +278 -0
  95. package/payload/.agents/skills/revops/references/routing-rules.md +203 -0
  96. package/payload/.agents/skills/revops/references/scoring-models.md +247 -0
  97. package/payload/.agents/skills/sales-enablement/SKILL.md +349 -0
  98. package/payload/.agents/skills/sales-enablement/evals/evals.json +91 -0
  99. package/payload/.agents/skills/sales-enablement/references/deck-frameworks.md +263 -0
  100. package/payload/.agents/skills/sales-enablement/references/demo-scripts.md +355 -0
  101. package/payload/.agents/skills/sales-enablement/references/objection-library.md +270 -0
  102. package/payload/.agents/skills/sales-enablement/references/one-pager-templates.md +208 -0
  103. package/payload/.agents/skills/schema-markup/SKILL.md +179 -0
  104. package/payload/.agents/skills/schema-markup/evals/evals.json +87 -0
  105. package/payload/.agents/skills/schema-markup/references/schema-examples.md +398 -0
  106. package/payload/.agents/skills/seo-audit/SKILL.md +412 -0
  107. package/payload/.agents/skills/seo-audit/evals/evals.json +136 -0
  108. package/payload/.agents/skills/seo-audit/references/ai-writing-detection.md +200 -0
  109. package/payload/.agents/skills/signup-flow-cro/SKILL.md +359 -0
  110. package/payload/.agents/skills/signup-flow-cro/evals/evals.json +88 -0
  111. package/payload/.agents/skills/site-architecture/SKILL.md +357 -0
  112. package/payload/.agents/skills/site-architecture/evals/evals.json +88 -0
  113. package/payload/.agents/skills/site-architecture/references/mermaid-templates.md +216 -0
  114. package/payload/.agents/skills/site-architecture/references/navigation-patterns.md +305 -0
  115. package/payload/.agents/skills/site-architecture/references/site-type-templates.md +293 -0
  116. package/payload/.agents/skills/social-content/SKILL.md +278 -0
  117. package/payload/.agents/skills/social-content/evals/evals.json +92 -0
  118. package/payload/.agents/skills/social-content/references/platforms.md +170 -0
  119. package/payload/.agents/skills/social-content/references/post-templates.md +177 -0
  120. package/payload/.agents/skills/social-content/references/reverse-engineering.md +195 -0
  121. package/payload/.maya/executor.md +79 -0
  122. package/payload/.maya/meta-api-agent.md +48 -0
  123. package/payload/.maya/modes/consult.md +63 -0
  124. package/payload/.maya/modes/task.md +97 -0
  125. package/payload/.maya/planner.md +69 -0
  126. package/payload/.maya/researcher.md +51 -0
  127. package/payload/.maya/templates/plan.md +77 -0
  128. package/payload/.maya/templates/state.md +87 -0
  129. package/payload/.maya/templates/task-packet.md +75 -0
  130. package/payload/MAYA-CATALOG.md +115 -0
  131. package/payload/MAYA-DEPENDENCIES.md +58 -0
  132. package/payload/MAYA.md +151 -0
  133. package/payload/campaigns/README.md +14 -0
  134. package/payload/commands/maya-consult.md +28 -0
  135. package/payload/commands/maya-task.md +38 -0
  136. package/payload/commands/product.md +55 -0
  137. package/payload/research/README.md +14 -0
  138. package/payload/templates/README.md +15 -0
  139. package/payload/templates/plan.md +77 -0
  140. package/payload/templates/state.md +87 -0
  141. package/payload/templates/task-packet.md +75 -0
  142. package/payload/tools/REGISTRY.md +368 -0
  143. package/payload/tools/clis/README.md +187 -0
  144. package/payload/tools/clis/activecampaign.js +435 -0
  145. package/payload/tools/clis/adobe-analytics.js +161 -0
  146. package/payload/tools/clis/ahrefs.js +192 -0
  147. package/payload/tools/clis/amplitude.js +182 -0
  148. package/payload/tools/clis/apollo.js +142 -0
  149. package/payload/tools/clis/beehiiv.js +245 -0
  150. package/payload/tools/clis/brevo.js +368 -0
  151. package/payload/tools/clis/buffer.js +260 -0
  152. package/payload/tools/clis/calendly.js +253 -0
  153. package/payload/tools/clis/clearbit.js +163 -0
  154. package/payload/tools/clis/customer-io.js +205 -0
  155. package/payload/tools/clis/dataforseo.js +257 -0
  156. package/payload/tools/clis/demio.js +149 -0
  157. package/payload/tools/clis/dub.js +158 -0
  158. package/payload/tools/clis/g2.js +186 -0
  159. package/payload/tools/clis/ga4.js +194 -0
  160. package/payload/tools/clis/google-ads.js +189 -0
  161. package/payload/tools/clis/google-search-console.js +166 -0
  162. package/payload/tools/clis/hotjar.js +167 -0
  163. package/payload/tools/clis/hunter.js +249 -0
  164. package/payload/tools/clis/instantly.js +270 -0
  165. package/payload/tools/clis/intercom.js +399 -0
  166. package/payload/tools/clis/keywords-everywhere.js +185 -0
  167. package/payload/tools/clis/kit.js +232 -0
  168. package/payload/tools/clis/klaviyo.js +348 -0
  169. package/payload/tools/clis/lemlist.js +221 -0
  170. package/payload/tools/clis/linkedin-ads.js +185 -0
  171. package/payload/tools/clis/livestorm.js +292 -0
  172. package/payload/tools/clis/mailchimp.js +220 -0
  173. package/payload/tools/clis/mention-me.js +161 -0
  174. package/payload/tools/clis/meta-ads.js +181 -0
  175. package/payload/tools/clis/mixpanel.js +248 -0
  176. package/payload/tools/clis/onesignal.js +241 -0
  177. package/payload/tools/clis/optimizely.js +233 -0
  178. package/payload/tools/clis/paddle.js +385 -0
  179. package/payload/tools/clis/partnerstack.js +382 -0
  180. package/payload/tools/clis/plausible.js +249 -0
  181. package/payload/tools/clis/postmark.js +375 -0
  182. package/payload/tools/clis/resend.js +370 -0
  183. package/payload/tools/clis/rewardful.js +160 -0
  184. package/payload/tools/clis/savvycal.js +223 -0
  185. package/payload/tools/clis/segment.js +192 -0
  186. package/payload/tools/clis/semrush.js +207 -0
  187. package/payload/tools/clis/sendgrid.js +211 -0
  188. package/payload/tools/clis/snov.js +237 -0
  189. package/payload/tools/clis/tiktok-ads.js +190 -0
  190. package/payload/tools/clis/tolt.js +153 -0
  191. package/payload/tools/clis/trustpilot.js +276 -0
  192. package/payload/tools/clis/typeform.js +269 -0
  193. package/payload/tools/clis/wistia.js +256 -0
  194. package/payload/tools/clis/zapier.js +160 -0
  195. package/payload/tools/integrations/activecampaign.md +337 -0
  196. package/payload/tools/integrations/adobe-analytics.md +156 -0
  197. package/payload/tools/integrations/ahrefs.md +142 -0
  198. package/payload/tools/integrations/amplitude.md +135 -0
  199. package/payload/tools/integrations/apollo.md +148 -0
  200. package/payload/tools/integrations/beehiiv.md +157 -0
  201. package/payload/tools/integrations/brevo.md +268 -0
  202. package/payload/tools/integrations/buffer.md +138 -0
  203. package/payload/tools/integrations/calendly.md +161 -0
  204. package/payload/tools/integrations/clearbit.md +142 -0
  205. package/payload/tools/integrations/customer-io.md +187 -0
  206. package/payload/tools/integrations/dataforseo.md +165 -0
  207. package/payload/tools/integrations/demio.md +182 -0
  208. package/payload/tools/integrations/dub-co.md +160 -0
  209. package/payload/tools/integrations/g2.md +179 -0
  210. package/payload/tools/integrations/ga4.md +126 -0
  211. package/payload/tools/integrations/google-ads.md +159 -0
  212. package/payload/tools/integrations/google-search-console.md +147 -0
  213. package/payload/tools/integrations/hotjar.md +147 -0
  214. package/payload/tools/integrations/hubspot.md +178 -0
  215. package/payload/tools/integrations/hunter.md +90 -0
  216. package/payload/tools/integrations/instantly.md +104 -0
  217. package/payload/tools/integrations/intercom.md +292 -0
  218. package/payload/tools/integrations/keywords-everywhere.md +207 -0
  219. package/payload/tools/integrations/kit.md +167 -0
  220. package/payload/tools/integrations/klaviyo.md +228 -0
  221. package/payload/tools/integrations/lemlist.md +110 -0
  222. package/payload/tools/integrations/linkedin-ads.md +164 -0
  223. package/payload/tools/integrations/livestorm.md +313 -0
  224. package/payload/tools/integrations/mailchimp.md +150 -0
  225. package/payload/tools/integrations/mention-me.md +160 -0
  226. package/payload/tools/integrations/meta-ads.md +147 -0
  227. package/payload/tools/integrations/mixpanel.md +137 -0
  228. package/payload/tools/integrations/onesignal.md +229 -0
  229. package/payload/tools/integrations/optimizely.md +171 -0
  230. package/payload/tools/integrations/paddle.md +212 -0
  231. package/payload/tools/integrations/partnerstack.md +222 -0
  232. package/payload/tools/integrations/plausible.md +177 -0
  233. package/payload/tools/integrations/posthog.md +151 -0
  234. package/payload/tools/integrations/postmark.md +234 -0
  235. package/payload/tools/integrations/resend.md +168 -0
  236. package/payload/tools/integrations/rewardful.md +147 -0
  237. package/payload/tools/integrations/salesforce.md +150 -0
  238. package/payload/tools/integrations/savvycal.md +181 -0
  239. package/payload/tools/integrations/segment.md +159 -0
  240. package/payload/tools/integrations/semrush.md +121 -0
  241. package/payload/tools/integrations/sendgrid.md +161 -0
  242. package/payload/tools/integrations/shopify.md +176 -0
  243. package/payload/tools/integrations/snov.md +94 -0
  244. package/payload/tools/integrations/stripe.md +148 -0
  245. package/payload/tools/integrations/tiktok-ads.md +161 -0
  246. package/payload/tools/integrations/tolt.md +144 -0
  247. package/payload/tools/integrations/trustpilot.md +191 -0
  248. package/payload/tools/integrations/typeform.md +190 -0
  249. package/payload/tools/integrations/webflow.md +198 -0
  250. package/payload/tools/integrations/wistia.md +164 -0
  251. package/payload/tools/integrations/wordpress.md +175 -0
  252. package/payload/tools/integrations/zapier.md +150 -0
  253. package/payload/tools/meta/README.md +55 -0
  254. package/payload/tools/meta/meta-cache-schema.md +65 -0
  255. package/payload/tools/meta/meta-fetch.ps1 +324 -0
  256. package/payload/tools/meta/meta-fetch.test.ps1 +38 -0
  257. package/vendor/shared-installer/manifests/claude-files.json +13 -0
  258. package/vendor/shared-installer/manifests/codex-files.json +13 -0
  259. package/vendor/shared-installer/manifests/common-files.json +13 -0
  260. package/vendor/shared-installer/package.json +15 -0
  261. package/vendor/shared-installer/src/bootstrap.js +12 -0
  262. package/vendor/shared-installer/src/cli-options.js +53 -0
  263. package/vendor/shared-installer/src/fs.js +105 -0
  264. package/vendor/shared-installer/src/index.js +44 -0
  265. package/vendor/shared-installer/src/install.js +157 -0
  266. package/vendor/shared-installer/src/manifest.js +52 -0
  267. package/vendor/shared-installer/templates/claude/.claude/skills/.gitkeep +1 -0
  268. package/vendor/shared-installer/templates/claude/CLAUDE.md +27 -0
  269. package/vendor/shared-installer/templates/codex/.agent/skills/.gitkeep +1 -0
  270. package/vendor/shared-installer/templates/codex/AGENTS.md +27 -0
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+
3
+ const API_KEY = process.env.BEEHIIV_API_KEY
4
+ const BASE_URL = 'https://api.beehiiv.com/v2'
5
+
6
+ if (!API_KEY) {
7
+ console.error(JSON.stringify({ error: 'BEEHIIV_API_KEY environment variable required' }))
8
+ process.exit(1)
9
+ }
10
+
11
+ async function api(method, path, body) {
12
+ if (args['dry-run']) {
13
+ return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { 'Authorization': '***', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: body || undefined }
14
+ }
15
+ const res = await fetch(`${BASE_URL}${path}`, {
16
+ method,
17
+ headers: {
18
+ 'Authorization': `Bearer ${API_KEY}`,
19
+ 'Content-Type': 'application/json',
20
+ 'Accept': 'application/json',
21
+ },
22
+ body: body ? JSON.stringify(body) : undefined,
23
+ })
24
+ const text = await res.text()
25
+ try {
26
+ return JSON.parse(text)
27
+ } catch {
28
+ return { status: res.status, body: text }
29
+ }
30
+ }
31
+
32
+ function parseArgs(args) {
33
+ const result = { _: [] }
34
+ for (let i = 0; i < args.length; i++) {
35
+ const arg = args[i]
36
+ if (arg.startsWith('--')) {
37
+ const key = arg.slice(2)
38
+ const next = args[i + 1]
39
+ if (next && !next.startsWith('--')) {
40
+ result[key] = next
41
+ i++
42
+ } else {
43
+ result[key] = true
44
+ }
45
+ } else {
46
+ result._.push(arg)
47
+ }
48
+ }
49
+ return result
50
+ }
51
+
52
+ const args = parseArgs(process.argv.slice(2))
53
+ const [cmd, sub, ...rest] = args._
54
+
55
+ async function main() {
56
+ let result
57
+ const pubId = args.publication || args.pub
58
+ const limit = args.limit ? Number(args.limit) : 10
59
+
60
+ switch (cmd) {
61
+ case 'publications':
62
+ switch (sub) {
63
+ case 'list':
64
+ result = await api('GET', '/publications')
65
+ break
66
+ case 'get': {
67
+ if (!pubId) { result = { error: '--publication required' }; break }
68
+ result = await api('GET', `/publications/${pubId}`)
69
+ break
70
+ }
71
+ default:
72
+ result = { error: 'Unknown publications subcommand. Use: list, get' }
73
+ }
74
+ break
75
+
76
+ case 'subscriptions':
77
+ switch (sub) {
78
+ case 'list': {
79
+ if (!pubId) { result = { error: '--publication required' }; break }
80
+ const params = new URLSearchParams()
81
+ params.set('limit', String(limit))
82
+ if (args.email) params.set('email', args.email)
83
+ if (args.status) params.set('status', args.status)
84
+ if (args.tier) params.set('tier', args.tier)
85
+ if (args.cursor) params.set('cursor', args.cursor)
86
+ if (args.expand) params.set('expand[]', args.expand)
87
+ result = await api('GET', `/publications/${pubId}/subscriptions?${params.toString()}`)
88
+ break
89
+ }
90
+ case 'get': {
91
+ if (!pubId) { result = { error: '--publication required' }; break }
92
+ const subId = args.id
93
+ if (!subId) { result = { error: '--id required' }; break }
94
+ result = await api('GET', `/publications/${pubId}/subscriptions/${subId}`)
95
+ break
96
+ }
97
+ case 'create': {
98
+ if (!pubId) { result = { error: '--publication required' }; break }
99
+ const email = args.email
100
+ if (!email) { result = { error: '--email required' }; break }
101
+ const body = { email }
102
+ if (args['reactivate-existing']) body.reactivate_existing = true
103
+ if (args['send-welcome-email']) body.send_welcome_email = true
104
+ if (args['utm-source']) body.utm_source = args['utm-source']
105
+ if (args['utm-medium']) body.utm_medium = args['utm-medium']
106
+ if (args['utm-campaign']) body.utm_campaign = args['utm-campaign']
107
+ if (args.tier) body.tier = args.tier
108
+ if (args['referring-site']) body.referring_site = args['referring-site']
109
+ result = await api('POST', `/publications/${pubId}/subscriptions`, body)
110
+ break
111
+ }
112
+ case 'update': {
113
+ if (!pubId) { result = { error: '--publication required' }; break }
114
+ const subId = args.id
115
+ if (!subId) { result = { error: '--id required' }; break }
116
+ const body = {}
117
+ if (args.tier) body.tier = args.tier
118
+ result = await api('PUT', `/publications/${pubId}/subscriptions/${subId}`, body)
119
+ break
120
+ }
121
+ case 'delete': {
122
+ if (!pubId) { result = { error: '--publication required' }; break }
123
+ const subId = args.id
124
+ if (!subId) { result = { error: '--id required' }; break }
125
+ result = await api('DELETE', `/publications/${pubId}/subscriptions/${subId}`)
126
+ break
127
+ }
128
+ default:
129
+ result = { error: 'Unknown subscriptions subcommand. Use: list, get, create, update, delete' }
130
+ }
131
+ break
132
+
133
+ case 'posts':
134
+ switch (sub) {
135
+ case 'list': {
136
+ if (!pubId) { result = { error: '--publication required' }; break }
137
+ const params = new URLSearchParams()
138
+ params.set('limit', String(limit))
139
+ if (args.status) params.set('status', args.status)
140
+ if (args.cursor) params.set('cursor', args.cursor)
141
+ result = await api('GET', `/publications/${pubId}/posts?${params.toString()}`)
142
+ break
143
+ }
144
+ case 'get': {
145
+ if (!pubId) { result = { error: '--publication required' }; break }
146
+ const postId = args.id
147
+ if (!postId) { result = { error: '--id required' }; break }
148
+ result = await api('GET', `/publications/${pubId}/posts/${postId}`)
149
+ break
150
+ }
151
+ case 'create': {
152
+ if (!pubId) { result = { error: '--publication required' }; break }
153
+ const title = args.title
154
+ if (!title) { result = { error: '--title required' }; break }
155
+ const body = { title }
156
+ if (args.subtitle) body.subtitle = args.subtitle
157
+ if (args.content) body.content = args.content
158
+ if (args.status) body.status = args.status
159
+ result = await api('POST', `/publications/${pubId}/posts`, body)
160
+ break
161
+ }
162
+ case 'delete': {
163
+ if (!pubId) { result = { error: '--publication required' }; break }
164
+ const postId = args.id
165
+ if (!postId) { result = { error: '--id required' }; break }
166
+ result = await api('DELETE', `/publications/${pubId}/posts/${postId}`)
167
+ break
168
+ }
169
+ default:
170
+ result = { error: 'Unknown posts subcommand. Use: list, get, create, delete' }
171
+ }
172
+ break
173
+
174
+ case 'segments':
175
+ switch (sub) {
176
+ case 'list': {
177
+ if (!pubId) { result = { error: '--publication required' }; break }
178
+ result = await api('GET', `/publications/${pubId}/segments`)
179
+ break
180
+ }
181
+ case 'get': {
182
+ if (!pubId) { result = { error: '--publication required' }; break }
183
+ const segId = args.id
184
+ if (!segId) { result = { error: '--id required' }; break }
185
+ result = await api('GET', `/publications/${pubId}/segments/${segId}`)
186
+ break
187
+ }
188
+ default:
189
+ result = { error: 'Unknown segments subcommand. Use: list, get' }
190
+ }
191
+ break
192
+
193
+ case 'automations':
194
+ switch (sub) {
195
+ case 'list': {
196
+ if (!pubId) { result = { error: '--publication required' }; break }
197
+ result = await api('GET', `/publications/${pubId}/automations`)
198
+ break
199
+ }
200
+ case 'get': {
201
+ if (!pubId) { result = { error: '--publication required' }; break }
202
+ const autoId = args.id
203
+ if (!autoId) { result = { error: '--id required' }; break }
204
+ result = await api('GET', `/publications/${pubId}/automations/${autoId}`)
205
+ break
206
+ }
207
+ default:
208
+ result = { error: 'Unknown automations subcommand. Use: list, get' }
209
+ }
210
+ break
211
+
212
+ case 'referral-program':
213
+ switch (sub) {
214
+ case 'get': {
215
+ if (!pubId) { result = { error: '--publication required' }; break }
216
+ result = await api('GET', `/publications/${pubId}/referral_program`)
217
+ break
218
+ }
219
+ default:
220
+ result = { error: 'Unknown referral-program subcommand. Use: get' }
221
+ }
222
+ break
223
+
224
+ default:
225
+ result = {
226
+ error: 'Unknown command',
227
+ usage: {
228
+ publications: 'publications [list | get --publication <id>]',
229
+ subscriptions: 'subscriptions [list | get --id <id> | create --email <email> | update --id <id> | delete --id <id>] --publication <id>',
230
+ posts: 'posts [list | get --id <id> | create --title <title> | delete --id <id>] --publication <id>',
231
+ segments: 'segments [list | get --id <id>] --publication <id>',
232
+ automations: 'automations [list | get --id <id>] --publication <id>',
233
+ 'referral-program': 'referral-program [get] --publication <id>',
234
+ options: '--publication <id> --limit <n> --email <email> --status <status> --tier <tier>',
235
+ }
236
+ }
237
+ }
238
+
239
+ console.log(JSON.stringify(result, null, 2))
240
+ }
241
+
242
+ main().catch(err => {
243
+ console.error(JSON.stringify({ error: err.message }))
244
+ process.exit(1)
245
+ })
@@ -0,0 +1,368 @@
1
+ #!/usr/bin/env node
2
+
3
+ const API_KEY = process.env.BREVO_API_KEY
4
+ const BASE_URL = 'https://api.brevo.com/v3'
5
+
6
+ if (!API_KEY) {
7
+ console.error(JSON.stringify({ error: 'BREVO_API_KEY environment variable required' }))
8
+ process.exit(1)
9
+ }
10
+
11
+ async function api(method, path, body) {
12
+ if (args['dry-run']) {
13
+ return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { 'api-key': '***', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: body || undefined }
14
+ }
15
+ const res = await fetch(`${BASE_URL}${path}`, {
16
+ method,
17
+ headers: {
18
+ 'api-key': API_KEY,
19
+ 'Content-Type': 'application/json',
20
+ 'Accept': 'application/json',
21
+ },
22
+ body: body ? JSON.stringify(body) : undefined,
23
+ })
24
+ const text = await res.text()
25
+ try {
26
+ return JSON.parse(text)
27
+ } catch {
28
+ return { status: res.status, body: text }
29
+ }
30
+ }
31
+
32
+ function parseArgs(args) {
33
+ const result = { _: [] }
34
+ for (let i = 0; i < args.length; i++) {
35
+ const arg = args[i]
36
+ if (arg.startsWith('--')) {
37
+ const key = arg.slice(2)
38
+ const next = args[i + 1]
39
+ if (next && !next.startsWith('--')) {
40
+ result[key] = next
41
+ i++
42
+ } else {
43
+ result[key] = true
44
+ }
45
+ } else {
46
+ result._.push(arg)
47
+ }
48
+ }
49
+ return result
50
+ }
51
+
52
+ const args = parseArgs(process.argv.slice(2))
53
+ const [cmd, sub, ...rest] = args._
54
+
55
+ async function main() {
56
+ let result
57
+ const limit = args.limit ? Number(args.limit) : 50
58
+ const offset = args.offset ? Number(args.offset) : 0
59
+
60
+ switch (cmd) {
61
+ case 'account':
62
+ switch (sub) {
63
+ case 'get':
64
+ result = await api('GET', '/account')
65
+ break
66
+ default:
67
+ result = { error: 'Unknown account subcommand. Use: get' }
68
+ }
69
+ break
70
+
71
+ case 'contacts':
72
+ switch (sub) {
73
+ case 'list': {
74
+ const params = new URLSearchParams()
75
+ params.set('limit', String(limit))
76
+ params.set('offset', String(offset))
77
+ if (args.sort) params.set('sort', args.sort)
78
+ result = await api('GET', `/contacts?${params.toString()}`)
79
+ break
80
+ }
81
+ case 'get': {
82
+ const id = args.id || args.email
83
+ if (!id) { result = { error: '--id or --email required' }; break }
84
+ result = await api('GET', `/contacts/${encodeURIComponent(id)}`)
85
+ break
86
+ }
87
+ case 'create': {
88
+ const email = args.email
89
+ if (!email) { result = { error: '--email required' }; break }
90
+ const body = { email }
91
+ if (args['first-name'] || args['last-name']) {
92
+ body.attributes = {}
93
+ if (args['first-name']) body.attributes.FIRSTNAME = args['first-name']
94
+ if (args['last-name']) body.attributes.LASTNAME = args['last-name']
95
+ }
96
+ if (args['list-ids']) body.listIds = args['list-ids'].split(',').map(Number)
97
+ result = await api('POST', '/contacts', body)
98
+ break
99
+ }
100
+ case 'update': {
101
+ const id = args.id || args.email
102
+ if (!id) { result = { error: '--id or --email required' }; break }
103
+ const body = {}
104
+ if (args['first-name'] || args['last-name']) {
105
+ body.attributes = {}
106
+ if (args['first-name']) body.attributes.FIRSTNAME = args['first-name']
107
+ if (args['last-name']) body.attributes.LASTNAME = args['last-name']
108
+ }
109
+ if (args['list-ids']) body.listIds = args['list-ids'].split(',').map(Number)
110
+ if (args['unlink-list-ids']) body.unlinkListIds = args['unlink-list-ids'].split(',').map(Number)
111
+ result = await api('PUT', `/contacts/${encodeURIComponent(id)}`, body)
112
+ break
113
+ }
114
+ case 'delete': {
115
+ const id = args.id || args.email
116
+ if (!id) { result = { error: '--id or --email required' }; break }
117
+ result = await api('DELETE', `/contacts/${encodeURIComponent(id)}`)
118
+ break
119
+ }
120
+ case 'import': {
121
+ const emails = args.emails?.split(',')
122
+ if (!emails) { result = { error: '--emails required (comma-separated)' }; break }
123
+ const body = {
124
+ jsonBody: emails.map(e => ({ email: e.trim() })),
125
+ }
126
+ if (args['list-ids']) body.listIds = args['list-ids'].split(',').map(Number)
127
+ result = await api('POST', '/contacts/import', body)
128
+ break
129
+ }
130
+ default:
131
+ result = { error: 'Unknown contacts subcommand. Use: list, get, create, update, delete, import' }
132
+ }
133
+ break
134
+
135
+ case 'lists':
136
+ switch (sub) {
137
+ case 'list': {
138
+ const params = new URLSearchParams()
139
+ params.set('limit', String(limit))
140
+ params.set('offset', String(offset))
141
+ if (args.sort) params.set('sort', args.sort)
142
+ result = await api('GET', `/contacts/lists?${params.toString()}`)
143
+ break
144
+ }
145
+ case 'get': {
146
+ const id = args.id
147
+ if (!id) { result = { error: '--id required' }; break }
148
+ result = await api('GET', `/contacts/lists/${id}`)
149
+ break
150
+ }
151
+ case 'create': {
152
+ const name = args.name
153
+ if (!name) { result = { error: '--name required' }; break }
154
+ const body = { name, folderId: args.folder ? Number(args.folder) : 1 }
155
+ result = await api('POST', '/contacts/lists', body)
156
+ break
157
+ }
158
+ case 'update': {
159
+ const id = args.id
160
+ if (!id) { result = { error: '--id required' }; break }
161
+ const body = {}
162
+ if (args.name) body.name = args.name
163
+ if (args.folder) body.folderId = Number(args.folder)
164
+ result = await api('PUT', `/contacts/lists/${id}`, body)
165
+ break
166
+ }
167
+ case 'delete': {
168
+ const id = args.id
169
+ if (!id) { result = { error: '--id required' }; break }
170
+ result = await api('DELETE', `/contacts/lists/${id}`)
171
+ break
172
+ }
173
+ case 'contacts': {
174
+ const id = args.id
175
+ if (!id) { result = { error: '--id required' }; break }
176
+ const params = new URLSearchParams()
177
+ params.set('limit', String(limit))
178
+ params.set('offset', String(offset))
179
+ result = await api('GET', `/contacts/lists/${id}/contacts?${params.toString()}`)
180
+ break
181
+ }
182
+ case 'add-contacts': {
183
+ const id = args.id
184
+ if (!id) { result = { error: '--id required' }; break }
185
+ const emails = args.emails?.split(',')
186
+ if (!emails) { result = { error: '--emails required (comma-separated)' }; break }
187
+ result = await api('POST', `/contacts/lists/${id}/contacts/add`, { emails })
188
+ break
189
+ }
190
+ case 'remove-contacts': {
191
+ const id = args.id
192
+ if (!id) { result = { error: '--id required' }; break }
193
+ const emails = args.emails?.split(',')
194
+ if (!emails) { result = { error: '--emails required (comma-separated)' }; break }
195
+ result = await api('POST', `/contacts/lists/${id}/contacts/remove`, { emails })
196
+ break
197
+ }
198
+ default:
199
+ result = { error: 'Unknown lists subcommand. Use: list, get, create, update, delete, contacts, add-contacts, remove-contacts' }
200
+ }
201
+ break
202
+
203
+ case 'email':
204
+ switch (sub) {
205
+ case 'send': {
206
+ const senderEmail = args.from
207
+ const to = args.to
208
+ const subject = args.subject
209
+ if (!senderEmail) { result = { error: '--from required' }; break }
210
+ if (!to) { result = { error: '--to required' }; break }
211
+ if (!subject) { result = { error: '--subject required' }; break }
212
+ const body = {
213
+ sender: { email: senderEmail },
214
+ to: to.split(',').map(e => ({ email: e.trim() })),
215
+ subject,
216
+ }
217
+ if (args['sender-name']) body.sender.name = args['sender-name']
218
+ if (args.html) body.htmlContent = args.html
219
+ if (args.text) body.textContent = args.text
220
+ if (!args.html && !args.text) body.textContent = ''
221
+ if (args['reply-to']) body.replyTo = { email: args['reply-to'] }
222
+ if (args.tags) body.tags = args.tags.split(',')
223
+ result = await api('POST', '/smtp/email', body)
224
+ break
225
+ }
226
+ default:
227
+ result = { error: 'Unknown email subcommand. Use: send' }
228
+ }
229
+ break
230
+
231
+ case 'campaigns':
232
+ switch (sub) {
233
+ case 'list': {
234
+ const params = new URLSearchParams()
235
+ params.set('limit', String(limit))
236
+ params.set('offset', String(offset))
237
+ if (args.type) params.set('type', args.type)
238
+ if (args.status) params.set('status', args.status)
239
+ if (args.sort) params.set('sort', args.sort)
240
+ result = await api('GET', `/emailCampaigns?${params.toString()}`)
241
+ break
242
+ }
243
+ case 'get': {
244
+ const id = args.id
245
+ if (!id) { result = { error: '--id required' }; break }
246
+ result = await api('GET', `/emailCampaigns/${id}`)
247
+ break
248
+ }
249
+ case 'create': {
250
+ const name = args.name
251
+ if (!name) { result = { error: '--name required' }; break }
252
+ const body = {
253
+ name,
254
+ sender: { email: args.from || '' },
255
+ subject: args.subject || '',
256
+ }
257
+ if (args['sender-name']) body.sender.name = args['sender-name']
258
+ if (args.html) body.htmlContent = args.html
259
+ if (args['list-ids']) body.recipients = { listIds: args['list-ids'].split(',').map(Number) }
260
+ result = await api('POST', '/emailCampaigns', body)
261
+ break
262
+ }
263
+ case 'update': {
264
+ const id = args.id
265
+ if (!id) { result = { error: '--id required' }; break }
266
+ const body = {}
267
+ if (args.name) body.name = args.name
268
+ if (args.subject) body.subject = args.subject
269
+ if (args.html) body.htmlContent = args.html
270
+ result = await api('PUT', `/emailCampaigns/${id}`, body)
271
+ break
272
+ }
273
+ case 'delete': {
274
+ const id = args.id
275
+ if (!id) { result = { error: '--id required' }; break }
276
+ result = await api('DELETE', `/emailCampaigns/${id}`)
277
+ break
278
+ }
279
+ case 'send-now': {
280
+ const id = args.id
281
+ if (!id) { result = { error: '--id required' }; break }
282
+ result = await api('POST', `/emailCampaigns/${id}/sendNow`)
283
+ break
284
+ }
285
+ case 'send-test': {
286
+ const id = args.id
287
+ if (!id) { result = { error: '--id required' }; break }
288
+ const emails = args.emails?.split(',')
289
+ if (!emails) { result = { error: '--emails required (comma-separated)' }; break }
290
+ result = await api('POST', `/emailCampaigns/${id}/sendTest`, { emailTo: emails })
291
+ break
292
+ }
293
+ default:
294
+ result = { error: 'Unknown campaigns subcommand. Use: list, get, create, update, delete, send-now, send-test' }
295
+ }
296
+ break
297
+
298
+ case 'sms':
299
+ switch (sub) {
300
+ case 'send': {
301
+ const sender = args.from
302
+ const recipient = args.to
303
+ const content = args.content
304
+ if (!sender) { result = { error: '--from required (sender name)' }; break }
305
+ if (!recipient) { result = { error: '--to required (phone number)' }; break }
306
+ if (!content) { result = { error: '--content required' }; break }
307
+ result = await api('POST', '/transactionalSMS/sms', {
308
+ sender,
309
+ recipient,
310
+ content,
311
+ type: args.type || 'transactional',
312
+ })
313
+ break
314
+ }
315
+ case 'campaigns': {
316
+ const params = new URLSearchParams()
317
+ params.set('limit', String(limit))
318
+ params.set('offset', String(offset))
319
+ if (args.status) params.set('status', args.status)
320
+ result = await api('GET', `/smsCampaigns?${params.toString()}`)
321
+ break
322
+ }
323
+ default:
324
+ result = { error: 'Unknown sms subcommand. Use: send, campaigns' }
325
+ }
326
+ break
327
+
328
+ case 'senders':
329
+ switch (sub) {
330
+ case 'list':
331
+ result = await api('GET', '/senders')
332
+ break
333
+ case 'create': {
334
+ const name = args.name
335
+ const email = args.email
336
+ if (!name) { result = { error: '--name required' }; break }
337
+ if (!email) { result = { error: '--email required' }; break }
338
+ result = await api('POST', '/senders', { name, email })
339
+ break
340
+ }
341
+ default:
342
+ result = { error: 'Unknown senders subcommand. Use: list, create' }
343
+ }
344
+ break
345
+
346
+ default:
347
+ result = {
348
+ error: 'Unknown command',
349
+ usage: {
350
+ account: 'account [get]',
351
+ contacts: 'contacts [list | get --email <email> | create --email <email> | update --email <email> | delete --email <email> | import --emails <e1,e2>]',
352
+ lists: 'lists [list | get --id <id> | create --name <name> | delete --id <id> | contacts --id <id> | add-contacts --id <id> --emails <e1,e2> | remove-contacts --id <id> --emails <e1,e2>]',
353
+ email: 'email [send --from <from> --to <to> --subject <subj>]',
354
+ campaigns: 'campaigns [list | get --id <id> | create --name <name> | send-now --id <id> | send-test --id <id> --emails <e1,e2>]',
355
+ sms: 'sms [send --from <name> --to <phone> --content <msg> | campaigns]',
356
+ senders: 'senders [list | create --name <name> --email <email>]',
357
+ options: '--limit <n> --offset <n> --status <status>',
358
+ }
359
+ }
360
+ }
361
+
362
+ console.log(JSON.stringify(result, null, 2))
363
+ }
364
+
365
+ main().catch(err => {
366
+ console.error(JSON.stringify({ error: err.message }))
367
+ process.exit(1)
368
+ })