@koda-sl/baker-cli 0.364.0-dev.18349e66a → 0.364.0-dev.894c59720
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/README.md +3 -5
- package/dist/{chunk-VVQLRFCI.js → chunk-A2LM5EDF.js} +2 -2
- package/dist/chunk-A2LM5EDF.js.map +1 -0
- package/dist/{chunk-SR56QQTD.js → chunk-BLMXG42J.js} +2 -2
- package/dist/cli.js +202 -380
- package/dist/cli.js.map +1 -1
- package/dist/{output-OSSBUGT7.js → output-M2DBCZFG.js} +2 -2
- package/dist/{shared-MSI4UMZ3.js → shared-BROA3UXS.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-VVQLRFCI.js.map +0 -1
- /package/dist/{chunk-SR56QQTD.js.map → chunk-BLMXG42J.js.map} +0 -0
- /package/dist/{output-OSSBUGT7.js.map → output-M2DBCZFG.js.map} +0 -0
- /package/dist/{shared-MSI4UMZ3.js.map → shared-BROA3UXS.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
resolveAccountIdArg,
|
|
79
79
|
resolveEffectiveStatus,
|
|
80
80
|
todayIso
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-BLMXG42J.js";
|
|
82
82
|
import {
|
|
83
83
|
buildQueryCacheKey,
|
|
84
84
|
cacheGet,
|
|
@@ -94,7 +94,7 @@ import {
|
|
|
94
94
|
writeAdsJson,
|
|
95
95
|
writeAdsOutput,
|
|
96
96
|
writeJsonEnvelope
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-A2LM5EDF.js";
|
|
98
98
|
import {
|
|
99
99
|
ApiError,
|
|
100
100
|
apiGet,
|
|
@@ -4394,7 +4394,7 @@ var CAPABILITY_SURFACE_SPECS = {
|
|
|
4394
4394
|
provider: "google-analytics",
|
|
4395
4395
|
resourceNoun: "property",
|
|
4396
4396
|
// Like Tag Manager: staged during the chat, applied for real at publish,
|
|
4397
|
-
//
|
|
4397
|
+
// every time. A connection made before writes existed is
|
|
4398
4398
|
// read-only until it is reconnected, and `access` does NOT say so — it
|
|
4399
4399
|
// reports what the Baker app asks Google for, which is now app-wide
|
|
4400
4400
|
// read-write. The per-company signal is `scopeBlockers`, which compares
|
|
@@ -8538,7 +8538,7 @@ var SURFACE_RULES = [
|
|
|
8538
8538
|
];
|
|
8539
8539
|
var FAN_OUT_NUDGE_THRESHOLD = 2;
|
|
8540
8540
|
var FAN_OUT_THRESHOLD = 3;
|
|
8541
|
-
var SCHEDULED_HINT = 'This reads as recurring/scheduled work. If it should run on a cadence or a future date, create a Scheduled agent instead \u2014 baker scheduled-agents create --cron "0 9 * * MON" (or --run-at, or --trigger for a reaction rather than a clock; guide: `__tooling__/docs/tools/baker/scheduled-agents.md`). Do
|
|
8541
|
+
var SCHEDULED_HINT = 'This reads as recurring/scheduled work. If it should run on a cadence or a future date, create a Scheduled agent instead \u2014 baker scheduled-agents create --cron "0 9 * * MON" (or --run-at, or --trigger for a reaction rather than a clock; guide: `__tooling__/docs/tools/baker/scheduled-agents.md`). Do not capture "set up a schedule" as a Work Action.';
|
|
8542
8542
|
function looksExecutable(name, description) {
|
|
8543
8543
|
const foldedName = fold(name);
|
|
8544
8544
|
const full = `${foldedName}
|
|
@@ -8789,7 +8789,7 @@ var claimCommand = defineCommand({
|
|
|
8789
8789
|
import { defineCommand as defineCommand2 } from "citty";
|
|
8790
8790
|
registerSchema({
|
|
8791
8791
|
command: "actions.complete",
|
|
8792
|
-
description: "Stage completion of an action (it was
|
|
8792
|
+
description: "Stage completion of an action (it was done). Accepts a real action ID (must be claimed) or a temp ID from the same draft. The action becomes completed when the chat is published. --note is required and must describe what you actually did to resolve it (what changed, where, and the outcome) \u2014 it is the client-facing record surfaced by `baker actions log`. Don't use this to drop an action you no longer want \u2014 to remove a staged op use `actions draft remove`, to close an unwanted published action use `actions discard`.",
|
|
8793
8793
|
args: {
|
|
8794
8794
|
id: { type: "string", description: "Action ID or temp ID", required: true },
|
|
8795
8795
|
note: {
|
|
@@ -12529,7 +12529,7 @@ var PLANNER_FIELD_DESCRIPTIONS = {
|
|
|
12529
12529
|
// src/commands/ads/google/keywords/discover.ts
|
|
12530
12530
|
registerSchema({
|
|
12531
12531
|
command: "ads.google.keywords.discover",
|
|
12532
|
-
description: 'Discover keyword ideas from seed keywords or URLs. Returns { source: "keyword_planner_estimate", keywords, total_results, next_page_token? }.
|
|
12532
|
+
description: 'Discover keyword ideas from seed keywords or URLs. Returns { source: "keyword_planner_estimate", keywords, total_results, next_page_token? }. These are Keyword Planner estimates of total market search volume, not this account\'s data: every row carries a source column and every metric is prefixed planner_ (planner_avg_monthly_searches, planner_competition, ...). Never report a planner_ number as impressions, clicks or any account metric \u2014 read those with `baker ads google query` against the account. If --location and --language are omitted, they default to United States (2840) and English (1000); `query_context` shows which were used.',
|
|
12533
12533
|
args: {
|
|
12534
12534
|
"customer-id": {
|
|
12535
12535
|
type: "string",
|
|
@@ -12540,12 +12540,12 @@ registerSchema({
|
|
|
12540
12540
|
url: { type: "string", description: "URL to extract keyword ideas from", required: false },
|
|
12541
12541
|
location: {
|
|
12542
12542
|
type: "string",
|
|
12543
|
-
description: "Geo target ID.
|
|
12543
|
+
description: "Geo target ID. Defaults to 2840 (United States) if omitted \u2014 always set this for non-US markets",
|
|
12544
12544
|
required: false
|
|
12545
12545
|
},
|
|
12546
12546
|
language: {
|
|
12547
12547
|
type: "string",
|
|
12548
|
-
description: "Language ID.
|
|
12548
|
+
description: "Language ID. Defaults to 1000 (English) if omitted \u2014 always set this for non-English markets",
|
|
12549
12549
|
required: false
|
|
12550
12550
|
},
|
|
12551
12551
|
limit: { type: "string", description: "Max keyword ideas (default: 20, max: 100)", required: false, default: 20 },
|
|
@@ -12706,7 +12706,7 @@ var locationsCommand = defineCommand25({
|
|
|
12706
12706
|
import { defineCommand as defineCommand26 } from "citty";
|
|
12707
12707
|
registerSchema({
|
|
12708
12708
|
command: "ads.google.keywords.metrics",
|
|
12709
|
-
description: 'Get historical market metrics for specific keywords. Returns { source: "keyword_planner_estimate", historical_metrics: [...] }.
|
|
12709
|
+
description: 'Get historical market metrics for specific keywords. Returns { source: "keyword_planner_estimate", historical_metrics: [...] }. These are Keyword Planner estimates of total market search volume, not this account\'s data: every row carries a source column and every metric is prefixed planner_ (planner_avg_monthly_searches, planner_competition, ...). Never report a planner_ number as impressions, clicks or any account metric \u2014 read those with `baker ads google query` against the account. If --location and --language are omitted, they default to United States (2840) and English (1000); `query_context` shows which were used.',
|
|
12710
12710
|
args: {
|
|
12711
12711
|
"customer-id": {
|
|
12712
12712
|
type: "string",
|
|
@@ -12716,12 +12716,12 @@ registerSchema({
|
|
|
12716
12716
|
keywords: { type: "string", description: "Comma-separated keywords to analyze (max 200)", required: true },
|
|
12717
12717
|
location: {
|
|
12718
12718
|
type: "string",
|
|
12719
|
-
description: "Geo target ID.
|
|
12719
|
+
description: "Geo target ID. Defaults to 2840 (United States) if omitted \u2014 always set this for non-US markets",
|
|
12720
12720
|
required: false
|
|
12721
12721
|
},
|
|
12722
12722
|
language: {
|
|
12723
12723
|
type: "string",
|
|
12724
|
-
description: "Language ID.
|
|
12724
|
+
description: "Language ID. Defaults to 1000 (English) if omitted \u2014 always set this for non-English markets",
|
|
12725
12725
|
required: false
|
|
12726
12726
|
},
|
|
12727
12727
|
output: { type: "string", description: "Format: json|csv|jsonl|md", required: false, default: "json" },
|
|
@@ -13635,7 +13635,7 @@ function completenessWarnings(read) {
|
|
|
13635
13635
|
return [
|
|
13636
13636
|
{
|
|
13637
13637
|
code: "TRUNCATED_RESULTS",
|
|
13638
|
-
message: `INCOMPLETE READ \u2014 ${cause} These rows are a page, not the data set.
|
|
13638
|
+
message: `INCOMPLETE READ \u2014 ${cause} These rows are a page, not the data set. Don't count, total or describe them as the whole picture. ${fix}`
|
|
13639
13639
|
}
|
|
13640
13640
|
];
|
|
13641
13641
|
}
|
|
@@ -18212,6 +18212,7 @@ var fileArg = {
|
|
|
18212
18212
|
description: "The op payload: a JSON file path, or the JSON object inline (flags override it)"
|
|
18213
18213
|
}
|
|
18214
18214
|
};
|
|
18215
|
+
var STAGED_WRITE = "Stages only \u2014 applies to the live account when the chat is published. Field contract: `baker capabilities google-ads`.";
|
|
18215
18216
|
var BUDGET_DEMAND_HINTS = [
|
|
18216
18217
|
"Check this daily budget against the search volume you measured for these keywords, not against the plan you had before you measured it. A budget many times larger than the traffic the target pool can absorb never spends, and reads to the client as a number nobody costed.",
|
|
18217
18218
|
"No volume measured yet? Pull it first \u2014 `baker ads google query --preset search-terms` for what the account already captures, `baker ads google keywords metrics` for the market estimate (those are planner figures, never account performance)."
|
|
@@ -18223,11 +18224,14 @@ var budgetsCommand = defineCommand31({
|
|
|
18223
18224
|
// first. A budget several times what the target pool can absorb never spends, and reads to the
|
|
18224
18225
|
// client as a plan nobody costed.
|
|
18225
18226
|
create: defineCommand31({
|
|
18226
|
-
meta: {
|
|
18227
|
+
meta: {
|
|
18228
|
+
name: "create",
|
|
18229
|
+
description: `Stage a daily campaign budget; campaigns reference it by the g_temp_* ref it returns (--budget-ref). ${STAGED_WRITE}`
|
|
18230
|
+
},
|
|
18227
18231
|
args: {
|
|
18228
18232
|
...customerIdArg,
|
|
18229
18233
|
...fileArg,
|
|
18230
|
-
name: { type: "string", description:
|
|
18234
|
+
name: { type: "string", description: 'Budget name as shown in Google Ads (e.g. "Brand search \u2014 daily")' },
|
|
18231
18235
|
amount: { type: "string", description: "Daily amount in major currency units (e.g. 50)" },
|
|
18232
18236
|
delivery: { type: "string", description: "STANDARD | ACCELERATED" },
|
|
18233
18237
|
shared: { type: "boolean", description: "Explicitly shared budget" }
|
|
@@ -18244,11 +18248,14 @@ var budgetsCommand = defineCommand31({
|
|
|
18244
18248
|
}
|
|
18245
18249
|
}),
|
|
18246
18250
|
update: defineCommand31({
|
|
18247
|
-
meta: {
|
|
18251
|
+
meta: {
|
|
18252
|
+
name: "update",
|
|
18253
|
+
description: `Stage a change to an existing budget's name, daily amount or delivery. ${STAGED_WRITE}`
|
|
18254
|
+
},
|
|
18248
18255
|
args: {
|
|
18249
18256
|
...customerIdArg,
|
|
18250
18257
|
...fileArg,
|
|
18251
|
-
name: { type: "string" },
|
|
18258
|
+
name: { type: "string", description: "New budget name as shown in Google Ads" },
|
|
18252
18259
|
amount: { type: "string", description: "New daily amount in major currency units" },
|
|
18253
18260
|
delivery: { type: "string" }
|
|
18254
18261
|
},
|
|
@@ -18457,11 +18464,14 @@ var campaignsCommand = defineCommand31({
|
|
|
18457
18464
|
meta: { name: "campaigns", description: "Stage campaign create/update/pause/resume/remove" },
|
|
18458
18465
|
subCommands: {
|
|
18459
18466
|
create: defineCommand31({
|
|
18460
|
-
meta: {
|
|
18467
|
+
meta: {
|
|
18468
|
+
name: "create",
|
|
18469
|
+
description: `Stage a new campaign on a budget (--budget-ref); it is created paused unless --status ENABLED. ${STAGED_WRITE}`
|
|
18470
|
+
},
|
|
18461
18471
|
args: {
|
|
18462
18472
|
...customerIdArg,
|
|
18463
18473
|
...fileArg,
|
|
18464
|
-
name: { type: "string" },
|
|
18474
|
+
name: { type: "string", description: 'Campaign name, unique in the account (e.g. "Search \u2014 Brand \u2014 ES")' },
|
|
18465
18475
|
"channel-type": {
|
|
18466
18476
|
type: "string",
|
|
18467
18477
|
description: "SEARCH | DISPLAY | SHOPPING | VIDEO | PERFORMANCE_MAX | DEMAND_GEN | \u2026"
|
|
@@ -18524,11 +18534,14 @@ var campaignsCommand = defineCommand31({
|
|
|
18524
18534
|
}
|
|
18525
18535
|
}),
|
|
18526
18536
|
update: defineCommand31({
|
|
18527
|
-
meta: {
|
|
18537
|
+
meta: {
|
|
18538
|
+
name: "update",
|
|
18539
|
+
description: `Stage a change to an existing campaign's name, budget, bidding or settings. ${STAGED_WRITE}`
|
|
18540
|
+
},
|
|
18528
18541
|
args: {
|
|
18529
18542
|
...customerIdArg,
|
|
18530
18543
|
...fileArg,
|
|
18531
|
-
name: { type: "string" },
|
|
18544
|
+
name: { type: "string", description: "New campaign name, unique in the account" },
|
|
18532
18545
|
"budget-ref": { type: "string" },
|
|
18533
18546
|
"bidding-strategy": {
|
|
18534
18547
|
type: "string",
|
|
@@ -18608,15 +18621,21 @@ var adGroupsCommand = defineCommand31({
|
|
|
18608
18621
|
meta: { name: "ad-groups", description: "Stage ad group create/update/pause/resume/remove" },
|
|
18609
18622
|
subCommands: {
|
|
18610
18623
|
create: defineCommand31({
|
|
18611
|
-
meta: {
|
|
18624
|
+
meta: {
|
|
18625
|
+
name: "create",
|
|
18626
|
+
description: `Stage a new ad group in a campaign (--campaign-ref); it is created paused unless --status ENABLED. ${STAGED_WRITE}`
|
|
18627
|
+
},
|
|
18612
18628
|
args: {
|
|
18613
18629
|
...customerIdArg,
|
|
18614
18630
|
...fileArg,
|
|
18615
|
-
name: {
|
|
18631
|
+
name: {
|
|
18632
|
+
type: "string",
|
|
18633
|
+
description: 'Ad group name, unique within its campaign (e.g. "Solar panels \u2014 price")'
|
|
18634
|
+
},
|
|
18616
18635
|
"campaign-ref": { type: "string", description: "Campaign ref (g_temp_*, id, or resource name)" },
|
|
18617
18636
|
type: {
|
|
18618
18637
|
type: "string",
|
|
18619
|
-
description: "Ad group type \u2014 leave it out and Google derives it from the campaign's channel, which is
|
|
18638
|
+
description: "Ad group type \u2014 leave it out and Google derives it from the campaign's channel, which is required on a Demand Gen campaign (there is no Demand Gen ad group type). SEARCH_STANDARD | DISPLAY_STANDARD | SHOPPING_PRODUCT_ADS | VIDEO_*"
|
|
18620
18639
|
},
|
|
18621
18640
|
"cpc-bid": { type: "string", description: "Default CPC bid in major units" },
|
|
18622
18641
|
status: { type: "string" }
|
|
@@ -18634,11 +18653,14 @@ var adGroupsCommand = defineCommand31({
|
|
|
18634
18653
|
}
|
|
18635
18654
|
}),
|
|
18636
18655
|
update: defineCommand31({
|
|
18637
|
-
meta: {
|
|
18656
|
+
meta: {
|
|
18657
|
+
name: "update",
|
|
18658
|
+
description: `Stage a change to an existing ad group's name, default CPC bid or status. ${STAGED_WRITE}`
|
|
18659
|
+
},
|
|
18638
18660
|
args: {
|
|
18639
18661
|
...customerIdArg,
|
|
18640
18662
|
...fileArg,
|
|
18641
|
-
name: { type: "string" },
|
|
18663
|
+
name: { type: "string", description: "New ad group name, unique within its campaign" },
|
|
18642
18664
|
"cpc-bid": { type: "string" },
|
|
18643
18665
|
status: { type: "string" }
|
|
18644
18666
|
},
|
|
@@ -19416,7 +19438,7 @@ var assetsCommand = defineCommand31({
|
|
|
19416
19438
|
),
|
|
19417
19439
|
update: assetsUpdateCommand,
|
|
19418
19440
|
attach: fileCreateCommand("attach", "google.assetLink.attach", "Attach an asset to a campaign/adGroup/customer", [
|
|
19419
|
-
"Image extensions cannot be linked \u2014 Google refuses AD_IMAGE and every marketing-image field type at every level, on every API version \u2014 but stage the link anyway: it is skipped rather than stored, the rest of a batch is unaffected, and it is what records the handover Task naming those images and that campaign. That is the
|
|
19441
|
+
"Image extensions cannot be linked \u2014 Google refuses AD_IMAGE and every marketing-image field type at every level, on every API version \u2014 but stage the link anyway: it is skipped rather than stored, the rest of a batch is unaffected, and it is what records the handover Task naming those images and that campaign. That is the only record when the images are already in the account and you are uploading nothing. Then tell the user they are already in their Google Ads account and only need adding to the campaign under Assets; do not stage a second Task with `baker actions`. Two images that do link: the advertiser's logo through this command (`BUSINESS_LOGO`, campaign or customer level, on a verified account), and Performance Max asset-group images, which are a different mechanism (`asset-groups attach`)."
|
|
19420
19442
|
]),
|
|
19421
19443
|
detach: statusCommand2("google.assetLink.detach", "asset link", [
|
|
19422
19444
|
"Pass the resource name Google gave you \u2014 `SELECT campaign_asset.resource_name \u2026 FROM campaign_asset WHERE campaign_asset.status != 'REMOVED'` (or `ad_group_asset` / `customer_asset`) \u2014 never one composed out of an owner id and an asset id. A link's own status is not its campaign's and not its ad group's, so an inventory read scoped only to those lists extensions that are already detached, and a link between an asset and an owner that never held it parses fine and exists nowhere. Either way the target is read back before it is staged, and a detach of a link that is not there is refused here rather than at publish."
|
|
@@ -19426,14 +19448,14 @@ var assetsCommand = defineCommand31({
|
|
|
19426
19448
|
var audienceModeArg = {
|
|
19427
19449
|
mode: {
|
|
19428
19450
|
type: "string",
|
|
19429
|
-
description: "observation = the audience only adjusts bids, reach is unchanged | targeting = the ads are shown
|
|
19451
|
+
description: "observation = the audience only adjusts bids, reach is unchanged | targeting = the ads are shown only to people in the audiences attached to this campaign/ad group"
|
|
19430
19452
|
}
|
|
19431
19453
|
};
|
|
19432
19454
|
function requireAudienceMode(value) {
|
|
19433
19455
|
const mode = typeof value === "string" ? value.toLowerCase() : void 0;
|
|
19434
19456
|
if (mode !== "observation" && mode !== "targeting") {
|
|
19435
19457
|
failWriteValidation(
|
|
19436
|
-
`pass --mode observation (the audience adjusts bids and reach is unchanged \u2014 the Google Ads interface's default) or --mode targeting (the ads are shown
|
|
19458
|
+
`pass --mode observation (the audience adjusts bids and reach is unchanged \u2014 the Google Ads interface's default) or --mode targeting (the ads are shown only to people in the audiences on this campaign/ad group). There is no safe default: the API's own default is targeting, which can cut a campaign's reach to the size of the list.`
|
|
19437
19459
|
);
|
|
19438
19460
|
}
|
|
19439
19461
|
return mode === "observation" ? "OBSERVATION" : "TARGETING";
|
|
@@ -22933,49 +22955,9 @@ Subcommands:
|
|
|
22933
22955
|
|
|
22934
22956
|
// src/commands/ads/linkedin/creatives.ts
|
|
22935
22957
|
import { defineCommand as defineCommand44 } from "citty";
|
|
22936
|
-
|
|
22937
|
-
// src/commands/ads/list-rows.ts
|
|
22938
22958
|
function asRecord(value) {
|
|
22939
22959
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
22940
22960
|
}
|
|
22941
|
-
function readPath2(row, path48) {
|
|
22942
|
-
let current = row;
|
|
22943
|
-
for (const segment of path48.split(".")) {
|
|
22944
|
-
const record = asRecord(current);
|
|
22945
|
-
if (!record) return void 0;
|
|
22946
|
-
current = record[segment];
|
|
22947
|
-
}
|
|
22948
|
-
return current;
|
|
22949
|
-
}
|
|
22950
|
-
function projectFields(rows, paths) {
|
|
22951
|
-
return rows.map((row) => {
|
|
22952
|
-
const projected = {};
|
|
22953
|
-
for (const path48 of paths) {
|
|
22954
|
-
const value = readPath2(row, path48);
|
|
22955
|
-
if (value !== void 0) {
|
|
22956
|
-
projected[path48] = value;
|
|
22957
|
-
}
|
|
22958
|
-
}
|
|
22959
|
-
return projected;
|
|
22960
|
-
});
|
|
22961
|
-
}
|
|
22962
|
-
function shapeListRows(rows, args5, compact3) {
|
|
22963
|
-
const raw = rows;
|
|
22964
|
-
const fields = typeof args5.fields === "string" ? args5.fields : void 0;
|
|
22965
|
-
if (fields) {
|
|
22966
|
-
const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
22967
|
-
if (paths.length > 0) {
|
|
22968
|
-
return { rows: projectFields(raw, paths), fields: paths };
|
|
22969
|
-
}
|
|
22970
|
-
}
|
|
22971
|
-
if (args5.full) return { rows: raw };
|
|
22972
|
-
return { rows: rows.map(compact3.row), fields: [...compact3.columns] };
|
|
22973
|
-
}
|
|
22974
|
-
|
|
22975
|
-
// src/commands/ads/linkedin/creatives.ts
|
|
22976
|
-
function asRecord2(value) {
|
|
22977
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
22978
|
-
}
|
|
22979
22961
|
function asString(value) {
|
|
22980
22962
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
22981
22963
|
}
|
|
@@ -22983,12 +22965,12 @@ function creativeDestination(content) {
|
|
|
22983
22965
|
if (!content) return { format: "unknown" };
|
|
22984
22966
|
const reference = asString(content.reference);
|
|
22985
22967
|
if (reference) return { format: "post", postUrn: reference };
|
|
22986
|
-
const textAd =
|
|
22968
|
+
const textAd = asRecord(content.textAd);
|
|
22987
22969
|
if (textAd) return { format: "text", landingUrl: asString(textAd.landingPage) };
|
|
22988
|
-
const spotlight =
|
|
22970
|
+
const spotlight = asRecord(content.spotlight);
|
|
22989
22971
|
if (spotlight) return { format: "spotlight", landingUrl: asString(spotlight.landingPage) };
|
|
22990
|
-
if (
|
|
22991
|
-
if (
|
|
22972
|
+
if (asRecord(content.follower)) return { format: "follower" };
|
|
22973
|
+
if (asRecord(content.jobs)) return { format: "jobs" };
|
|
22992
22974
|
return { format: "unknown" };
|
|
22993
22975
|
}
|
|
22994
22976
|
var COMPACT_COLUMNS = [
|
|
@@ -23016,6 +22998,27 @@ function compactRow(row) {
|
|
|
23016
22998
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
23017
22999
|
};
|
|
23018
23000
|
}
|
|
23001
|
+
function readPath2(row, path48) {
|
|
23002
|
+
let current = row;
|
|
23003
|
+
for (const segment of path48.split(".")) {
|
|
23004
|
+
const record = asRecord(current);
|
|
23005
|
+
if (!record) return void 0;
|
|
23006
|
+
current = record[segment];
|
|
23007
|
+
}
|
|
23008
|
+
return current;
|
|
23009
|
+
}
|
|
23010
|
+
function projectFields(rows, paths) {
|
|
23011
|
+
return rows.map((row) => {
|
|
23012
|
+
const projected = {};
|
|
23013
|
+
for (const path48 of paths) {
|
|
23014
|
+
const value = readPath2(row, path48);
|
|
23015
|
+
if (value !== void 0) {
|
|
23016
|
+
projected[path48] = value;
|
|
23017
|
+
}
|
|
23018
|
+
}
|
|
23019
|
+
return projected;
|
|
23020
|
+
});
|
|
23021
|
+
}
|
|
23019
23022
|
function unmappedShapeWarnings(rows, rawContentReturned) {
|
|
23020
23023
|
const unmapped = rows.filter((row) => row.content && creativeDestination(row.content).format === "unknown");
|
|
23021
23024
|
if (unmapped.length === 0) return [];
|
|
@@ -23027,6 +23030,18 @@ function unmappedShapeWarnings(rows, rawContentReturned) {
|
|
|
23027
23030
|
}
|
|
23028
23031
|
];
|
|
23029
23032
|
}
|
|
23033
|
+
function shapeRows(rows, args5) {
|
|
23034
|
+
const raw = rows;
|
|
23035
|
+
const fields = typeof args5.fields === "string" ? args5.fields : void 0;
|
|
23036
|
+
if (fields) {
|
|
23037
|
+
const paths = fields.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
23038
|
+
if (paths.length > 0) {
|
|
23039
|
+
return { rows: projectFields(raw, paths), fields: paths };
|
|
23040
|
+
}
|
|
23041
|
+
}
|
|
23042
|
+
if (args5.full) return { rows: raw };
|
|
23043
|
+
return { rows: rows.map(compactRow), fields: [...COMPACT_COLUMNS] };
|
|
23044
|
+
}
|
|
23030
23045
|
var listArgs3 = {
|
|
23031
23046
|
"account-id": { type: "string", description: "Numeric account ID or urn:li:sponsoredAccount:N" },
|
|
23032
23047
|
"account-urn": { type: "string", description: "Alias for --account-id" },
|
|
@@ -23058,10 +23073,7 @@ var creativesListCommand = defineCommand44({
|
|
|
23058
23073
|
if (args5.limit) params.limit = String(args5.limit);
|
|
23059
23074
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
23060
23075
|
const data = await apiGet("/api/ads/linkedin/creatives", params);
|
|
23061
|
-
const shaped =
|
|
23062
|
-
row: compactRow,
|
|
23063
|
-
columns: COMPACT_COLUMNS
|
|
23064
|
-
});
|
|
23076
|
+
const shaped = shapeRows(data, args5);
|
|
23065
23077
|
const fmt = csvOrJson2(args5);
|
|
23066
23078
|
if (fmt !== "json") {
|
|
23067
23079
|
writeAdsOutput(shaped.rows, fmt, shaped.fields);
|
|
@@ -23937,7 +23949,7 @@ Performance \u2014 the workhorse (3 axes):
|
|
|
23937
23949
|
baker ads linkedin analytics --list-intents
|
|
23938
23950
|
baker ads linkedin analytics --list-pivots
|
|
23939
23951
|
|
|
23940
|
-
Staged writes (
|
|
23952
|
+
Staged writes (never hit LinkedIn directly \u2014 ops stage on this chat's draft,
|
|
23941
23953
|
show in the dashboard as pending LinkedIn changes, and apply when the chat is
|
|
23942
23954
|
published, at which point they reach the real ad account):
|
|
23943
23955
|
baker ads linkedin account url-params \u2014 UTMs for every ad in the account
|
|
@@ -24079,178 +24091,22 @@ Examples:
|
|
|
24079
24091
|
|
|
24080
24092
|
// src/commands/ads/meta/activities.ts
|
|
24081
24093
|
import { defineCommand as defineCommand56 } from "citty";
|
|
24082
|
-
|
|
24083
|
-
// src/commands/ads/meta/list-rows.ts
|
|
24084
|
-
function pick(row, keys) {
|
|
24085
|
-
const picked = {};
|
|
24086
|
-
for (const key of keys) {
|
|
24087
|
-
if (row[key] !== void 0) picked[key] = row[key];
|
|
24088
|
-
}
|
|
24089
|
-
return picked;
|
|
24090
|
-
}
|
|
24091
|
-
function asRecord3(value) {
|
|
24092
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
24093
|
-
}
|
|
24094
|
-
var CAMPAIGN_COLUMNS = [
|
|
24095
|
-
"id",
|
|
24096
|
-
"name",
|
|
24097
|
-
"effective_status",
|
|
24098
|
-
"objective",
|
|
24099
|
-
"daily_budget",
|
|
24100
|
-
"lifetime_budget",
|
|
24101
|
-
"bid_strategy",
|
|
24102
|
-
"special_ad_categories",
|
|
24103
|
-
"stop_time",
|
|
24104
|
-
"created_time"
|
|
24105
|
-
];
|
|
24106
|
-
var ADSET_KEYS = [
|
|
24107
|
-
"id",
|
|
24108
|
-
"name",
|
|
24109
|
-
"campaign_id",
|
|
24110
|
-
"effective_status",
|
|
24111
|
-
"optimization_goal",
|
|
24112
|
-
"billing_event",
|
|
24113
|
-
"bid_strategy",
|
|
24114
|
-
"daily_budget",
|
|
24115
|
-
"lifetime_budget",
|
|
24116
|
-
"destination_type"
|
|
24117
|
-
];
|
|
24118
|
-
var ADSET_COLUMNS = [...ADSET_KEYS, "learning_stage", "end_time", "created_time"];
|
|
24119
|
-
function compactAdSet(row) {
|
|
24120
|
-
const learning = asRecord3(row.learning_stage_info)?.status;
|
|
24121
|
-
return {
|
|
24122
|
-
...pick(row, ADSET_KEYS),
|
|
24123
|
-
...typeof learning === "string" ? { learning_stage: learning } : {},
|
|
24124
|
-
...pick(row, ["end_time", "created_time"])
|
|
24125
|
-
};
|
|
24126
|
-
}
|
|
24127
|
-
var AD_COLUMNS = [
|
|
24128
|
-
"id",
|
|
24129
|
-
"name",
|
|
24130
|
-
"adset_id",
|
|
24131
|
-
"campaign_id",
|
|
24132
|
-
"effective_status",
|
|
24133
|
-
"creative_id",
|
|
24134
|
-
"issues",
|
|
24135
|
-
"created_time"
|
|
24136
|
-
];
|
|
24137
|
-
function adIssues(value) {
|
|
24138
|
-
if (!Array.isArray(value)) return [];
|
|
24139
|
-
return value.flatMap((entry) => {
|
|
24140
|
-
const issue = asRecord3(entry);
|
|
24141
|
-
const text2 = issue?.error_summary ?? issue?.error_message;
|
|
24142
|
-
return typeof text2 === "string" && text2 ? [text2] : [];
|
|
24143
|
-
});
|
|
24144
|
-
}
|
|
24145
|
-
function compactAd(row) {
|
|
24146
|
-
const creativeId = asRecord3(row.creative)?.id;
|
|
24147
|
-
const issues = adIssues(row.issues_info);
|
|
24148
|
-
return {
|
|
24149
|
-
...pick(row, ["id", "name", "adset_id", "campaign_id", "effective_status"]),
|
|
24150
|
-
...creativeId !== void 0 ? { creative_id: creativeId } : {},
|
|
24151
|
-
...issues.length > 0 ? { issues } : {},
|
|
24152
|
-
...pick(row, ["created_time"])
|
|
24153
|
-
};
|
|
24154
|
-
}
|
|
24155
|
-
var ACTIVITY_COLUMNS = [
|
|
24156
|
-
"event_time",
|
|
24157
|
-
"event_type",
|
|
24158
|
-
"actor_name",
|
|
24159
|
-
"object_type",
|
|
24160
|
-
"object_name",
|
|
24161
|
-
"object_id",
|
|
24162
|
-
"change"
|
|
24163
|
-
];
|
|
24164
|
-
function isScalar(value) {
|
|
24165
|
-
return value === null || typeof value === "string" || typeof value === "number";
|
|
24166
|
-
}
|
|
24167
|
-
function activityChange(extraData) {
|
|
24168
|
-
if (typeof extraData !== "string") return void 0;
|
|
24169
|
-
let parsed;
|
|
24170
|
-
try {
|
|
24171
|
-
parsed = JSON.parse(extraData);
|
|
24172
|
-
} catch {
|
|
24173
|
-
return void 0;
|
|
24174
|
-
}
|
|
24175
|
-
const data = asRecord3(parsed);
|
|
24176
|
-
if (!data || !("new_value" in data) || !isScalar(data.new_value) || !isScalar(data.old_value ?? null)) {
|
|
24177
|
-
return void 0;
|
|
24178
|
-
}
|
|
24179
|
-
const show = (value) => value === null || value === void 0 ? "(none)" : String(value);
|
|
24180
|
-
return `${show(data.old_value)} \u2192 ${show(data.new_value)}`;
|
|
24181
|
-
}
|
|
24182
|
-
function compactActivity(row) {
|
|
24183
|
-
const change = activityChange(row.extra_data);
|
|
24184
|
-
return {
|
|
24185
|
-
...pick(row, ["event_time", "event_type", "actor_name", "object_type", "object_name", "object_id"]),
|
|
24186
|
-
...change !== void 0 ? { change } : {}
|
|
24187
|
-
};
|
|
24188
|
-
}
|
|
24189
|
-
var PROJECTIONS = {
|
|
24190
|
-
campaigns: { row: (row) => pick(row, CAMPAIGN_COLUMNS), columns: CAMPAIGN_COLUMNS },
|
|
24191
|
-
adsets: { row: compactAdSet, columns: ADSET_COLUMNS },
|
|
24192
|
-
ads: { row: compactAd, columns: AD_COLUMNS },
|
|
24193
|
-
activities: { row: compactActivity, columns: ACTIVITY_COLUMNS }
|
|
24194
|
-
};
|
|
24195
|
-
function shapeMetaListRows(kind, rows, args5) {
|
|
24196
|
-
return shapeListRows(rows, args5, PROJECTIONS[kind]);
|
|
24197
|
-
}
|
|
24198
|
-
var META_LIST_SHAPE_ARGS = {
|
|
24199
|
-
fields: {
|
|
24200
|
-
type: "string",
|
|
24201
|
-
description: "CSV of dotted paths to return instead of the compact row, e.g. id,name,targeting.geo_locations"
|
|
24202
|
-
},
|
|
24203
|
-
full: { type: "boolean", description: "Return every field Meta sent (targeting, tracking specs, raw extra_data)" },
|
|
24204
|
-
output: { type: "string", description: "json|csv|jsonl|md \u2014 md prints a table of the compact row", default: "json" }
|
|
24205
|
-
};
|
|
24206
|
-
function registerMetaListSchema(kind, description, args5) {
|
|
24207
|
-
registerSchema({
|
|
24208
|
-
command: `ads.meta.${kind}`,
|
|
24209
|
-
description,
|
|
24210
|
-
args: Object.fromEntries(
|
|
24211
|
-
Object.entries(args5).map(([name, def]) => [
|
|
24212
|
-
name,
|
|
24213
|
-
{
|
|
24214
|
-
type: def.type,
|
|
24215
|
-
description: def.description ?? "",
|
|
24216
|
-
required: false,
|
|
24217
|
-
...def.default !== void 0 ? { default: def.default } : {}
|
|
24218
|
-
}
|
|
24219
|
-
])
|
|
24220
|
-
)
|
|
24221
|
-
});
|
|
24222
|
-
}
|
|
24223
|
-
|
|
24224
|
-
// src/commands/ads/meta/activities.ts
|
|
24225
|
-
var listArgs4 = {
|
|
24226
|
-
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
24227
|
-
days: { type: "string", description: "Lookback days (default 7)" },
|
|
24228
|
-
limit: { type: "string", description: "Max rows" },
|
|
24229
|
-
"no-cache": NO_CACHE_ARG,
|
|
24230
|
-
...META_LIST_SHAPE_ARGS
|
|
24231
|
-
};
|
|
24232
|
-
registerMetaListSchema(
|
|
24233
|
-
"activities",
|
|
24234
|
-
"Account change log. Compact by default, one row per event: event_time, event_type, actor_name, object_type, object_name, object_id, and change ('old \u2192 new' when the change is a single value). Start here: baker ads meta activities --account-id act_123 --days 2 --output md. --fields event_time,object_name,extra_data or --full for the raw change payload.",
|
|
24235
|
-
listArgs4
|
|
24236
|
-
);
|
|
24237
24094
|
var activitiesCommand = defineCommand56({
|
|
24238
24095
|
meta: {
|
|
24239
24096
|
name: "activities",
|
|
24240
24097
|
description: `Audit log of recent ad-account changes (created, paused, edited). Default lookback 7 days,
|
|
24241
24098
|
~90 day retention server-side.
|
|
24242
24099
|
|
|
24243
|
-
Compact by default, one row per event: event_time, event_type, actor_name, object_type,
|
|
24244
|
-
object_name, object_id, and change ("old \u2192 new" when the change is a single value: status,
|
|
24245
|
-
name, budget, goal). --fields takes dotted paths (extra_data holds the raw change); --full returns
|
|
24246
|
-
every field Meta sent.
|
|
24247
|
-
|
|
24248
24100
|
Examples:
|
|
24249
|
-
baker ads meta activities --account-id act_123 --days 14
|
|
24250
|
-
|
|
24251
|
-
|
|
24101
|
+
baker ads meta activities --account-id act_123 --days 14`
|
|
24102
|
+
},
|
|
24103
|
+
args: {
|
|
24104
|
+
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
24105
|
+
days: { type: "string", description: "Lookback days (default 7)" },
|
|
24106
|
+
limit: { type: "string", description: "Max rows" },
|
|
24107
|
+
"no-cache": NO_CACHE_ARG,
|
|
24108
|
+
output: { type: "string", description: "Output format", default: "json" }
|
|
24252
24109
|
},
|
|
24253
|
-
args: listArgs4,
|
|
24254
24110
|
run: async ({ args: args5 }) => {
|
|
24255
24111
|
const accountId = resolveAccountIdArg(args5);
|
|
24256
24112
|
try {
|
|
@@ -24259,13 +24115,12 @@ Examples:
|
|
|
24259
24115
|
if (args5.limit) params.limit = args5.limit;
|
|
24260
24116
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
24261
24117
|
const data = await apiGet("/api/ads/meta/activities", params);
|
|
24262
|
-
const shaped = shapeMetaListRows("activities", data, args5);
|
|
24263
24118
|
const fmt = csvOrJson(args5);
|
|
24264
24119
|
if (fmt !== "json") {
|
|
24265
|
-
writeAdsOutput(
|
|
24120
|
+
writeAdsOutput(data, fmt);
|
|
24266
24121
|
return;
|
|
24267
24122
|
}
|
|
24268
|
-
writeAdsJson({ ok: true, data
|
|
24123
|
+
writeAdsJson({ ok: true, data });
|
|
24269
24124
|
} catch (err) {
|
|
24270
24125
|
handleMetaError(err);
|
|
24271
24126
|
}
|
|
@@ -26526,8 +26381,8 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
26526
26381
|
run: async ({ args: args5 }) => {
|
|
26527
26382
|
const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
|
|
26528
26383
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
26529
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
26530
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26384
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-M2DBCZFG.js");
|
|
26385
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-BROA3UXS.js");
|
|
26531
26386
|
try {
|
|
26532
26387
|
const accountId = bareAccountId2(args5);
|
|
26533
26388
|
const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
|
|
@@ -26674,8 +26529,8 @@ function duplicateCommand2(entity, label) {
|
|
|
26674
26529
|
run: async ({ args: args5 }) => {
|
|
26675
26530
|
const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
|
|
26676
26531
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
26677
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
26678
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26532
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-M2DBCZFG.js");
|
|
26533
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-BROA3UXS.js");
|
|
26679
26534
|
try {
|
|
26680
26535
|
const accountId = bareAccountId2(args5);
|
|
26681
26536
|
const chatId = requireChatId2();
|
|
@@ -26708,7 +26563,7 @@ var adsArchiveCommand = statusCommand3("archive", "ad.update", "ad");
|
|
|
26708
26563
|
var adsDuplicateCommand = duplicateCommand2("ad", "ad");
|
|
26709
26564
|
|
|
26710
26565
|
// src/commands/ads/meta/ads.ts
|
|
26711
|
-
var
|
|
26566
|
+
var listArgs4 = {
|
|
26712
26567
|
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
26713
26568
|
"adset-id": { type: "string", description: "Filter to one adset" },
|
|
26714
26569
|
"campaign-id": { type: "string", description: "Filter to one campaign" },
|
|
@@ -26716,19 +26571,14 @@ var listArgs5 = {
|
|
|
26716
26571
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
26717
26572
|
limit: { type: "string", description: "Max rows (default 1000)" },
|
|
26718
26573
|
"no-cache": NO_CACHE_ARG,
|
|
26719
|
-
|
|
26574
|
+
output: { type: "string", description: "Output format", default: "json" }
|
|
26720
26575
|
};
|
|
26721
|
-
registerMetaListSchema(
|
|
26722
|
-
"ads",
|
|
26723
|
-
"List ads in a Meta ad account. Compact by default: id, name, adset_id, campaign_id, effective_status, creative_id, issues (why an ad is WITH_ISSUES), created_time. Start here: baker ads meta ads --adset-id 6123 --output md. --fields takes dotted paths (e.g. id,tracking_specs); --full returns every field Meta sent.",
|
|
26724
|
-
listArgs5
|
|
26725
|
-
);
|
|
26726
26576
|
var listCommand4 = defineCommand58({
|
|
26727
26577
|
meta: {
|
|
26728
26578
|
name: "list",
|
|
26729
26579
|
description: "List ads in a Meta ad account. Runs by default when no subcommand is given. Example: baker ads meta ads --account-id act_123"
|
|
26730
26580
|
},
|
|
26731
|
-
args:
|
|
26581
|
+
args: listArgs4,
|
|
26732
26582
|
run: async ({ args: args5 }) => {
|
|
26733
26583
|
const accountId = resolveAccountIdArg(args5);
|
|
26734
26584
|
const effectiveStatus = resolveEffectiveStatus(args5);
|
|
@@ -26740,13 +26590,12 @@ var listCommand4 = defineCommand58({
|
|
|
26740
26590
|
if (args5.limit) params.limit = args5.limit;
|
|
26741
26591
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
26742
26592
|
const data = await apiGet("/api/ads/meta/ads", params);
|
|
26743
|
-
const shaped = shapeMetaListRows("ads", data, args5);
|
|
26744
26593
|
const fmt = csvOrJson(args5);
|
|
26745
26594
|
if (fmt !== "json") {
|
|
26746
|
-
writeAdsOutput(
|
|
26595
|
+
writeAdsOutput(data, fmt);
|
|
26747
26596
|
return;
|
|
26748
26597
|
}
|
|
26749
|
-
writeAdsJson({ ok: true, data
|
|
26598
|
+
writeAdsJson({ ok: true, data });
|
|
26750
26599
|
} catch (err) {
|
|
26751
26600
|
handleMetaError(err);
|
|
26752
26601
|
}
|
|
@@ -26760,14 +26609,9 @@ Defaults to ACTIVE only \u2014 pass --all-statuses to widen. Write subcommands s
|
|
|
26760
26609
|
|
|
26761
26610
|
The dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPROVED, ADSET_PAUSED), not status.
|
|
26762
26611
|
|
|
26763
|
-
Listing rows are compact: id, name, adset_id, campaign_id, effective_status, creative_id, issues
|
|
26764
|
-
(why an ad is WITH_ISSUES), created_time. --fields takes dotted paths (e.g. tracking_specs,
|
|
26765
|
-
preview_shareable_link); --full returns every field.
|
|
26766
|
-
|
|
26767
26612
|
Examples:
|
|
26768
26613
|
baker ads meta ads --account-id act_123
|
|
26769
26614
|
baker ads meta ads --adset-id 6123
|
|
26770
|
-
baker ads meta ads --adset-id 6123 --fields id,name,preview_shareable_link
|
|
26771
26615
|
baker ads meta ads create --name "Ad 1" --adset meta_temp_as01 --creative meta_temp_cr01
|
|
26772
26616
|
baker ads meta ads pause 6123 --account-id act_123
|
|
26773
26617
|
baker ads meta ads retag 6123 --set "utm_medium=paid-social" \u2014 fix tracking on a LIVE ad, keeping everything else`
|
|
@@ -26786,32 +26630,27 @@ Examples:
|
|
|
26786
26630
|
// subcommand name using THIS command's arg defs, so without them `--account-id act_1`
|
|
26787
26631
|
// would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare
|
|
26788
26632
|
// invocation — citty falls through to `run` after a subcommand, double-executing it.
|
|
26789
|
-
args:
|
|
26633
|
+
args: listArgs4,
|
|
26790
26634
|
default: "list"
|
|
26791
26635
|
});
|
|
26792
26636
|
|
|
26793
26637
|
// src/commands/ads/meta/adsets.ts
|
|
26794
26638
|
import { defineCommand as defineCommand59 } from "citty";
|
|
26795
|
-
var
|
|
26639
|
+
var listArgs5 = {
|
|
26796
26640
|
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
26797
26641
|
"campaign-id": { type: "string", description: "Filter to one campaign" },
|
|
26798
26642
|
"effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
|
|
26799
26643
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
26800
26644
|
limit: { type: "string", description: "Max rows (default 1000)" },
|
|
26801
26645
|
"no-cache": NO_CACHE_ARG,
|
|
26802
|
-
|
|
26646
|
+
output: { type: "string", description: "Output format", default: "json" }
|
|
26803
26647
|
};
|
|
26804
|
-
registerMetaListSchema(
|
|
26805
|
-
"adsets",
|
|
26806
|
-
"List ad sets in a Meta ad account. Compact by default: id, name, campaign_id, effective_status, optimization_goal, billing_event, bid_strategy, budgets, destination_type, learning_stage, end_time, created_time. Targeting is not in the compact row \u2014 ask for it with --fields id,name,targeting (or --full). Start here: baker ads meta adsets --campaign-id 6123 --all-statuses.",
|
|
26807
|
-
listArgs6
|
|
26808
|
-
);
|
|
26809
26648
|
var listCommand5 = defineCommand59({
|
|
26810
26649
|
meta: {
|
|
26811
26650
|
name: "list",
|
|
26812
26651
|
description: "List ad sets in a Meta ad account. Runs by default when no subcommand is given. Example: baker ads meta adsets --account-id act_123"
|
|
26813
26652
|
},
|
|
26814
|
-
args:
|
|
26653
|
+
args: listArgs5,
|
|
26815
26654
|
run: async ({ args: args5 }) => {
|
|
26816
26655
|
const accountId = resolveAccountIdArg(args5);
|
|
26817
26656
|
const effectiveStatus = resolveEffectiveStatus(args5);
|
|
@@ -26822,13 +26661,12 @@ var listCommand5 = defineCommand59({
|
|
|
26822
26661
|
if (args5.limit) params.limit = args5.limit;
|
|
26823
26662
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
26824
26663
|
const data = await apiGet("/api/ads/meta/adsets", params);
|
|
26825
|
-
const shaped = shapeMetaListRows("adsets", data, args5);
|
|
26826
26664
|
const fmt = csvOrJson(args5);
|
|
26827
26665
|
if (fmt !== "json") {
|
|
26828
|
-
writeAdsOutput(
|
|
26666
|
+
writeAdsOutput(data, fmt);
|
|
26829
26667
|
return;
|
|
26830
26668
|
}
|
|
26831
|
-
writeAdsJson({ ok: true, data
|
|
26669
|
+
writeAdsJson({ ok: true, data });
|
|
26832
26670
|
} catch (err) {
|
|
26833
26671
|
handleMetaError(err);
|
|
26834
26672
|
}
|
|
@@ -26840,14 +26678,9 @@ var adsetsCommand = defineCommand59({
|
|
|
26840
26678
|
description: `List ad sets in a Meta ad account, or stage writes (create/update/pause/resume/archive/duplicate).
|
|
26841
26679
|
Defaults to ACTIVE only. Write subcommands stage ops on this chat's draft.
|
|
26842
26680
|
|
|
26843
|
-
Listing rows are compact: id, name, campaign_id, effective_status, optimization_goal, billing_event,
|
|
26844
|
-
bid_strategy, budgets, destination_type, learning_stage, end_time, created_time. Targeting is not in
|
|
26845
|
-
the compact row \u2014 ask for it with --fields (dotted paths) or --full.
|
|
26846
|
-
|
|
26847
26681
|
Examples:
|
|
26848
26682
|
baker ads meta adsets --account-id act_123
|
|
26849
26683
|
baker ads meta adsets --campaign-id 6123456789
|
|
26850
|
-
baker ads meta adsets --campaign-id 6123456789 --fields id,name,targeting.geo_locations
|
|
26851
26684
|
baker ads meta adsets create --campaign meta_temp_ab12 --name "US 25-54" --optimization-goal LINK_CLICKS --billing-event IMPRESSIONS --daily-budget 50 --targeting-file t.json`
|
|
26852
26685
|
},
|
|
26853
26686
|
subCommands: {
|
|
@@ -26863,13 +26696,13 @@ Examples:
|
|
|
26863
26696
|
// subcommand name using THIS command's arg defs, so without them `--account-id act_1`
|
|
26864
26697
|
// would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare
|
|
26865
26698
|
// invocation — citty falls through to `run` after a subcommand, double-executing it.
|
|
26866
|
-
args:
|
|
26699
|
+
args: listArgs5,
|
|
26867
26700
|
default: "list"
|
|
26868
26701
|
});
|
|
26869
26702
|
|
|
26870
26703
|
// src/commands/ads/meta/audiences.ts
|
|
26871
26704
|
import { defineCommand as defineCommand60 } from "citty";
|
|
26872
|
-
var
|
|
26705
|
+
var listArgs6 = {
|
|
26873
26706
|
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
26874
26707
|
limit: { type: "string", description: "Max rows" },
|
|
26875
26708
|
"no-cache": NO_CACHE_ARG,
|
|
@@ -26880,7 +26713,7 @@ var listCommand6 = defineCommand60({
|
|
|
26880
26713
|
name: "list",
|
|
26881
26714
|
description: "List custom audiences. Runs by default when no subcommand is given. Example: baker ads meta audiences --account-id act_123"
|
|
26882
26715
|
},
|
|
26883
|
-
args:
|
|
26716
|
+
args: listArgs6,
|
|
26884
26717
|
run: async ({ args: args5 }) => {
|
|
26885
26718
|
const accountId = resolveAccountIdArg(args5);
|
|
26886
26719
|
try {
|
|
@@ -26918,7 +26751,7 @@ Examples:
|
|
|
26918
26751
|
// subcommand name using THIS command's arg defs, so without them `--account-id act_1`
|
|
26919
26752
|
// would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare
|
|
26920
26753
|
// invocation — citty falls through to `run` after a subcommand, double-executing it.
|
|
26921
|
-
args:
|
|
26754
|
+
args: listArgs6,
|
|
26922
26755
|
default: "list"
|
|
26923
26756
|
});
|
|
26924
26757
|
|
|
@@ -26955,25 +26788,20 @@ Examples:
|
|
|
26955
26788
|
|
|
26956
26789
|
// src/commands/ads/meta/campaigns.ts
|
|
26957
26790
|
import { defineCommand as defineCommand62 } from "citty";
|
|
26958
|
-
var
|
|
26791
|
+
var listArgs7 = {
|
|
26959
26792
|
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
26960
26793
|
"effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
|
|
26961
26794
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter and return everything" },
|
|
26962
26795
|
limit: { type: "string", description: "Max rows (default 1000)" },
|
|
26963
26796
|
"no-cache": NO_CACHE_ARG,
|
|
26964
|
-
|
|
26797
|
+
output: { type: "string", description: "Output format", default: "json" }
|
|
26965
26798
|
};
|
|
26966
|
-
registerMetaListSchema(
|
|
26967
|
-
"campaigns",
|
|
26968
|
-
"List campaigns in a Meta ad account. Compact by default: id, name, effective_status, objective, budgets, bid_strategy, special_ad_categories, stop_time, created_time. ACTIVE only unless --all-statuses. Start here: baker ads meta campaigns --account-id act_123 --all-statuses --output md. --fields takes dotted paths for anything else; --full returns every field Meta sent.",
|
|
26969
|
-
listArgs8
|
|
26970
|
-
);
|
|
26971
26799
|
var listCommand7 = defineCommand62({
|
|
26972
26800
|
meta: {
|
|
26973
26801
|
name: "list",
|
|
26974
26802
|
description: "List campaigns for a Meta ad account. Runs by default when no subcommand is given. Example: baker ads meta campaigns --account-id act_123"
|
|
26975
26803
|
},
|
|
26976
|
-
args:
|
|
26804
|
+
args: listArgs7,
|
|
26977
26805
|
run: async ({ args: args5 }) => {
|
|
26978
26806
|
const accountId = resolveAccountIdArg(args5);
|
|
26979
26807
|
const effectiveStatus = resolveEffectiveStatus(args5);
|
|
@@ -26983,13 +26811,12 @@ var listCommand7 = defineCommand62({
|
|
|
26983
26811
|
if (args5.limit) params.limit = args5.limit;
|
|
26984
26812
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
26985
26813
|
const data = await apiGet("/api/ads/meta/campaigns", params);
|
|
26986
|
-
const shaped = shapeMetaListRows("campaigns", data, args5);
|
|
26987
26814
|
const fmt = csvOrJson(args5);
|
|
26988
26815
|
if (fmt !== "json") {
|
|
26989
|
-
writeAdsOutput(
|
|
26816
|
+
writeAdsOutput(data, fmt);
|
|
26990
26817
|
return;
|
|
26991
26818
|
}
|
|
26992
|
-
writeAdsJson({ ok: true, data
|
|
26819
|
+
writeAdsJson({ ok: true, data });
|
|
26993
26820
|
} catch (err) {
|
|
26994
26821
|
handleMetaError(err);
|
|
26995
26822
|
}
|
|
@@ -27005,14 +26832,9 @@ apply only when the chat is published.
|
|
|
27005
26832
|
In Meta's API "campaign" is the top-of-tree object (what marketers usually call a campaign group).
|
|
27006
26833
|
The dashboard shows effective_status: ACTIVE, PAUSED, DELETED, ARCHIVED, IN_PROCESS, WITH_ISSUES, etc.
|
|
27007
26834
|
|
|
27008
|
-
Listing rows are compact: id, name, effective_status, objective, daily/lifetime budget, bid_strategy,
|
|
27009
|
-
special_ad_categories, stop_time, created_time. --fields takes dotted paths for anything else; --full returns every field.
|
|
27010
|
-
|
|
27011
26835
|
Examples:
|
|
27012
26836
|
baker ads meta campaigns --account-id act_123 # ACTIVE only
|
|
27013
26837
|
baker ads meta campaigns --account-id act_123 --all-statuses # everything
|
|
27014
|
-
baker ads meta campaigns --account-id act_123 --all-statuses --output md # as a table
|
|
27015
|
-
baker ads meta campaigns --account-id act_123 --fields id,name,budget_remaining,start_time
|
|
27016
26838
|
baker ads meta campaigns create --account-id act_123 --name "Q3" --objective OUTCOME_LEADS --daily-budget 50
|
|
27017
26839
|
baker ads meta campaigns pause 6123 --account-id act_123`
|
|
27018
26840
|
},
|
|
@@ -27029,13 +26851,13 @@ Examples:
|
|
|
27029
26851
|
// subcommand name using THIS command's arg defs, so without them `--account-id act_1`
|
|
27030
26852
|
// would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare
|
|
27031
26853
|
// invocation — citty falls through to `run` after a subcommand, double-executing it.
|
|
27032
|
-
args:
|
|
26854
|
+
args: listArgs7,
|
|
27033
26855
|
default: "list"
|
|
27034
26856
|
});
|
|
27035
26857
|
|
|
27036
26858
|
// src/commands/ads/meta/creatives.ts
|
|
27037
26859
|
import { defineCommand as defineCommand63 } from "citty";
|
|
27038
|
-
var
|
|
26860
|
+
var listArgs8 = {
|
|
27039
26861
|
"account-id": { type: "string", description: "Meta ad account ID (required if no --creative-id)" },
|
|
27040
26862
|
"creative-id": { type: "string", description: "Single creative ID" },
|
|
27041
26863
|
limit: { type: "string", description: "Max rows (default 500)" },
|
|
@@ -27047,7 +26869,7 @@ var listCommand8 = defineCommand63({
|
|
|
27047
26869
|
name: "list",
|
|
27048
26870
|
description: "List ad creatives, or fetch one by ID. Runs by default when no subcommand is given. Example: baker ads meta creatives --account-id act_123"
|
|
27049
26871
|
},
|
|
27050
|
-
args:
|
|
26872
|
+
args: listArgs8,
|
|
27051
26873
|
run: async ({ args: args5 }) => {
|
|
27052
26874
|
try {
|
|
27053
26875
|
const params = {};
|
|
@@ -27093,7 +26915,7 @@ Examples:
|
|
|
27093
26915
|
// subcommand name using THIS command's arg defs, so without them `--account-id act_1`
|
|
27094
26916
|
// would read `act_1` as a subcommand. `default` (not `run`) dispatches the bare
|
|
27095
26917
|
// invocation — citty falls through to `run` after a subcommand, double-executing it.
|
|
27096
|
-
args:
|
|
26918
|
+
args: listArgs8,
|
|
27097
26919
|
default: "list"
|
|
27098
26920
|
});
|
|
27099
26921
|
|
|
@@ -27141,7 +26963,7 @@ registerSchema({
|
|
|
27141
26963
|
output: { type: "string", description: "json|csv", required: false, default: "json" }
|
|
27142
26964
|
}
|
|
27143
26965
|
});
|
|
27144
|
-
var
|
|
26966
|
+
var listArgs9 = {
|
|
27145
26967
|
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
27146
26968
|
full: { type: "boolean", description: "Include the raw rule JSON, retention and creation times" },
|
|
27147
26969
|
limit: { type: "string", description: "Max rows" },
|
|
@@ -27153,7 +26975,7 @@ var listCommand9 = defineCommand64({
|
|
|
27153
26975
|
name: "list",
|
|
27154
26976
|
description: "List custom conversions. Runs by default when no subcommand is given. Example: baker ads meta custom-conversions --account-id act_123"
|
|
27155
26977
|
},
|
|
27156
|
-
args:
|
|
26978
|
+
args: listArgs9,
|
|
27157
26979
|
run: async ({ args: args5 }) => {
|
|
27158
26980
|
const accountId = resolveAccountIdArg(args5);
|
|
27159
26981
|
try {
|
|
@@ -27191,7 +27013,7 @@ Examples:
|
|
|
27191
27013
|
// `args` stays even though the parent has no `run`: citty scans rawArgs for
|
|
27192
27014
|
// the subcommand name using THIS command's arg defs. `default` (not `run`)
|
|
27193
27015
|
// dispatches the bare invocation.
|
|
27194
|
-
args:
|
|
27016
|
+
args: listArgs9,
|
|
27195
27017
|
default: "list"
|
|
27196
27018
|
});
|
|
27197
27019
|
|
|
@@ -28903,7 +28725,7 @@ registerSchema({
|
|
|
28903
28725
|
output: { type: "string", description: "Format: json|csv|md", required: false, default: "json" }
|
|
28904
28726
|
}
|
|
28905
28727
|
});
|
|
28906
|
-
var
|
|
28728
|
+
var listArgs10 = {
|
|
28907
28729
|
"account-id": { type: "string", description: "X Ads account ID" },
|
|
28908
28730
|
"funding-instrument-ids": { type: "string", description: "CSV of funding instrument IDs" },
|
|
28909
28731
|
"campaign-ids": { type: "string", description: "CSV of campaign IDs" },
|
|
@@ -28973,7 +28795,7 @@ Examples:
|
|
|
28973
28795
|
},
|
|
28974
28796
|
// A parent must never declare `run`: citty falls through to it AFTER the
|
|
28975
28797
|
// matched subcommand, so every write would also trigger a full live list.
|
|
28976
|
-
args:
|
|
28798
|
+
args: listArgs10,
|
|
28977
28799
|
default: "list"
|
|
28978
28800
|
});
|
|
28979
28801
|
|
|
@@ -33225,7 +33047,7 @@ var sourcesResponseSchema = z40.strictObject({
|
|
|
33225
33047
|
import { defineCommand as defineCommand98 } from "citty";
|
|
33226
33048
|
|
|
33227
33049
|
// src/commands/hubspot/refusal.ts
|
|
33228
|
-
var CONTINUE = "
|
|
33050
|
+
var CONTINUE = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else. If the `request_connection` call fails, say so plainly and give the exact route: dashboard \u2192 Brain \u2192 Integrations \u2192 Tools \u2192 HubSpot.";
|
|
33229
33051
|
function hubspotRefusal(code, message) {
|
|
33230
33052
|
if (code === "NOT_FOUND" && message.includes(HUBSPOT_NOT_CONNECTED_MESSAGE)) {
|
|
33231
33053
|
return {
|
|
@@ -33241,7 +33063,7 @@ function hubspotRefusal(code, message) {
|
|
|
33241
33063
|
code: "HUBSPOT_RECONNECT_REQUIRED",
|
|
33242
33064
|
fix: {
|
|
33243
33065
|
action: "request_connection",
|
|
33244
|
-
explanation: 'AGENT INSTRUCTION: HubSpot
|
|
33066
|
+
explanation: 'AGENT INSTRUCTION: HubSpot is connected \u2014 do not tell the user it is missing, and do not retry. Its access does not cover this read (it was connected before Baker asked for it, or the access was withdrawn), and only the user can widen it. Call the `request_connection` tool with { platform: "hubspot", reason } naming what you need to read; the card offers them a Reconnect button. Run this command again once they have. ' + CONTINUE
|
|
33245
33067
|
}
|
|
33246
33068
|
};
|
|
33247
33069
|
}
|
|
@@ -34744,8 +34566,8 @@ import { defineCommand as defineCommand105 } from "citty";
|
|
|
34744
34566
|
import { defineCommand as defineCommand100 } from "citty";
|
|
34745
34567
|
|
|
34746
34568
|
// src/commands/avatars/casting.ts
|
|
34747
|
-
var CAST_FLAG_RULE = "Cast with `--avatar <handle>` on `baker studio generate`, `baker studio animate`, `baker canvas scaffold-ad`, `baker canvas scaffold-static-ad` and `baker canvas scaffold-video`.
|
|
34748
|
-
var VERBATIM_RULE = "When you do write the description yourself \u2014 a hand-built canvas node, a landing image, anywhere `--avatar` does not exist \u2014 copy `subjectDescription`
|
|
34569
|
+
var CAST_FLAG_RULE = "Cast with `--avatar <handle>` on `baker studio generate`, `baker studio animate`, `baker canvas scaffold-ad`, `baker canvas scaffold-static-ad` and `baker canvas scaffold-video`. Don't hand-roll it by pasting `subjectDescription` into the prompt or by passing the sheet through `--reference` \u2014 both render something that merely resembles them. `--avatar` is also the only thing that carries their accent and delivery into a clip. An avatar has no pinned voice by design (ADR 0005): the video model renders the voice, and the region on their profile is the only thing steering it \u2014 without the flag the clip is performed flat, in whatever accent the model picks on its own. `baker canvas scaffold-video` casts only their face: a reproduced video keeps the source ad's accent direction, so never tell the user it speaks in theirs.";
|
|
34570
|
+
var VERBATIM_RULE = "When you do write the description yourself \u2014 a hand-built canvas node, a landing image, anywhere `--avatar` does not exist \u2014 copy `subjectDescription` verbatim, word for word. Re-phrasing it per generation is the other reason a face drifts across a set.";
|
|
34749
34571
|
var VIDEO_ROUTING = "In video, a photoreal presenter renders on `google/veo-3.1` (or `google/veo-3.1-fast`), never `bytedance/seedance-2.0` \u2014 it refuses photoreal human faces, AI-generated ones included. Reproducing a video the user gave you: `baker canvas scaffold-video \u2026 --avatar <handle> --real-face`.";
|
|
34750
34572
|
function castingHints(avatar) {
|
|
34751
34573
|
if (avatar.status === "generating" && avatar.needsFace) {
|
|
@@ -34839,7 +34661,7 @@ function creationHints(created, profile) {
|
|
|
34839
34661
|
const casting = created.likeness === "synthetic" && created.faceChoice === "auto" ? [
|
|
34840
34662
|
`No one was asked about this face \u2014 \`--face auto\` cast it and it is kept. Do not tell the user they chose it, and do not offer them a pick you are not going to run. If this should have been theirs, say so and create it again with \`--face ask\`.`
|
|
34841
34663
|
] : created.likeness === "synthetic" ? [
|
|
34842
|
-
`The user is being shown real portraits of @${created.handle} right now, and the turn waits for them to pick \u2014 this happens on its own, triggered by the command you just ran.
|
|
34664
|
+
`The user is being shown real portraits of @${created.handle} right now, and the turn waits for them to pick \u2014 this happens on its own, triggered by the command you just ran. The picker is already showing, so don't call request_avatar_casting, don't ask about the face in a question of your own, and don't wait or poll: whatever you do next simply runs after they have chosen. Say what you created and get on with the work.`
|
|
34843
34665
|
] : [];
|
|
34844
34666
|
const hints2 = [
|
|
34845
34667
|
...casting,
|
|
@@ -34925,7 +34747,7 @@ function avatarFailureFix(err, handle, context = {}) {
|
|
|
34925
34747
|
if (err.code === "CONFLICT" && handle) {
|
|
34926
34748
|
return {
|
|
34927
34749
|
action: "use_the_existing_avatar",
|
|
34928
|
-
explanation: `@${handle} already exists in
|
|
34750
|
+
explanation: `@${handle} already exists in this company \u2014 avatars belong to the company, not to a chat, so one made in an earlier conversation is still here and still castable. If it is the person you want, use it as it is: \`--avatar ${handle}\`. Read it first with \`baker avatars get ${handle} --full\` and say who they already are. Do not create the same person under a second name: the user would be told about one avatar and handed another, and the company ends up with duplicates nobody chose a face for. If you genuinely need a different person, ask the user what to call them.`
|
|
34929
34751
|
};
|
|
34930
34752
|
}
|
|
34931
34753
|
return void 0;
|
|
@@ -35027,7 +34849,7 @@ registerSchema({
|
|
|
35027
34849
|
},
|
|
35028
34850
|
subject: {
|
|
35029
34851
|
type: "string",
|
|
35030
|
-
description: "The identity, reused
|
|
34852
|
+
description: "The identity, reused verbatim in every render: one person, plainly described (age, build, hair, skin, face). No scene, no lighting, no camera, no wardrobe \u2014 those belong in the render prompt or in --wardrobe/--setting.",
|
|
35031
34853
|
required: true
|
|
35032
34854
|
},
|
|
35033
34855
|
persona: { type: "string", description: "Who they are on camera \u2014 role, attitude, energy", required: false },
|
|
@@ -35255,7 +35077,7 @@ async function waitForSheet(first, read, sleep4 = (ms) => new Promise((resolve5)
|
|
|
35255
35077
|
// src/commands/avatars/get.ts
|
|
35256
35078
|
registerSchema({
|
|
35257
35079
|
command: "avatars.get",
|
|
35258
|
-
description: "Read one avatar by handle \u2014 the command you run before casting it. Returns its status (only `ready` can be cast), the identity sheet URL every render must be grounded on via --reference, and the subject description that goes into the prompt
|
|
35080
|
+
description: "Read one avatar by handle \u2014 the command you run before casting it. Returns its status (only `ready` can be cast), the identity sheet URL every render must be grounded on via --reference, and the subject description that goes into the prompt verbatim. Add --full for the whole written profile (persona, speech, motion, wardrobe, setting, guardrails, voice, source photos).",
|
|
35259
35081
|
args: {
|
|
35260
35082
|
handle: { type: "string", description: 'Avatar handle, e.g. "marta" (lowercase, dashes)', required: true },
|
|
35261
35083
|
full: {
|
|
@@ -35504,7 +35326,7 @@ How casting works:
|
|
|
35504
35326
|
2. baker avatars get <handle> Status, identity sheet URL, subject description
|
|
35505
35327
|
3. baker images generate "<scene>" --reference <sheetUrl>
|
|
35506
35328
|
Ground the render on the identity sheet, never on a source photo,
|
|
35507
|
-
and copy the subject description into the prompt
|
|
35329
|
+
and copy the subject description into the prompt verbatim
|
|
35508
35330
|
|
|
35509
35331
|
Examples:
|
|
35510
35332
|
baker avatars list --status ready --output md
|
|
@@ -36364,7 +36186,7 @@ async function unresolvedAction(css, unresolved) {
|
|
|
36364
36186
|
const { plans } = planFontAdoption(await astroSources(), unresolved);
|
|
36365
36187
|
if (plans.length > 0) {
|
|
36366
36188
|
const names = plans.map((p) => `"${p.family}"`).join(", ");
|
|
36367
|
-
return `Run \`baker brand fonts adopt\` \u2014 ${names} is already self-hosted by ${plans[0]?.files.join(", ")}, so it only needs moving into ${GLOBAL_CSS} to load on every page.
|
|
36189
|
+
return `Run \`baker brand fonts adopt\` \u2014 ${names} is already self-hosted by ${plans[0]?.files.join(", ")}, so it only needs moving into ${GLOBAL_CSS} to load on every page. Don't fetch it: that downloads a different build of the same face.`;
|
|
36368
36190
|
}
|
|
36369
36191
|
const viaFontsource = [...fontsourceFamilies(css)];
|
|
36370
36192
|
const stranded = unresolved.filter((family) => viaFontsource.includes(family.toLowerCase()));
|
|
@@ -38830,7 +38652,7 @@ function emitScreenScene(i, scene, lengths, out, surfaceIngests, nodes, clips) {
|
|
|
38830
38652
|
type: "ingest",
|
|
38831
38653
|
params: {
|
|
38832
38654
|
source: "path",
|
|
38833
|
-
path: `[TODO: supply the
|
|
38655
|
+
path: `[TODO: supply the real screen for "${label}" \u2014 never AI-generate a UI. Capture a clean, text-free screenshot with \`baker images screenshot https://<brand-domain>/<path>\` (image-library skill); spoken/overlay text rides the overlay layer, not the screenshot. Wire it in as a path relative to this canvas file, never an absolute path]`,
|
|
38834
38656
|
expect: "image"
|
|
38835
38657
|
}
|
|
38836
38658
|
});
|
|
@@ -38882,7 +38704,7 @@ function emitGraphicScene(i, scene, lengths, out, surfaceIngests, nodes, clips)
|
|
|
38882
38704
|
type: "ingest",
|
|
38883
38705
|
params: {
|
|
38884
38706
|
source: "path",
|
|
38885
|
-
path: `[TODO: supply the
|
|
38707
|
+
path: `[TODO: supply the real designed graphic for "${label}" \u2014 never AI-generate a designed panel (its typography/wordmarks garble). Rebuild it as brand HTML in video-overlay-composition (the scene's text/logos are already seeded there), export the design from the brand kit, or source stock art; text rides the overlay layer, not this plate. Wire it in as a path relative to this canvas file, never an absolute path]`,
|
|
38886
38708
|
expect: "image"
|
|
38887
38709
|
}
|
|
38888
38710
|
});
|
|
@@ -39965,13 +39787,13 @@ function uiSurfaceStub(blueprint, run, clock) {
|
|
|
39965
39787
|
}) : [];
|
|
39966
39788
|
const isGraphic = scenes.some((s) => (compositeRegionsOf(s) ?? []).some((r) => r.kind === "static_graphic"));
|
|
39967
39789
|
const sourcing = isGraphic ? [
|
|
39968
|
-
" Build it as a
|
|
39790
|
+
" Build it as a real designed panel; never AI-generate its text/typography:",
|
|
39969
39791
|
" hand-build a brand-accurate HTML block in this composition (restyle the seeded",
|
|
39970
39792
|
" overlay text, or `npx hyperframes add <block>` for a ready-made card),",
|
|
39971
39793
|
" \u2014 OR drop the design asset (export it from the brand kit) as panel.png here;",
|
|
39972
39794
|
" then nest it as a timed clip:"
|
|
39973
39795
|
] : [
|
|
39974
|
-
" Build it as a
|
|
39796
|
+
" Build it as a real surface, never AI: capture the live page \u2014",
|
|
39975
39797
|
" baker images screenshot https://<brand-domain>/<path> (image-library skill)",
|
|
39976
39798
|
" \u2014 OR hand-build a brand-accurate HTML screen; then frame it in a phone mockup:",
|
|
39977
39799
|
" npx hyperframes add phone-scroll (writes compositions/phone-scroll.html)",
|
|
@@ -40373,7 +40195,7 @@ function buildModelConstraints() {
|
|
|
40373
40195
|
};
|
|
40374
40196
|
}
|
|
40375
40197
|
return {
|
|
40376
|
-
note: "Switching a clip's video model has cross-node constraints.
|
|
40198
|
+
note: "Switching a clip's video model has cross-node constraints. All video_generate nodes in one canvas must share one aspect_ratio (the composite silently crops otherwise). Each model's `duration` is a hard enum and differs per model \u2014 a scene longer than the model's max must be split. `person_generation` differs (Veo requires \"allow_all\"). `baker canvas validate` gates duration, aspect agreement, per-model params, and a scene-span-vs-model-max advisory before any billed run \u2014 run it after every model edit.",
|
|
40377
40199
|
models
|
|
40378
40200
|
};
|
|
40379
40201
|
}
|
|
@@ -40448,7 +40270,7 @@ function buildMotionBoard(blueprint) {
|
|
|
40448
40270
|
});
|
|
40449
40271
|
}
|
|
40450
40272
|
var VIDEO_GUIDE = [
|
|
40451
|
-
"Scaffolded by `baker canvas scaffold-video` \u2014 a runnable reproduction of your reference video, built like an editing timeline. It is a sequence of clear SHOTS separated at COMPLETE BREAKS (hard cuts): two adjacent presenter shots at a cut are TWO clips, never glued into one take. What stays continuous is the VOICE \u2014 a voiceover narration is ONE read across the b-roll it plays over, and a b-roll CUTAWAY between two on-camera moments leaves the presenter shot continuous with the insert sliced in \u2014 and each person keeps ONE brand voice (all their clips' native audio re-voiced in a single per-speaker pass), so timbre holds across the cuts. A presenter shot is ONE Seedance clip (native lip-sync + audio); a pure-voiceover stretch is one ElevenLabs tts read; a sub-2s flash is a still hold. A single shot too long for one clip splits into takes that share a boundary frame \u2014 the spine drops the duplicated frame (`--seam-dedup head|tail|off`). Every clip gets a CLEAN-PLATE start AND end keyframe (no baked text), RECAST to your dropped reference assets \u2014 Seedance interpolates real in-shot motion between them. Each frame grounds
|
|
40273
|
+
"Scaffolded by `baker canvas scaffold-video` \u2014 a runnable reproduction of your reference video, built like an editing timeline. It is a sequence of clear SHOTS separated at COMPLETE BREAKS (hard cuts): two adjacent presenter shots at a cut are TWO clips, never glued into one take. What stays continuous is the VOICE \u2014 a voiceover narration is ONE read across the b-roll it plays over, and a b-roll CUTAWAY between two on-camera moments leaves the presenter shot continuous with the insert sliced in \u2014 and each person keeps ONE brand voice (all their clips' native audio re-voiced in a single per-speaker pass), so timbre holds across the cuts. A presenter shot is ONE Seedance clip (native lip-sync + audio); a pure-voiceover stretch is one ElevenLabs tts read; a sub-2s flash is a still hold. A single shot too long for one clip splits into takes that share a boundary frame \u2014 the spine drops the duplicated frame (`--seam-dedup head|tail|off`). Every clip gets a CLEAN-PLATE start AND end keyframe (no baked text), RECAST to your dropped reference assets \u2014 Seedance interpolates real in-shot motion between them. Each frame grounds only on its own extracted frame + el_* slots (never another generated frame), so all frames render in PARALLEL (no cross-frame cascade). A SPLIT-SCREEN / PICTURE-IN-PICTURE / KEYED-PRESENTER scene is reproduced as one clip PER REGION, stacked or overlaid (see `metadata.todo.composition`). On-screen text/graphics are a separate HTML overlay layer you paint; audio is the voice + SFX + a ducked music bed, normalized stereo. It is a STARTING POINT, not a locked render: add, delete, reorder, split, merge, or re-time scenes freely \u2014 see `metadata.todo.full_flexibility`.",
|
|
40452
40274
|
"",
|
|
40453
40275
|
"WHAT TO DO NEXT:",
|
|
40454
40276
|
"0. RE-CRAFT THE SCRIPT FIRST (don't clone). This reference already won in-market, but copying a video is much harder than a static: the hook is targeting and may not transfer, and the message must become TRUE for our brand. Work the `metadata.todo.script_recraft` checklist \u2014 for each scene judge its role (hook/body/CTA), decide keep/cut/reorder/replace, and re-author every line for OUR customer's pain + OUR offer. See `references/script-craft.md` (hook/body/CTA framework) and the `meta-ads-playbook` skill. Most of the work lives here.",
|
|
@@ -40489,7 +40311,7 @@ function recraftTextForRole(role, sceneIndex) {
|
|
|
40489
40311
|
return `[RECRAFT HOOK \u2014 the #1 decision, but usually the LIGHTEST move wins: this hook already worked, so default to KEEPING it and building on top (swap only the specifics for ours). REBUILD only when it doesn't transfer \u2014 a claim we lack or a different funnel/awareness stage \u2014 by reaching for its deeper INNER MECHANIC and delivering that truthfully. DIAGNOSE (device + mechanic + stage) \u2192 DECIDE keep/adapt/rebuild \u2192 hold the opener to criteria: ${HOOK_OPENER_CRITERIA}. It lives on s${sceneIndex}_start (first frame) + the scene-${sceneIndex} overlay. See references/hook-craft.md + meta-ads-playbook \xA710/\xA739.]`;
|
|
40490
40312
|
}
|
|
40491
40313
|
if (role === "cta") {
|
|
40492
|
-
return "[RECRAFT CTA \u2014 the close: state what to do (where to go) + what to expect (offer/bundle/discount) for OUR brand; soft for top-of-funnel, hard for bottom.
|
|
40314
|
+
return "[RECRAFT CTA \u2014 the close: state what to do (where to go) + what to expect (offer/bundle/discount) for OUR brand; soft for top-of-funnel, hard for bottom. Don't render the reference's words. See references/script-craft.md.]";
|
|
40493
40315
|
}
|
|
40494
40316
|
return `[RECRAFT: rewrite this ${role} for OUR brand \u2014 true claims only; do NOT render the reference's words. See references/script-craft.md + meta-ads-playbook.]`;
|
|
40495
40317
|
}
|
|
@@ -40572,7 +40394,7 @@ function buildVideoTodo(report, overlayCount, floatingCount, opts, blueprint) {
|
|
|
40572
40394
|
// ALWAYS-ON safety net: the scaffold can only seed what the deconstruct
|
|
40573
40395
|
// cataloged, and it under-detects on-image graphics + sound cues. Never trust
|
|
40574
40396
|
// "none detected" — re-watch the reference and fill the gaps with the right tool.
|
|
40575
|
-
completeness_check: 'The scaffold mirrors the deconstruct\'s catalog, which UNDER-DETECTS \u2014 never trust a 0 count. Re-watch the reference frame-by-frame and add anything missing: (1) ON-IMAGE GRAPHICS not in floating_elements (dollar/coin icons, emojis, checkmarks, rating stars, price tags, arrows, progress bars, app UI) \u2192 source each with `baker images icon "<desc>"` / `baker images sticker` / `baker images gif` / `baker images logo <domain>` and add it as an <img class="ov pos-* " data-start data-dur> in video-overlay-composition/index.html (
|
|
40397
|
+
completeness_check: 'The scaffold mirrors the deconstruct\'s catalog, which UNDER-DETECTS \u2014 never trust a 0 count. Re-watch the reference frame-by-frame and add anything missing: (1) ON-IMAGE GRAPHICS not in floating_elements (dollar/coin icons, emojis, checkmarks, rating stars, price tags, arrows, progress bars, app UI) \u2192 source each with `baker images icon "<desc>"` / `baker images sticker` / `baker images gif` / `baker images logo <domain>` and add it as an <img class="ov pos-* " data-start data-dur> in video-overlay-composition/index.html (never bake graphics into the frame plates). (2) SOUND CUES not in sound_effects (cha-ching/coin, whoosh, ding, pop, notification, keyboard) \u2192 add a `sound_effect` node (eleven_text_to_sound) and wire it onto `audio_mix` at its timestamp. (3) RECURRING people/animals/products/logos/sets with no el_* slot \u2192 add an `ingest` [TODO] slot and reference it from the frames they appear in. (4) Burned-in captions/text not in text_overlays \u2192 add an <img>-free <div class="ov"> in index.html. (5) ONE person playing MULTIPLE personas/wardrobes (skeptic vs believer, before vs after, two outfits) collapsed into a single el_* slot \u2192 split into one el_* slot PER look, each linked as the SAME individual via `same_as` so every outfit has its own reference image but the face/identity stays identical.',
|
|
40576
40398
|
scenes_clamped_to_15s: report.clamped_scenes,
|
|
40577
40399
|
oversize_scenes: report.oversize_scenes.length > 0 ? {
|
|
40578
40400
|
scenes: report.oversize_scenes,
|
|
@@ -42263,9 +42085,9 @@ ${describeRewrites(healed.rewrites)}
|
|
|
42263
42085
|
}) : null;
|
|
42264
42086
|
const hints2 = reviewable ? review === null ? [RENDER_REVIEW_UNAVAILABLE] : review.length === 0 ? ["Reviewed the finished video frame by frame \u2014 nothing to report."] : [
|
|
42265
42087
|
`Reviewed the finished video and found ${review.length} thing${review.length === 1 ? "" : "s"} to fix. Show the user what is wrong before you show them the ad.`,
|
|
42266
|
-
...review.map((f) => `${f.severity === "blocking" ? "
|
|
42088
|
+
...review.map((f) => `${f.severity === "blocking" ? "Must fix" : "Should fix"} \u2014 ${f.what}`),
|
|
42267
42089
|
...review.some((f) => f.scene) ? [
|
|
42268
|
-
`Anything about the
|
|
42090
|
+
`Anything about the mark or the closing card is a composition fix, not a re-render: both are drawn as HTML by the caption composition, so editing it and re-running re-renders only that pass \u2014 the clips are cached and no generation is paid for again. Fix them, then re-run: edit the \`show\` of the scene files named above \u2014 a shot with a person handling equipment is where limbs and objects go wrong, so widen it, move the hands out of frame, or drop the person from that beat. Re-running re-renders only the scenes you edited; everything else comes from the cache (this run: ${result.stats?.cached_nodes ?? 0} of ${result.stats?.total_nodes ?? 0} nodes were cached).`
|
|
42269
42091
|
] : []
|
|
42270
42092
|
] : [];
|
|
42271
42093
|
if (poster) {
|
|
@@ -43169,12 +42991,12 @@ function fail3(code, message) {
|
|
|
43169
42991
|
process.exit(2);
|
|
43170
42992
|
}
|
|
43171
42993
|
function resolveModels(args5) {
|
|
43172
|
-
const
|
|
42994
|
+
const pick = (flag, kind, fallback) => args5[flag] ? String(args5[flag]) : resolveModel(kind, fallback);
|
|
43173
42995
|
return {
|
|
43174
|
-
describeModel:
|
|
43175
|
-
selectModel:
|
|
43176
|
-
layoutModel:
|
|
43177
|
-
genModel:
|
|
42996
|
+
describeModel: pick("describe-model", "image_describe", "~google/gemini-pro-latest"),
|
|
42997
|
+
selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
|
|
42998
|
+
layoutModel: pick("layout-model", "text_generate", "~google/gemini-flash-latest"),
|
|
42999
|
+
genModel: pick("gen-model", "image_generate", "openai/gpt-image-2")
|
|
43178
43000
|
};
|
|
43179
43001
|
}
|
|
43180
43002
|
var PLATFORM_PLACEMENTS = {
|
|
@@ -44375,7 +44197,7 @@ registerSchema({
|
|
|
44375
44197
|
spec: {
|
|
44376
44198
|
type: "string",
|
|
44377
44199
|
required: true,
|
|
44378
|
-
description: 'Path to the ad spec JSON. Shape: { format?, market?, brand?, cast?, end_card?, voice?, music?, beats: [{ say, show, on_camera?, cast? }] }. Fill `brand` from src/brand/BRAND.md \u2014 `palette` (its hex tokens, most important first) and `logo` (the repo path to the mark) are what make the ad look like the client rather than like stock. `market` is where the ad is
|
|
44200
|
+
description: 'Path to the ad spec JSON. Shape: { format?, market?, brand?, cast?, end_card?, voice?, music?, beats: [{ say, show, on_camera?, cast? }] }. Fill `brand` from src/brand/BRAND.md \u2014 `palette` (its hex tokens, most important first) and `logo` (the repo path to the mark) are what make the ad look like the client rather than like stock. `market` is where the ad is set; omitted, it is inferred from the voice language, and getting it wrong is what fills a Spanish ad with British houses. `say` is one clause ending in its own punctuation \u2014 it becomes a caption card verbatim, so two sentences in one beat produce a card holding both. `show` is the shot brief for that line. Set `on_camera` only when that beat\'s subject talks to camera. A beat\'s `sound` is one sound effect for that shot, and most beats should not have one. Add it only where the picture shows a specific physical event the viewer expects to hear (a drill tightening a bolt, a door closing, rain on glass, a graphic snapping in). On a talking head or a calm lifestyle shot it reads as a stock sting, and one per beat turns a quiet ad into a noisy one. A music bed plus two well-placed effects beats eight. `voiceover: false` makes it a MUSIC-LED ad: nobody speaks, the `say` lines become on-screen text captioned straight from the script, and it needs `music`. `cast` is WHO the ad is about, and an ad with people in it needs one: `{ "avatar": "marta" }` names a cast avatar (`baker avatars list`) and every beat is grounded on that avatar\'s identity sheet with its subject description copied verbatim \u2014 the same face here as in the rest of the company\'s work. Without it each beat invents its own stranger, which is how one 28-second ad came back with five different men playing one customer. `{ "description": "..." }` is the fallback when there is no avatar, and it scaffolds a canvas that asks you to drop a photo before it can run \u2014 so prefer the avatar. A beat sets `cast: false` for a shot they are not in. `end_card` is on by default whenever `brand` is set: the last beat becomes a flat brand plate with the mark and a call to action drawn over it. `{ "cta": "..." }` sets the button copy \u2014 there is no default, so with no `cta` the card carries the mark alone, and a `cta` repeating the closing line is dropped rather than printed twice. `false` keeps the footage.'
|
|
44379
44201
|
},
|
|
44380
44202
|
avatar: {
|
|
44381
44203
|
type: "string",
|
|
@@ -44414,7 +44236,7 @@ function avatarVoiceBrief(avatar) {
|
|
|
44414
44236
|
var scaffoldAdCommand = defineCommand115({
|
|
44415
44237
|
meta: {
|
|
44416
44238
|
name: "scaffold-ad",
|
|
44417
|
-
description: 'Build a captioned vertical ad from a written spec, with no reference video to copy.\n\nA spec is a list of BEATS. One beat = one line the voice says + one shot on screen while it is said. That pairing is what keeps the ad honest: the caption card IS the line, so it can never end mid-sentence, and the picture can never drift from the read.\n\nTwo rules the spec enforces for you, both learned the expensive way:\n \u2022 `say` is
|
|
44239
|
+
description: 'Build a captioned vertical ad from a written spec, with no reference video to copy.\n\nA spec is a list of BEATS. One beat = one line the voice says + one shot on screen while it is said. That pairing is what keeps the ad honest: the caption card IS the line, so it can never end mid-sentence, and the picture can never drift from the read.\n\nTwo rules the spec enforces for you, both learned the expensive way:\n \u2022 `say` is one clause with its own punctuation. Two sentences in a beat is rejected.\n \u2022 Nobody in shot is speaking unless you set `on_camera` on that beat. A person visibly talking under a voice that is not theirs reads as bad dubbing.\n\nExample spec:\n { "beats": [\n { "say": "Mientras t\xFA sigues pagando la luz a precio de oro,", "show": "Aerial over Spanish rooftops at golden hour." },\n { "say": "Haz clic en el enlace y reserva tu estudio gratuito.", "show": "A couple walking home at sunset." } ] }\n\nWho is in it:\n `cast: { avatar: "marta" }` grounds every beat on that avatar\'s face \u2014 cast one with `baker avatars`.\n Without a cast, each beat invents its own person and the ad reads as a stock-footage collage.\n\nHow it ends: with a `brand`, the last beat closes on a flat brand plate carrying the mark and the CTA.\n\nThen: baker canvas run <the canvas it writes>'
|
|
44418
44240
|
},
|
|
44419
44241
|
args: {
|
|
44420
44242
|
spec: { type: "string", required: true, description: "Path to the ad spec JSON" },
|
|
@@ -44600,7 +44422,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
44600
44422
|
message: resolvedLogo ? `The brand mark at \`${resolvedLogo}\` does not exist, so this ad has no logo to put on screen.` : `This company has no brand mark in \`${BRAND_DIR}/logos/\`, so an ad cannot carry its logo.`,
|
|
44601
44423
|
// What the lookup against their own domain actually found, so the agent does not
|
|
44602
44424
|
// go looking for the mark somewhere else — which is the loop this replaced.
|
|
44603
|
-
fix: `${fetched?.reason ?? ""}
|
|
44425
|
+
fix: `${fetched?.reason ?? ""} Don't draw one or take one from an icon library: the mark is drawn on every frame and on the closing card, so a stand-in ships an ad wearing the wrong brand.`
|
|
44604
44426
|
}
|
|
44605
44427
|
});
|
|
44606
44428
|
process.exit(1);
|
|
@@ -44781,7 +44603,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
44781
44603
|
// getting it wrong is expensive: the pictures cost a fraction of the clips, and
|
|
44782
44604
|
// every defect anyone has caught in a finished ad was visible in them. The run
|
|
44783
44605
|
// stops, the frames are shown, and continuing pays for none of them twice.
|
|
44784
|
-
handle || staged ? `Wrote ${spec.data.beats.length} beats to ${outPath}. Run it with \`baker canvas run ${outPath} --until frames --brief "<what they asked for, their words>"\`,
|
|
44606
|
+
handle || staged ? `Wrote ${spec.data.beats.length} beats to ${outPath}. Run it with \`baker canvas run ${outPath} --until frames --brief "<what they asked for, their words>"\`, show the frames it returns and ask whether to carry on \u2014 then continue with the \`--run-id\` it gives you. This ad carries ${handle ? "a person's face" : "the client's mark"}, and a wrong look costs a whole ad to discover after the clips.` : `Wrote ${spec.data.beats.length} beats to ${outPath}. Run it with \`baker canvas run ${outPath} --brief "<what they asked for, their words>"\`.`,
|
|
44785
44607
|
...autoCast ? [
|
|
44786
44608
|
`Cast \`${autoCast}\` \u2014 the spec described this person in words, and they are one of this company's avatars. Every shot now grounds on their identity sheet and carries their accent and delivery. Write \`"cast": { "avatar": "` + autoCast + '" }` yourself next time; a written description is for someone the company does not have.'
|
|
44787
44609
|
] : [],
|
|
@@ -44823,7 +44645,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
44823
44645
|
// ad with no palette and no mark anywhere in 28 seconds.
|
|
44824
44646
|
`This spec has no ${!spec.data.brand?.palette?.length ? "`brand.palette`" : ""}${!spec.data.brand?.palette?.length && !spec.data.brand?.logo ? " and no " : ""}${!spec.data.brand?.logo ? "`brand.logo`" : ""}. Read src/brand/BRAND.md and re-run with them \u2014 a name alone leaves the ad in someone else's clothes.`
|
|
44825
44647
|
],
|
|
44826
|
-
"`brand.palette` colours the closing plate the card sits on; `brand.logo` is the repo path to the mark, and it is
|
|
44648
|
+
"`brand.palette` colours the closing plate the card sits on; `brand.logo` is the repo path to the mark, and it is drawn by the composition \u2014 top-left throughout and large on the closing card \u2014 never generated as a picture, so it cannot come back garbled. Give it whenever the client has one."
|
|
44827
44649
|
]
|
|
44828
44650
|
});
|
|
44829
44651
|
}
|
|
@@ -44831,7 +44653,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
44831
44653
|
function shortBeatHint(short, total) {
|
|
44832
44654
|
if (short.length === 0) return [];
|
|
44833
44655
|
return [
|
|
44834
|
-
`Beat${short.length === 1 ? "" : "s"} ${short.join(", ")} of ${total} ${short.length === 1 ? "is" : "are"} a fragment rather than a line \u2014 a few words with a whole shot to themselves. Every beat's picture holds for at least ${SPOKEN_CLIP_DURATION_S}s, so a two-word beat buys six seconds of somebody standing still, and a run of those plays as a slideshow rather than an ad.
|
|
44656
|
+
`Beat${short.length === 1 ? "" : "s"} ${short.join(", ")} of ${total} ${short.length === 1 ? "is" : "are"} a fragment rather than a line \u2014 a few words with a whole shot to themselves. Every beat's picture holds for at least ${SPOKEN_CLIP_DURATION_S}s, so a two-word beat buys six seconds of somebody standing still, and a run of those plays as a slideshow rather than an ad. Don't pad them. Merge them into the beat before or after, so each one carries a whole thought. Edit the spec and re-run this command.`
|
|
44835
44657
|
];
|
|
44836
44658
|
}
|
|
44837
44659
|
async function fetchClientLogo() {
|
|
@@ -45208,18 +45030,18 @@ function parseBudget(raw) {
|
|
|
45208
45030
|
throw new Error(`--budget must be one of ${VIDEO_BUDGETS.join(", ")} (got "${v}")`);
|
|
45209
45031
|
}
|
|
45210
45032
|
function resolveModels2(args5) {
|
|
45211
|
-
const
|
|
45033
|
+
const pick = (flag, kind, fallback) => args5[flag] ? String(args5[flag]) : resolveModel2(kind, fallback);
|
|
45212
45034
|
return {
|
|
45213
45035
|
// Flash by default: ~2-3× faster per call than Pro, which keeps each
|
|
45214
45036
|
// per-scene deconstruct step well inside the action time budget and turns a
|
|
45215
45037
|
// ~9 min run into ~3-4 min. Override with --deconstruct-model
|
|
45216
45038
|
// ~google/gemini-pro-latest for the densest extraction when speed matters less.
|
|
45217
|
-
deconstructModel:
|
|
45218
|
-
selectModel:
|
|
45039
|
+
deconstructModel: pick("deconstruct-model", "video_deconstruct", "~google/gemini-flash-latest"),
|
|
45040
|
+
selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
|
|
45219
45041
|
// Default to the strongest image model (matches the static-ad scaffold); the
|
|
45220
45042
|
// frame generators need the most faithful text/identity reproduction. Override
|
|
45221
45043
|
// with --image-model for a cheaper/faster pass.
|
|
45222
|
-
imageModel:
|
|
45044
|
+
imageModel: pick("image-model", "image_generate", "openai/gpt-image-2.5-sunburst")
|
|
45223
45045
|
};
|
|
45224
45046
|
}
|
|
45225
45047
|
function hasPhotorealCast(elements) {
|
|
@@ -45851,7 +45673,7 @@ function capabilityHints(surfaces, tools = []) {
|
|
|
45851
45673
|
const immediate = surfaces.filter((surface) => surface.writeMode === "applies-at-publish");
|
|
45852
45674
|
if (immediate.length > 0) {
|
|
45853
45675
|
hints2.push(
|
|
45854
|
-
`REAL AND IMMEDIATE: ${immediate.map((s) => s.label).join(", ")}
|
|
45676
|
+
`REAL AND IMMEDIATE: ${immediate.map((s) => s.label).join(", ")}. Completing this chat changes the user's live setup, so agree the changes before you finish, not after.`
|
|
45855
45677
|
);
|
|
45856
45678
|
}
|
|
45857
45679
|
const blocked = surfaces.filter((surface) => surface.blockers.length > 0);
|
|
@@ -50973,12 +50795,12 @@ function handleError5(err) {
|
|
|
50973
50795
|
...readOnly ? {
|
|
50974
50796
|
fix: {
|
|
50975
50797
|
action: "reconnect",
|
|
50976
|
-
explanation: "The Google Analytics connection is read-only. Ask the user to reconnect Google Analytics \u2014 in the dashboard, Brain \u2192 Integrations \u2192 Tools \u2192 Google Analytics \u2014 which grants the permission to change the property. Reporting (`baker ga4 query`, `baker ga4 audit`) keeps working meanwhile, so carry on with the rest of the job and tell them what you will set up once they have reconnected.
|
|
50798
|
+
explanation: "The Google Analytics connection is read-only. Ask the user to reconnect Google Analytics \u2014 in the dashboard, Brain \u2192 Integrations \u2192 Tools \u2192 Google Analytics \u2014 which grants the permission to change the property. Reporting (`baker ga4 query`, `baker ga4 audit`) keeps working meanwhile, so carry on with the rest of the job and tell them what you will set up once they have reconnected. Don't claim anything was configured."
|
|
50977
50799
|
}
|
|
50978
50800
|
} : err.code === "UNAUTHORIZED" || err.code === "FORBIDDEN" && isNotConnectedError(err.code, err.message) ? {
|
|
50979
50801
|
fix: {
|
|
50980
50802
|
action: "request_connection",
|
|
50981
|
-
explanation: 'Google Analytics is not connected for this company yet, or no property has been picked.
|
|
50803
|
+
explanation: 'Google Analytics is not connected for this company yet, or no property has been picked. Don\'t send the user to Settings \u2014 call the `request_connection` tool with { platform: "google-analytics", reason } and they connect and pick their property from inside the chat. If the `request_connection` call fails, say so plainly and give the exact route: dashboard \u2192 Brain \u2192 Integrations \u2192 Tools \u2192 Google Analytics. Then carry on with the rest of the task.'
|
|
50982
50804
|
}
|
|
50983
50805
|
} : {},
|
|
50984
50806
|
retryable: RETRYABLE_CODES.has(err.code)
|
|
@@ -51851,7 +51673,7 @@ Examples:
|
|
|
51851
51673
|
});
|
|
51852
51674
|
registerSchema({
|
|
51853
51675
|
command: "ga4.audience",
|
|
51854
|
-
description: "Create an audience (a saved group of users, e.g. everyone who started a demo but never finished), rename one, or archive one. Read `baker ga4 config` first to see the audiences that already exist.
|
|
51676
|
+
description: "Create an audience (a saved group of users, e.g. everyone who started a demo but never finished), rename one, or archive one. Read `baker ga4 config` first to see the audiences that already exist. Everything that defines who is in an audience \u2014 the conditions, the membership window \u2014 is frozen the moment it is created and cannot be edited afterwards, so get it right in one go. An audience only reaches Google Ads for retargeting if the property is linked to a Google Ads account.",
|
|
51855
51677
|
args: {
|
|
51856
51678
|
json: { type: "string", description: createJsonDescription("audience"), required: false },
|
|
51857
51679
|
file: { type: "string", description: "Path to a JSON file with the definition", required: false },
|
|
@@ -54308,7 +54130,7 @@ var extractCommand = defineCommand149({
|
|
|
54308
54130
|
import { defineCommand as defineCommand150 } from "citty";
|
|
54309
54131
|
|
|
54310
54132
|
// src/commands/images/providerHits.ts
|
|
54311
|
-
function
|
|
54133
|
+
function asRecord2(value) {
|
|
54312
54134
|
return value && typeof value === "object" ? value : {};
|
|
54313
54135
|
}
|
|
54314
54136
|
function str(value) {
|
|
@@ -54333,7 +54155,7 @@ function providerHitNormalizer(record, full) {
|
|
|
54333
54155
|
if (!full) {
|
|
54334
54156
|
return compact3;
|
|
54335
54157
|
}
|
|
54336
|
-
const group =
|
|
54158
|
+
const group = asRecord2(record.group);
|
|
54337
54159
|
return {
|
|
54338
54160
|
...compact3,
|
|
54339
54161
|
externalUrl: str(record.externalUrl),
|
|
@@ -58652,7 +58474,7 @@ var addCommand = defineCommand172({
|
|
|
58652
58474
|
"This page was already in the library, so nothing was re-studied \u2014 its sections are searchable now.",
|
|
58653
58475
|
`Search it with: baker landing inspiration search --domain ${new URL(data.canonicalUrl).hostname}`
|
|
58654
58476
|
] : [
|
|
58655
|
-
"Studying this page takes a few minutes.
|
|
58477
|
+
"Studying this page takes a few minutes. Don't wait on it \u2014 carry on, and search for it later in the turn or in a later one.",
|
|
58656
58478
|
"Meanwhile, search what is already in the library: baker landing inspiration search '<what you want to see>' --scope all",
|
|
58657
58479
|
"This is saved and being studied now, so it is listed as already applied \u2014 tell the user it is kept whatever they do with this chat.",
|
|
58658
58480
|
// The save is not a promise that the study succeeded. An agent that
|
|
@@ -61998,7 +61820,7 @@ var variantCommand = defineCommand181({
|
|
|
61998
61820
|
change: String(args5.change)
|
|
61999
61821
|
});
|
|
62000
61822
|
const hints2 = [
|
|
62001
|
-
forks.length === 0 ? `MISSING --fork: ${variantSlug2} currently renders exactly ${controlSlug}, so a test between them cannot conclude anything. Re-run with --fork <Component>, or copy the one section your change touches into src/pages/${variantSlug2}/_components/ and repoint that import.` : `Edit
|
|
61823
|
+
forks.length === 0 ? `MISSING --fork: ${variantSlug2} currently renders exactly ${controlSlug}, so a test between them cannot conclude anything. Re-run with --fork <Component>, or copy the one section your change touches into src/pages/${variantSlug2}/_components/ and repoint that import.` : `Edit only src/pages/${variantSlug2}/_components/${forks.join(", ")} \u2014 every other section is shared with ${controlSlug}, and editing a shared one changes both arms at once.`,
|
|
62002
61824
|
`Preview both at http://localhost:4321/${controlSlug}/ and http://localhost:4321/${variantSlug2}/ and check they differ only where you meant. Once it is live, only the first of those two answers \u2014 a variant has no public address of its own, and \`/${controlSlug}/?_bkr_preview=b\` is how anyone looks at it.`,
|
|
62003
61825
|
`Then: baker experiment start --landing ${controlSlug} --variant ${variantSlug2} --because "${String(args5.because)}" --change "${String(args5.change)}". Nothing is split until the session is published \u2014 the person publishing is the review of this page.`
|
|
62004
61826
|
];
|
|
@@ -62315,7 +62137,7 @@ import { defineCommand as defineCommand196 } from "citty";
|
|
|
62315
62137
|
import { defineCommand as defineCommand184 } from "citty";
|
|
62316
62138
|
|
|
62317
62139
|
// src/commands/research/hints.ts
|
|
62318
|
-
var AD_COPY_ROUTE = 'This returns competing
|
|
62140
|
+
var AD_COPY_ROUTE = 'This returns competing domains and their SERP economics \u2014 no ad copy, no headlines, no creative. For the actual copy of a competitor\'s ads: `baker winning-ads advertisers "<brand>"` \u2192 `baker winning-ads search "<brief>" --advertiser-id <id>` \u2192 `baker winning-ads content <adId>` (`primary_text` / `headline` / `cta`, plus the spoken transcript and on-screen text for video). That corpus is Meta and LinkedIn only \u2014 Google SERP ad copy is not available through any Baker command, so do not keep querying for it here.';
|
|
62319
62141
|
function noSerpRowsHints(rowCount2, queryContext) {
|
|
62320
62142
|
if (rowCount2 > 0) {
|
|
62321
62143
|
return [];
|
|
@@ -62486,7 +62308,7 @@ function handleResearchError(err, fixFor) {
|
|
|
62486
62308
|
// src/commands/research/advertisers.ts
|
|
62487
62309
|
registerSchema({
|
|
62488
62310
|
command: "research.advertisers",
|
|
62489
|
-
description: 'Returns a ranked list of
|
|
62311
|
+
description: 'Returns a ranked list of domains competing for one keyword in Google, with avg SERP position, relevance rating, estimated traffic value and visibility \u2014 domain economics, not ad copy. Despite the name it returns no headlines, descriptions or creative of any kind; for a competitor\'s actual ad copy use `baker winning-ads content <adId>` (Meta/LinkedIn only \u2014 Google SERP ad copy is not available anywhere in Baker). Start here: `baker research advertisers "<keyword>" --location <cc> --language <code>` to size up who owns a term. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.',
|
|
62490
62312
|
args: {
|
|
62491
62313
|
keyword: {
|
|
62492
62314
|
type: "string",
|
|
@@ -62495,12 +62317,12 @@ registerSchema({
|
|
|
62495
62317
|
},
|
|
62496
62318
|
location: {
|
|
62497
62319
|
type: "string",
|
|
62498
|
-
description: "Country code (us, uk, es, de...) or DataForSEO location code.
|
|
62320
|
+
description: "Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States) if omitted \u2014 always set this for non-US markets",
|
|
62499
62321
|
required: false
|
|
62500
62322
|
},
|
|
62501
62323
|
language: {
|
|
62502
62324
|
type: "string",
|
|
62503
|
-
description: "Language code or name (en, es, spanish...).
|
|
62325
|
+
description: "Language code or name (en, es, spanish...). Defaults to en (English) if omitted \u2014 always set this for non-English markets",
|
|
62504
62326
|
required: false
|
|
62505
62327
|
},
|
|
62506
62328
|
limit: { type: "string", description: "Max results (default: 20, max: 100)", required: false },
|
|
@@ -62573,17 +62395,17 @@ Examples:
|
|
|
62573
62395
|
import { defineCommand as defineCommand185 } from "citty";
|
|
62574
62396
|
registerSchema({
|
|
62575
62397
|
command: "research.autocomplete",
|
|
62576
|
-
description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for.
|
|
62398
|
+
description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
62577
62399
|
args: {
|
|
62578
62400
|
keyword: { type: "string", description: "Seed keyword (positional)", required: true },
|
|
62579
62401
|
location: {
|
|
62580
62402
|
type: "string",
|
|
62581
|
-
description: "Country code (us, uk, es, de...) or DataForSEO location code.
|
|
62403
|
+
description: "Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States) if omitted",
|
|
62582
62404
|
required: false
|
|
62583
62405
|
},
|
|
62584
62406
|
language: {
|
|
62585
62407
|
type: "string",
|
|
62586
|
-
description: "Language code or name.
|
|
62408
|
+
description: "Language code or name. Defaults to en (English) if omitted",
|
|
62587
62409
|
required: false
|
|
62588
62410
|
},
|
|
62589
62411
|
limit: { type: "string", description: "Max suggestions (default: 10, max: 20)", required: false },
|
|
@@ -62869,7 +62691,7 @@ Examples:
|
|
|
62869
62691
|
import { defineCommand as defineCommand188 } from "citty";
|
|
62870
62692
|
registerSchema({
|
|
62871
62693
|
command: "research.intent",
|
|
62872
|
-
description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate.
|
|
62694
|
+
description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
|
|
62873
62695
|
args: {
|
|
62874
62696
|
keywords: {
|
|
62875
62697
|
type: "string",
|
|
@@ -62878,7 +62700,7 @@ registerSchema({
|
|
|
62878
62700
|
},
|
|
62879
62701
|
language: {
|
|
62880
62702
|
type: "string",
|
|
62881
|
-
description: "Language code or name.
|
|
62703
|
+
description: "Language code or name. Defaults to en (English) if omitted \u2014 always set this for non-English keywords",
|
|
62882
62704
|
required: false
|
|
62883
62705
|
},
|
|
62884
62706
|
"no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
|
|
@@ -62940,18 +62762,18 @@ Examples:
|
|
|
62940
62762
|
import { defineCommand as defineCommand189 } from "citty";
|
|
62941
62763
|
registerSchema({
|
|
62942
62764
|
command: "research.keyword-gap",
|
|
62943
|
-
description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities.
|
|
62765
|
+
description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
62944
62766
|
args: {
|
|
62945
62767
|
competitor: { type: "string", description: "Competitor domain (positional 1)", required: true },
|
|
62946
62768
|
ours: { type: "string", description: "Your domain (positional 2)", required: true },
|
|
62947
62769
|
location: {
|
|
62948
62770
|
type: "string",
|
|
62949
|
-
description: "Country code (us, uk, es, de...) or DataForSEO location code.
|
|
62771
|
+
description: "Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States); set it for any non-US market.",
|
|
62950
62772
|
required: false
|
|
62951
62773
|
},
|
|
62952
62774
|
language: {
|
|
62953
62775
|
type: "string",
|
|
62954
|
-
description: "Language code or name.
|
|
62776
|
+
description: "Language code or name. Defaults to en (English) if omitted \u2014 always set this for non-English markets",
|
|
62955
62777
|
required: false
|
|
62956
62778
|
},
|
|
62957
62779
|
type: { type: "string", description: "Filter: paid, organic, all (default: all)", required: false },
|
|
@@ -63091,7 +62913,7 @@ function keywordMetricsFields(options) {
|
|
|
63091
62913
|
// src/commands/research/keyword-metrics.ts
|
|
63092
62914
|
registerSchema({
|
|
63093
62915
|
command: "research.keyword-metrics",
|
|
63094
|
-
description: "Search volume, CPC, top-of-page bids and competition for a list of keywords
|
|
62916
|
+
description: "Search volume, CPC, top-of-page bids and competition for a list of keywords you name \u2014 no domain needed. This is the command for sizing a market you have keywords for; the domain-bound ones (keywords-for-site, keyword-gap) answer a different question and should not be used as a workaround for this one. The volume is Google's Keyword Planner figure resold by DataForSEO, so it is not a second opinion on `baker ads google keywords metrics` \u2014 for that, pass --clickstream. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
63095
62917
|
args: {
|
|
63096
62918
|
keywords: {
|
|
63097
62919
|
type: "string",
|
|
@@ -63100,12 +62922,12 @@ registerSchema({
|
|
|
63100
62922
|
},
|
|
63101
62923
|
location: {
|
|
63102
62924
|
type: "string",
|
|
63103
|
-
description: "Country code (us, mx, br, es...) or DataForSEO location code.
|
|
62925
|
+
description: "Country code (us, mx, br, es...) or DataForSEO location code. Defaults to us (United States) if omitted \u2014 always set this for non-US markets",
|
|
63104
62926
|
required: false
|
|
63105
62927
|
},
|
|
63106
62928
|
language: {
|
|
63107
62929
|
type: "string",
|
|
63108
|
-
description: "Language code or name.
|
|
62930
|
+
description: "Language code or name. Defaults to en (English) if omitted \u2014 always set this for non-English markets",
|
|
63109
62931
|
required: false
|
|
63110
62932
|
},
|
|
63111
62933
|
clickstream: {
|
|
@@ -63206,17 +63028,17 @@ Examples:
|
|
|
63206
63028
|
import { defineCommand as defineCommand191 } from "citty";
|
|
63207
63029
|
registerSchema({
|
|
63208
63030
|
command: "research.keywords-for-site",
|
|
63209
|
-
description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only.
|
|
63031
|
+
description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
63210
63032
|
args: {
|
|
63211
63033
|
target: { type: "string", description: "Domain or URL to analyze (positional)", required: true },
|
|
63212
63034
|
location: {
|
|
63213
63035
|
type: "string",
|
|
63214
|
-
description: "Country code (us, uk, es, de...) or DataForSEO location code.
|
|
63036
|
+
description: "Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States) if omitted \u2014 always set this for non-US markets",
|
|
63215
63037
|
required: false
|
|
63216
63038
|
},
|
|
63217
63039
|
language: {
|
|
63218
63040
|
type: "string",
|
|
63219
|
-
description: "Language code or name.
|
|
63041
|
+
description: "Language code or name. Defaults to en (English) if omitted \u2014 always set this for non-English markets",
|
|
63220
63042
|
required: false
|
|
63221
63043
|
},
|
|
63222
63044
|
sort: {
|
|
@@ -63399,17 +63221,17 @@ Examples:
|
|
|
63399
63221
|
import { defineCommand as defineCommand194 } from "citty";
|
|
63400
63222
|
registerSchema({
|
|
63401
63223
|
command: "research.relevant-pages",
|
|
63402
|
-
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic.
|
|
63224
|
+
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
63403
63225
|
args: {
|
|
63404
63226
|
target: { type: "string", description: "Domain to analyze (positional, e.g. competitor.com)", required: true },
|
|
63405
63227
|
location: {
|
|
63406
63228
|
type: "string",
|
|
63407
|
-
description: "Country code (us, uk, es, de...) or DataForSEO location code.
|
|
63229
|
+
description: "Country code (us, uk, es, de...) or DataForSEO location code. Defaults to us (United States) if omitted",
|
|
63408
63230
|
required: false
|
|
63409
63231
|
},
|
|
63410
63232
|
language: {
|
|
63411
63233
|
type: "string",
|
|
63412
|
-
description: "Language code or name.
|
|
63234
|
+
description: "Language code or name. Defaults to en (English) if omitted",
|
|
63413
63235
|
required: false
|
|
63414
63236
|
},
|
|
63415
63237
|
limit: { type: "string", description: "Max results (default: 20, max: 1000)", required: false },
|
|
@@ -66047,7 +65869,7 @@ function handleError8(err) {
|
|
|
66047
65869
|
...err.code === "UNAUTHORIZED" || err.code === "FORBIDDEN" && isNotConnectedError(err.code, err.message) ? {
|
|
66048
65870
|
fix: {
|
|
66049
65871
|
action: "request_connection",
|
|
66050
|
-
explanation: 'Tag Manager is not connected for this company yet, or no container has been picked.
|
|
65872
|
+
explanation: 'Tag Manager is not connected for this company yet, or no container has been picked. Don\'t send the user to Settings \u2014 call the `request_connection` tool with { platform: "google-tag-manager", reason } and they connect and pick their containers (they can pick more than one) from inside the chat. `request_tag_input` is not the route: that form manages the container snippet on the site, not what runs inside the container, and it cannot pick a container. If the `request_connection` call fails, say so plainly and give the exact route: dashboard \u2192 Brain \u2192 Integrations \u2192 Tools \u2192 Google Tag Manager, where they also pick the container. Then carry on with the rest of the task.'
|
|
66051
65873
|
}
|
|
66052
65874
|
} : {},
|
|
66053
65875
|
retryable: RETRYABLE_CODES2.has(err.code)
|
|
@@ -66561,7 +66383,7 @@ ${configLines.join("\n")}` : header;
|
|
|
66561
66383
|
function tagsListHints() {
|
|
66562
66384
|
return [
|
|
66563
66385
|
"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.",
|
|
66564
|
-
"
|
|
66386
|
+
"Don't 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."
|
|
66565
66387
|
];
|
|
66566
66388
|
}
|
|
66567
66389
|
|
|
@@ -66596,7 +66418,7 @@ async function listTags(json) {
|
|
|
66596
66418
|
failApi3(err);
|
|
66597
66419
|
}
|
|
66598
66420
|
}
|
|
66599
|
-
var
|
|
66421
|
+
var listArgs11 = {
|
|
66600
66422
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
66601
66423
|
};
|
|
66602
66424
|
var listCommand19 = defineCommand222({
|
|
@@ -66604,7 +66426,7 @@ var listCommand19 = defineCommand222({
|
|
|
66604
66426
|
name: "list",
|
|
66605
66427
|
description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
|
|
66606
66428
|
},
|
|
66607
|
-
args:
|
|
66429
|
+
args: listArgs11,
|
|
66608
66430
|
run: async ({ args: args5 }) => {
|
|
66609
66431
|
await listTags(args5.json === true);
|
|
66610
66432
|
}
|
|
@@ -66633,7 +66455,7 @@ var tagsCommand4 = defineCommand222({
|
|
|
66633
66455
|
name: "tags",
|
|
66634
66456
|
description: `Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, \u2026) \u2014 production tags plus the changes staged in this chat.
|
|
66635
66457
|
|
|
66636
|
-
This command is
|
|
66458
|
+
This command is read-only. Every tag change \u2014 create, edit, or delete \u2014 goes through the request_tag_input tool (baker_ui MCP server): propose one or more changes (each becomes a tab in one approval form), pre-fill the non-secret fields you know, and the user reviews, fills secrets, and approves or skips each. Secret values (accessToken, apiSecret, authorizationToken, apiKey, conversionToken, OAuth connections) never pass through the CLI or the chat.
|
|
66637
66459
|
|
|
66638
66460
|
Refs: \`baker tags list\` prints each tag's ref \u2014 a real tag id, or tag_temp_* for creates staged in this chat. Use these refs as flow side-effect tagIds; they keep resolving after publish.
|
|
66639
66461
|
|
|
@@ -66652,7 +66474,7 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
66652
66474
|
// command's flags when it scans rawArgs for a subcommand name, and `default` (not
|
|
66653
66475
|
// `run`) dispatches the bare invocation — citty falls through to `run` after a
|
|
66654
66476
|
// subcommand, so a `run` here would also list on every `baker tags draft`.
|
|
66655
|
-
args:
|
|
66477
|
+
args: listArgs11,
|
|
66656
66478
|
default: "list"
|
|
66657
66479
|
});
|
|
66658
66480
|
|