@koda-sl/baker-cli 0.298.0-dev.fd66d4f19 → 0.298.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.
package/dist/cli.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  ulid,
59
59
  validateCanvasDeep,
60
60
  ytDlpBlockSignal
61
- } from "./chunk-HVITCN7H.js";
61
+ } from "./chunk-YFQWCJX4.js";
62
62
  import {
63
63
  csvOrJson,
64
64
  daysAgoIso,
@@ -1427,6 +1427,7 @@ var TEMP_REF_PREFIX = "li_temp_";
1427
1427
  var TEMP_REF_REGEX = /^li_temp_[A-Za-z0-9_-]{4,}$/;
1428
1428
  var NUMERIC_ID_REGEX = /^\d+$/;
1429
1429
  var URN_REGEX = /^urn:li:[a-zA-Z]+:.+$/;
1430
+ var CONVERSION_URN_REGEX = /^urn:lla:llaPartnerConversion:\d+$/;
1430
1431
  var SPONSORED_ACCOUNT_URN_REGEX = /^urn:li:sponsoredAccount:\d+$/;
1431
1432
  var IMAGE_URN_REGEX = /^urn:li:image:.+$/;
1432
1433
  var VIDEO_URN_REGEX = /^urn:li:video:.+$/;
@@ -2006,12 +2007,44 @@ var LINKEDIN_DRAFT_OP_KINDS = [
2006
2007
  "audience.uploadList",
2007
2008
  "conversion.create",
2008
2009
  "conversion.update",
2010
+ "conversion.associateCampaign",
2011
+ "conversion.dissociateCampaign",
2009
2012
  "leadForm.create",
2010
2013
  "leadForm.update"
2011
2014
  ];
2012
2015
  var linkedinDraftOpKindSchema = z3.enum(LINKEDIN_DRAFT_OP_KINDS);
2013
2016
  var accountIdSchema = z3.string().regex(NUMERIC_ID_REGEX, "accountId must be the bare numeric ad account id");
2014
2017
  var updateTargetSchema = z3.union([z3.string().regex(URN_REGEX), z3.string().regex(NUMERIC_ID_REGEX), tempRefSchema]);
2018
+ var conversionCampaignTargetSchema = z3.union([
2019
+ // LinkedIn's own namespace for a conversion rule is `urn:lla:` — it is what
2020
+ // the `campaignConversions` key and the CAPI payload use, and what LinkedIn's
2021
+ // docs show — while `conversions list` prints Baker's `urn:li:` spelling of
2022
+ // the same rule. `URN_REGEX` is urn:li: only, so accept the other one here
2023
+ // rather than have the agent translate between two names for one rule.
2024
+ z3.string().regex(CONVERSION_URN_REGEX),
2025
+ z3.string().regex(URN_REGEX),
2026
+ z3.string().regex(NUMERIC_ID_REGEX),
2027
+ tempRefSchema
2028
+ ]);
2029
+ var conversionCampaignSchema = z3.object({
2030
+ campaign: z3.union([z3.string().regex(URN_REGEX), z3.string().regex(NUMERIC_ID_REGEX), tempRefSchema])
2031
+ });
2032
+ function conversionCampaignOp(kind) {
2033
+ return z3.object({
2034
+ kind: z3.literal(kind),
2035
+ accountId: accountIdSchema,
2036
+ target: conversionCampaignTargetSchema,
2037
+ payload: conversionCampaignSchema
2038
+ }).superRefine((op, ctx) => {
2039
+ if (TEMP_REF_REGEX.test(op.target)) {
2040
+ ctx.addIssue({
2041
+ code: "custom",
2042
+ path: ["target"],
2043
+ message: "a conversion rule staged in this same chat has no id yet, so it cannot be linked to a campaign \u2014 stage the rule with associateAllCampaigns, or link it once this chat has published"
2044
+ });
2045
+ }
2046
+ });
2047
+ }
2015
2048
  function createOp(kind, payload) {
2016
2049
  return z3.object({ kind: z3.literal(kind), accountId: accountIdSchema, payload });
2017
2050
  }
@@ -2039,6 +2072,8 @@ var linkedinDraftOpInputSchema = z3.discriminatedUnion("kind", [
2039
2072
  createOp("audience.uploadList", audienceUploadListSchema),
2040
2073
  createOp("conversion.create", conversionCreateSchema),
2041
2074
  updateOp("conversion.update", conversionUpdateSchema),
2075
+ conversionCampaignOp("conversion.associateCampaign"),
2076
+ conversionCampaignOp("conversion.dissociateCampaign"),
2042
2077
  createOp("leadForm.create", leadFormCreateSchema),
2043
2078
  updateOp("leadForm.update", leadFormUpdateSchema)
2044
2079
  ]);
@@ -7339,16 +7374,7 @@ var SURFACE_RULES = [
7339
7374
  /\bhotjar\b/i,
7340
7375
  /\bgtm\s+snippet\b/i,
7341
7376
  /\bcapi\b/i,
7342
- /\b(?:install|add|remove|swap|instalar|colocar|poner|anadir|agregar)\b[\s\S]*\b(?:snippet|script|tags?|etiquetas?|pixel)\b/i,
7343
- // The product's own word for this object, in both languages. A tracking
7344
- // script named in Spanish ("el código de seguimiento de HubSpot", "una
7345
- // etiqueta tipo hubspot") matched none of the signals above, so the one
7346
- // Task that most needed the redirect — file it, or show the form? — was
7347
- // filed. `tag-manager` is evaluated first and still claims the container.
7348
- /\btracking\s+(?:code|script|snippet|tag)\b/i,
7349
- /\bcodigos?\s+de\s+seguimiento\b/i,
7350
- /\bscripts?\s+de\s+seguimiento\b/i,
7351
- /\betiquetas?\s+(?:de\s+seguimiento|de\s+medicion|tipo\s+\w+)\b/i
7377
+ /\b(?:install|add|remove|swap|instalar|colocar)\b[\s\S]*\b(?:snippet|script|tag)\b/i
7352
7378
  ],
7353
7379
  // Two vetoes. A structured snippet is a Google Ads extension, not a script
7354
7380
  // on the page — `ads-write` claims it above, and this stops both rules
@@ -18288,6 +18314,24 @@ registerSchema({
18288
18314
  file: { type: "string", description: "JSON file with fields to change", required: false }
18289
18315
  }
18290
18316
  });
