@koda-sl/baker-cli 0.182.0-dev.c8185c1b5 → 0.182.1-dev.c8185c1b5
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 -2
- package/dist/cli.js +128 -80
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4989,7 +4989,7 @@ baker landing inspiration code <section id> # the standalone bundle
|
|
|
4989
4989
|
baker landing inspiration page <source id> # a whole page as a section sequence
|
|
4990
4990
|
baker landing inspiration add https://linear.app --note "client likes this density"
|
|
4991
4991
|
baker landing inspiration favorites # what this company has saved
|
|
4992
|
-
baker landing inspiration scrape <url> --out <dir> #
|
|
4992
|
+
baker landing inspiration scrape <url> --out <dir> # capture any page now, synchronously
|
|
4993
4993
|
```
|
|
4994
4994
|
|
|
4995
4995
|
- **Hybrid search over three signals** — keywords, meaning, and *appearance* (the screenshot is embedded, so a query like "dark developer hero with a terminal" can match a section whose text never says "terminal"). Filters: `--type --composition --register --interaction --motion --media --device --theme --max-rank --min-craft --min-fidelity --domain --similar-to --scope --limit`.
|
|
@@ -4997,7 +4997,8 @@ baker landing inspiration scrape <url> --out <dir> # run the capture locally (
|
|
|
4997
4997
|
- **`fidelity` says how much to trust the code.** A measured 0–1 match between the live section and our standalone re-render, always reported. Above ~0.95 the markup renders like the original; below ~0.75 the section is scroll- or JS-driven and it does not.
|
|
4998
4998
|
- **`used_on_pages`** appears when a section shows up on more than one of that site's pages — a nav or footer they ship everywhere, which is a stronger reference than a one-off.
|
|
4999
4999
|
- **The corpus is shared across companies; favorites are per-company**, and search defaults to this company's saved sections.
|
|
5000
|
-
-
|
|
5000
|
+
- **`add` studies in the background; `scrape` returns with the page on disk.** `add` grows the shared library and takes minutes, so it can never answer "build our page like this one" within the same turn. `scrape` runs the identical capture locally and blocks until it finishes, writing section screenshots, standalone markup, a whole-page reproduction and `report.html`. `--no-motion` roughly halves the runtime; `--no-mobile`, `--no-code` and `--no-report` skip further passes.
|
|
5001
|
+
- **Inspiration, never a clipboard.** Both `code` and `scrape` record what was consulted, and `critique`'s `originality` family blocks a publish that reuses a reference's copy verbatim.
|
|
5001
5002
|
|
|
5002
5003
|
### `baker landing critique`
|
|
5003
5004
|
|
package/dist/cli.js
CHANGED
|
@@ -8125,11 +8125,11 @@ function rawTextEntries(value) {
|
|
|
8125
8125
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
8126
8126
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
8127
8127
|
}
|
|
8128
|
-
function rawFileEntries(
|
|
8129
|
-
if (typeof
|
|
8128
|
+
function rawFileEntries(path35) {
|
|
8129
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
8130
8130
|
return [];
|
|
8131
8131
|
}
|
|
8132
|
-
return readFileSync2(
|
|
8132
|
+
return readFileSync2(path35, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
8133
8133
|
}
|
|
8134
8134
|
function keywordEntries(args) {
|
|
8135
8135
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -8152,19 +8152,19 @@ function keywordEntries(args) {
|
|
|
8152
8152
|
}
|
|
8153
8153
|
return entries;
|
|
8154
8154
|
}
|
|
8155
|
-
function loadJsonFileArg(
|
|
8156
|
-
if (typeof
|
|
8155
|
+
function loadJsonFileArg(path35) {
|
|
8156
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
8157
8157
|
return {};
|
|
8158
8158
|
}
|
|
8159
8159
|
try {
|
|
8160
|
-
const parsed = JSON.parse(readFileSync2(
|
|
8160
|
+
const parsed = JSON.parse(readFileSync2(path35, "utf8"));
|
|
8161
8161
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8162
|
-
failWriteValidation(`${
|
|
8162
|
+
failWriteValidation(`${path35} must contain a JSON object`);
|
|
8163
8163
|
}
|
|
8164
8164
|
return parsed;
|
|
8165
8165
|
} catch (err) {
|
|
8166
8166
|
if (err instanceof SyntaxError) {
|
|
8167
|
-
failWriteValidation(`${
|
|
8167
|
+
failWriteValidation(`${path35} is not valid JSON: ${err.message}`);
|
|
8168
8168
|
}
|
|
8169
8169
|
throw err;
|
|
8170
8170
|
}
|
|
@@ -8294,10 +8294,10 @@ async function stageUpdate(kind, customerId, target, payload, hints) {
|
|
|
8294
8294
|
async function stageTarget(kind, customerId, target, hints) {
|
|
8295
8295
|
await stageGoogleOp({ kind, customerId, target }, hints);
|
|
8296
8296
|
}
|
|
8297
|
-
async function draftAction(
|
|
8297
|
+
async function draftAction(path35, body, chat) {
|
|
8298
8298
|
try {
|
|
8299
8299
|
const chatId = resolveChatId(chat);
|
|
8300
|
-
const response = await apiPost(
|
|
8300
|
+
const response = await apiPost(path35, { chatId, ...body });
|
|
8301
8301
|
writeJsonEnvelope(response);
|
|
8302
8302
|
} catch (err) {
|
|
8303
8303
|
handleGoogleError(err);
|
|
@@ -10965,19 +10965,19 @@ function failWriteValidation2(message) {
|
|
|
10965
10965
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
10966
10966
|
process.exit(1);
|
|
10967
10967
|
}
|
|
10968
|
-
function loadJsonFileArg2(
|
|
10969
|
-
if (typeof
|
|
10968
|
+
function loadJsonFileArg2(path35) {
|
|
10969
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
10970
10970
|
return {};
|
|
10971
10971
|
}
|
|
10972
10972
|
try {
|
|
10973
|
-
const parsed = JSON.parse(readFileSync4(
|
|
10973
|
+
const parsed = JSON.parse(readFileSync4(path35, "utf8"));
|
|
10974
10974
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
10975
|
-
failWriteValidation2(`${
|
|
10975
|
+
failWriteValidation2(`${path35} must contain a JSON object`);
|
|
10976
10976
|
}
|
|
10977
10977
|
return parsed;
|
|
10978
10978
|
} catch (err) {
|
|
10979
10979
|
if (err instanceof SyntaxError) {
|
|
10980
|
-
failWriteValidation2(`${
|
|
10980
|
+
failWriteValidation2(`${path35} is not valid JSON: ${err.message}`);
|
|
10981
10981
|
}
|
|
10982
10982
|
throw err;
|
|
10983
10983
|
}
|
|
@@ -11062,15 +11062,15 @@ function parseLocaleFlag(value) {
|
|
|
11062
11062
|
}
|
|
11063
11063
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
11064
11064
|
}
|
|
11065
|
-
function loadTargetingFileArg(
|
|
11066
|
-
if (typeof
|
|
11065
|
+
function loadTargetingFileArg(path35) {
|
|
11066
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
11067
11067
|
return void 0;
|
|
11068
11068
|
}
|
|
11069
|
-
const parsed = loadJsonFileArg2(
|
|
11069
|
+
const parsed = loadJsonFileArg2(path35);
|
|
11070
11070
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
11071
11071
|
if (!criteria.include) {
|
|
11072
11072
|
failWriteValidation2(
|
|
11073
|
-
`${
|
|
11073
|
+
`${path35} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
11074
11074
|
);
|
|
11075
11075
|
}
|
|
11076
11076
|
return criteria;
|
|
@@ -11105,14 +11105,14 @@ function parseCsvLine(line) {
|
|
|
11105
11105
|
cells.push(current);
|
|
11106
11106
|
return cells.map((cell) => cell.trim());
|
|
11107
11107
|
}
|
|
11108
|
-
function parseListFileArg(
|
|
11109
|
-
if (typeof
|
|
11108
|
+
function parseListFileArg(path35, maxRows) {
|
|
11109
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
11110
11110
|
return void 0;
|
|
11111
11111
|
}
|
|
11112
|
-
const raw = readFileSync4(
|
|
11112
|
+
const raw = readFileSync4(path35, "utf8");
|
|
11113
11113
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
11114
11114
|
if (lines.length < 2) {
|
|
11115
|
-
failWriteValidation2(`${
|
|
11115
|
+
failWriteValidation2(`${path35} needs a header row and at least one data row`);
|
|
11116
11116
|
}
|
|
11117
11117
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
11118
11118
|
const rows = [];
|
|
@@ -11131,7 +11131,7 @@ function parseListFileArg(path34, maxRows) {
|
|
|
11131
11131
|
}
|
|
11132
11132
|
}
|
|
11133
11133
|
if (rows.length > maxRows) {
|
|
11134
|
-
failWriteValidation2(`${
|
|
11134
|
+
failWriteValidation2(`${path35} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
11135
11135
|
}
|
|
11136
11136
|
return { columns, rows };
|
|
11137
11137
|
}
|
|
@@ -11227,11 +11227,11 @@ function readPositionals(args) {
|
|
|
11227
11227
|
function splitIdList(raw) {
|
|
11228
11228
|
return raw.split(",").map((id) => id.trim()).filter(Boolean);
|
|
11229
11229
|
}
|
|
11230
|
-
function idsFileEntries(
|
|
11231
|
-
if (typeof
|
|
11230
|
+
function idsFileEntries(path35) {
|
|
11231
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
11232
11232
|
return [];
|
|
11233
11233
|
}
|
|
11234
|
-
return readFileSync4(
|
|
11234
|
+
return readFileSync4(path35, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
11235
11235
|
}
|
|
11236
11236
|
function requireTargets(args, entity) {
|
|
11237
11237
|
const positionals = readPositionals(args);
|
|
@@ -13854,9 +13854,9 @@ function compactRow(row) {
|
|
|
13854
13854
|
...destination.postUrn ? { postUrn: destination.postUrn } : {}
|
|
13855
13855
|
};
|
|
13856
13856
|
}
|
|
13857
|
-
function readPath(row,
|
|
13857
|
+
function readPath(row, path35) {
|
|
13858
13858
|
let current = row;
|
|
13859
|
-
for (const segment of
|
|
13859
|
+
for (const segment of path35.split(".")) {
|
|
13860
13860
|
const record = asRecord2(current);
|
|
13861
13861
|
if (!record) return void 0;
|
|
13862
13862
|
current = record[segment];
|
|
@@ -13866,10 +13866,10 @@ function readPath(row, path34) {
|
|
|
13866
13866
|
function projectFields(rows, paths) {
|
|
13867
13867
|
return rows.map((row) => {
|
|
13868
13868
|
const projected = {};
|
|
13869
|
-
for (const
|
|
13870
|
-
const value = readPath(row,
|
|
13869
|
+
for (const path35 of paths) {
|
|
13870
|
+
const value = readPath(row, path35);
|
|
13871
13871
|
if (value !== void 0) {
|
|
13872
|
-
projected[
|
|
13872
|
+
projected[path35] = value;
|
|
13873
13873
|
}
|
|
13874
13874
|
}
|
|
13875
13875
|
return projected;
|
|
@@ -15076,11 +15076,11 @@ var updateStatusSchema = z18.enum(UPDATE_STATUSES);
|
|
|
15076
15076
|
function currencyMinimums2(currencyCode) {
|
|
15077
15077
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
15078
15078
|
}
|
|
15079
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
15079
|
+
function validateDailyBudgetFloor(money, ctx, path35) {
|
|
15080
15080
|
if (money?.currencyCode) {
|
|
15081
15081
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
15082
15082
|
if (Number(money.amount) < min) {
|
|
15083
|
-
ctx.addIssue({ code: "custom", path:
|
|
15083
|
+
ctx.addIssue({ code: "custom", path: path35, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
15084
15084
|
}
|
|
15085
15085
|
}
|
|
15086
15086
|
}
|
|
@@ -15723,19 +15723,19 @@ function failWriteValidation3(message) {
|
|
|
15723
15723
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
15724
15724
|
process.exit(1);
|
|
15725
15725
|
}
|
|
15726
|
-
function loadJsonFileArg3(
|
|
15727
|
-
if (typeof
|
|
15726
|
+
function loadJsonFileArg3(path35) {
|
|
15727
|
+
if (typeof path35 !== "string" || path35.length === 0) {
|
|
15728
15728
|
return {};
|
|
15729
15729
|
}
|
|
15730
15730
|
try {
|
|
15731
|
-
const parsed = JSON.parse(readFileSync8(
|
|
15731
|
+
const parsed = JSON.parse(readFileSync8(path35, "utf8"));
|
|
15732
15732
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
15733
|
-
failWriteValidation3(`${
|
|
15733
|
+
failWriteValidation3(`${path35} must contain a JSON object`);
|
|
15734
15734
|
}
|
|
15735
15735
|
return parsed;
|
|
15736
15736
|
} catch (err) {
|
|
15737
15737
|
if (err instanceof SyntaxError) {
|
|
15738
|
-
failWriteValidation3(`${
|
|
15738
|
+
failWriteValidation3(`${path35} is not valid JSON: ${err.message}`);
|
|
15739
15739
|
}
|
|
15740
15740
|
throw err;
|
|
15741
15741
|
}
|
|
@@ -26531,12 +26531,12 @@ function listFlowSlugs() {
|
|
|
26531
26531
|
return readdirSync2(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && entry.name !== ".gitkeep").map((entry) => entry.name).sort();
|
|
26532
26532
|
}
|
|
26533
26533
|
function readFlowTree(slug) {
|
|
26534
|
-
const
|
|
26535
|
-
if (!existsSync4(
|
|
26534
|
+
const path35 = join3(flowsDir(), slug, "_data.json");
|
|
26535
|
+
if (!existsSync4(path35)) {
|
|
26536
26536
|
failLocal(`No form "${slug}". Run "baker flows list" to see the forms in this workspace.`);
|
|
26537
26537
|
}
|
|
26538
26538
|
try {
|
|
26539
|
-
return JSON.parse(readFileSync9(
|
|
26539
|
+
return JSON.parse(readFileSync9(path35, "utf-8"));
|
|
26540
26540
|
} catch (error) {
|
|
26541
26541
|
failLocal(`Could not read form "${slug}": ${error instanceof Error ? error.message : String(error)}`);
|
|
26542
26542
|
}
|
|
@@ -26949,10 +26949,10 @@ async function stageOps(ops) {
|
|
|
26949
26949
|
handleError(err);
|
|
26950
26950
|
}
|
|
26951
26951
|
}
|
|
26952
|
-
async function draftAction2(
|
|
26952
|
+
async function draftAction2(path35, body, chat) {
|
|
26953
26953
|
const chatId = resolveChatId(chat);
|
|
26954
26954
|
try {
|
|
26955
|
-
const data = await apiPost(
|
|
26955
|
+
const data = await apiPost(path35, { chatId, ...body });
|
|
26956
26956
|
writeJsonEnvelope({ ok: true, data });
|
|
26957
26957
|
return data;
|
|
26958
26958
|
} catch (err) {
|
|
@@ -28976,9 +28976,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
28976
28976
|
}
|
|
28977
28977
|
return readFile19(pathOrUrl);
|
|
28978
28978
|
}
|
|
28979
|
-
async function isDirectory(
|
|
28979
|
+
async function isDirectory(path35) {
|
|
28980
28980
|
try {
|
|
28981
|
-
const s = await stat4(
|
|
28981
|
+
const s = await stat4(path35);
|
|
28982
28982
|
return s.isDirectory();
|
|
28983
28983
|
} catch {
|
|
28984
28984
|
return false;
|
|
@@ -32870,9 +32870,14 @@ async function readReferences(projectRoot) {
|
|
|
32870
32870
|
}
|
|
32871
32871
|
}
|
|
32872
32872
|
async function recordReference(projectRoot, reference) {
|
|
32873
|
+
return await recordReferences(projectRoot, [reference]);
|
|
32874
|
+
}
|
|
32875
|
+
async function recordReferences(projectRoot, references) {
|
|
32876
|
+
if (references.length === 0) return true;
|
|
32873
32877
|
try {
|
|
32874
32878
|
const existing = await readReferences(projectRoot);
|
|
32875
|
-
const
|
|
32879
|
+
const replaced = new Set(references.map((reference) => reference.sectionId));
|
|
32880
|
+
const merged = [...existing.filter((entry) => !replaced.has(entry.sectionId)), ...references];
|
|
32876
32881
|
const file = path25.join(projectRoot, REFERENCES_FILE);
|
|
32877
32882
|
await mkdir8(path25.dirname(file), { recursive: true });
|
|
32878
32883
|
await writeFile11(file, `${JSON.stringify(merged, null, 2)}
|
|
@@ -33419,8 +33424,25 @@ var pageCommand = defineCommand146({
|
|
|
33419
33424
|
});
|
|
33420
33425
|
|
|
33421
33426
|
// src/commands/landing/inspiration/scrape.ts
|
|
33427
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
33428
|
+
import path32 from "path";
|
|
33422
33429
|
import { defineCommand as defineCommand147 } from "citty";
|
|
33423
33430
|
|
|
33431
|
+
// src/engine/landing/lib/capturedReferences.ts
|
|
33432
|
+
var MAX_STRINGS_PER_SECTION = 40;
|
|
33433
|
+
function bodyOf(markup) {
|
|
33434
|
+
const body = markup.indexOf("<body");
|
|
33435
|
+
return body === -1 ? markup : markup.slice(body);
|
|
33436
|
+
}
|
|
33437
|
+
function capturedCopyStrings(markup) {
|
|
33438
|
+
const seen = /* @__PURE__ */ new Set();
|
|
33439
|
+
for (const { value } of extractVisibleStrings(bodyOf(markup))) {
|
|
33440
|
+
seen.add(value);
|
|
33441
|
+
if (seen.size >= MAX_STRINGS_PER_SECTION) break;
|
|
33442
|
+
}
|
|
33443
|
+
return [...seen];
|
|
33444
|
+
}
|
|
33445
|
+
|
|
33424
33446
|
// src/engine/landing-library/blocked.ts
|
|
33425
33447
|
var CHALLENGE_PHRASES = [
|
|
33426
33448
|
"just a moment",
|
|
@@ -34995,53 +35017,74 @@ async function scrapeLanding(options) {
|
|
|
34995
35017
|
}
|
|
34996
35018
|
|
|
34997
35019
|
// src/commands/landing/inspiration/scrape.ts
|
|
35020
|
+
async function recordCapture(manifest, outDir) {
|
|
35021
|
+
const consultedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
35022
|
+
const references = [];
|
|
35023
|
+
for (const section of manifest.sections) {
|
|
35024
|
+
if (!section.bundle) continue;
|
|
35025
|
+
try {
|
|
35026
|
+
const markup = await readFile24(path32.join(outDir, section.bundle), "utf8");
|
|
35027
|
+
const copyStrings = capturedCopyStrings(markup);
|
|
35028
|
+
if (copyStrings.length === 0) continue;
|
|
35029
|
+
references.push({
|
|
35030
|
+
sectionId: `local:${manifest.finalUrl}#${section.index}`,
|
|
35031
|
+
sourceUrl: manifest.finalUrl,
|
|
35032
|
+
copyStrings,
|
|
35033
|
+
consultedAt
|
|
35034
|
+
});
|
|
35035
|
+
} catch {
|
|
35036
|
+
}
|
|
35037
|
+
}
|
|
35038
|
+
return await recordReferences(process.cwd(), references);
|
|
35039
|
+
}
|
|
34998
35040
|
registerSchema({
|
|
34999
35041
|
command: "landing.inspiration.scrape",
|
|
35000
|
-
description: "
|
|
35042
|
+
description: "Start here when the user points at a specific page and wants it now: capture one landing page into a directory of section screenshots, standalone HTML bundles, a whole-page reproduction and motion filmstrips. Returns when the capture is done, unlike `add`. Read the screenshots. Also records every captured section for the originality check.",
|
|
35001
35043
|
args: {
|
|
35002
35044
|
url: { type: "string", description: "Page to capture", required: true },
|
|
35003
35045
|
out: { type: "string", description: "Output directory", required: true },
|
|
35004
|
-
|
|
35005
|
-
|
|
35046
|
+
mobile: { type: "boolean", description: "Phone-viewport pass. `--no-mobile` to skip", required: false },
|
|
35047
|
+
code: {
|
|
35006
35048
|
type: "boolean",
|
|
35007
|
-
description: "
|
|
35049
|
+
description: "Standalone HTML+CSS bundles and fidelity scores. `--no-code` to segment and screenshot only",
|
|
35008
35050
|
required: false
|
|
35009
35051
|
},
|
|
35010
|
-
|
|
35052
|
+
motion: {
|
|
35011
35053
|
type: "boolean",
|
|
35012
|
-
description: "
|
|
35054
|
+
description: "Film sections that move. `--no-motion` to skip \u2014 roughly halves runtime",
|
|
35013
35055
|
required: false
|
|
35014
35056
|
},
|
|
35015
|
-
|
|
35057
|
+
report: { type: "boolean", description: "Write report.html. `--no-report` to skip", required: false }
|
|
35016
35058
|
}
|
|
35017
35059
|
});
|
|
35018
35060
|
var scrapeCommand = defineCommand147({
|
|
35019
35061
|
meta: {
|
|
35020
35062
|
name: "scrape",
|
|
35021
|
-
description: "
|
|
35063
|
+
description: "Capture a landing page to a directory, now. Example: baker landing inspiration scrape https://linear.app --out .baker/inspiration/linear.app"
|
|
35022
35064
|
},
|
|
35023
35065
|
args: {
|
|
35024
35066
|
url: { type: "positional", description: "Page to capture", required: true },
|
|
35025
35067
|
out: { type: "string", description: "Output directory", required: true },
|
|
35026
|
-
|
|
35027
|
-
|
|
35028
|
-
|
|
35029
|
-
|
|
35068
|
+
mobile: { type: "boolean", description: "Phone-viewport pass (--no-mobile to skip)", required: false, default: true },
|
|
35069
|
+
code: { type: "boolean", description: "Bundles + fidelity (--no-code to skip)", required: false, default: true },
|
|
35070
|
+
motion: { type: "boolean", description: "Film moving sections (--no-motion to skip)", required: false, default: true },
|
|
35071
|
+
report: { type: "boolean", description: "Write report.html (--no-report to skip)", required: false, default: true }
|
|
35030
35072
|
},
|
|
35031
35073
|
run: async ({ args }) => {
|
|
35032
35074
|
try {
|
|
35033
35075
|
const manifest = await scrapeLanding({
|
|
35034
35076
|
url: args.url,
|
|
35035
35077
|
outDir: args.out,
|
|
35036
|
-
mobile:
|
|
35037
|
-
code:
|
|
35038
|
-
motion:
|
|
35039
|
-
report:
|
|
35078
|
+
mobile: args.mobile,
|
|
35079
|
+
code: args.code,
|
|
35080
|
+
motion: args.motion,
|
|
35081
|
+
report: args.report,
|
|
35040
35082
|
// Progress goes to stderr so stdout stays a clean JSON envelope.
|
|
35041
35083
|
onProgress: (message) => process.stderr.write(`${message}
|
|
35042
35084
|
`)
|
|
35043
35085
|
});
|
|
35044
35086
|
const scored = manifest.sections.map((section) => section.fidelity).filter((value) => value !== null).sort((a, b) => a - b);
|
|
35087
|
+
const recorded = await recordCapture(manifest, args.out);
|
|
35045
35088
|
writeJson({
|
|
35046
35089
|
ok: true,
|
|
35047
35090
|
data: {
|
|
@@ -35050,8 +35093,13 @@ var scrapeCommand = defineCommand147({
|
|
|
35050
35093
|
medianFidelity: scored.length > 0 ? scored[Math.floor(scored.length / 2)] : null,
|
|
35051
35094
|
pageFidelity: manifest.page.fidelity,
|
|
35052
35095
|
out: args.out,
|
|
35053
|
-
report: args
|
|
35054
|
-
}
|
|
35096
|
+
report: args.report ? `${args.out}/report.html` : null
|
|
35097
|
+
},
|
|
35098
|
+
hints: [
|
|
35099
|
+
INSPIRATION_HINTS.structureNotCopy,
|
|
35100
|
+
INSPIRATION_HINTS.adapt,
|
|
35101
|
+
recorded ? "These sections are recorded for the originality check \u2014 `baker landing critique` will block a publish that ships their copy." : "Could not record this capture, so the originality check cannot see it. Be especially careful not to reuse its copy."
|
|
35102
|
+
]
|
|
35055
35103
|
});
|
|
35056
35104
|
} catch (error) {
|
|
35057
35105
|
if (error instanceof BlockedPageError) {
|
|
@@ -35065,7 +35113,7 @@ var scrapeCommand = defineCommand147({
|
|
|
35065
35113
|
|
|
35066
35114
|
// src/commands/landing/inspiration/search.ts
|
|
35067
35115
|
import { mkdir as mkdir12, writeFile as writeFile16 } from "fs/promises";
|
|
35068
|
-
import
|
|
35116
|
+
import path33 from "path";
|
|
35069
35117
|
import { defineCommand as defineCommand148 } from "citty";
|
|
35070
35118
|
registerSchema({
|
|
35071
35119
|
command: "landing.inspiration.search",
|
|
@@ -35147,7 +35195,7 @@ function buildSearchBody(args) {
|
|
|
35147
35195
|
return body;
|
|
35148
35196
|
}
|
|
35149
35197
|
async function downloadShots(results) {
|
|
35150
|
-
const dir =
|
|
35198
|
+
const dir = path33.join(process.cwd(), ".baker", "inspiration");
|
|
35151
35199
|
await mkdir12(dir, { recursive: true });
|
|
35152
35200
|
const saved = /* @__PURE__ */ new Map();
|
|
35153
35201
|
await Promise.all(
|
|
@@ -35156,9 +35204,9 @@ async function downloadShots(results) {
|
|
|
35156
35204
|
try {
|
|
35157
35205
|
const response = await fetch(result.desktopShotUrl);
|
|
35158
35206
|
if (!response.ok) return;
|
|
35159
|
-
const file =
|
|
35207
|
+
const file = path33.join(dir, `${result.id}.png`);
|
|
35160
35208
|
await writeFile16(file, Buffer.from(await response.arrayBuffer()));
|
|
35161
|
-
saved.set(result.id,
|
|
35209
|
+
saved.set(result.id, path33.relative(process.cwd(), file));
|
|
35162
35210
|
} catch {
|
|
35163
35211
|
}
|
|
35164
35212
|
})
|
|
@@ -35245,7 +35293,7 @@ var searchCommand2 = defineCommand148({
|
|
|
35245
35293
|
|
|
35246
35294
|
// src/commands/landing/inspiration/view.ts
|
|
35247
35295
|
import { mkdir as mkdir13, writeFile as writeFile17 } from "fs/promises";
|
|
35248
|
-
import
|
|
35296
|
+
import path34 from "path";
|
|
35249
35297
|
import { defineCommand as defineCommand149 } from "citty";
|
|
35250
35298
|
registerSchema({
|
|
35251
35299
|
command: "landing.inspiration.view",
|
|
@@ -35257,9 +35305,9 @@ async function download(url, file) {
|
|
|
35257
35305
|
try {
|
|
35258
35306
|
const response = await fetch(url);
|
|
35259
35307
|
if (!response.ok) return null;
|
|
35260
|
-
await mkdir13(
|
|
35308
|
+
await mkdir13(path34.dirname(file), { recursive: true });
|
|
35261
35309
|
await writeFile17(file, Buffer.from(await response.arrayBuffer()));
|
|
35262
|
-
return
|
|
35310
|
+
return path34.relative(process.cwd(), file);
|
|
35263
35311
|
} catch {
|
|
35264
35312
|
return null;
|
|
35265
35313
|
}
|
|
@@ -35275,11 +35323,11 @@ var viewCommand2 = defineCommand149({
|
|
|
35275
35323
|
const id = args.id;
|
|
35276
35324
|
const data = await apiGet("/api/landing-inspiration/section", { id });
|
|
35277
35325
|
const section = data.section;
|
|
35278
|
-
const dir =
|
|
35326
|
+
const dir = path34.join(process.cwd(), ".baker", "inspiration", id);
|
|
35279
35327
|
const [desktop, mobile, filmstrip] = await Promise.all([
|
|
35280
|
-
download(section.desktopShotUrl,
|
|
35281
|
-
download(section.mobileShotUrl,
|
|
35282
|
-
download(section.motionFilmstripUrl,
|
|
35328
|
+
download(section.desktopShotUrl, path34.join(dir, "desktop.png")),
|
|
35329
|
+
download(section.mobileShotUrl, path34.join(dir, "mobile.png")),
|
|
35330
|
+
download(section.motionFilmstripUrl, path34.join(dir, "motion-filmstrip.png"))
|
|
35283
35331
|
]);
|
|
35284
35332
|
const hints = [INSPIRATION_HINTS.structureNotCopy, INSPIRATION_HINTS.adapt];
|
|
35285
35333
|
const fidelity = fidelityHint(section.fidelity);
|
|
@@ -37108,10 +37156,10 @@ async function stageOp4(op) {
|
|
|
37108
37156
|
handleError4(err);
|
|
37109
37157
|
}
|
|
37110
37158
|
}
|
|
37111
|
-
async function draftAction3(
|
|
37159
|
+
async function draftAction3(path35, body, chat) {
|
|
37112
37160
|
const chatId = resolveChatId(chat);
|
|
37113
37161
|
try {
|
|
37114
|
-
const data = await apiPost(
|
|
37162
|
+
const data = await apiPost(path35, { chatId, ...body });
|
|
37115
37163
|
writeJsonEnvelope({ ok: true, data });
|
|
37116
37164
|
return data;
|
|
37117
37165
|
} catch (err) {
|
|
@@ -38130,7 +38178,7 @@ var searchCommand4 = defineCommand183({
|
|
|
38130
38178
|
var tagsCommand5 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
38131
38179
|
|
|
38132
38180
|
// src/commands/videos/upload.ts
|
|
38133
|
-
import { readFile as
|
|
38181
|
+
import { readFile as readFile25, stat as stat7 } from "fs/promises";
|
|
38134
38182
|
import { extname as extname3 } from "path";
|
|
38135
38183
|
import { defineCommand as defineCommand184 } from "citty";
|
|
38136
38184
|
var MIME_MAP = {
|
|
@@ -38195,7 +38243,7 @@ var uploadCommand2 = defineCommand184({
|
|
|
38195
38243
|
return;
|
|
38196
38244
|
}
|
|
38197
38245
|
const { uploadUrl, videoId } = await apiPost("/api/videos/upload", {});
|
|
38198
|
-
const fileBuffer = await
|
|
38246
|
+
const fileBuffer = await readFile25(filePath);
|
|
38199
38247
|
const uploadResponse = await fetch(uploadUrl, {
|
|
38200
38248
|
method: "PUT",
|
|
38201
38249
|
headers: { "Content-Type": contentType },
|