@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,211 @@
1
+ #!/usr/bin/env node
2
+
3
+ const API_KEY = process.env.SENDGRID_API_KEY
4
+ const BASE_URL = 'https://api.sendgrid.com/v3'
5
+
6
+ if (!API_KEY) {
7
+ console.error(JSON.stringify({ error: 'SENDGRID_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' }, 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
+ },
21
+ body: body ? JSON.stringify(body) : undefined,
22
+ })
23
+ const text = await res.text()
24
+ try {
25
+ return JSON.parse(text)
26
+ } catch {
27
+ return { status: res.status, body: text }
28
+ }
29
+ }
30
+
31
+ function parseArgs(args) {
32
+ const result = { _: [] }
33
+ for (let i = 0; i < args.length; i++) {
34
+ const arg = args[i]
35
+ if (arg.startsWith('--')) {
36
+ const key = arg.slice(2)
37
+ const next = args[i + 1]
38
+ if (next && !next.startsWith('--')) {
39
+ result[key] = next
40
+ i++
41
+ } else {
42
+ result[key] = true
43
+ }
44
+ } else {
45
+ result._.push(arg)
46
+ }
47
+ }
48
+ return result
49
+ }
50
+
51
+ const args = parseArgs(process.argv.slice(2))
52
+ const [cmd, sub, ...rest] = args._
53
+
54
+ async function main() {
55
+ let result
56
+
57
+ switch (cmd) {
58
+ case 'send': {
59
+ if (!args.from || !args.to || !args.subject) { result = { error: '--from, --to, and --subject required' }; break }
60
+ const body = {
61
+ personalizations: [{
62
+ to: args.to.split(',').map(e => ({ email: e.trim() })),
63
+ }],
64
+ from: { email: args.from },
65
+ subject: args.subject,
66
+ }
67
+ if (args['template-id']) {
68
+ body.template_id = args['template-id']
69
+ if (args['template-data']) {
70
+ try { body.personalizations[0].dynamic_template_data = JSON.parse(args['template-data']) } catch (e) { result = { error: 'Invalid JSON for --template-data: ' + e.message }; break }
71
+ }
72
+ } else {
73
+ const content = []
74
+ if (args.text) content.push({ type: 'text/plain', value: args.text })
75
+ if (args.html) content.push({ type: 'text/html', value: args.html })
76
+ if (content.length > 0) body.content = content
77
+ }
78
+ if (args.cc) body.personalizations[0].cc = args.cc.split(',').map(e => ({ email: e.trim() }))
79
+ if (args.bcc) body.personalizations[0].bcc = args.bcc.split(',').map(e => ({ email: e.trim() }))
80
+ if (args['reply-to']) body.reply_to = { email: args['reply-to'] }
81
+ result = await api('POST', '/mail/send', body)
82
+ break
83
+ }
84
+
85
+ case 'contacts':
86
+ switch (sub) {
87
+ case 'list':
88
+ result = await api('GET', '/marketing/contacts')
89
+ break
90
+ case 'add': {
91
+ const body = {
92
+ contacts: [{
93
+ email: args.email,
94
+ }],
95
+ }
96
+ if (args['first-name']) body.contacts[0].first_name = args['first-name']
97
+ if (args['last-name']) body.contacts[0].last_name = args['last-name']
98
+ if (args['list-ids']) body.list_ids = args['list-ids'].split(',')
99
+ result = await api('PUT', '/marketing/contacts', body)
100
+ break
101
+ }
102
+ case 'search': {
103
+ const body = { query: args.query }
104
+ result = await api('POST', '/marketing/contacts/search', body)
105
+ break
106
+ }
107
+ default:
108
+ result = { error: 'Unknown contacts subcommand. Use: list, add, search' }
109
+ }
110
+ break
111
+
112
+ case 'campaigns':
113
+ switch (sub) {
114
+ case 'list': {
115
+ const params = new URLSearchParams()
116
+ if (args.limit) params.set('page_size', args.limit)
117
+ result = await api('GET', `/marketing/campaigns?${params}`)
118
+ break
119
+ }
120
+ case 'get':
121
+ if (!rest[0]) { result = { error: 'Campaign ID required' }; break }
122
+ result = await api('GET', `/marketing/campaigns/${rest[0]}`)
123
+ break
124
+ default:
125
+ result = { error: 'Unknown campaigns subcommand. Use: list, get' }
126
+ }
127
+ break
128
+
129
+ case 'stats': {
130
+ switch (sub) {
131
+ case 'get': {
132
+ const params = new URLSearchParams()
133
+ if (args['start-date']) params.set('start_date', args['start-date'])
134
+ if (args['end-date']) params.set('end_date', args['end-date'])
135
+ result = await api('GET', `/stats?${params}`)
136
+ break
137
+ }
138
+ default:
139
+ result = { error: 'Unknown stats subcommand. Use: get' }
140
+ }
141
+ break
142
+ }
143
+
144
+ case 'bounces':
145
+ switch (sub) {
146
+ case 'list': {
147
+ const params = new URLSearchParams()
148
+ if (args['start-time']) params.set('start_time', args['start-time'])
149
+ if (args['end-time']) params.set('end_time', args['end-time'])
150
+ if (args.limit) params.set('limit', args.limit)
151
+ result = await api('GET', `/suppression/bounces?${params}`)
152
+ break
153
+ }
154
+ default:
155
+ result = { error: 'Unknown bounces subcommand. Use: list' }
156
+ }
157
+ break
158
+
159
+ case 'spam-reports':
160
+ switch (sub) {
161
+ case 'list': {
162
+ const params = new URLSearchParams()
163
+ if (args['start-time']) params.set('start_time', args['start-time'])
164
+ if (args['end-time']) params.set('end_time', args['end-time'])
165
+ if (args.limit) params.set('limit', args.limit)
166
+ result = await api('GET', `/suppression/spam_reports?${params}`)
167
+ break
168
+ }
169
+ default:
170
+ result = { error: 'Unknown spam-reports subcommand. Use: list' }
171
+ }
172
+ break
173
+
174
+ case 'validate':
175
+ switch (sub) {
176
+ case 'email': {
177
+ if (!args.email && !rest[0]) { result = { error: '--email required' }; break }
178
+ const body = { email: args.email || rest[0] }
179
+ result = await api('POST', '/validations/email', body)
180
+ break
181
+ }
182
+ default: {
183
+ const body = { email: sub }
184
+ result = await api('POST', '/validations/email', body)
185
+ break
186
+ }
187
+ }
188
+ break
189
+
190
+ default:
191
+ result = {
192
+ error: 'Unknown command',
193
+ usage: {
194
+ send: 'send --from <email> --to <email> --subject <subject> --html <html> [--text <text>] [--template-id <id>] [--template-data <json>]',
195
+ contacts: 'contacts [list|add|search] [--email <email>] [--first-name <name>] [--last-name <name>] [--list-ids <ids>] [--query <sgql>]',
196
+ campaigns: 'campaigns [list|get] [id] [--limit <n>]',
197
+ stats: 'stats get [--start-date <YYYY-MM-DD>] [--end-date <YYYY-MM-DD>]',
198
+ bounces: 'bounces list [--start-time <ts>] [--end-time <ts>] [--limit <n>]',
199
+ 'spam-reports': 'spam-reports list [--start-time <ts>] [--end-time <ts>] [--limit <n>]',
200
+ validate: 'validate <email> OR validate email --email <email>',
201
+ }
202
+ }
203
+ }
204
+
205
+ console.log(JSON.stringify(result, null, 2))
206
+ }
207
+
208
+ main().catch(err => {
209
+ console.error(JSON.stringify({ error: err.message }))
210
+ process.exit(1)
211
+ })
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+
3
+ const CLIENT_ID = process.env.SNOV_CLIENT_ID
4
+ const CLIENT_SECRET = process.env.SNOV_CLIENT_SECRET
5
+ const BASE_URL = 'https://api.snov.io/v1'
6
+
7
+ if (!CLIENT_ID || !CLIENT_SECRET) {
8
+ console.error(JSON.stringify({ error: 'SNOV_CLIENT_ID and SNOV_CLIENT_SECRET environment variables required' }))
9
+ process.exit(1)
10
+ }
11
+
12
+ let cachedToken = null
13
+
14
+ async function getToken() {
15
+ if (cachedToken) return cachedToken
16
+ const res = await fetch('https://api.snov.io/v1/oauth/access_token', {
17
+ method: 'POST',
18
+ headers: { 'Content-Type': 'application/json' },
19
+ body: JSON.stringify({ grant_type: 'client_credentials', client_id: CLIENT_ID, client_secret: CLIENT_SECRET }),
20
+ })
21
+ const data = await res.json()
22
+ if (!data.access_token) {
23
+ throw new Error(data.error_description || data.error || 'Failed to obtain access token')
24
+ }
25
+ cachedToken = data.access_token
26
+ return cachedToken
27
+ }
28
+
29
+ async function api(method, path, body) {
30
+ if (args['dry-run']) {
31
+ return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { Authorization: '***', 'Content-Type': 'application/json', Accept: 'application/json' }, body: body || undefined }
32
+ }
33
+ const token = await getToken()
34
+ const opts = {
35
+ method,
36
+ headers: {
37
+ 'Authorization': `Bearer ${token}`,
38
+ 'Content-Type': 'application/json',
39
+ 'Accept': 'application/json',
40
+ },
41
+ }
42
+ if (body) opts.body = JSON.stringify(body)
43
+ const res = await fetch(`${BASE_URL}${path}`, opts)
44
+ const text = await res.text()
45
+ try {
46
+ return JSON.parse(text)
47
+ } catch {
48
+ return { status: res.status, body: text }
49
+ }
50
+ }
51
+
52
+ function parseArgs(args) {
53
+ const result = { _: [] }
54
+ for (let i = 0; i < args.length; i++) {
55
+ const arg = args[i]
56
+ if (arg.startsWith('--')) {
57
+ const key = arg.slice(2)
58
+ const next = args[i + 1]
59
+ if (next && !next.startsWith('--')) {
60
+ result[key] = next
61
+ i++
62
+ } else {
63
+ result[key] = true
64
+ }
65
+ } else {
66
+ result._.push(arg)
67
+ }
68
+ }
69
+ return result
70
+ }
71
+
72
+ const args = parseArgs(process.argv.slice(2))
73
+ const [cmd, sub, ...rest] = args._
74
+
75
+ async function main() {
76
+ let result
77
+
78
+ switch (cmd) {
79
+ case 'domain':
80
+ switch (sub) {
81
+ case 'search': {
82
+ const domain = args.domain
83
+ if (!domain) { result = { error: '--domain required' }; break }
84
+ const body = { domain, type: args.type || 'all', limit: Number(args.limit || 100), lastId: 0 }
85
+ result = await api('POST', '/get-domain-emails-with-info', body)
86
+ break
87
+ }
88
+ case 'count': {
89
+ const domain = args.domain
90
+ if (!domain) { result = { error: '--domain required' }; break }
91
+ result = await api('POST', '/get-domain-emails-count', { domain })
92
+ break
93
+ }
94
+ default:
95
+ result = { error: 'Unknown domain subcommand. Use: search, count' }
96
+ }
97
+ break
98
+
99
+ case 'email':
100
+ switch (sub) {
101
+ case 'find': {
102
+ const domain = args.domain
103
+ const firstName = args['first-name']
104
+ const lastName = args['last-name']
105
+ if (!domain || !firstName || !lastName) { result = { error: '--domain, --first-name, and --last-name required' }; break }
106
+ result = await api('POST', '/get-emails-from-names', { firstName, lastName, domain })
107
+ break
108
+ }
109
+ case 'verify': {
110
+ const email = args.email
111
+ if (!email) { result = { error: '--email required' }; break }
112
+ result = await api('POST', '/get-emails-verification-status', { emails: [email] })
113
+ break
114
+ }
115
+ default:
116
+ result = { error: 'Unknown email subcommand. Use: find, verify' }
117
+ }
118
+ break
119
+
120
+ case 'prospect':
121
+ switch (sub) {
122
+ case 'find': {
123
+ const email = args.email
124
+ if (!email) { result = { error: '--email required' }; break }
125
+ result = await api('POST', '/get-prospect-by-email', { email })
126
+ break
127
+ }
128
+ case 'add': {
129
+ const email = args.email
130
+ if (!email) { result = { error: '--email required' }; break }
131
+ const body = { email }
132
+ if (args['first-name']) body.firstName = args['first-name']
133
+ if (args['last-name']) body.lastName = args['last-name']
134
+ if (args['list-id']) body.listId = args['list-id']
135
+ result = await api('POST', '/add-prospect-to-list', body)
136
+ break
137
+ }
138
+ default:
139
+ result = { error: 'Unknown prospect subcommand. Use: find, add' }
140
+ }
141
+ break
142
+
143
+ case 'lists':
144
+ switch (sub) {
145
+ case 'list':
146
+ result = await api('GET', '/get-user-lists')
147
+ break
148
+ case 'prospects': {
149
+ const id = args.id
150
+ if (!id) { result = { error: '--id required' }; break }
151
+ const body = { listId: id }
152
+ if (args.page) body.page = Number(args.page)
153
+ if (args['per-page']) body.perPage = Number(args['per-page'])
154
+ result = await api('POST', '/prospect-list', body)
155
+ break
156
+ }
157
+ default:
158
+ result = { error: 'Unknown lists subcommand. Use: list, prospects' }
159
+ }
160
+ break
161
+
162
+ case 'technology':
163
+ switch (sub) {
164
+ case 'check': {
165
+ const domain = args.domain
166
+ if (!domain) { result = { error: '--domain required' }; break }
167
+ result = await api('POST', '/get-technology-checker', { domain })
168
+ break
169
+ }
170
+ default:
171
+ result = { error: 'Unknown technology subcommand. Use: check' }
172
+ }
173
+ break
174
+
175
+ case 'drips':
176
+ switch (sub) {
177
+ case 'list':
178
+ result = await api('GET', '/get-user-campaigns')
179
+ break
180
+ case 'get': {
181
+ const id = args.id
182
+ if (!id) { result = { error: '--id required' }; break }
183
+ result = await api('GET', `/get-emails-from-campaign?id=${encodeURIComponent(id)}`)
184
+ break
185
+ }
186
+ case 'add-prospect': {
187
+ const campaignId = args['campaign-id']
188
+ const email = args.email
189
+ if (!campaignId || !email) { result = { error: '--campaign-id and --email required' }; break }
190
+ const body = { campaignId, email }
191
+ if (args['first-name']) body.firstName = args['first-name']
192
+ if (args['last-name']) body.lastName = args['last-name']
193
+ result = await api('POST', '/add-prospect-to-email-campaign', body)
194
+ break
195
+ }
196
+ default:
197
+ result = { error: 'Unknown drips subcommand. Use: list, get, add-prospect' }
198
+ }
199
+ break
200
+
201
+ default:
202
+ result = {
203
+ error: 'Unknown command',
204
+ usage: {
205
+ domain: {
206
+ search: 'domain search --domain <domain> [--type all|personal|generic] [--limit <n>]',
207
+ count: 'domain count --domain <domain>',
208
+ },
209
+ email: {
210
+ find: 'email find --domain <domain> --first-name <name> --last-name <name>',
211
+ verify: 'email verify --email <email>',
212
+ },
213
+ prospect: {
214
+ find: 'prospect find --email <email>',
215
+ add: 'prospect add --email <email> [--first-name <name>] [--last-name <name>] [--list-id <id>]',
216
+ },
217
+ lists: {
218
+ list: 'lists list',
219
+ prospects: 'lists prospects --id <id> [--page <n>] [--per-page <n>]',
220
+ },
221
+ technology: 'technology check --domain <domain>',
222
+ drips: {
223
+ list: 'drips list',
224
+ get: 'drips get --id <id>',
225
+ 'add-prospect': 'drips add-prospect --campaign-id <id> --email <email> [--first-name <name>] [--last-name <name>]',
226
+ },
227
+ }
228
+ }
229
+ }
230
+
231
+ console.log(JSON.stringify(result, null, 2))
232
+ }
233
+
234
+ main().catch(err => {
235
+ console.error(JSON.stringify({ error: err.message }))
236
+ process.exit(1)
237
+ })
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env node
2
+
3
+ const TOKEN = process.env.TIKTOK_ACCESS_TOKEN
4
+ const ADVERTISER_ID = process.env.TIKTOK_ADVERTISER_ID
5
+ const BASE_URL = 'https://business-api.tiktok.com/open_api/v1.3'
6
+
7
+ if (!TOKEN) {
8
+ console.error(JSON.stringify({ error: 'TIKTOK_ACCESS_TOKEN environment variable required' }))
9
+ process.exit(1)
10
+ }
11
+
12
+ async function api(method, path, body) {
13
+ if (args['dry-run']) {
14
+ return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { 'Access-Token': '***', 'Content-Type': 'application/json' }, body: body || undefined }
15
+ }
16
+ const opts = {
17
+ method,
18
+ headers: {
19
+ 'Access-Token': TOKEN,
20
+ 'Content-Type': 'application/json',
21
+ },
22
+ }
23
+ if (body && method === 'POST') {
24
+ opts.body = JSON.stringify(body)
25
+ }
26
+ const res = await fetch(`${BASE_URL}${path}`, opts)
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
+ function getAdvertiserId() {
59
+ return args['advertiser-id'] || ADVERTISER_ID
60
+ }
61
+
62
+ async function main() {
63
+ let result
64
+
65
+ switch (cmd) {
66
+ case 'advertiser':
67
+ switch (sub) {
68
+ case 'info': {
69
+ const advId = getAdvertiserId()
70
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
71
+ const advParams = new URLSearchParams({ advertiser_ids: JSON.stringify([advId]) })
72
+ result = await api('GET', `/advertiser/info/?${advParams}`)
73
+ break
74
+ }
75
+ default:
76
+ result = { error: 'Unknown advertiser subcommand. Use: info' }
77
+ }
78
+ break
79
+
80
+ case 'campaigns':
81
+ switch (sub) {
82
+ case 'list': {
83
+ const advId = getAdvertiserId()
84
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
85
+ const campParams = new URLSearchParams({ advertiser_id: advId, page: '1', page_size: '20' })
86
+ result = await api('GET', `/campaign/get/?${campParams}`)
87
+ break
88
+ }
89
+ case 'create': {
90
+ const advId = getAdvertiserId()
91
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
92
+ if (!args.name || !args.objective) { result = { error: '--name and --objective required' }; break }
93
+ const body = {
94
+ advertiser_id: advId,
95
+ campaign_name: args.name,
96
+ objective_type: args.objective,
97
+ budget_mode: args['budget-mode'] || 'BUDGET_MODE_DAY',
98
+ }
99
+ if (args.budget) body.budget = parseFloat(args.budget)
100
+ result = await api('POST', '/campaign/create/', body)
101
+ break
102
+ }
103
+ case 'update-status': {
104
+ const advId = getAdvertiserId()
105
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
106
+ if (!args.ids || !args.status) { result = { error: '--ids and --status required' }; break }
107
+ result = await api('POST', '/campaign/status/update/', {
108
+ advertiser_id: advId,
109
+ campaign_ids: args.ids.split(','),
110
+ opt_status: args.status,
111
+ })
112
+ break
113
+ }
114
+ default:
115
+ result = { error: 'Unknown campaigns subcommand. Use: list, create, update-status' }
116
+ }
117
+ break
118
+
119
+ case 'adgroups':
120
+ switch (sub) {
121
+ case 'list': {
122
+ const advId = getAdvertiserId()
123
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
124
+ const agParams = new URLSearchParams({ advertiser_id: advId })
125
+ if (args['campaign-id']) agParams.set('campaign_ids', JSON.stringify([args['campaign-id']]))
126
+ result = await api('GET', `/adgroup/get/?${agParams}`)
127
+ break
128
+ }
129
+ default:
130
+ result = { error: 'Unknown adgroups subcommand. Use: list' }
131
+ }
132
+ break
133
+
134
+ case 'reports':
135
+ switch (sub) {
136
+ case 'get': {
137
+ const advId = getAdvertiserId()
138
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
139
+ if (!args['start-date'] || !args['end-date']) { result = { error: '--start-date and --end-date required (YYYY-MM-DD)' }; break }
140
+ const body = {
141
+ advertiser_id: advId,
142
+ report_type: 'BASIC',
143
+ dimensions: args.dimensions ? args.dimensions.split(',') : ['campaign_id'],
144
+ metrics: args.metrics ? args.metrics.split(',') : ['spend', 'impressions', 'clicks', 'conversion'],
145
+ data_level: args['data-level'] || 'AUCTION_CAMPAIGN',
146
+ start_date: args['start-date'],
147
+ end_date: args['end-date'],
148
+ }
149
+ result = await api('POST', '/report/integrated/get/', body)
150
+ break
151
+ }
152
+ default:
153
+ result = { error: 'Unknown reports subcommand. Use: get' }
154
+ }
155
+ break
156
+
157
+ case 'audiences':
158
+ switch (sub) {
159
+ case 'list': {
160
+ const advId = getAdvertiserId()
161
+ if (!advId) { result = { error: 'TIKTOK_ADVERTISER_ID env or --advertiser-id required' }; break }
162
+ const audParams = new URLSearchParams({ advertiser_id: advId })
163
+ result = await api('GET', `/dmp/custom_audience/list/?${audParams}`)
164
+ break
165
+ }
166
+ default:
167
+ result = { error: 'Unknown audiences subcommand. Use: list' }
168
+ }
169
+ break
170
+
171
+ default:
172
+ result = {
173
+ error: 'Unknown command',
174
+ usage: {
175
+ advertiser: 'advertiser [info]',
176
+ campaigns: 'campaigns [list|create|update-status] [--name <name>] [--objective <obj>] [--budget-mode BUDGET_MODE_DAY] [--budget <amount>] [--ids <id1,id2>] [--status ENABLE|DISABLE]',
177
+ adgroups: 'adgroups [list] [--campaign-id <id>]',
178
+ reports: 'reports [get] --start-date YYYY-MM-DD --end-date YYYY-MM-DD [--dimensions campaign_id] [--metrics spend,impressions,clicks,conversion] [--data-level AUCTION_CAMPAIGN]',
179
+ audiences: 'audiences [list]',
180
+ },
181
+ }
182
+ }
183
+
184
+ console.log(JSON.stringify(result, null, 2))
185
+ }
186
+
187
+ main().catch(err => {
188
+ console.error(JSON.stringify({ error: err.message }))
189
+ process.exit(1)
190
+ })