18317
+ registerSchema({
18318
+ command: "ads.linkedin.conversions.associate-campaign",
18319
+ description: "Count an existing conversion rule for one ad set. Which ad sets a rule counts for is a separate LinkedIn record, not a field on the rule \u2014 `conversions update` cannot change it, and `--associate-all-campaigns` exists only on create. Staged until publish.",
18320
+ args: {
18321
+ id: { type: "positional", description: "Conversion rule id or URN", required: true },
18322
+ ...writeAccountArgs,
18323
+ campaign: { type: "string", description: "Ad set (campaign) id or URN", required: true }
18324
+ }
18325
+ });
18326
+ registerSchema({
18327
+ command: "ads.linkedin.conversions.dissociate-campaign",
18328
+ description: "Stop counting an existing conversion rule for one ad set. Staged until publish.",
18329
+ args: {
18330
+ id: { type: "positional", description: "Conversion rule id or URN", required: true },
18331
+ ...writeAccountArgs,
18332
+ campaign: { type: "string", description: "Ad set (campaign) id or URN", required: true }
18333
+ }
18334
+ });
18291
18335
  registerSchema({
18292
18336
  command: "ads.linkedin.lead-forms.create",
18293
18337
  description: "Stage a new Lead Gen Form from a JSON file: {name, headline \u226460, description? \u2264160, privacyPolicyUrl, questions[] \u226412 (playbook: \u22644 for completion), thankYou?, legalDisclaimer?}. Staged until publish.",
@@ -19092,6 +19136,57 @@ Example: baker ads linkedin conversions update 104988516 --post-click-window 30
19092
19136
  });
19093
19137
  }
19094
19138
  });
