@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,232 @@
1
+ #!/usr/bin/env node
2
+
3
+ const API_SECRET = process.env.KIT_API_SECRET
4
+ const API_KEY = process.env.KIT_API_KEY
5
+ const BASE_URL = 'https://api.convertkit.com/v3'
6
+
7
+ if (!API_SECRET && !API_KEY) {
8
+ console.error(JSON.stringify({ error: 'KIT_API_SECRET or KIT_API_KEY environment variable required' }))
9
+ process.exit(1)
10
+ }
11
+
12
+ async function api(method, path, body, useSecret = true) {
13
+ const url = new URL(`${BASE_URL}${path}`)
14
+ if (method === 'GET' || method === 'DELETE') {
15
+ if (useSecret && API_SECRET) {
16
+ url.searchParams.set('api_secret', API_SECRET)
17
+ } else if (useSecret && !API_SECRET) {
18
+ return { error: 'KIT_API_SECRET required for this endpoint' }
19
+ } else if (API_KEY) {
20
+ url.searchParams.set('api_key', API_KEY)
21
+ }
22
+ }
23
+ const opts = {
24
+ method,
25
+ headers: { 'Content-Type': 'application/json' },
26
+ }
27
+ if (body && (method === 'POST' || method === 'PUT')) {
28
+ const authBody = { ...body }
29
+ if (useSecret && API_SECRET) {
30
+ authBody.api_secret = API_SECRET
31
+ } else if (useSecret && !API_SECRET) {
32
+ return { error: 'KIT_API_SECRET required for this endpoint' }
33
+ } else if (API_KEY) {
34
+ authBody.api_key = API_KEY
35
+ }
36
+ opts.body = JSON.stringify(authBody)
37
+ }
38
+ if (args['dry-run']) {
39
+ const dryRunHeaders = { ...opts.headers }
40
+ const dryRunUrl = url.toString().replace(API_SECRET, '***').replace(API_KEY, '***')
41
+ let dryRunBody = undefined
42
+ if (opts.body) {
43
+ const parsed = JSON.parse(opts.body)
44
+ if (parsed.api_secret) parsed.api_secret = '***'
45
+ if (parsed.api_key) parsed.api_key = '***'
46
+ dryRunBody = parsed
47
+ }
48
+ return { _dry_run: true, method, url: dryRunUrl, headers: dryRunHeaders, body: dryRunBody }
49
+ }
50
+ const res = await fetch(url.toString(), opts)
51
+ const text = await res.text()
52
+ try {
53
+ return JSON.parse(text)
54
+ } catch {
55
+ return { status: res.status, body: text }
56
+ }
57
+ }
58
+
59
+ function parseArgs(args) {
60
+ const result = { _: [] }
61
+ for (let i = 0; i < args.length; i++) {
62
+ const arg = args[i]
63
+ if (arg.startsWith('--')) {
64
+ const key = arg.slice(2)
65
+ const next = args[i + 1]
66
+ if (next && !next.startsWith('--')) {
67
+ result[key] = next
68
+ i++
69
+ } else {
70
+ result[key] = true
71
+ }
72
+ } else {
73
+ result._.push(arg)
74
+ }
75
+ }
76
+ return result
77
+ }
78
+
79
+ const args = parseArgs(process.argv.slice(2))
80
+ const [cmd, sub, ...rest] = args._
81
+
82
+ async function main() {
83
+ let result
84
+
85
+ switch (cmd) {
86
+ case 'subscribers':
87
+ switch (sub) {
88
+ case 'list': {
89
+ const params = args.page ? `&page=${args.page}` : ''
90
+ result = await api('GET', `/subscribers?${params}`)
91
+ break
92
+ }
93
+ case 'get':
94
+ if (!rest[0]) { result = { error: 'Subscriber ID required' }; break }
95
+ result = await api('GET', `/subscribers/${rest[0]}`)
96
+ break
97
+ case 'update': {
98
+ if (!rest[0]) { result = { error: 'Subscriber ID required' }; break }
99
+ const body = {}
100
+ if (args['first-name']) body.first_name = args['first-name']
101
+ if (args.fields) {
102
+ try { body.fields = JSON.parse(args.fields) } catch { result = { error: 'Invalid JSON in --fields' }; break }
103
+ }
104
+ result = await api('PUT', `/subscribers/${rest[0]}`, body)
105
+ break
106
+ }
107
+ case 'unsubscribe': {
108
+ const body = { email: args.email }
109
+ result = await api('PUT', '/unsubscribe', body)
110
+ break
111
+ }
112
+ default:
113
+ result = { error: 'Unknown subscribers subcommand. Use: list, get, update, unsubscribe' }
114
+ }
115
+ break
116
+
117
+ case 'forms':
118
+ switch (sub) {
119
+ case 'list':
120
+ result = await api('GET', '/forms', null, false)
121
+ break
122
+ case 'subscribe': {
123
+ if (!rest[0]) { result = { error: 'Form ID required' }; break }
124
+ if (!args.email) { result = { error: '--email required' }; break }
125
+ const formId = rest[0]
126
+ const body = { email: args.email }
127
+ if (args['first-name']) body.first_name = args['first-name']
128
+ if (args.fields) {
129
+ try { body.fields = JSON.parse(args.fields) } catch { result = { error: 'Invalid JSON in --fields' }; break }
130
+ }
131
+ result = await api('POST', `/forms/${formId}/subscribe`, body, false)
132
+ break
133
+ }
134
+ default:
135
+ result = { error: 'Unknown forms subcommand. Use: list, subscribe' }
136
+ }
137
+ break
138
+
139
+ case 'sequences':
140
+ switch (sub) {
141
+ case 'list':
142
+ result = await api('GET', '/sequences', null, false)
143
+ break
144
+ case 'subscribe': {
145
+ if (!rest[0]) { result = { error: 'Sequence ID required' }; break }
146
+ if (!args.email) { result = { error: '--email required' }; break }
147
+ const sequenceId = rest[0]
148
+ const body = { email: args.email }
149
+ if (args['first-name']) body.first_name = args['first-name']
150
+ if (args.fields) {
151
+ try { body.fields = JSON.parse(args.fields) } catch { result = { error: 'Invalid JSON in --fields' }; break }
152
+ }
153
+ result = await api('POST', `/sequences/${sequenceId}/subscribe`, body, false)
154
+ break
155
+ }
156
+ default:
157
+ result = { error: 'Unknown sequences subcommand. Use: list, subscribe' }
158
+ }
159
+ break
160
+
161
+ case 'tags':
162
+ switch (sub) {
163
+ case 'list':
164
+ result = await api('GET', '/tags', null, false)
165
+ break
166
+ case 'subscribe': {
167
+ if (!rest[0]) { result = { error: 'Tag ID required' }; break }
168
+ if (!args.email) { result = { error: '--email required' }; break }
169
+ const tagId = rest[0]
170
+ const body = { email: args.email }
171
+ if (args['first-name']) body.first_name = args['first-name']
172
+ if (args.fields) {
173
+ try { body.fields = JSON.parse(args.fields) } catch { result = { error: 'Invalid JSON in --fields' }; break }
174
+ }
175
+ result = await api('POST', `/tags/${tagId}/subscribe`, body, false)
176
+ break
177
+ }
178
+ case 'remove': {
179
+ if (!rest[0]) { result = { error: 'Tag ID required' }; break }
180
+ const tagId = rest[0]
181
+ const subscriberId = rest[1] || args['subscriber-id']
182
+ if (!subscriberId) { result = { error: 'Subscriber ID required' }; break }
183
+ result = await api('DELETE', `/subscribers/${subscriberId}/tags/${tagId}`)
184
+ break
185
+ }
186
+ default:
187
+ result = { error: 'Unknown tags subcommand. Use: list, subscribe, remove' }
188
+ }
189
+ break
190
+
191
+ case 'broadcasts':
192
+ switch (sub) {
193
+ case 'list': {
194
+ const params = args.page ? `&page=${args.page}` : ''
195
+ result = await api('GET', `/broadcasts?${params}`)
196
+ break
197
+ }
198
+ case 'create': {
199
+ if (!args.subject || !args.content) { result = { error: '--subject and --content required' }; break }
200
+ const body = {
201
+ subject: args.subject,
202
+ content: args.content,
203
+ }
204
+ if (args['email-layout-template']) body.email_layout_template = args['email-layout-template']
205
+ result = await api('POST', '/broadcasts', body)
206
+ break
207
+ }
208
+ default:
209
+ result = { error: 'Unknown broadcasts subcommand. Use: list, create' }
210
+ }
211
+ break
212
+
213
+ default:
214
+ result = {
215
+ error: 'Unknown command',
216
+ usage: {
217
+ subscribers: 'subscribers [list|get|update|unsubscribe] [id] [--email <email>] [--first-name <name>] [--fields <json>] [--page <n>]',
218
+ forms: 'forms [list|subscribe] [form_id] [--email <email>] [--first-name <name>] [--fields <json>]',
219
+ sequences: 'sequences [list|subscribe] [sequence_id] [--email <email>] [--first-name <name>] [--fields <json>]',
220
+ tags: 'tags [list|subscribe|remove] [tag_id] [subscriber_id] [--email <email>] [--subscriber-id <id>]',
221
+ broadcasts: 'broadcasts [list|create] [--subject <subject>] [--content <html>] [--email-layout-template <template>] [--page <n>]',
222
+ }
223
+ }
224
+ }
225
+
226
+ console.log(JSON.stringify(result, null, 2))
227
+ }
228
+
229
+ main().catch(err => {
230
+ console.error(JSON.stringify({ error: err.message }))
231
+ process.exit(1)
232
+ })
@@ -0,0 +1,348 @@
1
+ #!/usr/bin/env node
2
+
3
+ const API_KEY = process.env.KLAVIYO_API_KEY
4
+ const BASE_URL = 'https://a.klaviyo.com/api'
5
+ const REVISION = '2024-10-15'
6
+
7
+ if (!API_KEY) {
8
+ console.error(JSON.stringify({ error: 'KLAVIYO_API_KEY environment variable required' }))
9
+ process.exit(1)
10
+ }
11
+
12
+ async function api(method, path, body) {
13
+ const headers = {
14
+ 'Authorization': `Klaviyo-API-Key ${API_KEY}`,
15
+ 'Content-Type': 'application/json',
16
+ 'Accept': 'application/json',
17
+ 'revision': REVISION,
18
+ }
19
+ if (args['dry-run']) {
20
+ return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { ...headers, Authorization: '***' }, body: body || undefined }
21
+ }
22
+ const res = await fetch(`${BASE_URL}${path}`, {
23
+ method,
24
+ headers,
25
+ body: body ? JSON.stringify(body) : undefined,
26
+ })
27
+ const text = await res.text()
28
+ try {
29
+ return JSON.parse(text)
30
+ } catch {
31
+ return { status: res.status, body: text }
32
+ }
33
+ }
34
+
35
+ function parseArgs(args) {
36
+ const result = { _: [] }
37
+ for (let i = 0; i < args.length; i++) {
38
+ const arg = args[i]
39
+ if (arg.startsWith('--')) {
40
+ const key = arg.slice(2)
41
+ const next = args[i + 1]
42
+ if (next && !next.startsWith('--')) {
43
+ result[key] = next
44
+ i++
45
+ } else {
46
+ result[key] = true
47
+ }
48
+ } else {
49
+ result._.push(arg)
50
+ }
51
+ }
52
+ return result
53
+ }
54
+
55
+ const args = parseArgs(process.argv.slice(2))
56
+ const [cmd, sub, ...rest] = args._
57
+
58
+ async function main() {
59
+ let result
60
+
61
+ switch (cmd) {
62
+ case 'profiles':
63
+ switch (sub) {
64
+ case 'list': {
65
+ const params = new URLSearchParams()
66
+ if (args.filter) params.set('filter', args.filter)
67
+ if (args.sort) params.set('sort', args.sort)
68
+ if (args['page-size']) params.set('page[size]', args['page-size'])
69
+ if (args['page-cursor']) params.set('page[cursor]', args['page-cursor'])
70
+ const qs = params.toString()
71
+ result = await api('GET', `/profiles/${qs ? '?' + qs : ''}`)
72
+ break
73
+ }
74
+ case 'get': {
75
+ const id = args.id
76
+ if (!id) { result = { error: '--id required' }; break }
77
+ result = await api('GET', `/profiles/${id}/`)
78
+ break
79
+ }
80
+ case 'create': {
81
+ const email = args.email
82
+ if (!email) { result = { error: '--email required' }; break }
83
+ const attributes = { email }
84
+ if (args['first-name']) attributes.first_name = args['first-name']
85
+ if (args['last-name']) attributes.last_name = args['last-name']
86
+ if (args.phone) attributes.phone_number = args.phone
87
+ result = await api('POST', '/profiles/', {
88
+ data: { type: 'profile', attributes }
89
+ })
90
+ break
91
+ }
92
+ case 'update': {
93
+ const id = args.id
94
+ if (!id) { result = { error: '--id required' }; break }
95
+ const attributes = {}
96
+ if (args.email) attributes.email = args.email
97
+ if (args['first-name']) attributes.first_name = args['first-name']
98
+ if (args['last-name']) attributes.last_name = args['last-name']
99
+ if (args.phone) attributes.phone_number = args.phone
100
+ result = await api('PATCH', `/profiles/${id}/`, {
101
+ data: { type: 'profile', id, attributes }
102
+ })
103
+ break
104
+ }
105
+ default:
106
+ result = { error: 'Unknown profiles subcommand. Use: list, get, create, update' }
107
+ }
108
+ break
109
+
110
+ case 'lists':
111
+ switch (sub) {
112
+ case 'list': {
113
+ const params = new URLSearchParams()
114
+ if (args['page-size']) params.set('page[size]', args['page-size'])
115
+ const qs = params.toString()
116
+ result = await api('GET', `/lists/${qs ? '?' + qs : ''}`)
117
+ break
118
+ }
119
+ case 'get': {
120
+ const id = args.id
121
+ if (!id) { result = { error: '--id required' }; break }
122
+ result = await api('GET', `/lists/${id}/`)
123
+ break
124
+ }
125
+ case 'create': {
126
+ const name = args.name
127
+ if (!name) { result = { error: '--name required' }; break }
128
+ result = await api('POST', '/lists/', {
129
+ data: { type: 'list', attributes: { name } }
130
+ })
131
+ break
132
+ }
133
+ case 'delete': {
134
+ const id = args.id
135
+ if (!id) { result = { error: '--id required' }; break }
136
+ result = await api('DELETE', `/lists/${id}/`)
137
+ break
138
+ }
139
+ case 'add-profiles': {
140
+ const id = args.id
141
+ if (!id) { result = { error: '--id required (list ID)' }; break }
142
+ const profileIds = args.profiles?.split(',')
143
+ if (!profileIds) { result = { error: '--profiles required (comma-separated profile IDs)' }; break }
144
+ result = await api('POST', `/lists/${id}/relationships/profiles/`, {
145
+ data: profileIds.map(pid => ({ type: 'profile', id: pid }))
146
+ })
147
+ break
148
+ }
149
+ case 'remove-profiles': {
150
+ const id = args.id
151
+ if (!id) { result = { error: '--id required (list ID)' }; break }
152
+ const profileIds = args.profiles?.split(',')
153
+ if (!profileIds) { result = { error: '--profiles required (comma-separated profile IDs)' }; break }
154
+ result = await api('DELETE', `/lists/${id}/relationships/profiles/`, {
155
+ data: profileIds.map(pid => ({ type: 'profile', id: pid }))
156
+ })
157
+ break
158
+ }
159
+ default:
160
+ result = { error: 'Unknown lists subcommand. Use: list, get, create, delete, add-profiles, remove-profiles' }
161
+ }
162
+ break
163
+
164
+ case 'events':
165
+ switch (sub) {
166
+ case 'list': {
167
+ const params = new URLSearchParams()
168
+ if (args.filter) params.set('filter', args.filter)
169
+ if (args['page-size']) params.set('page[size]', args['page-size'])
170
+ const qs = params.toString()
171
+ result = await api('GET', `/events/${qs ? '?' + qs : ''}`)
172
+ break
173
+ }
174
+ case 'get': {
175
+ const id = args.id
176
+ if (!id) { result = { error: '--id required' }; break }
177
+ result = await api('GET', `/events/${id}/`)
178
+ break
179
+ }
180
+ case 'create': {
181
+ const metric = args.metric
182
+ const email = args.email
183
+ if (!metric) { result = { error: '--metric required (metric name)' }; break }
184
+ if (!email) { result = { error: '--email required' }; break }
185
+ const properties = {}
186
+ if (args.value) properties.value = Number(args.value)
187
+ if (args.property) {
188
+ const pairs = args.property.split(',')
189
+ for (const pair of pairs) {
190
+ const [k, v] = pair.split(':')
191
+ if (k && v) properties[k] = v
192
+ }
193
+ }
194
+ result = await api('POST', '/events/', {
195
+ data: {
196
+ type: 'event',
197
+ attributes: {
198
+ metric: { data: { type: 'metric', attributes: { name: metric } } },
199
+ profile: { data: { type: 'profile', attributes: { email } } },
200
+ properties,
201
+ time: new Date().toISOString(),
202
+ }
203
+ }
204
+ })
205
+ break
206
+ }
207
+ default:
208
+ result = { error: 'Unknown events subcommand. Use: list, get, create' }
209
+ }
210
+ break
211
+
212
+ case 'campaigns':
213
+ switch (sub) {
214
+ case 'list': {
215
+ const params = new URLSearchParams()
216
+ if (args.filter) params.set('filter', args.filter)
217
+ if (args['page-size']) params.set('page[size]', args['page-size'])
218
+ const qs = params.toString()
219
+ result = await api('GET', `/campaigns/${qs ? '?' + qs : ''}`)
220
+ break
221
+ }
222
+ case 'get': {
223
+ const id = args.id
224
+ if (!id) { result = { error: '--id required' }; break }
225
+ result = await api('GET', `/campaigns/${id}/`)
226
+ break
227
+ }
228
+ default:
229
+ result = { error: 'Unknown campaigns subcommand. Use: list, get' }
230
+ }
231
+ break
232
+
233
+ case 'flows':
234
+ switch (sub) {
235
+ case 'list': {
236
+ const params = new URLSearchParams()
237
+ if (args.filter) params.set('filter', args.filter)
238
+ if (args['page-size']) params.set('page[size]', args['page-size'])
239
+ const qs = params.toString()
240
+ result = await api('GET', `/flows/${qs ? '?' + qs : ''}`)
241
+ break
242
+ }
243
+ case 'get': {
244
+ const id = args.id
245
+ if (!id) { result = { error: '--id required' }; break }
246
+ result = await api('GET', `/flows/${id}/`)
247
+ break
248
+ }
249
+ case 'update': {
250
+ const id = args.id
251
+ if (!id) { result = { error: '--id required' }; break }
252
+ const attributes = {}
253
+ if (args.status) attributes.status = args.status
254
+ result = await api('PATCH', `/flows/${id}/`, {
255
+ data: { type: 'flow', id, attributes }
256
+ })
257
+ break
258
+ }
259
+ default:
260
+ result = { error: 'Unknown flows subcommand. Use: list, get, update' }
261
+ }
262
+ break
263
+
264
+ case 'metrics':
265
+ switch (sub) {
266
+ case 'list': {
267
+ const params = new URLSearchParams()
268
+ if (args['page-size']) params.set('page[size]', args['page-size'])
269
+ const qs = params.toString()
270
+ result = await api('GET', `/metrics/${qs ? '?' + qs : ''}`)
271
+ break
272
+ }
273
+ case 'get': {
274
+ const id = args.id
275
+ if (!id) { result = { error: '--id required' }; break }
276
+ result = await api('GET', `/metrics/${id}/`)
277
+ break
278
+ }
279
+ default:
280
+ result = { error: 'Unknown metrics subcommand. Use: list, get' }
281
+ }
282
+ break
283
+
284
+ case 'segments':
285
+ switch (sub) {
286
+ case 'list': {
287
+ const params = new URLSearchParams()
288
+ if (args['page-size']) params.set('page[size]', args['page-size'])
289
+ const qs = params.toString()
290
+ result = await api('GET', `/segments/${qs ? '?' + qs : ''}`)
291
+ break
292
+ }
293
+ case 'get': {
294
+ const id = args.id
295
+ if (!id) { result = { error: '--id required' }; break }
296
+ result = await api('GET', `/segments/${id}/`)
297
+ break
298
+ }
299
+ default:
300
+ result = { error: 'Unknown segments subcommand. Use: list, get' }
301
+ }
302
+ break
303
+
304
+ case 'templates':
305
+ switch (sub) {
306
+ case 'list': {
307
+ const params = new URLSearchParams()
308
+ if (args.filter) params.set('filter', args.filter)
309
+ if (args['page-size']) params.set('page[size]', args['page-size'])
310
+ const qs = params.toString()
311
+ result = await api('GET', `/templates/${qs ? '?' + qs : ''}`)
312
+ break
313
+ }
314
+ case 'get': {
315
+ const id = args.id
316
+ if (!id) { result = { error: '--id required' }; break }
317
+ result = await api('GET', `/templates/${id}/`)
318
+ break
319
+ }
320
+ default:
321
+ result = { error: 'Unknown templates subcommand. Use: list, get' }
322
+ }
323
+ break
324
+
325
+ default:
326
+ result = {
327
+ error: 'Unknown command',
328
+ usage: {
329
+ profiles: 'profiles [list | get --id <id> | create --email <email> | update --id <id>]',
330
+ lists: 'lists [list | get --id <id> | create --name <name> | delete --id <id> | add-profiles --id <list-id> --profiles <id1,id2> | remove-profiles --id <list-id> --profiles <id1,id2>]',
331
+ events: 'events [list | get --id <id> | create --metric <name> --email <email>]',
332
+ campaigns: 'campaigns [list | get --id <id>]',
333
+ flows: 'flows [list | get --id <id> | update --id <id> --status <status>]',
334
+ metrics: 'metrics [list | get --id <id>]',
335
+ segments: 'segments [list | get --id <id>]',
336
+ templates: 'templates [list | get --id <id>]',
337
+ options: '--filter <filter> --page-size <n> --page-cursor <cursor>',
338
+ }
339
+ }
340
+ }
341
+
342
+ console.log(JSON.stringify(result, null, 2))
343
+ }
344
+
345
+ main().catch(err => {
346
+ console.error(JSON.stringify({ error: err.message }))
347
+ process.exit(1)
348
+ })