@adkit/cli 1.13.5 → 1.13.6

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 +69 -21
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1253,7 +1253,7 @@ async function listMetaCampaigns(client, _args, flags) {
1253
1253
  }
1254
1254
  var CAMPAIGN_FLAGS = ["name", "objective", "status", "budget-daily", "budget-total", "abo", "bid-strategy"];
1255
1255
  var ADSET_FLAGS = ["campaign", "name", "status", "optimization", "budget-daily", "budget-total", "bid-strategy", "bid-amount", "countries", "genders", "targeting", "pixel", "event-type", "interest"];
1256
- var AD_FLAGS = ["creative", "adset", "name", "status", "media", "media-format", "primary-text", "headline", "description", "cta", "url", "lead-form", "page", "post"];
1256
+ var AD_FLAGS = ["creative", "adset", "name", "status", "media", "media-format", "primary-text", "headline", "link-description", "cta", "url", "lead-form", "page", "post"];
1257
1257
  var CREATIVE_FLAGS = ["page-id", "headline", "primary-text", "link-description", "link-url", "cta", "name", "image-hash", "image-url", "video-id", "force"];
1258
1258
  var MEDIA_FLAGS = ["file", "url", "account"];
1259
1259
  var ADSET_BID_STRATEGIES_REQUIRING_AMOUNT = /* @__PURE__ */ new Set(["cost_cap", "bid_cap"]);
@@ -1430,10 +1430,10 @@ async function createAd(client, _args, flags) {
1430
1430
  }
1431
1431
  validateFlags(flags, AD_FLAGS, "manage meta ads create");
1432
1432
  const creativeId = typeof flags.creative === "string" ? flags.creative : void 0;
1433
- const mediaFlags = ["media", "media-format", "primary-text", "headline", "description", "cta", "lead-form"];
1433
+ const mediaFlags = ["media", "media-format", "primary-text", "headline", "link-description", "cta", "lead-form"];
1434
1434
  const hasMediaFlags = mediaFlags.some((f) => flags[f] !== void 0);
1435
1435
  const postId = typeof flags.post === "string" ? flags.post : void 0;
1436
- if (creativeId && hasMediaFlags) throw new CliError("INVALID_VALUE", "`--creative` cannot be combined with --media, --primary-text, --headline, --description, or --cta", "Use --creative to reference an existing creative, OR use --media/--primary-text/etc. to create a new one");
1436
+ if (creativeId && hasMediaFlags) throw new CliError("INVALID_VALUE", "`--creative` cannot be combined with --media, --primary-text, --headline, --link-description, or --cta", "Use --creative to reference an existing creative, OR use --media/--primary-text/etc. to create a new one");
1437
1437
  if (postId && (creativeId || hasMediaFlags)) throw new CliError("INVALID_VALUE", "`--post` cannot be combined with --creative, --media, or text flags", "Use --post alone to create an ad from an existing post");
1438
1438
  if (flags["lead-form"] !== void 0 && (typeof flags["lead-form"] !== "string" || !flags["lead-form"].trim())) throw new CliError("MISSING_FLAG", "Lead Form ads require an Instant Form ID. Pass --lead-form <id>.", "Copy the form ID from Meta Instant Forms and pass it as --lead-form <id>.");