19139
+ var CONVERSION_CAMPAIGN_EXPLAINER = `Which ad sets a conversion rule counts for is a separate LinkedIn record, not a field on the rule \u2014 \`conversions update\` cannot change it, and \`--associate-all-campaigns\` only exists on create.`;
19140
+ function conversionCampaignArgs() {
19141
+ return {
19142
+ id: { type: "positional", description: "Conversion rule id or URN", required: true },
19143
+ ...accountArgs,
19144
+ campaign: { type: "string", description: "Ad set (campaign) id or URN", required: true }
19145
+ };
19146
+ }
19147
+ function requireCampaignArg(args) {
19148
+ const campaign = args.campaign;
19149
+ if (typeof campaign !== "string" || campaign.length === 0) {
19150
+ failWriteValidation2("--campaign is required \u2014 pass the ad set id or URN this conversion should count for");
19151
+ }
19152
+ return campaign;
19153
+ }
19154
+ var conversionsAssociateCommand = defineCommand33({
19155
+ meta: {
19156
+ name: "associate-campaign",
19157
+ description: `Count an existing conversion rule for one ad set. ${STAGED_NOTE}
19158
+ ${CONVERSION_CAMPAIGN_EXPLAINER}
19159
+ Example: baker ads linkedin conversions associate-campaign 104988516 --campaign 337643194`
19160
+ },
19161
+ args: conversionCampaignArgs(),
19162
+ run: async ({ args }) => {
19163
+ const accountId = bareAccountId(args);
19164
+ await stageOp({
19165
+ kind: "conversion.associateCampaign",
19166
+ accountId,
19167
+ target: requireTarget2(args, "conversion rule"),
19168
+ payload: { campaign: requireCampaignArg(args) }
19169
+ });
19170
+ }
19171
+ });
19172
+ var conversionsDissociateCommand = defineCommand33({
19173
+ meta: {
19174
+ name: "dissociate-campaign",
19175
+ description: `Stop counting an existing conversion rule for one ad set. ${STAGED_NOTE}
19176
+ ${CONVERSION_CAMPAIGN_EXPLAINER}
19177
+ Example: baker ads linkedin conversions dissociate-campaign 104988516 --campaign 337643194`
19178
+ },
19179
+ args: conversionCampaignArgs(),
19180
+ run: async ({ args }) => {
19181
+ const accountId = bareAccountId(args);
19182
+ await stageOp({
19183
+ kind: "conversion.dissociateCampaign",
19184
+ accountId,
19185
+ target: requireTarget2(args, "conversion rule"),
19186
+ payload: { campaign: requireCampaignArg(args) }
19187
+ });
19188
+ }
19189
+ });
19095
19190
  var leadFormsCreateCommand = defineCommand33({
19096
19191
  meta: {
19097
19192
  name: "create",
@@ -20224,13 +20319,17 @@ var conversionsCommand2 = defineCommand43({
20224
20319
  Subcommands:
20225
20320
  list \u2014 every rule on the account
20226
20321
  health \u2014 playbook \xA707 5-point health check
20227
- create / update \u2014 stage a conversion-rule write (applies on chat publish)`
20322
+ create / update \u2014 stage a conversion-rule write (applies on chat publish)
20323
+ associate-campaign / dissociate-campaign
20324
+ \u2014 which ad sets a rule counts for (its own LinkedIn record, not a field on the rule)`
20228
20325
  },
20229
20326
  subCommands: {
20230
20327
  list: listCmd,
20231
20328
  health: healthCmd,
20232
20329
  create: conversionsCreateCommand,
20233
- update: conversionsUpdateCommand
20330
+ update: conversionsUpdateCommand,
20331
+ "associate-campaign": conversionsAssociateCommand,
20332
+ "dissociate-campaign": conversionsDissociateCommand
20234
20333
  }
20235
20334
  });
20236
20335
 
@@ -57841,12 +57940,6 @@ function renderEffectiveEntry(entry) {
57841
57940
  return configLines.length > 0 ? `${header}
57842
57941
  ${configLines.join("\n")}` : header;
57843
57942
  }
57844
- function tagsListHints() {
57845
- return [
57846
- "To create, edit or delete a tag, call the `request_tag_input` approval form (tool `mcp__baker_ui__request_tag_input`, server `baker_ui`) \u2014 it is attached to every turn of this chat and collects any secret values itself.",
57847
- "Do NOT conclude the form is unavailable from your tool list: call it, and report what it returns. And never file a tag change as a Task \u2014 a Task hands the user work this chat can stage in one call."
57848
- ];
57849
- }
57850
57943
 
57851
57944
  // src/commands/tags/index.ts
57852
57945
  registerSchema({
@@ -57860,21 +57953,16 @@ async function listTags(json) {
57860
57953
  try {
57861
57954
  const chatId = requireChatId();
57862
57955
  const response = await apiPost("/api/tags/list", { chatId });
57863
- const hints2 = tagsListHints();
57864
57956
  if (json) {
57865
- writeJson({ ok: true, data: response, hints: hints2 });
57957
+ writeJson({ ok: true, data: response });
57866
57958
  return;
57867
57959
  }
57868
57960
  if (response.tags.length === 0) {
57869
- process.stdout.write("No tags configured.\n");
57870
- } else {
57871
- process.stdout.write(`${response.tags.map(renderEffectiveEntry).join("\n")}
57872
- `);
57961
+ process.stdout.write("No tags configured. Propose one with the request_tag_input tool (baker_ui).\n");
57962
+ return;
57873
57963
  }
57874
- for (const hint of hints2) {
57875
- process.stderr.write(`${hint}
57964
+ process.stdout.write(`${response.tags.map(renderEffectiveEntry).join("\n")}
57876
57965
  `);
57877
- }
57878
57966
  } catch (err) {
57879
57967
  failApi3(err);
57880
57968
  }
@@ -57896,7 +57984,7 @@ async function listDraft4(chat) {
57896
57984
  try {
57897
57985
  const chatId = resolveChatId(chat);
57898
57986
  const response = await apiPost("/api/tags/draft", { chatId });
57899
- writeJson({ ok: true, data: response, hints: tagsListHints() });
57987
+ writeJson({ ok: true, data: response });
57900
57988
  } catch (err) {
57901
57989
  failApi3(err);
57902
57990
  }