@koda-sl/baker-cli 0.354.0-dev.7687bbeae → 0.354.0-dev.9b7066502
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 -2
- package/dist/{chunk-NA5CPMUA.js → chunk-WJ5MYLLV.js} +14 -2
- package/dist/{chunk-NA5CPMUA.js.map → chunk-WJ5MYLLV.js.map} +1 -1
- package/dist/cli.js +18 -47
- package/dist/cli.js.map +1 -1
- package/dist/{shared-RYAF7Y7H.js → shared-4FS6FXCM.js} +4 -2
- package/package.json +1 -1
- /package/dist/{shared-RYAF7Y7H.js.map → shared-4FS6FXCM.js.map} +0 -0
package/README.md
CHANGED
|
@@ -696,7 +696,7 @@ Command groups: `budgets`, `campaigns`, `ad-groups`, `keywords` (add/update/remo
|
|
|
696
696
|
|
|
697
697
|
**Retiring a conversion action** — `status` accepts `ENABLED` and `REMOVED` only. Google denies `HIDDEN` on every conversion-action write, so to stop bidding toward an action while it keeps measuring use `--no-primary`, and to stop it counting at all use `"status": "REMOVED"`. Conversion actions **Google owns** cannot be changed at all — Smart campaign call/directions actions, the in-ad lead form's submit, YouTube subscriptions and follow-on views, Floodlight and Search Ads 360 imports, store visits, codeless webpage actions. Staging any edit to one, a rename included, is refused up front; there is no manual route either, since the Google Ads interface will not change them.
|
|
698
698
|
|
|
699
|
-
**Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Once the chat has published it reports the outcome instead — `published · N applied, M failed`, with a `✗` line naming each op that did not land and why
|
|
699
|
+
**Reviewing the draft** — `baker ads google draft list` renders everything you've staged as a grouped campaign ▸ ad group ▸ ad tree (with non-blocking completeness advisories), the CLI counterpart to the dashboard's Google Ads tab. Pass `--json` for the raw envelope. Once the chat has published it reports the outcome instead — `published · N applied, M failed`, with a `✗` line naming each op that did not land and why. Aim for a fully built campaign — 2–4 ad groups, ≥5 keywords each, 2–4 RSAs with 8–12 headlines, ≥4 sitelinks / ≥3 callouts / ≥1 structured snippet, and ≥1 shared negative list; the advisories flag what's still thin.
|
|
700
700
|
|
|
701
701
|
**Amending a staged op** — `draft amend <ref> (--file patch.json | --patch '<json>')` merges a JSON patch into an already-staged op's payload (objects deep-merge, `null` deletes a key, arrays/scalars replace) and re-validates it in full. Always prefer this over removing and re-staging — it preserves the op's ref (so dependents don't break) and its position in the draft. `draft show <ref>` prints the full staged payload (including warnings/annotations) so you can verify a change looks right before publish.
|
|
702
702
|
|
|
@@ -958,7 +958,7 @@ Status changes are `pause|resume|archive` subcommands on `campaigns`/`adsets`/`a
|
|
|
958
958
|
- Identity columns (`campaign_name`, `ad_name`, etc.) appended automatically per `--level` so rows are self-describing.
|
|
959
959
|
- Auto-async when the query is heavy (level=ad with breakdowns over an account, >2 breakdowns, >90-day range). Pass `--async` to force it or `--no-async` to refuse fallback.
|
|
960
960
|
|
|
961
|
-
**Listings (`campaigns`/`adsets`/`ads`)** default to `effective_status=ACTIVE` — pass `--all-statuses` to widen, or `--effective-status ACTIVE,PAUSED` for a custom set.
|
|
961
|
+
**Listings (`campaigns`/`adsets`/`ads`)** default to `effective_status=ACTIVE` — pass `--all-statuses` to widen, or `--effective-status ACTIVE,PAUSED` for a custom set. An empty filtered list carries a `hints` entry naming the filter and `--all-statuses`, so "nothing active" is never read as "nothing there".
|
|
962
962
|
|
|
963
963
|
**Pagination** is auto-drained (no manual cursor handling).
|
|
964
964
|
|
|
@@ -97,6 +97,17 @@ function resolveEffectiveStatus(args) {
|
|
|
97
97
|
}
|
|
98
98
|
return "ACTIVE";
|
|
99
99
|
}
|
|
100
|
+
function statusFilterHints(rows, effectiveStatus, noun) {
|
|
101
|
+
if (rows.length > 0 || effectiveStatus === void 0) return [];
|
|
102
|
+
if (effectiveStatus === "ACTIVE") {
|
|
103
|
+
return [
|
|
104
|
+
`No ACTIVE ${noun}. The ACTIVE filter hides paused, archived and in-review ones (under a paused campaign or ad set that is all of them), so this does NOT mean none exist. Re-run with --all-statuses before concluding there are none.`
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
return [
|
|
108
|
+
`No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`
|
|
109
|
+
];
|
|
110
|
+
}
|
|
100
111
|
|
|
101
112
|
export {
|
|
102
113
|
metaForbiddenFix,
|
|
@@ -106,6 +117,7 @@ export {
|
|
|
106
117
|
todayIso,
|
|
107
118
|
daysAgoIso,
|
|
108
119
|
csvOrJson,
|
|
109
|
-
resolveEffectiveStatus
|
|
120
|
+
resolveEffectiveStatus,
|
|
121
|
+
statusFilterHints
|
|
110
122
|
};
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
123
|
+
//# sourceMappingURL=chunk-WJ5MYLLV.js.map
|
|
@@ -1 +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 === \"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;AAAA,MACzD;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":[]}
|
|
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 === \"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\n/**\n * An empty listing under a status filter reads exactly like \"nothing exists\":\n * a paused campaign's ad sets are CAMPAIGN_PAUSED, so the ACTIVE default hides\n * every one of them. Say which filter produced the empty list and how to widen it.\n */\nexport function statusFilterHints(\n rows: ReadonlyArray<unknown>,\n effectiveStatus: string | undefined,\n noun: string,\n): string[] {\n if (rows.length > 0 || effectiveStatus === undefined) return [];\n if (effectiveStatus === \"ACTIVE\") {\n return [\n `No ACTIVE ${noun}. The ACTIVE filter hides paused, archived and in-review ones (under a paused campaign or ad set that is all of them), so this does NOT mean none exist. Re-run with --all-statuses before concluding there are none.`,\n ];\n }\n return [\n `No ${noun} with effective_status ${effectiveStatus}. Re-run with --all-statuses to see every status before concluding there are none.`,\n ];\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;AAAA,MACzD;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;AAOO,SAAS,kBACd,MACA,iBACA,MACU;AACV,MAAI,KAAK,SAAS,KAAK,oBAAoB,OAAW,QAAO,CAAC;AAC9D,MAAI,oBAAoB,UAAU;AAChC,WAAO;AAAA,MACL,aAAa,IAAI;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM,IAAI,0BAA0B,eAAe;AAAA,EACrD;AACF;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -76,8 +76,9 @@ import {
|
|
|
76
76
|
handleMetaError,
|
|
77
77
|
resolveAccountIdArg,
|
|
78
78
|
resolveEffectiveStatus,
|
|
79
|
+
statusFilterHints,
|
|
79
80
|
todayIso
|
|
80
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-WJ5MYLLV.js";
|
|
81
82
|
import {
|
|
82
83
|
buildQueryCacheKey,
|
|
83
84
|
cacheGet,
|
|
@@ -3569,10 +3570,7 @@ var googleDraftStatusNodeSchema = z6.lazy(
|
|
|
3569
3570
|
existing: z6.boolean(),
|
|
3570
3571
|
collections: z6.array(googleDraftStatusCollectionSchema),
|
|
3571
3572
|
children: z6.array(googleDraftStatusNodeSchema),
|
|
3572
|
-
warnings: z6.array(z6.string()).optional()
|
|
3573
|
-
result: googleDraftOpResultSchema.shape.status.optional(),
|
|
3574
|
-
foldedNotApplied: z6.object({ failed: z6.number(), skipped: z6.number() }).optional(),
|
|
3575
|
-
status: z6.string().optional()
|
|
3573
|
+
warnings: z6.array(z6.string()).optional()
|
|
3576
3574
|
})
|
|
3577
3575
|
);
|
|
3578
3576
|
var googleDraftListResponseSchema = z6.object({
|
|
@@ -11044,44 +11042,14 @@ var OPERATION_LABELS = {
|
|
|
11044
11042
|
update: "Updating",
|
|
11045
11043
|
pause: "Pausing",
|
|
11046
11044
|
resume: "Resuming",
|
|
11047
|
-
remove: "Removing"
|
|
11048
|
-
upload: "Uploading"
|
|
11049
|
-
};
|
|
11050
|
-
var APPLIED_LABELS = {
|
|
11051
|
-
create: "Created",
|
|
11052
|
-
update: "Updated",
|
|
11053
|
-
pause: "Paused",
|
|
11054
|
-
resume: "Resumed",
|
|
11055
|
-
remove: "Removed",
|
|
11056
|
-
upload: "Uploaded"
|
|
11045
|
+
remove: "Removing"
|
|
11057
11046
|
};
|
|
11058
|
-
function notAppliedText(node) {
|
|
11059
|
-
const { failed = 0, skipped = 0 } = node.foldedNotApplied ?? {};
|
|
11060
|
-
const changes = (n) => `${n} change${n === 1 ? "" : "s"}`;
|
|
11061
|
-
const parts = [
|
|
11062
|
-
...failed > 0 ? [`${changes(failed)} failed`] : [],
|
|
11063
|
-
...skipped > 0 ? [`${changes(skipped)} skipped`] : []
|
|
11064
|
-
];
|
|
11065
|
-
return parts.length > 0 ? parts.join(", ") : void 0;
|
|
11066
|
-
}
|
|
11067
|
-
function outcomeBadge(node, result) {
|
|
11068
|
-
const verb = node.operation ?? "update";
|
|
11069
|
-
if (result === "applied") {
|
|
11070
|
-
return node.operation ? APPLIED_LABELS[verb] ?? "Applied" : "Changes applied";
|
|
11071
|
-
}
|
|
11072
|
-
if (result === "simulated") {
|
|
11073
|
-
return `Simulated (${verb})`;
|
|
11074
|
-
}
|
|
11075
|
-
if (result === "failed") {
|
|
11076
|
-
return node.operation ? `Failed to ${verb}` : "Failed";
|
|
11077
|
-
}
|
|
11078
|
-
return "Skipped";
|
|
11079
|
-
}
|
|
11080
11047
|
function badge(node) {
|
|
11081
|
-
const label = node.
|
|
11082
|
-
|
|
11083
|
-
|
|
11084
|
-
|
|
11048
|
+
const label = node.operation ? OPERATION_LABELS[node.operation] : void 0;
|
|
11049
|
+
if (label) {
|
|
11050
|
+
return label;
|
|
11051
|
+
}
|
|
11052
|
+
return node.existing ? "on Google Ads" : "staged";
|
|
11085
11053
|
}
|
|
11086
11054
|
function collectionLine(collection) {
|
|
11087
11055
|
const parts = [];
|
|
@@ -11480,7 +11448,7 @@ var draftCommand2 = defineCommand22({
|
|
|
11480
11448
|
list: defineCommand22({
|
|
11481
11449
|
meta: {
|
|
11482
11450
|
name: "list",
|
|
11483
|
-
description: "Review everything staged as a campaign \u25B8 ad group \u25B8 ad tree
|
|
11451
|
+
description: "Review everything staged as a campaign \u25B8 ad group \u25B8 ad tree (--json for the raw envelope)"
|
|
11484
11452
|
},
|
|
11485
11453
|
args: {
|
|
11486
11454
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable tree" },
|
|
@@ -25499,7 +25467,7 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
25499
25467
|
const { apiPost: apiPost2 } = await import("./client-ODCNYCP4.js");
|
|
25500
25468
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
25501
25469
|
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-2XBCYF7L.js");
|
|
25502
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
25470
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-4FS6FXCM.js");
|
|
25503
25471
|
try {
|
|
25504
25472
|
const accountId = bareAccountId2(args5);
|
|
25505
25473
|
const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
|
|
@@ -25647,7 +25615,7 @@ function duplicateCommand2(entity, label) {
|
|
|
25647
25615
|
const { apiPost: apiPost2 } = await import("./client-ODCNYCP4.js");
|
|
25648
25616
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
25649
25617
|
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-2XBCYF7L.js");
|
|
25650
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
25618
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-4FS6FXCM.js");
|
|
25651
25619
|
try {
|
|
25652
25620
|
const accountId = bareAccountId2(args5);
|
|
25653
25621
|
const chatId = requireChatId2();
|
|
@@ -25712,7 +25680,8 @@ var listCommand4 = defineCommand58({
|
|
|
25712
25680
|
writeAdsOutput(data, fmt);
|
|
25713
25681
|
return;
|
|
25714
25682
|
}
|
|
25715
|
-
|
|
25683
|
+
const hints2 = statusFilterHints(data, effectiveStatus, "ads");
|
|
25684
|
+
writeJsonEnvelope(hints2.length > 0 ? { ok: true, data, hints: hints2 } : { ok: true, data });
|
|
25716
25685
|
} catch (err) {
|
|
25717
25686
|
handleMetaError(err);
|
|
25718
25687
|
}
|
|
@@ -25783,7 +25752,8 @@ var listCommand5 = defineCommand59({
|
|
|
25783
25752
|
writeAdsOutput(data, fmt);
|
|
25784
25753
|
return;
|
|
25785
25754
|
}
|
|
25786
|
-
|
|
25755
|
+
const hints2 = statusFilterHints(data, effectiveStatus, "ad sets");
|
|
25756
|
+
writeJsonEnvelope(hints2.length > 0 ? { ok: true, data, hints: hints2 } : { ok: true, data });
|
|
25787
25757
|
} catch (err) {
|
|
25788
25758
|
handleMetaError(err);
|
|
25789
25759
|
}
|
|
@@ -25933,7 +25903,8 @@ var listCommand7 = defineCommand62({
|
|
|
25933
25903
|
writeAdsOutput(data, fmt);
|
|
25934
25904
|
return;
|
|
25935
25905
|
}
|
|
25936
|
-
|
|
25906
|
+
const hints2 = statusFilterHints(data, effectiveStatus, "campaigns");
|
|
25907
|
+
writeJsonEnvelope(hints2.length > 0 ? { ok: true, data, hints: hints2 } : { ok: true, data });
|
|
25937
25908
|
} catch (err) {
|
|
25938
25909
|
handleMetaError(err);
|
|
25939
25910
|
}
|