@koda-sl/baker-cli 0.366.0-dev.1010f7728 → 0.366.0-dev.9bf895443
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 +2 -6
- package/dist/{chunk-WXSUOPOU.js → chunk-BLMXG42J.js} +1 -49
- package/dist/chunk-BLMXG42J.js.map +1 -0
- package/dist/cli.js +159 -46
- package/dist/cli.js.map +1 -1
- package/dist/{shared-3VVQPSFH.js → shared-BROA3UXS.js} +2 -8
- package/package.json +1 -1
- package/dist/chunk-WXSUOPOU.js.map +0 -1
- /package/dist/{shared-3VVQPSFH.js.map → shared-BROA3UXS.js.map} +0 -0
package/README.md
CHANGED
|
@@ -889,9 +889,6 @@ baker ads meta leads --form-id 987654321 --full # raw conta
|
|
|
889
889
|
baker ads meta campaigns --account-id act_123 # ACTIVE only by default
|
|
890
890
|
baker ads meta ads --account-id act_123 --all-statuses # widen to everything
|
|
891
891
|
|
|
892
|
-
# "Find the October ad" — Meta matches the name, so only that row is read
|
|
893
|
-
baker ads meta ads --account-id act_123 --all-statuses --name-contains octubre --fields id,name,adset_id,creative.id
|
|
894
|
-
|
|
895
892
|
# "Tell me about ad 9988"
|
|
896
893
|
baker ads meta creatives --creative-id 9988
|
|
897
894
|
baker ads meta preview --creative-id 9988 --ad-format MOBILE_FEED_STANDARD --out-file /tmp/p.html
|
|
@@ -946,7 +943,8 @@ baker ads meta creatives create --account-id act_123 --page 555 --instagram-us
|
|
|
946
943
|
baker ads meta ads create --account-id act_123 --name "Ad 1" --adset meta_temp_as --creative meta_temp_cr
|
|
947
944
|
|
|
948
945
|
# review + edit before publish
|
|
949
|
-
baker ads meta draft
|
|
946
|
+
baker ads meta draft # one line per op: ref · kind · summary · after <refs>, then advisories
|
|
947
|
+
baker ads meta draft --json # raw JSON envelope for scripting
|
|
950
948
|
baker ads meta draft show meta_temp_cr # full staged payload — the receipt before publish
|
|
951
949
|
baker ads meta draft remove meta_temp_cr # removing a create cascades to dependents
|
|
952
950
|
baker ads meta draft clear
|
|
@@ -968,8 +966,6 @@ Status changes are `pause|resume|archive` subcommands on `campaigns`/`adsets`/`a
|
|
|
968
966
|
|
|
969
967
|
**Listings (`campaigns`/`adsets`/`ads`)** default to `effective_status=ACTIVE` — pass `--all-statuses` to widen, or `--effective-status ACTIVE,PAUSED` for a custom set.
|
|
970
968
|
|
|
971
|
-
To find one entity by name, pass `--name-contains <text>`: Meta matches it server-side, so only the matching rows are read instead of the whole account. `--fields id,name,creative.id` prints only the named fields (nested ones by dotted path) instead of the full row.
|
|
972
|
-
|
|
973
969
|
**Pagination** is auto-drained (no manual cursor handling).
|
|
974
970
|
|
|
975
971
|
#### Full command surface
|
|
@@ -10,37 +10,6 @@ import {
|
|
|
10
10
|
getEnv
|
|
11
11
|
} from "./chunk-2OKSJNLA.js";
|
|
12
12
|
|
|
13
|
-
// src/commands/ads/project-fields.ts
|
|
14
|
-
function asRecord(value) {
|
|
15
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
16
|
-
}
|
|
17
|
-
function readPath(row, path) {
|
|
18
|
-
let current = row;
|
|
19
|
-
for (const segment of path.split(".")) {
|
|
20
|
-
const record = asRecord(current);
|
|
21
|
-
if (!record) return void 0;
|
|
22
|
-
current = record[segment];
|
|
23
|
-
}
|
|
24
|
-
return current;
|
|
25
|
-
}
|
|
26
|
-
function projectFields(rows, paths) {
|
|
27
|
-
return rows.map((row) => {
|
|
28
|
-
const projected = {};
|
|
29
|
-
for (const path of paths) {
|
|
30
|
-
const value = readPath(row, path);
|
|
31
|
-
if (value !== void 0) {
|
|
32
|
-
projected[path] = value;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return projected;
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
function parseFieldsArg(value) {
|
|
39
|
-
if (typeof value !== "string") return void 0;
|
|
40
|
-
const paths = value.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
|
|
41
|
-
return paths.length > 0 ? paths : void 0;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
13
|
// src/commands/ads/meta/shared.ts
|
|
45
14
|
var DAY_MS = 864e5;
|
|
46
15
|
function metaForbiddenFix(message) {
|
|
@@ -118,18 +87,6 @@ function daysAgoIso(days) {
|
|
|
118
87
|
function csvOrJson(args) {
|
|
119
88
|
return args.output ?? "json";
|
|
120
89
|
}
|
|
121
|
-
var NAME_CONTAINS_ARG = {
|
|
122
|
-
type: "string",
|
|
123
|
-
description: "Only rows whose name contains this text, matched by Meta before anything is returned. Start here to find one entity by name: --name-contains octubre --all-statuses"
|
|
124
|
-
};
|
|
125
|
-
var FIELDS_ARG = {
|
|
126
|
-
type: "string",
|
|
127
|
-
description: "Comma-separated fields to print instead of the whole row; nested ones by dotted path. Pair with --name-contains: --fields id,name,adset_id,creative.id"
|
|
128
|
-
};
|
|
129
|
-
function projectListRows(rows, args) {
|
|
130
|
-
const paths = parseFieldsArg(args.fields);
|
|
131
|
-
return paths ? { rows: projectFields(rows, paths), fields: paths } : { rows };
|
|
132
|
-
}
|
|
133
90
|
function resolveEffectiveStatus(args) {
|
|
134
91
|
if (args["all-statuses"]) {
|
|
135
92
|
return void 0;
|
|
@@ -142,8 +99,6 @@ function resolveEffectiveStatus(args) {
|
|
|
142
99
|
}
|
|
143
100
|
|
|
144
101
|
export {
|
|
145
|
-
projectFields,
|
|
146
|
-
parseFieldsArg,
|
|
147
102
|
metaForbiddenFix,
|
|
148
103
|
handleMetaError,
|
|
149
104
|
resolveAccountIdArg,
|
|
@@ -151,9 +106,6 @@ export {
|
|
|
151
106
|
todayIso,
|
|
152
107
|
daysAgoIso,
|
|
153
108
|
csvOrJson,
|
|
154
|
-
NAME_CONTAINS_ARG,
|
|
155
|
-
FIELDS_ARG,
|
|
156
|
-
projectListRows,
|
|
157
109
|
resolveEffectiveStatus
|
|
158
110
|
};
|
|
159
|
-
//# sourceMappingURL=chunk-
|
|
111
|
+
//# sourceMappingURL=chunk-BLMXG42J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/ads/meta/shared.ts"],"sourcesContent":["import { ApiError } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { writeAdsJson } from \"../output.ts\";\nimport type { AdsErrorEnvelope, QueryFix } from \"../types.ts\";\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Meta answers a permission refusal (Graph codes 200/10/294) with a bare\n * \"Permissions error\" that covers two causes needing opposite remedies: a\n * consent grant the connection never got — nothing validates Meta's granted\n * scopes after connect, unlike HubSpot's `requireCapability` — or a role the\n * user lacks on one asset, since a Pixel/Dataset, Page or catalog lives in a\n * Business and is assigned separately from the ad account. Only the blast radius\n * separates them, so hand the agent that test rather than a verdict: guessing\n * \"reconnect\" wastes the user's time on an unassigned asset, and ruling it out\n * strands a connection that really is short a scope.\n */\nexport function metaForbiddenFix(message: string): QueryFix {\n return {\n action: \"reject\",\n explanation: [\n message,\n \"This is a permission refusal, not a dead connection, and Meta returns the same code for two causes with opposite remedies. Tell them apart by how much else works before you answer.\",\n \"If other reads on this account are ALSO refused (campaigns, ad sets, insights), the connection is short a permission it was never granted. Only the user can widen it, by reconnecting Meta from the dashboard.\",\n \"If those reads work and only this object is refused, the asset (pixel/dataset, Page, or catalog) belongs to a Business the connected user holds no role in. Ad-account access does not carry asset access and reconnecting cannot grant it — the client assigns that asset to the connected user or partner in Meta Business settings, under the asset's own section (Data sources → Datasets for a pixel).\",\n \"Either way do not retry the same call, and do not abort the wider job. Continue with what you can read, and state in your answer that this specific check could not run and why — never present the task as verified when this step was skipped.\",\n ].join(\"\\n\\n\"),\n };\n}\n\nexport function handleMetaError(err: unknown): never {\n if (err instanceof ApiError) {\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"meta_ads\", err.message);\n }\n const envelope: AdsErrorEnvelope = {\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n fix: err.code === \"FORBIDDEN\" ? metaForbiddenFix(err.message) : { action: \"reject\", explanation: err.message },\n retryable: err.code === \"RATE_LIMITED\" || err.code === \"UNAVAILABLE\" || err.code === \"INTERNAL_ERROR\",\n },\n };\n writeAdsJson(envelope);\n process.exit(1);\n }\n const message = err instanceof Error ? err.message : \"Unexpected error\";\n writeAdsJson({ ok: false, error: { code: \"NETWORK_ERROR\", message } });\n process.exit(1);\n}\n\nconst ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;\n\n/** Pull the default Meta ad account ID from `--account-id` arg or `BAKER_META_AD_ACCOUNT_ID` env. */\nexport function resolveAccountIdArg(args: Record<string, unknown>): string {\n const fromArgs = args[\"account-id\"] as string | undefined;\n const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;\n if (!id) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"MISSING_ACCOUNT_ID\",\n message: \"Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs.\",\n },\n });\n process.exit(1);\n }\n if (!ACCOUNT_ID_RE.test(id)) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"INVALID_ACCOUNT_ID\",\n message: `Invalid account ID \"${id}\". Expected numeric ID, optionally prefixed with \"act_\".`,\n },\n });\n process.exit(1);\n }\n return id.startsWith(\"act_\") ? id : `act_${id}`;\n}\n\nexport function getDateRange(args: Record<string, unknown>): { datePreset?: string; since?: string; until?: string } {\n const datePreset = args[\"date-preset\"] as string | undefined;\n const since = args.since as string | undefined;\n const until = args.until as string | undefined;\n if (since && until) return { since, until };\n return { datePreset: datePreset ?? \"last_7d\" };\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function daysAgoIso(days: number): string {\n return new Date(Date.now() - days * DAY_MS).toISOString().slice(0, 10);\n}\n\nexport function csvOrJson(args: Record<string, unknown>): string {\n return (args.output as string | undefined) ?? \"json\";\n}\n\n/**\n * Default to ACTIVE-only on listings — that's almost always what an AI agent or\n * a human glance wants. Pass `--effective-status ACTIVE,PAUSED` to override, or\n * `--all-statuses` to drop the filter entirely.\n */\nexport function resolveEffectiveStatus(args: Record<string, unknown>): string | undefined {\n if (args[\"all-statuses\"]) {\n return undefined;\n }\n const explicit = args[\"effective-status\"] as string | undefined;\n if (explicit) {\n return explicit;\n }\n return \"ACTIVE\";\n}\n"],"mappings":";;;;;;;;;;;;;AAMA,IAAM,SAAS;AAaR,SAAS,iBAAiB,SAA2B;AAC1D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,MAAM;AAAA,EACf;AACF;AAEO,SAAS,gBAAgB,KAAqB;AACnD,MAAI,eAAe,UAAU;AAC3B,QAAI,mBAAmB,IAAI,MAAM,IAAI,OAAO,GAAG;AAC7C,4BAAsB,YAAY,IAAI,OAAO;AAAA,IAC/C;AACA,UAAM,WAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM,IAAI;AAAA,QACV,SAAS,IAAI;AAAA,QACb,KAAK,IAAI,SAAS,cAAc,iBAAiB,IAAI,OAAO,IAAI,EAAE,QAAQ,UAAU,aAAa,IAAI,QAAQ;AAAA,QAC7G,WAAW,IAAI,SAAS,kBAAkB,IAAI,SAAS,iBAAiB,IAAI,SAAS;AAAA,MACvF;AAAA,IACF;AACA,iBAAa,QAAQ;AACrB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAa,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,QAAQ,EAAE,CAAC;AACrE,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,gBAAgB;AAGf,SAAS,oBAAoB,MAAuC;AACzE,QAAM,WAAW,KAAK,YAAY;AAClC,QAAM,KAAK,YAAY,OAAO,EAAE;AAChC,MAAI,CAAC,IAAI;AACP,iBAAa;AAAA,MACX,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,cAAc,KAAK,EAAE,GAAG;AAC3B,iBAAa;AAAA,MACX,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,uBAAuB,EAAE;AAAA,MACpC;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO,GAAG,WAAW,MAAM,IAAI,KAAK,OAAO,EAAE;AAC/C;AAEO,SAAS,aAAa,MAAwF;AACnH,QAAM,aAAa,KAAK,aAAa;AACrC,QAAM,QAAQ,KAAK;AACnB,QAAM,QAAQ,KAAK;AACnB,MAAI,SAAS,MAAO,QAAO,EAAE,OAAO,MAAM;AAC1C,SAAO,EAAE,YAAY,cAAc,UAAU;AAC/C;AAEO,SAAS,WAAmB;AACjC,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAC7C;AAEO,SAAS,WAAW,MAAsB;AAC/C,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACvE;AAEO,SAAS,UAAU,MAAuC;AAC/D,SAAQ,KAAK,UAAiC;AAChD;AAOO,SAAS,uBAAuB,MAAmD;AACxF,MAAI,KAAK,cAAc,GAAG;AACxB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,kBAAkB;AACxC,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -71,19 +71,14 @@ import {
|
|
|
71
71
|
ytDlpBlockSignal
|
|
72
72
|
} from "./chunk-K2IKLMCM.js";
|
|
73
73
|
import {
|
|
74
|
-
FIELDS_ARG,
|
|
75
|
-
NAME_CONTAINS_ARG,
|
|
76
74
|
csvOrJson,
|
|
77
75
|
daysAgoIso,
|
|
78
76
|
getDateRange,
|
|
79
77
|
handleMetaError,
|
|
80
|
-
parseFieldsArg,
|
|
81
|
-
projectFields,
|
|
82
|
-
projectListRows,
|
|
83
78
|
resolveAccountIdArg,
|
|
84
79
|
resolveEffectiveStatus,
|
|
85
80
|
todayIso
|
|
86
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-BLMXG42J.js";
|
|
87
82
|
import {
|
|
88
83
|
buildQueryCacheKey,
|
|
89
84
|
cacheGet,
|
|
@@ -9797,7 +9792,7 @@ import { defineCommand as defineCommand19 } from "citty";
|
|
|
9797
9792
|
function listed(resources) {
|
|
9798
9793
|
return resources.map((resource) => resource.label ? `${resource.id} (${resource.label})` : resource.id).join("; ");
|
|
9799
9794
|
}
|
|
9800
|
-
function connectedResourceHints({ plural, singular, flag, resources }) {
|
|
9795
|
+
function connectedResourceHints({ plural: plural2, singular, flag, resources }) {
|
|
9801
9796
|
if (resources.length === 0) {
|
|
9802
9797
|
return [];
|
|
9803
9798
|
}
|
|
@@ -9805,7 +9800,7 @@ function connectedResourceHints({ plural, singular, flag, resources }) {
|
|
|
9805
9800
|
return [`This company connected one ${singular}: ${listed(resources)}. Commands use it unless you pass ${flag}.`];
|
|
9806
9801
|
}
|
|
9807
9802
|
return [
|
|
9808
|
-
`This company connected ${resources.length} ${
|
|
9803
|
+
`This company connected ${resources.length} ${plural2}: ${listed(resources)}. Each command works on one, so pass ${flag} \u2014 nothing is picked for you. A question about the whole business covers all ${resources.length}: answering from one and reporting it as the total is wrong.`
|
|
9809
9804
|
];
|
|
9810
9805
|
}
|
|
9811
9806
|
|
|
@@ -23003,6 +22998,27 @@ function compactRow(row) {
|
|
|
23003
22998
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
23004
22999
|
};
|
|
23005
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
|
+
}
|
|
23006
23022
|
function unmappedShapeWarnings(rows, rawContentReturned) {
|
|
23007
23023
|
const unmapped = rows.filter((row) => row.content && creativeDestination(row.content).format === "unknown");
|
|
23008
23024
|
if (unmapped.length === 0) return [];
|
|
@@ -23016,9 +23032,12 @@ function unmappedShapeWarnings(rows, rawContentReturned) {
|
|
|
23016
23032
|
}
|
|
23017
23033
|
function shapeRows(rows, args5) {
|
|
23018
23034
|
const raw = rows;
|
|
23019
|
-
const
|
|
23020
|
-
if (
|
|
23021
|
-
|
|
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
|
+
}
|
|
23022
23041
|
}
|
|
23023
23042
|
if (args5.full) return { rows: raw };
|
|
23024
23043
|
return { rows: rows.map(compactRow), fields: [...COMPACT_COLUMNS] };
|
|
@@ -26363,7 +26382,7 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
26363
26382
|
const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
|
|
26364
26383
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
26365
26384
|
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-M2DBCZFG.js");
|
|
26366
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26385
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-BROA3UXS.js");
|
|
26367
26386
|
try {
|
|
26368
26387
|
const accountId = bareAccountId2(args5);
|
|
26369
26388
|
const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
|
|
@@ -26511,7 +26530,7 @@ function duplicateCommand2(entity, label) {
|
|
|
26511
26530
|
const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
|
|
26512
26531
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
26513
26532
|
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-M2DBCZFG.js");
|
|
26514
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26533
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-BROA3UXS.js");
|
|
26515
26534
|
try {
|
|
26516
26535
|
const accountId = bareAccountId2(args5);
|
|
26517
26536
|
const chatId = requireChatId2();
|
|
@@ -26550,8 +26569,6 @@ var listArgs4 = {
|
|
|
26550
26569
|
"campaign-id": { type: "string", description: "Filter to one campaign" },
|
|
26551
26570
|
"effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
|
|
26552
26571
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
26553
|
-
"name-contains": NAME_CONTAINS_ARG,
|
|
26554
|
-
fields: FIELDS_ARG,
|
|
26555
26572
|
limit: { type: "string", description: "Max rows (default 1000)" },
|
|
26556
26573
|
"no-cache": NO_CACHE_ARG,
|
|
26557
26574
|
output: { type: "string", description: "Output format", default: "json" }
|
|
@@ -26570,17 +26587,15 @@ var listCommand4 = defineCommand58({
|
|
|
26570
26587
|
if (args5["adset-id"]) params["adset-id"] = args5["adset-id"];
|
|
26571
26588
|
if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
|
|
26572
26589
|
if (effectiveStatus) params["effective-status"] = effectiveStatus;
|
|
26573
|
-
if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
|
|
26574
26590
|
if (args5.limit) params.limit = args5.limit;
|
|
26575
26591
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
26576
26592
|
const data = await apiGet("/api/ads/meta/ads", params);
|
|
26577
|
-
const { rows, fields } = projectListRows(data, args5);
|
|
26578
26593
|
const fmt = csvOrJson(args5);
|
|
26579
26594
|
if (fmt !== "json") {
|
|
26580
|
-
writeAdsOutput(
|
|
26595
|
+
writeAdsOutput(data, fmt);
|
|
26581
26596
|
return;
|
|
26582
26597
|
}
|
|
26583
|
-
writeAdsJson({ ok: true, data
|
|
26598
|
+
writeAdsJson({ ok: true, data });
|
|
26584
26599
|
} catch (err) {
|
|
26585
26600
|
handleMetaError(err);
|
|
26586
26601
|
}
|
|
@@ -26597,7 +26612,6 @@ The dashboard shows effective_status (e.g. WITH_ISSUES, PENDING_REVIEW, DISAPPRO
|
|
|
26597
26612
|
Examples:
|
|
26598
26613
|
baker ads meta ads --account-id act_123
|
|
26599
26614
|
baker ads meta ads --adset-id 6123
|
|
26600
|
-
baker ads meta ads --account-id act_123 --all-statuses --name-contains octubre --fields id,name,adset_id,creative.id \u2014 find one ad by name
|
|
26601
26615
|
baker ads meta ads create --name "Ad 1" --adset meta_temp_as01 --creative meta_temp_cr01
|
|
26602
26616
|
baker ads meta ads pause 6123 --account-id act_123
|
|
26603
26617
|
baker ads meta ads retag 6123 --set "utm_medium=paid-social" \u2014 fix tracking on a LIVE ad, keeping everything else`
|
|
@@ -26627,8 +26641,6 @@ var listArgs5 = {
|
|
|
26627
26641
|
"campaign-id": { type: "string", description: "Filter to one campaign" },
|
|
26628
26642
|
"effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
|
|
26629
26643
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter" },
|
|
26630
|
-
"name-contains": NAME_CONTAINS_ARG,
|
|
26631
|
-
fields: FIELDS_ARG,
|
|
26632
26644
|
limit: { type: "string", description: "Max rows (default 1000)" },
|
|
26633
26645
|
"no-cache": NO_CACHE_ARG,
|
|
26634
26646
|
output: { type: "string", description: "Output format", default: "json" }
|
|
@@ -26646,17 +26658,15 @@ var listCommand5 = defineCommand59({
|
|
|
26646
26658
|
const params = { "account-id": accountId };
|
|
26647
26659
|
if (args5["campaign-id"]) params["campaign-id"] = args5["campaign-id"];
|
|
26648
26660
|
if (effectiveStatus) params["effective-status"] = effectiveStatus;
|
|
26649
|
-
if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
|
|
26650
26661
|
if (args5.limit) params.limit = args5.limit;
|
|
26651
26662
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
26652
26663
|
const data = await apiGet("/api/ads/meta/adsets", params);
|
|
26653
|
-
const { rows, fields } = projectListRows(data, args5);
|
|
26654
26664
|
const fmt = csvOrJson(args5);
|
|
26655
26665
|
if (fmt !== "json") {
|
|
26656
|
-
writeAdsOutput(
|
|
26666
|
+
writeAdsOutput(data, fmt);
|
|
26657
26667
|
return;
|
|
26658
26668
|
}
|
|
26659
|
-
writeAdsJson({ ok: true, data
|
|
26669
|
+
writeAdsJson({ ok: true, data });
|
|
26660
26670
|
} catch (err) {
|
|
26661
26671
|
handleMetaError(err);
|
|
26662
26672
|
}
|
|
@@ -26671,7 +26681,6 @@ Defaults to ACTIVE only. Write subcommands stage ops on this chat's draft.
|
|
|
26671
26681
|
Examples:
|
|
26672
26682
|
baker ads meta adsets --account-id act_123
|
|
26673
26683
|
baker ads meta adsets --campaign-id 6123456789
|
|
26674
|
-
baker ads meta adsets --account-id act_123 --all-statuses --name-contains retargeting --fields id,name,campaign_id \u2014 find one ad set by name
|
|
26675
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`
|
|
26676
26685
|
},
|
|
26677
26686
|
subCommands: {
|
|
@@ -26783,8 +26792,6 @@ var listArgs7 = {
|
|
|
26783
26792
|
"account-id": { type: "string", description: "Meta ad account ID" },
|
|
26784
26793
|
"effective-status": { type: "string", description: "Comma-separated effective_status filter (overrides default)" },
|
|
26785
26794
|
"all-statuses": { type: "boolean", description: "Drop the default ACTIVE filter and return everything" },
|
|
26786
|
-
"name-contains": NAME_CONTAINS_ARG,
|
|
26787
|
-
fields: FIELDS_ARG,
|
|
26788
26795
|
limit: { type: "string", description: "Max rows (default 1000)" },
|
|
26789
26796
|
"no-cache": NO_CACHE_ARG,
|
|
26790
26797
|
output: { type: "string", description: "Output format", default: "json" }
|
|
@@ -26801,17 +26808,15 @@ var listCommand7 = defineCommand62({
|
|
|
26801
26808
|
try {
|
|
26802
26809
|
const params = { "account-id": accountId };
|
|
26803
26810
|
if (effectiveStatus) params["effective-status"] = effectiveStatus;
|
|
26804
|
-
if (args5["name-contains"]) params["name-contains"] = args5["name-contains"];
|
|
26805
26811
|
if (args5.limit) params.limit = args5.limit;
|
|
26806
26812
|
if (args5["no-cache"]) params["skip-cache"] = "true";
|
|
26807
26813
|
const data = await apiGet("/api/ads/meta/campaigns", params);
|
|
26808
|
-
const { rows, fields } = projectListRows(data, args5);
|
|
26809
26814
|
const fmt = csvOrJson(args5);
|
|
26810
26815
|
if (fmt !== "json") {
|
|
26811
|
-
writeAdsOutput(
|
|
26816
|
+
writeAdsOutput(data, fmt);
|
|
26812
26817
|
return;
|
|
26813
26818
|
}
|
|
26814
|
-
writeAdsJson({ ok: true, data
|
|
26819
|
+
writeAdsJson({ ok: true, data });
|
|
26815
26820
|
} catch (err) {
|
|
26816
26821
|
handleMetaError(err);
|
|
26817
26822
|
}
|
|
@@ -26830,7 +26835,6 @@ The dashboard shows effective_status: ACTIVE, PAUSED, DELETED, ARCHIVED, IN_PROC
|
|
|
26830
26835
|
Examples:
|
|
26831
26836
|
baker ads meta campaigns --account-id act_123 # ACTIVE only
|
|
26832
26837
|
baker ads meta campaigns --account-id act_123 --all-statuses # everything
|
|
26833
|
-
baker ads meta campaigns --account-id act_123 --all-statuses --name-contains Q3 --fields id,name,status # find one by name
|
|
26834
26838
|
baker ads meta campaigns create --account-id act_123 --name "Q3" --objective OUTCOME_LEADS --daily-budget 50
|
|
26835
26839
|
baker ads meta campaigns pause 6123 --account-id act_123`
|
|
26836
26840
|
},
|
|
@@ -27015,11 +27019,114 @@ Examples:
|
|
|
27015
27019
|
|
|
27016
27020
|
// src/commands/ads/meta/draft.ts
|
|
27017
27021
|
import { defineCommand as defineCommand65 } from "citty";
|
|
27018
|
-
|
|
27022
|
+
|
|
27023
|
+
// src/commands/ads/meta/draft-status.ts
|
|
27024
|
+
var STATUS_HEADINGS = {
|
|
27025
|
+
active: "staged",
|
|
27026
|
+
publishing: "publishing",
|
|
27027
|
+
applied: "published",
|
|
27028
|
+
partial: "published with failures",
|
|
27029
|
+
discarded: "discarded",
|
|
27030
|
+
none: "none"
|
|
27031
|
+
};
|
|
27032
|
+
function plural(count2, word) {
|
|
27033
|
+
return `${count2} ${word}${count2 === 1 ? "" : "s"}`;
|
|
27034
|
+
}
|
|
27035
|
+
function headingLine(draft) {
|
|
27036
|
+
const heading = STATUS_HEADINGS[draft.status];
|
|
27037
|
+
if (draft.status === "active" || draft.status === "discarded") {
|
|
27038
|
+
return `Meta Ads \u2014 ${plural(draft.count, "change")} ${heading} \xB7 ${draft.mode}`;
|
|
27039
|
+
}
|
|
27040
|
+
const counts = /* @__PURE__ */ new Map();
|
|
27041
|
+
for (const op of draft.ops) {
|
|
27042
|
+
const status = op.result?.status ?? "pending";
|
|
27043
|
+
counts.set(status, (counts.get(status) ?? 0) + 1);
|
|
27044
|
+
}
|
|
27045
|
+
const summary = [...counts].map(([status, count2]) => `${count2} ${status}`).join(", ");
|
|
27046
|
+
return `Meta Ads \u2014 ${heading} \xB7 ${summary} \xB7 ${draft.mode}`;
|
|
27047
|
+
}
|
|
27048
|
+
function resultPart(op) {
|
|
27049
|
+
const result = op.result;
|
|
27050
|
+
if (!result) {
|
|
27051
|
+
return void 0;
|
|
27052
|
+
}
|
|
27053
|
+
if (result.status === "failed") {
|
|
27054
|
+
return `\u2717 failed: ${result.error ?? "no reason recorded"}`;
|
|
27055
|
+
}
|
|
27056
|
+
if (result.status === "skipped") {
|
|
27057
|
+
const because = result.skippedBecause;
|
|
27058
|
+
if (because && op.dependsOn.includes(because)) {
|
|
27059
|
+
return `\u2717 skipped: ${because} did not apply`;
|
|
27060
|
+
}
|
|
27061
|
+
return `\u2717 skipped: ${because ?? "a change it needs did not apply"}`;
|
|
27062
|
+
}
|
|
27063
|
+
const id = result.id ?? result.hash;
|
|
27064
|
+
const applied = `\u2713 ${result.status}${id ? ` \u2192 ${id}` : ""}`;
|
|
27065
|
+
const verification = result.verification;
|
|
27066
|
+
if (verification && verification.status !== "confirmed") {
|
|
27067
|
+
return `${applied} (read-back ${verification.status}${verification.note ? `: ${verification.note}` : ""})`;
|
|
27068
|
+
}
|
|
27069
|
+
return applied;
|
|
27070
|
+
}
|
|
27071
|
+
function opLine(op, showAccount) {
|
|
27072
|
+
const parts = [op.ref, op.kind, op.summary];
|
|
27073
|
+
if (op.target && op.target !== op.ref) {
|
|
27074
|
+
parts.push(`target ${op.target}`);
|
|
27075
|
+
}
|
|
27076
|
+
if (showAccount) {
|
|
27077
|
+
parts.push(`account ${op.accountId}`);
|
|
27078
|
+
}
|
|
27079
|
+
if (op.dependsOn.length > 0) {
|
|
27080
|
+
parts.push(`after ${op.dependsOn.join(", ")}`);
|
|
27081
|
+
}
|
|
27082
|
+
const result = resultPart(op);
|
|
27083
|
+
if (result) {
|
|
27084
|
+
parts.push(result);
|
|
27085
|
+
}
|
|
27086
|
+
return ` ${parts.join(" \xB7 ").replace(/[\r\n]+/g, " ")}`;
|
|
27087
|
+
}
|
|
27088
|
+
function renderDraftStatus3(draft) {
|
|
27089
|
+
if (draft.status === "none" || draft.count === 0) {
|
|
27090
|
+
return "No staged Meta changes on this chat.";
|
|
27091
|
+
}
|
|
27092
|
+
const lines = [headingLine(draft)];
|
|
27093
|
+
if (draft.status === "active") {
|
|
27094
|
+
lines.push("Publishing makes every change real on the ad account.");
|
|
27095
|
+
}
|
|
27096
|
+
lines.push("");
|
|
27097
|
+
const showAccount = new Set(draft.ops.map((op) => op.accountId)).size > 1;
|
|
27098
|
+
for (const op of draft.ops) {
|
|
27099
|
+
lines.push(opLine(op, showAccount));
|
|
27100
|
+
}
|
|
27101
|
+
if (draft.advisories.length > 0) {
|
|
27102
|
+
lines.push("", "Advisories");
|
|
27103
|
+
for (const advisory of draft.advisories) {
|
|
27104
|
+
lines.push(` ! ${advisory.ref}: ${advisory.message}`);
|
|
27105
|
+
}
|
|
27106
|
+
}
|
|
27107
|
+
lines.push("", "Full staged payload for one op: baker ads meta draft show <ref> \xB7 raw envelope: --json");
|
|
27108
|
+
return lines.join("\n");
|
|
27109
|
+
}
|
|
27110
|
+
|
|
27111
|
+
// src/commands/ads/meta/draft.ts
|
|
27112
|
+
registerSchema({
|
|
27113
|
+
command: "ads.meta.draft",
|
|
27114
|
+
description: "Review every Meta op staged on this chat, one line each: ref \xB7 kind \xB7 summary \xB7 what it waits on, and after a publish \u2713 applied \u2192 id or \u2717 failed: <error>. `draft show <ref>` prints one op's full payload.",
|
|
27115
|
+
args: {
|
|
27116
|
+
json: { type: "boolean", description: "Raw JSON envelope instead of the readable list", required: false },
|
|
27117
|
+
chat: { type: "string", description: "Read another chat's draft instead of this one", required: false }
|
|
27118
|
+
}
|
|
27119
|
+
});
|
|
27120
|
+
async function listDraft2(json, chat) {
|
|
27019
27121
|
try {
|
|
27020
27122
|
const chatId = resolveChatId(chat);
|
|
27021
27123
|
const response = await apiPost("/api/ads/meta/draft", { chatId });
|
|
27022
|
-
|
|
27124
|
+
if (json || !response.ok || !response.data) {
|
|
27125
|
+
writeJsonEnvelope(response);
|
|
27126
|
+
return;
|
|
27127
|
+
}
|
|
27128
|
+
process.stdout.write(`${renderDraftStatus3(response.data)}
|
|
27129
|
+
`);
|
|
27023
27130
|
} catch (err) {
|
|
27024
27131
|
handleMetaError(err);
|
|
27025
27132
|
}
|
|
@@ -27027,11 +27134,14 @@ async function listDraft2(chat) {
|
|
|
27027
27134
|
var listCommand10 = defineCommand65({
|
|
27028
27135
|
meta: {
|
|
27029
27136
|
name: "list",
|
|
27030
|
-
description: "Show every Meta write op staged in this chat,
|
|
27137
|
+
description: "Show every Meta write op staged in this chat, one line each (ref \xB7 kind \xB7 summary \xB7 dependencies \xB7 post-publish result); --json for the raw envelope. Publishing reaches the real ad account, so review this before you finish. Example: baker ads meta draft"
|
|
27138
|
+
},
|
|
27139
|
+
args: {
|
|
27140
|
+
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" },
|
|
27141
|
+
chat: CHAT_READ_ARG
|
|
27031
27142
|
},
|
|
27032
|
-
args: { chat: CHAT_READ_ARG },
|
|
27033
27143
|
run: async ({ args: args5 }) => {
|
|
27034
|
-
await listDraft2(args5.chat);
|
|
27144
|
+
await listDraft2(args5.json === true, args5.chat);
|
|
27035
27145
|
}
|
|
27036
27146
|
});
|
|
27037
27147
|
var showCommand2 = defineCommand65({
|
|
@@ -27101,7 +27211,10 @@ var metaDraftCommand = defineCommand65({
|
|
|
27101
27211
|
},
|
|
27102
27212
|
// Declared on the parent too: `default: "list"` dispatches the bare `draft --chat <id>` form, and
|
|
27103
27213
|
// citty prints help for a flag the parent does not know instead of forwarding it.
|
|
27104
|
-
args: {
|
|
27214
|
+
args: {
|
|
27215
|
+
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" },
|
|
27216
|
+
chat: CHAT_READ_ARG
|
|
27217
|
+
},
|
|
27105
27218
|
subCommands: { list: listCommand10, show: showCommand2, remove: removeCommand3, clear: clearCommand3 },
|
|
27106
27219
|
// `default` (not `run`) dispatches the bare invocation: citty falls through to `run`
|
|
27107
27220
|
// after dispatching a subcommand, so a `run` here would list the draft a second time
|
|
@@ -28914,7 +29027,7 @@ function renderNode3(node, depth, showAccount, out) {
|
|
|
28914
29027
|
}
|
|
28915
29028
|
}
|
|
28916
29029
|
var NO_CHANGES = "No X Ads changes staged";
|
|
28917
|
-
var
|
|
29030
|
+
var STATUS_HEADINGS2 = {
|
|
28918
29031
|
active: "staged",
|
|
28919
29032
|
publishing: "publishing",
|
|
28920
29033
|
applied: "published",
|
|
@@ -28926,8 +29039,8 @@ function didNotApply(op) {
|
|
|
28926
29039
|
function didApply(op) {
|
|
28927
29040
|
return op.result?.status === "applied" || op.result?.status === "simulated";
|
|
28928
29041
|
}
|
|
28929
|
-
function
|
|
28930
|
-
const heading =
|
|
29042
|
+
function headingLine2(draft) {
|
|
29043
|
+
const heading = STATUS_HEADINGS2[draft.status] ?? draft.status;
|
|
28931
29044
|
if (draft.status !== "applied" && draft.status !== "publishing") {
|
|
28932
29045
|
return `X Ads: ${draft.count} change${draft.count === 1 ? "" : "s"} ${heading}`;
|
|
28933
29046
|
}
|
|
@@ -28941,11 +29054,11 @@ function problemLines(draft) {
|
|
|
28941
29054
|
return `\u2717 ${op.summary} \u2014 failed: ${reason}`;
|
|
28942
29055
|
});
|
|
28943
29056
|
}
|
|
28944
|
-
function
|
|
29057
|
+
function renderDraftStatus4(draft) {
|
|
28945
29058
|
if (draft.status === "none" || draft.count === 0) {
|
|
28946
29059
|
return NO_CHANGES;
|
|
28947
29060
|
}
|
|
28948
|
-
const out = [
|
|
29061
|
+
const out = [headingLine2(draft), ""];
|
|
28949
29062
|
const tree = draft.tree ?? [];
|
|
28950
29063
|
const showAccount = accountsInTree3(tree).size > 1;
|
|
28951
29064
|
for (const node of tree) {
|
|
@@ -28983,7 +29096,7 @@ async function listDraft3(json, chat) {
|
|
|
28983
29096
|
writeJsonEnvelope(response);
|
|
28984
29097
|
return;
|
|
28985
29098
|
}
|
|
28986
|
-
process.stdout.write(`${
|
|
29099
|
+
process.stdout.write(`${renderDraftStatus4(response.data)}
|
|
28987
29100
|
`);
|
|
28988
29101
|
} catch (err) {
|
|
28989
29102
|
handleDraftError(err);
|