@koda-sl/baker-cli 0.121.0-dev.ea15b0199 → 0.121.0-dev.fff192e73
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 +10 -13
- package/dist/cli.js +18 -303
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1142,7 +1142,7 @@ Notes:
|
|
|
1142
1142
|
- All write commands take `--file <json>` payloads; explicit flags override file keys. `baker schema ads.linkedin.campaigns.create` for exact args.
|
|
1143
1143
|
- Money flags (`--bid`, `--daily-budget`, `--total-budget`) require `--currency`.
|
|
1144
1144
|
- Creative media comes from the Baker library (`--image-id`/`--video-id` from `baker images`/`baker videos` — uploaded to LinkedIn at publish) or as LinkedIn URNs (`--image-urn`/`--video-urn`). Formats: `image|video|text|spotlight|follower|document|carousel|conversation|tla|jobs`; complex formats take `--file` with the full content object; conversation ads take `--file` with the message flow (`{message: {subject, body, senderName?, buttons[]}}` — buttons `NESTED` (with `nestedMessage`) or `LANDING_PAGE` (with `landingPageUrl`), ≤25 messages, bodies ≤500 chars, labels ≤25). Limits: headline ≤70, text-ad 25/75, intro soft-truncates at 600 chars. TLA sponsors an existing post via `--post-urn`.
|
|
1145
|
-
- Lead forms are file-first (`lead-forms create --file form.json`). Required: name, headline (≤60), privacyPolicyUrl, questions[] (≤12; playbook: ≤4 for completion). Each question is a predefined profile field (`{ name, predefinedField: "EMAIL" }` — Contact/Work/Company/Education/Demographic library) or a custom question (`{ name, questionType: "SINGLE_LINE_TEXT" | "MULTIPLE_CHOICE", options?: [...] }`; ≤3 custom, MULTIPLE_CHOICE needs 2–30 options). Also supported: `locale {country,language}`, `formImageId`/`formImageUrn` (banner), `
|
|
1145
|
+
- Lead forms are file-first (`lead-forms create --file form.json`). Required: name, headline (≤60), privacyPolicyUrl, questions[] (≤12; playbook: ≤4 for completion). Each question is a predefined profile field (`{ name, predefinedField: "EMAIL" }` — Contact/Work/Company/Education/Demographic library) or a custom question (`{ name, questionType: "SINGLE_LINE_TEXT" | "MULTIPLE_CHOICE", options?: [...] }`; ≤3 custom, MULTIPLE_CHOICE needs 2–30 options). Also supported: `locale {country,language}`, `formImageId`/`formImageUrn` (banner), `consents[]` (≤5 disclosure checkboxes `{text, required}`), `hiddenFields[]` (≤20 `{name, value}` tracking fields), `legalDisclaimer`, `thankYou {message, cta, landingUrl | appointmentUrl}` (Calendly/Chili Piper booking link). The staged preview emits non-blocking best-practice warnings when a form has no qualifying question, no confirmation message/action, or no consent checkbox.
|
|
1146
1146
|
|
|
1147
1147
|
#### `audit` — playbook diagnostic
|
|
1148
1148
|
|
|
@@ -2504,26 +2504,22 @@ Rules:
|
|
|
2504
2504
|
|
|
2505
2505
|
### Marketing Tags (`baker tags`)
|
|
2506
2506
|
|
|
2507
|
-
|
|
2507
|
+
Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, PostHog, …) — production tags overlaid with the changes staged in this chat.
|
|
2508
|
+
|
|
2509
|
+
**The CLI is read-only.** Every tag change (create, edit, delete) goes through the `request_tag_input` tool (`baker_ui` MCP server): the agent proposes one or more changes — each becomes a tab in one blocking approval form — pre-filling the non-secret fields it knows; the user reviews, edits, fills secret fields, and approves or skips each tab. Approved changes stage on the chat and apply when the chat is published; discarding the chat drops them.
|
|
2508
2510
|
|
|
2509
2511
|
`BAKER_CHAT_ID` must be set.
|
|
2510
2512
|
|
|
2511
2513
|
```bash
|
|
2512
|
-
baker tags list
|
|
2513
|
-
baker tags
|
|
2514
|
-
baker tags add meta --set pixelId=123 --request-secret accessToken
|
|
2515
|
-
baker tags update <ref> --set pixelId=999 --clear testEventCode
|
|
2516
|
-
baker tags remove <ref> # stage deletion (tag_temp_* ref drops the staged create)
|
|
2517
|
-
baker tags draft # review staged ops
|
|
2518
|
-
baker tags draft remove <ref> # drop one staged op
|
|
2519
|
-
baker tags draft clear # drop everything staged
|
|
2514
|
+
baker tags list # effective view: production + staged, with secret status
|
|
2515
|
+
baker tags draft # review the staged changes awaiting publish
|
|
2520
2516
|
```
|
|
2521
2517
|
|
|
2522
2518
|
Notes:
|
|
2523
2519
|
|
|
2524
|
-
- **Secrets never travel through this CLI.** Secret fields (`accessToken`, `apiSecret`, `authorizationToken`, `apiKey`, `conversionToken`, `oauthProviderId`) are
|
|
2525
|
-
- Staged creates get a server-generated `tag_temp_*` ref. Use it (or a real tag id) as flow side-effect `tagIds` — the published tag keeps resolving under the temp ref.
|
|
2526
|
-
-
|
|
2520
|
+
- **Secrets never travel through this CLI or the chat.** Secret fields (`accessToken`, `apiSecret`, `authorizationToken`, `apiKey`, `conversionToken`, `oauthProviderId`) are entered only in the dashboard's secure tag form and flow straight into the staged draft; tool responses only ever name which secret fields are set/pending.
|
|
2521
|
+
- Staged creates get a server-generated `tag_temp_*` ref (returned in the tool result and printed by `list`). Use it (or a real tag id) as flow side-effect `tagIds` — the published tag keeps resolving under the temp ref.
|
|
2522
|
+
- Proposing a delete on a `tag_temp_*` ref drops the staged create instead.
|
|
2527
2523
|
- Single-instance types (`code`, `posthog`, `datafast`) reject a second instance against the chat's effective view.
|
|
2528
2524
|
- Conflicts at publish (tag deleted in the dashboard, config invalid) skip the op with a recorded reason — they never block the publish.
|
|
2529
2525
|
|
|
@@ -4545,6 +4541,7 @@ This CLI is designed for AI agent consumption. Key patterns:
|
|
|
4545
4541
|
- **0.105.0**: `baker images ...`, `baker videos ...`, and `baker testimonials ...` commands now type their `/api/{images,videos,testimonials}/...` request/response payloads from the shared `@baker/api` contract package instead of hand-written local interfaces. No command, flag, or output-shape changes.
|
|
4546
4542
|
- **0.106.0**: `baker ads linkedin` gains staged write commands — `campaign-groups`/`campaigns`/`creatives` create|update|pause|resume|(archive|)duplicate, `audiences create|upload`, `conversions create|update`, `lead-forms create|update`, plus `draft [remove|clear]` for review/undo. Ops validate at stage time, apply on chat publish, and run simulated (`urn:li:simulated:*`) unless LinkedIn writes are enabled for the company.
|
|
4547
4543
|
- **0.116.0**: `lead-forms create` models the full Campaign Manager form — `locale`, form banner image (`formImageId`/`formImageUrn`), predefined profile-field questions (validated enum) vs custom questions (`SINGLE_LINE_TEXT`/`MULTIPLE_CHOICE` with `options`, ≤3 custom), `privacyPolicyText`, disclosure `consents[]` (≤5), tracking `hiddenFields[]` (≤20), and `thankYou` confirmation CTA + landing/appointment link. Staged preview surfaces best-practice warnings (no qualifying question, no confirmation, no consent). No breaking flag changes.
|
|
4544
|
+
- **0.121.0**: `lead-forms create` drops the `privacyPolicyText` field — LinkedIn's versioned lead-form API has no privacy-policy-text slot, so it was silently discarded on publish. Use `legalDisclaimer` (shown under the form) or `consents[]` (disclosure checkboxes) instead. (Companion backend fix: staged lead-form questions were serialized in a shape LinkedIn dropped — they now publish correctly, and the staged preview lists each question.)
|
|
4548
4545
|
- **0.119.0**: `draft amend`/`draft show` land on both `baker ads google` and `baker ads linkedin` — a generic JSON-merge-patch to update any staged op in place plus a full-payload receipt, replacing remove+recreate as the correction path. Google gains `assets update` and `asset-groups create|update` (Performance Max asset groups are now their own entity — `ads create --format performanceMaxAssetGroup` never worked and is gone); `ads create --format video` moves from a bare YouTube id to `--video-assets` refs (**breaking flag change** — stage the video as an asset first); `--format demandGen` gains `--image-assets`/`--square-image-assets`/`--logo-image-assets` and flag-building for headlines/descriptions. LinkedIn's `draft list` now renders a readable Campaign group ▸ Campaign ▸ Creative tree by default (`--json` for raw), `creatives update` gains `--campaign` (re-parent while staged), and `campaigns update` passes create-only fields (`--group`/`--type`/`--locale`/`--associated-entity`) through when amending a `li_temp_*` staged create instead of always stripping them.
|
|
4549
4546
|
|
|
4550
4547
|
## Publishing
|
package/dist/cli.js
CHANGED
|
@@ -848,7 +848,6 @@ var LINKEDIN_LIMITS = {
|
|
|
848
848
|
choiceOptionsMax: 30,
|
|
849
849
|
choiceOptionTextMax: 100,
|
|
850
850
|
thankYouMessageMax: 300,
|
|
851
|
-
privacyPolicyTextMax: 2e3,
|
|
852
851
|
legalDisclaimerMax: 2e3,
|
|
853
852
|
consentsMax: 5,
|
|
854
853
|
// Campaign Manager caps disclosure checkboxes at 5
|
|
@@ -1443,7 +1442,6 @@ var leadFormFields = {
|
|
|
1443
1442
|
/** Form language, e.g. { country: "US", language: "en" }. Defaults to the account locale on LinkedIn. */
|
|
1444
1443
|
locale: z2.object({ country: z2.string().length(2), language: z2.string().length(2) }).optional(),
|
|
1445
1444
|
privacyPolicyUrl: httpsUrlSchema,
|
|
1446
|
-
privacyPolicyText: z2.string().max(LEAD.privacyPolicyTextMax).optional(),
|
|
1447
1445
|
questions: z2.array(leadFormQuestionSchema).min(1).max(LEAD.questionsMax),
|
|
1448
1446
|
consents: z2.array(leadFormConsentSchema).max(LEAD.consentsMax).optional(),
|
|
1449
1447
|
hiddenFields: z2.array(leadFormHiddenFieldSchema).max(LEAD.hiddenFieldsMax).optional(),
|
|
@@ -1941,46 +1939,6 @@ var TAG_TYPES = [
|
|
|
1941
1939
|
"twitterAds"
|
|
1942
1940
|
];
|
|
1943
1941
|
var tagTypeSchema = z5.enum(TAG_TYPES);
|
|
1944
|
-
var TAG_SECRET_FIELDS = {
|
|
1945
|
-
meta: ["accessToken"],
|
|
1946
|
-
amplitude: [],
|
|
1947
|
-
googleAds: ["oauthProviderId", "customerAccountId", "customerId", "loginCustomerId"],
|
|
1948
|
-
tiktok: ["accessToken"],
|
|
1949
|
-
vwo: [],
|
|
1950
|
-
hotjar: [],
|
|
1951
|
-
clarity: [],
|
|
1952
|
-
pinterest: ["conversionToken"],
|
|
1953
|
-
code: [],
|
|
1954
|
-
googleAnalytics: ["apiSecret"],
|
|
1955
|
-
googleTagManager: ["authorizationToken"],
|
|
1956
|
-
hubspot: [],
|
|
1957
|
-
linkedinInsightTag: ["oauthProviderId"],
|
|
1958
|
-
onetrust: [],
|
|
1959
|
-
posthog: [],
|
|
1960
|
-
datafast: ["apiKey"],
|
|
1961
|
-
recaptcha: [],
|
|
1962
|
-
twitterAds: ["oauthProviderId"]
|
|
1963
|
-
};
|
|
1964
|
-
var TAG_REQUESTABLE_SECRET_FIELDS = {
|
|
1965
|
-
meta: ["accessToken"],
|
|
1966
|
-
amplitude: [],
|
|
1967
|
-
googleAds: ["oauthProviderId", "customerAccountId"],
|
|
1968
|
-
tiktok: ["accessToken"],
|
|
1969
|
-
vwo: [],
|
|
1970
|
-
hotjar: [],
|
|
1971
|
-
clarity: [],
|
|
1972
|
-
pinterest: ["conversionToken"],
|
|
1973
|
-
code: [],
|
|
1974
|
-
googleAnalytics: ["apiSecret"],
|
|
1975
|
-
googleTagManager: ["authorizationToken"],
|
|
1976
|
-
hubspot: [],
|
|
1977
|
-
linkedinInsightTag: ["oauthProviderId"],
|
|
1978
|
-
onetrust: [],
|
|
1979
|
-
posthog: [],
|
|
1980
|
-
datafast: ["apiKey"],
|
|
1981
|
-
recaptcha: [],
|
|
1982
|
-
twitterAds: ["oauthProviderId"]
|
|
1983
|
-
};
|
|
1984
1942
|
var tagDraftOpKindSchema = z5.enum(["create", "update", "delete"]);
|
|
1985
1943
|
var tagDraftOpViewSchema = z5.object({
|
|
1986
1944
|
/** `tag_temp_*` for staged creates; the real tag id for update/delete ops. */
|
|
@@ -2016,49 +1974,17 @@ var tagsEffectiveEntrySchema = z5.object({
|
|
|
2016
1974
|
});
|
|
2017
1975
|
var tagsListRequestSchema = z5.object({ chatId: z5.string() });
|
|
2018
1976
|
var tagsListResponseSchema = z5.object({ tags: z5.array(tagsEffectiveEntrySchema) });
|
|
2019
|
-
var tagsDraftStageRequestSchema = z5.discriminatedUnion("kind", [
|
|
2020
|
-
z5.object({
|
|
2021
|
-
kind: z5.literal("create"),
|
|
2022
|
-
chatId: z5.string(),
|
|
2023
|
-
type: tagTypeSchema,
|
|
2024
|
-
config: z5.record(z5.string(), z5.string()),
|
|
2025
|
-
requestSecrets: z5.array(z5.string()).optional(),
|
|
2026
|
-
summary: z5.string().optional()
|
|
2027
|
-
}),
|
|
2028
|
-
z5.object({
|
|
2029
|
-
kind: z5.literal("update"),
|
|
2030
|
-
chatId: z5.string(),
|
|
2031
|
-
ref: z5.string(),
|
|
2032
|
-
config: z5.record(z5.string(), z5.string()).optional(),
|
|
2033
|
-
clearFields: z5.array(z5.string()).optional(),
|
|
2034
|
-
requestSecrets: z5.array(z5.string()).optional(),
|
|
2035
|
-
summary: z5.string().optional()
|
|
2036
|
-
}),
|
|
2037
|
-
z5.object({
|
|
2038
|
-
kind: z5.literal("delete"),
|
|
2039
|
-
chatId: z5.string(),
|
|
2040
|
-
ref: z5.string()
|
|
2041
|
-
})
|
|
2042
|
-
]);
|
|
2043
|
-
var tagsDraftStageResponseSchema = z5.object({
|
|
2044
|
-
/** Null when the request dissolved a staged create (delete/clearing an unpublished temp ref). */
|
|
2045
|
-
op: tagDraftOpViewSchema.nullable(),
|
|
2046
|
-
/** True when a `delete <tag_temp_*>` dropped the staged create instead of staging a delete. */
|
|
2047
|
-
removedStagedCreate: z5.boolean().optional()
|
|
2048
|
-
});
|
|
2049
1977
|
var tagsDraftListRequestSchema = z5.object({ chatId: z5.string() });
|
|
2050
1978
|
var tagsDraftListResponseSchema = z5.object({
|
|
2051
1979
|
status: z5.enum(["active", "publishing", "applied", "discarded", "none"]),
|
|
2052
1980
|
ops: z5.array(tagDraftOpViewSchema)
|
|
2053
1981
|
});
|
|
2054
|
-
var tagsDraftRemoveRequestSchema = z5.object({ chatId: z5.string(), ref: z5.string() });
|
|
2055
|
-
var tagsDraftRemoveResponseSchema = z5.object({ removed: z5.boolean() });
|
|
2056
|
-
var tagsDraftClearRequestSchema = z5.object({ chatId: z5.string() });
|
|
2057
|
-
var tagsDraftClearResponseSchema = z5.object({ cleared: z5.number() });
|
|
2058
1982
|
var tagInputRequestSchema = z5.object({
|
|
2059
|
-
|
|
1983
|
+
// Every tag change is a tab in the approval form: create/edit show the full
|
|
1984
|
+
// body; delete shows a confirm. No tag change bypasses this approval.
|
|
1985
|
+
mode: z5.enum(["create", "edit", "delete"]),
|
|
2060
1986
|
tagType: tagTypeSchema,
|
|
2061
|
-
/** Edit mode — the real tag id or `tag_temp_*` ref being
|
|
1987
|
+
/** Edit/delete mode — the real tag id or `tag_temp_*` ref being changed. */
|
|
2062
1988
|
ref: z5.string().optional(),
|
|
2063
1989
|
/** Non-secret values the agent proposes to prefill. Secret keys are stripped at every boundary. */
|
|
2064
1990
|
prefilledConfig: z5.record(z5.string(), z5.string()).optional(),
|
|
@@ -2067,6 +1993,9 @@ var tagInputRequestSchema = z5.object({
|
|
|
2067
1993
|
/** Short message shown above the form explaining why the input is needed. */
|
|
2068
1994
|
message: z5.string().optional()
|
|
2069
1995
|
});
|
|
1996
|
+
var tagChangeToolInputSchema = z5.object({
|
|
1997
|
+
changes: z5.array(tagInputRequestSchema).min(1).max(8)
|
|
1998
|
+
});
|
|
2070
1999
|
var tagInputResultSchema = z5.discriminatedUnion("status", [
|
|
2071
2000
|
z5.object({
|
|
2072
2001
|
status: z5.literal("submitted"),
|
|
@@ -2082,6 +2011,9 @@ var tagInputResultSchema = z5.discriminatedUnion("status", [
|
|
|
2082
2011
|
reason: z5.string().optional()
|
|
2083
2012
|
})
|
|
2084
2013
|
]);
|
|
2014
|
+
var tagChangeToolResultSchema = z5.object({
|
|
2015
|
+
results: z5.array(tagInputResultSchema)
|
|
2016
|
+
});
|
|
2085
2017
|
|
|
2086
2018
|
// ../api/src/testimonials.ts
|
|
2087
2019
|
import { z as z6 } from "zod";
|
|
@@ -9548,7 +9480,7 @@ var leadFormsCreateCommand = defineCommand38({
|
|
|
9548
9480
|
Required: name, headline (\u226460), privacyPolicyUrl, questions[] (\u226412; playbook: \u22644 for completion).
|
|
9549
9481
|
Each question is a predefined profile field ({ name, predefinedField: "EMAIL" }) or a custom question ({ name, questionType: "MULTIPLE_CHOICE", options: [...] }; \u22643 custom).
|
|
9550
9482
|
Best-practice fields the preview will nudge for if missing: 1-3 qualifying questions, consents[] (disclosure checkboxes), thankYou.message + thankYou.landingUrl|appointmentUrl.
|
|
9551
|
-
Also supported: locale, formImageId|formImageUrn,
|
|
9483
|
+
Also supported: locale, formImageId|formImageUrn, hiddenFields[], legalDisclaimer, thankYou.cta. Example: baker ads linkedin lead-forms create --file form.json`
|
|
9552
9484
|
},
|
|
9553
9485
|
args: {
|
|
9554
9486
|
...accountArgs,
|
|
@@ -23984,10 +23916,6 @@ var schemaCommand = defineCommand147({
|
|
|
23984
23916
|
import { defineCommand as defineCommand148 } from "citty";
|
|
23985
23917
|
|
|
23986
23918
|
// src/commands/tags/shared.ts
|
|
23987
|
-
function failValidation3(message) {
|
|
23988
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
23989
|
-
process.exit(1);
|
|
23990
|
-
}
|
|
23991
23919
|
function failApi3(err) {
|
|
23992
23920
|
if (err instanceof ApiError) {
|
|
23993
23921
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
@@ -24000,53 +23928,6 @@ function failApi3(err) {
|
|
|
24000
23928
|
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
24001
23929
|
process.exit(1);
|
|
24002
23930
|
}
|
|
24003
|
-
function parseTagType(value) {
|
|
24004
|
-
const parsed = tagTypeSchema.safeParse(value);
|
|
24005
|
-
if (!parsed.success) {
|
|
24006
|
-
failValidation3(`Unknown tag type "${value}". Valid types: ${TAG_TYPES.join(", ")}.`);
|
|
24007
|
-
}
|
|
24008
|
-
return parsed.data;
|
|
24009
|
-
}
|
|
24010
|
-
function toArray(value) {
|
|
24011
|
-
if (value === void 0 || typeof value === "boolean") {
|
|
24012
|
-
return [];
|
|
24013
|
-
}
|
|
24014
|
-
return Array.isArray(value) ? value : [value];
|
|
24015
|
-
}
|
|
24016
|
-
function parseSetArgs(value) {
|
|
24017
|
-
const config = {};
|
|
24018
|
-
for (const entry of toArray(value)) {
|
|
24019
|
-
const eq = entry.indexOf("=");
|
|
24020
|
-
if (eq <= 0) {
|
|
24021
|
-
failValidation3(`--set expects key=value, got "${entry}".`);
|
|
24022
|
-
}
|
|
24023
|
-
config[entry.slice(0, eq)] = entry.slice(eq + 1);
|
|
24024
|
-
}
|
|
24025
|
-
return config;
|
|
24026
|
-
}
|
|
24027
|
-
function parseListArg(value) {
|
|
24028
|
-
return toArray(value).flatMap(
|
|
24029
|
-
(entry) => entry.split(",").map((item) => item.trim()).filter((item) => item !== "")
|
|
24030
|
-
);
|
|
24031
|
-
}
|
|
24032
|
-
function rejectSecretSets(type, config) {
|
|
24033
|
-
const secretFields = TAG_SECRET_FIELDS[type];
|
|
24034
|
-
const offending = Object.keys(config).filter((key) => secretFields.includes(key));
|
|
24035
|
-
if (offending.length > 0) {
|
|
24036
|
-
failValidation3(
|
|
24037
|
-
`${offending.join(", ")} ${offending.length === 1 ? "is a secret field" : "are secret fields"} \u2014 never pass secret values on the command line. Re-run with --request-secret ${offending[0]} and the user will provide it via the secure tag form in the chat.`
|
|
24038
|
-
);
|
|
24039
|
-
}
|
|
24040
|
-
}
|
|
24041
|
-
function validateRequestSecrets(type, fields) {
|
|
24042
|
-
const requestable = TAG_REQUESTABLE_SECRET_FIELDS[type];
|
|
24043
|
-
const invalid = fields.filter((field) => !requestable.includes(field));
|
|
24044
|
-
if (invalid.length > 0) {
|
|
24045
|
-
failValidation3(
|
|
24046
|
-
`Cannot request ${invalid.join(", ")} for a ${type} tag. Requestable secret fields: ${requestable.length > 0 ? requestable.join(", ") : "(none \u2014 this type has no secret fields)"}.`
|
|
24047
|
-
);
|
|
24048
|
-
}
|
|
24049
|
-
}
|
|
24050
23931
|
function renderEffectiveEntry(entry) {
|
|
24051
23932
|
const parts = [entry.ref, entry.type];
|
|
24052
23933
|
if (entry.identifier !== void 0) {
|
|
@@ -24068,47 +23949,11 @@ function renderEffectiveEntry(entry) {
|
|
|
24068
23949
|
// src/commands/tags/index.ts
|
|
24069
23950
|
registerSchema({
|
|
24070
23951
|
command: "tags.list",
|
|
24071
|
-
description: "Effective marketing tags for this chat: production tags overlaid with the
|
|
23952
|
+
description: "Effective marketing tags for this chat: production tags overlaid with the changes staged in this chat. The printed refs (tag ids or tag_temp_*) are exactly what flow side-effect tagIds should reference. Read-only \u2014 every tag change (create, edit, delete) goes through the request_tag_input approval tool.",
|
|
24072
23953
|
args: {
|
|
24073
23954
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list", required: false }
|
|
24074
23955
|
}
|
|
24075
23956
|
});
|
|
24076
|
-
registerSchema({
|
|
24077
|
-
command: "tags.add",
|
|
24078
|
-
description: "Stage creation of a marketing tag (applies when the chat publishes). Set every non-secret field with --set; request secret fields (API keys, tokens, OAuth connections) with --request-secret \u2014 the user provides them via the secure tag form in the chat, never through the CLI.",
|
|
24079
|
-
args: {
|
|
24080
|
-
type: {
|
|
24081
|
-
type: "positional",
|
|
24082
|
-
description: "Tag type (see `baker tags list` output / meta, googleAnalytics, clarity, \u2026)",
|
|
24083
|
-
required: true
|
|
24084
|
-
},
|
|
24085
|
-
set: { type: "string", description: "Repeatable key=value for non-secret config fields", required: false },
|
|
24086
|
-
"request-secret": {
|
|
24087
|
-
type: "string",
|
|
24088
|
-
description: "Repeatable secret field name to request from the user",
|
|
24089
|
-
required: false
|
|
24090
|
-
}
|
|
24091
|
-
}
|
|
24092
|
-
});
|
|
24093
|
-
registerSchema({
|
|
24094
|
-
command: "tags.update",
|
|
24095
|
-
description: "Stage an update to a tag by ref (real tag id, or tag_temp_* to amend a create staged in this chat). --set patches fields, --clear removes them, --request-secret asks the user for secret values.",
|
|
24096
|
-
args: {
|
|
24097
|
-
ref: { type: "positional", description: "Tag ref from `baker tags list`", required: true },
|
|
24098
|
-
set: { type: "string", description: "Repeatable key=value for non-secret config fields", required: false },
|
|
24099
|
-
clear: { type: "string", description: "Repeatable field name to clear", required: false },
|
|
24100
|
-
"request-secret": {
|
|
24101
|
-
type: "string",
|
|
24102
|
-
description: "Repeatable secret field name to request from the user",
|
|
24103
|
-
required: false
|
|
24104
|
-
}
|
|
24105
|
-
}
|
|
24106
|
-
});
|
|
24107
|
-
registerSchema({
|
|
24108
|
-
command: "tags.remove",
|
|
24109
|
-
description: "Stage deletion of a tag by ref (applies on publish). Removing a tag_temp_* ref drops the staged create instead.",
|
|
24110
|
-
args: { ref: { type: "positional", description: "Tag ref from `baker tags list`", required: true } }
|
|
24111
|
-
});
|
|
24112
23957
|
async function listTags(json) {
|
|
24113
23958
|
try {
|
|
24114
23959
|
const chatId = requireChatId();
|
|
@@ -24118,7 +23963,7 @@ async function listTags(json) {
|
|
|
24118
23963
|
return;
|
|
24119
23964
|
}
|
|
24120
23965
|
if (response.tags.length === 0) {
|
|
24121
|
-
process.stdout.write("No tags configured.
|
|
23966
|
+
process.stdout.write("No tags configured. Propose one with the request_tag_input tool (baker_ui).\n");
|
|
24122
23967
|
return;
|
|
24123
23968
|
}
|
|
24124
23969
|
process.stdout.write(`${response.tags.map(renderEffectiveEntry).join("\n")}
|
|
@@ -24137,84 +23982,6 @@ var listCommand7 = defineCommand148({
|
|
|
24137
23982
|
await listTags(args.json === true);
|
|
24138
23983
|
}
|
|
24139
23984
|
});
|
|
24140
|
-
async function stage(body) {
|
|
24141
|
-
try {
|
|
24142
|
-
const response = await apiPost("/api/tags/draft/stage", body);
|
|
24143
|
-
writeJson({ ok: true, data: response });
|
|
24144
|
-
} catch (err) {
|
|
24145
|
-
failApi3(err);
|
|
24146
|
-
}
|
|
24147
|
-
}
|
|
24148
|
-
var addCommand2 = defineCommand148({
|
|
24149
|
-
meta: {
|
|
24150
|
-
name: "add",
|
|
24151
|
-
description: "Stage a new tag (applies on publish). Secret fields are never passed here \u2014 use --request-secret and the user fills them in the chat's secure tag form. Example: baker tags add meta --set pixelId=123456 --request-secret accessToken"
|
|
24152
|
-
},
|
|
24153
|
-
args: {
|
|
24154
|
-
type: {
|
|
24155
|
-
type: "positional",
|
|
24156
|
-
description: "Tag type (meta, googleAnalytics, googleAds, clarity, \u2026)",
|
|
24157
|
-
required: true
|
|
24158
|
-
},
|
|
24159
|
-
set: { type: "string", description: "key=value for a non-secret config field (repeatable)" },
|
|
24160
|
-
"request-secret": { type: "string", description: "Secret field name the user should provide (repeatable)" }
|
|
24161
|
-
},
|
|
24162
|
-
run: async ({ args }) => {
|
|
24163
|
-
const type = parseTagType(args.type);
|
|
24164
|
-
const config = parseSetArgs(args.set);
|
|
24165
|
-
const requestSecrets = parseListArg(args["request-secret"]);
|
|
24166
|
-
rejectSecretSets(type, config);
|
|
24167
|
-
validateRequestSecrets(type, requestSecrets);
|
|
24168
|
-
const chatId = requireChatId();
|
|
24169
|
-
await stage({
|
|
24170
|
-
kind: "create",
|
|
24171
|
-
chatId,
|
|
24172
|
-
type,
|
|
24173
|
-
config,
|
|
24174
|
-
...requestSecrets.length > 0 ? { requestSecrets } : {}
|
|
24175
|
-
});
|
|
24176
|
-
}
|
|
24177
|
-
});
|
|
24178
|
-
var updateCommand3 = defineCommand148({
|
|
24179
|
-
meta: {
|
|
24180
|
-
name: "update",
|
|
24181
|
-
description: "Stage an update to a tag. A tag_temp_* ref amends the create staged in this chat. Example: baker tags update <ref> --set pixelId=999 --clear testEventCode"
|
|
24182
|
-
},
|
|
24183
|
-
args: {
|
|
24184
|
-
ref: { type: "positional", description: "Tag ref from `baker tags list`", required: true },
|
|
24185
|
-
set: { type: "string", description: "key=value patch for a non-secret config field (repeatable)" },
|
|
24186
|
-
clear: { type: "string", description: "Field name to clear (repeatable)" },
|
|
24187
|
-
"request-secret": { type: "string", description: "Secret field name the user should provide (repeatable)" }
|
|
24188
|
-
},
|
|
24189
|
-
run: async ({ args }) => {
|
|
24190
|
-
const config = parseSetArgs(args.set);
|
|
24191
|
-
const clearFields = parseListArg(args.clear);
|
|
24192
|
-
const requestSecrets = parseListArg(args["request-secret"]);
|
|
24193
|
-
if (Object.keys(config).length === 0 && clearFields.length === 0 && requestSecrets.length === 0) {
|
|
24194
|
-
failValidation3("Nothing to update \u2014 pass --set, --clear, or --request-secret.");
|
|
24195
|
-
}
|
|
24196
|
-
const chatId = requireChatId();
|
|
24197
|
-
await stage({
|
|
24198
|
-
kind: "update",
|
|
24199
|
-
chatId,
|
|
24200
|
-
ref: args.ref,
|
|
24201
|
-
...Object.keys(config).length > 0 ? { config } : {},
|
|
24202
|
-
...clearFields.length > 0 ? { clearFields } : {},
|
|
24203
|
-
...requestSecrets.length > 0 ? { requestSecrets } : {}
|
|
24204
|
-
});
|
|
24205
|
-
}
|
|
24206
|
-
});
|
|
24207
|
-
var removeCommand5 = defineCommand148({
|
|
24208
|
-
meta: {
|
|
24209
|
-
name: "remove",
|
|
24210
|
-
description: "Stage deletion of a tag (applies on publish). Removing a tag_temp_* ref drops the staged create instead. Example: baker tags remove <ref>"
|
|
24211
|
-
},
|
|
24212
|
-
args: { ref: { type: "positional", description: "Tag ref from `baker tags list`", required: true } },
|
|
24213
|
-
run: async ({ args }) => {
|
|
24214
|
-
const chatId = requireChatId();
|
|
24215
|
-
await stage({ kind: "delete", chatId, ref: args.ref });
|
|
24216
|
-
}
|
|
24217
|
-
});
|
|
24218
23985
|
async function listDraft3() {
|
|
24219
23986
|
try {
|
|
24220
23987
|
const chatId = requireChatId();
|
|
@@ -24224,55 +23991,10 @@ async function listDraft3() {
|
|
|
24224
23991
|
failApi3(err);
|
|
24225
23992
|
}
|
|
24226
23993
|
}
|
|
24227
|
-
var draftListCommand = defineCommand148({
|
|
24228
|
-
meta: { name: "list", description: "Review the tag ops staged in this chat. Example: baker tags draft" },
|
|
24229
|
-
run: async () => {
|
|
24230
|
-
await listDraft3();
|
|
24231
|
-
}
|
|
24232
|
-
});
|
|
24233
|
-
var draftRemoveCommand = defineCommand148({
|
|
24234
|
-
meta: {
|
|
24235
|
-
name: "remove",
|
|
24236
|
-
description: "Drop one staged tag op by ref. Example: baker tags draft remove tag_temp_abc123"
|
|
24237
|
-
},
|
|
24238
|
-
args: { ref: { type: "positional", description: "Staged op ref", required: true } },
|
|
24239
|
-
run: async ({ args }) => {
|
|
24240
|
-
try {
|
|
24241
|
-
const chatId = requireChatId();
|
|
24242
|
-
const response = await apiPost("/api/tags/draft/remove", {
|
|
24243
|
-
chatId,
|
|
24244
|
-
ref: args.ref
|
|
24245
|
-
});
|
|
24246
|
-
writeJson({ ok: true, data: response });
|
|
24247
|
-
} catch (err) {
|
|
24248
|
-
failApi3(err);
|
|
24249
|
-
}
|
|
24250
|
-
}
|
|
24251
|
-
});
|
|
24252
|
-
var draftClearCommand = defineCommand148({
|
|
24253
|
-
meta: {
|
|
24254
|
-
name: "clear",
|
|
24255
|
-
description: "Drop ALL tag ops staged in this chat \u2014 nothing will apply on publish. Example: baker tags draft clear"
|
|
24256
|
-
},
|
|
24257
|
-
run: async () => {
|
|
24258
|
-
try {
|
|
24259
|
-
const chatId = requireChatId();
|
|
24260
|
-
const response = await apiPost("/api/tags/draft/clear", { chatId });
|
|
24261
|
-
writeJson({ ok: true, data: response });
|
|
24262
|
-
} catch (err) {
|
|
24263
|
-
failApi3(err);
|
|
24264
|
-
}
|
|
24265
|
-
}
|
|
24266
|
-
});
|
|
24267
23994
|
var draftCommand3 = defineCommand148({
|
|
24268
23995
|
meta: {
|
|
24269
23996
|
name: "draft",
|
|
24270
|
-
description: "Review
|
|
24271
|
-
},
|
|
24272
|
-
subCommands: {
|
|
24273
|
-
list: draftListCommand,
|
|
24274
|
-
remove: draftRemoveCommand,
|
|
24275
|
-
clear: draftClearCommand
|
|
23997
|
+
description: "Review the tag changes staged in this chat (read-only). Staged changes were approved via request_tag_input and apply when the chat is published; to amend or drop one, propose a follow-up change through the same tool (a delete on a tag_temp_* ref drops the staged create)."
|
|
24276
23998
|
},
|
|
24277
23999
|
run: async () => {
|
|
24278
24000
|
await listDraft3();
|
|
@@ -24281,25 +24003,18 @@ var draftCommand3 = defineCommand148({
|
|
|
24281
24003
|
var tagsCommand3 = defineCommand148({
|
|
24282
24004
|
meta: {
|
|
24283
24005
|
name: "tags",
|
|
24284
|
-
description: `
|
|
24006
|
+
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.
|
|
24285
24007
|
|
|
24286
|
-
|
|
24008
|
+
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.
|
|
24287
24009
|
|
|
24288
24010
|
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.
|
|
24289
24011
|
|
|
24290
24012
|
Examples:
|
|
24291
|
-
baker tags list
|
|
24292
|
-
baker tags
|
|
24293
|
-
baker tags add meta --set pixelId=123 --request-secret accessToken
|
|
24294
|
-
baker tags update <ref> --set pixelId=999 --clear testEventCode
|
|
24295
|
-
baker tags remove <ref> # stage deletion (temp ref = drop the create)
|
|
24296
|
-
baker tags draft # review staged ops before finishing`
|
|
24013
|
+
baker tags list # production + staged, with secret status
|
|
24014
|
+
baker tags draft # review the staged changes awaiting publish`
|
|
24297
24015
|
},
|
|
24298
24016
|
subCommands: {
|
|
24299
24017
|
list: listCommand7,
|
|
24300
|
-
add: addCommand2,
|
|
24301
|
-
update: updateCommand3,
|
|
24302
|
-
remove: removeCommand5,
|
|
24303
24018
|
draft: draftCommand3
|
|
24304
24019
|
},
|
|
24305
24020
|
run: async () => {
|