@koda-sl/baker-cli 0.376.0 → 0.377.0
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 +1 -1
- package/dist/cli.js +53 -22
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5452,7 +5452,7 @@ Validate, then execute the graph. Blocks until done. Logs one line per node. Ret
|
|
|
5452
5452
|
|
|
5453
5453
|
**Run history streams live.** The run posts its plan (every node + its dependency edges) the moment validation passes, then re-posts a progress snapshot as each node starts and settles — the dashboard's creative workflow graph shows nodes flipping pending → running → done in real time, with each node's outputs attached as they land. A failed run keeps its per-node trail (what completed, what died). All best-effort: an unreachable backend never changes the run's outcome.
|
|
5454
5454
|
|
|
5455
|
-
**Failures don't abandon sibling work.** Nodes in a layer run under the concurrency cap and every one **settles** — a failed clip no longer kills its in-flight siblings, whose finished results still land in the content-addressed cache. One failure re-throws as-is; several are reported together (each failed node named). Re-running `baker canvas run` resumes from the cache and re-executes **only** the failed nodes and their descendants — never hand-orchestrate per-node renders. Long `video_generate` clips execute as **backend jobs** (the CLI polls; a CDN/proxy timeout can no longer kill a generation mid-flight).
|
|
5455
|
+
**Failures don't abandon sibling work.** Nodes in a layer run under the concurrency cap and every one **settles** — a failed clip no longer kills its in-flight siblings, whose finished results still land in the content-addressed cache. One failure re-throws as-is; several are reported together (each failed node named). Re-running `baker canvas run` resumes from the cache and re-executes **only** the failed nodes and their descendants — never hand-orchestrate per-node renders. **One render per canvas at a time:** a `run` of a canvas that another live process in the same workspace is still rendering (a backgrounded render, or a subagent's) is refused with `CONFLICT` instead of sharing its run, `--run-id` included — wait for it and use its result. Long `video_generate` clips execute as **backend jobs** (the CLI polls; a CDN/proxy timeout can no longer kill a generation mid-flight).
|
|
5456
5456
|
|
|
5457
5457
|
#### `baker canvas scaffold-video <video> [flags]`
|
|
5458
5458
|
|
package/dist/cli.js
CHANGED
|
@@ -41621,6 +41621,7 @@ async function clearCreativeDirty(slug, base) {
|
|
|
41621
41621
|
}
|
|
41622
41622
|
|
|
41623
41623
|
// src/commands/canvas/run-resume.ts
|
|
41624
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
41624
41625
|
import { mkdir as mkdir4, readFile as readFile9, rm as rm4, writeFile as writeFile6 } from "fs/promises";
|
|
41625
41626
|
import path13 from "path";
|
|
41626
41627
|
function markerKey(canvasPath) {
|
|
@@ -41642,10 +41643,13 @@ function classifyRemoteRun(run, now) {
|
|
|
41642
41643
|
return age > REMOTE_ADOPT_STALE_MS ? "adopt" : "concurrent";
|
|
41643
41644
|
}
|
|
41644
41645
|
async function resolveRunId(opts) {
|
|
41646
|
+
const existing = await readMarker(opts.outputsDir, opts.canvasPath);
|
|
41647
|
+
if (existing?.pid !== void 0 && existing.pid !== process.pid && (opts.isRendering ?? isRenderProcess)(existing.pid)) {
|
|
41648
|
+
return { runId: existing.runId, resumed: false, rendering: { runId: existing.runId, pid: existing.pid } };
|
|
41649
|
+
}
|
|
41645
41650
|
if (opts.explicitRunId) return { runId: opts.explicitRunId, resumed: false };
|
|
41646
41651
|
if (!opts.fresh) {
|
|
41647
|
-
|
|
41648
|
-
if (existing) return { runId: existing, resumed: true, source: "local" };
|
|
41652
|
+
if (existing) return { runId: existing.runId, resumed: true, source: "local" };
|
|
41649
41653
|
if (opts.remote) {
|
|
41650
41654
|
try {
|
|
41651
41655
|
const active = await opts.remote.getActiveRun(opts.remote.creativeSlug, opts.remote.canvasSha);
|
|
@@ -41665,22 +41669,31 @@ async function resolveRunId(opts) {
|
|
|
41665
41669
|
}
|
|
41666
41670
|
return { runId: `r_${ulid()}`, resumed: false };
|
|
41667
41671
|
}
|
|
41668
|
-
async function
|
|
41672
|
+
async function readMarker(outputsDir, canvasPath) {
|
|
41669
41673
|
for (const key of [markerKey(canvasPath), legacyMarkerKey(canvasPath)]) {
|
|
41670
41674
|
try {
|
|
41671
41675
|
const raw = await readFile9(markerFile(outputsDir, key), "utf8");
|
|
41672
41676
|
const parsed = JSON.parse(raw);
|
|
41673
|
-
if (typeof parsed.runId === "string" && parsed.runId.length > 0)
|
|
41677
|
+
if (typeof parsed.runId === "string" && parsed.runId.length > 0) {
|
|
41678
|
+
return { runId: parsed.runId, ...Number.isInteger(parsed.pid) ? { pid: parsed.pid } : {} };
|
|
41679
|
+
}
|
|
41674
41680
|
} catch {
|
|
41675
41681
|
}
|
|
41676
41682
|
}
|
|
41677
41683
|
return null;
|
|
41678
41684
|
}
|
|
41685
|
+
function isRenderProcess(pid) {
|
|
41686
|
+
try {
|
|
41687
|
+
return readFileSync14(`/proc/${pid}/cmdline`, "utf8").includes("canvas");
|
|
41688
|
+
} catch {
|
|
41689
|
+
return false;
|
|
41690
|
+
}
|
|
41691
|
+
}
|
|
41679
41692
|
async function markRunInFlight(outputsDir, canvasPath, runId) {
|
|
41680
41693
|
try {
|
|
41681
41694
|
const file = markerFile(outputsDir, markerKey(canvasPath));
|
|
41682
41695
|
await mkdir4(path13.dirname(file), { recursive: true });
|
|
41683
|
-
await writeFile6(file, JSON.stringify({ runId, canvasPath: path13.resolve(canvasPath), startedAt: Date.now() }));
|
|
41696
|
+
await writeFile6(file, JSON.stringify({ runId, pid: process.pid, canvasPath: path13.resolve(canvasPath), startedAt: Date.now() }));
|
|
41684
41697
|
} catch {
|
|
41685
41698
|
}
|
|
41686
41699
|
}
|
|
@@ -42636,13 +42649,31 @@ ${describeRewrites(healed.rewrites)}
|
|
|
42636
42649
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
42637
42650
|
const client = opts.record === false ? null : buildBackendClient();
|
|
42638
42651
|
const outputsDir = opts.outputsDir ? path16.resolve(opts.outputsDir) : canvasRoot;
|
|
42639
|
-
const { runId, resumed, source, concurrentRunId } = await resolveRunId({
|
|
42652
|
+
const { runId, resumed, source, concurrentRunId, rendering } = await resolveRunId({
|
|
42640
42653
|
explicitRunId: opts.runId,
|
|
42641
42654
|
fresh: opts.fresh === true,
|
|
42642
42655
|
outputsDir,
|
|
42643
42656
|
canvasPath: filePath,
|
|
42644
42657
|
remote: client && creativeSlug ? { creativeSlug, canvasSha, getActiveRun: (slug, sha) => client.getActiveRun(slug, sha) } : void 0
|
|
42645
42658
|
});
|
|
42659
|
+
if (rendering) {
|
|
42660
|
+
process.stderr.write(
|
|
42661
|
+
`${JSON.stringify(
|
|
42662
|
+
{
|
|
42663
|
+
ok: false,
|
|
42664
|
+
error: {
|
|
42665
|
+
code: "CONFLICT",
|
|
42666
|
+
message: `This canvas is already rendering in another process (run ${rendering.runId}, pid ${rendering.pid}).`,
|
|
42667
|
+
fix: "Wait for that render to finish and use its result instead of starting a second one: two renders of one canvas share a run and overwrite each other. If you started it in the background, read its output when it completes."
|
|
42668
|
+
}
|
|
42669
|
+
},
|
|
42670
|
+
null,
|
|
42671
|
+
2
|
|
42672
|
+
)}
|
|
42673
|
+
`
|
|
42674
|
+
);
|
|
42675
|
+
process.exit(2);
|
|
42676
|
+
}
|
|
42646
42677
|
if (resumed) {
|
|
42647
42678
|
process.stdout.write(
|
|
42648
42679
|
`[resume] continuing interrupted run ${runId}${source === "remote" ? " (adopted from run history)" : ""} \u2014 in-flight jobs re-attach, cached nodes skip
|
|
@@ -49102,11 +49133,11 @@ var addSideEffectCommand = defineCommand125({
|
|
|
49102
49133
|
});
|
|
49103
49134
|
|
|
49104
49135
|
// src/commands/flows/map.ts
|
|
49105
|
-
import { readFileSync as
|
|
49136
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
49106
49137
|
import { defineCommand as defineCommand126 } from "citty";
|
|
49107
49138
|
|
|
49108
49139
|
// src/commands/flows/value-expression.ts
|
|
49109
|
-
import { existsSync as existsSync6, readFileSync as
|
|
49140
|
+
import { existsSync as existsSync6, readFileSync as readFileSync15 } from "fs";
|
|
49110
49141
|
import { join as join4 } from "path";
|
|
49111
49142
|
var PREFIXES2 = ["field", "tracking", "global", "code"];
|
|
49112
49143
|
function splitParts(raw) {
|
|
@@ -49193,7 +49224,7 @@ function trackingFieldIds() {
|
|
|
49193
49224
|
const path48 = join4(flowsDir(), "..", "tracking.ts");
|
|
49194
49225
|
if (!existsSync6(path48)) return null;
|
|
49195
49226
|
try {
|
|
49196
|
-
const source =
|
|
49227
|
+
const source = readFileSync15(path48, "utf-8");
|
|
49197
49228
|
const block2 = source.match(/TRACKING_FIELD_IDS\s*=\s*\[([\s\S]*?)\]\s*as const/)?.[1];
|
|
49198
49229
|
if (!block2) return null;
|
|
49199
49230
|
const ids = [...block2.matchAll(/"(tracking\.[a-z0-9_]+)"/g)].map((match) => match[1]);
|
|
@@ -49770,7 +49801,7 @@ function specsFromFile(parsed) {
|
|
|
49770
49801
|
function readSpecFile(path48) {
|
|
49771
49802
|
let raw;
|
|
49772
49803
|
try {
|
|
49773
|
-
raw = path48 === "-" ?
|
|
49804
|
+
raw = path48 === "-" ? readFileSync16(0, "utf-8") : readFileSync16(path48, "utf-8");
|
|
49774
49805
|
} catch (error) {
|
|
49775
49806
|
refuse(
|
|
49776
49807
|
`Could not read ${path48 === "-" ? "the mapping from stdin" : `"${path48}"`}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -50469,7 +50500,7 @@ Full guide: __tooling__/docs/tools/baker/flows.md`
|
|
|
50469
50500
|
});
|
|
50470
50501
|
|
|
50471
50502
|
// src/commands/funnel/index.ts
|
|
50472
|
-
import { readFileSync as
|
|
50503
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
50473
50504
|
import { defineCommand as defineCommand130 } from "citty";
|
|
50474
50505
|
|
|
50475
50506
|
// src/commands/funnel/formMoments.ts
|
|
@@ -51265,7 +51296,7 @@ function workspaceForms() {
|
|
|
51265
51296
|
const forms = [];
|
|
51266
51297
|
for (const slug of listFlowSlugs()) {
|
|
51267
51298
|
try {
|
|
51268
|
-
forms.push({ slug, tree: JSON.parse(
|
|
51299
|
+
forms.push({ slug, tree: JSON.parse(readFileSync17(flowDataPath(slug), "utf-8")) });
|
|
51269
51300
|
} catch {
|
|
51270
51301
|
}
|
|
51271
51302
|
}
|
|
@@ -51400,7 +51431,7 @@ Examples:
|
|
|
51400
51431
|
import { defineCommand as defineCommand132 } from "citty";
|
|
51401
51432
|
|
|
51402
51433
|
// src/commands/ga4/shared.ts
|
|
51403
|
-
import { readFileSync as
|
|
51434
|
+
import { readFileSync as readFileSync18 } from "fs";
|
|
51404
51435
|
function failValidation3(message) {
|
|
51405
51436
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
51406
51437
|
process.exit(1);
|
|
@@ -51416,7 +51447,7 @@ function requireTarget5(args5, entity) {
|
|
|
51416
51447
|
function readJsonSource(args5, flag) {
|
|
51417
51448
|
const inline = args5[flag];
|
|
51418
51449
|
const file = args5.file;
|
|
51419
|
-
const raw = typeof file === "string" && file.length > 0 ?
|
|
51450
|
+
const raw = typeof file === "string" && file.length > 0 ? readFileSync18(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
51420
51451
|
if (raw === void 0) {
|
|
51421
51452
|
failValidation3(`pass --${flag} with inline JSON or --file with a path to a JSON file`);
|
|
51422
51453
|
}
|
|
@@ -51767,7 +51798,7 @@ Examples:
|
|
|
51767
51798
|
});
|
|
51768
51799
|
|
|
51769
51800
|
// src/commands/ga4/query.ts
|
|
51770
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as
|
|
51801
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync7, readFileSync as readFileSync19, writeFileSync as writeFileSync4 } from "fs";
|
|
51771
51802
|
import { resolve as resolve2 } from "path";
|
|
51772
51803
|
import { defineCommand as defineCommand135 } from "citty";
|
|
51773
51804
|
|
|
@@ -51858,7 +51889,7 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
51858
51889
|
writeFileSync4(filePath, content, "utf-8");
|
|
51859
51890
|
}
|
|
51860
51891
|
} else if (append && existsSync7(filePath)) {
|
|
51861
|
-
const existing = JSON.parse(
|
|
51892
|
+
const existing = JSON.parse(readFileSync19(filePath, "utf-8"));
|
|
51862
51893
|
writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
51863
51894
|
} else {
|
|
51864
51895
|
writeFileSync4(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -52710,7 +52741,7 @@ Full guide: __tooling__/docs/tools/baker/ga4.md`
|
|
|
52710
52741
|
import { defineCommand as defineCommand141 } from "citty";
|
|
52711
52742
|
|
|
52712
52743
|
// src/commands/gsc/query.ts
|
|
52713
|
-
import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as
|
|
52744
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync8, readFileSync as readFileSync20, writeFileSync as writeFileSync5 } from "fs";
|
|
52714
52745
|
import { resolve as resolve3 } from "path";
|
|
52715
52746
|
import { defineCommand as defineCommand138 } from "citty";
|
|
52716
52747
|
|
|
@@ -52858,7 +52889,7 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
52858
52889
|
writeFileSync5(filePath, content, "utf-8");
|
|
52859
52890
|
}
|
|
52860
52891
|
} else if (append && existsSync8(filePath)) {
|
|
52861
|
-
const existing = JSON.parse(
|
|
52892
|
+
const existing = JSON.parse(readFileSync20(filePath, "utf-8"));
|
|
52862
52893
|
writeFileSync5(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
52863
52894
|
} else {
|
|
52864
52895
|
writeFileSync5(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -66583,7 +66614,7 @@ import { defineCommand as defineCommand221 } from "citty";
|
|
|
66583
66614
|
import { defineCommand as defineCommand218 } from "citty";
|
|
66584
66615
|
|
|
66585
66616
|
// src/commands/tag-manager/shared.ts
|
|
66586
|
-
import { readFileSync as
|
|
66617
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
66587
66618
|
function failValidation5(message) {
|
|
66588
66619
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
66589
66620
|
process.exit(1);
|
|
@@ -66599,7 +66630,7 @@ function requireTarget6(args5, entity) {
|
|
|
66599
66630
|
function loadJsonArg2(args5, flag = "json") {
|
|
66600
66631
|
const inline = args5[flag];
|
|
66601
66632
|
const file = args5.file;
|
|
66602
|
-
const raw = typeof file === "string" && file.length > 0 ?
|
|
66633
|
+
const raw = typeof file === "string" && file.length > 0 ? readFileSync21(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
66603
66634
|
if (raw === void 0) {
|
|
66604
66635
|
failValidation5(`pass --${flag} with inline JSON or --file with a path to a JSON file`);
|
|
66605
66636
|
}
|
|
@@ -69747,7 +69778,7 @@ Full guide: __tooling__/docs/tools/baker/winning-ads.md`
|
|
|
69747
69778
|
});
|
|
69748
69779
|
|
|
69749
69780
|
// src/version.ts
|
|
69750
|
-
import { readFileSync as
|
|
69781
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
69751
69782
|
function packageJsonUrl() {
|
|
69752
69783
|
return new URL("../package.json", import.meta.url);
|
|
69753
69784
|
}
|
|
@@ -69759,7 +69790,7 @@ function parsePackageVersion(raw) {
|
|
|
69759
69790
|
throw new Error("Invalid CLI package.json: missing version");
|
|
69760
69791
|
}
|
|
69761
69792
|
function getCliVersion() {
|
|
69762
|
-
return parsePackageVersion(
|
|
69793
|
+
return parsePackageVersion(readFileSync22(packageJsonUrl(), "utf8"));
|
|
69763
69794
|
}
|
|
69764
69795
|
|
|
69765
69796
|
// src/cli.ts
|