1439
1439
  if (postId) {
@@ -1466,7 +1466,7 @@ async function createAd(client, _args, flags) {
1466
1466
  const mediaFormatInputs = collectFlagValues(flags, "media-format");
1467
1467
  const primaryTexts = collectFlagValues(flags, "primary-text");
1468
1468
  const headlines = collectFlagValues(flags, "headline");
1469
- const descriptions = collectFlagValues(flags, "description");
1469
+ const linkDescriptions = collectFlagValues(flags, "link-description");
1470
1470
  if (mediaInputs.length === 0) throw new CliError("MISSING_FLAG", "Missing required flag: `--media` (or use `--creative` to reference an existing creative)", 'Run: adkit manage meta ads create --media ./hero.mp4 --primary-text "Hello" --adset as_xyz --publish');
1471
1471
  if (mediaFormatInputs.length > 0 && mediaFormatInputs.length !== mediaInputs.length) throw new CliError("INVALID_VALUE", "Pass one --media-format value for each --media value.", "Use --media-format default for the base media, then square, vertical, or horizontal for replacements.");
1472
1472
  const mediaFormats = mediaFormatInputs.map(readMediaFormatFlag);
@@ -1509,7 +1509,7 @@ async function createAd(client, _args, flags) {
1509
1509
  const ad = { adsetId, media };
1510
1510
  if (primaryTexts.length) ad.primaryTexts = primaryTexts;
1511
1511
  if (headlines.length) ad.headlines = headlines;
1512
- if (descriptions.length) ad.descriptions = descriptions;
1512
+ if (linkDescriptions.length) ad.linkDescriptions = linkDescriptions;
1513
1513
  if (typeof flags.cta === "string") ad.cta = flags.cta;
1514
1514
  if (typeof flags.name === "string") ad.name = flags.name;
1515
1515
  if (typeof flags.url === "string") ad.url = flags.url;
@@ -1852,6 +1852,7 @@ var CONVERSION_UPLOAD_FLAGS = ["conversion", "gclid", "gbraid", "wbraid", "occur
1852
1852
  var CHANGE_HISTORY_FLAGS = ["account", "period", "from", "to", "limit", "resource", "campaign", "ad-group"];
1853
1853
  var KEYWORD_RESEARCH_FLAGS = ["url", "location", "language", "limit", "min-volume"];
1854
1854
  var TARGETING_RESEARCH_FLAGS = ["limit"];
1855
+ var GEO_LOCATION_SEARCH_FLAGS = ["country-code", "locale", "type", "limit"];
1855
1856
  var NUMBER_FLAG_PATTERN = /^(?:\d+|\d+\.\d+|\.\d+)(?:e[+-]?\d+)?$/iu;
1856
1857
  function generateCampaignName2() {
1857
1858
  return `campaign ${getDateStamp()}`;
@@ -2815,6 +2816,18 @@ async function researchInterests(client, args, flags) {
2815
2816
  const path3 = `/manage/google/research/interests${qs}`;
2816
2817
  return client.get(path3);
2817
2818
  }
2819
+ async function searchGoogleGeoLocations(client, args, flags) {
2820
+ validateFlags(flags, GEO_LOCATION_SEARCH_FLAGS, "manage google geo-locations search");
2821
+ const query = args.join(" ").trim();
2822
+ if (!query) throw new CliError("MISSING_ARGUMENT", "Missing location query", 'Run: adkit manage google geo-locations search "Austin, Texas" --country-code US --type city');
2823
+ const accountId = typeof flags.account === "string" ? flags.account : void 0;
2824
+ const countryCode = typeof flags["country-code"] === "string" ? flags["country-code"] : void 0;
2825
+ const locale = typeof flags.locale === "string" ? flags.locale : void 0;
2826
+ const type = typeof flags.type === "string" ? flags.type : void 0;
2827
+ const limit = typeof flags.limit === "string" ? flags.limit : void 0;
2828
+ const qs = queryString({ accountId, query, countryCode, locale, type, limit });
2829
+ return client.get(`/manage/google/geo-locations${qs}`);
2830
+ }
2818
2831
  function buildGoogleTargetingResearchQuery(args, flags, missingQueryHint) {
2819
2832
  const q = args.join(" ").trim();
2820
2833
  if (!q) throw new CliError("MISSING_ARGUMENT", "Missing query", missingQueryHint);
@@ -4745,7 +4758,7 @@ Flags (create \u2014 new creative from media):
4745
4758
  --media <path|url> Media file or URL (repeatable). Handles upload + processing automatically for single-image/video ads
4746
4759
  --primary-text <t> Ad body text (repeatable)
4747
4760
  --headline <text> Headline text (repeatable)
4748
- --description <t> Description text (repeatable, optional)
4761
+ --link-description <t> Link preview subtitle (repeatable, optional)
4749
4762
  ${FLAG.cta}
4750
4763
  --name <name> Ad name
4751
4764
  --url <url> Landing page URL
@@ -4807,7 +4820,7 @@ Flags (create \u2014 new creative from media):
4807
4820
  --media-format <f> Optional format for each --media: default, square, vertical, horizontal
4808
4821
  --primary-text <t> Ad body text (repeatable)
4809
4822
  --headline <text> Headline text (repeatable)
4810
- --description <t> Description text (repeatable, optional)
4823
+ --link-description <t> Link preview subtitle (repeatable, optional)
4811
4824
  ${FLAG.cta}
4812
4825
  --name <name> Ad name
4813
4826
  --url <url> Landing page URL
@@ -4843,6 +4856,7 @@ Note:
4843
4856
  media [{ id: "imageHashOrVideoId" }, { id: "...", format: "vertical" }]
4844
4857
  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).
4845
4858
  Do not use top-level media for carousel ads.
4859
+ linkDescriptions Link-preview subtitle copy for feed ads.
4846
4860
  carouselCards
4847
4861
  Card list for carousel ads. Each card needs headline and media.
4848
4862
  carouselCards[].headline
@@ -5144,7 +5158,8 @@ Flags (list):
5144
5158
 
5145
5159
  Note:
5146
5160
  list returns campaign configuration only (name, status, budget).
5147
- Geo targeting lives in targeting.geoLocations. Use type=country for country targeting.
5161
+ Geo targeting lives in targeting.geoLocations. Use type=country for countries.
5162
+ For cities, regions, postal codes, and metros, run google geo-locations search and use the returned bare code.
5148
5163
  Advanced geo examples: adkit manage google campaigns --help full
5149
5164
  Display creation starts here: campaigns create --campaign-type display, then create Display ad groups and responsive_display ads.
5150
5165
  Performance Max: campaignType "performance_max" with asset groups \u2014 build it with --data. See --help full.
@@ -5195,9 +5210,9 @@ Flags (list):
5195
5210
  Notes:
5196
5211
  Use google assets for explicit account/campaign/ad-group attachment, reusable libraries, or richer sitelinks via --data.
5197
5212
  list returns campaign configuration only (name, status, budget).
5198
- Geo targeting lives in targeting.geoLocations. Use type=country for simple countries, or type=platformLocation for raw Google location/proximity geo.
5199
- With platformLocation, pass the exact Google geo object to send; AdKit does not look up or convert city names or addresses.
5200
- Google excludes support location geo target constants, not proximity radius exclusions.
5213
+ Geo targeting lives in targeting.geoLocations. Use type=country for countries and copy named locations from google geo-locations search.
5214
+ platformLocation accepts exact Google geo objects for advanced criteria and existing raw values.
5215
+ Google exclusions support named locations. Proximity circles belong in include.
5201
5216
  Display campaign creation uses campaignType:"display" or --campaign-type display. Videos are not supported for Display media in v1.
5202
5217
  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 (publish is blocked without one). Non-retail only. Build it with --data.
5203
5218
  View a Performance Max campaign by ID to read back assetGroups from Google. There is no separate google asset-groups command.
@@ -5207,7 +5222,7 @@ Examples:
5207
5222
  adkit manage google campaigns list --account 1234567890
5208
5223
  adkit manage google campaigns create --name "Display Prospecting" --campaign-type display --budget-daily 50 --account 1234567890
5209
5224
  adkit manage google campaigns create --data '{"campaigns":[{"name":"Display US","campaignType":"display","budget":{"daily":50},"targeting":{"geoLocations":{"include":[{"type":"country","country":"US"}]}}}]}' --account 1234567890
5210
- adkit manage google campaigns create --data '{"campaigns":[{"name":"Search US Native","campaignType":"search","budget":{"daily":5},"targeting":{"geoLocations":{"include":[{"type":"platformLocation","platform":"google","value":{"location":{"geo_target_constant":"geoTargetConstants/2840"}}}]}}}]}' --account 1234567890
5225
+ adkit manage google campaigns create --data '{"campaigns":[{"name":"Austin Search","campaignType":"search","budget":{"daily":5},"targeting":{"geoLocations":{"include":[{"type":"city","code":"1026201"}]}}}]}' --account 1234567890
5211
5226
  adkit manage google campaigns create --data '{"campaigns":[{"name":"SF Radius","campaignType":"search","budget":{"daily":5},"targeting":{"geoLocations":{"include":[{"type":"platformLocation","platform":"google","value":{"proximity":{"geo_point":{"latitude_in_micro_degrees":37774900,"longitude_in_micro_degrees":-122419400},"radius":5,"radius_units":"MILES"}}}]}}}]}' --account 1234567890
5212
5227
  adkit manage google campaigns create --data '{"campaigns":[{"name":"PMAX Launch","campaignType":"performance_max","budget":{"daily":50},"bidStrategy":"maximize_conversions","assetGroups":[{"name":"Asset Group 1","finalUrls":["https://example.com"],"assets":[{"role":"headline","text":"Ship faster"},{"role":"headline","text":"Save hours every week"},{"role":"headline","text":"Start free today"},{"role":"long_headline","text":"Automate your ad workflow and launch in minutes"},{"role":"description","text":"Automate your workflow in minutes"},{"role":"description","text":"No credit card required"},{"role":"business_name","text":"Acme"},{"role":"logo","id":"<uploaded-asset-id>"},{"role":"marketing_image","id":"<uploaded-asset-id>"},{"role":"square_marketing_image","id":"<uploaded-asset-id>"}],"signals":[{"type":"search_theme","text":"project management software"}]}]}]}' --account 1234567890
5213
5228
  adkit manage google campaigns update 987654321 --status paused --account 1234567890
@@ -5731,6 +5746,24 @@ Notes:
5731
5746
  Topic search returns IDs for targeting.content.topics.include/exclude.
5732
5747
  Interest search returns IDs for targeting.audience.interests.include/exclude.
5733
5748
  Websites use direct URLs in targeting.content.websites.include/exclude. Bare numeric customAudiences IDs are treated as Google user lists (remarketing/Customer Match); for custom segments, pass a customAudiences/{id} or customers/{accountId}/customAudiences/{id} resource path.`;
5749
+ var GOOGLE_GEO_LOCATIONS_HELP = `adkit manage google geo-locations \u2014 Find locations for campaign targeting
5750
+
5751
+ search <place...> Find enabled Google locations and return bare codes and AdKit types
5752
+
5753
+ Flags:
5754
+ --account <id> Optional if one Google Ads account is connected
5755
+ --country-code <c> ISO country code such as US
5756
+ --locale <locale> Google result locale such as en
5757
+ --type <type> country, region, city, postal_code, or metro
5758
+ --limit <n> Max results (1-50, default: 10)
5759
+
5760
+ Examples:
5761
+ adkit manage google geo-locations search "Austin, Texas" --country-code US --type city
5762
+ adkit manage google geo-locations search Paris --country-code FR --locale fr
5763
+
5764
+ Supported results contain type; unmapped Google categories contain platformType.
5765
+ Pass type and the bare code into campaign targeting. For country, use {"type":"country","country":"US"}.
5766
+ AdKit builds the Google resource name.`;
5734
5767
  var GOOGLE_MEDIA_HELP = `adkit manage google media \u2014 Upload creative media to Google Ads
5735
5768
 
5736
5769
  upload Upload an image and return reusable Google asset IDs
@@ -5841,6 +5874,7 @@ Examples:
5841
5874
  "google results keywords": GOOGLE_RESULTS_KEYWORDS_HELP,
5842
5875
  "google change-history": GOOGLE_CHANGE_HISTORY_HELP,
5843
5876
  "google research": GOOGLE_RESEARCH_HELP,
5877
+ "google geo-locations": GOOGLE_GEO_LOCATIONS_HELP,
5844
5878
  "google media": GOOGLE_MEDIA_HELP,
5845
5879
  "google conversions": GOOGLE_CONVERSIONS_HELP,
5846
5880
  "tiktok accounts": `adkit manage tiktok accounts \u2014 TikTok Ads accounts
@@ -6274,6 +6308,7 @@ Entity groups:
6274
6308
  results Performance metrics (campaigns, ad-groups, ads, keywords, search-terms)
6275
6309
  change-history Recent Google Ads account changes from the last 30 days
6276
6310
  research Keyword Planner plus Display topic/interest IDs
6311
+ geo-locations Find Google location codes for campaign targeting
6277
6312
  assets Manage reusable assets (sitelinks, callouts, structured snippets, images)
6278
6313
  media Upload images for Display creative media
6279
6314
 
@@ -6615,6 +6650,7 @@ var HELP_FULL = {
6615
6650
  "google results keywords": GOOGLE_RESULTS_KEYWORDS_HELP,
6616
6651
  "google change-history": GOOGLE_CHANGE_HISTORY_HELP,
6617
6652
  "google research": GOOGLE_RESEARCH_HELP,
6653
+ "google geo-locations": GOOGLE_GEO_LOCATIONS_HELP,
6618
6654
  "google media": GOOGLE_MEDIA_HELP,
6619
6655
  "google conversions": GOOGLE_CONVERSIONS_HELP,
6620
6656
  "meta research": META_RESEARCH_HELP,
@@ -6951,15 +6987,17 @@ function printSingleEntity(e, entity) {
6951
6987
  const creative = ad.creative;
6952
6988
  if (creative) {
6953
6989
  lines.push("", " Creative", "");
6954
- if (creative.id) lines.push(` ID: ${formatForTTY(creative.id)}`);
6955
- if (creative.headline) lines.push(` Headline: ${formatForTTY(creative.headline)}`);
6956
- if (creative.body) lines.push(` Body: ${formatForTTY(creative.body)}`);
6957
- if (creative.description) lines.push(` Description: ${formatForTTY(creative.description)}`);
6990
+ const headlines = creative.headlines?.join(", ");
6991
+ const primaryTexts = creative.primaryTexts?.join(", ");
6992
+ const linkDescriptions = creative.linkDescriptions?.join(", ");
6993
+ const mediaItems = creative.media?.map((item) => `${item.role}:${item.id}`) ?? [];
6994
+ const media = mediaItems.join(", ");
6995
+ if (headlines) lines.push(` Headline: ${formatForTTY(headlines)}`);
6996
+ if (primaryTexts) lines.push(` Body: ${formatForTTY(primaryTexts)}`);
6997
+ if (linkDescriptions) lines.push(` Description: ${formatForTTY(linkDescriptions)}`);
6958
6998
  if (creative.cta) lines.push(` CTA: ${formatForTTY(creative.cta)}`);
6959
- if (creative.linkUrl) lines.push(` Link: ${formatForTTY(creative.linkUrl)}`);
6960
- if (creative.imageUrl) lines.push(` Image: ${formatForTTY(creative.imageUrl)}`);
6961
- if (creative.thumbnailUrl) lines.push(` Thumbnail: ${formatForTTY(creative.thumbnailUrl)}`);
6962
- if (creative.videoId) lines.push(` Video ID: ${formatForTTY(creative.videoId)}`);
6999
+ if (creative.url) lines.push(` Link: ${formatForTTY(creative.url)}`);
7000
+ if (media) lines.push(` Media: ${formatForTTY(media)}`);
6963
7001
  }
6964
7002
  if (createdAt) lines.push(` Created: ${createdAt}`);
6965
7003
  }
@@ -7978,8 +8016,18 @@ async function main() {
7978
8016
  }
7979
8017
  break;
7980
8018
  }
8019
+ case "geo-locations": {
8020
+ if (!action) {
8021
+ showHelp("google geo-locations", flags.help === "full");
8022
+ return;
8023
+ }
8024
+ if (action !== "search") throw new CliError("UNKNOWN_COMMAND", `Unknown action: google geo-locations ${action}`, "Available: search");
8025
+ data = await searchGoogleGeoLocations(client, restArgs, flags);
8026
+ emptyHint = "No matching Google locations found. Try a broader place name or country filter.";
8027
+ break;
8028
+ }
7981
8029
  default:
7982
- throw new CliError("UNKNOWN_COMMAND", `Unknown entity: google ${entity}`, "Available: accounts, assets, media, campaigns, ad-groups, ads, keywords, conversions, results, change-history, research");
8030
+ throw new CliError("UNKNOWN_COMMAND", `Unknown entity: google ${entity}`, "Available: accounts, assets, media, campaigns, ad-groups, ads, keywords, conversions, results, change-history, research, geo-locations");
7983
8031
  }
7984
8032
  } else if (platform2 === "tiktok") {
7985
8033
  switch (entity) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adkit/cli",
3
- "version": "1.13.5",
3
+ "version": "1.13.6",
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",