@nodaro/prompts 1.38.0 → 1.40.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/dist/chunk-2EW5B7ZV.cjs +86 -0
- package/dist/chunk-2EW5B7ZV.cjs.map +1 -0
- package/dist/chunk-2P26SZX5.cjs +414 -0
- package/dist/chunk-2P26SZX5.cjs.map +1 -0
- package/dist/{chunk-7XKHDXCL.cjs → chunk-3U7X6JZN.cjs} +13 -12
- package/dist/chunk-3U7X6JZN.cjs.map +1 -0
- package/dist/chunk-4GKTOVFM.cjs +8 -0
- package/dist/chunk-4GKTOVFM.cjs.map +1 -0
- package/dist/{chunk-HRBBNODV.js → chunk-6GVFJLDL.js} +4 -3
- package/dist/chunk-6GVFJLDL.js.map +1 -0
- package/dist/{chunk-LVSH7K7R.cjs → chunk-C3NHNECH.cjs} +165 -88
- package/dist/chunk-C3NHNECH.cjs.map +1 -0
- package/dist/{chunk-CEPVQQVO.js → chunk-C46256GZ.js} +43 -5
- package/dist/chunk-C46256GZ.js.map +1 -0
- package/dist/{chunk-JKCR6WRZ.cjs → chunk-DQFQJECU.cjs} +43 -5
- package/dist/chunk-DQFQJECU.cjs.map +1 -0
- package/dist/{chunk-QDEWBBUR.js → chunk-DUXX6CBX.js} +12 -143
- package/dist/chunk-DUXX6CBX.js.map +1 -0
- package/dist/chunk-EAYEZXWT.js +388 -0
- package/dist/chunk-EAYEZXWT.js.map +1 -0
- package/dist/chunk-GILUVQQJ.js +6 -0
- package/dist/chunk-GILUVQQJ.js.map +1 -0
- package/dist/{chunk-KIYNOOPJ.js → chunk-GTDKDD7Y.js} +12 -6
- package/dist/chunk-GTDKDD7Y.js.map +1 -0
- package/dist/{chunk-QBEZMR2F.js → chunk-HQTHDTHN.js} +137 -62
- package/dist/chunk-HQTHDTHN.js.map +1 -0
- package/dist/{chunk-TLVX5PXD.cjs → chunk-IUCNJAHW.cjs} +13 -7
- package/dist/chunk-IUCNJAHW.cjs.map +1 -0
- package/dist/{chunk-ZFIXQRBZ.cjs → chunk-LXPKTI2K.cjs} +12 -83
- package/dist/chunk-LXPKTI2K.cjs.map +1 -0
- package/dist/{chunk-CVPB2N3Z.cjs → chunk-LZ53F5BN.cjs} +103 -5
- package/dist/chunk-LZ53F5BN.cjs.map +1 -0
- package/dist/{chunk-4FDNVNJE.js → chunk-N6VMPG5S.js} +12 -79
- package/dist/chunk-N6VMPG5S.js.map +1 -0
- package/dist/{chunk-LK2CZK5U.cjs → chunk-PWWM7Q3T.cjs} +7 -7
- package/dist/{chunk-LK2CZK5U.cjs.map → chunk-PWWM7Q3T.cjs.map} +1 -1
- package/dist/{chunk-N7TOWXDJ.js → chunk-QDUTMOF4.js} +3 -3
- package/dist/{chunk-N7TOWXDJ.js.map → chunk-QDUTMOF4.js.map} +1 -1
- package/dist/{chunk-NO6XHX4R.js → chunk-RB2F5JQF.js} +100 -7
- package/dist/chunk-RB2F5JQF.js.map +1 -0
- package/dist/{chunk-MENBHEAY.cjs → chunk-WRM52ZBN.cjs} +19 -161
- package/dist/chunk-WRM52ZBN.cjs.map +1 -0
- package/dist/chunk-YS6HOWMW.js +80 -0
- package/dist/chunk-YS6HOWMW.js.map +1 -0
- package/dist/entries/assembly.cjs +34 -25
- package/dist/entries/assembly.d.cts +121 -37
- package/dist/entries/assembly.d.ts +121 -37
- package/dist/entries/assembly.js +5 -4
- package/dist/entries/doctrine.cjs +46 -46
- package/dist/entries/doctrine.d.cts +3 -3
- package/dist/entries/doctrine.d.ts +3 -3
- package/dist/entries/doctrine.js +1 -1
- package/dist/entries/picker-catalogs.cjs +42 -42
- package/dist/entries/picker-catalogs.js +3 -3
- package/dist/entries/presets.cjs +49 -26
- package/dist/entries/presets.d.cts +53 -1
- package/dist/entries/presets.d.ts +53 -1
- package/dist/entries/presets.js +4 -1
- package/dist/entries/prompt-builder.cjs +135 -98
- package/dist/entries/prompt-builder.d.cts +22 -11
- package/dist/entries/prompt-builder.d.ts +22 -11
- package/dist/entries/prompt-builder.js +4 -3
- package/dist/entries/prompt-fields.cjs +41 -40
- package/dist/entries/prompt-fields.d.cts +2 -1
- package/dist/entries/prompt-fields.d.ts +2 -1
- package/dist/entries/prompt-fields.js +2 -1
- package/dist/index.cjs +339 -273
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +11 -9
- package/dist/{subject-registry-BUswuEVD.d.cts → subject-registry-CQi_CZfJ.d.cts} +78 -9
- package/dist/{subject-registry-D7V8PEG-.d.ts → subject-registry-DFiGx49v.d.ts} +78 -9
- package/package.json +2 -2
- package/src/__tests__/assemble-image-input-style-references.test.ts +173 -0
- package/src/__tests__/catalog-id-guard.test.ts +30 -0
- package/src/__tests__/factory-preset-previews.test.ts +123 -0
- package/src/__tests__/factory-preset-references.test.ts +222 -0
- package/src/__tests__/factory-presets-prototype-keys.test.ts +43 -0
- package/src/__tests__/frame-reference-slots.test.ts +43 -0
- package/src/__tests__/gemini-omni-inputs.test.ts +12 -10
- package/src/__tests__/provider-prompt-doctrine.test.ts +14 -0
- package/src/__tests__/user-direction-refs.test.ts +180 -0
- package/src/__tests__/veo-i2v-inputs.test.ts +16 -11
- package/src/assemble-image-input.ts +114 -13
- package/src/catalog-id-guard.ts +18 -2
- package/src/color-names.ts +192 -0
- package/src/direction-registry.ts +66 -5
- package/src/entries/assembly.ts +1 -0
- package/src/entries/prompt-builder.ts +2 -0
- package/src/factory-presets/generate-image.ts +29 -0
- package/src/factory-presets/index.ts +6 -1
- package/src/factory-presets/preview-files.generated.ts +4 -0
- package/src/factory-presets/previews.ts +40 -0
- package/src/factory-presets/references.ts +81 -0
- package/src/factory-presets/shared-image.ts +4 -0
- package/src/factory-presets/types.ts +8 -0
- package/src/frame-reference-slots.ts +92 -0
- package/src/gemini-omni-inputs.ts +23 -22
- package/src/image-reference-doctrine.ts +3 -3
- package/src/image-token-pattern.ts +13 -0
- package/src/node-prompt-fields.ts +5 -3
- package/src/own-entry.ts +11 -0
- package/src/prompt-builder.ts +4 -5
- package/src/prompt-style-section.ts +3 -3
- package/src/prompt-wizard-categories.ts +2 -0
- package/src/provider-prompt-doctrine.ts +45 -3
- package/src/ref-binding.ts +28 -3
- package/src/resolve-prompt.ts +2 -1
- package/src/seedance-2-inputs.ts +15 -40
- package/src/user-direction-refs.ts +110 -0
- package/src/veo-i2v-inputs.ts +24 -17
- package/src/video-reference-resolver.ts +1 -1
- package/dist/chunk-4FDNVNJE.js.map +0 -1
- package/dist/chunk-7XKHDXCL.cjs.map +0 -1
- package/dist/chunk-CEPVQQVO.js.map +0 -1
- package/dist/chunk-CVPB2N3Z.cjs.map +0 -1
- package/dist/chunk-HRBBNODV.js.map +0 -1
- package/dist/chunk-JKCR6WRZ.cjs.map +0 -1
- package/dist/chunk-KIYNOOPJ.js.map +0 -1
- package/dist/chunk-LVSH7K7R.cjs.map +0 -1
- package/dist/chunk-MENBHEAY.cjs.map +0 -1
- package/dist/chunk-NO6XHX4R.js.map +0 -1
- package/dist/chunk-QBEZMR2F.js.map +0 -1
- package/dist/chunk-QDEWBBUR.js.map +0 -1
- package/dist/chunk-TLVX5PXD.cjs.map +0 -1
- package/dist/chunk-UJKFHPZ7.js +0 -37
- package/dist/chunk-UJKFHPZ7.js.map +0 -1
- package/dist/chunk-W5SCZIOB.cjs +0 -43
- package/dist/chunk-W5SCZIOB.cjs.map +0 -1
- package/dist/chunk-ZFIXQRBZ.cjs.map +0 -1
|
@@ -5,6 +5,12 @@ var workflow = require('@nodaro/shared/workflow');
|
|
|
5
5
|
var nodes = require('@nodaro/shared/nodes');
|
|
6
6
|
var social = require('@nodaro/shared/social');
|
|
7
7
|
|
|
8
|
+
// src/own-entry.ts
|
|
9
|
+
function ownEntry(record, key) {
|
|
10
|
+
return key !== void 0 && Object.prototype.hasOwnProperty.call(record, key) ? record[key] : void 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// src/resolve-prompt.ts
|
|
8
14
|
var present = (s) => typeof s === "string" && s.trim().length > 0;
|
|
9
15
|
var rr = (s, m) => m.size > 0 ? workflow.resolveNodeRefs(s, m) : s;
|
|
10
16
|
var GLUE_PUNCTUATION = /* @__PURE__ */ new Set([",", ".", ";", ":", "!", "?", ")"]);
|
|
@@ -76,7 +82,7 @@ function computeNodePrompt(nodeType, data, { override, wired, refMap, appendWire
|
|
|
76
82
|
if (nodeType === "text-to-speech") {
|
|
77
83
|
typed = data.textSource === "direct" || !present(wired) ? [data.directText] : [];
|
|
78
84
|
} else {
|
|
79
|
-
const fields = NODE_PROMPT_CANDIDATE_FIELDS
|
|
85
|
+
const fields = ownEntry(NODE_PROMPT_CANDIDATE_FIELDS, nodeType) ?? ["prompt"];
|
|
80
86
|
typed = fields.map((f) => data[f]);
|
|
81
87
|
}
|
|
82
88
|
return resolvePrompt({ override, typed, wired, refMap, appendWired, affixes: nodes.readPromptAffixes(data) });
|
|
@@ -92,28 +98,6 @@ function computeScriptTopic(data, { override, wired, refMap }) {
|
|
|
92
98
|
return applyPromptAffixes(core === void 0 ? "" : rr(core, refMap), nodes.readPromptAffixes(data), refMap);
|
|
93
99
|
}
|
|
94
100
|
|
|
95
|
-
// src/audio-tags.ts
|
|
96
|
-
function removeBracketTags(text) {
|
|
97
|
-
let out = "";
|
|
98
|
-
let from = 0;
|
|
99
|
-
let open = text.indexOf("[");
|
|
100
|
-
while (open !== -1) {
|
|
101
|
-
const close = text.indexOf("]", open + 1);
|
|
102
|
-
if (close === -1) break;
|
|
103
|
-
if (close === open + 1) {
|
|
104
|
-
open = text.indexOf("[", open + 1);
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
out += text.slice(from, open);
|
|
108
|
-
from = close + 1;
|
|
109
|
-
open = text.indexOf("[", from);
|
|
110
|
-
}
|
|
111
|
-
return out + text.slice(from);
|
|
112
|
-
}
|
|
113
|
-
function stripAudioTags(text) {
|
|
114
|
-
return removeBracketTags(text).replace(/\s{2,}/g, " ").trim();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
101
|
// src/node-prompt-fields.ts
|
|
118
102
|
var NODE_PROMPT_FIELDS = {
|
|
119
103
|
// ── Image ──
|
|
@@ -188,7 +172,7 @@ var NODE_PROMPT_FIELDS = {
|
|
|
188
172
|
"edit-plan": { prompt: "instructions", promptLabel: "Editing instructions", media: "video", inline: false }
|
|
189
173
|
};
|
|
190
174
|
function getPromptFields(nodeType) {
|
|
191
|
-
return nodeType ? NODE_PROMPT_FIELDS
|
|
175
|
+
return nodeType ? ownEntry(NODE_PROMPT_FIELDS, nodeType) : void 0;
|
|
192
176
|
}
|
|
193
177
|
function nodeHasPromptField(nodeType) {
|
|
194
178
|
return getPromptFields(nodeType) !== void 0;
|
|
@@ -212,75 +196,20 @@ function promptFieldCarriesAffixes(nodeType, promptField) {
|
|
|
212
196
|
const core = promptAffixCoreField(nodeType);
|
|
213
197
|
if (core === void 0) return false;
|
|
214
198
|
if (promptField === void 0) return getPromptFields(nodeType).prompt === core;
|
|
215
|
-
return promptField === core || (NODE_PROMPT_CANDIDATE_FIELDS
|
|
199
|
+
return promptField === core || (ownEntry(NODE_PROMPT_CANDIDATE_FIELDS, nodeType) ?? []).includes(promptField);
|
|
216
200
|
}
|
|
217
201
|
var PROMPT_AFFIX_NODE_TYPES = new Set(
|
|
218
202
|
Object.entries(NODE_PROMPT_FIELDS).filter(([, s]) => s.affixes !== false).map(([t]) => t)
|
|
219
203
|
);
|
|
220
|
-
var WIRED_OUTPUT_NODE_TYPES = /* @__PURE__ */ new Set(["webhook-output", ...social.SOCIAL_POST_NODE_TYPES]);
|
|
221
|
-
var TEXT_REQUIRED_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
222
|
-
"llm-chat",
|
|
223
|
-
"ai-writer",
|
|
224
|
-
"generate-script",
|
|
225
|
-
"text-to-speech",
|
|
226
|
-
"generate-music",
|
|
227
|
-
"text-to-audio",
|
|
228
|
-
// Save to Collection refuses an empty record ("nothing to save"): a feed
|
|
229
|
-
// with nothing new wired straight into it must skip it, not fail the run.
|
|
230
|
-
"collection-write",
|
|
231
|
-
// Generate Image: an empty prompt is a legal request in general (references
|
|
232
|
-
// alone), but when the text it was WIRED produced nothing this run — the skip
|
|
233
|
-
// rule's precondition — an empty prompt is a paid picture of nothing.
|
|
234
|
-
"generate-image"
|
|
235
|
-
]);
|
|
236
|
-
var withoutAffixes = (data) => ({ ...data, promptPrefix: void 0, promptSuffix: void 0 });
|
|
237
|
-
var present2 = (s) => typeof s === "string" && s.trim().length > 0;
|
|
238
|
-
function computeAiWriterInput(data, { override, wired }) {
|
|
239
|
-
return [override, wired, data.userInput, data.prompt].find(present2) ?? "";
|
|
240
|
-
}
|
|
241
|
-
function computeNodeSendText(nodeType, data, args) {
|
|
242
|
-
const bare = withoutAffixes(data);
|
|
243
|
-
switch (nodeType) {
|
|
244
|
-
case "llm-chat":
|
|
245
|
-
return computeLlmChatFields(bare, {
|
|
246
|
-
override: args.override,
|
|
247
|
-
wiredUserInput: args.wired,
|
|
248
|
-
wiredSystemPrompt: args.wiredSystemPrompt,
|
|
249
|
-
refMap: args.refMap
|
|
250
|
-
}).userInput;
|
|
251
|
-
case "ai-writer":
|
|
252
|
-
return computeAiWriterInput(bare, args);
|
|
253
|
-
case "generate-script":
|
|
254
|
-
return computeScriptTopic(bare, { override: args.override, wired: args.wired, refMap: args.refMap });
|
|
255
|
-
case "generate-music": {
|
|
256
|
-
const prompt = computeNodePrompt(nodeType, bare, { override: args.override, wired: args.wired, refMap: args.refMap });
|
|
257
|
-
return present2(prompt) ? prompt : present2(data.lyrics) ? data.lyrics : "";
|
|
258
|
-
}
|
|
259
|
-
case "text-to-speech":
|
|
260
|
-
case "text-to-audio":
|
|
261
|
-
case "generate-image":
|
|
262
|
-
return computeNodePrompt(nodeType, bare, { override: args.override, wired: args.wired, refMap: args.refMap });
|
|
263
|
-
case "collection-write": {
|
|
264
|
-
const typed = [data.title, data.text, data.link].map((v) => typeof v === "string" ? workflow.resolveNodeRefs(v, args.refMap) : v).find((v) => present2(v));
|
|
265
|
-
return [args.override, args.wired, typed].find(present2) ?? "";
|
|
266
|
-
}
|
|
267
|
-
default:
|
|
268
|
-
return void 0;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
204
|
|
|
272
205
|
exports.NODE_PROMPT_CANDIDATE_FIELDS = NODE_PROMPT_CANDIDATE_FIELDS;
|
|
273
206
|
exports.NODE_PROMPT_FIELDS = NODE_PROMPT_FIELDS;
|
|
274
207
|
exports.PROMPT_AFFIX_CORE_FIELD_OVERRIDES = PROMPT_AFFIX_CORE_FIELD_OVERRIDES;
|
|
275
208
|
exports.PROMPT_AFFIX_NODE_TYPES = PROMPT_AFFIX_NODE_TYPES;
|
|
276
|
-
exports.TEXT_REQUIRED_NODE_TYPES = TEXT_REQUIRED_NODE_TYPES;
|
|
277
|
-
exports.WIRED_OUTPUT_NODE_TYPES = WIRED_OUTPUT_NODE_TYPES;
|
|
278
209
|
exports.applyPromptAffixes = applyPromptAffixes;
|
|
279
210
|
exports.composeNegative = composeNegative;
|
|
280
|
-
exports.computeAiWriterInput = computeAiWriterInput;
|
|
281
211
|
exports.computeLlmChatFields = computeLlmChatFields;
|
|
282
212
|
exports.computeNodePrompt = computeNodePrompt;
|
|
283
|
-
exports.computeNodeSendText = computeNodeSendText;
|
|
284
213
|
exports.computeScriptTopic = computeScriptTopic;
|
|
285
214
|
exports.getPromptFields = getPromptFields;
|
|
286
215
|
exports.getSnippetMedia = getSnippetMedia;
|
|
@@ -288,10 +217,10 @@ exports.joinPromptParts = joinPromptParts;
|
|
|
288
217
|
exports.nodeHasInlinePrompt = nodeHasInlinePrompt;
|
|
289
218
|
exports.nodeHasPromptField = nodeHasPromptField;
|
|
290
219
|
exports.nodeSupportsPromptAffixes = nodeSupportsPromptAffixes;
|
|
220
|
+
exports.ownEntry = ownEntry;
|
|
291
221
|
exports.promptAffixCoreField = promptAffixCoreField;
|
|
292
222
|
exports.promptFieldCarriesAffixes = promptFieldCarriesAffixes;
|
|
293
223
|
exports.promptPartSeparator = promptPartSeparator;
|
|
294
224
|
exports.resolvePrompt = resolvePrompt;
|
|
295
|
-
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
297
|
-
//# sourceMappingURL=chunk-ZFIXQRBZ.cjs.map
|
|
225
|
+
//# sourceMappingURL=chunk-LXPKTI2K.cjs.map
|
|
226
|
+
//# sourceMappingURL=chunk-LXPKTI2K.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/own-entry.ts","../src/resolve-prompt.ts","../src/node-prompt-fields.ts"],"names":["resolveNodeRefs","joinSentences","SOCIAL_POST_NODE_TYPES","readPromptAffixes"],"mappings":"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","file":"chunk-LXPKTI2K.cjs","sourcesContent":["/**\n * A registry keyed by node type is a plain object, and the key is\n * caller-supplied (`?nodeType=` on a public route, a preset row's `node_type`,\n * workflow JSON). A plain `record[key] ?? fallback` reads an Object.prototype\n * member for `\"constructor\"`, `\"toString\"` or `\"__proto__\"` — a function or\n * the prototype itself, which the caller then maps or iterates and throws on.\n * This reads an OWN entry only, so such a name is \"no such type\".\n */\nexport function ownEntry<T>(record: Readonly<Record<string, T>>, key: string | undefined): T | undefined {\n return key !== undefined && Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined\n}\n","import { resolveNodeRefs } from \"@nodaro/shared/workflow\"\nimport { readPromptAffixes, type PromptAffixes } from \"@nodaro/shared/nodes\"\nimport { SOCIAL_POST_NODE_TYPES } from \"@nodaro/shared/social\"\nimport { joinSentences } from \"./hint-join.js\"\nimport { ownEntry } from \"./own-entry.js\"\n\nexport interface ResolvePromptArgs {\n override?: string\n typed?: ReadonlyArray<string | undefined>\n wired?: string\n refMap: ReadonlyMap<string, string>\n /** Opt-in (generate-image / generate-video only): APPEND the wired\n * (connected-prompt) value to the TYPED base instead of treating wired as a\n * fallback, so a connected prompt auto-injects alongside the typed prompt. An\n * `override` (list fan-out item) still fully replaces — no wired append.\n * Off/undefined = exact legacy precedence (override > typed > wired) for every\n * other node type. */\n appendWired?: boolean\n /** Pre/post text wrapped around WHICHEVER core precedence produced (override,\n * typed, wired, or the appendWired combination). Applied last. */\n affixes?: PromptAffixes\n}\nconst present = (s?: string): s is string => typeof s === \"string\" && s.trim().length > 0\nconst rr = (s: string, m: ReadonlyMap<string, string>) => (m.size > 0 ? resolveNodeRefs(s, m) : s)\n\n// ---------------------------------------------------------------------------\n// Prompt affixes (pre/post text) — see docs/prompt-pre-post-text.md (join rule, empty-core, no-op guarantee)\n// ---------------------------------------------------------------------------\n\nconst GLUE_PUNCTUATION = new Set([\",\", \".\", \";\", \":\", \"!\", \"?\", \")\"])\n\n/** The ONE join rule between two non-blank prompt parts: a single space unless\n * the boundary already has whitespace on either side or the right part opens\n * with sentence punctuation. Shared by `joinPromptParts` and the editor's\n * Final-view segment builder so preview and run agree byte-for-byte. */\nexport function promptPartSeparator(left: string, right: string): \"\" | \" \" {\n if (left.length === 0 || right.length === 0) return \"\"\n if (/\\s$/.test(left) || /^\\s/.test(right)) return \"\"\n if (GLUE_PUNCTUATION.has(right[0])) return \"\"\n return \" \"\n}\n\n/** Join prompt parts with `promptPartSeparator`; blank parts are dropped,\n * non-blank parts are used verbatim (no trimming). */\nexport function joinPromptParts(parts: ReadonlyArray<string | undefined>): string {\n let out = \"\"\n for (const part of parts) {\n if (!present(part)) continue\n out = out.length === 0 ? part : out + promptPartSeparator(out, part) + part\n }\n return out\n}\n\n/**\n * Wrap `core` with the node's pre/post text. `{Label}` refs are resolved in the\n * AFFIXES only — the core arrives exactly as the caller's precedence produced it.\n * NO-OP GUARANTEE: with no non-blank affix the core is returned unchanged (same\n * reference) — every existing workflow stays byte-identical.\n * EMPTY CORE: a blank core with affixes yields the joined affixes alone.\n */\nexport function applyPromptAffixes(core: string, affixes: PromptAffixes | undefined, refMap: ReadonlyMap<string, string>): string\nexport function applyPromptAffixes(core: string | undefined, affixes: PromptAffixes | undefined, refMap: ReadonlyMap<string, string>): string | undefined\nexport function applyPromptAffixes(\n core: string | undefined,\n affixes: PromptAffixes | undefined,\n refMap: ReadonlyMap<string, string>,\n): string | undefined {\n const prefix = present(affixes?.prefix) ? rr(affixes!.prefix!, refMap) : undefined\n const suffix = present(affixes?.suffix) ? rr(affixes!.suffix!, refMap) : undefined\n if (prefix === undefined && suffix === undefined) return core\n return joinPromptParts([prefix, core, suffix])\n}\n\n/** SINGLE SOURCE OF TRUTH for prompt precedence across both DAG engines:\n * override (list fan-out) > first present typed candidate > wired > \"\".\n * \"present\" = non-empty after trim. {Label} refs are resolved on the chosen\n * branch via the shared resolveNodeRefs. With `appendWired`, the chosen base\n * AND the wired value are both emitted, joined as sentences (`joinSentences`:\n * \". \", or a space after one that already ends). Affixes wrap the result. */\nexport function resolvePrompt({ override, typed = [], wired, refMap, appendWired, affixes }: ResolvePromptArgs): string {\n return applyPromptAffixes(resolveCore({ override, typed, wired, refMap, appendWired }), affixes, refMap)\n}\n\nfunction resolveCore({ override, typed = [], wired, refMap, appendWired }: Omit<ResolvePromptArgs, \"affixes\">): string {\n // appendWired: a connected prompt APPENDS to the TYPED base. An `override`\n // (list fan-out item) still fully REPLACES — it never receives a wired append,\n // so per-item fan-out prompts are unchanged.\n if (appendWired && !present(override)) {\n const base = typed.find(present)\n return joinSentences([base, wired].filter(present).map((s) => rr(s, refMap)))\n }\n if (present(override)) return rr(override, refMap)\n for (const t of typed) if (present(t)) return rr(t, refMap)\n if (present(wired)) return rr(wired, refMap)\n return \"\"\n}\n\n/** Compose a final NEGATIVE prompt from a TYPED base + a WIRED (connected\n * negative-handle) value: both are emitted, joined as sentences (`joinSentences`, mirrors `appendWired`\n * for the positive prompt). Pure join — the caller resolves `{label}` refs on\n * the typed value first, and the wired value is already a resolved output that\n * the input-resolver has filtered (referenced / Inject-Negative-off dropped).\n * Generate-image / generate-video only; empty parts are dropped. */\nexport function composeNegative(typed?: string, wired?: string): string {\n return joinSentences([typed, wired])\n}\n\n/** Ordered typed-candidate fields per node type — the precedence source of\n * truth (NOT NODE_MAPPABLE_FIELDS, which is field-mapping eligibility, omits\n * video-retake, and orders llm-chat wrong). */\nexport const NODE_PROMPT_CANDIDATE_FIELDS: Readonly<Record<string, readonly string[]>> = {\n \"generate-image\": [\"prompt\"],\n // motionPrompt is here so generate-video re-typed to text-to-video keeps a\n // prompt stored in data.motionPrompt (the inline picker's legacy field). Safe\n // for a standalone text-to-video node — it never carries data.motionPrompt.\n \"text-to-video\": [\"prompt\", \"motionPrompt\"],\n \"video-to-video\": [\"prompt\"],\n \"generate-music\": [\"prompt\"],\n \"speech-to-video\": [\"prompt\"],\n \"cinematic-avatar\": [\"prompt\"],\n \"extend-video\": [\"prompt\"],\n \"video-retake\": [\"prompt\"],\n \"suno-replace-section\": [\"prompt\"],\n \"image-to-video\": [\"prompt\", \"motionPrompt\"],\n \"generate-video\": [\"prompt\", \"motionPrompt\"],\n \"text-to-audio\": [\"prompt\", \"text\"],\n // Social posts: the orchestrator + frontend executor match per-platform node\n // types (node.type is \"instagram-post\", \"telegram-post\", …), NOT a unified\n // \"social-publish\" type — so every platform needs its own [\"caption\"] entry.\n // Derived from the shared SOCIAL_POST_NODE_TYPES single source of truth so a\n // new platform can't drift out of the precedence map.\n ...Object.fromEntries(\n [...SOCIAL_POST_NODE_TYPES].map((t) => [t, [\"caption\"] as readonly string[]]),\n ),\n // Kept for any caller that passes the aggregate type instead of a platform.\n \"social-publish\": [\"caption\"],\n}\n\nexport interface ComputeNodePromptArgs {\n override?: string\n wired?: string\n refMap: ReadonlyMap<string, string>\n /** See ResolvePromptArgs.appendWired — generate-image / generate-video only. */\n appendWired?: boolean\n}\n/** Resolve a single-prompt node's final prompt (typed-primary). Both engines\n * call this so field-selection + precedence are structurally identical. */\nexport function computeNodePrompt(\n nodeType: string,\n data: Record<string, unknown>,\n { override, wired, refMap, appendWired }: ComputeNodePromptArgs,\n): string {\n let typed: ReadonlyArray<string | undefined>\n if (nodeType === \"text-to-speech\") {\n // data.text is a phantom field on TTS; only directText (gated) is real.\n //\n // The gate is a PREFERENCE, not a lock: when textSource is \"connected\" we\n // still fall back to typed text if nothing is wired. Writers flip the gate\n // (PromptFieldSpec.promptGate), but data reaches nodes from places no\n // writer touches — workflows saved before that fix, JSON imports, MCP\n // writes, templates — and there the text sat visible in the node while the\n // run failed with \"no text found\" (founder, 2026-08-14). Coerce rather\n // than reject, same principle as normalizeModelInput.\n typed =\n data.textSource === \"direct\" || !present(wired)\n ? [data.directText as string | undefined]\n : []\n } else {\n const fields = ownEntry(NODE_PROMPT_CANDIDATE_FIELDS, nodeType) ?? [\"prompt\"]\n typed = fields.map((f) => data[f] as string | undefined)\n }\n return resolvePrompt({ override, typed, wired, refMap, appendWired, affixes: readPromptAffixes(data) })\n}\n\nexport interface LlmChatFieldArgs {\n override?: string\n wiredUserInput?: string\n wiredSystemPrompt?: string\n refMap: ReadonlyMap<string, string>\n}\n/** llm-chat resolves TWO independent fields. override applies to userInput only. */\nexport function computeLlmChatFields(\n data: Record<string, unknown>,\n { override, wiredUserInput, wiredSystemPrompt, refMap }: LlmChatFieldArgs,\n): { userInput: string; systemPrompt: string } {\n return {\n userInput: resolvePrompt({ override, typed: [data.userInput as string | undefined], wired: wiredUserInput, refMap, affixes: readPromptAffixes(data) }),\n systemPrompt: resolvePrompt({ typed: [data.systemPrompt as string | undefined], wired: wiredSystemPrompt, refMap }),\n }\n}\n\n/** generate-script's topic. Both engines call this, so a wired Text node reads\n * the same on a single-node run and a server run.\n *\n * Precedence is override (a list fan-out item) > wired > `data.prompt`. Wired\n * comes BEFORE the typed field, the reverse of `computeNodePrompt`, because\n * `data.prompt` has no editor: the panel's text field is the style guide. A\n * value there was written by the old connect-time `{Label}` auto-fill or by an\n * agent, and it is kept only as the fallback that saved workflows rely on. */\nexport function computeScriptTopic(\n data: Record<string, unknown>,\n { override, wired, refMap }: Omit<ComputeNodePromptArgs, \"appendWired\">,\n): string {\n const core = [override, wired, data.prompt as string | undefined].find(present)\n return applyPromptAffixes(core === undefined ? \"\" : rr(core, refMap), readPromptAffixes(data), refMap)\n}\n","/**\n * Single source of truth: which data field(s) hold a node's user-editable\n * prompt text. Drives the quick-edit Prompt modal so it can work generically\n * across every AI node without each call site hardcoding a field name.\n *\n * The registry LIVES HERE (`@nodaro/prompts`) so the backend orchestrator, the\n * `/v1/nodes` registry, the prompt-affix totality tests and the docs tooling\n * read the SAME list the editor does. `frontend/src/lib/prompt-fields.ts` is a\n * pure re-export of this module — frontend code keeps importing\n * `@/lib/prompt-fields` unchanged.\n *\n * Most nodes store the prompt in `data.prompt`, but several don't\n * (`text-prompt` → `text`, `image-to-text` → `customPrompt`, …) — this map is\n * where that knowledge lives, once.\n *\n * INVARIANT: every node that exposes a user-editable prompt MUST have an entry\n * here, or the quick-edit modal silently does nothing for it. A guard test\n * (`prompt-fields.test.ts`) keeps this in sync with the node set.\n *\n * This module is intentionally pure data (no React/lucide imports) so it can be\n * pulled into the app-runtime bundle and any test without dragging in the icon\n * library. The string `icon` kind is mapped to a concrete lucide component in\n * `prompt-edit-button.tsx` (`getPromptIcon`), the only place that renders it.\n */\n\nimport type { SnippetMedia } from \"./factory-snippets/types.js\"\nimport { NODE_PROMPT_CANDIDATE_FIELDS } from \"./resolve-prompt.js\"\nimport { ownEntry } from \"./own-entry.js\"\n\n/** Which lucide glyph a node's prompt affordance uses. Kept as a string so this\n * module stays icon-library-free; mapped to a component in the strip button. */\nexport type PromptIconKind = \"pencil\" | \"paintbrush\"\n\nexport interface PromptFieldSpec {\n /** Data key holding the primary prompt (e.g. \"prompt\", \"text\", \"customPrompt\"). */\n readonly prompt: string\n /** Data key holding the negative prompt, when the node supports one. */\n readonly negative?: string\n /** Label override for the primary field (defaults to \"Prompt\"). */\n readonly promptLabel?: string\n /** Icon for the prompt affordance (strip button + modal title). Defaults to a\n * pencil; image-editing nodes use a paintbrush to read as \"edit\". */\n readonly icon?: PromptIconKind\n /** Node modality for prompt-snippet scoping — drives which snippet pool the\n * \"/\" menu and Snippets button show for this node's prompt fields. REQUIRED\n * so a new node cannot forget to declare it (compile error). */\n readonly media: SnippetMedia\n /** True when this node renders a media-result preview body and therefore\n * participates in inline-prompt mode (the `InlineNodePrompt` editor on the\n * node face, centralized in `BaseNode`). REQUIRED (like `media`) so a new\n * prompt node must consciously choose — compile error if omitted. The set of\n * `inline: true` types is guarded in `prompt-fields.test.ts`. */\n readonly inline: boolean\n /** Some nodes only READ their prompt field when a sibling discriminator\n * selects it — TTS keeps `directText` but resolves it only while\n * `textSource === \"direct\"`, defaulting to `\"connected\"`. Writing the text\n * without flipping the discriminator saved the value and then failed with\n * \"no text found\" (founder hit it live, 2026-08-14). Declare the pair here\n * and every writer flips it automatically. */\n readonly promptGate?: { readonly field: string; readonly value: string }\n /** Prompt pre/post text (`promptPrefix` / `promptSuffix`) support. Defaults to\n * ON for every prompt node; set `false` ONLY for a node whose \"prompt\" is not\n * a model prompt (the plain Text input node). Read via `nodeSupportsPromptAffixes`. */\n readonly affixes?: false\n}\n\nexport const NODE_PROMPT_FIELDS: Readonly<Record<string, PromptFieldSpec>> = {\n // ── Image ──\n // (`edit-image` / `image-to-image` are legacy types consolidated into\n // `modify-image`; they're not in the creatable node set, so a node of that\n // type never mounts and needs no entry here. The guard test enforces that.)\n \"generate-image\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"image\", inline: true },\n \"modify-image\": { prompt: \"prompt\", negative: \"negativePrompt\", icon: \"paintbrush\", media: \"image\", inline: true },\n \"generate-mask\": { prompt: \"prompt\", promptLabel: \"What to mask\", media: \"image\", inline: true },\n // ── Video ──\n \"generate-video\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"video\", inline: true },\n // Trimmed multi-segment stitch sibling of generate-video — no negativePrompt field.\n \"generate-video-pro\": { prompt: \"prompt\", media: \"video\", inline: true },\n // Span-replace sibling of generate-video-pro — no negativePrompt field.\n \"edit-video-pro\": { prompt: \"prompt\", media: \"video\", inline: true },\n \"text-to-video\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"video\", inline: true },\n \"image-to-video\": { prompt: \"prompt\", negative: \"negativePrompt\", promptLabel: \"Motion prompt\", media: \"video\", inline: true },\n \"video-to-video\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"video\", inline: true },\n \"switchx\": { prompt: \"prompt\", promptLabel: \"Look prompt\", media: \"video\", inline: true },\n \"extend-video\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"video\", inline: true },\n \"speech-to-video\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"video\", inline: true },\n \"motion-transfer\": { prompt: \"prompt\", negative: \"negativePrompt\", media: \"video\", inline: true },\n // Cinematic Avatar (HeyGen) — generative prompt (NOT a verbatim script),\n // so it participates in the quick-edit Prompt modal like other AI video nodes.\n \"cinematic-avatar\": { prompt: \"prompt\", media: \"video\", inline: true },\n \"video-sfx\": { prompt: \"prompt\", negative: \"negativePrompt\", promptLabel: \"Sound prompt\", media: \"audio\", inline: true },\n \"video-retake\": { prompt: \"prompt\", promptLabel: \"Retake prompt\", media: \"video\", inline: true },\n // Video Mask (SAM 3) — the subject to track, like Generate Mask's \"what to mask\".\n \"video-mask\": { prompt: \"prompt\", promptLabel: \"What to mask\", media: \"video\", inline: true },\n // ── Audio / music ──\n \"generate-music\": { prompt: \"prompt\", media: \"audio\", inline: true },\n \"suno-generate\": { prompt: \"prompt\", media: \"audio\", inline: true },\n \"text-to-audio\": { prompt: \"prompt\", media: \"audio\", inline: true },\n // ── Text / LLM (no media-result preview body → no inline editor) ──\n \"text-prompt\": { prompt: \"text\", promptLabel: \"Text\", media: \"text\", inline: false, affixes: false },\n \"image-to-text\": { prompt: \"customPrompt\", promptLabel: \"Question\", media: \"text\", inline: false },\n \"llm-chat\": { prompt: \"userInput\", promptLabel: \"Prompt\", media: \"text\", inline: false },\n // ── Speech / voice ──\n \"text-to-speech\": { prompt: \"directText\", promptLabel: \"Text\", media: \"audio\", inline: true, promptGate: { field: \"textSource\", value: \"direct\" } },\n \"voice-design\": { prompt: \"voiceDescription\", promptLabel: \"Voice description\", media: \"audio\", inline: true },\n \"voice-remix\": { prompt: \"voiceDescription\", promptLabel: \"Voice description\", media: \"audio\", inline: true },\n \"lip-sync\": { prompt: \"prompt\", media: \"audio\", inline: true },\n // ── Suno (music) ──\n \"suno-cover\": { prompt: \"prompt\", media: \"audio\", inline: true },\n \"suno-extend\": { prompt: \"prompt\", media: \"audio\", inline: true },\n \"suno-replace-section\": { prompt: \"prompt\", media: \"audio\", inline: true },\n \"suno-upload-extend\": { prompt: \"prompt\", media: \"audio\", inline: true },\n // NOTE: `suno-add-vocals` is intentionally absent — its node has no\n // user-editable prompt (SunoAddVocalsData declares only `model`; the config\n // panel + backend route take taskId/audioId/model, never a prompt). A stale\n // entry here rendered a phantom Prompt editor in the quick-edit modal that\n // wrote to a `data.prompt` key nothing ever reads (the dead-field class the\n // guard test now catches via defaultData ownership).\n \"suno-lyrics\": { prompt: \"prompt\", media: \"audio\", inline: false },\n \"suno-style-boost\": { prompt: \"content\", promptLabel: \"Style\", media: \"audio\", inline: false },\n // ── Composition / FX (compact, no media-result preview → no inline editor) ──\n \"image-critic\": { prompt: \"prompt\", promptLabel: \"Criteria\", media: \"image\", inline: false },\n \"motion-graphics\": { prompt: \"motionPrompt\", promptLabel: \"Motion prompt\", media: \"video\", inline: false },\n \"pro-3d-render\": { prompt: \"scenePrompt\", promptLabel: \"Scene\", media: \"text\", inline: false },\n \"generate-3d-scene\": { prompt: \"scenePrompt\", promptLabel: \"Scene\", media: \"text\", inline: false },\n \"edit-3d-scene\": { prompt: \"editPrompt\", promptLabel: \"Edit instruction\", media: \"text\", inline: false },\n \"3d-title\": { prompt: \"titlePrompt\", promptLabel: \"Title\", media: \"text\", inline: false },\n // ── Script / alignment (their primary text field) ──\n \"generate-script\": { prompt: \"styleGuide\", promptLabel: \"Style guide\", media: \"text\", inline: false },\n \"forced-alignment\": { prompt: \"transcript\", promptLabel: \"Transcript\", media: \"audio\", inline: false },\n // Video Analysis — its focus hint is the editable prompt (renders a JSON scene\n // table, not a media preview → no inline editor).\n \"video-analysis\": { prompt: \"analysisFocus\", promptLabel: \"Analysis focus\", media: \"video\", inline: false },\n // Edit Plan (podcast editing) — its free-text editing instructions are the\n // editable prompt; the affixes wrap them. Emits an EDL (JSON), not a media\n // preview, so no inline editor.\n \"edit-plan\": { prompt: \"instructions\", promptLabel: \"Editing instructions\", media: \"video\", inline: false },\n}\n\n/** The prompt-field spec for a node type, or undefined if it has none (an\n * Object.prototype member name such as `constructor` has none). */\nexport function getPromptFields(nodeType: string | undefined): PromptFieldSpec | undefined {\n return nodeType ? ownEntry(NODE_PROMPT_FIELDS, nodeType) : undefined\n}\n\n/** True when this node type has a registered, quick-editable prompt field. */\nexport function nodeHasPromptField(nodeType: string | undefined): boolean {\n return getPromptFields(nodeType) !== undefined\n}\n\n/** Snippet modality for a node type (drives the snippet pool), or undefined\n * when the node has no prompt field. */\nexport function getSnippetMedia(nodeType: string | undefined): SnippetMedia | undefined {\n return getPromptFields(nodeType)?.media\n}\n\n/** True when this node type renders the inline on-node prompt editor — the\n * media-preview nodes (image/video/audio result body). Single source for\n * BaseNode's centralized `InlineNodePrompt` rendering and the gold nodes'\n * `showInline` derivation (`useInlinePromptActive`). */\nexport function nodeHasInlinePrompt(nodeType: string | undefined): boolean {\n return getPromptFields(nodeType)?.inline === true\n}\n\n/** True when the node type carries `promptPrefix` / `promptSuffix` — every\n * registered prompt node except explicit opt-outs (`affixes: false`). The single\n * predicate the config panel, Final view, `/v1/nodes` registry, totality tests\n * and docs tooling all gate on. */\nexport function nodeSupportsPromptAffixes(nodeType: string | undefined): boolean {\n const spec = getPromptFields(nodeType)\n return spec !== undefined && spec.affixes !== false\n}\n\n/**\n * Where the RUN-TIME prompt lives when it differs from the editor's prompt\n * field (spec §7). `generate-script`'s editable prompt is its `styleGuide`, but\n * the run wraps the topic `prompt` with the affixes — so previewing the style\n * guide must NOT show them.\n */\nexport const PROMPT_AFFIX_CORE_FIELD_OVERRIDES: Readonly<Record<string, string>> = { \"generate-script\": \"prompt\" }\n\n/** The data key whose value the run wraps with promptPrefix/promptSuffix, or\n * undefined when the node has no affixes. */\nexport function promptAffixCoreField(nodeType: string | undefined): string | undefined {\n if (!nodeSupportsPromptAffixes(nodeType)) return undefined\n return PROMPT_AFFIX_CORE_FIELD_OVERRIDES[nodeType!] ?? getPromptFields(nodeType)!.prompt\n}\n\n/**\n * True when a preview of `promptField` on this node must show the affixes —\n * i.e. that key is what the run actually wraps. THE gate for the editor's Final\n * view, so a sibling field (llm-chat's `systemPrompt`, generate-script's\n * `styleGuide`) never renders a wrap the run doesn't perform.\n *\n * Two ways a key qualifies:\n * - it IS the core field ({@link promptAffixCoreField}), or\n * - it is a run-time FALLBACK candidate for the type\n * ({@link NODE_PROMPT_CANDIDATE_FIELDS}) — `computeNodePrompt` picks the\n * first present candidate and wraps THAT, so i2v's legacy `motionPrompt`\n * genuinely receives the affixes when `data.prompt` is empty.\n *\n * The two rules never collide: no override type declares candidates (guarded in\n * `node-prompt-fields.test.ts`).\n *\n * `undefined` means \"the node's primary prompt field\" — the common call.\n */\nexport function promptFieldCarriesAffixes(nodeType: string | undefined, promptField: string | undefined): boolean {\n const core = promptAffixCoreField(nodeType)\n if (core === undefined) return false\n if (promptField === undefined) return getPromptFields(nodeType)!.prompt === core\n return promptField === core || (ownEntry(NODE_PROMPT_CANDIDATE_FIELDS, nodeType) ?? []).includes(promptField)\n}\n\n/** The affix-capable node types, derived from the registry (never hand-listed). */\nexport const PROMPT_AFFIX_NODE_TYPES: ReadonlySet<string> = new Set(\n Object.entries(NODE_PROMPT_FIELDS).filter(([, s]) => s.affixes !== false).map(([t]) => t),\n)\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var chunkLXPKTI2K_cjs = require('./chunk-LXPKTI2K.cjs');
|
|
4
|
+
var chunk4GKTOVFM_cjs = require('./chunk-4GKTOVFM.cjs');
|
|
3
5
|
var chunkNAFD6MGH_cjs = require('./chunk-NAFD6MGH.cjs');
|
|
4
6
|
var models = require('@nodaro/shared/models');
|
|
5
7
|
|
|
@@ -137,7 +139,9 @@ function stylizedSubjectFor(nodeType) {
|
|
|
137
139
|
name: p.name,
|
|
138
140
|
description: p.description,
|
|
139
141
|
group: "Stylized Subject",
|
|
140
|
-
data: { provider: editProviderFor(nodeType), ...p.data }
|
|
142
|
+
data: { provider: editProviderFor(nodeType), ...p.data },
|
|
143
|
+
// Restyles the person in the connected photo ("the reference image").
|
|
144
|
+
minReferences: 1
|
|
141
145
|
}));
|
|
142
146
|
}
|
|
143
147
|
var IMAGE_EDITS = [
|
|
@@ -261,7 +265,9 @@ function editsFor(nodeType) {
|
|
|
261
265
|
name: p.name,
|
|
262
266
|
description: p.description,
|
|
263
267
|
group: "Edits",
|
|
264
|
-
data: { provider: editProviderFor(nodeType), ...p.data }
|
|
268
|
+
data: { provider: editProviderFor(nodeType), ...p.data },
|
|
269
|
+
// Every edit operates on the connected photo.
|
|
270
|
+
minReferences: 1
|
|
265
271
|
}));
|
|
266
272
|
}
|
|
267
273
|
|
|
@@ -270,12 +276,17 @@ var sentences = (...parts) => parts.join(" ");
|
|
|
270
276
|
var REALISM_MODEL = { provider: "gpt-image-2", resolution: "2K" };
|
|
271
277
|
var SKIN_STUDY_MODEL = { provider: "seedream-5-pro", quality: "high" };
|
|
272
278
|
var GENERATE_IMAGE_PRESETS = [
|
|
279
|
+
// `minReferences` marks a preset that works from connected photos its prompt
|
|
280
|
+
// describes in words ("the attached photo"); `{image:N}` tokens count on their
|
|
281
|
+
// own, so a tokenized preset declares nothing. The groups stay all-or-nothing
|
|
282
|
+
// (factory-preset-references.test.ts), so a new preset copies the line along.
|
|
273
283
|
// ── Reference Sheet ──────────────────────────────────────────────────────
|
|
274
284
|
{
|
|
275
285
|
id: "generate-image/character-board",
|
|
276
286
|
name: "Character Board",
|
|
277
287
|
description: "Connect a sharp, well-lit photo \u2192 dense character sheet; reuse it as a reference for consistent shots.",
|
|
278
288
|
group: "Reference Sheet",
|
|
289
|
+
minReferences: 1,
|
|
279
290
|
data: {
|
|
280
291
|
provider: "gpt-image-2",
|
|
281
292
|
aspectRatio: "16:9",
|
|
@@ -290,6 +301,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
290
301
|
name: "Pose Board",
|
|
291
302
|
description: "Connect a sharp photo \u2192 animation-ready pose & expression sheet; reuse it as a reference for consistent action.",
|
|
292
303
|
group: "Reference Sheet",
|
|
304
|
+
minReferences: 1,
|
|
293
305
|
data: {
|
|
294
306
|
provider: "gpt-image-2",
|
|
295
307
|
aspectRatio: "16:9",
|
|
@@ -304,6 +316,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
304
316
|
name: "Location Board",
|
|
305
317
|
description: "Connect a photo \u2192 dense location sheet; reuse it as a reference for consistent scenes.",
|
|
306
318
|
group: "Reference Sheet",
|
|
319
|
+
minReferences: 1,
|
|
307
320
|
data: {
|
|
308
321
|
provider: "gpt-image-2",
|
|
309
322
|
aspectRatio: "16:9",
|
|
@@ -318,6 +331,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
318
331
|
name: "Product Board",
|
|
319
332
|
description: "Connect a photo \u2192 dense product sheet; reuse it as a reference for consistent shots.",
|
|
320
333
|
group: "Reference Sheet",
|
|
334
|
+
minReferences: 1,
|
|
321
335
|
data: {
|
|
322
336
|
provider: "gpt-image-2",
|
|
323
337
|
aspectRatio: "16:9",
|
|
@@ -332,6 +346,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
332
346
|
name: "Outfit Board",
|
|
333
347
|
description: "Connect a photo \u2192 dense wardrobe sheet; reuse it as a reference for consistent looks.",
|
|
334
348
|
group: "Reference Sheet",
|
|
349
|
+
minReferences: 1,
|
|
335
350
|
data: {
|
|
336
351
|
provider: "gpt-image-2",
|
|
337
352
|
aspectRatio: "16:9",
|
|
@@ -346,6 +361,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
346
361
|
name: "Scene Board",
|
|
347
362
|
description: "Connect a photo \u2192 set-dressing & props study; reuse it as a reference for consistent sets.",
|
|
348
363
|
group: "Reference Sheet",
|
|
364
|
+
minReferences: 1,
|
|
349
365
|
data: {
|
|
350
366
|
provider: "gpt-image-2",
|
|
351
367
|
aspectRatio: "16:9",
|
|
@@ -360,6 +376,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
360
376
|
name: "Creature Board",
|
|
361
377
|
description: "Connect a sharp photo \u2192 dense creature sheet; reuse it as a reference for consistent shots.",
|
|
362
378
|
group: "Reference Sheet",
|
|
379
|
+
minReferences: 1,
|
|
363
380
|
data: {
|
|
364
381
|
provider: "gpt-image-2",
|
|
365
382
|
aspectRatio: "16:9",
|
|
@@ -374,6 +391,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
374
391
|
name: "Vehicle Board",
|
|
375
392
|
description: "Connect a photo \u2192 dense vehicle sheet; reuse it as a reference for consistent shots.",
|
|
376
393
|
group: "Reference Sheet",
|
|
394
|
+
minReferences: 1,
|
|
377
395
|
data: {
|
|
378
396
|
provider: "gpt-image-2",
|
|
379
397
|
aspectRatio: "16:9",
|
|
@@ -388,6 +406,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
388
406
|
name: "Food Board",
|
|
389
407
|
description: "Connect a photo \u2192 dense dish sheet; reuse it as a reference for consistent food shots.",
|
|
390
408
|
group: "Reference Sheet",
|
|
409
|
+
minReferences: 1,
|
|
391
410
|
data: {
|
|
392
411
|
provider: "gpt-image-2",
|
|
393
412
|
aspectRatio: "16:9",
|
|
@@ -402,6 +421,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
402
421
|
name: "Mascot Board",
|
|
403
422
|
description: "Connect a mascot image \u2192 brand-character sheet with brand applications; reuse it for a consistent mascot.",
|
|
404
423
|
group: "Reference Sheet",
|
|
424
|
+
minReferences: 1,
|
|
405
425
|
data: {
|
|
406
426
|
provider: "gpt-image-2",
|
|
407
427
|
aspectRatio: "16:9",
|
|
@@ -416,6 +436,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
416
436
|
name: "Pet Board",
|
|
417
437
|
description: "Connect a sharp photo \u2192 dense pet sheet; reuse it as a reference for consistent shots.",
|
|
418
438
|
group: "Reference Sheet",
|
|
439
|
+
minReferences: 1,
|
|
419
440
|
data: {
|
|
420
441
|
provider: "gpt-image-2",
|
|
421
442
|
aspectRatio: "16:9",
|
|
@@ -430,6 +451,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
430
451
|
name: "Skin Detail Sheet",
|
|
431
452
|
description: "Connect a sharp face photo \u2192 a six-panel skin reference.",
|
|
432
453
|
group: "Reference Sheet",
|
|
454
|
+
minReferences: 1,
|
|
433
455
|
data: {
|
|
434
456
|
...SKIN_STUDY_MODEL,
|
|
435
457
|
aspectRatio: "3:2",
|
|
@@ -452,6 +474,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
452
474
|
name: "Character Reference Grid",
|
|
453
475
|
description: "Connect a photo \u2192 clean 4-angle identity grid (no decorations) \u2014 the strongest consistency anchor.",
|
|
454
476
|
group: "Cast & Consistency",
|
|
477
|
+
minReferences: 1,
|
|
455
478
|
data: {
|
|
456
479
|
provider: "gpt-image-2",
|
|
457
480
|
aspectRatio: "3:4",
|
|
@@ -466,6 +489,8 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
466
489
|
name: "Cast Mega Grid",
|
|
467
490
|
description: "Connect 2\u20134 character refs \u2192 one labeled cast sheet; then reference cast members by name in scenes.",
|
|
468
491
|
group: "Cast & Consistency",
|
|
492
|
+
// A cast sheet is two characters or more ("Connect 2–4 character refs").
|
|
493
|
+
minReferences: 2,
|
|
469
494
|
data: {
|
|
470
495
|
provider: "gpt-image-2",
|
|
471
496
|
aspectRatio: "3:4",
|
|
@@ -479,6 +504,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
479
504
|
name: "Cast Scene (by name)",
|
|
480
505
|
description: "Connect a cast grid \u2192 stage a scene naming the characters; never re-describe their looks.",
|
|
481
506
|
group: "Cast & Consistency",
|
|
507
|
+
minReferences: 1,
|
|
482
508
|
data: {
|
|
483
509
|
provider: "gpt-image-2",
|
|
484
510
|
aspectRatio: "16:9",
|
|
@@ -493,6 +519,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
493
519
|
name: "Label Elements",
|
|
494
520
|
description: "Step 1 \xB7 connect a photo \u2192 the same image with a numbered label on each changeable element.",
|
|
495
521
|
group: "Edit by Name",
|
|
522
|
+
minReferences: 1,
|
|
496
523
|
data: {
|
|
497
524
|
provider: "gpt-image-2",
|
|
498
525
|
quality: "high",
|
|
@@ -505,6 +532,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
505
532
|
name: "Apply Named Edit",
|
|
506
533
|
description: 'Step 2 \xB7 connect the labeled sheet \u2192 type your change in the prompt (e.g. change "drink 1" to blue); the labels are removed from the result.',
|
|
507
534
|
group: "Edit by Name",
|
|
535
|
+
minReferences: 1,
|
|
508
536
|
data: {
|
|
509
537
|
provider: "gpt-image-2",
|
|
510
538
|
quality: "high",
|
|
@@ -1713,6 +1741,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1713
1741
|
name: "Five Ages (Timeless Soul)",
|
|
1714
1742
|
description: "One person at 5 ages, studio line-up. Needs a reference photo.",
|
|
1715
1743
|
group: "Portrait Transformations",
|
|
1744
|
+
minReferences: 1,
|
|
1716
1745
|
data: {
|
|
1717
1746
|
provider: "gpt-image-2",
|
|
1718
1747
|
aspectRatio: "3:4",
|
|
@@ -1725,6 +1754,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1725
1754
|
name: "Three-Age Triptych",
|
|
1726
1755
|
description: "Same person at 3 ages (~10 / 40 / 75). Needs a reference photo.",
|
|
1727
1756
|
group: "Portrait Transformations",
|
|
1757
|
+
minReferences: 1,
|
|
1728
1758
|
data: {
|
|
1729
1759
|
provider: "gpt-image-2",
|
|
1730
1760
|
aspectRatio: "3:4",
|
|
@@ -1737,6 +1767,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1737
1767
|
name: "Five Ages \u2014 B&W",
|
|
1738
1768
|
description: "Monochrome age line-up. Needs a reference photo.",
|
|
1739
1769
|
group: "Portrait Transformations",
|
|
1770
|
+
minReferences: 1,
|
|
1740
1771
|
data: {
|
|
1741
1772
|
provider: "gpt-image-2",
|
|
1742
1773
|
aspectRatio: "3:4",
|
|
@@ -1749,6 +1780,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1749
1780
|
name: "Decade Timeline",
|
|
1750
1781
|
description: "Same person across the '80s\u20132020s. Needs a reference photo.",
|
|
1751
1782
|
group: "Portrait Transformations",
|
|
1783
|
+
minReferences: 1,
|
|
1752
1784
|
data: {
|
|
1753
1785
|
provider: "gpt-image-2",
|
|
1754
1786
|
aspectRatio: "3:4",
|
|
@@ -1761,6 +1793,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1761
1793
|
name: "Four Seasons",
|
|
1762
1794
|
description: "Same person in spring / summer / autumn / winter. Needs a reference photo.",
|
|
1763
1795
|
group: "Portrait Transformations",
|
|
1796
|
+
minReferences: 1,
|
|
1764
1797
|
data: {
|
|
1765
1798
|
provider: "gpt-image-2",
|
|
1766
1799
|
aspectRatio: "3:4",
|
|
@@ -1773,6 +1806,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1773
1806
|
name: "Times of Day",
|
|
1774
1807
|
description: "Same person at dawn / midday / golden hour / night. Needs a reference photo.",
|
|
1775
1808
|
group: "Portrait Transformations",
|
|
1809
|
+
minReferences: 1,
|
|
1776
1810
|
data: {
|
|
1777
1811
|
provider: "gpt-image-2",
|
|
1778
1812
|
aspectRatio: "3:4",
|
|
@@ -1785,6 +1819,7 @@ var GENERATE_IMAGE_PRESETS = [
|
|
|
1785
1819
|
name: "Sports Jersey Portrait",
|
|
1786
1820
|
description: "You in an oversized team jersey, studio editorial. Needs a reference photo.",
|
|
1787
1821
|
group: "Portrait Transformations",
|
|
1822
|
+
minReferences: 1,
|
|
1788
1823
|
data: {
|
|
1789
1824
|
provider: "nano-banana-2-1",
|
|
1790
1825
|
aspectRatio: "4:5",
|
|
@@ -5116,6 +5151,64 @@ function groupFactoryPresets(presets) {
|
|
|
5116
5151
|
}
|
|
5117
5152
|
return buckets;
|
|
5118
5153
|
}
|
|
5154
|
+
var MAX_PRESET_REFERENCES = Math.max(
|
|
5155
|
+
1,
|
|
5156
|
+
...[...models.MODELS_WITH_REFERENCE_IMAGE_SUPPORT].map((provider) => models.imageReferenceLimit(provider))
|
|
5157
|
+
);
|
|
5158
|
+
function promptFieldsOf(nodeType) {
|
|
5159
|
+
const spec = chunkLXPKTI2K_cjs.getPromptFields(nodeType);
|
|
5160
|
+
const candidates = chunkLXPKTI2K_cjs.ownEntry(chunkLXPKTI2K_cjs.NODE_PROMPT_CANDIDATE_FIELDS, nodeType) ?? [];
|
|
5161
|
+
if (!spec && candidates.length === 0) return [];
|
|
5162
|
+
const fields = new Set(candidates);
|
|
5163
|
+
if (spec) {
|
|
5164
|
+
fields.add(spec.prompt);
|
|
5165
|
+
if (spec.negative) fields.add(spec.negative);
|
|
5166
|
+
}
|
|
5167
|
+
const core = chunkLXPKTI2K_cjs.promptAffixCoreField(nodeType);
|
|
5168
|
+
if (core) fields.add(core);
|
|
5169
|
+
if (chunkLXPKTI2K_cjs.nodeSupportsPromptAffixes(nodeType)) {
|
|
5170
|
+
fields.add("promptPrefix");
|
|
5171
|
+
fields.add("promptSuffix");
|
|
5172
|
+
}
|
|
5173
|
+
return [...fields];
|
|
5174
|
+
}
|
|
5175
|
+
function highestImageToken(text) {
|
|
5176
|
+
let highest = 0;
|
|
5177
|
+
for (const match of text.matchAll(chunk4GKTOVFM_cjs.IMAGE_TOKEN_PATTERN)) {
|
|
5178
|
+
const n = Number.parseInt(match[1] ?? "", 10);
|
|
5179
|
+
if (Number.isInteger(n) && n > highest) highest = n;
|
|
5180
|
+
}
|
|
5181
|
+
return highest;
|
|
5182
|
+
}
|
|
5183
|
+
function presetMinReferences(nodeType, data, declared) {
|
|
5184
|
+
let count = typeof declared === "number" && Number.isInteger(declared) && declared > 0 ? declared : 0;
|
|
5185
|
+
for (const field of promptFieldsOf(nodeType)) {
|
|
5186
|
+
const value = data[field];
|
|
5187
|
+
if (typeof value === "string") count = Math.max(count, highestImageToken(value));
|
|
5188
|
+
}
|
|
5189
|
+
return Math.min(count, MAX_PRESET_REFERENCES);
|
|
5190
|
+
}
|
|
5191
|
+
|
|
5192
|
+
// src/factory-presets/preview-files.generated.ts
|
|
5193
|
+
var FACTORY_PRESET_PREVIEW_FILES = {};
|
|
5194
|
+
|
|
5195
|
+
// src/factory-presets/previews.ts
|
|
5196
|
+
var PRESET_PREVIEW_PATH = "/preset-previews/";
|
|
5197
|
+
function originOf(baseUrl) {
|
|
5198
|
+
try {
|
|
5199
|
+
const url = new URL(baseUrl);
|
|
5200
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
|
|
5201
|
+
return url.origin + url.pathname.replace(/\/+$/, "");
|
|
5202
|
+
} catch {
|
|
5203
|
+
return void 0;
|
|
5204
|
+
}
|
|
5205
|
+
}
|
|
5206
|
+
function factoryPresetPreviewUrl(presetId, baseUrl, files = FACTORY_PRESET_PREVIEW_FILES) {
|
|
5207
|
+
const file = Object.prototype.hasOwnProperty.call(files, presetId) ? files[presetId] : void 0;
|
|
5208
|
+
if (!file) return null;
|
|
5209
|
+
const origin = originOf(baseUrl);
|
|
5210
|
+
return origin ? `${origin}${PRESET_PREVIEW_PATH}${file}` : null;
|
|
5211
|
+
}
|
|
5119
5212
|
|
|
5120
5213
|
// src/factory-presets/index.ts
|
|
5121
5214
|
function forModifyImage(p) {
|
|
@@ -5147,7 +5240,7 @@ var FACTORY_PRESETS = {
|
|
|
5147
5240
|
"lottie-overlay": LOTTIE_OVERLAY_PRESETS
|
|
5148
5241
|
};
|
|
5149
5242
|
function getFactoryPresets(nodeType) {
|
|
5150
|
-
return FACTORY_PRESETS
|
|
5243
|
+
return chunkLXPKTI2K_cjs.ownEntry(FACTORY_PRESETS, nodeType) ?? [];
|
|
5151
5244
|
}
|
|
5152
5245
|
|
|
5153
5246
|
// src/caption-treatments.ts
|
|
@@ -5532,8 +5625,10 @@ exports.BRAND_PRESET_META = BRAND_PRESET_META;
|
|
|
5532
5625
|
exports.CAPTION_LEVERS_BY_LANGUAGE = CAPTION_LEVERS_BY_LANGUAGE;
|
|
5533
5626
|
exports.CAPTION_SEGMENT_LEVER_KEYS = CAPTION_SEGMENT_LEVER_KEYS;
|
|
5534
5627
|
exports.FACTORY_PRESETS = FACTORY_PRESETS;
|
|
5628
|
+
exports.FACTORY_PRESET_PREVIEW_FILES = FACTORY_PRESET_PREVIEW_FILES;
|
|
5535
5629
|
exports.FACTORY_SNIPPETS = FACTORY_SNIPPETS;
|
|
5536
5630
|
exports.HOOK_PLATE_PRESET_ID = HOOK_PLATE_PRESET_ID;
|
|
5631
|
+
exports.MAX_PRESET_REFERENCES = MAX_PRESET_REFERENCES;
|
|
5537
5632
|
exports.OBJECT_ANGLE_PRESETS = OBJECT_ANGLE_PRESETS;
|
|
5538
5633
|
exports.OBJECT_ANGLE_PROMPTS = OBJECT_ANGLE_PROMPTS;
|
|
5539
5634
|
exports.OBJECT_ASSET_PRESETS = OBJECT_ASSET_PRESETS;
|
|
@@ -5542,13 +5637,16 @@ exports.OBJECT_MATERIAL_PRESETS = OBJECT_MATERIAL_PRESETS;
|
|
|
5542
5637
|
exports.OBJECT_MATERIAL_PROMPTS = OBJECT_MATERIAL_PROMPTS;
|
|
5543
5638
|
exports.OBJECT_VARIATION_PRESETS = OBJECT_VARIATION_PRESETS;
|
|
5544
5639
|
exports.OBJECT_VARIATION_PROMPTS = OBJECT_VARIATION_PROMPTS;
|
|
5640
|
+
exports.PRESET_PREVIEW_PATH = PRESET_PREVIEW_PATH;
|
|
5545
5641
|
exports.SNIPPET_MEDIA_VALUES = SNIPPET_MEDIA_VALUES;
|
|
5546
5642
|
exports.STYLE_PRESETS = STYLE_PRESETS;
|
|
5643
|
+
exports.factoryPresetPreviewUrl = factoryPresetPreviewUrl;
|
|
5547
5644
|
exports.getFactoryPresets = getFactoryPresets;
|
|
5548
5645
|
exports.getFactorySnippets = getFactorySnippets;
|
|
5549
5646
|
exports.getStylePreset = getStylePreset;
|
|
5550
5647
|
exports.groupFactoryPresets = groupFactoryPresets;
|
|
5551
5648
|
exports.hookPlateCaptionSegments = hookPlateCaptionSegments;
|
|
5649
|
+
exports.presetMinReferences = presetMinReferences;
|
|
5552
5650
|
exports.resolveBrandInput = resolveBrandInput;
|
|
5553
|
-
//# sourceMappingURL=chunk-
|
|
5554
|
-
//# sourceMappingURL=chunk-
|
|
5651
|
+
//# sourceMappingURL=chunk-LZ53F5BN.cjs.map
|
|
5652
|
+
//# sourceMappingURL=chunk-LZ53F5BN.cjs.map
|