@rslsp1/fa-app-tools 3.0.0 → 5.0.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-TCJ3CMCK.mjs → chunk-TW4IDHAN.mjs} +1660 -604
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1699 -693
- package/dist/index.mjs +9 -8
- package/dist/szenen.d.mts +501 -23
- package/dist/szenen.d.ts +501 -23
- package/dist/szenen.js +1905 -734
- package/dist/szenen.mjs +169 -29
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -807,7 +807,7 @@ __export(index_exports, {
|
|
|
807
807
|
module.exports = __toCommonJS(index_exports);
|
|
808
808
|
|
|
809
809
|
// package.json
|
|
810
|
-
var version = "
|
|
810
|
+
var version = "5.0.0";
|
|
811
811
|
|
|
812
812
|
// src/hooks/useOnClickOutside.ts
|
|
813
813
|
var import_react = require("react");
|
|
@@ -846,7 +846,7 @@ function useKeyboardNavigation(history, currentResult, setCurrentResult) {
|
|
|
846
846
|
}
|
|
847
847
|
|
|
848
848
|
// src/features/szenen/szenenViewStyles.generated.ts
|
|
849
|
-
var SZENEN_VIEW_STYLES = '/* ==========================================================================\n SZENEN VIEW\n ========================================================================== */\n\n.szenen-view {\n display: grid;\n gap: var(--space-md);\n width: 100%;\n min-width: 0;\n font-family: var(--font-sans);\n padding: var(--space-md);\n}\n\n@media (max-width: 760px) {\n .szenen-view {\n padding: var(--space-sm);\n gap: var(--space-sm);\n }\n}\n\n.szenen-view__intro {\n display: flex;\n align-items: end;\n justify-content: space-between;\n gap: var(--space-md);\n padding: clamp(1rem, 3vw, 1.75rem);\n color: var(--color-text-primary);\n background:\n radial-gradient(circle at 85% 15%, rgba(45, 212, 191, 0.16), transparent 34%),\n linear-gradient(135deg, var(--color-bg-surface), var(--color-bg-elevated));\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view__intro h2,\n.szenen-view__intro p {\n margin: 0;\n}\n\n.szenen-view__intro h2 {\n margin-bottom: var(--space-xs);\n font-size: clamp(1.25rem, 4vw, 2rem);\n}\n\n.szenen-view__intro > div > p:last-child {\n max-width: 44rem;\n color: var(--color-text-secondary);\n}\n\n.szenen-view__eyebrow {\n margin-bottom: var(--space-xs) !important;\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.72rem;\n font-weight: 800;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n}\n\n.szenen-view__step {\n flex: none;\n padding: 0.35rem 0.65rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.78rem;\n font-weight: 700;\n}\n\n.szenen-view__nav {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view__nav button,\n.szenen-view button {\n min-height: 2.25rem;\n padding: 0.45rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-view button:hover:not(:disabled) {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-border-hover);\n}\n\n.szenen-view button:focus-visible,\n.szenen-view input:focus-visible,\n.szenen-view select:focus-visible,\n.szenen-view textarea:focus-visible {\n outline: 2px solid var(--color-accent-blue);\n outline-offset: 2px;\n}\n\n.szenen-view button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.szenen-view__nav button.is-active,\n.szenen-view__nav button[aria-selected="true"] {\n color: var(--color-text-primary);\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-view__area {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-view__capability-note,\n.szenen-area__lead {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-accent-purple);\n border-radius: var(--radius-sm);\n}\n\n.szenen-view__host-notes {\n color: var(--color-text-secondary);\n}\n\n.szenen-view__host-notes > summary {\n cursor: pointer;\n font-size: 0.8rem;\n}\n\n.szenen-view input:not([type="checkbox"]),\n.szenen-view select,\n.szenen-view textarea {\n width: 100%;\n min-height: 2.25rem;\n padding: 0.5rem 0.65rem;\n color: var(--color-text-primary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font: inherit;\n}\n\n.szenen-view textarea {\n min-height: 7rem;\n resize: vertical;\n font-family: var(--font-mono);\n font-size: 0.8rem;\n}\n\n.szenen-view label {\n display: grid;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-view code,\n.szenen-view pre {\n font-family: var(--font-mono);\n overflow-wrap: anywhere;\n}\n\n.szenen-view h3,\n.szenen-view h4,\n.szenen-view h5 {\n margin-top: 0;\n}\n\n.szenen-view ul,\n.szenen-view ol {\n padding-left: 1.25rem;\n}\n\n.szenen-elements,\n.szenen-detail,\n.szenen-scene,\n.szenen-setup,\n.szenen-shot,\n.szenen-media,\n.szenen-runs {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n.szenen-elements__filter,\n.szenen-elements__create,\n.szenen-detail__actions,\n.szenen-runs__start,\n.szenen-scene-editor__add,\n.szenen-scene-editor__add-relation {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-elements__filter > label,\n.szenen-elements__create > input,\n.szenen-runs__start > label,\n.szenen-scene-editor__add > input {\n flex: 1 1 16rem;\n}\n\n.szenen-elements__filter > label:has(input[type="checkbox"]) {\n display: flex;\n flex: 1 1 16rem;\n flex-direction: row;\n align-items: center;\n}\n\n.szenen-elements__filter input[type="checkbox"] {\n width: 1rem;\n height: 1rem;\n accent-color: var(--color-accent-blue);\n}\n\n.szenen-elements__list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-elements__list > li > button {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: var(--space-xs) var(--space-sm);\n width: 100%;\n height: 100%;\n text-align: left;\n}\n\n.szenen-elements__list > li > button.is-selected,\n.szenen-elements__list > li > button[aria-current="true"] {\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-elements__type {\n color: var(--color-accent-blue);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-elements__title {\n color: var(--color-text-primary);\n font-size: 0.95rem;\n}\n\n.szenen-elements__technical {\n grid-column: 1 / -1;\n color: var(--color-text-tertiary);\n font-size: 0.72rem;\n}\n\n.szenen-elements__subtype,\n.szenen-elements__retired {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-elements__retired {\n color: var(--color-warning);\n}\n\n.szenen-elements__id {\n grid-column: 1 / -1;\n color: var(--color-text-tertiary);\n font-size: 0.72rem;\n}\n\n.szenen-detail {\n margin-top: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n@media (min-width: 761px) {\n .szenen-detail {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n }\n}\n\n.szenen-detail > header,\n.szenen-detail__heads,\n.szenen-detail__draft,\n.szenen-capability {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* .szenen-runs ist ein eigenst\xE4ndiger sichtbarer Bereich, beh\xE4lt Styling auf Desktop */\n@media (min-width: 761px) {\n .szenen-runs {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n }\n}\n\n@media (max-width: 760px) {\n .szenen-runs {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n}\n\n.szenen-detail__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin-bottom: 0;\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__heads ul,\n.szenen-scene-editor ul,\n.szenen-runs > ol,\n.szenen-capability > ul {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-detail__heads li,\n.szenen-scene-editor li,\n.szenen-runs > ol > li,\n.szenen-capability > ul > li {\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__field {\n margin-bottom: var(--space-md);\n}\n\n/* Stufe 6.7.2 (D-126) \u2014 Advanced-/Debug-Fl\xE4che f\xFCr die rohe, schema-getriebene\n * Feldliste einer Szene. Gestrichelt wie die anderen \u201EAngebot statt\n * Auskunft"-Bereiche, aber ohne Akzentfarbe: sie ist kein Vorschlag, sondern\n * ein Eskalationsweg. */\n.szenen-detail__technical {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__technical > summary {\n margin-bottom: var(--space-sm);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__technical[open] > summary {\n margin-bottom: var(--space-md);\n}\n\n.szenen-detail__field small,\n.szenen-capability small {\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__preview-errors,\n.szenen-detail__notice--error,\n.szenen-view [role="alert"] {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-detail__notice {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__notice--success,\n.szenen-view [data-tone="success"] {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n border-color: var(--color-accent-green);\n}\n\n.szenen-scene-editor {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-md);\n margin-bottom: 0;\n}\n\n.szenen-scene-editor > section {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* \u2500\u2500 Stufe 6.7.2 (D-126): Node-/Relationskarten \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Nodes und Beziehungen sind `<details>` \u2014 dieselbe Interaktionssprache wie\n * \u201ERohantwort (Diagnose)" und \u201EBilder zu diesem Lauf" in RunsPanel.tsx. Kopf\n * (immer sichtbar) tr\xE4gt Inhalt zuerst, Technik zuletzt; Body (nur bei\n * ge\xF6ffneter Karte) tr\xE4gt die Bearbeitungscontrols. Padding wandert von der\n * `<li>` in Kopf/Body, damit die Karte keinen doppelten Rand bekommt. */\n.szenen-scene-editor li {\n padding: 0;\n overflow: hidden;\n}\n\n.szenen-node-karte__kopf,\n.szenen-relation-karte__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-sm);\n padding: var(--space-sm);\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-node-karte__kopf::-webkit-details-marker,\n.szenen-relation-karte__kopf::-webkit-details-marker {\n display: none;\n}\n\n.szenen-node-karte__titel {\n flex: 1 1 12rem;\n min-width: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-node-karte__typ {\n flex: none;\n padding: 0.15rem 0.55rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n white-space: nowrap;\n}\n\n/* node_id klein, monospace, sekund\xE4r \u2014 sichtbar auch bei zugeklappter Karte,\n * aber optisch klar hinter Beschreibung und Typ. */\n.szenen-node-karte__meta {\n flex: 1 1 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n.szenen-node-karte__meta code {\n font-size: inherit;\n}\n\n.szenen-node-karte__body,\n.szenen-relation-karte__body {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-sm) var(--space-sm);\n border-top: 1px solid var(--color-border);\n}\n\n/* \xA74 \u2014 Prim\xE4raktion und destruktive Aktion optisch getrennt: \u201ENode/Beziehung\n * entfernen" bekommt einen eigenen, warnenden Ton statt gleichgewichtig neben\n * der normalen Bearbeitung zu stehen. */\n.szenen-node-karte__entfernen,\n.szenen-relation-karte__entfernen {\n justify-self: start;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-relation-karte__kopf {\n font-size: 0.9rem;\n}\n\n.szenen-relation-karte__kopf code {\n overflow-wrap: anywhere;\n}\n\n.szenen-relation-karte__pfeil {\n flex: none;\n color: var(--color-text-secondary);\n}\n\n/* Die Composer-\xD6ffner (\u201E+ Node hinzuf\xFCgen", \u201E+ Beziehung hinzuf\xFCgen") sind\n * Angebote, keine Ausk\xFCnfte \u2014 dasselbe gestrichelte Muster wie beim Folgelauf\n * und der Fehlerrettung (\xA73.3/\xA73.5). */\n.szenen-scene-editor__oeffnen {\n width: 100%;\n border-style: dashed;\n}\n\n.szenen-refpicker {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-sm) 0;\n padding: var(--space-sm) 0;\n border: none;\n border-radius: 0;\n}\n\n.szenen-refpicker legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-capability > ul > li {\n display: grid;\n grid-template-columns: minmax(10rem, 1fr) auto minmax(14rem, 2fr);\n align-items: start;\n gap: var(--space-sm);\n}\n\n.szenen-capability__state {\n padding: 0.1rem 0.5rem;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-capability__state--yes {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n}\n\n.szenen-capability__state--no {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n}\n\n.szenen-capability__state--unknown {\n color: #fef08a;\n background: rgba(234, 179, 8, 0.2);\n}\n\n.szenen-runs > ol > li {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-runs > ol > li > header {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n color: var(--color-text-secondary);\n}\n\n.szenen-runs > ol > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-runs > ol > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-runs details pre {\n max-height: 20rem;\n overflow: auto;\n padding: var(--space-sm);\n white-space: pre-wrap;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n}\n\n.szenen-media > section {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-media__lookup,\n.szenen-media__attach {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-media__lookup > label,\n.szenen-media__attach > label:first-child {\n flex: 1 1 18rem;\n}\n\n.szenen-media__list {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-media__list > li {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n@media (max-width: 760px) {\n .szenen-view {\n gap: var(--space-sm);\n }\n\n .szenen-view__intro {\n align-items: start;\n flex-direction: column;\n gap: var(--space-sm);\n padding: var(--space-md);\n }\n\n .szenen-view__intro h2 {\n font-size: 1.25rem;\n }\n\n .szenen-view__intro > div > p:last-child {\n font-size: 0.9rem;\n }\n\n .szenen-view__nav {\n position: sticky;\n top: 0;\n z-index: 2;\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-xs);\n padding: var(--space-xs);\n }\n\n .szenen-view__nav button {\n width: 100%;\n min-width: 0;\n min-height: 2.5rem;\n padding: 0.35rem 0.5rem;\n }\n\n\n .szenen-scene-editor {\n grid-template-columns: 1fr;\n }\n\n .szenen-capability > ul > li {\n grid-template-columns: 1fr;\n }\n\n .szenen-derive,\n .szenen-elements,\n .szenen-scene,\n .szenen-setup,\n .szenen-shot,\n .szenen-media,\n .szenen-runs {\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter,\n .szenen-elements__create {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter > label,\n .szenen-elements__create > input {\n width: 100%;\n min-width: 0;\n flex: none;\n }\n\n .szenen-elements__filter > label:first-child,\n .szenen-elements__create > input {\n grid-column: 1 / -1;\n }\n\n .szenen-elements__filter > label:has(input[type="checkbox"]) {\n flex: none;\n }\n\n .szenen-detail__actions,\n .szenen-runs__start,\n .szenen-scene-editor__add,\n .szenen-scene-editor__add-relation {\n align-items: stretch;\n flex-direction: column;\n }\n\n .szenen-runs__start > *,\n .szenen-scene-editor__add > *,\n .szenen-scene-editor__add-relation > * {\n width: 100%;\n flex: none;\n }\n}\n\n/* \u2500\u2500 Stufe 6.5: Rekonstruktion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich zeigt drei Dinge nebeneinander: den Vorschlag, das nicht\n * Ableitbare und die Widerspr\xFCche. Die Diagnosen sind deshalb bewusst nicht\n * kleiner gesetzt als der Vorschlag \u2014 wer sie \xFCbersieht, \xFCbernimmt Geratenes.\n */\n\n.szenen-derive {\n display: grid;\n gap: var(--space-md);\n}\n\n.szenen-form {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-field {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-field > span {\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-error {\n padding: var(--space-sm) var(--space-md);\n color: var(--color-danger);\n background: var(--color-accent-red-dim);\n border: 1px solid var(--color-accent-red);\n border-radius: var(--radius-sm);\n}\n\n.szenen-empty {\n padding: var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-diagnose {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-warning);\n border-radius: var(--radius-sm);\n}\n\n/* Ein Widerspruch ist der schwerste der drei Befunde: dort steht eine\n * Entscheidung aus, die das System bewusst nicht getroffen hat (D-74). */\n.szenen-diagnose--konflikt {\n border-left-color: var(--color-danger);\n}\n\n.szenen-diagnose > h4 {\n margin: 0 0 var(--space-sm);\n font-size: 0.9375rem;\n}\n\n.szenen-diagnose ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-proposal {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-proposal > h4 {\n margin: 0 0 var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.9375rem;\n}\n\n.szenen-proposal__payload {\n max-height: 18rem;\n margin: 0 0 var(--space-sm);\n padding: var(--space-sm);\n overflow: auto;\n /* Ein erzeugter Prompt ist ein einziger langer Satz \u2014 ohne Umbruch\n verschwindet er nach rechts aus dem Bild. JSON-Payloads bringen ihre\n eigenen Zeilenumbrueche mit und leiden nicht darunter. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-proposal__done {\n margin: var(--space-sm) 0 0;\n color: var(--color-success);\n}\n\n/* Die Belege eines Laufs: Rohantwort und Systemprompt. Zum Lesen und Kopieren,\n nicht zum Bedienen \u2014 deshalb voll markierbar und in Monospace. */\n.szenen-beleg__text {\n width: 100%;\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre;\n background: var(--color-bg-app);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n resize: vertical;\n}\n\n/* Der Folgelauf (D-87): abgesetzt, damit er nicht wie Teil des Ergebnisses\n aussieht \u2014 er ist eine Frage, keine Auskunft. */\n.szenen-folgelauf {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-folgelauf > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-run__herkunft {\n margin: 0 0 var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-muted, inherit);\n}\n\n/* Widerspricht das Modell, ist das das Wichtigste auf der Seite. */\n.szenen-diagnose--antwort {\n border-left: 3px solid var(--color-accent, var(--color-border));\n}\n\n/* Der Bildw\xE4hler (D-92) \u2014 Kacheln wie in den Labs, aber mit dem CSS dieser\n Ansicht: eine gemeinsame Komponente \xFCber zwei Dom\xE4nengrenzen w\xE4re eine\n Kopplung, die keiner gewollt hat. */\n.szenen-bildwahl__liste {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__liste button {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n width: 100%;\n padding: var(--space-sm);\n text-align: left;\n font-size: 0.8125rem;\n}\n\n.szenen-bildwahl__liste img {\n width: 100%;\n aspect-ratio: 1;\n object-fit: cover;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__gewaehlt {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__gewaehlt li {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-beleg__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details + details {\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details > summary {\n cursor: pointer;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Die Fehlerrettung (Stufe 6.6, A5) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Sie steht im Fehlerblock und muss trotzdem als Werkzeug lesbar sein, nicht\n * als weitere Fehlermeldung. Deshalb abgesetzt wie der Folgelauf \u2014 und aus\n * demselben Grund: Beides sind Angebote, keine Ausk\xFCnfte.\n *\n * Der wichtigste optische Punkt ist die Trennung von Original und\n * Arbeitskopie. Das Original bekommt den ruhigen, \u201Efesten" Hintergrund der\n * Belege; die Kopie sieht aus wie ein normales Eingabefeld, weil sie eines\n * ist. */\n.szenen-rettung {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-rettung > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-rettung textarea[readonly] {\n background: var(--color-bg-surface);\n color: var(--color-text-secondary);\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung textarea:not([readonly]) {\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0;\n}\n\n/* Ein Befund tr\xE4gt Code, Bezug und Meldung. Der Code steht klein und\n * monospaced davor: Er ist die Kennung, nicht die Aussage. */\n.szenen-diagnose__liste {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-diagnose__liste code {\n font-size: 0.8125rem;\n}\n\n.szenen-diagnose__liste > li[data-severity=\'warning\'] {\n color: var(--color-text-secondary);\n}\n\n/* \u2500\u2500 Die Draft-Kette (Stufe 6.6, C4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Hauptweg. Er steht nach den Einzel\xFCbernahmen und muss als das erkennbar\n * sein, was er ist: nicht eine weitere Option, sondern der k\xFCrzere Weg zum\n * selben Ziel. Deshalb durchgezogener Rahmen statt gestricheltem \u2014 er ist\n * Angebot **und** Empfehlung. */\n.szenen-kette {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-kette > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-kette ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0 0 var(--space-sm);\n padding-left: var(--space-md);\n}\n\n.szenen-kette code {\n font-size: 0.8125rem;\n}\n\n/* Ein Hinweis, der eine Bedingung erklaert \u2014 nicht rot, weil er kein Fehler\n ist, aber abgesetzt, weil er eine Folge hat. */\n.szenen-detail__hint {\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Stufe 6.7: Bilder am Prompt-Lauf (H0/H1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich tr\xE4gt zwei Dinge, die man nie verwechseln darf: den **Eingang**\n * (woraus der Prompt entstand) und den **Ausgang** (was daraus wurde). Sie\n * bekommen deshalb verschiedene Akzentkanten statt nur verschiedener\n * \xDCberschriften \u2014 wer schnell liest, sieht die Trennung, bevor er sie liest.\n */\n.szenen-bilder {\n display: grid;\n gap: var(--space-md);\n margin-top: var(--space-sm);\n}\n\n.szenen-bilder__eingang,\n.szenen-bilder__ausgang {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__eingang {\n border-left: 3px solid var(--color-accent-purple, var(--color-border));\n}\n\n.szenen-bilder__ausgang {\n border-left: 3px solid var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-bilder h5 {\n margin: 0;\n}\n\n.szenen-bilder__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: 0;\n align-items: baseline;\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-bilder__eingangsliste,\n.szenen-bilder__batchliste,\n.szenen-bilder__auftraege {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bilder__eingangsliste > li,\n.szenen-bilder__batchliste > li,\n.szenen-bilder__auftraege > li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n/* Ein unterbrochener Auftrag ist der Fall, f\xFCr den der Auftragssatz existiert.\n Er wird deshalb markiert \u2014 nicht rot, denn er ist kein Fehler, sondern eine\n offene Entscheidung. */\n.szenen-bilder__auftraege > li[data-status="started"] {\n border-left: 3px solid var(--color-warning);\n}\n\n.szenen-bilder__auftraege > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-bilder__auftraege > li[data-status="partial"] {\n border-left: 3px solid var(--color-accent-blue, var(--color-border));\n}\n\n.szenen-bilder__auftraege > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-bilder__eingangsliste img,\n.szenen-bilder__batchliste img {\n width: 4rem;\n height: 4rem;\n object-fit: cover;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batch {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* Die Aktionen stehen abgesetzt: Sie sind Angebote, keine Ausk\xFCnfte \u2014 dasselbe\n Muster wie beim Folgelauf und bei der Fehlerrettung. */\n.szenen-bilder__aktion {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__aktion > h5 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-bilder__aktion ol {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n font-size: 0.8125rem;\n}\n\n/* ==========================================================================\n STUFE 6.10 \u2014 ELEMENTEDITOR UND VERSIONSNAVIGATION\n ========================================================================== */\n\n/* \xA74.2 \u2014 vier Sachverhalte, vier Marken. Die Marken stehen in einer eigenen\n * Spalte, damit ANGEZEIGT + BEVORZUGT nebeneinander lesbar bleiben, statt sich\n * durch den Text zu schieben. */\n.szenen-detail__heads li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-version__titel {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n margin-right: auto;\n}\n\n/* V17 \u2014 Kennungen bleiben vollst\xE4ndig sichtbar, aber optisch sekund\xE4r. */\n.szenen-version__id,\n.szenen-ref__id,\n.szenen-detail__field-key {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-version__marken {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-version__marken > span {\n padding: 0.1rem 0.5rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.7rem;\n font-weight: 800;\n letter-spacing: 0.08em;\n}\n\n.szenen-version--angezeigt {\n border-color: var(--color-accent-teal, #2dd4bf) !important;\n}\n\n/* V9 \u2014 der Basiswechsel ist eine Entscheidung, keine Nebenwirkung. */\n.szenen-detail__confirm {\n display: grid;\n gap: var(--space-sm);\n margin: var(--space-md) 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-accent-amber, #f59e0b);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__confirm p {\n margin: 0;\n}\n\n/* Untergruppen aufgeklappter Objektfelder (`prompt_render_settings`). */\n.szenen-detail__group {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-md) 0;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group > legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-detail__field {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-detail__field > span {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n}\n\n/* Mehrfachauswahl und Listeneditoren. */\n.szenen-feld__mehrfach,\n.szenen-feld__liste,\n.szenen-feld__reflist,\n.szenen-feld__ref,\n.szenen-feld__zielmodell,\n.szenen-feld__kamera {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-feld__mehrfach > label,\n.szenen-feld__null {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-feld__liste-zeile {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__reflist ol {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-feld__reflist li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n padding: var(--space-xs) var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \xA76.1 \u2014 Titel und Typ zuerst, Kennungen daneben. */\n.szenen-ref__anzeige {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-ref__typ {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-ref__warn {\n padding: 0.1rem 0.5rem;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n/* \xA76.5 \u2014 abgeleitete Angaben, ausdr\xFCcklich nur Anzeige. */\n.szenen-detail__derived {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__derived dl {\n display: grid;\n grid-template-columns: minmax(10rem, auto) 1fr;\n gap: var(--space-xs) var(--space-sm);\n margin: 0;\n}\n\n.szenen-detail__derived dt {\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__derived dd {\n margin: 0;\n}\n\n.szenen-feld__abgeleitet {\n margin: 0;\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n}\n';
|
|
849
|
+
var SZENEN_VIEW_STYLES = '/* ==========================================================================\n SZENEN VIEW\n ========================================================================== */\n\n.szenen-view {\n display: grid;\n gap: var(--space-md);\n width: 100%;\n min-width: 0;\n font-family: var(--font-sans);\n padding: var(--space-md);\n}\n\n@media (max-width: 760px) {\n .szenen-view {\n padding: var(--space-sm);\n gap: var(--space-sm);\n }\n}\n\n.szenen-view__intro {\n display: flex;\n align-items: end;\n justify-content: space-between;\n gap: var(--space-md);\n padding: clamp(1rem, 3vw, 1.75rem);\n color: var(--color-text-primary);\n background:\n radial-gradient(circle at 85% 15%, rgba(45, 212, 191, 0.16), transparent 34%),\n linear-gradient(135deg, var(--color-bg-surface), var(--color-bg-elevated));\n border: 1px solid var(--color-border);\n border-radius: var(--radius-lg);\n}\n\n.szenen-view__intro h2,\n.szenen-view__intro p {\n margin: 0;\n}\n\n.szenen-view__intro h2 {\n margin-bottom: var(--space-xs);\n font-size: clamp(1.25rem, 4vw, 2rem);\n}\n\n.szenen-view__intro > div > p:last-child {\n max-width: 44rem;\n color: var(--color-text-secondary);\n}\n\n.szenen-view__eyebrow {\n margin-bottom: var(--space-xs) !important;\n color: var(--color-accent-teal, #2dd4bf);\n font-size: 0.72rem;\n font-weight: 800;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n}\n\n.szenen-view__step {\n flex: none;\n padding: 0.35rem 0.65rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.78rem;\n font-weight: 700;\n}\n\n.szenen-view__nav {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-view__nav button,\n.szenen-view button {\n min-height: 2.25rem;\n padding: 0.45rem 0.75rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n cursor: pointer;\n}\n\n.szenen-view button:hover:not(:disabled) {\n color: var(--color-text-primary);\n background: var(--color-bg-surface-hover);\n border-color: var(--color-border-hover);\n}\n\n.szenen-view button:focus-visible,\n.szenen-view input:focus-visible,\n.szenen-view select:focus-visible,\n.szenen-view textarea:focus-visible {\n outline: 2px solid var(--color-accent-blue);\n outline-offset: 2px;\n}\n\n.szenen-view button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.szenen-view__nav button.is-active,\n.szenen-view__nav button[aria-selected="true"] {\n color: var(--color-text-primary);\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-view__area {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-view__capability-note,\n.szenen-area__lead {\n margin: 0;\n padding: var(--space-sm) var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-accent-purple);\n border-radius: var(--radius-sm);\n}\n\n.szenen-view__host-notes {\n color: var(--color-text-secondary);\n}\n\n.szenen-view__host-notes > summary {\n cursor: pointer;\n font-size: 0.8rem;\n}\n\n.szenen-view input:not([type="checkbox"]),\n.szenen-view select,\n.szenen-view textarea {\n width: 100%;\n min-height: 2.25rem;\n padding: 0.5rem 0.65rem;\n color: var(--color-text-primary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font: inherit;\n}\n\n.szenen-view textarea {\n min-height: 7rem;\n resize: vertical;\n font-family: var(--font-mono);\n font-size: 0.8rem;\n}\n\n.szenen-view label {\n display: grid;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-view code,\n.szenen-view pre {\n font-family: var(--font-mono);\n overflow-wrap: anywhere;\n}\n\n.szenen-view h3,\n.szenen-view h4,\n.szenen-view h5 {\n margin-top: 0;\n}\n\n.szenen-view ul,\n.szenen-view ol {\n padding-left: 1.25rem;\n}\n\n.szenen-elements,\n.szenen-detail,\n.szenen-scene,\n.szenen-setup,\n.szenen-shot,\n.szenen-media,\n.szenen-runs {\n display: grid;\n gap: var(--space-md);\n min-width: 0;\n}\n\n/* Arbeitsoberflaeche: Liste links, Bearbeitung rechts.\n *\n * Breit stehen beide Spalten nebeneinander \u2014 die Auswahl bleibt sichtbar,\n * waehrend bearbeitet wird. Schmal rendert die Komponente nur eine der beiden;\n * hier steht deshalb keine Regel, die die andere versteckt. */\n@media (min-width: 761px) {\n .szenen-elements {\n grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);\n align-items: start;\n }\n\n .szenen-elements__master,\n .szenen-elements__detail {\n min-width: 0;\n }\n}\n\n.szenen-elements__master,\n.szenen-elements__detail {\n display: grid;\n gap: var(--space-sm);\n align-content: start;\n min-width: 0;\n}\n\n.szenen-elements__toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-sm);\n}\n\n.szenen-elements__heading {\n margin: 0;\n font-size: 1.05rem;\n}\n\n.szenen-elements__scope {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n min-width: 0;\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-elements__scope > select {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.szenen-elements__new {\n flex: none;\n font-weight: 700;\n}\n\n.szenen-elements__create {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-accent-blue);\n border-radius: var(--radius-sm);\n}\n\n.szenen-elements__create label {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-elements__create-actions {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n}\n\n.szenen-elements__options > summary {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n cursor: pointer;\n}\n\n.szenen-elements__back {\n justify-self: start;\n font-weight: 700;\n}\n\n.szenen-elements__empty-detail {\n margin: 0;\n color: var(--color-text-tertiary);\n}\n\n.szenen-elements__filter,\n.szenen-detail__actions,\n.szenen-runs__start,\n.szenen-scene-editor__add,\n.szenen-scene-editor__add-relation {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-elements__filter > label,\n.szenen-runs__start > label,\n.szenen-scene-editor__add > input {\n flex: 1 1 16rem;\n}\n\n.szenen-elements__filter > label:has(input[type="checkbox"]) {\n display: flex;\n flex: 1 1 16rem;\n flex-direction: row;\n align-items: center;\n}\n\n.szenen-elements__filter input[type="checkbox"] {\n width: 1rem;\n height: 1rem;\n accent-color: var(--color-accent-blue);\n}\n\n.szenen-elements__list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-elements__list > li > button {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs) var(--space-sm);\n width: 100%;\n height: 100%;\n text-align: left;\n}\n\n.szenen-elements__list > li > button > .szenen-elements__title {\n flex: 1 1 100%;\n}\n\n.szenen-elements__list > li > button.is-selected,\n.szenen-elements__list > li > button[aria-current="true"] {\n background: var(--color-accent-blue-dim);\n border-color: var(--color-accent-blue);\n}\n\n.szenen-elements__type {\n color: var(--color-accent-blue);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-elements__title {\n color: var(--color-text-primary);\n font-size: 0.95rem;\n}\n\n.szenen-elements__subtype,\n.szenen-elements__retired {\n color: var(--color-text-secondary);\n font-size: 0.75rem;\n}\n\n.szenen-elements__retired {\n color: var(--color-warning);\n}\n\n.szenen-detail {\n margin-top: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n@media (min-width: 761px) {\n .szenen-detail {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n }\n}\n\n.szenen-detail > header,\n.szenen-detail__heads,\n.szenen-detail__draft,\n.szenen-capability {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* .szenen-runs ist ein eigenst\xE4ndiger sichtbarer Bereich, beh\xE4lt Styling auf Desktop */\n@media (min-width: 761px) {\n .szenen-runs {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n }\n}\n\n@media (max-width: 760px) {\n .szenen-runs {\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n }\n}\n\n.szenen-detail__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin-bottom: 0;\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__heads ul,\n.szenen-scene-editor ul,\n.szenen-runs > ol,\n.szenen-capability > ul {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-detail__heads li,\n.szenen-scene-editor li,\n.szenen-runs > ol > li,\n.szenen-capability > ul > li {\n padding: var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__field {\n margin-bottom: var(--space-md);\n}\n\n/* Stufe 6.7.2 (D-126) \u2014 Advanced-/Debug-Fl\xE4che f\xFCr die rohe, schema-getriebene\n * Feldliste einer Szene. Gestrichelt wie die anderen \u201EAngebot statt\n * Auskunft"-Bereiche, aber ohne Akzentfarbe: sie ist kein Vorschlag, sondern\n * ein Eskalationsweg. */\n.szenen-detail__technical {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__technical > summary {\n margin-bottom: var(--space-sm);\n color: var(--color-text-secondary);\n font-weight: 600;\n cursor: pointer;\n}\n\n.szenen-detail__technical[open] > summary {\n margin-bottom: var(--space-md);\n}\n\n.szenen-detail__field small,\n.szenen-capability small {\n color: var(--color-text-tertiary);\n}\n\n.szenen-detail__preview-errors,\n.szenen-detail__notice--error,\n.szenen-view [role="alert"] {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-detail__notice {\n padding: var(--space-sm) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__notice--success,\n.szenen-view [data-tone="success"] {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n border-color: var(--color-accent-green);\n}\n\n.szenen-scene-editor {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-md);\n margin-bottom: 0;\n}\n\n.szenen-scene-editor > section {\n min-width: 0;\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n/* \u2500\u2500 Stufe 6.7.2 (D-126): Node-/Relationskarten \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Nodes und Beziehungen sind `<details>` \u2014 dieselbe Interaktionssprache wie\n * \u201ERohantwort (Diagnose)" und \u201EBilder zu diesem Lauf" in RunsPanel.tsx. Kopf\n * (immer sichtbar) tr\xE4gt Inhalt zuerst, Technik zuletzt; Body (nur bei\n * ge\xF6ffneter Karte) tr\xE4gt die Bearbeitungscontrols. Padding wandert von der\n * `<li>` in Kopf/Body, damit die Karte keinen doppelten Rand bekommt. */\n.szenen-scene-editor li {\n padding: 0;\n overflow: hidden;\n}\n\n.szenen-node-karte__kopf,\n.szenen-relation-karte__kopf {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs) var(--space-sm);\n padding: var(--space-sm);\n cursor: pointer;\n list-style: none;\n}\n\n.szenen-node-karte__kopf::-webkit-details-marker,\n.szenen-relation-karte__kopf::-webkit-details-marker {\n display: none;\n}\n\n.szenen-node-karte__titel {\n flex: 1 1 12rem;\n min-width: 0;\n color: var(--color-text-primary);\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n\n.szenen-node-karte__typ {\n flex: none;\n padding: 0.15rem 0.55rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n white-space: nowrap;\n}\n\n/* node_id klein, monospace, sekund\xE4r \u2014 sichtbar auch bei zugeklappter Karte,\n * aber optisch klar hinter Beschreibung und Typ. */\n.szenen-node-karte__meta {\n flex: 1 1 100%;\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n color: var(--color-text-tertiary);\n font-size: 0.75rem;\n}\n\n.szenen-node-karte__meta code {\n font-size: inherit;\n}\n\n.szenen-node-karte__body,\n.szenen-relation-karte__body {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-sm) var(--space-sm);\n border-top: 1px solid var(--color-border);\n}\n\n/* \xA74 \u2014 Prim\xE4raktion und destruktive Aktion optisch getrennt: \u201ENode/Beziehung\n * entfernen" bekommt einen eigenen, warnenden Ton statt gleichgewichtig neben\n * der normalen Bearbeitung zu stehen. */\n.szenen-node-karte__entfernen,\n.szenen-relation-karte__entfernen {\n justify-self: start;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-color: var(--color-accent-red);\n}\n\n.szenen-relation-karte__kopf {\n font-size: 0.9rem;\n}\n\n.szenen-relation-karte__kopf code {\n overflow-wrap: anywhere;\n}\n\n.szenen-relation-karte__pfeil {\n flex: none;\n color: var(--color-text-secondary);\n}\n\n/* Die Composer-\xD6ffner (\u201E+ Node hinzuf\xFCgen", \u201E+ Beziehung hinzuf\xFCgen") sind\n * Angebote, keine Ausk\xFCnfte \u2014 dasselbe gestrichelte Muster wie beim Folgelauf\n * und der Fehlerrettung (\xA73.3/\xA73.5). */\n.szenen-scene-editor__oeffnen {\n width: 100%;\n border-style: dashed;\n}\n\n.szenen-refpicker {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-sm) 0;\n padding: var(--space-sm) 0;\n border: none;\n border-radius: 0;\n}\n\n.szenen-refpicker legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-capability > ul > li {\n display: grid;\n grid-template-columns: minmax(10rem, 1fr) auto minmax(14rem, 2fr);\n align-items: start;\n gap: var(--space-sm);\n}\n\n.szenen-capability__state {\n padding: 0.1rem 0.5rem;\n border-radius: var(--radius-full);\n font-size: 0.75rem;\n font-weight: 700;\n text-transform: uppercase;\n}\n\n.szenen-capability__state--yes {\n color: #bbf7d0;\n background: var(--color-accent-green-dim);\n}\n\n.szenen-capability__state--no {\n color: #fecaca;\n background: var(--color-accent-red-dim);\n}\n\n.szenen-capability__state--unknown {\n color: #fef08a;\n background: rgba(234, 179, 8, 0.2);\n}\n\n.szenen-runs > ol > li {\n display: grid;\n gap: var(--space-sm);\n}\n\n.szenen-runs > ol > li > header {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n color: var(--color-text-secondary);\n}\n\n.szenen-runs > ol > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-runs > ol > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-runs details pre {\n max-height: 20rem;\n overflow: auto;\n padding: var(--space-sm);\n white-space: pre-wrap;\n color: var(--color-text-secondary);\n background: var(--color-bg-app);\n border-radius: var(--radius-sm);\n}\n\n.szenen-media > section {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-media__lookup,\n.szenen-media__attach {\n display: flex;\n flex-wrap: wrap;\n align-items: end;\n gap: var(--space-sm);\n}\n\n.szenen-media__lookup > label,\n.szenen-media__attach > label:first-child {\n flex: 1 1 18rem;\n}\n\n.szenen-media__list {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-media__list > li {\n display: grid;\n grid-template-columns: minmax(12rem, 1fr) auto auto auto;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n@media (max-width: 760px) {\n .szenen-view {\n gap: var(--space-sm);\n }\n\n .szenen-view__intro {\n align-items: start;\n flex-direction: column;\n gap: var(--space-sm);\n padding: var(--space-md);\n }\n\n .szenen-view__intro h2 {\n font-size: 1.25rem;\n }\n\n .szenen-view__intro > div > p:last-child {\n font-size: 0.9rem;\n }\n\n .szenen-view__nav {\n position: sticky;\n top: 0;\n z-index: 2;\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-xs);\n padding: var(--space-xs);\n }\n\n .szenen-view__nav button {\n width: 100%;\n min-width: 0;\n min-height: 2.5rem;\n padding: 0.35rem 0.5rem;\n }\n\n\n .szenen-scene-editor {\n grid-template-columns: 1fr;\n }\n\n .szenen-capability > ul > li {\n grid-template-columns: 1fr;\n }\n\n .szenen-derive,\n .szenen-elements,\n .szenen-scene,\n .szenen-setup,\n .szenen-shot,\n .szenen-media,\n .szenen-runs {\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-sm);\n }\n\n .szenen-elements__filter > label {\n width: 100%;\n min-width: 0;\n flex: none;\n }\n\n .szenen-elements__filter > label:has(input[type="checkbox"]) {\n flex: none;\n grid-column: 1 / -1;\n }\n\n /* Schmal ist die Liste eine Spalte, und die Auswahl fuehrt weiter \u2014 der\n * Eintrag ist deshalb ein Ziel fuer den Finger, keine Kachel. */\n .szenen-elements__list {\n grid-template-columns: minmax(0, 1fr);\n }\n\n .szenen-elements__list > li > button {\n min-height: 2.75rem;\n }\n\n .szenen-elements__back {\n justify-self: stretch;\n min-height: 2.5rem;\n }\n\n .szenen-detail__actions,\n .szenen-runs__start,\n .szenen-scene-editor__add,\n .szenen-scene-editor__add-relation {\n align-items: stretch;\n flex-direction: column;\n }\n\n .szenen-runs__start > *,\n .szenen-scene-editor__add > *,\n .szenen-scene-editor__add-relation > * {\n width: 100%;\n flex: none;\n }\n}\n\n/* \u2500\u2500 Stufe 6.5: Rekonstruktion \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich zeigt drei Dinge nebeneinander: den Vorschlag, das nicht\n * Ableitbare und die Widerspr\xFCche. Die Diagnosen sind deshalb bewusst nicht\n * kleiner gesetzt als der Vorschlag \u2014 wer sie \xFCbersieht, \xFCbernimmt Geratenes.\n */\n\n.szenen-derive {\n display: grid;\n gap: var(--space-md);\n}\n\n.szenen-form {\n display: grid;\n gap: var(--space-sm);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: 0;\n}\n\n.szenen-field {\n display: grid;\n gap: var(--space-xs);\n}\n\n.szenen-field > span {\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-error {\n padding: var(--space-sm) var(--space-md);\n color: var(--color-danger);\n background: var(--color-accent-red-dim);\n border: 1px solid var(--color-accent-red);\n border-radius: var(--radius-sm);\n}\n\n.szenen-empty {\n padding: var(--space-md);\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-diagnose {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-warning);\n border-radius: var(--radius-sm);\n}\n\n/* Ein Widerspruch ist der schwerste der drei Befunde: dort steht eine\n * Entscheidung aus, die das System bewusst nicht getroffen hat (D-74). */\n.szenen-diagnose--konflikt {\n border-left-color: var(--color-danger);\n}\n\n.szenen-diagnose > h4 {\n margin: 0 0 var(--space-sm);\n font-size: 0.9375rem;\n}\n\n.szenen-diagnose ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-proposal {\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n\n.szenen-proposal > h4 {\n margin: 0 0 var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.9375rem;\n}\n\n.szenen-proposal__payload {\n max-height: 18rem;\n margin: 0 0 var(--space-sm);\n padding: var(--space-sm);\n overflow: auto;\n /* Ein erzeugter Prompt ist ein einziger langer Satz \u2014 ohne Umbruch\n verschwindet er nach rechts aus dem Bild. JSON-Payloads bringen ihre\n eigenen Zeilenumbrueche mit und leiden nicht darunter. */\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-proposal__done {\n margin: var(--space-sm) 0 0;\n color: var(--color-success);\n}\n\n/* Die Belege eines Laufs: Rohantwort und Systemprompt. Zum Lesen und Kopieren,\n nicht zum Bedienen \u2014 deshalb voll markierbar und in Monospace. */\n.szenen-beleg__text {\n width: 100%;\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-family: var(--font-mono);\n font-size: 0.8125rem;\n line-height: 1.5;\n white-space: pre;\n background: var(--color-bg-app);\n color: var(--color-text);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n resize: vertical;\n}\n\n/* Der Folgelauf (D-87): abgesetzt, damit er nicht wie Teil des Ergebnisses\n aussieht \u2014 er ist eine Frage, keine Auskunft. */\n.szenen-folgelauf {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-folgelauf > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-run__herkunft {\n margin: 0 0 var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-muted, inherit);\n}\n\n/* Widerspricht das Modell, ist das das Wichtigste auf der Seite. */\n.szenen-diagnose--antwort {\n border-left: 3px solid var(--color-accent, var(--color-border));\n}\n\n/* Der Bildw\xE4hler (D-92) \u2014 zweistufig wie in den Labs, aber mit dem CSS dieser\n Ansicht: eine gemeinsame Komponente \xFCber zwei Dom\xE4nengrenzen w\xE4re eine\n Kopplung, die keiner gewollt hat.\n\n Die Kachel ist die Einheit, nicht die Textzeile. Der gemeldete Screenshot vom\n 2026-08-22 zeigte im Flow-Host sechs schmale Spalten mit langen Prompttexten;\n `minmax(7rem, 1fr)` plus ein quadratisches Bild h\xE4lt die Karte auch auf\n schmalen Displays greifbar. */\n.szenen-bildwahl__raster {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__raster button {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n width: 100%;\n padding: var(--space-sm);\n text-align: left;\n font-size: 0.8125rem;\n}\n\n/* Der Platz der Kachel steht, bevor das Bild da ist \u2014 sonst springt das ganze\n Raster, sobald die erste Vorschau eintrifft. */\n.szenen-bildkachel {\n display: block;\n width: 100%;\n aspect-ratio: 1;\n border-radius: var(--radius-sm);\n overflow: hidden;\n background: var(--color-bg-app);\n}\n\n.szenen-bildkachel img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.szenen-bildkachel__leer {\n display: block;\n width: 100%;\n height: 100%;\n background: linear-gradient(135deg, var(--color-bg-app), var(--color-bg-surface));\n}\n\n/* Wie viele Varianten das Werk hat \u2014 dieselbe Auskunft wie im LabImagePicker,\n und der Grund, warum ein Klick auf die Karte eine Galerie \xF6ffnet. */\n.szenen-bildwahl__anzahl {\n position: absolute;\n top: calc(var(--space-sm) + 0.25rem);\n right: calc(var(--space-sm) + 0.25rem);\n padding: 0.05rem 0.35rem;\n font-size: 0.6875rem;\n font-weight: 700;\n color: var(--color-text-primary);\n background: var(--color-bg-elevated);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bildwahl__nummer {\n font-size: 0.6875rem;\n color: var(--color-text-secondary);\n}\n\n/* Zwei Zeilen Titel, dann Schluss: Der Prompt eines Werkes ist oft mehrere\n hundert Zeichen lang und w\xE4re als Prim\xE4rdarstellung eine Textw\xFCste. */\n.szenen-bildwahl__titel {\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n line-height: 1.25;\n}\n\n.szenen-bildwahl__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n flex-wrap: wrap;\n margin-top: var(--space-sm);\n}\n\n.szenen-bildwahl__werktitel {\n font-size: 0.8125rem;\n color: var(--color-text-secondary);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.szenen-bildwahl__gewaehlt {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bildwahl__gewaehlt li {\n display: flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.25rem 0.5rem;\n font-size: 0.8125rem;\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n max-width: 100%;\n}\n\n/* Das gew\xE4hlte Bild wird best\xE4tigt, nicht nur benannt: eine kleine Vorschau\n neben dem Titel. */\n.szenen-bildwahl__gewaehlt .szenen-bildkachel {\n width: 2.5rem;\n flex: 0 0 auto;\n}\n\n.szenen-bildwahl__gewaehlt .szenen-bildwahl__titel {\n min-width: 0;\n max-width: 14rem;\n}\n\n.szenen-beleg__kopf {\n display: flex;\n align-items: center;\n gap: var(--space-sm);\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details + details {\n margin-top: var(--space-sm);\n}\n\n.szenen-diagnose > details > summary {\n cursor: pointer;\n font-weight: 600;\n}\n\n/* \u2500\u2500 Die Fehlerrettung (Stufe 6.6, A5) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Sie steht im Fehlerblock und muss trotzdem als Werkzeug lesbar sein, nicht\n * als weitere Fehlermeldung. Deshalb abgesetzt wie der Folgelauf \u2014 und aus\n * demselben Grund: Beides sind Angebote, keine Ausk\xFCnfte.\n *\n * Der wichtigste optische Punkt ist die Trennung von Original und\n * Arbeitskopie. Das Original bekommt den ruhigen, \u201Efesten" Hintergrund der\n * Belege; die Kopie sieht aus wie ein normales Eingabefeld, weil sie eines\n * ist. */\n.szenen-rettung {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-rettung > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-rettung textarea[readonly] {\n background: var(--color-bg-surface);\n color: var(--color-text-secondary);\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung textarea:not([readonly]) {\n font-family: var(--font-mono, monospace);\n font-size: 0.8125rem;\n}\n\n.szenen-rettung__aktionen {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: var(--space-sm) 0;\n}\n\n/* Ein Befund tr\xE4gt Code, Bezug und Meldung. Der Code steht klein und\n * monospaced davor: Er ist die Kennung, nicht die Aussage. */\n.szenen-diagnose__liste {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n}\n\n.szenen-diagnose__liste code {\n font-size: 0.8125rem;\n}\n\n.szenen-diagnose__liste > li[data-severity=\'warning\'] {\n color: var(--color-text-secondary);\n}\n\n/* \u2500\u2500 Die Draft-Kette (Stufe 6.6, C4) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Hauptweg. Er steht nach den Einzel\xFCbernahmen und muss als das erkennbar\n * sein, was er ist: nicht eine weitere Option, sondern der k\xFCrzere Weg zum\n * selben Ziel. Deshalb durchgezogener Rahmen statt gestricheltem \u2014 er ist\n * Angebot **und** Empfehlung. */\n.szenen-kette {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-left: 3px solid var(--color-accent, var(--color-border));\n border-radius: var(--radius-sm);\n}\n\n.szenen-kette > h4 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-kette ul {\n display: grid;\n gap: var(--space-xs);\n margin: 0 0 var(--space-sm);\n padding-left: var(--space-md);\n}\n\n.szenen-kette code {\n font-size: 0.8125rem;\n}\n\n/* Ein Hinweis, der eine Bedingung erklaert \u2014 nicht rot, weil er kein Fehler\n ist, aber abgesetzt, weil er eine Folge hat. */\n.szenen-detail__hint {\n margin: var(--space-sm) 0 0;\n padding: var(--space-sm);\n font-size: 0.875rem;\n color: var(--color-text-secondary);\n background: var(--color-bg-surface);\n border-left: 3px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \u2500\u2500 Stufe 6.7: Bilder am Prompt-Lauf (H0/H1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n *\n * Der Bereich tr\xE4gt zwei Dinge, die man nie verwechseln darf: den **Eingang**\n * (woraus der Prompt entstand) und den **Ausgang** (was daraus wurde). Sie\n * bekommen deshalb verschiedene Akzentkanten statt nur verschiedener\n * \xDCberschriften \u2014 wer schnell liest, sieht die Trennung, bevor er sie liest.\n */\n.szenen-bilder {\n display: grid;\n gap: var(--space-md);\n margin-top: var(--space-sm);\n}\n\n.szenen-bilder__eingang,\n.szenen-bilder__ausgang {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__eingang {\n border-left: 3px solid var(--color-accent-purple, var(--color-border));\n}\n\n.szenen-bilder__ausgang {\n border-left: 3px solid var(--color-accent-teal, var(--color-border));\n}\n\n.szenen-bilder h5 {\n margin: 0;\n}\n\n.szenen-bilder__ids {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-sm);\n margin: 0;\n align-items: baseline;\n color: var(--color-text-secondary);\n font-size: 0.875rem;\n}\n\n.szenen-bilder__eingangsliste,\n.szenen-bilder__batchliste,\n.szenen-bilder__auftraege {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-bilder__eingangsliste > li,\n.szenen-bilder__batchliste > li,\n.szenen-bilder__auftraege > li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n font-size: 0.8125rem;\n}\n\n/* Ein unterbrochener Auftrag ist der Fall, f\xFCr den der Auftragssatz existiert.\n Er wird deshalb markiert \u2014 nicht rot, denn er ist kein Fehler, sondern eine\n offene Entscheidung. */\n.szenen-bilder__auftraege > li[data-status="started"] {\n border-left: 3px solid var(--color-warning);\n}\n\n.szenen-bilder__auftraege > li[data-status="succeeded"] {\n border-left: 3px solid var(--color-success);\n}\n\n.szenen-bilder__auftraege > li[data-status="partial"] {\n border-left: 3px solid var(--color-accent-blue, var(--color-border));\n}\n\n.szenen-bilder__auftraege > li[data-status="failed"] {\n border-left: 3px solid var(--color-danger);\n}\n\n.szenen-bilder__eingangsliste img,\n.szenen-bilder__batchliste img {\n width: 4rem;\n height: 4rem;\n object-fit: cover;\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__batch {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm);\n background: var(--color-bg-app);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* Die Aktionen stehen abgesetzt: Sie sind Angebote, keine Ausk\xFCnfte \u2014 dasselbe\n Muster wie beim Folgelauf und bei der Fehlerrettung. */\n.szenen-bilder__aktion {\n display: grid;\n gap: var(--space-sm);\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px dashed var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-bilder__aktion > h5 {\n margin: var(--space-sm) 0 0;\n}\n\n.szenen-bilder__aktion ol {\n display: grid;\n gap: var(--space-sm);\n margin: 0;\n padding-left: var(--space-md);\n font-size: 0.8125rem;\n}\n\n/* ==========================================================================\n STUFE 6.10 \u2014 ELEMENTEDITOR UND VERSIONSNAVIGATION\n ========================================================================== */\n\n/* \xA74.2 \u2014 vier Sachverhalte, vier Marken. Die Marken stehen in einer eigenen\n * Spalte, damit ANGEZEIGT + BEVORZUGT nebeneinander lesbar bleiben, statt sich\n * durch den Text zu schieben. */\n.szenen-detail__heads li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-sm);\n}\n\n.szenen-version__titel {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n margin-right: auto;\n}\n\n/* V17 \u2014 Kennungen bleiben vollst\xE4ndig sichtbar, aber optisch sekund\xE4r. */\n.szenen-version__id,\n.szenen-ref__id,\n.szenen-detail__field-key {\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n overflow-wrap: anywhere;\n}\n\n.szenen-version__marken {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-version__marken > span {\n padding: 0.1rem 0.5rem;\n color: var(--color-text-primary);\n background: rgba(45, 212, 191, 0.12);\n border: 1px solid rgba(45, 212, 191, 0.35);\n border-radius: var(--radius-full);\n font-size: 0.7rem;\n font-weight: 800;\n letter-spacing: 0.08em;\n}\n\n.szenen-version--angezeigt {\n border-color: var(--color-accent-teal, #2dd4bf) !important;\n}\n\n/* V9 \u2014 der Basiswechsel ist eine Entscheidung, keine Nebenwirkung. */\n.szenen-detail__confirm {\n display: grid;\n gap: var(--space-sm);\n margin: var(--space-md) 0;\n padding: var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-accent-amber, #f59e0b);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__confirm p {\n margin: 0;\n}\n\n/* Untergruppen aufgeklappter Objektfelder (`prompt_render_settings`). */\n.szenen-detail__group {\n display: grid;\n gap: var(--space-sm);\n min-width: 0;\n margin: var(--space-md) 0;\n padding: var(--space-sm) var(--space-md) var(--space-md);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__group > legend {\n padding: 0 var(--space-xs);\n color: var(--color-text-secondary);\n font-weight: 600;\n}\n\n.szenen-detail__field {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-detail__field > span {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n}\n\n/* Mehrfachauswahl und Listeneditoren. */\n.szenen-feld__mehrfach,\n.szenen-feld__liste,\n.szenen-feld__reflist,\n.szenen-feld__ref,\n.szenen-feld__zielmodell,\n.szenen-feld__kamera {\n display: grid;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-feld__mehrfach > label,\n.szenen-feld__null {\n display: flex;\n align-items: center;\n gap: var(--space-xs);\n color: var(--color-text-secondary);\n font-size: 0.85rem;\n}\n\n.szenen-feld__liste-zeile {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-xs);\n}\n\n.szenen-feld__reflist ol {\n display: grid;\n gap: var(--space-xs);\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.szenen-feld__reflist li {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-xs);\n padding: var(--space-xs) var(--space-sm);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n/* \xA76.1 \u2014 Titel und Typ zuerst, Kennungen daneben. */\n.szenen-ref__anzeige {\n display: inline-flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-xs);\n min-width: 0;\n}\n\n.szenen-ref__typ {\n color: var(--color-text-secondary);\n font-size: 0.8rem;\n}\n\n.szenen-ref__warn {\n padding: 0.1rem 0.5rem;\n color: #fecaca;\n background: var(--color-accent-red-dim);\n border-radius: var(--radius-full);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n/* \xA76.5 \u2014 abgeleitete Angaben, ausdr\xFCcklich nur Anzeige. */\n.szenen-detail__derived {\n margin-top: var(--space-md);\n padding: var(--space-sm) var(--space-md);\n background: var(--color-bg-surface);\n border: 1px solid var(--color-border);\n border-radius: var(--radius-sm);\n}\n\n.szenen-detail__derived dl {\n display: grid;\n grid-template-columns: minmax(10rem, auto) 1fr;\n gap: var(--space-xs) var(--space-sm);\n margin: 0;\n}\n\n.szenen-detail__derived dt {\n color: var(--color-text-secondary);\n}\n\n.szenen-detail__derived dd {\n margin: 0;\n}\n\n.szenen-feld__abgeleitet {\n margin: 0;\n color: var(--color-text-tertiary);\n font-size: 0.78rem;\n}\n';
|
|
850
850
|
|
|
851
851
|
// src/lib/utils.ts
|
|
852
852
|
var getFormattedTimestamp = () => {
|
|
@@ -2225,7 +2225,7 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
|
|
|
2225
2225
|
}
|
|
2226
2226
|
|
|
2227
2227
|
// src/components/AvatarArchitectApp.tsx
|
|
2228
|
-
var
|
|
2228
|
+
var import_react49 = require("react");
|
|
2229
2229
|
|
|
2230
2230
|
// src/components/PromptTab.tsx
|
|
2231
2231
|
var import_react15 = require("react");
|
|
@@ -6532,7 +6532,7 @@ function FlowWorkspacePicker({
|
|
|
6532
6532
|
}
|
|
6533
6533
|
|
|
6534
6534
|
// src/features/szenen/SzenenView.tsx
|
|
6535
|
-
var
|
|
6535
|
+
var import_react48 = require("react");
|
|
6536
6536
|
|
|
6537
6537
|
// src/lib/szenen/viewPort.ts
|
|
6538
6538
|
function capabilitiesOf(port) {
|
|
@@ -6556,93 +6556,6 @@ async function callOptional(capability, operation) {
|
|
|
6556
6556
|
return operation();
|
|
6557
6557
|
}
|
|
6558
6558
|
|
|
6559
|
-
// src/features/szenen/szenenViewModel.ts
|
|
6560
|
-
var ALLE_BEREICHE = [
|
|
6561
|
-
{
|
|
6562
|
-
id: "derive",
|
|
6563
|
-
title: "0 \xB7 Rekonstruktion",
|
|
6564
|
-
description: "Aus einem Bild oder Prompt einen Szenenentwurf vorschlagen lassen."
|
|
6565
|
-
},
|
|
6566
|
-
{
|
|
6567
|
-
id: "elements",
|
|
6568
|
-
title: "1 \xB7 Bausteine",
|
|
6569
|
-
description: "Figuren, Orte, Stile und Regeln f\xFCr sp\xE4tere Bildprompts pflegen."
|
|
6570
|
-
},
|
|
6571
|
-
{
|
|
6572
|
-
id: "scene",
|
|
6573
|
-
title: "2 \xB7 Szene",
|
|
6574
|
-
description: "Aus Bausteinen eine konkrete Szene und ihre Beziehungen bauen."
|
|
6575
|
-
},
|
|
6576
|
-
{
|
|
6577
|
-
id: "setup",
|
|
6578
|
-
title: "3 \xB7 Bildaufbau",
|
|
6579
|
-
description: "Stil, Komposition und Kamera f\xFCr das sp\xE4tere Bild festlegen."
|
|
6580
|
-
},
|
|
6581
|
-
{
|
|
6582
|
-
id: "shot",
|
|
6583
|
-
title: "4 \xB7 Prompt",
|
|
6584
|
-
description: "Bildprompt erzeugen, Varianten vergleichen und als Item speichern."
|
|
6585
|
-
},
|
|
6586
|
-
{
|
|
6587
|
-
id: "media",
|
|
6588
|
-
title: "Referenzen",
|
|
6589
|
-
description: "Referenzmedien einer Elementversion ansehen und zuordnen."
|
|
6590
|
-
}
|
|
6591
|
-
];
|
|
6592
|
-
function areasFor(port) {
|
|
6593
|
-
const faehig = capabilitiesOf(port);
|
|
6594
|
-
return ALLE_BEREICHE.filter((bereich) => {
|
|
6595
|
-
if (bereich.id === "media") return faehig.media;
|
|
6596
|
-
if (bereich.id === "derive") return faehig.derivation;
|
|
6597
|
-
return true;
|
|
6598
|
-
});
|
|
6599
|
-
}
|
|
6600
|
-
function resolveArea(port, gewuenscht) {
|
|
6601
|
-
const verfuegbar = areasFor(port);
|
|
6602
|
-
if (gewuenscht && verfuegbar.some((b) => b.id === gewuenscht)) return gewuenscht;
|
|
6603
|
-
return verfuegbar.find((b) => b.id === "elements")?.id ?? verfuegbar[0].id;
|
|
6604
|
-
}
|
|
6605
|
-
function noticeFor(ergebnis, was) {
|
|
6606
|
-
switch (ergebnis.kind) {
|
|
6607
|
-
case "ok":
|
|
6608
|
-
return { tone: "ok", text: `${was}: erledigt.` };
|
|
6609
|
-
case "conflict": {
|
|
6610
|
-
const aktuell = ergebnis.actualRevision;
|
|
6611
|
-
return {
|
|
6612
|
-
tone: "conflict",
|
|
6613
|
-
text: `${was}: inzwischen von anderer Seite ge\xE4ndert` + (aktuell !== void 0 ? ` (aktueller Stand: Revision ${String(aktuell)})` : "") + ". Bitte neu laden und erneut versuchen."
|
|
6614
|
-
};
|
|
6615
|
-
}
|
|
6616
|
-
case "rejected": {
|
|
6617
|
-
const fehler4 = ergebnis.errors ?? [];
|
|
6618
|
-
const ungeprueft = ergebnis.unchecked ?? [];
|
|
6619
|
-
return {
|
|
6620
|
-
tone: "rejected",
|
|
6621
|
-
text: `${was}: abgelehnt \u2014 ${fehler4.length} Befund${fehler4.length === 1 ? "" : "e"}.`,
|
|
6622
|
-
details: [
|
|
6623
|
-
...fehler4.map((f) => `${f.path ?? "(ohne Pfad)"}: ${f.message ?? "ohne Meldung"}`),
|
|
6624
|
-
// Nicht verschweigen: was nicht geprüft wurde, ist nicht in Ordnung,
|
|
6625
|
-
// sondern ungeprüft.
|
|
6626
|
-
...ungeprueft.map((u) => `ungepr\xFCft: ${u}`)
|
|
6627
|
-
]
|
|
6628
|
-
};
|
|
6629
|
-
}
|
|
6630
|
-
case "unsupported":
|
|
6631
|
-
return {
|
|
6632
|
-
tone: "unsupported",
|
|
6633
|
-
text: `${was}: von diesem Host nicht angeboten (${String(ergebnis.capability ?? was)}). Das ist kein Fehler und kein vor\xFCbergehender Zustand.`
|
|
6634
|
-
};
|
|
6635
|
-
default:
|
|
6636
|
-
return {
|
|
6637
|
-
tone: "error",
|
|
6638
|
-
text: `${was}: ${String(ergebnis.message ?? "unbekannter Fehler")}`
|
|
6639
|
-
};
|
|
6640
|
-
}
|
|
6641
|
-
}
|
|
6642
|
-
|
|
6643
|
-
// src/features/szenen/areas/ElementsArea.tsx
|
|
6644
|
-
var import_react42 = require("react");
|
|
6645
|
-
|
|
6646
6559
|
// src/lib/szenen/jsonSchema.ts
|
|
6647
6560
|
var SUPPORTED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
6648
6561
|
"$ref",
|
|
@@ -9716,6 +9629,99 @@ function formatSchemaErrors(errors) {
|
|
|
9716
9629
|
return errors.map((e) => `${e.instancePath || "/"} ${e.message}`).join("; ");
|
|
9717
9630
|
}
|
|
9718
9631
|
|
|
9632
|
+
// src/features/szenen/szenenViewModel.ts
|
|
9633
|
+
var KEINE_BAUSTEINE = [
|
|
9634
|
+
"scene",
|
|
9635
|
+
"scene_setup",
|
|
9636
|
+
"shot"
|
|
9637
|
+
];
|
|
9638
|
+
var BAUSTEIN_TYPES = SZENEN_ELEMENT_TYPES.filter((typ) => !KEINE_BAUSTEINE.includes(typ));
|
|
9639
|
+
var ALLE_BEREICHE = [
|
|
9640
|
+
{
|
|
9641
|
+
id: "derive",
|
|
9642
|
+
title: "0 \xB7 Rekonstruktion",
|
|
9643
|
+
description: "Aus einem Bild oder Prompt einen Szenenentwurf vorschlagen lassen."
|
|
9644
|
+
},
|
|
9645
|
+
{
|
|
9646
|
+
id: "elements",
|
|
9647
|
+
title: "1 \xB7 Bausteine",
|
|
9648
|
+
description: "Figuren, Orte, Stile und Regeln f\xFCr sp\xE4tere Bildprompts pflegen."
|
|
9649
|
+
},
|
|
9650
|
+
{
|
|
9651
|
+
id: "scene",
|
|
9652
|
+
title: "2 \xB7 Szene",
|
|
9653
|
+
description: "Aus Bausteinen eine konkrete Szene und ihre Beziehungen bauen."
|
|
9654
|
+
},
|
|
9655
|
+
{
|
|
9656
|
+
id: "setup",
|
|
9657
|
+
title: "3 \xB7 Bildaufbau",
|
|
9658
|
+
description: "Stil, Komposition und Kamera f\xFCr das sp\xE4tere Bild festlegen."
|
|
9659
|
+
},
|
|
9660
|
+
{
|
|
9661
|
+
id: "shot",
|
|
9662
|
+
title: "4 \xB7 Prompt",
|
|
9663
|
+
description: "Bildprompt erzeugen, Varianten vergleichen und als Item speichern."
|
|
9664
|
+
},
|
|
9665
|
+
{
|
|
9666
|
+
id: "media",
|
|
9667
|
+
title: "Referenzen",
|
|
9668
|
+
description: "Referenzmedien einer Elementversion ansehen und zuordnen."
|
|
9669
|
+
}
|
|
9670
|
+
];
|
|
9671
|
+
function areasFor(port) {
|
|
9672
|
+
const faehig = capabilitiesOf(port);
|
|
9673
|
+
return ALLE_BEREICHE.filter((bereich) => {
|
|
9674
|
+
if (bereich.id === "media") return faehig.media;
|
|
9675
|
+
if (bereich.id === "derive") return faehig.derivation;
|
|
9676
|
+
return true;
|
|
9677
|
+
});
|
|
9678
|
+
}
|
|
9679
|
+
function resolveArea(port, gewuenscht) {
|
|
9680
|
+
const verfuegbar = areasFor(port);
|
|
9681
|
+
if (gewuenscht && verfuegbar.some((b) => b.id === gewuenscht)) return gewuenscht;
|
|
9682
|
+
return verfuegbar.find((b) => b.id === "elements")?.id ?? verfuegbar[0].id;
|
|
9683
|
+
}
|
|
9684
|
+
function noticeFor(ergebnis, was) {
|
|
9685
|
+
switch (ergebnis.kind) {
|
|
9686
|
+
case "ok":
|
|
9687
|
+
return { tone: "ok", text: `${was}: erledigt.` };
|
|
9688
|
+
case "conflict": {
|
|
9689
|
+
const aktuell = ergebnis.actualRevision;
|
|
9690
|
+
return {
|
|
9691
|
+
tone: "conflict",
|
|
9692
|
+
text: `${was}: inzwischen von anderer Seite ge\xE4ndert` + (aktuell !== void 0 ? ` (aktueller Stand: Revision ${String(aktuell)})` : "") + ". Bitte neu laden und erneut versuchen."
|
|
9693
|
+
};
|
|
9694
|
+
}
|
|
9695
|
+
case "rejected": {
|
|
9696
|
+
const fehler4 = ergebnis.errors ?? [];
|
|
9697
|
+
const ungeprueft = ergebnis.unchecked ?? [];
|
|
9698
|
+
return {
|
|
9699
|
+
tone: "rejected",
|
|
9700
|
+
text: `${was}: abgelehnt \u2014 ${fehler4.length} Befund${fehler4.length === 1 ? "" : "e"}.`,
|
|
9701
|
+
details: [
|
|
9702
|
+
...fehler4.map((f) => `${f.path ?? "(ohne Pfad)"}: ${f.message ?? "ohne Meldung"}`),
|
|
9703
|
+
// Nicht verschweigen: was nicht geprüft wurde, ist nicht in Ordnung,
|
|
9704
|
+
// sondern ungeprüft.
|
|
9705
|
+
...ungeprueft.map((u) => `ungepr\xFCft: ${u}`)
|
|
9706
|
+
]
|
|
9707
|
+
};
|
|
9708
|
+
}
|
|
9709
|
+
case "unsupported":
|
|
9710
|
+
return {
|
|
9711
|
+
tone: "unsupported",
|
|
9712
|
+
text: `${was}: von diesem Host nicht angeboten (${String(ergebnis.capability ?? was)}). Das ist kein Fehler und kein vor\xFCbergehender Zustand.`
|
|
9713
|
+
};
|
|
9714
|
+
default:
|
|
9715
|
+
return {
|
|
9716
|
+
tone: "error",
|
|
9717
|
+
text: `${was}: ${String(ergebnis.message ?? "unbekannter Fehler")}`
|
|
9718
|
+
};
|
|
9719
|
+
}
|
|
9720
|
+
}
|
|
9721
|
+
|
|
9722
|
+
// src/features/szenen/areas/ElementsArea.tsx
|
|
9723
|
+
var import_react43 = require("react");
|
|
9724
|
+
|
|
9719
9725
|
// src/features/szenen/areas/usePortQuery.ts
|
|
9720
9726
|
var import_react33 = require("react");
|
|
9721
9727
|
function usePortQuery(frage, abhaengigkeiten) {
|
|
@@ -9748,6 +9754,32 @@ function usePortQuery(frage, abhaengigkeiten) {
|
|
|
9748
9754
|
// src/features/szenen/areas/ElementDetail.tsx
|
|
9749
9755
|
var import_react41 = require("react");
|
|
9750
9756
|
|
|
9757
|
+
// src/features/szenen/elementLabels.ts
|
|
9758
|
+
var LABELS = {
|
|
9759
|
+
scene_component: { singular: "Szenenbaustein", plural: "Szenenbausteine" },
|
|
9760
|
+
scene: { singular: "Szene", plural: "Szenen" },
|
|
9761
|
+
shot_concept: { singular: "Prompt-Idee", plural: "Prompt-Ideen" },
|
|
9762
|
+
camera_preset: { singular: "Kamera", plural: "Kameras" },
|
|
9763
|
+
camera_pattern: { singular: "Kamera-Muster", plural: "Kamera-Muster" },
|
|
9764
|
+
style: { singular: "Stil", plural: "Stile" },
|
|
9765
|
+
scene_setup: { singular: "Bildaufbau", plural: "Bildaufbauten" },
|
|
9766
|
+
shot: { singular: "Prompt", plural: "Prompts" },
|
|
9767
|
+
prompt_policy: { singular: "Prompt-Regel", plural: "Prompt-Regeln" },
|
|
9768
|
+
prompt_fragment: { singular: "Prompt-Baustein", plural: "Prompt-Bausteine" },
|
|
9769
|
+
target_model: { singular: "Zielmodell", plural: "Zielmodelle" },
|
|
9770
|
+
sequence: { singular: "Sequenz", plural: "Sequenzen" },
|
|
9771
|
+
scene_derivation_policy: {
|
|
9772
|
+
singular: "Rekonstruktions-Regel",
|
|
9773
|
+
plural: "Rekonstruktions-Regeln"
|
|
9774
|
+
}
|
|
9775
|
+
};
|
|
9776
|
+
function elementTypLabel(typ) {
|
|
9777
|
+
return LABELS[typ]?.singular ?? typ;
|
|
9778
|
+
}
|
|
9779
|
+
function elementTypPlural(typ) {
|
|
9780
|
+
return LABELS[typ]?.plural ?? typ;
|
|
9781
|
+
}
|
|
9782
|
+
|
|
9751
9783
|
// src/features/szenen/schemaForm.ts
|
|
9752
9784
|
var FORM_JE_REF = {
|
|
9753
9785
|
"common.schema.json#/$defs/slug": "slug",
|
|
@@ -10351,7 +10383,7 @@ var SEMANTIK = {
|
|
|
10351
10383
|
function feldSemantik(type, pfad) {
|
|
10352
10384
|
return SEMANTIK[`${type}.${pfad}`] ?? null;
|
|
10353
10385
|
}
|
|
10354
|
-
var
|
|
10386
|
+
var LABELS2 = {
|
|
10355
10387
|
key: "Kennung",
|
|
10356
10388
|
name: "Name",
|
|
10357
10389
|
text: "Text",
|
|
@@ -10396,7 +10428,7 @@ var LABELS = {
|
|
|
10396
10428
|
properties: "Zusatzangaben"
|
|
10397
10429
|
};
|
|
10398
10430
|
function feldLabel(type, pfad, name) {
|
|
10399
|
-
return feldSemantik(type, pfad)?.label ??
|
|
10431
|
+
return feldSemantik(type, pfad)?.label ?? LABELS2[name] ?? name;
|
|
10400
10432
|
}
|
|
10401
10433
|
|
|
10402
10434
|
// src/lib/szenen/imageGenerationCapability.ts
|
|
@@ -10424,6 +10456,22 @@ function checkImageExecutionProfile(profile) {
|
|
|
10424
10456
|
}
|
|
10425
10457
|
return befunde;
|
|
10426
10458
|
}
|
|
10459
|
+
function checkImageExecutionProfiles(profiles) {
|
|
10460
|
+
const anzahlJeKennung = /* @__PURE__ */ new Map();
|
|
10461
|
+
for (const profil of profiles ?? []) {
|
|
10462
|
+
if (!isObject3(profil) || !istText(profil.profile_id)) continue;
|
|
10463
|
+
anzahlJeKennung.set(profil.profile_id, (anzahlJeKennung.get(profil.profile_id) ?? 0) + 1);
|
|
10464
|
+
}
|
|
10465
|
+
return (profiles ?? []).map((profil) => {
|
|
10466
|
+
const befunde = [...checkImageExecutionProfile(profil)];
|
|
10467
|
+
if (isObject3(profil) && istText(profil.profile_id) && (anzahlJeKennung.get(profil.profile_id) ?? 0) > 1) {
|
|
10468
|
+
befunde.push(
|
|
10469
|
+
`Die profile_id "${profil.profile_id}" kommt in diesem Zielmodell mehrfach vor \u2014 die Auswahl waere nicht mehr eindeutig aufloesbar.`
|
|
10470
|
+
);
|
|
10471
|
+
}
|
|
10472
|
+
return befunde;
|
|
10473
|
+
});
|
|
10474
|
+
}
|
|
10427
10475
|
function executableImageModels(promptTargetModelKey, targets, capability) {
|
|
10428
10476
|
const models = [];
|
|
10429
10477
|
const invalid = [];
|
|
@@ -10437,8 +10485,9 @@ function executableImageModels(promptTargetModelKey, targets, capability) {
|
|
|
10437
10485
|
};
|
|
10438
10486
|
}
|
|
10439
10487
|
for (const target of targets ?? []) {
|
|
10440
|
-
|
|
10441
|
-
|
|
10488
|
+
const profilBefunde = checkImageExecutionProfiles(target.executionProfiles ?? []);
|
|
10489
|
+
for (const [index, roh] of (target.executionProfiles ?? []).entries()) {
|
|
10490
|
+
const befunde = profilBefunde[index] ?? [];
|
|
10442
10491
|
if (befunde.length > 0) {
|
|
10443
10492
|
const kennung = isObject3(roh) && istText(roh.profile_id) ? roh.profile_id : "(ohne profile_id)";
|
|
10444
10493
|
invalid.push(`${target.key}/${kennung}: ${befunde.join(" ")}`);
|
|
@@ -10447,13 +10496,20 @@ function executableImageModels(promptTargetModelKey, targets, capability) {
|
|
|
10447
10496
|
const profil = roh;
|
|
10448
10497
|
if (!profil.enabled) continue;
|
|
10449
10498
|
if (!profil.environments.includes(capability.environment_id)) continue;
|
|
10450
|
-
|
|
10499
|
+
const weg = capability.execution_paths.find((r) => r.execution_path === profil.execution_path);
|
|
10500
|
+
if (!weg) continue;
|
|
10501
|
+
if (target.provider !== weg.provider) {
|
|
10502
|
+
invalid.push(
|
|
10503
|
+
`${target.key}/${profil.profile_id}: Das Zielmodell nennt den Anbieter ${target.provider === null ? "(keinen)" : `"${target.provider}"`}, der Aufrufweg "${weg.execution_path}" fuehrt aber zu "${weg.provider}".`
|
|
10504
|
+
);
|
|
10505
|
+
continue;
|
|
10506
|
+
}
|
|
10451
10507
|
models.push({
|
|
10452
10508
|
selection_id: `${target.key}#${profil.profile_id}`,
|
|
10453
10509
|
target_model_key: target.key,
|
|
10454
10510
|
...target.versionId ? { target_model_version_id: target.versionId } : {},
|
|
10455
10511
|
display_name: target.title,
|
|
10456
|
-
provider:
|
|
10512
|
+
provider: weg.provider,
|
|
10457
10513
|
profile_id: profil.profile_id,
|
|
10458
10514
|
environment_id: capability.environment_id,
|
|
10459
10515
|
execution_path: profil.execution_path,
|
|
@@ -10472,7 +10528,7 @@ function executableImageModels(promptTargetModelKey, targets, capability) {
|
|
|
10472
10528
|
models: [],
|
|
10473
10529
|
default_selection_id: null,
|
|
10474
10530
|
invalid_profiles: invalid,
|
|
10475
|
-
reason: `In dieser Umgebung (${capability.environment_id}) traegt kein sichtbares Zielmodell ein aktives Ausfuehrungsprofil fuer einen Aufrufweg dieses Hosts (${capability.execution_paths.join(", ") || "keiner"}).`
|
|
10531
|
+
reason: `In dieser Umgebung (${capability.environment_id}) traegt kein sichtbares Zielmodell ein aktives Ausfuehrungsprofil fuer einen Aufrufweg dieses Hosts (${capability.execution_paths.map((r) => r.execution_path).join(", ") || "keiner"}).`
|
|
10476
10532
|
};
|
|
10477
10533
|
}
|
|
10478
10534
|
const passend = models.find((m) => m.is_prompt_target);
|
|
@@ -11214,6 +11270,7 @@ var AusfuehrungsprofileFeld = ({ feld, wert, onChange, readOnly }) => {
|
|
|
11214
11270
|
const profile = (gelesen ?? []).filter(isObject4);
|
|
11215
11271
|
const unlesbar = gelesen === null;
|
|
11216
11272
|
const schreibe = (neu) => onChange(feld.path, schreibListe(neu));
|
|
11273
|
+
const alleBefunde = checkImageExecutionProfiles(profile);
|
|
11217
11274
|
const aendere = (index, patch) => schreibe(profile.map((p, i) => i === index ? { ...p, ...patch } : p));
|
|
11218
11275
|
if (unlesbar) {
|
|
11219
11276
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { role: "alert", "data-testid": `feld-${feld.path}-unlesbar`, children: "Der gespeicherte Wert ist keine Profilliste. Er bleibt unver\xE4ndert stehen; bitte an der Quelle korrigieren." });
|
|
@@ -11221,7 +11278,7 @@ var AusfuehrungsprofileFeld = ({ feld, wert, onChange, readOnly }) => {
|
|
|
11221
11278
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { className: "szenen-feld__profile", "data-testid": `feld-${feld.path}`, children: [
|
|
11222
11279
|
profile.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { "data-testid": `feld-${feld.path}-keine`, children: "Dieses Zielmodell wird f\xFCr die Prompt-Optimierung verwendet und ist derzeit nicht direkt aus der App aufrufbar." }),
|
|
11223
11280
|
profile.map((profil, index) => {
|
|
11224
|
-
const befunde =
|
|
11281
|
+
const befunde = alleBefunde[index] ?? [];
|
|
11225
11282
|
const text = (schluessel) => typeof profil[schluessel] === "string" ? profil[schluessel] : "";
|
|
11226
11283
|
const liste = (schluessel) => Array.isArray(profil[schluessel]) ? profil[schluessel].join(", ") : "";
|
|
11227
11284
|
return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("fieldset", { "data-testid": `profil-${index}`, className: "szenen-feld__profil", children: [
|
|
@@ -12700,6 +12757,93 @@ function finish(report) {
|
|
|
12700
12757
|
};
|
|
12701
12758
|
}
|
|
12702
12759
|
|
|
12760
|
+
// src/lib/szenen/promptOperation.ts
|
|
12761
|
+
var PROMPT_RULE_EFFECT = {
|
|
12762
|
+
"P-01": "diagnostic",
|
|
12763
|
+
// Kamera-ID im Rig nicht auflösbar → ohne Kamera weiter
|
|
12764
|
+
"P-02": "diagnostic",
|
|
12765
|
+
// mehrdeutige Kamera-ID → erklären, nicht sperren
|
|
12766
|
+
"P-03": "diagnostic",
|
|
12767
|
+
// Abstammungsintegrität einer camera_id — Publish-Frage
|
|
12768
|
+
"P-04": "diagnostic",
|
|
12769
|
+
// referenzierte Version nicht veröffentlicht/sichtbar
|
|
12770
|
+
"P-05": "diagnostic",
|
|
12771
|
+
// Node-Referenz nicht auflösbar → Teil auslassen
|
|
12772
|
+
"P-06": "diagnostic",
|
|
12773
|
+
// Placement-Node mehrdeutig → ohne exakte Platzierung
|
|
12774
|
+
"P-07": "diagnostic",
|
|
12775
|
+
// spatial Pattern ohne can_place → Pattern weglassen
|
|
12776
|
+
"P-08": "diagnostic",
|
|
12777
|
+
// unvollständige Pattern-Bindings
|
|
12778
|
+
"P-09": "not_applicable",
|
|
12779
|
+
// reine Publish-/Prozessregel für sequence
|
|
12780
|
+
"P-10": "diagnostic",
|
|
12781
|
+
// Zyklus: Blocker nur, wenn keine endliche Auflösung bleibt
|
|
12782
|
+
"P-11": "diagnostic",
|
|
12783
|
+
// Override-Disziplin, schon bisher advisory
|
|
12784
|
+
"P-12": "not_applicable",
|
|
12785
|
+
// Laufzeitregel der Auflösung, keine Bedingung
|
|
12786
|
+
"P-13": "diagnostic",
|
|
12787
|
+
// pattern_derived ohne Pattern-Platzierung
|
|
12788
|
+
"P-14": "diagnostic",
|
|
12789
|
+
// Bildgrößen-/Optik-Plausibilität, erklärte Absicht gewinnt
|
|
12790
|
+
"P-15": "diagnostic",
|
|
12791
|
+
// vertikaler look_at ohne up_hint — Rollwinkel ist Spezialpräzision
|
|
12792
|
+
"P-16": "diagnostic",
|
|
12793
|
+
// Placements ohne Koordinatensystem
|
|
12794
|
+
"P-17": "diagnostic"
|
|
12795
|
+
// Target Model nicht auflösbar → generischer Prompt
|
|
12796
|
+
};
|
|
12797
|
+
function diagnosticOfFinding(finding) {
|
|
12798
|
+
return {
|
|
12799
|
+
code: finding.rule,
|
|
12800
|
+
origin: "rule",
|
|
12801
|
+
path: finding.path,
|
|
12802
|
+
message: finding.message
|
|
12803
|
+
};
|
|
12804
|
+
}
|
|
12805
|
+
function diagnosticOfSchemaError(error, where) {
|
|
12806
|
+
return {
|
|
12807
|
+
code: "schema",
|
|
12808
|
+
origin: "schema",
|
|
12809
|
+
path: error.instancePath || "/",
|
|
12810
|
+
message: `${where}: ${error.message}`
|
|
12811
|
+
};
|
|
12812
|
+
}
|
|
12813
|
+
function promptDiagnosticsOf(checks) {
|
|
12814
|
+
const befunde = [];
|
|
12815
|
+
for (const finding of checks.findings) {
|
|
12816
|
+
if (PROMPT_RULE_EFFECT[finding.rule] === "not_applicable") continue;
|
|
12817
|
+
befunde.push(diagnosticOfFinding(finding));
|
|
12818
|
+
}
|
|
12819
|
+
return befunde;
|
|
12820
|
+
}
|
|
12821
|
+
var isObject8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
12822
|
+
var asArray2 = (v) => Array.isArray(v) ? v : [];
|
|
12823
|
+
var istText2 = (v) => typeof v === "string" && v.trim().length > 0;
|
|
12824
|
+
function describableContent(scenePayload) {
|
|
12825
|
+
if (!isObject8(scenePayload)) {
|
|
12826
|
+
return {
|
|
12827
|
+
ok: false,
|
|
12828
|
+
message: `Die Szene ist kein Objekt, sondern ${Array.isArray(scenePayload) ? "ein Array" : typeof scenePayload}. Daraus laesst sich kein Textauftrag herstellen.`
|
|
12829
|
+
};
|
|
12830
|
+
}
|
|
12831
|
+
const nodes = asArray2(scenePayload.nodes);
|
|
12832
|
+
for (const node of nodes) {
|
|
12833
|
+
if (!isObject8(node)) continue;
|
|
12834
|
+
const semantic = isObject8(node.semantic) ? node.semantic : null;
|
|
12835
|
+
if (semantic && istText2(semantic.description)) return { ok: true };
|
|
12836
|
+
if (asArray2(node.component_refs).length > 0) return { ok: true };
|
|
12837
|
+
}
|
|
12838
|
+
const environment = isObject8(scenePayload.environment) ? scenePayload.environment : null;
|
|
12839
|
+
if (environment && istText2(environment.text)) return { ok: true };
|
|
12840
|
+
if (environment && asArray2(environment.component_refs).length > 0) return { ok: true };
|
|
12841
|
+
return {
|
|
12842
|
+
ok: false,
|
|
12843
|
+
message: nodes.length === 0 ? "Die Szene hat keine Knoten und keinen Umgebungstext. Ohne beschreibbaren Inhalt gibt es nichts, woraus ein Prompt entstehen koennte." : `Keiner der ${nodes.length} Knoten traegt eine Beschreibung oder eine Komponentenreferenz, und es gibt keinen Umgebungstext. Ein Prompt daraus waere eine leere Behauptung.`
|
|
12844
|
+
};
|
|
12845
|
+
}
|
|
12846
|
+
|
|
12703
12847
|
// src/lib/szenen/capabilities.ts
|
|
12704
12848
|
var CapabilityAnchorError = class extends Error {
|
|
12705
12849
|
};
|
|
@@ -12730,9 +12874,9 @@ var FLAG_OF_SCOPE = {
|
|
|
12730
12874
|
// die Vererbung an die beiden anderen weitergereicht.
|
|
12731
12875
|
global: "can_describe_scene"
|
|
12732
12876
|
};
|
|
12733
|
-
var
|
|
12877
|
+
var isObject9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
12734
12878
|
function nodeCountOf(scenePayload) {
|
|
12735
|
-
if (!
|
|
12879
|
+
if (!isObject9(scenePayload)) return 0;
|
|
12736
12880
|
return Array.isArray(scenePayload.nodes) ? scenePayload.nodes.length : 0;
|
|
12737
12881
|
}
|
|
12738
12882
|
async function capabilityReport(input) {
|
|
@@ -12757,7 +12901,7 @@ async function capabilityReport(input) {
|
|
|
12757
12901
|
reason: "Payload verletzt das Schema \u2014 die Publish-Regeln wurden nicht ausgefuehrt"
|
|
12758
12902
|
}))
|
|
12759
12903
|
} : await runPublishChecks({ type, payload: setupPayload, elementId, parents, resolver });
|
|
12760
|
-
if (!
|
|
12904
|
+
if (!isObject9(setupPayload)) {
|
|
12761
12905
|
const vorgefunden = Array.isArray(setupPayload) ? "array" : typeof setupPayload;
|
|
12762
12906
|
const reasons = [
|
|
12763
12907
|
{
|
|
@@ -12767,10 +12911,14 @@ async function capabilityReport(input) {
|
|
|
12767
12911
|
];
|
|
12768
12912
|
return {
|
|
12769
12913
|
can_describe_scene: { state: "no", reasons },
|
|
12914
|
+
// Auch fuer den Promptpfad ein echter Blocker: Eine Payload, die kein
|
|
12915
|
+
// Objekt ist, ist technisch unlesbar (Schritt 07, Klasse A/C) — nicht
|
|
12916
|
+
// bloss fachlich unvollstaendig.
|
|
12770
12917
|
can_render_prompt: { state: "no", reasons },
|
|
12771
12918
|
can_place: { state: "no", reasons },
|
|
12772
12919
|
checks,
|
|
12773
|
-
schemaErrors
|
|
12920
|
+
schemaErrors,
|
|
12921
|
+
promptDiagnostics: []
|
|
12774
12922
|
};
|
|
12775
12923
|
}
|
|
12776
12924
|
const blockedByScope = /* @__PURE__ */ new Map();
|
|
@@ -12806,6 +12954,8 @@ async function capabilityReport(input) {
|
|
|
12806
12954
|
};
|
|
12807
12955
|
const base = forFlag("can_describe_scene");
|
|
12808
12956
|
let describe;
|
|
12957
|
+
let szenenPayload = null;
|
|
12958
|
+
let sceneVersionId = null;
|
|
12809
12959
|
if (base.blocked.length > 0) {
|
|
12810
12960
|
describe = { state: "no", reasons: base.blocked };
|
|
12811
12961
|
} else if (schemaErrors.length > 0) {
|
|
@@ -12831,9 +12981,10 @@ async function capabilityReport(input) {
|
|
|
12831
12981
|
]
|
|
12832
12982
|
};
|
|
12833
12983
|
} else {
|
|
12834
|
-
const sceneRef =
|
|
12835
|
-
|
|
12984
|
+
const sceneRef = isObject9(setupPayload.scene_ref) ? setupPayload.scene_ref : null;
|
|
12985
|
+
sceneVersionId = typeof sceneRef?.version_id === "string" ? sceneRef.version_id : null;
|
|
12836
12986
|
const scene = chainScene !== void 0 ? { payload: chainScene } : sceneVersionId ? await resolver.getVersion(sceneVersionId) : null;
|
|
12987
|
+
if (scene) szenenPayload = { payload: scene.payload };
|
|
12837
12988
|
const nodes = nodeCountOf(scene?.payload);
|
|
12838
12989
|
if (nodes === 0) {
|
|
12839
12990
|
describe = {
|
|
@@ -12880,15 +13031,59 @@ async function capabilityReport(input) {
|
|
|
12880
13031
|
if (own.unchecked.length > 0) return { state: "unknown", reasons: own.unchecked };
|
|
12881
13032
|
return { state: "yes", reasons: [] };
|
|
12882
13033
|
};
|
|
13034
|
+
const promptFlag = (() => {
|
|
13035
|
+
if (!szenenPayload) {
|
|
13036
|
+
return {
|
|
13037
|
+
state: "unknown",
|
|
13038
|
+
reasons: [
|
|
13039
|
+
{
|
|
13040
|
+
kind: "structure",
|
|
13041
|
+
message: `Die Szene ${sceneVersionId ?? "(ohne version_id)"} wurde nicht gelesen; ob beschreibbarer Inhalt vorliegt, ist damit offen \u2014 keine Absage.`
|
|
13042
|
+
}
|
|
13043
|
+
]
|
|
13044
|
+
};
|
|
13045
|
+
}
|
|
13046
|
+
const inhalt = describableContent(szenenPayload.payload);
|
|
13047
|
+
if (!inhalt.ok) {
|
|
13048
|
+
return { state: "no", reasons: [{ kind: "structure", message: inhalt.message }] };
|
|
13049
|
+
}
|
|
13050
|
+
return { state: "yes", reasons: [] };
|
|
13051
|
+
})();
|
|
13052
|
+
const promptDiagnostics = [
|
|
13053
|
+
...schemaErrors.map((e) => diagnosticOfSchemaError(e, `Scene Setup ${elementId}`)),
|
|
13054
|
+
...promptDiagnosticsOf(checks)
|
|
13055
|
+
];
|
|
12883
13056
|
return {
|
|
12884
13057
|
can_describe_scene: describe,
|
|
12885
|
-
can_render_prompt:
|
|
13058
|
+
can_render_prompt: promptFlag,
|
|
12886
13059
|
can_place: derived("can_place", {
|
|
12887
13060
|
ok: hasPlacementCapability(setupPayload),
|
|
12888
13061
|
message: "Das Scene Setup traegt kein coordinate_system und ist damit nicht platzierbar (D-65)."
|
|
12889
13062
|
}),
|
|
12890
13063
|
checks,
|
|
12891
|
-
schemaErrors
|
|
13064
|
+
schemaErrors,
|
|
13065
|
+
promptDiagnostics
|
|
13066
|
+
};
|
|
13067
|
+
}
|
|
13068
|
+
function sceneOnlyCapabilities(scenePayload) {
|
|
13069
|
+
const knoten = nodeCountOf(scenePayload);
|
|
13070
|
+
const inhalt = describableContent(scenePayload);
|
|
13071
|
+
return {
|
|
13072
|
+
can_describe_scene: knoten > 0 ? { state: "yes", reasons: [] } : {
|
|
13073
|
+
state: "no",
|
|
13074
|
+
reasons: [{
|
|
13075
|
+
kind: "structure",
|
|
13076
|
+
message: "Die Szene hat keine Knoten. Ohne Knoten gibt es nichts zu beschreiben."
|
|
13077
|
+
}]
|
|
13078
|
+
},
|
|
13079
|
+
can_render_prompt: inhalt.ok ? { state: "yes", reasons: [] } : { state: "no", reasons: [{ kind: "structure", message: inhalt.message }] },
|
|
13080
|
+
can_place: {
|
|
13081
|
+
state: "no",
|
|
13082
|
+
reasons: [{
|
|
13083
|
+
kind: "structure",
|
|
13084
|
+
message: "Zu dieser Szene gehoert kein Scene Setup. Weltplatzierung und coordinate_system liegen ausschliesslich dort (D-39/D-65) \u2014 es gibt also keine belastbaren Koordinaten."
|
|
13085
|
+
}]
|
|
13086
|
+
}
|
|
12892
13087
|
};
|
|
12893
13088
|
}
|
|
12894
13089
|
|
|
@@ -13007,60 +13202,72 @@ var CapabilityPanel = ({ port, elementId, setupPayload }) => {
|
|
|
13007
13202
|
] });
|
|
13008
13203
|
};
|
|
13009
13204
|
|
|
13010
|
-
// src/features/szenen/areas/
|
|
13205
|
+
// src/features/szenen/areas/PromptStartAction.tsx
|
|
13011
13206
|
var import_react38 = require("react");
|
|
13012
13207
|
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
13013
|
-
var
|
|
13208
|
+
var PromptStartAction = ({
|
|
13014
13209
|
port,
|
|
13015
|
-
|
|
13210
|
+
source,
|
|
13211
|
+
hinweise = [],
|
|
13212
|
+
blocker = null,
|
|
13213
|
+
onLauf
|
|
13016
13214
|
}) => {
|
|
13017
13215
|
const [lauf, setLauf] = (0, import_react38.useState)(null);
|
|
13018
13216
|
const [meldung, setMeldung] = (0, import_react38.useState)(null);
|
|
13019
13217
|
const [ausgang, setAusgang] = (0, import_react38.useState)(null);
|
|
13020
13218
|
const [laeuft, setLaeuft] = (0, import_react38.useState)(false);
|
|
13021
13219
|
const runs = port.runs;
|
|
13220
|
+
const ausKette = source.kind === "draft_chain";
|
|
13221
|
+
const id = (name) => ausKette ? `kette-${name}` : `szene-${name}`;
|
|
13022
13222
|
async function erzeugen() {
|
|
13023
13223
|
setLaeuft(true);
|
|
13024
13224
|
setMeldung(null);
|
|
13025
13225
|
setAusgang(null);
|
|
13026
13226
|
try {
|
|
13027
|
-
const ergebnis = await runs.startRunFromDraft({ shotElementId });
|
|
13227
|
+
const ergebnis = source.kind === "draft_chain" ? await runs.startRunFromDraft({ shotElementId: source.shotElementId }) : await runs.startRunFromScene({ sceneElementId: source.sceneElementId });
|
|
13028
13228
|
if (ergebnis.kind !== "ok") {
|
|
13029
13229
|
setMeldung(ergebnis.kind === "unsupported" ? `Dieser Host kann "${ergebnis.capability}" nicht.` : ergebnis.message);
|
|
13030
13230
|
setAusgang(ergebnis.kind === "unsupported" ? "error" : ergebnis.kind);
|
|
13031
13231
|
return;
|
|
13032
13232
|
}
|
|
13033
13233
|
setLauf(ergebnis.value);
|
|
13234
|
+
onLauf?.();
|
|
13034
13235
|
} finally {
|
|
13035
13236
|
setLaeuft(false);
|
|
13036
13237
|
}
|
|
13037
13238
|
}
|
|
13038
|
-
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "szenen-kette", "data-testid": "
|
|
13039
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h5", { children: "Prompt aus der Draft-Kette" }),
|
|
13040
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.
|
|
13239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: "szenen-kette", "data-testid": id("prompt-aktion"), children: [
|
|
13240
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h5", { children: ausKette ? "Prompt aus der Draft-Kette" : "Prompt aus dieser Szene" }),
|
|
13241
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "szenen-area__lead", children: ausKette ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
13041
13242
|
"Dieser Shot geh\xF6rt zu einer Draft-Kette. Der Lauf friert Szene, Aufbau und Shot in dem Stand ein, den er gerade vorfindet \u2014",
|
|
13042
13243
|
" ",
|
|
13043
13244
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "ohne" }),
|
|
13044
13245
|
" dass etwas ver\xF6ffentlicht werden muss."
|
|
13045
|
-
] }),
|
|
13246
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_jsx_runtime33.Fragment, { children: [
|
|
13247
|
+
"Der Lauf friert diese Szene in dem Stand ein, den er gerade vorfindet. Bildaufbau, Kamera und Zielmodell sind ",
|
|
13248
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "nicht n\xF6tig" }),
|
|
13249
|
+
" \u2014 was fehlt, wird weggelassen und am Lauf festgehalten, nicht erg\xE4nzt."
|
|
13250
|
+
] }) }),
|
|
13251
|
+
hinweise.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("ul", { className: "szenen-detail__hint", "data-testid": id("hinweise"), role: "status", children: hinweise.map((hinweis, i) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("li", { children: hinweis }, i)) }),
|
|
13252
|
+
blocker && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "szenen-error", role: "alert", "data-testid": id("blocker"), children: blocker }),
|
|
13046
13253
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
13047
13254
|
"button",
|
|
13048
13255
|
{
|
|
13049
13256
|
type: "button",
|
|
13050
|
-
disabled: laeuft,
|
|
13257
|
+
disabled: laeuft || blocker !== null,
|
|
13051
13258
|
onClick: () => void erzeugen(),
|
|
13052
|
-
"data-testid": "
|
|
13053
|
-
children: laeuft ? "Pr\xFCft und erzeugt \u2026" : "Draft-Kette pr\xFCfen und Prompt erzeugen (kostet einen Modellaufruf)"
|
|
13259
|
+
"data-testid": id("prompt"),
|
|
13260
|
+
children: laeuft ? "Pr\xFCft und erzeugt \u2026" : ausKette ? "Draft-Kette pr\xFCfen und Prompt erzeugen (kostet einen Modellaufruf)" : "Prompt erzeugen (kostet einen Modellaufruf)"
|
|
13054
13261
|
}
|
|
13055
13262
|
),
|
|
13056
|
-
meldung && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "szenen-error", role: "alert", "data-testid": "
|
|
13263
|
+
meldung && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "szenen-error", role: "alert", "data-testid": id("meldung"), children: [
|
|
13057
13264
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: meldung }),
|
|
13058
|
-
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": "
|
|
13059
|
-
ausgang === "conflict" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": "
|
|
13060
|
-
ausgang === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": "
|
|
13061
|
-
ausgang === "error" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": "
|
|
13265
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": id("kein-modell"), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: "Es wurde kein Modell gerufen." }) }),
|
|
13266
|
+
ausgang === "conflict" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": id("konflikt"), children: ausKette ? "Ein Entwurf der Kette wurde zwischenzeitlich ge\xE4ndert. Ein erneuter Versuch friert den aktuellen Stand ein." : "Die Szene wurde zwischenzeitlich ge\xE4ndert. Ein erneuter Versuch friert den aktuellen Stand ein." }),
|
|
13267
|
+
ausgang === "rejected" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": id("mangel"), children: ausKette ? "Die Kette selbst ist noch nicht vollst\xE4ndig. Ein erneuter Versuch \xE4ndert daran nichts \u2014 die Entw\xFCrfe m\xFCssen zuerst erg\xE4nzt werden." : "Aus diesem Stand l\xE4sst sich kein Auftrag herstellen. Ein erneuter Versuch \xE4ndert daran nichts \u2014 die Szene muss zuerst Inhalt bekommen." }),
|
|
13268
|
+
ausgang === "error" && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { "data-testid": id("technisch"), children: "Das war ein technisches Problem beim Zugriff, kein fachlicher Mangel. Ein erneuter Versuch ist sinnvoll." })
|
|
13062
13269
|
] }),
|
|
13063
|
-
lauf && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "szenen-run", "data-testid": "
|
|
13270
|
+
lauf && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "szenen-run", "data-testid": id("lauf"), children: [
|
|
13064
13271
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("h5", { children: [
|
|
13065
13272
|
"Prompt-Lauf ",
|
|
13066
13273
|
lauf.status === "succeeded" ? "gelungen" : "gescheitert"
|
|
@@ -13072,7 +13279,7 @@ var ChainPromptAction = ({
|
|
|
13072
13279
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("code", { children: lauf.model_id }),
|
|
13073
13280
|
"."
|
|
13074
13281
|
] }),
|
|
13075
|
-
lauf.status === "succeeded" && lauf.output && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { className: "szenen-proposal__payload", "data-testid": "
|
|
13282
|
+
lauf.status === "succeeded" && lauf.output && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("pre", { className: "szenen-proposal__payload", "data-testid": id("prompt-text"), children: lauf.output.positive }),
|
|
13076
13283
|
lauf.status === "failed" && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { className: "szenen-error", children: [
|
|
13077
13284
|
lauf.failure?.class,
|
|
13078
13285
|
" \u2014 ",
|
|
@@ -13632,12 +13839,27 @@ var RunImagesPanel = ({ port, lauf }) => {
|
|
|
13632
13839
|
"Lauf ",
|
|
13633
13840
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { "data-testid": `eingang-lauf-${lauf.run_id}`, children: lauf.run_id })
|
|
13634
13841
|
] }),
|
|
13635
|
-
quelle.kind === "published"
|
|
13842
|
+
quelle.kind === "published" && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
|
|
13636
13843
|
"ver\xF6ffentlichte Shot-Version ",
|
|
13637
13844
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { children: quelle.shot_version_id })
|
|
13638
|
-
] })
|
|
13845
|
+
] }),
|
|
13846
|
+
quelle.kind === "draft_chain" && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
|
|
13639
13847
|
"Draft-Kette ",
|
|
13640
13848
|
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { children: quelle.chain_id })
|
|
13849
|
+
] }),
|
|
13850
|
+
quelle.kind === "scene_direct" && /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { "data-testid": `eingang-herkunft-${lauf.run_id}`, children: [
|
|
13851
|
+
"Szene ",
|
|
13852
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { children: quelle.scene.element_id }),
|
|
13853
|
+
quelle.scene.draft_id ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
13854
|
+
" \xB7 Entwurf ",
|
|
13855
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { children: quelle.scene.draft_id }),
|
|
13856
|
+
" (Revision ",
|
|
13857
|
+
quelle.scene.revision,
|
|
13858
|
+
")"
|
|
13859
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
|
|
13860
|
+
" \xB7 Version ",
|
|
13861
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { children: quelle.scene.version_id })
|
|
13862
|
+
] })
|
|
13641
13863
|
] })
|
|
13642
13864
|
] }),
|
|
13643
13865
|
quelle.kind === "draft_chain" && quelle.derivation_run_id ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
@@ -14203,9 +14425,13 @@ var RunsPanel = ({ port, source, contextId }) => {
|
|
|
14203
14425
|
const [notiz, setNotiz] = (0, import_react40.useState)(null);
|
|
14204
14426
|
const [nachladen, setNachladen] = (0, import_react40.useState)(0);
|
|
14205
14427
|
const faehig = capabilitiesOf(port);
|
|
14206
|
-
const quellSchluessel = source.kind === "published" ? source.shotVersionId : source.chainId;
|
|
14428
|
+
const quellSchluessel = source.kind === "published" ? source.shotVersionId : source.kind === "draft_chain" ? source.chainId : source.sceneElementId;
|
|
14207
14429
|
const [phase, neuLaden] = usePortQuery(
|
|
14208
|
-
() =>
|
|
14430
|
+
() => {
|
|
14431
|
+
if (source.kind === "published") return port.runs.listRunsForShot(source.shotVersionId);
|
|
14432
|
+
if (source.kind === "draft_chain") return port.runs.listRunsForChain(source.chainId);
|
|
14433
|
+
return port.runs.listRunsForScene(source.sceneElementId);
|
|
14434
|
+
},
|
|
14209
14435
|
[port, source.kind, quellSchluessel, nachladen]
|
|
14210
14436
|
);
|
|
14211
14437
|
const starten = async () => {
|
|
@@ -14244,7 +14470,7 @@ var RunsPanel = ({ port, source, contextId }) => {
|
|
|
14244
14470
|
"L\xE4ufe konnten nicht geladen werden: ",
|
|
14245
14471
|
phase.message
|
|
14246
14472
|
] }),
|
|
14247
|
-
phase.status === "ready" && laeufe.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { "data-testid": "keine-laeufe", children: source.kind === "published" ? "F\xFCr diese Shot-Version gibt es noch keinen Lauf." : "F\xFCr diese Draft-Kette gibt es noch keinen Lauf." }),
|
|
14473
|
+
phase.status === "ready" && laeufe.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { "data-testid": "keine-laeufe", children: source.kind === "published" ? "F\xFCr diese Shot-Version gibt es noch keinen Lauf." : source.kind === "draft_chain" ? "F\xFCr diese Draft-Kette gibt es noch keinen Lauf." : "F\xFCr diese Szene gibt es noch keinen direkten Lauf." }),
|
|
14248
14474
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("ol", { "data-testid": "runden-liste", children: laeufe.map((lauf) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
14249
14475
|
RundenEintrag,
|
|
14250
14476
|
{
|
|
@@ -14449,6 +14675,23 @@ var ElementDetail = ({
|
|
|
14449
14675
|
if (!kette2) return null;
|
|
14450
14676
|
return kette2.links[0]?.field ?? null;
|
|
14451
14677
|
}, [schnappschuss?.draft?.chain]);
|
|
14678
|
+
const laufStand = (0, import_react41.useMemo)(() => {
|
|
14679
|
+
if (!schnappschuss || schnappschuss.element.type !== "scene") return null;
|
|
14680
|
+
if (schnappschuss.draft) return schnappschuss.draft.payload;
|
|
14681
|
+
const kopf = usableHeadVersionId(kopfAufloesung);
|
|
14682
|
+
if (!kopf) return null;
|
|
14683
|
+
return schnappschuss.versions.find((v) => v.version_id === kopf)?.payload ?? null;
|
|
14684
|
+
}, [schnappschuss, kopfAufloesung]);
|
|
14685
|
+
const szenenBlocker = (0, import_react41.useMemo)(() => {
|
|
14686
|
+
if (!schnappschuss || schnappschuss.element.type !== "scene") return null;
|
|
14687
|
+
if (laufStand === null) {
|
|
14688
|
+
return schnappschuss.versions.length > 0 ? "Diese Szene hat keinen Entwurf und in diesem Kontext keinen bevorzugten Kopf. Welcher Stand gilt, entscheidet keine Reihenfolge (D-36) \u2014 bitte oben eine Version als bevorzugt setzen." : "Diese Szene hat noch keinen gespeicherten Stand. Ein Lauf friert ein, was gespeichert ist \u2014 bitte zuerst den Entwurf speichern.";
|
|
14689
|
+
}
|
|
14690
|
+
const flag = sceneOnlyCapabilities(laufStand).can_render_prompt;
|
|
14691
|
+
if (flag.state === "yes") return null;
|
|
14692
|
+
const grund = flag.reasons[0];
|
|
14693
|
+
return grund && "message" in grund ? grund.message : "Kein Lauf moeglich.";
|
|
14694
|
+
}, [schnappschuss, laufStand]);
|
|
14452
14695
|
const vorschau = (0, import_react41.useMemo)(() => {
|
|
14453
14696
|
if (!schnappschuss) return null;
|
|
14454
14697
|
try {
|
|
@@ -14582,8 +14825,7 @@ var ElementDetail = ({
|
|
|
14582
14825
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("header", { children: [
|
|
14583
14826
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("h3", { children: schnappschuss.metadata?.title ?? "(ohne Titel)" }),
|
|
14584
14827
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("p", { className: "szenen-detail__ids", children: [
|
|
14585
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: typ }),
|
|
14586
|
-
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("code", { children: schnappschuss.element.element_id }),
|
|
14828
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "data-testid": "element-typ", children: elementTypLabel(typ) }),
|
|
14587
14829
|
schnappschuss.element.retired && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "data-testid": "ist-stillgelegt", children: "stillgelegt" })
|
|
14588
14830
|
] })
|
|
14589
14831
|
] }),
|
|
@@ -14761,10 +15003,13 @@ var ElementDetail = ({
|
|
|
14761
15003
|
// voraus" gilt nur noch fuer den Einzel-Shot.
|
|
14762
15004
|
draft?.chain ? /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
14763
15005
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
14764
|
-
|
|
15006
|
+
PromptStartAction,
|
|
14765
15007
|
{
|
|
14766
15008
|
port,
|
|
14767
|
-
|
|
15009
|
+
source: {
|
|
15010
|
+
kind: "draft_chain",
|
|
15011
|
+
shotElementId: schnappschuss.element.element_id
|
|
15012
|
+
}
|
|
14768
15013
|
}
|
|
14769
15014
|
),
|
|
14770
15015
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
@@ -14784,12 +15029,36 @@ var ElementDetail = ({
|
|
|
14784
15029
|
source: { kind: "published", shotVersionId: laufVersionId }
|
|
14785
15030
|
}
|
|
14786
15031
|
) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { "data-testid": "laufquelle-unklar", children: "Dieser Shot hat mehrere ver\xF6ffentlichte Versionen und keinen bevorzugten Kopf in diesem Kontext. Welche davon einen Lauf tr\xE4gt, entscheidet keine Reihenfolge \u2014 bitte oben eine Version anzeigen oder als bevorzugt setzen." })),
|
|
14787
|
-
typ === "
|
|
14788
|
-
|
|
14789
|
-
|
|
14790
|
-
|
|
14791
|
-
|
|
14792
|
-
|
|
15032
|
+
typ === "scene" && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
|
|
15033
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
15034
|
+
PromptStartAction,
|
|
15035
|
+
{
|
|
15036
|
+
port,
|
|
15037
|
+
source: { kind: "scene", sceneElementId: schnappschuss.element.element_id },
|
|
15038
|
+
hinweise: [
|
|
15039
|
+
"Kein Bildaufbau und keine Kamera \u2014 der Prompt wird ohne Kameravorgabe erzeugt.",
|
|
15040
|
+
"Kein Zielmodell \u2014 generische Promptableitung ohne Modelloptimierung.",
|
|
15041
|
+
schnappschuss.draft ? "Eingefroren wird der gespeicherte Entwurf. Nicht gespeicherte Aenderungen im Formular gehen nicht mit." : "Eingefroren wird die wirksame veroeffentlichte Version."
|
|
15042
|
+
],
|
|
15043
|
+
blocker: szenenBlocker,
|
|
15044
|
+
onLauf: () => setNachladen((n) => n + 1)
|
|
15045
|
+
}
|
|
15046
|
+
),
|
|
15047
|
+
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
15048
|
+
RunsPanel,
|
|
15049
|
+
{
|
|
15050
|
+
port,
|
|
15051
|
+
contextId,
|
|
15052
|
+
source: { kind: "scene", sceneElementId: schnappschuss.element.element_id }
|
|
15053
|
+
}
|
|
15054
|
+
)
|
|
15055
|
+
] }),
|
|
15056
|
+
typ === "scene_setup" && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
15057
|
+
CapabilityPanel,
|
|
15058
|
+
{
|
|
15059
|
+
port,
|
|
15060
|
+
elementId,
|
|
15061
|
+
setupPayload: payloadAusFormular()
|
|
14793
15062
|
}
|
|
14794
15063
|
),
|
|
14795
15064
|
notiz && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
|
|
@@ -14808,6 +15077,26 @@ var ElementDetail = ({
|
|
|
14808
15077
|
] });
|
|
14809
15078
|
};
|
|
14810
15079
|
|
|
15080
|
+
// src/features/szenen/areas/useSchmalesDisplay.ts
|
|
15081
|
+
var import_react42 = require("react");
|
|
15082
|
+
var SCHMALE_ANSICHT = "(max-width: 760px)";
|
|
15083
|
+
function messen(abfrage) {
|
|
15084
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
15085
|
+
return window.matchMedia(abfrage).matches;
|
|
15086
|
+
}
|
|
15087
|
+
function useSchmalesDisplay(abfrage = SCHMALE_ANSICHT) {
|
|
15088
|
+
const [schmal, setSchmal] = (0, import_react42.useState)(() => messen(abfrage));
|
|
15089
|
+
(0, import_react42.useEffect)(() => {
|
|
15090
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
|
|
15091
|
+
const liste = window.matchMedia(abfrage);
|
|
15092
|
+
const aktualisieren = () => setSchmal(liste.matches);
|
|
15093
|
+
aktualisieren();
|
|
15094
|
+
liste.addEventListener?.("change", aktualisieren);
|
|
15095
|
+
return () => liste.removeEventListener?.("change", aktualisieren);
|
|
15096
|
+
}, [abfrage]);
|
|
15097
|
+
return schmal;
|
|
15098
|
+
}
|
|
15099
|
+
|
|
14811
15100
|
// src/features/szenen/areas/ElementsArea.tsx
|
|
14812
15101
|
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
14813
15102
|
var ElementsArea = ({
|
|
@@ -14816,18 +15105,31 @@ var ElementsArea = ({
|
|
|
14816
15105
|
author = "szenen-view",
|
|
14817
15106
|
restrictToTypes,
|
|
14818
15107
|
allTypesLabel,
|
|
15108
|
+
listTitle,
|
|
14819
15109
|
onSelect
|
|
14820
15110
|
}) => {
|
|
14821
15111
|
const auswahlTypen = restrictToTypes ?? SZENEN_ELEMENT_TYPES;
|
|
14822
|
-
const
|
|
14823
|
-
|
|
14824
|
-
);
|
|
14825
|
-
const
|
|
14826
|
-
const [
|
|
14827
|
-
const [
|
|
14828
|
-
const [
|
|
14829
|
-
const [
|
|
14830
|
-
const [
|
|
15112
|
+
const einzelTyp = auswahlTypen.length === 1 ? auswahlTypen[0] : null;
|
|
15113
|
+
const gemischt = auswahlTypen.length > 1;
|
|
15114
|
+
const ueberschrift = listTitle ?? (einzelTyp ? elementTypPlural(einzelTyp) : "Bausteine");
|
|
15115
|
+
const einzahl = einzelTyp ? elementTypLabel(einzelTyp) : "Objekt";
|
|
15116
|
+
const [typ, setTyp] = (0, import_react43.useState)(einzelTyp ?? "");
|
|
15117
|
+
const [zeigeStillgelegte, setZeigeStillgelegte] = (0, import_react43.useState)(false);
|
|
15118
|
+
const [gewaehlt, setGewaehlt] = (0, import_react43.useState)(null);
|
|
15119
|
+
const [neuerTitel, setNeuerTitel] = (0, import_react43.useState)("");
|
|
15120
|
+
const [neuerTyp, setNeuerTyp] = (0, import_react43.useState)(auswahlTypen[0]);
|
|
15121
|
+
const [notiz, setNotiz] = (0, import_react43.useState)(null);
|
|
15122
|
+
const [anlegend, setAnlegend] = (0, import_react43.useState)(false);
|
|
15123
|
+
const [anlageOffen, setAnlageOffen] = (0, import_react43.useState)(false);
|
|
15124
|
+
const schmal = useSchmalesDisplay();
|
|
15125
|
+
const [ansicht, setAnsicht] = (0, import_react43.useState)("liste");
|
|
15126
|
+
const zeigeListe = !schmal || ansicht === "liste";
|
|
15127
|
+
const zeigeDetail = !schmal || ansicht === "detail";
|
|
15128
|
+
const waehle = (elementId) => {
|
|
15129
|
+
setGewaehlt(elementId);
|
|
15130
|
+
setAnsicht("detail");
|
|
15131
|
+
onSelect?.(elementId);
|
|
15132
|
+
};
|
|
14831
15133
|
const [phase, neuLaden] = usePortQuery(
|
|
14832
15134
|
() => port.elements.listElements({
|
|
14833
15135
|
contextId,
|
|
@@ -14836,128 +15138,199 @@ var ElementsArea = ({
|
|
|
14836
15138
|
}),
|
|
14837
15139
|
[port, contextId, typ, zeigeStillgelegte]
|
|
14838
15140
|
);
|
|
14839
|
-
|
|
14840
|
-
|
|
14841
|
-
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
14848
|
-
|
|
14849
|
-
|
|
14850
|
-
|
|
14851
|
-
|
|
14852
|
-
|
|
14853
|
-
|
|
14854
|
-
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
14866
|
-
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14883
|
-
})
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
if (ergebnis.kind === "ok") {
|
|
14887
|
-
setNeuerTitel("");
|
|
14888
|
-
setGewaehlt(ergebnis.value.element_id);
|
|
14889
|
-
onSelect?.(ergebnis.value.element_id);
|
|
14890
|
-
neuLaden();
|
|
14891
|
-
}
|
|
14892
|
-
},
|
|
14893
|
-
children: [
|
|
14894
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
14895
|
-
"input",
|
|
15141
|
+
const anlageSchliessen = () => {
|
|
15142
|
+
setAnlageOffen(false);
|
|
15143
|
+
setNeuerTitel("");
|
|
15144
|
+
};
|
|
15145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
15146
|
+
"div",
|
|
15147
|
+
{
|
|
15148
|
+
className: "szenen-elements",
|
|
15149
|
+
"data-testid": "bereich-elemente",
|
|
15150
|
+
"data-ansicht": schmal ? ansicht : "beide",
|
|
15151
|
+
children: [
|
|
15152
|
+
zeigeListe && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "szenen-elements__master", "data-testid": "elemente-master", children: [
|
|
15153
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "szenen-elements__toolbar", children: [
|
|
15154
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("h3", { className: "szenen-elements__heading", children: ueberschrift }),
|
|
15155
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15156
|
+
"button",
|
|
15157
|
+
{
|
|
15158
|
+
type: "button",
|
|
15159
|
+
className: "szenen-elements__new",
|
|
15160
|
+
"data-testid": "neu-oeffnen",
|
|
15161
|
+
"aria-expanded": anlageOffen,
|
|
15162
|
+
onClick: () => {
|
|
15163
|
+
setNotiz(null);
|
|
15164
|
+
if (anlageOffen) anlageSchliessen();
|
|
15165
|
+
else setAnlageOffen(true);
|
|
15166
|
+
},
|
|
15167
|
+
children: "+ Neu"
|
|
15168
|
+
}
|
|
15169
|
+
)
|
|
15170
|
+
] }),
|
|
15171
|
+
gemischt && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: "szenen-elements__scope", children: [
|
|
15172
|
+
"Art",
|
|
15173
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
15174
|
+
"select",
|
|
15175
|
+
{
|
|
15176
|
+
"data-testid": "filter-typ",
|
|
15177
|
+
value: typ,
|
|
15178
|
+
onChange: (e) => setTyp(e.target.value),
|
|
15179
|
+
children: [
|
|
15180
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("option", { value: "", children: allTypesLabel ?? "alle Typen" }),
|
|
15181
|
+
auswahlTypen.map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("option", { value: t, children: elementTypPlural(t) }, t))
|
|
15182
|
+
]
|
|
15183
|
+
}
|
|
15184
|
+
)
|
|
15185
|
+
] }),
|
|
15186
|
+
anlageOffen && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
15187
|
+
"form",
|
|
14896
15188
|
{
|
|
14897
|
-
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
|
|
15189
|
+
className: "szenen-elements__create",
|
|
15190
|
+
"data-testid": "element-anlegen",
|
|
15191
|
+
onSubmit: async (e) => {
|
|
15192
|
+
e.preventDefault();
|
|
15193
|
+
if (!neuerTitel.trim()) return;
|
|
15194
|
+
setAnlegend(true);
|
|
15195
|
+
const gewuenschterTyp = einzelTyp ?? neuerTyp;
|
|
15196
|
+
const titel = neuerTitel.trim();
|
|
15197
|
+
const ergebnis = await port.elements.createElement({
|
|
15198
|
+
type: gewuenschterTyp,
|
|
15199
|
+
title: titel,
|
|
15200
|
+
contextId
|
|
15201
|
+
});
|
|
15202
|
+
setNotiz(noticeFor(
|
|
15203
|
+
ergebnis,
|
|
15204
|
+
`${elementTypLabel(gewuenschterTyp)} \u201E${titel}" anlegen`
|
|
15205
|
+
));
|
|
15206
|
+
setAnlegend(false);
|
|
15207
|
+
if (ergebnis.kind === "ok") {
|
|
15208
|
+
anlageSchliessen();
|
|
15209
|
+
waehle(ergebnis.value.element_id);
|
|
15210
|
+
neuLaden();
|
|
15211
|
+
}
|
|
15212
|
+
},
|
|
15213
|
+
children: [
|
|
15214
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: "szenen-elements__create-title", children: [
|
|
15215
|
+
einzelTyp ? `Neue ${einzahl}` : "Titel",
|
|
15216
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15217
|
+
"input",
|
|
15218
|
+
{
|
|
15219
|
+
"data-testid": "neuer-titel",
|
|
15220
|
+
value: neuerTitel,
|
|
15221
|
+
autoFocus: true,
|
|
15222
|
+
placeholder: einzelTyp ? `Titel der neuen ${einzahl}` : "Titel",
|
|
15223
|
+
onChange: (e) => setNeuerTitel(e.target.value)
|
|
15224
|
+
}
|
|
15225
|
+
)
|
|
15226
|
+
] }),
|
|
15227
|
+
gemischt && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { className: "szenen-elements__create-type", children: [
|
|
15228
|
+
"Art",
|
|
15229
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15230
|
+
"select",
|
|
15231
|
+
{
|
|
15232
|
+
"data-testid": "neuer-typ",
|
|
15233
|
+
value: neuerTyp,
|
|
15234
|
+
onChange: (e) => setNeuerTyp(e.target.value),
|
|
15235
|
+
children: auswahlTypen.map((t) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("option", { value: t, children: elementTypLabel(t) }, t))
|
|
15236
|
+
}
|
|
15237
|
+
)
|
|
15238
|
+
] }),
|
|
15239
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "szenen-elements__create-actions", children: [
|
|
15240
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15241
|
+
"button",
|
|
15242
|
+
{
|
|
15243
|
+
type: "submit",
|
|
15244
|
+
"data-testid": "anlegen",
|
|
15245
|
+
disabled: anlegend || !neuerTitel.trim(),
|
|
15246
|
+
children: "anlegen"
|
|
15247
|
+
}
|
|
15248
|
+
),
|
|
15249
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15250
|
+
"button",
|
|
15251
|
+
{
|
|
15252
|
+
type: "button",
|
|
15253
|
+
"data-testid": "anlegen-abbrechen",
|
|
15254
|
+
onClick: anlageSchliessen,
|
|
15255
|
+
children: "abbrechen"
|
|
15256
|
+
}
|
|
15257
|
+
)
|
|
15258
|
+
] })
|
|
15259
|
+
]
|
|
14901
15260
|
}
|
|
14902
15261
|
),
|
|
14903
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
14904
|
-
|
|
15262
|
+
notiz && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { "data-testid": "anlegen-notiz", "data-tone": notiz.tone, children: notiz.text }),
|
|
15263
|
+
phase.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { "data-testid": "elemente-laden", children: "Elemente werden geladen \u2026" }),
|
|
15264
|
+
phase.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { "data-testid": "elemente-fehler", role: "alert", children: [
|
|
15265
|
+
"Elemente konnten nicht geladen werden: ",
|
|
15266
|
+
phase.message,
|
|
15267
|
+
phase.retryable && " \u2014 ein erneuter Versuch kann helfen."
|
|
15268
|
+
] }),
|
|
15269
|
+
phase.status === "ready" && phase.value.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { "data-testid": "elemente-leer", children: [
|
|
15270
|
+
typ ? `Keine ${elementTypPlural(typ)} in diesem Kontext.` : "Nichts in diesem Kontext.",
|
|
15271
|
+
" ",
|
|
15272
|
+
'Mit \u201E+ Neu" anlegen.'
|
|
15273
|
+
] }),
|
|
15274
|
+
phase.status === "ready" && phase.value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "szenen-elements__list", "data-testid": "elemente-liste", children: phase.value.map((element) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("li", { "data-element-id": element.element_id, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
15275
|
+
"button",
|
|
15276
|
+
{
|
|
15277
|
+
type: "button",
|
|
15278
|
+
"data-testid": `element-waehlen-${element.element_id}`,
|
|
15279
|
+
"aria-current": element.element_id === gewaehlt,
|
|
15280
|
+
className: element.element_id === gewaehlt ? "is-selected" : void 0,
|
|
15281
|
+
onClick: () => waehle(element.element_id),
|
|
15282
|
+
children: [
|
|
15283
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("strong", { className: "szenen-elements__title", children: element.title || "Unbenanntes Element" }),
|
|
15284
|
+
gemischt && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "szenen-elements__type", children: elementTypLabel(element.type) }),
|
|
15285
|
+
element.subtype && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "szenen-elements__subtype", children: element.subtype }),
|
|
15286
|
+
element.retired && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "szenen-elements__retired", children: "stillgelegt" })
|
|
15287
|
+
]
|
|
15288
|
+
}
|
|
15289
|
+
) }, element.element_id)) }),
|
|
15290
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("details", { className: "szenen-elements__options", "data-testid": "listen-optionen", children: [
|
|
15291
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("summary", { children: "Listenoptionen" }),
|
|
15292
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "szenen-elements__filter", children: [
|
|
15293
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("label", { children: [
|
|
15294
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15295
|
+
"input",
|
|
15296
|
+
{
|
|
15297
|
+
type: "checkbox",
|
|
15298
|
+
"data-testid": "filter-stillgelegt",
|
|
15299
|
+
checked: zeigeStillgelegte,
|
|
15300
|
+
onChange: (e) => setZeigeStillgelegte(e.target.checked)
|
|
15301
|
+
}
|
|
15302
|
+
),
|
|
15303
|
+
"stillgelegte Elemente einblenden"
|
|
15304
|
+
] }),
|
|
15305
|
+
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", "data-testid": "neu-laden", onClick: neuLaden, children: "neu laden" })
|
|
15306
|
+
] })
|
|
15307
|
+
] })
|
|
15308
|
+
] }),
|
|
15309
|
+
zeigeDetail && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "szenen-elements__detail", "data-testid": "elemente-detail-spalte", children: [
|
|
15310
|
+
schmal && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15311
|
+
"button",
|
|
14905
15312
|
{
|
|
14906
|
-
|
|
14907
|
-
|
|
14908
|
-
|
|
14909
|
-
|
|
15313
|
+
type: "button",
|
|
15314
|
+
className: "szenen-elements__back",
|
|
15315
|
+
"data-testid": "zurueck-zur-liste",
|
|
15316
|
+
onClick: () => setAnsicht("liste"),
|
|
15317
|
+
children: "\u2190 Zur\xFCck zur Liste"
|
|
14910
15318
|
}
|
|
14911
15319
|
),
|
|
14912
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
|
|
14919
|
-
|
|
14920
|
-
|
|
14921
|
-
|
|
14922
|
-
|
|
14923
|
-
|
|
14924
|
-
|
|
14925
|
-
|
|
14926
|
-
"."
|
|
14927
|
-
] }),
|
|
14928
|
-
phase.status === "ready" && phase.value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("ul", { className: "szenen-elements__list", "data-testid": "elemente-liste", children: phase.value.map((element) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("li", { "data-element-id": element.element_id, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(
|
|
14929
|
-
"button",
|
|
14930
|
-
{
|
|
14931
|
-
type: "button",
|
|
14932
|
-
"aria-current": element.element_id === gewaehlt,
|
|
14933
|
-
className: element.element_id === gewaehlt ? "is-selected" : void 0,
|
|
14934
|
-
onClick: () => {
|
|
14935
|
-
setGewaehlt(element.element_id);
|
|
14936
|
-
onSelect?.(element.element_id);
|
|
14937
|
-
},
|
|
14938
|
-
children: [
|
|
14939
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("strong", { className: "szenen-elements__title", children: element.title || "Unbenanntes Element" }),
|
|
14940
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "szenen-elements__type", children: element.type }),
|
|
14941
|
-
element.subtype && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "szenen-elements__subtype", children: element.subtype }),
|
|
14942
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("span", { className: "szenen-elements__technical", children: [
|
|
14943
|
-
"ID ",
|
|
14944
|
-
/* @__PURE__ */ (0, import_jsx_runtime38.jsx)("code", { className: "szenen-elements__id", children: element.element_id })
|
|
14945
|
-
] }),
|
|
14946
|
-
element.retired && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "szenen-elements__retired", children: "stillgelegt" })
|
|
14947
|
-
]
|
|
14948
|
-
}
|
|
14949
|
-
) }, element.element_id)) }),
|
|
14950
|
-
gewaehlt && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
14951
|
-
ElementDetail,
|
|
14952
|
-
{
|
|
14953
|
-
port,
|
|
14954
|
-
elementId: gewaehlt,
|
|
14955
|
-
contextId,
|
|
14956
|
-
author,
|
|
14957
|
-
onChanged: neuLaden
|
|
14958
|
-
}
|
|
14959
|
-
)
|
|
14960
|
-
] });
|
|
15320
|
+
gewaehlt ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
15321
|
+
ElementDetail,
|
|
15322
|
+
{
|
|
15323
|
+
port,
|
|
15324
|
+
elementId: gewaehlt,
|
|
15325
|
+
contextId,
|
|
15326
|
+
author,
|
|
15327
|
+
onChanged: neuLaden
|
|
15328
|
+
}
|
|
15329
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "szenen-elements__empty-detail", "data-testid": "keine-auswahl", children: "Nichts ausgew\xE4hlt. Ein Eintrag aus der Liste \xF6ffnet die Bearbeitung." })
|
|
15330
|
+
] })
|
|
15331
|
+
]
|
|
15332
|
+
}
|
|
15333
|
+
);
|
|
14961
15334
|
};
|
|
14962
15335
|
|
|
14963
15336
|
// src/features/szenen/areas/SceneArea.tsx
|
|
@@ -14970,14 +15343,15 @@ var SceneArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime3
|
|
|
14970
15343
|
// src/features/szenen/areas/SetupArea.tsx
|
|
14971
15344
|
var import_jsx_runtime40 = require("react/jsx-runtime");
|
|
14972
15345
|
var SetupArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "szenen-setup", "data-testid": "bereich-setup", children: [
|
|
14973
|
-
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "szenen-area__lead", children: "
|
|
15346
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "szenen-area__lead", children: "Bildaufbauten, Kameras und Stile dieses Kontexts." }),
|
|
14974
15347
|
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
14975
15348
|
ElementsArea,
|
|
14976
15349
|
{
|
|
14977
15350
|
port,
|
|
14978
15351
|
contextId,
|
|
14979
15352
|
restrictToTypes: ["scene_setup", "camera_preset", "camera_pattern", "style"],
|
|
14980
|
-
allTypesLabel: "alle Bildaufbau-Typen"
|
|
15353
|
+
allTypesLabel: "alle Bildaufbau-Typen",
|
|
15354
|
+
listTitle: "Bildaufbau"
|
|
14981
15355
|
}
|
|
14982
15356
|
)
|
|
14983
15357
|
] });
|
|
@@ -14985,34 +15359,35 @@ var SetupArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime4
|
|
|
14985
15359
|
// src/features/szenen/areas/ShotArea.tsx
|
|
14986
15360
|
var import_jsx_runtime41 = require("react/jsx-runtime");
|
|
14987
15361
|
var ShotArea = ({ port, contextId }) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "szenen-shot", "data-testid": "bereich-shot", children: [
|
|
14988
|
-
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "szenen-area__lead", children: "
|
|
15362
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "szenen-area__lead", children: "Prompts dieses Kontexts. Auswahl zeigt Runden und startet Prompt-L\xE4ufe." }),
|
|
14989
15363
|
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
|
|
14990
15364
|
ElementsArea,
|
|
14991
15365
|
{
|
|
14992
15366
|
port,
|
|
14993
15367
|
contextId,
|
|
14994
15368
|
restrictToTypes: ["shot", "shot_concept", "target_model"],
|
|
14995
|
-
allTypesLabel: "alle Prompt-Typen"
|
|
15369
|
+
allTypesLabel: "alle Prompt-Typen",
|
|
15370
|
+
listTitle: "Prompts"
|
|
14996
15371
|
}
|
|
14997
15372
|
)
|
|
14998
15373
|
] });
|
|
14999
15374
|
|
|
15000
15375
|
// src/features/szenen/areas/MediaArea.tsx
|
|
15001
|
-
var
|
|
15376
|
+
var import_react44 = require("react");
|
|
15002
15377
|
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
15003
15378
|
var leer = async () => ({ kind: "ok", value: [] });
|
|
15004
15379
|
var MediaArea = ({ port }) => {
|
|
15005
15380
|
const media = port.media;
|
|
15006
|
-
const [versionInput, setVersionInput] = (0,
|
|
15007
|
-
const [versionId, setVersionId] = (0,
|
|
15008
|
-
const [itemInput, setItemInput] = (0,
|
|
15009
|
-
const [itemId, setItemId] = (0,
|
|
15010
|
-
const [assetId, setAssetId] = (0,
|
|
15011
|
-
const [role, setRole] = (0,
|
|
15012
|
-
const [position, setPosition] = (0,
|
|
15013
|
-
const [notiz, setNotiz] = (0,
|
|
15014
|
-
const [busy, setBusy] = (0,
|
|
15015
|
-
const [refresh, setRefresh] = (0,
|
|
15381
|
+
const [versionInput, setVersionInput] = (0, import_react44.useState)("");
|
|
15382
|
+
const [versionId, setVersionId] = (0, import_react44.useState)("");
|
|
15383
|
+
const [itemInput, setItemInput] = (0, import_react44.useState)("");
|
|
15384
|
+
const [itemId, setItemId] = (0, import_react44.useState)("");
|
|
15385
|
+
const [assetId, setAssetId] = (0, import_react44.useState)("");
|
|
15386
|
+
const [role, setRole] = (0, import_react44.useState)("reference");
|
|
15387
|
+
const [position, setPosition] = (0, import_react44.useState)("0");
|
|
15388
|
+
const [notiz, setNotiz] = (0, import_react44.useState)(null);
|
|
15389
|
+
const [busy, setBusy] = (0, import_react44.useState)(false);
|
|
15390
|
+
const [refresh, setRefresh] = (0, import_react44.useState)(0);
|
|
15016
15391
|
const [versionPhase] = usePortQuery(
|
|
15017
15392
|
() => versionId ? media.listVersionMedia(versionId) : leer(),
|
|
15018
15393
|
[media, versionId, refresh]
|
|
@@ -15138,7 +15513,30 @@ var MediaArea = ({ port }) => {
|
|
|
15138
15513
|
};
|
|
15139
15514
|
|
|
15140
15515
|
// src/features/szenen/areas/DeriveArea.tsx
|
|
15141
|
-
var
|
|
15516
|
+
var import_react47 = require("react");
|
|
15517
|
+
|
|
15518
|
+
// src/lib/szenen/bildVorschau.ts
|
|
15519
|
+
async function ladeVorschauen(port, mediaRefs, fertig, optionen = {}) {
|
|
15520
|
+
const laden = port.loadPreview;
|
|
15521
|
+
if (!laden) return;
|
|
15522
|
+
const parallel = Math.max(1, optionen.parallel ?? 4);
|
|
15523
|
+
const lauf = optionen.lauf;
|
|
15524
|
+
const offen = mediaRefs.filter((ref) => !(optionen.hat?.(ref) ?? false));
|
|
15525
|
+
let naechster = 0;
|
|
15526
|
+
async function arbeiter() {
|
|
15527
|
+
while (naechster < offen.length) {
|
|
15528
|
+
if (lauf?.abgebrochen) return;
|
|
15529
|
+
const ref = offen[naechster];
|
|
15530
|
+
naechster += 1;
|
|
15531
|
+
const ergebnis = await laden.call(port, ref);
|
|
15532
|
+
if (lauf?.abgebrochen) return;
|
|
15533
|
+
if (ergebnis.kind === "ok") fertig(ref, ergebnis.value);
|
|
15534
|
+
}
|
|
15535
|
+
}
|
|
15536
|
+
await Promise.all(
|
|
15537
|
+
Array.from({ length: Math.min(parallel, offen.length) }, () => arbeiter())
|
|
15538
|
+
);
|
|
15539
|
+
}
|
|
15142
15540
|
|
|
15143
15541
|
// src/lib/szenen/derivationExamples.ts
|
|
15144
15542
|
var PROPOSAL_EXAMPLE = {
|
|
@@ -15546,7 +15944,7 @@ function validateDerivationInput(input) {
|
|
|
15546
15944
|
if (input.policy.produces.length === 0) return "Die Regel erzeugt keinen einzigen Vorschlag.";
|
|
15547
15945
|
return null;
|
|
15548
15946
|
}
|
|
15549
|
-
var
|
|
15947
|
+
var isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
15550
15948
|
var MAX_PROPOSAL_TITLE_LENGTH = 120;
|
|
15551
15949
|
function fallbackProposalTitle(type) {
|
|
15552
15950
|
return `Rekonstruktion ${type}`;
|
|
@@ -15572,7 +15970,7 @@ function resolveJsonPointer(wurzel, pointer) {
|
|
|
15572
15970
|
aktuell = aktuell[index];
|
|
15573
15971
|
continue;
|
|
15574
15972
|
}
|
|
15575
|
-
if (!
|
|
15973
|
+
if (!isObject10(aktuell) || !(schluessel in aktuell)) {
|
|
15576
15974
|
return { found: false, value: void 0 };
|
|
15577
15975
|
}
|
|
15578
15976
|
aktuell = aktuell[schluessel];
|
|
@@ -15586,7 +15984,7 @@ function collectVersionRefs2(value) {
|
|
|
15586
15984
|
knoten.forEach(besuchen);
|
|
15587
15985
|
return;
|
|
15588
15986
|
}
|
|
15589
|
-
if (!
|
|
15987
|
+
if (!isObject10(knoten)) return;
|
|
15590
15988
|
if (typeof knoten.element_id === "string" && typeof knoten.version_id === "string") {
|
|
15591
15989
|
gefunden.push({ element_id: knoten.element_id, version_id: knoten.version_id });
|
|
15592
15990
|
}
|
|
@@ -15652,7 +16050,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15652
16050
|
envelope: null,
|
|
15653
16051
|
contract_ok: false
|
|
15654
16052
|
});
|
|
15655
|
-
if (!
|
|
16053
|
+
if (!isObject10(value)) {
|
|
15656
16054
|
befund({
|
|
15657
16055
|
code: "response.not_object",
|
|
15658
16056
|
severity: "error",
|
|
@@ -15670,7 +16068,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15670
16068
|
});
|
|
15671
16069
|
}
|
|
15672
16070
|
const rohProposals = value.proposals;
|
|
15673
|
-
const proposalsLesbar =
|
|
16071
|
+
const proposalsLesbar = isObject10(rohProposals);
|
|
15674
16072
|
if (!proposalsLesbar) {
|
|
15675
16073
|
befund({
|
|
15676
16074
|
code: "envelope.proposals_missing",
|
|
@@ -15680,7 +16078,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15680
16078
|
});
|
|
15681
16079
|
}
|
|
15682
16080
|
const roh = proposalsLesbar ? rohProposals : {};
|
|
15683
|
-
const rohGaps =
|
|
16081
|
+
const rohGaps = isObject10(value.gaps) ? value.gaps : {};
|
|
15684
16082
|
const gapsUngefragt = Object.keys(rohGaps).filter(
|
|
15685
16083
|
(t) => !input.policy.produces.includes(t)
|
|
15686
16084
|
);
|
|
@@ -15692,7 +16090,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15692
16090
|
pointer: "/gaps"
|
|
15693
16091
|
});
|
|
15694
16092
|
}
|
|
15695
|
-
const fehlend = input.policy.produces.filter((t) => !
|
|
16093
|
+
const fehlend = input.policy.produces.filter((t) => !isObject10(roh[t]));
|
|
15696
16094
|
if (fehlend.length > 0 && proposalsLesbar) {
|
|
15697
16095
|
const d = befund({
|
|
15698
16096
|
code: "envelope.proposals_missing_types",
|
|
@@ -15713,10 +16111,10 @@ function assessDerivationResponse(value, input) {
|
|
|
15713
16111
|
pointer: "/proposals"
|
|
15714
16112
|
});
|
|
15715
16113
|
}
|
|
15716
|
-
const rohTitles =
|
|
16114
|
+
const rohTitles = isObject10(value.titles) ? value.titles : {};
|
|
15717
16115
|
const umgebucht = [];
|
|
15718
16116
|
for (const type of input.policy.produces) {
|
|
15719
|
-
if (!
|
|
16117
|
+
if (!isObject10(roh[type])) continue;
|
|
15720
16118
|
const payload = roh[type];
|
|
15721
16119
|
const eigene = [];
|
|
15722
16120
|
const bezug = REFERENCE_FIELD[type];
|
|
@@ -15752,7 +16150,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15752
16150
|
const bezugPointer = bezug ? `/${bezug.field}` : null;
|
|
15753
16151
|
let gapFehler = false;
|
|
15754
16152
|
for (const eintrag of benannt) {
|
|
15755
|
-
if (!
|
|
16153
|
+
if (!isObject10(eintrag) || typeof eintrag.pointer !== "string" || typeof eintrag.reason !== "string" || !eintrag.reason.trim()) {
|
|
15756
16154
|
eigene.push(befund({
|
|
15757
16155
|
code: "proposal.gap_entry_invalid",
|
|
15758
16156
|
severity: "error",
|
|
@@ -15828,7 +16226,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15828
16226
|
});
|
|
15829
16227
|
} else {
|
|
15830
16228
|
for (const eintrag of value.not_derivable) {
|
|
15831
|
-
if (!
|
|
16229
|
+
if (!isObject10(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.reason !== "string") {
|
|
15832
16230
|
befund({
|
|
15833
16231
|
code: "envelope.not_derivable_entry_invalid",
|
|
15834
16232
|
severity: "error",
|
|
@@ -15853,7 +16251,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15853
16251
|
});
|
|
15854
16252
|
} else {
|
|
15855
16253
|
for (const eintrag of value.conflicts) {
|
|
15856
|
-
if (!
|
|
16254
|
+
if (!isObject10(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.from_image !== "string" || typeof eintrag.from_prompt !== "string") {
|
|
15857
16255
|
befund({
|
|
15858
16256
|
code: "envelope.conflicts_entry_invalid",
|
|
15859
16257
|
severity: "error",
|
|
@@ -15977,7 +16375,7 @@ async function runSceneDerivation(input, port, userPrompt) {
|
|
|
15977
16375
|
}
|
|
15978
16376
|
|
|
15979
16377
|
// src/features/szenen/areas/RecoveryPanel.tsx
|
|
15980
|
-
var
|
|
16378
|
+
var import_react45 = require("react");
|
|
15981
16379
|
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
15982
16380
|
var Diagnosen = ({ befunde, testId }) => {
|
|
15983
16381
|
if (befunde.length === 0) return null;
|
|
@@ -16028,11 +16426,11 @@ var Ausbeute = ({ bewertung }) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)
|
|
|
16028
16426
|
] })
|
|
16029
16427
|
] });
|
|
16030
16428
|
var RecoveryPanel = ({ port, lauf }) => {
|
|
16031
|
-
const [arbeitskopie, setArbeitskopie] = (0,
|
|
16032
|
-
const [bewertung, setBewertung] = (0,
|
|
16033
|
-
const [gesichert, setGesichert] = (0,
|
|
16034
|
-
const [meldung, setMeldung] = (0,
|
|
16035
|
-
const [laeuft, setLaeuft] = (0,
|
|
16429
|
+
const [arbeitskopie, setArbeitskopie] = (0, import_react45.useState)(null);
|
|
16430
|
+
const [bewertung, setBewertung] = (0, import_react45.useState)(null);
|
|
16431
|
+
const [gesichert, setGesichert] = (0, import_react45.useState)(null);
|
|
16432
|
+
const [meldung, setMeldung] = (0, import_react45.useState)(null);
|
|
16433
|
+
const [laeuft, setLaeuft] = (0, import_react45.useState)(false);
|
|
16036
16434
|
if (!port.derivation) return null;
|
|
16037
16435
|
if (typeof lauf.raw_output !== "string" || lauf.raw_output.length === 0) return null;
|
|
16038
16436
|
const derivation = port.derivation;
|
|
@@ -16155,12 +16553,12 @@ var RecoveryPanel = ({ port, lauf }) => {
|
|
|
16155
16553
|
};
|
|
16156
16554
|
|
|
16157
16555
|
// src/features/szenen/areas/ChainActions.tsx
|
|
16158
|
-
var
|
|
16556
|
+
var import_react46 = require("react");
|
|
16159
16557
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
16160
16558
|
var ChainActions = ({ port, runId, recoveryId }) => {
|
|
16161
|
-
const [graph, setGraph] = (0,
|
|
16162
|
-
const [meldung, setMeldung] = (0,
|
|
16163
|
-
const [laeuft, setLaeuft] = (0,
|
|
16559
|
+
const [graph, setGraph] = (0, import_react46.useState)(null);
|
|
16560
|
+
const [meldung, setMeldung] = (0, import_react46.useState)(null);
|
|
16561
|
+
const [laeuft, setLaeuft] = (0, import_react46.useState)(false);
|
|
16164
16562
|
if (!port.derivation) return null;
|
|
16165
16563
|
const derivation = port.derivation;
|
|
16166
16564
|
const runs = port.runs;
|
|
@@ -16226,7 +16624,13 @@ var ChainActions = ({ port, runId, recoveryId }) => {
|
|
|
16226
16624
|
] }),
|
|
16227
16625
|
shotKnoten && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
|
|
16228
16626
|
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { children: 'Die Entw\xFCrfe lassen sich jetzt unter \u201E1 \xB7 Bausteine" \xE4ndern. Der Prompt-Lauf friert den Stand ein, den er dabei vorfindet \u2014 dieselbe Aktion steht auch am Shot selbst, unter \u201E4 \xB7 Prompt".' }),
|
|
16229
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
16627
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
16628
|
+
PromptStartAction,
|
|
16629
|
+
{
|
|
16630
|
+
port,
|
|
16631
|
+
source: { kind: "draft_chain", shotElementId: shotKnoten.elementId }
|
|
16632
|
+
}
|
|
16633
|
+
)
|
|
16230
16634
|
] }),
|
|
16231
16635
|
meldung && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "szenen-error", role: "alert", "data-testid": "kette-meldung", children: meldung })
|
|
16232
16636
|
] });
|
|
@@ -16240,8 +16644,8 @@ var MODUS_TEXT = {
|
|
|
16240
16644
|
image_prompt: "Bild und Prompt"
|
|
16241
16645
|
};
|
|
16242
16646
|
var BelegFeld = ({ titel, text, testId, offen }) => {
|
|
16243
|
-
const [kopiert, setKopiert] = (0,
|
|
16244
|
-
const feld = (0,
|
|
16647
|
+
const [kopiert, setKopiert] = (0, import_react47.useState)(false);
|
|
16648
|
+
const feld = (0, import_react47.useRef)(null);
|
|
16245
16649
|
async function kopieren() {
|
|
16246
16650
|
try {
|
|
16247
16651
|
await navigator.clipboard.writeText(text);
|
|
@@ -16336,14 +16740,64 @@ function readAsBase642(datei) {
|
|
|
16336
16740
|
leser.readAsDataURL(datei);
|
|
16337
16741
|
});
|
|
16338
16742
|
}
|
|
16743
|
+
function useVorschauen(port, mediaRefs) {
|
|
16744
|
+
const [quellen, setQuellen] = (0, import_react47.useState)(() => /* @__PURE__ */ new Map());
|
|
16745
|
+
const gehalten = (0, import_react47.useRef)(/* @__PURE__ */ new Map());
|
|
16746
|
+
const schluessel = mediaRefs.join(" ");
|
|
16747
|
+
(0, import_react47.useEffect)(() => {
|
|
16748
|
+
const bestand = port.imageLibrary;
|
|
16749
|
+
if (!bestand?.loadPreview) return void 0;
|
|
16750
|
+
const refs = schluessel ? schluessel.split(" ") : [];
|
|
16751
|
+
const lauf = { abgebrochen: false };
|
|
16752
|
+
void ladeVorschauen(
|
|
16753
|
+
bestand,
|
|
16754
|
+
refs,
|
|
16755
|
+
(mediaRef, quelle) => {
|
|
16756
|
+
gehalten.current.set(mediaRef, quelle);
|
|
16757
|
+
setQuellen(new Map(gehalten.current));
|
|
16758
|
+
},
|
|
16759
|
+
{ parallel: 4, hat: (ref) => gehalten.current.has(ref), lauf }
|
|
16760
|
+
);
|
|
16761
|
+
return () => {
|
|
16762
|
+
lauf.abgebrochen = true;
|
|
16763
|
+
};
|
|
16764
|
+
}, [port, schluessel]);
|
|
16765
|
+
return quellen;
|
|
16766
|
+
}
|
|
16767
|
+
var Kachel = ({ quelle, alt }) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "szenen-bildkachel", children: quelle ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("img", { src: quelle, alt, loading: "lazy" }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "szenen-bildkachel__leer", "aria-hidden": "true" }) });
|
|
16339
16768
|
var BildWaehler = ({ port, gewaehlt, onWaehlen, onEntfernen }) => {
|
|
16340
|
-
const [suche, setSuche] = (0,
|
|
16341
|
-
const [
|
|
16342
|
-
|
|
16769
|
+
const [suche, setSuche] = (0, import_react47.useState)("");
|
|
16770
|
+
const [offenesWerk, setOffenesWerk] = (0, import_react47.useState)(null);
|
|
16771
|
+
const [items] = usePortQuery(
|
|
16772
|
+
() => port.imageLibrary.listItems({ search: suche.trim() || void 0, limit: 60 }),
|
|
16343
16773
|
[port, suche]
|
|
16344
16774
|
);
|
|
16775
|
+
const werk = items.status === "ready" ? items.value.find((i) => i.itemRef === offenesWerk) ?? null : null;
|
|
16776
|
+
const sichtbar = (0, import_react47.useMemo)(() => {
|
|
16777
|
+
const refs = werk ? werk.images.map((b) => b.mediaRef) : items.status === "ready" ? items.value.map((i) => i.images[0]?.mediaRef).filter((r) => Boolean(r)) : [];
|
|
16778
|
+
return [.../* @__PURE__ */ new Set([...refs, ...gewaehlt.map((b) => b.mediaRef)])];
|
|
16779
|
+
}, [items, werk, gewaehlt]);
|
|
16780
|
+
const quellen = useVorschauen(port, sichtbar);
|
|
16781
|
+
const quelleVon = (bild) => bild.thumbUrl || quellen.get(bild.mediaRef) || null;
|
|
16345
16782
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "szenen-bildwahl", "data-testid": "bildwahl", children: [
|
|
16346
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("
|
|
16783
|
+
werk ? /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("div", { className: "szenen-bildwahl__kopf", children: [
|
|
16784
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
16785
|
+
"button",
|
|
16786
|
+
{
|
|
16787
|
+
type: "button",
|
|
16788
|
+
className: "szenen-bildwahl__zurueck",
|
|
16789
|
+
onClick: () => setOffenesWerk(null),
|
|
16790
|
+
"data-testid": "bildwahl-zurueck",
|
|
16791
|
+
children: "Zurueck zur Auswahl"
|
|
16792
|
+
}
|
|
16793
|
+
),
|
|
16794
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "szenen-bildwahl__werktitel", "data-testid": "bildwahl-werktitel", children: [
|
|
16795
|
+
werk.title,
|
|
16796
|
+
" \xB7 ",
|
|
16797
|
+
werk.images.length,
|
|
16798
|
+
" Bilder"
|
|
16799
|
+
] })
|
|
16800
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("label", { className: "szenen-field", children: [
|
|
16347
16801
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { children: "Bild aus dem Bestand" }),
|
|
16348
16802
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
16349
16803
|
"input",
|
|
@@ -16351,31 +16805,70 @@ var BildWaehler = ({ port, gewaehlt, onWaehlen, onEntfernen }) => {
|
|
|
16351
16805
|
type: "search",
|
|
16352
16806
|
value: suche,
|
|
16353
16807
|
onChange: (e) => setSuche(e.target.value),
|
|
16808
|
+
onKeyDown: (e) => {
|
|
16809
|
+
if (e.key === "Enter") e.preventDefault();
|
|
16810
|
+
},
|
|
16354
16811
|
placeholder: "Suchen \u2026",
|
|
16355
16812
|
"data-testid": "bild-suche"
|
|
16356
16813
|
}
|
|
16357
16814
|
)
|
|
16358
16815
|
] }),
|
|
16359
|
-
|
|
16360
|
-
|
|
16816
|
+
items.status === "loading" && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { children: "Bilder werden geladen \u2026" }),
|
|
16817
|
+
items.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { className: "szenen-error", role: "alert", children: [
|
|
16361
16818
|
"Der Bildbestand ist nicht lesbar: ",
|
|
16362
|
-
|
|
16819
|
+
items.message
|
|
16363
16820
|
] }),
|
|
16364
|
-
|
|
16365
|
-
|
|
16821
|
+
items.status === "ready" && items.value.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("p", { className: "szenen-empty", "data-testid": "bildwahl-leer", children: "Zu dieser Suche gibt es kein Bild. Ohne Treffer bleibt der Upload." }),
|
|
16822
|
+
werk && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { className: "szenen-bildwahl__raster", "data-testid": "bildwahl-galerie", children: werk.images.map((bild, position) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
16366
16823
|
"button",
|
|
16367
16824
|
{
|
|
16368
16825
|
type: "button",
|
|
16369
|
-
onClick: () =>
|
|
16826
|
+
onClick: () => {
|
|
16827
|
+
onWaehlen(bild);
|
|
16828
|
+
setOffenesWerk(null);
|
|
16829
|
+
},
|
|
16370
16830
|
"data-testid": `bild-waehlen-${bild.mediaRef}`,
|
|
16831
|
+
title: bild.title,
|
|
16371
16832
|
children: [
|
|
16372
|
-
|
|
16373
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.
|
|
16833
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Kachel, { quelle: quelleVon(bild), alt: bild.title }),
|
|
16834
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "szenen-bildwahl__nummer", children: [
|
|
16835
|
+
"#",
|
|
16836
|
+
position + 1
|
|
16837
|
+
] })
|
|
16374
16838
|
]
|
|
16375
16839
|
}
|
|
16376
16840
|
) }, bild.mediaRef)) }),
|
|
16841
|
+
!werk && items.status === "ready" && items.value.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { className: "szenen-bildwahl__raster", "data-testid": "bildwahl-werke", children: items.value.map((item) => {
|
|
16842
|
+
const deckbild = item.images[0];
|
|
16843
|
+
if (!deckbild) return null;
|
|
16844
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
16845
|
+
"button",
|
|
16846
|
+
{
|
|
16847
|
+
type: "button",
|
|
16848
|
+
onClick: () => item.images.length === 1 ? onWaehlen(deckbild) : setOffenesWerk(item.itemRef),
|
|
16849
|
+
"data-testid": `item-waehlen-${item.itemRef}`,
|
|
16850
|
+
title: item.title,
|
|
16851
|
+
children: [
|
|
16852
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Kachel, { quelle: quelleVon(deckbild), alt: item.title }),
|
|
16853
|
+
item.images.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
16854
|
+
"span",
|
|
16855
|
+
{
|
|
16856
|
+
className: "szenen-bildwahl__anzahl",
|
|
16857
|
+
"data-testid": `item-anzahl-${item.itemRef}`,
|
|
16858
|
+
children: [
|
|
16859
|
+
item.images.length,
|
|
16860
|
+
"x"
|
|
16861
|
+
]
|
|
16862
|
+
}
|
|
16863
|
+
),
|
|
16864
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "szenen-bildwahl__titel", children: item.title })
|
|
16865
|
+
]
|
|
16866
|
+
}
|
|
16867
|
+
) }, item.itemRef);
|
|
16868
|
+
}) }),
|
|
16377
16869
|
gewaehlt.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("ul", { className: "szenen-bildwahl__gewaehlt", "data-testid": "bilder-gewaehlt", children: gewaehlt.map((bild) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("li", { children: [
|
|
16378
|
-
bild.title,
|
|
16870
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Kachel, { quelle: quelleVon(bild), alt: bild.title }),
|
|
16871
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "szenen-bildwahl__titel", children: bild.title }),
|
|
16379
16872
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
16380
16873
|
"button",
|
|
16381
16874
|
{
|
|
@@ -16395,26 +16888,29 @@ async function digestOf(datei) {
|
|
|
16395
16888
|
return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
16396
16889
|
}
|
|
16397
16890
|
var DeriveArea = ({ port, contextId }) => {
|
|
16398
|
-
const [policyVersionId, setPolicyVersionId] = (0,
|
|
16399
|
-
const [modus, setModus] = (0,
|
|
16400
|
-
const [promptText, setPromptText] = (0,
|
|
16401
|
-
const [dateien, setDateien] = (0,
|
|
16402
|
-
const [bestandsbilder, setBestandsbilder] = (0,
|
|
16403
|
-
const [laeuft, setLaeuft] = (0,
|
|
16404
|
-
const [lauf, setLauf] = (0,
|
|
16405
|
-
const [meldung, setMeldung] = (0,
|
|
16406
|
-
const [uebernommen, setUebernommen] = (0,
|
|
16407
|
-
const [titel, setTitel] = (0,
|
|
16408
|
-
const [referenzen, setReferenzen] = (0,
|
|
16409
|
-
const [beanstandung, setBeanstandung] = (0,
|
|
16410
|
-
const [zusatz, setZusatz] = (0,
|
|
16891
|
+
const [policyVersionId, setPolicyVersionId] = (0, import_react47.useState)("");
|
|
16892
|
+
const [modus, setModus] = (0, import_react47.useState)("prompt");
|
|
16893
|
+
const [promptText, setPromptText] = (0, import_react47.useState)("");
|
|
16894
|
+
const [dateien, setDateien] = (0, import_react47.useState)([]);
|
|
16895
|
+
const [bestandsbilder, setBestandsbilder] = (0, import_react47.useState)([]);
|
|
16896
|
+
const [laeuft, setLaeuft] = (0, import_react47.useState)(false);
|
|
16897
|
+
const [lauf, setLauf] = (0, import_react47.useState)(null);
|
|
16898
|
+
const [meldung, setMeldung] = (0, import_react47.useState)(null);
|
|
16899
|
+
const [uebernommen, setUebernommen] = (0, import_react47.useState)({});
|
|
16900
|
+
const [titel, setTitel] = (0, import_react47.useState)({});
|
|
16901
|
+
const [referenzen, setReferenzen] = (0, import_react47.useState)({});
|
|
16902
|
+
const [beanstandung, setBeanstandung] = (0, import_react47.useState)(null);
|
|
16903
|
+
const [zusatz, setZusatz] = (0, import_react47.useState)("");
|
|
16411
16904
|
const [regeln] = usePortQuery(
|
|
16412
16905
|
() => port.derivation.listPolicies(contextId),
|
|
16413
16906
|
[port, contextId]
|
|
16414
16907
|
);
|
|
16415
16908
|
const gewaehlt = regeln.status === "ready" ? regeln.value.find((r) => r.versionId === policyVersionId) ?? null : null;
|
|
16416
16909
|
async function starten(folgt) {
|
|
16417
|
-
if (!gewaehlt)
|
|
16910
|
+
if (!gewaehlt) {
|
|
16911
|
+
setMeldung("Bitte zuerst eine Rekonstruktionsregel waehlen \u2014 ohne sie ist kein Lauf reproduzierbar (D-03).");
|
|
16912
|
+
return;
|
|
16913
|
+
}
|
|
16418
16914
|
setLaeuft(true);
|
|
16419
16915
|
setMeldung(null);
|
|
16420
16916
|
setLauf(null);
|
|
@@ -16791,9 +17287,9 @@ var SzenenView = ({
|
|
|
16791
17287
|
initialArea,
|
|
16792
17288
|
onAreaChange
|
|
16793
17289
|
}) => {
|
|
16794
|
-
const bereiche = (0,
|
|
16795
|
-
const faehig = (0,
|
|
16796
|
-
const [aktiv, setAktiv] = (0,
|
|
17290
|
+
const bereiche = (0, import_react48.useMemo)(() => areasFor(port), [port]);
|
|
17291
|
+
const faehig = (0, import_react48.useMemo)(() => capabilitiesOf(port), [port]);
|
|
17292
|
+
const [aktiv, setAktiv] = (0, import_react48.useState)(() => resolveArea(port, initialArea));
|
|
16797
17293
|
const wechsle = (id) => {
|
|
16798
17294
|
setAktiv(id);
|
|
16799
17295
|
onAreaChange?.(id);
|
|
@@ -16824,7 +17320,16 @@ var SzenenView = ({
|
|
|
16824
17320
|
)) }),
|
|
16825
17321
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("section", { className: "szenen-view__area", "aria-label": aktuellerBereich.title, children: [
|
|
16826
17322
|
aktiv === "derive" && port.derivation && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(DeriveArea, { port, contextId }),
|
|
16827
|
-
aktiv === "elements" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
17323
|
+
aktiv === "elements" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
17324
|
+
ElementsArea,
|
|
17325
|
+
{
|
|
17326
|
+
port,
|
|
17327
|
+
contextId,
|
|
17328
|
+
restrictToTypes: BAUSTEIN_TYPES,
|
|
17329
|
+
allTypesLabel: "alle Bausteine",
|
|
17330
|
+
listTitle: "Bausteine"
|
|
17331
|
+
}
|
|
17332
|
+
),
|
|
16828
17333
|
aktiv === "scene" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SceneArea, { port, contextId }),
|
|
16829
17334
|
aktiv === "setup" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SetupArea, { port, contextId }),
|
|
16830
17335
|
aktiv === "shot" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ShotArea, { port, contextId }),
|
|
@@ -16839,6 +17344,17 @@ var SzenenView = ({
|
|
|
16839
17344
|
};
|
|
16840
17345
|
|
|
16841
17346
|
// src/lib/szenen/flowTextGenerationPort.ts
|
|
17347
|
+
function alsFlowTextZugang(sdk) {
|
|
17348
|
+
return async (prompt, options) => {
|
|
17349
|
+
const antwort = await sdk(prompt, options);
|
|
17350
|
+
if (typeof antwort?.text !== "string") {
|
|
17351
|
+
throw new Error(
|
|
17352
|
+
`Flow.generate.text lieferte kein { text: string }, sondern ${antwort === null || antwort === void 0 ? String(antwort) : typeof antwort}: ${JSON.stringify(antwort)?.slice(0, 200)}`
|
|
17353
|
+
);
|
|
17354
|
+
}
|
|
17355
|
+
return antwort.text;
|
|
17356
|
+
};
|
|
17357
|
+
}
|
|
16842
17358
|
function createFlowTextGenerationPort(generateText, options = {}) {
|
|
16843
17359
|
const provider = options.provider ?? "flow";
|
|
16844
17360
|
const modelId = options.modelId ?? "flow.generate.text";
|
|
@@ -17602,7 +18118,7 @@ var CHAIN_EDGES = {
|
|
|
17602
18118
|
scene_ref: { from: "scene_setup", to: "scene" },
|
|
17603
18119
|
scene_setup_ref: { from: "shot", to: "scene_setup" }
|
|
17604
18120
|
};
|
|
17605
|
-
function
|
|
18121
|
+
function istText3(wert) {
|
|
17606
18122
|
return typeof wert === "string" && wert.trim().length > 0;
|
|
17607
18123
|
}
|
|
17608
18124
|
function checkDraftChainMeta(meta, type) {
|
|
@@ -17613,14 +18129,14 @@ function checkDraftChainMeta(meta, type) {
|
|
|
17613
18129
|
};
|
|
17614
18130
|
}
|
|
17615
18131
|
const m = meta;
|
|
17616
|
-
if (!
|
|
17617
|
-
if (!
|
|
18132
|
+
if (!istText3(m.chain_id)) return { ok: false, message: '"chain_id" fehlt oder ist leer.' };
|
|
18133
|
+
if (!istText3(m.source_run_id)) {
|
|
17618
18134
|
return {
|
|
17619
18135
|
ok: false,
|
|
17620
18136
|
message: '"source_run_id" fehlt oder ist leer \u2014 ohne sie ist die Herkunft eines Kettenknotens nicht rekonstruierbar (D-96/B3).'
|
|
17621
18137
|
};
|
|
17622
18138
|
}
|
|
17623
|
-
if (m.source_recovery_id !== void 0 && !
|
|
18139
|
+
if (m.source_recovery_id !== void 0 && !istText3(m.source_recovery_id)) {
|
|
17624
18140
|
return { ok: false, message: '"source_recovery_id" ist gesetzt, aber leer.' };
|
|
17625
18141
|
}
|
|
17626
18142
|
if (!Array.isArray(m.links)) {
|
|
@@ -17645,7 +18161,7 @@ function checkDraftChainMeta(meta, type) {
|
|
|
17645
18161
|
message: `"${l.field}" gehoert an einen ${kante.from}, nicht an einen ${type}.`
|
|
17646
18162
|
};
|
|
17647
18163
|
}
|
|
17648
|
-
if (!
|
|
18164
|
+
if (!istText3(l.target_element_id) || !istText3(l.target_draft_id)) {
|
|
17649
18165
|
return {
|
|
17650
18166
|
ok: false,
|
|
17651
18167
|
message: `"links[${index}]" braucht target_element_id und target_draft_id.`
|
|
@@ -18292,12 +18808,12 @@ function createHfEventChannel(options) {
|
|
|
18292
18808
|
// src/lib/szenen/resolve.ts
|
|
18293
18809
|
var ResolveTechnicalError = class extends Error {
|
|
18294
18810
|
};
|
|
18295
|
-
var
|
|
18296
|
-
var
|
|
18811
|
+
var isObject11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
18812
|
+
var asArray3 = (v) => Array.isArray(v) ? v : [];
|
|
18297
18813
|
var str = (v) => typeof v === "string" ? v : null;
|
|
18298
18814
|
var num = (v) => typeof v === "number" ? v : null;
|
|
18299
18815
|
async function refOf(resolver, ref, expected, path) {
|
|
18300
|
-
const versionId =
|
|
18816
|
+
const versionId = isObject11(ref) ? str(ref.version_id) : null;
|
|
18301
18817
|
if (!versionId) {
|
|
18302
18818
|
return {
|
|
18303
18819
|
ok: false,
|
|
@@ -18349,8 +18865,11 @@ async function refOf(resolver, ref, expected, path) {
|
|
|
18349
18865
|
}
|
|
18350
18866
|
return { ok: true, version: version2 };
|
|
18351
18867
|
}
|
|
18868
|
+
function ausgelassen(diagnostics, code, path, message) {
|
|
18869
|
+
diagnostics.push({ code, origin: "resolution", path, message });
|
|
18870
|
+
}
|
|
18352
18871
|
function entraeumlichtePlatzierung(placement, assumptions) {
|
|
18353
|
-
if (!
|
|
18872
|
+
if (!isObject11(placement)) return null;
|
|
18354
18873
|
if (placement.mode !== "pattern") {
|
|
18355
18874
|
assumptions.push(
|
|
18356
18875
|
`Die Kameraplatzierung (mode "${str(placement.mode) ?? "unbekannt"}") ist metrisch und entfaellt ohne can_place. Der Renderer darf daraus keine Position ableiten.`
|
|
@@ -18365,7 +18884,7 @@ function entraeumlichtePlatzierung(placement, assumptions) {
|
|
|
18365
18884
|
const entfallen = [];
|
|
18366
18885
|
if (placement.offsets !== void 0) entfallen.push("offsets");
|
|
18367
18886
|
const height = placement.height;
|
|
18368
|
-
if (
|
|
18887
|
+
if (isObject11(height)) {
|
|
18369
18888
|
if (height.mode === "anchor") {
|
|
18370
18889
|
const behalteneHoehe = {
|
|
18371
18890
|
mode: "anchor",
|
|
@@ -18444,142 +18963,328 @@ async function resolveShotPayload(input) {
|
|
|
18444
18963
|
chain
|
|
18445
18964
|
} = input;
|
|
18446
18965
|
const assumptions = [];
|
|
18447
|
-
const
|
|
18448
|
-
|
|
18449
|
-
element_id: shotElementId,
|
|
18450
|
-
payload: shotPayload
|
|
18451
|
-
};
|
|
18452
|
-
const shotErrors = ohneKettenReferenz(
|
|
18453
|
-
validatePayload("shot", shotVersion.payload).errors,
|
|
18454
|
-
chain ? "scene_setup_ref" : null
|
|
18455
|
-
);
|
|
18456
|
-
if (shotErrors.length > 0) {
|
|
18966
|
+
const diagnostics = [];
|
|
18967
|
+
if (!isObject11(shotPayload)) {
|
|
18457
18968
|
return {
|
|
18458
18969
|
kind: "rejected",
|
|
18459
18970
|
failure: {
|
|
18460
18971
|
class: "schema",
|
|
18461
18972
|
where: "shot",
|
|
18462
|
-
message: `Die Shot-Payload
|
|
18463
|
-
errors:
|
|
18973
|
+
message: `Die Shot-Payload ist kein Objekt, sondern ${Array.isArray(shotPayload) ? "ein Array" : typeof shotPayload}. Daraus laesst sich kein Auftrag herstellen.`,
|
|
18974
|
+
errors: []
|
|
18975
|
+
}
|
|
18976
|
+
};
|
|
18977
|
+
}
|
|
18978
|
+
const shot = shotPayload;
|
|
18979
|
+
for (const fehler4 of ohneKettenReferenz(
|
|
18980
|
+
validatePayload("shot", shotPayload).errors,
|
|
18981
|
+
chain ? "scene_setup_ref" : null
|
|
18982
|
+
)) {
|
|
18983
|
+
diagnostics.push(diagnosticOfSchemaError(fehler4, `Shot ${shotElementId}`));
|
|
18984
|
+
}
|
|
18985
|
+
let setup = null;
|
|
18986
|
+
let report = null;
|
|
18987
|
+
let canPlace = false;
|
|
18988
|
+
let capabilities;
|
|
18989
|
+
let scene;
|
|
18990
|
+
const nenntSetup = chain !== void 0 || shot.scene_setup_ref !== void 0;
|
|
18991
|
+
if (!nenntSetup) {
|
|
18992
|
+
return {
|
|
18993
|
+
kind: "rejected",
|
|
18994
|
+
failure: {
|
|
18995
|
+
class: "no_content",
|
|
18996
|
+
message: `Der Shot ${shotElementId} nennt kein scene_setup_ref und fuehrt keine Draft-Kette. Ohne Setup gibt es keinen Weg zu einer Szene und damit keinen beschreibbaren Inhalt.`
|
|
18464
18997
|
}
|
|
18465
18998
|
};
|
|
18466
18999
|
}
|
|
18467
|
-
const shot = shotVersion.payload;
|
|
18468
19000
|
const setupRef = chain ? { ok: true, version: chain.setup } : await refOf(resolver, shot.scene_setup_ref, "scene_setup", "/scene_setup_ref");
|
|
18469
19001
|
if (!setupRef.ok) return { kind: "rejected", failure: setupRef.failure };
|
|
18470
|
-
|
|
18471
|
-
validatePayload("scene_setup", setupRef.version.payload).errors,
|
|
18472
|
-
chain ? "scene_ref" : null
|
|
18473
|
-
);
|
|
18474
|
-
if (setupErrors.length > 0) {
|
|
19002
|
+
if (!isObject11(setupRef.version.payload)) {
|
|
18475
19003
|
return {
|
|
18476
19004
|
kind: "rejected",
|
|
18477
19005
|
failure: {
|
|
18478
19006
|
class: "schema",
|
|
18479
19007
|
where: "scene_setup",
|
|
18480
|
-
message: `Die Scene-Setup-Payload
|
|
18481
|
-
errors:
|
|
19008
|
+
message: `Die Scene-Setup-Payload ist kein Objekt, sondern ${Array.isArray(setupRef.version.payload) ? "ein Array" : typeof setupRef.version.payload}.`,
|
|
19009
|
+
errors: []
|
|
18482
19010
|
}
|
|
18483
19011
|
};
|
|
18484
19012
|
}
|
|
18485
|
-
|
|
18486
|
-
|
|
19013
|
+
setup = {
|
|
19014
|
+
element_id: setupRef.version.element_id,
|
|
19015
|
+
version_id: setupRef.version.version_id,
|
|
19016
|
+
payload: setupRef.version.payload
|
|
19017
|
+
};
|
|
19018
|
+
report = await capabilityReport({
|
|
18487
19019
|
type: "scene_setup",
|
|
18488
|
-
setupPayload: setup,
|
|
18489
|
-
elementId:
|
|
19020
|
+
setupPayload: setup.payload,
|
|
19021
|
+
elementId: setup.element_id,
|
|
18490
19022
|
resolver,
|
|
18491
19023
|
// Bei einer Draft-Kette kommt die Szene von hier, nicht aus `scene_ref`
|
|
18492
19024
|
// (C1). Dasselbe Regelwerk, ein anderer Weg zur selben Szene.
|
|
18493
19025
|
...chain ? { chainScene: chain.scene.payload } : {}
|
|
18494
19026
|
});
|
|
18495
|
-
|
|
18496
|
-
|
|
18497
|
-
const placeGate = capabilityGate(report, "can_place");
|
|
18498
|
-
if (placeGate && placeGate.class === "capability_undetermined") {
|
|
18499
|
-
return { kind: "rejected", failure: placeGate };
|
|
18500
|
-
}
|
|
18501
|
-
const canPlace = report.can_place.state === "yes";
|
|
19027
|
+
diagnostics.push(...report.promptDiagnostics);
|
|
19028
|
+
canPlace = report.can_place.state === "yes";
|
|
18502
19029
|
if (!canPlace) {
|
|
18503
19030
|
assumptions.push(
|
|
18504
|
-
|
|
19031
|
+
`can_place ist "${report.can_place.state}" \u2014 alle Platzierungen bleiben null. Der Renderer darf daraus keine Koordinaten ableiten (D-47).`
|
|
18505
19032
|
);
|
|
18506
19033
|
}
|
|
18507
|
-
|
|
19034
|
+
capabilities = {
|
|
19035
|
+
can_describe_scene: report.can_describe_scene.state,
|
|
19036
|
+
can_render_prompt: report.can_render_prompt.state,
|
|
19037
|
+
can_place: report.can_place.state
|
|
19038
|
+
};
|
|
19039
|
+
const sceneRef = chain ? { ok: true, version: chain.scene } : await refOf(resolver, setup.payload.scene_ref, "scene", "/scene_ref");
|
|
18508
19040
|
if (!sceneRef.ok) return { kind: "rejected", failure: sceneRef.failure };
|
|
18509
|
-
|
|
18510
|
-
const cameraId = str(shot.camera_id) ?? "";
|
|
18511
|
-
const rig = isObject10(setup.camera_rig) ? setup.camera_rig : {};
|
|
18512
|
-
const cameras = asArray2(rig.cameras);
|
|
18513
|
-
const cameraIndex = cameras.findIndex(
|
|
18514
|
-
(camera2) => isObject10(camera2) && camera2.camera_id === cameraId
|
|
18515
|
-
);
|
|
18516
|
-
if (cameraIndex < 0) {
|
|
19041
|
+
if (!isObject11(sceneRef.version.payload)) {
|
|
18517
19042
|
return {
|
|
18518
19043
|
kind: "rejected",
|
|
18519
19044
|
failure: {
|
|
18520
|
-
class: "
|
|
18521
|
-
|
|
18522
|
-
|
|
18523
|
-
|
|
18524
|
-
reason: "unknown"
|
|
19045
|
+
class: "schema",
|
|
19046
|
+
where: "scene",
|
|
19047
|
+
message: `Die Szenen-Payload ist kein Objekt, sondern ${Array.isArray(sceneRef.version.payload) ? "ein Array" : typeof sceneRef.version.payload}.`,
|
|
19048
|
+
errors: []
|
|
18525
19049
|
}
|
|
18526
19050
|
};
|
|
18527
19051
|
}
|
|
18528
|
-
|
|
18529
|
-
|
|
19052
|
+
scene = {
|
|
19053
|
+
element_id: sceneRef.version.element_id,
|
|
19054
|
+
version_id: sceneRef.version.version_id,
|
|
19055
|
+
payload: sceneRef.version.payload
|
|
19056
|
+
};
|
|
19057
|
+
return komponiere({
|
|
19058
|
+
shot: { element_id: shotElementId, version_id: shotVersionId, payload: shot },
|
|
19059
|
+
setup,
|
|
19060
|
+
scene,
|
|
19061
|
+
report,
|
|
19062
|
+
capabilities,
|
|
19063
|
+
canPlace,
|
|
18530
19064
|
resolver,
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
18545
|
-
|
|
18546
|
-
|
|
18547
|
-
|
|
18548
|
-
|
|
18549
|
-
|
|
18550
|
-
|
|
18551
|
-
|
|
18552
|
-
|
|
18553
|
-
|
|
18554
|
-
|
|
18555
|
-
|
|
18556
|
-
if (!conceptRef.ok) return { kind: "rejected", failure: conceptRef.failure };
|
|
18557
|
-
shotConcept = conceptRef.version.payload;
|
|
19065
|
+
contextChain,
|
|
19066
|
+
userInstruction,
|
|
19067
|
+
assumptions,
|
|
19068
|
+
diagnostics
|
|
19069
|
+
});
|
|
19070
|
+
}
|
|
19071
|
+
async function resolveScenePayload(input) {
|
|
19072
|
+
const {
|
|
19073
|
+
scenePayload,
|
|
19074
|
+
sceneElementId,
|
|
19075
|
+
sceneVersionId = "",
|
|
19076
|
+
resolver,
|
|
19077
|
+
contextChain,
|
|
19078
|
+
userInstruction
|
|
19079
|
+
} = input;
|
|
19080
|
+
if (!isObject11(scenePayload)) {
|
|
19081
|
+
return {
|
|
19082
|
+
kind: "rejected",
|
|
19083
|
+
failure: {
|
|
19084
|
+
class: "schema",
|
|
19085
|
+
where: "scene",
|
|
19086
|
+
message: `Die Szenen-Payload ist kein Objekt, sondern ${Array.isArray(scenePayload) ? "ein Array" : typeof scenePayload}.`,
|
|
19087
|
+
errors: []
|
|
19088
|
+
}
|
|
19089
|
+
};
|
|
18558
19090
|
}
|
|
18559
|
-
const
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
18564
|
-
|
|
18565
|
-
|
|
18566
|
-
|
|
19091
|
+
const assumptions = [
|
|
19092
|
+
"Kein Scene Setup, kein Shot: Der Lauf entsteht aus der Szene allein. Bildaufbau, Kamera und Zielmodell wurden nicht ergaenzt, sondern sind nicht vorhanden (D-135)."
|
|
19093
|
+
];
|
|
19094
|
+
const diagnostics = [];
|
|
19095
|
+
for (const fehler4 of validatePayload("scene", scenePayload).errors) {
|
|
19096
|
+
diagnostics.push(diagnosticOfSchemaError(fehler4, `Szene ${sceneElementId}`));
|
|
19097
|
+
}
|
|
19098
|
+
const faehig = sceneOnlyCapabilities(scenePayload);
|
|
19099
|
+
return komponiere({
|
|
19100
|
+
shot: null,
|
|
19101
|
+
setup: null,
|
|
19102
|
+
scene: { element_id: sceneElementId, version_id: sceneVersionId, payload: scenePayload },
|
|
19103
|
+
report: null,
|
|
19104
|
+
capabilities: {
|
|
19105
|
+
can_describe_scene: faehig.can_describe_scene.state,
|
|
19106
|
+
can_render_prompt: faehig.can_render_prompt.state,
|
|
19107
|
+
can_place: faehig.can_place.state
|
|
19108
|
+
},
|
|
19109
|
+
canPlace: false,
|
|
19110
|
+
resolver,
|
|
19111
|
+
contextChain,
|
|
19112
|
+
userInstruction,
|
|
19113
|
+
assumptions,
|
|
19114
|
+
diagnostics
|
|
19115
|
+
});
|
|
19116
|
+
}
|
|
19117
|
+
async function komponiere(z) {
|
|
19118
|
+
const {
|
|
19119
|
+
shot,
|
|
19120
|
+
setup,
|
|
19121
|
+
scene,
|
|
19122
|
+
report,
|
|
19123
|
+
capabilities,
|
|
19124
|
+
canPlace,
|
|
19125
|
+
resolver,
|
|
19126
|
+
contextChain,
|
|
19127
|
+
userInstruction,
|
|
19128
|
+
assumptions,
|
|
19129
|
+
diagnostics
|
|
19130
|
+
} = z;
|
|
19131
|
+
const inhalt = describableContent(scene.payload);
|
|
19132
|
+
if (!inhalt.ok) {
|
|
19133
|
+
return {
|
|
19134
|
+
kind: "rejected",
|
|
19135
|
+
failure: {
|
|
19136
|
+
class: "no_content",
|
|
19137
|
+
message: `Szene ${scene.element_id}: ${inhalt.message}`
|
|
19138
|
+
}
|
|
19139
|
+
};
|
|
19140
|
+
}
|
|
19141
|
+
const eingefroreneFaehigkeiten = {
|
|
19142
|
+
...capabilities,
|
|
19143
|
+
can_render_prompt: "yes"
|
|
19144
|
+
};
|
|
19145
|
+
const shotOverrides = shot && isObject11(shot.payload.overrides) ? shot.payload.overrides : {};
|
|
19146
|
+
const settings = shot && isObject11(shot.payload.prompt_render_settings) ? shot.payload.prompt_render_settings : {};
|
|
19147
|
+
let camera = null;
|
|
19148
|
+
if (shot && setup) {
|
|
19149
|
+
const cameraId = str(shot.payload.camera_id);
|
|
19150
|
+
const rig = isObject11(setup.payload.camera_rig) ? setup.payload.camera_rig : {};
|
|
19151
|
+
const cameras = asArray3(rig.cameras);
|
|
19152
|
+
const cameraIndex = cameraId === null ? -1 : cameras.findIndex((c) => isObject11(c) && c.camera_id === cameraId);
|
|
19153
|
+
if (cameraId === null) {
|
|
19154
|
+
ausgelassen(
|
|
19155
|
+
diagnostics,
|
|
19156
|
+
"P-01",
|
|
19157
|
+
"/camera_id",
|
|
19158
|
+
`Der Shot ${shot.element_id} nennt keine camera_id. Der Prompt entsteht ohne Kameravorgabe; eine Kamera wird nicht erfunden (D-75).`
|
|
19159
|
+
);
|
|
19160
|
+
} else if (cameraIndex < 0) {
|
|
19161
|
+
ausgelassen(
|
|
19162
|
+
diagnostics,
|
|
19163
|
+
"P-01",
|
|
19164
|
+
"/camera_id",
|
|
19165
|
+
`Die aktive camera_id "${cameraId}" kommt im Rig der Scene-Setup-Version ${setup.version_id} nicht vor. Der Prompt entsteht ohne Kameravorgabe.`
|
|
19166
|
+
);
|
|
19167
|
+
} else {
|
|
19168
|
+
const rohKamera = cameras[cameraIndex];
|
|
19169
|
+
let preset = null;
|
|
19170
|
+
const presetRef = await refOf(
|
|
19171
|
+
resolver,
|
|
19172
|
+
rohKamera.preset_ref,
|
|
19173
|
+
"camera_preset",
|
|
19174
|
+
`/camera_rig/cameras/${cameraIndex}/preset_ref`
|
|
19175
|
+
);
|
|
19176
|
+
if (presetRef.ok) preset = presetRef.version.payload;
|
|
19177
|
+
else {
|
|
19178
|
+
ausgelassen(
|
|
19179
|
+
diagnostics,
|
|
19180
|
+
"P-04",
|
|
19181
|
+
`/camera_rig/cameras/${cameraIndex}/preset_ref`,
|
|
19182
|
+
`${presetRef.failure.message} Die Kamera geht ohne Preset in den Prompt.`
|
|
19183
|
+
);
|
|
19184
|
+
}
|
|
19185
|
+
let pattern = null;
|
|
19186
|
+
const placementSpec = isObject11(rohKamera.placement) ? rohKamera.placement : null;
|
|
19187
|
+
if (placementSpec && isObject11(placementSpec.pattern_ref)) {
|
|
19188
|
+
const patternRef = await refOf(
|
|
19189
|
+
resolver,
|
|
19190
|
+
placementSpec.pattern_ref,
|
|
19191
|
+
"camera_pattern",
|
|
19192
|
+
`/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`
|
|
19193
|
+
);
|
|
19194
|
+
if (patternRef.ok) pattern = patternRef.version.payload;
|
|
19195
|
+
else {
|
|
19196
|
+
ausgelassen(
|
|
19197
|
+
diagnostics,
|
|
19198
|
+
"P-04",
|
|
19199
|
+
`/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`,
|
|
19200
|
+
`${patternRef.failure.message} Das Kameramuster entfaellt im Prompt.`
|
|
19201
|
+
);
|
|
19202
|
+
}
|
|
19203
|
+
}
|
|
19204
|
+
const cameraPlacement = canPlace ? rohKamera.placement ?? null : entraeumlichtePlatzierung(rohKamera.placement, assumptions);
|
|
19205
|
+
camera = {
|
|
19206
|
+
camera_id: cameraId,
|
|
19207
|
+
name: str(rohKamera.name),
|
|
19208
|
+
preset,
|
|
19209
|
+
placement: cameraPlacement,
|
|
19210
|
+
orientation: rohKamera.orientation ?? null,
|
|
19211
|
+
// Der Shot darf Bildgroesse und Fokus ueberschreiben (D-40) — das ist
|
|
19212
|
+
// die oberste Stufe der Vorrangkette.
|
|
19213
|
+
framing: shotOverrides.framing ?? rohKamera.framing ?? null,
|
|
19214
|
+
focus: shotOverrides.focus !== void 0 ? shotOverrides.focus : rohKamera.focus ?? null,
|
|
19215
|
+
pattern
|
|
19216
|
+
};
|
|
19217
|
+
}
|
|
19218
|
+
} else if (shot && !setup) {
|
|
19219
|
+
ausgelassen(
|
|
19220
|
+
diagnostics,
|
|
19221
|
+
"P-01",
|
|
19222
|
+
"/camera_id",
|
|
19223
|
+
"Ohne Scene Setup gibt es kein Camera Rig. Der Prompt entsteht ohne Kameravorgabe."
|
|
19224
|
+
);
|
|
19225
|
+
}
|
|
19226
|
+
let shotConcept = null;
|
|
19227
|
+
if (shot && isObject11(shot.payload.shot_concept_ref)) {
|
|
19228
|
+
const conceptRef = await refOf(
|
|
19229
|
+
resolver,
|
|
19230
|
+
shot.payload.shot_concept_ref,
|
|
19231
|
+
"shot_concept",
|
|
19232
|
+
"/shot_concept_ref"
|
|
19233
|
+
);
|
|
19234
|
+
if (conceptRef.ok) shotConcept = conceptRef.version.payload;
|
|
19235
|
+
else {
|
|
19236
|
+
ausgelassen(
|
|
19237
|
+
diagnostics,
|
|
19238
|
+
"P-04",
|
|
19239
|
+
"/shot_concept_ref",
|
|
19240
|
+
`${conceptRef.failure.message} Das Shot Concept entfaellt im Prompt.`
|
|
19241
|
+
);
|
|
19242
|
+
}
|
|
19243
|
+
}
|
|
19244
|
+
const styles = [];
|
|
19245
|
+
for (const [ebene, refs] of [
|
|
19246
|
+
["scene_setup", setup ? asArray3(setup.payload.style_refs) : []],
|
|
19247
|
+
["shot", shot ? asArray3(shot.payload.style_refs) : []]
|
|
19248
|
+
]) {
|
|
19249
|
+
for (const [i, ref] of refs.entries()) {
|
|
19250
|
+
const resolved = await refOf(resolver, ref, "style", `/${ebene}/style_refs/${i}`);
|
|
19251
|
+
if (!resolved.ok) {
|
|
19252
|
+
ausgelassen(
|
|
19253
|
+
diagnostics,
|
|
19254
|
+
"P-04",
|
|
19255
|
+
`/${ebene}/style_refs/${i}`,
|
|
19256
|
+
`${resolved.failure.message} Dieser Stil entfaellt im Prompt.`
|
|
19257
|
+
);
|
|
19258
|
+
continue;
|
|
19259
|
+
}
|
|
18567
19260
|
const payload = resolved.version.payload;
|
|
18568
19261
|
styles.push({
|
|
18569
|
-
role: str(
|
|
18570
|
-
rank: num(
|
|
18571
|
-
weight: num(
|
|
19262
|
+
role: str(isObject11(ref) ? ref.role : null) ?? str(payload.role) ?? "unspecified",
|
|
19263
|
+
rank: num(isObject11(ref) ? ref.rank : null) ?? 0,
|
|
19264
|
+
weight: num(isObject11(ref) ? ref.weight : null),
|
|
18572
19265
|
text: str(payload.text) ?? "",
|
|
18573
19266
|
locale: str(payload.locale)
|
|
18574
19267
|
});
|
|
18575
19268
|
}
|
|
18576
19269
|
}
|
|
18577
19270
|
styles.sort((a, b) => a.rank - b.rank);
|
|
18578
|
-
const settings = isObject10(shot.prompt_render_settings) ? shot.prompt_render_settings : {};
|
|
18579
19271
|
const policies = [];
|
|
18580
|
-
for (const [i, ref] of
|
|
18581
|
-
const resolved = await refOf(
|
|
18582
|
-
|
|
19272
|
+
for (const [i, ref] of asArray3(settings.policy_refs).entries()) {
|
|
19273
|
+
const resolved = await refOf(
|
|
19274
|
+
resolver,
|
|
19275
|
+
ref,
|
|
19276
|
+
"prompt_policy",
|
|
19277
|
+
`/prompt_render_settings/policy_refs/${i}`
|
|
19278
|
+
);
|
|
19279
|
+
if (!resolved.ok) {
|
|
19280
|
+
ausgelassen(
|
|
19281
|
+
diagnostics,
|
|
19282
|
+
"P-04",
|
|
19283
|
+
`/prompt_render_settings/policy_refs/${i}`,
|
|
19284
|
+
`${resolved.failure.message} Diese Policy entfaellt im Prompt.`
|
|
19285
|
+
);
|
|
19286
|
+
continue;
|
|
19287
|
+
}
|
|
18583
19288
|
const payload = resolved.version.payload;
|
|
18584
19289
|
policies.push({
|
|
18585
19290
|
subtype: str(payload.subtype) ?? "general",
|
|
@@ -18590,14 +19295,22 @@ async function resolveShotPayload(input) {
|
|
|
18590
19295
|
}
|
|
18591
19296
|
policies.sort((a, b) => a.rank - b.rank);
|
|
18592
19297
|
const fragments = [];
|
|
18593
|
-
for (const [i, ref] of
|
|
19298
|
+
for (const [i, ref] of asArray3(settings.fragment_refs).entries()) {
|
|
18594
19299
|
const resolved = await refOf(
|
|
18595
19300
|
resolver,
|
|
18596
19301
|
ref,
|
|
18597
19302
|
"prompt_fragment",
|
|
18598
19303
|
`/prompt_render_settings/fragment_refs/${i}`
|
|
18599
19304
|
);
|
|
18600
|
-
if (!resolved.ok)
|
|
19305
|
+
if (!resolved.ok) {
|
|
19306
|
+
ausgelassen(
|
|
19307
|
+
diagnostics,
|
|
19308
|
+
"P-04",
|
|
19309
|
+
`/prompt_render_settings/fragment_refs/${i}`,
|
|
19310
|
+
`${resolved.failure.message} Dieses Fragment entfaellt im Prompt.`
|
|
19311
|
+
);
|
|
19312
|
+
continue;
|
|
19313
|
+
}
|
|
18601
19314
|
const payload = resolved.version.payload;
|
|
18602
19315
|
fragments.push({
|
|
18603
19316
|
channel: str(payload.channel) ?? "positive",
|
|
@@ -18607,83 +19320,102 @@ async function resolveShotPayload(input) {
|
|
|
18607
19320
|
});
|
|
18608
19321
|
}
|
|
18609
19322
|
fragments.sort((a, b) => a.rank - b.rank);
|
|
18610
|
-
|
|
18611
|
-
|
|
18612
|
-
|
|
18613
|
-
|
|
18614
|
-
|
|
18615
|
-
|
|
18616
|
-
|
|
18617
|
-
|
|
18618
|
-
}
|
|
18619
|
-
|
|
18620
|
-
}
|
|
18621
|
-
if (!resolver.resolveTargetModel) {
|
|
19323
|
+
let targetModelPayload = null;
|
|
19324
|
+
let targetModelResolution = null;
|
|
19325
|
+
const key = shot ? str(settings.target_model_id) : null;
|
|
19326
|
+
if (key === null) {
|
|
19327
|
+
ausgelassen(
|
|
19328
|
+
diagnostics,
|
|
19329
|
+
"P-17",
|
|
19330
|
+
"/prompt_render_settings/target_model_id",
|
|
19331
|
+
shot ? `Der Shot ${shot.element_id} nennt kein target_model_id. Der Prompt wird generisch abgeleitet, ohne Modelloptimierung.` : "Ohne Shot gibt es kein target_model_id. Der Prompt wird generisch abgeleitet, ohne Modelloptimierung."
|
|
19332
|
+
);
|
|
19333
|
+
} else if (!resolver.resolveTargetModel) {
|
|
18622
19334
|
throw new ResolveTechnicalError(
|
|
18623
19335
|
`Der Resolver bietet keine Zielmodellsuche an (kein ContextChainPort). Ein Lauf ohne Kontextkette wuerde ein Zielmodell melden, das nicht das gesuchte ist.`
|
|
18624
19336
|
);
|
|
18625
|
-
}
|
|
18626
|
-
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
|
|
18633
|
-
|
|
19337
|
+
} else {
|
|
19338
|
+
const targetModel = await resolver.resolveTargetModel(key, shot.element_id);
|
|
19339
|
+
if (targetModel.kind !== "resolved") {
|
|
19340
|
+
ausgelassen(
|
|
19341
|
+
diagnostics,
|
|
19342
|
+
"P-17",
|
|
19343
|
+
"/prompt_render_settings/target_model_id",
|
|
19344
|
+
`${describeTargetModelFailure(targetModel)} Der Prompt wird generisch abgeleitet, ohne Modelloptimierung.`
|
|
19345
|
+
);
|
|
19346
|
+
} else {
|
|
19347
|
+
targetModelPayload = targetModel.payload;
|
|
19348
|
+
targetModelResolution = {
|
|
19349
|
+
element_id: targetModel.elementId,
|
|
19350
|
+
version_id: targetModel.versionId,
|
|
19351
|
+
chain_index: targetModel.chainIndex,
|
|
19352
|
+
head: targetModel.head,
|
|
19353
|
+
shadowed_retired: targetModel.shadowedRetired.map((entry) => ({
|
|
19354
|
+
element_id: entry.elementId,
|
|
19355
|
+
context_id: entry.contextId
|
|
19356
|
+
}))
|
|
19357
|
+
};
|
|
19358
|
+
for (const uebergangen of targetModel.shadowedRetired) {
|
|
19359
|
+
assumptions.push(
|
|
19360
|
+
`Ein stillgelegtes target_model (${uebergangen.elementId}, Kontext ${uebergangen.contextId ?? "global"}) wurde uebergangen; verwendet wird ${targetModel.elementId} von Kettenglied ${targetModel.chainIndex}.`
|
|
19361
|
+
);
|
|
18634
19362
|
}
|
|
18635
|
-
|
|
18636
|
-
|
|
18637
|
-
|
|
18638
|
-
|
|
18639
|
-
|
|
18640
|
-
|
|
18641
|
-
}
|
|
18642
|
-
if (targetModel.head.kind === "selected" && targetModel.head.stale) {
|
|
18643
|
-
assumptions.push(
|
|
18644
|
-
`Die Auswahl des Zielmodell-Heads (${targetModel.versionId}) ist veraltet \u2014 es gibt neuere Heads. Die Auswahl gilt, weil sie getroffen wurde (D-36).`
|
|
18645
|
-
);
|
|
19363
|
+
if (targetModel.head.kind === "selected" && targetModel.head.stale) {
|
|
19364
|
+
assumptions.push(
|
|
19365
|
+
`Die Auswahl des Zielmodell-Heads (${targetModel.versionId}) ist veraltet \u2014 es gibt neuere Heads. Die Auswahl gilt, weil sie getroffen wurde (D-36).`
|
|
19366
|
+
);
|
|
19367
|
+
}
|
|
19368
|
+
}
|
|
18646
19369
|
}
|
|
18647
19370
|
const overrides = /* @__PURE__ */ new Map();
|
|
18648
|
-
for (const entry of
|
|
18649
|
-
if (
|
|
19371
|
+
for (const entry of setup ? asArray3(setup.payload.node_overrides) : []) {
|
|
19372
|
+
if (isObject11(entry) && typeof entry.node_id === "string") overrides.set(entry.node_id, entry);
|
|
18650
19373
|
}
|
|
18651
19374
|
const placements = /* @__PURE__ */ new Map();
|
|
18652
|
-
for (const entry of
|
|
18653
|
-
if (!
|
|
19375
|
+
for (const entry of setup ? asArray3(setup.payload.placements) : []) {
|
|
19376
|
+
if (!isObject11(entry) || typeof entry.node_id !== "string") continue;
|
|
18654
19377
|
placements.set(entry.node_id, {
|
|
18655
|
-
position:
|
|
18656
|
-
...entry.rotation_euler_deg ? { rotation_euler_deg:
|
|
18657
|
-
...entry.scale ? { scale:
|
|
19378
|
+
position: asArray3(entry.position),
|
|
19379
|
+
...entry.rotation_euler_deg ? { rotation_euler_deg: asArray3(entry.rotation_euler_deg) } : {},
|
|
19380
|
+
...entry.scale ? { scale: asArray3(entry.scale) } : {}
|
|
18658
19381
|
});
|
|
18659
19382
|
}
|
|
18660
|
-
const
|
|
18661
|
-
|
|
19383
|
+
const hidden = new Set(
|
|
19384
|
+
asArray3(shotOverrides.hidden_nodes).filter((v) => typeof v === "string")
|
|
19385
|
+
);
|
|
18662
19386
|
const nodes = [];
|
|
18663
|
-
for (const raw of
|
|
18664
|
-
if (!
|
|
19387
|
+
for (const raw of asArray3(scene.payload.nodes)) {
|
|
19388
|
+
if (!isObject11(raw) || typeof raw.node_id !== "string") continue;
|
|
18665
19389
|
const nodeId = raw.node_id;
|
|
18666
19390
|
const contributions = [];
|
|
18667
|
-
for (const [i, ref] of
|
|
19391
|
+
for (const [i, ref] of asArray3(raw.component_refs).entries()) {
|
|
18668
19392
|
const resolved = await refOf(
|
|
18669
19393
|
resolver,
|
|
18670
19394
|
ref,
|
|
18671
19395
|
"scene_component",
|
|
18672
19396
|
`/nodes/${nodeId}/component_refs/${i}`
|
|
18673
19397
|
);
|
|
18674
|
-
if (!resolved.ok)
|
|
19398
|
+
if (!resolved.ok) {
|
|
19399
|
+
ausgelassen(
|
|
19400
|
+
diagnostics,
|
|
19401
|
+
"P-05",
|
|
19402
|
+
`/nodes/${nodeId}/component_refs/${i}`,
|
|
19403
|
+
`${resolved.failure.message} Dieser Beitrag entfaellt; der Knoten bleibt mit seinen uebrigen Beitraegen im Prompt.`
|
|
19404
|
+
);
|
|
19405
|
+
continue;
|
|
19406
|
+
}
|
|
18675
19407
|
const payload = resolved.version.payload;
|
|
18676
19408
|
contributions.push({
|
|
18677
19409
|
source: "component",
|
|
18678
19410
|
element_id: resolved.version.element_id,
|
|
18679
19411
|
version_id: resolved.version.version_id,
|
|
18680
|
-
role: str(
|
|
18681
|
-
rank: num(
|
|
19412
|
+
role: str(isObject11(ref) ? ref.role : null),
|
|
19413
|
+
rank: num(isObject11(ref) ? ref.rank : null) ?? 0,
|
|
18682
19414
|
locale: str(payload.locale),
|
|
18683
19415
|
text: str(payload.text) ?? ""
|
|
18684
19416
|
});
|
|
18685
19417
|
}
|
|
18686
|
-
const semantic =
|
|
19418
|
+
const semantic = isObject11(raw.semantic) ? raw.semantic : null;
|
|
18687
19419
|
if (semantic && str(semantic.description)) {
|
|
18688
19420
|
contributions.push({
|
|
18689
19421
|
source: "node_semantic",
|
|
@@ -18697,12 +19429,12 @@ async function resolveShotPayload(input) {
|
|
|
18697
19429
|
});
|
|
18698
19430
|
}
|
|
18699
19431
|
const override = overrides.get(nodeId);
|
|
18700
|
-
const overrideSemantic = override &&
|
|
18701
|
-
if (overrideSemantic && str(overrideSemantic.description)) {
|
|
19432
|
+
const overrideSemantic = override && isObject11(override.semantic) ? override.semantic : null;
|
|
19433
|
+
if (overrideSemantic && str(overrideSemantic.description) && setup) {
|
|
18702
19434
|
contributions.push({
|
|
18703
19435
|
source: "setup_override",
|
|
18704
|
-
element_id:
|
|
18705
|
-
version_id:
|
|
19436
|
+
element_id: setup.element_id,
|
|
19437
|
+
version_id: setup.version_id,
|
|
18706
19438
|
role: null,
|
|
18707
19439
|
rank: Number.MAX_SAFE_INTEGER,
|
|
18708
19440
|
locale: null,
|
|
@@ -18711,8 +19443,8 @@ async function resolveShotPayload(input) {
|
|
|
18711
19443
|
}
|
|
18712
19444
|
contributions.sort((a, b) => a.rank - b.rank);
|
|
18713
19445
|
const properties = {
|
|
18714
|
-
...
|
|
18715
|
-
...
|
|
19446
|
+
...isObject11(semantic?.properties) ? semantic.properties : {},
|
|
19447
|
+
...isObject11(overrideSemantic?.properties) ? overrideSemantic.properties : {}
|
|
18716
19448
|
};
|
|
18717
19449
|
nodes.push({
|
|
18718
19450
|
node_id: nodeId,
|
|
@@ -18723,9 +19455,6 @@ async function resolveShotPayload(input) {
|
|
|
18723
19455
|
hidden: hidden.has(nodeId)
|
|
18724
19456
|
});
|
|
18725
19457
|
}
|
|
18726
|
-
const cameraPlacement = canPlace ? camera.placement ?? null : entraeumlichtePlatzierung(camera.placement, assumptions);
|
|
18727
|
-
const framing = shotOverrides.framing ?? camera.framing;
|
|
18728
|
-
const focus = shotOverrides.focus !== void 0 ? shotOverrides.focus : camera.focus ?? null;
|
|
18729
19458
|
const shotInstruction = str(settings.user_instruction);
|
|
18730
19459
|
if (userInstruction && shotInstruction && userInstruction !== shotInstruction) {
|
|
18731
19460
|
assumptions.push(
|
|
@@ -18739,92 +19468,40 @@ async function resolveShotPayload(input) {
|
|
|
18739
19468
|
kind: "resolved",
|
|
18740
19469
|
report,
|
|
18741
19470
|
input: {
|
|
18742
|
-
shot: {
|
|
18743
|
-
version_id:
|
|
18744
|
-
element_id:
|
|
18745
|
-
camera_id:
|
|
19471
|
+
shot: shot ? {
|
|
19472
|
+
version_id: shot.version_id,
|
|
19473
|
+
element_id: shot.element_id,
|
|
19474
|
+
camera_id: camera ? camera.camera_id : null,
|
|
18746
19475
|
shot_concept: shotConcept,
|
|
18747
19476
|
// Der Aufrufer darf die im Shot hinterlegte Anweisung ueberschreiben
|
|
18748
19477
|
// (§4.1). Beide Herkuenfte sind unterschiedliche Sachverhalte, deshalb
|
|
18749
19478
|
// wird der Fall in `assumptions` benannt statt still ersetzt.
|
|
18750
|
-
user_instruction: userInstruction ??
|
|
19479
|
+
user_instruction: userInstruction ?? shotInstruction,
|
|
18751
19480
|
text_override: str(shotOverrides.text)
|
|
18752
|
-
},
|
|
19481
|
+
} : null,
|
|
19482
|
+
setup: setup ? { version_id: setup.version_id, element_id: setup.element_id } : null,
|
|
18753
19483
|
scene: {
|
|
18754
|
-
|
|
19484
|
+
element_id: scene.element_id,
|
|
19485
|
+
version_id: scene.version_id,
|
|
18755
19486
|
nodes,
|
|
18756
|
-
relations:
|
|
18757
|
-
environment: scene.environment ?? null,
|
|
18758
|
-
unit_system: scene.unit_system ?? null
|
|
18759
|
-
},
|
|
18760
|
-
camera: {
|
|
18761
|
-
camera_id: cameraId,
|
|
18762
|
-
name: str(camera.name),
|
|
18763
|
-
preset: presetRef.version.payload,
|
|
18764
|
-
placement: cameraPlacement,
|
|
18765
|
-
orientation: camera.orientation ?? null,
|
|
18766
|
-
framing: framing ?? null,
|
|
18767
|
-
focus,
|
|
18768
|
-
pattern
|
|
19487
|
+
relations: asArray3(scene.payload.relations),
|
|
19488
|
+
environment: scene.payload.environment ?? null,
|
|
19489
|
+
unit_system: scene.payload.unit_system ?? null
|
|
18769
19490
|
},
|
|
19491
|
+
camera,
|
|
18770
19492
|
styles,
|
|
18771
19493
|
policies,
|
|
18772
19494
|
fragments,
|
|
18773
|
-
target_model:
|
|
19495
|
+
target_model: targetModelPayload,
|
|
18774
19496
|
localization_notes: [],
|
|
18775
19497
|
assumptions,
|
|
18776
|
-
|
|
18777
|
-
|
|
18778
|
-
can_render_prompt: report.can_render_prompt.state,
|
|
18779
|
-
can_place: report.can_place.state
|
|
18780
|
-
},
|
|
19498
|
+
diagnostics,
|
|
19499
|
+
capabilities: eingefroreneFaehigkeiten,
|
|
18781
19500
|
context_chain: [...contextChain],
|
|
18782
|
-
target_model_resolution:
|
|
18783
|
-
element_id: targetModel.elementId,
|
|
18784
|
-
version_id: targetModel.versionId,
|
|
18785
|
-
chain_index: targetModel.chainIndex,
|
|
18786
|
-
head: targetModel.head,
|
|
18787
|
-
shadowed_retired: targetModel.shadowedRetired.map((entry) => ({
|
|
18788
|
-
element_id: entry.elementId,
|
|
18789
|
-
context_id: entry.contextId
|
|
18790
|
-
}))
|
|
18791
|
-
}
|
|
19501
|
+
target_model_resolution: targetModelResolution
|
|
18792
19502
|
}
|
|
18793
19503
|
};
|
|
18794
19504
|
}
|
|
18795
|
-
function capabilityGate(report, flag) {
|
|
18796
|
-
const value = report[flag];
|
|
18797
|
-
if (value.state === "yes") return null;
|
|
18798
|
-
if (value.state === "no") {
|
|
18799
|
-
const findings = value.reasons.filter((reason) => reason.kind === "blocked").map((reason) => reason.finding);
|
|
18800
|
-
return {
|
|
18801
|
-
class: "capability_blocked",
|
|
18802
|
-
flag,
|
|
18803
|
-
message: `${flag} ist "no" \u2014 der Aufbau erfuellt die Voraussetzung nachweislich nicht. ` + (findings.length > 0 ? findings.map((f) => `${f.rule}: ${f.message}`).join(" | ") : value.reasons.map(describeReason).join(" | ")),
|
|
18804
|
-
findings
|
|
18805
|
-
};
|
|
18806
|
-
}
|
|
18807
|
-
return {
|
|
18808
|
-
class: "capability_undetermined",
|
|
18809
|
-
flag,
|
|
18810
|
-
message: `${flag} ist "unknown" \u2014 es liess sich nicht feststellen, ob die Voraussetzung erfuellt ist. Ein Lauf wuerde eine unbestimmte Annahme einfrieren (D-22). ` + value.reasons.map(describeReason).join(" | "),
|
|
18811
|
-
reasons: value.reasons
|
|
18812
|
-
};
|
|
18813
|
-
}
|
|
18814
|
-
function describeReason(reason) {
|
|
18815
|
-
switch (reason.kind) {
|
|
18816
|
-
case "schema":
|
|
18817
|
-
return `Schemafehler unter ${reason.error.instancePath || "/"}: ${reason.error.message}`;
|
|
18818
|
-
case "blocked":
|
|
18819
|
-
return `${reason.finding.rule} bei ${reason.finding.path || "/"}: ${reason.finding.message}`;
|
|
18820
|
-
case "unchecked":
|
|
18821
|
-
return `${reason.rule} nicht geprueft: ${reason.reason}`;
|
|
18822
|
-
case "structure":
|
|
18823
|
-
return reason.message;
|
|
18824
|
-
case "inherited":
|
|
18825
|
-
return reason.message;
|
|
18826
|
-
}
|
|
18827
|
-
}
|
|
18828
19505
|
|
|
18829
19506
|
// src/lib/szenen/freezeDraftChain.ts
|
|
18830
19507
|
function ladeKnoten(sicht, elementId, erwarteterTyp) {
|
|
@@ -18960,9 +19637,117 @@ async function freezeDraftChain(input) {
|
|
|
18960
19637
|
...shot.chain.source_recovery_id ? { sourceRecoveryId: shot.chain.source_recovery_id } : {}
|
|
18961
19638
|
};
|
|
18962
19639
|
}
|
|
19640
|
+
function ladeSzene(sicht, elementId, contextChain) {
|
|
19641
|
+
const gelesen = sicht.getElement(elementId);
|
|
19642
|
+
if (gelesen.kind !== "ok") {
|
|
19643
|
+
return {
|
|
19644
|
+
fehler: gelesen.message ?? `Element ${elementId} konnte nicht gelesen werden.`,
|
|
19645
|
+
technisch: true
|
|
19646
|
+
};
|
|
19647
|
+
}
|
|
19648
|
+
const snapshot = gelesen.value;
|
|
19649
|
+
if (!snapshot) return { fehler: `Element ${elementId} ist unbekannt.` };
|
|
19650
|
+
if (snapshot.element.type !== "scene") {
|
|
19651
|
+
return {
|
|
19652
|
+
fehler: `Element ${elementId} ist vom Typ "${snapshot.element.type}", erwartet "scene".`
|
|
19653
|
+
};
|
|
19654
|
+
}
|
|
19655
|
+
if (snapshot.draftFork) {
|
|
19656
|
+
return {
|
|
19657
|
+
fehler: `Element ${elementId} hat parallele Entwuerfe. Solange sie nicht aufgeloest sind, gibt es keinen eindeutigen Arbeitsstand (D-29).`
|
|
19658
|
+
};
|
|
19659
|
+
}
|
|
19660
|
+
if (snapshot.draft) {
|
|
19661
|
+
return {
|
|
19662
|
+
element_id: elementId,
|
|
19663
|
+
draft_id: snapshot.draft.draft_id,
|
|
19664
|
+
revision: snapshot.draft.revision,
|
|
19665
|
+
version_id: null,
|
|
19666
|
+
payload: snapshot.draft.payload
|
|
19667
|
+
};
|
|
19668
|
+
}
|
|
19669
|
+
const versionen = snapshot.versions ?? [];
|
|
19670
|
+
if (versionen.length === 0) {
|
|
19671
|
+
return {
|
|
19672
|
+
fehler: `Element ${elementId} hat weder einen Entwurf noch eine veroeffentlichte Version. Es gibt nichts einzufrieren.`
|
|
19673
|
+
};
|
|
19674
|
+
}
|
|
19675
|
+
const kopf = effectivePreferredHeadSafe(
|
|
19676
|
+
{ element: snapshot.element, versions: versionen, preferredHeads: snapshot.preferredHeads },
|
|
19677
|
+
contextChain
|
|
19678
|
+
);
|
|
19679
|
+
if (kopf.kind === "dag_fehler") {
|
|
19680
|
+
return { fehler: `Der Versionsgraph von Element ${elementId} ist nicht aufbaubar: ${kopf.message}` };
|
|
19681
|
+
}
|
|
19682
|
+
const versionId = usableHeadVersionId(resolutionOf(kopf));
|
|
19683
|
+
if (!versionId) {
|
|
19684
|
+
return {
|
|
19685
|
+
fehler: `Element ${elementId} hat mehrere veroeffentlichte Koepfe und in diesem Kontext keine Auswahl. Welcher Stand gilt, entscheidet keine Reihenfolge (D-36) \u2014 bitte einen bevorzugten Kopf setzen.`
|
|
19686
|
+
};
|
|
19687
|
+
}
|
|
19688
|
+
const version2 = versionen.find((v) => v.version_id === versionId);
|
|
19689
|
+
if (!version2) {
|
|
19690
|
+
return {
|
|
19691
|
+
fehler: `Die wirksame Version ${versionId} von Element ${elementId} steht nicht in der gelesenen Momentaufnahme.`
|
|
19692
|
+
};
|
|
19693
|
+
}
|
|
19694
|
+
return {
|
|
19695
|
+
element_id: elementId,
|
|
19696
|
+
draft_id: null,
|
|
19697
|
+
revision: null,
|
|
19698
|
+
version_id: versionId,
|
|
19699
|
+
payload: version2.payload
|
|
19700
|
+
};
|
|
19701
|
+
}
|
|
19702
|
+
async function freezeSceneWorkingState(input) {
|
|
19703
|
+
const { sceneElementId, store, resolver, contextChain, userInstruction } = input;
|
|
19704
|
+
const a = await store.readSnapshot({ fresh: false });
|
|
19705
|
+
const szene = ladeSzene(a, sceneElementId, contextChain);
|
|
19706
|
+
if ("fehler" in szene) return ausfallErgebnis(szene);
|
|
19707
|
+
const b = await store.readSnapshot({ fresh: true });
|
|
19708
|
+
const erneut = ladeSzene(b, sceneElementId, contextChain);
|
|
19709
|
+
if ("fehler" in erneut) return ausfallErgebnis(erneut);
|
|
19710
|
+
if (erneut.draft_id !== szene.draft_id || erneut.revision !== szene.revision || erneut.version_id !== szene.version_id) {
|
|
19711
|
+
return {
|
|
19712
|
+
kind: "conflict",
|
|
19713
|
+
message: `Der Arbeitsstand der Szene ${sceneElementId} hat sich waehrend des Einfrierens geaendert (erwartet ${szene.draft_id ? `Entwurf ${szene.draft_id}, Revision ${szene.revision}` : `Version ${szene.version_id}`}, vorhanden ${erneut.draft_id ? `Entwurf ${erneut.draft_id}, Revision ${erneut.revision}` : `Version ${erneut.version_id}`}). Es wurde kein Modell gerufen.`,
|
|
19714
|
+
node: { type: "scene", element_id: sceneElementId, draft_id: szene.draft_id ?? "" },
|
|
19715
|
+
expectedRevision: szene.revision ?? 0,
|
|
19716
|
+
actualRevision: erneut.revision ?? 0
|
|
19717
|
+
};
|
|
19718
|
+
}
|
|
19719
|
+
const aufgeloest = await resolveScenePayload({
|
|
19720
|
+
scenePayload: szene.payload,
|
|
19721
|
+
sceneElementId: szene.element_id,
|
|
19722
|
+
// Ein Entwurf hat keine Version — und bekommt hier auch keine erfundene
|
|
19723
|
+
// (D-98/D-75).
|
|
19724
|
+
sceneVersionId: szene.version_id ?? "",
|
|
19725
|
+
resolver,
|
|
19726
|
+
contextChain,
|
|
19727
|
+
userInstruction
|
|
19728
|
+
});
|
|
19729
|
+
if (aufgeloest.kind !== "resolved") {
|
|
19730
|
+
return {
|
|
19731
|
+
kind: "rejected",
|
|
19732
|
+
message: aufgeloest.failure.message,
|
|
19733
|
+
failure: aufgeloest.failure
|
|
19734
|
+
};
|
|
19735
|
+
}
|
|
19736
|
+
return {
|
|
19737
|
+
kind: "ok",
|
|
19738
|
+
scene: {
|
|
19739
|
+
element_id: szene.element_id,
|
|
19740
|
+
draft_id: szene.draft_id,
|
|
19741
|
+
revision: szene.revision,
|
|
19742
|
+
version_id: szene.version_id
|
|
19743
|
+
},
|
|
19744
|
+
input: aufgeloest.input
|
|
19745
|
+
};
|
|
19746
|
+
}
|
|
18963
19747
|
|
|
18964
19748
|
// src/lib/szenen/promptRun.ts
|
|
18965
19749
|
function buildSystemInstruction2(input) {
|
|
19750
|
+
const ohneZielmodell = input.target_model === null || input.target_model === void 0;
|
|
18966
19751
|
const model = input.target_model ?? {};
|
|
18967
19752
|
const sprache = typeof model.prompt_language === "string" ? model.prompt_language : "en";
|
|
18968
19753
|
const negativ = model.supports_negative_prompt === true;
|
|
@@ -18983,7 +19768,11 @@ function buildSystemInstruction2(input) {
|
|
|
18983
19768
|
"",
|
|
18984
19769
|
`Der Prompt wird in der Sprache "${sprache}" formuliert.`
|
|
18985
19770
|
];
|
|
18986
|
-
if (
|
|
19771
|
+
if (ohneZielmodell) {
|
|
19772
|
+
zeilen.push(
|
|
19773
|
+
'Es ist KEIN Zielmodell angegeben. Formuliere einen generischen Prompt und richte ihn nicht an einer bestimmten Bildmodell-Syntax aus. "negative" bleibt null, weil kein Modell zugesagt hat, ein Negativfeld zu fuehren; was mit negativen Fragmenten geschehen ist, gehoert in "notes".'
|
|
19774
|
+
);
|
|
19775
|
+
} else if (!negativ) {
|
|
18987
19776
|
zeilen.push(
|
|
18988
19777
|
'Das Zielmodell kennt KEIN Negativ-Prompt-Feld. "negative" bleibt null; was mit negativen Fragmenten geschehen ist, gehoert in "notes".'
|
|
18989
19778
|
);
|
|
@@ -19012,6 +19801,14 @@ function buildSystemInstruction2(input) {
|
|
|
19012
19801
|
'Widersprechen sie einander, nenne den Widerspruch mit beiden Quellen in "notes" \u2014',
|
|
19013
19802
|
"waehle nicht still eine Seite."
|
|
19014
19803
|
);
|
|
19804
|
+
if (input.camera === null) {
|
|
19805
|
+
zeilen.push(
|
|
19806
|
+
"",
|
|
19807
|
+
"Es ist KEINE Kamera angegeben. Erfinde keine Brennweite, keinen Bildausschnitt",
|
|
19808
|
+
"und keine Kameraposition. Wo eine Kameraaussage noetig waere, formuliere sie",
|
|
19809
|
+
'als Annahme und nenne sie in "notes".'
|
|
19810
|
+
);
|
|
19811
|
+
}
|
|
19015
19812
|
if (input.capabilities.can_place !== "yes") {
|
|
19016
19813
|
zeilen.push(
|
|
19017
19814
|
"",
|
|
@@ -19025,7 +19822,7 @@ function buildSystemInstruction2(input) {
|
|
|
19025
19822
|
function buildUserPrompt2(input) {
|
|
19026
19823
|
return JSON.stringify(input, null, 2);
|
|
19027
19824
|
}
|
|
19028
|
-
var
|
|
19825
|
+
var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
19029
19826
|
function parseRunResponse(raw) {
|
|
19030
19827
|
const text = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
19031
19828
|
if (text.length === 0) return { ok: false, message: "Die Antwort war leer." };
|
|
@@ -19039,7 +19836,7 @@ function parseRunResponse(raw) {
|
|
|
19039
19836
|
}
|
|
19040
19837
|
}
|
|
19041
19838
|
function checkRunResponse(value, input) {
|
|
19042
|
-
if (!
|
|
19839
|
+
if (!isObject12(value)) {
|
|
19043
19840
|
return { ok: false, message: `Die Antwort ist kein Objekt, sondern ${Array.isArray(value) ? "array" : typeof value}.` };
|
|
19044
19841
|
}
|
|
19045
19842
|
if (typeof value.positive !== "string" || value.positive.trim().length === 0) {
|
|
@@ -19057,11 +19854,11 @@ function checkRunResponse(value, input) {
|
|
|
19057
19854
|
if (negative !== null && !negativErlaubt) {
|
|
19058
19855
|
return {
|
|
19059
19856
|
ok: false,
|
|
19060
|
-
message: `Das Zielmodell fuehrt kein Negativ-Prompt-Feld (supports_negative_prompt = false), die Antwort liefert aber eines.`
|
|
19857
|
+
message: input.target_model ? `Das Zielmodell fuehrt kein Negativ-Prompt-Feld (supports_negative_prompt = false), die Antwort liefert aber eines.` : `Dieser Lauf hat kein Zielmodell (generische Ableitung); ein Negativ-Prompt-Feld ist damit nicht zugesagt, die Antwort liefert aber eines.`
|
|
19061
19858
|
};
|
|
19062
19859
|
}
|
|
19063
19860
|
const visibility = value.visibility;
|
|
19064
|
-
if (!
|
|
19861
|
+
if (!isObject12(visibility)) {
|
|
19065
19862
|
return { ok: false, message: '"visibility" fehlt \u2014 die Pflichtdiagnosen aus D-21.' };
|
|
19066
19863
|
}
|
|
19067
19864
|
if (typeof visibility.basis !== "string") {
|
|
@@ -19073,7 +19870,7 @@ function checkRunResponse(value, input) {
|
|
|
19073
19870
|
const genannt = /* @__PURE__ */ new Set();
|
|
19074
19871
|
const nodes = [];
|
|
19075
19872
|
for (const eintrag of visibility.nodes) {
|
|
19076
|
-
if (!
|
|
19873
|
+
if (!isObject12(eintrag) || typeof eintrag.node_id !== "string" || typeof eintrag.state !== "string") {
|
|
19077
19874
|
return { ok: false, message: 'Ein Eintrag in "visibility.nodes" hat keine node_id oder keinen state.' };
|
|
19078
19875
|
}
|
|
19079
19876
|
genannt.add(eintrag.node_id);
|
|
@@ -19218,6 +20015,23 @@ function createEventLogRunPersistence(channel) {
|
|
|
19218
20015
|
return queryError(error, `Laeufe der Kette ${chainId} konnten nicht gelesen werden`);
|
|
19219
20016
|
}
|
|
19220
20017
|
},
|
|
20018
|
+
async listForScene(sceneElementId) {
|
|
20019
|
+
try {
|
|
20020
|
+
const events = await channel.readEvents();
|
|
20021
|
+
return {
|
|
20022
|
+
kind: "ok",
|
|
20023
|
+
value: collectPromptRuns(events).filter((run) => {
|
|
20024
|
+
const quelle = sourceOf(run);
|
|
20025
|
+
return quelle.kind === "scene_direct" && quelle.scene.element_id === sceneElementId;
|
|
20026
|
+
})
|
|
20027
|
+
};
|
|
20028
|
+
} catch (error) {
|
|
20029
|
+
return queryError(
|
|
20030
|
+
error,
|
|
20031
|
+
`Laeufe der Szene ${sceneElementId} konnten nicht gelesen werden`
|
|
20032
|
+
);
|
|
20033
|
+
}
|
|
20034
|
+
},
|
|
19221
20035
|
async record(record) {
|
|
19222
20036
|
try {
|
|
19223
20037
|
await channel.appendEvent(SZENEN_EVENT_TYPES.promptRunRecorded, record);
|
|
@@ -19304,13 +20118,21 @@ function createClientRunPort(options) {
|
|
|
19304
20118
|
return { kind: "error", message: resolved.failure.message, retryable: false };
|
|
19305
20119
|
}
|
|
19306
20120
|
const outcome = await runPromptDerivation(resolved.input, text);
|
|
20121
|
+
if (!resolved.input.shot) {
|
|
20122
|
+
return {
|
|
20123
|
+
kind: "error",
|
|
20124
|
+
message: `Die Aufloesung der Shot-Version ${input.shotVersionId} lieferte eine Eingabe ohne Shot. Das ist ein Programmfehler, kein Lauf.`,
|
|
20125
|
+
retryable: false
|
|
20126
|
+
};
|
|
20127
|
+
}
|
|
19307
20128
|
const record = {
|
|
19308
20129
|
run_id: newRunId(),
|
|
19309
20130
|
shot_version_id: input.shotVersionId,
|
|
19310
20131
|
shot_element_id: resolved.input.shot.element_id,
|
|
19311
20132
|
scene_setup_version_id: resolved.input.scene.version_id,
|
|
19312
|
-
|
|
19313
|
-
|
|
20133
|
+
// Leer heisst „kein Wert", nicht „Wert unbekannt" (D-75/D-135).
|
|
20134
|
+
camera_id: resolved.input.shot.camera_id ?? "",
|
|
20135
|
+
target_model_version_id: resolved.input.target_model_resolution?.version_id ?? "",
|
|
19314
20136
|
provider: outcome.provider,
|
|
19315
20137
|
model_id: outcome.model_id,
|
|
19316
20138
|
system_prompt: outcome.system_prompt,
|
|
@@ -19382,8 +20204,8 @@ function createClientRunPort(options) {
|
|
|
19382
20204
|
shot_version_id: "",
|
|
19383
20205
|
shot_element_id: input.shotElementId,
|
|
19384
20206
|
scene_setup_version_id: "",
|
|
19385
|
-
camera_id: eingefroren.input.shot
|
|
19386
|
-
target_model_version_id: eingefroren.input.target_model_resolution
|
|
20207
|
+
camera_id: eingefroren.input.shot?.camera_id ?? "",
|
|
20208
|
+
target_model_version_id: eingefroren.input.target_model_resolution?.version_id ?? "",
|
|
19387
20209
|
provider: outcome.provider,
|
|
19388
20210
|
model_id: outcome.model_id,
|
|
19389
20211
|
system_prompt: outcome.system_prompt,
|
|
@@ -19417,6 +20239,95 @@ function createClientRunPort(options) {
|
|
|
19417
20239
|
async listRunsForChain(chainId) {
|
|
19418
20240
|
const alle = await runs.listForChain(chainId);
|
|
19419
20241
|
return alle;
|
|
20242
|
+
},
|
|
20243
|
+
// ── Der Lauf direkt aus einer Szene (D-135) ───────────────────────────
|
|
20244
|
+
//
|
|
20245
|
+
// Bewusst **derselbe** Ablauf wie oben: Kontext ermitteln, Kette
|
|
20246
|
+
// aufloesen, einfrieren, dann erst rufen. Was sich unterscheidet, ist
|
|
20247
|
+
// ausschliesslich, **was** eingefroren wird — ein Szenen-Arbeitsstand
|
|
20248
|
+
// statt einer Drei-Knoten-Kette.
|
|
20249
|
+
async startRunFromScene(input) {
|
|
20250
|
+
try {
|
|
20251
|
+
let contextId = input.contextId;
|
|
20252
|
+
if (contextId === void 0) {
|
|
20253
|
+
const element = await elements.getElement(input.sceneElementId);
|
|
20254
|
+
if (element.kind !== "ok") {
|
|
20255
|
+
return { kind: "error", message: element.message, retryable: element.retryable };
|
|
20256
|
+
}
|
|
20257
|
+
if (element.value === null) {
|
|
20258
|
+
return {
|
|
20259
|
+
kind: "error",
|
|
20260
|
+
message: `Element ${input.sceneElementId} ist unbekannt.`,
|
|
20261
|
+
retryable: false
|
|
20262
|
+
};
|
|
20263
|
+
}
|
|
20264
|
+
contextId = element.value.element.context_id;
|
|
20265
|
+
}
|
|
20266
|
+
const chain = await context.chainFor(contextId ?? null);
|
|
20267
|
+
if (chain.kind !== "ok") {
|
|
20268
|
+
return { kind: "error", message: chain.message, retryable: chain.retryable };
|
|
20269
|
+
}
|
|
20270
|
+
const eingefroren = await freezeSceneWorkingState({
|
|
20271
|
+
sceneElementId: input.sceneElementId,
|
|
20272
|
+
store: elements,
|
|
20273
|
+
resolver,
|
|
20274
|
+
contextChain: chain.value,
|
|
20275
|
+
userInstruction: input.userInstruction ?? null
|
|
20276
|
+
});
|
|
20277
|
+
if (eingefroren.kind === "conflict") {
|
|
20278
|
+
return {
|
|
20279
|
+
kind: "conflict",
|
|
20280
|
+
message: eingefroren.message,
|
|
20281
|
+
node: eingefroren.node,
|
|
20282
|
+
expectedRevision: eingefroren.expectedRevision,
|
|
20283
|
+
actualRevision: eingefroren.actualRevision
|
|
20284
|
+
};
|
|
20285
|
+
}
|
|
20286
|
+
if (eingefroren.kind === "error") {
|
|
20287
|
+
return { kind: "error", message: eingefroren.message, retryable: eingefroren.retryable };
|
|
20288
|
+
}
|
|
20289
|
+
if (eingefroren.kind !== "ok") {
|
|
20290
|
+
return { kind: "rejected", message: eingefroren.message };
|
|
20291
|
+
}
|
|
20292
|
+
const outcome = await runPromptDerivation(eingefroren.input, text);
|
|
20293
|
+
const record = {
|
|
20294
|
+
run_id: newRunId(),
|
|
20295
|
+
// Keine fingierten Kennungen (D-98/D-75). Was es nicht gibt, bleibt
|
|
20296
|
+
// leer — die Herkunft steht in `source`.
|
|
20297
|
+
shot_version_id: "",
|
|
20298
|
+
shot_element_id: "",
|
|
20299
|
+
scene_setup_version_id: "",
|
|
20300
|
+
camera_id: "",
|
|
20301
|
+
target_model_version_id: eingefroren.input.target_model_resolution?.version_id ?? "",
|
|
20302
|
+
provider: outcome.provider,
|
|
20303
|
+
model_id: outcome.model_id,
|
|
20304
|
+
system_prompt: outcome.system_prompt,
|
|
20305
|
+
input_payload: eingefroren.input,
|
|
20306
|
+
status: outcome.status,
|
|
20307
|
+
failure: outcome.status === "failed" ? outcome.failure : null,
|
|
20308
|
+
output: outcome.status === "succeeded" ? outcome.output : null,
|
|
20309
|
+
raw_output: outcome.raw_output,
|
|
20310
|
+
source: { kind: "scene_direct", scene: eingefroren.scene },
|
|
20311
|
+
created_at: now().toISOString()
|
|
20312
|
+
};
|
|
20313
|
+
return await runs.record(record);
|
|
20314
|
+
} catch (error) {
|
|
20315
|
+
return {
|
|
20316
|
+
kind: "error",
|
|
20317
|
+
message: `Prompt-Lauf aus der Szene ${input.sceneElementId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
|
|
20318
|
+
retryable: true
|
|
20319
|
+
};
|
|
20320
|
+
}
|
|
20321
|
+
},
|
|
20322
|
+
async listRunsForScene(sceneElementId) {
|
|
20323
|
+
try {
|
|
20324
|
+
return await runs.listForScene(sceneElementId);
|
|
20325
|
+
} catch (error) {
|
|
20326
|
+
return queryError(
|
|
20327
|
+
error,
|
|
20328
|
+
`Laeufe der Szene ${sceneElementId} konnten nicht gelesen werden`
|
|
20329
|
+
);
|
|
20330
|
+
}
|
|
19420
20331
|
}
|
|
19421
20332
|
};
|
|
19422
20333
|
}
|
|
@@ -19450,6 +20361,7 @@ function createHfImageStore(options) {
|
|
|
19450
20361
|
const basisMs = options.leseBasisMs ?? 400;
|
|
19451
20362
|
const schlafen2 = options.schlafen ?? warten;
|
|
19452
20363
|
const abgelegt = /* @__PURE__ */ new Map();
|
|
20364
|
+
const vorschauen = /* @__PURE__ */ new Map();
|
|
19453
20365
|
const bekanntePfade = /* @__PURE__ */ new Set();
|
|
19454
20366
|
let gefalteterBestand = null;
|
|
19455
20367
|
let laufenderAbgleich = null;
|
|
@@ -19473,7 +20385,7 @@ function createHfImageStore(options) {
|
|
|
19473
20385
|
}
|
|
19474
20386
|
return laufenderAbgleich;
|
|
19475
20387
|
}
|
|
19476
|
-
|
|
20388
|
+
const speicher = {
|
|
19477
20389
|
bestand: bestandAbgleichen,
|
|
19478
20390
|
async putWithId(id, base64, mimeType, titel) {
|
|
19479
20391
|
const echterTyp = typAusBytes(base64, mimeType);
|
|
@@ -19492,6 +20404,38 @@ function createHfImageStore(options) {
|
|
|
19492
20404
|
}, []);
|
|
19493
20405
|
abgelegt.set(id, { data: base64, mimeType: echterTyp });
|
|
19494
20406
|
},
|
|
20407
|
+
async preview(id) {
|
|
20408
|
+
const bekannt = vorschauen.get(id);
|
|
20409
|
+
if (bekannt) return bekannt;
|
|
20410
|
+
const eben = abgelegt.get(id);
|
|
20411
|
+
if (eben) {
|
|
20412
|
+
const quelle2 = `data:${eben.mimeType};base64,${eben.data}`;
|
|
20413
|
+
vorschauen.set(id, quelle2);
|
|
20414
|
+
return quelle2;
|
|
20415
|
+
}
|
|
20416
|
+
const zustand = await bestandAbgleichen();
|
|
20417
|
+
const eintrag = zustand.metadata.find((e) => e.id === id);
|
|
20418
|
+
if (eintrag?.hasThumb && eintrag.filename) {
|
|
20419
|
+
const klein = await hfLoadImageAsBase64(
|
|
20420
|
+
id,
|
|
20421
|
+
token,
|
|
20422
|
+
void 0,
|
|
20423
|
+
eintrag.filename,
|
|
20424
|
+
void 0,
|
|
20425
|
+
eintrag.mimeType,
|
|
20426
|
+
true
|
|
20427
|
+
);
|
|
20428
|
+
if (klein) {
|
|
20429
|
+
const quelle2 = `data:${eintrag.mimeType || "image/jpeg"};base64,${klein}`;
|
|
20430
|
+
vorschauen.set(id, quelle2);
|
|
20431
|
+
return quelle2;
|
|
20432
|
+
}
|
|
20433
|
+
}
|
|
20434
|
+
const voll = await speicher.resolve(id);
|
|
20435
|
+
const quelle = `data:${voll.mimeType};base64,${voll.data}`;
|
|
20436
|
+
vorschauen.set(id, quelle);
|
|
20437
|
+
return quelle;
|
|
20438
|
+
},
|
|
19495
20439
|
async resolve(id, mimeType) {
|
|
19496
20440
|
const eben = abgelegt.get(id);
|
|
19497
20441
|
if (eben) return eben;
|
|
@@ -19529,6 +20473,47 @@ function createHfImageStore(options) {
|
|
|
19529
20473
|
);
|
|
19530
20474
|
}
|
|
19531
20475
|
};
|
|
20476
|
+
return speicher;
|
|
20477
|
+
}
|
|
20478
|
+
|
|
20479
|
+
// src/lib/szenen/libraryItems.ts
|
|
20480
|
+
var LOCATOR = /^(.+)-(\d+)$/;
|
|
20481
|
+
function locatorTeile(mediaRef) {
|
|
20482
|
+
const treffer = LOCATOR.exec(mediaRef);
|
|
20483
|
+
if (!treffer) return { stamm: mediaRef, position: null };
|
|
20484
|
+
return { stamm: treffer[1], position: Number(treffer[2]) };
|
|
20485
|
+
}
|
|
20486
|
+
function gruppiereZuItems(bilder) {
|
|
20487
|
+
const gruppen = /* @__PURE__ */ new Map();
|
|
20488
|
+
for (const bild of bilder) {
|
|
20489
|
+
const { stamm } = locatorTeile(bild.mediaRef);
|
|
20490
|
+
const vorhanden = gruppen.get(stamm);
|
|
20491
|
+
if (vorhanden) vorhanden.push(bild);
|
|
20492
|
+
else gruppen.set(stamm, [bild]);
|
|
20493
|
+
}
|
|
20494
|
+
const items = [...gruppen.entries()].map(([stamm, mitglieder]) => {
|
|
20495
|
+
const sortiert = [...mitglieder].sort((a, b) => {
|
|
20496
|
+
const pa = locatorTeile(a.mediaRef).position ?? 0;
|
|
20497
|
+
const pb = locatorTeile(b.mediaRef).position ?? 0;
|
|
20498
|
+
return pa - pb;
|
|
20499
|
+
});
|
|
20500
|
+
const erstes = sortiert[0];
|
|
20501
|
+
const itemRef = sortiert.length === 1 ? erstes.mediaRef : stamm;
|
|
20502
|
+
const juengstes = sortiert.reduce(
|
|
20503
|
+
(max, b) => Math.max(max, b.timestamp ?? 0),
|
|
20504
|
+
0
|
|
20505
|
+
);
|
|
20506
|
+
return {
|
|
20507
|
+
item: {
|
|
20508
|
+
itemRef,
|
|
20509
|
+
title: erstes.itemTitle?.trim() || erstes.title || itemRef,
|
|
20510
|
+
images: sortiert.map(({ timestamp: _t, itemTitle: _i, ...bild }) => bild)
|
|
20511
|
+
},
|
|
20512
|
+
juengstes
|
|
20513
|
+
};
|
|
20514
|
+
});
|
|
20515
|
+
items.sort((a, b) => b.juengstes - a.juengstes);
|
|
20516
|
+
return items.map((e) => e.item);
|
|
19532
20517
|
}
|
|
19533
20518
|
|
|
19534
20519
|
// src/lib/szenen/hfImageLibrary.ts
|
|
@@ -19536,13 +20521,22 @@ function fehler2(nachricht, retryable = false) {
|
|
|
19536
20521
|
return { kind: "error", message: nachricht, retryable };
|
|
19537
20522
|
}
|
|
19538
20523
|
function alsBild(eintrag) {
|
|
20524
|
+
const { position } = locatorTeile(eintrag.id);
|
|
20525
|
+
const werk = eintrag.prompt?.trim() || "";
|
|
19539
20526
|
return {
|
|
19540
20527
|
mediaRef: eintrag.id,
|
|
19541
|
-
//
|
|
19542
|
-
//
|
|
19543
|
-
|
|
20528
|
+
// Innerhalb eines mehrbildigen Werkes tragen alle Einträge denselben
|
|
20529
|
+
// Prompt — der Abgleich schreibt ihn je Bild aus derselben Library-Zeile.
|
|
20530
|
+
// Deshalb bekommt die Kachel dort die Position dazu, sonst stünde
|
|
20531
|
+
// vierzehnmal derselbe Satz.
|
|
20532
|
+
title: position === null ? werk || eintrag.id : `${werk || eintrag.id} \xB7 Bild ${position + 1}`,
|
|
19544
20533
|
mimeType: eintrag.mimeType || "image/jpeg",
|
|
19545
|
-
thumbUrl
|
|
20534
|
+
// Kein `thumbUrl`: Die Datei liegt auf HF hinter einem Token, und ein
|
|
20535
|
+
// `<img src>` käme dort nicht durch. Die Quelle entsteht über
|
|
20536
|
+
// `loadPreview()` — und nur für die Kacheln, die wirklich gezeigt werden.
|
|
20537
|
+
thumbUrl: null,
|
|
20538
|
+
itemTitle: werk || null,
|
|
20539
|
+
...typeof eintrag.timestamp === "number" ? { timestamp: eintrag.timestamp } : {}
|
|
19546
20540
|
};
|
|
19547
20541
|
}
|
|
19548
20542
|
function createHfImageLibrary(options) {
|
|
@@ -19553,15 +20547,14 @@ function createHfImageLibrary(options) {
|
|
|
19553
20547
|
...options.now ? { now: options.now } : {}
|
|
19554
20548
|
});
|
|
19555
20549
|
return {
|
|
19556
|
-
async
|
|
20550
|
+
async listItems(query) {
|
|
19557
20551
|
try {
|
|
19558
20552
|
const zustand = await store.bestand();
|
|
19559
20553
|
const eintraege = zustand?.metadata ?? [];
|
|
20554
|
+
const items = gruppiereZuItems(eintraege.map(alsBild));
|
|
19560
20555
|
const gesucht = query?.search?.trim().toLowerCase();
|
|
19561
|
-
const gefiltert = gesucht ?
|
|
19562
|
-
|
|
19563
|
-
const begrenzt = query?.limit ? sortiert.slice(0, query.limit) : sortiert;
|
|
19564
|
-
return { kind: "ok", value: begrenzt.map(alsBild) };
|
|
20556
|
+
const gefiltert = gesucht ? items.filter((i) => i.title.toLowerCase().includes(gesucht) || i.itemRef.toLowerCase().includes(gesucht)) : items;
|
|
20557
|
+
return { kind: "ok", value: query?.limit ? gefiltert.slice(0, query.limit) : gefiltert };
|
|
19565
20558
|
} catch (error) {
|
|
19566
20559
|
return fehler2(
|
|
19567
20560
|
`Der Bildbestand konnte nicht gelesen werden: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -19569,6 +20562,16 @@ function createHfImageLibrary(options) {
|
|
|
19569
20562
|
);
|
|
19570
20563
|
}
|
|
19571
20564
|
},
|
|
20565
|
+
async loadPreview(mediaRef) {
|
|
20566
|
+
try {
|
|
20567
|
+
return { kind: "ok", value: await store.preview(mediaRef) };
|
|
20568
|
+
} catch (error) {
|
|
20569
|
+
return fehler2(
|
|
20570
|
+
`Die Vorschau von ${mediaRef} ist nicht ladbar: ${error instanceof Error ? error.message : String(error)}`,
|
|
20571
|
+
true
|
|
20572
|
+
);
|
|
20573
|
+
}
|
|
20574
|
+
},
|
|
19572
20575
|
async resolveImage(mediaRef, mimeTypeHinweis) {
|
|
19573
20576
|
try {
|
|
19574
20577
|
const bild = await store.resolve(mediaRef, mimeTypeHinweis);
|
|
@@ -19581,10 +20584,13 @@ function createHfImageLibrary(options) {
|
|
|
19581
20584
|
const id = newImageId();
|
|
19582
20585
|
try {
|
|
19583
20586
|
await store.putWithId(id, input.data, input.mime_type, input.title);
|
|
19584
|
-
|
|
19585
|
-
|
|
19586
|
-
|
|
20587
|
+
const abgelegt = {
|
|
20588
|
+
mediaRef: id,
|
|
20589
|
+
title: input.title,
|
|
20590
|
+
mimeType: input.mime_type,
|
|
20591
|
+
thumbUrl: null
|
|
19587
20592
|
};
|
|
20593
|
+
return { kind: "ok", value: abgelegt };
|
|
19588
20594
|
} catch (error) {
|
|
19589
20595
|
return fehler2(
|
|
19590
20596
|
`Das Bild konnte nicht abgelegt werden: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -19655,7 +20661,7 @@ function createFlowImageProvider(generateImage) {
|
|
|
19655
20661
|
}
|
|
19656
20662
|
|
|
19657
20663
|
// src/lib/szenen/imageGenerationOrderStore.ts
|
|
19658
|
-
function
|
|
20664
|
+
function istText4(wert) {
|
|
19659
20665
|
return typeof wert === "string" && wert.trim().length > 0;
|
|
19660
20666
|
}
|
|
19661
20667
|
function collectImageGenerationOrders(events) {
|
|
@@ -19663,7 +20669,7 @@ function collectImageGenerationOrders(events) {
|
|
|
19663
20669
|
for (const event of events) {
|
|
19664
20670
|
if (event.type !== SZENEN_EVENT_TYPES.imageGenerationStarted) continue;
|
|
19665
20671
|
const payload = event.payload;
|
|
19666
|
-
if (!payload || !
|
|
20672
|
+
if (!payload || !istText4(payload.generation_batch_id) || !istText4(payload.prompt_run_id)) continue;
|
|
19667
20673
|
if (byBatchId.has(payload.generation_batch_id)) continue;
|
|
19668
20674
|
byBatchId.set(payload.generation_batch_id, {
|
|
19669
20675
|
generation_batch_id: payload.generation_batch_id,
|
|
@@ -19677,7 +20683,7 @@ function collectImageGenerationOrders(events) {
|
|
|
19677
20683
|
for (const event of events) {
|
|
19678
20684
|
if (event.type !== SZENEN_EVENT_TYPES.imageGenerationFinished) continue;
|
|
19679
20685
|
const payload = event.payload;
|
|
19680
|
-
if (!payload || !
|
|
20686
|
+
if (!payload || !istText4(payload.generation_batch_id)) continue;
|
|
19681
20687
|
const auftrag = byBatchId.get(payload.generation_batch_id);
|
|
19682
20688
|
if (!auftrag) continue;
|
|
19683
20689
|
if (auftrag.status !== "started") continue;
|
|
@@ -19698,18 +20704,18 @@ function ordersForPromptRun(events, runId) {
|
|
|
19698
20704
|
}
|
|
19699
20705
|
|
|
19700
20706
|
// src/lib/szenen/imageBatchStore.ts
|
|
19701
|
-
var
|
|
20707
|
+
var istText5 = (wert) => typeof wert === "string" && wert.trim().length > 0;
|
|
19702
20708
|
function alsBilder(rohe) {
|
|
19703
20709
|
if (!Array.isArray(rohe)) return [];
|
|
19704
|
-
return rohe.filter((b) => !!b && typeof b === "object").filter((b) =>
|
|
20710
|
+
return rohe.filter((b) => !!b && typeof b === "object").filter((b) => istText5(b.media_ref) && typeof b.position === "number").map((b) => ({
|
|
19705
20711
|
media_ref: b.media_ref,
|
|
19706
20712
|
position: b.position,
|
|
19707
|
-
...
|
|
20713
|
+
...istText5(b.asset_id) ? { asset_id: b.asset_id } : {},
|
|
19708
20714
|
// Der bestätigte MIME-Typ (Review 2026-08-18 §5 P2) muss durch das
|
|
19709
20715
|
// Rücklesen hindurch: Genau hier braucht ihn der Lesepfad, um den
|
|
19710
20716
|
// Dateipfad `images/<id>.<ext>` zu bilden, statt ihn zu erraten. Nur
|
|
19711
20717
|
// gesetzt, wenn er im Ereignis steht — ältere Batches tragen ihn nicht.
|
|
19712
|
-
...
|
|
20718
|
+
...istText5(b.mime_type) ? { mime_type: b.mime_type } : {},
|
|
19713
20719
|
model: b.model ?? null,
|
|
19714
20720
|
seed: b.seed ?? null,
|
|
19715
20721
|
width: b.width ?? null,
|
|
@@ -19721,7 +20727,7 @@ function collectImageBatches(events) {
|
|
|
19721
20727
|
for (const event of events) {
|
|
19722
20728
|
if (event.type !== SZENEN_EVENT_TYPES.imageBatchPersisted) continue;
|
|
19723
20729
|
const payload = event.payload;
|
|
19724
|
-
if (!payload || !
|
|
20730
|
+
if (!payload || !istText5(payload.item_id) || !istText5(payload.prompt_run_id) || !istText5(payload.generation_batch_id)) continue;
|
|
19725
20731
|
if (payload.source_kind !== "generated_in_app" && payload.source_kind !== "external_import") continue;
|
|
19726
20732
|
const bestehend = byItemId.get(payload.item_id);
|
|
19727
20733
|
if (bestehend?.generation_batch_ids.includes(payload.generation_batch_id)) continue;
|
|
@@ -19732,7 +20738,7 @@ function collectImageBatches(events) {
|
|
|
19732
20738
|
prompt_run_id: payload.prompt_run_id,
|
|
19733
20739
|
generation_batch_ids: [payload.generation_batch_id],
|
|
19734
20740
|
source_kind: payload.source_kind,
|
|
19735
|
-
title:
|
|
20741
|
+
title: istText5(payload.title) ? payload.title : `Batch aus Lauf ${payload.prompt_run_id}`,
|
|
19736
20742
|
images: bilder
|
|
19737
20743
|
});
|
|
19738
20744
|
continue;
|
|
@@ -20209,7 +21215,7 @@ function createFlowSzenenViewPort(options) {
|
|
|
20209
21215
|
...options.now ? { now: options.now } : {}
|
|
20210
21216
|
}) : void 0;
|
|
20211
21217
|
const bildProvider = options.imageProvider ?? (options.generateImage ? createFlowImageProvider(options.generateImage) : void 0);
|
|
20212
|
-
const bildFaehigkeit = options.imageCapability ?? { environment_id: "flow", execution_paths: [FLOW_EXECUTION_PATH] };
|
|
21218
|
+
const bildFaehigkeit = options.imageCapability ?? { environment_id: "flow", execution_paths: [{ execution_path: FLOW_EXECUTION_PATH, provider: "google" }] };
|
|
20213
21219
|
const imageGeneration = bildProvider && imageBatchWrite ? createImageGenerationPort({
|
|
20214
21220
|
runs: { async getRun(runId) {
|
|
20215
21221
|
return runs.getRun(runId);
|
|
@@ -20301,7 +21307,7 @@ function resolveBootstrapTarget(input) {
|
|
|
20301
21307
|
// src/components/AvatarArchitectApp.tsx
|
|
20302
21308
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
20303
21309
|
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, initialHfToken, hfNamespace, allowDevNamespace, requireWorkspaceSelection = false, serverBaseUrl, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
|
|
20304
|
-
(0,
|
|
21310
|
+
(0, import_react49.useEffect)(() => {
|
|
20305
21311
|
const id = "flow-styles";
|
|
20306
21312
|
if (!document.getElementById(id)) {
|
|
20307
21313
|
const style = document.createElement("style");
|
|
@@ -20310,36 +21316,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20310
21316
|
document.head.appendChild(style);
|
|
20311
21317
|
}
|
|
20312
21318
|
}, []);
|
|
20313
|
-
const [showStart, setShowStart] = (0,
|
|
20314
|
-
const [showSzenen, setShowSzenen] = (0,
|
|
20315
|
-
const [layoutChoice, setLayoutChoice] = (0,
|
|
21319
|
+
const [showStart, setShowStart] = (0, import_react49.useState)(true);
|
|
21320
|
+
const [showSzenen, setShowSzenen] = (0, import_react49.useState)(false);
|
|
21321
|
+
const [layoutChoice, setLayoutChoice] = (0, import_react49.useState)(() => {
|
|
20316
21322
|
try {
|
|
20317
21323
|
return localStorage.getItem("aa-layout") || null;
|
|
20318
21324
|
} catch {
|
|
20319
21325
|
return null;
|
|
20320
21326
|
}
|
|
20321
21327
|
});
|
|
20322
|
-
const [projectLoaded, setProjectLoaded] = (0,
|
|
20323
|
-
const [hfToken, setHfToken] = (0,
|
|
20324
|
-
const [hfTokenInput, setHfTokenInput] = (0,
|
|
20325
|
-
const [isLoadingFromHF, setIsLoadingFromHF] = (0,
|
|
20326
|
-
const [hfNamespaceLocal, setHfNamespaceLocal] = (0,
|
|
21328
|
+
const [projectLoaded, setProjectLoaded] = (0, import_react49.useState)(false);
|
|
21329
|
+
const [hfToken, setHfToken] = (0, import_react49.useState)(initialHfToken || "");
|
|
21330
|
+
const [hfTokenInput, setHfTokenInput] = (0, import_react49.useState)(initialHfToken || "");
|
|
21331
|
+
const [isLoadingFromHF, setIsLoadingFromHF] = (0, import_react49.useState)(false);
|
|
21332
|
+
const [hfNamespaceLocal, setHfNamespaceLocal] = (0, import_react49.useState)(() => {
|
|
20327
21333
|
try {
|
|
20328
21334
|
return normalizeSelectableNamespace(localStorage.getItem("aa-hf-namespace"));
|
|
20329
21335
|
} catch {
|
|
20330
21336
|
return DEFAULT_NAMESPACE;
|
|
20331
21337
|
}
|
|
20332
21338
|
});
|
|
20333
|
-
const [hfNamespaceFromServer, setHfNamespaceFromServer] = (0,
|
|
20334
|
-
const [serverProbeFailed, setServerProbeFailed] = (0,
|
|
20335
|
-
(0,
|
|
21339
|
+
const [hfNamespaceFromServer, setHfNamespaceFromServer] = (0, import_react49.useState)(null);
|
|
21340
|
+
const [serverProbeFailed, setServerProbeFailed] = (0, import_react49.useState)(false);
|
|
21341
|
+
(0, import_react49.useEffect)(() => {
|
|
20336
21342
|
if (hfNamespace !== void 0 || !serverBaseUrl) return;
|
|
20337
21343
|
fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
|
|
20338
21344
|
if (typeof d.hfNamespace === "string" && d.hfNamespace) setHfNamespaceFromServer(d.hfNamespace);
|
|
20339
21345
|
else setServerProbeFailed(true);
|
|
20340
21346
|
}).catch(() => setServerProbeFailed(true));
|
|
20341
21347
|
}, [hfNamespace, serverBaseUrl]);
|
|
20342
|
-
const [targetConfirmed, setTargetConfirmed] = (0,
|
|
21348
|
+
const [targetConfirmed, setTargetConfirmed] = (0, import_react49.useState)(false);
|
|
20343
21349
|
const isDialogTarget = hfNamespace === void 0 && hfNamespaceFromServer === null && (!serverBaseUrl || serverProbeFailed);
|
|
20344
21350
|
const isProbingServer = hfNamespace === void 0 && !!serverBaseUrl && hfNamespaceFromServer === null && !serverProbeFailed;
|
|
20345
21351
|
const bootstrapTarget = resolveBootstrapTarget({
|
|
@@ -20350,8 +21356,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20350
21356
|
isStartDialogOpen: isDialogTarget && !targetConfirmed
|
|
20351
21357
|
});
|
|
20352
21358
|
const effectiveNamespace = bootstrapTarget.namespace ?? "";
|
|
20353
|
-
const kontextRef = (0,
|
|
20354
|
-
const szenenPort = (0,
|
|
21359
|
+
const kontextRef = (0, import_react49.useRef)(null);
|
|
21360
|
+
const szenenPort = (0, import_react49.useMemo)(() => hfToken && effectiveNamespace ? createFlowSzenenViewPort({
|
|
20355
21361
|
generateText: onGeneratePrompt,
|
|
20356
21362
|
token: hfToken,
|
|
20357
21363
|
namespace: effectiveNamespace,
|
|
@@ -20373,10 +21379,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20373
21379
|
const tagBaseResult = useTagBase(hfToken, effectiveNamespace);
|
|
20374
21380
|
const szenenKontextId = tagBaseResult.selectedContextId === null ? null : String(tagBaseResult.selectedContextId);
|
|
20375
21381
|
kontextRef.current = szenenKontextId;
|
|
20376
|
-
const [imageUploadStatus, setImageUploadStatus] = (0,
|
|
20377
|
-
const [bootstrapLog, setBootstrapLog] = (0,
|
|
20378
|
-
const [isBootstrapping, setIsBootstrapping] = (0,
|
|
20379
|
-
const [hfMissingImages, setHfMissingImages] = (0,
|
|
21382
|
+
const [imageUploadStatus, setImageUploadStatus] = (0, import_react49.useState)(/* @__PURE__ */ new Map());
|
|
21383
|
+
const [bootstrapLog, setBootstrapLog] = (0, import_react49.useState)([]);
|
|
21384
|
+
const [isBootstrapping, setIsBootstrapping] = (0, import_react49.useState)(false);
|
|
21385
|
+
const [hfMissingImages, setHfMissingImages] = (0, import_react49.useState)([]);
|
|
20380
21386
|
const syncTopSlot = /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
20381
21387
|
localOnlyCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { style: { background: "rgba(234,179,8,0.15)", border: "1px solid rgba(234,179,8,0.3)", padding: "4px 10px", fontSize: 11, color: "#fbbf24", borderRadius: 4, marginBottom: 4 }, children: [
|
|
20382
21388
|
"\u26A0 ",
|
|
@@ -20426,7 +21432,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20426
21432
|
bootstrapLog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { style: { marginTop: 6, fontFamily: "monospace", fontSize: 10, color: "#78716c", lineHeight: 1.6 }, children: bootstrapLog.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { children: l }, i)) })
|
|
20427
21433
|
] })
|
|
20428
21434
|
] });
|
|
20429
|
-
const wsInputRef = (0,
|
|
21435
|
+
const wsInputRef = (0, import_react49.useRef)(null);
|
|
20430
21436
|
const startApp = (choice) => {
|
|
20431
21437
|
try {
|
|
20432
21438
|
localStorage.setItem("aa-layout", choice);
|
|
@@ -20436,18 +21442,18 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20436
21442
|
setTargetConfirmed(true);
|
|
20437
21443
|
setShowStart(false);
|
|
20438
21444
|
};
|
|
20439
|
-
const [nodes, setNodes] = (0,
|
|
20440
|
-
const [edges, setEdges] = (0,
|
|
20441
|
-
const [history, setHistory] = (0,
|
|
20442
|
-
const [galleryItems, setGalleryItems] = (0,
|
|
20443
|
-
const galleryItemsRef = (0,
|
|
20444
|
-
(0,
|
|
21445
|
+
const [nodes, setNodes] = (0, import_react49.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
21446
|
+
const [edges, setEdges] = (0, import_react49.useState)([]);
|
|
21447
|
+
const [history, setHistory] = (0, import_react49.useState)([]);
|
|
21448
|
+
const [galleryItems, setGalleryItems] = (0, import_react49.useState)([]);
|
|
21449
|
+
const galleryItemsRef = (0, import_react49.useRef)([]);
|
|
21450
|
+
(0, import_react49.useEffect)(() => {
|
|
20445
21451
|
galleryItemsRef.current = galleryItems;
|
|
20446
21452
|
}, [galleryItems]);
|
|
20447
|
-
const hfImageNotFoundRef = (0,
|
|
20448
|
-
const [galleryVisibleCount, setGalleryVisibleCount] = (0,
|
|
20449
|
-
const [historyVisibleCount, setHistoryVisibleCount] = (0,
|
|
20450
|
-
const loadThumbnailsForEntries = (0,
|
|
21453
|
+
const hfImageNotFoundRef = (0, import_react49.useRef)(/* @__PURE__ */ new Map());
|
|
21454
|
+
const [galleryVisibleCount, setGalleryVisibleCount] = (0, import_react49.useState)(20);
|
|
21455
|
+
const [historyVisibleCount, setHistoryVisibleCount] = (0, import_react49.useState)(20);
|
|
21456
|
+
const loadThumbnailsForEntries = (0, import_react49.useCallback)(async (entries) => {
|
|
20451
21457
|
for (const entry of entries) {
|
|
20452
21458
|
if (galleryItemsRef.current.find((g) => g.id === entry.id)?.base64) continue;
|
|
20453
21459
|
if (hfImageNotFoundRef.current.has(entry.id)) continue;
|
|
@@ -20466,7 +21472,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20466
21472
|
}
|
|
20467
21473
|
}
|
|
20468
21474
|
}, [hfToken, effectiveNamespace]);
|
|
20469
|
-
(0,
|
|
21475
|
+
(0, import_react49.useEffect)(() => {
|
|
20470
21476
|
if (!hfState) return;
|
|
20471
21477
|
if (hfState.tags?.by_category) setWorkspaceTags(hfState.tags);
|
|
20472
21478
|
const hfIds = new Set(hfState.metadata.map((m) => m.id));
|
|
@@ -20493,36 +21499,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20493
21499
|
return [...localOnly, ...merged].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
20494
21500
|
});
|
|
20495
21501
|
}, [hfState]);
|
|
20496
|
-
(0,
|
|
21502
|
+
(0, import_react49.useEffect)(() => {
|
|
20497
21503
|
if (!hfState) return;
|
|
20498
21504
|
const sortedMeta = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
20499
21505
|
const skeletons = sortedMeta.map((m) => ({ id: m.id, prompt: m.prompt, timestamp: m.timestamp, status: "done", nodeId: m.id, tags: m.tags || [] }));
|
|
20500
21506
|
const repIds = new Set(groupByPrompt(skeletons).slice(0, galleryVisibleCount).map((g) => g.representative.id));
|
|
20501
21507
|
loadThumbnailsForEntries(sortedMeta.filter((e) => repIds.has(e.id)));
|
|
20502
21508
|
}, [hfState, galleryVisibleCount, loadThumbnailsForEntries]);
|
|
20503
|
-
(0,
|
|
21509
|
+
(0, import_react49.useEffect)(() => {
|
|
20504
21510
|
if (!hfState) return;
|
|
20505
21511
|
const sortedMeta = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
20506
21512
|
loadThumbnailsForEntries(sortedMeta.slice(0, historyVisibleCount));
|
|
20507
21513
|
}, [hfState, historyVisibleCount, loadThumbnailsForEntries]);
|
|
20508
|
-
const [activePrompt, setActivePrompt] = (0,
|
|
20509
|
-
const [isSynthesizing, setIsSynthesizing] = (0,
|
|
20510
|
-
const [activeGenerationsCount, setActiveGenerationsCount] = (0,
|
|
20511
|
-
const [currentResult, setCurrentResult] = (0,
|
|
20512
|
-
const [focusedNodeId, setFocusedNodeId] = (0,
|
|
20513
|
-
const [leftTab, setLeftTab] = (0,
|
|
20514
|
-
const [promptFeedback, setPromptFeedback] = (0,
|
|
20515
|
-
const [lastPromptPayload, setLastPromptPayload] = (0,
|
|
20516
|
-
const [isPromptTabGenerating, setIsPromptTabGenerating] = (0,
|
|
20517
|
-
const [activeTab, setActiveTab] = (0,
|
|
20518
|
-
const [mobileTab, setMobileTab] = (0,
|
|
20519
|
-
const [middlePanel, setMiddlePanel] = (0,
|
|
20520
|
-
const [recentLabItems, setRecentLabItems] = (0,
|
|
20521
|
-
const [aspectRatio, setAspectRatio] = (0,
|
|
20522
|
-
const [selectedModel, setSelectedModel] = (0,
|
|
20523
|
-
const [seed, setSeed] = (0,
|
|
20524
|
-
const [seedMode, setSeedMode] = (0,
|
|
20525
|
-
const [imageCount, setImageCount] = (0,
|
|
21514
|
+
const [activePrompt, setActivePrompt] = (0, import_react49.useState)("");
|
|
21515
|
+
const [isSynthesizing, setIsSynthesizing] = (0, import_react49.useState)(false);
|
|
21516
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react49.useState)(0);
|
|
21517
|
+
const [currentResult, setCurrentResult] = (0, import_react49.useState)(null);
|
|
21518
|
+
const [focusedNodeId, setFocusedNodeId] = (0, import_react49.useState)(null);
|
|
21519
|
+
const [leftTab, setLeftTab] = (0, import_react49.useState)("prompt");
|
|
21520
|
+
const [promptFeedback, setPromptFeedback] = (0, import_react49.useState)(null);
|
|
21521
|
+
const [lastPromptPayload, setLastPromptPayload] = (0, import_react49.useState)(null);
|
|
21522
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react49.useState)(false);
|
|
21523
|
+
const [activeTab, setActiveTab] = (0, import_react49.useState)("history");
|
|
21524
|
+
const [mobileTab, setMobileTab] = (0, import_react49.useState)("stage");
|
|
21525
|
+
const [middlePanel, setMiddlePanel] = (0, import_react49.useState)("stage");
|
|
21526
|
+
const [recentLabItems, setRecentLabItems] = (0, import_react49.useState)([]);
|
|
21527
|
+
const [aspectRatio, setAspectRatio] = (0, import_react49.useState)("1:1");
|
|
21528
|
+
const [selectedModel, setSelectedModel] = (0, import_react49.useState)("\u{1F34C} Nano Banana Pro");
|
|
21529
|
+
const [seed, setSeed] = (0, import_react49.useState)(Math.floor(Math.random() * 1e6));
|
|
21530
|
+
const [seedMode, setSeedMode] = (0, import_react49.useState)("random");
|
|
21531
|
+
const [imageCount, setImageCount] = (0, import_react49.useState)(() => {
|
|
20526
21532
|
try {
|
|
20527
21533
|
const v = parseInt(localStorage.getItem("aa-image-count") || "", 10);
|
|
20528
21534
|
return v >= 1 && v <= 8 ? v : 4;
|
|
@@ -20544,45 +21550,45 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20544
21550
|
{ label: "4 Bilder", value: "4" },
|
|
20545
21551
|
{ label: "8 Bilder", value: "8" }
|
|
20546
21552
|
];
|
|
20547
|
-
const [isLeftCollapsed, setIsLeftCollapsed] = (0,
|
|
20548
|
-
const [isRightCollapsed, setIsRightCollapsed] = (0,
|
|
20549
|
-
const [leftPanelWidth, setLeftPanelWidth] = (0,
|
|
21553
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react49.useState)(false);
|
|
21554
|
+
const [isRightCollapsed, setIsRightCollapsed] = (0, import_react49.useState)(false);
|
|
21555
|
+
const [leftPanelWidth, setLeftPanelWidth] = (0, import_react49.useState)(() => {
|
|
20550
21556
|
try {
|
|
20551
21557
|
return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
|
|
20552
21558
|
} catch {
|
|
20553
21559
|
return 260;
|
|
20554
21560
|
}
|
|
20555
21561
|
});
|
|
20556
|
-
const [rightPanelWidth, setRightPanelWidth] = (0,
|
|
21562
|
+
const [rightPanelWidth, setRightPanelWidth] = (0, import_react49.useState)(() => {
|
|
20557
21563
|
try {
|
|
20558
21564
|
return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
|
|
20559
21565
|
} catch {
|
|
20560
21566
|
return 320;
|
|
20561
21567
|
}
|
|
20562
21568
|
});
|
|
20563
|
-
const [isPromptCollapsed, setIsPromptCollapsed] = (0,
|
|
20564
|
-
const [projectActionState, setProjectActionState] = (0,
|
|
20565
|
-
const syncServerDataRef = (0,
|
|
20566
|
-
const [workspaceTags, setWorkspaceTags] = (0,
|
|
20567
|
-
const [serverProjects, setServerProjects] = (0,
|
|
20568
|
-
const [isLoadingFromServer, setIsLoadingFromServer] = (0,
|
|
20569
|
-
const [highContrast, setHighContrast] = (0,
|
|
21569
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react49.useState)(false);
|
|
21570
|
+
const [projectActionState, setProjectActionState] = (0, import_react49.useState)("idle");
|
|
21571
|
+
const syncServerDataRef = (0, import_react49.useRef)(null);
|
|
21572
|
+
const [workspaceTags, setWorkspaceTags] = (0, import_react49.useState)(null);
|
|
21573
|
+
const [serverProjects, setServerProjects] = (0, import_react49.useState)([]);
|
|
21574
|
+
const [isLoadingFromServer, setIsLoadingFromServer] = (0, import_react49.useState)(false);
|
|
21575
|
+
const [highContrast, setHighContrast] = (0, import_react49.useState)(() => {
|
|
20570
21576
|
try {
|
|
20571
21577
|
return localStorage.getItem("aa-contrast") === "high";
|
|
20572
21578
|
} catch {
|
|
20573
21579
|
return false;
|
|
20574
21580
|
}
|
|
20575
21581
|
});
|
|
20576
|
-
const [activeReferenceId, setActiveReferenceId] = (0,
|
|
20577
|
-
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0,
|
|
20578
|
-
const [isScanningImage, setIsScanningImage] = (0,
|
|
20579
|
-
const [touchStartX, setTouchStartX] = (0,
|
|
20580
|
-
const [isFullscreen, setIsFullscreen] = (0,
|
|
20581
|
-
const [zoomScale, setZoomScale] = (0,
|
|
20582
|
-
const [zoomOffset, setZoomOffset] = (0,
|
|
20583
|
-
const lastPinchDist = (0,
|
|
20584
|
-
const lastTapTime = (0,
|
|
20585
|
-
const dragStart = (0,
|
|
21582
|
+
const [activeReferenceId, setActiveReferenceId] = (0, import_react49.useState)(null);
|
|
21583
|
+
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react49.useState)(null);
|
|
21584
|
+
const [isScanningImage, setIsScanningImage] = (0, import_react49.useState)(false);
|
|
21585
|
+
const [touchStartX, setTouchStartX] = (0, import_react49.useState)(null);
|
|
21586
|
+
const [isFullscreen, setIsFullscreen] = (0, import_react49.useState)(false);
|
|
21587
|
+
const [zoomScale, setZoomScale] = (0, import_react49.useState)(1);
|
|
21588
|
+
const [zoomOffset, setZoomOffset] = (0, import_react49.useState)({ x: 0, y: 0 });
|
|
21589
|
+
const lastPinchDist = (0, import_react49.useRef)(null);
|
|
21590
|
+
const lastTapTime = (0, import_react49.useRef)(0);
|
|
21591
|
+
const dragStart = (0, import_react49.useRef)(null);
|
|
20586
21592
|
const openFullscreen = () => {
|
|
20587
21593
|
setIsFullscreen(true);
|
|
20588
21594
|
setZoomScale(1);
|
|
@@ -20645,7 +21651,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20645
21651
|
setActiveReferenceId(null);
|
|
20646
21652
|
setActiveReferenceThumbnail(null);
|
|
20647
21653
|
};
|
|
20648
|
-
const labServices = (0,
|
|
21654
|
+
const labServices = (0, import_react49.useMemo)(() => {
|
|
20649
21655
|
const available = groupGenerationsToLabItems([...galleryItems, ...history]);
|
|
20650
21656
|
return {
|
|
20651
21657
|
availableItems: available,
|
|
@@ -20725,14 +21731,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20725
21731
|
setIsScanningImage(false);
|
|
20726
21732
|
}
|
|
20727
21733
|
};
|
|
20728
|
-
const currentIndex = (0,
|
|
20729
|
-
const goToPrev = (0,
|
|
21734
|
+
const currentIndex = (0, import_react49.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
21735
|
+
const goToPrev = (0, import_react49.useCallback)(() => {
|
|
20730
21736
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
20731
21737
|
}, [currentIndex, history]);
|
|
20732
|
-
const goToNext = (0,
|
|
21738
|
+
const goToNext = (0, import_react49.useCallback)(() => {
|
|
20733
21739
|
if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
|
|
20734
21740
|
}, [currentIndex, history]);
|
|
20735
|
-
const handleGallerySelect = (0,
|
|
21741
|
+
const handleGallerySelect = (0, import_react49.useCallback)((g) => {
|
|
20736
21742
|
setCurrentResult(g);
|
|
20737
21743
|
setMobileTab("stage");
|
|
20738
21744
|
if (g.hasThumb && g.filename && hfToken && !g.fullBase64) {
|
|
@@ -20745,7 +21751,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20745
21751
|
});
|
|
20746
21752
|
}
|
|
20747
21753
|
}, [hfToken, effectiveNamespace]);
|
|
20748
|
-
const handleTitleSet = (0,
|
|
21754
|
+
const handleTitleSet = (0, import_react49.useCallback)((id) => {
|
|
20749
21755
|
const ts = Date.now();
|
|
20750
21756
|
setGalleryItems((prev) => prev.map((g) => g.id === id ? { ...g, titleTs: ts } : g));
|
|
20751
21757
|
setHistory((prev) => prev.map((g) => g.id === id ? { ...g, titleTs: ts } : g));
|
|
@@ -20754,13 +21760,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20754
21760
|
});
|
|
20755
21761
|
}
|
|
20756
21762
|
}, [hfToken, effectiveNamespace, hfWriteEvent]);
|
|
20757
|
-
const currentGroup = (0,
|
|
21763
|
+
const currentGroup = (0, import_react49.useMemo)(() => {
|
|
20758
21764
|
if (!currentResult?.prompt) return [];
|
|
20759
21765
|
const groups = groupByPrompt(galleryItems.filter((g) => g.status === "done" && !!g.base64));
|
|
20760
21766
|
const group = groups.find((gr) => gr.prompt === currentResult.prompt);
|
|
20761
21767
|
return group ? group.items : [];
|
|
20762
21768
|
}, [galleryItems, currentResult?.prompt]);
|
|
20763
|
-
(0,
|
|
21769
|
+
(0, import_react49.useEffect)(() => {
|
|
20764
21770
|
if (!currentResult?.prompt || !hfToken || !effectiveNamespace || !hfState) return;
|
|
20765
21771
|
const siblings = galleryItemsRef.current.filter(
|
|
20766
21772
|
(g) => g.prompt === currentResult.prompt && !g.base64 && !hfImageNotFoundRef.current.has(g.id)
|
|
@@ -20799,7 +21805,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20799
21805
|
}
|
|
20800
21806
|
) : null;
|
|
20801
21807
|
useKeyboardNavigation(history, currentResult, setCurrentResult);
|
|
20802
|
-
const getSubtreeFormat = (0,
|
|
21808
|
+
const getSubtreeFormat = (0, import_react49.useCallback)((nodeId, depth = 0) => {
|
|
20803
21809
|
const node = nodes.find((n) => n.id === nodeId);
|
|
20804
21810
|
if (!node) return "";
|
|
20805
21811
|
const childrenIds = edges.filter((e) => e.source === nodeId).map((e) => e.target);
|
|
@@ -20807,7 +21813,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20807
21813
|
return `${indent}- ${node.data.label || "(unbenannt)"}
|
|
20808
21814
|
` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
|
|
20809
21815
|
}, [nodes, edges]);
|
|
20810
|
-
const activePath = (0,
|
|
21816
|
+
const activePath = (0, import_react49.useMemo)(() => {
|
|
20811
21817
|
if (!focusedNodeId) return /* @__PURE__ */ new Set();
|
|
20812
21818
|
const path = /* @__PURE__ */ new Set([focusedNodeId]);
|
|
20813
21819
|
let currId = focusedNodeId;
|
|
@@ -21173,7 +22179,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
21173
22179
|
setTimeout(() => setProjectActionState("idle"), 4e3);
|
|
21174
22180
|
}
|
|
21175
22181
|
};
|
|
21176
|
-
(0,
|
|
22182
|
+
(0, import_react49.useEffect)(() => {
|
|
21177
22183
|
if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
|
|
21178
22184
|
}, [activeTab]);
|
|
21179
22185
|
const mergeWorkspaceTags = (local, remote) => {
|
|
@@ -22205,7 +23211,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
22205
23211
|
}
|
|
22206
23212
|
|
|
22207
23213
|
// src/components/FaApp.tsx
|
|
22208
|
-
var
|
|
23214
|
+
var import_react50 = require("react");
|
|
22209
23215
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
22210
23216
|
function FaApp({
|
|
22211
23217
|
onGenerateImage,
|
|
@@ -22225,18 +23231,18 @@ function FaApp({
|
|
|
22225
23231
|
onServerDelete,
|
|
22226
23232
|
buildInfo
|
|
22227
23233
|
}) {
|
|
22228
|
-
const [hfNamespace, setHfNamespace] = (0,
|
|
22229
|
-
(0,
|
|
23234
|
+
const [hfNamespace, setHfNamespace] = (0, import_react50.useState)(void 0);
|
|
23235
|
+
(0, import_react50.useEffect)(() => {
|
|
22230
23236
|
if (!serverBaseUrl) return;
|
|
22231
23237
|
fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
|
|
22232
23238
|
if (typeof d.hfNamespace === "string") setHfNamespace(d.hfNamespace);
|
|
22233
23239
|
}).catch(() => {
|
|
22234
23240
|
});
|
|
22235
23241
|
}, [serverBaseUrl]);
|
|
22236
|
-
const wrappedPrompt =
|
|
22237
|
-
|
|
22238
|
-
|
|
22239
|
-
|
|
23242
|
+
const wrappedPrompt = (0, import_react50.useMemo)(
|
|
23243
|
+
() => alsFlowTextZugang(onGeneratePrompt),
|
|
23244
|
+
[onGeneratePrompt]
|
|
23245
|
+
);
|
|
22240
23246
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
22241
23247
|
AvatarArchitectApp,
|
|
22242
23248
|
{
|
|
@@ -22491,15 +23497,15 @@ function createInMemoryWorkspacePersistence(now = () => Date.now()) {
|
|
|
22491
23497
|
}
|
|
22492
23498
|
|
|
22493
23499
|
// node_modules/zustand/esm/react.mjs
|
|
22494
|
-
var
|
|
23500
|
+
var import_react51 = __toESM(require("react"), 1);
|
|
22495
23501
|
var identity = (arg) => arg;
|
|
22496
23502
|
function useStore(api, selector = identity) {
|
|
22497
|
-
const slice =
|
|
23503
|
+
const slice = import_react51.default.useSyncExternalStore(
|
|
22498
23504
|
api.subscribe,
|
|
22499
|
-
|
|
22500
|
-
|
|
23505
|
+
import_react51.default.useCallback(() => selector(api.getState()), [api, selector]),
|
|
23506
|
+
import_react51.default.useCallback(() => selector(api.getInitialState()), [api, selector])
|
|
22501
23507
|
);
|
|
22502
|
-
|
|
23508
|
+
import_react51.default.useDebugValue(slice);
|
|
22503
23509
|
return slice;
|
|
22504
23510
|
}
|
|
22505
23511
|
|