@adkit/cli 1.12.4 → 1.12.9

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 (2) hide show
  1. package/dist/cli.js +151 -108
  2. package/package.json +4 -1
package/dist/cli.js CHANGED
@@ -1,12 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // ../shared/dist/utils/service-status.js
4
- var ADKIT_STATUS_NOTICE = null;
5
- function getAdKitStatusNotice() {
6
- const statusNotice = ADKIT_STATUS_NOTICE?.trim();
7
- return statusNotice ? `Active AdKit status notice: ${statusNotice}` : void 0;
8
- }
9
-
10
3
  // src/config.ts
11
4
  import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
12
5
  import { join } from "node:path";
@@ -72,6 +65,15 @@ function readLegacyProjectApiKey(config, selectedProject) {
72
65
  return config.projects?.[selectedProject]?.apiKey ?? null;
73
66
  }
74
67
 
68
+ // ../shared/dist/errors.js
69
+ function describeRetryDelay(retryAfterSeconds) {
70
+ if (!retryAfterSeconds || retryAfterSeconds <= 300)
71
+ return "in a few minutes";
72
+ if (retryAfterSeconds <= 3600)
73
+ return "within the hour";
74
+ return "in a few hours";
75
+ }
76
+
75
77
  // src/errors.ts
76
78
  var CliError = class extends Error {
77
79
  code;
@@ -86,6 +88,19 @@ var CliError = class extends Error {
86
88
  };
87
89
 
88
90
  // src/client.ts
91
+ var noticePrinted = false;
92
+ function printServerNotice(response) {
93
+ if (noticePrinted) return;
94
+ const encoded = response.headers.get("x-adkit-notice");
95
+ if (!encoded) return;
96
+ noticePrinted = true;
97
+ const text = decodeURIComponent(encoded);
98
+ const dim = "\x1B[2m";
99
+ const yellow = "\x1B[33m";
100
+ const reset = "\x1B[0m";
101
+ process.stderr.write(`${yellow}${dim}[AdKit notice] ${text}${reset}
102
+ `);
103
+ }
89
104
  function isErrorResponse(value) {
90
105
  return value != null && typeof value === "object";
91
106
  }
@@ -135,12 +150,18 @@ function appendErrorDetail(message, detail) {
135
150
  }
136
151
  function buildRetrySuggestion(retryable, retryAfterSeconds) {
137
152
  if (retryable !== true) return void 0;
138
- if (typeof retryAfterSeconds === "number") return `Wait ${String(retryAfterSeconds)} seconds before retrying`;
153
+ if (typeof retryAfterSeconds === "number" && retryAfterSeconds <= 300) return `Wait ${String(retryAfterSeconds)} seconds before retrying`;
154
+ if (typeof retryAfterSeconds === "number") return `Try again ${describeRetryDelay(retryAfterSeconds)}`;
139
155
  return "Retry in a few seconds";
140
156
  }
141
- var AUTH_CODES = /* @__PURE__ */ new Set(["not_connected", "token_expired", "refresh_token_expired"]);
157
+ function buildMetaDsaSuggestion(code) {
158
+ if (code !== "meta_dsa_identity_required") return void 0;
159
+ return 'Run: adkit manage meta accounts <account-id> update --beneficiary "<promoted person/org>" --payor "<payer>"';
160
+ }
161
+ var AUTH_CODES = /* @__PURE__ */ new Set(["invalid_grant", "auth_error", "auth_expired", "not_connected", "token_expired", "refresh_token_expired"]);
142
162
  function buildAuthSuggestion(code) {
143
- if (!AUTH_CODES.has(code)) return void 0;
163
+ const normalizedCode = code.toLowerCase();
164
+ if (!AUTH_CODES.has(normalizedCode)) return void 0;
144
165
  return "Run: adkit setup manage";
145
166
  }
146
167
  var AdkitClient = class {
@@ -178,6 +199,7 @@ var AdkitClient = class {
178
199
  const detail = code ?? (err instanceof Error ? err.message : String(err));
179
200
  throw new CliError("NETWORK_ERROR", `Cannot reach ${target} (${detail})`, "Verify your network connection");
180
201
  }
202
+ printServerNotice(response);
181
203
  if (response.status === 204) return void 0;
182
204
  if (!response.ok) {
183
205
  let serverMessage = "";
@@ -201,7 +223,7 @@ var AdkitClient = class {
201
223
  if (structured) {
202
224
  const fallbackMsg = response.status >= 500 ? `Server error (HTTP ${String(response.status)})` : `Request failed (HTTP ${String(response.status)})`;
203
225
  const errorMsg = appendErrorDetail(dataMessage || serverMessage || fallbackMsg, batchSummary);
204
- const suggestion2 = buildRetrySuggestion(retryable, retryAfterSeconds) ?? buildAuthSuggestion(structured.code);
226
+ const suggestion2 = buildMetaDsaSuggestion(structured.code) ?? buildRetrySuggestion(retryable, retryAfterSeconds) ?? buildAuthSuggestion(structured.code);
205
227
  const error = new CliError(structured.code, errorMsg, suggestion2);
206
228
  error.instructions = structured.instructions;
207
229
  error.actionUrl = structured.actionUrl;
@@ -2656,12 +2678,12 @@ var PLATFORM_OVERRIDE_FLAG = "platform-overrides";
2656
2678
  var CAMPAIGN_CREATE_FLAGS = ["name", "objective", "status", "budget-daily", "budget-lifetime", PLATFORM_OVERRIDE_FLAG];
2657
2679
  var CAMPAIGN_UPDATE_FLAGS = ["name", "status", "budget-daily", "budget-lifetime", PLATFORM_OVERRIDE_FLAG];
2658
2680
  var AD_GROUP_LIST_FLAGS2 = ["campaign-ids", "fields", "limit", "offset"];
2659
- var AD_GROUP_CREATE_FLAGS = ["campaign", "name", "status", "budget-daily", "budget-lifetime", "billing-event", "bid-strategy", "optimization", "schedule-start-time", "schedule-end-time", "schedule-type", "pacing", "bid-amount", "event-type", "pixel", "placement", PLATFORM_OVERRIDE_FLAG];
2660
- var AD_GROUP_UPDATE_FLAGS = ["name", "status", "budget-daily", "budget-lifetime", "billing-event", "optimization", "schedule-start-time", "schedule-end-time", "schedule-type", "pacing", "bid-amount", "event-type", "pixel", PLATFORM_OVERRIDE_FLAG];
2681
+ var AD_GROUP_CREATE_FLAGS = ["campaign", "name", "status", "budget-daily", "budget-lifetime", "billing-event", "bid-strategy", "optimization", "start-date", "end-date", "pacing", "bid-amount", "event-type", "pixel", "placement", PLATFORM_OVERRIDE_FLAG];
2682
+ var AD_GROUP_UPDATE_FLAGS = ["name", "status", "budget-daily", "budget-lifetime", "billing-event", "optimization", "start-date", "end-date", "pacing", "bid-amount", "event-type", "pixel", PLATFORM_OVERRIDE_FLAG];
2661
2683
  var AD_LIST_FLAGS2 = ["ad-group-ids", "campaign-ids", "fields", "limit", "offset"];
2662
2684
  var AD_CREATE_FLAGS = ["ad-group", "name", "status", "media-id", "ad-text", "url", "cta", "display-name", "identity-id", "identity-type", "tracking-pixel", PLATFORM_OVERRIDE_FLAG];
2663
2685
  var AD_UPDATE_FLAGS = ["ad-group", "name", "status", "media-id", "ad-text", "url", "cta", "display-name", "identity-id", "identity-type", "tracking-pixel", PLATFORM_OVERRIDE_FLAG];
2664
- var RESULTS_FLAGS = ["level", "dimensions", "metrics", "from", "to", "order-field", "order-type", "limit", "offset"];
2686
+ var RESULTS_FLAGS = ["level", "fields", "breakdowns", "from", "to", "sort", "sort-direction", "limit", "offset"];
2665
2687
  function readSingleFlagValue2(flags, key, duplicateHint) {
2666
2688
  const value = flags[key];
2667
2689
  if (Array.isArray(value)) {
@@ -2800,19 +2822,15 @@ function buildTikTokAdGroupPayload(flags, mode) {
2800
2822
  if (mode === "create") {
2801
2823
  payload.campaignId = requireFlag(flags, "campaign", 'Run: adkit manage tiktok ad-groups create --campaign <campaign-id> --name "US Broad"');
2802
2824
  payload.name = requireFlag(flags, "name", 'Run: adkit manage tiktok ad-groups create --name "US Broad"');
2803
- payload.scheduleStartTime = requireFlag(flags, "schedule-start-time", "Use YYYY-MM-DD HH:mm:ss, or pass a full JSON body with --data");
2804
- } else {
2805
- if (typeof flags.name === "string") payload.name = flags.name;
2806
- if (typeof flags["schedule-start-time"] === "string") payload.scheduleStartTime = flags["schedule-start-time"];
2807
- }
2825
+ } else if (typeof flags.name === "string") payload.name = flags.name;
2808
2826
  const budget = buildTikTokBudget(flags);
2809
2827
  if (budget) payload.budget = budget;
2810
2828
  if (typeof flags.status === "string") payload.status = flags.status;
2811
2829
  if (typeof flags["billing-event"] === "string") payload.billingEvent = flags["billing-event"];
2812
2830
  if (mode === "create" && typeof flags["bid-strategy"] === "string") payload.bidStrategy = flags["bid-strategy"];
2813
2831
  if (typeof flags.optimization === "string") payload.optimization = flags.optimization;
2814
- if (typeof flags["schedule-end-time"] === "string") payload.scheduleEndTime = flags["schedule-end-time"];
2815
- if (typeof flags["schedule-type"] === "string") payload.scheduleType = flags["schedule-type"];
2832
+ if (typeof flags["start-date"] === "string") payload.startDate = flags["start-date"];
2833
+ if (typeof flags["end-date"] === "string") payload.endDate = flags["end-date"];
2816
2834
  if (typeof flags.pacing === "string") payload.pacing = flags.pacing;
2817
2835
  const bidAmount = readNumberFlag(flags, "bid-amount");
2818
2836
  if (bidAmount !== void 0) payload.bidAmount = bidAmount;
@@ -2986,14 +3004,14 @@ async function listTikTokResults(client, _args, flags) {
2986
3004
  const accountId = typeof flags.account === "string" ? flags.account : void 0;
2987
3005
  const query = queryString({
2988
3006
  accountId,
2989
- dimensions: typeof flags.dimensions === "string" ? flags.dimensions : void 0,
3007
+ breakdowns: typeof flags.breakdowns === "string" ? flags.breakdowns : void 0,
3008
+ fields: typeof flags.fields === "string" ? flags.fields : void 0,
2990
3009
  from: typeof flags.from === "string" ? flags.from : void 0,
2991
3010
  level: typeof flags.level === "string" ? flags.level : void 0,
2992
3011
  limit: typeof flags.limit === "string" ? flags.limit : void 0,
2993
- metrics: typeof flags.metrics === "string" ? flags.metrics : void 0,
2994
3012
  offset: typeof flags.offset === "string" ? flags.offset : void 0,
2995
- orderField: typeof flags["order-field"] === "string" ? flags["order-field"] : void 0,
2996
- orderType: typeof flags["order-type"] === "string" ? flags["order-type"] : void 0,
3013
+ sort: typeof flags.sort === "string" ? flags.sort : void 0,
3014
+ sortDirection: typeof flags["sort-direction"] === "string" ? flags["sort-direction"] : void 0,
2997
3015
  to: typeof flags.to === "string" ? flags.to : void 0
2998
3016
  });
2999
3017
  return client.get(`/manage/tiktok/results${query}`);
@@ -4089,13 +4107,15 @@ Rules:
4089
4107
  Note:
4090
4108
  list returns ad set configuration only (targeting, budget, optimization).
4091
4109
  AdKit hides deleted and archived ad sets by default. Use --status to include them.
4092
- Geo targeting lives in targeting.geoLocations. Use type=country for country targeting.
4093
- Advanced geo examples: adkit manage meta adsets --help full
4110
+ Geo targeting lives in targeting.geoLocations. Use type=country or type=radius with latitude/longitude coordinates.
4111
+ Native city/place/zip examples: adkit manage meta adsets --help full
4094
4112
  For spend/clicks/conversions: adkit manage meta results
4095
4113
 
4096
4114
  Examples:
4097
4115
  # Conversion-optimized ad set targeting the US
4098
4116
  adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"US Broad","optimization":"conversions","eventType":"purchase","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]}}}' --publish
4117
+ # Radius targeting around coordinates
4118
+ adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"Strijen 30km","optimization":"link_clicks","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"radius","latitude":51.745,"longitude":4.55,"radius":30,"radiusUnit":"km"}]}}}' --publish
4099
4119
  # Target specific interests
4100
4120
  adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"US SaaS","optimization":"conversions","eventType":"purchase","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]},"interests":["6003344765839","6003127206524"]}}' --publish
4101
4121
  # Engagement-optimized ad set
@@ -4155,7 +4175,7 @@ Advanced flags:
4155
4175
  promotedObject.customEventType (string) Custom conversion event
4156
4176
  promotedObject.pageId (string) Facebook Page ID
4157
4177
  targeting.age (object) {"min":25,"max":55}
4158
- targeting.geoLocations (object) {"include":[{"type":"country","country":"US"}]} or {"include":[{"type":"platformLocation","platform":"meta","value":{"custom_locations":[...]}}]}
4178
+ targeting.geoLocations (object) {"include":[{"type":"country","country":"US"}]} or {"include":[{"type":"radius","latitude":51.745,"longitude":4.55,"radius":30,"radiusUnit":"km"}]}
4159
4179
  targeting.publisherPlatforms (string[]) facebook, instagram, audience_network, messenger
4160
4180
  targeting.devicePlatforms (string[]) mobile, desktop
4161
4181
  targeting.interests (string[]) Interest IDs
@@ -4172,15 +4192,16 @@ Advanced flags:
4172
4192
  Note:
4173
4193
  list returns ad set configuration only (targeting, budget, optimization).
4174
4194
  AdKit hides deleted and archived ad sets by default. Use --status to include them.
4175
- Geo targeting lives in targeting.geoLocations. Use type=country for simple countries, or type=platformLocation for raw Meta geo like custom_locations.
4176
- With platformLocation, pass the exact Meta geo object to send; AdKit does not look up or convert city names or addresses.
4195
+ Geo targeting lives in targeting.geoLocations. Use type=country for simple countries or type=radius for coordinate-radius targeting.
4196
+ Radius targeting requires latitude/longitude coordinates; AdKit does not geocode addresses yet.
4197
+ With platformLocation, pass the exact Meta geo object to send for native city/place/zip IDs and unsupported geo fields.
4177
4198
  For spend/clicks/conversions: adkit manage meta results
4178
4199
 
4179
4200
  Examples:
4180
4201
  # Conversion-optimized ad set targeting the US
4181
4202
  adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"US Broad","optimization":"conversions","eventType":"purchase","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]}}}' --publish
4182
- # Radius targeting through raw Meta geo
4183
- adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"SF 5mi","optimization":"link_clicks","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"platformLocation","platform":"meta","value":{"custom_locations":[{"latitude":37.7749,"longitude":-122.4194,"radius":5,"distance_unit":"mile"}]}}]}}}' --publish
4203
+ # Radius targeting around coordinates
4204
+ adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"Strijen 30km","optimization":"link_clicks","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"radius","latitude":51.745,"longitude":4.55,"radius":30,"radiusUnit":"km"}]}}}' --publish
4184
4205
  # Target specific interests
4185
4206
  adkit manage meta adsets create --data '{"campaignId":"cmp_abc","name":"US SaaS","optimization":"conversions","eventType":"purchase","budget":{"daily":20},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]},"interests":["6003344765839","6003127206524"]}}' --publish
4186
4207
  # Full JSON payload with custom targeting and age range
@@ -4205,7 +4226,7 @@ var ADS_HELP = `adkit manage meta ads \u2014 Meta ads
4205
4226
 
4206
4227
  Flags (create \u2014 new creative from media):
4207
4228
  --adset <id> Ad set ID (required)
4208
- --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically
4229
+ --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically for single-image/video ads
4209
4230
  --primary-text <t> Ad body text (repeatable)
4210
4231
  --headline <text> Headline text (repeatable)
4211
4232
  --description <t> Description text (repeatable, optional)
@@ -4232,6 +4253,7 @@ Note:
4232
4253
  update is partial. If --data sends an array field, it replaces that whole array; omitted arrays stay unchanged.
4233
4254
  list returns ad configuration only (creative, status, adset).
4234
4255
  AdKit hides deleted and archived ads by default. Use --status to include them.
4256
+ Single-image/video ads use --media. Carousel ads use --data with carouselCards.
4235
4257
 
4236
4258
  Examples:
4237
4259
  # Create an ad with a local video file
@@ -4254,7 +4276,7 @@ Examples:
4254
4276
  Tip: to share engagement (likes/comments) across ads, reuse the creative ID
4255
4277
  from your first ad: --creative <id>
4256
4278
 
4257
- Run --help full for all fields including per-placement creative (--media-format).`;
4279
+ Run --help full for all fields including carouselCards and per-placement creative (--media-format).`;
4258
4280
  var ADS_HELP_FULL = `adkit manage meta ads \u2014 Meta ads
4259
4281
 
4260
4282
  list List ads
@@ -4265,7 +4287,7 @@ var ADS_HELP_FULL = `adkit manage meta ads \u2014 Meta ads
4265
4287
 
4266
4288
  Flags (create \u2014 new creative from media):
4267
4289
  --adset <id> Ad set ID (required)
4268
- --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically
4290
+ --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically for single-image/video ads
4269
4291
  --media-format <f> Optional format for each --media: default, square, vertical, horizontal
4270
4292
  --primary-text <t> Ad body text (repeatable)
4271
4293
  --headline <text> Headline text (repeatable)
@@ -4293,6 +4315,7 @@ Note:
4293
4315
  update is partial. If --data sends an array field, it replaces that whole array; omitted arrays stay unchanged.
4294
4316
  list returns ad configuration only (creative, status, adset).
4295
4317
  AdKit hides deleted and archived ads by default. Use --status to include them.
4318
+ Single-image/video ads use --media. Carousel ads use --data with carouselCards.
4296
4319
 
4297
4320
  --data JSON fields:
4298
4321
  adsetId (required) Parent ad set ID
@@ -4303,6 +4326,17 @@ Note:
4303
4326
  Keeps its likes/comments/shares. Cannot combine with media/creative fields.
4304
4327
  media [{ id: "imageHashOrVideoId" }, { id: "...", format: "vertical" }]
4305
4328
  Normal media works on all placements. Add format only to replace a specific placement group with different media: square (Feed), vertical (Stories/Reels), horizontal (Right Column).
4329
+ Do not use top-level media for carousel ads.
4330
+ carouselCards
4331
+ Card list for carousel ads. Each card needs headline and media.
4332
+ carouselCards[].headline
4333
+ Required card title.
4334
+ carouselCards[].description
4335
+ Optional card text.
4336
+ carouselCards[].linkUrl
4337
+ Optional card destination. Defaults to url when omitted.
4338
+ carouselCards[].media
4339
+ Required card media: [{ role: "image"|"video", id }]. Use uploaded image hashes or video IDs.
4306
4340
  leadFormId Existing Meta Instant Form ID; requires media + url
4307
4341
  platformOverrides Raw Meta API fields merged onto the payload
4308
4342
 
@@ -4323,6 +4357,17 @@ Examples:
4323
4357
  adkit manage meta ads create --adset as_789 \\
4324
4358
  --media ./feed.jpg --media ./story.mp4 --media-format default --media-format vertical \\
4325
4359
  --primary-text "Try it free" --headline "Get started" --url https://example.com --publish
4360
+ # Create a carousel ad with existing uploaded media IDs
4361
+ adkit manage meta ads create --data '{
4362
+ "ads":[{
4363
+ "adsetId":"as_789","name":"Carousel v1","pageId":"pg_123",
4364
+ "primaryTexts":["Shop the collection"],"url":"https://example.com","cta":"shop_now",
4365
+ "carouselCards":[
4366
+ {"headline":"Product 1","media":[{"role":"image","id":"abc123hash"}]},
4367
+ {"headline":"Product 2","media":[{"role":"video","id":"120..."}]}
4368
+ ]
4369
+ }]
4370
+ }' --publish
4326
4371
  # Create an ad from an existing creative (shares engagement)
4327
4372
  adkit manage meta ads create --adset as_789 --creative cr_abc --name "Hero v1" --publish
4328
4373
  # Use an existing Facebook post as the ad
@@ -4471,7 +4516,7 @@ var GOOGLE_ASSET_HELP = `adkit manage google assets \u2014 Reusable Google manua
4471
4516
  Flags (list):
4472
4517
  --type <type> callout, sitelink, structured-snippet
4473
4518
  --scope <scope> account, campaign, ad-group
4474
- --scope-id <id> Campaign/ad-group ID for scoped filtering
4519
+ --scope-id <id> Google campaign/ad group ID (platformId); required for campaign/ad-group scope
4475
4520
 
4476
4521
  Flags (create/update):
4477
4522
  --type <type> callout, sitelink, structured-snippet
@@ -4483,7 +4528,7 @@ Flags (create/update):
4483
4528
  Flags (attach/detach):
4484
4529
  --type <type> callout, sitelink, structured-snippet, image
4485
4530
  --scope <scope> account, campaign, ad-group
4486
- --scope-id <id> Required for campaign/ad-group scope
4531
+ --scope-id <id> Google campaign/ad group ID (platformId); required for campaign/ad-group scope
4487
4532
 
4488
4533
  Examples:
4489
4534
  adkit manage google assets list --type callout --account 1234567890
@@ -4510,7 +4555,7 @@ var GOOGLE_ASSET_HELP_FULL = `adkit manage google assets \u2014 Reusable Google
4510
4555
  Flags (list):
4511
4556
  --type <type> callout, sitelink, structured-snippet
4512
4557
  --scope <scope> account, campaign, ad-group
4513
- --scope-id <id> Campaign/ad-group ID for scoped filtering
4558
+ --scope-id <id> Google campaign/ad group ID (platformId); required for campaign/ad-group scope
4514
4559
  ${FLAG.account}
4515
4560
 
4516
4561
  Flags (create/update):
@@ -4532,7 +4577,7 @@ ${FLAG.data}
4532
4577
  Flags (attach/detach):
4533
4578
  --type <type> callout, sitelink, structured-snippet, image
4534
4579
  --scope <scope> account, campaign, ad-group
4535
- --scope-id <id> Required for campaign/ad-group scope
4580
+ --scope-id <id> Google campaign/ad group ID (platformId); required for campaign/ad-group scope
4536
4581
  --status <s> enabled, paused, removed
4537
4582
  ${FLAG.account}
4538
4583
  ${FLAG.publish}
@@ -4550,9 +4595,9 @@ var GOOGLE_CAMPAIGN_HELP = `adkit manage google campaigns \u2014 Google Ads camp
4550
4595
 
4551
4596
  list List campaigns
4552
4597
  create Create a campaign
4553
- update <id> Update a campaign
4554
- delete <id> Delete a campaign
4555
- <id> View campaign details
4598
+ update <id> Update by Google campaign ID (platformId)
4599
+ delete <id> Delete by Google campaign ID (platformId)
4600
+ <id> View by Google campaign ID (platformId)
4556
4601
 
4557
4602
  Flags (create):
4558
4603
  --name <name> Campaign name (required)
@@ -4578,6 +4623,7 @@ Note:
4578
4623
  Advanced geo examples: adkit manage google campaigns --help full
4579
4624
  Display creation starts here: campaigns create --campaign-type display, then create Display ad groups and responsive_display ads.
4580
4625
  Performance Max: campaignType "performance_max" with asset groups \u2014 build it with --data. See --help full.
4626
+ View a Performance Max campaign by ID to read back its assetGroups from Google.
4581
4627
  For spend/clicks/conversions: adkit manage google results
4582
4628
 
4583
4629
  Examples:
@@ -4592,9 +4638,9 @@ var GOOGLE_CAMPAIGN_HELP_FULL = `adkit manage google campaigns \u2014 Google Ads
4592
4638
 
4593
4639
  list List campaigns
4594
4640
  create Create a campaign
4595
- update <id> Update a campaign
4596
- delete <id> Delete a campaign
4597
- <id> View campaign details
4641
+ update <id> Update by Google campaign ID (platformId)
4642
+ delete <id> Delete by Google campaign ID (platformId)
4643
+ <id> View by Google campaign ID (platformId)
4598
4644
 
4599
4645
  Flags (create):
4600
4646
  --name <name> Campaign name (required)
@@ -4628,6 +4674,7 @@ Notes:
4628
4674
  Google excludes support location geo target constants, not proximity radius exclusions.
4629
4675
  Display campaign creation uses campaignType:"display" or --campaign-type display. Videos are not supported for Display media in v1.
4630
4676
  Performance Max: campaignType "performance_max" with exactly one assetGroups[] entry. Text assets inline ({role,text}); image assets are uploaded via google media first, then referenced by id/resourceName. Needs an enabled conversion action (publish is blocked without one). Non-retail only. Build it with --data.
4677
+ View a Performance Max campaign by ID to read back assetGroups from Google. There is no separate google asset-groups command.
4631
4678
  For spend/clicks/conversions: adkit manage google results
4632
4679
 
4633
4680
  Examples:
@@ -4643,18 +4690,18 @@ var GOOGLE_AD_GROUP_HELP = `adkit manage google ad-groups \u2014 Google Ads ad g
4643
4690
 
4644
4691
  list List ad groups
4645
4692
  create Create an ad group
4646
- update <id> Update an ad group
4647
- delete <id> Delete an ad group
4648
- <id> View ad group details
4693
+ update <id> Update by Google ad group ID (platformId)
4694
+ delete <id> Delete by Google ad group ID (platformId)
4695
+ <id> View by Google ad group ID (platformId)
4649
4696
 
4650
4697
  Flags (create/update):
4651
- --campaign <id> Parent campaign ID
4698
+ --campaign <id> Google campaign ID (platformId)
4652
4699
  --name <name> Ad group name
4653
4700
  --status <s> enabled, paused, removed
4654
4701
  --cpc-bid <n> CPC bid in account currency
4655
4702
 
4656
4703
  Flags (list):
4657
- --campaign <id> Filter by campaign ID
4704
+ --campaign <id> Filter by Google campaign ID (platformId)
4658
4705
  --status <s> Filter by ad group status (default: enabled,paused; use all for every status)
4659
4706
  --limit <n> Max results
4660
4707
  --offset <n> Pagination offset
@@ -4679,12 +4726,12 @@ var GOOGLE_AD_GROUP_HELP_FULL = `adkit manage google ad-groups \u2014 Google Ads
4679
4726
 
4680
4727
  list List ad groups
4681
4728
  create Create an ad group
4682
- update <id> Update an ad group
4683
- delete <id> Delete an ad group
4684
- <id> View ad group details
4729
+ update <id> Update by Google ad group ID (platformId)
4730
+ delete <id> Delete by Google ad group ID (platformId)
4731
+ <id> View by Google ad group ID (platformId)
4685
4732
 
4686
4733
  Flags (create/update):
4687
- --campaign <id> Parent campaign ID
4734
+ --campaign <id> Google campaign ID (platformId)
4688
4735
  --name <name> Ad group name
4689
4736
  --status <s> enabled, paused, removed
4690
4737
  --cpc-bid <n> CPC bid in account currency
@@ -4693,7 +4740,7 @@ ${FLAG.publish}
4693
4740
  ${FLAG.data}
4694
4741
 
4695
4742
  Flags (list):
4696
- --campaign <id> Filter by campaign ID
4743
+ --campaign <id> Filter by Google campaign ID (platformId)
4697
4744
  --status <s> Filter by ad group status (default: enabled,paused; use all for every status)
4698
4745
  --limit <n> Max results
4699
4746
  --offset <n> Pagination offset
@@ -4720,12 +4767,12 @@ var GOOGLE_AD_HELP = `adkit manage google ads \u2014 Google ads
4720
4767
 
4721
4768
  list List ads
4722
4769
  create Create an ad
4723
- update <id> Update an ad
4724
- delete <id> Delete an ad
4725
- <id> View ad details
4770
+ update <id> Update by Google ad ID (platformId)
4771
+ delete <id> Delete by Google ad ID (platformId)
4772
+ <id> View by Google ad ID (platformId)
4726
4773
 
4727
4774
  Flags (create/update):
4728
- --ad-group <id> Parent ad group ID
4775
+ --ad-group <id> Google ad group ID (platformId)
4729
4776
  --headline <text> Search RSA headline (repeatable, max 30 chars each). Use --headline-1/2/3 to pin to position 1\u20133.
4730
4777
  --description <text> Search RSA description (repeatable, max 90 chars each). Use --description-1/2 to pin to position 1\u20132.
4731
4778
  --callout <value> Repeatable. Use asset:<id> or raw callout text
@@ -4735,7 +4782,7 @@ Flags (create/update):
4735
4782
  --status <s> enabled, paused, removed
4736
4783
 
4737
4784
  Flags (list):
4738
- --ad-group <id> Filter by ad group ID
4785
+ --ad-group <id> Filter by Google ad group ID (platformId)
4739
4786
  --status <s> Filter by ad status (default: enabled,paused; use all for every status)
4740
4787
  --limit <n> Max results
4741
4788
  --offset <n> Pagination offset
@@ -4767,12 +4814,12 @@ var GOOGLE_AD_HELP_FULL = `adkit manage google ads \u2014 Google ads
4767
4814
 
4768
4815
  list List ads
4769
4816
  create Create an ad
4770
- update <id> Update an ad
4771
- delete <id> Delete an ad
4772
- <id> View ad details
4817
+ update <id> Update by Google ad ID (platformId)
4818
+ delete <id> Delete by Google ad ID (platformId)
4819
+ <id> View by Google ad ID (platformId)
4773
4820
 
4774
4821
  Flags (create/update):
4775
- --ad-group <id> Parent ad group ID
4822
+ --ad-group <id> Google ad group ID (platformId)
4776
4823
  --headline <text> Search RSA headline (repeatable, unpinned, max 30 chars each). Up to 15 per ad.
4777
4824
  --headline-1/2/3 <t> Search RSA headline pinned to position 1, 2, or 3 (repeatable, max 30 chars each).
4778
4825
  --description <text> Search RSA description (repeatable, unpinned, max 90 chars each). Up to 4 per ad.
@@ -4787,7 +4834,7 @@ ${FLAG.publish}
4787
4834
  ${FLAG.data}
4788
4835
 
4789
4836
  Flags (list):
4790
- --ad-group <id> Filter by ad group ID
4837
+ --ad-group <id> Filter by Google ad group ID (platformId)
4791
4838
  --status <s> Filter by ad status (default: enabled,paused; use all for every status)
4792
4839
  --limit <n> Max results
4793
4840
  --offset <n> Pagination offset
@@ -4823,22 +4870,22 @@ var GOOGLE_KEYWORD_HELP = `adkit manage google keywords \u2014 Google Ads keywor
4823
4870
  negatives Manage negative keywords
4824
4871
  negative-lists Manage reusable shared negative lists
4825
4872
  add Add a keyword
4826
- update <id> Update a keyword
4827
- remove <id> Remove a keyword
4828
- <id> View keyword details
4873
+ update <id> Update by Google keyword ID (platformId)
4874
+ remove <id> Remove by Google keyword ID (platformId)
4875
+ <id> View by Google keyword ID (platformId)
4829
4876
 
4830
4877
  Flags (add):
4831
- --ad-group <id> Parent ad group ID
4878
+ --ad-group <id> Google ad group ID (platformId)
4832
4879
  --text <keyword> Keyword text
4833
4880
  --match-type <type> exact, phrase, broad
4834
4881
 
4835
4882
  Flags (update):
4836
- --ad-group <id> Parent ad group ID
4883
+ --ad-group <id> Google ad group ID (platformId)
4837
4884
  --cpc-bid <n> CPC bid in account currency
4838
4885
  --status <s> enabled, paused, removed
4839
4886
 
4840
4887
  Flags (list):
4841
- --ad-group <id> Filter by ad group ID
4888
+ --ad-group <id> Filter by Google ad group ID (platformId)
4842
4889
  --status <s> Filter by keyword status (default: enabled,paused; use all for every status)
4843
4890
  --limit <n> Max results
4844
4891
  --offset <n> Pagination offset
@@ -4861,17 +4908,17 @@ var GOOGLE_KEYWORD_HELP_FULL = `adkit manage google keywords \u2014 Google Ads k
4861
4908
  negatives Manage negative keywords
4862
4909
  negative-lists Manage reusable shared negative lists
4863
4910
  add Add a keyword
4864
- update <id> Update a keyword
4865
- remove <id> Remove a keyword
4866
- <id> View keyword details
4911
+ update <id> Update by Google keyword ID (platformId)
4912
+ remove <id> Remove by Google keyword ID (platformId)
4913
+ <id> View by Google keyword ID (platformId)
4867
4914
 
4868
4915
  Flags (add):
4869
- --ad-group <id> Parent ad group ID
4916
+ --ad-group <id> Google ad group ID (platformId)
4870
4917
  --text <keyword> Keyword text
4871
4918
  --match-type <type> exact, phrase, broad
4872
4919
 
4873
4920
  Flags (update):
4874
- --ad-group <id> Parent ad group ID
4921
+ --ad-group <id> Google ad group ID (platformId)
4875
4922
  --cpc-bid <n> CPC bid in account currency
4876
4923
  --status <s> enabled, paused, removed
4877
4924
  ${FLAG.account}
@@ -4879,7 +4926,7 @@ ${FLAG.publish}
4879
4926
  ${FLAG.data}
4880
4927
 
4881
4928
  Flags (list):
4882
- --ad-group <id> Filter by ad group ID
4929
+ --ad-group <id> Filter by Google ad group ID (platformId)
4883
4930
  --status <s> Filter by keyword status (default: enabled,paused; use all for every status)
4884
4931
  --limit <n> Max results
4885
4932
  --offset <n> Pagination offset
@@ -4902,17 +4949,17 @@ var GOOGLE_KEYWORD_NEGATIVES_HELP = `adkit manage google keywords negatives \u20
4902
4949
  remove <id> Remove a negative keyword
4903
4950
 
4904
4951
  Flags (list):
4905
- --campaign <id> Filter by campaign
4906
- --ad-group <id> Filter by ad group
4907
- --negative-keyword-list <id> Filter by shared negative list
4952
+ --campaign <id> Filter by Google campaign ID (platformId)
4953
+ --ad-group <id> Filter by Google ad group ID (platformId)
4954
+ --negative-keyword-list <id> Filter by Google negative keyword list ID (platformId)
4908
4955
  --limit <n> Max results
4909
4956
 
4910
4957
  Flags (add):
4911
4958
  --text <keyword> Keyword text (repeatable; supports bracket shorthand: [exact], "phrase", broad)
4912
4959
  --match-type <type> Explicit match type (repeat once or once per --text)
4913
- --campaign <id> Add at campaign scope
4914
- --ad-group <id> Add at ad group scope
4915
- --negative-keyword-list <id> Add to a shared negative list
4960
+ --campaign <id> Google campaign ID (platformId)
4961
+ --ad-group <id> Google ad group ID (platformId)
4962
+ --negative-keyword-list <id> Google negative keyword list ID (platformId)
4916
4963
  ${FLAG.publish}
4917
4964
  ${FLAG.data}
4918
4965
 
@@ -4943,7 +4990,7 @@ ${FLAG.publish}
4943
4990
  ${FLAG.data}
4944
4991
 
4945
4992
  Flags (attach/detach):
4946
- --campaign <id> Campaign ID
4993
+ --campaign <id> Google campaign ID (platformId)
4947
4994
  ${FLAG.publish}
4948
4995
 
4949
4996
  Examples:
@@ -4965,8 +5012,8 @@ var GOOGLE_RESULTS_HELP = `adkit manage google results \u2014 Google Ads perform
4965
5012
  search-terms Search terms that triggered your ads
4966
5013
 
4967
5014
  Flags:
4968
- --campaign <id> Filter by campaign ID
4969
- --ad-group <id> Filter by ad group ID
5015
+ --campaign <id> Filter by Google campaign ID (platformId)
5016
+ --ad-group <id> Filter by Google ad group ID (platformId)
4970
5017
  --period <period> Date range (30d, 90d, this_month, last_year, maximum, etc. Default: 30d)
4971
5018
  --from <date> Start date (YYYY-MM-DD, requires --to)
4972
5019
  --to <date> End date (YYYY-MM-DD, requires --from)
@@ -5001,8 +5048,8 @@ var GOOGLE_RESULTS_PLACEMENTS_HELP = `adkit manage google results placements \u2
5001
5048
 
5002
5049
  Flags:
5003
5050
  --account <id> Optional if one Google Ads account is connected
5004
- --campaign <id> Filter by campaign
5005
- --ad-group <id> Filter by ad group
5051
+ --campaign <id> Filter by Google campaign ID (platformId)
5052
+ --ad-group <id> Filter by Google ad group ID (platformId)
5006
5053
  --period <preset> Date range: 30d, 90d, this_month, last_year, maximum, etc. (default: 30d)
5007
5054
  --from <date> Custom start date (YYYY-MM-DD, requires --to)
5008
5055
  --to <date> Custom end date (YYYY-MM-DD, requires --from)
@@ -5019,8 +5066,8 @@ var GOOGLE_KEYWORD_SEARCH_TERMS_HELP = `adkit manage google results search-terms
5019
5066
 
5020
5067
  Flags:
5021
5068
  --account <id> Optional if one Google Ads account is connected
5022
- --campaign <id> Filter by campaign
5023
- --ad-group <id> Filter by ad group
5069
+ --campaign <id> Filter by Google campaign ID (platformId)
5070
+ --ad-group <id> Filter by Google ad group ID (platformId)
5024
5071
  --keyword <text> Filter by matched keyword text
5025
5072
  --keyword-match-type Filter by matched keyword match type: exact, phrase, broad
5026
5073
  --period <preset> Date range: 30d, 90d, this_month, last_year, maximum, etc. (default: maximum)
@@ -5048,8 +5095,8 @@ var GOOGLE_RESULTS_KEYWORDS_HELP = `adkit manage google results keywords \u2014
5048
5095
 
5049
5096
  Flags:
5050
5097
  --account <id> Optional if one Google Ads account is connected
5051
- --campaign <id> Filter by campaign
5052
- --ad-group <id> Filter by ad group
5098
+ --campaign <id> Filter by Google campaign ID (platformId)
5099
+ --ad-group <id> Filter by Google ad group ID (platformId)
5053
5100
  --period <preset> Date range: 30d, 90d, this_month, last_year, maximum, etc. (default: 30d)
5054
5101
  --from <date> Custom start date (YYYY-MM-DD, requires --to)
5055
5102
  --to <date> Custom end date (YYYY-MM-DD, requires --from)
@@ -5266,8 +5313,8 @@ ${FLAG.data}
5266
5313
  --status <s> active, paused
5267
5314
  --budget-daily <n> Daily budget in account currency
5268
5315
  --budget-lifetime <n> Lifetime budget in account currency
5269
- --schedule-start-time <value> Required for create, e.g. "2026-05-15 12:00:00"
5270
- --schedule-end-time <value> Optional end time
5316
+ --start-date <value> Optional TikTok schedule datetime; omit to start now
5317
+ --end-date <value> Optional TikTok schedule datetime; required with lifetime budget
5271
5318
  --billing-event <s> cpc, cpm, ocpm
5272
5319
  --bid-strategy <s> bid_type_no_bid, bid_type_custom, bid_type_max_conversion
5273
5320
  --optimization <s> click, convert, lead_generation, video_view, reach
@@ -5277,8 +5324,8 @@ ${FLAG.data}
5277
5324
  --placement <ids> Override TikTok placement IDs (publish default: PLACEMENT_TIKTOK)
5278
5325
 
5279
5326
  Examples:
5280
- adkit manage tiktok ad-groups create --campaign 1770 --name "US Broad" --budget-daily 50 --schedule-start-time "2026-05-15 12:00:00" --billing-event cpc --optimization click
5281
- adkit manage tiktok ad-groups create --data '{"adGroups":[{"campaignId":"1770","name":"Purchase","budget":{"daily":50},"scheduleStartTime":"2026-05-15 12:00:00","bidAmount":80,"conversion":{"eventType":"purchase"},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]}}}]}'`.trim(),
5327
+ adkit manage tiktok ad-groups create --campaign 1770 --name "US Broad" --budget-daily 50 --billing-event cpc --optimization click
5328
+ adkit manage tiktok ad-groups create --data '{"adGroups":[{"campaignId":"1770","name":"Purchase","budget":{"daily":50},"startDate":"2026-05-15 12:00:00","bidAmount":80,"conversion":{"eventType":"purchase"},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]}}}]}'`.trim(),
5282
5329
  "tiktok ads": `adkit manage tiktok ads \u2014 TikTok video ads
5283
5330
 
5284
5331
  list List ads
@@ -5314,19 +5361,19 @@ Examples:
5314
5361
  Flags:
5315
5362
  ${FLAG.account}
5316
5363
  --level <level> account, campaigns, ad-groups, ads (default: campaigns)
5317
- --dimensions <csv> TikTok reporting dimensions, e.g. campaign_id
5318
- --metrics <csv> TikTok reporting metrics, e.g. spend,impressions,clicks
5364
+ --fields <csv> Normalized fields, e.g. spend,impressions,clicks,conversions
5365
+ --breakdowns <csv> Row breakdowns, e.g. day
5319
5366
  --from <date> YYYY-MM-DD
5320
5367
  --to <date> YYYY-MM-DD
5321
- --order-field <f> Optional sort metric/field
5322
- --order-type <t> asc or desc
5368
+ --sort <field> Optional normalized sort field, e.g. spend
5369
+ --sort-direction <t> asc or desc
5323
5370
  --limit <n> Max rows
5324
5371
 
5325
5372
  Note:
5326
- Results MVP passes TikTok report dimension/metric names through to the TikTok reporting API.
5373
+ For raw TikTok report dimensions/metrics outside this normalized contract, use platform-api-request with TikTok report/integrated/get.
5327
5374
 
5328
5375
  Example:
5329
- adkit manage tiktok results --level campaigns --dimensions campaign_id --metrics spend,impressions,clicks --from 2026-05-01 --to 2026-05-15`.trim(),
5376
+ adkit manage tiktok results --level campaigns --fields spend,impressions,clicks --breakdowns day --from 2026-05-01 --to 2026-05-15`.trim(),
5330
5377
  "reddit accounts": `adkit manage reddit accounts \u2014 Reddit Ads accounts
5331
5378
 
5332
5379
  list List connected Reddit ad accounts
@@ -6027,7 +6074,7 @@ function printSingleEntity(e, entity) {
6027
6074
  } else {
6028
6075
  const ad = e;
6029
6076
  const createdAt = shortDate(ad.createdAt);
6030
- lines.push(` Ad: ${formatForTTY(ad.name)}`, ` ID: ${formatForTTY(ad.id)}`, ` Ad Set: ${formatForTTY(ad.adsetId)}`, ` Campaign: ${formatForTTY(ad.campaignId)}`, ` Status: ${formatForTTY(ad.status)}`);
6077
+ lines.push(` Ad: ${formatForTTY(ad.name)}`, ` ID: ${formatForTTY(ad.platformId)}`, ` Ad Set: ${formatForTTY(ad.adsetId)}`, ` Campaign: ${formatForTTY(ad.campaignId)}`, ` Status: ${formatForTTY(ad.status)}`);
6031
6078
  const creative = ad.creative;
6032
6079
  if (creative) {
6033
6080
  lines.push("", " Creative", "");
@@ -6442,11 +6489,7 @@ function showHelp(key, full = false) {
6442
6489
  return false;
6443
6490
  }
6444
6491
  function printHelp(text) {
6445
- const statusNotice = getAdKitStatusNotice();
6446
- const helpText = statusNotice ? `${statusNotice}
6447
-
6448
- ${text}` : text;
6449
- console.log(helpText);
6492
+ console.log(text);
6450
6493
  }
6451
6494
  async function selfUpdate(currentVersion) {
6452
6495
  const { execSync } = await import("node:child_process");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adkit/cli",
3
- "version": "1.12.4",
3
+ "version": "1.12.9",
4
4
  "description": "The Ads CLI for AI agents — manage Meta & Google ad campaigns, browse the ad library, and generate creatives from your terminal.",
5
5
  "keywords": [
6
6
  "ads cli",
@@ -34,6 +34,9 @@
34
34
  "build": "esbuild src/cli.ts --bundle --format=esm --platform=node --target=node18 --outfile=dist/cli.js --banner:js='#!/usr/bin/env node'",
35
35
  "release": "cd ../shared && npm run build && cd ../cli && npm version patch && npm run build && npm publish --access public"
36
36
  },
37
+ "dependencies": {
38
+ "open": "^10.2.0"
39
+ },
37
40
  "devDependencies": {
38
41
  "@adkit/shared": "*",
39
42
  "@types/node": "^20.10.0",