@adkit/cli 1.12.24 → 1.12.26

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 +136 -68
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -80,6 +80,7 @@ var CliError = class extends Error {
80
80
  suggestion;
81
81
  instructions;
82
82
  actionUrl;
83
+ notice;
83
84
  constructor(code, message, suggestion) {
84
85
  super(message);
85
86
  this.code = code;
@@ -90,16 +91,17 @@ var CliError = class extends Error {
90
91
  // src/client.ts
91
92
  var noticePrinted = false;
92
93
  function printServerNotice(response) {
93
- if (noticePrinted) return;
94
94
  const encoded = response.headers.get("x-adkit-notice");
95
- if (!encoded) return;
96
- noticePrinted = true;
95
+ if (!encoded) return void 0;
97
96
  const text = decodeURIComponent(encoded);
97
+ if (noticePrinted) return text;
98
+ noticePrinted = true;
98
99
  const dim = "\x1B[2m";
99
100
  const yellow = "\x1B[33m";
100
101
  const reset = "\x1B[0m";
101
102
  process.stderr.write(`${yellow}${dim}[AdKit notice] ${text}${reset}
102
103
  `);
104
+ return text;
103
105
  }
104
106
  function isErrorResponse(value) {
105
107
  return value != null && typeof value === "object";
@@ -204,7 +206,7 @@ var AdkitClient = class {
204
206
  const detail = code ?? (err instanceof Error ? err.message : String(err));
205
207
  throw new CliError("NETWORK_ERROR", `Cannot reach ${target} (${detail})`, "Verify your network connection");
206
208
  }
207
- printServerNotice(response);
209
+ const serverNotice = printServerNotice(response);
208
210
  if (response.status === 204) return void 0;
209
211
  if (!response.ok) {
210
212
  let serverMessage = "";
@@ -229,27 +231,40 @@ var AdkitClient = class {
229
231
  const fallbackMsg = response.status >= 500 ? `Server error (HTTP ${String(response.status)})` : `Request failed (HTTP ${String(response.status)})`;
230
232
  const errorMsg = appendErrorDetail(dataMessage || serverMessage || fallbackMsg, batchSummary);
231
233
  const suggestion2 = buildMetaDsaSuggestion(structured.code) ?? buildRetrySuggestion(retryable, retryAfterSeconds) ?? buildAuthSuggestion(structured.code);
232
- const error = new CliError(structured.code, errorMsg, suggestion2);
233
- error.instructions = structured.instructions;
234
- error.actionUrl = structured.actionUrl;
235
- throw error;
234
+ const error2 = new CliError(structured.code, errorMsg, suggestion2);
235
+ error2.instructions = structured.instructions;
236
+ error2.actionUrl = structured.actionUrl;
237
+ error2.notice = serverNotice;
238
+ throw error2;
239
+ }
240
+ if (response.status === 401) {
241
+ const error2 = new CliError("INVALID_API_KEY", `Invalid or expired API key${serverMessage ? ` \u2014 ${serverMessage}` : ""}`, "Run: adkit setup");
242
+ error2.notice = serverNotice;
243
+ throw error2;
236
244
  }
237
- if (response.status === 401) throw new CliError("INVALID_API_KEY", `Invalid or expired API key${serverMessage ? ` \u2014 ${serverMessage}` : ""}`, "Run: adkit setup");
238
245
  if (response.status === 429) {
239
246
  const waitMsg = buildRetrySuggestion(true, retryAfterSeconds) ?? "Wait a moment before retrying";
240
- throw new CliError("RATE_LIMITED", appendErrorDetail(serverMessage || "Rate limit exceeded", batchSummary), waitMsg);
247
+ const error2 = new CliError("RATE_LIMITED", appendErrorDetail(serverMessage || "Rate limit exceeded", batchSummary), waitMsg);
248
+ error2.notice = serverNotice;
249
+ throw error2;
241
250
  }
242
251
  if (response.status === 404) {
243
252
  const fallback = `Not found: ${method} ${path3} \u2014 the resource may have been deleted or the ID is wrong`;
244
- throw new CliError("NOT_FOUND", appendErrorDetail(serverMessage || fallback, batchSummary), "Check the resource ID");
253
+ const error2 = new CliError("NOT_FOUND", appendErrorDetail(serverMessage || fallback, batchSummary), "Check the resource ID");
254
+ error2.notice = serverNotice;
255
+ throw error2;
245
256
  }
246
257
  if (response.status >= 500) {
247
258
  const errorMsg = appendErrorDetail(dataMessage || serverMessage || `Server error (HTTP ${String(response.status)})`, batchSummary);
248
259
  const suggestion2 = buildRetrySuggestion(retryable, retryAfterSeconds);
249
- throw new CliError("SERVER_ERROR", errorMsg, suggestion2);
260
+ const error2 = new CliError("SERVER_ERROR", errorMsg, suggestion2);
261
+ error2.notice = serverNotice;
262
+ throw error2;
250
263
  }
251
264
  const suggestion = buildRetrySuggestion(retryable, retryAfterSeconds);
252
- throw new CliError("SERVER_ERROR", appendErrorDetail(serverMessage || `Request failed (HTTP ${String(response.status)})`, batchSummary), suggestion);
265
+ const error = new CliError("SERVER_ERROR", appendErrorDetail(serverMessage || `Request failed (HTTP ${String(response.status)})`, batchSummary), suggestion);
266
+ error.notice = serverNotice;
267
+ throw error;
253
268
  }
254
269
  return response.json();
255
270
  }
@@ -3168,6 +3183,12 @@ async function disconnectRedditAccount(client, args, flags) {
3168
3183
  return client.delete(`/manage/reddit/accounts/${adAccountId}`);
3169
3184
  }
3170
3185
 
3186
+ // src/commands/linkedin.ts
3187
+ async function listLinkedInAvailableAccounts(client, _args, flags) {
3188
+ validateFlags(flags, [], "manage linkedin accounts available");
3189
+ return client.get("/manage/linkedin/accounts/available");
3190
+ }
3191
+
3171
3192
  // src/commands/status.ts
3172
3193
  function isStatusResponse(value) {
3173
3194
  if (!value || typeof value !== "object") return false;
@@ -3529,8 +3550,8 @@ async function requestMultipart(client, pathName, formData) {
3529
3550
  try {
3530
3551
  const json = await response.json();
3531
3552
  if (isErrorResponse2(json)) {
3532
- serverMessage = json.statusMessage ?? json.message ?? "";
3533
3553
  dataMessage = json.data?.message ?? "";
3554
+ serverMessage = dataMessage || json.message || json.statusMessage || "";
3534
3555
  retryable = json.data?.retryable;
3535
3556
  retryAfterSeconds = json.data?.retryAfterSeconds ?? void 0;
3536
3557
  }
@@ -3885,11 +3906,23 @@ function toGoogleSearchTermDisplayRows(row) {
3885
3906
  import { createRequire } from "node:module";
3886
3907
 
3887
3908
  // src/update-check.ts
3888
- import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
3909
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
3889
3910
  import { join as join2 } from "node:path";
3890
3911
  var CACHE_PATH = join2(CONFIG_DIR, "update-check.json");
3891
3912
  var FETCH_TIMEOUT_MS = 3e3;
3892
3913
  var REGISTRY_URL = "https://registry.npmjs.org/@adkit/cli/latest";
3914
+ function readCache() {
3915
+ try {
3916
+ const raw = readFileSync4(CACHE_PATH, "utf-8");
3917
+ const parsed = JSON.parse(raw);
3918
+ if (!parsed || typeof parsed !== "object") return void 0;
3919
+ const cache = parsed;
3920
+ if (typeof cache.lastCheck !== "number" || typeof cache.latestVersion !== "string") return void 0;
3921
+ return { lastCheck: cache.lastCheck, latestVersion: cache.latestVersion };
3922
+ } catch {
3923
+ return void 0;
3924
+ }
3925
+ }
3893
3926
  function writeCache(data) {
3894
3927
  try {
3895
3928
  const cacheJson = JSON.stringify(data);
@@ -3939,7 +3972,8 @@ function isNewer(latest, current) {
3939
3972
  return false;
3940
3973
  }
3941
3974
  function startUpdateCheck(currentVersion) {
3942
- const pending = fetch(REGISTRY_URL, {
3975
+ const cached = readCache();
3976
+ void fetch(REGISTRY_URL, {
3943
3977
  signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
3944
3978
  }).then(async (res) => {
3945
3979
  if (!res.ok) return null;
@@ -3955,12 +3989,11 @@ function startUpdateCheck(currentVersion) {
3955
3989
  return null;
3956
3990
  }).catch(() => null);
3957
3991
  return () => {
3958
- void pending.then((latest) => {
3959
- if (latest && isNewer(latest, currentVersion)) {
3960
- const updateNotice = formatUpdateNotice(currentVersion, latest);
3961
- process.stderr.write(updateNotice);
3962
- }
3963
- });
3992
+ const latest = cached?.latestVersion;
3993
+ if (latest && isNewer(latest, currentVersion)) {
3994
+ const updateNotice = formatUpdateNotice(currentVersion, latest);
3995
+ process.stderr.write(updateNotice);
3996
+ }
3964
3997
  };
3965
3998
  }
3966
3999
 
@@ -4104,6 +4137,7 @@ Manage platforms:
4104
4137
  google Google Ads
4105
4138
  tiktok TikTok Ads
4106
4139
  reddit Reddit Ads
4140
+ linkedin LinkedIn Ads
4107
4141
  drafts Drafts across platforms
4108
4142
 
4109
4143
  Run \`adkit <command> --help\` for details.
@@ -4117,7 +4151,7 @@ var FLAG = {
4117
4151
  budgetDaily: " --budget-daily <n> Daily budget in account currency",
4118
4152
  cta: " --cta <type> sign_up, learn_more, shop_now, download, get_offer, contact_us, subscribe, get_quote, book_now, apply_now"
4119
4153
  };
4120
- var RAW_PLATFORM_LABELS = { google: "Google", meta: "Meta", reddit: "Reddit", tiktok: "TikTok", x: "X" };
4154
+ var RAW_PLATFORM_LABELS = { google: "Google", meta: "Meta", reddit: "Reddit", tiktok: "TikTok", x: "X", linkedin: "LinkedIn" };
4121
4155
  function rawPlatformCommandLine(platform2) {
4122
4156
  return `Raw ${RAW_PLATFORM_LABELS[platform2] ?? platform2} API calls use the shared command: adkit manage platform-api-requests --platform ${platform2} ...`;
4123
4157
  }
@@ -5636,7 +5670,7 @@ Examples:
5636
5670
 
5637
5671
  Flags:
5638
5672
  --data <json> Full request object (preferred for agents)
5639
- --platform <meta|google|tiktok|reddit|x> Target platform (required)
5673
+ --platform <meta|google|tiktok|reddit|x|linkedin> Target platform (required)
5640
5674
  --endpoint <path> Relative API path (required)
5641
5675
  --payload <json> JSON body for POST/PUT/PATCH, query params for GET, omit for DELETE
5642
5676
  --method <GET|POST|PUT|PATCH|DELETE> HTTP method (default: POST)
@@ -5653,7 +5687,8 @@ Examples:
5653
5687
  adkit manage platform-api-requests --platform google --endpoint "customers/123/googleAds:mutate" --payload '{"mutateOperations":[...]}' --request-description "Pause ad" --account 123
5654
5688
  adkit manage platform-api-requests --platform tiktok --endpoint "campaign/get/" --method GET --payload '{"advertiser_id":"123"}' --request-description "List TikTok campaigns" --account 123
5655
5689
  adkit manage platform-api-requests --platform reddit --endpoint "ad_accounts/a2_example/campaigns" --payload '{"name":"Test","objective":"TRAFFIC","configured_status":"PAUSED"}' --request-description "Create paused Reddit campaign" --account a2_example
5656
- adkit manage platform-api-requests --platform x --endpoint "accounts/18ce54d4x5t/campaigns" --method GET --request-description "List X campaigns" --account 18ce54d4x5t`.trim(),
5690
+ adkit manage platform-api-requests --platform x --endpoint "accounts/18ce54d4x5t/campaigns" --method GET --request-description "List X campaigns" --account 18ce54d4x5t
5691
+ adkit manage platform-api-requests --platform linkedin --endpoint "adCampaignGroups/(account:urn:li:sponsoredAccount:512345678)" --method GET --request-description "List LinkedIn campaign groups" --account 512345678`.trim(),
5657
5692
  manage: `adkit manage \u2014 Ad platform management
5658
5693
 
5659
5694
  Platforms:
@@ -5662,6 +5697,7 @@ Platforms:
5662
5697
  tiktok TikTok Ads
5663
5698
  reddit Reddit Ads
5664
5699
  x X Ads raw API access
5700
+ linkedin LinkedIn Ads (account discovery + raw API access)
5665
5701
  drafts Manage drafts across platforms
5666
5702
  platform-api-requests Send raw API requests (escape hatch)
5667
5703
 
@@ -5754,6 +5790,19 @@ ${rawPlatformCommandLine("x")}
5754
5790
 
5755
5791
  Examples:
5756
5792
  adkit manage platform-api-requests --platform x --endpoint "accounts/18ce54d4x5t/campaigns" --method GET --request-description "List X campaigns" --account 18ce54d4x5t`.trim(),
5793
+ linkedin: `adkit manage linkedin \u2014 LinkedIn Ads management
5794
+
5795
+ Entity groups:
5796
+ accounts available List LinkedIn ad accounts discoverable from connected workspace logins
5797
+
5798
+ Account discovery currently supports "available" only \u2014 connect/disconnect/list are not exposed yet.
5799
+ First-class LinkedIn campaign/ad reads and writes are not enabled yet.
5800
+ ${rawPlatformCommandLine("linkedin")}
5801
+
5802
+ General flags:
5803
+ ${FLAG.account}
5804
+
5805
+ Run adkit manage linkedin accounts available to discover ad accounts.`.trim(),
5757
5806
  drafts: `adkit manage drafts \u2014 Manage drafts
5758
5807
 
5759
5808
  list List all drafts
@@ -6680,7 +6729,7 @@ function readRawRequestData(flags) {
6680
6729
  };
6681
6730
  }
6682
6731
  function readRawRequestFlags(flags) {
6683
- const platform2 = requireFlag(flags, "platform", "Required: --platform meta, google, tiktok, reddit, or x");
6732
+ const platform2 = requireFlag(flags, "platform", "Required: --platform meta, google, tiktok, reddit, x, or linkedin");
6684
6733
  const method = readRawRequestMethod(flags.method);
6685
6734
  const rawPayload = readRawRequestFlagPayload(flags);
6686
6735
  const payload = readRawRequestPayload({ method, payload: rawPayload, source: "flag" });
@@ -6715,8 +6764,8 @@ function readRawRequestString(input) {
6715
6764
  throw new CliError("MISSING_FLAG", `Missing required field: \`${input.field}\``, input.hint);
6716
6765
  }
6717
6766
  function readRawRequestPlatform(value) {
6718
- if (value === "meta" || value === "google" || value === "tiktok" || value === "reddit" || value === "x") return value;
6719
- throw new CliError("INVALID_VALUE", `Invalid platform: ${String(value)}`, "Use meta, google, tiktok, reddit, or x");
6767
+ if (value === "meta" || value === "google" || value === "tiktok" || value === "reddit" || value === "x" || value === "linkedin") return value;
6768
+ throw new CliError("INVALID_VALUE", `Invalid platform: ${String(value)}`, "Use meta, google, tiktok, reddit, x, or linkedin");
6720
6769
  }
6721
6770
  function readRawRequestMethod(value) {
6722
6771
  const method = typeof value === "string" ? value.toUpperCase() : "POST";
@@ -6783,7 +6832,8 @@ async function selfUpdate(currentVersion) {
6783
6832
  else console.log(`Updated: ${currentVersion} \u2192 ${newVersion}`);
6784
6833
  } catch {
6785
6834
  console.error("Update failed. Try manually: npm install -g @adkit/cli@latest");
6786
- process.exit(1);
6835
+ process.exitCode = 1;
6836
+ return;
6787
6837
  }
6788
6838
  }
6789
6839
  async function main() {
@@ -6835,18 +6885,18 @@ async function main() {
6835
6885
  const manageTarget = args[1];
6836
6886
  if (flags.help && !manageTarget) {
6837
6887
  showHelp("manage", flags.help === "full");
6838
- process.exit(0);
6888
+ return;
6839
6889
  }
6840
6890
  if (!manageTarget) {
6841
6891
  showHelp("manage", flags.help === "full");
6842
- process.exit(0);
6892
+ return;
6843
6893
  }
6844
6894
  if (manageTarget === "drafts") {
6845
6895
  const action2 = args[2];
6846
6896
  const restArgs2 = args.slice(3);
6847
6897
  if (flags.help) {
6848
6898
  showHelp("drafts", flags.help === "full");
6849
- process.exit(0);
6899
+ return;
6850
6900
  }
6851
6901
  const client2 = requireClient(flags);
6852
6902
  let data2;
@@ -6878,7 +6928,7 @@ async function main() {
6878
6928
  if (manageTarget === "platform-api-requests") {
6879
6929
  if (flags.help) {
6880
6930
  showHelp("platform-api-requests", flags.help === "full");
6881
- process.exit(0);
6931
+ return;
6882
6932
  }
6883
6933
  const client2 = requireClient(flags);
6884
6934
  const data2 = await sendRawRequest(client2, flags);
@@ -6886,19 +6936,19 @@ async function main() {
6886
6936
  return;
6887
6937
  }
6888
6938
  const platform2 = manageTarget;
6889
- if (platform2 !== "meta" && platform2 !== "google" && platform2 !== "tiktok" && platform2 !== "reddit" && platform2 !== "x") throw new CliError("UNKNOWN_COMMAND", `Unknown platform: ${platform2}`, "Available: meta, google, tiktok, reddit, x, drafts, platform-api-requests");
6939
+ if (platform2 !== "meta" && platform2 !== "google" && platform2 !== "tiktok" && platform2 !== "reddit" && platform2 !== "x" && platform2 !== "linkedin") throw new CliError("UNKNOWN_COMMAND", `Unknown platform: ${platform2}`, "Available: meta, google, tiktok, reddit, x, linkedin, drafts, platform-api-requests");
6890
6940
  const entity = args[2];
6891
6941
  const action = args[3];
6892
6942
  const restArgs = args.slice(4);
6893
6943
  if (flags.help) {
6894
6944
  const helpCandidates = [action ? `${platform2} ${entity} ${action}` : void 0, entity ? `${platform2} ${entity}` : void 0, platform2];
6895
- for (const helpKey of helpCandidates) if (helpKey && showHelp(helpKey, flags.help === "full")) process.exit(0);
6945
+ for (const helpKey of helpCandidates) if (helpKey && showHelp(helpKey, flags.help === "full")) return;
6896
6946
  printHelp(USAGE);
6897
- process.exit(0);
6947
+ return;
6898
6948
  }
6899
6949
  if (!entity) {
6900
6950
  showHelp(platform2, flags.help === "full");
6901
- process.exit(0);
6951
+ return;
6902
6952
  }
6903
6953
  const client = requireClient(flags);
6904
6954
  let data;
@@ -6940,7 +6990,7 @@ async function main() {
6940
6990
  case "campaigns": {
6941
6991
  if (!action) {
6942
6992
  showHelp("meta campaigns", flags.help === "full");
6943
- process.exit(0);
6993
+ return;
6944
6994
  }
6945
6995
  switch (action) {
6946
6996
  case "list":
@@ -6967,7 +7017,7 @@ async function main() {
6967
7017
  case "adsets": {
6968
7018
  if (!action) {
6969
7019
  showHelp("meta adsets", flags.help === "full");
6970
- process.exit(0);
7020
+ return;
6971
7021
  }
6972
7022
  switch (action) {
6973
7023
  case "list":
@@ -6994,7 +7044,7 @@ async function main() {
6994
7044
  case "ads": {
6995
7045
  if (!action) {
6996
7046
  showHelp("meta ads", flags.help === "full");
6997
- process.exit(0);
7047
+ return;
6998
7048
  }
6999
7049
  switch (action) {
7000
7050
  case "list":
@@ -7029,7 +7079,7 @@ async function main() {
7029
7079
  case "lead-forms": {
7030
7080
  if (!action) {
7031
7081
  showHelp("meta lead-forms", flags.help === "full");
7032
- process.exit(0);
7082
+ return;
7033
7083
  }
7034
7084
  switch (action) {
7035
7085
  case "list":
@@ -7115,7 +7165,7 @@ async function main() {
7115
7165
  case "assets": {
7116
7166
  if (!action) {
7117
7167
  showHelp("google assets", flags.help === "full");
7118
- process.exit(0);
7168
+ return;
7119
7169
  }
7120
7170
  switch (action) {
7121
7171
  case "list":
@@ -7143,7 +7193,7 @@ async function main() {
7143
7193
  case "media": {
7144
7194
  if (!action || flags.help) {
7145
7195
  showHelp("google media", flags.help === "full");
7146
- process.exit(0);
7196
+ return;
7147
7197
  }
7148
7198
  switch (action) {
7149
7199
  case "upload":
@@ -7157,7 +7207,7 @@ async function main() {
7157
7207
  case "campaigns": {
7158
7208
  if (!action) {
7159
7209
  showHelp("google campaigns", flags.help === "full");
7160
- process.exit(0);
7210
+ return;
7161
7211
  }
7162
7212
  switch (action) {
7163
7213
  case "list":
@@ -7182,7 +7232,7 @@ async function main() {
7182
7232
  case "ad-groups": {
7183
7233
  if (!action) {
7184
7234
  showHelp("google ad-groups", flags.help === "full");
7185
- process.exit(0);
7235
+ return;
7186
7236
  }
7187
7237
  switch (action) {
7188
7238
  case "list":
@@ -7207,7 +7257,7 @@ async function main() {
7207
7257
  case "ads": {
7208
7258
  if (!action) {
7209
7259
  showHelp("google ads", flags.help === "full");
7210
- process.exit(0);
7260
+ return;
7211
7261
  }
7212
7262
  switch (action) {
7213
7263
  case "list":
@@ -7234,7 +7284,7 @@ async function main() {
7234
7284
  case "keywords": {
7235
7285
  if (!action) {
7236
7286
  showHelp("google keywords", flags.help === "full");
7237
- process.exit(0);
7287
+ return;
7238
7288
  }
7239
7289
  switch (action) {
7240
7290
  case "list":
@@ -7254,7 +7304,7 @@ async function main() {
7254
7304
  const negativesAction = restArgs[0];
7255
7305
  if (!negativesAction || flags.help) {
7256
7306
  showHelp("google keywords negatives", flags.help === "full");
7257
- process.exit(0);
7307
+ return;
7258
7308
  }
7259
7309
  switch (negativesAction) {
7260
7310
  case "list":
@@ -7276,7 +7326,7 @@ async function main() {
7276
7326
  const negativeListsAction = restArgs[0];
7277
7327
  if (!negativeListsAction || flags.help) {
7278
7328
  showHelp("google keywords negative-lists", flags.help === "full");
7279
- process.exit(0);
7329
+ return;
7280
7330
  }
7281
7331
  const negativeListArgs = restArgs.slice(1);
7282
7332
  switch (negativeListsAction) {
@@ -7330,7 +7380,7 @@ async function main() {
7330
7380
  case "conversions": {
7331
7381
  if (!action || flags.help) {
7332
7382
  showHelp("google conversions", flags.help === "full");
7333
- process.exit(0);
7383
+ return;
7334
7384
  }
7335
7385
  switch (action) {
7336
7386
  case "upload":
@@ -7396,7 +7446,7 @@ async function main() {
7396
7446
  case "media": {
7397
7447
  if (!action || flags.help) {
7398
7448
  showHelp("tiktok media", flags.help === "full");
7399
- process.exit(0);
7449
+ return;
7400
7450
  }
7401
7451
  switch (action) {
7402
7452
  case "list":
@@ -7414,7 +7464,7 @@ async function main() {
7414
7464
  case "campaigns": {
7415
7465
  if (!action) {
7416
7466
  showHelp("tiktok campaigns", flags.help === "full");
7417
- process.exit(0);
7467
+ return;
7418
7468
  }
7419
7469
  switch (action) {
7420
7470
  case "list":
@@ -7436,7 +7486,7 @@ async function main() {
7436
7486
  case "ad-groups": {
7437
7487
  if (!action) {
7438
7488
  showHelp("tiktok ad-groups", flags.help === "full");
7439
- process.exit(0);
7489
+ return;
7440
7490
  }
7441
7491
  switch (action) {
7442
7492
  case "list":
@@ -7458,7 +7508,7 @@ async function main() {
7458
7508
  case "ads": {
7459
7509
  if (!action) {
7460
7510
  showHelp("tiktok ads", flags.help === "full");
7461
- process.exit(0);
7511
+ return;
7462
7512
  }
7463
7513
  switch (action) {
7464
7514
  case "list":
@@ -7513,8 +7563,23 @@ async function main() {
7513
7563
  default:
7514
7564
  throw new CliError("UNKNOWN_COMMAND", `Unknown entity: reddit ${entity}`, "Available: accounts, platform-api-requests");
7515
7565
  }
7566
+ } else if (platform2 === "linkedin") {
7567
+ switch (entity) {
7568
+ case "accounts":
7569
+ switch (action) {
7570
+ case "available":
7571
+ data = await listLinkedInAvailableAccounts(client, restArgs, flags);
7572
+ emptyHint = "No LinkedIn ad accounts available from the connected workspace login.";
7573
+ break;
7574
+ default:
7575
+ throw new CliError("UNKNOWN_COMMAND", `Unknown action: linkedin accounts ${action}`, "Available: available.");
7576
+ }
7577
+ break;
7578
+ default:
7579
+ throw new CliError("UNKNOWN_COMMAND", `Unknown entity: linkedin ${entity}`, "Available: accounts, platform-api-requests");
7580
+ }
7516
7581
  } else if (platform2 === "x") throw new CliError("UNKNOWN_COMMAND", `Unknown entity: x ${entity}`, "Available: platform-api-requests");
7517
- else throw new CliError("UNKNOWN_COMMAND", "Unknown platform", "Available: meta, google, tiktok, reddit, x, drafts, platform-api-requests");
7582
+ else throw new CliError("UNKNOWN_COMMAND", "Unknown platform", "Available: meta, google, tiktok, reddit, x, linkedin, drafts, platform-api-requests");
7518
7583
  printResult(data, flags, emptyHint, detailEntity);
7519
7584
  return;
7520
7585
  }
@@ -7522,17 +7587,17 @@ async function main() {
7522
7587
  const libraryTarget = args[1];
7523
7588
  if (flags.help && !libraryTarget) {
7524
7589
  showHelp("library", flags.help === "full");
7525
- process.exit(0);
7590
+ return;
7526
7591
  }
7527
7592
  if (!libraryTarget) {
7528
7593
  showHelp("library", flags.help === "full");
7529
- process.exit(0);
7594
+ return;
7530
7595
  }
7531
7596
  if (libraryTarget === "advertisers") {
7532
7597
  const action = args[2];
7533
7598
  if (flags.help || !action) {
7534
7599
  showHelp("library advertisers", flags.help === "full");
7535
- process.exit(0);
7600
+ return;
7536
7601
  }
7537
7602
  const client = requireClient(flags);
7538
7603
  if (action === "add") {
@@ -7553,7 +7618,8 @@ async function main() {
7553
7618
  const query = args.slice(3).join(" ");
7554
7619
  if (!query) {
7555
7620
  console.error("Usage: adkit library advertisers search <query>");
7556
- process.exit(1);
7621
+ process.exitCode = 1;
7622
+ return;
7557
7623
  }
7558
7624
  flags.search = query;
7559
7625
  const data = await listAdvertisers(client, [], flags);
@@ -7610,7 +7676,7 @@ ${pageInfo}`);
7610
7676
  const action = args[2];
7611
7677
  if (flags.help) {
7612
7678
  showHelp("library ads", flags.help === "full");
7613
- process.exit(0);
7679
+ return;
7614
7680
  }
7615
7681
  const client = requireClient(flags);
7616
7682
  if (action && action !== "list") {
@@ -7621,7 +7687,7 @@ ${pageInfo}`);
7621
7687
  const hasFilters = ["platform", "status", "format", "min-days", "max-days", "language", "min-score", "min-spend", "query", "search", "advertiser", "ids", "sort"].some((f) => typeof flags[f] === "string");
7622
7688
  if (!action && !hasFilters) {
7623
7689
  showHelp("library ads", flags.help === "full");
7624
- process.exit(0);
7690
+ return;
7625
7691
  }
7626
7692
  const data = await listLibraryAds(client, args.slice(3), flags);
7627
7693
  if (wantsJson(flags)) printResult(data, flags, "No ads found. Try adjusting your filters.");
@@ -7654,11 +7720,11 @@ ${pageInfo}`);
7654
7720
  const studioTarget = args[1];
7655
7721
  if (flags.help && !studioTarget) {
7656
7722
  showHelp("studio", flags.help === "full");
7657
- process.exit(0);
7723
+ return;
7658
7724
  }
7659
7725
  if (!studioTarget) {
7660
7726
  showHelp("studio", flags.help === "full");
7661
- process.exit(0);
7727
+ return;
7662
7728
  }
7663
7729
  let data;
7664
7730
  let emptyHint;
@@ -7668,7 +7734,7 @@ ${pageInfo}`);
7668
7734
  const restArgs = args.slice(3);
7669
7735
  if (flags.help) {
7670
7736
  showHelp("studio ads", flags.help === "full");
7671
- process.exit(0);
7737
+ return;
7672
7738
  }
7673
7739
  const client = requireClient(flags);
7674
7740
  switch (action) {
@@ -7699,7 +7765,7 @@ ${pageInfo}`);
7699
7765
  const restArgs = args.slice(3);
7700
7766
  if (flags.help) {
7701
7767
  showHelp("studio media", flags.help === "full");
7702
- process.exit(0);
7768
+ return;
7703
7769
  }
7704
7770
  const client = requireClient(flags);
7705
7771
  switch (action) {
@@ -7731,7 +7797,7 @@ ${pageInfo}`);
7731
7797
  case "share":
7732
7798
  if (flags.help) {
7733
7799
  showHelp("studio share", flags.help === "full");
7734
- process.exit(0);
7800
+ return;
7735
7801
  }
7736
7802
  data = await shareAd(requireClient(flags), args.slice(2), flags);
7737
7803
  break;
@@ -7745,7 +7811,7 @@ ${pageInfo}`);
7745
7811
  const action = args[1];
7746
7812
  if (flags.help) {
7747
7813
  showHelp("projects", flags.help === "full");
7748
- process.exit(0);
7814
+ return;
7749
7815
  }
7750
7816
  const client = requireClient(flags, { projectOptional: true });
7751
7817
  switch (action) {
@@ -7808,6 +7874,7 @@ ${pageInfo}`);
7808
7874
  ...err.instructions && { instructions: err.instructions },
7809
7875
  ...err.actionUrl && { actionUrl: err.actionUrl },
7810
7876
  ...err.suggestion && { suggestion: err.suggestion },
7877
+ ...err.notice && { notice: err.notice },
7811
7878
  ...shouldNudgeFeedback && { hint: "If this error is unexpected, report it using: adkit feedback" }
7812
7879
  });
7813
7880
  console.error(errorPayload);
@@ -7835,7 +7902,8 @@ ${pageInfo}`);
7835
7902
  INVALID_API_KEY: 4,
7836
7903
  NOT_AUTHENTICATED: 4
7837
7904
  };
7838
- process.exit(err instanceof CliError ? EXIT_CODES[err.code] ?? 1 : 1);
7905
+ process.exitCode = err instanceof CliError ? EXIT_CODES[err.code] ?? 1 : 1;
7906
+ return;
7839
7907
  } finally {
7840
7908
  if (args[0] !== "update") printUpdateNotice();
7841
7909
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adkit/cli",
3
- "version": "1.12.24",
3
+ "version": "1.12.26",
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",