@field/cascade 0.11.0 → 0.12.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/AGENTS.md +7 -4
- package/ARCHITECTURE.md +5 -4
- package/CHANGELOG.md +195 -0
- package/README.md +1 -1
- package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
- package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
- package/dist/assets/{CodeEditor-4O7FQ__R.js → CodeEditor-C-xYG-Wn.js} +120 -120
- package/dist/assets/CodePanel-CtXd50m6.js +2 -0
- package/dist/assets/CookInfoPanel-B3NMhKJF.css +1 -0
- package/dist/assets/CookInfoPanel-DG4_TRsX.js +2 -0
- package/dist/assets/CustomNodeDialog-CHfZUs-r.js +1 -0
- package/dist/assets/DefinitionNode-CaRTXQ_b.js +1 -0
- package/dist/assets/DefinitionPanel-C3CxZY9r.js +1 -0
- package/dist/assets/DefinitionPanel-VNLnAiQD.css +1 -0
- package/dist/assets/OpenGraphDialog-BLdr6k_q.js +1 -0
- package/dist/assets/ProjectSettings-ZnvmIAir.js +2 -0
- package/dist/assets/{SettingsDialog-Bz8JxISH.js → SettingsDialog-CBX3Wa87.js} +1 -1
- package/dist/assets/TimelinePanel-CDeR0arY.css +1 -0
- package/dist/assets/TimelinePanel-CWgnFH1e.js +1 -0
- package/dist/assets/{VersionHistoryDialog-D5Z0nJ5-.js → VersionHistoryDialog-BOSoW1R-.js} +1 -1
- package/dist/assets/assert-BO2_erPD.js +1 -0
- package/dist/assets/assert-hvykGCnP.js +1 -0
- package/dist/assets/builder-BmBKcDix.js +1 -0
- package/dist/assets/camera-DFF7YA3F.js +1 -0
- package/dist/assets/checks-DAvyO9Gf.js +1 -0
- package/dist/assets/contactSheet-N1NcaWxw.js +2 -0
- package/dist/assets/{core-Yqi0Ni61.js → core-DB-MkGjj.js} +3 -4
- package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
- package/dist/assets/{cssMode-CxUzc4vp.js → cssMode-DPVckSOc.js} +1 -1
- package/dist/assets/definitions-B227e7f_.js +1 -0
- package/dist/assets/definitions-D0WOUJd7.js +1 -0
- package/dist/assets/{editor.api-BNFb25CX.js → editor.api-Dkutg_Z1.js} +1 -1
- package/dist/assets/expressions-X-Z-GrgW.js +5 -0
- package/dist/assets/file-DAL6IfjV.js +1 -0
- package/dist/assets/filters-D3k1LRMa.js +1 -0
- package/dist/assets/{freemarker2-0ZDnWxeM.js → freemarker2-CLiLKk3B.js} +1 -1
- package/dist/assets/generators-BhDxRAFC.js +1 -0
- package/dist/assets/geo-BsMImJIJ.js +1 -0
- package/dist/assets/geo-C4YngDob.js +2 -0
- package/dist/assets/{handlebars-Cy18MoaD.js → handlebars-CcD3aMeL.js} +1 -1
- package/dist/assets/{html-B-2Dx7nq.js → html-DvZWGfqb.js} +1 -1
- package/dist/assets/{htmlMode-DUAc9B_d.js → htmlMode-DUD3VaoN.js} +1 -1
- package/dist/assets/image-0SfH-snh.js +1 -0
- package/dist/assets/image-Ck-RdGU4.js +2 -0
- package/dist/assets/index-BWnrmIB9.js +137 -0
- package/dist/assets/index-DIaxEONI.css +1 -0
- package/dist/assets/io-BGmt2g0D.js +1 -0
- package/dist/assets/{javascript-DeQsDqP5.js → javascript-Cap2ahgh.js} +1 -1
- package/dist/assets/{jsonMode-BiFwJVSk.js → jsonMode-B0uLjp9C.js} +1 -1
- package/dist/assets/{liquid-BLoHH68a.js → liquid-CnxwhfLn.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-CNFgm1Kv.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
- package/dist/assets/math-GeULS-sk.js +1 -0
- package/dist/assets/{mdx-CFXQVNfs.js → mdx-BV3jbrVa.js} +1 -1
- package/dist/assets/pop-KMF_qloi.js +1 -0
- package/dist/assets/preload-helper-Czpn1I53.js +1 -0
- package/dist/assets/{python-Cf7S7p2E.js → python-CGyFk4XK.js} +1 -1
- package/dist/assets/{razor-CMHBcG-g.js → razor-CQfzX3-N.js} +1 -1
- package/dist/assets/remap-5SjXQU-q.js +1 -0
- package/dist/assets/renderMarkdown-ork0Oir7.js +67 -0
- package/dist/assets/studioImages-CAyH-0Pl.js +1 -0
- package/dist/assets/text-ZpX7qNkx.js +2 -0
- package/dist/assets/time-P_OiBhcf.js +1 -0
- package/dist/assets/{tsMode-BEih0GDj.js → tsMode-BOeXzO9H.js} +1 -1
- package/dist/assets/{typescript-COEKYD_a.js → typescript-J1SnE_Tu.js} +1 -1
- package/dist/assets/{workers-BNhAhMNn.js → workers-CYwwTiVF.js} +1 -1
- package/dist/assets/{xml-CPiMpnPl.js → xml-DnPRNzK9.js} +1 -1
- package/dist/assets/{yaml-Bgp1ITLR.js → yaml-BmmYBNa9.js} +1 -1
- package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
- package/dist/cli/{Graph-ZJJTRQTM.js → Graph-OB6EWSGL.js} +12 -12
- package/dist/cli/assert-GROGQNCQ.js +25 -0
- package/dist/cli/checks-3WB44XBL.js +189 -0
- package/dist/cli/{chunk-RQZ4SX5R.js → chunk-2JEU3MGB.js} +2 -2
- package/dist/cli/{chunk-WKURDVYP.js → chunk-3RXL5GHB.js} +28 -331
- package/dist/cli/chunk-53LGFPWX.js +138 -0
- package/dist/cli/chunk-5ORUQ6ES.js +267 -0
- package/dist/cli/chunk-73S4JZXK.js +336 -0
- package/dist/cli/{chunk-YAT5Y25U.js → chunk-7QE2ZNSN.js} +3 -3
- package/dist/cli/{chunk-SGJAET2L.js → chunk-BPODRH52.js} +8 -4
- package/dist/cli/{chunk-XWDSKG7N.js → chunk-BZ63XQ3I.js} +2 -2
- package/dist/cli/{chunk-FCDXJ6EK.js → chunk-CTPLRSWF.js} +2 -13
- package/dist/cli/chunk-EU4ZFZ7Y.js +122 -0
- package/dist/cli/{chunk-WIH4TEIS.js → chunk-EZRWJ4G2.js} +1 -1
- package/dist/cli/{chunk-BIJO5OFS.js → chunk-FWMSGKEH.js} +1 -1
- package/dist/cli/{chunk-POMMNKZZ.js → chunk-G23A2BZZ.js} +38 -5
- package/dist/cli/{chunk-35D343DC.js → chunk-GRIN2DDP.js} +19 -1
- package/dist/cli/chunk-JVOCK5W4.js +83 -0
- package/dist/cli/chunk-KBGUO27Q.js +15 -0
- package/dist/cli/{chunk-GFS6W3C5.js → chunk-L6B6FUQP.js} +54 -32
- package/dist/cli/chunk-LTXWBXOM.js +438 -0
- package/dist/cli/chunk-MI5JLQYA.js +220 -0
- package/dist/cli/{chunk-EUIAC3U3.js → chunk-MP653A5O.js} +884 -124
- package/dist/cli/{chunk-A4OAMOZH.js → chunk-NJFMDXHR.js} +13 -3
- package/dist/cli/{chunk-3JTJHF7V.js → chunk-OM6BEME6.js} +4 -4
- package/dist/cli/{chunk-DUIUFVU2.js → chunk-ST6LROUG.js} +49 -23
- package/dist/cli/{chunk-RLCAJBVR.js → chunk-TJW67QSI.js} +8 -7
- package/dist/cli/chunk-WGKPJZDY.js +364 -0
- package/dist/cli/{chunk-D6BUOHUG.js → chunk-X4WKAOQP.js} +4 -4
- package/dist/cli/{chunk-VVGSLVSF.js → chunk-X566FWBV.js} +6 -1
- package/dist/cli/chunk-YH637PDL.js +317 -0
- package/dist/cli/chunk-ZSCUZE6I.js +112 -0
- package/dist/cli/{cliCommands-UQSFGEHF.js → cliCommands-JJN5Z3ZC.js} +23 -17
- package/dist/cli/{commands-Q23M26QM.js → commands-PHYFYA3F.js} +129 -47
- package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
- package/dist/cli/{definitions-HF2FTHYU.js → definitions-BPOPW52L.js} +7 -7
- package/dist/cli/{doctorCommand-B7BPQMN6.js → doctorCommand-ORWQRNYP.js} +36 -6
- package/dist/cli/{edit-JHCPTQFT.js → edit-S5KEQ5RA.js} +3 -3
- package/dist/cli/editorCommands-NFR32JOY.js +41 -0
- package/dist/cli/{encode-HAUZTYPT.js → encode-ICPEPMH5.js} +2 -2
- package/dist/cli/file-3HTQHPYQ.js +41 -0
- package/dist/cli/filters-6ODFWYK4.js +379 -0
- package/dist/cli/generators-YU7GB4MD.js +210 -0
- package/dist/cli/{geo-4RNK3QVN.js → geo-6ZPGKZRU.js} +7 -7
- package/dist/cli/{graphCommands-6BMAKGQE.js → graphCommands-EOUOBOIJ.js} +4 -4
- package/dist/cli/{graphFile-VPSQ6OF7.js → graphFile-YTGJB5F5.js} +25 -19
- package/dist/cli/{headlessCanvas-5XLDZT7M.js → headlessCanvas-ENRHC7GS.js} +3 -2
- package/dist/cli/{helpCommand-3VRE3KVO.js → helpCommand-PULH6ZYB.js} +9 -7
- package/dist/cli/image-TXELZZK5.js +55 -0
- package/dist/cli/index.js +14 -14
- package/dist/cli/{math-ZRMLKU2D.js → math-RSYRQ3C6.js} +5 -5
- package/dist/cli/{mcp-ZLEEMYGF.js → mcp-JVZFQOEX.js} +4 -4
- package/dist/cli/{parity-KINARCP2.js → parity-X6DEH2DV.js} +42 -36
- package/dist/cli/{pop-USDFXB7H.js → pop-B7SIIYKN.js} +5 -5
- package/dist/cli/project-VYGIA7JX.js +12 -0
- package/dist/cli/{projectDefinition-DMTZN2NE.js → projectDefinition-F3D7UIHJ.js} +8 -8
- package/dist/cli/{projectRuntime-Z5PJOH47.js → projectRuntime-2Q4JKEH3.js} +19 -12
- package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
- package/dist/cli/{render-YURAPPUI.js → render-PT4MWI6U.js} +24 -22
- package/dist/cli/{runCommand-PI764LEG.js → runCommand-HNPQVZMS.js} +3 -3
- package/dist/cli/runner-5XPXVW7J.js +43 -0
- package/dist/cli/runtime/image.ts +27 -2
- package/dist/cli/runtime/io.ts +78 -0
- package/dist/cli/share-MHF6TNRK.js +166 -0
- package/dist/cli/stageCache-TY2BFZJR.js +15 -0
- package/dist/cli/{stageRunner-KUNIMQKJ.js → stageRunner-KY2EJP7X.js} +2 -2
- package/dist/cli/text-MB3EKR4H.js +126 -0
- package/dist/cli/{verbs-RCE3K4VQ.js → verbs-PI2JH5FI.js} +2 -2
- package/dist/cli/webBuild-WPPMGGW7.js +44 -0
- package/dist/contracts/capabilities.d.ts +18 -1
- package/dist/contracts/color.d.ts +8 -0
- package/dist/contracts/color.js +23 -0
- package/dist/contracts/definition.d.ts +10 -0
- package/dist/contracts/schema.d.ts +1 -1
- package/dist/contracts/schema.js +1 -0
- package/dist/contracts/validate.js +11 -1
- package/dist/contracts/values.d.ts +24 -0
- package/dist/image.d.ts +15 -0
- package/dist/image.js +36 -2
- package/dist/index.html +8 -2
- package/dist/io.d.ts +29 -0
- package/dist/io.js +40 -0
- package/dist/player/app.js +3 -2
- package/dist/player/editor.js +3 -2
- package/dist/player/editorEngine.js +3 -2
- package/dist/runtime/builtins/assert/checks.d.ts +18 -0
- package/dist/runtime/builtins/assert/checks.js +207 -0
- package/dist/runtime/builtins/assert/definitions.d.ts +130 -0
- package/dist/runtime/builtins/assert/definitions.js +54 -0
- package/dist/runtime/builtins/assert/index.d.ts +152 -0
- package/dist/runtime/builtins/assert/index.js +36 -0
- package/dist/runtime/builtins/image/contactSheet.d.ts +3 -165
- package/dist/runtime/builtins/image/contactSheet.js +0 -49
- package/dist/runtime/builtins/image/definitions.d.ts +950 -0
- package/dist/runtime/builtins/image/definitions.js +343 -0
- package/dist/runtime/builtins/image/file.d.ts +8 -0
- package/dist/runtime/builtins/image/file.js +37 -0
- package/dist/runtime/builtins/image/filters.d.ts +8 -0
- package/dist/runtime/builtins/image/filters.js +394 -0
- package/dist/runtime/builtins/image/generators.d.ts +7 -0
- package/dist/runtime/builtins/image/generators.js +144 -0
- package/dist/runtime/builtins/image/index.d.ts +947 -4
- package/dist/runtime/builtins/image/index.js +41 -6
- package/dist/runtime/builtins/image/io.d.ts +100 -0
- package/dist/runtime/builtins/image/io.js +142 -0
- package/dist/runtime/builtins/image/planar.d.ts +55 -0
- package/dist/runtime/builtins/image/planar.js +274 -0
- package/dist/runtime/builtins/image/simplex.d.ts +22 -0
- package/dist/runtime/builtins/image/simplex.js +92 -0
- package/dist/runtime/builtins/image/text.d.ts +4 -0
- package/dist/runtime/builtins/image/text.js +141 -0
- package/dist/runtime/builtins/index.d.ts +3 -0
- package/dist/runtime/builtins/index.js +7 -0
- package/dist/runtime/gpu.d.ts +25 -0
- package/dist/runtime/gpu.js +40 -0
- package/dist/runtime/runtime.d.ts +2 -0
- package/dist/runtime/runtime.js +268 -44
- package/dist/runtime/types.d.ts +30 -0
- package/doc/CLI_REFERENCE.md +21 -3
- package/doc/EDITOR_EXPORT.md +26 -0
- package/doc/MCP.md +2 -1
- package/doc/NODE_REFERENCE.md +286 -14
- package/doc/PROJECT_AUTHORING.md +98 -3
- package/package.json +4 -1
- package/dist/assets/CodePanel-BU-autmq.js +0 -2
- package/dist/assets/CustomNodeDialog-BRpDfOV5.js +0 -1
- package/dist/assets/OpenGraphDialog-BwbRlC0X.js +0 -1
- package/dist/assets/ProjectSettings-DLOXLxcA.js +0 -2
- package/dist/assets/definitions-GreEMXLV.js +0 -1
- package/dist/assets/geo-u0n_jOsD.js +0 -1
- package/dist/assets/image-cAa-Nu9O.js +0 -2062
- package/dist/assets/index-5ZtDAuy2.js +0 -220
- package/dist/assets/index-7vae6YFC.css +0 -1
- package/dist/assets/math-DioIQOPJ.js +0 -1
- package/dist/assets/pop-DC_TQG9t.js +0 -1
- package/dist/cli/chunk-36P5K3SD.js +0 -631
- package/dist/cli/chunk-4UDFYF5G.js +0 -132
- package/dist/cli/chunk-53NMBJAO.js +0 -35
- package/dist/cli/chunk-MIIEFUGG.js +0 -623
- package/dist/cli/chunk-QBBKRNGY.js +0 -90
- package/dist/cli/chunk-WPUDGEFY.js +0 -20
- package/dist/cli/editorCommands-UIF5YLUZ.js +0 -33
- package/dist/cli/project-K3QIPGBB.js +0 -12
- package/dist/cli/registerStandardNodes-S2VLMF6J.js +0 -3081
- package/dist/cli/runner-RA6UKEPD.js +0 -37
- package/dist/cli/webBuild-GT4PZT5D.js +0 -37
- package/dist/runtime/builtins/headless.d.ts +0 -19
- package/dist/runtime/builtins/headless.js +0 -25
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// server/src/stageCache.ts
|
|
2
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3
|
+
import fs3 from "node:fs";
|
|
4
|
+
import path2 from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
// server/src/atomicWrite.ts
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import fsp from "node:fs/promises";
|
|
10
|
+
var temporaryFor = (file) => `${file}.${process.pid}.tmp`;
|
|
11
|
+
async function writeFileAtomic(file, data, options = {}) {
|
|
12
|
+
const temporary = temporaryFor(file);
|
|
13
|
+
await fsp.writeFile(temporary, data, options.mode === void 0 ? void 0 : { mode: options.mode });
|
|
14
|
+
await fsp.rename(temporary, file);
|
|
15
|
+
}
|
|
16
|
+
function writeFileAtomicSync(file, data) {
|
|
17
|
+
const temporary = temporaryFor(file);
|
|
18
|
+
fs.writeFileSync(temporary, data);
|
|
19
|
+
fs.renameSync(temporary, file);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// server/src/stageSources.ts
|
|
23
|
+
import { createHash } from "node:crypto";
|
|
24
|
+
import fs2 from "node:fs";
|
|
25
|
+
import path from "node:path";
|
|
26
|
+
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set(["__pycache__", "node_modules", "venv", ".venv", ".git", ".cascade", ".cascade-cache"]);
|
|
27
|
+
var digests = /* @__PURE__ */ new Map();
|
|
28
|
+
function contentDigest(fullPath) {
|
|
29
|
+
let stat;
|
|
30
|
+
try {
|
|
31
|
+
stat = fs2.statSync(fullPath, { bigint: true });
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (!stat.isFile()) return null;
|
|
36
|
+
const stamp = `${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
37
|
+
const known = digests.get(fullPath);
|
|
38
|
+
if (known?.stamp === stamp) return known.digest;
|
|
39
|
+
const hash = createHash("sha256");
|
|
40
|
+
const handle = fs2.openSync(fullPath, "r");
|
|
41
|
+
try {
|
|
42
|
+
const buffer = Buffer.allocUnsafe(1 << 20);
|
|
43
|
+
let read;
|
|
44
|
+
while ((read = fs2.readSync(handle, buffer, 0, buffer.length, null)) > 0) hash.update(buffer.subarray(0, read));
|
|
45
|
+
} finally {
|
|
46
|
+
fs2.closeSync(handle);
|
|
47
|
+
}
|
|
48
|
+
const digest = hash.digest("hex");
|
|
49
|
+
digests.set(fullPath, { stamp, digest });
|
|
50
|
+
return digest;
|
|
51
|
+
}
|
|
52
|
+
var StageSources = class {
|
|
53
|
+
constructor(project, roots) {
|
|
54
|
+
this.project = project;
|
|
55
|
+
this.roots = [...new Set(roots)].sort();
|
|
56
|
+
}
|
|
57
|
+
/** The default roots for a stage configuration without `sources`. */
|
|
58
|
+
static defaultRoots(project, entrypoint, worker) {
|
|
59
|
+
const roots = [path.posix.dirname(entrypoint)];
|
|
60
|
+
if (worker) roots.push(path.posix.dirname(worker));
|
|
61
|
+
if (fs2.existsSync(project.resolve("src"))) roots.push("src");
|
|
62
|
+
return roots.map((root) => root === "" ? "." : root);
|
|
63
|
+
}
|
|
64
|
+
/** Every source file, project-relative and sorted. */
|
|
65
|
+
files() {
|
|
66
|
+
const found = /* @__PURE__ */ new Set();
|
|
67
|
+
for (const root of this.roots) {
|
|
68
|
+
let full;
|
|
69
|
+
try {
|
|
70
|
+
full = this.project.resolveMedia(root);
|
|
71
|
+
} catch {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
let stat;
|
|
75
|
+
try {
|
|
76
|
+
stat = fs2.statSync(full);
|
|
77
|
+
} catch {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (stat.isFile()) found.add(root);
|
|
81
|
+
else if (stat.isDirectory()) this.walk(full, root, found);
|
|
82
|
+
}
|
|
83
|
+
return [...found].sort();
|
|
84
|
+
}
|
|
85
|
+
walk(directory, relative, found) {
|
|
86
|
+
let entries;
|
|
87
|
+
try {
|
|
88
|
+
entries = fs2.readdirSync(directory, { withFileTypes: true });
|
|
89
|
+
} catch {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
const child = relative === "." ? entry.name : path.posix.join(relative, entry.name);
|
|
94
|
+
if (entry.isDirectory()) {
|
|
95
|
+
if (SKIPPED_DIRECTORIES.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
96
|
+
this.walk(path.join(directory, entry.name), child, found);
|
|
97
|
+
} else if (entry.isFile() && entry.name.endsWith(".py")) {
|
|
98
|
+
found.add(child);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
digest(relative) {
|
|
103
|
+
return contentDigest(this.project.resolveMedia(relative)) ?? "missing";
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The code hash, 16 hex characters. A file added, removed or edited changes
|
|
107
|
+
* it. Cheap to call per request: one directory walk and one stat per file,
|
|
108
|
+
* with a file read only when its stat changed.
|
|
109
|
+
*/
|
|
110
|
+
codeHash() {
|
|
111
|
+
const hash = createHash("sha256");
|
|
112
|
+
for (const file of this.files()) hash.update(`${file}\0${this.digest(file)}
|
|
113
|
+
`);
|
|
114
|
+
return hash.digest("hex").slice(0, 16);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// server/src/stageCache.ts
|
|
119
|
+
var CACHE_FORMAT = 1;
|
|
120
|
+
var CACHE_DIRECTORY = ".cascade/cache/stages";
|
|
121
|
+
var version;
|
|
122
|
+
function cascadeVersion() {
|
|
123
|
+
if (version) return version;
|
|
124
|
+
let directory = path2.dirname(fileURLToPath(import.meta.url));
|
|
125
|
+
for (let depth = 0; depth < 6; depth++) {
|
|
126
|
+
try {
|
|
127
|
+
const manifest = JSON.parse(fs3.readFileSync(path2.join(directory, "package.json"), "utf8"));
|
|
128
|
+
if (manifest.name === "@field/cascade" && manifest.version) return version = manifest.version;
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
directory = path2.dirname(directory);
|
|
132
|
+
}
|
|
133
|
+
return version = "unknown";
|
|
134
|
+
}
|
|
135
|
+
function projectFile(project, value) {
|
|
136
|
+
if (!value || value.length > 1024 || value.includes("\0") || /^[a-z][a-z0-9+.-]*:/i.test(value)) return null;
|
|
137
|
+
if (path2.isAbsolute(value) || !/[./]/.test(value)) return null;
|
|
138
|
+
try {
|
|
139
|
+
return project.resolveMedia(value.replace(/^\.\//, ""));
|
|
140
|
+
} catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function replaceFiles(project, value, at, skip, onFile) {
|
|
145
|
+
if (typeof value === "string") {
|
|
146
|
+
const full = projectFile(project, value);
|
|
147
|
+
const digest = full ? contentDigest(full) : null;
|
|
148
|
+
if (!digest) return value;
|
|
149
|
+
onFile(at, value, digest);
|
|
150
|
+
return `file:${digest}`;
|
|
151
|
+
}
|
|
152
|
+
if (Array.isArray(value)) return value.map((item, index) => replaceFiles(project, item, `${at}[${index}]`, skip, onFile));
|
|
153
|
+
if (value && typeof value === "object") {
|
|
154
|
+
const out = {};
|
|
155
|
+
for (const name of Object.keys(value).sort()) {
|
|
156
|
+
const child = value[name];
|
|
157
|
+
const where = at ? `${at}.${name}` : name;
|
|
158
|
+
out[name] = !at && skip.has(name) ? child : replaceFiles(project, child, where, skip, onFile);
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
function stageCacheKey(project, stage, args, code, outputs = []) {
|
|
165
|
+
const inputs = {};
|
|
166
|
+
const params = replaceFiles(project, args, "", new Set(outputs), (where, _relative, digest) => {
|
|
167
|
+
inputs[where] = digest.slice(0, 16);
|
|
168
|
+
});
|
|
169
|
+
const cascade = cascadeVersion();
|
|
170
|
+
const blob = JSON.stringify({ format: CACHE_FORMAT, stage, code, cascade, params });
|
|
171
|
+
return { key: createHash2("sha256").update(blob).digest("hex").slice(0, 32), code, cascade, inputs };
|
|
172
|
+
}
|
|
173
|
+
function entryPath(project, stage, key) {
|
|
174
|
+
return project.resolve(path2.posix.join(CACHE_DIRECTORY, stage, `${key}.json`));
|
|
175
|
+
}
|
|
176
|
+
function resultFiles(project, result) {
|
|
177
|
+
const files = {};
|
|
178
|
+
replaceFiles(project, result, "", /* @__PURE__ */ new Set(), (_where, relative, digest) => {
|
|
179
|
+
files[relative] = digest;
|
|
180
|
+
});
|
|
181
|
+
return files;
|
|
182
|
+
}
|
|
183
|
+
function readEntry(project, stage, key) {
|
|
184
|
+
let entry;
|
|
185
|
+
try {
|
|
186
|
+
entry = JSON.parse(fs3.readFileSync(entryPath(project, stage, key), "utf8"));
|
|
187
|
+
} catch {
|
|
188
|
+
return { why: "no entry" };
|
|
189
|
+
}
|
|
190
|
+
if (entry.format !== CACHE_FORMAT || entry.key !== key) return { why: "no entry" };
|
|
191
|
+
for (const [relative, digest] of Object.entries(entry.outputs ?? {})) {
|
|
192
|
+
const full = projectFile(project, relative);
|
|
193
|
+
if (!full || contentDigest(full) !== digest) return { why: `output changed: ${relative}` };
|
|
194
|
+
}
|
|
195
|
+
return { result: entry.result };
|
|
196
|
+
}
|
|
197
|
+
function writeEntry(project, stage, key, result) {
|
|
198
|
+
const file = entryPath(project, stage, key);
|
|
199
|
+
const entry = { format: CACHE_FORMAT, stage, key, result, outputs: resultFiles(project, result) };
|
|
200
|
+
fs3.mkdirSync(path2.dirname(file), { recursive: true });
|
|
201
|
+
writeFileAtomicSync(file, JSON.stringify(entry));
|
|
202
|
+
}
|
|
203
|
+
function cacheMode(policy, stage, caller, env) {
|
|
204
|
+
if (env.CASCADE_STAGE_CACHE === "off") return { use: false, bypass: true, why: "CASCADE_STAGE_CACHE=off" };
|
|
205
|
+
if (!policy.enabled) return { use: false, bypass: false, why: "not enabled" };
|
|
206
|
+
if (policy.exclude.includes(stage)) return { use: false, bypass: false, why: "excluded" };
|
|
207
|
+
if (policy.scope === "cook" && caller !== "cook") return { use: false, bypass: false, why: "not a cook call" };
|
|
208
|
+
return { use: true, bypass: false };
|
|
209
|
+
}
|
|
210
|
+
function stageSources(project, config) {
|
|
211
|
+
return new StageSources(project, config.sources ?? StageSources.defaultRoots(project, config.entrypoint, config.worker));
|
|
212
|
+
}
|
|
213
|
+
async function callStage(project, config, stage, args, invoke, options = {}) {
|
|
214
|
+
const started = performance.now();
|
|
215
|
+
const code = stageSources(project, config).codeHash();
|
|
216
|
+
const identity = stageCacheKey(project, stage, args, code, config.cache.outputs);
|
|
217
|
+
const mode = cacheMode(config.cache, stage, options.caller ?? "cook", options.env ?? process.env);
|
|
218
|
+
const finish = (result, trace) => {
|
|
219
|
+
const full = {
|
|
220
|
+
stage,
|
|
221
|
+
key: identity.key,
|
|
222
|
+
...trace,
|
|
223
|
+
code: identity.code,
|
|
224
|
+
cascade: identity.cascade,
|
|
225
|
+
inputs: identity.inputs,
|
|
226
|
+
ms: Math.round(performance.now() - started)
|
|
227
|
+
};
|
|
228
|
+
options.onTrace?.(full);
|
|
229
|
+
return { result, trace: full };
|
|
230
|
+
};
|
|
231
|
+
let why = mode.why;
|
|
232
|
+
if (mode.use) {
|
|
233
|
+
const stored = readEntry(project, stage, identity.key);
|
|
234
|
+
if ("result" in stored) return finish(stored.result, { cache: "hit" });
|
|
235
|
+
why = stored.why;
|
|
236
|
+
}
|
|
237
|
+
const answer = await invoke({ key: identity.key, code, cache: mode.bypass ? "off" : "use" });
|
|
238
|
+
if (mode.use) {
|
|
239
|
+
try {
|
|
240
|
+
writeEntry(project, stage, identity.key, answer.result);
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return finish(answer.result, {
|
|
245
|
+
cache: mode.use ? "miss" : "off",
|
|
246
|
+
...why ? { why } : {},
|
|
247
|
+
...answer.projectCache ? { project: answer.projectCache } : {},
|
|
248
|
+
...answer.restarted ? { restarted: true } : {}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
function formatStageTrace(trace) {
|
|
252
|
+
const reason = trace.why ? ` (${trace.why})` : "";
|
|
253
|
+
const project = trace.project ? ` project:${trace.project}` : "";
|
|
254
|
+
const restarted = trace.restarted ? " worker restarted for new code" : "";
|
|
255
|
+
return `${trace.stage}: ${trace.cache}${reason}${project} key ${trace.key.slice(0, 12)} code ${trace.code} ${trace.ms} ms${restarted}`;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export {
|
|
259
|
+
writeFileAtomic,
|
|
260
|
+
writeFileAtomicSync,
|
|
261
|
+
cascadeVersion,
|
|
262
|
+
stageCacheKey,
|
|
263
|
+
stageSources,
|
|
264
|
+
callStage,
|
|
265
|
+
formatStageTrace
|
|
266
|
+
};
|
|
267
|
+
//# sourceMappingURL=chunk-5ORUQ6ES.js.map
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import {
|
|
2
|
+
installHeadlessCanvas
|
|
3
|
+
} from "./chunk-EZRWJ4G2.js";
|
|
4
|
+
import {
|
|
5
|
+
applyScene,
|
|
6
|
+
exportEditor,
|
|
7
|
+
formatPlan,
|
|
8
|
+
fromBase64,
|
|
9
|
+
parseScene
|
|
10
|
+
} from "./chunk-3RXL5GHB.js";
|
|
11
|
+
import {
|
|
12
|
+
cookProjectGraph,
|
|
13
|
+
installProjectIo
|
|
14
|
+
} from "./chunk-MP653A5O.js";
|
|
15
|
+
import {
|
|
16
|
+
ProjectRoot
|
|
17
|
+
} from "./chunk-2JEU3MGB.js";
|
|
18
|
+
|
|
19
|
+
// src/cli/editorCommands.ts
|
|
20
|
+
import fs from "node:fs/promises";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
var EDITOR_COMMANDS = ["export", "share", "freeze", "publish", "scene"];
|
|
23
|
+
var EDITOR_HELP = `
|
|
24
|
+
Shareable editors (see doc/EDITOR_EXPORT.md):
|
|
25
|
+
cascade export <graph> --plan Print what would ship, build nothing
|
|
26
|
+
cascade export <graph> --out <dir> [--deploy vercel [--project <name>] [--scope <team>] [--public]]
|
|
27
|
+
cascade share <graph | site-dir> [--name <slug>] [--scope <team>] [--protected] Deploy as cascade-<slug>, print the link
|
|
28
|
+
cascade publish <graph> <node>.<prop> [--id <id>] [--label <text>] [--group <name>]
|
|
29
|
+
[--control <kind>] [--min n] [--max n] [--step n] [--help <text>] [--remove]
|
|
30
|
+
cascade freeze <graph> <node> --fields <a,b.c> [--output <port>] [--personal <a,..>]
|
|
31
|
+
cascade scene <graph> <scene.json> --out <new-graph.cascade>
|
|
32
|
+
cascade run <graph> --scene <scene.json> [--write <node>.<port>=<file>]...
|
|
33
|
+
`;
|
|
34
|
+
async function runEditorCommand(args) {
|
|
35
|
+
const [command, graph] = args;
|
|
36
|
+
if (command === "share") {
|
|
37
|
+
const { runShareCommand } = await import("./share-MHF6TNRK.js");
|
|
38
|
+
return runShareCommand(args);
|
|
39
|
+
}
|
|
40
|
+
if (!graph || graph.startsWith("-")) throw new Error(`cascade ${command} requires a graph file`);
|
|
41
|
+
const flags = parseFlags(args.slice(2));
|
|
42
|
+
switch (command) {
|
|
43
|
+
case "export":
|
|
44
|
+
return exportCommand(graph, flags);
|
|
45
|
+
case "publish":
|
|
46
|
+
return publishCommand(graph, flags);
|
|
47
|
+
case "freeze":
|
|
48
|
+
return freezeCommand(graph, flags);
|
|
49
|
+
case "scene":
|
|
50
|
+
return sceneCommand(graph, flags);
|
|
51
|
+
case "run":
|
|
52
|
+
return runWithScene(graph, flags);
|
|
53
|
+
default:
|
|
54
|
+
throw new Error(`Unknown command ${command}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
var SWITCHES = /* @__PURE__ */ new Set(["--plan", "--remove", "--json", "--public"]);
|
|
58
|
+
function parseFlags(args) {
|
|
59
|
+
const positional = [];
|
|
60
|
+
const values = /* @__PURE__ */ new Map();
|
|
61
|
+
const switches = /* @__PURE__ */ new Set();
|
|
62
|
+
for (let index = 0; index < args.length; index++) {
|
|
63
|
+
const arg = args[index];
|
|
64
|
+
if (!arg.startsWith("--")) {
|
|
65
|
+
positional.push(arg);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (SWITCHES.has(arg)) {
|
|
69
|
+
switches.add(arg);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const value = args[index + 1];
|
|
73
|
+
if (value === void 0 || value.startsWith("--") && !/^--?\d/.test(value)) throw new Error(`${arg} needs a value`);
|
|
74
|
+
values.set(arg, [...values.get(arg) ?? [], value]);
|
|
75
|
+
index++;
|
|
76
|
+
}
|
|
77
|
+
return { positional, values, switches };
|
|
78
|
+
}
|
|
79
|
+
var one = (flags, name) => {
|
|
80
|
+
const list = flags.values.get(name);
|
|
81
|
+
return list?.[list.length - 1];
|
|
82
|
+
};
|
|
83
|
+
async function exportCommand(graph, flags) {
|
|
84
|
+
const deploy = one(flags, "--deploy");
|
|
85
|
+
if (deploy && deploy !== "vercel") throw new Error("--deploy supports vercel only");
|
|
86
|
+
const result = await exportEditor(graph, {
|
|
87
|
+
plan: flags.switches.has("--plan"),
|
|
88
|
+
out: one(flags, "--out"),
|
|
89
|
+
...deploy ? { deploy: "vercel" } : {},
|
|
90
|
+
project: one(flags, "--project"),
|
|
91
|
+
scope: one(flags, "--scope"),
|
|
92
|
+
...flags.switches.has("--public") ? { public: true } : {}
|
|
93
|
+
});
|
|
94
|
+
if (flags.switches.has("--json")) console.log(JSON.stringify(result.plan, null, 2));
|
|
95
|
+
else console.log(formatPlan(result.plan));
|
|
96
|
+
if (result.directory) console.log(`
|
|
97
|
+
Editor exported: ${result.directory}
|
|
98
|
+
Manifest: ${path.join(result.directory, "export-manifest.json")}`);
|
|
99
|
+
if (result.url) console.log(`Deployed: ${result.url}`);
|
|
100
|
+
}
|
|
101
|
+
async function readGraph(file) {
|
|
102
|
+
return JSON.parse(await fs.readFile(file, "utf8"));
|
|
103
|
+
}
|
|
104
|
+
async function writeEditor(file, document, editor) {
|
|
105
|
+
const next = { ...document, editor };
|
|
106
|
+
await fs.writeFile(file, `${JSON.stringify(next, null, 2)}
|
|
107
|
+
`);
|
|
108
|
+
}
|
|
109
|
+
async function publishCommand(graph, flags) {
|
|
110
|
+
const target = flags.positional[0];
|
|
111
|
+
const match = target ? /^([^.]+)\.(.+)$/.exec(target) : null;
|
|
112
|
+
if (!match) throw new Error("cascade publish needs <node>.<prop>");
|
|
113
|
+
const [, node, prop] = match;
|
|
114
|
+
const document = await readGraph(graph);
|
|
115
|
+
if (!document.nodes.some((item) => item.id === node)) throw new Error(`No node ${node} in ${graph}`);
|
|
116
|
+
const editor = document.editor ?? { id: path.basename(graph).replace(/\.cascade$/, "") };
|
|
117
|
+
const parameters = [...editor.parameters ?? []];
|
|
118
|
+
const id = one(flags, "--id") ?? prop;
|
|
119
|
+
const existing = parameters.findIndex((item) => item.node === node && item.prop === prop);
|
|
120
|
+
if (flags.switches.has("--remove")) {
|
|
121
|
+
if (existing < 0) throw new Error(`${node}.${prop} is not published`);
|
|
122
|
+
parameters.splice(existing, 1);
|
|
123
|
+
await writeEditor(graph, document, { ...editor, parameters });
|
|
124
|
+
console.log(`Unpublished ${node}.${prop}`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const number = (name) => {
|
|
128
|
+
const value = one(flags, name);
|
|
129
|
+
if (value === void 0) return void 0;
|
|
130
|
+
const parsed = Number(value);
|
|
131
|
+
if (!Number.isFinite(parsed)) throw new Error(`${name} must be a number`);
|
|
132
|
+
return parsed;
|
|
133
|
+
};
|
|
134
|
+
const previous = existing >= 0 ? parameters[existing] : void 0;
|
|
135
|
+
const parameter = {
|
|
136
|
+
...previous,
|
|
137
|
+
id: previous?.id ?? id,
|
|
138
|
+
node,
|
|
139
|
+
prop,
|
|
140
|
+
...one(flags, "--label") ? { label: one(flags, "--label") } : {},
|
|
141
|
+
...one(flags, "--group") ? { group: one(flags, "--group") } : {},
|
|
142
|
+
...one(flags, "--control") ? { control: one(flags, "--control") } : {},
|
|
143
|
+
...number("--min") !== void 0 ? { min: number("--min") } : {},
|
|
144
|
+
...number("--max") !== void 0 ? { max: number("--max") } : {},
|
|
145
|
+
...number("--step") !== void 0 ? { step: number("--step") } : {},
|
|
146
|
+
...number("--order") !== void 0 ? { order: number("--order") } : {},
|
|
147
|
+
...one(flags, "--help") ? { help: one(flags, "--help") } : {},
|
|
148
|
+
...one(flags, "--unit") ? { unit: one(flags, "--unit") } : {}
|
|
149
|
+
};
|
|
150
|
+
if (existing >= 0) parameters[existing] = parameter;
|
|
151
|
+
else {
|
|
152
|
+
if (parameters.some((item) => item.id === parameter.id)) throw new Error(`Parameter id ${parameter.id} is taken; pass --id`);
|
|
153
|
+
parameters.push(parameter);
|
|
154
|
+
}
|
|
155
|
+
await writeEditor(graph, document, { ...editor, parameters });
|
|
156
|
+
console.log(`${existing >= 0 ? "Updated" : "Published"} ${node}.${prop} as "${parameter.id}"`);
|
|
157
|
+
}
|
|
158
|
+
async function freezeCommand(graph, flags) {
|
|
159
|
+
const node = flags.positional[0];
|
|
160
|
+
if (!node) throw new Error("cascade freeze needs a node id");
|
|
161
|
+
const fields = (one(flags, "--fields") ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
162
|
+
if (!fields.length) throw new Error("cascade freeze needs --fields: name exactly the values to keep");
|
|
163
|
+
const personal = (one(flags, "--personal") ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
164
|
+
const document = await readGraph(graph);
|
|
165
|
+
if (!document.nodes.some((item) => item.id === node)) throw new Error(`No node ${node} in ${graph}`);
|
|
166
|
+
const graphFile = path.resolve(graph);
|
|
167
|
+
const project = new ProjectRoot(path.dirname(graphFile));
|
|
168
|
+
await installHeadlessCanvas().catch(() => void 0);
|
|
169
|
+
const removeIo = installProjectIo(project);
|
|
170
|
+
const { outputs } = await cookProjectGraph(graphFile, document, node).finally(removeIo);
|
|
171
|
+
const produced = outputs.get(node);
|
|
172
|
+
if (!produced) throw new Error(`${node} produced nothing`);
|
|
173
|
+
const output = one(flags, "--output") ?? [...produced.keys()][0];
|
|
174
|
+
if (!produced.has(output)) throw new Error(`${node} has no output ${output}; it has ${[...produced.keys()].join(", ")}`);
|
|
175
|
+
const full = toJson(produced.get(output));
|
|
176
|
+
const directory = path.join("frozen", node);
|
|
177
|
+
await fs.mkdir(project.resolve(directory), { recursive: true });
|
|
178
|
+
const files = [];
|
|
179
|
+
const pick = async (value) => {
|
|
180
|
+
if (value && typeof value === "object" && !Array.isArray(value) && typeof value.path === "string") {
|
|
181
|
+
const from = value.path;
|
|
182
|
+
const source = project.resolve(from.replace(/^\.\//, ""));
|
|
183
|
+
const name = `${directory}/${path.basename(from)}`;
|
|
184
|
+
await fs.copyFile(source, project.resolve(name));
|
|
185
|
+
files.push(name);
|
|
186
|
+
return { ...value, path: name };
|
|
187
|
+
}
|
|
188
|
+
if (Array.isArray(value)) return Promise.all(value.map(pick));
|
|
189
|
+
if (value && typeof value === "object")
|
|
190
|
+
return Object.fromEntries(await Promise.all(Object.entries(value).map(async ([key, item]) => [key, await pick(item)])));
|
|
191
|
+
return value;
|
|
192
|
+
};
|
|
193
|
+
const chosen = {};
|
|
194
|
+
for (const field of fields) {
|
|
195
|
+
const value = getPath(full, field);
|
|
196
|
+
if (value === void 0) throw new Error(`${node}.${output} has no field ${field}`);
|
|
197
|
+
setPath(chosen, field, await pick(value));
|
|
198
|
+
}
|
|
199
|
+
if (fields.includes("path") && typeof chosen.path === "string" && full && typeof full === "object" && !Array.isArray(full)) {
|
|
200
|
+
const { path: copied } = await pick({ path: chosen.path });
|
|
201
|
+
chosen.path = copied;
|
|
202
|
+
}
|
|
203
|
+
const snapshot = {
|
|
204
|
+
format: "cascade.frozen",
|
|
205
|
+
version: 1,
|
|
206
|
+
node,
|
|
207
|
+
output,
|
|
208
|
+
fields,
|
|
209
|
+
...personal.length ? { personal } : {},
|
|
210
|
+
value: chosen,
|
|
211
|
+
...files.length ? { files } : {},
|
|
212
|
+
frozenAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
213
|
+
};
|
|
214
|
+
const snapshotFile = `${directory}.json`;
|
|
215
|
+
await fs.writeFile(project.resolve(snapshotFile), `${JSON.stringify(snapshot, null, 2)}
|
|
216
|
+
`);
|
|
217
|
+
const editor = document.editor ?? { id: path.basename(graph).replace(/\.cascade$/, "") };
|
|
218
|
+
const freeze = (editor.freeze ?? []).filter((item) => item.node !== node);
|
|
219
|
+
freeze.push({ node, output, snapshot: snapshotFile });
|
|
220
|
+
await writeEditor(graph, document, { ...editor, freeze });
|
|
221
|
+
console.log(`Froze ${node}.${output}: ${fields.join(", ")} \u2192 ${snapshotFile}${files.length ? ` (+${files.length} file${files.length > 1 ? "s" : ""})` : ""}`);
|
|
222
|
+
}
|
|
223
|
+
async function sceneCommand(graph, flags) {
|
|
224
|
+
const sceneFile = flags.positional[0];
|
|
225
|
+
const out = one(flags, "--out");
|
|
226
|
+
if (!sceneFile || !out) throw new Error("cascade scene needs <scene.json> --out <new-graph.cascade>");
|
|
227
|
+
if (path.resolve(out) === path.resolve(graph)) throw new Error("--out must be a new file; the source graph is never overwritten");
|
|
228
|
+
const { document, warnings } = await sceneDocument(graph, sceneFile);
|
|
229
|
+
await fs.writeFile(out, `${JSON.stringify(document, null, 2)}
|
|
230
|
+
`);
|
|
231
|
+
for (const warning of warnings) console.warn(`Warning: ${warning}`);
|
|
232
|
+
console.log(`Scene applied: ${out}`);
|
|
233
|
+
}
|
|
234
|
+
async function sceneDocument(graph, sceneFile) {
|
|
235
|
+
const document = await readGraph(graph);
|
|
236
|
+
const scene = parseScene(await fs.readFile(sceneFile, "utf8"));
|
|
237
|
+
const project = new ProjectRoot(path.dirname(path.resolve(graph)));
|
|
238
|
+
const located = /* @__PURE__ */ new Map();
|
|
239
|
+
for (const [id, file] of Object.entries(scene.files ?? {})) {
|
|
240
|
+
const found = await locateSceneFile(project, file);
|
|
241
|
+
if (found) located.set(id, { path: found, ...file.mediaType ? { mediaType: file.mediaType } : {} });
|
|
242
|
+
}
|
|
243
|
+
return applyScene(document, scene, { resolveFile: (parameter) => located.get(parameter.id) });
|
|
244
|
+
}
|
|
245
|
+
async function locateSceneFile(project, file) {
|
|
246
|
+
const { createHash } = await import("node:crypto");
|
|
247
|
+
const safe = path.basename(file.name).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
248
|
+
if (file.data) {
|
|
249
|
+
const bytes = fromBase64(file.data);
|
|
250
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
251
|
+
if (digest !== file.sha256) throw new Error(`Scene file ${file.name} does not match its hash`);
|
|
252
|
+
const name = `assets/scenes/${digest.slice(0, 12)}-${safe}`;
|
|
253
|
+
await fs.mkdir(path.dirname(project.resolve(name)), { recursive: true });
|
|
254
|
+
await fs.writeFile(project.resolve(name), bytes);
|
|
255
|
+
return name;
|
|
256
|
+
}
|
|
257
|
+
for (const candidate of await filesNamed(project.root, path.basename(file.name))) {
|
|
258
|
+
const digest = createHash("sha256").update(await fs.readFile(candidate)).digest("hex");
|
|
259
|
+
if (digest === file.sha256) return path.relative(project.root, candidate).split(path.sep).join("/");
|
|
260
|
+
}
|
|
261
|
+
return void 0;
|
|
262
|
+
}
|
|
263
|
+
async function filesNamed(root, name) {
|
|
264
|
+
const found = [];
|
|
265
|
+
const walk = async (directory, depth) => {
|
|
266
|
+
if (depth > 6) return;
|
|
267
|
+
for (const entry of await fs.readdir(directory, { withFileTypes: true }).catch(() => [])) {
|
|
268
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".cascade-cache") continue;
|
|
269
|
+
const file = path.join(directory, entry.name);
|
|
270
|
+
if (entry.isDirectory()) await walk(file, depth + 1);
|
|
271
|
+
else if (entry.name === name) found.push(file);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
await walk(path.join(root, "assets"), 0);
|
|
275
|
+
await walk(path.join(root, "licensed"), 0);
|
|
276
|
+
return found;
|
|
277
|
+
}
|
|
278
|
+
async function runWithScene(graph, flags) {
|
|
279
|
+
const graphFile = path.resolve(graph);
|
|
280
|
+
let document = await readGraph(graph);
|
|
281
|
+
const scene = one(flags, "--scene");
|
|
282
|
+
if (scene) {
|
|
283
|
+
const applied = await sceneDocument(graph, scene);
|
|
284
|
+
document = applied.document;
|
|
285
|
+
for (const warning of applied.warnings) console.warn(`Warning: ${warning}`);
|
|
286
|
+
}
|
|
287
|
+
await installHeadlessCanvas().catch(() => void 0);
|
|
288
|
+
const project = new ProjectRoot(path.dirname(graphFile));
|
|
289
|
+
const removeIo = installProjectIo(project);
|
|
290
|
+
const { outputs } = await cookProjectGraph(graphFile, document).finally(removeIo);
|
|
291
|
+
for (const spec of flags.values.get("--write") ?? []) {
|
|
292
|
+
const match = /^([^.=]+)\.([^=]+)=(.+)$/.exec(spec);
|
|
293
|
+
if (!match) throw new Error(`--write expects <node>.<port>=<file>, got ${spec}`);
|
|
294
|
+
const [, node, port, file] = match;
|
|
295
|
+
const value = outputs.get(node)?.get(port);
|
|
296
|
+
if (value === void 0) throw new Error(`${node}.${port} produced nothing`);
|
|
297
|
+
if (typeof value === "string") await fs.writeFile(file, value);
|
|
298
|
+
else if (value && typeof value === "object" && typeof value.path === "string")
|
|
299
|
+
await fs.copyFile(project.resolve(value.path.replace(/^\.\//, "")), file);
|
|
300
|
+
else await fs.writeFile(file, JSON.stringify(toJson(value)));
|
|
301
|
+
console.log(`Wrote ${node}.${port} \u2192 ${file}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function toJson(value) {
|
|
305
|
+
return JSON.parse(JSON.stringify(value, (_key, item) => ArrayBuffer.isView(item) ? Array.from(item) : item) ?? "null");
|
|
306
|
+
}
|
|
307
|
+
function getPath(value, field) {
|
|
308
|
+
let current = value;
|
|
309
|
+
for (const part of field.split(".").flatMap((item) => item.split(/\[(\d+)\]/).filter(Boolean))) {
|
|
310
|
+
if (current === null || typeof current !== "object") return void 0;
|
|
311
|
+
current = current[part];
|
|
312
|
+
}
|
|
313
|
+
return current;
|
|
314
|
+
}
|
|
315
|
+
function setPath(target, field, value) {
|
|
316
|
+
const parts = field.split(".").flatMap((item) => item.split(/\[(\d+)\]/).filter(Boolean));
|
|
317
|
+
let current = target;
|
|
318
|
+
parts.forEach((part, index) => {
|
|
319
|
+
const last = index === parts.length - 1;
|
|
320
|
+
const container = current;
|
|
321
|
+
if (last) {
|
|
322
|
+
container[part] = value;
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (container[part] === void 0) container[part] = /^\d+$/.test(parts[index + 1]) ? [] : {};
|
|
326
|
+
current = container[part];
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export {
|
|
331
|
+
EDITOR_COMMANDS,
|
|
332
|
+
EDITOR_HELP,
|
|
333
|
+
runEditorCommand,
|
|
334
|
+
sceneDocument
|
|
335
|
+
};
|
|
336
|
+
//# sourceMappingURL=chunk-73S4JZXK.js.map
|
|
@@ -52,7 +52,7 @@ async function encodeSequence(options) {
|
|
|
52
52
|
if (frames[index] !== frames[index - 1] + 1) throw new Error("--mp4 needs a contiguous range of whole frames (no step)");
|
|
53
53
|
}
|
|
54
54
|
const { prefix, width, extension } = options.sequence;
|
|
55
|
-
const pattern = path.
|
|
55
|
+
const pattern = path.resolve(options.root, `${prefix}.%0${width}d${extension}`);
|
|
56
56
|
const output = path.resolve(options.root, options.file);
|
|
57
57
|
await fs.mkdir(path.dirname(output), { recursive: true });
|
|
58
58
|
const size = scale === 1 ? "pad=ceil(iw/2)*2:ceil(ih/2)*2" : `scale=trunc(iw*${scale}/2)*2:trunc(ih*${scale}/2)*2:flags=lanczos`;
|
|
@@ -60,7 +60,7 @@ async function encodeSequence(options) {
|
|
|
60
60
|
let pixelFormat;
|
|
61
61
|
let codecArgs;
|
|
62
62
|
if (options.codec === "prores") {
|
|
63
|
-
const first = path.
|
|
63
|
+
const first = path.resolve(options.root, `${prefix}.${String(frames[0]).padStart(width, "0")}${extension}`);
|
|
64
64
|
const alpha = await hasTransparency(first);
|
|
65
65
|
pixelFormat = alpha ? "yuva444p10le" : "yuv422p10le";
|
|
66
66
|
codecArgs = ["-c:v", "prores_ks", "-profile:v", alpha ? "4" : "3", "-vendor", "apl0", "-pix_fmt", pixelFormat];
|
|
@@ -118,4 +118,4 @@ export {
|
|
|
118
118
|
hasFfmpeg,
|
|
119
119
|
encodeSequence
|
|
120
120
|
};
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-7QE2ZNSN.js.map
|
|
@@ -3,15 +3,16 @@ import {
|
|
|
3
3
|
packagePathToType,
|
|
4
4
|
registerNodeClasses,
|
|
5
5
|
registerNodeMetadata
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CTPLRSWF.js";
|
|
7
7
|
import {
|
|
8
8
|
bundleValueProblem,
|
|
9
|
+
gpuLimitShortfall,
|
|
9
10
|
graphSeed,
|
|
10
11
|
isGpuHost,
|
|
11
12
|
nodeSeed,
|
|
12
13
|
seededRandom,
|
|
13
14
|
selectBundleFields
|
|
14
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-L6B6FUQP.js";
|
|
15
16
|
|
|
16
17
|
// src/nodes/definition/DefinitionNode.ts
|
|
17
18
|
var silentProgress = { report: () => {
|
|
@@ -136,7 +137,10 @@ function attachDefinition(node, registration, capabilities) {
|
|
|
136
137
|
const gpuHost = (definition.capabilities ?? []).includes("gpu") && isGpuHost(capabilities.gpu) ? capabilities.gpu : null;
|
|
137
138
|
if (gpuHost) {
|
|
138
139
|
await gpuHost.ensure();
|
|
139
|
-
|
|
140
|
+
const gpu = gpuHost.forNode(node.id);
|
|
141
|
+
const shortfall = gpuLimitShortfall(node.id, definition.gpuLimits, gpu);
|
|
142
|
+
if (shortfall) throw new Error(shortfall);
|
|
143
|
+
nodeCapabilities = { ...capabilities, gpu };
|
|
140
144
|
}
|
|
141
145
|
const seed = nodeSeed(graphSeed({ seed: node.documentSeed }), node.id);
|
|
142
146
|
const context = {
|
|
@@ -194,4 +198,4 @@ export {
|
|
|
194
198
|
attachDefinition,
|
|
195
199
|
registerDefinitionNodes
|
|
196
200
|
};
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-BPODRH52.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
canConnectTypes
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FWMSGKEH.js";
|
|
4
4
|
|
|
5
5
|
// packages/runtime/src/edit/document.ts
|
|
6
6
|
var SUBNET = "cascade.core.Subnet";
|
|
@@ -1298,4 +1298,4 @@ export {
|
|
|
1298
1298
|
applyOperation,
|
|
1299
1299
|
readGraph
|
|
1300
1300
|
};
|
|
1301
|
-
//# sourceMappingURL=chunk-
|
|
1301
|
+
//# sourceMappingURL=chunk-BZ63XQ3I.js.map
|