@koda-sl/baker-cli 0.151.0-dev.1a051172a → 0.151.0-dev.4932063cd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -33
- package/dist/{chunk-JBDSJZBZ.js → chunk-S43JQWI2.js} +92 -14
- package/dist/chunk-S43JQWI2.js.map +1 -0
- package/dist/cli.js +483 -970
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-JBDSJZBZ.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
toModelSafeImage,
|
|
37
37
|
ulid,
|
|
38
38
|
validateCanvasDeep
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-S43JQWI2.js";
|
|
40
40
|
import {
|
|
41
41
|
csvOrJson,
|
|
42
42
|
daysAgoIso,
|
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
} from "./chunk-RK67WL4O.js";
|
|
76
76
|
|
|
77
77
|
// src/cli.ts
|
|
78
|
-
import { defineCommand as
|
|
78
|
+
import { defineCommand as defineCommand178, runMain } from "citty";
|
|
79
79
|
|
|
80
80
|
// src/commands/actions/index.ts
|
|
81
81
|
import { defineCommand as defineCommand18 } from "citty";
|
|
@@ -4042,21 +4042,11 @@ var FIELD_DESCRIPTIONS = {
|
|
|
4042
4042
|
"asset_group.status": "ENABLED, PAUSED, or REMOVED",
|
|
4043
4043
|
"asset_group_asset.field_type": "Where the asset is used (HEADLINE, DESCRIPTION, LOGO, etc.)",
|
|
4044
4044
|
"asset_group_asset.performance_label": "Performance rating: BEST, GOOD, LOW, LEARNING",
|
|
4045
|
-
// Change events
|
|
4045
|
+
// Change events
|
|
4046
4046
|
"change_event.change_date_time": "When the change occurred (ISO 8601)",
|
|
4047
4047
|
"change_event.change_resource_type": "What was changed: CAMPAIGN, AD_GROUP, AD, etc.",
|
|
4048
4048
|
"change_event.resource_change_operation": "CREATE, UPDATE, or REMOVE",
|
|
4049
4049
|
"change_event.user_email": "Email of user who made the change",
|
|
4050
|
-
// Change status (which resources changed, last 90 days — no values, no user)
|
|
4051
|
-
"change_status.last_change_date_time": "When this resource last changed (ISO 8601)",
|
|
4052
|
-
"change_status.resource_type": "What changed: CAMPAIGN, AD_GROUP, AD_GROUP_AD, AD_GROUP_CRITERION, etc.",
|
|
4053
|
-
"change_status.resource_status": "ADDED, CHANGED, or REMOVED \u2014 not the old or new value",
|
|
4054
|
-
"change_status.resource_name": "Identifier of the changed resource; query it to read its current values",
|
|
4055
|
-
"change_status.campaign": "Resource name of the campaign the change belongs to",
|
|
4056
|
-
"change_status.ad_group": "Resource name of the ad group the change belongs to",
|
|
4057
|
-
"change_status.ad_group_ad": "Resource name of the changed ad",
|
|
4058
|
-
"change_status.ad_group_criterion": "Resource name of the changed keyword or criterion",
|
|
4059
|
-
"change_status.campaign_criterion": "Resource name of the changed campaign-level criterion",
|
|
4060
4050
|
// Landing pages
|
|
4061
4051
|
"landing_page_view.unexpanded_final_url": "Landing page URL",
|
|
4062
4052
|
// Geo
|
|
@@ -4074,89 +4064,6 @@ function getFieldDescriptions(fields) {
|
|
|
4074
4064
|
return result;
|
|
4075
4065
|
}
|
|
4076
4066
|
|
|
4077
|
-
// src/commands/ads/google/changes-window.ts
|
|
4078
|
-
var CHANGE_SCOPE_MAX_DAYS = {
|
|
4079
|
-
detail: 30,
|
|
4080
|
-
summary: 90
|
|
4081
|
-
};
|
|
4082
|
-
var DEFAULT_CHANGE_DAYS = 7;
|
|
4083
|
-
function isChangeScope(value) {
|
|
4084
|
-
return value === "detail" || value === "summary";
|
|
4085
|
-
}
|
|
4086
|
-
function resolveChangesWindow(input) {
|
|
4087
|
-
const scope = input.scope ?? "detail";
|
|
4088
|
-
if (!isChangeScope(scope)) {
|
|
4089
|
-
return {
|
|
4090
|
-
ok: false,
|
|
4091
|
-
error: {
|
|
4092
|
-
code: "INVALID_SCOPE",
|
|
4093
|
-
message: `Unknown scope '${scope}'. Use 'detail' (field-level changes, 30 days) or 'summary' (which resources changed, 90 days).`,
|
|
4094
|
-
fix: {
|
|
4095
|
-
action: "retry_with_flag",
|
|
4096
|
-
explanation: "Pass --scope detail or --scope summary."
|
|
4097
|
-
}
|
|
4098
|
-
}
|
|
4099
|
-
};
|
|
4100
|
-
}
|
|
4101
|
-
const days = input.days ?? DEFAULT_CHANGE_DAYS;
|
|
4102
|
-
if (!Number.isInteger(days) || days < 1) {
|
|
4103
|
-
return {
|
|
4104
|
-
ok: false,
|
|
4105
|
-
error: {
|
|
4106
|
-
code: "INVALID_LOOKBACK",
|
|
4107
|
-
message: `--days must be a whole number of days, got '${days}'.`,
|
|
4108
|
-
fix: {
|
|
4109
|
-
action: "retry_with_flag",
|
|
4110
|
-
explanation: `Pass --days as a positive integer, e.g. --days ${DEFAULT_CHANGE_DAYS}.`
|
|
4111
|
-
}
|
|
4112
|
-
}
|
|
4113
|
-
};
|
|
4114
|
-
}
|
|
4115
|
-
const max = CHANGE_SCOPE_MAX_DAYS[scope];
|
|
4116
|
-
if (days > max) {
|
|
4117
|
-
return { ok: false, error: lookbackTooLong(scope, days, max) };
|
|
4118
|
-
}
|
|
4119
|
-
return { ok: true, scope, days, hints: hintsFor(scope, days) };
|
|
4120
|
-
}
|
|
4121
|
-
function lookbackTooLong(scope, days, max) {
|
|
4122
|
-
if (scope === "detail" && days <= CHANGE_SCOPE_MAX_DAYS.summary) {
|
|
4123
|
-
return {
|
|
4124
|
-
code: "LOOKBACK_TOO_LONG",
|
|
4125
|
-
message: `Google keeps field-level change detail for ${max} days only; ${days} days is outside that window.`,
|
|
4126
|
-
fix: {
|
|
4127
|
-
action: "narrow_date_range",
|
|
4128
|
-
explanation: `Re-run with --scope summary --days ${days} to reach back ${CHANGE_SCOPE_MAX_DAYS.summary} days. Summary tells you which campaigns, ad groups, ads and criteria changed and when, but not the old and new values \u2014 read the resource itself for current values.`
|
|
4129
|
-
}
|
|
4130
|
-
};
|
|
4131
|
-
}
|
|
4132
|
-
return {
|
|
4133
|
-
code: "LOOKBACK_TOO_LONG",
|
|
4134
|
-
message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days} days is outside that window.`,
|
|
4135
|
-
fix: {
|
|
4136
|
-
action: "use_different_resource",
|
|
4137
|
-
explanation: "Do not abort \u2014 infer the change from performance instead. Query monthly metrics per campaign (SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_12_MONTHS) to see which campaigns stopped or started spending. That shows what changed and when, though not who changed it. Older history exists only in the Google Ads web UI, which has no API \u2014 ask the user to check it if the 'who' matters."
|
|
4138
|
-
}
|
|
4139
|
-
};
|
|
4140
|
-
}
|
|
4141
|
-
function hintsFor(scope, days) {
|
|
4142
|
-
const hints = [];
|
|
4143
|
-
if (scope === "detail") {
|
|
4144
|
-
hints.push(
|
|
4145
|
-
`Detailed history covers the last ${CHANGE_SCOPE_MAX_DAYS.detail} days. For anything older use --scope summary (reaches ${CHANGE_SCOPE_MAX_DAYS.summary} days, reports which resources changed but not their values).`
|
|
4146
|
-
);
|
|
4147
|
-
} else {
|
|
4148
|
-
hints.push(
|
|
4149
|
-
"Summary history reports which resources changed and when, not old and new values. To see what a changed resource looks like now, query it by resource_name."
|
|
4150
|
-
);
|
|
4151
|
-
if (days > CHANGE_SCOPE_MAX_DAYS.detail) {
|
|
4152
|
-
hints.push(
|
|
4153
|
-
`Changes inside the last ${CHANGE_SCOPE_MAX_DAYS.detail} days also have field-level detail \u2014 re-run with --scope detail for those.`
|
|
4154
|
-
);
|
|
4155
|
-
}
|
|
4156
|
-
}
|
|
4157
|
-
return hints;
|
|
4158
|
-
}
|
|
4159
|
-
|
|
4160
4067
|
// src/commands/ads/google/correction-table.ts
|
|
4161
4068
|
function buildCommand(query, ctx) {
|
|
4162
4069
|
return `baker ads google query "${query}" --customer-id ${ctx.customerId}`;
|
|
@@ -4485,35 +4392,6 @@ var CORRECTION_RULES = [
|
|
|
4485
4392
|
};
|
|
4486
4393
|
}
|
|
4487
4394
|
},
|
|
4488
|
-
// 20a. change_event past its 30-day reach → change_status, which reaches 90 days.
|
|
4489
|
-
// The enum prefix in the API message is what separates this from the change_status
|
|
4490
|
-
// case below; a bare START_DATE_TOO_OLD falls through to the query-pattern pass,
|
|
4491
|
-
// which routes on the resource the caller actually queried.
|
|
4492
|
-
{
|
|
4493
|
-
matchQuery: /FROM\s+change_event\b/i,
|
|
4494
|
-
matchApiError: /ChangeEventError\.START_DATE_TOO_OLD/i,
|
|
4495
|
-
fix: (ctx) => {
|
|
4496
|
-
const limit = ctx.originalQuery.match(/LIMIT\s+(\d+)/i)?.[1] ?? "50";
|
|
4497
|
-
const requested = ctx.originalQuery.match(/change_date_time\s*>=\s*'([^']+)'/i)?.[1]?.slice(0, 10);
|
|
4498
|
-
const ninetyDaysAgo = new Date(Date.now() - 90 * 24 * 60 * 60 * 1e3).toISOString().slice(0, 10);
|
|
4499
|
-
const start = requested && requested > ninetyDaysAgo ? requested : ninetyDaysAgo;
|
|
4500
|
-
const corrected = `SELECT change_status.last_change_date_time, change_status.resource_type, change_status.resource_status, change_status.resource_name, change_status.campaign, change_status.ad_group FROM change_status WHERE change_status.last_change_date_time >= '${start}' ORDER BY change_status.last_change_date_time DESC LIMIT ${limit}`;
|
|
4501
|
-
return {
|
|
4502
|
-
action: "use_different_resource",
|
|
4503
|
-
correctedCommand: buildCommand(corrected, ctx),
|
|
4504
|
-
explanation: `change_event only reaches back 30 days. change_status reaches 90 (from ${start}) but reports only which resources changed and whether they were added, changed or removed \u2014 no old/new values and no user email. Read a changed resource by its resource_name to see its current values.`
|
|
4505
|
-
};
|
|
4506
|
-
}
|
|
4507
|
-
},
|
|
4508
|
-
// 20b. Past 90 days no history resource reaches — infer the change from spend instead.
|
|
4509
|
-
{
|
|
4510
|
-
matchQuery: /FROM\s+change_status\b/i,
|
|
4511
|
-
matchApiError: /ChangeStatusError\.START_DATE_TOO_OLD/i,
|
|
4512
|
-
fix: () => ({
|
|
4513
|
-
action: "use_different_resource",
|
|
4514
|
-
explanation: "Google's account history reaches back 90 days at most, and this query asks for more. Do not abort \u2014 infer the change from performance: SELECT campaign.name, segments.month, metrics.cost_micros, metrics.conversions FROM campaign WHERE segments.date DURING LAST_12_MONTHS shows which campaigns started or stopped spending and when, though not who changed them. Anything older with attribution exists only in the Google Ads web UI, which has no API."
|
|
4515
|
-
})
|
|
4516
|
-
},
|
|
4517
4395
|
// 20. change_event without date constraint
|
|
4518
4396
|
{
|
|
4519
4397
|
matchQuery: /FROM\s+change_event\b(?!.*change_date_time)/i,
|
|
@@ -4667,25 +4545,14 @@ function parseApiError(errorMessage, originalQuery, customerId) {
|
|
|
4667
4545
|
// src/commands/ads/google/changes.ts
|
|
4668
4546
|
registerSchema({
|
|
4669
4547
|
command: "ads.google.changes",
|
|
4670
|
-
description: "
|
|
4548
|
+
description: "Get recent change logs with performance impact. Shows what changed and how it affected metrics.",
|
|
4671
4549
|
args: {
|
|
4672
4550
|
"customer-id": {
|
|
4673
4551
|
type: "string",
|
|
4674
4552
|
description: "Google Ads customer ID (10 digits, no dashes). Falls back to BAKER_GOOGLE_ADS_CUSTOMER_ID env var.",
|
|
4675
4553
|
required: false
|
|
4676
4554
|
},
|
|
4677
|
-
days: {
|
|
4678
|
-
type: "string",
|
|
4679
|
-
description: `Lookback days (default: ${DEFAULT_CHANGE_DAYS}). Max ${CHANGE_SCOPE_MAX_DAYS.detail} with --scope detail, ${CHANGE_SCOPE_MAX_DAYS.summary} with --scope summary. Google keeps nothing older behind any API.`,
|
|
4680
|
-
required: false,
|
|
4681
|
-
default: DEFAULT_CHANGE_DAYS
|
|
4682
|
-
},
|
|
4683
|
-
scope: {
|
|
4684
|
-
type: "string",
|
|
4685
|
-
description: `detail|summary (default: detail). detail = old/new values plus who made the change, ${CHANGE_SCOPE_MAX_DAYS.detail} days. summary = which resources were added, changed or removed, ${CHANGE_SCOPE_MAX_DAYS.summary} days, without values.`,
|
|
4686
|
-
required: false,
|
|
4687
|
-
default: "detail"
|
|
4688
|
-
},
|
|
4555
|
+
days: { type: "string", description: "Lookback days (default: 7, max: 90)", required: false, default: 7 },
|
|
4689
4556
|
"resource-type": {
|
|
4690
4557
|
type: "string",
|
|
4691
4558
|
description: "Filter by type: CAMPAIGN, AD_GROUP, AD_GROUP_AD, AD_GROUP_CRITERION",
|
|
@@ -4698,24 +4565,15 @@ registerSchema({
|
|
|
4698
4565
|
var changesCommand = defineCommand20({
|
|
4699
4566
|
meta: {
|
|
4700
4567
|
name: "changes",
|
|
4701
|
-
description: `
|
|
4702
|
-
|
|
4703
|
-
Google keeps account history in two layers, and neither reaches past 90 days:
|
|
4704
|
-
--scope detail (default) what changed, old \u2192 new value, who changed it \u2014 last ${CHANGE_SCOPE_MAX_DAYS.detail} days
|
|
4705
|
-
--scope summary which resources were added, changed or removed \u2014 last ${CHANGE_SCOPE_MAX_DAYS.summary} days
|
|
4706
|
-
|
|
4707
|
-
For anything older, infer it from performance instead \u2014 a monthly spend trend per
|
|
4708
|
-
campaign shows what started or stopped, just not who did it.
|
|
4568
|
+
description: `Get recent changes in a Google Ads account with performance data.
|
|
4709
4569
|
|
|
4710
4570
|
Examples:
|
|
4711
4571
|
baker ads google changes --customer-id 1234567890
|
|
4712
|
-
baker ads google changes --customer-id 1234567890 --days 14 --resource-type CAMPAIGN
|
|
4713
|
-
baker ads google changes --customer-id 1234567890 --days 60 --scope summary`
|
|
4572
|
+
baker ads google changes --customer-id 1234567890 --days 14 --resource-type CAMPAIGN`
|
|
4714
4573
|
},
|
|
4715
4574
|
args: {
|
|
4716
4575
|
"customer-id": { type: "string", description: "Google Ads customer ID", required: false },
|
|
4717
|
-
days: { type: "string", description:
|
|
4718
|
-
scope: { type: "string", description: "detail (30 days) or summary (90 days)", required: false },
|
|
4576
|
+
days: { type: "string", description: "Lookback days (default 7)", required: false },
|
|
4719
4577
|
"resource-type": { type: "string", description: "Filter by resource type", required: false },
|
|
4720
4578
|
limit: { type: "string", description: "Max results (default 50)", required: false },
|
|
4721
4579
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false },
|
|
@@ -4723,19 +4581,9 @@ Examples:
|
|
|
4723
4581
|
},
|
|
4724
4582
|
run: async ({ args }) => {
|
|
4725
4583
|
const customerId = await resolveCustomerId(args);
|
|
4726
|
-
const window = resolveChangesWindow({
|
|
4727
|
-
days: args.days ? Number(args.days) : void 0,
|
|
4728
|
-
scope: args.scope
|
|
4729
|
-
});
|
|
4730
|
-
if (!window.ok) {
|
|
4731
|
-
writeJsonEnvelope({ ok: false, error: { ...window.error, retryable: false } });
|
|
4732
|
-
process.exit(1);
|
|
4733
|
-
return;
|
|
4734
|
-
}
|
|
4735
4584
|
const body = {
|
|
4736
4585
|
customerId,
|
|
4737
|
-
days:
|
|
4738
|
-
scope: window.scope,
|
|
4586
|
+
days: args.days ? Number(args.days) : 7,
|
|
4739
4587
|
limit: args.limit ? Number(args.limit) : 50
|
|
4740
4588
|
};
|
|
4741
4589
|
const managerId = getManagerIdForCustomer(customerId);
|
|
@@ -4752,7 +4600,7 @@ Examples:
|
|
|
4752
4600
|
const first = data[0];
|
|
4753
4601
|
const fields = first ? Object.keys(first) : [];
|
|
4754
4602
|
const fieldDescs = getFieldDescriptions(fields);
|
|
4755
|
-
|
|
4603
|
+
writeAdsJson({ ok: true, data, fields: fieldDescs });
|
|
4756
4604
|
} catch (err) {
|
|
4757
4605
|
if (err instanceof ApiError) {
|
|
4758
4606
|
writeAdsJson(parseApiError(err.message, "", customerId));
|
|
@@ -5838,11 +5686,11 @@ function rawTextEntries(value) {
|
|
|
5838
5686
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
5839
5687
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
5840
5688
|
}
|
|
5841
|
-
function rawFileEntries(
|
|
5842
|
-
if (typeof
|
|
5689
|
+
function rawFileEntries(path27) {
|
|
5690
|
+
if (typeof path27 !== "string" || path27.length === 0) {
|
|
5843
5691
|
return [];
|
|
5844
5692
|
}
|
|
5845
|
-
return readFileSync2(
|
|
5693
|
+
return readFileSync2(path27, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
5846
5694
|
}
|
|
5847
5695
|
function keywordEntries(args) {
|
|
5848
5696
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -5865,19 +5713,19 @@ function keywordEntries(args) {
|
|
|
5865
5713
|
}
|
|
5866
5714
|
return entries;
|
|
5867
5715
|
}
|
|
5868
|
-
function loadJsonFileArg(
|
|
5869
|
-
if (typeof
|
|
5716
|
+
function loadJsonFileArg(path27) {
|
|
5717
|
+
if (typeof path27 !== "string" || path27.length === 0) {
|
|
5870
5718
|
return {};
|
|
5871
5719
|
}
|
|
5872
5720
|
try {
|
|
5873
|
-
const parsed = JSON.parse(readFileSync2(
|
|
5721
|
+
const parsed = JSON.parse(readFileSync2(path27, "utf8"));
|
|
5874
5722
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
5875
|
-
failWriteValidation(`${
|
|
5723
|
+
failWriteValidation(`${path27} must contain a JSON object`);
|
|
5876
5724
|
}
|
|
5877
5725
|
return parsed;
|
|
5878
5726
|
} catch (err) {
|
|
5879
5727
|
if (err instanceof SyntaxError) {
|
|
5880
|
-
failWriteValidation(`${
|
|
5728
|
+
failWriteValidation(`${path27} is not valid JSON: ${err.message}`);
|
|
5881
5729
|
}
|
|
5882
5730
|
throw err;
|
|
5883
5731
|
}
|
|
@@ -5999,10 +5847,10 @@ async function stageUpdate(kind, customerId, target, payload) {
|
|
|
5999
5847
|
async function stageTarget(kind, customerId, target) {
|
|
6000
5848
|
await stageGoogleOp({ kind, customerId, target });
|
|
6001
5849
|
}
|
|
6002
|
-
async function draftAction(
|
|
5850
|
+
async function draftAction(path27, body) {
|
|
6003
5851
|
try {
|
|
6004
5852
|
const chatId = requireChatId();
|
|
6005
|
-
const response = await apiPost(
|
|
5853
|
+
const response = await apiPost(path27, { chatId, ...body });
|
|
6006
5854
|
writeJsonEnvelope(response);
|
|
6007
5855
|
} catch (err) {
|
|
6008
5856
|
handleGoogleError(err);
|
|
@@ -9585,19 +9433,19 @@ function failWriteValidation2(message) {
|
|
|
9585
9433
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
9586
9434
|
process.exit(1);
|
|
9587
9435
|
}
|
|
9588
|
-
function loadJsonFileArg2(
|
|
9589
|
-
if (typeof
|
|
9436
|
+
function loadJsonFileArg2(path27) {
|
|
9437
|
+
if (typeof path27 !== "string" || path27.length === 0) {
|
|
9590
9438
|
return {};
|
|
9591
9439
|
}
|
|
9592
9440
|
try {
|
|
9593
|
-
const parsed = JSON.parse(readFileSync6(
|
|
9441
|
+
const parsed = JSON.parse(readFileSync6(path27, "utf8"));
|
|
9594
9442
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
9595
|
-
failWriteValidation2(`${
|
|
9443
|
+
failWriteValidation2(`${path27} must contain a JSON object`);
|
|
9596
9444
|
}
|
|
9597
9445
|
return parsed;
|
|
9598
9446
|
} catch (err) {
|
|
9599
9447
|
if (err instanceof SyntaxError) {
|
|
9600
|
-
failWriteValidation2(`${
|
|
9448
|
+
failWriteValidation2(`${path27} is not valid JSON: ${err.message}`);
|
|
9601
9449
|
}
|
|
9602
9450
|
throw err;
|
|
9603
9451
|
}
|
|
@@ -9682,15 +9530,15 @@ function parseLocaleFlag(value) {
|
|
|
9682
9530
|
}
|
|
9683
9531
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
9684
9532
|
}
|
|
9685
|
-
function loadTargetingFileArg(
|
|
9686
|
-
if (typeof
|
|
9533
|
+
function loadTargetingFileArg(path27) {
|
|
9534
|
+
if (typeof path27 !== "string" || path27.length === 0) {
|
|
9687
9535
|
return void 0;
|
|
9688
9536
|
}
|
|
9689
|
-
const parsed = loadJsonFileArg2(
|
|
9537
|
+
const parsed = loadJsonFileArg2(path27);
|
|
9690
9538
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
9691
9539
|
if (!criteria.include) {
|
|
9692
9540
|
failWriteValidation2(
|
|
9693
|
-
`${
|
|
9541
|
+
`${path27} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
9694
9542
|
);
|
|
9695
9543
|
}
|
|
9696
9544
|
return criteria;
|
|
@@ -9725,14 +9573,14 @@ function parseCsvLine(line) {
|
|
|
9725
9573
|
cells.push(current);
|
|
9726
9574
|
return cells.map((cell) => cell.trim());
|
|
9727
9575
|
}
|
|
9728
|
-
function parseListFileArg(
|
|
9729
|
-
if (typeof
|
|
9576
|
+
function parseListFileArg(path27, maxRows) {
|
|
9577
|
+
if (typeof path27 !== "string" || path27.length === 0) {
|
|
9730
9578
|
return void 0;
|
|
9731
9579
|
}
|
|
9732
|
-
const raw = readFileSync6(
|
|
9580
|
+
const raw = readFileSync6(path27, "utf8");
|
|
9733
9581
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
9734
9582
|
if (lines.length < 2) {
|
|
9735
|
-
failWriteValidation2(`${
|
|
9583
|
+
failWriteValidation2(`${path27} needs a header row and at least one data row`);
|
|
9736
9584
|
}
|
|
9737
9585
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
9738
9586
|
const rows = [];
|
|
@@ -9751,7 +9599,7 @@ function parseListFileArg(path28, maxRows) {
|
|
|
9751
9599
|
}
|
|
9752
9600
|
}
|
|
9753
9601
|
if (rows.length > maxRows) {
|
|
9754
|
-
failWriteValidation2(`${
|
|
9602
|
+
failWriteValidation2(`${path27} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
9755
9603
|
}
|
|
9756
9604
|
return { columns, rows };
|
|
9757
9605
|
}
|
|
@@ -11851,11 +11699,11 @@ var updateStatusSchema = z14.enum(UPDATE_STATUSES);
|
|
|
11851
11699
|
function currencyMinimums2(currencyCode) {
|
|
11852
11700
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
11853
11701
|
}
|
|
11854
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
11702
|
+
function validateDailyBudgetFloor(money, ctx, path27) {
|
|
11855
11703
|
if (money?.currencyCode) {
|
|
11856
11704
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
11857
11705
|
if (Number(money.amount) < min) {
|
|
11858
|
-
ctx.addIssue({ code: "custom", path:
|
|
11706
|
+
ctx.addIssue({ code: "custom", path: path27, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
11859
11707
|
}
|
|
11860
11708
|
}
|
|
11861
11709
|
}
|
|
@@ -12487,19 +12335,19 @@ function failWriteValidation3(message) {
|
|
|
12487
12335
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
12488
12336
|
process.exit(1);
|
|
12489
12337
|
}
|
|
12490
|
-
function loadJsonFileArg3(
|
|
12491
|
-
if (typeof
|
|
12338
|
+
function loadJsonFileArg3(path27) {
|
|
12339
|
+
if (typeof path27 !== "string" || path27.length === 0) {
|
|
12492
12340
|
return {};
|
|
12493
12341
|
}
|
|
12494
12342
|
try {
|
|
12495
|
-
const parsed = JSON.parse(readFileSync8(
|
|
12343
|
+
const parsed = JSON.parse(readFileSync8(path27, "utf8"));
|
|
12496
12344
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
12497
|
-
failWriteValidation3(`${
|
|
12345
|
+
failWriteValidation3(`${path27} must contain a JSON object`);
|
|
12498
12346
|
}
|
|
12499
12347
|
return parsed;
|
|
12500
12348
|
} catch (err) {
|
|
12501
12349
|
if (err instanceof SyntaxError) {
|
|
12502
|
-
failWriteValidation3(`${
|
|
12350
|
+
failWriteValidation3(`${path27} is not valid JSON: ${err.message}`);
|
|
12503
12351
|
}
|
|
12504
12352
|
throw err;
|
|
12505
12353
|
}
|
|
@@ -15438,346 +15286,12 @@ Full guides: __tooling__/docs/tools/baker/ads-<platform>.md (google|meta|linkedi
|
|
|
15438
15286
|
}
|
|
15439
15287
|
});
|
|
15440
15288
|
|
|
15441
|
-
// src/commands/brand/index.ts
|
|
15442
|
-
import { defineCommand as defineCommand86 } from "citty";
|
|
15443
|
-
|
|
15444
|
-
// src/commands/brand/fonts.ts
|
|
15445
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
15446
|
-
import path from "path";
|
|
15447
|
-
import { defineCommand as defineCommand85 } from "citty";
|
|
15448
|
-
|
|
15449
|
-
// src/engine/brand/fonts.ts
|
|
15450
|
-
var GOOGLE_CSS2 = "https://fonts.googleapis.com/css2";
|
|
15451
|
-
function parseGoogleFontFaces(css) {
|
|
15452
|
-
const faces = [];
|
|
15453
|
-
const re = /\/\*\s*([\w-]+)\s*\*\/\s*@font-face\s*\{([^}]*)\}/g;
|
|
15454
|
-
for (const match of String(css).matchAll(re)) {
|
|
15455
|
-
const subset = match[1] ?? "";
|
|
15456
|
-
const body = match[2] ?? "";
|
|
15457
|
-
const family = body.match(/font-family\s*:\s*['"]?([^'";]+)['"]?\s*;/i)?.[1]?.trim();
|
|
15458
|
-
const url = body.match(/src\s*:\s*url\(\s*['"]?([^'")]+)['"]?\s*\)/i)?.[1]?.trim();
|
|
15459
|
-
const weight = body.match(/font-weight\s*:\s*(\d{3})\s*;/i)?.[1];
|
|
15460
|
-
if (!family || !url || !weight) continue;
|
|
15461
|
-
faces.push({
|
|
15462
|
-
subset,
|
|
15463
|
-
family,
|
|
15464
|
-
style: body.match(/font-style\s*:\s*([\w-]+)\s*;/i)?.[1]?.trim() ?? "normal",
|
|
15465
|
-
weight: Number(weight),
|
|
15466
|
-
url,
|
|
15467
|
-
unicodeRange: body.match(/unicode-range\s*:\s*([^;]+);/i)?.[1]?.trim() ?? ""
|
|
15468
|
-
});
|
|
15469
|
-
}
|
|
15470
|
-
return faces;
|
|
15471
|
-
}
|
|
15472
|
-
function fontFileName(face) {
|
|
15473
|
-
const family = face.family.replace(/[^A-Za-z0-9]/g, "");
|
|
15474
|
-
const style = face.style === "italic" ? "italic" : "";
|
|
15475
|
-
return `${family}-${face.weight}${style}-${face.subset}.woff2`;
|
|
15476
|
-
}
|
|
15477
|
-
function renderFontFaceCss(faces, hrefFor) {
|
|
15478
|
-
return faces.map(
|
|
15479
|
-
(face) => [
|
|
15480
|
-
"@font-face {",
|
|
15481
|
-
` font-family: '${face.family}';`,
|
|
15482
|
-
` font-style: ${face.style};`,
|
|
15483
|
-
` font-weight: ${face.weight};`,
|
|
15484
|
-
" font-display: swap;",
|
|
15485
|
-
` src: url('${hrefFor(face)}') format('woff2');`,
|
|
15486
|
-
...face.unicodeRange ? [` unicode-range: ${face.unicodeRange};`] : [],
|
|
15487
|
-
"}"
|
|
15488
|
-
].join("\n")
|
|
15489
|
-
).join("\n");
|
|
15490
|
-
}
|
|
15491
|
-
function parseWeightAxis(spec) {
|
|
15492
|
-
const axis = spec.match(/wght@([^&]+)/i)?.[1] ?? "";
|
|
15493
|
-
const weights = /* @__PURE__ */ new Set();
|
|
15494
|
-
for (const tuple of axis.split(";")) {
|
|
15495
|
-
const last = tuple.split(",").pop()?.trim() ?? "";
|
|
15496
|
-
const range = last.match(/^(\d{3})\.\.(\d{3})$/);
|
|
15497
|
-
if (range) {
|
|
15498
|
-
for (let w = Number(range[1]); w <= Number(range[2]); w += 100) weights.add(w);
|
|
15499
|
-
} else if (/^\d{3}$/.test(last)) {
|
|
15500
|
-
weights.add(Number(last));
|
|
15501
|
-
}
|
|
15502
|
-
}
|
|
15503
|
-
return [...weights].sort((a, b) => a - b);
|
|
15504
|
-
}
|
|
15505
|
-
function googleFontRequests(css) {
|
|
15506
|
-
const out = [];
|
|
15507
|
-
for (const link of String(css).matchAll(/fonts\.googleapis\.com\/[^\s"')]+/gi)) {
|
|
15508
|
-
for (const param of link[0].matchAll(/[?&]family=([^&]+)/gi)) {
|
|
15509
|
-
const [namePart, ...specParts] = (param[1] ?? "").split(":");
|
|
15510
|
-
const family = decodeURIComponent((namePart ?? "").replaceAll("+", " ")).trim();
|
|
15511
|
-
if (!family) continue;
|
|
15512
|
-
out.push({ family, weights: parseWeightAxis(specParts.join(":")) });
|
|
15513
|
-
}
|
|
15514
|
-
}
|
|
15515
|
-
return out;
|
|
15516
|
-
}
|
|
15517
|
-
function resolveFetchWeights(flag, declared) {
|
|
15518
|
-
if (flag) {
|
|
15519
|
-
return String(flag).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
|
|
15520
|
-
}
|
|
15521
|
-
return declared?.length ? declared : [400];
|
|
15522
|
-
}
|
|
15523
|
-
function googleFontCssUrl(family, weights) {
|
|
15524
|
-
const name = family.trim().split(/\s+/).map(encodeURIComponent).join("+");
|
|
15525
|
-
const axis = [...new Set(weights)].sort((a, b) => a - b).join(";");
|
|
15526
|
-
const spec = axis ? `${name}:wght@${axis}` : name;
|
|
15527
|
-
return `${GOOGLE_CSS2}?family=${spec}&display=swap`;
|
|
15528
|
-
}
|
|
15529
|
-
var STANDARD_WEIGHTS = [100, 200, 300, 400, 500, 600, 700, 800, 900];
|
|
15530
|
-
async function probeServedWeights(family, fetchCss) {
|
|
15531
|
-
const probes = await Promise.all(
|
|
15532
|
-
STANDARD_WEIGHTS.map(async (weight) => await fetchCss(googleFontCssUrl(family, [weight])) ? weight : null)
|
|
15533
|
-
);
|
|
15534
|
-
return probes.filter((w) => w !== null);
|
|
15535
|
-
}
|
|
15536
|
-
async function checkFontRequests(requests, fetchCss) {
|
|
15537
|
-
const results = [];
|
|
15538
|
-
for (const request of requests) {
|
|
15539
|
-
const css = await fetchCss(googleFontCssUrl(request.family, request.weights));
|
|
15540
|
-
if (css === null) {
|
|
15541
|
-
const served2 = await probeServedWeights(request.family, fetchCss);
|
|
15542
|
-
results.push({
|
|
15543
|
-
family: request.family,
|
|
15544
|
-
requested: request.weights,
|
|
15545
|
-
served: served2,
|
|
15546
|
-
missing: request.weights.filter((w) => !served2.includes(w)),
|
|
15547
|
-
subsets: [],
|
|
15548
|
-
cause: served2.length === 0 ? "unknown-family" : "unavailable-weight"
|
|
15549
|
-
});
|
|
15550
|
-
continue;
|
|
15551
|
-
}
|
|
15552
|
-
const faces = parseGoogleFontFaces(css);
|
|
15553
|
-
const served = [...new Set(faces.map((f) => f.weight))].sort((a, b) => a - b);
|
|
15554
|
-
results.push({
|
|
15555
|
-
family: request.family,
|
|
15556
|
-
requested: request.weights,
|
|
15557
|
-
served,
|
|
15558
|
-
missing: request.weights.filter((w) => !served.includes(w)),
|
|
15559
|
-
subsets: [...new Set(faces.map((f) => f.subset))]
|
|
15560
|
-
});
|
|
15561
|
-
}
|
|
15562
|
-
return results;
|
|
15563
|
-
}
|
|
15564
|
-
|
|
15565
|
-
// src/commands/brand/fonts.ts
|
|
15566
|
-
var GLOBAL_CSS = path.join("src", "styles", "global.css");
|
|
15567
|
-
var FONTS_DIR = path.join("src", "brand", "fonts");
|
|
15568
|
-
var DEFAULT_SUBSETS = "latin";
|
|
15569
|
-
var BROWSER_UA = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36";
|
|
15570
|
-
registerSchema({
|
|
15571
|
-
command: "brand.fonts.check",
|
|
15572
|
-
description: "Start here when a brand's fonts are 'confirmed' but nobody verified it. Asks Google Fonts what it ACTUALLY serves for every family/weight src/styles/global.css requests, and reports any the brand promises but Google will not serve.",
|
|
15573
|
-
args: {}
|
|
15574
|
-
});
|
|
15575
|
-
registerSchema({
|
|
15576
|
-
command: "brand.fonts.fetch",
|
|
15577
|
-
description: "Download a Google font into src/brand/fonts/ so the brand stops depending on a third party at page load, and print the @font-face block to paste above @theme in src/styles/global.css.",
|
|
15578
|
-
args: {
|
|
15579
|
-
family: { type: "string", description: 'Font family, e.g. "DM Sans"', required: true },
|
|
15580
|
-
weights: {
|
|
15581
|
-
type: "string",
|
|
15582
|
-
description: "Comma-separated weights (default: what global.css requests, else 400)",
|
|
15583
|
-
required: false
|
|
15584
|
-
},
|
|
15585
|
-
subsets: {
|
|
15586
|
-
type: "string",
|
|
15587
|
-
description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})`,
|
|
15588
|
-
required: false
|
|
15589
|
-
}
|
|
15590
|
-
}
|
|
15591
|
-
});
|
|
15592
|
-
function fail(code, message, fix) {
|
|
15593
|
-
writeJson({ ok: false, error: { code, message, ...fix ? { fix } : {} } });
|
|
15594
|
-
process.exit(2);
|
|
15595
|
-
}
|
|
15596
|
-
var REQUEST_TIMEOUT_MS = 15e3;
|
|
15597
|
-
async function fetchGoogleCss(url) {
|
|
15598
|
-
try {
|
|
15599
|
-
const res = await fetch(url, {
|
|
15600
|
-
headers: { "User-Agent": BROWSER_UA },
|
|
15601
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
15602
|
-
});
|
|
15603
|
-
if (!res.ok) return null;
|
|
15604
|
-
return await res.text();
|
|
15605
|
-
} catch {
|
|
15606
|
-
return null;
|
|
15607
|
-
}
|
|
15608
|
-
}
|
|
15609
|
-
async function readGlobalCss() {
|
|
15610
|
-
try {
|
|
15611
|
-
return await readFile(path.resolve(process.cwd(), GLOBAL_CSS), "utf8");
|
|
15612
|
-
} catch {
|
|
15613
|
-
return "";
|
|
15614
|
-
}
|
|
15615
|
-
}
|
|
15616
|
-
var fontsCheckCommand = defineCommand85({
|
|
15617
|
-
meta: {
|
|
15618
|
-
name: "check",
|
|
15619
|
-
description: "Verify the brand's fonts really exist. For every family/weight src/styles/global.css requests from Google Fonts, ask Google what it actually serves and report anything missing \u2014 a weight nobody serves renders as a synthesized fallback and looks off-brand everywhere."
|
|
15620
|
-
},
|
|
15621
|
-
async run() {
|
|
15622
|
-
const css = await readGlobalCss();
|
|
15623
|
-
const requests = googleFontRequests(css);
|
|
15624
|
-
if (requests.length === 0) {
|
|
15625
|
-
writeJson({
|
|
15626
|
-
ok: true,
|
|
15627
|
-
data: { families: [], selfHosted: true },
|
|
15628
|
-
hints: [
|
|
15629
|
-
`No Google Fonts requested in ${GLOBAL_CSS}. If the brand self-hosts, the offline validator already checks those files; nothing to verify against Google.`
|
|
15630
|
-
]
|
|
15631
|
-
});
|
|
15632
|
-
return;
|
|
15633
|
-
}
|
|
15634
|
-
const families = await checkFontRequests(requests, fetchGoogleCss);
|
|
15635
|
-
const broken = families.filter((f) => f.missing.length > 0);
|
|
15636
|
-
if (broken.length > 0) {
|
|
15637
|
-
const summary = broken.map(
|
|
15638
|
-
(f) => f.cause === "unknown-family" ? `${f.family} (no such family on Google Fonts \u2014 check the exact spelling)` : `${f.family} ${f.missing.join("/")} (served: ${f.served.join("/") || "none"})`
|
|
15639
|
-
).join("; ");
|
|
15640
|
-
fail("FONT_NOT_SERVED", `Google Fonts does not serve: ${summary}`, {
|
|
15641
|
-
action: `Correct the family name or weight in ${GLOBAL_CSS} and src/brand/BRAND.md, picking from the \`served\` weights below.`,
|
|
15642
|
-
explanation: "A requested weight Google does not serve is silently synthesized by the browser, so the page looks subtly wrong with nothing failing.",
|
|
15643
|
-
// The per-family breakdown is the point of the command, so it ships on
|
|
15644
|
-
// the failure path too — otherwise the only remedy is re-running the
|
|
15645
|
-
// command that just failed. Healthy families are included so a
|
|
15646
|
-
// multi-family brand shows what NOT to touch.
|
|
15647
|
-
families
|
|
15648
|
-
});
|
|
15649
|
-
}
|
|
15650
|
-
writeJson({
|
|
15651
|
-
ok: true,
|
|
15652
|
-
data: { families },
|
|
15653
|
-
hints: [
|
|
15654
|
-
"Every requested family and weight is really served by Google.",
|
|
15655
|
-
`To stop depending on Google at page load, run \`baker brand fonts fetch "<family>"\` to self-host into ${FONTS_DIR}.`
|
|
15656
|
-
]
|
|
15657
|
-
});
|
|
15658
|
-
}
|
|
15659
|
-
});
|
|
15660
|
-
var fontsFetchCommand = defineCommand85({
|
|
15661
|
-
meta: {
|
|
15662
|
-
name: "fetch",
|
|
15663
|
-
description: "Download a Google font into src/brand/fonts/ and print the @font-face block to paste above @theme in src/styles/global.css. Use when a brand font should be self-hosted rather than requested from Google on every page load."
|
|
15664
|
-
},
|
|
15665
|
-
args: {
|
|
15666
|
-
family: { type: "positional", required: true, description: 'Font family, e.g. "DM Sans"' },
|
|
15667
|
-
weights: { type: "string", description: "Comma-separated weights (default: what global.css requests, else 400)" },
|
|
15668
|
-
subsets: { type: "string", description: `Comma-separated unicode subsets (default: ${DEFAULT_SUBSETS})` }
|
|
15669
|
-
},
|
|
15670
|
-
async run({ args }) {
|
|
15671
|
-
const family = String(args.family).trim();
|
|
15672
|
-
if (!family) fail("INVALID_FAMILY", 'Pass a font family, e.g. `baker brand fonts fetch "DM Sans"`.');
|
|
15673
|
-
const css = await readGlobalCss();
|
|
15674
|
-
const declared = googleFontRequests(css).find((r) => r.family.toLowerCase() === family.toLowerCase());
|
|
15675
|
-
const weights = resolveFetchWeights(args.weights, declared?.weights);
|
|
15676
|
-
if (weights.length === 0) {
|
|
15677
|
-
fail("INVALID_WEIGHTS", `"${args.weights}" has no usable weight \u2014 pass whole hundreds, e.g. --weights 400,700.`);
|
|
15678
|
-
}
|
|
15679
|
-
const wanted = new Set(
|
|
15680
|
-
String(args.subsets ?? DEFAULT_SUBSETS).split(",").map((s) => s.trim()).filter(Boolean)
|
|
15681
|
-
);
|
|
15682
|
-
const servedCss = await fetchGoogleCss(googleFontCssUrl(family, weights));
|
|
15683
|
-
if (servedCss === null) {
|
|
15684
|
-
const [diagnosis] = await checkFontRequests([{ family, weights }], fetchGoogleCss);
|
|
15685
|
-
const served = diagnosis?.served ?? [];
|
|
15686
|
-
fail(
|
|
15687
|
-
"FONT_NOT_SERVED",
|
|
15688
|
-
served.length === 0 ? `Google Fonts has no family called "${family}".` : `"${family}" exists on Google Fonts but not at weight ${weights.join("/")}.`,
|
|
15689
|
-
served.length === 0 ? {
|
|
15690
|
-
action: "Check the exact family name at fonts.google.com, then retry.",
|
|
15691
|
-
explanation: "Family names are case- and space-sensitive in the Google Fonts API."
|
|
15692
|
-
} : {
|
|
15693
|
-
action: `Retry with --weights set to one of these: ${served.join(",")}.`,
|
|
15694
|
-
explanation: "Google rejects the whole request when one requested weight does not exist.",
|
|
15695
|
-
served
|
|
15696
|
-
}
|
|
15697
|
-
);
|
|
15698
|
-
}
|
|
15699
|
-
const faces = parseGoogleFontFaces(servedCss).filter((f) => wanted.has(f.subset));
|
|
15700
|
-
if (faces.length === 0) {
|
|
15701
|
-
fail("SUBSET_NOT_SERVED", `"${family}" has no ${[...wanted].join("/")} subset.`, {
|
|
15702
|
-
action: `Retry with --subsets set to one Google actually serves for this family.`,
|
|
15703
|
-
explanation: "Google splits each family into unicode subsets; not every family ships every subset."
|
|
15704
|
-
});
|
|
15705
|
-
}
|
|
15706
|
-
const fontsDir = path.resolve(process.cwd(), FONTS_DIR);
|
|
15707
|
-
await mkdir(fontsDir, { recursive: true });
|
|
15708
|
-
const downloaded = [];
|
|
15709
|
-
for (const face of faces) {
|
|
15710
|
-
const res = await fetch(face.url, {
|
|
15711
|
-
headers: { "User-Agent": BROWSER_UA },
|
|
15712
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
15713
|
-
});
|
|
15714
|
-
if (!res.ok) continue;
|
|
15715
|
-
await writeFile(path.join(fontsDir, fontFileName(face)), Buffer.from(await res.arrayBuffer()));
|
|
15716
|
-
downloaded.push(face);
|
|
15717
|
-
}
|
|
15718
|
-
const written = downloaded.map(fontFileName);
|
|
15719
|
-
if (written.length === 0) {
|
|
15720
|
-
fail("DOWNLOAD_FAILED", `Could not download any file for "${family}".`, {
|
|
15721
|
-
action: "Retry; if it keeps failing, keep the Google @import and note it in BRAND.md.",
|
|
15722
|
-
explanation: "The font stylesheet resolved but the font files themselves did not download."
|
|
15723
|
-
});
|
|
15724
|
-
}
|
|
15725
|
-
const fontFace = renderFontFaceCss(downloaded, (f) => `/${FONTS_DIR}/${fontFileName(f)}`);
|
|
15726
|
-
const downloadedWeights = [...new Set(downloaded.map((f) => f.weight))].sort((a, b) => a - b);
|
|
15727
|
-
const incomplete = weights.filter((w) => !downloadedWeights.includes(w));
|
|
15728
|
-
writeJson({
|
|
15729
|
-
ok: true,
|
|
15730
|
-
data: { family, weights: downloadedWeights, files: written, fontFace },
|
|
15731
|
-
hints: [
|
|
15732
|
-
`Paste the \`fontFace\` block ABOVE the @theme block in ${GLOBAL_CSS}, then remove "${family}" from the Google @import so the page stops fetching it at load.`,
|
|
15733
|
-
`Record the exact weights (${downloadedWeights.join(", ")}) in src/brand/BRAND.md \u2014 a weight listed there but not downloaded renders as a synthesized fallback.`,
|
|
15734
|
-
...incomplete.length > 0 ? [
|
|
15735
|
-
`PARTIAL: ${incomplete.join(", ")} did not download and is NOT in the \`fontFace\` block. Keep "${family}" in the Google @import for those weights, or re-run \`baker brand fonts fetch "${family}" --weights ${incomplete.join(",")}\`.`
|
|
15736
|
-
] : [],
|
|
15737
|
-
"Licensing: Google Fonts are open-licensed and safe to self-host. A client's own commercial face is not \u2014 confirm before re-hosting one."
|
|
15738
|
-
]
|
|
15739
|
-
});
|
|
15740
|
-
}
|
|
15741
|
-
});
|
|
15742
|
-
var fontsCommand = defineCommand85({
|
|
15743
|
-
meta: {
|
|
15744
|
-
name: "fonts",
|
|
15745
|
-
description: `Verify and self-host the brand's typefaces.
|
|
15746
|
-
|
|
15747
|
-
Start here: \`baker brand fonts check\` \u2014 confirms the fonts the brand claims are really served.
|
|
15748
|
-
|
|
15749
|
-
Subcommands:
|
|
15750
|
-
baker brand fonts check \u2014 ask Google what it actually serves for every family/weight global.css requests
|
|
15751
|
-
baker brand fonts fetch <family> \u2014 download a family into src/brand/fonts/ and print its @font-face block`
|
|
15752
|
-
},
|
|
15753
|
-
subCommands: {
|
|
15754
|
-
check: fontsCheckCommand,
|
|
15755
|
-
fetch: fontsFetchCommand
|
|
15756
|
-
}
|
|
15757
|
-
});
|
|
15758
|
-
|
|
15759
|
-
// src/commands/brand/index.ts
|
|
15760
|
-
var brandCommand = defineCommand86({
|
|
15761
|
-
meta: {
|
|
15762
|
-
name: "brand",
|
|
15763
|
-
description: `Brand asset verification for src/brand/.
|
|
15764
|
-
|
|
15765
|
-
Start here: \`baker brand fonts check\` after defining or editing the brand's typography.
|
|
15766
|
-
|
|
15767
|
-
Subcommands:
|
|
15768
|
-
baker brand fonts \u2014 verify the brand's typefaces really load, and self-host them into src/brand/fonts/`
|
|
15769
|
-
},
|
|
15770
|
-
subCommands: {
|
|
15771
|
-
fonts: fontsCommand
|
|
15772
|
-
}
|
|
15773
|
-
});
|
|
15774
|
-
|
|
15775
15289
|
// src/commands/canvas/index.ts
|
|
15776
|
-
import { defineCommand as
|
|
15290
|
+
import { defineCommand as defineCommand95 } from "citty";
|
|
15777
15291
|
|
|
15778
15292
|
// src/commands/canvas/catalog.ts
|
|
15779
|
-
import { defineCommand as
|
|
15780
|
-
var catalogCommand =
|
|
15293
|
+
import { defineCommand as defineCommand85 } from "citty";
|
|
15294
|
+
var catalogCommand = defineCommand85({
|
|
15781
15295
|
meta: {
|
|
15782
15296
|
name: "catalog",
|
|
15783
15297
|
description: "Print the agent-facing node catalog (JSON Schema). Includes every registered node grouped by category."
|
|
@@ -15790,9 +15304,9 @@ var catalogCommand = defineCommand87({
|
|
|
15790
15304
|
});
|
|
15791
15305
|
|
|
15792
15306
|
// src/commands/canvas/critique.ts
|
|
15793
|
-
import { readFile
|
|
15794
|
-
import
|
|
15795
|
-
import { defineCommand as
|
|
15307
|
+
import { readFile } from "fs/promises";
|
|
15308
|
+
import path from "path";
|
|
15309
|
+
import { defineCommand as defineCommand86 } from "citty";
|
|
15796
15310
|
|
|
15797
15311
|
// src/engine/scaffold/lib/critique.ts
|
|
15798
15312
|
var VIBE_CUE = /\b(light|lighting|golden|moody|warm|cool|tone|grade|contrast|shadow|glow|rim|backlit|neon|soft)\b/i;
|
|
@@ -15912,15 +15426,15 @@ function critiqueCanvas(canvas) {
|
|
|
15912
15426
|
}
|
|
15913
15427
|
|
|
15914
15428
|
// src/commands/canvas/critique.ts
|
|
15915
|
-
var critiqueCommand =
|
|
15429
|
+
var critiqueCommand = defineCommand86({
|
|
15916
15430
|
meta: {
|
|
15917
15431
|
name: "critique",
|
|
15918
15432
|
description: "Pre-spend creative critic (ADVISORY \u2014 never blocks). Scores a scaffolded creative BEFORE the billed render, so weak spots get fixed for free. A VIDEO creative is scored on hook strength, sound-off first-frame legibility, retention risk, and mechanism clarity; a STATIC ad on baked-text legibility risk, identity grounding, brand-type fidelity, and mechanism clarity. Ground a video hook against `baker winning-ads hooks` for a proven pattern."
|
|
15919
15433
|
},
|
|
15920
15434
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
15921
15435
|
async run({ args }) {
|
|
15922
|
-
const filePath =
|
|
15923
|
-
const raw = await
|
|
15436
|
+
const filePath = path.resolve(String(args.file));
|
|
15437
|
+
const raw = await readFile(filePath, "utf8");
|
|
15924
15438
|
let parsed;
|
|
15925
15439
|
try {
|
|
15926
15440
|
parsed = JSON.parse(raw);
|
|
@@ -15951,12 +15465,12 @@ var critiqueCommand = defineCommand88({
|
|
|
15951
15465
|
|
|
15952
15466
|
// src/commands/canvas/inspect.ts
|
|
15953
15467
|
import { execFile } from "child_process";
|
|
15954
|
-
import { readdir, readFile as
|
|
15955
|
-
import
|
|
15468
|
+
import { readdir, readFile as readFile2, stat } from "fs/promises";
|
|
15469
|
+
import path2 from "path";
|
|
15956
15470
|
import { promisify } from "util";
|
|
15957
|
-
import { defineCommand as
|
|
15471
|
+
import { defineCommand as defineCommand87 } from "citty";
|
|
15958
15472
|
var execFileAsync = promisify(execFile);
|
|
15959
|
-
var inspectCommand =
|
|
15473
|
+
var inspectCommand = defineCommand87({
|
|
15960
15474
|
meta: {
|
|
15961
15475
|
name: "inspect",
|
|
15962
15476
|
description: "Dump a one-page summary of a canvas run: per-node duration + cache status, list of output files in the run dir, and optionally three thumbnail frames per video output. Pass either a run_id (resolved against --outputs-dir) or an absolute run directory."
|
|
@@ -15970,7 +15484,7 @@ var inspectCommand = defineCommand89({
|
|
|
15970
15484
|
}
|
|
15971
15485
|
},
|
|
15972
15486
|
async run({ args }) {
|
|
15973
|
-
const outputsDir =
|
|
15487
|
+
const outputsDir = path2.resolve(String(args["outputs-dir"] ?? "canvas"));
|
|
15974
15488
|
const runArg = String(args.run);
|
|
15975
15489
|
const runDir = await resolveRunDir(runArg, outputsDir);
|
|
15976
15490
|
const manifest = await loadManifest(runDir);
|
|
@@ -15982,7 +15496,7 @@ var inspectCommand = defineCommand89({
|
|
|
15982
15496
|
}
|
|
15983
15497
|
const summary = {
|
|
15984
15498
|
ok: true,
|
|
15985
|
-
run_id: manifest.run_id ??
|
|
15499
|
+
run_id: manifest.run_id ?? path2.basename(runDir),
|
|
15986
15500
|
run_dir: runDir,
|
|
15987
15501
|
stats: manifest.stats ?? null,
|
|
15988
15502
|
output: manifest.output ?? null,
|
|
@@ -15995,20 +15509,20 @@ var inspectCommand = defineCommand89({
|
|
|
15995
15509
|
}
|
|
15996
15510
|
});
|
|
15997
15511
|
async function resolveRunDir(run, outputsDir) {
|
|
15998
|
-
if (
|
|
15512
|
+
if (path2.isAbsolute(run)) {
|
|
15999
15513
|
const s2 = await stat(run).catch(() => null);
|
|
16000
15514
|
if (s2?.isDirectory()) return run;
|
|
16001
15515
|
throw new Error(`inspect: ${run} is not a directory`);
|
|
16002
15516
|
}
|
|
16003
|
-
const candidate =
|
|
15517
|
+
const candidate = path2.join(outputsDir, run);
|
|
16004
15518
|
const s = await stat(candidate).catch(() => null);
|
|
16005
15519
|
if (s?.isDirectory()) return candidate;
|
|
16006
15520
|
throw new Error(`inspect: no run directory at ${candidate}`);
|
|
16007
15521
|
}
|
|
16008
15522
|
async function loadManifest(runDir) {
|
|
16009
|
-
const manifestPath =
|
|
15523
|
+
const manifestPath = path2.join(runDir, "manifest.json");
|
|
16010
15524
|
try {
|
|
16011
|
-
const raw = await
|
|
15525
|
+
const raw = await readFile2(manifestPath, "utf-8");
|
|
16012
15526
|
return JSON.parse(raw);
|
|
16013
15527
|
} catch {
|
|
16014
15528
|
return {};
|
|
@@ -16018,7 +15532,7 @@ async function listRunFiles(runDir) {
|
|
|
16018
15532
|
const out = [];
|
|
16019
15533
|
const names = await readdir(runDir);
|
|
16020
15534
|
for (const name of names) {
|
|
16021
|
-
const abs =
|
|
15535
|
+
const abs = path2.join(runDir, name);
|
|
16022
15536
|
const s = await stat(abs).catch(() => null);
|
|
16023
15537
|
if (!s?.isFile()) continue;
|
|
16024
15538
|
out.push({ name, path: abs, size: s.size });
|
|
@@ -16063,13 +15577,13 @@ async function probeDuration(filePath) {
|
|
|
16063
15577
|
}
|
|
16064
15578
|
|
|
16065
15579
|
// src/commands/canvas/rerun.ts
|
|
16066
|
-
import
|
|
16067
|
-
import { defineCommand as
|
|
15580
|
+
import path13 from "path";
|
|
15581
|
+
import { defineCommand as defineCommand89 } from "citty";
|
|
16068
15582
|
|
|
16069
15583
|
// src/commands/canvas/run.ts
|
|
16070
|
-
import { readFile as
|
|
16071
|
-
import
|
|
16072
|
-
import { defineCommand as
|
|
15584
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
15585
|
+
import path12 from "path";
|
|
15586
|
+
import { defineCommand as defineCommand88 } from "citty";
|
|
16073
15587
|
|
|
16074
15588
|
// src/commands/canvas/placeholders.ts
|
|
16075
15589
|
function unsuppliedPlaceholderAssets(canvas) {
|
|
@@ -16088,7 +15602,7 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
16088
15602
|
}
|
|
16089
15603
|
|
|
16090
15604
|
// src/commands/canvas/resolve-paths.ts
|
|
16091
|
-
import
|
|
15605
|
+
import path3 from "path";
|
|
16092
15606
|
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
16093
15607
|
if (!canvas || typeof canvas !== "object") return canvas;
|
|
16094
15608
|
const c = canvas;
|
|
@@ -16101,24 +15615,24 @@ function resolveNode(node, baseDir) {
|
|
|
16101
15615
|
const params = n.params;
|
|
16102
15616
|
if (!params || typeof params !== "object") return node;
|
|
16103
15617
|
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
16104
|
-
return { ...node, params: { ...params, path:
|
|
15618
|
+
return { ...node, params: { ...params, path: path3.resolve(baseDir, params.path) } };
|
|
16105
15619
|
}
|
|
16106
15620
|
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
16107
|
-
return { ...node, params: { ...params, composition:
|
|
15621
|
+
return { ...node, params: { ...params, composition: path3.resolve(baseDir, params.composition) } };
|
|
16108
15622
|
}
|
|
16109
15623
|
return node;
|
|
16110
15624
|
}
|
|
16111
15625
|
function isResolvableRelative(value) {
|
|
16112
|
-
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !
|
|
15626
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path3.isAbsolute(value);
|
|
16113
15627
|
}
|
|
16114
15628
|
|
|
16115
15629
|
// src/commands/canvas/source-version.ts
|
|
16116
|
-
import { readFile as
|
|
16117
|
-
import
|
|
15630
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
15631
|
+
import path5 from "path";
|
|
16118
15632
|
|
|
16119
15633
|
// src/commands/canvas/scene-files.ts
|
|
16120
|
-
import { mkdir
|
|
16121
|
-
import
|
|
15634
|
+
import { mkdir, readFile as readFile3, readdir as readdir2, rm, writeFile } from "fs/promises";
|
|
15635
|
+
import path4 from "path";
|
|
16122
15636
|
var SCENES_DIR = "scenes";
|
|
16123
15637
|
var GLOBAL_PROMPT_FILE = "prompt.json";
|
|
16124
15638
|
var REBUILD_FILE = "prompt.rebuild.json";
|
|
@@ -16135,19 +15649,19 @@ function splitBlueprint(blueprint) {
|
|
|
16135
15649
|
}
|
|
16136
15650
|
async function writeSceneFiles(outDir, blueprint) {
|
|
16137
15651
|
const { global, scenes } = splitBlueprint(blueprint);
|
|
16138
|
-
await
|
|
15652
|
+
await writeFile(path4.join(outDir, GLOBAL_PROMPT_FILE), `${JSON.stringify(global, null, 2)}
|
|
16139
15653
|
`, "utf8");
|
|
16140
|
-
const scenesDir =
|
|
16141
|
-
await
|
|
15654
|
+
const scenesDir = path4.join(outDir, SCENES_DIR);
|
|
15655
|
+
await mkdir(scenesDir, { recursive: true });
|
|
16142
15656
|
const written = /* @__PURE__ */ new Set();
|
|
16143
15657
|
for (let i = 0; i < scenes.length; i++) {
|
|
16144
15658
|
const name = sceneFileName(i, scenes.length);
|
|
16145
15659
|
written.add(name);
|
|
16146
|
-
await
|
|
15660
|
+
await writeFile(path4.join(scenesDir, name), `${JSON.stringify(scenes[i], null, 2)}
|
|
16147
15661
|
`, "utf8");
|
|
16148
15662
|
}
|
|
16149
15663
|
for (const name of await listSceneFileNames(scenesDir)) {
|
|
16150
|
-
if (!written.has(name)) await rm(
|
|
15664
|
+
if (!written.has(name)) await rm(path4.join(scenesDir, name), { force: true });
|
|
16151
15665
|
}
|
|
16152
15666
|
}
|
|
16153
15667
|
async function listSceneFileNames(scenesDir) {
|
|
@@ -16160,17 +15674,17 @@ async function listSceneFileNames(scenesDir) {
|
|
|
16160
15674
|
return entries.filter((n) => /^s\d+\.json$/.test(n)).sort(bySceneIndex);
|
|
16161
15675
|
}
|
|
16162
15676
|
async function listSceneFiles(creativeDir) {
|
|
16163
|
-
const scenesDir =
|
|
16164
|
-
return (await listSceneFileNames(scenesDir)).map((n) =>
|
|
15677
|
+
const scenesDir = path4.join(creativeDir, SCENES_DIR);
|
|
15678
|
+
return (await listSceneFileNames(scenesDir)).map((n) => path4.join(scenesDir, n));
|
|
16165
15679
|
}
|
|
16166
15680
|
async function reassembleBlueprint(creativeDir) {
|
|
16167
15681
|
const files = await listSceneFiles(creativeDir);
|
|
16168
15682
|
if (files.length === 0) return null;
|
|
16169
|
-
const globalRaw = await
|
|
15683
|
+
const globalRaw = await readFile3(path4.join(creativeDir, GLOBAL_PROMPT_FILE), "utf8");
|
|
16170
15684
|
const global = JSON.parse(globalRaw);
|
|
16171
15685
|
const scenes = [];
|
|
16172
15686
|
for (const file of files) {
|
|
16173
|
-
scenes.push(JSON.parse(await
|
|
15687
|
+
scenes.push(JSON.parse(await readFile3(file, "utf8")));
|
|
16174
15688
|
}
|
|
16175
15689
|
return { ...global, scenes };
|
|
16176
15690
|
}
|
|
@@ -16184,15 +15698,15 @@ function bySceneIndex(a, b) {
|
|
|
16184
15698
|
async function computeSourceSha(canvasPath) {
|
|
16185
15699
|
let canvasBytes;
|
|
16186
15700
|
try {
|
|
16187
|
-
canvasBytes = await
|
|
15701
|
+
canvasBytes = await readFile4(canvasPath);
|
|
16188
15702
|
} catch {
|
|
16189
15703
|
return void 0;
|
|
16190
15704
|
}
|
|
16191
|
-
const canvasDir =
|
|
16192
|
-
const promptPath =
|
|
15705
|
+
const canvasDir = path5.dirname(canvasPath);
|
|
15706
|
+
const promptPath = path5.join(canvasDir, "prompt.json");
|
|
16193
15707
|
let promptBytes;
|
|
16194
15708
|
try {
|
|
16195
|
-
promptBytes = await
|
|
15709
|
+
promptBytes = await readFile4(promptPath);
|
|
16196
15710
|
} catch {
|
|
16197
15711
|
promptBytes = Buffer.alloc(0);
|
|
16198
15712
|
}
|
|
@@ -16205,7 +15719,7 @@ async function computeSourceSha(canvasPath) {
|
|
|
16205
15719
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
16206
15720
|
let sceneBytes;
|
|
16207
15721
|
try {
|
|
16208
|
-
sceneBytes = await
|
|
15722
|
+
sceneBytes = await readFile4(sceneFile);
|
|
16209
15723
|
} catch {
|
|
16210
15724
|
sceneBytes = Buffer.alloc(0);
|
|
16211
15725
|
}
|
|
@@ -16215,8 +15729,8 @@ async function computeSourceSha(canvasPath) {
|
|
|
16215
15729
|
}
|
|
16216
15730
|
|
|
16217
15731
|
// src/commands/canvas/scene-projection.ts
|
|
16218
|
-
import { readFile as
|
|
16219
|
-
import
|
|
15732
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
15733
|
+
import path6 from "path";
|
|
16220
15734
|
|
|
16221
15735
|
// src/engine/scaffold/video.ts
|
|
16222
15736
|
import { toCardinal as nwAr } from "n2words/ar-SA";
|
|
@@ -19475,12 +18989,12 @@ function nonPromptParamsDiverge(live = {}, rebuilt = {}) {
|
|
|
19475
18989
|
return false;
|
|
19476
18990
|
}
|
|
19477
18991
|
async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
19478
|
-
const creativeDir =
|
|
18992
|
+
const creativeDir = path6.dirname(canvasPath);
|
|
19479
18993
|
const blueprint = await reassembleBlueprint(creativeDir);
|
|
19480
18994
|
if (!blueprint) return "not_applicable";
|
|
19481
18995
|
let rebuildRaw;
|
|
19482
18996
|
try {
|
|
19483
|
-
rebuildRaw = await
|
|
18997
|
+
rebuildRaw = await readFile5(path6.join(creativeDir, REBUILD_FILE), "utf8");
|
|
19484
18998
|
} catch {
|
|
19485
18999
|
return "not_applicable";
|
|
19486
19000
|
}
|
|
@@ -19521,7 +19035,7 @@ async function syncSceneNodeParams(canvas, canvasPath, log) {
|
|
|
19521
19035
|
}
|
|
19522
19036
|
|
|
19523
19037
|
// src/commands/canvas/style-projection.ts
|
|
19524
|
-
import { readFile as
|
|
19038
|
+
import { readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
|
|
19525
19039
|
function findBlueprintProjection(canvas) {
|
|
19526
19040
|
if (!canvas || typeof canvas !== "object") return null;
|
|
19527
19041
|
const nodes = canvas.nodes;
|
|
@@ -19549,10 +19063,10 @@ function renderStyleProjectionFromValue(blueprint) {
|
|
|
19549
19063
|
async function syncStyleProjection(canvas, log) {
|
|
19550
19064
|
const pair = findBlueprintProjection(canvas);
|
|
19551
19065
|
if (!pair) return "not_applicable";
|
|
19552
|
-
const rendered = renderStyleProjection(await
|
|
19553
|
-
const current = await
|
|
19066
|
+
const rendered = renderStyleProjection(await readFile6(pair.promptPath, "utf8"));
|
|
19067
|
+
const current = await readFile6(pair.stylePath, "utf8").catch(() => null);
|
|
19554
19068
|
if (current === rendered) return "up_to_date";
|
|
19555
|
-
await
|
|
19069
|
+
await writeFile2(pair.stylePath, rendered, "utf8");
|
|
19556
19070
|
log(
|
|
19557
19071
|
"[style] prompt.style.json regenerated from prompt.json \u2014 every frame's shared ad spec changed; affected image frames will re-bill on the next run"
|
|
19558
19072
|
);
|
|
@@ -19612,13 +19126,13 @@ ${body}` : header || body || compactJson(record);
|
|
|
19612
19126
|
}
|
|
19613
19127
|
|
|
19614
19128
|
// src/commands/canvas/run-record.ts
|
|
19615
|
-
import
|
|
19129
|
+
import path7 from "path";
|
|
19616
19130
|
var MAX_RUN_NODES = 200;
|
|
19617
19131
|
var MAX_OUTPUTS_PER_NODE = 10;
|
|
19618
19132
|
var MAX_FINAL_OUTPUTS = 10;
|
|
19619
19133
|
var MAX_CREATIVE_SLUG_LENGTH = 100;
|
|
19620
19134
|
function creativeSlugFromCanvasPath(filePath) {
|
|
19621
|
-
const normalized = filePath.split(
|
|
19135
|
+
const normalized = filePath.split(path7.sep).join("/");
|
|
19622
19136
|
const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
|
|
19623
19137
|
const slug = match?.[1] ?? null;
|
|
19624
19138
|
return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
|
|
@@ -19906,7 +19420,7 @@ var RunRecordPoster = class {
|
|
|
19906
19420
|
|
|
19907
19421
|
// src/commands/canvas/run-retention.ts
|
|
19908
19422
|
import { rm as rm2 } from "fs/promises";
|
|
19909
|
-
import
|
|
19423
|
+
import path8 from "path";
|
|
19910
19424
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
19911
19425
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
19912
19426
|
if (keep <= 0) return runs;
|
|
@@ -19923,7 +19437,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
19923
19437
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
19924
19438
|
if (toPrune.length === 0) return;
|
|
19925
19439
|
for (const dir of toPrune) {
|
|
19926
|
-
await rm2(
|
|
19440
|
+
await rm2(path8.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
19927
19441
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
19928
19442
|
);
|
|
19929
19443
|
}
|
|
@@ -19931,13 +19445,13 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
19931
19445
|
}
|
|
19932
19446
|
|
|
19933
19447
|
// src/commands/canvas/dirty-marker.ts
|
|
19934
|
-
import { mkdir as
|
|
19935
|
-
import
|
|
19448
|
+
import { mkdir as mkdir2, readdir as readdir3, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
19449
|
+
import path9 from "path";
|
|
19936
19450
|
function creativeDirtyDir(base) {
|
|
19937
|
-
return base ??
|
|
19451
|
+
return base ?? path9.resolve("canvas", ".dirty");
|
|
19938
19452
|
}
|
|
19939
19453
|
function dirtyMarkerFile(slug, base) {
|
|
19940
|
-
return
|
|
19454
|
+
return path9.join(creativeDirtyDir(base), `${slug}.json`);
|
|
19941
19455
|
}
|
|
19942
19456
|
async function clearCreativeDirty(slug, base) {
|
|
19943
19457
|
try {
|
|
@@ -19947,18 +19461,18 @@ async function clearCreativeDirty(slug, base) {
|
|
|
19947
19461
|
}
|
|
19948
19462
|
|
|
19949
19463
|
// src/commands/canvas/run-resume.ts
|
|
19950
|
-
import { mkdir as
|
|
19951
|
-
import
|
|
19464
|
+
import { mkdir as mkdir3, readFile as readFile7, rm as rm4, writeFile as writeFile4 } from "fs/promises";
|
|
19465
|
+
import path10 from "path";
|
|
19952
19466
|
function markerKey(canvasPath) {
|
|
19953
19467
|
const slug = creativeSlugFromCanvasPath(canvasPath);
|
|
19954
|
-
const identity = slug ??
|
|
19468
|
+
const identity = slug ?? path10.relative(process.cwd(), path10.resolve(canvasPath));
|
|
19955
19469
|
return sha256Hex(Buffer.from(identity)).slice(0, 32);
|
|
19956
19470
|
}
|
|
19957
19471
|
function legacyMarkerKey(canvasPath) {
|
|
19958
|
-
return sha256Hex(Buffer.from(
|
|
19472
|
+
return sha256Hex(Buffer.from(path10.resolve(canvasPath))).slice(0, 32);
|
|
19959
19473
|
}
|
|
19960
19474
|
function markerFile(outputsDir, key) {
|
|
19961
|
-
return
|
|
19475
|
+
return path10.join(outputsDir, ".inflight", `${key}.json`);
|
|
19962
19476
|
}
|
|
19963
19477
|
var REMOTE_ADOPT_STALE_MS = 12e4;
|
|
19964
19478
|
function classifyRemoteRun(run, now) {
|
|
@@ -19994,7 +19508,7 @@ async function resolveRunId(opts) {
|
|
|
19994
19508
|
async function readMarkerRunId(outputsDir, canvasPath) {
|
|
19995
19509
|
for (const key of [markerKey(canvasPath), legacyMarkerKey(canvasPath)]) {
|
|
19996
19510
|
try {
|
|
19997
|
-
const raw = await
|
|
19511
|
+
const raw = await readFile7(markerFile(outputsDir, key), "utf8");
|
|
19998
19512
|
const parsed = JSON.parse(raw);
|
|
19999
19513
|
if (typeof parsed.runId === "string" && parsed.runId.length > 0) return parsed.runId;
|
|
20000
19514
|
} catch {
|
|
@@ -20005,8 +19519,8 @@ async function readMarkerRunId(outputsDir, canvasPath) {
|
|
|
20005
19519
|
async function markRunInFlight(outputsDir, canvasPath, runId) {
|
|
20006
19520
|
try {
|
|
20007
19521
|
const file = markerFile(outputsDir, markerKey(canvasPath));
|
|
20008
|
-
await
|
|
20009
|
-
await
|
|
19522
|
+
await mkdir3(path10.dirname(file), { recursive: true });
|
|
19523
|
+
await writeFile4(file, JSON.stringify({ runId, canvasPath: path10.resolve(canvasPath), startedAt: Date.now() }));
|
|
20010
19524
|
} catch {
|
|
20011
19525
|
}
|
|
20012
19526
|
}
|
|
@@ -20020,8 +19534,8 @@ async function clearRunMarker(outputsDir, canvasPath) {
|
|
|
20020
19534
|
}
|
|
20021
19535
|
|
|
20022
19536
|
// src/commands/canvas/run-snapshot.ts
|
|
20023
|
-
import { mkdir as
|
|
20024
|
-
import
|
|
19537
|
+
import { mkdir as mkdir4, readdir as readdir4, readFile as readFile8, stat as stat2, writeFile as writeFile5 } from "fs/promises";
|
|
19538
|
+
import path11 from "path";
|
|
20025
19539
|
var SNAPSHOT_SCHEMA = "baker-canvas-snapshot/1";
|
|
20026
19540
|
var MAX_SNAPSHOT_FILE_BYTES = 32 * 1024 * 1024;
|
|
20027
19541
|
var EXT_TO_MIME = {
|
|
@@ -20048,11 +19562,11 @@ var EXT_TO_MIME = {
|
|
|
20048
19562
|
woff2: "font/woff2"
|
|
20049
19563
|
};
|
|
20050
19564
|
function mimeForFile(filePath) {
|
|
20051
|
-
const ext =
|
|
19565
|
+
const ext = path11.extname(filePath).slice(1).toLowerCase();
|
|
20052
19566
|
return EXT_TO_MIME[ext] ?? "application/octet-stream";
|
|
20053
19567
|
}
|
|
20054
19568
|
function toPosix(p) {
|
|
20055
|
-
return p.split(
|
|
19569
|
+
return p.split(path11.sep).join("/");
|
|
20056
19570
|
}
|
|
20057
19571
|
function localPathRefsFromCanvas(parsed) {
|
|
20058
19572
|
const nodes = parsed?.nodes;
|
|
@@ -20077,37 +19591,37 @@ function isSnapshotablePath(value) {
|
|
|
20077
19591
|
async function sourceRefsToSnapshot(canvasDir, parsed) {
|
|
20078
19592
|
const refs = new Set(localPathRefsFromCanvas(parsed));
|
|
20079
19593
|
for (const sceneFile of await listSceneFiles(canvasDir)) {
|
|
20080
|
-
refs.add(toPosix(
|
|
19594
|
+
refs.add(toPosix(path11.relative(canvasDir, sceneFile)));
|
|
20081
19595
|
}
|
|
20082
19596
|
refs.add(REBUILD_FILE);
|
|
20083
19597
|
return [...refs];
|
|
20084
19598
|
}
|
|
20085
19599
|
async function uploadRunSnapshot(client, opts) {
|
|
20086
19600
|
try {
|
|
20087
|
-
const canvasDir =
|
|
19601
|
+
const canvasDir = path11.dirname(opts.canvasPath);
|
|
20088
19602
|
const put = (bytes, mime) => putContentAddressed(client, bytes, mime, opts.signal);
|
|
20089
19603
|
const canvasBytes = Buffer.from(opts.raw);
|
|
20090
19604
|
const canvasUpload = await put(canvasBytes, "application/json");
|
|
20091
19605
|
const files = [];
|
|
20092
19606
|
const skipped = [];
|
|
20093
19607
|
for (const refPath of await sourceRefsToSnapshot(canvasDir, opts.parsed)) {
|
|
20094
|
-
const abs =
|
|
19608
|
+
const abs = path11.isAbsolute(refPath) ? refPath : path11.resolve(canvasDir, refPath);
|
|
20095
19609
|
let st;
|
|
20096
19610
|
try {
|
|
20097
19611
|
st = await stat2(abs);
|
|
20098
19612
|
} catch {
|
|
20099
|
-
skipped.push({ path: toPosix(
|
|
19613
|
+
skipped.push({ path: toPosix(path11.relative(canvasDir, abs)), reason: "missing" });
|
|
20100
19614
|
continue;
|
|
20101
19615
|
}
|
|
20102
19616
|
const fileList = st.isDirectory() ? await listFilesRecursive(abs) : [abs];
|
|
20103
19617
|
for (const file of fileList) {
|
|
20104
|
-
const rel = toPosix(
|
|
19618
|
+
const rel = toPosix(path11.relative(canvasDir, file));
|
|
20105
19619
|
const size = (await stat2(file)).size;
|
|
20106
19620
|
if (size > MAX_SNAPSHOT_FILE_BYTES) {
|
|
20107
19621
|
skipped.push({ path: rel, reason: `too large (${size} bytes)` });
|
|
20108
19622
|
continue;
|
|
20109
19623
|
}
|
|
20110
|
-
const bytes = await
|
|
19624
|
+
const bytes = await readFile8(file);
|
|
20111
19625
|
const upload = await put(bytes, mimeForFile(file));
|
|
20112
19626
|
files.push({ path: rel, sha256: upload.sha256, url: upload.url });
|
|
20113
19627
|
}
|
|
@@ -20116,7 +19630,7 @@ async function uploadRunSnapshot(client, opts) {
|
|
|
20116
19630
|
schema: SNAPSHOT_SCHEMA,
|
|
20117
19631
|
creativeSlug: opts.creativeSlug,
|
|
20118
19632
|
canvasSha: canvasUpload.sha256,
|
|
20119
|
-
canvas: { path:
|
|
19633
|
+
canvas: { path: path11.basename(opts.canvasPath), sha256: canvasUpload.sha256, url: canvasUpload.url },
|
|
20120
19634
|
files,
|
|
20121
19635
|
skipped: skipped.length > 0 ? skipped : void 0
|
|
20122
19636
|
};
|
|
@@ -20143,7 +19657,7 @@ async function putContentAddressed(client, bytes, mime, signal) {
|
|
|
20143
19657
|
}
|
|
20144
19658
|
async function listFilesRecursive(dir) {
|
|
20145
19659
|
const entries = await readdir4(dir, { recursive: true, withFileTypes: true });
|
|
20146
|
-
return entries.filter((d) => d.isFile()).map((d) =>
|
|
19660
|
+
return entries.filter((d) => d.isFile()).map((d) => path11.join(d.parentPath, d.name));
|
|
20147
19661
|
}
|
|
20148
19662
|
var SnapshotConflictError = class extends Error {
|
|
20149
19663
|
conflicts;
|
|
@@ -20155,19 +19669,19 @@ var SnapshotConflictError = class extends Error {
|
|
|
20155
19669
|
};
|
|
20156
19670
|
async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
20157
19671
|
const entries = [manifest.canvas, ...manifest.files];
|
|
20158
|
-
const resolvedTarget =
|
|
19672
|
+
const resolvedTarget = path11.resolve(targetDir);
|
|
20159
19673
|
const planned = [];
|
|
20160
19674
|
const conflicts = [];
|
|
20161
19675
|
const upToDate = [];
|
|
20162
19676
|
for (const entry of entries) {
|
|
20163
|
-
if (
|
|
19677
|
+
if (path11.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
20164
19678
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
20165
19679
|
}
|
|
20166
|
-
const target =
|
|
20167
|
-
if (target !== resolvedTarget && !target.startsWith(resolvedTarget +
|
|
19680
|
+
const target = path11.resolve(resolvedTarget, entry.path);
|
|
19681
|
+
if (target !== resolvedTarget && !target.startsWith(resolvedTarget + path11.sep)) {
|
|
20168
19682
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
20169
19683
|
}
|
|
20170
|
-
const existing = await
|
|
19684
|
+
const existing = await readFile8(target).catch(() => null);
|
|
20171
19685
|
if (existing) {
|
|
20172
19686
|
if (sha256Hex(existing) === entry.sha256) {
|
|
20173
19687
|
upToDate.push(entry.path);
|
|
@@ -20189,15 +19703,15 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
20189
19703
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
20190
19704
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
20191
19705
|
}
|
|
20192
|
-
await
|
|
20193
|
-
await
|
|
19706
|
+
await mkdir4(path11.dirname(target), { recursive: true });
|
|
19707
|
+
await writeFile5(target, bytes);
|
|
20194
19708
|
restored.push(entry.path);
|
|
20195
19709
|
}
|
|
20196
|
-
return { canvasPath:
|
|
19710
|
+
return { canvasPath: path11.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
20197
19711
|
}
|
|
20198
19712
|
|
|
20199
19713
|
// src/commands/canvas/run.ts
|
|
20200
|
-
var runCommand =
|
|
19714
|
+
var runCommand = defineCommand88({
|
|
20201
19715
|
meta: { name: "run", description: "Validate and execute a canvas JSON file." },
|
|
20202
19716
|
args: {
|
|
20203
19717
|
file: { type: "positional", required: true, description: "Path to canvas JSON" },
|
|
@@ -20273,8 +19787,8 @@ function resolveMaxCredits(...candidates) {
|
|
|
20273
19787
|
return void 0;
|
|
20274
19788
|
}
|
|
20275
19789
|
async function executeCanvasRun(opts) {
|
|
20276
|
-
const filePath =
|
|
20277
|
-
const raw = await
|
|
19790
|
+
const filePath = path12.resolve(opts.file);
|
|
19791
|
+
const raw = await readFile9(filePath, "utf8");
|
|
20278
19792
|
let parsed;
|
|
20279
19793
|
try {
|
|
20280
19794
|
parsed = JSON.parse(raw);
|
|
@@ -20286,7 +19800,7 @@ async function executeCanvasRun(opts) {
|
|
|
20286
19800
|
}
|
|
20287
19801
|
const attemptedSlug = creativeSlugFromCanvasPath(filePath);
|
|
20288
19802
|
if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
|
|
20289
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
19803
|
+
parsed = resolveRelativeCanvasPaths(parsed, path12.dirname(filePath));
|
|
20290
19804
|
try {
|
|
20291
19805
|
await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
20292
19806
|
`));
|
|
@@ -20392,7 +19906,7 @@ async function executeCanvasRun(opts) {
|
|
|
20392
19906
|
const canvasSha = sha256Hex(Buffer.from(raw));
|
|
20393
19907
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
20394
19908
|
const client = opts.record === false ? null : buildBackendClient();
|
|
20395
|
-
const outputsDir = opts.outputsDir ?
|
|
19909
|
+
const outputsDir = opts.outputsDir ? path12.resolve(opts.outputsDir) : path12.resolve("canvas");
|
|
20396
19910
|
const { runId, resumed, source, concurrentRunId } = await resolveRunId({
|
|
20397
19911
|
explicitRunId: opts.runId,
|
|
20398
19912
|
fresh: opts.fresh === true,
|
|
@@ -20426,7 +19940,7 @@ async function executeCanvasRun(opts) {
|
|
|
20426
19940
|
const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw, creativeSlug, parsed }) ?? void 0 : void 0;
|
|
20427
19941
|
const recordMeta = {
|
|
20428
19942
|
creativeSlug,
|
|
20429
|
-
canvasPath:
|
|
19943
|
+
canvasPath: path12.relative(process.cwd(), filePath) || void 0,
|
|
20430
19944
|
canvasSha,
|
|
20431
19945
|
// The fingerprint the dashboard compares against the current source to flag
|
|
20432
19946
|
// "edited since last render". Computed from the on-disk canvas.json +
|
|
@@ -20567,7 +20081,7 @@ async function postInitialRunRecord(client, payload) {
|
|
|
20567
20081
|
|
|
20568
20082
|
// src/commands/canvas/rerun.ts
|
|
20569
20083
|
var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
20570
|
-
var rerunCommand =
|
|
20084
|
+
var rerunCommand = defineCommand89({
|
|
20571
20085
|
meta: {
|
|
20572
20086
|
name: "rerun",
|
|
20573
20087
|
description: "Re-run a creative's latest recorded canvas. Restores its definition files from run history first, so it works in a fresh workspace that never had the source chat's files \u2014 an interrupted run resumes (in-flight jobs re-attach), a completed one re-renders from the cache."
|
|
@@ -20596,24 +20110,24 @@ var rerunCommand = defineCommand91({
|
|
|
20596
20110
|
async run({ args }) {
|
|
20597
20111
|
const slug = String(args.slug);
|
|
20598
20112
|
if (!SLUG_PATTERN.test(slug)) {
|
|
20599
|
-
|
|
20113
|
+
fail("invalid_slug", `"${slug}" is not a valid creative slug`);
|
|
20600
20114
|
}
|
|
20601
20115
|
const client = buildBackendClient();
|
|
20602
20116
|
if (!client) {
|
|
20603
|
-
|
|
20117
|
+
fail("missing_credentials", "rerun needs backend credentials (BAKER_API_URL / BAKER_API_KEY)");
|
|
20604
20118
|
}
|
|
20605
20119
|
const latest = await client.getLatestSnapshotRun(slug);
|
|
20606
20120
|
if (!latest) {
|
|
20607
|
-
|
|
20121
|
+
fail(
|
|
20608
20122
|
"no_snapshot_run",
|
|
20609
20123
|
`no rerunnable history for "${slug}" \u2014 the creative was never run by a CLI that records canvas snapshots`
|
|
20610
20124
|
);
|
|
20611
20125
|
}
|
|
20612
20126
|
const manifest = await fetchManifest(latest.canvasSnapshotUrl);
|
|
20613
20127
|
if (latest.canvasSha && manifest.canvasSha !== latest.canvasSha) {
|
|
20614
|
-
|
|
20128
|
+
fail("snapshot_mismatch", `snapshot manifest for run ${latest.runId} does not match its recorded canvas sha`);
|
|
20615
20129
|
}
|
|
20616
|
-
const targetDir =
|
|
20130
|
+
const targetDir = path13.resolve("src", "creatives", slug);
|
|
20617
20131
|
let restoredCanvasPath;
|
|
20618
20132
|
try {
|
|
20619
20133
|
const restore = await restoreRunSnapshot(manifest, targetDir, { force: args["force-remote"] === true });
|
|
@@ -20631,7 +20145,7 @@ var rerunCommand = defineCommand91({
|
|
|
20631
20145
|
}
|
|
20632
20146
|
} catch (e) {
|
|
20633
20147
|
if (e instanceof SnapshotConflictError) {
|
|
20634
|
-
|
|
20148
|
+
fail(
|
|
20635
20149
|
"local_files_differ",
|
|
20636
20150
|
`local files differ from the recorded snapshot: ${e.conflicts.join(", ")}. Re-run with --force-remote to overwrite them, or run the local canvas directly with \`baker canvas run\`.`
|
|
20637
20151
|
);
|
|
@@ -20646,25 +20160,25 @@ var rerunCommand = defineCommand91({
|
|
|
20646
20160
|
});
|
|
20647
20161
|
}
|
|
20648
20162
|
});
|
|
20649
|
-
function
|
|
20163
|
+
function fail(code, message) {
|
|
20650
20164
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
20651
20165
|
`);
|
|
20652
20166
|
process.exit(2);
|
|
20653
20167
|
}
|
|
20654
20168
|
async function fetchManifest(url) {
|
|
20655
20169
|
const res = await fetch(url);
|
|
20656
|
-
if (!res.ok)
|
|
20170
|
+
if (!res.ok) fail("snapshot_unavailable", `snapshot manifest download failed: ${res.status} ${res.statusText}`);
|
|
20657
20171
|
const manifest = await res.json();
|
|
20658
20172
|
if (manifest?.schema !== SNAPSHOT_SCHEMA || typeof manifest.canvas?.path !== "string") {
|
|
20659
|
-
|
|
20173
|
+
fail("snapshot_invalid", "snapshot manifest has an unexpected shape");
|
|
20660
20174
|
}
|
|
20661
20175
|
return manifest;
|
|
20662
20176
|
}
|
|
20663
20177
|
|
|
20664
20178
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
20665
|
-
import { access, mkdir as
|
|
20666
|
-
import
|
|
20667
|
-
import { defineCommand as
|
|
20179
|
+
import { access, mkdir as mkdir5, readFile as readFile11, writeFile as writeFile6 } from "fs/promises";
|
|
20180
|
+
import path17 from "path";
|
|
20181
|
+
import { defineCommand as defineCommand91 } from "citty";
|
|
20668
20182
|
|
|
20669
20183
|
// src/engine/scaffold/staticAd.ts
|
|
20670
20184
|
import { z as z17 } from "zod";
|
|
@@ -20941,7 +20455,7 @@ function staticAdReport(input, elementsInput, opts) {
|
|
|
20941
20455
|
}
|
|
20942
20456
|
|
|
20943
20457
|
// src/commands/canvas/creative-definition.ts
|
|
20944
|
-
import
|
|
20458
|
+
import path14 from "path";
|
|
20945
20459
|
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
20946
20460
|
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
20947
20461
|
function titleFromSlug(slug) {
|
|
@@ -20989,16 +20503,16 @@ function buildCreativeDefinition(input) {
|
|
|
20989
20503
|
}
|
|
20990
20504
|
|
|
20991
20505
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
20992
|
-
import
|
|
20506
|
+
import path15 from "path";
|
|
20993
20507
|
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd(), slug) {
|
|
20994
20508
|
const file = rawFile.trim();
|
|
20995
20509
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
20996
|
-
const imageSource = imageIsUrl ? file :
|
|
20997
|
-
const outPath = out ?
|
|
20998
|
-
const blueprintPath =
|
|
20999
|
-
const creativeDir = slug ?
|
|
21000
|
-
const definitionPath = creativeDir ?
|
|
21001
|
-
const referencesDir = creativeDir ?
|
|
20510
|
+
const imageSource = imageIsUrl ? file : path15.resolve(cwd, file);
|
|
20511
|
+
const outPath = out ? path15.resolve(cwd, out) : slug ? path15.join(cwd, "src", "creatives", slug, `${slug}.canvas.json`) : imageIsUrl ? path15.join(cwd, "static-ad.canvas.json") : path15.join(path15.dirname(imageSource), "static-ad.canvas.json");
|
|
20512
|
+
const blueprintPath = path15.join(path15.dirname(outPath), "prompt.json");
|
|
20513
|
+
const creativeDir = slug ? path15.dirname(outPath) : null;
|
|
20514
|
+
const definitionPath = creativeDir ? path15.join(creativeDir, "_definition.md") : null;
|
|
20515
|
+
const referencesDir = creativeDir ? path15.join(creativeDir, "references") : null;
|
|
21002
20516
|
return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
|
|
21003
20517
|
}
|
|
21004
20518
|
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
@@ -21008,9 +20522,9 @@ function isValidScaffoldSlug(slug) {
|
|
|
21008
20522
|
}
|
|
21009
20523
|
|
|
21010
20524
|
// src/commands/canvas/sync-definition.ts
|
|
21011
|
-
import { readdir as readdir5, readFile as
|
|
21012
|
-
import
|
|
21013
|
-
import { defineCommand as
|
|
20525
|
+
import { readdir as readdir5, readFile as readFile10, stat as stat3 } from "fs/promises";
|
|
20526
|
+
import path16 from "path";
|
|
20527
|
+
import { defineCommand as defineCommand90 } from "citty";
|
|
21014
20528
|
|
|
21015
20529
|
// src/commands/canvas/definition-graph.ts
|
|
21016
20530
|
var MAX_NODES = 300;
|
|
@@ -21102,15 +20616,15 @@ async function syncCreativeDefinitionBestEffort(input) {
|
|
|
21102
20616
|
}
|
|
21103
20617
|
}
|
|
21104
20618
|
async function resolveCanvasPath(inputPath) {
|
|
21105
|
-
const resolved =
|
|
20619
|
+
const resolved = path16.resolve(inputPath);
|
|
21106
20620
|
let dir = resolved;
|
|
21107
20621
|
try {
|
|
21108
20622
|
if ((await stat3(resolved)).isFile()) {
|
|
21109
20623
|
if (resolved.endsWith(".canvas.json")) return resolved;
|
|
21110
|
-
dir =
|
|
20624
|
+
dir = path16.dirname(resolved);
|
|
21111
20625
|
}
|
|
21112
20626
|
} catch {
|
|
21113
|
-
dir = resolved.endsWith(".canvas.json") ?
|
|
20627
|
+
dir = resolved.endsWith(".canvas.json") ? path16.dirname(resolved) : resolved;
|
|
21114
20628
|
}
|
|
21115
20629
|
let entries;
|
|
21116
20630
|
try {
|
|
@@ -21121,9 +20635,9 @@ async function resolveCanvasPath(inputPath) {
|
|
|
21121
20635
|
const canvases = entries.filter((name) => name.endsWith(".canvas.json"));
|
|
21122
20636
|
const slug = creativeSlugFromCanvasPath(`${dir}/x/`);
|
|
21123
20637
|
const chosen = (slug ? canvases.find((name) => name === `${slug}.canvas.json`) : void 0) ?? canvases[0];
|
|
21124
|
-
return chosen ?
|
|
20638
|
+
return chosen ? path16.join(dir, chosen) : null;
|
|
21125
20639
|
}
|
|
21126
|
-
var syncDefinitionCommand =
|
|
20640
|
+
var syncDefinitionCommand = defineCommand90({
|
|
21127
20641
|
meta: {
|
|
21128
20642
|
name: "sync-definition",
|
|
21129
20643
|
description: "Push a creative's current node-graph + input thumbnails to the dashboard without rendering. Runs automatically when you edit a creative's canvas.json or prompt.json."
|
|
@@ -21144,7 +20658,7 @@ var syncDefinitionCommand = defineCommand92({
|
|
|
21144
20658
|
if (!slug) return;
|
|
21145
20659
|
let canvas;
|
|
21146
20660
|
try {
|
|
21147
|
-
canvas = JSON.parse(await
|
|
20661
|
+
canvas = JSON.parse(await readFile10(canvasPath, "utf8"));
|
|
21148
20662
|
} catch {
|
|
21149
20663
|
return;
|
|
21150
20664
|
}
|
|
@@ -21169,7 +20683,7 @@ async function uploadSourceAsReference(source, isUrl, client) {
|
|
|
21169
20683
|
if (!res.ok) throw new Error(`failed to download source image (${res.status})`);
|
|
21170
20684
|
bytes = Buffer.from(await res.arrayBuffer());
|
|
21171
20685
|
} else {
|
|
21172
|
-
bytes = await
|
|
20686
|
+
bytes = await readFile11(source);
|
|
21173
20687
|
}
|
|
21174
20688
|
const safe = await toModelSafeImage(bytes);
|
|
21175
20689
|
const sha256 = sha256Hex(safe.bytes);
|
|
@@ -21224,7 +20738,7 @@ DROP background extras, decorative props, generic scenery, and anything small or
|
|
|
21224
20738
|
For each kept element return: { "type": one of logo|product|person|animal|badge, "label": a short UPPER_SNAKE_CASE name (e.g. LOGO, PRODUCT, HERO_DOG, TRUSTPILOT), "description": a concrete reusable description to source/shoot the real asset (include the exact expression for a living subject, and its castable attributes \u2014 breed/species for an animal, apparent age band, apparent origin/ethnicity, and wardrobe/setting for a person \u2014 so it can be recast to fit OUR audience/market), "expression": the facial expression for a living subject or null, "reason": why it is identity-critical, "locator": the blueprint entry this element came from as { "collection": one of "subjects" | "people" | "brands_logos", "index": its 0-based position in that array } (people -> people; logos/badges -> brands_logos; products/animals/objects -> subjects). Output ONLY the JSON object.`;
|
|
21225
20739
|
async function loadAssetText(ref, label) {
|
|
21226
20740
|
const r = ref;
|
|
21227
|
-
if (typeof r?.path === "string") return
|
|
20741
|
+
if (typeof r?.path === "string") return readFile11(r.path, "utf8");
|
|
21228
20742
|
if (typeof r?.url === "string") {
|
|
21229
20743
|
const res = await fetch(r.url);
|
|
21230
20744
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -21248,7 +20762,7 @@ function parseLayout(raw) {
|
|
|
21248
20762
|
}
|
|
21249
20763
|
return null;
|
|
21250
20764
|
}
|
|
21251
|
-
function
|
|
20765
|
+
function fail2(code, message) {
|
|
21252
20766
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
21253
20767
|
`);
|
|
21254
20768
|
process.exit(2);
|
|
@@ -21339,8 +20853,8 @@ async function runVisionPasses(canvas) {
|
|
|
21339
20853
|
outputsByNode = result.outputs_by_node;
|
|
21340
20854
|
creditsSpent = result.stats?.total_credits;
|
|
21341
20855
|
} catch (e) {
|
|
21342
|
-
if (e instanceof ValidationError) return
|
|
21343
|
-
return
|
|
20856
|
+
if (e instanceof ValidationError) return fail2("validation", JSON.stringify(e.issues));
|
|
20857
|
+
return fail2("describe", e instanceof Error ? e.message : String(e));
|
|
21344
20858
|
}
|
|
21345
20859
|
try {
|
|
21346
20860
|
const blueprint = JSON.parse(await loadAssetText(outputsByNode.describe?.description, "describe output"));
|
|
@@ -21348,10 +20862,10 @@ async function runVisionPasses(canvas) {
|
|
|
21348
20862
|
const layout = parseLayout(await loadAssetText(outputsByNode.layout?.text, "layout output"));
|
|
21349
20863
|
return { blueprint, elements, layout, creditsSpent };
|
|
21350
20864
|
} catch (e) {
|
|
21351
|
-
return
|
|
20865
|
+
return fail2("read_outputs", e instanceof Error ? e.message : String(e));
|
|
21352
20866
|
}
|
|
21353
20867
|
}
|
|
21354
|
-
var scaffoldStaticAdCommand =
|
|
20868
|
+
var scaffoldStaticAdCommand = defineCommand91({
|
|
21355
20869
|
meta: {
|
|
21356
20870
|
name: "scaffold-static-ad",
|
|
21357
20871
|
description: "Turn a source/inspiration image into a runnable static-ad canvas. Runs billed passes \u2014 image_describe (the blueprint, baked to prompt.json as the editable 'prompt'), an AI selection of the image's MAIN identity elements, and a structured global-layout pass (the column/row grid with per-region bounds and text sizes) \u2014 then scaffolds a canvas that wires one [TODO] ingest slot per element (logo/product/subject/badge + brand font) into image_generate. By default it also fans the hero out to the platform's placement ratios (via image_aspect_adapt \u2014 the hero ratio is free, the rest are billed AI recompositions); pass --placements none for a single base ad, or a preset to pick the set. Edit prompt.json and drop the real assets, then `baker canvas run` it."
|
|
@@ -21400,7 +20914,7 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21400
20914
|
process.cwd(),
|
|
21401
20915
|
slug
|
|
21402
20916
|
);
|
|
21403
|
-
await
|
|
20917
|
+
await mkdir5(path17.dirname(outPath), { recursive: true });
|
|
21404
20918
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
21405
20919
|
let durableSourceUrl;
|
|
21406
20920
|
if (referencesDir) {
|
|
@@ -21409,7 +20923,7 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21409
20923
|
try {
|
|
21410
20924
|
durableSourceUrl = await uploadSourceAsReference(imageSource, imageIsUrl, client);
|
|
21411
20925
|
} catch (e) {
|
|
21412
|
-
return
|
|
20926
|
+
return fail2("source_unavailable", e instanceof Error ? e.message : String(e));
|
|
21413
20927
|
}
|
|
21414
20928
|
}
|
|
21415
20929
|
}
|
|
@@ -21426,7 +20940,7 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21426
20940
|
if (layout && annotated && typeof annotated === "object") {
|
|
21427
20941
|
annotated.layout = layout;
|
|
21428
20942
|
}
|
|
21429
|
-
await
|
|
20943
|
+
await writeFile6(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
21430
20944
|
`, "utf8");
|
|
21431
20945
|
let canvasImagePath = imageSource;
|
|
21432
20946
|
let canvasImageIsUrl = imageIsUrl;
|
|
@@ -21443,7 +20957,7 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21443
20957
|
args.placements ? String(args.placements) : void 0,
|
|
21444
20958
|
definitionPlatform
|
|
21445
20959
|
);
|
|
21446
|
-
if (!placementsResult.ok) return
|
|
20960
|
+
if (!placementsResult.ok) return fail2("invalid_placements", placementsResult.message);
|
|
21447
20961
|
const placements = placementsResult.placements;
|
|
21448
20962
|
const opts = {
|
|
21449
20963
|
genModel,
|
|
@@ -21461,7 +20975,7 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21461
20975
|
canvas = scaffoldStaticAd(blueprint, elements, opts);
|
|
21462
20976
|
report = staticAdReport(blueprint, elements, opts);
|
|
21463
20977
|
} catch (e) {
|
|
21464
|
-
return
|
|
20978
|
+
return fail2("scaffold", e instanceof Error ? e.message : String(e));
|
|
21465
20979
|
}
|
|
21466
20980
|
const validation = await validateCanvasDeep(canvas, defaultRegistry());
|
|
21467
20981
|
if (!validation.ok) {
|
|
@@ -21471,10 +20985,10 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21471
20985
|
);
|
|
21472
20986
|
process.exit(2);
|
|
21473
20987
|
}
|
|
21474
|
-
await
|
|
20988
|
+
await writeFile6(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
21475
20989
|
`, "utf8");
|
|
21476
20990
|
if (definitionPath && !await fileExists(definitionPath)) {
|
|
21477
|
-
await
|
|
20991
|
+
await writeFile6(
|
|
21478
20992
|
definitionPath,
|
|
21479
20993
|
buildCreativeDefinition({
|
|
21480
20994
|
title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
|
|
@@ -21520,7 +21034,7 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21520
21034
|
run_estimated_credits: validation.estimatedCredits
|
|
21521
21035
|
},
|
|
21522
21036
|
checklist: {
|
|
21523
|
-
edit_prompt: `Edit ${
|
|
21037
|
+
edit_prompt: `Edit ${path17.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
|
|
21524
21038
|
assets_to_supply: report.elements,
|
|
21525
21039
|
font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path (the describe pass recorded the ad's typefaces under `fonts` in prompt.json \u2014 match those). The font is wired into the render as a TYPE SPECIMEN reference so generated text takes the brand letterforms. Delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
|
|
21526
21040
|
actor_sheets: report.actor_sheets.length > 0 ? `Each living hero (${report.actor_sheets.join(", ")}) is fused into a generated multi-view reference sheet (image_reference_sheet) that the render grounds on \u2014 so drop ONE clean photo at that hero's ingest and the sheet builds the consistent turnaround. Pass --skip-actor-sheets to ground on the lone photo instead.` : "none (no person/animal heroes detected, or --skip-actor-sheets)",
|
|
@@ -21537,10 +21051,10 @@ var scaffoldStaticAdCommand = defineCommand93({
|
|
|
21537
21051
|
});
|
|
21538
21052
|
|
|
21539
21053
|
// src/commands/canvas/scaffold-video.ts
|
|
21540
|
-
import { access as access2, cp, mkdir as
|
|
21054
|
+
import { access as access2, cp, mkdir as mkdir6, readFile as readFile14, rm as rm6, writeFile as writeFile7 } from "fs/promises";
|
|
21541
21055
|
import { tmpdir as tmpdir2 } from "os";
|
|
21542
|
-
import
|
|
21543
|
-
import { defineCommand as
|
|
21056
|
+
import path20 from "path";
|
|
21057
|
+
import { defineCommand as defineCommand92 } from "citty";
|
|
21544
21058
|
|
|
21545
21059
|
// src/engine/scaffold/lib/model-router.ts
|
|
21546
21060
|
var SEEDANCE = "bytedance/seedance-2.0";
|
|
@@ -21578,7 +21092,7 @@ function routeVideoModel(input) {
|
|
|
21578
21092
|
|
|
21579
21093
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
21580
21094
|
import { execFile as execFile2 } from "child_process";
|
|
21581
|
-
import { mkdtemp, readdir as readdir6, readFile as
|
|
21095
|
+
import { mkdtemp, readdir as readdir6, readFile as readFile12, rm as rm5 } from "fs/promises";
|
|
21582
21096
|
import { tmpdir } from "os";
|
|
21583
21097
|
import { join as join2 } from "path";
|
|
21584
21098
|
import { promisify as promisify2 } from "util";
|
|
@@ -21654,7 +21168,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
21654
21168
|
);
|
|
21655
21169
|
const csvName = (await readdir6(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
21656
21170
|
if (!csvName) return [];
|
|
21657
|
-
return parsePySceneDetectCsvCuts(await
|
|
21171
|
+
return parsePySceneDetectCsvCuts(await readFile12(join2(outDir, csvName), "utf-8"));
|
|
21658
21172
|
} finally {
|
|
21659
21173
|
await rm5(outDir, { recursive: true, force: true });
|
|
21660
21174
|
}
|
|
@@ -21679,23 +21193,23 @@ async function detectSceneCutsPySceneDetect(filePath, opts = {}) {
|
|
|
21679
21193
|
|
|
21680
21194
|
// src/commands/canvas/composition-path.ts
|
|
21681
21195
|
import { existsSync as existsSync3 } from "fs";
|
|
21682
|
-
import
|
|
21196
|
+
import path18 from "path";
|
|
21683
21197
|
function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
|
|
21684
|
-
const rel =
|
|
21198
|
+
const rel = path18.join("canvas", name);
|
|
21685
21199
|
let dir = startDir;
|
|
21686
21200
|
for (let i = 0; i < maxDepth; i++) {
|
|
21687
|
-
const candidate =
|
|
21688
|
-
if (exists(
|
|
21689
|
-
const parent =
|
|
21201
|
+
const candidate = path18.join(dir, rel);
|
|
21202
|
+
if (exists(path18.join(candidate, "meta.json"))) return candidate;
|
|
21203
|
+
const parent = path18.dirname(dir);
|
|
21690
21204
|
if (parent === dir) break;
|
|
21691
21205
|
dir = parent;
|
|
21692
21206
|
}
|
|
21693
|
-
return
|
|
21207
|
+
return path18.resolve(startDir, "../../../", rel);
|
|
21694
21208
|
}
|
|
21695
21209
|
|
|
21696
21210
|
// src/commands/canvas/gitignore.ts
|
|
21697
|
-
import { appendFile, readFile as
|
|
21698
|
-
import
|
|
21211
|
+
import { appendFile, readFile as readFile13 } from "fs/promises";
|
|
21212
|
+
import path19 from "path";
|
|
21699
21213
|
function missingGitignoreEntries(existing, entries) {
|
|
21700
21214
|
const present2 = new Set(
|
|
21701
21215
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -21703,10 +21217,10 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
21703
21217
|
return entries.filter((e) => !present2.has(e.trim().replace(/\/+$/, "")));
|
|
21704
21218
|
}
|
|
21705
21219
|
async function ensureGitignore(dir, entries) {
|
|
21706
|
-
const file =
|
|
21220
|
+
const file = path19.join(dir, ".gitignore");
|
|
21707
21221
|
let existing;
|
|
21708
21222
|
try {
|
|
21709
|
-
existing = await
|
|
21223
|
+
existing = await readFile13(file, "utf8");
|
|
21710
21224
|
} catch {
|
|
21711
21225
|
return;
|
|
21712
21226
|
}
|
|
@@ -21745,7 +21259,7 @@ ONE PERSON, MULTIPLE LOOKS: if a single individual plays MULTIPLE personas or wa
|
|
|
21745
21259
|
For each kept element return: { "type": one of person|animal|product|logo|badge|location, "label": a short UPPER_SNAKE_CASE name (e.g. HERO, CREATOR_SKEPTIC, INSURANCE_CARD, LOGO), "description": a concrete reusable description to source/shoot the real asset \u2014 for a person/animal give a NEUTRAL castable role (e.g. "hero pet-owner, woman in her 30s" or "a small beagle"), NOT the original individual's literal face/identity: we RECAST with a FRESH person/animal, so never tell the agent to reuse the original. "expression": a living subject's typical expression or null, "cast_id": the global.cast id if it maps to one else null, "same_as": the label of another element this is the SAME individual as (different wardrobe/persona) else null, "scenes": the 0-based indices of ONLY the scenes where the element is ACTUALLY VISIBLE ON SCREEN \u2014 judged from that scene's start_frame_prompt / end_frame_prompt subjects and its action_detail, NOT from who is merely speaking. A narrator heard over b-roll is NOT present in that b-roll scene; a dog-running cutaway does NOT contain the couch creator just because she talks across it. Do NOT pad the list \u2014 an element wrongly listed in a scene makes the reproduction render the wrong subject there (e.g. the creator appearing in a pure-dog b-roll). When in doubt, leave a scene OUT. Output ONLY the JSON object.`;
|
|
21746
21260
|
async function loadAssetText2(ref, label) {
|
|
21747
21261
|
const r = ref;
|
|
21748
|
-
if (typeof r?.path === "string") return
|
|
21262
|
+
if (typeof r?.path === "string") return readFile14(r.path, "utf8");
|
|
21749
21263
|
if (typeof r?.url === "string") {
|
|
21750
21264
|
const res = await fetch(r.url);
|
|
21751
21265
|
if (!res.ok) throw new Error(`failed to fetch ${label} (${res.status})`);
|
|
@@ -21764,7 +21278,7 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
21764
21278
|
async function stageCaptions(outDir, transcript) {
|
|
21765
21279
|
const text = transcript?.trim();
|
|
21766
21280
|
if (!text || text === "[]") return {};
|
|
21767
|
-
const compositionPath =
|
|
21281
|
+
const compositionPath = path20.join(outDir, "tiktok-captions-composition");
|
|
21768
21282
|
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
21769
21283
|
return { compositionPath };
|
|
21770
21284
|
}
|
|
@@ -21782,12 +21296,12 @@ function patchCompositionHtml(html, dims) {
|
|
|
21782
21296
|
return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
|
|
21783
21297
|
}
|
|
21784
21298
|
async function stampCompositionDims(compositionDir, dims) {
|
|
21785
|
-
const metaPath =
|
|
21786
|
-
const rawMeta = await
|
|
21787
|
-
await
|
|
21788
|
-
const htmlPath =
|
|
21789
|
-
const rawHtml = await
|
|
21790
|
-
await
|
|
21299
|
+
const metaPath = path20.join(compositionDir, "meta.json");
|
|
21300
|
+
const rawMeta = await readFile14(metaPath, "utf8");
|
|
21301
|
+
await writeFile7(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
21302
|
+
const htmlPath = path20.join(compositionDir, "index.html");
|
|
21303
|
+
const rawHtml = await readFile14(htmlPath, "utf8");
|
|
21304
|
+
await writeFile7(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
21791
21305
|
}
|
|
21792
21306
|
function parseElements2(raw) {
|
|
21793
21307
|
const parsed = JSON.parse(raw);
|
|
@@ -21822,7 +21336,7 @@ async function detectShotCutsBestEffort(videoPath, threshold) {
|
|
|
21822
21336
|
return void 0;
|
|
21823
21337
|
}
|
|
21824
21338
|
}
|
|
21825
|
-
function
|
|
21339
|
+
function fail3(code, message) {
|
|
21826
21340
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code, message } }, null, 2)}
|
|
21827
21341
|
`);
|
|
21828
21342
|
process.exit(2);
|
|
@@ -21834,7 +21348,7 @@ var VIDEO_EXT_BY_MIME = {
|
|
|
21834
21348
|
"video/x-matroska": ".mkv"
|
|
21835
21349
|
};
|
|
21836
21350
|
function referenceVideoExt(url, contentType) {
|
|
21837
|
-
const fromPath =
|
|
21351
|
+
const fromPath = path20.extname(new URL(url).pathname).toLowerCase();
|
|
21838
21352
|
if (fromPath && fromPath.length <= 5) return fromPath;
|
|
21839
21353
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
21840
21354
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
@@ -21860,7 +21374,7 @@ function videoDefinitionDescription(blueprint) {
|
|
|
21860
21374
|
return typeof product === "string" && product.trim() ? product.trim() : void 0;
|
|
21861
21375
|
}
|
|
21862
21376
|
async function materializeReferenceVideo(fileArg2) {
|
|
21863
|
-
if (!/^https?:\/\//i.test(fileArg2)) return
|
|
21377
|
+
if (!/^https?:\/\//i.test(fileArg2)) return path20.resolve(fileArg2);
|
|
21864
21378
|
let res;
|
|
21865
21379
|
try {
|
|
21866
21380
|
res = await fetch(fileArg2);
|
|
@@ -21870,11 +21384,11 @@ async function materializeReferenceVideo(fileArg2) {
|
|
|
21870
21384
|
if (!res.ok) throw new Error(`failed to download reference video (${res.status} ${res.statusText})`);
|
|
21871
21385
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
21872
21386
|
if (bytes.length === 0) throw new Error("reference video download was empty");
|
|
21873
|
-
const dest =
|
|
21387
|
+
const dest = path20.join(
|
|
21874
21388
|
tmpdir2(),
|
|
21875
21389
|
`baker-ref-${sha256Hex(bytes).slice(0, 16)}${referenceVideoExt(fileArg2, res.headers.get("content-type"))}`
|
|
21876
21390
|
);
|
|
21877
|
-
await
|
|
21391
|
+
await writeFile7(dest, bytes);
|
|
21878
21392
|
return dest;
|
|
21879
21393
|
}
|
|
21880
21394
|
function resolveSeamDedup(raw) {
|
|
@@ -21982,9 +21496,9 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
|
|
|
21982
21496
|
blueprint = JSON.parse(await loadAssetText2(r1.outputs_by_node.deconstruct?.analysis, "deconstruct output"));
|
|
21983
21497
|
transcript = await loadTranscriptBestEffort(r1.outputs_by_node.deconstruct?.transcript);
|
|
21984
21498
|
} catch (e) {
|
|
21985
|
-
if (e instanceof ValidationError) return
|
|
21986
|
-
if (e instanceof SyntaxError) return
|
|
21987
|
-
return
|
|
21499
|
+
if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
|
|
21500
|
+
if (e instanceof SyntaxError) return fail3("read_outputs", e.message);
|
|
21501
|
+
return fail3("deconstruct", e instanceof Error ? e.message : String(e));
|
|
21988
21502
|
}
|
|
21989
21503
|
const slimJson = JSON.stringify(slimBlueprintForSelection(blueprint));
|
|
21990
21504
|
try {
|
|
@@ -21993,12 +21507,12 @@ async function runAnalysisPasses(deconstructCanvas, selectModel) {
|
|
|
21993
21507
|
const elements = parseElements2(await loadAssetText2(r2.outputs_by_node.select?.text, "selection output"));
|
|
21994
21508
|
return { blueprint, elements, transcript, creditsSpent: sawCredits ? credits : void 0 };
|
|
21995
21509
|
} catch (e) {
|
|
21996
|
-
if (e instanceof ValidationError) return
|
|
21997
|
-
if (e instanceof SyntaxError) return
|
|
21998
|
-
return
|
|
21510
|
+
if (e instanceof ValidationError) return fail3("validation", JSON.stringify(e.issues));
|
|
21511
|
+
if (e instanceof SyntaxError) return fail3("read_outputs", e.message);
|
|
21512
|
+
return fail3("deconstruct", e instanceof Error ? e.message : String(e));
|
|
21999
21513
|
}
|
|
22000
21514
|
}
|
|
22001
|
-
var scaffoldVideoCommand =
|
|
21515
|
+
var scaffoldVideoCommand = defineCommand92({
|
|
22002
21516
|
meta: {
|
|
22003
21517
|
name: "scaffold-video",
|
|
22004
21518
|
description: "Turn a reference video into a runnable reproduction canvas in one command. Runs billed passes \u2014 video_deconstruct (the full scene-by-scene blueprint + transcript, baked to a split, editable blueprint: a global prompt.json plus one small scenes/sNN.json per scene) and an AI selection of the video's RECURRING identity elements (person/animal/product/logo) \u2014 then scaffolds a pipeline where every scene boundary is a static-ad-grade frame (the blueprint as target_blueprint, a reference legend, the real frame as anchor) and each recurring element gets ONE shared [TODO] ingest slot wired into every frame it appears in. The clips feed Seedance an ultra-detailed motion brief (action, camera, dialogue, transcript). Edit a scene's scenes/sNN.json (or prompt.json for global cast/palette/brand), drop the real source images, then `baker canvas run`."
|
|
@@ -22079,7 +21593,7 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22079
21593
|
}
|
|
22080
21594
|
const isUrl = /^https?:\/\//i.test(fileArg2);
|
|
22081
21595
|
if (isUrl && !slug && !args.out) {
|
|
22082
|
-
return
|
|
21596
|
+
return fail3(
|
|
22083
21597
|
"missing_output_target",
|
|
22084
21598
|
"When the reference is a URL, pass --slug (writes src/creatives/<slug>/) or --out <path> so the scaffolded canvas has a home in the repo."
|
|
22085
21599
|
);
|
|
@@ -22088,13 +21602,13 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22088
21602
|
try {
|
|
22089
21603
|
videoPath = await materializeReferenceVideo(fileArg2);
|
|
22090
21604
|
} catch (e) {
|
|
22091
|
-
return
|
|
21605
|
+
return fail3("download", e instanceof Error ? e.message : String(e));
|
|
22092
21606
|
}
|
|
22093
|
-
const base =
|
|
22094
|
-
const outPath = args.out ?
|
|
22095
|
-
const outDir =
|
|
22096
|
-
const blueprintPath =
|
|
22097
|
-
const blueprintStylePath =
|
|
21607
|
+
const base = path20.basename(videoPath, path20.extname(videoPath));
|
|
21608
|
+
const outPath = args.out ? path20.resolve(String(args.out)) : slug ? path20.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path20.join(path20.dirname(videoPath), `${base}.video.canvas.json`);
|
|
21609
|
+
const outDir = path20.dirname(outPath);
|
|
21610
|
+
const blueprintPath = path20.join(outDir, "prompt.json");
|
|
21611
|
+
const blueprintStylePath = path20.join(outDir, "prompt.style.json");
|
|
22098
21612
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
22099
21613
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
22100
21614
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -22118,10 +21632,10 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22118
21632
|
process.stderr.write(`\u{1F3AC} Photoreal on-camera cast detected \u2192 generating clips on ${videoModel} (dodges Seedance's real-person filter).
|
|
22119
21633
|
`);
|
|
22120
21634
|
}
|
|
22121
|
-
await
|
|
21635
|
+
await mkdir6(outDir, { recursive: true });
|
|
22122
21636
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
22123
21637
|
await writeSceneFiles(outDir, annotated);
|
|
22124
|
-
await
|
|
21638
|
+
await writeFile7(blueprintStylePath, renderStyleProjectionFromValue(annotated), "utf8");
|
|
22125
21639
|
let aspect;
|
|
22126
21640
|
try {
|
|
22127
21641
|
aspect = resolveAspect(
|
|
@@ -22130,7 +21644,7 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22130
21644
|
genAspectsFor(videoModel)
|
|
22131
21645
|
);
|
|
22132
21646
|
} catch (e) {
|
|
22133
|
-
return
|
|
21647
|
+
return fail3("aspect", e instanceof Error ? e.message : String(e));
|
|
22134
21648
|
}
|
|
22135
21649
|
const outDims = canvasDims(aspect.outAr);
|
|
22136
21650
|
if (aspect.remapped) {
|
|
@@ -22139,29 +21653,29 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22139
21653
|
`
|
|
22140
21654
|
);
|
|
22141
21655
|
}
|
|
22142
|
-
const compositionDest =
|
|
21656
|
+
const compositionDest = path20.join(outDir, "video-overlay-composition");
|
|
22143
21657
|
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
22144
21658
|
await stampCompositionDims(compositionDest, outDims);
|
|
22145
|
-
const indexPath =
|
|
21659
|
+
const indexPath = path20.join(compositionDest, "index.html");
|
|
22146
21660
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
|
|
22147
|
-
const indexHtml = await
|
|
21661
|
+
const indexHtml = await readFile14(indexPath, "utf8");
|
|
22148
21662
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
22149
21663
|
if (injected === indexHtml && overlayHtml.trim()) {
|
|
22150
|
-
|
|
21664
|
+
fail3(
|
|
22151
21665
|
"composition_marker_missing",
|
|
22152
21666
|
`video-overlay-composition/index.html is missing the <!--OVERLAYS--> marker \u2014 cannot inject the overlay layer`
|
|
22153
21667
|
);
|
|
22154
21668
|
}
|
|
22155
|
-
await
|
|
21669
|
+
await writeFile7(indexPath, injected, "utf8");
|
|
22156
21670
|
const captions = await stageCaptions(outDir, transcript);
|
|
22157
21671
|
if (captions.compositionPath) await stampCompositionDims(captions.compositionPath, outDims);
|
|
22158
21672
|
const opts = {
|
|
22159
21673
|
imageModel,
|
|
22160
21674
|
videoModel,
|
|
22161
|
-
overlayCompositionPath:
|
|
22162
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
22163
|
-
blueprintPath:
|
|
22164
|
-
blueprintStylePath:
|
|
21675
|
+
overlayCompositionPath: path20.relative(outDir, compositionDest),
|
|
21676
|
+
captionsCompositionPath: captions.compositionPath ? path20.relative(outDir, captions.compositionPath) : void 0,
|
|
21677
|
+
blueprintPath: path20.relative(outDir, blueprintPath),
|
|
21678
|
+
blueprintStylePath: path20.relative(outDir, blueprintStylePath),
|
|
22165
21679
|
frames,
|
|
22166
21680
|
ambient: Boolean(args.ambient),
|
|
22167
21681
|
seamDedup: resolveSeamDedup(args["seam-dedup"]),
|
|
@@ -22174,7 +21688,7 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22174
21688
|
canvas = scaffoldVideoCanvas(blueprint, elements, opts);
|
|
22175
21689
|
report = videoReport(blueprint, elements);
|
|
22176
21690
|
} catch (e) {
|
|
22177
|
-
return
|
|
21691
|
+
return fail3("scaffold", e instanceof Error ? e.message : String(e));
|
|
22178
21692
|
}
|
|
22179
21693
|
if (captions.compositionPath && !canvas.nodes.some((n) => n.id === "captions")) {
|
|
22180
21694
|
await rm6(captions.compositionPath, { recursive: true, force: true });
|
|
@@ -22186,10 +21700,10 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22186
21700
|
todo.blocking_validation_issues = validation.issues;
|
|
22187
21701
|
meta.todo = todo;
|
|
22188
21702
|
}
|
|
22189
|
-
await
|
|
21703
|
+
await writeFile7(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
22190
21704
|
`, "utf8");
|
|
22191
|
-
await
|
|
22192
|
-
|
|
21705
|
+
await writeFile7(
|
|
21706
|
+
path20.join(outDir, REBUILD_FILE),
|
|
22193
21707
|
`${JSON.stringify({ elements, opts }, null, 2)}
|
|
22194
21708
|
`,
|
|
22195
21709
|
"utf8"
|
|
@@ -22214,9 +21728,9 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22214
21728
|
await ensureGitignore(process.cwd(), ["canvas/", ".context/"]);
|
|
22215
21729
|
const sourceRef = videoSourceReference(blueprint, fileArg2);
|
|
22216
21730
|
if (slug) {
|
|
22217
|
-
const definitionPath =
|
|
21731
|
+
const definitionPath = path20.join(outDir, "_definition.md");
|
|
22218
21732
|
if (!await fileExists2(definitionPath)) {
|
|
22219
|
-
await
|
|
21733
|
+
await writeFile7(
|
|
22220
21734
|
definitionPath,
|
|
22221
21735
|
buildCreativeDefinition({
|
|
22222
21736
|
title: titleFromSlug(slug),
|
|
@@ -22269,7 +21783,7 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22269
21783
|
graph: canvas.metadata?.video?.graph_stats
|
|
22270
21784
|
},
|
|
22271
21785
|
checklist: {
|
|
22272
|
-
edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${
|
|
21786
|
+
edit_prompt: `The blueprint is split so you edit ONE small file at a time \u2014 never a giant one. Per-scene content (a scene's dialogue, action, frame prompts, overlays) lives in \`scenes/sNN.json\` \u2014 edit the single scene you want to change. Global cast/palette/brand/copy lives in \`${path20.basename(blueprintPath)}\`. \`baker canvas validate\`/\`run\` re-assemble the blueprint and re-flow every edited scene back into the render (and regenerate ${path20.basename(blueprintStylePath)}, the projection each frame's target_blueprint reads) \u2014 so your scene edits reach the render automatically. Never hand-edit the inlined node prompts in the canvas or the derived ${path20.basename(blueprintStylePath)}; both are regenerated.`,
|
|
22273
21787
|
recurring_elements_to_supply: report.elements,
|
|
22274
21788
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
22275
21789
|
scene: d.scene,
|
|
@@ -22306,9 +21820,9 @@ var scaffoldVideoCommand = defineCommand94({
|
|
|
22306
21820
|
});
|
|
22307
21821
|
|
|
22308
21822
|
// src/commands/canvas/set-prompt.ts
|
|
22309
|
-
import { readFile as
|
|
22310
|
-
import
|
|
22311
|
-
import { defineCommand as
|
|
21823
|
+
import { readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
|
|
21824
|
+
import path21 from "path";
|
|
21825
|
+
import { defineCommand as defineCommand93 } from "citty";
|
|
22312
21826
|
function setNodePrompt(canvas, nodeId, text) {
|
|
22313
21827
|
const nodes = canvas?.nodes;
|
|
22314
21828
|
if (!Array.isArray(nodes)) throw new Error("canvas has no nodes array");
|
|
@@ -22323,7 +21837,7 @@ function setNodePrompt(canvas, nodeId, text) {
|
|
|
22323
21837
|
newNodes[idx] = newNode;
|
|
22324
21838
|
return { ...canvas, nodes: newNodes };
|
|
22325
21839
|
}
|
|
22326
|
-
var setPromptCommand =
|
|
21840
|
+
var setPromptCommand = defineCommand93({
|
|
22327
21841
|
meta: {
|
|
22328
21842
|
name: "set-prompt",
|
|
22329
21843
|
description: "Safely set a node's params.prompt (a frame description, motion prompt, etc.) without hand-editing the JSON. Prefer --text-file for multi-line/accented copy \u2014 it preserves UTF-8 exactly, unlike shell-quoted jq."
|
|
@@ -22335,17 +21849,17 @@ var setPromptCommand = defineCommand95({
|
|
|
22335
21849
|
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
22336
21850
|
},
|
|
22337
21851
|
async run({ args }) {
|
|
22338
|
-
const filePath =
|
|
21852
|
+
const filePath = path21.resolve(String(args.file));
|
|
22339
21853
|
let canvas;
|
|
22340
21854
|
try {
|
|
22341
|
-
canvas = JSON.parse(await
|
|
21855
|
+
canvas = JSON.parse(await readFile15(filePath, "utf8"));
|
|
22342
21856
|
} catch (e) {
|
|
22343
21857
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "parse", message: String(e) } }, null, 2)}
|
|
22344
21858
|
`);
|
|
22345
21859
|
process.exit(2);
|
|
22346
21860
|
}
|
|
22347
21861
|
let text;
|
|
22348
|
-
if (args["text-file"]) text = await
|
|
21862
|
+
if (args["text-file"]) text = await readFile15(path21.resolve(String(args["text-file"])), "utf8");
|
|
22349
21863
|
else if (args.text !== void 0) text = String(args.text);
|
|
22350
21864
|
else {
|
|
22351
21865
|
process.stderr.write(
|
|
@@ -22366,14 +21880,14 @@ var setPromptCommand = defineCommand95({
|
|
|
22366
21880
|
process.exit(2);
|
|
22367
21881
|
return;
|
|
22368
21882
|
}
|
|
22369
|
-
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated,
|
|
21883
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path21.dirname(filePath)), defaultRegistry());
|
|
22370
21884
|
if (!validation.ok) {
|
|
22371
21885
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
22372
21886
|
`);
|
|
22373
21887
|
process.exit(2);
|
|
22374
21888
|
return;
|
|
22375
21889
|
}
|
|
22376
|
-
await
|
|
21890
|
+
await writeFile8(filePath, `${JSON.stringify(updated, null, 2)}
|
|
22377
21891
|
`, "utf8");
|
|
22378
21892
|
process.stdout.write(`${JSON.stringify({ ok: true, node: String(args.node), bytes: text.length }, null, 2)}
|
|
22379
21893
|
`);
|
|
@@ -22381,18 +21895,18 @@ var setPromptCommand = defineCommand95({
|
|
|
22381
21895
|
});
|
|
22382
21896
|
|
|
22383
21897
|
// src/commands/canvas/validate.ts
|
|
22384
|
-
import { readFile as
|
|
22385
|
-
import
|
|
22386
|
-
import { defineCommand as
|
|
22387
|
-
var validateCommand =
|
|
21898
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
21899
|
+
import path22 from "path";
|
|
21900
|
+
import { defineCommand as defineCommand94 } from "citty";
|
|
21901
|
+
var validateCommand = defineCommand94({
|
|
22388
21902
|
meta: {
|
|
22389
21903
|
name: "validate",
|
|
22390
21904
|
description: "Validate a canvas JSON file (no execution). Includes a per-node cost preview and runs each node's deep validators (composition meta checks for hyperframe_render/_snapshot)."
|
|
22391
21905
|
},
|
|
22392
21906
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
22393
21907
|
async run({ args }) {
|
|
22394
|
-
const filePath =
|
|
22395
|
-
const raw = await
|
|
21908
|
+
const filePath = path22.resolve(String(args.file));
|
|
21909
|
+
const raw = await readFile16(filePath, "utf8");
|
|
22396
21910
|
let parsed;
|
|
22397
21911
|
try {
|
|
22398
21912
|
parsed = JSON.parse(raw);
|
|
@@ -22402,7 +21916,7 @@ var validateCommand = defineCommand96({
|
|
|
22402
21916
|
`);
|
|
22403
21917
|
process.exit(2);
|
|
22404
21918
|
}
|
|
22405
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
21919
|
+
parsed = resolveRelativeCanvasPaths(parsed, path22.dirname(filePath));
|
|
22406
21920
|
let styleProjection = "not_applicable";
|
|
22407
21921
|
try {
|
|
22408
21922
|
styleProjection = await syncStyleProjection(parsed, (line) => process.stderr.write(`${line}
|
|
@@ -22454,7 +21968,7 @@ var validateCommand = defineCommand96({
|
|
|
22454
21968
|
});
|
|
22455
21969
|
|
|
22456
21970
|
// src/commands/canvas/index.ts
|
|
22457
|
-
var canvasCommand =
|
|
21971
|
+
var canvasCommand = defineCommand95({
|
|
22458
21972
|
meta: {
|
|
22459
21973
|
name: "canvas",
|
|
22460
21974
|
description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
|
|
@@ -22488,7 +22002,7 @@ Full guide: __tooling__/docs/tools/baker/canvas.md`
|
|
|
22488
22002
|
});
|
|
22489
22003
|
|
|
22490
22004
|
// src/commands/chats/index.ts
|
|
22491
|
-
import { defineCommand as
|
|
22005
|
+
import { defineCommand as defineCommand96 } from "citty";
|
|
22492
22006
|
var STATUS_GROUPS = ["active", "archived", "all"];
|
|
22493
22007
|
var REPO_SURFACES = ["knowledge", "company", "brand", "landings", "flows", "creatives"];
|
|
22494
22008
|
function parseBoundedInt(raw, name, min, max) {
|
|
@@ -22510,7 +22024,7 @@ registerSchema({
|
|
|
22510
22024
|
full: { type: "boolean", description: "Include each Session's full change list", required: false, default: false }
|
|
22511
22025
|
}
|
|
22512
22026
|
});
|
|
22513
|
-
var listCommand5 =
|
|
22027
|
+
var listCommand5 = defineCommand96({
|
|
22514
22028
|
meta: { name: "list", description: "List other Sessions on this account, newest first." },
|
|
22515
22029
|
args: {
|
|
22516
22030
|
status: { type: "string", description: "Filter: active|archived|all (default: all)", required: false },
|
|
@@ -22565,7 +22079,7 @@ registerSchema({
|
|
|
22565
22079
|
}
|
|
22566
22080
|
}
|
|
22567
22081
|
});
|
|
22568
|
-
var viewCommand =
|
|
22082
|
+
var viewCommand = defineCommand96({
|
|
22569
22083
|
meta: {
|
|
22570
22084
|
name: "view",
|
|
22571
22085
|
description: "Inspect one Session's full effects \u2014 git content + actions/tags/ads, kickoff, commits."
|
|
@@ -22609,7 +22123,7 @@ registerSchema({
|
|
|
22609
22123
|
}
|
|
22610
22124
|
}
|
|
22611
22125
|
});
|
|
22612
|
-
var transcriptCommand =
|
|
22126
|
+
var transcriptCommand = defineCommand96({
|
|
22613
22127
|
meta: { name: "transcript", description: "Read another Session's conversation." },
|
|
22614
22128
|
args: {
|
|
22615
22129
|
id: { type: "positional", description: "The Session id", required: true },
|
|
@@ -22661,7 +22175,7 @@ registerSchema({
|
|
|
22661
22175
|
}
|
|
22662
22176
|
}
|
|
22663
22177
|
});
|
|
22664
|
-
var diffCommand =
|
|
22178
|
+
var diffCommand = defineCommand96({
|
|
22665
22179
|
meta: { name: "diff", description: "See a published Session's real file-level changes." },
|
|
22666
22180
|
args: {
|
|
22667
22181
|
id: { type: "positional", description: "The Session id", required: true },
|
|
@@ -22705,7 +22219,7 @@ var diffCommand = defineCommand98({
|
|
|
22705
22219
|
}
|
|
22706
22220
|
}
|
|
22707
22221
|
});
|
|
22708
|
-
var chatsCommand =
|
|
22222
|
+
var chatsCommand = defineCommand96({
|
|
22709
22223
|
meta: {
|
|
22710
22224
|
name: "chats",
|
|
22711
22225
|
description: `Inspect other Sessions on this account (read-only): list them, view what they produced, read their conversation, and see their real file changes \u2014 so you can reuse past work for a new goal.
|
|
@@ -22720,13 +22234,13 @@ Full guide: __tooling__/docs/tools/baker/chats.md`
|
|
|
22720
22234
|
});
|
|
22721
22235
|
|
|
22722
22236
|
// src/commands/creatives/index.ts
|
|
22723
|
-
import { defineCommand as
|
|
22237
|
+
import { defineCommand as defineCommand98 } from "citty";
|
|
22724
22238
|
|
|
22725
22239
|
// src/commands/creatives/publish.ts
|
|
22726
|
-
import { defineCommand as
|
|
22240
|
+
import { defineCommand as defineCommand97 } from "citty";
|
|
22727
22241
|
|
|
22728
22242
|
// src/commands/images/api.ts
|
|
22729
|
-
import { readFile as
|
|
22243
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
22730
22244
|
import { extname } from "path";
|
|
22731
22245
|
var imageProcessingTimeoutMs = 18e4;
|
|
22732
22246
|
var imageReadyPollIntervalMs = 2e3;
|
|
@@ -22740,7 +22254,7 @@ var mimeMap = {
|
|
|
22740
22254
|
".avif": "image/avif"
|
|
22741
22255
|
};
|
|
22742
22256
|
var defaultImageApiDeps = {
|
|
22743
|
-
readFile:
|
|
22257
|
+
readFile: readFile17,
|
|
22744
22258
|
post: apiPost,
|
|
22745
22259
|
get: apiGet,
|
|
22746
22260
|
sleep: (ms) => new Promise((resolve5) => setTimeout(resolve5, ms))
|
|
@@ -22867,7 +22381,7 @@ async function publishCreative(args, deps = defaultImageApiDeps) {
|
|
|
22867
22381
|
chatId: chatIdFromEnv()
|
|
22868
22382
|
});
|
|
22869
22383
|
}
|
|
22870
|
-
var publishCommand =
|
|
22384
|
+
var publishCommand = defineCommand97({
|
|
22871
22385
|
meta: {
|
|
22872
22386
|
name: "publish",
|
|
22873
22387
|
description: "Publish a final static creative image to Baker Creatives and print the creative reference JSON."
|
|
@@ -22925,7 +22439,7 @@ var publishCommand = defineCommand99({
|
|
|
22925
22439
|
});
|
|
22926
22440
|
|
|
22927
22441
|
// src/commands/creatives/index.ts
|
|
22928
|
-
var creativesCommand3 =
|
|
22442
|
+
var creativesCommand3 = defineCommand98({
|
|
22929
22443
|
meta: {
|
|
22930
22444
|
name: "creatives",
|
|
22931
22445
|
description: `Publish static ad creatives as first-class Baker outputs.
|
|
@@ -22942,7 +22456,7 @@ Full guide: __tooling__/docs/tools/baker/creatives.md`
|
|
|
22942
22456
|
});
|
|
22943
22457
|
|
|
22944
22458
|
// src/commands/flows/index.ts
|
|
22945
|
-
import { defineCommand as
|
|
22459
|
+
import { defineCommand as defineCommand99 } from "citty";
|
|
22946
22460
|
|
|
22947
22461
|
// src/commands/flows/shared.ts
|
|
22948
22462
|
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
|
|
@@ -22975,12 +22489,12 @@ function listFlowSlugs() {
|
|
|
22975
22489
|
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
|
|
22976
22490
|
}
|
|
22977
22491
|
function readFlowTree(slug) {
|
|
22978
|
-
const
|
|
22979
|
-
if (!existsSync4(
|
|
22492
|
+
const path27 = join3(flowsDir(), slug, "_data.json");
|
|
22493
|
+
if (!existsSync4(path27)) {
|
|
22980
22494
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
22981
22495
|
}
|
|
22982
22496
|
try {
|
|
22983
|
-
return JSON.parse(readFileSync9(
|
|
22497
|
+
return JSON.parse(readFileSync9(path27, "utf-8"));
|
|
22984
22498
|
} catch (error) {
|
|
22985
22499
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
22986
22500
|
}
|
|
@@ -23097,7 +22611,7 @@ function displayName(slug) {
|
|
|
23097
22611
|
const name = tree.displayName;
|
|
23098
22612
|
return typeof name === "string" && name.trim() ? name.trim() : slug;
|
|
23099
22613
|
}
|
|
23100
|
-
var listCommand6 =
|
|
22614
|
+
var listCommand6 = defineCommand99({
|
|
23101
22615
|
meta: {
|
|
23102
22616
|
name: "list",
|
|
23103
22617
|
description: "List Forms in this workspace with the count of confidential fields still needing setup. Example: baker flows list"
|
|
@@ -23111,7 +22625,7 @@ var listCommand6 = defineCommand101({
|
|
|
23111
22625
|
writeJson({ ok: true, data: { flows } });
|
|
23112
22626
|
}
|
|
23113
22627
|
});
|
|
23114
|
-
var showCommand2 =
|
|
22628
|
+
var showCommand2 = defineCommand99({
|
|
23115
22629
|
meta: {
|
|
23116
22630
|
name: "show",
|
|
23117
22631
|
description: "Show a Form's confidential fields and their configuration status (never secret values). Example: baker flows show contact"
|
|
@@ -23132,7 +22646,7 @@ var showCommand2 = defineCommand101({
|
|
|
23132
22646
|
writeJson({ ok: true, data: response });
|
|
23133
22647
|
}
|
|
23134
22648
|
});
|
|
23135
|
-
var flowsCommand =
|
|
22649
|
+
var flowsCommand = defineCommand99({
|
|
23136
22650
|
meta: {
|
|
23137
22651
|
name: "flows",
|
|
23138
22652
|
description: `Read this workspace's Forms (flows) and the configuration status of their confidential fields \u2014 connection secrets, OAuth connections, and third-party field definitions (HubSpot, Calendly, HighLevel, SavvyCal).
|
|
@@ -23160,10 +22674,10 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
23160
22674
|
});
|
|
23161
22675
|
|
|
23162
22676
|
// src/commands/ga4/index.ts
|
|
23163
|
-
import { defineCommand as
|
|
22677
|
+
import { defineCommand as defineCommand103 } from "citty";
|
|
23164
22678
|
|
|
23165
22679
|
// src/commands/ga4/audit.ts
|
|
23166
|
-
import { defineCommand as
|
|
22680
|
+
import { defineCommand as defineCommand100 } from "citty";
|
|
23167
22681
|
|
|
23168
22682
|
// src/commands/ga4/resolve.ts
|
|
23169
22683
|
async function fetchProperties(useCache = true) {
|
|
@@ -23226,7 +22740,7 @@ registerSchema({
|
|
|
23226
22740
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23227
22741
|
}
|
|
23228
22742
|
});
|
|
23229
|
-
var auditCommand2 =
|
|
22743
|
+
var auditCommand2 = defineCommand100({
|
|
23230
22744
|
meta: {
|
|
23231
22745
|
name: "audit",
|
|
23232
22746
|
description: `Run all GA4 admin health checks. Returns property config with playbook warnings.
|
|
@@ -23278,7 +22792,7 @@ Examples:
|
|
|
23278
22792
|
});
|
|
23279
22793
|
|
|
23280
22794
|
// src/commands/ga4/properties.ts
|
|
23281
|
-
import { defineCommand as
|
|
22795
|
+
import { defineCommand as defineCommand101 } from "citty";
|
|
23282
22796
|
registerSchema({
|
|
23283
22797
|
command: "ga4.properties",
|
|
23284
22798
|
description: "List all accessible GA4 properties. Returns property IDs needed for query and audit commands. Run this first to find property IDs.",
|
|
@@ -23286,7 +22800,7 @@ registerSchema({
|
|
|
23286
22800
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23287
22801
|
}
|
|
23288
22802
|
});
|
|
23289
|
-
var propertiesCommand =
|
|
22803
|
+
var propertiesCommand = defineCommand101({
|
|
23290
22804
|
meta: {
|
|
23291
22805
|
name: "properties",
|
|
23292
22806
|
description: `List accessible GA4 properties.
|
|
@@ -23336,7 +22850,7 @@ Examples:
|
|
|
23336
22850
|
// src/commands/ga4/query.ts
|
|
23337
22851
|
import { appendFileSync as appendFileSync2, existsSync as existsSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync3 } from "fs";
|
|
23338
22852
|
import { resolve as resolve2 } from "path";
|
|
23339
|
-
import { defineCommand as
|
|
22853
|
+
import { defineCommand as defineCommand102 } from "citty";
|
|
23340
22854
|
|
|
23341
22855
|
// src/commands/ga4/presets.ts
|
|
23342
22856
|
var GA4_PRESETS = [
|
|
@@ -23468,7 +22982,7 @@ function handleError(err) {
|
|
|
23468
22982
|
});
|
|
23469
22983
|
process.exit(1);
|
|
23470
22984
|
}
|
|
23471
|
-
var queryCommand2 =
|
|
22985
|
+
var queryCommand2 = defineCommand102({
|
|
23472
22986
|
meta: {
|
|
23473
22987
|
name: "query",
|
|
23474
22988
|
description: `Run GA4 Data API reports. Preset-first with free-form escape hatch.
|
|
@@ -23539,7 +23053,7 @@ Free-form (escape hatch):
|
|
|
23539
23053
|
});
|
|
23540
23054
|
|
|
23541
23055
|
// src/commands/ga4/index.ts
|
|
23542
|
-
var ga4Command =
|
|
23056
|
+
var ga4Command = defineCommand103({
|
|
23543
23057
|
meta: {
|
|
23544
23058
|
name: "ga4",
|
|
23545
23059
|
description: `Google Analytics 4 commands. Audit property config, run playbook-aligned reports.
|
|
@@ -23563,12 +23077,12 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
23563
23077
|
});
|
|
23564
23078
|
|
|
23565
23079
|
// src/commands/gsc/index.ts
|
|
23566
|
-
import { defineCommand as
|
|
23080
|
+
import { defineCommand as defineCommand107 } from "citty";
|
|
23567
23081
|
|
|
23568
23082
|
// src/commands/gsc/query.ts
|
|
23569
23083
|
import { appendFileSync as appendFileSync3, existsSync as existsSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
|
|
23570
23084
|
import { resolve as resolve3 } from "path";
|
|
23571
|
-
import { defineCommand as
|
|
23085
|
+
import { defineCommand as defineCommand104 } from "citty";
|
|
23572
23086
|
|
|
23573
23087
|
// src/commands/gsc/presets.ts
|
|
23574
23088
|
var GSC_PRESETS = [
|
|
@@ -23756,7 +23270,7 @@ function handleError2(err) {
|
|
|
23756
23270
|
});
|
|
23757
23271
|
process.exit(1);
|
|
23758
23272
|
}
|
|
23759
|
-
var queryCommand3 =
|
|
23273
|
+
var queryCommand3 = defineCommand104({
|
|
23760
23274
|
meta: {
|
|
23761
23275
|
name: "query",
|
|
23762
23276
|
description: `Run GSC Search Analytics queries. Preset-first with free-form escape hatch.
|
|
@@ -23834,7 +23348,7 @@ Free-form (escape hatch):
|
|
|
23834
23348
|
});
|
|
23835
23349
|
|
|
23836
23350
|
// src/commands/gsc/sitemaps.ts
|
|
23837
|
-
import { defineCommand as
|
|
23351
|
+
import { defineCommand as defineCommand105 } from "citty";
|
|
23838
23352
|
registerSchema({
|
|
23839
23353
|
command: "gsc.sitemaps",
|
|
23840
23354
|
description: "List sitemaps for a Search Console site. Check sitemap health and errors.",
|
|
@@ -23843,7 +23357,7 @@ registerSchema({
|
|
|
23843
23357
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23844
23358
|
}
|
|
23845
23359
|
});
|
|
23846
|
-
var sitemapsCommand =
|
|
23360
|
+
var sitemapsCommand = defineCommand105({
|
|
23847
23361
|
meta: {
|
|
23848
23362
|
name: "sitemaps",
|
|
23849
23363
|
description: `List sitemaps for a site. Check health and errors.
|
|
@@ -23893,7 +23407,7 @@ Examples:
|
|
|
23893
23407
|
});
|
|
23894
23408
|
|
|
23895
23409
|
// src/commands/gsc/sites.ts
|
|
23896
|
-
import { defineCommand as
|
|
23410
|
+
import { defineCommand as defineCommand106 } from "citty";
|
|
23897
23411
|
registerSchema({
|
|
23898
23412
|
command: "gsc.sites",
|
|
23899
23413
|
description: "List all verified Google Search Console sites. Returns site URLs needed for query and sitemaps commands.",
|
|
@@ -23901,7 +23415,7 @@ registerSchema({
|
|
|
23901
23415
|
"no-cache": { type: "boolean", description: "Skip cache, hit API directly", required: false }
|
|
23902
23416
|
}
|
|
23903
23417
|
});
|
|
23904
|
-
var sitesCommand =
|
|
23418
|
+
var sitesCommand = defineCommand106({
|
|
23905
23419
|
meta: {
|
|
23906
23420
|
name: "sites",
|
|
23907
23421
|
description: `List verified Search Console sites.
|
|
@@ -23949,7 +23463,7 @@ Examples:
|
|
|
23949
23463
|
});
|
|
23950
23464
|
|
|
23951
23465
|
// src/commands/gsc/index.ts
|
|
23952
|
-
var gscCommand =
|
|
23466
|
+
var gscCommand = defineCommand107({
|
|
23953
23467
|
meta: {
|
|
23954
23468
|
name: "gsc",
|
|
23955
23469
|
description: `Google Search Console commands. PPC-SEO arbitrage, brand halo analysis, negative keyword discovery.
|
|
@@ -23973,7 +23487,7 @@ Full guide: __tooling__/docs/tools/baker/gsc.md`
|
|
|
23973
23487
|
});
|
|
23974
23488
|
|
|
23975
23489
|
// src/commands/history/index.ts
|
|
23976
|
-
import { defineCommand as
|
|
23490
|
+
import { defineCommand as defineCommand108 } from "citty";
|
|
23977
23491
|
registerSchema({
|
|
23978
23492
|
command: "history.list",
|
|
23979
23493
|
description: "Start here: unified account history (audit log) \u2014 everything that changed on this account, newest first: publishes, chat lifecycle, backlog actions, team changes, setup links, tags, schedules, ad-platform writes, followed advertisers, media, creatives, reports, domains, and integrations. Use it to see what happened recently before planning work. Compact by default; add --full for raw metadata per entry.",
|
|
@@ -24028,7 +23542,7 @@ function parseBoundedInt2(raw, name, min, max) {
|
|
|
24028
23542
|
}
|
|
24029
23543
|
return value;
|
|
24030
23544
|
}
|
|
24031
|
-
var listCommand7 =
|
|
23545
|
+
var listCommand7 = defineCommand108({
|
|
24032
23546
|
meta: {
|
|
24033
23547
|
name: "list",
|
|
24034
23548
|
description: "List recent account changes (unified audit log), newest first."
|
|
@@ -24074,7 +23588,7 @@ var listCommand7 = defineCommand110({
|
|
|
24074
23588
|
}
|
|
24075
23589
|
}
|
|
24076
23590
|
});
|
|
24077
|
-
var historyCommand =
|
|
23591
|
+
var historyCommand = defineCommand108({
|
|
24078
23592
|
meta: {
|
|
24079
23593
|
name: "history",
|
|
24080
23594
|
description: `Unified account history (audit log): what changed, who did it, and when.
|
|
@@ -24084,10 +23598,10 @@ Full guide: __tooling__/docs/tools/baker/history.md`
|
|
|
24084
23598
|
});
|
|
24085
23599
|
|
|
24086
23600
|
// src/commands/images/index.ts
|
|
24087
|
-
import { defineCommand as
|
|
23601
|
+
import { defineCommand as defineCommand132 } from "citty";
|
|
24088
23602
|
|
|
24089
23603
|
// src/commands/images/crop.ts
|
|
24090
|
-
import { defineCommand as
|
|
23604
|
+
import { defineCommand as defineCommand109 } from "citty";
|
|
24091
23605
|
|
|
24092
23606
|
// src/lib/image/crop-sprite.ts
|
|
24093
23607
|
import sharp from "sharp";
|
|
@@ -24102,7 +23616,7 @@ function cropSprite(input, region) {
|
|
|
24102
23616
|
|
|
24103
23617
|
// src/lib/image/io.ts
|
|
24104
23618
|
import { randomBytes } from "crypto";
|
|
24105
|
-
import { glob as fsGlob, readFile as
|
|
23619
|
+
import { glob as fsGlob, readFile as readFile18, rename, stat as stat4, writeFile as writeFile9 } from "fs/promises";
|
|
24106
23620
|
import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
|
|
24107
23621
|
var REMOTE_RE = /^https?:\/\//i;
|
|
24108
23622
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -24138,11 +23652,11 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
24138
23652
|
}
|
|
24139
23653
|
return Buffer.from(await response.arrayBuffer());
|
|
24140
23654
|
}
|
|
24141
|
-
return
|
|
23655
|
+
return readFile18(pathOrUrl);
|
|
24142
23656
|
}
|
|
24143
|
-
async function isDirectory(
|
|
23657
|
+
async function isDirectory(path27) {
|
|
24144
23658
|
try {
|
|
24145
|
-
const s = await stat4(
|
|
23659
|
+
const s = await stat4(path27);
|
|
24146
23660
|
return s.isDirectory();
|
|
24147
23661
|
} catch {
|
|
24148
23662
|
return false;
|
|
@@ -24161,7 +23675,7 @@ async function atomicWrite(targetPath, data) {
|
|
|
24161
23675
|
const absolute = resolve4(targetPath);
|
|
24162
23676
|
const dir = dirname2(absolute);
|
|
24163
23677
|
const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
24164
|
-
await
|
|
23678
|
+
await writeFile9(tmp, data);
|
|
24165
23679
|
await rename(tmp, absolute);
|
|
24166
23680
|
}
|
|
24167
23681
|
|
|
@@ -24212,7 +23726,7 @@ function emitError2(err) {
|
|
|
24212
23726
|
}
|
|
24213
23727
|
process.exit(1);
|
|
24214
23728
|
}
|
|
24215
|
-
var cropCommand =
|
|
23729
|
+
var cropCommand = defineCommand109({
|
|
24216
23730
|
meta: {
|
|
24217
23731
|
name: "crop",
|
|
24218
23732
|
description: "Crop a rectangular region from an image.\n\nExample: baker images crop sprite.png --x 0 --y 0 --width 64 --height 64 --output icon.png"
|
|
@@ -24248,7 +23762,7 @@ var cropCommand = defineCommand111({
|
|
|
24248
23762
|
});
|
|
24249
23763
|
|
|
24250
23764
|
// src/commands/images/delete.ts
|
|
24251
|
-
import { defineCommand as
|
|
23765
|
+
import { defineCommand as defineCommand110 } from "citty";
|
|
24252
23766
|
registerSchema({
|
|
24253
23767
|
command: "images.delete",
|
|
24254
23768
|
description: "Delete an image by ID",
|
|
@@ -24262,7 +23776,7 @@ registerSchema({
|
|
|
24262
23776
|
}
|
|
24263
23777
|
}
|
|
24264
23778
|
});
|
|
24265
|
-
var deleteCommand =
|
|
23779
|
+
var deleteCommand = defineCommand110({
|
|
24266
23780
|
meta: {
|
|
24267
23781
|
name: "delete",
|
|
24268
23782
|
description: "Delete an image by ID. Use --dry-run to preview. Example: baker images delete j571abc123 --dry-run"
|
|
@@ -24303,7 +23817,7 @@ var deleteCommand = defineCommand112({
|
|
|
24303
23817
|
});
|
|
24304
23818
|
|
|
24305
23819
|
// src/commands/images/dimensions.ts
|
|
24306
|
-
import { defineCommand as
|
|
23820
|
+
import { defineCommand as defineCommand111 } from "citty";
|
|
24307
23821
|
|
|
24308
23822
|
// src/lib/image/dimensions.ts
|
|
24309
23823
|
import { imageSize } from "image-size";
|
|
@@ -24326,7 +23840,7 @@ registerSchema({
|
|
|
24326
23840
|
target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
|
|
24327
23841
|
}
|
|
24328
23842
|
});
|
|
24329
|
-
var dimensionsCommand =
|
|
23843
|
+
var dimensionsCommand = defineCommand111({
|
|
24330
23844
|
meta: {
|
|
24331
23845
|
name: "dimensions",
|
|
24332
23846
|
description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
|
|
@@ -24370,7 +23884,7 @@ var dimensionsCommand = defineCommand113({
|
|
|
24370
23884
|
});
|
|
24371
23885
|
|
|
24372
23886
|
// src/commands/images/extract.ts
|
|
24373
|
-
import { defineCommand as
|
|
23887
|
+
import { defineCommand as defineCommand112 } from "citty";
|
|
24374
23888
|
registerSchema({
|
|
24375
23889
|
command: "images.extract",
|
|
24376
23890
|
description: "Extract images from a URL via Firecrawl (formats: images).",
|
|
@@ -24386,7 +23900,7 @@ registerSchema({
|
|
|
24386
23900
|
}
|
|
24387
23901
|
}
|
|
24388
23902
|
});
|
|
24389
|
-
var extractCommand =
|
|
23903
|
+
var extractCommand = defineCommand112({
|
|
24390
23904
|
meta: {
|
|
24391
23905
|
name: "extract",
|
|
24392
23906
|
description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5"
|
|
@@ -24424,7 +23938,7 @@ var extractCommand = defineCommand114({
|
|
|
24424
23938
|
});
|
|
24425
23939
|
|
|
24426
23940
|
// src/commands/images/find.ts
|
|
24427
|
-
import { defineCommand as
|
|
23941
|
+
import { defineCommand as defineCommand113 } from "citty";
|
|
24428
23942
|
registerSchema({
|
|
24429
23943
|
command: "images.find",
|
|
24430
23944
|
description: "Fanout image search: library first, then opted-in external providers.",
|
|
@@ -24456,7 +23970,7 @@ registerSchema({
|
|
|
24456
23970
|
}
|
|
24457
23971
|
}
|
|
24458
23972
|
});
|
|
24459
|
-
var findCommand =
|
|
23973
|
+
var findCommand = defineCommand113({
|
|
24460
23974
|
meta: {
|
|
24461
23975
|
name: "find",
|
|
24462
23976
|
description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin. With --auto-ingest, ingested external hits return Baker-owned URLs.\n\nExample: baker images find 'office' --sources library,magnific --limit 20"
|
|
@@ -24504,8 +24018,8 @@ var findCommand = defineCommand115({
|
|
|
24504
24018
|
});
|
|
24505
24019
|
|
|
24506
24020
|
// src/commands/images/generate.ts
|
|
24507
|
-
import { readFile as
|
|
24508
|
-
import { defineCommand as
|
|
24021
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
24022
|
+
import { defineCommand as defineCommand114 } from "citty";
|
|
24509
24023
|
import sharp2 from "sharp";
|
|
24510
24024
|
var GENERATE_TIMEOUT_MS = 18e4;
|
|
24511
24025
|
var REFERENCE_MAX_EDGE = 1536;
|
|
@@ -24594,7 +24108,7 @@ async function resolveReferences(spec) {
|
|
|
24594
24108
|
}
|
|
24595
24109
|
let raw;
|
|
24596
24110
|
try {
|
|
24597
|
-
raw = await
|
|
24111
|
+
raw = await readFile19(entry);
|
|
24598
24112
|
} catch {
|
|
24599
24113
|
throw new ApiError("VALIDATION_ERROR", `Reference file not found: ${entry}`);
|
|
24600
24114
|
}
|
|
@@ -24608,7 +24122,7 @@ async function resolveReferences(spec) {
|
|
|
24608
24122
|
}
|
|
24609
24123
|
return out;
|
|
24610
24124
|
}
|
|
24611
|
-
var generateCommand =
|
|
24125
|
+
var generateCommand = defineCommand114({
|
|
24612
24126
|
meta: {
|
|
24613
24127
|
name: "generate",
|
|
24614
24128
|
description: "Generate an image with AI and store it in the library (cost-tracked per request via OpenRouter usage). Models mirror the canvas: google/gemini-3.1-flash-image-preview (Nano Banana flash \u2014 default, fast, extreme aspect ratios), google/gemini-3-pro-image-preview (Nano Banana Pro \u2014 highest fidelity), openai/gpt-image-2 (photoreal, cleanest in-image text, best for ad/landing reproduction \u2014 no --image-size, and no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/SVG-style with palette control). The result is auto-ingested (describe + embed), so the next `baker images library` query finds it. Pass --reference with image URLs and/or local file paths (Pinterest, stock, brand assets, sandbox files) to ground generation in reality.\n\nExamples:\n baker images generate 'a friendly golden retriever sitting in a bright modern living room' --aspect-ratio 16:9\n baker images generate 'hero shot of a matte black water bottle on marble' --model openai/gpt-image-2 --aspect-ratio 3:2\n baker images generate 'lifestyle photo matching this mood' --reference 'https://\u2026/ref1.jpg,https://\u2026/ref2.jpg'\n baker images generate 'put this product on a marble countertop, soft daylight' --reference './src/brand/logos/product.png,./refs/kitchen-mood.jpg'\n baker images generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
|
|
@@ -24660,7 +24174,7 @@ var generateCommand = defineCommand116({
|
|
|
24660
24174
|
});
|
|
24661
24175
|
|
|
24662
24176
|
// src/commands/images/get.ts
|
|
24663
|
-
import { defineCommand as
|
|
24177
|
+
import { defineCommand as defineCommand115 } from "citty";
|
|
24664
24178
|
registerSchema({
|
|
24665
24179
|
command: "images.get",
|
|
24666
24180
|
description: "Get a single image by ID",
|
|
@@ -24668,7 +24182,7 @@ registerSchema({
|
|
|
24668
24182
|
id: { type: "string", description: "Image ID", required: true }
|
|
24669
24183
|
}
|
|
24670
24184
|
});
|
|
24671
|
-
var getCommand2 =
|
|
24185
|
+
var getCommand2 = defineCommand115({
|
|
24672
24186
|
meta: { name: "get", description: "Get a single image by ID. Example: baker images get j571abc123" },
|
|
24673
24187
|
args: {
|
|
24674
24188
|
id: { type: "positional", description: "Image ID", required: false },
|
|
@@ -24704,7 +24218,7 @@ var getCommand2 = defineCommand117({
|
|
|
24704
24218
|
});
|
|
24705
24219
|
|
|
24706
24220
|
// src/commands/images/gif.ts
|
|
24707
|
-
import { defineCommand as
|
|
24221
|
+
import { defineCommand as defineCommand116 } from "citty";
|
|
24708
24222
|
registerSchema({
|
|
24709
24223
|
command: "images.gif",
|
|
24710
24224
|
description: "Search Giphy for GIFs / reaction memes (paid social creative).",
|
|
@@ -24736,7 +24250,7 @@ registerSchema({
|
|
|
24736
24250
|
}
|
|
24737
24251
|
}
|
|
24738
24252
|
});
|
|
24739
|
-
var gifCommand =
|
|
24253
|
+
var gifCommand = defineCommand116({
|
|
24740
24254
|
meta: {
|
|
24741
24255
|
name: "gif",
|
|
24742
24256
|
description: "Search Giphy for GIFs / reaction memes \u2014 built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API. Each hit carries WebP + GIF + MP4 URLs in providerMeta so you can pick the right format per platform.\n\nExample: baker images gif 'this is fine' --limit 10\nExample: baker images gif 'office reaction' --rating pg --auto-ingest 2\nExample: baker images gif --trending --limit 25"
|
|
@@ -24783,7 +24297,7 @@ var gifCommand = defineCommand118({
|
|
|
24783
24297
|
});
|
|
24784
24298
|
|
|
24785
24299
|
// src/commands/images/google.ts
|
|
24786
|
-
import { defineCommand as
|
|
24300
|
+
import { defineCommand as defineCommand117 } from "citty";
|
|
24787
24301
|
|
|
24788
24302
|
// src/commands/images/searchHints.ts
|
|
24789
24303
|
var FALLBACK = {
|
|
@@ -24847,7 +24361,7 @@ registerSchema({
|
|
|
24847
24361
|
}
|
|
24848
24362
|
}
|
|
24849
24363
|
});
|
|
24850
|
-
var googleCommand2 =
|
|
24364
|
+
var googleCommand2 = defineCommand117({
|
|
24851
24365
|
meta: {
|
|
24852
24366
|
name: "google",
|
|
24853
24367
|
description: "Google Images via the official Custom Search JSON API ($0.005/query, free 100/day). \u26A0 Source unverified \u2014 watermarks, low-res, mislabeled results are common. Use as last resort. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExample: baker images google 'industrial workshop' --type photo --size large --limit 20"
|
|
@@ -24903,7 +24417,7 @@ var googleCommand2 = defineCommand119({
|
|
|
24903
24417
|
});
|
|
24904
24418
|
|
|
24905
24419
|
// src/commands/images/icon.ts
|
|
24906
|
-
import { defineCommand as
|
|
24420
|
+
import { defineCommand as defineCommand118 } from "citty";
|
|
24907
24421
|
registerSchema({
|
|
24908
24422
|
command: "images.icon",
|
|
24909
24423
|
description: "Icon lookup via Iconify (200+ icon sets, free CDN).",
|
|
@@ -24929,7 +24443,7 @@ registerSchema({
|
|
|
24929
24443
|
}
|
|
24930
24444
|
}
|
|
24931
24445
|
});
|
|
24932
|
-
var iconCommand =
|
|
24446
|
+
var iconCommand = defineCommand118({
|
|
24933
24447
|
meta: {
|
|
24934
24448
|
name: "icon",
|
|
24935
24449
|
description: "Icon via Iconify (simple-icons, logos, lucide, devicon, heroicons, tabler, phosphor, material-symbols, \u2026). Free CDN, no API key.\n\nExample: baker images icon react --set devicon\nExample: baker images icon lucide:check --color '#0a0a0a'"
|
|
@@ -24969,7 +24483,7 @@ var iconCommand = defineCommand120({
|
|
|
24969
24483
|
});
|
|
24970
24484
|
|
|
24971
24485
|
// src/commands/images/ingest.ts
|
|
24972
|
-
import { defineCommand as
|
|
24486
|
+
import { defineCommand as defineCommand119 } from "citty";
|
|
24973
24487
|
registerSchema({
|
|
24974
24488
|
command: "images.ingest",
|
|
24975
24489
|
description: "Ingest a remote image URL into the library (full describe + embed).",
|
|
@@ -24981,7 +24495,7 @@ registerSchema({
|
|
|
24981
24495
|
context: { type: "string", description: "Description context hint", required: false }
|
|
24982
24496
|
}
|
|
24983
24497
|
});
|
|
24984
|
-
var ingestCommand =
|
|
24498
|
+
var ingestCommand = defineCommand119({
|
|
24985
24499
|
meta: {
|
|
24986
24500
|
name: "ingest",
|
|
24987
24501
|
description: "Download a remote URL and store it in the library. Hash-deduped on bytes + externalId.\n\nExample: baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345"
|
|
@@ -25023,7 +24537,7 @@ var ingestCommand = defineCommand121({
|
|
|
25023
24537
|
});
|
|
25024
24538
|
|
|
25025
24539
|
// src/commands/images/library.ts
|
|
25026
|
-
import { defineCommand as
|
|
24540
|
+
import { defineCommand as defineCommand120 } from "citty";
|
|
25027
24541
|
registerSchema({
|
|
25028
24542
|
command: "images.library",
|
|
25029
24543
|
description: "Search the company image library. Returns only ready images.",
|
|
@@ -25049,7 +24563,7 @@ registerSchema({
|
|
|
25049
24563
|
}
|
|
25050
24564
|
}
|
|
25051
24565
|
});
|
|
25052
|
-
var libraryCommand =
|
|
24566
|
+
var libraryCommand = defineCommand120({
|
|
25053
24567
|
meta: {
|
|
25054
24568
|
name: "library",
|
|
25055
24569
|
description: "Search the company image library (hybrid BM25 + vector + Cohere rerank). Use this BEFORE any external provider.\n\nExample: baker images library 'hero banner' --aspect-ratio 16:9 --source magnific"
|
|
@@ -25106,7 +24620,7 @@ var libraryCommand = defineCommand122({
|
|
|
25106
24620
|
});
|
|
25107
24621
|
|
|
25108
24622
|
// src/commands/images/logo.ts
|
|
25109
|
-
import { defineCommand as
|
|
24623
|
+
import { defineCommand as defineCommand121 } from "citty";
|
|
25110
24624
|
registerSchema({
|
|
25111
24625
|
command: "images.logo",
|
|
25112
24626
|
description: "Brand logo lookup via Brandfetch CDN (fallback/404). Auto-ingests by default.",
|
|
@@ -25131,7 +24645,7 @@ registerSchema({
|
|
|
25131
24645
|
}
|
|
25132
24646
|
}
|
|
25133
24647
|
});
|
|
25134
|
-
var logoCommand =
|
|
24648
|
+
var logoCommand = defineCommand121({
|
|
25135
24649
|
meta: {
|
|
25136
24650
|
name: "logo",
|
|
25137
24651
|
description: "Brand logo via Brandfetch CDN. Returns up to 5 variants (icon, light/dark logo, light/dark symbol). Auto-ingests the first variant.\n\nExample: baker images logo stripe.com --variant logo"
|
|
@@ -25169,7 +24683,7 @@ var logoCommand = defineCommand123({
|
|
|
25169
24683
|
});
|
|
25170
24684
|
|
|
25171
24685
|
// src/commands/images/normalize.ts
|
|
25172
|
-
import { defineCommand as
|
|
24686
|
+
import { defineCommand as defineCommand122 } from "citty";
|
|
25173
24687
|
|
|
25174
24688
|
// src/lib/image/color-changer.ts
|
|
25175
24689
|
import quantize from "quantize";
|
|
@@ -25901,7 +25415,7 @@ function coerceRawArgs(args) {
|
|
|
25901
25415
|
"dry-run": bool(args["dry-run"])
|
|
25902
25416
|
};
|
|
25903
25417
|
}
|
|
25904
|
-
var normalizeCommand =
|
|
25418
|
+
var normalizeCommand = defineCommand122({
|
|
25905
25419
|
meta: {
|
|
25906
25420
|
name: "normalize",
|
|
25907
25421
|
description: `Normalize logos / images: declarative recolor + bg removal + trim + resize. Operates on local files; writes in-place by default.
|
|
@@ -25956,7 +25470,7 @@ Examples:
|
|
|
25956
25470
|
});
|
|
25957
25471
|
|
|
25958
25472
|
// src/commands/images/pinterest.ts
|
|
25959
|
-
import { defineCommand as
|
|
25473
|
+
import { defineCommand as defineCommand123 } from "citty";
|
|
25960
25474
|
registerSchema({
|
|
25961
25475
|
command: "images.pinterest",
|
|
25962
25476
|
description: "Pinterest image search via ScrapeCreators. Reference-grade real-world photography, product styling, interiors, fashion, food, and aesthetic mood boards. Inspect before placing \u2014 Pinterest is unverified, trademark-bearing web content.",
|
|
@@ -25976,7 +25490,7 @@ registerSchema({
|
|
|
25976
25490
|
}
|
|
25977
25491
|
}
|
|
25978
25492
|
});
|
|
25979
|
-
var pinterestCommand =
|
|
25493
|
+
var pinterestCommand = defineCommand123({
|
|
25980
25494
|
meta: {
|
|
25981
25495
|
name: "pinterest",
|
|
25982
25496
|
description: "Pinterest image search via ScrapeCreators ($0.00188/request). Best for photo-realistic reference imagery \u2014 lifestyle, interiors, fashion, food, product styling, and mood boards to brief AI generation against. \u26A0 Unverified, trademark-bearing web content \u2014 inspect and respect rights before placing on a customer page. Browse first; auto-ingest only the pins you commit to.\n\nExamples:\n baker images pinterest 'scandinavian living room'\n baker images pinterest 'minimalist skincare product photography' --limit 20\n baker images pinterest 'cozy coffee shop interior' --auto-ingest 2 --context 'Mood reference for hero photography'"
|
|
@@ -26016,7 +25530,7 @@ var pinterestCommand = defineCommand125({
|
|
|
26016
25530
|
});
|
|
26017
25531
|
|
|
26018
25532
|
// src/commands/images/screenshot.ts
|
|
26019
|
-
import { defineCommand as
|
|
25533
|
+
import { defineCommand as defineCommand124 } from "citty";
|
|
26020
25534
|
registerSchema({
|
|
26021
25535
|
command: "images.screenshot",
|
|
26022
25536
|
description: "Capture a website screenshot via ScreenshotOne. Auto-ingests on success.",
|
|
@@ -26032,7 +25546,7 @@ registerSchema({
|
|
|
26032
25546
|
}
|
|
26033
25547
|
}
|
|
26034
25548
|
});
|
|
26035
|
-
var screenshotCommand =
|
|
25549
|
+
var screenshotCommand = defineCommand124({
|
|
26036
25550
|
meta: {
|
|
26037
25551
|
name: "screenshot",
|
|
26038
25552
|
description: "Screenshot a URL via ScreenshotOne. $0.009/capture. Auto-ingests to library.\n\nExample: baker images screenshot https://stripe.com --full-page"
|
|
@@ -26095,7 +25609,7 @@ var screenshotCommand = defineCommand126({
|
|
|
26095
25609
|
});
|
|
26096
25610
|
|
|
26097
25611
|
// src/commands/images/search.ts
|
|
26098
|
-
import { defineCommand as
|
|
25612
|
+
import { defineCommand as defineCommand125 } from "citty";
|
|
26099
25613
|
registerSchema({
|
|
26100
25614
|
command: "images.search",
|
|
26101
25615
|
description: "Search images by text query. Only returns ready images.",
|
|
@@ -26111,7 +25625,7 @@ registerSchema({
|
|
|
26111
25625
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
26112
25626
|
}
|
|
26113
25627
|
});
|
|
26114
|
-
var searchCommand =
|
|
25628
|
+
var searchCommand = defineCommand125({
|
|
26115
25629
|
meta: {
|
|
26116
25630
|
name: "search",
|
|
26117
25631
|
description: "Semantic search images by text query. Uses hybrid BM25 + vector + reranking. Example: baker images search 'hero banner' --aspect-ratio 16:9 --tags logo"
|
|
@@ -26171,7 +25685,7 @@ var searchCommand = defineCommand127({
|
|
|
26171
25685
|
});
|
|
26172
25686
|
|
|
26173
25687
|
// src/commands/images/sticker.ts
|
|
26174
|
-
import { defineCommand as
|
|
25688
|
+
import { defineCommand as defineCommand126 } from "citty";
|
|
26175
25689
|
registerSchema({
|
|
26176
25690
|
command: "images.sticker",
|
|
26177
25691
|
description: "Search Giphy stickers \u2014 transparent-background overlays for ad creative.",
|
|
@@ -26203,7 +25717,7 @@ registerSchema({
|
|
|
26203
25717
|
}
|
|
26204
25718
|
}
|
|
26205
25719
|
});
|
|
26206
|
-
var stickerCommand =
|
|
25720
|
+
var stickerCommand = defineCommand126({
|
|
26207
25721
|
meta: {
|
|
26208
25722
|
name: "sticker",
|
|
26209
25723
|
description: "Search Giphy's sticker corpus \u2014 transparent-background WebPs / GIFs ideal for overlaying on ad creative (Meta, TikTok, Stories). Same Giphy free API as `baker images gif`; results carry WebP + GIF + MP4 URLs in providerMeta.\n\nExample: baker images sticker 'thumbs up' --limit 10\nExample: baker images sticker celebration --rating g --auto-ingest 3\nExample: baker images sticker --trending --limit 25"
|
|
@@ -26250,7 +25764,7 @@ var stickerCommand = defineCommand128({
|
|
|
26250
25764
|
});
|
|
26251
25765
|
|
|
26252
25766
|
// src/commands/images/stock.ts
|
|
26253
|
-
import { defineCommand as
|
|
25767
|
+
import { defineCommand as defineCommand127 } from "citty";
|
|
26254
25768
|
var STOCK_ERROR_FIX = {
|
|
26255
25769
|
action: "use_different_resource",
|
|
26256
25770
|
explanation: "Switch provider instead of retrying stock search. Stock search is one of several image sources. Run `baker images find <query> --sources library,pinterest,google` (`--sources` is required \u2014 `find` alone searches the library only) or `baker images generate` to make the asset. Never sleep-and-retry this command \u2014 the CLI already backs off on rate limits. If no image can be sourced, continue the rest of the task with a placeholder rather than aborting it."
|
|
@@ -26327,7 +25841,7 @@ function buildStockRequest(query, args) {
|
|
|
26327
25841
|
if (args.context) body.descriptionContext = args.context;
|
|
26328
25842
|
return body;
|
|
26329
25843
|
}
|
|
26330
|
-
var stockCommand =
|
|
25844
|
+
var stockCommand = defineCommand127({
|
|
26331
25845
|
meta: {
|
|
26332
25846
|
name: "stock",
|
|
26333
25847
|
description: "Stock search via Magnific \u2014 Freepik's developer API (~250M assets: photos, vectors, illustrations, icons, PSDs). $0.002/req. With --auto-ingest, ingested hits return Baker-owned URLs.\n\nExamples:\n baker images stock 'minimalist office'\n baker images stock 'flat office workers' --type vector\n baker images stock 'hero photo of a kitchen' --type photo --orientation landscape --ai exclude\n baker images stock 'brand pattern' --color '#0a0a0a' --license freemium --auto-ingest 2"
|
|
@@ -26383,7 +25897,7 @@ var stockCommand = defineCommand129({
|
|
|
26383
25897
|
});
|
|
26384
25898
|
|
|
26385
25899
|
// src/lib/tags-command.ts
|
|
26386
|
-
import { defineCommand as
|
|
25900
|
+
import { defineCommand as defineCommand128 } from "citty";
|
|
26387
25901
|
function makeTagsCommand(command, label, endpoint) {
|
|
26388
25902
|
registerSchema({
|
|
26389
25903
|
command: `${command}.tags`,
|
|
@@ -26392,7 +25906,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
26392
25906
|
output: { type: "string", description: "Output format: md|json", required: false, default: "md" }
|
|
26393
25907
|
}
|
|
26394
25908
|
});
|
|
26395
|
-
return
|
|
25909
|
+
return defineCommand128({
|
|
26396
25910
|
meta: {
|
|
26397
25911
|
name: "tags",
|
|
26398
25912
|
description: `List the available ${label} tag names (defaults + company custom tags). Use before filtering with --tags. Example: baker ${command} tags`
|
|
@@ -26428,7 +25942,7 @@ function makeTagsCommand(command, label, endpoint) {
|
|
|
26428
25942
|
var tagsCommand2 = makeTagsCommand("images", "image", "/api/images/tags");
|
|
26429
25943
|
|
|
26430
25944
|
// src/commands/images/upload.ts
|
|
26431
|
-
import { defineCommand as
|
|
25945
|
+
import { defineCommand as defineCommand129 } from "citty";
|
|
26432
25946
|
registerSchema({
|
|
26433
25947
|
command: "images.upload",
|
|
26434
25948
|
description: "Upload an image to the library \u2014 local file path or remote http(s) URL.",
|
|
@@ -26466,7 +25980,7 @@ registerSchema({
|
|
|
26466
25980
|
function isRemoteUrl2(value) {
|
|
26467
25981
|
return /^https?:\/\//i.test(value);
|
|
26468
25982
|
}
|
|
26469
|
-
var uploadCommand =
|
|
25983
|
+
var uploadCommand = defineCommand129({
|
|
26470
25984
|
meta: {
|
|
26471
25985
|
name: "upload",
|
|
26472
25986
|
description: "Upload an image to the library \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: reads bytes, sends to /api/images/upload, content-type auto-detected from extension.\nRemote: dispatches to /api/images/ingest with hash-dedup on bytes + externalId.\n\nExamples:\n baker images upload ./logo.png --source uploaded\n baker images upload ./cert.png --context 'ISO 27001 badge \u2014 enterprise tier'\n baker images upload https://acme.com/hero.png --source firecrawl --context 'Acme competitor pricing hero'"
|
|
@@ -26559,7 +26073,7 @@ async function uploadLocal(target, args) {
|
|
|
26559
26073
|
}
|
|
26560
26074
|
|
|
26561
26075
|
// src/commands/images/upscale.ts
|
|
26562
|
-
import { defineCommand as
|
|
26076
|
+
import { defineCommand as defineCommand130 } from "citty";
|
|
26563
26077
|
registerSchema({
|
|
26564
26078
|
command: "images.upscale",
|
|
26565
26079
|
description: "Upscale a library image via the backend (Replicate, cost-tracked). Waits for completion by default. The image must be status 'ready' and raster (not SVG/AVIF).",
|
|
@@ -26574,7 +26088,7 @@ registerSchema({
|
|
|
26574
26088
|
}
|
|
26575
26089
|
});
|
|
26576
26090
|
var POLL_INTERVAL_MS3 = 1500;
|
|
26577
|
-
var upscaleCommand =
|
|
26091
|
+
var upscaleCommand = defineCommand130({
|
|
26578
26092
|
meta: {
|
|
26579
26093
|
name: "upscale",
|
|
26580
26094
|
description: "Upscale a library image via the Convex backend (Replicate, cost-tracked at $0.05/image). Waits for completion by default.\n\nExample: baker images upscale j571abc123def\nExample: baker images upscale j571abc123def --max-wait 0 # fire-and-forget"
|
|
@@ -26629,7 +26143,7 @@ var upscaleCommand = defineCommand132({
|
|
|
26629
26143
|
});
|
|
26630
26144
|
|
|
26631
26145
|
// src/commands/images/use.ts
|
|
26632
|
-
import { defineCommand as
|
|
26146
|
+
import { defineCommand as defineCommand131 } from "citty";
|
|
26633
26147
|
registerSchema({
|
|
26634
26148
|
command: "images.use",
|
|
26635
26149
|
description: "Ingest a URL and wait for the library record to be ready.",
|
|
@@ -26645,7 +26159,7 @@ registerSchema({
|
|
|
26645
26159
|
}
|
|
26646
26160
|
});
|
|
26647
26161
|
var POLL_INTERVAL_MS4 = 1500;
|
|
26648
|
-
var useCommand =
|
|
26162
|
+
var useCommand = defineCommand131({
|
|
26649
26163
|
meta: {
|
|
26650
26164
|
name: "use",
|
|
26651
26165
|
description: "Sugar over `ingest`: download \u2192 store \u2192 wait until describe + embed complete \u2192 return ready library record.\n\nExample: baker images use https://cdn.example.com/hero.png --source uploaded"
|
|
@@ -26691,7 +26205,7 @@ var useCommand = defineCommand133({
|
|
|
26691
26205
|
});
|
|
26692
26206
|
|
|
26693
26207
|
// src/commands/images/index.ts
|
|
26694
|
-
var imagesCommand =
|
|
26208
|
+
var imagesCommand = defineCommand132({
|
|
26695
26209
|
meta: {
|
|
26696
26210
|
name: "images",
|
|
26697
26211
|
description: `Find, source, and normalize images. Subcommands route by provider so cost + license are explicit.
|
|
@@ -26762,16 +26276,16 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
26762
26276
|
});
|
|
26763
26277
|
|
|
26764
26278
|
// src/commands/landing/index.ts
|
|
26765
|
-
import { defineCommand as
|
|
26279
|
+
import { defineCommand as defineCommand134 } from "citty";
|
|
26766
26280
|
|
|
26767
26281
|
// src/commands/landing/critique.ts
|
|
26768
26282
|
import { readdir as readdir8, stat as stat6 } from "fs/promises";
|
|
26769
|
-
import
|
|
26770
|
-
import { defineCommand as
|
|
26283
|
+
import path26 from "path";
|
|
26284
|
+
import { defineCommand as defineCommand133 } from "citty";
|
|
26771
26285
|
|
|
26772
26286
|
// src/engine/landing/lib/brand-tokens.ts
|
|
26773
|
-
import { readFile as
|
|
26774
|
-
import
|
|
26287
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
26288
|
+
import path23 from "path";
|
|
26775
26289
|
|
|
26776
26290
|
// src/engine/landing/lib/color.ts
|
|
26777
26291
|
var NEUTRAL_COLOR_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -26933,14 +26447,14 @@ function parseBrandMd(brandMd, fonts, colors) {
|
|
|
26933
26447
|
}
|
|
26934
26448
|
}
|
|
26935
26449
|
async function loadBrandTokens(projectRoot) {
|
|
26936
|
-
const globalCss = await safeRead(
|
|
26937
|
-
const brandMd = await safeRead(
|
|
26450
|
+
const globalCss = await safeRead(path23.join(projectRoot, "src", "styles", "global.css"));
|
|
26451
|
+
const brandMd = await safeRead(path23.join(projectRoot, "src", "brand", "BRAND.md"));
|
|
26938
26452
|
if (!globalCss && !brandMd) return EMPTY;
|
|
26939
26453
|
return parseBrandTokens(globalCss, brandMd);
|
|
26940
26454
|
}
|
|
26941
26455
|
async function safeRead(file) {
|
|
26942
26456
|
try {
|
|
26943
|
-
return await
|
|
26457
|
+
return await readFile20(file, "utf8");
|
|
26944
26458
|
} catch {
|
|
26945
26459
|
return "";
|
|
26946
26460
|
}
|
|
@@ -27726,40 +27240,40 @@ function describeCounts(findings) {
|
|
|
27726
27240
|
}
|
|
27727
27241
|
|
|
27728
27242
|
// src/commands/landing/snapshot.ts
|
|
27729
|
-
import { mkdir as
|
|
27730
|
-
import
|
|
27243
|
+
import { mkdir as mkdir7, rename as rename2, writeFile as writeFile10 } from "fs/promises";
|
|
27244
|
+
import path24 from "path";
|
|
27731
27245
|
var CRITIC_VERSION = "1";
|
|
27732
27246
|
function critiqueCacheDir(projectRoot) {
|
|
27733
|
-
return
|
|
27247
|
+
return path24.join(projectRoot, ".cache", "landing-critique");
|
|
27734
27248
|
}
|
|
27735
27249
|
function snapshotPath(projectRoot, slug) {
|
|
27736
|
-
return
|
|
27250
|
+
return path24.join(critiqueCacheDir(projectRoot), `${slug}.json`);
|
|
27737
27251
|
}
|
|
27738
27252
|
async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
27739
|
-
await
|
|
27253
|
+
await mkdir7(critiqueCacheDir(projectRoot), { recursive: true });
|
|
27740
27254
|
const dest = snapshotPath(projectRoot, snapshot.slug);
|
|
27741
27255
|
const tmp = `${dest}.tmp`;
|
|
27742
|
-
await
|
|
27256
|
+
await writeFile10(tmp, `${JSON.stringify(snapshot, null, 2)}
|
|
27743
27257
|
`, "utf8");
|
|
27744
27258
|
await rename2(tmp, dest);
|
|
27745
27259
|
}
|
|
27746
27260
|
|
|
27747
27261
|
// src/commands/landing/source-version.ts
|
|
27748
|
-
import { readdir as readdir7, readFile as
|
|
27749
|
-
import
|
|
27262
|
+
import { readdir as readdir7, readFile as readFile21, stat as stat5 } from "fs/promises";
|
|
27263
|
+
import path25 from "path";
|
|
27750
27264
|
async function landingSourceRelPaths(landingDir) {
|
|
27751
27265
|
const rel = [];
|
|
27752
|
-
if (await isFile(
|
|
27753
|
-
const componentsDir =
|
|
27266
|
+
if (await isFile(path25.join(landingDir, "index.astro"))) rel.push("index.astro");
|
|
27267
|
+
const componentsDir = path25.join(landingDir, "_components");
|
|
27754
27268
|
for (const abs of await walkAstro(componentsDir)) {
|
|
27755
|
-
rel.push(
|
|
27269
|
+
rel.push(path25.relative(landingDir, abs).split(path25.sep).join("/"));
|
|
27756
27270
|
}
|
|
27757
27271
|
return rel.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
27758
27272
|
}
|
|
27759
27273
|
async function readLandingSources(landingDir) {
|
|
27760
27274
|
const rel = await landingSourceRelPaths(landingDir);
|
|
27761
27275
|
const out = [];
|
|
27762
|
-
for (const r of rel) out.push({ path: r, text: await
|
|
27276
|
+
for (const r of rel) out.push({ path: r, text: await readFile21(path25.join(landingDir, r), "utf8") });
|
|
27763
27277
|
return out;
|
|
27764
27278
|
}
|
|
27765
27279
|
async function computeLandingSourceSha(landingDir) {
|
|
@@ -27768,7 +27282,7 @@ async function computeLandingSourceSha(landingDir) {
|
|
|
27768
27282
|
for (const r of rel) {
|
|
27769
27283
|
let bytes;
|
|
27770
27284
|
try {
|
|
27771
|
-
bytes = await
|
|
27285
|
+
bytes = await readFile21(path25.join(landingDir, r));
|
|
27772
27286
|
} catch {
|
|
27773
27287
|
bytes = Buffer.alloc(0);
|
|
27774
27288
|
}
|
|
@@ -27792,7 +27306,7 @@ async function walkAstro(dir) {
|
|
|
27792
27306
|
}
|
|
27793
27307
|
const out = [];
|
|
27794
27308
|
for (const entry of entries) {
|
|
27795
|
-
const abs =
|
|
27309
|
+
const abs = path25.join(dir, entry.name);
|
|
27796
27310
|
if (entry.isDirectory()) out.push(...await walkAstro(abs));
|
|
27797
27311
|
else if (entry.isFile() && entry.name.endsWith(".astro")) out.push(abs);
|
|
27798
27312
|
}
|
|
@@ -27813,14 +27327,14 @@ registerSchema({
|
|
|
27813
27327
|
}
|
|
27814
27328
|
});
|
|
27815
27329
|
var SLUG_RE = /^[a-z0-9][a-z0-9._-]*$/i;
|
|
27816
|
-
function
|
|
27330
|
+
function fail4(code, message, fix) {
|
|
27817
27331
|
process.stderr.write(
|
|
27818
27332
|
`${JSON.stringify({ ok: false, error: { code, message, ...fix ? { fix } : {} } }, null, 2)}
|
|
27819
27333
|
`
|
|
27820
27334
|
);
|
|
27821
27335
|
process.exit(2);
|
|
27822
27336
|
}
|
|
27823
|
-
var critiqueCommand2 =
|
|
27337
|
+
var critiqueCommand2 = defineCommand133({
|
|
27824
27338
|
meta: {
|
|
27825
27339
|
name: "critique",
|
|
27826
27340
|
description: "Start here: `baker landing critique <slug>` after building or editing a landing. Deterministic design-quality critic (ADVISORY \u2014 findings never fail it). Flags the known AI design tells (gradient text, overused fonts, side-tab borders, cream palettes, buzzword copy, broken images) tiered block/warn/advisory, respecting the client's BRAND.md as the allowlist. Also records the critique that publishing requires \u2014 run it before finishing a landing."
|
|
@@ -27833,15 +27347,15 @@ var critiqueCommand2 = defineCommand135({
|
|
|
27833
27347
|
const slug = String(args.slug);
|
|
27834
27348
|
const projectRoot = process.cwd();
|
|
27835
27349
|
if (!SLUG_RE.test(slug) || slug.includes("..")) {
|
|
27836
|
-
|
|
27350
|
+
fail4(
|
|
27837
27351
|
"INVALID_SLUG",
|
|
27838
27352
|
`"${slug}" is not a landing slug \u2014 use the folder name directly under src/pages/ (letters, digits, dashes; not a path, not a _-private folder).`,
|
|
27839
27353
|
{ availableSlugs: await listLandingSlugs(projectRoot) }
|
|
27840
27354
|
);
|
|
27841
27355
|
}
|
|
27842
|
-
const landingDir =
|
|
27356
|
+
const landingDir = path26.resolve(projectRoot, "src", "pages", slug);
|
|
27843
27357
|
if (!await isDir(landingDir)) {
|
|
27844
|
-
|
|
27358
|
+
fail4("NOT_FOUND", `No landing at src/pages/${slug}/`, {
|
|
27845
27359
|
availableSlugs: await listLandingSlugs(projectRoot)
|
|
27846
27360
|
});
|
|
27847
27361
|
}
|
|
@@ -27894,7 +27408,7 @@ var critiqueCommand2 = defineCommand135({
|
|
|
27894
27408
|
});
|
|
27895
27409
|
async function listLandingSlugs(projectRoot) {
|
|
27896
27410
|
try {
|
|
27897
|
-
const entries = await readdir8(
|
|
27411
|
+
const entries = await readdir8(path26.join(projectRoot, "src", "pages"), { withFileTypes: true });
|
|
27898
27412
|
return entries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith(".")).map((e) => e.name).sort();
|
|
27899
27413
|
} catch {
|
|
27900
27414
|
return [];
|
|
@@ -27920,7 +27434,7 @@ async function isDir(p) {
|
|
|
27920
27434
|
}
|
|
27921
27435
|
|
|
27922
27436
|
// src/commands/landing/index.ts
|
|
27923
|
-
var landingCommand =
|
|
27437
|
+
var landingCommand = defineCommand134({
|
|
27924
27438
|
meta: {
|
|
27925
27439
|
name: "landing",
|
|
27926
27440
|
description: `Design-quality tools for landing pages (src/pages/<slug>/).
|
|
@@ -27936,7 +27450,7 @@ Subcommands:
|
|
|
27936
27450
|
});
|
|
27937
27451
|
|
|
27938
27452
|
// src/commands/mcp/index.ts
|
|
27939
|
-
import { defineCommand as
|
|
27453
|
+
import { defineCommand as defineCommand135 } from "citty";
|
|
27940
27454
|
var SCOPES = ["user", "user_org", "company", "org"];
|
|
27941
27455
|
function parseScope(raw) {
|
|
27942
27456
|
const scope = raw === void 0 ? "company" : String(raw);
|
|
@@ -27962,7 +27476,7 @@ function parseHeaders(raw) {
|
|
|
27962
27476
|
}
|
|
27963
27477
|
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
27964
27478
|
}
|
|
27965
|
-
function
|
|
27479
|
+
function fail5(err) {
|
|
27966
27480
|
if (err instanceof ApiError) {
|
|
27967
27481
|
writeJson({ ok: false, error: { code: err.code, message: err.message } });
|
|
27968
27482
|
process.exit(1);
|
|
@@ -27975,7 +27489,7 @@ registerSchema({
|
|
|
27975
27489
|
description: "List every third-party tool this chat can reach: managed integrations (Attio, Slack, Gmail, Google Sheets, \u2026) plus custom MCP servers. Start here when the user mentions an external tool.",
|
|
27976
27490
|
args: {}
|
|
27977
27491
|
});
|
|
27978
|
-
var connectedCommand =
|
|
27492
|
+
var connectedCommand = defineCommand135({
|
|
27979
27493
|
meta: {
|
|
27980
27494
|
name: "connected",
|
|
27981
27495
|
description: `List all connected third-party tools \u2014 managed integrations plus custom MCP servers.
|
|
@@ -28013,7 +27527,7 @@ A tool the user names that is NOT listed here is simply not connected yet.`
|
|
|
28013
27527
|
hints
|
|
28014
27528
|
});
|
|
28015
27529
|
} catch (err) {
|
|
28016
|
-
|
|
27530
|
+
fail5(err);
|
|
28017
27531
|
}
|
|
28018
27532
|
}
|
|
28019
27533
|
});
|
|
@@ -28022,7 +27536,7 @@ registerSchema({
|
|
|
28022
27536
|
description: "List the custom MCP servers this company's chats see (org + company + your own user scope).",
|
|
28023
27537
|
args: {}
|
|
28024
27538
|
});
|
|
28025
|
-
var listCommand8 =
|
|
27539
|
+
var listCommand8 = defineCommand135({
|
|
28026
27540
|
meta: { name: "list", description: "List custom MCP servers visible to this company's chats." },
|
|
28027
27541
|
run: async () => {
|
|
28028
27542
|
try {
|
|
@@ -28033,7 +27547,7 @@ var listCommand8 = defineCommand137({
|
|
|
28033
27547
|
);
|
|
28034
27548
|
writeJson({ ok: true, data: data.servers });
|
|
28035
27549
|
} catch (err) {
|
|
28036
|
-
|
|
27550
|
+
fail5(err);
|
|
28037
27551
|
}
|
|
28038
27552
|
}
|
|
28039
27553
|
});
|
|
@@ -28047,7 +27561,7 @@ registerSchema({
|
|
|
28047
27561
|
header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
|
|
28048
27562
|
}
|
|
28049
27563
|
});
|
|
28050
|
-
var addCommand =
|
|
27564
|
+
var addCommand = defineCommand135({
|
|
28051
27565
|
meta: {
|
|
28052
27566
|
name: "add",
|
|
28053
27567
|
description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
|
|
@@ -28079,7 +27593,7 @@ Examples:
|
|
|
28079
27593
|
});
|
|
28080
27594
|
writeJson({ ok: true, data });
|
|
28081
27595
|
} catch (err) {
|
|
28082
|
-
|
|
27596
|
+
fail5(err);
|
|
28083
27597
|
}
|
|
28084
27598
|
}
|
|
28085
27599
|
});
|
|
@@ -28088,7 +27602,7 @@ registerSchema({
|
|
|
28088
27602
|
description: "Remove a company custom MCP server by name.",
|
|
28089
27603
|
args: { name: { type: "string", description: "Server name to remove", required: true } }
|
|
28090
27604
|
});
|
|
28091
|
-
var removeCommand4 =
|
|
27605
|
+
var removeCommand4 = defineCommand135({
|
|
28092
27606
|
meta: {
|
|
28093
27607
|
name: "remove",
|
|
28094
27608
|
description: `Remove a company custom MCP server by name.
|
|
@@ -28106,11 +27620,11 @@ Example:
|
|
|
28106
27620
|
});
|
|
28107
27621
|
writeJson({ ok: true, data });
|
|
28108
27622
|
} catch (err) {
|
|
28109
|
-
|
|
27623
|
+
fail5(err);
|
|
28110
27624
|
}
|
|
28111
27625
|
}
|
|
28112
27626
|
});
|
|
28113
|
-
var mcpCommand =
|
|
27627
|
+
var mcpCommand = defineCommand135({
|
|
28114
27628
|
meta: {
|
|
28115
27629
|
name: "mcp",
|
|
28116
27630
|
description: `Third-party tools for this company \u2014 see what's connected, register custom HTTPS MCP endpoints.
|
|
@@ -28136,10 +27650,10 @@ Full guide: __tooling__/docs/tools/baker/mcp.md`
|
|
|
28136
27650
|
});
|
|
28137
27651
|
|
|
28138
27652
|
// src/commands/research/index.ts
|
|
28139
|
-
import { defineCommand as
|
|
27653
|
+
import { defineCommand as defineCommand146 } from "citty";
|
|
28140
27654
|
|
|
28141
27655
|
// src/commands/research/advertisers.ts
|
|
28142
|
-
import { defineCommand as
|
|
27656
|
+
import { defineCommand as defineCommand136 } from "citty";
|
|
28143
27657
|
|
|
28144
27658
|
// src/commands/research/output.ts
|
|
28145
27659
|
var RESEARCH_DATA_NOTE = "Estimates based on third-party SERP data \u2014 not exact figures. Use for directional insights, not precise measurement.";
|
|
@@ -28252,7 +27766,7 @@ var FIELDS3 = {
|
|
|
28252
27766
|
etv: "Estimated traffic value (USD)",
|
|
28253
27767
|
visibility: "SERP visibility score (0-1)"
|
|
28254
27768
|
};
|
|
28255
|
-
var advertisersCommand =
|
|
27769
|
+
var advertisersCommand = defineCommand136({
|
|
28256
27770
|
meta: {
|
|
28257
27771
|
name: "advertisers",
|
|
28258
27772
|
description: `Find domains competing for a keyword in Google SERPs.
|
|
@@ -28299,7 +27813,7 @@ Examples:
|
|
|
28299
27813
|
});
|
|
28300
27814
|
|
|
28301
27815
|
// src/commands/research/autocomplete.ts
|
|
28302
|
-
import { defineCommand as
|
|
27816
|
+
import { defineCommand as defineCommand137 } from "citty";
|
|
28303
27817
|
registerSchema({
|
|
28304
27818
|
command: "research.autocomplete",
|
|
28305
27819
|
description: "Get Google Autocomplete suggestions for a seed keyword. Useful for keyword expansion and discovering what people actually search for. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -28322,7 +27836,7 @@ registerSchema({
|
|
|
28322
27836
|
var FIELDS4 = {
|
|
28323
27837
|
suggestion: "Autocomplete suggestion from Google"
|
|
28324
27838
|
};
|
|
28325
|
-
var autocompleteCommand =
|
|
27839
|
+
var autocompleteCommand = defineCommand137({
|
|
28326
27840
|
meta: {
|
|
28327
27841
|
name: "autocomplete",
|
|
28328
27842
|
description: `Get Google Autocomplete suggestions for keyword expansion.
|
|
@@ -28368,7 +27882,7 @@ Examples:
|
|
|
28368
27882
|
});
|
|
28369
27883
|
|
|
28370
27884
|
// src/commands/research/countries.ts
|
|
28371
|
-
import { defineCommand as
|
|
27885
|
+
import { defineCommand as defineCommand138 } from "citty";
|
|
28372
27886
|
registerSchema({
|
|
28373
27887
|
command: "research.countries",
|
|
28374
27888
|
description: "List all supported country codes for --location flag in research commands.",
|
|
@@ -28425,7 +27939,7 @@ var FIELDS5 = {
|
|
|
28425
27939
|
code: "Country code to pass as --location",
|
|
28426
27940
|
name: "Country name"
|
|
28427
27941
|
};
|
|
28428
|
-
var countriesCommand =
|
|
27942
|
+
var countriesCommand = defineCommand138({
|
|
28429
27943
|
meta: {
|
|
28430
27944
|
name: "countries",
|
|
28431
27945
|
description: "List all supported country codes for --location flag."
|
|
@@ -28436,7 +27950,7 @@ var countriesCommand = defineCommand140({
|
|
|
28436
27950
|
});
|
|
28437
27951
|
|
|
28438
27952
|
// src/commands/research/intent.ts
|
|
28439
|
-
import { defineCommand as
|
|
27953
|
+
import { defineCommand as defineCommand139 } from "citty";
|
|
28440
27954
|
registerSchema({
|
|
28441
27955
|
command: "research.intent",
|
|
28442
27956
|
description: "Classify Google Search intent for keywords. Determines if someone searching is looking to buy, research, or navigate. IMPORTANT: If --language is omitted, defaults to English (en). The response includes a query_context object showing which language was used.",
|
|
@@ -28459,7 +27973,7 @@ var FIELDS6 = {
|
|
|
28459
27973
|
intent: "Primary Google Search intent: informational, navigational, commercial, transactional",
|
|
28460
27974
|
probability: "Confidence score 0.0-1.0"
|
|
28461
27975
|
};
|
|
28462
|
-
var intentCommand =
|
|
27976
|
+
var intentCommand = defineCommand139({
|
|
28463
27977
|
meta: {
|
|
28464
27978
|
name: "intent",
|
|
28465
27979
|
description: `Classify Google Search intent for keywords. Returns intent type and confidence.
|
|
@@ -28507,7 +28021,7 @@ Examples:
|
|
|
28507
28021
|
});
|
|
28508
28022
|
|
|
28509
28023
|
// src/commands/research/keyword-gap.ts
|
|
28510
|
-
import { defineCommand as
|
|
28024
|
+
import { defineCommand as defineCommand140 } from "citty";
|
|
28511
28025
|
registerSchema({
|
|
28512
28026
|
command: "research.keyword-gap",
|
|
28513
28027
|
description: "Find keywords a competitor ranks for (organic or paid) that you don't. Discovers expansion opportunities. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
@@ -28536,7 +28050,7 @@ var FIELDS7 = {
|
|
|
28536
28050
|
cpc: "Cost per click USD",
|
|
28537
28051
|
their_position: "Competitor's ranking position"
|
|
28538
28052
|
};
|
|
28539
|
-
var keywordGapCommand =
|
|
28053
|
+
var keywordGapCommand = defineCommand140({
|
|
28540
28054
|
meta: {
|
|
28541
28055
|
name: "keyword-gap",
|
|
28542
28056
|
description: `Find keywords a competitor has that you don't. Supports pagination via --offset.
|
|
@@ -28610,7 +28124,7 @@ Examples:
|
|
|
28610
28124
|
});
|
|
28611
28125
|
|
|
28612
28126
|
// src/commands/research/keywords-for-site.ts
|
|
28613
|
-
import { defineCommand as
|
|
28127
|
+
import { defineCommand as defineCommand141 } from "citty";
|
|
28614
28128
|
registerSchema({
|
|
28615
28129
|
command: "research.keywords-for-site",
|
|
28616
28130
|
description: "Get keywords a competitor targets in Google. Use --type paid to see only paid keywords, --type organic for organic only. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en). The response includes a query_context object showing which location/language were used.",
|
|
@@ -28643,7 +28157,7 @@ var FIELDS8 = {
|
|
|
28643
28157
|
competition: "LOW, MEDIUM, or HIGH",
|
|
28644
28158
|
competition_index: "Competition score 0-100"
|
|
28645
28159
|
};
|
|
28646
|
-
var keywordsForSiteCommand =
|
|
28160
|
+
var keywordsForSiteCommand = defineCommand141({
|
|
28647
28161
|
meta: {
|
|
28648
28162
|
name: "keywords-for-site",
|
|
28649
28163
|
description: `Get keywords a competitor targets in Google. Use --type to filter paid/organic.
|
|
@@ -28696,7 +28210,7 @@ Examples:
|
|
|
28696
28210
|
});
|
|
28697
28211
|
|
|
28698
28212
|
// src/commands/research/languages.ts
|
|
28699
|
-
import { defineCommand as
|
|
28213
|
+
import { defineCommand as defineCommand142 } from "citty";
|
|
28700
28214
|
registerSchema({
|
|
28701
28215
|
command: "research.languages",
|
|
28702
28216
|
description: "List all supported language codes for --language flag in research commands.",
|
|
@@ -28726,7 +28240,7 @@ var FIELDS9 = {
|
|
|
28726
28240
|
code: "Language code to pass as --language",
|
|
28727
28241
|
name: "Language name (also accepted by --language)"
|
|
28728
28242
|
};
|
|
28729
|
-
var languagesCommand2 =
|
|
28243
|
+
var languagesCommand2 = defineCommand142({
|
|
28730
28244
|
meta: {
|
|
28731
28245
|
name: "languages",
|
|
28732
28246
|
description: "List all supported language codes for --language flag."
|
|
@@ -28737,7 +28251,7 @@ var languagesCommand2 = defineCommand144({
|
|
|
28737
28251
|
});
|
|
28738
28252
|
|
|
28739
28253
|
// src/commands/research/lighthouse.ts
|
|
28740
|
-
import { defineCommand as
|
|
28254
|
+
import { defineCommand as defineCommand143 } from "citty";
|
|
28741
28255
|
registerSchema({
|
|
28742
28256
|
command: "research.lighthouse",
|
|
28743
28257
|
description: "Landing page performance audit. Returns metrics that affect Google Ads Quality Score and CPC.",
|
|
@@ -28756,7 +28270,7 @@ var FIELDS10 = {
|
|
|
28756
28270
|
speed_index_ms: "Speed Index in ms (good: < 3400)",
|
|
28757
28271
|
interactive_ms: "Time to Interactive in ms (good: < 3800)"
|
|
28758
28272
|
};
|
|
28759
|
-
var lighthouseCommand =
|
|
28273
|
+
var lighthouseCommand = defineCommand143({
|
|
28760
28274
|
meta: {
|
|
28761
28275
|
name: "lighthouse",
|
|
28762
28276
|
description: `Landing page performance audit. Metrics affecting Google Ads Quality Score.
|
|
@@ -28794,7 +28308,7 @@ Examples:
|
|
|
28794
28308
|
});
|
|
28795
28309
|
|
|
28796
28310
|
// src/commands/research/relevant-pages.ts
|
|
28797
|
-
import { defineCommand as
|
|
28311
|
+
import { defineCommand as defineCommand144 } from "citty";
|
|
28798
28312
|
registerSchema({
|
|
28799
28313
|
command: "research.relevant-pages",
|
|
28800
28314
|
description: "Get the top pages of a competitor domain with organic traffic and ranking data. Shows which pages drive the most traffic. IMPORTANT: If --location and --language are omitted, defaults to United States (us) and English (en).",
|
|
@@ -28820,7 +28334,7 @@ var FIELDS11 = {
|
|
|
28820
28334
|
keywords: "Total organic keywords the page ranks for",
|
|
28821
28335
|
top_10: "Keywords in positions 1-10"
|
|
28822
28336
|
};
|
|
28823
|
-
var relevantPagesCommand =
|
|
28337
|
+
var relevantPagesCommand = defineCommand144({
|
|
28824
28338
|
meta: {
|
|
28825
28339
|
name: "relevant-pages",
|
|
28826
28340
|
description: `Get the top pages of a competitor domain with traffic data.
|
|
@@ -28866,7 +28380,7 @@ Examples:
|
|
|
28866
28380
|
});
|
|
28867
28381
|
|
|
28868
28382
|
// src/commands/research/web.ts
|
|
28869
|
-
import { defineCommand as
|
|
28383
|
+
import { defineCommand as defineCommand145 } from "citty";
|
|
28870
28384
|
registerSchema({
|
|
28871
28385
|
command: "research.web",
|
|
28872
28386
|
description: "Search the web with AI to answer marketing questions \u2014 competitors, ICP, pricing, pain points, market trends. Three depth levels: medium (quick, default), high (thorough), xhigh (exhaustive deep research).",
|
|
@@ -28917,7 +28431,7 @@ async function runDeepResearch(question) {
|
|
|
28917
28431
|
}
|
|
28918
28432
|
throw new Error("Deep research timed out");
|
|
28919
28433
|
}
|
|
28920
|
-
var webCommand =
|
|
28434
|
+
var webCommand = defineCommand145({
|
|
28921
28435
|
meta: {
|
|
28922
28436
|
name: "web",
|
|
28923
28437
|
description: `Search the web with AI to answer any open-ended marketing question. Uses live internet data via Google Search.
|
|
@@ -28977,7 +28491,7 @@ Examples:
|
|
|
28977
28491
|
});
|
|
28978
28492
|
|
|
28979
28493
|
// src/commands/research/index.ts
|
|
28980
|
-
var researchCommand =
|
|
28494
|
+
var researchCommand = defineCommand146({
|
|
28981
28495
|
meta: {
|
|
28982
28496
|
name: "research",
|
|
28983
28497
|
description: `Competitive intelligence and AI-powered research commands.
|
|
@@ -29018,10 +28532,10 @@ Full guide: __tooling__/docs/tools/baker/research.md`
|
|
|
29018
28532
|
});
|
|
29019
28533
|
|
|
29020
28534
|
// src/commands/scheduled-actions/index.ts
|
|
29021
|
-
import { defineCommand as
|
|
28535
|
+
import { defineCommand as defineCommand153 } from "citty";
|
|
29022
28536
|
|
|
29023
28537
|
// src/commands/scheduled-actions/create.ts
|
|
29024
|
-
import { defineCommand as
|
|
28538
|
+
import { defineCommand as defineCommand147 } from "citty";
|
|
29025
28539
|
|
|
29026
28540
|
// src/commands/scheduled-actions/shared.ts
|
|
29027
28541
|
var TEMP_SCHEDULED_ACTION_PREFIX = "temp_sched_";
|
|
@@ -29136,7 +28650,7 @@ registerSchema({
|
|
|
29136
28650
|
prompt: { type: "string", description: "Additional prompt instructions for the spawned agent", required: false }
|
|
29137
28651
|
}
|
|
29138
28652
|
});
|
|
29139
|
-
var createCommand2 =
|
|
28653
|
+
var createCommand2 = defineCommand147({
|
|
29140
28654
|
meta: {
|
|
29141
28655
|
name: "create",
|
|
29142
28656
|
description: 'Stage a scheduled action. Example: baker scheduled-actions create --name "Weekly report" --description "..." --cron "0 9 * * MON"'
|
|
@@ -29185,7 +28699,7 @@ var createCommand2 = defineCommand149({
|
|
|
29185
28699
|
});
|
|
29186
28700
|
|
|
29187
28701
|
// src/commands/scheduled-actions/delete.ts
|
|
29188
|
-
import { defineCommand as
|
|
28702
|
+
import { defineCommand as defineCommand148 } from "citty";
|
|
29189
28703
|
registerSchema({
|
|
29190
28704
|
command: "scheduled-actions.delete",
|
|
29191
28705
|
description: "Stage deletion of a published scheduled action or cancellation of a temp_sched_* draft creation.",
|
|
@@ -29193,7 +28707,7 @@ registerSchema({
|
|
|
29193
28707
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
29194
28708
|
}
|
|
29195
28709
|
});
|
|
29196
|
-
var deleteCommand2 =
|
|
28710
|
+
var deleteCommand2 = defineCommand148({
|
|
29197
28711
|
meta: {
|
|
29198
28712
|
name: "delete",
|
|
29199
28713
|
description: "Stage scheduled action deletion. Example: baker scheduled-actions delete <id-or-temp_sched_id>"
|
|
@@ -29222,7 +28736,7 @@ var deleteCommand2 = defineCommand150({
|
|
|
29222
28736
|
});
|
|
29223
28737
|
|
|
29224
28738
|
// src/commands/scheduled-actions/get.ts
|
|
29225
|
-
import { defineCommand as
|
|
28739
|
+
import { defineCommand as defineCommand149 } from "citty";
|
|
29226
28740
|
registerSchema({
|
|
29227
28741
|
command: "scheduled-actions.get",
|
|
29228
28742
|
description: "Get a published scheduled action or a temp_sched_* draft-created scheduled action.",
|
|
@@ -29230,7 +28744,7 @@ registerSchema({
|
|
|
29230
28744
|
id: { type: "string", description: "Published scheduled action ID or temp_sched_* draft ID", required: true }
|
|
29231
28745
|
}
|
|
29232
28746
|
});
|
|
29233
|
-
var getCommand3 =
|
|
28747
|
+
var getCommand3 = defineCommand149({
|
|
29234
28748
|
meta: {
|
|
29235
28749
|
name: "get",
|
|
29236
28750
|
description: "Get a scheduled action. Example: baker scheduled-actions get <id-or-temp_sched_id>"
|
|
@@ -29267,13 +28781,13 @@ var getCommand3 = defineCommand151({
|
|
|
29267
28781
|
});
|
|
29268
28782
|
|
|
29269
28783
|
// src/commands/scheduled-actions/list.ts
|
|
29270
|
-
import { defineCommand as
|
|
28784
|
+
import { defineCommand as defineCommand150 } from "citty";
|
|
29271
28785
|
registerSchema({
|
|
29272
28786
|
command: "scheduled-actions.list",
|
|
29273
28787
|
description: "List published scheduled actions. Includes draft state when BAKER_CHAT_ID is set.",
|
|
29274
28788
|
args: {}
|
|
29275
28789
|
});
|
|
29276
|
-
var listCommand9 =
|
|
28790
|
+
var listCommand9 = defineCommand150({
|
|
29277
28791
|
meta: {
|
|
29278
28792
|
name: "list",
|
|
29279
28793
|
description: "List scheduled actions. Includes staged draft ops when BAKER_CHAT_ID is set."
|
|
@@ -29294,7 +28808,7 @@ var listCommand9 = defineCommand152({
|
|
|
29294
28808
|
});
|
|
29295
28809
|
|
|
29296
28810
|
// src/commands/scheduled-actions/trigger.ts
|
|
29297
|
-
import { defineCommand as
|
|
28811
|
+
import { defineCommand as defineCommand151 } from "citty";
|
|
29298
28812
|
registerSchema({
|
|
29299
28813
|
command: "scheduled-actions.trigger",
|
|
29300
28814
|
description: "Immediately trigger a published scheduled action. Does not require BAKER_CHAT_ID and rejects temp_sched_* IDs.",
|
|
@@ -29302,7 +28816,7 @@ registerSchema({
|
|
|
29302
28816
|
id: { type: "string", description: "Published scheduled action ID", required: true }
|
|
29303
28817
|
}
|
|
29304
28818
|
});
|
|
29305
|
-
var triggerCommand =
|
|
28819
|
+
var triggerCommand = defineCommand151({
|
|
29306
28820
|
meta: {
|
|
29307
28821
|
name: "trigger",
|
|
29308
28822
|
description: "Immediately trigger a published scheduled action. Example: baker scheduled-actions trigger <id>"
|
|
@@ -29339,7 +28853,7 @@ var triggerCommand = defineCommand153({
|
|
|
29339
28853
|
});
|
|
29340
28854
|
|
|
29341
28855
|
// src/commands/scheduled-actions/update.ts
|
|
29342
|
-
import { defineCommand as
|
|
28856
|
+
import { defineCommand as defineCommand152 } from "citty";
|
|
29343
28857
|
registerSchema({
|
|
29344
28858
|
command: "scheduled-actions.update",
|
|
29345
28859
|
description: "Stage an update to a published scheduled action or temp_sched_* draft-created scheduled action.",
|
|
@@ -29364,7 +28878,7 @@ registerSchema({
|
|
|
29364
28878
|
prompt: { type: "string", description: "Replacement additional spawned-agent instructions", required: false }
|
|
29365
28879
|
}
|
|
29366
28880
|
});
|
|
29367
|
-
var updateCommand2 =
|
|
28881
|
+
var updateCommand2 = defineCommand152({
|
|
29368
28882
|
meta: {
|
|
29369
28883
|
name: "update",
|
|
29370
28884
|
description: "Stage a scheduled action update. Example: baker scheduled-actions update <id> --enabled false"
|
|
@@ -29435,7 +28949,7 @@ var updateCommand2 = defineCommand154({
|
|
|
29435
28949
|
});
|
|
29436
28950
|
|
|
29437
28951
|
// src/commands/scheduled-actions/index.ts
|
|
29438
|
-
var scheduledActionsCommand =
|
|
28952
|
+
var scheduledActionsCommand = defineCommand153({
|
|
29439
28953
|
meta: {
|
|
29440
28954
|
name: "scheduled-actions",
|
|
29441
28955
|
description: `Manage Scheduled Actions. Subcommands: list, get, create, update, delete, trigger.
|
|
@@ -29462,8 +28976,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-actions.md`
|
|
|
29462
28976
|
});
|
|
29463
28977
|
|
|
29464
28978
|
// src/commands/schema.ts
|
|
29465
|
-
import { defineCommand as
|
|
29466
|
-
var schemaCommand =
|
|
28979
|
+
import { defineCommand as defineCommand154 } from "citty";
|
|
28980
|
+
var schemaCommand = defineCommand154({
|
|
29467
28981
|
meta: {
|
|
29468
28982
|
name: "schema",
|
|
29469
28983
|
description: "Inspect command argument schemas (for AI agent introspection). Lists all commands if no argument given. Example: baker schema images.search"
|
|
@@ -29505,7 +29019,7 @@ var schemaCommand = defineCommand156({
|
|
|
29505
29019
|
});
|
|
29506
29020
|
|
|
29507
29021
|
// src/commands/tags/index.ts
|
|
29508
|
-
import { defineCommand as
|
|
29022
|
+
import { defineCommand as defineCommand155 } from "citty";
|
|
29509
29023
|
|
|
29510
29024
|
// src/commands/tags/shared.ts
|
|
29511
29025
|
function failApi3(err) {
|
|
@@ -29571,7 +29085,7 @@ async function listTags(json) {
|
|
|
29571
29085
|
failApi3(err);
|
|
29572
29086
|
}
|
|
29573
29087
|
}
|
|
29574
|
-
var listCommand10 =
|
|
29088
|
+
var listCommand10 = defineCommand155({
|
|
29575
29089
|
meta: {
|
|
29576
29090
|
name: "list",
|
|
29577
29091
|
description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
|
|
@@ -29590,7 +29104,7 @@ async function listDraft3() {
|
|
|
29590
29104
|
failApi3(err);
|
|
29591
29105
|
}
|
|
29592
29106
|
}
|
|
29593
|
-
var draftCommand3 =
|
|
29107
|
+
var draftCommand3 = defineCommand155({
|
|
29594
29108
|
meta: {
|
|
29595
29109
|
name: "draft",
|
|
29596
29110
|
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)."
|
|
@@ -29599,7 +29113,7 @@ var draftCommand3 = defineCommand157({
|
|
|
29599
29113
|
await listDraft3();
|
|
29600
29114
|
}
|
|
29601
29115
|
});
|
|
29602
|
-
var tagsCommand3 =
|
|
29116
|
+
var tagsCommand3 = defineCommand155({
|
|
29603
29117
|
meta: {
|
|
29604
29118
|
name: "tags",
|
|
29605
29119
|
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.
|
|
@@ -29625,10 +29139,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
29625
29139
|
});
|
|
29626
29140
|
|
|
29627
29141
|
// src/commands/testimonials/index.ts
|
|
29628
|
-
import { defineCommand as
|
|
29142
|
+
import { defineCommand as defineCommand159 } from "citty";
|
|
29629
29143
|
|
|
29630
29144
|
// src/commands/testimonials/get.ts
|
|
29631
|
-
import { defineCommand as
|
|
29145
|
+
import { defineCommand as defineCommand156 } from "citty";
|
|
29632
29146
|
registerSchema({
|
|
29633
29147
|
command: "testimonials.get",
|
|
29634
29148
|
description: "Get a single testimonial by ID",
|
|
@@ -29636,7 +29150,7 @@ registerSchema({
|
|
|
29636
29150
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
29637
29151
|
}
|
|
29638
29152
|
});
|
|
29639
|
-
var getCommand4 =
|
|
29153
|
+
var getCommand4 = defineCommand156({
|
|
29640
29154
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
29641
29155
|
args: {
|
|
29642
29156
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -29673,7 +29187,7 @@ var getCommand4 = defineCommand158({
|
|
|
29673
29187
|
});
|
|
29674
29188
|
|
|
29675
29189
|
// src/commands/testimonials/list.ts
|
|
29676
|
-
import { defineCommand as
|
|
29190
|
+
import { defineCommand as defineCommand157 } from "citty";
|
|
29677
29191
|
registerSchema({
|
|
29678
29192
|
command: "testimonials.list",
|
|
29679
29193
|
description: "List testimonials with optional filters.",
|
|
@@ -29703,7 +29217,7 @@ registerSchema({
|
|
|
29703
29217
|
limit: { type: "number", description: "Max results (default 50)", required: false, default: 50 }
|
|
29704
29218
|
}
|
|
29705
29219
|
});
|
|
29706
|
-
var listCommand11 =
|
|
29220
|
+
var listCommand11 = defineCommand157({
|
|
29707
29221
|
meta: {
|
|
29708
29222
|
name: "list",
|
|
29709
29223
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -29752,7 +29266,7 @@ var listCommand11 = defineCommand159({
|
|
|
29752
29266
|
});
|
|
29753
29267
|
|
|
29754
29268
|
// src/commands/testimonials/search.ts
|
|
29755
|
-
import { defineCommand as
|
|
29269
|
+
import { defineCommand as defineCommand158 } from "citty";
|
|
29756
29270
|
function languageBiasHint(results, requestedLanguage) {
|
|
29757
29271
|
if (requestedLanguage) {
|
|
29758
29272
|
return null;
|
|
@@ -29830,7 +29344,7 @@ function buildSearchRequest(query, args) {
|
|
|
29830
29344
|
}
|
|
29831
29345
|
return body;
|
|
29832
29346
|
}
|
|
29833
|
-
var searchCommand2 =
|
|
29347
|
+
var searchCommand2 = defineCommand158({
|
|
29834
29348
|
meta: {
|
|
29835
29349
|
name: "search",
|
|
29836
29350
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -29886,7 +29400,7 @@ var searchCommand2 = defineCommand160({
|
|
|
29886
29400
|
var tagsCommand4 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
29887
29401
|
|
|
29888
29402
|
// src/commands/testimonials/index.ts
|
|
29889
|
-
var testimonialsCommand =
|
|
29403
|
+
var testimonialsCommand = defineCommand159({
|
|
29890
29404
|
meta: {
|
|
29891
29405
|
name: "testimonials",
|
|
29892
29406
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -29908,10 +29422,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
29908
29422
|
});
|
|
29909
29423
|
|
|
29910
29424
|
// src/commands/videos/index.ts
|
|
29911
|
-
import { defineCommand as
|
|
29425
|
+
import { defineCommand as defineCommand164 } from "citty";
|
|
29912
29426
|
|
|
29913
29427
|
// src/commands/videos/delete.ts
|
|
29914
|
-
import { defineCommand as
|
|
29428
|
+
import { defineCommand as defineCommand160 } from "citty";
|
|
29915
29429
|
registerSchema({
|
|
29916
29430
|
command: "videos.delete",
|
|
29917
29431
|
description: "Delete a video by ID",
|
|
@@ -29925,7 +29439,7 @@ registerSchema({
|
|
|
29925
29439
|
}
|
|
29926
29440
|
}
|
|
29927
29441
|
});
|
|
29928
|
-
var deleteCommand3 =
|
|
29442
|
+
var deleteCommand3 = defineCommand160({
|
|
29929
29443
|
meta: {
|
|
29930
29444
|
name: "delete",
|
|
29931
29445
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -29966,7 +29480,7 @@ var deleteCommand3 = defineCommand162({
|
|
|
29966
29480
|
});
|
|
29967
29481
|
|
|
29968
29482
|
// src/commands/videos/get.ts
|
|
29969
|
-
import { defineCommand as
|
|
29483
|
+
import { defineCommand as defineCommand161 } from "citty";
|
|
29970
29484
|
registerSchema({
|
|
29971
29485
|
command: "videos.get",
|
|
29972
29486
|
description: "Get a single video by ID",
|
|
@@ -29974,7 +29488,7 @@ registerSchema({
|
|
|
29974
29488
|
id: { type: "string", description: "Video ID", required: true }
|
|
29975
29489
|
}
|
|
29976
29490
|
});
|
|
29977
|
-
var getCommand5 =
|
|
29491
|
+
var getCommand5 = defineCommand161({
|
|
29978
29492
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
29979
29493
|
args: {
|
|
29980
29494
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -30011,7 +29525,7 @@ var getCommand5 = defineCommand163({
|
|
|
30011
29525
|
});
|
|
30012
29526
|
|
|
30013
29527
|
// src/commands/videos/search.ts
|
|
30014
|
-
import { defineCommand as
|
|
29528
|
+
import { defineCommand as defineCommand162 } from "citty";
|
|
30015
29529
|
registerSchema({
|
|
30016
29530
|
command: "videos.search",
|
|
30017
29531
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -30021,7 +29535,7 @@ registerSchema({
|
|
|
30021
29535
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
30022
29536
|
}
|
|
30023
29537
|
});
|
|
30024
|
-
var searchCommand3 =
|
|
29538
|
+
var searchCommand3 = defineCommand162({
|
|
30025
29539
|
meta: {
|
|
30026
29540
|
name: "search",
|
|
30027
29541
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -30071,9 +29585,9 @@ var searchCommand3 = defineCommand164({
|
|
|
30071
29585
|
var tagsCommand5 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
30072
29586
|
|
|
30073
29587
|
// src/commands/videos/upload.ts
|
|
30074
|
-
import { readFile as
|
|
29588
|
+
import { readFile as readFile22, stat as stat7 } from "fs/promises";
|
|
30075
29589
|
import { extname as extname3 } from "path";
|
|
30076
|
-
import { defineCommand as
|
|
29590
|
+
import { defineCommand as defineCommand163 } from "citty";
|
|
30077
29591
|
var MIME_MAP = {
|
|
30078
29592
|
".mp4": "video/mp4",
|
|
30079
29593
|
".mov": "video/quicktime",
|
|
@@ -30107,7 +29621,7 @@ function detectContentType(filePath) {
|
|
|
30107
29621
|
}
|
|
30108
29622
|
return mime;
|
|
30109
29623
|
}
|
|
30110
|
-
var uploadCommand2 =
|
|
29624
|
+
var uploadCommand2 = defineCommand163({
|
|
30111
29625
|
meta: {
|
|
30112
29626
|
name: "upload",
|
|
30113
29627
|
description: "Upload a video file to Baker via Mux direct upload. Auto-detects content type. Example: baker videos upload ./demo.mp4"
|
|
@@ -30136,7 +29650,7 @@ var uploadCommand2 = defineCommand165({
|
|
|
30136
29650
|
return;
|
|
30137
29651
|
}
|
|
30138
29652
|
const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
|
|
30139
|
-
const fileBuffer = await
|
|
29653
|
+
const fileBuffer = await readFile22(filePath);
|
|
30140
29654
|
const uploadResponse = await fetch(uploadUrl, {
|
|
30141
29655
|
method: "PUT",
|
|
30142
29656
|
headers: { "Content-Type": contentType },
|
|
@@ -30161,7 +29675,7 @@ var uploadCommand2 = defineCommand165({
|
|
|
30161
29675
|
});
|
|
30162
29676
|
|
|
30163
29677
|
// src/commands/videos/index.ts
|
|
30164
|
-
var videosCommand =
|
|
29678
|
+
var videosCommand = defineCommand164({
|
|
30165
29679
|
meta: {
|
|
30166
29680
|
name: "videos",
|
|
30167
29681
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, delete, tags.
|
|
@@ -30185,10 +29699,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
30185
29699
|
});
|
|
30186
29700
|
|
|
30187
29701
|
// src/commands/winning-ads/index.ts
|
|
30188
|
-
import { defineCommand as
|
|
29702
|
+
import { defineCommand as defineCommand177 } from "citty";
|
|
30189
29703
|
|
|
30190
29704
|
// src/commands/winning-ads/advertisers.ts
|
|
30191
|
-
import { defineCommand as
|
|
29705
|
+
import { defineCommand as defineCommand165 } from "citty";
|
|
30192
29706
|
|
|
30193
29707
|
// src/commands/winning-ads/shared.ts
|
|
30194
29708
|
function splitList(value) {
|
|
@@ -30241,7 +29755,7 @@ function advertiserNormalizer(record, full) {
|
|
|
30241
29755
|
last_synced_at: record.last_synced_at ?? null
|
|
30242
29756
|
};
|
|
30243
29757
|
}
|
|
30244
|
-
var advertisersCommand2 =
|
|
29758
|
+
var advertisersCommand2 = defineCommand165({
|
|
30245
29759
|
meta: {
|
|
30246
29760
|
name: "advertisers",
|
|
30247
29761
|
description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
|
|
@@ -30299,7 +29813,7 @@ var advertisersCommand2 = defineCommand167({
|
|
|
30299
29813
|
});
|
|
30300
29814
|
|
|
30301
29815
|
// src/commands/winning-ads/brief.ts
|
|
30302
|
-
import { defineCommand as
|
|
29816
|
+
import { defineCommand as defineCommand166 } from "citty";
|
|
30303
29817
|
registerSchema({
|
|
30304
29818
|
command: "winning-ads.brief",
|
|
30305
29819
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -30345,7 +29859,7 @@ function parseDna(raw) {
|
|
|
30345
29859
|
}
|
|
30346
29860
|
return parsed;
|
|
30347
29861
|
}
|
|
30348
|
-
var briefCommand =
|
|
29862
|
+
var briefCommand = defineCommand166({
|
|
30349
29863
|
meta: {
|
|
30350
29864
|
name: "brief",
|
|
30351
29865
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -30381,7 +29895,7 @@ var briefCommand = defineCommand168({
|
|
|
30381
29895
|
});
|
|
30382
29896
|
|
|
30383
29897
|
// src/commands/winning-ads/content.ts
|
|
30384
|
-
import { defineCommand as
|
|
29898
|
+
import { defineCommand as defineCommand167 } from "citty";
|
|
30385
29899
|
registerSchema({
|
|
30386
29900
|
command: "winning-ads.content",
|
|
30387
29901
|
description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
|
|
@@ -30394,7 +29908,7 @@ registerSchema({
|
|
|
30394
29908
|
}
|
|
30395
29909
|
}
|
|
30396
29910
|
});
|
|
30397
|
-
var contentCommand =
|
|
29911
|
+
var contentCommand = defineCommand167({
|
|
30398
29912
|
meta: {
|
|
30399
29913
|
name: "content",
|
|
30400
29914
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -30443,7 +29957,7 @@ var contentCommand = defineCommand169({
|
|
|
30443
29957
|
});
|
|
30444
29958
|
|
|
30445
29959
|
// src/commands/winning-ads/feed.ts
|
|
30446
|
-
import { defineCommand as
|
|
29960
|
+
import { defineCommand as defineCommand168 } from "citty";
|
|
30447
29961
|
function buildFeedParams(input) {
|
|
30448
29962
|
const params = {};
|
|
30449
29963
|
const advertiser = splitList(input.advertiser);
|
|
@@ -30495,7 +30009,7 @@ registerSchema({
|
|
|
30495
30009
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
30496
30010
|
}
|
|
30497
30011
|
});
|
|
30498
|
-
var feedCommand =
|
|
30012
|
+
var feedCommand = defineCommand168({
|
|
30499
30013
|
meta: {
|
|
30500
30014
|
name: "feed",
|
|
30501
30015
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -30580,7 +30094,7 @@ var feedCommand = defineCommand170({
|
|
|
30580
30094
|
});
|
|
30581
30095
|
|
|
30582
30096
|
// src/commands/winning-ads/follow.ts
|
|
30583
|
-
import { defineCommand as
|
|
30097
|
+
import { defineCommand as defineCommand169 } from "citty";
|
|
30584
30098
|
var PLATFORMS = ["meta", "linkedin"];
|
|
30585
30099
|
registerSchema({
|
|
30586
30100
|
command: "winning-ads.follow",
|
|
@@ -30595,7 +30109,7 @@ registerSchema({
|
|
|
30595
30109
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
30596
30110
|
}
|
|
30597
30111
|
});
|
|
30598
|
-
var followCommand =
|
|
30112
|
+
var followCommand = defineCommand169({
|
|
30599
30113
|
meta: {
|
|
30600
30114
|
name: "follow",
|
|
30601
30115
|
description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks both Meta + LinkedIn. Example: baker winning-ads follow "deel.com" --platform meta'
|
|
@@ -30642,7 +30156,7 @@ var followCommand = defineCommand171({
|
|
|
30642
30156
|
});
|
|
30643
30157
|
|
|
30644
30158
|
// src/commands/winning-ads/follow-competitors.ts
|
|
30645
|
-
import { defineCommand as
|
|
30159
|
+
import { defineCommand as defineCommand170 } from "citty";
|
|
30646
30160
|
var PLATFORMS2 = ["meta", "linkedin"];
|
|
30647
30161
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
30648
30162
|
function buildFollowBatchBody(input) {
|
|
@@ -30675,7 +30189,7 @@ registerSchema({
|
|
|
30675
30189
|
}
|
|
30676
30190
|
}
|
|
30677
30191
|
});
|
|
30678
|
-
var followCompetitorsCommand =
|
|
30192
|
+
var followCompetitorsCommand = defineCommand170({
|
|
30679
30193
|
meta: {
|
|
30680
30194
|
name: "follow-competitors",
|
|
30681
30195
|
description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
|
|
@@ -30750,7 +30264,7 @@ var followCompetitorsCommand = defineCommand172({
|
|
|
30750
30264
|
});
|
|
30751
30265
|
|
|
30752
30266
|
// src/commands/winning-ads/following.ts
|
|
30753
|
-
import { defineCommand as
|
|
30267
|
+
import { defineCommand as defineCommand171 } from "citty";
|
|
30754
30268
|
registerSchema({
|
|
30755
30269
|
command: "winning-ads.following",
|
|
30756
30270
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts.",
|
|
@@ -30783,7 +30297,7 @@ function followingNormalizer(record, full) {
|
|
|
30783
30297
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
30784
30298
|
};
|
|
30785
30299
|
}
|
|
30786
|
-
var followingCommand =
|
|
30300
|
+
var followingCommand = defineCommand171({
|
|
30787
30301
|
meta: {
|
|
30788
30302
|
name: "following",
|
|
30789
30303
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. Example: baker winning-ads following --output md"
|
|
@@ -30818,7 +30332,7 @@ var followingCommand = defineCommand173({
|
|
|
30818
30332
|
});
|
|
30819
30333
|
|
|
30820
30334
|
// src/commands/winning-ads/patterns.ts
|
|
30821
|
-
import { defineCommand as
|
|
30335
|
+
import { defineCommand as defineCommand172 } from "citty";
|
|
30822
30336
|
registerSchema({
|
|
30823
30337
|
command: "winning-ads.patterns",
|
|
30824
30338
|
description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
|
|
@@ -30857,7 +30371,7 @@ function discriminatorRow(record) {
|
|
|
30857
30371
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
30858
30372
|
};
|
|
30859
30373
|
}
|
|
30860
|
-
var patternsCommand =
|
|
30374
|
+
var patternsCommand = defineCommand172({
|
|
30861
30375
|
meta: {
|
|
30862
30376
|
name: "patterns",
|
|
30863
30377
|
description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
|
|
@@ -30913,7 +30427,7 @@ var patternsCommand = defineCommand174({
|
|
|
30913
30427
|
});
|
|
30914
30428
|
|
|
30915
30429
|
// src/commands/winning-ads/search.ts
|
|
30916
|
-
import { defineCommand as
|
|
30430
|
+
import { defineCommand as defineCommand173 } from "citty";
|
|
30917
30431
|
registerSchema({
|
|
30918
30432
|
command: "winning-ads.search",
|
|
30919
30433
|
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
|
|
@@ -31021,7 +30535,7 @@ function buildSearchBody(args) {
|
|
|
31021
30535
|
}
|
|
31022
30536
|
return body;
|
|
31023
30537
|
}
|
|
31024
|
-
var searchCommand4 =
|
|
30538
|
+
var searchCommand4 = defineCommand173({
|
|
31025
30539
|
meta: {
|
|
31026
30540
|
name: "search",
|
|
31027
30541
|
description: "Search winning reference ads. Example: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --winner-category winner --exclude-advertiser adv_123 --output md"
|
|
@@ -31136,7 +30650,7 @@ var searchCommand4 = defineCommand175({
|
|
|
31136
30650
|
});
|
|
31137
30651
|
|
|
31138
30652
|
// src/commands/winning-ads/seeds.ts
|
|
31139
|
-
import { defineCommand as
|
|
30653
|
+
import { defineCommand as defineCommand174 } from "citty";
|
|
31140
30654
|
function leanRow(r) {
|
|
31141
30655
|
return {
|
|
31142
30656
|
key: r.key,
|
|
@@ -31164,7 +30678,7 @@ function makeSeedCommand(opts) {
|
|
|
31164
30678
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
31165
30679
|
}
|
|
31166
30680
|
});
|
|
31167
|
-
return
|
|
30681
|
+
return defineCommand174({
|
|
31168
30682
|
meta: { name: opts.name, description: opts.description },
|
|
31169
30683
|
args: {
|
|
31170
30684
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -31213,7 +30727,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
31213
30727
|
});
|
|
31214
30728
|
|
|
31215
30729
|
// src/commands/winning-ads/unfollow.ts
|
|
31216
|
-
import { defineCommand as
|
|
30730
|
+
import { defineCommand as defineCommand175 } from "citty";
|
|
31217
30731
|
registerSchema({
|
|
31218
30732
|
command: "winning-ads.unfollow",
|
|
31219
30733
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -31221,7 +30735,7 @@ registerSchema({
|
|
|
31221
30735
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
31222
30736
|
}
|
|
31223
30737
|
});
|
|
31224
|
-
var unfollowCommand =
|
|
30738
|
+
var unfollowCommand = defineCommand175({
|
|
31225
30739
|
meta: {
|
|
31226
30740
|
name: "unfollow",
|
|
31227
30741
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -31242,7 +30756,7 @@ var unfollowCommand = defineCommand177({
|
|
|
31242
30756
|
});
|
|
31243
30757
|
|
|
31244
30758
|
// src/commands/winning-ads/winners.ts
|
|
31245
|
-
import { defineCommand as
|
|
30759
|
+
import { defineCommand as defineCommand176 } from "citty";
|
|
31246
30760
|
registerSchema({
|
|
31247
30761
|
command: "winning-ads.winners",
|
|
31248
30762
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -31252,7 +30766,7 @@ registerSchema({
|
|
|
31252
30766
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin", required: false }
|
|
31253
30767
|
}
|
|
31254
30768
|
});
|
|
31255
|
-
var winnersCommand =
|
|
30769
|
+
var winnersCommand = defineCommand176({
|
|
31256
30770
|
meta: {
|
|
31257
30771
|
name: "winners",
|
|
31258
30772
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -31302,7 +30816,7 @@ var winnersCommand = defineCommand178({
|
|
|
31302
30816
|
});
|
|
31303
30817
|
|
|
31304
30818
|
// src/commands/winning-ads/index.ts
|
|
31305
|
-
var winningAdsCommand =
|
|
30819
|
+
var winningAdsCommand = defineCommand177({
|
|
31306
30820
|
meta: {
|
|
31307
30821
|
name: "winning-ads",
|
|
31308
30822
|
description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
|
|
@@ -31374,7 +30888,7 @@ function getCliVersion() {
|
|
|
31374
30888
|
}
|
|
31375
30889
|
|
|
31376
30890
|
// src/cli.ts
|
|
31377
|
-
var main =
|
|
30891
|
+
var main = defineCommand178({
|
|
31378
30892
|
meta: {
|
|
31379
30893
|
name: "baker",
|
|
31380
30894
|
version: getCliVersion(),
|
|
@@ -31390,7 +30904,6 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
|
|
|
31390
30904
|
actions: actionsCommand,
|
|
31391
30905
|
"scheduled-actions": scheduledActionsCommand,
|
|
31392
30906
|
ads: adsCommand2,
|
|
31393
|
-
brand: brandCommand,
|
|
31394
30907
|
ga4: ga4Command,
|
|
31395
30908
|
gsc: gscCommand,
|
|
31396
30909
|
research: researchCommand,
|